This patch contains:
authorMiguel de Icaza <miguel@gnome.org>
Fri, 15 Dec 2006 22:49:32 +0000 (22:49 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Fri, 15 Dec 2006 22:49:32 +0000 (22:49 -0000)
        SafeWaitHandle support for WaitHandles (2.0)

        A few APIs implemented from Marshal.

2006-12-11  Miguel de Icaza  <miguel@novell.com>

        * WaitHandle.cs: In 2.0 use SafeWaitHandles and the SafeWaitHandle
        patterns instead of using directly the IntPtr Handle.

        Refactor the code to reuse as much as possible, and follow the new
        conventions where appropriate.

2006-12-15  Miguel de Icaza  <miguel@novell.com>

        * Marshal.cs (SecureStringToCoTaskMemAnsi, SecureStringToBSTR,
        SecureStringToCoTaskMemUnicode, ZeroFreeCoTaskMemAnsi,
        ZeroFreeCoTaskMemUnicode, ZeroFreeGlobalAllocAnsi,
        ZeroFreeGlobalAllocUnicode): Implement.

        (StringToCoTaskAuto): return the same as Ansi.

        The ANSI code is out of sync with Mono, which treats ANSI as
        UTF-8.

        Code formatting changes

svn path=/trunk/mcs/; revision=69552

mcs/class/corlib/System.Runtime.InteropServices/ChangeLog
mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs
mcs/class/corlib/System.Threading/ChangeLog
mcs/class/corlib/System.Threading/WaitHandle.cs

index 347ca3cf86940389f594a10a7bc016312f43c530..8ec4421313db36eba0d4156d857bc49fa577958e 100644 (file)
@@ -5,7 +5,12 @@
 
 2006-12-15  Miguel de Icaza  <miguel@novell.com>
 
-       * Marshal.cs (StringToCoTaskAuto): return the same as Ansi.  
+       * Marshal.cs (SecureStringToCoTaskMemAnsi, SecureStringToBSTR,
+       SecureStringToCoTaskMemUnicode, ZeroFreeCoTaskMemAnsi,
+       ZeroFreeCoTaskMemUnicode, ZeroFreeGlobalAllocAnsi,
+       ZeroFreeGlobalAllocUnicode): Implement.
+
+       (StringToCoTaskAuto): return the same as Ansi.  
 
        The ANSI code is out of sync with Mono, which treats ANSI as
        UTF-8. 
index 6b392613fd21e3f22ee32c2a4a148212814d37a1..e213d53c22d7cd846050edb446f87b5122384103 100644 (file)
@@ -209,34 +209,55 @@ namespace System.Runtime.InteropServices
                public extern static void FreeHGlobal (IntPtr hglobal);
 
 #if NET_2_0
-               [MonoTODO]
+
+               static void ClearBSTR (IntPtr ptr)
+               {
+                       int len = ReadInt32 (ptr, -4);
+
+                       for (int i = 0; i < len; i++)
+                               WriteByte (ptr, i, 0);
+               }
+               
                public static void ZeroFreeBSTR (IntPtr ptr)
                {
-                       throw new NotImplementedException ();
+                       ClearBSTR (ptr);
+                       FreeBSTR (ptr);
                }
 
-               [MonoTODO]
+               static void ClearAnsi (IntPtr ptr)
+               {
+                       for (int i = 0; ReadByte (ptr, i) != 0; i++)
+                               WriteByte (ptr, i, 0);
+               }
+
+               static void ClearUnicode (IntPtr ptr)
+               {
+                       for (int i = 0; ReadInt16 (ptr, i) != 0; i += 2)
+                               WriteInt16 (ptr, i, 0);
+               }
+               
                public static void ZeroFreeCoTaskMemAnsi (IntPtr ptr)
                {
-                       throw new NotImplementedException ();
+                       ClearAnsi (ptr);
+                       FreeCoTaskMem (ptr);
                }
 
-               [MonoTODO]
                public static void ZeroFreeCoTaskMemUnicode (IntPtr ptr)
                {
-                       throw new NotImplementedException ();
+                       ClearUnicode (ptr);
+                       FreeCoTaskMem (ptr);
                }
 
-               [MonoTODO]
                public static void ZeroFreeGlobalAllocAnsi (IntPtr hglobal)
                {
-                       throw new NotImplementedException ();
+                       ClearAnsi (hglobal);
+                       FreeHGlobal (hglobal);
                }
 
-               [MonoTODO]
                public static void ZeroFreeGlobalAllocUnicode (IntPtr hglobal)
                {
-                       throw new NotImplementedException ();
+                       ClearUnicode (hglobal);
+                       FreeHGlobal (hglobal);
                }
 #endif
 
@@ -814,44 +835,92 @@ namespace System.Runtime.InteropServices
                public extern static IntPtr StringToHGlobalUni (string s);
 
 #if NET_2_0
-               [MonoTODO]
                public static IntPtr SecureStringToBSTR (SecureString s)
                {
                        if (s == null)
                                throw new ArgumentNullException ("s");
-                       throw new NotSupportedException ();
+                       int len = s.Length;
+                       IntPtr ctm = AllocCoTaskMem ((len+1) * 2 + 4);
+                       byte [] buffer = null;
+                       WriteInt32 (ctm, 0, len);
+                       try {
+                               buffer = s.GetBuffer ();
+
+                               for (int i = 0; i < len; i++)
+                                       WriteInt16 (ctm, 4 + (i * 2), (short) ((buffer [(i*2)] << 8) | (buffer [i*2+1])));
+                               WriteInt16 (ctm, 4 + buffer.Length, 0);
+                       } finally {
+                               if (buffer != null)
+                                       for (int i = buffer.Length; i > 0; ){
+                                               i--;
+                                               buffer [i] = 0;
+                                       }
+                       }
+                       return (IntPtr) ((long)ctm + 4);
                }
 
-               [MonoTODO]
                public static IntPtr SecureStringToCoTaskMemAnsi (SecureString s)
                {
                        if (s == null)
                                throw new ArgumentNullException ("s");
-                       throw new NotSupportedException ();
+                       int len = s.Length;
+                       IntPtr ctm = AllocCoTaskMem (len + 1);
+                       byte [] copy = new byte [len+1];
+
+                       try {
+                               byte [] buffer = s.GetBuffer ();
+                               int i = 0, j = 0;
+                               for (; i < len; i++, j += 2){
+                                       copy [i] = buffer [j+1];
+                                       buffer [j] = 0;
+                                       buffer [j+1] = 0;
+                               }
+                               copy [i] = 0;
+                               copy_to_unmanaged (copy, 0, ctm, len+1);
+                       } finally {
+                               // Ensure that we clear the buffer.
+                               for (int i = len; i > 0; ){
+                                       i--;
+                                       copy [i] = 0;
+                               }
+                       }
+                       return ctm;
                }
 
-               [MonoTODO]
                public static IntPtr SecureStringToCoTaskMemUnicode (SecureString s)
                {
                        if (s == null)
                                throw new ArgumentNullException ("s");
-                       throw new NotSupportedException ();
+                       int len = s.Length;
+                       IntPtr ctm = AllocCoTaskMem (len * 2 + 2);
+                       byte [] buffer = null;
+                       try {
+                               buffer = s.GetBuffer ();
+                               for (int i = 0; i < len; i++)
+                                       WriteInt16 (ctm, i * 2, (short) ((buffer [(i*2)] << 8) | (buffer [i*2+1])));
+                               WriteInt16 (ctm, buffer.Length, 0);
+                       } finally {
+                               if (buffer != null)
+                                       for (int i = buffer.Length; i > 0; ){
+                                               i--;
+                                               buffer [i] = 0;
+                                       }
+                       }
+                       return ctm;
                }
 
-               [MonoTODO]
                public static IntPtr SecureStringToGlobalAllocAnsi (SecureString s)
                {
                        if (s == null)
                                throw new ArgumentNullException ("s");
-                       throw new NotSupportedException ();
+                       return SecureStringToCoTaskMemAnsi (s);
                }
 
-               [MonoTODO]
                public static IntPtr SecureStringToGlobalAllocUnicode (SecureString s)
                {
                        if (s == null)
                                throw new ArgumentNullException ("s");
-                       throw new NotSupportedException ();
+                       return SecureStringToCoTaskMemUnicode (s);
                }
 #endif
 
index e116de00c53167186a2db0afad4e37f3569fe170..205eb01ce431ef8b9e94a0d43e196711359817e6 100644 (file)
@@ -1,7 +1,15 @@
+2006-12-11  Miguel de Icaza  <miguel@novell.com>
+
+       * WaitHandle.cs: In 2.0 use SafeWaitHandles and the SafeWaitHandle
+       patterns instead of using directly the IntPtr Handle.
+
+       Refactor the code to reuse as much as possible, and follow the new
+       conventions where appropriate. 
+
 2006-11-07  Robert Jordan  <robertj@gmx.net>
 
-       * WaitHandle.cs: Don't assume Assembly.GetEntryAssembly () != null.
-       Fixes bug #79859.
+       * WaitHandle.cs: Don't assume Assembly.GetEntryAssembly () !=
+       null.  Fixes bug #79859.
 
 2006-11-02  Dick Porter  <dick@ximian.com>
 
index 9081ece31d9c559e21cc1c3fc0461bb3e15a566a..47f535490a9ac9099c6ee0d8497413e7eb6e6c03 100644 (file)
@@ -34,6 +34,11 @@ using System.Runtime.CompilerServices;
 using System.Runtime.Remoting.Contexts;
 using System.Security.Permissions;
 
+#if NET_2_0
+using System.Runtime.InteropServices;
+using Microsoft.Win32.SafeHandles;
+#endif
+
 namespace System.Threading
 {
        public abstract class WaitHandle : MarshalByRefObject, IDisposable
@@ -57,8 +62,13 @@ namespace System.Threading
                                if (w == null)
                                        throw new ArgumentNullException ("waitHandles", "null handle");
 
+#if NET_2_0
+                               if (w.safe_wait_handle == null)
+                                       throw new ArgumentException ("null element found", "waitHandle");
+#else
                                if (w.os_handle == InvalidHandle)
                                        throw new ArgumentException ("null element found", "waitHandle");
+#endif
                        }
                }
 
