| 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.Core.Native.Msi |
| 4 | { |
| 5 | using System; |
| 6 | using System.Diagnostics; |
| 7 | using System.Runtime.InteropServices; |
| 8 | using System.Text; |
| 9 | |
| 10 | /// <summary> |
| 11 | /// A callback function that the installer calls for progress notification and error messages. |
| 12 | /// </summary> |
| 13 | /// <param name="context">Pointer to an application context. |
| 14 | /// This parameter can be used for error checking.</param> |
| 15 | /// <param name="messageType">Specifies a combination of one message box style, |
| 16 | /// one message box icon type, one default button, and one installation message type.</param> |
| 17 | /// <param name="message">Specifies the message text.</param> |
| 18 | /// <returns>-1 for an error, 0 if no action was taken, 1 if OK, 3 to abort.</returns> |
| 19 | public delegate int InstallUIHandler(IntPtr context, uint messageType, [MarshalAs(UnmanagedType.LPWStr)] string message); |
| 20 | |
| 21 | /// <summary> |
| 22 | /// Represents the Windows Installer, provides wrappers to |
| 23 | /// create the top-level objects and access their methods. |
| 24 | /// </summary> |
| 25 | public static class Installer |
| 26 | { |
| 27 | /// <summary> |
| 28 | /// Extacts the patch metadata as XML. |
| 29 | /// </summary> |
| 30 | /// <param name="path">Path to patch.</param> |
| 31 | /// <returns>String XML.</returns> |
| 32 | public static string ExtractPatchXml(string path) |
| 33 | { |
| 34 | var buffer = new StringBuilder(65535); |
| 35 | var size = buffer.Capacity; |
| 36 | |
| 37 | var error = MsiInterop.MsiExtractPatchXMLData(path, 0, buffer, ref size); |
| 38 | if (234 == error) |
| 39 | { |
| 40 | buffer.EnsureCapacity(++size); |
| 41 | error = MsiInterop.MsiExtractPatchXMLData(path, 0, buffer, ref size); |
| 42 | } |
| 43 | |
| 44 | if (error != 0) |
| 45 | { |
| 46 | throw new MsiException(error); |
| 47 | } |
| 48 | |
| 49 | return buffer.ToString(); |
| 50 | } |
| 51 | |
| 52 | /// <summary> |
| 53 | /// Takes the path to a file and returns a 128-bit hash of that file. |
| 54 | /// </summary> |
| 55 | /// <param name="filePath">Path to file that is to be hashed.</param> |
| 56 | /// <param name="options">The value in this column must be 0. This parameter is reserved for future use.</param> |
| 57 | /// <param name="hash">Int array that receives the returned file hash information.</param> |
| 58 | public static void GetFileHash(string filePath, int options, out int[] hash) |
| 59 | { |
| 60 | var hashInterop = new MSIFILEHASHINFO(); |
| 61 | hashInterop.FileHashInfoSize = 20; |
| 62 | |
| 63 | var error = MsiInterop.MsiGetFileHash(filePath, Convert.ToUInt32(options), hashInterop); |
| 64 | if (0 != error) |
| 65 | { |
| 66 | throw new MsiException(error); |
| 67 | } |
| 68 | |
| 69 | Debug.Assert(20 == hashInterop.FileHashInfoSize); |
| 70 | |
| 71 | hash = new int[4]; |
| 72 | hash[0] = hashInterop.Data0; |
| 73 | hash[1] = hashInterop.Data1; |
| 74 | hash[2] = hashInterop.Data2; |
| 75 | hash[3] = hashInterop.Data3; |
| 76 | } |
| 77 | |
| 78 | /// <summary> |
| 79 | /// Returns the version string and language string in the format that the installer |
| 80 | /// expects to find them in the database. If you just want version information, set |
| 81 | /// lpLangBuf and pcchLangBuf to zero. If you just want language information, set |
| 82 | /// lpVersionBuf and pcchVersionBuf to zero. |
| 83 | /// </summary> |
| 84 | /// <param name="filePath">Specifies the path to the file.</param> |
| 85 | /// <param name="version">Returns the file version. Set to 0 for language information only.</param> |
| 86 | /// <param name="language">Returns the file language. Set to 0 for version information only.</param> |
| 87 | public static void GetFileVersion(string filePath, out string version, out string language) |
| 88 | { |
| 89 | var versionLength = 20; |
| 90 | var languageLength = 20; |
| 91 | var versionBuffer = new StringBuilder(versionLength); |
| 92 | var languageBuffer = new StringBuilder(languageLength); |
| 93 | |
| 94 | var error = MsiInterop.MsiGetFileVersion(filePath, versionBuffer, ref versionLength, languageBuffer, ref languageLength); |
| 95 | if (234 == error) |
| 96 | { |
| 97 | versionBuffer.EnsureCapacity(++versionLength); |
| 98 | languageBuffer.EnsureCapacity(++languageLength); |
| 99 | error = MsiInterop.MsiGetFileVersion(filePath, versionBuffer, ref versionLength, languageBuffer, ref languageLength); |
| 100 | } |
| 101 | else if (1006 == error) |
| 102 | { |
| 103 | // file has no version or language, so no error |
| 104 | error = 0; |
| 105 | } |
| 106 | |
| 107 | if (0 != error) |
| 108 | { |
| 109 | throw new MsiException(error); |
| 110 | } |
| 111 | |
| 112 | version = versionBuffer.ToString(); |
| 113 | language = languageBuffer.ToString(); |
| 114 | } |
| 115 | |
| 116 | /// <summary> |
| 117 | /// Enables an external user-interface handler. |
| 118 | /// </summary> |
| 119 | /// <param name="installUIHandler">Specifies a callback function.</param> |
| 120 | /// <param name="messageFilter">Specifies which messages to handle using the external message handler.</param> |
| 121 | /// <param name="context">Pointer to an application context that is passed to the callback function.</param> |
| 122 | /// <returns>The return value is the previously set external handler, or null if there was no previously set handler.</returns> |
| 123 | public static InstallUIHandler SetExternalUI(InstallUIHandler installUIHandler, int messageFilter, IntPtr context) |
| 124 | { |
| 125 | return MsiInterop.MsiSetExternalUI(installUIHandler, messageFilter, context); |
| 126 | } |
| 127 | |
| 128 | /// <summary> |
| 129 | /// Enables the installer's internal user interface. |
| 130 | /// </summary> |
| 131 | /// <param name="uiLevel">Specifies the level of complexity of the user interface.</param> |
| 132 | /// <param name="hwnd">Pointer to a window. This window becomes the owner of any user interface created.</param> |
| 133 | /// <returns>The previous user interface level is returned. If an invalid dwUILevel is passed, then INSTALLUILEVEL_NOCHANGE is returned.</returns> |
| 134 | public static int SetInternalUI(int uiLevel, ref IntPtr hwnd) |
| 135 | { |
| 136 | return MsiInterop.MsiSetInternalUI(uiLevel, ref hwnd); |
| 137 | } |
| 138 | } |
| 139 | } |