Improved parameters on LibLoaderApi functions. Converted SafeResourceDataHandle to HRSRCDATA since it does not need disposal.

pull/60/head
David Hall 2019-06-19 10:06:37 -06:00
parent 6595d81b92
commit 9914ab53c1
4 changed files with 252 additions and 127 deletions

View File

@ -1176,7 +1176,7 @@ namespace Vanara.PInvoke
[PInvokeData("Winbase.h", MSDNShortId = "ms648044")]
[Obsolete]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeResource([In] SafeResourceDataHandle hglbResource);
public static extern bool FreeResource([In] HRSRCDATA hglbResource);
/// <summary>
/// <para>
@ -1250,7 +1250,7 @@ namespace Vanara.PInvoke
public static string GetModuleFileName(HINSTANCE hModule)
{
var buffer = new StringBuilder(MAX_PATH);
Label_000B:
Label_000B:
var num1 = GetModuleFileName(hModule, buffer, (uint)buffer.Capacity);
if (num1 == 0)
throw new Win32Exception();
@ -1324,7 +1324,7 @@ namespace Vanara.PInvoke
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("Winbase.h", MSDNShortId = "ms683200")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG dwFlags, [Optional] string lpModuleName, out IntPtr phModule);
public static extern bool GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG dwFlags, [Optional] string lpModuleName, out HINSTANCE phModule);
/// <summary>Retrieves the address of an exported function or variable from the specified dynamic-link library (DLL).</summary>
/// <param name="hModule">
@ -1743,7 +1743,7 @@ namespace Vanara.PInvoke
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
[PInvokeData("Winbase.h", MSDNShortId = "ms648046")]
[SuppressUnmanagedCodeSecurity]
public static extern SafeResourceDataHandle LoadResource(HINSTANCE hModule, HRSRC hResInfo);
public static extern HRSRCDATA LoadResource(HINSTANCE hModule, HRSRC hResInfo);
/// <summary>Retrieves a pointer to the specified resource in memory.</summary>
/// <param name="hResData">
@ -1764,16 +1764,12 @@ namespace Vanara.PInvoke
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("Winbase.h", MSDNShortId = "ms648047")]
[SuppressUnmanagedCodeSecurity]
public static extern IntPtr LockResource(SafeResourceDataHandle hResData);
public static extern IntPtr LockResource(HRSRCDATA hResData);
/// <summary>
/// <para>Determines whether the specified function in a delay-loaded DLL is available on the system.</para>
/// </summary>
/// <summary>Determines whether the specified function in a delay-loaded DLL is available on the system.</summary>
/// <param name="hParentModule">
/// <para>
/// A handle to the calling module. Desktop applications can use the GetModuleHandle or GetModuleHandleEx function to get this
/// handle. Windows Store apps should set this parameter to .
/// </para>
/// handle. Windows Store apps should set this parameter to <c>static_cast&lt;HMODULE&gt;(&amp;__ImageBase)</c>.
/// </param>
/// <param name="lpDllName">
/// <para>The file name of the delay-loaded DLL that exports the specified function. This parameter is case-insensitive.</para>
@ -1782,17 +1778,11 @@ namespace Vanara.PInvoke
/// than kernel32.dll.
/// </para>
/// </param>
/// <param name="lpProcName">
/// <para>The name of the function to query. This parameter is case-sensitive.</para>
/// </param>
/// <param name="Reserved">
/// <para>This parameter is reserved and must be zero (0).</para>
/// </param>
/// <param name="lpProcName">The name of the function to query. This parameter is case-sensitive.</param>
/// <param name="Reserved">This parameter is reserved and must be zero (0).</param>
/// <returns>
/// <para>
/// TRUE if the specified function is available on the system. If the specified function is not available on the system, this
/// function returns FALSE. To get extended error information, call GetLastError.
/// </para>
/// </returns>
/// <remarks>
/// <para>
@ -1822,12 +1812,12 @@ namespace Vanara.PInvoke
/// available on the system.
/// </para>
/// </remarks>
// https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi2/nf-libloaderapi2-queryoptionaldelayloadedapi BOOL
// QueryOptionalDelayLoadedAPI( HMODULE hParentModule, LPCSTR lpDllName, LPCSTR lpProcName, DWORD Reserved );
[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Ansi)]
// https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi2/nf-libloaderapi2-queryoptionaldelayloadedapi
// BOOL QueryOptionalDelayLoadedAPI( HMODULE hParentModule, LPCSTR lpDllName, LPCSTR lpProcName, DWORD Reserved );
[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
[PInvokeData("libloaderapi2.h", MSDNShortId = "43690689-4372-48ae-ac6d-230250f05f7c")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool QueryOptionalDelayLoadedAPI(HINSTANCE hParentModule, string lpDllName, string lpProcName, uint Reserved = 0);
public static extern bool QueryOptionalDelayLoadedAPI(HINSTANCE hParentModule, [MarshalAs(UnmanagedType.LPStr)] string lpDllName, [MarshalAs(UnmanagedType.LPStr)] string lpProcName, uint Reserved = 0);
/// <summary>Removes a directory that was added to the process DLL search path by using <c>AddDllDirectory</c>.</summary>
/// <param name="Cookie">The cookie returned by <c>AddDllDirectory</c> when the directory was added to the search path.</param>
@ -1956,6 +1946,54 @@ namespace Vanara.PInvoke
public IntPtr DangerousGetHandle() => handle;
}
/// <summary>Provides a handle to resource data.</summary>
[StructLayout(LayoutKind.Sequential)]
public struct HRSRCDATA : IHandle
{
private IntPtr handle;
/// <summary>Initializes a new instance of the <see cref="HRSRCDATA"/> struct.</summary>
/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
public HRSRCDATA(IntPtr preexistingHandle) => handle = preexistingHandle;
/// <summary>Returns an invalid handle by instantiating a <see cref="HRSRCDATA"/> object with <see cref="IntPtr.Zero"/>.</summary>
public static HRSRCDATA NULL => new HRSRCDATA(IntPtr.Zero);
/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
public bool IsNull => handle == IntPtr.Zero;
/// <summary>Performs an explicit conversion from <see cref="HRSRCDATA"/> to <see cref="IntPtr"/>.</summary>
/// <param name="h">The handle.</param>
/// <returns>The result of the conversion.</returns>
public static explicit operator IntPtr(HRSRCDATA h) => h.handle;
/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="HRSRCDATA"/>.</summary>
/// <param name="h">The pointer to a handle.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator HRSRCDATA(IntPtr h) => new HRSRCDATA(h);
/// <summary>Implements the operator !=.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(HRSRCDATA h1, HRSRCDATA h2) => !(h1 == h2);
/// <summary>Implements the operator ==.</summary>
/// <param name="h1">The first handle.</param>
/// <param name="h2">The second handle.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(HRSRCDATA h1, HRSRCDATA h2) => h1.Equals(h2);
/// <inheritdoc/>
public override bool Equals(object obj) => obj is HRSRCDATA h ? handle == h.handle : false;
/// <inheritdoc/>
public override int GetHashCode() => handle.GetHashCode();
/// <inheritdoc/>
public IntPtr DangerousGetHandle() => handle;
}
/// <summary>Provides a <see cref="SafeHandle"/> to a that releases a created HINSTANCE instance at disposal using FreeLibrary.</summary>
[PInvokeData("LibLoaderAPI.h")]
public class SafeHINSTANCE : SafeHANDLE
@ -1993,25 +2031,5 @@ namespace Vanara.PInvoke
/// <inheritdoc/>
protected override bool InternalReleaseHandle() => FreeLibrary(this);
}
/// <summary>Represents a loaded resource handle.</summary>
/// <seealso cref="Vanara.InteropServices.GenericSafeHandle"/>
public class SafeResourceDataHandle : SafeHANDLE
{
private IntPtr bptr;
/// <summary>Initializes a new instance of the <see cref="SafeResourceDataHandle"/> class.</summary>
public SafeResourceDataHandle() : base() { }
/// <summary>Initializes a new instance of the <see cref="SafeResourceDataHandle"/> class.</summary>
/// <param name="handle">The handle.</param>
public SafeResourceDataHandle(IntPtr handle) : base(handle, false) { }
/// <summary>Gets the pointer to the memory of the resource.</summary>
public IntPtr LockedPtr => bptr != null ? bptr : (bptr = LockResource(this));
/// <inheritdoc/>
protected override bool InternalReleaseHandle() => throw new NotImplementedException();
}
}
}

