| 1 | // 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. |
| 2 | |
| 3 | namespace WixToolset.Harvesters |
| 4 | { |
| 5 | using System; |
| 6 | using System.Reflection; |
| 7 | using System.Reflection.Emit; |
| 8 | using System.Runtime.InteropServices; |
| 9 | using Wix = WixToolset.Harvesters.Serialize; |
| 10 | |
| 11 | /// <summary> |
| 12 | /// Harvest WiX authoring from a native DLL file. |
| 13 | /// </summary> |
| 14 | public sealed class DllHarvester |
| 15 | { |
| 16 | /// <summary> |
| 17 | /// Harvest the registry values written by calling DllRegisterServer on the specified file. |
| 18 | /// </summary> |
| 19 | /// <param name="file">The file to harvest registry values from.</param> |
| 20 | /// <returns>The harvested registry values.</returns> |
| 21 | public Wix.RegistryValue[] HarvestRegistryValues(string file) |
| 22 | { |
| 23 | // load the DLL |
| 24 | NativeMethods.LoadLibrary(file); |
| 25 | |
| 26 | using (RegistryHarvester registryHarvester = new RegistryHarvester(true)) |
| 27 | { |
| 28 | try |
| 29 | { |
| 30 | DynamicPInvoke(file, "DllRegisterServer", typeof(int), null, null); |
| 31 | |
| 32 | return registryHarvester.HarvestRegistry(); |
| 33 | } |
| 34 | catch (TargetInvocationException e) |
| 35 | { |
| 36 | e.Data["file"] = file; |
| 37 | throw; |
| 38 | } |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | /// <summary> |
| 43 | /// Dynamically PInvokes into a DLL. |
| 44 | /// </summary> |
| 45 | /// <param name="dll">Dynamic link library containing the entry point.</param> |
| 46 | /// <param name="entryPoint">Entry point into dynamic link library.</param> |
| 47 | /// <param name="returnType">Return type of entry point.</param> |
| 48 | /// <param name="parameterTypes">Type of parameters to entry point.</param> |
| 49 | /// <param name="parameterValues">Value of parameters to entry point.</param> |
| 50 | /// <returns>Value from invoked code.</returns> |
| 51 | private static object DynamicPInvoke(string dll, string entryPoint, Type returnType, Type[] parameterTypes, object[] parameterValues) |
| 52 | { |
| 53 | #if NETCOREAPP |
| 54 | throw new PlatformNotSupportedException(); |
| 55 | #else |
| 56 | AssemblyName assemblyName = new AssemblyName(); |
| 57 | assemblyName.Name = "wixTempAssembly"; |
| 58 | |
| 59 | AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); |
| 60 | ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("wixTempModule"); |
| 61 | |
| 62 | MethodBuilder dynamicMethod = dynamicModule.DefinePInvokeMethod(entryPoint, dll, MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.PinvokeImpl, CallingConventions.Standard, returnType, parameterTypes, CallingConvention.Winapi, CharSet.Ansi); |
| 63 | dynamicModule.CreateGlobalFunctions(); |
| 64 | |
| 65 | MethodInfo methodInfo = dynamicModule.GetMethod(entryPoint); |
| 66 | return methodInfo.Invoke(null, parameterValues); |
| 67 | #endif |
| 68 | } |
| 69 | |
| 70 | /// <summary> |
| 71 | /// Native methods for loading libraries. |
| 72 | /// </summary> |
| 73 | private sealed class NativeMethods |
| 74 | { |
| 75 | private const UInt32 LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008; |
| 76 | |
| 77 | /// <summary> |
| 78 | /// Load a DLL library. |
| 79 | /// </summary> |
| 80 | /// <param name="file">The file name of the executable module.</param> |
| 81 | /// <returns>If the function succeeds, the return value is a handle to the mapped executable module.</returns> |
| 82 | internal static IntPtr LoadLibrary(string file) |
| 83 | { |
| 84 | IntPtr dllHandle = LoadLibraryEx(file, IntPtr.Zero, NativeMethods.LOAD_WITH_ALTERED_SEARCH_PATH); |
| 85 | |
| 86 | if (IntPtr.Zero == dllHandle) |
| 87 | { |
| 88 | int lastError = Marshal.GetLastWin32Error(); |
| 89 | throw new Exception(String.Format("Unable to load file: {0}, error: {1}", file, lastError)); |
| 90 | } |
| 91 | |
| 92 | return dllHandle; |
| 93 | } |
| 94 | |
| 95 | /// <summary> |
| 96 | /// Maps the specified executable module into the address space of the calling process. |
| 97 | /// </summary> |
| 98 | /// <param name="file">The file name of the executable module.</param> |
| 99 | /// <param name="fileHandle">This parameter is reserved for future use. It must be NULL.</param> |
| 100 | /// <param name="flags">Action to take when loading the module.</param> |
| 101 | /// <returns>If the function succeeds, the return value is a handle to the mapped executable module.</returns> |
| 102 | [DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true)] |
| 103 | private static extern IntPtr LoadLibraryEx(string file, IntPtr fileHandle, UInt32 flags); |
| 104 | } |
| 105 | } |
| 106 | } |