Do I need to marshal the IStream returned by CreateStreamOnHGlobal for streaming?

I have a COM stream object ( IStream) created using CreateStreamOnHGlobal.

I want to use it in different threads within the same process. Do I need to marshal the stream object itself (using CoMarshalInterface, etc.)? Or is it already thread safe?

EDITED , read / write / search correctly synchronized with locks in my codes.

+3
source share
2 answers

COM IStream , . , IStream, CoMarshalInterThreadInterfaceInStream.

2003 : COM-.

Update:

, , . OLE- IStream, CreateStreamOnHGlobal CoMarshalInterThreadInterfaceInStream .

. CoMarshalInterThreadInterfaceInStream :

, ppStm, , , , .

CreateStreamOnHGlobal SHCreateMemStream:

, CreateStreamOnHGlobal, .

IStream. , CoMarshalInterThreadInterfaceInStream, . , COM , ( ) , . , , - . , Global Interface Table.

+3

EDITED, MSDN:

. , SHCreateMemStream, Windows 8. . , CreateStreamOnHGlobal, .

, . , @HansPassant , @IInpectable . , IStream.

:

  • , IStream . .

  • MTA, IStream from thread unmarshaled thread2 IUnknown, .

  • thread1 - STA, thread2 - MTA, . , thread, - thread2.

, stream1 , . , , /. , , , IStream, CreateStreamOnHGlobal, .

, COM IStream, , - , CreateStreamOnHGlobal.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static void TestStream()
        {
            // start thread1
            var thread1 = new Thread(() =>
            {
                // create stream1 on thread1
                System.Runtime.InteropServices.ComTypes.IStream stream1;
                CreateStreamOnHGlobal(IntPtr.Zero, true, out stream1);
                IntPtr unkStream1 = Marshal.GetIUnknownForObject(stream1);

                // marshal stream1, to be unmarshalled on thread2
                Guid iid = typeof(System.Runtime.InteropServices.ComTypes.IStream).GUID;
                System.Runtime.InteropServices.ComTypes.IStream marshallerStream;
                CoMarshalInterThreadInterfaceInStream(ref iid, stream1, out marshallerStream);

                // write to stream1
                var buf1 = new byte[] { 1, 2, 3, 4 };
                stream1.Write(buf1, buf1.Length, IntPtr.Zero);

                // start thread2
                var thread2 = new Thread(() =>
                {
                    // read from stream1 (the direct reference) on thread2

                    var buf2 = new byte[buf1.Length];
                    for (var i = 0; i < 10000; i++)
                    {
                        stream1.Seek(0, 0, IntPtr.Zero);
                        stream1.Read(buf2, buf2.Length, IntPtr.Zero);

                        // trule thread safe, this always works!
                        for (var j = 0; j < buf2.Length; j++)
                            Debug.Assert(buf1[j] == buf2[j]);
                    }

                    // Unmarshal and compare IUnknown pointers
                    object stream2;
                    CoGetInterfaceAndReleaseStream(marshallerStream, ref iid, out stream2);
                    IntPtr unkStream2 = Marshal.GetIUnknownForObject(stream2);

                    // Bangs if thread1 is STA, works OK if thread1 is MTA
                    Debug.Assert(unkStream1 == unkStream2);

                    Marshal.Release(unkStream2);
                });

                for (var i = 0; i < 10000; i++)
                {
                    stream1.Seek(0, 0, IntPtr.Zero);
                    stream1.Write(buf1, buf1.Length, IntPtr.Zero);
                }

                thread2.SetApartmentState(ApartmentState.MTA);
                thread2.Start();
                thread2.Join();

                Marshal.Release(unkStream1);
            });

            thread1.SetApartmentState(ApartmentState.STA);
            thread1.Start();
            thread1.Join();
        }

        static void Main(string[] args)
        {
            TestStream();
        }

        [DllImport("ole32.dll", PreserveSig = false)]
        public static extern void CreateStreamOnHGlobal(
            IntPtr hGlobal,
            bool fDeleteOnRelease,
            [Out] out System.Runtime.InteropServices.ComTypes.IStream pStream);

        [DllImport("ole32.dll", PreserveSig = false)]
        public static extern void CoMarshalInterThreadInterfaceInStream(
            [In] ref Guid riid,
            [MarshalAs(UnmanagedType.IUnknown)] object unk,
            out System.Runtime.InteropServices.ComTypes.IStream stream);

        [DllImport("ole32.dll", PreserveSig = false)]
        public static extern void CoGetInterfaceAndReleaseStream(
            [In] System.Runtime.InteropServices.ComTypes.IStream stream,
            [In] ref Guid riid,
            [Out, MarshalAs(UnmanagedType.IUnknown)] out object unk);
    }
}
+1

All Articles