VirtualBox

source: vbox/trunk/src/VBox/Installer/win/InstallHelper/VBoxCommon.cpp@ 108416

最後變更 在這個檔案從108416是 108285,由 vboxsync 提交於 4 週 前

Host installer/win: Added routines for handling CustomActionData to the common InstallHelper.dll code. Required as a prerequisite for using shared (sessison / system) CustomActionData by the installer, to better support elevated driver installs on modern Windows OSes (>= 10). bugref:10762

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 14.4 KB
 
1/* $Id: VBoxCommon.cpp 108285 2025-02-19 10:53:35Z vboxsync $ */
2/** @file
3 * VBoxCommon - Misc helper routines for install helper.
4 *
5 * This is used by internal/serial.cpp and VBoxInstallHelper.cpp.
6 */
7
8/*
9 * Copyright (C) 2008-2024 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.alldomusa.eu.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * SPDX-License-Identifier: GPL-3.0-only
28 */
29
30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
34#include <iprt/win/windows.h>
35#include <msi.h>
36#include <msiquery.h>
37
38#include <iprt/mem.h>
39#include <iprt/string.h>
40#include <iprt/utf16.h>
41
42#include <VBox/GuestHost/VBoxWinDrvInst.h>
43#include <VBoxWinDrvCommon.h>
44#include "VBoxCommon.h"
45
46
47/**
48 * Retrieves a MSI property (in UTF-16), extended version.
49 *
50 * @returns VBox status code.
51 * @param hMsi MSI handle to use.
52 * @param pwszName Name of property to retrieve.
53 * @param pwszVal Where to store the allocated value on success.
54 * @param pcwVal Input and output size (in WCHARs) of \a pwszVal.
55 */
56int VBoxMsiQueryPropEx(MSIHANDLE hMsi, const WCHAR *pwszName, WCHAR *pwszVal, DWORD *pcwVal)
57{
58 AssertPtrReturn(pwszName, VERR_INVALID_POINTER);
59 AssertPtrReturn(pwszVal, VERR_INVALID_POINTER);
60 AssertPtrReturn(pcwVal, VERR_INVALID_POINTER);
61 AssertReturn(*pcwVal, VERR_INVALID_PARAMETER);
62
63 int rc;
64
65 RT_BZERO(pwszVal, *pcwVal * sizeof(WCHAR));
66 UINT uRc = MsiGetPropertyW(hMsi, pwszName, pwszVal, pcwVal);
67 if (uRc == ERROR_SUCCESS)
68 {
69 if (*pcwVal > 0)
70 {
71 rc = VINF_SUCCESS;
72 }
73 else /* Indicates value not found. */
74 rc = VERR_NOT_FOUND;
75 }
76 else
77 rc = RTErrConvertFromWin32(uRc);
78
79 return rc;
80}
81
82#ifndef TESTCASE
83/**
84 * Retrieves a MSI property (in UTF-16).
85 *
86 * @returns VBox status code.
87 * @param hMsi MSI handle to use.
88 * @param pwszName Name of property to retrieve.
89 * @param pwszVal Where to store the allocated value on success.
90 * @param cwVal Input size (in WCHARs) of \a pwszVal.
91 */
92int VBoxMsiQueryProp(MSIHANDLE hMsi, const WCHAR *pwszName, WCHAR *pwszVal, DWORD cwVal)
93{
94 return VBoxMsiQueryPropEx(hMsi, pwszName, pwszVal, &cwVal);
95}
96#endif /* !TESTCASE */
97
98/**
99 * Destroys a custom action data entry.
100 *
101 * @param pEntry Custom action data entry to destroy.
102 */
103static void vboxMsiCustomActionDataEntryDestroy(PVBOXMSICUSTOMACTIONDATAENTRY pEntry)
104{
105 if (!pEntry)
106 return;
107
108 RTStrFree(pEntry->pszKey);
109 pEntry->pszKey = NULL;
110 RTStrFree(pEntry->pszVal);
111 pEntry->pszVal = NULL;
112}
113
114/**
115 * Queries custom action data entries, extended version.
116 *
117 * @returns VBox status code.
118 * @param hMsi MSI handle to use.
119 * @param pszSep Separator to use for parsing the key=value pairs.
120 * @param ppaEntries Where to return the allocated custom action data entries.
121 Might be NULL if \a pcEntries returns 0.
122 * Must be destroyed using vboxMsiCustomActionDataEntryDestroy().
123 * @param pcEntries Where to return the number of allocated custom action data entries of \a ppaEntries.
124 *
125 * @note The "CustomActionData" property used is fixed by the MSI engine and must not be changed.
126 */
127static int vboxMsiCustomActionDataQueryEx(MSIHANDLE hMsi, const char *pszSep, PVBOXMSICUSTOMACTIONDATAENTRY *ppaEntries, size_t *pcEntries)
128{
129 char *pszData = NULL;
130 int rc = VBoxMsiQueryPropUtf8(hMsi, "CustomActionData", &pszData);
131 if (RT_FAILURE(rc))
132 return rc;
133
134 *ppaEntries = NULL;
135
136 char **ppapszPairs; /* key=value pairs. */
137 size_t cPairs;
138 rc = RTStrSplit(pszData, strlen(pszData) + 1 /* Must include terminator */, pszSep, &ppapszPairs, &cPairs);
139 if ( RT_SUCCESS(rc)
140 && cPairs)
141 {
142 PVBOXMSICUSTOMACTIONDATAENTRY paEntries =
143 (PVBOXMSICUSTOMACTIONDATAENTRY)RTMemAllocZ(cPairs * sizeof(VBOXMSICUSTOMACTIONDATAENTRY));
144 if (paEntries)
145 {
146 size_t i = 0;
147 for (; i < cPairs; i++)
148 {
149 const char *pszPair = ppapszPairs[i];
150
151 char **ppapszKeyVal;
152 size_t cKeyVal;
153 rc = RTStrSplit(pszPair, strlen(pszPair) + 1 /* Must include terminator */, "=", &ppapszKeyVal, &cKeyVal);
154 if (RT_SUCCESS(rc))
155 {
156 if (cKeyVal == 2) /* Exactly one key=val pair. */
157 {
158 /* paEntries[i] will take ownership of ppapszKeyVal. */
159 paEntries[i].pszKey = ppapszKeyVal[0];
160 ppapszKeyVal[0] = NULL;
161 paEntries[i].pszVal = ppapszKeyVal[1];
162 ppapszKeyVal[1] = NULL;
163 }
164 else
165 rc = VERR_INVALID_PARAMETER;
166
167 for (size_t a = 0; a < cKeyVal; a++)
168 RTStrFree(ppapszKeyVal[a]);
169 RTMemFree(ppapszKeyVal);
170 }
171
172 if (RT_FAILURE(rc))
173 break;
174 }
175
176 if (RT_FAILURE(rc))
177 {
178 /* Rollback on failure. */
179 while (i)
180 vboxMsiCustomActionDataEntryDestroy(&paEntries[i--]);
181 RTMemFree(paEntries);
182 }
183 else
184 {
185 *ppaEntries = paEntries;
186 *pcEntries = cPairs;
187 }
188 }
189 else
190 rc = VERR_NO_MEMORY;
191
192 for (size_t i = 0; i < cPairs; i++)
193 RTStrFree(ppapszPairs[i]);
194 RTMemFree(ppapszPairs);
195 }
196
197 return rc;
198}
199
200/**
201 * Queries custom action data entries.
202 *
203 * @returns VBox status code.
204 * @param hMsi MSI handle to use.
205 * @param ppaEntries Where to return the allocated custom action data entries.
206 * Must be destroyed using vboxMsiCustomActionDataEntryDestroy().
207 * @param pcEntries Where to return the number of allocated custom action data entries of \a ppaEntries.
208 */
209static int vboxMsiCustomActionDataQuery(MSIHANDLE hMsi, PVBOXMSICUSTOMACTIONDATAENTRY *ppaEntries, size_t *pcEntries)
210{
211 return vboxMsiCustomActionDataQueryEx(hMsi, VBOX_MSI_CUSTOMACTIONDATA_SEP_STR, ppaEntries, pcEntries);
212}
213
214/**
215 * Frees custom action data.
216 *
217 * @returns VBox status code.
218 * @param pData Custom action data to free.
219 * The pointer will be invalid on return.
220 */
221void VBoxMsiCustomActionDataFree(PVBOXMSICUSTOMACTIONDATA pData)
222{
223 if (!pData)
224 return;
225
226 for (size_t i = 0; i < pData->cEntries; i++)
227 vboxMsiCustomActionDataEntryDestroy(&pData->paEntries[i]);
228
229 RTMemFree(pData);
230 pData = NULL;
231}
232
233/**
234 * Queries custom action data, extended version.
235 *
236 * @returns VBox status code.
237 * @param hMsi MSI handle to use.
238 * @param pszSep Separator to use for parsing the key=value pairs.
239 * @param ppData Where to return the allocated custom action data.
240 * Needs to be free'd using VBoxMsiCustomActionDataFree().
241 */
242int VBoxMsiCustomActionDataQueryEx(MSIHANDLE hMsi, const char *pszSep, PVBOXMSICUSTOMACTIONDATA *ppData)
243{
244 AssertPtrReturn(pszSep, VERR_INVALID_POINTER);
245 AssertPtrReturn(ppData, VERR_INVALID_POINTER);
246
247 PVBOXMSICUSTOMACTIONDATA pData = (PVBOXMSICUSTOMACTIONDATA)RTMemAllocZ(sizeof(VBOXMSICUSTOMACTIONDATA));
248 AssertPtrReturn(pData, VERR_NO_MEMORY);
249
250 int rc = vboxMsiCustomActionDataQueryEx(hMsi, pszSep, &pData->paEntries, &pData->cEntries);
251 if (RT_SUCCESS(rc))
252 {
253 *ppData = pData;
254 }
255 else
256 VBoxMsiCustomActionDataFree(pData);
257
258 return rc;
259}
260
261/**
262 * Queries custom action data.
263 *
264 * @returns VBox status code.
265 * @param hMsi MSI handle to use.
266 * @param ppData Where to return the allocated custom action data.
267 * Needs to be free'd using VBoxMsiCustomActionDataFree().
268 */
269int VBoxMsiCustomActionDataQuery(MSIHANDLE hMsi, PVBOXMSICUSTOMACTIONDATA *ppData)
270{
271 return VBoxMsiCustomActionDataQueryEx(hMsi, VBOX_MSI_CUSTOMACTIONDATA_SEP_STR, ppData);
272}
273
274/**
275 * Finds a key in custom action data and returns its value.
276 *
277 * @returns Value if found, or NULL if not found.
278 * @param pHaystack Custom action data to search in.
279 * @param pszNeedle Key to search for. Case-sensitive.
280 */
281const char *VBoxMsiCustomActionDataFind(PVBOXMSICUSTOMACTIONDATA pHaystack, const char *pszNeedle)
282{
283 AssertPtrReturn(pHaystack, NULL);
284 AssertPtrReturn(pszNeedle, NULL);
285
286 for (size_t i = 0; i < pHaystack->cEntries; i++)
287 {
288 if (!RTStrICmp(pHaystack->paEntries[i].pszKey, pszNeedle))
289 return pHaystack->paEntries[i].pszVal;
290 }
291
292 return NULL;
293}
294
295/**
296 * Retrieves a MSI property (in UTF-8).
297 *
298 * Convenience function for VBoxGetMsiProp().
299 *
300 * @returns VBox status code.
301 * @param hMsi MSI handle to use.
302 * @param pszName Name of property to retrieve.
303 * @param ppszValue Where to store the allocated value on success.
304 * Must be free'd using RTStrFree() by the caller.
305 */
306int VBoxMsiQueryPropUtf8(MSIHANDLE hMsi, const char *pszName, char **ppszValue)
307{
308 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
309 AssertPtrReturn(ppszValue, VERR_INVALID_POINTER);
310
311 PRTUTF16 pwszName;
312 int rc = RTStrToUtf16(pszName, &pwszName);
313 if (RT_SUCCESS(rc))
314 {
315 WCHAR wszValue[1024]; /* 1024 should be enough for everybody (tm). */
316 rc = VBoxMsiQueryProp(hMsi, pwszName, wszValue, RT_ELEMENTS(wszValue));
317 if (RT_SUCCESS(rc))
318 rc = RTUtf16ToUtf8(wszValue, ppszValue);
319
320 RTUtf16Free(pwszName);
321 }
322
323 return rc;
324}
325
326#ifndef TESTCASE
327int VBoxMsiQueryPropInt32(MSIHANDLE hMsi, const char *pszName, DWORD *pdwValue)
328{
329 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
330 AssertPtrReturn(pdwValue, VERR_INVALID_POINTER);
331
332 char *pszTemp;
333 int rc = VBoxMsiQueryPropUtf8(hMsi, pszName, &pszTemp);
334 if (RT_SUCCESS(rc))
335 {
336 *pdwValue = RTStrToInt32(pszTemp);
337 RTStrFree(pszTemp);
338 }
339
340 return rc;
341}
342
343/**
344 * Sets a MSI property.
345 *
346 * @returns UINT
347 * @param hMsi MSI handle to use.
348 * @param pwszName Name of property to set.
349 * @param pwszValue Value to set.
350 */
351UINT VBoxMsiSetProp(MSIHANDLE hMsi, const WCHAR *pwszName, const WCHAR *pwszValue)
352{
353 return MsiSetPropertyW(hMsi, pwszName, pwszValue);
354}
355#endif /* TESTCASE */
356
357/**
358 * Sets a MSI property (in UTF-8).
359 *
360 * Convenience function for VBoxMsiSetProp().
361 *
362 * @returns VBox status code.
363 * @param hMsi MSI handle to use.
364 * @param pszName Name of property to set.
365 * @param pszValue Value to set.
366 */
367int VBoxMsiSetPropUtf8(MSIHANDLE hMsi, const char *pszName, const char *pszValue)
368{
369 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
370 AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
371
372 PRTUTF16 pwszName;
373 int rc = RTStrToUtf16(pszName, &pwszName);
374 if (RT_SUCCESS(rc))
375 {
376 PRTUTF16 pwszValue;
377 rc = RTStrToUtf16(pszValue, &pwszValue);
378 if (RT_SUCCESS(rc))
379 {
380 UINT const uRc = VBoxMsiSetProp(hMsi, pwszName, pwszValue);
381 if (uRc != ERROR_SUCCESS)
382 rc = RTErrConvertFromWin32(uRc);
383 RTUtf16Free(pwszValue);
384 }
385
386 RTUtf16Free(pwszName);
387 }
388
389 return rc;
390}
391
392/**
393 * Sets a MSI property (DWORD).
394 *
395 * Convenience function for VBoxMsiSetProp().
396 *
397 * @returns UINT
398 * @param hMsi MSI handle to use.
399 * @param pwszName Name of property to set.
400 * @param dwVal Value to set.
401 */
402UINT VBoxMsiSetPropDWORD(MSIHANDLE hMsi, const WCHAR *pwszName, DWORD dwVal)
403{
404 wchar_t wszTemp[32];
405 RTUtf16Printf(wszTemp, RT_ELEMENTS(wszTemp), "%u", dwVal);
406 return VBoxMsiSetProp(hMsi, pwszName, wszTemp);
407}
408
409/**
410 * Queries a DWORD value from a Windows registry key, Unicode (wide char) version.
411 *
412 * @returns VBox status code.
413 * @retval VERR_FILE_NOT_FOUND if the value has not been found.
414 * @retval VERR_WRONG_TYPE if the type (DWORD) of the value does not match.
415 * @retval VERR_MISMATCH if the type sizes do not match.
416 * @param hMsi MSI handle to use.
417 * @param hKey Registry handle of key to query.
418 * @param pwszName Name of the value to query.
419 * @param pdwValue Where to return the actual value on success.
420 */
421int VBoxMsiRegQueryDWORDW(MSIHANDLE hMsi, HKEY hKey, LPCWSTR pwszName, DWORD *pdwValue)
422{
423 RT_NOREF(hMsi);
424
425 return VBoxWinDrvRegQueryDWORDW(hKey, pwszName, pdwValue);
426}
427
428/**
429 * Queries a DWORD value from a Windows registry key.
430 *
431 * @returns VBox status code.
432 * @retval VERR_FILE_NOT_FOUND if the value has not been found.
433 * @retval VERR_WRONG_TYPE if the type (DWORD) of the value does not match.
434 * @retval VERR_MISMATCH if the type sizes do not match.
435 * @param hKey Registry handle of key to query.
436 * @param pszName Name of the value to query.
437 * @param pdwValue Where to return the actual value on success.
438 */
439int VBoxMsiRegQueryDWORD(MSIHANDLE hMsi, HKEY hKey, const char *pszName, DWORD *pdwValue)
440{
441 PRTUTF16 pwszName;
442 int rc = RTStrToUtf16Ex(pszName, RTSTR_MAX, &pwszName, 0, NULL);
443 if (RT_SUCCESS(rc))
444 {
445 rc = VBoxMsiRegQueryDWORDW(hMsi, hKey, pwszName, pdwValue);
446 RTUtf16Free(pwszName);
447 }
448
449 return rc;
450}
451
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette