From: Zeng Jiang Date: Fri, 16 Nov 2018 01:49:41 +0000 (+0800) Subject: Add PInvoke/SafeHandles tests (#19330) X-Git-Tag: accepted/tizen/unified/20190422.045933~630 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c1ae5a5600247cbe9790e40cd127363c43a17b35;p=platform%2Fupstream%2Fcoreclr.git Add PInvoke/SafeHandles tests (#19330) * Add PInvoke/SafeHandles tests * Fix compile warnings - include header file with relative path * Run SafeHandle tests only on Windows. The tests are very Windows-centric, so we'd have to do quite a bit of a re-write to get them working xplat. * Fix CMake project references. * Fix interface CMakeLists project reference. * Add casts for string literals. * Use LPOLESTR and the W macro instead of OLECHAR* cast and L prefix. --- diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index 27d3049..1ecb281 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -59,6 +59,9 @@ add_subdirectory(ExecInDefAppDom) if(WIN32) add_subdirectory(PInvoke/Variant) add_subdirectory(PInvoke/Varargs) + add_subdirectory(PInvoke/SafeHandles) + add_subdirectory(PInvoke/SafeHandles/ReleaseHandle) + add_subdirectory(PInvoke/SafeHandles/Interface) add_subdirectory(PInvoke/NativeCallManagedComVisible) # This test doesn't necessarily need to be Windows-only, but the implementation is very tied to Windows APIs add_subdirectory(PInvoke/DateTime) diff --git a/tests/src/Interop/PInvoke/SafeHandles/AbstractDerived/AbstractDerivedTest.cs b/tests/src/Interop/PInvoke/SafeHandles/AbstractDerived/AbstractDerivedTest.cs new file mode 100644 index 0000000..fdbb931 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/AbstractDerived/AbstractDerivedTest.cs @@ -0,0 +1,85 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Runtime.InteropServices; +using SafeHandlesTests; +using TestLibrary; + +public abstract class AllMySafeHandles : SafeHandle +{ + private static readonly IntPtr _invalidHandleValue = new IntPtr(-1); + + //0 or -1 considered invalid + public override bool IsInvalid + { + get { return handle == IntPtr.Zero || handle == _invalidHandleValue; } + } + + protected AllMySafeHandles(bool ownsHandle) : base(IntPtr.Zero, ownsHandle) { } +} + +public sealed class MySafeEventHandle : AllMySafeHandles +{ + private MySafeEventHandle() : base(true) { } + + [DllImport("api-ms-win-core-synch-l1-2-0", SetLastError = true, EntryPoint = "CreateEventW")] + internal static extern MySafeEventHandle CreateEvent(IntPtr mustBeZero, bool isManualReset, bool initialState, String name); + + [DllImport("api-ms-win-core-synch-l1-2-0", SetLastError = true)] + internal static extern bool SetEvent(MySafeEventHandle handle); + + [DllImport("api-ms-win-core-handle-l1-1-0")] + private static extern bool CloseHandle(IntPtr handle); + + override protected bool ReleaseHandle() + { + return CloseHandle(handle); + } +} + +public class AbstractDerivedSHTester +{ + private static void ClassHierarchyTest() + { + Console.WriteLine("Class hierarchy test..."); + + //create an event + Console.WriteLine("\tCreate new event"); + MySafeEventHandle sh = MySafeEventHandle.CreateEvent(IntPtr.Zero, true, false, null); + Assert.IsFalse(sh.IsInvalid, "CreateEvent returned an invalid SafeHandle!"); + Assert.IsTrue(MySafeEventHandle.SetEvent(sh), "SetEvent failed on a SafeHandle!"); + + Console.WriteLine("\tFirst test: Call dispose on sh"); + sh.Dispose(); + Console.WriteLine("\tCall succeeded.\n"); + + // Now create another event and force the critical finalizer to run. + Console.WriteLine("\tCreate new event"); + sh = MySafeEventHandle.CreateEvent(IntPtr.Zero, false, true, null); + Assert.IsFalse(sh.IsInvalid, "CreateEvent returned an invalid SafeHandle!"); + + Console.WriteLine("\tSecond test: Force critical finalizer to run"); + sh = null; + GC.Collect(); + GC.WaitForPendingFinalizers(); + Console.WriteLine("\tSucceeded.\n"); + } + + private static int Main() + { + try + { + ClassHierarchyTest(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } +} \ No newline at end of file diff --git a/tests/src/Interop/PInvoke/SafeHandles/AbstractDerived/AbstractDerivedTest.csproj b/tests/src/Interop/PInvoke/SafeHandles/AbstractDerived/AbstractDerivedTest.csproj new file mode 100644 index 0000000..f3080e2 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/AbstractDerived/AbstractDerivedTest.csproj @@ -0,0 +1,38 @@ + + + + + Debug + AnyCPU + AbstractDerivedTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + true + true + + + + + + + False + + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/SafeHandles/CMakeLists.txt b/tests/src/Interop/PInvoke/SafeHandles/CMakeLists.txt new file mode 100644 index 0000000..6c1321e --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/CMakeLists.txt @@ -0,0 +1,15 @@ +#VCXPROJ +cmake_minimum_required (VERSION 2.6) +project (PInvoke_SafeHandle) +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES + SafeHandleNative.cpp +) +# Additional files to reference: +# StructDefs.h +# SafeHandleNative.def +# add the executable +add_library (PInvoke_SafeHandle SHARED ${SOURCES}) +# add the install targets +install (TARGETS PInvoke_SafeHandle DESTINATION bin) diff --git a/tests/src/Interop/PInvoke/SafeHandles/CleanUpCheck/CleanUpCheckTest.cs b/tests/src/Interop/PInvoke/SafeHandles/CleanUpCheck/CleanUpCheckTest.cs new file mode 100644 index 0000000..d7f61eb --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/CleanUpCheck/CleanUpCheckTest.cs @@ -0,0 +1,161 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using SafeHandlesTests; +using TestLibrary; + +public class SHTester +{ + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_In([In]SafeFileHandle sh1, Int32 sh1Value); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Out(out SFH_NoCloseHandle sh1); + + [DllImport("PInvoke_SafeHandle", PreserveSig = false, SetLastError = true)] + public static extern SFH_NoCloseHandle SHParam_OutRetVal(); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Ref(ref SFH_NoCloseHandle sh1, Int32 sh1Value); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Multiple([In]SafeFileHandle sh1, out SFH_NoCloseHandle sh2, ref SFH_NoCloseHandle sh3, Int32 sh1Value, Int32 sh3Value); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_In([In]StructWithSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Out(out StructWithSHFld s); + + [DllImport("PInvoke_SafeHandle", PreserveSig = false, SetLastError = true)] + public static extern StructWithSHFld SHStructParam_OutRetVal(); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Ref1(ref StructWithSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Ref2(ref StructWithSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple1([In]StructWithSHFld sh1, out StructWithSHFld sh2, ref StructWithSHFld sh3, Int32 sh1fldValue, Int32 sh2fldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple2([In]StructWithSHFld sh1, ref StructWithSHFld sh2, Int32 sh1fldValue, Int32 sh2fldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple3([In]StructWithSHFld sh1, ref StructWithSHFld sh2, Int32 sh1fldValue, Int32 sh2fldValue); + + public static int Main() + { + try + { + RunSHParamTests(); + RunSHStructParamTests(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } + + /// + ///passing SH subclass parameters to unmanaged code in various combinations and forms; + ///it uses the PInvoke signatures defined above it + ///1- passing SH subclass parameters individually in separate methods (In, out, ref) + ///2- passing SH subclass parameters in combination in the same method + /// + public static void RunSHParamTests() + { + Console.WriteLine("\nRunSHParamTests():"); + ///1- passing SH subclass parameters individually in separate methods (In, out, ref) + //get a new SH + SafeFileHandle hnd = Helper.NewSFH(); + Int32 hndInt32 = Helper.SHInt32(hnd); //get the 32-bit value associated with hnd + + Console.WriteLine("Testing SHParam_In..."); + SHParam_In(hnd, hndInt32); + CheckCleanUp(hnd); + + SFH_NoCloseHandle hndout = Helper.NewSFH_NoCloseHandle(); //get a new value + SafeHandle hnd_ref_backup = hndout; + hndInt32 = Helper.SHInt32(hndout); + Console.WriteLine("Testing SHParam_Ref..."); + SHParam_Ref(ref hndout, hndInt32); + CheckCleanUp(hnd_ref_backup); + + ///2- passing SH subclass parameters in combination in the same method + //initialize parameters + SafeFileHandle hnd1 = Helper.NewSFH(); + Int32 hnd1Int32 = Helper.SHInt32(hnd1); //get the 32-bit value associated with hnd1 + + SFH_NoCloseHandle hnd2 = null; //out parameter + + SFH_NoCloseHandle hnd3 = Helper.NewSFH_NoCloseHandle(); + SafeHandle hnd3_ref_backup = hnd3; + Int32 hnd3Int32 = Helper.SHInt32(hnd3); //get the 32-bit value associated with hnd3 + + Console.WriteLine("Testing SHParam_Multiple..."); + SHParam_Multiple(hnd1, out hnd2, ref hnd3, hnd1Int32, hnd3Int32); + CheckCleanUp(hnd1); + CheckCleanUp(hnd2); + CheckCleanUp(hnd3_ref_backup); + } + + /// + ///passing structures (with SH subclass fields) as parameters in various combinations and forms; + ///it uses the PInvoke signatures defined above it + ///1- passing structures (In, out, ref) (with SH subclass fields) individually in separate methods + ///2- passing structures (In, out, ref) (with SH subclass fields) in combination in the same method + /// + public static void RunSHStructParamTests() + { + Console.WriteLine("\nRunSHStructParamTests():"); + ///1- passing structures (In, out, ref) (with SH subclass fields) individually in separate methods + /// + /// + + //initialize a new StructWithSHFld + StructWithSHFld s = new StructWithSHFld(); + s.hnd = Helper.NewSFH(); //get a new SH + Int32 hndInt32 = Helper.SHInt32(s.hnd); //get the 32-bit value associated with s.hnd + + Console.WriteLine("Testing SHStructParam_In..."); + SHStructParam_In(s, hndInt32); + CheckCleanUp(s.hnd); + + s.hnd = Helper.NewSFH(); //get a new SH + SafeHandle hnd_ref_backup = s.hnd; + hndInt32 = Helper.SHInt32(s.hnd); //get the 32-bit value associated with s.hnd + Console.WriteLine("Testing SHStructParam_Ref1 (does not change value of handle field)..."); + SHStructParam_Ref1(ref s, hndInt32); + CheckCleanUp(hnd_ref_backup); + + ///2- passing structures (In, out, ref) (with SH subclass fields) in combination in the same method + /// + /// + //initialize parameters + StructWithSHFld s1 = new StructWithSHFld(); + s1.hnd = Helper.NewSFH(); + Int32 hnd1Int32 = Helper.SHInt32(s1.hnd); //get the 32-bit value associated with s1.hnd + + StructWithSHFld s3 = new StructWithSHFld(); + s3.hnd = Helper.NewSFH(); + Int32 hnd3Int32 = Helper.SHInt32(s3.hnd); //get the 32-bit value associated with s3.hnd + SafeHandle hnd3_ref_backup = s3.hnd; + Console.WriteLine("Testing SHStructParam_Multiple2 (takes a ref struct as one of the params)..."); + SHStructParam_Multiple2(s1, ref s3, hnd1Int32, hnd3Int32); + CheckCleanUp(s1.hnd); + CheckCleanUp(hnd3_ref_backup); + } + + static void CheckCleanUp(SafeHandle hnd) + { + Assert.IsFalse(hnd.IsClosed, "Failed: SafeFileHandle Closed before calling close"); + } +} \ No newline at end of file diff --git a/tests/src/Interop/PInvoke/SafeHandles/CleanUpCheck/CleanUpCheckTest.csproj b/tests/src/Interop/PInvoke/SafeHandles/CleanUpCheck/CleanUpCheckTest.csproj new file mode 100644 index 0000000..ae60938 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/CleanUpCheck/CleanUpCheckTest.csproj @@ -0,0 +1,38 @@ + + + + + Debug + AnyCPU + CleanUpCheckTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + true + true + + + + + + + False + + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/SafeHandles/Default/DefaultTest.cs b/tests/src/Interop/PInvoke/SafeHandles/Default/DefaultTest.cs new file mode 100644 index 0000000..9e864fd --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/Default/DefaultTest.cs @@ -0,0 +1,171 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using SafeHandlesTests; +using TestLibrary; + +public class SHTester +{ + public static int Main() + { + try + { + RunSHParamTests(); + RunSHStructParamTests(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_In([In]SafeFileHandle sh1, Int32 sh1Value); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Out(out SFH_NoCloseHandle sh1); + + [DllImport("PInvoke_SafeHandle", PreserveSig = false, SetLastError = true)] + public static extern SFH_NoCloseHandle SHParam_OutRetVal(); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Ref(ref SFH_NoCloseHandle sh1, Int32 sh1Value); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Multiple([In]SafeFileHandle sh1, out SFH_NoCloseHandle sh2, ref SFH_NoCloseHandle sh3, Int32 sh1Value, Int32 sh3Value); + + /// + ///passing SH subclass parameters to unmanaged code in various combinations and forms; + ///it uses the PInvoke signatures defined above it + ///1- passing SH subclass parameters individually in separate methods (In, out, ref) + ///2- passing SH subclass parameters in combination in the same method + /// + public static void RunSHParamTests() + { + Console.WriteLine("SHParam_In"); + SafeFileHandle hnd = Helper.NewSFH(); //get a new SH + Int32 hndInt32 = Helper.SHInt32(hnd); //get the 32-bit value associated with hnd + Assert.IsTrue(SHParam_In(hnd, hndInt32), "SHParam_In did not receive hnd as expected"); + Assert.IsTrue(!Helper.IsChanged(hnd), "SHParam_In did not return hnd as expected."); + + Console.WriteLine("SHParam_Out"); + SFH_NoCloseHandle hndout; + SHParam_Out(out hndout); + Assert.IsTrue(Helper.IsChanged(hndout), "SHParam_Out did not return hndout as expected. hndout = " + Helper.SHInt32(hndout)); + + Console.WriteLine("SHParam_OutRetVal"); + hndout = null; + hndout = SHParam_OutRetVal(); + Assert.IsTrue(Helper.IsChanged(hndout), "SHParam_OutRetVal did not return hndout as expected."); + + Console.WriteLine("SHParam_Ref"); + hndout = Helper.NewSFH_NoCloseHandle(); //get a new value + hndInt32 = Helper.SHInt32(hndout); + Assert.IsTrue(SHParam_Ref(ref hndout, hndInt32), "SHParam_Ref did not receive hndout as expected"); + Assert.IsTrue(Helper.IsChanged(hndout), "SHParam_Ref did not return hndout as expected."); + + Console.WriteLine("SHParam_Multiple"); + SafeFileHandle hnd1 = Helper.NewSFH(); + Int32 hnd1Int32 = Helper.SHInt32(hnd1); //get the 32-bit value associated with hnd1 + SFH_NoCloseHandle hnd2 = null; //out parameter + SFH_NoCloseHandle hnd3 = Helper.NewSFH_NoCloseHandle(); + Int32 hnd3Int32 = Helper.SHInt32(hnd3); //get the 32-bit value associated with hnd3 + + Assert.IsTrue(SHParam_Multiple(hnd1, out hnd2, ref hnd3, hnd1Int32, hnd3Int32), "SHParam_Multiple did not receive parameter(s) as expected."); + + Assert.IsTrue(Helper.IsChanged(hnd2), "HParam_Multiple did not return hnd2 as expected."); + Assert.IsTrue(Helper.IsChanged(hnd3), "HParam_Multiple did not return hnd3 as expected."); + } + + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_In([In]StructWithSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Out(out StructWithSHFld s); + + [DllImport("PInvoke_SafeHandle", PreserveSig = false, SetLastError = true)] + public static extern StructWithSHFld SHStructParam_OutRetVal(); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Ref1(ref StructWithSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Ref2(ref StructWithSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple1([In]StructWithSHFld sh1, out StructWithSHFld sh2, ref StructWithSHFld sh3, Int32 sh1fldValue, Int32 sh2fldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple2([In]StructWithSHFld sh1, ref StructWithSHFld sh2, Int32 sh1fldValue, Int32 sh2fldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple3([In]StructWithSHFld sh1, ref StructWithSHFld sh2, Int32 sh1fldValue, Int32 sh2fldValue); + + /// + ///passing structures (with SH subclass fields) as parameters in various combinations and forms; + ///it uses the PInvoke signatures defined above it + ///1- passing structures (In, out, ref) (with SH subclass fields) individually in separate methods + ///2- passing structures (In, out, ref) (with SH subclass fields) in combination in the same method + /// + public static void RunSHStructParamTests() + { + Console.WriteLine("\nRunSHStructParamTests():"); + + Console.WriteLine("SHStructParam_In"); + StructWithSHFld s = new StructWithSHFld();//initialize a new StructWithSHFld + s.hnd = Helper.NewSFH(); //get a new SH + Int32 hndInt32 = Helper.SHInt32(s.hnd); //get the 32-bit value associated with s.hnd + Assert.IsTrue(SHStructParam_In(s, hndInt32), "SHStructParam_In did not receive param as expected."); + Assert.IsTrue(!Helper.IsChanged(s.hnd), "SHStructParam_In did not return param as expected.");//check that the value of the HANDLE field did not change + + Console.WriteLine("SHStructParam_Out"); + Assert.Throws(() => SHStructParam_Out(out s), "SHStructParam_Out"); + + Console.WriteLine("SHStructParam_OutRetVal"); + //mangling the unmanaged signature and returning the structure should cause this exception since PInvoke does not support returning + //non-blittable value classes + Assert.Throws(() => SHStructParam_OutRetVal(), "SHStructParam_OutRetVal"); + + Console.WriteLine("SHStructParam_Ref1"); //Testing SHStructParam_Ref1 (does not change value of handle field) + s.hnd = Helper.NewSFH(); //get a new SH + hndInt32 = Helper.SHInt32(s.hnd); //get the 32-bit value associated with s.hnd + Assert.IsTrue(SHStructParam_Ref1(ref s, hndInt32), "SHStructParam_Ref1 did not receive param as expected."); + Assert.IsTrue(!Helper.IsChanged(s.hnd), "SHStructParam_Ref1 did not return param as expected."); //check that the value of the HANDLE field is not changed + + Console.WriteLine("SHStructParam_Ref2"); + Assert.Throws(() => SHStructParam_Ref2(ref s, hndInt32), "SHStructParam_Ref2"); + /// + ///2- passing structures (In, out, ref) (with SH subclass fields) in combination in the same method + /// + + StructWithSHFld s1 = new StructWithSHFld();//initialize parameters + s1.hnd = Helper.NewSFH(); + Int32 hnd1Int32 = Helper.SHInt32(s1.hnd); //get the 32-bit value associated with s1.hnd + + StructWithSHFld s2; //out parameter + + StructWithSHFld s3 = new StructWithSHFld(); + s3.hnd = Helper.NewSFH(); + Int32 hnd3Int32 = Helper.SHInt32(s3.hnd); //get the 32-bit value associated with s3.hnd + + Console.WriteLine("SHStructParam_Multiple1: takes an out struct as one of the params and so is expected to result in an exception"); + Assert.Throws(() => SHStructParam_Multiple1(s1, out s2, ref s3, hnd1Int32, hnd3Int32), "SHStructParam_Multiple1"); + + Console.WriteLine("SHStructParam_Multiple2:takes a ref struct as one of the params"); + s3.hnd = Helper.NewSFH(); + hnd3Int32 = Helper.SHInt32(s3.hnd); //get the 32-bit value associated with s3.hnd + Assert.IsTrue(SHStructParam_Multiple2(s1, ref s3, hnd1Int32, hnd3Int32), "SHStructParam_Multiple2 did not receive parameter(s) as expected."); + Assert.IsTrue(!Helper.IsChanged(s1.hnd), "SHStructParam_Multiple2 did not return s1.hnd as expected."); + Assert.IsTrue(!Helper.IsChanged(s3.hnd), "SHStructParam_Multiple2 did not return s3.hnd as expected."); + + Console.WriteLine("SHStructParam_Multiple3:takes a ref struct as one of the params aand changes its handle field and so is expected to result in an exception"); + Assert.Throws(() => SHStructParam_Multiple3(s1, ref s3, hnd1Int32, hnd3Int32), "SHStructParam_Multiple3"); + } +} \ No newline at end of file diff --git a/tests/src/Interop/PInvoke/SafeHandles/Default/DefaultTest.csproj b/tests/src/Interop/PInvoke/SafeHandles/Default/DefaultTest.csproj new file mode 100644 index 0000000..067e960 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/Default/DefaultTest.csproj @@ -0,0 +1,38 @@ + + + + + Debug + AnyCPU + DefaultTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + true + true + + + + + + + False + + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/SafeHandles/Helper.cs b/tests/src/Interop/PInvoke/SafeHandles/Helper.cs new file mode 100644 index 0000000..cc22959 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/Helper.cs @@ -0,0 +1,271 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using SafeHandlesTests; + +namespace SafeHandlesTests{ + public class Helper + { + public const int N = 3; + public const int ReturnValue = 123; + + /// + /// Creates and returns a new SFH_NoCloseHandle + /// + /// + public static SFH_NoCloseHandle NewSFH_NoCloseHandle() + { + String lpFileName = "C.txt"; + DesiredAccess dwDesiredAccess = DesiredAccess.GENERIC_WRITE; + ShareMode dwShareMode = ShareMode.FILE_SHARE_WRITE; + IntPtr lpSecurityAttributes = IntPtr.Zero; + CreationDisposition dwCreationDisposition = CreationDisposition.CREATE_ALWAYS; + FlagsAndAttributes dwFlagsAndAttributes = FlagsAndAttributes.None; + IntPtr hTemplateFile = IntPtr.Zero; + + //create the handle + SFH_NoCloseHandle hnd = SFH_NoCloseHandle.CreateFile(lpFileName, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile); + + return hnd; + } + + /// + /// Creates and returns a new ChildSFH_NoCloseHandle + /// + /// + public static ChildSFH_NoCloseHandle NewChildSFH_NoCloseHandle() + { + String lpFileName = "D.txt"; + DesiredAccess dwDesiredAccess = DesiredAccess.GENERIC_WRITE; + ShareMode dwShareMode = ShareMode.FILE_SHARE_WRITE; + IntPtr lpSecurityAttributes = IntPtr.Zero; + CreationDisposition dwCreationDisposition = CreationDisposition.CREATE_ALWAYS; + FlagsAndAttributes dwFlagsAndAttributes = FlagsAndAttributes.None; + IntPtr hTemplateFile = IntPtr.Zero; + + //create the handle + ChildSFH_NoCloseHandle hnd = ChildSFH_NoCloseHandle.CreateChildSafeFileHandle(lpFileName, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile); + + return hnd; + } + + /// + /// Creates and returns a new ChildSafeFileHandle + /// + /// + public static ChildSafeFileHandle NewChildSFH() + { + String lpFileName = "B.txt"; + DesiredAccess dwDesiredAccess = DesiredAccess.GENERIC_WRITE; + ShareMode dwShareMode = ShareMode.FILE_SHARE_WRITE; + IntPtr lpSecurityAttributes = IntPtr.Zero; + CreationDisposition dwCreationDisposition = CreationDisposition.CREATE_ALWAYS; + FlagsAndAttributes dwFlagsAndAttributes = FlagsAndAttributes.None; + IntPtr hTemplateFile = IntPtr.Zero; + + //create the handle + ChildSafeFileHandle hnd = ChildSafeFileHandle.CreateChildSafeFileHandle(lpFileName, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile); + + return hnd; + } + + /// + /// Creates and returns a new SafeFileHandle + /// + /// + public static SafeFileHandle NewSFH() + { + String lpFileName = "A.txt"; + DesiredAccess dwDesiredAccess = DesiredAccess.GENERIC_WRITE; + ShareMode dwShareMode = ShareMode.FILE_SHARE_WRITE; + IntPtr lpSecurityAttributes = IntPtr.Zero; + CreationDisposition dwCreationDisposition = CreationDisposition.CREATE_ALWAYS; + FlagsAndAttributes dwFlagsAndAttributes = FlagsAndAttributes.None; + IntPtr hTemplateFile = IntPtr.Zero; + + //create the handle + SafeFileHandle hnd = SafeFileHandle.CreateFile(lpFileName, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile); + + return hnd; + } + + /// + /// Returns the Int32 value associated with a SFH_NoCloseHandle + /// + /// + public static Int32 SHInt32(SFH_NoCloseHandle hnd) + { + IntPtr hndIntPtr = hnd.DangerousGetHandle(); //get the IntPtr associated with hnd + return hndIntPtr.ToInt32(); //return the 32-bit value associated with hnd + } + + /// + /// Returns the Int32 value associated with a ChildSFH_NoCloseHandle + /// + /// + public static Int32 SHInt32(ChildSFH_NoCloseHandle hnd) + { + IntPtr hndIntPtr = hnd.DangerousGetHandle(); //get the IntPtr associated with hnd + return hndIntPtr.ToInt32(); //return the 32-bit value associated with hnd + } + + /// + /// Returns the Int32 value associated with a ChildSafeFileHandle + /// + /// + public static Int32 SHInt32(ChildSafeFileHandle hnd) + { + IntPtr hndIntPtr = hnd.DangerousGetHandle(); //get the IntPtr associated with hnd + return hndIntPtr.ToInt32(); //return the 32-bit value associated with hnd + } + + /// + /// Returns the Int32 value associated with a SafeFileHandle + /// + /// + public static Int32 SHInt32(SafeFileHandle hnd) + { + IntPtr hndIntPtr = hnd.DangerousGetHandle(); //get the IntPtr associated with hnd + return hndIntPtr.ToInt32(); //return the 32-bit value associated with hnd + } + + /// + /// Returns the Int32 value associated with a SafeHandle + /// + /// + public static Int32 SHInt32(SafeHandle hnd) + { + IntPtr hndIntPtr = hnd.DangerousGetHandle(); //get the IntPtr associated with hnd + return hndIntPtr.ToInt32(); //return the 32-bit value associated with hnd + } + + /// + /// Returns true if SH subclass (SFH_NoCloseHandle) value has changed else returns false + /// + /// + public static bool IsChanged(SFH_NoCloseHandle hnd) + { + Int32 hndInt32 = SHInt32(hnd); //get the 32-bit value associated with hnd + if (hndInt32 == ReturnValue) + return true; + return false; + } + + /// + /// Returns true if ChildSFH_NoCloseHandle value has changed else returns false + /// + /// + public static bool IsChanged(ChildSFH_NoCloseHandle hnd) + { + Int32 hndInt32 = SHInt32(hnd); //get the 32-bit value associated with hnd + if (hndInt32 == ReturnValue) + return true; + return false; + } + + /// + /// Returns true if SafeFileHandle subclass value has changed else returns false + /// + /// + public static bool IsChanged(ChildSafeFileHandle hnd) + { + Int32 hndInt32 = SHInt32(hnd); //get the 32-bit value associated with hnd + if (hndInt32 == ReturnValue) + return true; + return false; + } + + /// + /// Returns true if SH subclass value has changed else returns false + /// + /// + public static bool IsChanged(SafeFileHandle hnd) + { + Int32 hndInt32 = SHInt32(hnd); //get the 32-bit value associated with hnd + if (hndInt32 == ReturnValue) + return true; + return false; + } + + /// + /// Returns true if SH value has changed else returns false + /// + /// + public static bool IsChanged(SafeHandle hnd) + { + Int32 hndInt32 = SHInt32(hnd); //get the 32-bit value associated with hnd + if (hndInt32 == ReturnValue) + return true; + return false; + } + + /// + /// Creates a new StructWithManySHFlds; Fills in arrInt32s with the 32-bit values + /// of the handle flds of the struct + /// + /// StructWithManySHFlds + public static StructWithManySHFlds NewStructWithManySHFlds(ref Int32[] arrInt32s) + { + arrInt32s = new Int32[15]; //size corresponds to the number of flds + StructWithManySHFlds s = new StructWithManySHFlds(); + s.hnd1 = NewSFH(); //get a new SH + arrInt32s[0] = SHInt32(s.hnd1); + s.hnd2 = NewSFH(); //get a new SH + arrInt32s[1] = SHInt32(s.hnd2); + s.hnd3 = NewChildSFH(); //get a new SH + arrInt32s[2] = SHInt32(s.hnd3); + s.hnd4 = NewSFH(); //get a new SH + arrInt32s[3] = SHInt32(s.hnd4); + s.hnd5 = NewSFH(); //get a new SH + arrInt32s[4] = SHInt32(s.hnd5); + s.hnd6 = NewChildSFH(); //get a new SH + arrInt32s[5] = SHInt32(s.hnd6); + s.hnd7 = NewSFH(); //get a new SH + arrInt32s[6] = SHInt32(s.hnd7); + s.hnd8 = NewSFH(); //get a new SH + arrInt32s[7] = SHInt32(s.hnd8); + s.hnd9 = NewChildSFH(); //get a new SH + arrInt32s[8] = SHInt32(s.hnd9); + s.hnd10 = NewSFH(); //get a new SH + arrInt32s[9] = SHInt32(s.hnd10); + s.hnd11 = NewSFH(); //get a new SH + arrInt32s[10] = SHInt32(s.hnd11); + s.hnd12 = NewChildSFH(); //get a new SH + arrInt32s[11] = SHInt32(s.hnd12); + s.hnd13 = NewSFH(); //get a new SH + arrInt32s[12] = SHInt32(s.hnd13); + s.hnd14 = NewSFH(); //get a new SH + arrInt32s[13] = SHInt32(s.hnd14); + s.hnd15 = NewChildSFH(); //get a new SH + arrInt32s[14] = SHInt32(s.hnd15); + + return s; + } + + /// + /// Returns true if any of the handle flds has changed else returns false + /// + public static bool IsChangedStructWithManySHFlds(StructWithManySHFlds s, Int32[] arrInt32s) + { + if (SHInt32(s.hnd1) != arrInt32s[0] || SHInt32(s.hnd2) != arrInt32s[1] || SHInt32(s.hnd3) != arrInt32s[2] || + SHInt32(s.hnd4) != arrInt32s[3] || SHInt32(s.hnd5) != arrInt32s[4] || SHInt32(s.hnd6) != arrInt32s[5] || + SHInt32(s.hnd7) != arrInt32s[6] || SHInt32(s.hnd8) != arrInt32s[7] || SHInt32(s.hnd9) != arrInt32s[8] || + SHInt32(s.hnd10) != arrInt32s[9] || SHInt32(s.hnd11) != arrInt32s[10] || SHInt32(s.hnd12) != arrInt32s[11] || + SHInt32(s.hnd13) != arrInt32s[12] || SHInt32(s.hnd14) != arrInt32s[13] || SHInt32(s.hnd15) != arrInt32s[14]) + return true; + return false; + } + + } //end of class Helper +} diff --git a/tests/src/Interop/PInvoke/SafeHandles/Interface/CMakeLists.txt b/tests/src/Interop/PInvoke/SafeHandles/Interface/CMakeLists.txt new file mode 100644 index 0000000..8fd1a0f --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/Interface/CMakeLists.txt @@ -0,0 +1,15 @@ +#VCXPROJ +cmake_minimum_required (VERSION 2.6) +project (PInvoke_SafeHandle_MarshalAs_Interface) +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") +include_directories("..") +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES + InterfaceNative.cpp +) +# Additional files to reference: +# InterfaceNative.def +# add the executable +add_library (PInvoke_SafeHandle_MarshalAs_Interface SHARED ${SOURCES}) +# add the install targets +install (TARGETS PInvoke_SafeHandle_MarshalAs_Interface DESTINATION bin) diff --git a/tests/src/Interop/PInvoke/SafeHandles/Interface/InterfaceNative.cpp b/tests/src/Interop/PInvoke/SafeHandles/Interface/InterfaceNative.cpp new file mode 100644 index 0000000..eaf5c8f --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/Interface/InterfaceNative.cpp @@ -0,0 +1,616 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include +#include +#include +#include +#include "StructDefs.h" + +/////////////////////////////////Internal Helper Methods +///////////////////////////////// +BOOL static CheckGetIDsOfNamesHR(HRESULT hr) +{ + if( FAILED(hr) ) + { + printf("\t\t\tGetIDsOfNames Call FAILED!\n"); + if( hr == E_OUTOFMEMORY ) + printf("\t\t\thr == E_OUTOFMEMORY\n"); + else if( hr == DISP_E_UNKNOWNNAME ) + printf("\t\t\thr == DISP_E_UNKNOWNNAME\n"); + else + printf("\t\t\thr == DISP_E_UNKNOWNLCID\n"); + return FALSE; + } + return TRUE; +} + +BOOL static CheckInvokeHR(HRESULT hr) +{ + if( FAILED(hr) ) + { + printf("\t\t\tInvoke FAILED!\n"); + if( hr == DISP_E_BADPARAMCOUNT ) + printf("\t\t\thr == DISP_E_BADPARAMCOUNT\n"); + else if( hr == DISP_E_EXCEPTION ) + printf("\t\t\thr == DISP_E_EXCEPTION\n"); + else if( hr == DISP_E_MEMBERNOTFOUND ) + printf("\t\t\thr == DISP_E_MEMBERNOTFOUND\n"); + else if( hr == DISP_E_UNKNOWNINTERFACE ) + printf("\t\t\thr == DISP_E_UNKNOWNINTERFACE\n"); + else if( hr == DISP_E_BADVARTYPE ) + printf("\t\t\thr == DISP_E_BADVARTYPE\n"); + else if( hr == DISP_E_NONAMEDARGS ) + printf("\t\t\thr == DISP_E_NONAMEDARGS\n"); + else if( hr == DISP_E_OVERFLOW ) + printf("\t\t\thr == DISP_E_OVERFLOW\n"); + else if( hr == DISP_E_PARAMNOTFOUND ) + printf("\t\t\thr == DISP_E_PARAMNOTFOUND\n"); + else if( hr == DISP_E_TYPEMISMATCH ) + printf("\t\t\thr == DISP_E_TYPEMISMATCH\n"); + else if( hr == DISP_E_UNKNOWNLCID ) + printf("\t\t\thr == DISP_E_UNKNOWNLCID\n"); + else + printf("\t\t\thr == DISP_E_PARAMNOTOPTIONAL\n"); + return FALSE; + } + return TRUE; +} + +BOOL static InvokeAllFldsAndProps(IDispatch* ptoIntf, long shfld1Val, long shfld2Val) +{ + HRESULT hr; + DISPID dispid_DangerousGetHandle, dispid_IsInvalid, dispid_shfld1, dispid_shfld2_prop; + OLECHAR FAR* szMember; + VARIANTARG varargs; + DISPPARAMS DispParams = {&varargs, NULL, 0, 0}; + VARIANT VarResult, VarResultBool, VarResultDangHnd; + + printf("\t\t\tCalling GetIDsOfNames() for shfld1...\n"); + szMember = (LPOLESTR)W("shfld1"); + hr = ptoIntf->GetIDsOfNames(IID_NULL, + &szMember, + 1, + LOCALE_SYSTEM_DEFAULT, + &dispid_shfld1); + if( !CheckGetIDsOfNamesHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + + printf("\t\t\tCalling GetIDsOfNames() for shfld2_prop...\n"); + szMember = (LPOLESTR)W("shfld2_prop"); + hr = ptoIntf->GetIDsOfNames(IID_NULL, + &szMember, + 1, + LOCALE_SYSTEM_DEFAULT, + &dispid_shfld2_prop); + if( !CheckGetIDsOfNamesHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + + printf("\n"); + + ////////////////////////////////////////////////////////////////// + //NOTE: The SH fld is being returned as type VT_DISPATCH + /* printf("\t\t\tInvoking shfld1...\n"); + hr = ptoIntf->Invoke(dispid_shfld1, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_PROPERTYGET, + &DispParams, + &VarResult, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + if( VarResult.vt != VT_INT || VarResult.intVal != shfld1Val ) + { + printf("\t\t\t\tThe return Variant is incorrect!\n"); + return FALSE; + } + */ + + //Get the property + printf("\t\t\tInvoking shfld2_prop (Getting)...\n"); + hr = ptoIntf->Invoke(dispid_shfld2_prop, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_PROPERTYGET, + &DispParams, + &VarResult, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + if( VarResult.vt != VT_DISPATCH ) + { + printf("\t\t\t\tThe return Variant is incorrect!\n"); + return FALSE; + } + else //invoke DangerousGetHandle on this SH property using VarResult.pdispVal + { + printf("\t\t\t\tCalling GetIDsOfNames() for IsInvalid (shfld2_prop)...\n"); + szMember = (LPOLESTR)W("IsInvalid"); + hr = (VarResult.pdispVal)->GetIDsOfNames(IID_NULL, + &szMember, + 1, + LOCALE_SYSTEM_DEFAULT, + &dispid_IsInvalid); + if( !CheckGetIDsOfNamesHR(hr) ) + return FALSE; + else + printf("\t\t\t\tCall completed successfully.\n"); + + printf("\t\t\t\tInvoking IsInValid (shfld2_prop)...\n"); + hr = (VarResult.pdispVal)->Invoke(dispid_IsInvalid, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_PROPERTYGET, + &DispParams, + &VarResultBool, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\t\tCall completed successfully.\n"); + if( VarResultBool.vt != VT_BOOL || VarResultBool.bVal != 0 ) //should be valid + { + printf("\t\t\t\t\tThe return Variant is incorrect!\n"); + return FALSE; + } + + printf("\t\t\t\tCalling GetIDsOfNames() for DangerousGetHandle (shfld2_prop)...\n"); + szMember = (LPOLESTR)W("DangerousGetHandle"); + hr = (VarResult.pdispVal)->GetIDsOfNames(IID_NULL, + &szMember, + 1, + LOCALE_SYSTEM_DEFAULT, + &dispid_DangerousGetHandle); + if( !CheckGetIDsOfNamesHR(hr) ) + return FALSE; + else + printf("\t\t\t\tCall completed successfully.\n"); + + printf("\t\t\t\tInvoking DangerousGetHandle (shfld2_prop)...\n"); + hr = (VarResult.pdispVal)->Invoke(dispid_DangerousGetHandle, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_METHOD, + &DispParams, + &VarResultDangHnd, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\t\tCall completed successfully.\n"); + if( VarResultDangHnd.vt != VT_INT || VarResultDangHnd.intVal != shfld2Val ) + { + printf("\t\t\t\t\tThe return Variant is incorrect!\n"); + return FALSE; + } + + } //end of else + + //Set the property to a SFH interface + DISPPARAMS DispParams_prop = {&varargs,NULL, 1, 0}; + DispParams_prop.rgvarg[0].vt = VT_DISPATCH; + DispParams_prop.rgvarg[0].pdispVal = ptoIntf; //Set the value of the property to its parent pointer + printf("\t\t\tInvoking shfld2_prop (Setting)...\n"); + hr = ptoIntf->Invoke(dispid_shfld2_prop, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_PROPERTYPUT, + &DispParams_prop, + &VarResult, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + + + return TRUE; +} //end of InvokeAllFldsAndProps + +BOOL static InvokeAllInSHIntf(IDispatch* ptoIntf, long shVal, long shfld1Val, long shfld2Val) +{ + HRESULT hr; + DISPID dispid_DangerousGetHandle, dispid_IsClosed, dispid_IsInvalid, dispid_Close, dispid_Dispose, dispid_SetHandleAsInvalid; + OLECHAR FAR* szMember; + VARIANTARG varargs; + DISPPARAMS DispParams = {&varargs, NULL, 0, 0}; + VARIANT VarResult; + + /////////////////////////////////////////////////////////////////// + printf("\t\t\tCalling GetIDsOfNames() for DangerousGetHandle...\n"); + szMember = (LPOLESTR)W("DangerousGetHandle"); + hr = ptoIntf->GetIDsOfNames(IID_NULL, + &szMember, + 1, + LOCALE_SYSTEM_DEFAULT, + &dispid_DangerousGetHandle); + if( !CheckGetIDsOfNamesHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + + printf("\t\t\tCalling GetIDsOfNames() for IsClosed...\n"); + szMember = (LPOLESTR)W("IsClosed"); + hr = ptoIntf->GetIDsOfNames(IID_NULL, + &szMember, + 1, + LOCALE_SYSTEM_DEFAULT, + &dispid_IsClosed); + if( !CheckGetIDsOfNamesHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + + printf("\t\t\tCalling GetIDsOfNames() for IsInvalid...\n"); + szMember = (LPOLESTR)W("IsInvalid"); + hr = ptoIntf->GetIDsOfNames(IID_NULL, + &szMember, + 1, + LOCALE_SYSTEM_DEFAULT, + &dispid_IsInvalid); + if( !CheckGetIDsOfNamesHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + + printf("\t\t\tCalling GetIDsOfNames() for Close...\n"); + szMember = (LPOLESTR)W("Close"); + hr = ptoIntf->GetIDsOfNames(IID_NULL, + &szMember, + 1, + LOCALE_SYSTEM_DEFAULT, + &dispid_Close); + if( !CheckGetIDsOfNamesHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + + printf("\t\t\tCalling GetIDsOfNames() for Dispose...\n"); + szMember = (LPOLESTR)W("Dispose"); + hr = ptoIntf->GetIDsOfNames(IID_NULL, + &szMember, + 1, + LOCALE_SYSTEM_DEFAULT, + &dispid_Dispose); + if( !CheckGetIDsOfNamesHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + + printf("\t\t\tCalling GetIDsOfNames() for SetHandleAsInvalid...\n"); + szMember = (LPOLESTR)W("SetHandleAsInvalid"); + hr = ptoIntf->GetIDsOfNames(IID_NULL, + &szMember, + 1, + LOCALE_SYSTEM_DEFAULT, + &dispid_SetHandleAsInvalid); + if( !CheckGetIDsOfNamesHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + + + printf("\n"); + ////////////////////////////////////////////////////////////////// + printf("\t\t\tInvoking IsInvalid...\n"); + hr = ptoIntf->Invoke(dispid_IsInvalid, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_PROPERTYGET, + &DispParams, + &VarResult, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + if( VarResult.vt != VT_BOOL || VarResult.boolVal != 0 ) + { + printf("\t\t\t\tThe return Variant is incorrect!\n"); + return FALSE; + } + + ////////////////////////////////////////////////////////////////// + printf("\t\t\tInvoking IsClosed...\n"); + hr = ptoIntf->Invoke(dispid_IsClosed, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_PROPERTYGET, + &DispParams, + &VarResult, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + if( VarResult.vt != VT_BOOL || VarResult.boolVal != 0 ) + { + printf("\t\t\t\tThe return Variant is incorrect!\n"); + return FALSE; + } + + ////////////////////////////////////////////////////////////////// + printf("\t\t\tInvoking DangerousGetHandle...\n"); + hr = ptoIntf->Invoke(dispid_DangerousGetHandle, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_METHOD, + &DispParams, + &VarResult, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + if( VarResult.vt != VT_INT || VarResult.intVal != shVal ) + { + printf("\t\t\t\tThe return Variant is incorrect!\n"); + return FALSE; + } + + ///////////////////////////////////////////////////////////////////// + //invoke close repetitively to make sure nothing out of the ordinary happens + for(int i = 0; i < 3; i++) + { + printf("\t\t\tInvoking Close...\n"); + hr = ptoIntf->Invoke(dispid_Close, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_METHOD, + &DispParams, + &VarResult, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + } + + ///////////////////////////////////////////////////////////////////// + printf("\t\t\tInvoking Dispose...\n"); + hr = ptoIntf->Invoke(dispid_Dispose, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_METHOD, + &DispParams, + &VarResult, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + + ///////////////////////////////////////////////////////////////////// + /* NOTE: This method should really be named SetHandleAsClosed since it + only closes the handle and does not set it to its invalid values; this + decision was taken because the runtime would have had to waste storage + on remembering what the invalid values for this handle were */ + printf("\t\t\tInvoking SetHandleAsInvalid...\n"); + hr = ptoIntf->Invoke(dispid_SetHandleAsInvalid, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_METHOD, + &DispParams, + &VarResult, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + + //////////////////////////////////////////////////////////////////// + /* 01/16/04 comment: This check is not needed (see note in previous + call); removing because I am also removing the IsClosed check in the + IsInvalid property of the handle; since we no longer check IsClosed, + calling IsInvalid after SetHandleAsInvalid returns false since + SetHandleAsInvalid only closes the handle + + printf("\t\t\tInvoking IsInvalid...\n"); + hr = ptoIntf->Invoke(dispid_IsInvalid, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_PROPERTYGET, + &DispParams, + &VarResult, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + if( VarResult.vt != VT_BOOL || VarResult.boolVal != -1 ) //should be invalid since we closed the handle + { + printf("\t\t\t\tThe return Variant is incorrect!\n"); + return FALSE; + } + */ + ////////////////////////////////////////////////////////////////// + printf("\t\t\tInvoking IsClosed...\n"); + hr = ptoIntf->Invoke(dispid_IsClosed, + IID_NULL, + LOCALE_SYSTEM_DEFAULT, + DISPATCH_PROPERTYGET, + &DispParams, + &VarResult, + NULL, + NULL); + if( !CheckInvokeHR(hr) ) + return FALSE; + else + printf("\t\t\tCall completed successfully.\n"); + if( VarResult.vt != VT_BOOL || VarResult.boolVal != -1 ) //should be invalid since we closed the handle + { + printf("\t\t\t\tThe return Variant is incorrect!\n"); + return FALSE; + } + + printf("\n"); + ///////////////////////////////////////////////////////////// + ///Invoke SH fields and properties that are defined in SFH class + /////////////////////////////////////////////////////////////////// + if( !InvokeAllFldsAndProps(ptoIntf, shfld1Val, shfld2Val) ) + return FALSE; + + + return TRUE; +} //end of InvokeAllInSHIntf + + +/////////////////////////////////Exported Methods +///////////////////////////////// + +extern "C" DLL_EXPORT BOOL __stdcall SH_MAIntf(IDispatch* ptoIntf, long shIntfVal, long shfld1Val, long shfld2Val) +{ + printf("\t\tIN SH_MAIntf!\n"); + + return InvokeAllInSHIntf(ptoIntf, shIntfVal, shfld1Val, shfld2Val); +} + +extern "C" DLL_EXPORT BOOL __stdcall SH_MAIntf_Ref(IDispatch** ptoIntf, long shIntfVal, long shfld1Val, long shfld2Val) +{ + printf("\t\tIN SH_MAIntf_Ref!\n"); + + return InvokeAllInSHIntf(*ptoIntf, shIntfVal, shfld1Val, shfld2Val); +} + + +extern "C" DLL_EXPORT BOOL __stdcall SHFld_MAIntf(StructMAIntf s, long shndVal, long shfld1Val, long shfld2Val) +{ + printf("\t\tIN SHFld_MAIntf!\n"); + + return InvokeAllInSHIntf(s.ptoIntf, shndVal, shfld1Val, shfld2Val); +} + +extern "C" DLL_EXPORT BOOL __stdcall SHObjectParam(VARIANT v, int shVal, int shfld1Val, int shfld2Val, LPSTR objtype) +{ + if( strcmp(objtype, "DispatchWrapper") == 0 ) + { + if( v.vt != VT_DISPATCH ) + { + printf("\tSHObjectParam: v.vt != VT_DISPATCH\n"); + return FALSE; + } + else //use the IDispatch pointer to invoke some methods + return InvokeAllInSHIntf(v.pdispVal, shVal, shfld1Val, shfld2Val); + } + else if( strcmp(objtype, "UnknownWrapper") == 0 ) + { + if( v.vt != VT_UNKNOWN ) + { + printf("\tSHObjectParam: v.vt != VT_UNKNOWN\n"); + return FALSE; + } + else //use the IDispatch pointer to invoke some methods + return InvokeAllInSHIntf(v.pdispVal, shVal, shfld1Val, shfld2Val); + } + else if( strcmp(objtype, "SafeFileHandle") == 0 ) + { + if( v.vt != VT_DISPATCH ) //if the Object implements IDISPATCH, then it is marshaled to VT_DISPATCH + { + printf("\tSHObjectParam: v.vt != VT_DISPATCH\n"); + return FALSE; + } + else //use the IUnknown pointer to QI for IDispatch + { + HRESULT hr; + IDispatch* pIDisp; + + //QI for IDispatch pointer to SH + printf("\tSHObjectParam: QI for IDispatch using IUnknown pointer (v.punkVal)\n"); + hr = v.punkVal->QueryInterface(IID_IDispatch, (void**)&pIDisp); + if( FAILED(hr) ) + { + printf("\tSHObjectParam: hr = E_NOINTERFACE\n"); + return FALSE; + } + printf("\tSHObjectParam: QI Done\n"); + + //use IDispatch pointer obtained from QI + return InvokeAllInSHIntf(pIDisp, shVal, shfld1Val, shfld2Val); + } + } + else + { + printf("\tSHObjectParam: ERROR! String param is not as expected!\n"); + printf("\tSHObjectParam: objtype = %s\n",objtype); + return FALSE; + } +} + +extern "C" DLL_EXPORT BOOL __stdcall SHStructWithObjectFldParam(StructWithVARIANTFld s, int shVal, int shfld1Val, int shfld2Val, LPSTR objtype) +{ + if( strcmp(objtype, "DispatchWrapper") == 0 ) + { + if( s.v.vt != VT_DISPATCH ) + { + printf("\tSHStructWithObjectFldParam: s.v.vt != VT_DISPATCH\n"); + return FALSE; + } + else //use the IDispatch pointer to invoke some methods + return InvokeAllInSHIntf(s.v.pdispVal, shVal, shfld1Val, shfld2Val); + } + else if( strcmp(objtype, "UnknownWrapper") == 0 ) + { + if( s.v.vt != VT_UNKNOWN ) + { + printf("\tSHStructWithObjectFldParam: s.v.vt != VT_UNKNOWN\n"); + return FALSE; + } + else //use the IUnknown pointer to QI for IDispatch + { + HRESULT hr; + IDispatch* pIDisp; + + //QI for IDispatch pointer to SH + printf("\tSHStructWithObjectFldParam: QI for IDispatch using IUnknown pointer (s.v.punkVal)\n"); + hr = s.v.punkVal->QueryInterface(IID_IDispatch, (void**)&pIDisp); + if( FAILED(hr) ) + { + printf("\tSHStructWithObjectFldParam: hr = E_NOINTERFACE\n"); + return FALSE; + } + printf("\tSHStructWithObjectFldParam: QI Done\n"); + + //use IDispatch pointer obtained from QI + return InvokeAllInSHIntf(pIDisp, shVal, shfld1Val, shfld2Val); + } + } + else if( strcmp(objtype, "SafeFileHandle") == 0 ) + { + if( s.v.vt != VT_DISPATCH ) + { + printf("\tSHStructWithObjectFldParam: s.v.vt != VT_DISPATCH\n"); + return FALSE; + } + else //use the IDispatch pointer to invoke some methods + return InvokeAllInSHIntf(s.v.pdispVal, shVal, shfld1Val, shfld2Val); + } + else + { + printf("\tSHStructWithObjectFldParam: ERROR! String param is not as expected!\n"); + printf("\tSHStructWithObjectFldParam: objtype = %s\n",objtype); + return FALSE; + } +} diff --git a/tests/src/Interop/PInvoke/SafeHandles/Interface/InterfaceTest.cs b/tests/src/Interop/PInvoke/SafeHandles/Interface/InterfaceTest.cs new file mode 100644 index 0000000..3dac428 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/Interface/InterfaceTest.cs @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using SafeHandlesTests; +using System.Threading; +using TestLibrary; + +[StructLayout(LayoutKind.Sequential)] +public struct StructMAIntf +{ + [MarshalAs(UnmanagedType.Interface)] + public SafeFileHandle hnd; +} + +public class SHtoIntfTester +{ + public static int Main() + { + try + { + RunTests(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } + + [DllImport("PInvoke_SafeHandle_MarshalAs_Interface")] + public static extern bool SH_MAIntf([MarshalAs(UnmanagedType.Interface)]SafeFileHandle sh, Int32 shVal, Int32 shfld1Val, Int32 shfld2Val); + + [DllImport("PInvoke_SafeHandle_MarshalAs_Interface")] + public static extern bool SH_MAIntf_Ref([MarshalAs(UnmanagedType.Interface)]ref SafeFileHandle sh, Int32 shVal, Int32 shfld1Val, Int32 shfld2Val); + + [DllImport("PInvoke_SafeHandle_MarshalAs_Interface")] + public static extern bool SHFld_MAIntf(StructMAIntf s, Int32 shndVal, Int32 shfld1Val, Int32 shfld2Val); + + public static void RunTests() + { + Console.WriteLine("RunTests started"); + + //////////////////////////////////////////////////////// + SafeFileHandle sh = Helper.NewSFH(); + Int32 shVal = Helper.SHInt32(sh); + sh.shfld1 = Helper.NewSFH(); //SH field of SFH class + Int32 shfld1Val = Helper.SHInt32(sh.shfld1); + sh.shfld2 = Helper.NewSFH(); //SFH field of SFH class + Int32 shfld2Val = Helper.SHInt32(sh.shfld2); + + //NOTE: SafeHandle is now ComVisible(false)...QIs for IDispatch or the class interface on a + // type with a ComVisible(false) type in its hierarchy are no longer allowed; so calling + // the DW ctor with a SH subclass causes an invalidoperationexception to be thrown since + // the ctor QIs for IDispatch + Console.WriteLine("Testing SH_MAIntf..."); + Assert.Throws(() => SH_MAIntf(sh, shVal, shfld1Val, shfld2Val), "Did not throw InvalidOperationException!"); + + //////////////////////////////////////////////////////// + sh = Helper.NewSFH(); + shVal = Helper.SHInt32(sh); + sh.shfld1 = Helper.NewSFH(); //SH field of SFH class + shfld1Val = Helper.SHInt32(sh.shfld1); + sh.shfld2 = Helper.NewSFH(); //SFH field of SFH class + shfld2Val = Helper.SHInt32(sh.shfld2); + + //NOTE: SafeHandle is now ComVisible(false)...QIs for IDispatch or the class interface on a + // type with a ComVisible(false) type in its hierarchy are no longer allowed; so calling + // the DW ctor with a SH subclass causes an invalidoperationexception to be thrown since + // the ctor QIs for IDispatch + Console.WriteLine("Testing SH_MAIntf_Ref..."); + Assert.Throws(() => SH_MAIntf_Ref(ref sh, shVal, shfld1Val, shfld2Val), "Did not throw InvalidOperationException!"); + + //////////////////////////////////////////////////////// + StructMAIntf s = new StructMAIntf(); + s.hnd = Helper.NewSFH(); + Int32 shndVal = Helper.SHInt32(s.hnd); + s.hnd.shfld1 = Helper.NewSFH(); //SH field of SFH field of struct + shfld1Val = Helper.SHInt32(s.hnd.shfld1); + s.hnd.shfld2 = Helper.NewSFH(); //SFH field of SFH field of struct + shfld2Val = Helper.SHInt32(s.hnd.shfld2); + + //NOTE: SafeHandle is now ComVisible(false)...QIs for IDispatch or the class interface on a + // type with a ComVisible(false) type in its hierarchy are no longer allowed; so calling + // the DW ctor with a SH subclass causes an invalidoperationexception to be thrown since + // the ctor QIs for IDispatch + Console.WriteLine("Testing SHFld_MAIntf..."); + Assert.Throws(() => SHFld_MAIntf(s, shndVal, shfld1Val, shfld2Val), "Did not throw InvalidOperationException!"); + + Console.WriteLine("RunTests end"); + } +} \ No newline at end of file diff --git a/tests/src/Interop/PInvoke/SafeHandles/Interface/InterfaceTest.csproj b/tests/src/Interop/PInvoke/SafeHandles/Interface/InterfaceTest.csproj new file mode 100644 index 0000000..15130a4 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/Interface/InterfaceTest.csproj @@ -0,0 +1,38 @@ + + + + + Debug + AnyCPU + InterfaceTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + true + true + + + + + + + False + + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/SafeHandles/InvalidMarshalAs/InvalidMarshalAsTest.cs b/tests/src/Interop/PInvoke/SafeHandles/InvalidMarshalAs/InvalidMarshalAsTest.cs new file mode 100644 index 0000000..eadb7aa --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/InvalidMarshalAs/InvalidMarshalAsTest.cs @@ -0,0 +1,801 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using SafeHandlesTests; +using TestLibrary; + +#pragma warning disable 618 +public class SHTester_MA +{ + public static int Main() + { + try + { + RunSHInvalidMATests(); + RunSHInvalidretMATests(); + RunSHFldInvalidMATests(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + + } + + /// + /// All the invalid MarshalAs signatures follow + /// + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA1([MarshalAs(UnmanagedType.AnsiBStr)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA2([MarshalAs(UnmanagedType.AsAny)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA3([MarshalAs(UnmanagedType.Bool)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA4([MarshalAs(UnmanagedType.BStr)]SafeFileHandle sh); + + // NOTE: Specified unmanaged type is only valid on fields. + //[DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError=true)] + //public static extern bool SHInvalid_MA5([MarshalAs(UnmanagedType.ByValArray)]SafeFileHandle sh); + + //NOTE: Specified unmanaged type is only valid on fields. + //[DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError=true)] + //public static extern bool SHInvalid_MA6([MarshalAs(UnmanagedType.ByValTStr, SizeConst=10)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA7([MarshalAs(UnmanagedType.Currency)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA9([MarshalAs(UnmanagedType.Error)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA10([MarshalAs(UnmanagedType.FunctionPtr)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA11([MarshalAs(UnmanagedType.I1)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA12([MarshalAs(UnmanagedType.I2)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA13([MarshalAs(UnmanagedType.I4)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA14([MarshalAs(UnmanagedType.I8)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA15([MarshalAs(UnmanagedType.IDispatch)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA16([MarshalAs(UnmanagedType.Interface)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA17([MarshalAs(UnmanagedType.IUnknown)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA18([MarshalAs(UnmanagedType.LPArray)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA19([MarshalAs(UnmanagedType.LPStr)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA20([MarshalAs(UnmanagedType.LPStruct)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA21([MarshalAs(UnmanagedType.LPTStr)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA22([MarshalAs(UnmanagedType.LPWStr)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA23([MarshalAs(UnmanagedType.R4)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA24([MarshalAs(UnmanagedType.R8)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA25([MarshalAs(UnmanagedType.SafeArray)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA26([MarshalAs(UnmanagedType.Struct)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA27([MarshalAs(UnmanagedType.SysInt)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA28([MarshalAs(UnmanagedType.SysUInt)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA29([MarshalAs(UnmanagedType.TBStr)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA30([MarshalAs(UnmanagedType.U1)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA31([MarshalAs(UnmanagedType.U2)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA32([MarshalAs(UnmanagedType.U4)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA33([MarshalAs(UnmanagedType.U8)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA34([MarshalAs(UnmanagedType.VariantBool)]SafeFileHandle sh); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_MA", SetLastError = true)] + public static extern bool SHInvalid_MA35([MarshalAs(UnmanagedType.VBByRefStr)]SafeFileHandle sh); + + /// + ///runs all tests involving pinvoke signatures with invalid MarshalAs attributes + /// + public static void RunSHInvalidMATests() + { + Console.WriteLine("\nRunSHInvalidMATests():"); + + SafeFileHandle hnd = Helper.NewSFH(); + + Console.WriteLine("Testing SHInvalid_MA1..."); + Assert.Throws(() => SHInvalid_MA1(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA2..."); + Assert.Throws(() => SHInvalid_MA2(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA3..."); + Assert.Throws(() => SHInvalid_MA3(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA4..."); + Assert.Throws(() => SHInvalid_MA4(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("SHInvalid_MA5 cannot be tested (see PInvoke signatures in test source for comments)..."); + Console.WriteLine("SHInvalid_MA6 cannot be tested (see PInvoke signatures in test source for comments)..."); + + Console.WriteLine("Testing SHInvalid_MA7..."); + Assert.Throws(() => SHInvalid_MA7(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("SHInvalid_MA8 cannot be tested (see PInvoke signatures in test source for comments)..."); + + Console.WriteLine("Testing SHInvalid_MA9..."); + Assert.Throws(() => SHInvalid_MA9(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA10..."); + Assert.Throws(() => SHInvalid_MA10(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA11..."); + Assert.Throws(() => SHInvalid_MA11(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA12..."); + Assert.Throws(() => SHInvalid_MA12(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA13..."); + Assert.Throws(() => SHInvalid_MA13(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA14..."); + Assert.Throws(() => SHInvalid_MA14(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA15..."); + Assert.Throws(() => SHInvalid_MA15(hnd), "FAILED! Exception not thrown."); + + //NOTE: UnmanagedType.Interface is the only MA attribute that is valid + //Console.WriteLine("Testing SHInvalid_MA16..."); + + Console.WriteLine("Testing SHInvalid_MA17..."); + Assert.Throws(() => SHInvalid_MA17(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA18..."); + Assert.Throws(() => SHInvalid_MA18(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA19..."); + Assert.Throws(() => SHInvalid_MA19(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA20..."); + Assert.Throws(() => SHInvalid_MA20(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA21..."); + Assert.Throws(() => SHInvalid_MA21(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA22..."); + Assert.Throws(() => SHInvalid_MA22(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA23..."); + Assert.Throws(() => SHInvalid_MA23(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA24..."); + Assert.Throws(() => SHInvalid_MA24(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA25..."); + Assert.Throws(() => SHInvalid_MA25(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA26..."); + Assert.Throws(() => SHInvalid_MA26(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA27..."); + Assert.Throws(() => SHInvalid_MA27(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA28..."); + Assert.Throws(() => SHInvalid_MA28(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA29..."); + Assert.Throws(() => SHInvalid_MA29(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA30..."); + Assert.Throws(() => SHInvalid_MA30(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA31..."); + Assert.Throws(() => SHInvalid_MA31(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA32..."); + Assert.Throws(() => SHInvalid_MA32(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA33..."); + Assert.Throws(() => SHInvalid_MA33(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA34..."); + Assert.Throws(() => SHInvalid_MA34(hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_MA35..."); + Assert.Throws(() => SHInvalid_MA35(hnd), "FAILED! Exception not thrown."); + } + + /// + /// All the invalid return MarshalAs signatures follow + /// + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.AnsiBStr)] + public static extern SafeFileHandle SHInvalid_retMA1(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.AsAny)] + public static extern SafeFileHandle SHInvalid_retMA2(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern SafeFileHandle SHInvalid_retMA3(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.BStr)] + public static extern SafeFileHandle SHInvalid_retMA4(); + + //NOTE: Specified unmanaged type is only valid on fields. + //[DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError=true)] + //[return:MarshalAs(UnmanagedType.ByValArray)] + //public static extern SafeFileHandle SHInvalid_retMA5(); + + //NOTE: Specified unmanaged type is only valid on fields. + //[DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError=true)] + //[return:MarshalAs(UnmanagedType.ByValTStr)] + //public static extern SafeFileHandle SHInvalid_retMA6(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Currency)] + public static extern SafeFileHandle SHInvalid_retMA7(); + + //NOTE: Specified unmanaged type also needs MarshalType or MarshalTypeRef which indicate the custom marshaler + //[DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError=true)] + //[return:MarshalAs(UnmanagedType.CustomMarshaler)] + //public static extern SafeFileHandle SHInvalid_retMA8(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Error)] + public static extern SafeFileHandle SHInvalid_retMA9(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.FunctionPtr)] + public static extern SafeFileHandle SHInvalid_retMA10(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.I1)] + public static extern SafeFileHandle SHInvalid_retMA11(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.I2)] + public static extern SafeFileHandle SHInvalid_retMA12(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.I4)] + public static extern SafeFileHandle SHInvalid_retMA13(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.I8)] + public static extern SafeFileHandle SHInvalid_retMA14(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.IDispatch)] + public static extern SafeFileHandle SHInvalid_retMA15(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Interface)] + public static extern SafeFileHandle SHInvalid_retMA16(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.IUnknown)] + public static extern SafeFileHandle SHInvalid_retMA17(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.LPArray)] + public static extern SafeFileHandle SHInvalid_retMA18(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.LPStr)] + public static extern SafeFileHandle SHInvalid_retMA19(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.LPStruct)] + public static extern SafeFileHandle SHInvalid_retMA20(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.LPTStr)] + public static extern SafeFileHandle SHInvalid_retMA21(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.LPWStr)] + public static extern SafeFileHandle SHInvalid_retMA22(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.R4)] + public static extern SafeFileHandle SHInvalid_retMA23(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.R8)] + public static extern SafeFileHandle SHInvalid_retMA24(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.SafeArray)] + public static extern SafeFileHandle SHInvalid_retMA25(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Struct)] + public static extern SafeFileHandle SHInvalid_retMA26(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.SysInt)] + public static extern SafeFileHandle SHInvalid_retMA27(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.SysUInt)] + public static extern SafeFileHandle SHInvalid_retMA28(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.TBStr)] + public static extern SafeFileHandle SHInvalid_retMA29(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.U1)] + public static extern SafeFileHandle SHInvalid_retMA30(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.U2)] + public static extern SafeFileHandle SHInvalid_retMA31(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.U4)] + public static extern SafeFileHandle SHInvalid_retMA32(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.U8)] + public static extern SafeFileHandle SHInvalid_retMA33(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.VariantBool)] + public static extern SafeFileHandle SHInvalid_retMA34(); + + [DllImport("PInvoke_SafeHandle", EntryPoint="SHInvalid_retMA", SetLastError = true)] + [return: MarshalAs(UnmanagedType.VBByRefStr)] + public static extern SafeFileHandle SHInvalid_retMA35(); + + /// + ///runs all tests involving pinvoke signatures with invalid return MarshalAs attributes + /// + public static void RunSHInvalidretMATests() + { + Console.WriteLine("\nRunSHInvalidretMATests():"); + + Console.WriteLine("Testing SHInvalid_retMA1..."); + Assert.Throws(() => SHInvalid_retMA1(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA2..."); + Assert.Throws(() => SHInvalid_retMA2(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA3..."); + Assert.Throws(() => SHInvalid_retMA3(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA4..."); + Assert.Throws(() => SHInvalid_retMA4(), "FAILED! Exception not thrown."); + + Console.WriteLine("SHInvalid_retMA5 cannot be tested (see PInvoke signatures in test source for comments)..."); + Console.WriteLine("SHInvalid_retMA6 cannot be tested (see PInvoke signatures in test source for comments)..."); + + Console.WriteLine("Testing SHInvalid_retMA7..."); + Assert.Throws(() => SHInvalid_retMA7(), "FAILED! Exception not thrown."); + + Console.WriteLine("SHInvalid_retMA8 cannot be tested (see PInvoke signatures in test source for comments)..."); + + Console.WriteLine("Testing SHInvalid_retMA9..."); + Assert.Throws(() => SHInvalid_retMA9(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA10..."); + Assert.Throws(() => SHInvalid_retMA10(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA11..."); + Assert.Throws(() => SHInvalid_retMA11(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA12..."); + Assert.Throws(() => SHInvalid_retMA12(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA13..."); + Assert.Throws(() => SHInvalid_retMA13(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA14..."); + Assert.Throws(() => SHInvalid_retMA14(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA15..."); + Assert.Throws(() => SHInvalid_retMA15(), "FAILED! Exception not thrown."); + + //NOTE: If the return type is marked as Unman.Intf, then the unmanaged code should return an Interface + // pointer and not an integer---doing so will cause unexpected behavior + /* + Console.WriteLine("Testing SHInvalid_retMA16..."); + Assert.Throws(() => SHInvalid_retMA16(), "FAILED! Exception not thrown."); + */ + + Console.WriteLine("Testing SHInvalid_retMA17..."); + Assert.Throws(() => SHInvalid_retMA17(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA18..."); + Assert.Throws(() => SHInvalid_retMA18(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA19..."); + Assert.Throws(() => SHInvalid_retMA19(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA20..."); + Assert.Throws(() => SHInvalid_retMA20(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA21..."); + Assert.Throws(() => SHInvalid_retMA21(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA22..."); + Assert.Throws(() => SHInvalid_retMA22(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA23..."); + Assert.Throws(() => SHInvalid_retMA23(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA24..."); + Assert.Throws(() => SHInvalid_retMA24(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA25..."); + Assert.Throws(() => SHInvalid_retMA25(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA26..."); + Assert.Throws(() => SHInvalid_retMA26(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA27..."); + Assert.Throws(() => SHInvalid_retMA27(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA28..."); + Assert.Throws(() => SHInvalid_retMA28(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA29..."); + Assert.Throws(() => SHInvalid_retMA29(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA30..."); + Assert.Throws(() => SHInvalid_retMA30(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA31..."); + Assert.Throws(() => SHInvalid_retMA31(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA32..."); + Assert.Throws(() => SHInvalid_retMA32(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA33..."); + Assert.Throws(() => SHInvalid_retMA33(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA34..."); + Assert.Throws(() => SHInvalid_retMA34(), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHInvalid_retMA35..."); + Assert.Throws(() => SHInvalid_retMA35(), "FAILED! Exception not thrown."); + } + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA1 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA2 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA3 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA4 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA5 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA6 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA7 s); + + //NOTE: no corresponding struct definition + //[DllImport("PInvoke_SafeHandle", SetLastError=true)] + //public static extern bool SHFldInvalid_MA(StructMA8 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA9 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA10 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA11 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA12 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA13 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA14 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA15 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA16 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA17 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA18 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA19 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA20 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA21 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA22 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA23 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA24 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA25 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA26 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA27 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA28 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA29 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA30 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA31 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA32 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA33 s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHFldInvalid_MA(StructMA34 s); + + /// + ///runs all tests involving pinvoke signatures passing/returning structures + ///containing SH fields with invalid MarshalAs attributes + /// + public static void RunSHFldInvalidMATests() + { + Console.WriteLine("\nRunSHFldInvalidMATests():"); + + StructMA1 s1 = new StructMA1(); + s1.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA1..."); + Assert.Throws(() => SHFldInvalid_MA(s1), "FAILED! Exception not thrown."); + + StructMA2 s2 = new StructMA2(); + s2.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA2..."); + Assert.Throws(() => SHFldInvalid_MA(s2), "FAILED! Exception not thrown."); + + StructMA3 s3 = new StructMA3(); + s3.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA3..."); + Assert.Throws(() => SHFldInvalid_MA(s3), "FAILED! Exception not thrown."); + + StructMA4 s4 = new StructMA4(); + s4.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA4..."); + Assert.Throws(() => SHFldInvalid_MA(s4), "FAILED! Exception not thrown."); + + StructMA5 s5 = new StructMA5(); + s5.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA5..."); + Assert.Throws(() => SHFldInvalid_MA(s5), "FAILED! Exception not thrown."); + + StructMA6 s6 = new StructMA6(); + s6.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA6..."); + Assert.Throws(() => SHFldInvalid_MA(s6), "FAILED! Exception not thrown."); + + StructMA7 s7 = new StructMA7(); + s7.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA7..."); + Assert.Throws(() => SHFldInvalid_MA(s7), "FAILED! Exception not thrown."); + + /* + StructMA8 s8 = new StructMA8(); + s5.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA8..."); + Assert.Throws(() => SHFldInvalid_MA(s8), "FAILED! Exception not thrown."); + */ + + StructMA9 s9 = new StructMA9(); + s9.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA9..."); + Assert.Throws(() => SHFldInvalid_MA(s9), "FAILED! Exception not thrown."); + + StructMA10 s10 = new StructMA10(); + s10.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA10..."); + Assert.Throws(() => SHFldInvalid_MA(s10), "FAILED! Exception not thrown."); + + StructMA11 s11 = new StructMA11(); + s11.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA11..."); + Assert.Throws(() => SHFldInvalid_MA(s11), "FAILED! Exception not thrown."); + + StructMA12 s12 = new StructMA12(); + s12.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA12..."); + Assert.Throws(() => SHFldInvalid_MA(s12), "FAILED! Exception not thrown."); + + StructMA13 s13 = new StructMA13(); + s13.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA13..."); + Assert.Throws(() => SHFldInvalid_MA(s13), "FAILED! Exception not thrown."); + + StructMA14 s14 = new StructMA14(); + s14.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA14..."); + Assert.Throws(() => SHFldInvalid_MA(s14), "FAILED! Exception not thrown."); + + StructMA15 s15 = new StructMA15(); + s15.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA15..."); + Assert.Throws(() => SHFldInvalid_MA(s15), "FAILED! Exception not thrown."); + + //NOTE: UnmanagedType.Interface is the only MA attribute allowed + /* + StructMA16 s16 = new StructMA16(); + s16.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA16..."); + Assert.Throws(() => SHFldInvalid_MA(s16), "FAILED! Exception not thrown."); + */ + + StructMA17 s17 = new StructMA17(); + s17.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA17..."); + Assert.Throws(() => SHFldInvalid_MA(s17), "FAILED! Exception not thrown."); + + StructMA18 s18 = new StructMA18(); + s18.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA18..."); + Assert.Throws(() => SHFldInvalid_MA(s18), "FAILED! Exception not thrown."); + + StructMA19 s19 = new StructMA19(); + s19.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA19..."); + Assert.Throws(() => SHFldInvalid_MA(s19), "FAILED! Exception not thrown."); + + StructMA20 s20 = new StructMA20(); + s20.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA20..."); + Assert.Throws(() => SHFldInvalid_MA(s20), "FAILED! Exception not thrown."); + + StructMA21 s21 = new StructMA21(); + s21.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA21..."); + Assert.Throws(() => SHFldInvalid_MA(s21), "FAILED! Exception not thrown."); + + StructMA22 s22 = new StructMA22(); + s22.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA22..."); + Assert.Throws(() => SHFldInvalid_MA(s22), "FAILED! Exception not thrown."); + + StructMA23 s23 = new StructMA23(); + s23.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA23..."); + Assert.Throws(() => SHFldInvalid_MA(s23), "FAILED! Exception not thrown."); + + StructMA24 s24 = new StructMA24(); + s24.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA24..."); + Assert.Throws(() => SHFldInvalid_MA(s24), "FAILED! Exception not thrown."); + + StructMA25 s25 = new StructMA25(); + s25.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA25..."); + Assert.Throws(() => SHFldInvalid_MA(s25), "FAILED! Exception not thrown."); + + StructMA26 s26 = new StructMA26(); + s26.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA26..."); + Assert.Throws(() => SHFldInvalid_MA(s26), "FAILED! Exception not thrown."); + + StructMA27 s27 = new StructMA27(); + s27.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA27..."); + Assert.Throws(() => SHFldInvalid_MA(s27), "FAILED! Exception not thrown."); + + StructMA28 s28 = new StructMA28(); + s28.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA28..."); + Assert.Throws(() => SHFldInvalid_MA(s28), "FAILED! Exception not thrown."); + + StructMA29 s29 = new StructMA29(); + s29.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA29..."); + Assert.Throws(() => SHFldInvalid_MA(s29), "FAILED! Exception not thrown."); + + StructMA30 s30 = new StructMA30(); + s30.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA30..."); + Assert.Throws(() => SHFldInvalid_MA(s30), "FAILED! Exception not thrown."); + + StructMA31 s31 = new StructMA31(); + s31.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA31..."); + Assert.Throws(() => SHFldInvalid_MA(s31), "FAILED! Exception not thrown."); + + StructMA32 s32 = new StructMA32(); + s32.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA32..."); + Assert.Throws(() => SHFldInvalid_MA(s32), "FAILED! Exception not thrown."); + + StructMA33 s33 = new StructMA33(); + s33.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA33..."); + Assert.Throws(() => SHFldInvalid_MA(s33), "FAILED! Exception not thrown."); + + StructMA34 s34 = new StructMA34(); + s34.hnd = Helper.NewSFH(); + Console.WriteLine("Testing StructMA34..."); + Assert.Throws(() => SHFldInvalid_MA(s34), "FAILED! Exception not thrown."); + } +} +#pragma warning restore 618 + + + + + + diff --git a/tests/src/Interop/PInvoke/SafeHandles/InvalidMarshalAs/InvalidMarshalAsTest.csproj b/tests/src/Interop/PInvoke/SafeHandles/InvalidMarshalAs/InvalidMarshalAsTest.csproj new file mode 100644 index 0000000..811ba20 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/InvalidMarshalAs/InvalidMarshalAsTest.csproj @@ -0,0 +1,38 @@ + + + + + Debug + AnyCPU + InvalidMarshalAsTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + true + true + + + + + + + False + + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/SafeHandles/Misc.Unsupported/MiscUnsupportedTest.cs b/tests/src/Interop/PInvoke/SafeHandles/Misc.Unsupported/MiscUnsupportedTest.cs new file mode 100644 index 0000000..d5e8455 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/Misc.Unsupported/MiscUnsupportedTest.cs @@ -0,0 +1,114 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using SafeHandlesTests; +using TestLibrary; + +public class SHTester_Misc +{ + public static int Main() + { + try + { + RunSHMiscTests(); + RunChildSHStructParamTests(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHArrayParam(SafeFileHandle[] arr, Int32[] arrInt32s, int length); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern StructWithSHFld SHReturnStruct(); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_In2([In]StructWithSHArrayFld s, Int32[] arrInt32s, int length); + + /// + ///runs all other miscellaneous tests; + ///it uses the PInvoke signatures defined above it + ///1-passing arrays of SHs as parameters + ///2-passing arrays of structures (with SH subclass fields) as parameters + ///3-returning SHs from unmanaged code as pure return values + ///4-returning structures (with SH subclass fields) from unmanaged code as pure return values + ///5-passing nested structures (with the nested structure having a SH subclass field) + ///6-passing structures with SH Array fields + ///7-passing mixed params (SH, SH subclass, subclass of SH subclass) + ///8-passing struct params that have many handle fields [in, ref (with and without changes to flds)] + ///9-passing SH subclass in Dispatch\UnknownWrapper, expecting a VARIANT (of type VT_DISPATCH or + ///VT_UNKNOWN) on the managed side; as params and as fields + /// + public static void RunSHMiscTests() + { + Console.WriteLine("\nRunSHMiscTests():"); + + ///1-passing arrays of SHs as parameters + + SafeFileHandle[] hndArray = new SafeFileHandle[Helper.N]; + //the following array will contain the 32-bit values corresponding to hndArray's elements + Int32[] hndArrayInt32s = new Int32[Helper.N]; + for (int i = 0; i < Helper.N; i++) + { + hndArray[i] = Helper.NewSFH(); + hndArrayInt32s[i] = Helper.SHInt32(hndArray[i]); + } + Console.WriteLine("Testing SHArrayParam..."); + Assert.Throws(() => SHArrayParam(hndArray, hndArrayInt32s, Helper.N), "FAILED! Exception not thrown."); + + //4-returning structures (with SH subclass fields) from unmanaged code as pure return values + Console.WriteLine("Testing SHReturnStruct..."); + Assert.Throws(() => SHReturnStruct(), "FAILED! Exception not thrown."); + + //6-passing structures with SH Array fields + hndArray = new SafeFileHandle[Helper.N]; + //the following array will contain the 32-bit values corresponding to hndArray's elements + hndArrayInt32s = new Int32[Helper.N]; + for (int i = 0; i < Helper.N; i++) + { + hndArray[i] = Helper.NewSFH(); + hndArrayInt32s[i] = Helper.SHInt32(hndArray[i]); + } + StructWithSHArrayFld sWithArrFld = new StructWithSHArrayFld(); + sWithArrFld.sharr = hndArray; //assign hnd array to hnd array field + Console.WriteLine("Testing SHStructParam_In2..."); + Assert.Throws(() => SHStructParam_In2(sWithArrFld, hndArrayInt32s, Helper.N), "FAILED! Exception not thrown."); + } + + /// + ///passing SafeFileHandle subclass parameters to unmanaged code in various combinations and forms; + ///it uses the PInvoke signatures defined above it + ///1-passing SafeFileHandle subclass parameters individually in separate methods (In, out, ref) + ///2-passing SafeFileHandle subclass parameters in combination in the same method + /// + + [DllImport("PInvoke_SafeHandle", PreserveSig = false, SetLastError = true)] + public static extern StructWithChildSHFld SHStructParam_OutRetVal(); + + /// + ///passing structures (with SafeFileHandle subclass fields) as parameters in various combinations and forms; + ///it uses the PInvoke signatures defined above it + ///1-passing structures (In, out, ref) (with SafeFileHandle subclass fields) individually in separate methods + ///2-passing structures (In, out, ref) (with SafeFileHandle subclass fields) in combination in the same method + /// + public static void RunChildSHStructParamTests() + { + Console.WriteLine("\nRunChildSHStructParamTests():"); + + StructWithChildSHFld s = new StructWithChildSHFld(); + s.hnd = Helper.NewChildSFH(); //get a new SH + Int32 hndInt32 = Helper.SHInt32(s.hnd); //get the 32-bit value associated with s.hnd + + Console.WriteLine("Testing SHStructParam_OutRetVal..."); + Assert.Throws(() => s = SHStructParam_OutRetVal(), "FAILED! Exception not thrown."); + } +} \ No newline at end of file diff --git a/tests/src/Interop/PInvoke/SafeHandles/Misc.Unsupported/MiscUnsupportedTest.csproj b/tests/src/Interop/PInvoke/SafeHandles/Misc.Unsupported/MiscUnsupportedTest.csproj new file mode 100644 index 0000000..56ecdd8 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/Misc.Unsupported/MiscUnsupportedTest.csproj @@ -0,0 +1,38 @@ + + + + + Debug + AnyCPU + MiscUnsupportedTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + true + true + + + + + + + False + + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/SafeHandles/Misc/MiscTest.cs b/tests/src/Interop/PInvoke/SafeHandles/Misc/MiscTest.cs new file mode 100644 index 0000000..2d87481 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/Misc/MiscTest.cs @@ -0,0 +1,365 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using SafeHandlesTests; +using TestLibrary; + +#pragma warning disable 618 +public class SHTester_Misc +{ + public static int Main() + { + try + { + RunSHMiscTests(); + RunChildSHParamTests(); + RunChildSHStructParamTests(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructArrayParam(StructWithSHFld[] arr, Int32[] arrInt32s, int length); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern SFH_NoCloseHandle SHReturn(); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructNestedParam(StructNestedParent sn, Int32 arrInt32s); + + [DllImport("PInvoke_SafeHandle")] + public static extern bool SHMixedParam1(SafeHandle sh1, out SFH_NoCloseHandle sh2, ref ChildSFH_NoCloseHandle sh3, StructWithBaseSHFld s1, + StructWithSHFld s2, ref StructWithChildSHFld s3, Int32 sh1Value, Int32 sh3Value, Int32 s1fldValue, Int32 s2fldValue, Int32 s3fldValue); + + [DllImport("PInvoke_SafeHandle")] + public static extern bool SHStructWithManySHFldsParam_In(StructWithManySHFlds s, Int32[] arrInt32s); + + [DllImport("PInvoke_SafeHandle")] + public static extern bool SHStructWithManySHFldsParam_Ref1(ref StructWithManySHFlds s, Int32[] arrInt32s); + + [DllImport("PInvoke_SafeHandle")] + public static extern bool SHStructWithManySHFldsParam_Ref2(ref StructWithManySHFlds s, Int32[] arrInt32s); + + [DllImport(@"PInvoke_SafeHandle_MarshalAs_Interface.dll", CharSet = CharSet.Ansi)] //the MA attribute indicates that obj is to be marshaled as a VARIANT + public static extern bool SHObjectParam([MarshalAs(UnmanagedType.Struct)]Object obj, Int32 shValue, Int32 shfld1Value, Int32 shfld2Value, String wrapper); + + [DllImport(@"PInvoke_SafeHandle_MarshalAs_Interface.dll", CharSet = CharSet.Ansi)] + public static extern bool SHStructWithObjectFldParam(StructWithObjFld s, Int32 shValue, Int32 shfld1Value, Int32 shfld2Value, String objtype); + + /// + ///runs all other miscellaneous tests; + ///it uses the PInvoke signatures defined above it + ///1-passing arrays of SHs as parameters + ///2-passing arrays of structures (with SH subclass fields) as parameters + ///3-returning SHs from unmanaged code as pure return values + ///4-returning structures (with SH subclass fields) from unmanaged code as pure return values + ///5-passing nested structures (with the nested structure having a SH subclass field) + ///6-passing structures with SH Array fields + ///7-passing mixed params (SH, SH subclass, subclass of SH subclass) + ///8-passing struct params that have many handle fields [in, ref (with and without changes to flds)] + ///9-passing SH subclass in Dispatch\UnknownWrapper, expecting a VARIANT (of type VT_DISPATCH or + ///VT_UNKNOWN) on the managed side; as params and as fields + /// + public static void RunSHMiscTests() + { + Console.WriteLine("\nRunSHMiscTests():"); + + SafeFileHandle[] hndArray = new SafeFileHandle[Helper.N]; + //the following array will contain the 32-bit values corresponding to hndArray's elements + Int32[] hndArrayInt32s = new Int32[Helper.N]; + + //2-passing arrays of structures (with SH subclass fields) as parameters + StructWithSHFld[] structArray = new StructWithSHFld[Helper.N]; + //the following array will contain the 32-bit values corresponding to structArray's elements + Int32[] structArrayInt32s = new Int32[Helper.N]; + for (int i = 0; i < Helper.N; i++) + { + structArray[i] = new StructWithSHFld(); + structArray[i].hnd = Helper.NewSFH(); + structArrayInt32s[i] = Helper.SHInt32(structArray[i].hnd); + } + + Console.WriteLine("Testing SHStructArrayParam..."); + Assert.Throws(() => SHStructArrayParam(structArray, structArrayInt32s, Helper.N), "FAILED! Expected Exception Not Thrown!"); + + //3-returning SHs from unmanaged code as pure return values + SFH_NoCloseHandle hnd; + Console.WriteLine("Testing SHReturn..."); + hnd = SHReturn(); + Assert.IsTrue(Helper.IsChanged(hnd), "FAILED! SHReturn did not return hnd as expected."); + + //5-passing nested structures (with the nested structure having a SH subclass field) + StructNestedParent sn = new StructNestedParent(); + sn.snOneDeep = new StructNestedOneDeep(); + sn.snOneDeep.s = new StructWithSHFld(); + sn.snOneDeep.s.hnd = Helper.NewSFH(); + Int32 hndInt32 = Helper.SHInt32(sn.snOneDeep.s.hnd); + Console.WriteLine("Testing SHStructNestedParam..."); + Assert.IsTrue(SHStructNestedParam(sn, hndInt32), "FAILED! SHStructNestedParam did not receive param as expected."); + //check that the value of the HANDLE field did not change + Assert.IsFalse(Helper.IsChanged(sn.snOneDeep.s.hnd), "FAILED! SHStructNestedParam did not return param as expected."); + + //7-passing mixed params (SH, SH subclass, subclass of SH subclass) + SafeHandle sh1 = Helper.NewSFH(); + SFH_NoCloseHandle sh2; + ChildSFH_NoCloseHandle sh3 = Helper.NewChildSFH_NoCloseHandle(); + StructWithBaseSHFld s1 = new StructWithBaseSHFld(); s1.hnd = Helper.NewSFH(); + StructWithSHFld s2 = new StructWithSHFld(); s2.hnd = Helper.NewSFH(); + StructWithChildSHFld s3 = new StructWithChildSHFld(); s3.hnd = Helper.NewChildSFH(); + Int32 sh1Value = Helper.SHInt32(sh1); + Int32 sh3Value = Helper.SHInt32(sh3); + Int32 s1fldValue = Helper.SHInt32(s1.hnd); + Int32 s2fldValue = Helper.SHInt32(s2.hnd); + Int32 s3fldValue = Helper.SHInt32(s3.hnd); + + Console.WriteLine("Testing SHMixedParam1..."); + Assert.IsTrue(SHMixedParam1(sh1, out sh2, ref sh3, s1, s2, ref s3, sh1Value, sh3Value, s1fldValue, s2fldValue, s3fldValue), "FAILED! SHMixedParam1 did not receive params as expected."); + //check the values after the call + Assert.IsFalse(Helper.IsChanged(sh1) || !Helper.IsChanged(sh2) || Helper.IsChanged(sh3) || Helper.IsChanged(s1.hnd) || + Helper.IsChanged(s2.hnd) || Helper.IsChanged(s3.hnd), "FAILED! SHMixedParam1 did not return params as expected."); + + //8-passing struct params that have many handle fields [in, ref (with and without changes to flds)] + + //initialize a new StructWithManySHFlds + Int32[] arrInt32s = null; + StructWithManySHFlds s = Helper.NewStructWithManySHFlds(ref arrInt32s); + + Console.WriteLine("Testing SHStructWithManySHFldsParam_In..."); + Assert.IsTrue(SHStructWithManySHFldsParam_In(s, arrInt32s), "FAILED! SHStructWithManySHFldsaram_In did not receive param as expected."); + //check that the value of the HANDLE fields did not change + Assert.IsFalse(Helper.IsChangedStructWithManySHFlds(s, arrInt32s), "FAILED! SHStructWithManySHFldsParam_In did not return param as expected."); + + Console.WriteLine("Testing SHStructWithManySHFldsParam_Ref1..."); + Assert.IsTrue(SHStructWithManySHFldsParam_Ref1(ref s, arrInt32s), "FAILED! SHStructWithManySHFldsaram_Ref1 did not receive param as expected."); + //check that the value of the HANDLE fields did not change + Assert.IsFalse(Helper.IsChangedStructWithManySHFlds(s, arrInt32s), "FAILED! SHStructWithManySHFldsParam_Ref1 did not return param as expected."); + + Console.WriteLine("Testing SHStructWithManySHFldsParam_Ref2..."); + Assert.Throws(() => SHStructWithManySHFldsParam_Ref2(ref s, arrInt32s), "FAILED! Expected Exception Not Thrown!"); + + //9-passing SH subclass in Dispatch\UnknownWrapper, expecting a VARIANT (of type VT_DISPATCH or + //VT_UNKNOWN) on the managed side + SafeFileHandle sfh = Helper.NewSFH(); //SafeFileHandle + sfh.shfld1 = Helper.NewSFH(); + sfh.shfld2 = Helper.NewSFH(); + Int32 shValue = Helper.SHInt32(sfh); + Int32 shfld1Value = Helper.SHInt32(sfh.shfld1); + Int32 shfld2Value = Helper.SHInt32(sfh.shfld2); + + SafeFileHandle sfh2 = Helper.NewSFH(); //SafeFileHandle + sfh2.shfld1 = Helper.NewSFH(); + sfh2.shfld2 = Helper.NewSFH(); + Int32 sh2Value = Helper.SHInt32(sfh2); + Int32 sh2fld1Value = Helper.SHInt32(sfh2.shfld1); + Int32 sh2fld2Value = Helper.SHInt32(sfh2.shfld2); + + //re-initialize + sfh = Helper.NewSFH(); //SafeFileHandle + sfh.shfld1 = Helper.NewSFH(); + sfh.shfld2 = Helper.NewSFH(); + shValue = Helper.SHInt32(sfh); + shfld1Value = Helper.SHInt32(sfh.shfld1); + shfld2Value = Helper.SHInt32(sfh.shfld2); + String sfhstr = "SafeFileHandle"; + + Console.WriteLine("Testing SHObjectParam with SFH..."); + Assert.Throws(() => SHObjectParam(sfh, shValue, shfld1Value, shfld2Value, sfhstr), "FAILED! Expected Exception Not Thrown!"); + + //re-initialize SH's that will be wrapped for the structure fields + sfh = Helper.NewSFH(); //SafeFileHandle + sfh.shfld1 = Helper.NewSFH(); + sfh.shfld2 = Helper.NewSFH(); + shValue = Helper.SHInt32(sfh); + shfld1Value = Helper.SHInt32(sfh.shfld1); + shfld2Value = Helper.SHInt32(sfh.shfld2); + + sfh2 = Helper.NewSFH(); //SafeFileHandle + sfh2.shfld1 = Helper.NewSFH(); + sfh2.shfld2 = Helper.NewSFH(); + sh2Value = Helper.SHInt32(sfh2); + sh2fld1Value = Helper.SHInt32(sfh2.shfld1); + sh2fld2Value = Helper.SHInt32(sfh2.shfld2); + + //re-initialize + sfh = Helper.NewSFH(); //SafeFileHandle + sfh.shfld1 = Helper.NewSFH(); + sfh.shfld2 = Helper.NewSFH(); + shValue = Helper.SHInt32(sfh); + shfld1Value = Helper.SHInt32(sfh.shfld1); + shfld2Value = Helper.SHInt32(sfh.shfld2); + + StructWithObjFld sWithSFHFld = new StructWithObjFld(); + sWithSFHFld.obj = sfh; + + Console.WriteLine("Testing SHStructWithObjectFldParam with sWithSFHFld..."); + Assert.Throws(() => SHStructWithObjectFldParam(sWithSFHFld, shValue, shfld1Value, shfld2Value, sfhstr), "FAILED! Expected Exception Not Thrown!"); + } + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_In([In]ChildSafeFileHandle sh1, Int32 sh1Value); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Out(out ChildSFH_NoCloseHandle sh1); + + [DllImport("PInvoke_SafeHandle", PreserveSig = false, SetLastError = true)] + public static extern ChildSFH_NoCloseHandle SHParam_OutRetVal(); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Ref(ref ChildSFH_NoCloseHandle sh1, Int32 sh1Value); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Multiple([In]ChildSafeFileHandle sh1, out ChildSFH_NoCloseHandle sh2, ref ChildSFH_NoCloseHandle sh3, Int32 sh1Value, Int32 sh3Value); + + /// + ///passing SafeFileHandle subclass parameters to unmanaged code in various combinations and forms; + ///it uses the PInvoke signatures defined above it + ///1-passing SafeFileHandle subclass parameters individually in separate methods (In, out, ref) + ///2-passing SafeFileHandle subclass parameters in combination in the same method + /// + public static void RunChildSHParamTests() + { + Console.WriteLine("\nRunChildSHParamTests():"); + + //1-passing SafeFileHandle subclass parameters individually in separate methods (In, out, ref) + + //get a new SH + ChildSafeFileHandle hnd = Helper.NewChildSFH(); + Int32 hndInt32 = Helper.SHInt32(hnd); //get the 32-bit value associated with hnd + + Console.WriteLine("Testing SHParam_In..."); + Assert.IsTrue(SHParam_In(hnd, hndInt32), "FAILED! SHParam_In did not receive hnd as expected."); + //check that the value of the HANDLE did not change + Assert.IsFalse(Helper.IsChanged(hnd), "FAILED! SHParam_In did not return hnd as expected."); + + Console.WriteLine("Testing SHParam_Out..."); + ChildSFH_NoCloseHandle hndout; + SHParam_Out(out hndout); + //check that the value of the HANDLE changed + Assert.IsTrue(Helper.IsChanged(hndout), "FAILED! SHParam_Out did not return hndout as expected."); + + Console.WriteLine("Testing SHParam_OutRetVal..."); + hndout = null; + hndout = SHParam_OutRetVal(); + //check that the value of the HANDLE changed + Assert.IsTrue(Helper.IsChanged(hndout), "FAILED! SHParam_OutRetVal did not return hndout as expected."); + + hndout = Helper.NewChildSFH_NoCloseHandle(); //get a new value + hndInt32 = Helper.SHInt32(hndout); + Console.WriteLine("Testing SHParam_Ref..."); + Assert.IsTrue(SHParam_Ref(ref hndout, hndInt32), "FAILED! SHParam_Ref did not receive hndout as expected."); + //check that the value of the HANDLE changed + Assert.IsTrue(Helper.IsChanged(hndout), "FAILED! SHParam_Ref did not return hndout as expected."); + + //2-passing SafeFileHandle subclass parameters in combination in the same method + + //initialize parameters + ChildSafeFileHandle hnd1 = Helper.NewChildSFH(); + Int32 hnd1Int32 = Helper.SHInt32(hnd1); //get the 32-bit value associated with hnd1 + + ChildSFH_NoCloseHandle hnd2 = null; //out parameter + + ChildSFH_NoCloseHandle hnd3 = Helper.NewChildSFH_NoCloseHandle(); + Int32 hnd3Int32 = Helper.SHInt32(hnd3); //get the 32-bit value associated with hnd3 + + Console.WriteLine("Testing SHParam_Multiple..."); + Assert.IsTrue(SHParam_Multiple(hnd1, out hnd2, ref hnd3, hnd1Int32, hnd3Int32), "FAILED! SHParam_Multiple did not receive parameter(s) as expected."); + //check that the value of the HANDLES are as expected + Assert.IsFalse(Helper.IsChanged(hnd1), "FAILED! SHParam_Multiple did not return handle:hnd1 as expected."); + Assert.IsTrue(Helper.IsChanged(hnd2), "FAILED! SHParam_Multiple did not return handle:hnd2 as expected."); + Assert.IsTrue(Helper.IsChanged(hnd3), "FAILED! SHParam_Multiple did not return handle:hnd3 as expected."); + } + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_In([In]StructWithChildSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Out(out StructWithChildSHFld s); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Ref1(ref StructWithChildSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Ref2(ref StructWithChildSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple1([In]StructWithChildSHFld sh1, out StructWithChildSHFld sh2, + ref StructWithChildSHFld sh3, Int32 sh1fldValue, Int32 sh2fldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple2([In]StructWithChildSHFld sh1, ref StructWithChildSHFld sh2, Int32 sh1fldValue, Int32 sh2fldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple3([In]StructWithChildSHFld sh1, ref StructWithChildSHFld sh2, Int32 sh1fldValue, Int32 sh2fldValue); + + /// + ///passing structures (with SafeFileHandle subclass fields) as parameters in various combinations and forms; + ///it uses the PInvoke signatures defined above it + ///1-passing structures (In, out, ref) (with SafeFileHandle subclass fields) individually in separate methods + ///2-passing structures (In, out, ref) (with SafeFileHandle subclass fields) in combination in the same method + /// + public static void RunChildSHStructParamTests() + { + Console.WriteLine("\nRunChildSHStructParamTests():"); + + //1-passing structures (In, out, ref) (with SafeFileHandle subclass fields) individually in separate methods + + //initialize a new StructWithChildSHFld + StructWithChildSHFld s = new StructWithChildSHFld(); + s.hnd = Helper.NewChildSFH(); //get a new SH + Int32 hndInt32 = Helper.SHInt32(s.hnd); //get the 32-bit value associated with s.hnd + + Console.WriteLine("Testing SHStructParam_In..."); + Assert.IsTrue(SHStructParam_In(s, hndInt32), "FAILED! SHStructParam_In did not receive param as expected."); + //check that the value of the HANDLE field did not change + Assert.IsFalse(Helper.IsChanged(s.hnd), "FAILED! SHStructParam_In did not return param as expected."); + + Console.WriteLine("Testing SHStructParam_Out..."); + Assert.Throws(() => SHStructParam_Out(out s), "FAILED! Expected Exception not thrown."); + + s.hnd = Helper.NewChildSFH(); //get a new SH + hndInt32 = Helper.SHInt32(s.hnd); //get the 32-bit value associated with s.hnd + Console.WriteLine("Testing SHStructParam_Ref1 (does not change value of handle field)..."); + Assert.IsTrue(SHStructParam_Ref1(ref s, hndInt32), "FAILED! SHStructParam_Ref1 did not receive param as expected."); + //check that the value of the HANDLE field is not changed + Assert.IsFalse(Helper.IsChanged(s.hnd), "FAILED! SHStructParam_Ref1 did not return param as expected."); + + Console.WriteLine("Testing SHStructParam_Ref2 (does change value of handle field)..."); + Assert.Throws(() => SHStructParam_Ref2(ref s, hndInt32), "FAILED! Expected Exception not thrown."); + + //2-passing structures (In, out, ref) (with SafeFileHandle subclass fields) in combination in the same method + + //initialize parameters + StructWithChildSHFld s1 = new StructWithChildSHFld(); + s1.hnd = Helper.NewChildSFH(); + Int32 hnd1Int32 = Helper.SHInt32(s1.hnd); //get the 32-bit value associated with s1.hnd + + StructWithChildSHFld s2; //out parameter + + StructWithChildSHFld s3 = new StructWithChildSHFld(); + s3.hnd = Helper.NewChildSFH(); + Int32 hnd3Int32 = Helper.SHInt32(s3.hnd); //get the 32-bit value associated with s3.hnd + + Console.WriteLine("Testing SHStructParam_Multiple1 (takes an out struct as one of the params and so is expected to result in an exception)..."); + Assert.Throws(() => SHStructParam_Multiple1(s1, out s2, ref s3, hnd1Int32, hnd3Int32), "FAILED! Exception not thrown."); + + s3.hnd = Helper.NewChildSFH(); + hnd3Int32 = Helper.SHInt32(s3.hnd); //get the 32-bit value associated with s3.hnd + Console.WriteLine("Testing SHStructParam_Multiple2 (takes a ref struct as one of the params)..."); + Assert.IsTrue(SHStructParam_Multiple2(s1, ref s3, hnd1Int32, hnd3Int32), "FAILED! SHStructParam_Multiple2 did not receive parameter(s) as expected."); + //check that the value of the HANDLES are as expected + Assert.IsFalse(Helper.IsChanged(s1.hnd) || Helper.IsChanged(s3.hnd), "FAILED! SHStructParam_Multiple2 did not return handles as expected."); + + Console.WriteLine("Testing SHStructParam_Multiple3 (takes a ref struct as one of the params and changes it and so is expected to result in an exception)..."); + Assert.Throws(() => SHStructParam_Multiple3(s1, ref s3, hnd1Int32, hnd3Int32), "FAILED! Expected Exception not thrown."); + } +} +#pragma warning restore 618 \ No newline at end of file diff --git a/tests/src/Interop/PInvoke/SafeHandles/Misc/MiscTest.csproj b/tests/src/Interop/PInvoke/SafeHandles/Misc/MiscTest.csproj new file mode 100644 index 0000000..ff40161 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/Misc/MiscTest.csproj @@ -0,0 +1,39 @@ + + + + + Debug + AnyCPU + MiscTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + true + true + + + + + + + False + + + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/CMakeLists.txt b/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/CMakeLists.txt new file mode 100644 index 0000000..baf7c1e --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/CMakeLists.txt @@ -0,0 +1,14 @@ +#VCXPROJ +cmake_minimum_required (VERSION 2.6) +project (PInvoke_SafeHandle_ReleaseHandle) +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") +include_directories(${INC_PLATFORM_DIR}) +set(SOURCES + ReleaseHandleNative.cpp +) +# Additional files to reference: +# ReleaseHandleNative.def +# add the executable +add_library (PInvoke_SafeHandle_ReleaseHandle SHARED ${SOURCES}) +# add the install targets +install (TARGETS PInvoke_SafeHandle_ReleaseHandle DESTINATION bin) diff --git a/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/ReleaseHandleNative.cpp b/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/ReleaseHandleNative.cpp new file mode 100644 index 0000000..2f90a35 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/ReleaseHandleNative.cpp @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include +#include +#include + +bool g_myResourceReleaseMethodCalled = false; + +extern "C" DLL_EXPORT void __stdcall MyResourceReleaseMethod(HANDLE hnd) +{ + g_myResourceReleaseMethodCalled = true; + + //call CloseHandle to actually release the handle corresponding to the SafeFileHandle + CloseHandle(hnd); +} + +extern "C" DLL_EXPORT bool GetMyResourceReleaseMethodCalled() +{ + return g_myResourceReleaseMethodCalled; +} + +extern "C" DLL_EXPORT void ResetMyResourceReleaseMethodCalled() +{ + g_myResourceReleaseMethodCalled = false; +} + +extern "C" DLL_EXPORT void __stdcall SHReleasing_OutParams(IUnknown* ppIUnknFOO, HANDLE* phnd, IUnknown** ppIUnknBAR, int* pInt) +{ + //initialize the hnd out param + *phnd = (HANDLE)123; + + //initialize the IUnknBAR out param + *ppIUnknBAR = ppIUnknFOO; + ppIUnknFOO->AddRef(); //addref Foo + + //initialize the int out param + *pInt = 123; +} diff --git a/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/ReleaseHandleTest.cs b/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/ReleaseHandleTest.cs new file mode 100644 index 0000000..b8e16c7 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/ReleaseHandleTest.cs @@ -0,0 +1,102 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.ConstrainedExecution; +using SafeHandlesTests; +using TestLibrary; + +class SafeFileHandle : SafeHandle //SafeHandle subclass +{ + private static readonly IntPtr _invalidHandleValue = new IntPtr(-1); + + //0 or -1 considered invalid + public override bool IsInvalid + { + get { return handle == IntPtr.Zero || handle == _invalidHandleValue; } + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [DllImport("PInvoke_SafeHandle_ReleaseHandle")] + private static extern bool MyResourceReleaseMethod(IntPtr handle); + + //default constructor which just calls the base class constructor + public SafeFileHandle() + : base(IntPtr.Zero, true) + { + } + + override protected bool ReleaseHandle() + { + // this method will not actually call any resource releasing API method + // since the out/ref SFH param is not actually initialized to an OS allocated + // HANDLE---instead the unmanaged side just initializes/changes it to some integer; + // If a resource releasing API method like CloseHandle were called then + // it would return false and an unhandled exception would be thrown by the + // runtime indicating that the release method failed + MyResourceReleaseMethod(handle); + return true; + } + +} //end of SafeFileHandle class + +class Foo +{ + int FooMethod(int x, int y) { return x + y; } +} + +class Bar +{ + void BarMethod() { } +} + +internal class SHReleasingTester +{ + [DllImport("PInvoke_SafeHandle_ReleaseHandle")] + private static extern void SHReleasing_OutParams( + [MarshalAs(UnmanagedType.Interface)]Foo foo, + out SafeFileHandle sh, + [MarshalAs(UnmanagedType.Interface)]out Bar bar, out int x); + + [DllImport("PInvoke_SafeHandle_ReleaseHandle")] + [return:MarshalAs(UnmanagedType.I1)]private static extern bool GetMyResourceReleaseMethodCalled(); + + [DllImport("PInvoke_SafeHandle_ReleaseHandle")] + private static extern void ResetMyResourceReleaseMethodCalled(); + + public static int Main() + { + try{ + Console.WriteLine("SHReleasing_OutParams"); + SafeFileHandle sh; + Foo foo = new Foo(); + Bar bar; + int x; + + ResetMyResourceReleaseMethodCalled(); + + //this unmanaged method will try to set the out Bar parameter to a Foo type + //this should cause an InvalidCastException on the way back from unmanaged + Assert.Throws(() => SHReleasing_OutParams(foo, out sh, out bar, out x), "SHReleasing_OutParams"); + + //force the finalizer for the SFH param to run + Console.WriteLine("\tForcing finalizer for the SFH param to run..."); + sh = null; + GC.Collect(); + GC.WaitForPendingFinalizers(); + + Assert.IsTrue(GetMyResourceReleaseMethodCalled(), "MyResourceReleaseMethod was NOT called"); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } +} + diff --git a/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/ReleaseHandleTest.csproj b/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/ReleaseHandleTest.csproj new file mode 100644 index 0000000..54fa726 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/ReleaseHandle/ReleaseHandleTest.csproj @@ -0,0 +1,38 @@ + + + + + Debug + AnyCPU + ReleaseHandleTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + true + true + + + + + + + False + + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/SafeHandles/SafeFileHandle.cs b/tests/src/Interop/PInvoke/SafeHandles/SafeFileHandle.cs new file mode 100644 index 0000000..b88696f --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/SafeFileHandle.cs @@ -0,0 +1,237 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using System.Runtime.ConstrainedExecution; + +// special subclass for out/ref ChildSFH params that are changed in unmanaged code +// (see comments above ReleaseHandle for details) +namespace SafeHandlesTests{ + public class ChildSFH_NoCloseHandle : SafeFileHandle + { + /////////////////////////////////////////////////////////// + private static readonly IntPtr _invalidHandleValue = new IntPtr(-1); + + //0 or -1 considered invalid + public override bool IsInvalid + { + get { return handle == IntPtr.Zero || handle == _invalidHandleValue; } + } + + //each SafeHandle subclass will expose a static method for instance creation + [DllImport("api-ms-win-core-file-l1-2-1", EntryPoint = "CreateFileW", SetLastError = true)] + public static extern ChildSFH_NoCloseHandle CreateChildSafeFileHandle(String lpFileName, + DesiredAccess dwDesiredAccess, ShareMode dwShareMode, + IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, + FlagsAndAttributes dwFlagsAndAttributes, IntPtr hTemplateFile); + + //default constructor which just calls the base class constructor + public ChildSFH_NoCloseHandle() + : base() + { + } + + // this method will not actually call any resource releasing API method + // since the out/ref ChildSFH param is not actually initialized to an OS allocated + // HANDLE---instead the unmanaged side just initializes/changes it to some integer; + // If a resource releasing API method like CloseHandle were called then + // it would return false and an unhandled exception would be thrown by the + // runtime indicating that the release method failed + override protected bool ReleaseHandle() + { + return true; + } + + } //end fo ChildSFH_NoCloseHandle + + public class ChildSafeFileHandle : SafeFileHandle + { + //each SafeHandle subclass will expose a static method for instance creation + [DllImport("api-ms-win-core-file-l1-2-1", EntryPoint = "CreateFileW", SetLastError = true)] + public static extern ChildSafeFileHandle CreateChildSafeFileHandle(String lpFileName, + DesiredAccess dwDesiredAccess, ShareMode dwShareMode, + IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, + FlagsAndAttributes dwFlagsAndAttributes, IntPtr hTemplateFile); + + //default constructor which just calls the base class constructor + public ChildSafeFileHandle() + : base() + { + } + + } //end fo ChildSafeFileHandle + + // special subclass for out/ref SFH params that are changed in unmanaged code + // (see comments above ReleaseHandle for details) + public class SFH_NoCloseHandle : SafeHandle //SafeHandle subclass + { + /////////////////////////////////////////////////////////// + private static readonly IntPtr _invalidHandleValue = new IntPtr(-1); + + //0 or -1 considered invalid + public override bool IsInvalid + { + get { return handle == IntPtr.Zero || handle == _invalidHandleValue; } + } + + //each SafeHandle subclass will expose a static method for instance creation + [DllImport("api-ms-win-core-file-l1-2-1", EntryPoint = "CreateFileW", SetLastError = true)] + public static extern SFH_NoCloseHandle CreateFile(String lpFileName, + DesiredAccess dwDesiredAccess, ShareMode dwShareMode, + IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, + FlagsAndAttributes dwFlagsAndAttributes, IntPtr hTemplateFile); + + //default constructor which just calls the base class constructor + public SFH_NoCloseHandle() + : base(IntPtr.Zero, true) + { + } + + // this method will not actually call any resource releasing API method + // since the out/ref SFH param is not actually initialized to an OS allocated + // HANDLE---instead the unmanaged side just initializes/changes it to some integer; + // If a resource releasing API method like CloseHandle were called then + // it would return false and an unhandled exception would be thrown by the + // runtime indicating that the release method failed + override protected bool ReleaseHandle() + { + return true; + } + + } //end of SFH_NoCloseHandle class + + public class SafeFileHandle : SafeHandle //SafeHandle subclass + { + //public fields and properties + public SafeHandle shfld1; + + public SafeFileHandle shfld2; + public SafeFileHandle shfld2_prop + { + [return: MarshalAs(UnmanagedType.Interface)] + get { return shfld2; } + [param: MarshalAs(UnmanagedType.Interface)] + set { shfld2 = value; } + } + + /////////////////////////////////////////////////////////// + private static readonly IntPtr _invalidHandleValue = new IntPtr(-1); + + //0 or -1 considered invalid + public override bool IsInvalid + { + get { return handle == IntPtr.Zero || handle == _invalidHandleValue; } + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [DllImport("api-ms-win-core-handle-l1-1-0", SetLastError = true)] + private static extern bool CloseHandle(IntPtr handle); + + + //each SafeHandle subclass will expose a static method for instance creation + [DllImport("api-ms-win-core-file-l1-2-1", EntryPoint = "CreateFileW", SetLastError = true)] + public static extern SafeFileHandle CreateFile(String lpFileName, + DesiredAccess dwDesiredAccess, ShareMode dwShareMode, + IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, + FlagsAndAttributes dwFlagsAndAttributes, IntPtr hTemplateFile); + + //default constructor which just calls the base class constructor + public SafeFileHandle() + : base(IntPtr.Zero, true) + { + } + + override protected bool ReleaseHandle() + { + return CloseHandle(handle); + } + + } //end of SafeFileHandle class + + /// + /// The following public enums are for use in creating the + /// new file i.e. setting attributes etc. on the file + /// + + // This enumeration defines the level of desired access. The + // enumeration contains a special member for querying the + // device without accessing it. + public enum DesiredAccess : uint + { + QueryDeviceOnly = 0, + GENERIC_READ = 0x80000000, + GENERIC_WRITE = 0x40000000, + GENERIC_EXECUTE = 0x20000000, + GENERIC_ALL = 0x10000000, + DELETE = 0x00010000, + READ_CONTROL = 0x00020000, + WRITE_DAC = 0x00040000, + WRITE_OWNER = 0x00080000, + SYNCHRONIZE = 0x00100000, + STANDARD_RIGHTS_REQUIRED = 0x000F0000, + STANDARD_RIGHTS_READ = READ_CONTROL, + STANDARD_RIGHTS_WRITE = READ_CONTROL, + STANDARD_RIGHTS_EXECUTE = READ_CONTROL, + STANDARD_RIGHTS_ALL = 0x001F0000, + SPECIFIC_RIGHTS_ALL = 0x0000FFFF, + ACCESS_SYSTEM_SECURITY = 0x01000000, + MAXIMUM_ALLOWED = 0x02000000 + } + + // This enumeration defines the type of sharing to support. It + // includes a special member for no sharing at all. + public enum ShareMode + { + NotShared = 0, + FILE_SHARE_READ = 0x00000001, + FILE_SHARE_WRITE = 0x00000002, + FILE_SHARE_DELETE = 0x00000004 + } + + // This enumeration defines how the call will treat files or + // other objects that already exist. You must provide one of + // these values as input. + public enum CreationDisposition + { + CREATE_NEW = 1, + CREATE_ALWAYS = 2, + OPEN_EXISTING = 3, + OPEN_ALWAYS = 4, + TRUNCATE_EXISTING = 5 + } + + // This enumeration defines additional flags and attributes the + // call will use when opening an object. This enumeration contains + // as special value for no flags or attributes. + public enum FlagsAndAttributes : uint + { + None = 0, + FILE_ATTRIBUTE_READONLY = 0x00000001, + FILE_ATTRIBUTE_HIDDEN = 0x00000002, + FILE_ATTRIBUTE_SYSTEM = 0x00000004, + FILE_ATTRIBUTE_ARCHIVE = 0x00000020, + FILE_ATTRIBUTE_NORMAL = 0x00000080, + FILE_ATTRIBUTE_TEMPORARY = 0x00000100, + FILE_ATTRIBUTE_OFFLINE = 0x00001000, + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000, + FILE_ATTRIBUTE_ENCRYPTED = 0x00004000, + FILE_FLAG_WRITE_THROUGH = 0x80000000, + FILE_FLAG_OVERLAPPED = 0x40000000, + FILE_FLAG_NO_BUFFERING = 0x20000000, + FILE_FLAG_RANDOM_ACCESS = 0x10000000, + FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000, + FILE_FLAG_DELETE_ON_CLOSE = 0x04000000, + FILE_FLAG_BACKUP_SEMANTICS = 0x02000000, + FILE_FLAG_POSIX_SEMANTICS = 0x01000000, + FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000, + FILE_FLAG_OPEN_NO_RECALL = 0x00100000, + SECURITY_ANONYMOUS = 0x00000000, + SECURITY_IDENTIFICATION = 0x00010000, + SECURITY_IMPERSONATION = 0x00020000, + SECURITY_DELEGATION = 0x00030000, + SECURITY_CONTEXT_TRACKING = 0x00040000, + SECURITY_EFFECTIVE_ONLY = 0x00080000 + } +} diff --git a/tests/src/Interop/PInvoke/SafeHandles/SafeHandleNative.cpp b/tests/src/Interop/PInvoke/SafeHandles/SafeHandleNative.cpp new file mode 100644 index 0000000..0cbcd87 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/SafeHandleNative.cpp @@ -0,0 +1,334 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include +#include +#include +#include "StructDefs.h" //all the unmanaged struct defs are in this file + +//Global Handle Return Value +HANDLE returnHandleValue = (HANDLE)123; + +//Method for Invalid MarshalAs tests +extern "C" DLL_EXPORT BOOL __stdcall SHFldInvalid_MA(StructWithSHFld s) +{ + printf("\t\tIN SHFldInvalid_MA!\n"); + return TRUE; +} + +extern "C" DLL_EXPORT HANDLE __stdcall SHInvalid_retMA16() +{ + printf("\t\tIN SHInvalid_retMA16!\n"); + HANDLE *hnd = (HANDLE*)GlobalAlloc(0, sizeof(HANDLE)); //new HANDLE + *hnd = returnHandleValue; + return (*hnd); +} + +//////////////Methods used by RunParamTests +/////////////////////////////////////////// +extern "C" DLL_EXPORT BOOL __stdcall SHParam_In(HANDLE sh1, int sh1Value) +{ + if( (intptr_t)sh1 != sh1Value ) + return FALSE; + return TRUE; +} + +extern "C" DLL_EXPORT BOOL __stdcall SHParam_Out(HANDLE* sh1) +{ + *sh1 = returnHandleValue; + return TRUE; +} + +extern "C" DLL_EXPORT HRESULT _stdcall SHParam_OutRetVal(HANDLE* sh1) +{ + *sh1 = returnHandleValue; + return S_OK; +} + +extern "C" DLL_EXPORT BOOL __stdcall SHParam_Ref(HANDLE* sh1, int sh1Value) +{ + if( (intptr_t)*sh1 != sh1Value ) + return FALSE; + //change the value of the HANDLE---this is equivalent to assigning a new HANDLE + *sh1 = returnHandleValue; + return TRUE; +} + +extern "C" DLL_EXPORT BOOL __stdcall SHParam_Multiple(HANDLE sh1, HANDLE* sh2, HANDLE* sh3, int sh1Value, int sh3Value) +{ + if( (intptr_t)sh1 != sh1Value ) + { + printf("\t\tIn SHParam_Multiple: sh1 value not received as expected.\n"); + return FALSE; + } + else if( (intptr_t)*sh3 != sh3Value ) + { + printf("\t\tIn SHParam_Multiple: sh3 value not received as expected.\n"); + //printf("\t\t\t*sh3 = %d, sh3Value = %d\n", (int)*sh3, sh3Value); + return FALSE; + } + //change the out and ref values + *sh2 = returnHandleValue; + *sh3 = returnHandleValue; + return TRUE; +} + +//////////////Methods used by RunStructParamTests +///////////////////////////////////////////////// +extern "C" DLL_EXPORT BOOL __stdcall SHStructParam_In(StructWithSHFld s, int shndValue) +{ + if( (intptr_t)s.hnd != shndValue ) + return FALSE; + s.hnd = returnHandleValue; //try to change hnd value; should not be reflected on managed side + return TRUE; +} + +extern "C" DLL_EXPORT BOOL __stdcall SHStructParam_Out(StructWithSHFld* ps) +{ + ps->hnd = returnHandleValue; + return TRUE; +} + +extern "C" DLL_EXPORT HRESULT _stdcall SHStructParam_OutRetVal(StructWithSHFld* ps) +{ + ps->hnd = returnHandleValue; + return S_OK; +} + +//this method will NOT change the value of the ref SH subclass field +extern "C" DLL_EXPORT BOOL __stdcall SHStructParam_Ref1(StructWithSHFld* ps, int shndValue) +{ + if( (intptr_t)(ps->hnd) != shndValue ) + return FALSE; + return TRUE; +} + +//this method will change the value of the SH subclass field +extern "C" DLL_EXPORT BOOL __stdcall SHStructParam_Ref2(StructWithSHFld* ps, int shndValue) +{ + if( (intptr_t)(ps->hnd) != shndValue ) + return FALSE; + //change the value of the HANDLE---this is equivalent to assigning a new HANDLE + ps->hnd = returnHandleValue; + return TRUE; +} + +//this takes an out param and so is expected to result in an exception +extern "C" DLL_EXPORT BOOL __stdcall SHStructParam_Multiple1(StructWithSHFld s1, StructWithSHFld* ps2, + StructWithSHFld* ps3, int s1hndValue, + int s3hndValue) +{ + if( (intptr_t)s1.hnd != s1hndValue || (intptr_t)(ps3->hnd) != s3hndValue ) + return FALSE; + //change the handle field of the out parameter + ps2->hnd = returnHandleValue; + return TRUE; +} + +//this takes a ref param and does not change the SH subclass field +extern "C" DLL_EXPORT BOOL __stdcall SHStructParam_Multiple2(StructWithSHFld s1, StructWithSHFld* ps2, + int s1hndValue, int s2hndValue) +{ + if( (intptr_t)s1.hnd != s1hndValue || (intptr_t)(ps2->hnd) != s2hndValue ) + return FALSE; + return TRUE; +} + +//this takes a ref param and tries to change the SH subclass field and so is expected to result in an exception +extern "C" DLL_EXPORT BOOL __stdcall SHStructParam_Multiple3(StructWithSHFld s1, StructWithSHFld* ps2, + int s1hndValue, int s2hndValue) +{ + if( (intptr_t)s1.hnd != s1hndValue || (intptr_t)(ps2->hnd) != s2hndValue ) + return FALSE; + //change the handle field of the ref parameter + ps2->hnd = returnHandleValue; + return TRUE; +} + +//////////////Methods used by RunMiscellaneousTests +/////////////////////////////////////////////////// +extern "C" DLL_EXPORT BOOL __stdcall SHArrayParam(HANDLE* ptoArr, int* ptoArrInt32s, int length) +{ + for(int i = 0; i < length; i++) + if( (intptr_t)ptoArr[i] != ptoArrInt32s[i] ) + { + printf("\t\tptoArr[%d] = %d, ptoArrInt32s[%d] = %d\n", i, (int)(intptr_t)ptoArr[i], i, ptoArrInt32s[i]); + return FALSE; + } + return TRUE; +} + +extern "C" DLL_EXPORT BOOL __stdcall SHStructArrayParam(StructWithSHFld* ptoArr, int* ptoArrInt32s, int length) +{ + for(int i = 0; i < length; i++) + if( (intptr_t)(ptoArr[i].hnd) != ptoArrInt32s[i] ) + return FALSE; + return TRUE; +} + +extern "C" DLL_EXPORT HANDLE __stdcall SHReturn() +{ + HANDLE *hnd = (HANDLE*)GlobalAlloc(0, sizeof(HANDLE)); //new HANDLE + *hnd = returnHandleValue; + return (*hnd); +} + +extern "C" DLL_EXPORT StructWithSHFld __stdcall SHReturnStruct() +{ + StructWithSHFld* ptoStruct = (StructWithSHFld*)GlobalAlloc(0, sizeof(StructWithSHFld)); + ptoStruct->hnd = returnHandleValue; + return (*ptoStruct); +} + +extern "C" DLL_EXPORT BOOL __stdcall SHStructNestedParam(StructNestedParent sn, int shndValue) +{ + if( (intptr_t)sn.snOneDeep.s.hnd != shndValue ) + return FALSE; + return TRUE; +} + +extern "C" DLL_EXPORT BOOL __stdcall SHStructParam_In2(StructWithSHArrayFld s, int* ptoArrInt32s, int length) +{ + for(int i = 0; i < length; i++) + if( (intptr_t)s.sharr[i] != ptoArrInt32s[i] ) + { + printf("\t\ts.sharr[%d] = %d, ptoArrInt32s[%d] = %d\n", i, (int)(intptr_t)s.sharr[i], i, ptoArrInt32s[i]); + return FALSE; + } + return TRUE; +} + +extern "C" DLL_EXPORT BOOL __stdcall SHMixedParam1(HANDLE sh1, HANDLE* sh2, HANDLE* sh3, StructWithSHFld s1, StructWithSHFld s2, + StructWithSHFld* s3, int sh1Value, int sh3Value, int s1fldValue, int s2fldValue, + int s3fldValue) +{ + if( (intptr_t)sh1 != sh1Value || (intptr_t)*sh3 != sh3Value || (intptr_t)s1.hnd != s1fldValue || (intptr_t)s2.hnd != s2fldValue + || (intptr_t)s3->hnd != s3fldValue ) + return FALSE; + *sh2 = returnHandleValue; //the out parameter + return TRUE; +} + +BOOL static CertifyStructWithManySHFlds(StructWithManySHFlds s, int* ptoArrInt32s) +{ + if( (intptr_t)s.hnd1 != ptoArrInt32s[0] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd1 != ptoArrInt32s[0]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd2 != ptoArrInt32s[1] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd2 != ptoArrInt32s[1]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd3 != ptoArrInt32s[2] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd3 != ptoArrInt32s[2]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd4 != ptoArrInt32s[3] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd4 != ptoArrInt32s[3]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd5 != ptoArrInt32s[4] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd5 != ptoArrInt32s[4]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd6 != ptoArrInt32s[5] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd6 != ptoArrInt32s[5]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd7 != ptoArrInt32s[6] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd7 != ptoArrInt32s[6]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd8 != ptoArrInt32s[7] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd8 != ptoArrInt32s[7]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd9 != ptoArrInt32s[8] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd9 != ptoArrInt32s[8]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd10 != ptoArrInt32s[9] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd10 != ptoArrInt32s[9]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd11 != ptoArrInt32s[10] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd11 != ptoArrInt32s[10]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd12 != ptoArrInt32s[11] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd12 != ptoArrInt32s[11]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd13 != ptoArrInt32s[12] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd13 != ptoArrInt32s[12]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd14 != ptoArrInt32s[13] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd14 != ptoArrInt32s[13]\n"); + return FALSE; + } + else if( (intptr_t)s.hnd15 != ptoArrInt32s[14] ) + { + printf("\t\tCertifyStructWithManySHFlds: s.hnd15 != ptoArrInt32s[14]\n"); + return FALSE; + } + else + return TRUE; +} + +//ptoArrInt32 is a pointer to an array of int32s---each element of which matches a fld of the struct +extern "C" DLL_EXPORT BOOL __stdcall SHStructWithManySHFldsParam_In(StructWithManySHFlds s, int* ptoArrInt32s) +{ + if ( !CertifyStructWithManySHFlds(s, ptoArrInt32s) ) + return FALSE; + s.hnd14 = returnHandleValue; //try to change a fld; should not be reflected on managed side + return TRUE; +} + +//ptoArrInt32 is a pointer to an array of int32s---each element of which matches a fld of the struct +//Ref1 will not change any of the flds +extern "C" DLL_EXPORT BOOL __stdcall SHStructWithManySHFldsParam_Ref1(StructWithManySHFlds* ptos, int* ptoArrInt32s) +{ + return CertifyStructWithManySHFlds(*ptos, ptoArrInt32s); +} + +//ptoArrInt32 is a pointer to an array of int32s---each element of which matches a fld of the struct +//Ref2 will change one of the flds +extern "C" DLL_EXPORT BOOL __stdcall SHStructWithManySHFldsParam_Ref2(StructWithManySHFlds* ptos, int* ptoArrInt32s) +{ + if( !CertifyStructWithManySHFlds(*ptos, ptoArrInt32s) ) + return FALSE; + else + (*ptos).hnd14 = returnHandleValue; //change one of the flds + return TRUE; +} + +extern "C" DLL_EXPORT int __stdcall SHInvalid_MA() +{ + // NOT REACHABLE from test because we are supposed to throw MarshalDirectionException from stubs + // This is needed to make ProjectN happy because ProjectN always do early binding + return 0; +} + +extern "C" DLL_EXPORT int __stdcall SHInvalid_retMA() +{ + // NOT REACHABLE from test because we are supposed to throw MarshalDirectionException from stubs + // This is needed to make ProjectN happy because ProjectN always do early binding + return 0; +} diff --git a/tests/src/Interop/PInvoke/SafeHandles/SigDiff/SigDiffTest.cs b/tests/src/Interop/PInvoke/SafeHandles/SigDiff/SigDiffTest.cs new file mode 100644 index 0000000..c67673b --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/SigDiff/SigDiffTest.cs @@ -0,0 +1,176 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using SafeHandlesTests; +using TestLibrary; + +public class SHTester_SigDiff +{ + public static int Main() + { + try + { + RunSHParamTests(); + RunSHStructParamTests(); + + return 100; + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + } //end of Main + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_In([In]SafeHandle sh1, Int32 sh1Value); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Out(out SafeHandle sh1); + + [DllImport("PInvoke_SafeHandle", PreserveSig = false, SetLastError = true)] + public static extern SafeHandle SHParam_OutRetVal(); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Ref(ref SafeHandle sh1, Int32 sh1Value); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHParam_Multiple([In]SafeHandle sh1, out SafeHandle sh2, ref SafeHandle sh3, Int32 sh1Value, Int32 sh3Value); + + /// + ///passing SH parameters to unmanaged code in various combinations and forms; + ///it uses the PInvoke signatures defined above it + ///1- passing SH parameters individually in separate methods (In, out, ref) + ///2- passing SH parameters in combination in the same method + /// + public static void RunSHParamTests() + { + Console.WriteLine("\nRunSHParamTests():"); + + //1- passing SH parameters individually in separate methods (In, out, ref) + + //get a new SH + SafeHandle hnd = Helper.NewSFH(); //NOTE that this is equivalent to SafeHandle = SafeFileHandle.CreateFile(); + Int32 hndInt32 = Helper.SHInt32(hnd); //get the 32-bit value associated with hnd + + Console.WriteLine("Testing SHParam_In..."); + Assert.IsTrue(SHParam_In(hnd, hndInt32), "FAILED! SHParam_In did not receive hnd as expected."); + //check that the value of the HANDLE did not change + Assert.IsFalse(Helper.IsChanged(hnd), "FAILED! SHParam_In did not return hnd as expected."); + + Console.WriteLine("Testing SHParam_Out..."); + Assert.Throws(() => SHParam_Out(out hnd), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHParam_OutRetVal..."); + hnd = null; + Assert.Throws(() => hnd = SHParam_OutRetVal(), "FAILED! Exception not thrown."); + + hnd = Helper.NewSFH(); //get a new value + hndInt32 = Helper.SHInt32(hnd); + Console.WriteLine("Testing SHParam_Ref..."); + Assert.Throws(() => SHParam_Ref(ref hnd, hndInt32), "FAILED! Exception not thrown."); + + //2- passing SH parameters in combination in the same method + + //initialize parameters + SafeHandle hnd1 = Helper.NewSFH(); + Int32 hnd1Int32 = Helper.SHInt32(hnd1); //get the 32-bit value associated with hnd1 + + SafeHandle hnd2 = null; //out parameter + + SafeHandle hnd3 = Helper.NewSFH(); + Int32 hnd3Int32 = Helper.SHInt32(hnd3); //get the 32-bit value associated with hnd3 + + Console.WriteLine("Testing SHParam_Multiple..."); + Assert.Throws(() => SHParam_Multiple(hnd1, out hnd2, ref hnd3, hnd1Int32, hnd3Int32), "FAILED! Exception not thrown."); + } //end of static method RunParamTests + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_In([In]StructWithBaseSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Out(out StructWithBaseSHFld s); + + [DllImport("PInvoke_SafeHandle", PreserveSig = false, SetLastError = true)] + public static extern StructWithBaseSHFld SHStructParam_OutRetVal(); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Ref1(ref StructWithBaseSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Ref2(ref StructWithBaseSHFld s, Int32 shfldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple1([In]StructWithBaseSHFld sh1, out StructWithBaseSHFld sh2, + ref StructWithBaseSHFld sh3, Int32 sh1fldValue, Int32 sh2fldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple2([In]StructWithBaseSHFld sh1, ref StructWithBaseSHFld sh2, Int32 sh1fldValue, Int32 sh2fldValue); + + [DllImport("PInvoke_SafeHandle", SetLastError = true)] + public static extern bool SHStructParam_Multiple3([In]StructWithBaseSHFld sh1, ref StructWithBaseSHFld sh2, Int32 sh1fldValue, Int32 sh2fldValue); + + /// + ///passing structures (with SH fields) as parameters in various combinations and forms; + ///it uses the PInvoke signatures defined above it + ///1- passing structures (In, out, ref) (with SH fields) individually in separate methods + ///2- passing structures (In, out, ref) (with SH fields) in combination in the same method + /// + public static void RunSHStructParamTests() + { + Console.WriteLine("\nRunSHStructParamTests():"); + + //1- passing structures (In, out, ref) (with SH fields) individually in separate methods + + //initialize a new StructWithBaseSHFld + StructWithBaseSHFld s = new StructWithBaseSHFld(); + s.hnd = Helper.NewSFH(); //get a new SH + Int32 hndInt32 = Helper.SHInt32(s.hnd); //get the 32-bit value associated with s.hnd + + Console.WriteLine("Testing SHStructParam_In..."); + Assert.IsTrue(SHStructParam_In(s, hndInt32), "FAILED! SHStructParam_In did not receive param as expected."); + Assert.IsFalse(Helper.IsChanged(s.hnd), "FAILED! SHStructParam_In did not return param as expected."); + + Console.WriteLine("Testing SHStructParam_Out..."); + Assert.Throws(() => SHStructParam_Out(out s), "FAILED! Exception not thrown."); + + Console.WriteLine("Testing SHStructParam_OutRetVal..."); + Assert.Throws(() => s = SHStructParam_OutRetVal(), "FAILED! Exception not thrown."); + + s.hnd = Helper.NewSFH(); //get a new SH + hndInt32 = Helper.SHInt32(s.hnd); //get the 32-bit value associated with s.hnd + Console.WriteLine("Testing SHStructParam_Ref1 (does not change value of handle field)..."); + Assert.IsTrue(SHStructParam_Ref1(ref s, hndInt32), "FAILED! SHStructParam_Ref1 did not receive param as expected."); + //check that the value of the HANDLE field is not changed + Assert.IsFalse(Helper.IsChanged(s.hnd), "FAILED! SHStructParam_Ref1 did not return param as expected."); + + Console.WriteLine("Testing SHStructParam_Ref2 (does change value of handle field)..."); + Assert.Throws(() => SHStructParam_Ref2(ref s, hndInt32), "FAILED! Exception not thrown."); + + //2- passing structures (In, out, ref) (with SH fields) in combination in the same method + + //initialize parameters + StructWithBaseSHFld s1 = new StructWithBaseSHFld(); + s1.hnd = Helper.NewSFH(); + Int32 hnd1Int32 = Helper.SHInt32(s1.hnd); //get the 32-bit value associated with s1.hnd + StructWithBaseSHFld s2; //out parameter + StructWithBaseSHFld s3 = new StructWithBaseSHFld(); + s3.hnd = Helper.NewSFH(); + Int32 hnd3Int32 = Helper.SHInt32(s3.hnd); //get the 32-bit value associated with s3.hnd + + Console.WriteLine("Testing SHStructParam_Multiple1 (takes an out struct as one of the params and so is expected to result in an exception)..."); + Assert.Throws(() => SHStructParam_Multiple1(s1, out s2, ref s3, hnd1Int32, hnd3Int32), "FAILED! Exception not thrown."); + + s3.hnd = Helper.NewSFH(); + hnd3Int32 = Helper.SHInt32(s3.hnd); //get the 32-bit value associated with s3.hnd + Console.WriteLine("Testing SHStructParam_Multiple2 (takes a ref struct as one of the params)..."); + Assert.IsTrue(SHStructParam_Multiple2(s1, ref s3, hnd1Int32, hnd3Int32), "FAILED! SHStructParam_Multiple2 did not receive parameter(s) as expected."); + Assert.IsFalse(Helper.IsChanged(s1.hnd) || Helper.IsChanged(s3.hnd), "FAILED! SHStructParam_Multiple2 did not return handles as expected."); + + Console.WriteLine("Testing SHStructParam_Multiple3 (takes a ref struct as one of the params and changes its handle field and so is expected to result in an exception)..."); + Assert.Throws(() => SHStructParam_Multiple3(s1, ref s3, hnd1Int32, hnd3Int32), "FAILED! Exception not thrown."); + } +} \ No newline at end of file diff --git a/tests/src/Interop/PInvoke/SafeHandles/SigDiff/SigDiffTest.csproj b/tests/src/Interop/PInvoke/SafeHandles/SigDiff/SigDiffTest.csproj new file mode 100644 index 0000000..67a5e53 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/SigDiff/SigDiffTest.csproj @@ -0,0 +1,38 @@ + + + + + Debug + AnyCPU + SigDiffTest + 2.0 + {F1E66554-8C8E-4141-85CF-D0CD6A0CD0B0} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC + + true + true + + + + + + + False + + + + + + + + + + + + + + + diff --git a/tests/src/Interop/PInvoke/SafeHandles/StructDefs.cs b/tests/src/Interop/PInvoke/SafeHandles/StructDefs.cs new file mode 100644 index 0000000..a50f9ec --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/StructDefs.cs @@ -0,0 +1,331 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using SafeHandlesTests; + +#pragma warning disable 618 +namespace SafeHandlesTests{ + [StructLayout(LayoutKind.Sequential)] + public struct StructWithSHFld + { + public SafeFileHandle hnd; //SH subclass field + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructWithBaseSHFld + { + public SafeHandle hnd; //SH field + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructWithChildSHFld + { + public ChildSafeFileHandle hnd; //SafeFileHandle subclass field + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructNestedParent + { + public StructNestedOneDeep snOneDeep; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructNestedOneDeep + { + public StructWithSHFld s; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructWithSHArrayFld + { + public SafeFileHandle[] sharr; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructWithManySHFlds + { + public SafeHandle hnd1; + public SafeFileHandle hnd2; + public ChildSafeFileHandle hnd3; + + public SafeHandle hnd4; + public SafeFileHandle hnd5; + public ChildSafeFileHandle hnd6; + + public SafeHandle hnd7; + public SafeFileHandle hnd8; + public ChildSafeFileHandle hnd9; + + public SafeHandle hnd10; + public SafeFileHandle hnd11; + public ChildSafeFileHandle hnd12; + + public SafeHandle hnd13; + public SafeFileHandle hnd14; + public ChildSafeFileHandle hnd15; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructWithObjFld + { + //the MA attribute indicates that obj is to be marshaled as a VARIANT + [MarshalAs(UnmanagedType.Struct)] + public Object obj; + } + + ////The following Structure definitions are for negative testing purposes + /// + [StructLayout(LayoutKind.Sequential)] + public struct StructMA1 + { + [MarshalAs(UnmanagedType.AnsiBStr)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA2 + { + [MarshalAs(UnmanagedType.AsAny)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA3 + { + [MarshalAs(UnmanagedType.Bool)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA4 + { + [MarshalAs(UnmanagedType.BStr)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA5 + { + [MarshalAs(UnmanagedType.ByValArray)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA6 + { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA7 + { + [MarshalAs(UnmanagedType.Currency)] + public SafeFileHandle hnd; + } + + //NOTE: Specified unmanaged type also needs MarshalType or MarshalTypeRef which indicates the custom marshaler + //[StructLayout(LayoutKind.Sequential)] + //public struct StructMA8 + //{ + // [MarshalAs(UnmanagedType.CustomMarshaler)] + // public SafeFileHandle hnd; + //} + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA9 + { + [MarshalAs(UnmanagedType.Error)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA10 + { + [MarshalAs(UnmanagedType.FunctionPtr)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA11 + { + [MarshalAs(UnmanagedType.I1)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA12 + { + [MarshalAs(UnmanagedType.I2)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA13 + { + [MarshalAs(UnmanagedType.I4)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA14 + { + [MarshalAs(UnmanagedType.I8)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA15 + { + [MarshalAs(UnmanagedType.IDispatch)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA16 + { + [MarshalAs(UnmanagedType.Interface)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA17 + { + [MarshalAs(UnmanagedType.IUnknown)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA18 + { + [MarshalAs(UnmanagedType.LPArray)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA19 + { + [MarshalAs(UnmanagedType.LPStr)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA20 + { + [MarshalAs(UnmanagedType.LPStruct)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA21 + { + [MarshalAs(UnmanagedType.LPTStr)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA22 + { + [MarshalAs(UnmanagedType.LPWStr)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA23 + { + [MarshalAs(UnmanagedType.R4)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA24 + { + [MarshalAs(UnmanagedType.R8)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA25 + { + [MarshalAs(UnmanagedType.SafeArray)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA26 + { + [MarshalAs(UnmanagedType.Struct)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA27 + { + [MarshalAs(UnmanagedType.SysInt)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA28 + { + [MarshalAs(UnmanagedType.SysUInt)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA29 + { + [MarshalAs(UnmanagedType.TBStr)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA30 + { + [MarshalAs(UnmanagedType.U1)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA31 + { + [MarshalAs(UnmanagedType.U2)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA32 + { + [MarshalAs(UnmanagedType.U4)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA33 + { + [MarshalAs(UnmanagedType.U8)] + public SafeFileHandle hnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StructMA34 + { + [MarshalAs(UnmanagedType.VariantBool)] + public SafeFileHandle hnd; + } + + //NOTE: This unmanagedtype is not valid for fields + //[StructLayout(LayoutKind.Sequential)] + //public struct StructMA35 + //{ + // [MarshalAs(UnmanagedType.VBByRefStr)] + // public SafeFileHandle hnd; + //} +} +#pragma warning restore 618 + + + diff --git a/tests/src/Interop/PInvoke/SafeHandles/StructDefs.h b/tests/src/Interop/PInvoke/SafeHandles/StructDefs.h new file mode 100644 index 0000000..f96b089 --- /dev/null +++ b/tests/src/Interop/PInvoke/SafeHandles/StructDefs.h @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +struct StructWithSHFld +{ + HANDLE hnd; +}; + +struct StructNestedOneDeep +{ + StructWithSHFld s; +}; + +struct StructNestedParent +{ + StructNestedOneDeep snOneDeep; +}; + +struct StructWithSHArrayFld +{ + HANDLE* sharr; +}; + +struct StructWithManySHFlds +{ + HANDLE hnd1; + HANDLE hnd2; + HANDLE hnd3; + + HANDLE hnd4; + HANDLE hnd5; + HANDLE hnd6; + + HANDLE hnd7; + HANDLE hnd8; + HANDLE hnd9; + + HANDLE hnd10; + HANDLE hnd11; + HANDLE hnd12; + + HANDLE hnd13; + HANDLE hnd14; + HANDLE hnd15; +}; + +struct StructMAIntf +{ + IDispatch* ptoIntf; +}; + +struct StructWithVARIANTFld +{ + VARIANT v; +}; \ No newline at end of file