| 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 | #include "precomp.h" |
| 4 | |
| 5 | // globals |
| 6 | HMODULE g_hInstCADLL; |
| 7 | |
| 8 | // statics |
| 9 | static BOOL s_fInitialized; |
| 10 | static MSIHANDLE s_hInstall; |
| 11 | static MSIHANDLE s_hDatabase; |
| 12 | static char s_szCustomActionLogName[32]; |
| 13 | static UINT s_iRetVal; |
| 14 | |
| 15 | static void CALLBACK WcaTraceError( |
| 16 | __in_z LPCSTR szFile, |
| 17 | __in int iLine, |
| 18 | __in REPORT_LEVEL rl, |
| 19 | __in UINT source, |
| 20 | __in HRESULT hrError, |
| 21 | __in_z __format_string LPCSTR szFormat, |
| 22 | __in va_list args |
| 23 | ); |
| 24 | |
| 25 | /******************************************************************** |
| 26 | WcaGlobalInitialize() - initializes the Wca library, should be |
| 27 | called once per custom action Dll during |
| 28 | DllMain on DLL_PROCESS_ATTACH |
| 29 | |
| 30 | ********************************************************************/ |
| 31 | extern "C" void WIXAPI WcaGlobalInitialize( |
| 32 | __in HINSTANCE hInst |
| 33 | ) |
| 34 | { |
| 35 | g_hInstCADLL = hInst; |
| 36 | DutilInitialize(&WcaTraceError); |
| 37 | MemInitialize(); |
| 38 | |
| 39 | AssertSetModule(g_hInstCADLL); |
| 40 | AssertSetDisplayFunction(WcaDisplayAssert); |
| 41 | } |
| 42 | |
| 43 | |
| 44 | /******************************************************************** |
| 45 | WcaGlobalFinalize() - finalizes the Wca library, should be the |
| 46 | called once per custom action Dll during |
| 47 | DllMain on DLL_PROCESS_DETACH |
| 48 | |
| 49 | ********************************************************************/ |
| 50 | extern "C" void WIXAPI WcaGlobalFinalize() |
| 51 | { |
| 52 | #ifdef DEBUG |
| 53 | if (WcaIsInitialized()) |
| 54 | { |
| 55 | CHAR szBuf[2048]; |
| 56 | StringCchPrintfA(szBuf, countof(szBuf), "CustomAction %s called WcaInitialize() but not WcaFinalize()", WcaGetLogName()); |
| 57 | |
| 58 | AssertSz(FALSE, szBuf); |
| 59 | } |
| 60 | #endif |
| 61 | MemUninitialize(); |
| 62 | DutilUninitialize(); |
| 63 | g_hInstCADLL = NULL; |
| 64 | } |
| 65 | |
| 66 | |
| 67 | /******************************************************************** |
| 68 | WcaInitialize() - initializes the Wca framework, should be the first |
| 69 | thing called by all CustomActions |
| 70 | |
| 71 | ********************************************************************/ |
| 72 | extern "C" HRESULT WIXAPI WcaInitialize( |
| 73 | __in MSIHANDLE hInstall, |
| 74 | __in_z PCSTR szCustomActionLogName |
| 75 | ) |
| 76 | { |
| 77 | WCHAR wzCAFileName[MAX_PATH] = {0}; |
| 78 | DWORD dwMajorVersion = 0; |
| 79 | DWORD dwMinorVersion = 0; |
| 80 | |
| 81 | // these statics should be called once per CustomAction invocation. |
| 82 | // Darwin does doesn't preserve DLL state across CustomAction calls so |
| 83 | // these should always be initialized to NULL. If that behavior changes |
| 84 | // we would need to do a careful review of all of our module/global data. |
| 85 | AssertSz(!s_fInitialized, "WcaInitialize() should only be called once per CustomAction"); |
| 86 | Assert(NULL == s_hInstall); |
| 87 | Assert(NULL == s_hDatabase); |
| 88 | Assert(0 == *s_szCustomActionLogName); |
| 89 | |
| 90 | HRESULT hr = S_OK; |
| 91 | |
| 92 | s_fInitialized = TRUE; |
| 93 | s_iRetVal = ERROR_SUCCESS; // assume all will go well |
| 94 | |
| 95 | s_hInstall = hInstall; |
| 96 | s_hDatabase = ::MsiGetActiveDatabase(s_hInstall); // may return null if deferred CustomAction |
| 97 | |
| 98 | hr = ::StringCchCopy(s_szCustomActionLogName, countof(s_szCustomActionLogName), szCustomActionLogName); |
| 99 | ExitOnFailure(hr, "Failed to copy CustomAction log name: %s", szCustomActionLogName); |
| 100 | |
| 101 | // If we got the database handle IE: immediate CA |
| 102 | if (s_hDatabase) |
| 103 | { |
| 104 | hr = SetVerboseLoggingAtom(IsVerboseLogging()); |
| 105 | ExitOnFailure(hr, "Failed to set verbose logging global atom"); |
| 106 | } |
| 107 | |
| 108 | if (!::GetModuleFileNameW(g_hInstCADLL, wzCAFileName, countof(wzCAFileName))) |
| 109 | { |
| 110 | ExitWithLastError(hr, "Failed to get module filename"); |
| 111 | } |
| 112 | |
| 113 | FileVersion(wzCAFileName, &dwMajorVersion, &dwMinorVersion); // Ignore failure, just log 0.0.0.0 |
| 114 | |
| 115 | WcaLog(LOGMSG_VERBOSE, "Entering %s in %ls, version %u.%u.%u.%u", szCustomActionLogName, wzCAFileName, (DWORD)HIWORD(dwMajorVersion), (DWORD)LOWORD(dwMajorVersion), (DWORD)HIWORD(dwMinorVersion), (DWORD)LOWORD(dwMinorVersion)); |
| 116 | |
| 117 | Assert(s_hInstall); |
| 118 | LExit: |
| 119 | if (FAILED(hr)) |
| 120 | { |
| 121 | if (s_hDatabase) |
| 122 | { |
| 123 | ::MsiCloseHandle(s_hDatabase); |
| 124 | s_hDatabase = NULL; |
| 125 | } |
| 126 | |
| 127 | s_hInstall = NULL; |
| 128 | s_fInitialized = FALSE; |
| 129 | } |
| 130 | |
| 131 | return hr; |
| 132 | } |
| 133 | |
| 134 | |
| 135 | /******************************************************************** |
| 136 | WcaFinalize() - cleans up after the Wca framework, should be the last |
| 137 | thing called by all CustomActions |
| 138 | |
| 139 | ********************************************************************/ |
| 140 | extern "C" UINT WIXAPI WcaFinalize( |
| 141 | __in UINT iReturnValue |
| 142 | ) |
| 143 | { |
| 144 | AssertSz(!WcaIsWow64Initialized(), "WcaFinalizeWow64() should be called before calling WcaFinalize()"); |
| 145 | |
| 146 | // clean up after our initialization |
| 147 | if (s_hDatabase) |
| 148 | { |
| 149 | ::MsiCloseHandle(s_hDatabase); |
| 150 | s_hDatabase = NULL; |
| 151 | } |
| 152 | |
| 153 | s_hInstall = NULL; |
| 154 | s_fInitialized = FALSE; |
| 155 | |
| 156 | // if no error occurred during the processing of the CusotmAction return the passed in return value |
| 157 | // otherwise return the previous failure |
| 158 | return (ERROR_SUCCESS == s_iRetVal) ? iReturnValue : s_iRetVal; |
| 159 | } |
| 160 | |
| 161 | |
| 162 | /******************************************************************** |
| 163 | WcaIsInitialized() - determines if WcaInitialize() has been called |
| 164 | |
| 165 | ********************************************************************/ |
| 166 | extern "C" BOOL WIXAPI WcaIsInitialized() |
| 167 | { |
| 168 | return s_fInitialized; |
| 169 | } |
| 170 | |
| 171 | |
| 172 | /******************************************************************** |
| 173 | WcaGetInstallHandle() - gets the handle to the active install session |
| 174 | |
| 175 | ********************************************************************/ |
| 176 | extern "C" MSIHANDLE WIXAPI WcaGetInstallHandle() |
| 177 | { |
| 178 | AssertSz(s_hInstall, "WcaInitialize() should be called before attempting to access the install handle."); |
| 179 | return s_hInstall; |
| 180 | } |
| 181 | |
| 182 | |
| 183 | /******************************************************************** |
| 184 | WcaGetDatabaseHandle() - gets the handle to the active database |
| 185 | |
| 186 | NOTE: this function can only be used in immediate CustomActions. |
| 187 | Deferred CustomActions do not have access to the active |
| 188 | database. |
| 189 | ********************************************************************/ |
| 190 | extern "C" MSIHANDLE WIXAPI WcaGetDatabaseHandle() |
| 191 | { |
| 192 | AssertSz(s_hDatabase, "WcaInitialize() should be called before attempting to access the install handle. Also note that deferred CustomActions do not have access to the active database."); |
| 193 | return s_hDatabase; |
| 194 | } |
| 195 | |
| 196 | |
| 197 | /******************************************************************** |
| 198 | WcaGetLogName() - gets the name of the CustomAction used in logging |
| 199 | |
| 200 | ********************************************************************/ |
| 201 | extern "C" const char* WIXAPI WcaGetLogName() |
| 202 | { |
| 203 | return s_szCustomActionLogName; |
| 204 | } |
| 205 | |
| 206 | |
| 207 | /******************************************************************** |
| 208 | WcaSetReturnValue() - sets the value to return from the CustomAction |
| 209 | |
| 210 | ********************************************************************/ |
| 211 | extern "C" void WIXAPI WcaSetReturnValue( |
| 212 | __in UINT iReturnValue |
| 213 | ) |
| 214 | { |
| 215 | s_iRetVal = iReturnValue; |
| 216 | } |
| 217 | |
| 218 | |
| 219 | /******************************************************************** |
| 220 | WcaCancelDetected() - determines if the user has canceled yet |
| 221 | |
| 222 | NOTE: returns true when WcaSetReturnValue() is set to ERROR_INSTALL_USEREXIT |
| 223 | ********************************************************************/ |
| 224 | extern "C" BOOL WIXAPI WcaCancelDetected() |
| 225 | { |
| 226 | return ERROR_INSTALL_USEREXIT == s_iRetVal; |
| 227 | } |
| 228 | |
| 229 | static void CALLBACK WcaTraceError( |
| 230 | __in_z LPCSTR /*szFile*/, |
| 231 | __in int /*iLine*/, |
| 232 | __in REPORT_LEVEL /*rl*/, |
| 233 | __in UINT source, |
| 234 | __in HRESULT hrError, |
| 235 | __in_z __format_string LPCSTR szFormat, |
| 236 | __in va_list args |
| 237 | ) |
| 238 | { |
| 239 | if (DUTIL_SOURCE_DEFAULT == source) |
| 240 | { |
| 241 | WcaLogErrorArgs(hrError, szFormat, args); |
| 242 | } |
| 243 | } |