@@ -163,8 +173,130 @@ namespace System.Threading
                        // FIXME
                }
 
+               public virtual void Close() {
+                       Dispose(true);
+                       GC.SuppressFinalize (this);
+               }
+
                public const int WaitTimeout = 258;
 
+#if NET_2_0
+               //
+               // In 2.0 we use SafeWaitHandles instead of IntPtrs
+               //
+               SafeWaitHandle safe_wait_handle;
+
+               [Obsolete ("In the profiles > 2.x, use SafeHandle instead of Handle")]
+               public virtual IntPtr Handle {
+                       get {
+                               return safe_wait_handle.DangerousGetHandle ();
+                       }
+
+                       [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode = true)]
+                       [SecurityPermission (SecurityAction.InheritanceDemand, UnmanagedCode = true)]
+                       set {
+                               //
+                               // Notice, from the 2.x documentation:
+                               //    Assigning a new value to the Handle property, will not release
+                               //    the previous handle, this could lead to a leak
+                               //
+                               safe_wait_handle = new SafeWaitHandle (value, false);
+                       }
+               }
+               
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext);
+
+               protected virtual void Dispose (bool explicitDisposing)
+               {
+                       if (!disposed){
+                               disposed = true;
+
+                               //
+                               // This is only the case if the handle was never properly initialized
+                               // most likely a but in the derived class
+                               //
+                               if (safe_wait_handle == null)
+                                       return;
+
+                               lock (this){
+                                       if (safe_wait_handle != null)
+                                               safe_wait_handle.Dispose ();
+                               }
+                       }
+               }
+
+               public SafeWaitHandle SafeWaitHandle {
+                       get {
+                               return safe_wait_handle;
+                       }
+
+                       set {
+                               if (safe_wait_handle != null)
+                                       safe_wait_handle.Close ();
+                               
+                               safe_wait_handle = value;
+                       }
+               }
+
+               public virtual bool WaitOne()
+               {
+                       CheckDisposed ();
+                       bool release = false;
+                       try {
+                               safe_wait_handle.DangerousAddRef (ref release);
+                               return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), Timeout.Infinite, false));
+                       } finally {
+                               if (release)
+                                       safe_wait_handle.DangerousRelease ();
+                       }
+               }
+
+               public virtual bool WaitOne(int millisecondsTimeout, bool exitContext)
+               {
+                       CheckDisposed ();
+                       bool release = false;
+                       try {
+                               if (exitContext)
+                                       SynchronizationAttribute.ExitContext ();
+                               safe_wait_handle.DangerousAddRef (ref release);
+                               return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), millisecondsTimeout, exitContext));
+                       } finally {
+                               if (exitContext)
+                                       SynchronizationAttribute.EnterContext ();
+                               if (release)
+                                       safe_wait_handle.DangerousRelease ();
+                       }
+               }
+
+               public virtual bool WaitOne(TimeSpan timeout, bool exitContext)
+               {
+                       CheckDisposed ();
+                       long ms = (long) timeout.TotalMilliseconds;
+                       if (ms < -1 || ms > Int32.MaxValue)
+                               throw new ArgumentOutOfRangeException ("timeout");
+
+                       bool release = false;
+                       try {
+                               if (exitContext)
+                                       SynchronizationAttribute.ExitContext ();
+                               safe_wait_handle.DangerousAddRef (ref release);
+                               return (WaitOne_internal(safe_wait_handle.DangerousGetHandle (), (int) ms, exitContext));
+                       }
+                       finally {
+                               if (exitContext)
+                                       SynchronizationAttribute.EnterContext ();
+                               if (release)
+                                       safe_wait_handle.DangerousRelease ();
+                       }
+               }
+
+               internal void CheckDisposed ()
+               {
+                       if (disposed || safe_wait_handle == null)
+                               throw new ObjectDisposedException (GetType ().FullName);
+               }
+#else
                private IntPtr os_handle = InvalidHandle;
                
                public virtual IntPtr Handle {
@@ -179,11 +311,6 @@ namespace System.Threading
                        }
                }
 
-               public virtual void Close() {
-                       Dispose(true);
-                       GC.SuppressFinalize (this);
-               }
-
                internal void CheckDisposed ()
                {
                        if (disposed || os_handle == InvalidHandle)
@@ -193,6 +320,22 @@ namespace System.Threading
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern bool WaitOne_internal(IntPtr handle, int ms, bool exitContext);
 
+               protected virtual void Dispose(bool explicitDisposing) {
+                       // Check to see if Dispose has already been called.
+                       if (!disposed) {
+                               disposed=true;
+                               if (os_handle == InvalidHandle)
+                                       return;
+
+                               lock (this) {
+                                       if (os_handle != InvalidHandle) {
+                                               NativeEventCalls.CloseEvent_internal (os_handle);
+                                               os_handle = InvalidHandle;
+                                       }
+                               }
+                       }
+               }
+               
                public virtual bool WaitOne()
                {
                        CheckDisposed ();
@@ -226,9 +369,9 @@ namespace System.Threading
                                if (exitContext) SynchronizationAttribute.EnterContext ();
                        }
                }
+#endif
 
                protected static readonly IntPtr InvalidHandle = IntPtr.Zero;
-
                bool disposed = false;
 
                void IDisposable.Dispose() {
@@ -237,22 +380,6 @@ namespace System.Threading
                        GC.SuppressFinalize(this);
                }
                
-               protected virtual void Dispose(bool explicitDisposing) {
-                       // Check to see if Dispose has already been called.
-                       if (!disposed) {
-                               disposed=true;
-                               if (os_handle == InvalidHandle)
-                                       return;
-
-                               lock (this) {
-                                       if (os_handle != InvalidHandle) {
-                                               NativeEventCalls.CloseEvent_internal (os_handle);
-                                               os_handle = InvalidHandle;
-                                       }
-                               }
-                       }
-               }
-
                ~WaitHandle() {
                        Dispose(false);
                }