VirtualBox

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

Last change on this file since 106389 was 106321, checked in by vboxsync, 7 months ago

Windows installers: Big revamp for removing all DIFxApp-related / DIFxApi-related code and build dependencies for the host and guest installers. bugref:10762

This implements an own framework (VBoxWinDrvInst and VBoxWinDrvStore) for installing Windows drivers and querying / handling the Windows driver store,
along with testcases for the Windows guest and host installers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1/* $Id: VBoxWinDrvCommon.cpp 106321 2024-10-15 13:06:30Z 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 * Opens an INF file, extended version.
255 *
256 * @returns VBox status code.
257 * @param pwszInfFile Path to INF file to open.
258 * @param pwszClassName Class name to use.
259 * @param phInf Where to return the INF handle on success.
260 */
261int VBoxWinDrvInfOpenEx(PCRTUTF16 pwszInfFile, PRTUTF16 pwszClassName, HINF *phInf)
262{
263 HINF hInf = SetupOpenInfFileW(pwszInfFile, pwszClassName, INF_STYLE_WIN4, NULL /*__in PUINT ErrorLine */);
264 if (hInf == INVALID_HANDLE_VALUE)
265 return RTErrConvertFromWin32(GetLastError());
266
267 *phInf = hInf;
268
269 return VINF_SUCCESS;
270}
271
272/**
273 * Opens an INF file, wide char version.
274 *
275 * @returns VBox status code.
276 * @param pwszInfFile Path to INF file to open.
277 * @param phInf Where to return the INF handle on success.
278 *
279 * @note Queryies the class name automatically from the given INF file.
280 */
281int VBoxWinDrvInfOpen(PCRTUTF16 pwszInfFile, HINF *phInf)
282{
283 int rc;
284
285 GUID guid = {};
286 RTUTF16 pwszClassName[MAX_CLASS_NAME_LEN] = { };
287 if (SetupDiGetINFClassW(pwszInfFile, &guid, &(pwszClassName[0]), sizeof(pwszClassName), NULL))
288 {
289 rc = VBoxWinDrvInfOpenEx(pwszInfFile, pwszClassName, phInf);
290 }
291 else
292 rc = RTErrConvertFromWin32(GetLastError());
293
294 return rc;
295}
296
297/**
298 * Opens an INF file.
299 *
300 * @returns VBox status code.
301 * @param pszInfFile Path to INF file to open.
302 * @param phInf Where to return the INF handle on success.
303 *
304 * @note Queryies the class name automatically from the given INF file.
305 */
306int VBoxWinDrvInfOpenUtf8(const char *pszInfFile, HINF *phInf)
307{
308 PRTUTF16 pwszInfFile;
309 int rc = RTStrToUtf16(pszInfFile, &pwszInfFile);
310 AssertRCReturn(rc, rc);
311
312 rc = VBoxWinDrvInfOpen(pwszInfFile, phInf);
313
314 RTUtf16Free(pwszInfFile);
315 return rc;
316}
317
318/**
319 * Closes an INF file.
320 *
321 * @returns VBox status code.
322 * @param hInf INF handle to use.
323 */
324int VBoxWinDrvInfClose(HINF hInf)
325{
326 SetupCloseInfFile(hInf);
327
328 return VINF_SUCCESS;
329}
330
331/**
332 * Queries the first (device) model from an INF file.
333 *
334 * @returns VBox status code.
335 * @param hInf INF handle to use.
336 * @param ppwszModel Where to return the model on success.
337 * Needs to be free'd by RTUtf16Free().
338 */
339int VBoxWinDrvInfQueryFirstModel(HINF hInf, PRTUTF16 *ppwszModel)
340{
341 *ppwszModel = NULL;
342
343 return VBoxWinDrvInfQueryModelsSectionName(hInf, ppwszModel, NULL);
344}
345
346/**
347 * Queries the first PnP ID from an INF file.
348 *
349 * @returns VBox status code.
350 * @param hInf INF handle to use.
351 * @param pwszModel Model to query PnP ID for.
352 * @param ppwszPnPId Where to return the PnP ID on success.
353 * Needs to be free'd by RTUtf16Free().
354 */
355int VBoxWinDrvInfQueryFirstPnPId(HINF hInf, PRTUTF16 pwszModel, PRTUTF16 *ppwszPnPId)
356{
357 *ppwszPnPId = NULL;
358
359 PRTUTF16 pwszPnPId = NULL;
360 INFCONTEXT InfCtx;
361 int rc = VBoxWinDrvInfQueryContext(hInf, pwszModel, NULL, &InfCtx);
362 if (RT_SUCCESS(rc))
363 {
364 rc = VBoxWinDrvInfQueryKeyValue(&InfCtx, 2, &pwszPnPId, NULL);
365 if (RT_SUCCESS(rc))
366 *ppwszPnPId = pwszPnPId;
367 }
368
369 return rc;
370}
371
Note: See TracBrowser for help on using the repository browser.

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