View File

@ -46,6 +46,7 @@
<Compile Include="AppModelTests.cs" />
<Compile Include="InterlockedApiTests.cs" />
<Compile Include="InteropServices\SafeLocalHandleTests.cs" />
<Compile Include="LibLoaderApiTests.cs" />
<Compile Include="JobApiTests.cs" />
<Compile Include="IoApiSetTests.cs" />
<Compile Include="Kernel32Tests.cs" />

View File

@ -13,8 +13,6 @@ namespace Vanara.PInvoke.Tests
[TestFixture]
public class Kernel32Tests
{
internal const string badlibfn = @"C:\Windows\System32\ole3.dll";
internal const string libfn = @"ole32.dll";
internal const string tmpstr = @"Temporary";
internal const string fn = @"C:\Temp\help.ico";
@ -75,18 +73,6 @@ namespace Vanara.PInvoke.Tests
File.Delete(fn);
}
[Test]
public void EnumResourceNamesTest()
{
using (var hLib = LoadLibraryEx(@"C:\Windows\System32\en-US\aclui.dll.mui", IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE))
{
var l = EnumResourceNamesEx(hLib, ResourceType.RT_STRING);
Assert.That(l.Count, Is.GreaterThan(0));
foreach (var resourceName in l)
Assert.That(resourceName.ToString(), Has.Length.GreaterThan(0));
}
}
[Test]
public void FileTimeToSystemTimeTest()
{
@ -99,16 +85,6 @@ namespace Vanara.PInvoke.Tests
Assert.That(dt.Day, Is.EqualTo(st.wDay));
}
[Test]
public void FindResourceTest()
{
using (var hLib = LoadLibraryEx(@"comctl32.dll", IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE))
{
var ptr = FindResource(hLib, 65, ResourceType.RT_STRING);
Assert.That(ptr, Is.Not.EqualTo(IntPtr.Zero));
}
}
[Test]
public void GetCompressedFileSizeTest()
{
@ -150,28 +126,6 @@ namespace Vanara.PInvoke.Tests
Assert.That(i.deviceId == GAMING_DEVICE_DEVICE_ID.GAMING_DEVICE_DEVICE_ID_NONE);
}
[Test]
public void GetModuleFileNameTest()
{
const string fn = @"C:\Windows\System32\tzres.dll";
using (var hLib = LoadLibrary(fn))
{
var f = GetModuleFileName(hLib);
Assert.That(f, Is.SamePath(fn));
}
}
[Test]
public void GetProcAddressTest()
{
const string fn = @"C:\Windows\System32\kernel32.dll";
using (var hLib = LoadLibrary(fn))
{
var a = GetProcAddress(hLib, "GetNativeSystemInfo");
Assert.That(a, Is.Not.EqualTo(IntPtr.Zero));
}
}
[Test]
public void GlobalLockTest()
{
@ -188,44 +142,6 @@ namespace Vanara.PInvoke.Tests
}
}
[Test]
public void LoadLibraryTest()
{
var hlib = LoadLibrary(badlibfn);
Assert.That((HINSTANCE)hlib, Is.EqualTo(HINSTANCE.NULL));
Assert.That(Marshal.GetLastWin32Error(), Is.Not.Zero);
hlib = LoadLibrary(libfn);
Assert.That((HINSTANCE)hlib, Is.Not.EqualTo(HINSTANCE.NULL));
}
[Test]
public void LoadLibraryExTest()
{
var hlib = LoadLibraryEx(badlibfn, IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_DATAFILE);
Assert.That((HINSTANCE)hlib, Is.EqualTo(HINSTANCE.NULL));
Assert.That(Marshal.GetLastWin32Error(), Is.Not.Zero);
hlib = LoadLibraryEx(libfn, IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_DATAFILE);
Assert.That((HINSTANCE)hlib, Is.Not.EqualTo(HINSTANCE.NULL));
}
[Test]
public void LoadResourceTest()
{
using (var hlib = LoadLibraryEx("ole32.dll", IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_DATAFILE))
{
var hres = FindResource(hlib, 4, ResourceType.RT_CURSOR);
Assert.That(hres, Is.Not.EqualTo(IntPtr.Zero));
var sz = SizeofResource(hlib, hres);
Assert.That(sz, Is.GreaterThan(0));
var pres = LoadResource(hlib, hres);
Assert.That(pres, Is.Not.EqualTo(IntPtr.Zero));
var pmem = LockResource(pres);
Assert.That(pmem, Is.Not.EqualTo(IntPtr.Zero));
}
}
[Test]
public void QueryDosDeviceTest()
{

View File

@ -0,0 +1,190 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Vanara.InteropServices;
using static Vanara.PInvoke.AdvApi32;
using static Vanara.PInvoke.Kernel32;
namespace Vanara.PInvoke.Tests
{
[TestFixture]
public class LibLoaderApiTests
{
internal const string badlibfn = @"C:\Windows\System32\ole3.dll";
internal const string libfn = @"ole32.dll";
const string resFile = @"C:\Windows\en-US\regedit.exe.mui";
[Test]
public void AddRemoveDllDirectoryTest()
{
var ptr = AddDllDirectory(@"C:\Temp");
Assert.That(ptr, Is.Not.EqualTo(IntPtr.Zero));
Assert.That(RemoveDllDirectory(ptr), Is.True);
}
[Test]
public void EnumResourceLanguagesExTest()
{
using (var hLib = LoadLibraryEx(resFile, IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE))
{
IList<ushort> l = null;
Assert.That(() => l = EnumResourceLanguagesEx(hLib, ResourceType.RT_STRING, 2), Throws.Nothing);
Assert.That(l.Count, Is.GreaterThan(0));
TestContext.WriteLine(string.Join(" : ", l));
}
}
[Test]
public void EnumResourceTypesExTest()
{
using (var hLib = LoadLibraryEx(resFile, IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE))
{
IList<ResourceId> l = null;
Assert.That(() => l = EnumResourceTypesEx(hLib), Throws.Nothing);
Assert.That(l.Count, Is.GreaterThan(0));
TestContext.WriteLine(string.Join(" : ", l.Select(i => (ResourceType)i.id)));
}
}
[Test]
public void EnumResourceNamesTest()
{
using (var hLib = LoadLibraryEx(resFile, IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE))
{
IList<ResourceId> l = null;
Assert.That(() => l = EnumResourceNamesEx(hLib, ResourceType.RT_STRING), Throws.Nothing);
Assert.That(l.Count, Is.GreaterThan(0));
foreach (var resourceName in l)
Assert.That(resourceName.ToString(), Has.Length.GreaterThan(0));
TestContext.WriteLine(string.Join(" : ", l.Select(i => i.id)));
}
}
[Test]
public void FindResourceTest()
{
using (var hLib = LoadLibraryEx(@"comctl32.dll", IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE))
{
var ptr = (IntPtr)FindResource(hLib, 65, ResourceType.RT_STRING);
Assert.That(ptr, Is.Not.EqualTo(IntPtr.Zero));
}
}
[Test]
public void FindResourceExTest()
{
using (var hLib = LoadLibraryEx(@"comctl32.dll", IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE))
{
var ptr = (IntPtr)FindResourceEx(hLib, 65, ResourceType.RT_STRING, 1033);
Assert.That(ptr, Is.Not.EqualTo(IntPtr.Zero));
}
}
[Test]
public void FindStringOrdinalTest()
{
const string src = "How do you do today?";
Assert.That(FindStringOrdinal(SEARCH_FLAGS.FIND_ENDSWITH, src, src.Length, "DAY?", 4, true), Is.GreaterThan(0));
Assert.That(FindStringOrdinal(SEARCH_FLAGS.FIND_FROMEND, src, src.Length, "do", 2, false), Is.EqualTo(11));
Assert.That(FindStringOrdinal(SEARCH_FLAGS.FIND_FROMSTART, src, src.Length, "do", 2, false), Is.EqualTo(4));
Assert.That(FindStringOrdinal(SEARCH_FLAGS.FIND_STARTSWITH, src, src.Length, "how", 2, false), Is.EqualTo(-1));
Assert.That(FindStringOrdinal(SEARCH_FLAGS.FIND_STARTSWITH, src, src.Length, "how", 2, true), Is.EqualTo(0));
}
[Test]
public void FreeLibraryAndExitThreadTest()
{
var t = new System.Threading.Thread(ThreadFunc);
t.Start();
t.Join();
void ThreadFunc()
{
const string fn = @"C:\Windows\System32\kernel32.dll";
using (var hLib = LoadLibrary(fn))
{
FreeLibraryAndExitThread(hLib, 20);
hLib.SetHandleAsInvalid();
}
}
}
[Test]
public void GetModuleFileNameHandleTest()
{
const string fn = @"C:\Windows\System32\tzres.dll";
using (var hLib = LoadLibrary(fn))
{
var f = GetModuleFileName(hLib);
Assert.That(f, Is.SamePath(fn));
var hmod = GetModuleHandle(fn);
Assert.That(hLib.Equals(hmod), Is.True);
Assert.That(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG.GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, fn, out hmod), Is.True);
Assert.That(hLib.Equals(hmod), Is.True);
}
}
[Test]
public void GetProcAddressTest()
{
const string fn = @"C:\Windows\System32\kernel32.dll";
using (var hLib = LoadLibrary(fn))
{
var a = GetProcAddress(hLib, "GetNativeSystemInfo");
Assert.That(a, Is.Not.EqualTo(IntPtr.Zero));
}
}
[Test]
public void LoadLibraryTest()
{
using (var hlib = LoadLibrary(badlibfn))
{
Assert.That((HINSTANCE)hlib, Is.EqualTo(HINSTANCE.NULL));
Assert.That(Marshal.GetLastWin32Error(), Is.Not.Zero);
}
using (var hlib = LoadLibrary(libfn))
Assert.That((HINSTANCE)hlib, Is.Not.EqualTo(HINSTANCE.NULL));
}
[Test]
public void LoadLibraryExTest()
{
using (var hlib = LoadLibraryEx(badlibfn, IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_DATAFILE))
{
Assert.That((HINSTANCE)hlib, Is.EqualTo(HINSTANCE.NULL));
Assert.That(Marshal.GetLastWin32Error(), Is.Not.Zero);
}
using (var hlib = LoadLibraryEx(libfn, IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_DATAFILE))
Assert.That((HINSTANCE)hlib, Is.Not.EqualTo(HINSTANCE.NULL));
}
[Test]
public void FindLoadLockSizeofResourceTest()
{
using (var hlib = LoadLibraryEx("ole32.dll", IntPtr.Zero, LoadLibraryExFlags.LOAD_LIBRARY_AS_DATAFILE))
{
var hres = FindResource(hlib, 4, ResourceType.RT_CURSOR);
Assert.That(hres, Is.Not.EqualTo(IntPtr.Zero));
var sz = SizeofResource(hlib, hres);
Assert.That(sz, Is.GreaterThan(0));
var pres = LoadResource(hlib, hres);
Assert.That((IntPtr)pres, Is.Not.EqualTo(IntPtr.Zero));
var pmem = LockResource(pres);
Assert.That(pmem, Is.Not.EqualTo(IntPtr.Zero));
}
}
[Test]
public void QueryOptionalDelayLoadedAPITest()
{
Assert.That(() => QueryOptionalDelayLoadedAPI(GetModuleHandle(), "kernel32.dll", "GetNativeSystemInfo"), Throws.Nothing);
}
}
}