// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. namespace WixToolset.Harvesters { using System; using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; using Wix = WixToolset.Harvesters.Serialize; /// /// Harvest WiX authoring from a native DLL file. /// public sealed class DllHarvester { /// /// Harvest the registry values written by calling DllRegisterServer on the specified file. /// /// The file to harvest registry values from. /// The harvested registry values. public Wix.RegistryValue[] HarvestRegistryValues(string file) { // load the DLL NativeMethods.LoadLibrary(file); using (RegistryHarvester registryHarvester = new RegistryHarvester(true)) { try { DynamicPInvoke(file, "DllRegisterServer", typeof(int), null, null); return registryHarvester.HarvestRegistry(); } catch (TargetInvocationException e) { e.Data["file"] = file; throw; } } } /// /// Dynamically PInvokes into a DLL. /// /// Dynamic link library containing the entry point. /// Entry point into dynamic link library. /// Return type of entry point. /// Type of parameters to entry point. /// Value of parameters to entry point. /// Value from invoked code. private static object DynamicPInvoke(string dll, string entryPoint, Type returnType, Type[] parameterTypes, object[] parameterValues) { #if NETCOREAPP throw new PlatformNotSupportedException(); #else AssemblyName assemblyName = new AssemblyName(); assemblyName.Name = "wixTempAssembly"; AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("wixTempModule"); MethodBuilder dynamicMethod = dynamicModule.DefinePInvokeMethod(entryPoint, dll, MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.PinvokeImpl, CallingConventions.Standard, returnType, parameterTypes, CallingConvention.Winapi, CharSet.Ansi); dynamicModule.CreateGlobalFunctions(); MethodInfo methodInfo = dynamicModule.GetMethod(entryPoint); return methodInfo.Invoke(null, parameterValues); #endif } /// /// Native methods for loading libraries. /// private sealed class NativeMethods { private const UInt32 LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008; /// /// Load a DLL library. /// /// The file name of the executable module. /// If the function succeeds, the return value is a handle to the mapped executable module. internal static IntPtr LoadLibrary(string file) { IntPtr dllHandle = LoadLibraryEx(file, IntPtr.Zero, NativeMethods.LOAD_WITH_ALTERED_SEARCH_PATH); if (IntPtr.Zero == dllHandle) { int lastError = Marshal.GetLastWin32Error(); throw new Exception(String.Format("Unable to load file: {0}, error: {1}", file, lastError)); } return dllHandle; } /// /// Maps the specified executable module into the address space of the calling process. /// /// The file name of the executable module. /// This parameter is reserved for future use. It must be NULL. /// Action to take when loading the module. /// If the function succeeds, the return value is a handle to the mapped executable module. [DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr LoadLibraryEx(string file, IntPtr fileHandle, UInt32 flags); } } }