Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / System.Drawing / System.Drawing / ComIStreamMarshaler.cs
1 //
2 // System.Drawing.ComIStreamMarshaler.cs
3 //
4 // Author:
5 //   Kornél Pál <http://www.kornelpal.hu/>
6 //
7 // Copyright (C) 2005-2006 Kornél Pál
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 // Undefine to debug the protected blocks
32 #define MAP_EX_TO_HR
33
34 // Define to debug wrappers recursively
35 // #define RECURSIVE_WRAPPING
36
37 using System;
38 using System.IO;
39 using System.Reflection;
40 using System.Runtime.InteropServices;
41 using System.Runtime.InteropServices.ComTypes;
42 using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;
43
44 namespace System.Drawing
45 {
46         // Mono does not implement COM interface marshaling
47         // This custom marshaler should be replaced with UnmanagedType.Interface
48         // Provides identical behaviour under Mono and .NET Framework
49         internal sealed class ComIStreamMarshaler : ICustomMarshaler
50         {
51                 private const int S_OK = 0x00000000;
52                 private const int E_NOINTERFACE = unchecked((int)0x80004002);
53
54                 private delegate int QueryInterfaceDelegate(IntPtr @this, [In()] ref Guid riid, IntPtr ppvObject);
55                 private delegate int AddRefDelegate(IntPtr @this);
56                 private delegate int ReleaseDelegate(IntPtr @this);
57                 private delegate int ReadDelegate(IntPtr @this, [Out(), MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pv, int cb, IntPtr pcbRead);
58                 private delegate int WriteDelegate(IntPtr @this, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pv, int cb, IntPtr pcbWritten);
59                 private delegate int SeekDelegate(IntPtr @this, long dlibMove, int dwOrigin, IntPtr plibNewPosition);
60                 private delegate int SetSizeDelegate(IntPtr @this, long libNewSize);
61                 private delegate int CopyToDelegate(IntPtr @this, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(ComIStreamMarshaler))] IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);
62                 private delegate int CommitDelegate(IntPtr @this, int grfCommitFlags);
63                 private delegate int RevertDelegate(IntPtr @this);
64                 private delegate int LockRegionDelegate(IntPtr @this, long libOffset, long cb, int dwLockType);
65                 private delegate int UnlockRegionDelegate(IntPtr @this, long libOffset, long cb, int dwLockType);
66                 private delegate int StatDelegate(IntPtr @this, out STATSTG pstatstg, int grfStatFlag);
67                 private delegate int CloneDelegate(IntPtr @this, out IntPtr ppstm);
68
69                 [StructLayout(LayoutKind.Sequential)]
70                 private sealed class IStreamInterface
71                 {
72                         internal IntPtr lpVtbl;
73                         internal IntPtr gcHandle;
74                 }
75
76                 [StructLayout(LayoutKind.Sequential)]
77                 private sealed class IStreamVtbl
78                 {
79                         internal QueryInterfaceDelegate QueryInterface;
80                         internal AddRefDelegate AddRef;
81                         internal ReleaseDelegate Release;
82                         internal ReadDelegate Read;
83                         internal WriteDelegate Write;
84                         internal SeekDelegate Seek;
85                         internal SetSizeDelegate SetSize;
86                         internal CopyToDelegate CopyTo;
87                         internal CommitDelegate Commit;
88                         internal RevertDelegate Revert;
89                         internal LockRegionDelegate LockRegion;
90                         internal UnlockRegionDelegate UnlockRegion;
91                         internal StatDelegate Stat;
92                         internal CloneDelegate Clone;
93                 }
94
95                 // Managed COM Callable Wrapper implementation
96                 // Reference counting is thread safe
97                 private sealed class ManagedToNativeWrapper
98                 {
99                         // Mono does not implement Marshal.Release
100                         [StructLayout(LayoutKind.Sequential)]
101                         private sealed class ReleaseSlot
102                         {
103                                 internal ReleaseDelegate Release;
104                         }
105
106                         private static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
107                         private static readonly Guid IID_IStream = new Guid("0000000C-0000-0000-C000-000000000046");
108                         private static readonly MethodInfo exceptionGetHResult = typeof(Exception).GetProperty("HResult", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.ExactBinding, null, typeof(int), new Type[] {}, null).GetGetMethod(true);
109                         // Keeps delegates alive while they are marshaled
110                         private static readonly IStreamVtbl managedVtable;
111                         private static IntPtr comVtable;
112                         private static int vtableRefCount;
113
114                         private IStream managedInterface;
115                         private IntPtr comInterface;
116                         // Keeps the object alive when it has no managed references
117                         private GCHandle gcHandle;
118                         private int refCount = 1;
119
120                         static ManagedToNativeWrapper()
121                         {
122                                 EventHandler onShutdown;
123                                 AppDomain currentDomain;
124                                 IStreamVtbl newVtable;
125
126                                 onShutdown = new EventHandler(OnShutdown);
127                                 currentDomain = AppDomain.CurrentDomain;
128                                 currentDomain.DomainUnload += onShutdown;
129                                 currentDomain.ProcessExit += onShutdown;
130
131                                 newVtable = new IStreamVtbl();
132                                 newVtable.QueryInterface = new QueryInterfaceDelegate(QueryInterface);
133                                 newVtable.AddRef = new AddRefDelegate(AddRef);
134                                 newVtable.Release = new ReleaseDelegate(Release);
135                                 newVtable.Read = new ReadDelegate(Read);
136                                 newVtable.Write = new WriteDelegate(Write);
137                                 newVtable.Seek = new SeekDelegate(Seek);
138                                 newVtable.SetSize = new SetSizeDelegate(SetSize);
139                                 newVtable.CopyTo = new CopyToDelegate(CopyTo);
140                                 newVtable.Commit = new CommitDelegate(Commit);
141                                 newVtable.Revert = new RevertDelegate(Revert);
142                                 newVtable.LockRegion = new LockRegionDelegate(LockRegion);
143                                 newVtable.UnlockRegion = new UnlockRegionDelegate(UnlockRegion);
144                                 newVtable.Stat = new StatDelegate(Stat);
145                                 newVtable.Clone = new CloneDelegate(Clone);
146                                 managedVtable = newVtable;
147
148                                 CreateVtable();
149                         }
150
151                         private ManagedToNativeWrapper(IStream managedInterface)
152                         {
153                                 IStreamInterface newInterface;
154
155                                 lock (managedVtable)
156                                 {
157                                         // Vtable may have been disposed when shutting down
158                                         if (vtableRefCount == 0 && comVtable == IntPtr.Zero)
159                                                 CreateVtable();
160                                         vtableRefCount++;
161                                 }
162
163                                 try
164                                 {
165                                         this.managedInterface = managedInterface;
166                                         gcHandle = GCHandle.Alloc(this);
167
168                                         newInterface = new IStreamInterface();
169                                         newInterface.lpVtbl = comVtable;
170                                         newInterface.gcHandle = (IntPtr)gcHandle;
171                                         comInterface = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IStreamInterface)));
172                                         Marshal.StructureToPtr(newInterface, comInterface, false);
173                                 }
174                                 catch
175                                 {
176                                         this.Dispose();
177                                         throw;
178                                 }
179                         }
180
181                         private void Dispose()
182                         {
183                                 if (gcHandle.IsAllocated)
184                                         gcHandle.Free();
185
186                                 if (comInterface != IntPtr.Zero)
187                                 {
188                                         Marshal.FreeHGlobal(comInterface);
189                                         comInterface = IntPtr.Zero;
190                                 }
191
192                                 managedInterface = null;
193
194                                 lock (managedVtable)
195                                 {
196                                         // Dispose vtable when shutting down
197                                         if (--vtableRefCount == 0 && Environment.HasShutdownStarted)
198                                                 DisposeVtable();
199                                 }
200                         }
201
202                         private static void OnShutdown(object sender, EventArgs e)
203                         {
204                                 lock (managedVtable)
205                                 {
206                                         // There may be object instances when shutting down
207                                         if (vtableRefCount == 0 && comVtable != IntPtr.Zero)
208                                                 DisposeVtable();
209                                 }
210                         }
211
212                         private static void CreateVtable()
213                         {
214                                 comVtable = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IStreamVtbl)));
215                                 Marshal.StructureToPtr(managedVtable, comVtable, false);
216                         }
217
218                         private static void DisposeVtable()
219                         {
220                                 Marshal.DestroyStructure(comVtable, typeof(IStreamVtbl));
221                                 Marshal.FreeHGlobal(comVtable);
222                                 comVtable = IntPtr.Zero;
223                         }
224
225                         internal static IStream GetUnderlyingInterface(IntPtr comInterface, bool outParam)
226                         {
227                                 if (Marshal.ReadIntPtr(comInterface) == comVtable)
228                                 {
229                                         IStream managedInterface = GetObject(comInterface).managedInterface;
230
231                                         if (outParam)
232                                                 Release(comInterface);
233
234                                         return managedInterface;
235                                 }
236                                 else
237                                         return null;
238                         }
239
240                         internal static IntPtr GetInterface(IStream managedInterface)
241                         {
242                                 IntPtr comInterface;
243
244                                 if (managedInterface == null)
245                                         return IntPtr.Zero;
246 #if !RECURSIVE_WRAPPING
247                                 else if ((comInterface = NativeToManagedWrapper.GetUnderlyingInterface(managedInterface)) == IntPtr.Zero)
248 #endif
249                                         comInterface = new ManagedToNativeWrapper(managedInterface).comInterface;
250
251                                 return comInterface;
252                         }
253
254                         internal static void ReleaseInterface(IntPtr comInterface)
255                         {
256                                 if (comInterface != IntPtr.Zero)
257                                 {
258                                         IntPtr vtable = Marshal.ReadIntPtr(comInterface);
259
260                                         if (vtable == comVtable)
261                                                 Release(comInterface);
262                                         else
263                                         {
264                                                 ReleaseSlot releaseSlot = (ReleaseSlot)Marshal.PtrToStructure((IntPtr)((long)vtable + (long)(IntPtr.Size * 2)), typeof(ReleaseSlot));
265                                                 releaseSlot.Release(comInterface);
266                                         }
267                                 }
268                         }
269
270                         // Mono does not implement Marshal.GetHRForException
271                         private static int GetHRForException(Exception e)
272                         {
273                                 return (int)exceptionGetHResult.Invoke(e, null);
274                         }
275
276                         private static ManagedToNativeWrapper GetObject(IntPtr @this)
277                         {
278                                 return (ManagedToNativeWrapper)((GCHandle)Marshal.ReadIntPtr(@this, IntPtr.Size)).Target;
279                         }
280
281                         private static int QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject)
282                         {
283 #if MAP_EX_TO_HR
284                                 try
285                                 {
286 #endif
287                                         if (IID_IUnknown.Equals(riid) || IID_IStream.Equals(riid))
288                                         {
289                                                 Marshal.WriteIntPtr(ppvObject, @this);
290                                                 AddRef(@this);
291                                                 return S_OK;
292                                         }
293                                         else
294                                         {
295                                                 Marshal.WriteIntPtr(ppvObject, IntPtr.Zero);
296                                                 return E_NOINTERFACE;
297                                         }
298 #if MAP_EX_TO_HR
299                                 }
300                                 catch (Exception e)
301                                 {
302                                         return GetHRForException(e);
303                                 }
304 #endif
305                         }
306
307                         private static int AddRef(IntPtr @this)
308                         {
309 #if MAP_EX_TO_HR
310                                 try
311                                 {
312 #endif
313                                         ManagedToNativeWrapper thisObject = GetObject(@this);
314
315                                         lock (thisObject)
316                                         {
317                                                 return ++thisObject.refCount;
318                                         }
319 #if MAP_EX_TO_HR
320                                 }
321                                 catch
322                                 {
323                                         return 0;
324                                 }
325 #endif
326                         }
327
328                         private static int Release(IntPtr @this)
329                         {
330 #if MAP_EX_TO_HR
331                                 try
332                                 {
333 #endif
334                                         ManagedToNativeWrapper thisObject = GetObject(@this);
335
336                                         lock (thisObject)
337                                         {
338                                                 if ((thisObject.refCount != 0) && (--thisObject.refCount == 0))
339                                                         thisObject.Dispose();
340
341                                                 return thisObject.refCount;
342                                         }
343 #if MAP_EX_TO_HR
344                                 }
345                                 catch
346                                 {
347                                         return 0;
348                                 }
349 #endif
350                         }
351
352                         private static int Read(IntPtr @this, byte[] pv, int cb, IntPtr pcbRead)
353                         {
354 #if MAP_EX_TO_HR
355                                 try
356                                 {
357 #endif
358                                         GetObject(@this).managedInterface.Read(pv, cb, pcbRead);
359                                         return S_OK;
360 #if MAP_EX_TO_HR
361                                 }
362                                 catch (Exception e)
363                                 {
364                                         return GetHRForException(e);
365                                 }
366 #endif
367                         }
368
369                         private static int Write(IntPtr @this, byte[] pv, int cb, IntPtr pcbWritten)
370                         {
371 #if MAP_EX_TO_HR
372                                 try
373                                 {
374 #endif
375                                         GetObject(@this).managedInterface.Write(pv, cb, pcbWritten);
376                                         return S_OK;
377 #if MAP_EX_TO_HR
378                                 }
379                                 catch (Exception e)
380                                 {
381                                         return GetHRForException(e);
382                                 }
383 #endif
384                         }
385
386                         private static int Seek(IntPtr @this, long dlibMove, int dwOrigin, IntPtr plibNewPosition)
387                         {
388 #if MAP_EX_TO_HR
389                                 try
390                                 {
391 #endif
392                                         GetObject(@this).managedInterface.Seek(dlibMove, dwOrigin, plibNewPosition);
393                                         return S_OK;
394 #if MAP_EX_TO_HR
395                                 }
396                                 catch (Exception e)
397                                 {
398                                         return GetHRForException(e);
399                                 }
400 #endif
401                         }
402
403                         private static int SetSize(IntPtr @this, long libNewSize)
404                         {
405 #if MAP_EX_TO_HR
406                                 try
407                                 {
408 #endif
409                                         GetObject(@this).managedInterface.SetSize(libNewSize);
410                                         return S_OK;
411 #if MAP_EX_TO_HR
412                                 }
413                                 catch (Exception e)
414                                 {
415                                         return GetHRForException(e);
416                                 }
417 #endif
418                         }
419
420                         private static int CopyTo(IntPtr @this, IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
421                         {
422 #if MAP_EX_TO_HR
423                                 try
424                                 {
425 #endif
426                                         GetObject(@this).managedInterface.CopyTo(pstm, cb, pcbRead, pcbWritten);
427                                         return S_OK;
428 #if MAP_EX_TO_HR
429                                 }
430                                 catch (Exception e)
431                                 {
432                                         return GetHRForException(e);
433                                 }
434 #endif
435                         }
436
437                         private static int Commit(IntPtr @this, int grfCommitFlags)
438                         {
439 #if MAP_EX_TO_HR
440                                 try
441                                 {
442 #endif
443                                         GetObject(@this).managedInterface.Commit(grfCommitFlags);
444                                         return S_OK;
445 #if MAP_EX_TO_HR
446                                 }
447                                 catch (Exception e)
448                                 {
449                                         return GetHRForException(e);
450                                 }
451 #endif
452                         }
453
454                         private static int Revert(IntPtr @this)
455                         {
456 #if MAP_EX_TO_HR
457                                 try
458                                 {
459 #endif
460                                         GetObject(@this).managedInterface.Revert();
461                                         return S_OK;
462 #if MAP_EX_TO_HR
463                                 }
464                                 catch (Exception e)
465                                 {
466                                         return GetHRForException(e);
467                                 }
468 #endif
469                         }
470
471                         private static int LockRegion(IntPtr @this, long libOffset, long cb, int dwLockType)
472                         {
473 #if MAP_EX_TO_HR
474                                 try
475                                 {
476 #endif
477                                         GetObject(@this).managedInterface.LockRegion(libOffset, cb, dwLockType);
478                                         return S_OK;
479 #if MAP_EX_TO_HR
480                                 }
481                                 catch (Exception e)
482                                 {
483                                         return GetHRForException(e);
484                                 }
485 #endif
486                         }
487
488                         private static int UnlockRegion(IntPtr @this, long libOffset, long cb, int dwLockType)
489                         {
490 #if MAP_EX_TO_HR
491                                 try
492                                 {
493 #endif
494                                         GetObject(@this).managedInterface.UnlockRegion(libOffset, cb, dwLockType);
495                                         return S_OK;
496 #if MAP_EX_TO_HR
497                                 }
498                                 catch (Exception e)
499                                 {
500                                         return GetHRForException(e);
501                                 }
502 #endif
503                         }
504
505                         private static int Stat(IntPtr @this, out STATSTG pstatstg, int grfStatFlag)
506                         {
507 #if MAP_EX_TO_HR
508                                 try
509                                 {
510 #endif
511                                         GetObject(@this).managedInterface.Stat(out pstatstg, grfStatFlag);
512                                         return S_OK;
513 #if MAP_EX_TO_HR
514                                 }
515                                 catch (Exception e)
516                                 {
517                                         pstatstg = new STATSTG();
518                                         return GetHRForException(e);
519                                 }
520 #endif
521                         }
522
523                         private static int Clone(IntPtr @this, out IntPtr ppstm)
524                         {
525                                 ppstm = IntPtr.Zero;
526 #if MAP_EX_TO_HR
527                                 try
528                                 {
529 #endif
530                                         IStream newInterface;
531
532                                         GetObject(@this).managedInterface.Clone(out newInterface);
533                                         ppstm = ManagedToNativeWrapper.GetInterface(newInterface);
534                                         return S_OK;
535 #if MAP_EX_TO_HR
536                                 }
537                                 catch (Exception e)
538                                 {
539                                         return GetHRForException(e);
540                                 }
541 #endif
542                         }
543                 }
544
545                 // Managed Runtime Callable Wrapper implementation
546                 private sealed class NativeToManagedWrapper : IStream
547                 {
548                         private IntPtr comInterface;
549                         private IStreamVtbl managedVtable;
550
551                         private NativeToManagedWrapper(IntPtr comInterface, bool outParam)
552                         {
553                                 this.comInterface = comInterface;
554                                 managedVtable = (IStreamVtbl)Marshal.PtrToStructure(Marshal.ReadIntPtr(comInterface), typeof(IStreamVtbl));
555                                 if (!outParam)
556                                         managedVtable.AddRef(comInterface);
557                         }
558
559                         ~NativeToManagedWrapper()
560                         {
561                                 Dispose(false);
562                         }
563
564                         private void Dispose(bool disposing)
565                         {
566                                 managedVtable.Release(comInterface);
567                                 if (disposing)
568                                 {
569                                         comInterface = IntPtr.Zero;
570                                         managedVtable = null;
571                                         GC.SuppressFinalize(this);
572                                 }
573                         }
574
575                         internal static IntPtr GetUnderlyingInterface(IStream managedInterface)
576                         {
577                                 if (managedInterface is NativeToManagedWrapper)
578                                 {
579                                         NativeToManagedWrapper wrapper = (NativeToManagedWrapper)managedInterface;
580
581                                         wrapper.managedVtable.AddRef(wrapper.comInterface);
582                                         return wrapper.comInterface;
583                                 }
584                                 else
585                                         return IntPtr.Zero;
586                         }
587
588                         internal static IStream GetInterface(IntPtr comInterface, bool outParam)
589                         {
590                                 IStream managedInterface;
591
592                                 if (comInterface == IntPtr.Zero)
593                                         return null;
594 #if !RECURSIVE_WRAPPING
595                                 else if ((managedInterface = ManagedToNativeWrapper.GetUnderlyingInterface(comInterface, outParam)) == null)
596 #endif
597                                         managedInterface = (IStream)new NativeToManagedWrapper(comInterface, outParam);
598
599                                 return managedInterface;
600                         }
601
602                         internal static void ReleaseInterface(IStream managedInterface)
603                         {
604                                 if (managedInterface is NativeToManagedWrapper)
605                                         ((NativeToManagedWrapper)managedInterface).Dispose(true);
606                         }
607
608                         // Mono does not implement Marshal.ThrowExceptionForHR
609                         private static void ThrowExceptionForHR(int result)
610                         {
611                                 if (result < 0)
612                                         throw new COMException(null, result);
613                         }
614
615                         public void Read(byte[] pv, int cb, IntPtr pcbRead)
616                         {
617                                 ThrowExceptionForHR(managedVtable.Read(comInterface, pv, cb, pcbRead));
618                         }
619
620                         public void Write(byte[] pv, int cb, IntPtr pcbWritten)
621                         {
622                                 ThrowExceptionForHR(managedVtable.Write(comInterface, pv, cb, pcbWritten));
623                         }
624
625                         public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
626                         {
627                                 ThrowExceptionForHR(managedVtable.Seek(comInterface, dlibMove, dwOrigin, plibNewPosition));
628                         }
629
630                         public void SetSize(long libNewSize)
631                         {
632                                 ThrowExceptionForHR(managedVtable.SetSize(comInterface, libNewSize));
633                         }
634
635                         public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
636                         {
637                                 ThrowExceptionForHR(managedVtable.CopyTo(comInterface, pstm, cb, pcbRead, pcbWritten));
638                         }
639
640                         public void Commit(int grfCommitFlags)
641                         {
642                                 ThrowExceptionForHR(managedVtable.Commit(comInterface, grfCommitFlags));
643                         }
644
645                         public void Revert()
646                         {
647                                 ThrowExceptionForHR(managedVtable.Revert(comInterface));
648                         }
649
650                         public void LockRegion(long libOffset, long cb, int dwLockType)
651                         {
652                                 ThrowExceptionForHR(managedVtable.LockRegion(comInterface, libOffset, cb, dwLockType));
653                         }
654
655                         public void UnlockRegion(long libOffset, long cb, int dwLockType)
656                         {
657                                 ThrowExceptionForHR(managedVtable.UnlockRegion(comInterface, libOffset, cb, dwLockType));
658                         }
659
660                         public void Stat(out STATSTG pstatstg, int grfStatFlag)
661                         {
662                                 ThrowExceptionForHR(managedVtable.Stat(comInterface, out pstatstg, grfStatFlag));
663                         }
664
665                         public void Clone(out IStream ppstm)
666                         {
667                                 IntPtr newInterface;
668
669                                 ThrowExceptionForHR(managedVtable.Clone(comInterface, out newInterface));
670                                 ppstm = NativeToManagedWrapper.GetInterface(newInterface, true);
671                         }
672                 }
673
674                 private static readonly ComIStreamMarshaler defaultInstance = new ComIStreamMarshaler();
675
676                 private ComIStreamMarshaler()
677                 {
678                 }
679
680                 private static ICustomMarshaler GetInstance(string cookie)
681                 {
682                         return defaultInstance;
683                 }
684
685                 public IntPtr MarshalManagedToNative(object managedObj)
686                 {
687 #if RECURSIVE_WRAPPING
688                         managedObj = NativeToManagedWrapper.GetInterface(ManagedToNativeWrapper.GetInterface((IStream)managedObj), true);
689 #endif
690                         return ManagedToNativeWrapper.GetInterface((IStream)managedObj);
691                 }
692
693                 public void CleanUpNativeData(IntPtr pNativeData)
694                 {
695                         ManagedToNativeWrapper.ReleaseInterface(pNativeData);
696                 }
697
698                 public object MarshalNativeToManaged(IntPtr pNativeData)
699                 {
700 #if RECURSIVE_WRAPPING
701                         pNativeData = ManagedToNativeWrapper.GetInterface(NativeToManagedWrapper.GetInterface(pNativeData, true));
702 #endif
703                         return NativeToManagedWrapper.GetInterface(pNativeData, false);
704                 }
705
706                 public void CleanUpManagedData(object managedObj)
707                 {
708                         NativeToManagedWrapper.ReleaseInterface((IStream)managedObj);
709                 }
710
711                 public int GetNativeDataSize()
712                 {
713                         return -1;
714                 }
715         }
716 }