VirtualBox

source: vbox/trunk/src/VBox/GuestHost/installation/VBoxWinDrvCommon.cpp@ 106679

Last change on this file since 106679 was 106395, checked in by vboxsync, 4 months ago

Windows installers: Added code for also parsing and querying version information from INF files. Will be also displayed in tstVBoxInstHlpDrvInst now [build fix]. bugref:10762

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/* $Id: VBoxWinDrvCommon.cpp 106395 2024-10-16 16:27:03Z vboxsync $ */
2/** @file
3 * VBoxWinDrvCommon - Common Windows driver functions.
4 */
5
6/*
7 * Copyright (C) 2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/win/windows.h>
33#include <iprt/win/setupapi.h>
34#include <newdev.h> /* For INSTALLFLAG_XXX. */
35#include <cfgmgr32.h> /* For MAX_DEVICE_ID_LEN. */
36
37#include <iprt/assert.h>
38#include <iprt/dir.h>
39#include <iprt/errcore.h>
40#include <iprt/ldr.h>
41#include <iprt/list.h>
42#include <iprt/mem.h>
43#include <iprt/once.h>
44#include <iprt/path.h>
45#include <iprt/string.h>
46#include <iprt/system.h>
47#include <iprt/utf16.h>
48
49#ifdef DEBUG
50# include <iprt/stream.h>
51#endif
52
53#include "VBoxWinDrvCommon.h"
54
55
56/*********************************************************************************************************************************
57* Defines *
58*********************************************************************************************************************************/
59
60
61/*********************************************************************************************************************************
62* Defined Constants And Macros *
63*********************************************************************************************************************************/
64
65
66/*********************************************************************************************************************************
67* Structures and Typedefs *
68*********************************************************************************************************************************/
69
70
71/*********************************************************************************************************************************
72* Global Variables *
73*********************************************************************************************************************************/
74
75
76/*********************************************************************************************************************************
77* Implementation *
78*********************************************************************************************************************************/
79
80
81/**
82 * Queries an INF context from an INF handle.
83 *
84 * @returns VBox status code.
85 * @param hInf INF handle to use.
86 * @param pwszSection Section name to query context for.
87 * @param pwszKey Key to query context for.
88 * @param pCtx Where to return the INF context on success.
89 */
90int VBoxWinDrvInfQueryContext(HINF hInf, LPCWSTR pwszSection, LPCWSTR pwszKey, PINFCONTEXT pCtx)
91{
92 if (!SetupFindFirstLineW(hInf, pwszSection, pwszKey, pCtx))
93 return VERR_NOT_FOUND;
94
95 return VINF_SUCCESS;
96}
97
98/**
99 * Queries a value from an INF context.
100 *
101 * @returns VBox status code.
102 * @param pCtx INF context to use.
103 * @param iValue Index to query.
104 * @param ppwszValue Where to return the value on success.
105 * @param pcwcValue Where to return the number of characters for \a ppwszValue. Optional an can be NULL.
106 */
107int VBoxWinDrvInfQueryKeyValue(PINFCONTEXT pCtx, DWORD iValue, PRTUTF16 *ppwszValue, PDWORD pcwcValue)
108{
109 *ppwszValue = NULL;
110 if (pcwcValue)
111 *pcwcValue = 0;
112
113 DWORD cwcValue;
114 if (!SetupGetStringFieldW(pCtx, iValue, NULL, 0, &cwcValue))
115 {
116 DWORD const dwErr = GetLastError();
117 if (dwErr != ERROR_INSUFFICIENT_BUFFER)
118 return RTErrConvertFromWin32(dwErr);
119 }
120
121 LPWSTR pwszValue = (LPWSTR)RTMemAlloc(cwcValue * sizeof(pwszValue[0]));
122 AssertPtrReturn(pwszValue, VERR_NO_MEMORY);
123
124 if (!SetupGetStringFieldW(pCtx, iValue, pwszValue, cwcValue, &cwcValue))
125 {
126 RTMemFree(pwszValue);
127 return RTErrConvertFromWin32(GetLastError());
128 }
129
130 *ppwszValue = pwszValue;
131 if (pcwcValue)
132 *pcwcValue = cwcValue;
133
134 return VINF_SUCCESS;
135}
136
137/**
138 * Queries for the model name in an INF file.
139 *
140 * @returns VBox status code.
141 * @param hInf INF handle to use.
142 * @param ppwszValue Where to return the model name on success.
143 * @param pcwcValue Where to return the number of characters for \a ppwszValue. Optional an can be NULL.
144 */
145int VBoxWinDrvInfQueryModelsSectionName(HINF hInf, PRTUTF16 *ppwszValue, PDWORD pcwcValue)
146{
147 *ppwszValue = NULL;
148 if (pcwcValue)
149 *pcwcValue = 0;
150
151 /* Sorted by most likely-ness. */
152 static PRTUTF16 s_apwszSections[] =
153 {
154 /* The more specific (using decorations), the better. Try these first. */
155 L"Manufacturer" VBOXWINDRVINF_DOT_NT_NATIVE_ARCH_STR,
156 L"DefaultInstall" VBOXWINDRVINF_DOT_NT_NATIVE_ARCH_STR,
157 L"DefaultUninstall" VBOXWINDRVINF_DOT_NT_NATIVE_ARCH_STR,
158 /* Try undecorated sections last. */
159 L"Manufacturer",
160 L"DefaultInstall",
161 L"DefaultUninstall"
162 };
163
164 int rc = VINF_SUCCESS;
165
166 INFCONTEXT InfCtx;
167 for (int i = 0; i < RT_ELEMENTS(s_apwszSections); i++)
168 {
169 PRTUTF16 const pwszSection = s_apwszSections[i];
170 rc = VBoxWinDrvInfQueryContext(hInf, pwszSection, NULL, &InfCtx);
171 if (RT_SUCCESS(rc))
172 break;
173 }
174
175 if (RT_FAILURE(rc))
176 return rc;
177
178 LPWSTR pwszModels;
179 DWORD cwcModels;
180 rc = VBoxWinDrvInfQueryKeyValue(&InfCtx, 1, &pwszModels, &cwcModels);
181 if (RT_FAILURE(rc))
182 return rc;
183
184 LPWSTR pwszPlatform = NULL;
185 DWORD cwcPlatform = 0;
186 bool fArch = false;
187 bool fNt = false;
188
189 LPWSTR pwszPlatformCur;
190 DWORD cwcPlatformCur;
191 for (DWORD i = 2; (rc = VBoxWinDrvInfQueryKeyValue(&InfCtx, i, &pwszPlatformCur, &cwcPlatformCur)) == VINF_SUCCESS; ++i)
192 {
193 if (RTUtf16ICmpAscii(pwszPlatformCur, "NT" VBOXWINDRVINF_NATIVE_ARCH_STR) == 0)
194 fArch = true;
195 else
196 {
197 if ( fNt
198 || RTUtf16ICmpAscii(pwszPlatformCur, "NT") != 0)
199 {
200 RTMemFree(pwszPlatformCur);
201 pwszPlatformCur = NULL;
202 continue;
203 }
204 fNt = true;
205 }
206
207 cwcPlatform = cwcPlatformCur;
208 if (pwszPlatform)
209 RTMemFree(pwszPlatform);
210 pwszPlatform = pwszPlatformCur;
211 pwszPlatformCur = NULL;
212 }
213
214 rc = VINF_SUCCESS;
215
216 LPWSTR pwszResult = NULL;
217 DWORD cwcResult = 0;
218 if (pwszPlatform)
219 {
220 pwszResult = (LPWSTR)RTMemAlloc((cwcModels + cwcPlatform) * sizeof(pwszResult[0]));
221 if (pwszResult)
222 {
223 memcpy(pwszResult, pwszModels, (cwcModels - 1) * sizeof(pwszResult[0]));
224 pwszResult[cwcModels - 1] = L'.';
225 memcpy(&pwszResult[cwcModels], pwszPlatform, cwcPlatform * sizeof(pwszResult[0]));
226 cwcResult = cwcModels + cwcPlatform;
227 }
228 else
229 rc = VERR_NO_MEMORY;
230 }
231 else
232 {
233 pwszResult = pwszModels;
234 cwcResult = cwcModels;
235 pwszModels = NULL;
236 }
237
238 if (pwszModels)
239 RTMemFree(pwszModels);
240 if (pwszPlatform)
241 RTMemFree(pwszPlatform);
242
243 if (RT_SUCCESS(rc))
244 {
245 *ppwszValue = pwszResult;
246 if (pcwcValue)
247 *pcwcValue = cwcResult;
248 }
249
250 return rc;
251}
252
253/**
254 * Queries the "Version" section of an INF file, extended version.
255 *
256 * @returns VBox status code.
257 * @param hInf INF handle to use.
258 * @param uIndex Index of version information to query. Usually 0.
259 * @param pVer Where to return the Version section information on success.
260 */
261int VBoxWinDrvInfQuerySectionVerEx(HINF hInf, UINT uIndex, PVBOXWINDRVINFSEC_VERSION pVer)
262{
263 DWORD dwSize = 0;
264 bool fRc = SetupGetInfInformationW(hInf, INFINFO_INF_SPEC_IS_HINF, NULL, 0, &dwSize);
265 if (!fRc || !dwSize)
266 return VERR_NOT_FOUND;
267
268 int rc = VINF_SUCCESS;
269
270 PSP_INF_INFORMATION pInfo = (PSP_INF_INFORMATION)RTMemAlloc(dwSize);
271 AssertPtrReturn(pInfo, VERR_NO_MEMORY);
272 fRc = SetupGetInfInformationW(hInf, INFINFO_INF_SPEC_IS_HINF, pInfo, dwSize, NULL);
273 if (fRc)
274 {
275 if (pInfo->InfStyle == INF_STYLE_WIN4)
276 {
277 dwSize = 0;
278 fRc = SetupQueryInfVersionInformationW(pInfo, uIndex, NULL /* Key, NULL means all */,
279 NULL, 0, &dwSize);
280 if (fRc)
281 {
282 PRTUTF16 pwszInfo = (PRTUTF16)RTMemAlloc(dwSize * sizeof(RTUTF16));
283 if (pwszInfo)
284 {
285 fRc = SetupQueryInfVersionInformationW(pInfo, uIndex, NULL /* Key, NULL means all */,
286 pwszInfo, dwSize, NULL);
287
288/** Macro to find a specific key and assign its value to the given string. */
289#define GET_VALUE(a_Key, a_String) \
290 if (!RTUtf16ICmp(pwsz, a_Key)) \
291 { \
292 rc = RTUtf16Printf(a_String, RT_ELEMENTS(a_String), "%ls", pwsz + cch + 1 /* SKip key + terminator */); \
293 AssertRCBreak(rc); \
294 }
295 PRTUTF16 pwsz = pwszInfo;
296 while (dwSize)
297 {
298 size_t const cch = RTUtf16Len(pwsz);
299
300 GET_VALUE(L"DriverVer", pVer->wszDriverVer);
301 GET_VALUE(L"Provider", pVer->wszProvider);
302 GET_VALUE(L"CatalogFile", pVer->wszCatalogFile);
303
304 dwSize -= (DWORD)cch + 1;
305 pwsz += cch + 1;
306 }
307 Assert(dwSize == 0);
308#undef GET_VALUE
309 RTMemFree(pwszInfo);
310 }
311 else
312 rc = VERR_NO_MEMORY;
313 }
314 else
315 rc = RTErrConvertFromWin32(GetLastError());
316 }
317 else /* Legacy INF files are not supported. */
318 rc = VERR_NOT_SUPPORTED;
319 }
320 else
321 rc = RTErrConvertFromWin32(GetLastError());
322
323 RTMemFree(pInfo);
324 return rc;
325}
326
327/**
328 * Queries the "Version" section of an INF file.
329 *
330 * @returns VBox status code.
331 * @param hInf INF handle to use.
332 * @param pVer Where to return the Version section information on success.
333 */
334int VBoxWinDrvInfQuerySectionVer(HINF hInf, PVBOXWINDRVINFSEC_VERSION pVer)
335{
336 return VBoxWinDrvInfQuerySectionVerEx(hInf, 0 /* uIndex */, pVer);
337}
338
339/**
340 * Opens an INF file, extended version.
341 *
342 * @returns VBox status code.
343 * @param pwszInfFile Path to INF file to open.
344 * @param pwszClassName Class name to use.
345 * @param phInf Where to return the INF handle on success.
346 */
347int VBoxWinDrvInfOpenEx(PCRTUTF16 pwszInfFile, PRTUTF16 pwszClassName, HINF *phInf)
348{
349 HINF hInf = SetupOpenInfFileW(pwszInfFile, pwszClassName, INF_STYLE_WIN4, NULL /*__in PUINT ErrorLine */);
350 if (hInf == INVALID_HANDLE_VALUE)
351 return RTErrConvertFromWin32(GetLastError());
352
353 *phInf = hInf;
354
355 return VINF_SUCCESS;
356}
357
358/**
359 * Opens an INF file, wide char version.
360 *
361 * @returns VBox status code.
362 * @param pwszInfFile Path to INF file to open.
363 * @param phInf Where to return the INF handle on success.
364 *
365 * @note Queryies the class name automatically from the given INF file.
366 */
367int VBoxWinDrvInfOpen(PCRTUTF16 pwszInfFile, HINF *phInf)
368{
369 int rc;
370
371 GUID guid = {};
372 RTUTF16 pwszClassName[MAX_CLASS_NAME_LEN] = { };
373 if (SetupDiGetINFClassW(pwszInfFile, &guid, &(pwszClassName[0]), sizeof(pwszClassName), NULL))
374 {
375 rc = VBoxWinDrvInfOpenEx(pwszInfFile, pwszClassName, phInf);
376 }
377 else
378 rc = RTErrConvertFromWin32(GetLastError());
379
380 return rc;
381}
382
383/**
384 * Opens an INF file.
385 *
386 * @returns VBox status code.
387 * @param pszInfFile Path to INF file to open.
388 * @param phInf Where to return the INF handle on success.
389 *
390 * @note Queryies the class name automatically from the given INF file.
391 */
392int VBoxWinDrvInfOpenUtf8(const char *pszInfFile, HINF *phInf)
393{
394 PRTUTF16 pwszInfFile;
395 int rc = RTStrToUtf16(pszInfFile, &pwszInfFile);
396 AssertRCReturn(rc, rc);
397
398 rc = VBoxWinDrvInfOpen(pwszInfFile, phInf);
399
400 RTUtf16Free(pwszInfFile);
401 return rc;
402}
403
404/**
405 * Closes an INF file.
406 *
407 * @returns VBox status code.
408 * @param hInf INF handle to use.
409 */
410int VBoxWinDrvInfClose(HINF hInf)
411{
412 SetupCloseInfFile(hInf);
413
414 return VINF_SUCCESS;
415}
416
417/**
418 * Queries the first (device) model from an INF file.
419 *
420 * @returns VBox status code.
421 * @param hInf INF handle to use.
422 * @param ppwszModel Where to return the model on success.
423 * Needs to be free'd by RTUtf16Free().
424 */
425int VBoxWinDrvInfQueryFirstModel(HINF hInf, PRTUTF16 *ppwszModel)
426{
427 *ppwszModel = NULL;
428
429 return VBoxWinDrvInfQueryModelsSectionName(hInf, ppwszModel, NULL);
430}
431
432/**
433 * Queries the first PnP ID from an INF file.
434 *
435 * @returns VBox status code.
436 * @param hInf INF handle to use.
437 * @param pwszModel Model to query PnP ID for.
438 * @param ppwszPnPId Where to return the PnP ID on success.
439 * Needs to be free'd by RTUtf16Free().
440 */
441int VBoxWinDrvInfQueryFirstPnPId(HINF hInf, PRTUTF16 pwszModel, PRTUTF16 *ppwszPnPId)
442{
443 *ppwszPnPId = NULL;
444
445 PRTUTF16 pwszPnPId = NULL;
446 INFCONTEXT InfCtx;
447 int rc = VBoxWinDrvInfQueryContext(hInf, pwszModel, NULL, &InfCtx);
448 if (RT_SUCCESS(rc))
449 {
450 rc = VBoxWinDrvInfQueryKeyValue(&InfCtx, 2, &pwszPnPId, NULL);
451 if (RT_SUCCESS(rc))
452 *ppwszPnPId = pwszPnPId;
453 }
454
455 return rc;
456}
457
Note: See TracBrowser for help on using the repository browser.

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