| 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 | |
| 6 | static HRESULT SendRequiredBextMessage( |
| 7 | __in BURN_EXTENSION* pExtension, |
| 8 | __in BOOTSTRAPPER_EXTENSION_MESSAGE message, |
| 9 | __in const LPVOID pvArgs, |
| 10 | __inout LPVOID pvResults |
| 11 | ); |
| 12 | |
| 13 | // function definitions |
| 14 | |
| 15 | /******************************************************************* |
| 16 | BurnExtensionParseFromXml - |
| 17 | |
| 18 | *******************************************************************/ |
| 19 | EXTERN_C HRESULT BurnExtensionParseFromXml( |
| 20 | __in BURN_EXTENSIONS* pBurnExtensions, |
| 21 | __in BURN_PAYLOADS* pBaPayloads, |
| 22 | __in IXMLDOMNode* pixnBundle |
| 23 | ) |
| 24 | { |
| 25 | HRESULT hr = S_OK; |
| 26 | IXMLDOMNodeList* pixnNodes = NULL; |
| 27 | IXMLDOMNode* pixnNode = NULL; |
| 28 | DWORD cNodes = 0; |
| 29 | LPWSTR scz = NULL; |
| 30 | |
| 31 | // Select BootstrapperExtension nodes. |
| 32 | hr = XmlSelectNodes(pixnBundle, L"BootstrapperExtension", &pixnNodes); |
| 33 | ExitOnFailure(hr, "Failed to select BootstrapperExtension nodes."); |
| 34 | |
| 35 | // Get BootstrapperExtension node count. |
| 36 | hr = pixnNodes->get_length((long*)&cNodes); |
| 37 | ExitOnFailure(hr, "Failed to get BootstrapperExtension node count."); |
| 38 | |
| 39 | if (!cNodes) |
| 40 | { |
| 41 | ExitFunction(); |
| 42 | } |
| 43 | |
| 44 | // Allocate memory for BootstrapperExtensions. |
| 45 | pBurnExtensions->rgExtensions = (BURN_EXTENSION*)MemAlloc(sizeof(BURN_EXTENSION) * cNodes, TRUE); |
| 46 | ExitOnNull(pBurnExtensions->rgExtensions, hr, E_OUTOFMEMORY, "Failed to allocate memory for BootstrapperExtension structs."); |
| 47 | |
| 48 | pBurnExtensions->cExtensions = cNodes; |
| 49 | |
| 50 | // parse search elements |
| 51 | for (DWORD i = 0; i < cNodes; ++i) |
| 52 | { |
| 53 | BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i]; |
| 54 | |
| 55 | hr = XmlNextElement(pixnNodes, &pixnNode, NULL); |
| 56 | ExitOnFailure(hr, "Failed to get next node."); |
| 57 | |
| 58 | // @Id |
| 59 | hr = XmlGetAttributeEx(pixnNode, L"Id", &pExtension->sczId); |
| 60 | ExitOnFailure(hr, "Failed to get @Id."); |
| 61 | |
| 62 | // @EntryPayloadId |
| 63 | hr = XmlGetAttributeEx(pixnNode, L"EntryPayloadSourcePath", &scz); |
| 64 | ExitOnFailure(hr, "Failed to get @EntryPayloadSourcePath."); |
| 65 | |
| 66 | hr = PayloadFindEmbeddedBySourcePath(pBaPayloads->sdhPayloads, scz, &pExtension->pEntryPayload); |
| 67 | ExitOnFailure(hr, "Failed to find BootstrapperExtension EntryPayload '%ls'.", pExtension->sczId); |
| 68 | |
| 69 | // prepare next iteration |
| 70 | ReleaseNullObject(pixnNode); |
| 71 | } |
| 72 | |
| 73 | hr = S_OK; |
| 74 | |
| 75 | LExit: |
| 76 | ReleaseStr(scz); |
| 77 | ReleaseObject(pixnNode); |
| 78 | ReleaseObject(pixnNodes); |
| 79 | |
| 80 | return hr; |
| 81 | } |
| 82 | |
| 83 | /******************************************************************* |
| 84 | BurnExtensionUninitialize - |
| 85 | |
| 86 | *******************************************************************/ |
| 87 | EXTERN_C void BurnExtensionUninitialize( |
| 88 | __in BURN_EXTENSIONS* pBurnExtensions |
| 89 | ) |
| 90 | { |
| 91 | if (pBurnExtensions->rgExtensions) |
| 92 | { |
| 93 | for (DWORD i = 0; i < pBurnExtensions->cExtensions; ++i) |
| 94 | { |
| 95 | BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i]; |
| 96 | |
| 97 | ReleaseStr(pExtension->sczId); |
| 98 | } |
| 99 | MemFree(pBurnExtensions->rgExtensions); |
| 100 | } |
| 101 | |
| 102 | // clear struct |
| 103 | memset(pBurnExtensions, 0, sizeof(BURN_EXTENSIONS)); |
| 104 | } |
| 105 | |
| 106 | /******************************************************************* |
| 107 | BurnExtensionLoad - |
| 108 | |
| 109 | *******************************************************************/ |
| 110 | EXTERN_C HRESULT BurnExtensionLoad( |
| 111 | __in BURN_EXTENSIONS * pBurnExtensions, |
| 112 | __in BURN_EXTENSION_ENGINE_CONTEXT* pEngineContext |
| 113 | ) |
| 114 | { |
| 115 | HRESULT hr = S_OK; |
| 116 | LPWSTR sczBootstrapperExtensionDataPath = NULL; |
| 117 | BOOTSTRAPPER_EXTENSION_CREATE_ARGS args = { }; |
| 118 | BOOTSTRAPPER_EXTENSION_CREATE_RESULTS results = { }; |
| 119 | |
| 120 | if (!pBurnExtensions->rgExtensions || !pBurnExtensions->cExtensions) |
| 121 | { |
| 122 | ExitFunction(); |
| 123 | } |
| 124 | |
| 125 | hr = PathConcat(pEngineContext->pEngineState->userExperience.sczTempDirectory, L"BootstrapperExtensionData.xml", &sczBootstrapperExtensionDataPath); |
| 126 | ExitOnFailure(hr, "Failed to get BootstrapperExtensionDataPath."); |
| 127 | |
| 128 | for (DWORD i = 0; i < pBurnExtensions->cExtensions; ++i) |
| 129 | { |
| 130 | BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i]; |
| 131 | |
| 132 | memset(&args, 0, sizeof(BOOTSTRAPPER_EXTENSION_CREATE_ARGS)); |
| 133 | memset(&results, 0, sizeof(BOOTSTRAPPER_EXTENSION_CREATE_RESULTS)); |
| 134 | |
| 135 | args.cbSize = sizeof(BOOTSTRAPPER_EXTENSION_CREATE_ARGS); |
| 136 | args.pfnBootstrapperExtensionEngineProc = EngineForExtensionProc; |
| 137 | args.pvBootstrapperExtensionEngineProcContext = pEngineContext; |
| 138 | args.qwEngineAPIVersion = MAKEQWORDVERSION(2021, 4, 27, 0); |
| 139 | args.wzBootstrapperWorkingFolder = pEngineContext->pEngineState->userExperience.sczTempDirectory; |
| 140 | args.wzBootstrapperExtensionDataPath = sczBootstrapperExtensionDataPath; |
| 141 | args.wzExtensionId = pExtension->sczId; |
| 142 | |
| 143 | results.cbSize = sizeof(BOOTSTRAPPER_EXTENSION_CREATE_RESULTS); |
| 144 | |
| 145 | // Load BootstrapperExtension DLL. |
| 146 | pExtension->hBextModule = ::LoadLibraryExW(pExtension->pEntryPayload->sczLocalFilePath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); |
| 147 | ExitOnNullWithLastError(pExtension->hBextModule, hr, "Failed to load BootstrapperExtension DLL '%ls': '%ls'.", pExtension->sczId, pExtension->pEntryPayload->sczLocalFilePath); |
| 148 | |
| 149 | // Get BootstrapperExtensionCreate entry-point. |
| 150 | PFN_BOOTSTRAPPER_EXTENSION_CREATE pfnCreate = (PFN_BOOTSTRAPPER_EXTENSION_CREATE)::GetProcAddress(pExtension->hBextModule, "BootstrapperExtensionCreate"); |
| 151 | ExitOnNullWithLastError(pfnCreate, hr, "Failed to get BootstrapperExtensionCreate entry-point '%ls'.", pExtension->sczId); |
| 152 | |
| 153 | // Create BootstrapperExtension. |
| 154 | hr = pfnCreate(&args, &results); |
| 155 | ExitOnFailure(hr, "Failed to create BootstrapperExtension '%ls'.", pExtension->sczId); |
| 156 | |
| 157 | pExtension->pfnBurnExtensionProc = results.pfnBootstrapperExtensionProc; |
| 158 | pExtension->pvBurnExtensionProcContext = results.pvBootstrapperExtensionProcContext; |
| 159 | } |
| 160 | |
| 161 | LExit: |
| 162 | ReleaseStr(sczBootstrapperExtensionDataPath); |
| 163 | |
| 164 | return hr; |
| 165 | } |
| 166 | |
| 167 | /******************************************************************* |
| 168 | BurnExtensionUnload - |
| 169 | |
| 170 | *******************************************************************/ |
| 171 | EXTERN_C void BurnExtensionUnload( |
| 172 | __in BURN_EXTENSIONS * pBurnExtensions |
| 173 | ) |
| 174 | { |
| 175 | HRESULT hr = S_OK; |
| 176 | |
| 177 | if (pBurnExtensions->rgExtensions) |
| 178 | { |
| 179 | for (DWORD i = 0; i < pBurnExtensions->cExtensions; ++i) |
| 180 | { |
| 181 | BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i]; |
| 182 | |
| 183 | if (pExtension->hBextModule) |
| 184 | { |
| 185 | // Get BootstrapperExtensionDestroy entry-point and call it if it exists. |
| 186 | PFN_BOOTSTRAPPER_EXTENSION_DESTROY pfnDestroy = (PFN_BOOTSTRAPPER_EXTENSION_DESTROY)::GetProcAddress(pExtension->hBextModule, "BootstrapperExtensionDestroy"); |
| 187 | if (pfnDestroy) |
| 188 | { |
| 189 | pfnDestroy(); |
| 190 | } |
| 191 | |
| 192 | // Free BootstrapperExtension DLL. |
| 193 | if (!::FreeLibrary(pExtension->hBextModule)) |
| 194 | { |
| 195 | hr = HRESULT_FROM_WIN32(::GetLastError()); |
| 196 | TraceError(hr, "Failed to unload BootstrapperExtension DLL."); |
| 197 | } |
| 198 | pExtension->hBextModule = NULL; |
| 199 | } |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | EXTERN_C HRESULT BurnExtensionFindById( |
| 205 | __in BURN_EXTENSIONS* pBurnExtensions, |
| 206 | __in_z LPCWSTR wzId, |
| 207 | __out BURN_EXTENSION** ppExtension |
| 208 | ) |
| 209 | { |
| 210 | HRESULT hr = S_OK; |
| 211 | BURN_EXTENSION* pExtension = NULL; |
| 212 | |
| 213 | for (DWORD i = 0; i < pBurnExtensions->cExtensions; ++i) |
| 214 | { |
| 215 | pExtension = &pBurnExtensions->rgExtensions[i]; |
| 216 | |
| 217 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pExtension->sczId, -1, wzId, -1)) |
| 218 | { |
| 219 | *ppExtension = pExtension; |
| 220 | ExitFunction1(hr = S_OK); |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | hr = E_NOTFOUND; |
| 225 | |
| 226 | LExit: |
| 227 | return hr; |
| 228 | } |
| 229 | |
| 230 | EXTERN_C BEEAPI BurnExtensionPerformSearch( |
| 231 | __in BURN_EXTENSION* pExtension, |
| 232 | __in LPWSTR wzSearchId, |
| 233 | __in LPWSTR wzVariable |
| 234 | ) |
| 235 | { |
| 236 | HRESULT hr = S_OK; |
| 237 | BOOTSTRAPPER_EXTENSION_SEARCH_ARGS args = { }; |
| 238 | BOOTSTRAPPER_EXTENSION_SEARCH_RESULTS results = { }; |
| 239 | |
| 240 | args.cbSize = sizeof(args); |
| 241 | args.wzId = wzSearchId; |
| 242 | args.wzVariable = wzVariable; |
| 243 | |
| 244 | results.cbSize = sizeof(results); |
| 245 | |
| 246 | hr = SendRequiredBextMessage(pExtension, BOOTSTRAPPER_EXTENSION_MESSAGE_SEARCH, &args, &results); |
| 247 | ExitOnFailure(hr, "BootstrapperExtension '%ls' Search '%ls' failed.", pExtension->sczId, wzSearchId); |
| 248 | |
| 249 | LExit: |
| 250 | return hr; |
| 251 | } |
| 252 | |
| 253 | static HRESULT SendRequiredBextMessage( |
| 254 | __in BURN_EXTENSION* pExtension, |
| 255 | __in BOOTSTRAPPER_EXTENSION_MESSAGE message, |
| 256 | __in const LPVOID pvArgs, |
| 257 | __inout LPVOID pvResults |
| 258 | ) |
| 259 | { |
| 260 | HRESULT hr = S_OK; |
| 261 | |
| 262 | hr = pExtension->pfnBurnExtensionProc(message, pvArgs, pvResults, pExtension->pvBurnExtensionProcContext); |
| 263 | |
| 264 | return hr; |
| 265 | } |