2005-10-04 Zoltan Varga <vargaz@freemail.hu>
[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 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 #if NET_2_0
42 using System.Runtime.InteropServices.ComTypes;
43 using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;
44 #else
45 using IStream = System.Runtime.InteropServices.UCOMIStream;
46 #endif
47
48 namespace System.Drawing
49 {
50         // Mono does not implement COM interface marshaling
51         // This custom marshaler should be replaced with UnmanagedType.Interface
52         // Provides identical behaviour under Mono and .NET Framework
53         internal sealed class ComIStreamMarshaler : ICustomMarshaler
54         {
55                 private const int S_OK = 0x00000000;
56                 private const int E_NOINTERFACE = unchecked((int)0x80004002);
57
58                 private delegate int QueryInterfaceDelegate(IntPtr @this, [In()] ref Guid riid, IntPtr ppvObject);
59                 private delegate int AddRefDelegate(IntPtr @this);
60                 private delegate int ReleaseDelegate(IntPtr @this);
61                 private delegate int ReadDelegate(IntPtr @this, [Out(), MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pv, int cb, IntPtr pcbRead);
62                 private delegate int WriteDelegate(IntPtr @this, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pv, int cb, IntPtr pcbWritten);
63                 private delegate int SeekDelegate(IntPtr @this, long dlibMove, int dwOrigin, IntPtr plibNewPosition);
64                 private delegate int SetSizeDelegate(IntPtr @this, long libNewSize);
65                 private delegate int CopyToDelegate(IntPtr @this, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(ComIStreamMarshaler))] IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);
66                 private delegate int CommitDelegate(IntPtr @this, int grfCommitFlags);
67                 private delegate int RevertDelegate(IntPtr @this);
68                 private delegate int LockRegionDelegate(IntPtr @this, long libOffset, long cb, int dwLockType);
69                 private delegate int UnlockRegionDelegate(IntPtr @this, long libOffset, long cb, int dwLockType);
70                 private delegate int StatDelegate(IntPtr @this, out STATSTG pstatstg, int grfStatFlag);
71                 private delegate int CloneDelegate(IntPtr @this, out IntPtr ppstm);
72
73                 [StructLayout(LayoutKind.Sequential)]
74                 private sealed class IStreamInterface
75                 {
76                         internal IntPtr lpVtbl;
77                         internal IntPtr gcHandle;
78                 }
79
80                 [StructLayout(LayoutKind.Sequential)]
81                 private sealed class IStreamVtbl
82                 {
83                         internal QueryInterfaceDelegate QueryInterface;
84                         internal AddRefDelegate AddRef;
85                         internal ReleaseDelegate Release;
86                         internal ReadDelegate Read;
87                         internal WriteDelegate Write;
88                         internal SeekDelegate Seek;
89                         internal SetSizeDelegate SetSize;
90                         internal CopyToDelegate CopyTo;
91                         internal CommitDelegate Commit;
92                         internal RevertDelegate Revert;
93                         internal LockRegionDelegate LockRegion;
94                         internal UnlockRegionDelegate UnlockRegion;
95                         internal StatDelegate Stat;
96                         internal CloneDelegate Clone;
97                 }
98
99                 // Managed COM Callable Wrapper implementation
100                 // Reference counting is thread safe
101                 private sealed class ManagedToNativeWrapper
102                 {
103                         // Mono does not implement Marshal.Release
104                         [StructLayout(LayoutKind.Sequential)]
105                         private sealed class ReleaseSlot
106                         {
107                                 internal ReleaseDelegate Release;
108                         }
109
110                         private sealed class VtableDestructor
111                         {
112                                 ~VtableDestructor()
113                                 {
114                                         Marshal.DestroyStructure(comVtable, typeof(IStreamVtbl));
115                                         Marshal.FreeHGlobal(comVtable);
116                                 }
117                         }
118
119                         private static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
120                         private static readonly Guid IID_IStream = new Guid("0000000C-0000-0000-C000-000000000046");
121                         private static readonly MethodInfo exceptionGetHResult = typeof(Exception).GetProperty("HResult", BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.ExactBinding, null, typeof(int), new Type[] {}, null).GetGetMethod(true);
122                         // Keeps delegates alive while they are marshaled
123                         private static readonly IStreamVtbl managedVtable;
124                         private static readonly IntPtr comVtable;
125                         private static readonly VtableDestructor vtableDestructor;
126
127                         private IStream managedInterface;
128                         private IntPtr comInterface;
129                         // Keeps the object alive when it has no managed references
130                         private GCHandle gcHandle;
131                         private int refCount = 1;
132
133                         static ManagedToNativeWrapper()
134                         {
135                                 IStreamVtbl newVtable;
136
137                                 newVtable = new IStreamVtbl();
138                                 newVtable.QueryInterface = new QueryInterfaceDelegate(QueryInterface);
139                                 newVtable.AddRef = new AddRefDelegate(AddRef);
140                                 newVtable.Release = new ReleaseDelegate(Release);
141                                 newVtable.Read = new ReadDelegate(Read);
142                                 newVtable.Write = new WriteDelegate(Write);
143                                 newVtable.Seek = new SeekDelegate(Seek);
144                                 newVtable.SetSize = new SetSizeDelegate(SetSize);
145                                 newVtable.CopyTo = new CopyToDelegate(CopyTo);
146                                 newVtable.Commit = new CommitDelegate(Commit);
147                                 newVtable.Revert = new RevertDelegate(Revert);
148                                 newVtable.LockRegion = new LockRegionDelegate(LockRegion);
149                                 newVtable.UnlockRegion = new UnlockRegionDelegate(UnlockRegion);
150                                 newVtable.Stat = new StatDelegate(Stat);
151                                 newVtable.Clone = new CloneDelegate(Clone);
152                                 comVtable = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IStreamVtbl)));
153                                 Marshal.StructureToPtr(newVtable, comVtable, false);
154                                 managedVtable = newVtable;
155
156                                 vtableDestructor = new VtableDestructor();
157                         }
158
159                         private ManagedToNativeWrapper(IStream managedInterface)
160                         {
161                                 IStreamInterface newInterface;
162
163                                 this.managedInterface = managedInterface;
164                                 gcHandle = GCHandle.Alloc(this);
165
166                                 newInterface = new IStreamInterface();
167                                 newInterface.lpVtbl = comVtable;
168                                 newInterface.gcHandle = (IntPtr)gcHandle;
169                                 comInterface = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IStreamInterface)));
170                                 Marshal.StructureToPtr(newInterface, comInterface, false);
171                         }
172
173                         ~ManagedToNativeWrapper()
174                         {
175                                 Dispose(false);
176                         }
177
178                         private void Dispose(bool disposing)
179                         {
180                                 Marshal.FreeHGlobal(comInterface);
181                                 gcHandle.Free();
182                                 if (disposing)
183                                 {
184                                         comInterface = IntPtr.Zero;
185                                         managedInterface = null;
186                                         GC.SuppressFinalize(this);
187                                 }
188                         }
189
190                         internal static IStream GetUnderlyingInterface(IntPtr comInterface, bool outParam)
191                         {
192                                 if (Marshal.ReadIntPtr(comInterface) == comVtable)
193                                 {
194                                         IStream managedInterface = GetObject(comInterface).managedInterface;
195
196                                         if (outParam)
197                                                 Release(comInterface);
198
199                                         return managedInterface;
200                                 }
201                                 else
202                                         return null;
203                         }
204
205                         internal static IntPtr GetInterface(IStream managedInterface)
206                         {
207                                 IntPtr comInterface;
208
209                                 if (managedInterface == null)
210                                         return IntPtr.Zero;
211 #if !RECURSIVE_WRAPPING
212                                 else if ((comInterface = NativeToManagedWrapper.GetUnderlyingInterface(managedInterface)) == IntPtr.Zero)
213 #endif
214                                         comInterface = new ManagedToNativeWrapper(managedInterface).comInterface;
215
216                                 return comInterface;
217                         }
218
219                         internal static void ReleaseInterface(IntPtr comInterface)
220                         {
221                                 if (comInterface != IntPtr.Zero)
222                                 {
223                                         IntPtr vtable = Marshal.ReadIntPtr(comInterface);
224
225                                         if (vtable == comVtable)
226                                                 Release(comInterface);
227                                         else
228                                         {
229                                                 ReleaseSlot releaseSlot = (ReleaseSlot)Marshal.PtrToStructure((IntPtr)((long)vtable + (long)(IntPtr.Size * 2)), typeof(ReleaseSlot));
230                                                 releaseSlot.Release(comInterface);
231                                         }
232                                 }
233                         }
234
235                         // Mono does not implement Marshal.GetHRForException
236                         private static int GetHRForException(Exception e)
237                         {
238                                 return (int)exceptionGetHResult.Invoke(e, null);
239                         }
240
241                         private static ManagedToNativeWrapper GetObject(IntPtr @this)
242                         {
243                                 return (ManagedToNativeWrapper)((GCHandle)Marshal.ReadIntPtr(@this, IntPtr.Size)).Target;
244                         }
245
246                         private static int QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject)
247                         {
248 #if MAP_EX_TO_HR
249                                 try
250                                 {
251 #endif
252                                         if (IID_IUnknown.Equals(riid) || IID_IStream.Equals(riid))
253                                         {
254                                                 Marshal.WriteIntPtr(ppvObject, @this);
255                                                 AddRef(@this);
256                                                 return S_OK;
257                                         }
258                                         else
259                                         {
260                                                 Marshal.WriteIntPtr(ppvObject, IntPtr.Zero);
261                                                 return E_NOINTERFACE;
262                                         }
263 #if MAP_EX_TO_HR
264                                 }
265                                 catch (Exception e)
266                                 {
267                                         return GetHRForException(e);
268                                 }
269 #endif
270                         }
271
272                         private static int AddRef(IntPtr @this)
273                         {
274 #if MAP_EX_TO_HR
275                                 try
276                                 {
277 #endif
278                                         ManagedToNativeWrapper thisObject = GetObject(@this);
279
280                                         lock (thisObject)
281                                         {
282                                                 return ++thisObject.refCount;
283                                         }
284 #if MAP_EX_TO_HR
285                                 }
286                                 catch
287                                 {
288                                         return 0;
289                                 }
290 #endif
291                         }
292
293                         private static int Release(IntPtr @this)
294                         {
295 #if MAP_EX_TO_HR
296                                 try
297                                 {
298 #endif
299                                         ManagedToNativeWrapper thisObject = GetObject(@this);
300
301                                         lock (thisObject)
302                                         {
303                                                 if ((thisObject.refCount != 0) && (--thisObject.refCount == 0))
304                                                         thisObject.Dispose(true);
305
306                                                 return thisObject.refCount;
307                                         }
308 #if MAP_EX_TO_HR
309                                 }
310                                 catch
311                                 {
312                                         return 0;
313                                 }
314 #endif
315                         }
316
317                         private static int Read(IntPtr @this, byte[] pv, int cb, IntPtr pcbRead)
318                         {
319 #if MAP_EX_TO_HR
320                                 try
321                                 {
322 #endif
323                                         GetObject(@this).managedInterface.Read(pv, cb, pcbRead);
324                                         return S_OK;
325 #if MAP_EX_TO_HR
326                                 }
327                                 catch (Exception e)
328                                 {
329                                         return GetHRForException(e);
330                                 }
331 #endif
332                         }
333
334                         private static int Write(IntPtr @this, byte[] pv, int cb, IntPtr pcbWritten)
335                         {
336 #if MAP_EX_TO_HR
337                                 try
338                                 {
339 #endif
340                                         GetObject(@this).managedInterface.Write(pv, cb, pcbWritten);
341                                         return S_OK;
342 #if MAP_EX_TO_HR
343                                 }
344                                 catch (Exception e)
345                                 {
346                                         return GetHRForException(e);
347                                 }
348 #endif
349                         }
350
351                         private static int Seek(IntPtr @this, long dlibMove, int dwOrigin, IntPtr plibNewPosition)
352                         {
353 #if MAP_EX_TO_HR
354                                 try
355                                 {
356 #endif
357                                         GetObject(@this).managedInterface.Seek(dlibMove, dwOrigin, plibNewPosition);
358                                         return S_OK;
359 #if MAP_EX_TO_HR
360                                 }
361                                 catch (Exception e)
362                                 {
363                                         return GetHRForException(e);
364                                 }
365 #endif
366                         }
367
368                         private static int SetSize(IntPtr @this, long libNewSize)
369                         {
370 #if MAP_EX_TO_HR
371                                 try
372                                 {
373 #endif
374                                         GetObject(@this).managedInterface.SetSize(libNewSize);
375                                         return S_OK;
376 #if MAP_EX_TO_HR
377                                 }
378                                 catch (Exception e)
379                                 {
380                                         return GetHRForException(e);
381                                 }
382 #endif
383                         }
384
385                         private static int CopyTo(IntPtr @this, IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
386                         {
387 #if MAP_EX_TO_HR
388                                 try
389                                 {
390 #endif
391                                         GetObject(@this).managedInterface.CopyTo(pstm, cb, pcbRead, pcbWritten);
392                                         return S_OK;
393 #if MAP_EX_TO_HR
394                                 }
395                                 catch (Exception e)
396                                 {
397                                         return GetHRForException(e);
398                                 }
399 #endif
400                         }
401
402                         private static int Commit(IntPtr @this, int grfCommitFlags)
403                         {
404 #if MAP_EX_TO_HR
405                                 try
406                                 {
407 #endif
408                                         GetObject(@this).managedInterface.Commit(grfCommitFlags);
409                                         return S_OK;
410 #if MAP_EX_TO_HR
411                                 }
412                                 catch (Exception e)
413                                 {
414                                         return GetHRForException(e);
415                                 }
416 #endif
417                         }
418
419                         private static int Revert(IntPtr @this)
420                         {
421 #if MAP_EX_TO_HR
422                                 try
423                                 {
424 #endif
425                                         GetObject(@this).managedInterface.Revert();
426                                         return S_OK;
427 #if MAP_EX_TO_HR
428                                 }
429                                 catch (Exception e)
430                                 {
431                                         return GetHRForException(e);
432                                 }
433 #endif
434                         }
435
436                         private static int LockRegion(IntPtr @this, long libOffset, long cb, int dwLockType)
437                         {
438 #if MAP_EX_TO_HR
439                                 try
440                                 {
441 #endif
442                                         GetObject(@this).managedInterface.LockRegion(libOffset, cb, dwLockType);
443                                         return S_OK;
444 #if MAP_EX_TO_HR
445                                 }
446                                 catch (Exception e)
447                                 {
448                                         return GetHRForException(e);
449                                 }
450 #endif
451                         }
452
453                         private static int UnlockRegion(IntPtr @this, long libOffset, long cb, int dwLockType)
454                         {
455 #if MAP_EX_TO_HR
456                                 try
457                                 {
458 #endif
459                                         GetObject(@this).managedInterface.UnlockRegion(libOffset, cb, dwLockType);
460                                         return S_OK;
461 #if MAP_EX_TO_HR
462                                 }
463                                 catch (Exception e)
464                                 {
465                                         return GetHRForException(e);
466                                 }
467 #endif
468                         }
469
470                         private static int Stat(IntPtr @this, out STATSTG pstatstg, int grfStatFlag)
471                         {
472 #if MAP_EX_TO_HR
473                                 try
474                                 {
475 #endif
476                                         GetObject(@this).managedInterface.Stat(out pstatstg, grfStatFlag);
477                                         return S_OK;
478 #if MAP_EX_TO_HR
479                                 }
480                                 catch (Exception e)
481                                 {
482                                         pstatstg = new STATSTG();
483                                         return GetHRForException(e);
484                                 }
485 #endif
486                         }
487
488                         private static int Clone(IntPtr @this, out IntPtr ppstm)
489                         {
490                                 ppstm = IntPtr.Zero;
491 #if MAP_EX_TO_HR
492                                 try
493                                 {
494 #endif
495                                         IStream newInterface;
496
497                                         GetObject(@this).managedInterface.Clone(out newInterface);
498                                         ppstm = ManagedToNativeWrapper.GetInterface(newInterface);
499                                         return S_OK;
500 #if MAP_EX_TO_HR
501                                 }
502                                 catch (Exception e)
503                                 {
504                                         return GetHRForException(e);
505                                 }
506 #endif
507                         }
508                 }
509
510                 // Managed Runtime Callable Wrapper implementation
511                 private sealed class NativeToManagedWrapper : IStream
512                 {
513                         private IntPtr comInterface;
514                         private IStreamVtbl managedVtable;
515
516                         private NativeToManagedWrapper(IntPtr comInterface, bool outParam)
517                         {
518                                 this.comInterface = comInterface;
519                                 managedVtable = (IStreamVtbl)Marshal.PtrToStructure(Marshal.ReadIntPtr(comInterface), typeof(IStreamVtbl));
520                                 if (!outParam)
521                                         managedVtable.AddRef(comInterface);
522                         }
523
524                         ~NativeToManagedWrapper()
525                         {
526                                 Dispose(false);
527                         }
528
529                         private void Dispose(bool disposing)
530                         {
531                                 managedVtable.Release(comInterface);
532                                 if (disposing)
533                                 {
534                                         comInterface = IntPtr.Zero;
535                                         managedVtable = null;
536                                         GC.SuppressFinalize(this);
537                                 }
538                         }
539
540                         internal static IntPtr GetUnderlyingInterface(IStream managedInterface)
541                         {
542                                 if (managedInterface is NativeToManagedWrapper)
543                                 {
544                                         NativeToManagedWrapper wrapper = (NativeToManagedWrapper)managedInterface;
545
546                                         wrapper.managedVtable.AddRef(wrapper.comInterface);
547                                         return wrapper.comInterface;
548                                 }
549                                 else
550                                         return IntPtr.Zero;
551                         }
552
553                         internal static IStream GetInterface(IntPtr comInterface, bool outParam)
554                         {
555                                 IStream managedInterface;
556
557                                 if (comInterface == IntPtr.Zero)
558                                         return null;
559 #if !RECURSIVE_WRAPPING
560                                 else if ((managedInterface = ManagedToNativeWrapper.GetUnderlyingInterface(comInterface, outParam)) == null)
561 #endif
562                                         managedInterface = (IStream)new NativeToManagedWrapper(comInterface, outParam);
563
564                                 return managedInterface;
565                         }
566
567                         internal static void ReleaseInterface(IStream managedInterface)
568                         {
569                                 if (managedInterface is NativeToManagedWrapper)
570                                         ((NativeToManagedWrapper)managedInterface).Dispose(true);
571                         }
572
573                         // Mono does not implement Marshal.ThrowExceptionForHR
574                         private static void ThrowExceptionForHR(int result)
575                         {
576                                 if (result < 0)
577                                         throw new COMException(null, result);
578                         }
579
580                         public void Read(byte[] pv, int cb, IntPtr pcbRead)
581                         {
582                                 ThrowExceptionForHR(managedVtable.Read(comInterface, pv, cb, pcbRead));
583                         }
584
585                         public void Write(byte[] pv, int cb, IntPtr pcbWritten)
586                         {
587                                 ThrowExceptionForHR(managedVtable.Write(comInterface, pv, cb, pcbWritten));
588                         }
589
590                         public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
591                         {
592                                 ThrowExceptionForHR(managedVtable.Seek(comInterface, dlibMove, dwOrigin, plibNewPosition));
593                         }
594
595                         public void SetSize(long libNewSize)
596                         {
597                                 ThrowExceptionForHR(managedVtable.SetSize(comInterface, libNewSize));
598                         }
599
600                         public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
601                         {
602                                 ThrowExceptionForHR(managedVtable.CopyTo(comInterface, pstm, cb, pcbRead, pcbWritten));
603                         }
604
605                         public void Commit(int grfCommitFlags)
606                         {
607                                 ThrowExceptionForHR(managedVtable.Commit(comInterface, grfCommitFlags));
608                         }
609
610                         public void Revert()
611                         {
612                                 ThrowExceptionForHR(managedVtable.Revert(comInterface));
613                         }
614
615                         public void LockRegion(long libOffset, long cb, int dwLockType)
616                         {
617                                 ThrowExceptionForHR(managedVtable.LockRegion(comInterface, libOffset, cb, dwLockType));
618                         }
619
620                         public void UnlockRegion(long libOffset, long cb, int dwLockType)
621                         {
622                                 ThrowExceptionForHR(managedVtable.UnlockRegion(comInterface, libOffset, cb, dwLockType));
623                         }
624
625                         public void Stat(out STATSTG pstatstg, int grfStatFlag)
626                         {
627                                 ThrowExceptionForHR(managedVtable.Stat(comInterface, out pstatstg, grfStatFlag));
628                         }
629
630                         public void Clone(out IStream ppstm)
631                         {
632                                 IntPtr newInterface;
633
634                                 ThrowExceptionForHR(managedVtable.Clone(comInterface, out newInterface));
635                                 ppstm = NativeToManagedWrapper.GetInterface(newInterface, true);
636                         }
637                 }
638
639                 private static readonly ComIStreamMarshaler defaultInstance = new ComIStreamMarshaler();
640
641                 private ComIStreamMarshaler()
642                 {
643                 }
644
645                 private static ICustomMarshaler GetInstance(string cookie)
646                 {
647                         return defaultInstance;
648                 }
649
650                 public IntPtr MarshalManagedToNative(object managedObj)
651                 {
652 #if RECURSIVE_WRAPPING
653                         managedObj = NativeToManagedWrapper.GetInterface(ManagedToNativeWrapper.GetInterface((IStream)managedObj), true);
654 #endif
655                         return ManagedToNativeWrapper.GetInterface((IStream)managedObj);
656                 }
657
658                 public void CleanUpNativeData(IntPtr pNativeData)
659                 {
660                         ManagedToNativeWrapper.ReleaseInterface(pNativeData);
661                 }
662
663                 public object MarshalNativeToManaged(IntPtr pNativeData)
664                 {
665 #if RECURSIVE_WRAPPING
666                         pNativeData = ManagedToNativeWrapper.GetInterface(NativeToManagedWrapper.GetInterface(pNativeData, true));
667 #endif
668                         return NativeToManagedWrapper.GetInterface(pNativeData, false);
669                 }
670
671                 public void CleanUpManagedData(object managedObj)
672                 {
673                         NativeToManagedWrapper.ReleaseInterface((IStream)managedObj);
674                 }
675
676                 public int GetNativeDataSize()
677                 {
678                         return -1;
679                 }
680         }
681 }