VirtualBox

source: vbox/trunk/src/VBox/GuestHost/installation/VBoxWinDrvInst.cpp@ 108014

Last change on this file since 108014 was 107994, checked in by vboxsync, 4 weeks ago

Windows driver installation: Fixed vboxWinDrvInstControlServiceEx() naming and made a bit more clear how to use the timeout value + log it. bugref:10762

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 103.6 KB
Line 
1/* $Id: VBoxWinDrvInst.cpp 107994 2025-01-30 15:59:32Z vboxsync $ */
2/** @file
3 * VBoxWinDrvInst - Windows driver installation handling.
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#ifdef RT_ARCH_X86
37# include <wintrust.h>
38# include <softpub.h>
39#endif
40
41#include <iprt/assert.h>
42#include <iprt/buildconfig.h>
43#include <iprt/cdefs.h>
44#include <iprt/dir.h>
45#include <iprt/ldr.h>
46#include <iprt/list.h>
47#include <iprt/mem.h>
48#include <iprt/once.h>
49#include <iprt/path.h>
50#include <iprt/stream.h>
51#include <iprt/string.h>
52#include <iprt/system.h>
53#include <iprt/thread.h> /* For RTThreadSleep(). */
54#include <iprt/utf16.h>
55
56#include <package-generated.h>
57#include "product-generated.h"
58
59#include <VBox/err.h> /* For VERR_PLATFORM_ARCH_NOT_SUPPORTED.*/
60#include <VBox/version.h>
61
62#include <VBox/GuestHost/VBoxWinDrvDefs.h>
63#include <VBox/GuestHost/VBoxWinDrvInst.h>
64#include <VBox/GuestHost/VBoxWinDrvStore.h>
65
66#include "VBoxWinDrvCommon.h"
67#include "VBoxWinDrvInstInternal.h"
68
69
70/*********************************************************************************************************************************
71* Defines *
72*********************************************************************************************************************************/
73
74/* Defines from newdev.h (WINVER >= _WIN32_WINNT_VISTA). */
75#define DIIRFLAG_INF_ALREADY_COPIED 0x00000001
76#define DIIRFLAG_FORCE_INF 0x00000002
77#define DIIRFLAG_HW_USING_THE_INF 0x00000004
78#define DIIRFLAG_HOTPATCH 0x00000008
79#define DIIRFLAG_NOBACKUP 0x00000010
80
81
82/* SetupUninstallOEMInf Flags values. */
83#define SUOI_FORCEDELETE 0x00000001
84
85
86/*********************************************************************************************************************************
87* Defined Constants And Macros *
88*********************************************************************************************************************************/
89/** The magic value for RTFTPSERVERINTERNAL::u32Magic. */
90#define VBOXWINDRVINST_MAGIC UINT32_C(0x20171201)
91
92/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
93#define VBOXWINDRVINST_VALID_RETURN_RC(hDrvInst, a_rc) \
94 do { \
95 AssertPtrReturn((hDrvInst), (a_rc)); \
96 AssertReturn((hDrvInst)->u32Magic == VBOXWINDRVINST_MAGIC, (a_rc)); \
97 } while (0)
98
99/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
100#define VBOXWINDRVINST_VALID_RETURN(hDrvInst) VBOXWINDRVINST_VALID_RETURN_RC((hDrvInst), VERR_INVALID_HANDLE)
101
102/** Validates a handle and returns (void) if not valid. */
103#define VBOXWINDRVINST_VALID_RETURN_VOID(hDrvInst) \
104 do { \
105 AssertPtrReturnVoid(hDrvInst); \
106 AssertReturnVoid((hDrvInst)->u32Magic == VBOXWINDRVINST_MAGIC); \
107 } while (0)
108
109
110/*********************************************************************************************************************************
111* Structures and Typedefs *
112*********************************************************************************************************************************/
113/* newdev.dll: */
114typedef BOOL(WINAPI* PFNDIINSTALLDRIVERW) (HWND hwndParent, LPCWSTR InfPath, DWORD Flags, PBOOL NeedReboot);
115typedef BOOL(WINAPI* PFNDIUNINSTALLDRIVERW) (HWND hwndParent, LPCWSTR InfPath, DWORD Flags, PBOOL NeedReboot);
116typedef BOOL(WINAPI* PFNUPDATEDRIVERFORPLUGANDPLAYDEVICESW) (HWND hwndParent, LPCWSTR HardwareId, LPCWSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired);
117/* setupapi.dll: */
118typedef VOID(WINAPI* PFNINSTALLHINFSECTIONW) (HWND Window, HINSTANCE ModuleHandle, PCWSTR CommandLine, INT ShowCommand);
119typedef BOOL(WINAPI* PFNSETUPCOPYOEMINFW) (PCWSTR SourceInfFileName, PCWSTR OEMSourceMediaLocation, DWORD OEMSourceMediaType, DWORD CopyStyle, PWSTR DestinationInfFileName, DWORD DestinationInfFileNameSize, PDWORD RequiredSize, PWSTR DestinationInfFileNameComponent);
120typedef HINF(WINAPI* PFNSETUPOPENINFFILEW) (PCWSTR FileName, PCWSTR InfClass, DWORD InfStyle, PUINT ErrorLine);
121typedef VOID(WINAPI* PFNSETUPCLOSEINFFILE) (HINF InfHandle);
122typedef BOOL(WINAPI* PFNSETUPDIGETINFCLASSW) (PCWSTR, LPGUID, PWSTR, DWORD, PDWORD);
123typedef BOOL(WINAPI* PFNSETUPUNINSTALLOEMINFW) (PCWSTR InfFileName, DWORD Flags, PVOID Reserved);
124typedef BOOL(WINAPI *PFNSETUPSETNONINTERACTIVEMODE) (BOOL NonInteractiveFlag);
125/* advapi32.dll: */
126typedef BOOL(WINAPI *PFNQUERYSERVICESTATUSEX) (SC_HANDLE, SC_STATUS_TYPE, LPBYTE, DWORD, LPDWORD);
127
128/** Function pointer for a general try INF section callback. */
129typedef int (*PFNVBOXWINDRVINST_TRYINFSECTION_CALLBACK)(HINF hInf, PCRTUTF16 pwszSection, void *pvCtx);
130
131
132/*********************************************************************************************************************************
133* Global Variables *
134*********************************************************************************************************************************/
135/** Init once structure for run-as-user functions we need. */
136DECL_HIDDEN_DATA(RTONCE) g_vboxWinDrvInstResolveOnce = RTONCE_INITIALIZER;
137
138/* newdev.dll: */
139DECL_HIDDEN_DATA(PFNDIINSTALLDRIVERW) g_pfnDiInstallDriverW = NULL; /* For Vista+ .*/
140DECL_HIDDEN_DATA(PFNDIUNINSTALLDRIVERW) g_pfnDiUninstallDriverW = NULL; /* Since Win 10 version 1703. */
141DECL_HIDDEN_DATA(PFNUPDATEDRIVERFORPLUGANDPLAYDEVICESW) g_pfnUpdateDriverForPlugAndPlayDevicesW = NULL; /* For < Vista .*/
142/* setupapi.dll: */
143DECL_HIDDEN_DATA(PFNINSTALLHINFSECTIONW) g_pfnInstallHinfSectionW = NULL; /* For W2K+. */
144DECL_HIDDEN_DATA(PFNSETUPCOPYOEMINFW) g_pfnSetupCopyOEMInfW = NULL; /* For W2K+. */
145DECL_HIDDEN_DATA(PFNSETUPOPENINFFILEW) g_pfnSetupOpenInfFileW = NULL; /* For W2K+. */
146DECL_HIDDEN_DATA(PFNSETUPCLOSEINFFILE) g_pfnSetupCloseInfFile = NULL; /* For W2K+. */
147DECL_HIDDEN_DATA(PFNSETUPDIGETINFCLASSW) g_pfnSetupDiGetINFClassW = NULL; /* For W2K+. */
148DECL_HIDDEN_DATA(PFNSETUPUNINSTALLOEMINFW) g_pfnSetupUninstallOEMInfW = NULL; /* For XP+. */
149DECL_HIDDEN_DATA(PFNSETUPSETNONINTERACTIVEMODE) g_pfnSetupSetNonInteractiveMode = NULL; /* For W2K+. */
150/* advapi32.dll: */
151DECL_HIDDEN_DATA(PFNQUERYSERVICESTATUSEX) g_pfnQueryServiceStatusEx = NULL; /* For W2K+. */
152
153/**
154 * Structure for keeping the internal Windows driver context.
155 */
156typedef struct VBOXWINDRVINSTINTERNAL
157{
158 /** Magic value. */
159 uint32_t u32Magic;
160 /** Callback function for logging output. Optional and can be NULL. */
161 PFNVBOXWINDRIVERLOGMSG pfnLog;
162 /** User-supplied pointer for \a pfnLog. Optional and can be NULL. */
163 void *pvUser;
164 /** Currently set verbosity level. */
165 unsigned uVerbosity;
166 /** Number of (logged) warnings. */
167 unsigned cWarnings;
168 /** Number of (logged) errors. */
169 unsigned cErrors;
170 /** Whether a reboot is needed in order to perform the current (un)installation. */
171 bool fReboot;
172 /** OS version to use. Detected on creation. RTSYSTEM_NT_VERSION_GET_XXX style.
173 * Can be overwritten via VBoxWinDrvInstSetOsVersion(). */
174 uint64_t uOsVer;
175 /** Parameters for (un)installation. */
176 VBOXWINDRVINSTPARMS Parms;
177 /** Driver store entry to use. */
178 PVBOXWINDRVSTORE pStore;
179} VBOXWINDRVINSTINTERNAL;
180/** Pointer to an internal Windows driver installation context. */
181typedef VBOXWINDRVINSTINTERNAL *PVBOXWINDRVINSTINTERNAL;
182
183/**
184 * Structure for holding a single DLL import symbol.
185 *
186 * Ordinal currently ignored.
187 */
188typedef struct VBOXWINDRVINSTIMPORTSYMBOL
189{
190 /** Symbol name. */
191 const char *pszSymbol;
192 /** Function pointer. */
193 void **pfnFunc;
194} VBOXWINDRVINSTIMPORTSYMBOL;
195
196
197/*********************************************************************************************************************************
198* Prototypes *
199*********************************************************************************************************************************/
200static int vboxWinDrvParmsDetermine(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms, bool fForce);
201
202
203/*********************************************************************************************************************************
204* Import tables *
205*********************************************************************************************************************************/
206
207/* setupapi.dll: */
208static VBOXWINDRVINSTIMPORTSYMBOL s_aSetupApiImports[] =
209{
210 { "InstallHinfSectionW", (void **)&g_pfnInstallHinfSectionW },
211 { "SetupCopyOEMInfW", (void **)&g_pfnSetupCopyOEMInfW },
212 { "SetupUninstallOEMInfW", (void **)&g_pfnSetupUninstallOEMInfW },
213 { "SetupOpenInfFileW", (void **)&g_pfnSetupOpenInfFileW },
214 { "SetupCloseInfFile", (void **)&g_pfnSetupCloseInfFile },
215 { "SetupDiGetINFClassW", (void **)&g_pfnSetupDiGetINFClassW },
216 { "SetupSetNonInteractiveMode", (void **)&g_pfnSetupSetNonInteractiveMode }
217};
218
219/* newdev.dll: */
220static VBOXWINDRVINSTIMPORTSYMBOL s_aNewDevImports[] =
221{
222 /* Only for Vista / 2008 Server and up. */
223 { "DiInstallDriverW", (void **)&g_pfnDiInstallDriverW },
224 { "DiUninstallDriverW", (void **)&g_pfnDiUninstallDriverW },
225 /* Anything older (must support Windows 2000). */
226 { "UpdateDriverForPlugAndPlayDevicesW", (void **)&g_pfnUpdateDriverForPlugAndPlayDevicesW }
227};
228
229/* newdev.dll: */
230static VBOXWINDRVINSTIMPORTSYMBOL s_aAdvApi32Imports[] =
231{
232 /* Only for Windows 2000 and up. */
233 { "QueryServiceStatusEx", (void **)&g_pfnQueryServiceStatusEx }
234};
235
236
237/*********************************************************************************************************************************
238* Implementation *
239*********************************************************************************************************************************/
240
241/**
242 * Logs message, va_list version.
243 *
244 * @returns VBox status code.
245 * @param pCtx Windows driver installer context.
246 * @param enmType Log type to use.
247 * @param pszFormat Format string to log.
248 * @param args va_list to use.
249 */
250DECLINLINE(void) vboxWinDrvInstLogExV(PVBOXWINDRVINSTINTERNAL pCtx,
251 VBOXWINDRIVERLOGTYPE enmType, const char *pszFormat, va_list args)
252{
253 if (!pCtx->pfnLog)
254 return;
255
256 char *psz = NULL;
257 RTStrAPrintfV(&psz, pszFormat, args);
258 AssertPtrReturnVoid(psz);
259
260 pCtx->pfnLog(enmType, psz, pCtx->pvUser);
261 RTStrFree(psz);
262}
263
264/**
265 * Logs message, extended version.
266 *
267 * @returns VBox status code.
268 * @param pCtx Windows driver installer context.
269 * @param enmType Log type to use.
270 * @param pszFormat Format string to log.
271 */
272DECLINLINE(void) vboxWinDrvInstLogEx(PVBOXWINDRVINSTINTERNAL pCtx,
273 VBOXWINDRIVERLOGTYPE enmType, const char *pszFormat, ...)
274{
275 va_list args;
276 va_start(args, pszFormat);
277 vboxWinDrvInstLogExV(pCtx, enmType, pszFormat, args);
278 va_end(args);
279}
280
281/**
282 * Logs an error message, extended version.
283 *
284 * @returns VBox status code.
285 * @param pCtx Windows driver installer context.
286 * @param fIgnore Whether to ignore the error in the error count or not.
287 * @param pszFormat Format string to log.
288 * @param args va_list for \a pszFormat.
289 */
290DECLINLINE(void) vboxWinDrvInstLogErrorExV(PVBOXWINDRVINSTINTERNAL pCtx, bool fIgnore, const char *pszFormat, va_list args)
291{
292 vboxWinDrvInstLogExV(pCtx, VBOXWINDRIVERLOGTYPE_ERROR, pszFormat, args);
293 if (!fIgnore)
294 pCtx->cErrors++;
295}
296
297#ifdef RT_ARCH_X86
298/**
299 * Logs an error message but ignores (skips) the error count.
300 *
301 * @returns VBox status code.
302 * @param pCtx Windows driver installer context.
303 * @param pszFormat Format string to log.
304 * @param ... Variable arguments for \a pszFormat.
305 */
306DECLINLINE(void) vboxWinDrvInstLogErrorIgn(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
307{
308 va_list args;
309 va_start(args, pszFormat);
310 vboxWinDrvInstLogErrorExV(pCtx, true /* fIgnore */, pszFormat, args);
311 va_end(args);
312}
313
314/**
315 * Logs an error message, ignores (skips) the error count and returns the given rc for convenience.
316 *
317 * @returns VBox status code, given by \a rc.
318 * @param pCtx Windows driver installer context.
319 * @param rc rc to return.
320 * @param pszFormat Format string to log.
321 * @param ... Variable arguments for \a pszFormat.
322 */
323DECLINLINE(int) vboxWinDrvInstLogErrorRetIgn(PVBOXWINDRVINSTINTERNAL pCtx, int rc, const char *pszFormat, ...)
324{
325 va_list args;
326 va_start(args, pszFormat);
327 vboxWinDrvInstLogErrorExV(pCtx, true /* fIgnore */, pszFormat, args);
328 va_end(args);
329
330 return rc;
331}
332#endif /* RT_ARCH_X86 */
333
334/**
335 * Logs an error message.
336 *
337 * @returns VBox status code.
338 * @param pCtx Windows driver installer context.
339 * @param pszFormat Format string to log.
340 */
341DECLINLINE(void) vboxWinDrvInstLogError(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
342{
343 va_list args;
344 va_start(args, pszFormat);
345 vboxWinDrvInstLogErrorExV(pCtx, false /* fIgnore */, pszFormat, args);
346 va_end(args);
347}
348
349/**
350 * Logs a warning message.
351 *
352 * @returns VBox status code.
353 * @param pCtx Windows driver installer context.
354 * @param pszFormat Format string to log.
355 */
356DECLINLINE(void) vboxWinDrvInstLogWarn(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
357{
358 va_list args;
359 va_start(args, pszFormat);
360 vboxWinDrvInstLogExV(pCtx, VBOXWINDRIVERLOGTYPE_WARN, pszFormat, args);
361 va_end(args);
362
363 pCtx->cWarnings++;
364}
365
366/**
367 * Logs an information message.
368 *
369 * @returns VBox status code.
370 * @param pCtx Windows driver installer context.
371 * @param pszFormat Format string to log.
372 */
373DECLINLINE(void) vboxWinDrvInstLogInfo(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
374{
375 va_list args;
376 va_start(args, pszFormat);
377 vboxWinDrvInstLogExV(pCtx, VBOXWINDRIVERLOGTYPE_INFO, pszFormat, args);
378 va_end(args);
379}
380
381/**
382 * Logs a verbose message.
383 *
384 * @returns VBox status code.
385 * @param pCtx Windows driver installer context.
386 * @param uVerbosity Verbosity level to use for logging.
387 * @param pszFormat Format string to log.
388 */
389DECLINLINE(void) vboxWinDrvInstLogVerbose(PVBOXWINDRVINSTINTERNAL pCtx, unsigned uVerbosity, const char *pszFormat, ...)
390{
391 if (uVerbosity <= pCtx->uVerbosity)
392 {
393 va_list args;
394 va_start(args, pszFormat);
395 vboxWinDrvInstLogExV(pCtx, VBOXWINDRIVERLOGTYPE_VERBOSE, pszFormat, args);
396 va_end(args);
397 }
398}
399
400/**
401 * Logs (and indicates) that a reboot is needed.
402 *
403 * @returns VBox status code.
404 * @param pCtx Windows driver installer context.
405 * @param pszFormat Format string to log.
406 */
407DECLINLINE(void) vboxWinDrvInstLogRebootNeeded(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
408{
409 va_list args;
410 va_start(args, pszFormat);
411 vboxWinDrvInstLogExV(pCtx, VBOXWINDRIVERLOGTYPE_REBOOT_NEEDED, pszFormat, args);
412 va_end(args);
413}
414
415/**
416 * Logs the last Windows error given via GetLastError().
417 *
418 * @returns Last Windows error translated into VBox status code.
419 * @retval VERR_INSTALLATION_FAILED if a translation to a VBox status code wasn't possible.
420 * @param pCtx Windows driver installer context.
421 * @param pszFormat Format string to log.
422 */
423DECLINLINE(int) vboxWinDrvInstLogLastError(PVBOXWINDRVINSTINTERNAL pCtx, const char *pszFormat, ...)
424{
425 DWORD const dwErr = GetLastError();
426
427 va_list args;
428 va_start(args, pszFormat);
429
430 char *psz = NULL;
431 RTStrAPrintfV(&psz, pszFormat, args);
432 AssertPtrReturn(psz, VERR_NO_MEMORY);
433
434 int rc = VERR_INSTALLATION_FAILED;
435
436#ifdef DEBUG_andy
437 bool const fAssertMayPanic = RTAssertMayPanic();
438 RTAssertSetMayPanic(false);
439#endif
440
441 /* Try resolving Setup API errors first (we don't handle those in IPRT). */
442 const char *pszErr = VBoxWinDrvSetupApiErrToStr(dwErr);
443 if (!pszErr) /* Also ask for special winerr.h codes we don't handle in IPRT. */
444 pszErr = VBoxWinDrvWinErrToStr(dwErr);
445 if (!pszErr)
446 rc = RTErrConvertFromWin32(dwErr);
447
448#ifdef DEBUG_andy
449 RTAssertSetMayPanic(fAssertMayPanic);
450#endif
451
452 if (pszErr)
453 vboxWinDrvInstLogError(pCtx, "%s: %s (%ld / %#x)", psz, pszErr, dwErr, dwErr);
454 else
455 vboxWinDrvInstLogError(pCtx, "%s: %Rrc (%ld / %#x)", psz, rc, dwErr, dwErr);
456
457 RTStrFree(psz);
458
459 va_end(args);
460
461 return rc;
462}
463
464/**
465 * Resolves a single symbol of a module (DLL).
466 *
467 * @returns VBox status code.
468 * @param pCtx Windows driver installer context.
469 * @param hMod Module handle to use.
470 * @param pszSymbol Name of symbol to resolve.
471 * @param pfnFunc Where to return the function pointer for resolved symbol on success.
472 */
473DECLINLINE(int) vboxWinDrvInstInstModResolveSym(PVBOXWINDRVINSTINTERNAL pCtx, RTLDRMOD hMod, const char *pszSymbol,
474 void **pfnFunc)
475{
476 int rc = RTLdrGetSymbol(hMod, pszSymbol, pfnFunc);
477 if (RT_FAILURE(rc))
478 {
479 vboxWinDrvInstLogVerbose(pCtx, 1, "Warning: Symbol \"%s\" not found (%Rrc)", pszSymbol, rc);
480 *pfnFunc = NULL;
481 }
482
483 return rc;
484}
485
486/**
487 * Resolves symbols of a specific module (DLL).
488 *
489 * @returns VBox status code.
490 * @param pCtx Windows driver installer context.
491 * @param pszFilename Path of module to resolve symbols for.
492 * @param pSymbols Table of symbols to resolve.
493 * @param cSymbols Number of symbols within \a pSymbols to resolve.
494 */
495static DECLCALLBACK(int) vboxWinDrvInstResolveMod(PVBOXWINDRVINSTINTERNAL pCtx,
496 const char *pszFilename, VBOXWINDRVINSTIMPORTSYMBOL *pSymbols, size_t cSymbols)
497{
498 vboxWinDrvInstLogVerbose(pCtx, 1, "Resolving symbols for module \"%s\" ...", pszFilename);
499
500 RTLDRMOD hMod;
501 int rc = RTLdrLoadSystem(pszFilename, true /*fNoUnload*/, &hMod);
502 if (RT_SUCCESS(rc))
503 {
504 for (size_t i = 0; i < cSymbols; i++)
505 {
506 void *pfnFunc;
507 rc = vboxWinDrvInstInstModResolveSym(pCtx, hMod, pSymbols[i].pszSymbol, &pfnFunc);
508 if (RT_SUCCESS(rc))
509 *pSymbols[i].pfnFunc = pfnFunc;
510 }
511
512 RTLdrClose(hMod);
513 }
514 else
515 vboxWinDrvInstLogError(pCtx, "Unabled to load module \"%s\" (%Rrc)", pszFilename, rc);
516
517 return rc;
518}
519
520/**
521 * Initialize the import APIs for run-as-user and special environment support.
522 *
523 * @returns VBox status code.
524 * @param pvUser Pointer to VBOXWINDRVINSTINTERNAL.
525 */
526static DECLCALLBACK(int) vboxWinDrvInstResolveOnce(void *pvUser)
527{
528 PVBOXWINDRVINSTINTERNAL pCtx = (PVBOXWINDRVINSTINTERNAL)pvUser;
529
530 /*
531 * Note: Any use of Difx[app|api].dll imports is forbidden (and also marked as being deprecated since Windows 10)!
532 */
533
534 /* rc ignored, keep going */ vboxWinDrvInstResolveMod(pCtx, "setupapi.dll",
535 s_aSetupApiImports, RT_ELEMENTS(s_aSetupApiImports));
536 /* rc ignored, keep going */ vboxWinDrvInstResolveMod(pCtx, "newdev.dll",
537 s_aNewDevImports, RT_ELEMENTS(s_aNewDevImports));
538 /* rc ignored, keep going */ vboxWinDrvInstResolveMod(pCtx, "advapi32.dll",
539 s_aAdvApi32Imports, RT_ELEMENTS(s_aAdvApi32Imports));
540 return VINF_SUCCESS;
541}
542
543/**
544 * Initializes a driver installation parameters structure.
545 *
546 * @param pParms Installation parameters structure to initialize.
547 */
548static void vboxWinDrvInstParmsInit(PVBOXWINDRVINSTPARMS pParms)
549{
550 RT_BZERO(pParms, sizeof(VBOXWINDRVINSTPARMS));
551}
552
553/**
554 * Destroys a driver installation parameters structure.
555 *
556 * @param pParms Installation parameters structure to destroy.
557 */
558static void vboxWinDrvInstParmsDestroy(PVBOXWINDRVINSTPARMS pParms)
559{
560 switch (pParms->enmMode)
561 {
562 case VBOXWINDRVINSTMODE_INSTALL:
563 case VBOXWINDRVINSTMODE_UNINSTALL:
564 {
565 RTUtf16Free(pParms->u.UnInstall.pwszModel);
566 pParms->u.UnInstall.pwszModel = NULL;
567 RTUtf16Free(pParms->u.UnInstall.pwszPnpId);
568 pParms->u.UnInstall.pwszPnpId = NULL;
569 RTUtf16Free(pParms->u.UnInstall.pwszSection);
570 pParms->u.UnInstall.pwszSection = NULL;
571 break;
572 }
573
574 case VBOXWINDRVINSTMODE_INSTALL_INFSECTION:
575 case VBOXWINDRVINSTMODE_UNINSTALL_INFSECTION:
576 {
577 RTUtf16Free(pParms->u.ExecuteInf.pwszSection);
578 pParms->u.ExecuteInf.pwszSection = NULL;
579 break;
580 }
581
582 case VBOXWINDRVINSTMODE_INVALID:
583 break;
584
585 default:
586 AssertFailed();
587 break;
588 }
589
590 RTUtf16Free(pParms->pwszInfFile);
591 pParms->pwszInfFile = NULL;
592}
593
594/**
595 * Structure for keeping callback data for vboxDrvInstExecuteInfFileCallback().
596 */
597typedef struct VBOXDRVINSTINFCALLBACKCTX
598{
599 /** Pointer to driver installer instance. */
600 PVBOXWINDRVINSTINTERNAL pThis;
601 /** Weak pointer to INF section being handled. */
602 PCRTUTF16 pwszSection;
603 /** User-supplied context pointer. */
604 void *pvSetupContext;
605} VBOXDRVINSTINFCALLBACKCTX;
606/** Pointer to structure for keeping callback data for vboxDrvInstExecuteInfFileCallback(). */
607typedef VBOXDRVINSTINFCALLBACKCTX *PVBOXDRVINSTINFCALLBACKCTX;
608
609/** Callback for SetupInstallFromInfSectionW(). */
610RT_C_DECLS_BEGIN /** @todo r=andy Not sure if we have something else to use. */
611static UINT WINAPI vboxDrvInstExecuteInfFileCallback(PVOID pvCtx,
612 UINT uNotification,
613 UINT_PTR Param1,
614 UINT_PTR Param2)
615{
616 RT_NOREF(Param2);
617
618 PVBOXDRVINSTINFCALLBACKCTX pCtx = (PVBOXDRVINSTINFCALLBACKCTX)pvCtx;
619
620 vboxWinDrvInstLogVerbose(pCtx->pThis, 4, "Got installation notification %#x", uNotification);
621
622 switch (uNotification)
623 {
624 case SPFILENOTIFY_NEEDMEDIA:
625 {
626 PSOURCE_MEDIA_W pSourceMedia = (PSOURCE_MEDIA_W)Param1;
627 vboxWinDrvInstLogInfo(pCtx->pThis, "Requesting installation media \"%ls\\%ls\"...",
628 pSourceMedia->SourcePath, pSourceMedia->SourceFile);
629 break;
630 }
631
632 case SPFILENOTIFY_STARTCOPY:
633 case SPFILENOTIFY_ENDCOPY:
634 {
635 PFILEPATHS_W pFilePaths = (PFILEPATHS_W)Param1;
636 vboxWinDrvInstLogInfo(pCtx->pThis, "%s copying \"%ls\" -> \"%ls\"",
637 uNotification == SPFILENOTIFY_STARTCOPY
638 ? "Started" : "Finished", pFilePaths->Source, pFilePaths->Target);
639 break;
640 }
641
642 case SPFILENOTIFY_RENAMEERROR:
643 case SPFILENOTIFY_DELETEERROR:
644 case SPFILENOTIFY_COPYERROR:
645 {
646 PFILEPATHS_W pFilePaths = (PFILEPATHS_W)Param1;
647 vboxWinDrvInstLogError(pCtx->pThis, "Rename/Delete/Copy error \"%ls\" -> \"%s\" (%#x)",
648 pFilePaths->Source, pFilePaths->Target, pFilePaths->Win32Error);
649 break;
650 }
651
652 case SPFILENOTIFY_TARGETNEWER:
653 vboxWinDrvInstLogInfo(pCtx->pThis, "A newer version of the specified file exists on the target");
654 break;
655
656 case SPFILENOTIFY_TARGETEXISTS:
657 vboxWinDrvInstLogInfo(pCtx->pThis, "A copy of the specified file already exists on the target");
658 break;
659
660 default:
661 break;
662 }
663
664 return SetupDefaultQueueCallbackW(pCtx->pvSetupContext, uNotification, Param1, Param2);;
665}
666RT_C_DECLS_END
667
668/**
669 * Generic function to for probing a list of well-known sections for [un]installation.
670 *
671 * Due to the nature of INF files this function tries different combinations of decorations (e.g. SectionName[.NTAMD64|.X86])
672 * and invokes the given callback for the first found section.
673 *
674 * @returns VBox status code.
675 * @param pCtx Windows driver installer context.
676 * @param hInf Handle of INF file.
677 * @param pwszSection Section to invoke for [un]installation.
678 * If NULL, the "DefaultInstall" / "DefaultUninstall" section will be tried.
679 * @param pfnCallback Callback to invoke for each found section.
680 */
681static int vboxWinDrvTryInfSectionEx(PVBOXWINDRVINSTINTERNAL pCtx, HINF hInf, PCRTUTF16 pwszSection,
682 PFNVBOXWINDRVINST_TRYINFSECTION_CALLBACK pfnCallback)
683{
684 if (pwszSection)
685 vboxWinDrvInstLogVerbose(pCtx, 1, "Trying section \"%ls\"", pwszSection);
686
687 /* Sorted by most likely-ness. */
688 PCRTUTF16 apwszTryInstallSections[] =
689 {
690 /* The more specific (using decorations), the better. Try these first. Might be NULL. */
691 pwszSection,
692 /* The Default[Un]Install sections apply to primitive (and legacy) drivers. */
693 pCtx->Parms.enmMode == VBOXWINDRVINSTMODE_INSTALL
694 ? L"DefaultInstall" : L"DefaultUninstall"
695 };
696
697 PCRTUTF16 apwszTryInstallDecorations[] =
698 {
699 /* No decoration. Try that first. */
700 L"",
701 /* Native architecture. */
702 L"" VBOXWINDRVINF_DOT_NT_NATIVE_ARCH_STR
703 };
704
705 int rc = VERR_NOT_FOUND;
706
707 for (size_t i = 0; i < RT_ELEMENTS(apwszTryInstallSections); i++)
708 {
709 PCRTUTF16 const pwszTrySection = apwszTryInstallSections[i];
710 if (!pwszTrySection)
711 continue;
712
713 for (size_t d = 0; d < RT_ELEMENTS(apwszTryInstallDecorations); d++)
714 {
715 RTUTF16 wszTrySection[64];
716 rc = RTUtf16Copy(wszTrySection, sizeof(wszTrySection), pwszTrySection);
717 AssertRCBreak(rc);
718 rc = RTUtf16Cat(wszTrySection, sizeof(wszTrySection), apwszTryInstallDecorations[d]);
719 AssertRCBreak(rc);
720
721 rc = pfnCallback(hInf, wszTrySection, pCtx /* pvCtx */);
722 if (RT_SUCCESS(rc))
723 break;
724
725 if (rc == VERR_FILE_NOT_FOUND) /* File gone already. */
726 {
727 rc = VINF_SUCCESS;
728 break;
729 }
730
731 if (rc != VERR_NOT_FOUND)
732 vboxWinDrvInstLogError(pCtx, "Trying INF section failed with %Rrc", rc);
733 }
734
735 if (RT_SUCCESS(rc)) /* Bail out if callback above succeeded. */
736 break;
737 }
738
739 if (rc == VERR_NOT_FOUND)
740 {
741 vboxWinDrvInstLogWarn(pCtx, "No matching sections to try found -- buggy driver?");
742 rc = VINF_SUCCESS;
743 }
744
745 return rc;
746}
747
748/**
749 * Generic function to for probing a list of well-known sections for [un]installation.
750 *
751 * Due to the nature of INF files this function tries different combinations of decorations (e.g. SectionName[.NTAMD64|.X86])
752 * and invokes the given callback for the first found section.
753 *
754 * @returns VBox status code.
755 * @param pCtx Windows driver installer context.
756 * @param pwszInfPathAbs Absolute path of INF file to use for [un]installation.
757 * @param pwszSection Section to invoke for [un]installation.
758 * If NULL, the "DefaultInstall" / "DefaultUninstall" section will be tried.
759 * @param pfnCallback Callback to invoke for each found section.
760 */
761static int vboxWinDrvTryInfSection(PVBOXWINDRVINSTINTERNAL pCtx, PCRTUTF16 pwszInfPathAbs, PCRTUTF16 pwszSection,
762 PFNVBOXWINDRVINST_TRYINFSECTION_CALLBACK pfnCallback)
763{
764 HINF hInf;
765 int rc = VBoxWinDrvInfOpen(pwszInfPathAbs, &hInf);
766 if (RT_FAILURE(rc))
767 {
768 vboxWinDrvInstLogError(pCtx, "Unable to open INF file: %Rrc\n", rc);
769 return rc;
770 }
771 vboxWinDrvInstLogVerbose(pCtx, 1, "INF file \"%ls\" opened", pwszInfPathAbs);
772
773 rc = vboxWinDrvTryInfSectionEx(pCtx, hInf, pwszSection, pfnCallback);
774
775 VBoxWinDrvInfClose(hInf);
776 vboxWinDrvInstLogVerbose(pCtx, 1, "INF file \"%ls\" closed", pwszInfPathAbs);
777
778 return rc;
779}
780
781/**
782 * Uninstalls a section of a given INF file.
783 *
784 * @returns VBox status code.
785 * @retval VERR_NOT_FOUND if the given section has not been found.
786 * @param pCtx Windows driver installer context.
787 * @param hInf Handle of INF file.
788 * @param pwszSection Section within INF file to uninstall.
789 * Can have a platform decoration (e.g. "Foobar.NTx86").
790 */
791static int vboxWinDrvUninstallInfSectionEx(PVBOXWINDRVINSTINTERNAL pCtx, HINF hInf, PCRTUTF16 pwszSection)
792{
793 AssertPtrReturn(pwszSection, VERR_INVALID_POINTER);
794
795 int rc = VINF_SUCCESS;
796
797 vboxWinDrvInstLogInfo(pCtx, "Uninstalling INF section \"%ls\" ...", pwszSection);
798
799 /*
800 * Uninstall services (if any).
801 */
802 RTUTF16 wszSection[64];
803 ssize_t const cwchSection = RTUtf16Printf(wszSection, RT_ELEMENTS(wszSection),
804 "%ls%s", pwszSection, ".Services");
805 if (cwchSection > 0)
806 {
807 /* We always want to be the first service tag in the group order list (if any). */
808 DWORD fFlags = SPSVCINST_TAGTOFRONT;
809 BOOL fRc = SetupInstallServicesFromInfSectionW(hInf, wszSection, fFlags);
810 if (!fRc)
811 {
812 DWORD const dwErr = GetLastError();
813 if (dwErr == ERROR_SECTION_NOT_FOUND)
814 {
815 vboxWinDrvInstLogVerbose(pCtx, 1, "INF section \"%ls\" not found", wszSection);
816 rc = VERR_NOT_FOUND;
817 }
818 else
819 {
820 rc = vboxWinDrvInstLogLastError(pCtx, "Could not uninstall INF services section \"%ls\"", wszSection);
821 if (rc == VERR_FILE_NOT_FOUND)
822 {
823 /* Hint: Getting VERR_FILE_NOT_FOUND here might mean that an old service entry still is dangling around.
824 * 'sc query <service name> won't show this, however.
825 * Use 'sc delete <service name>' to delete the leftover. */
826 vboxWinDrvInstLogError(pCtx,
827 "Hint: An old service (SCM) entry might be dangling around.\n"
828 "Try removing it via 'sc delete <service name>' and try again.");
829 }
830 }
831 }
832 else
833 vboxWinDrvInstLogInfo(pCtx, "Uninstalling INF services section \"%ls\" successful", wszSection);
834
835 }
836 else
837 {
838 vboxWinDrvInstLogError(pCtx, "Unable to build uninstallation section string");
839 rc = VERR_BUFFER_OVERFLOW;
840 }
841
842 return rc;
843}
844
845/**
846 * Installs a section of a given INF file.
847 *
848 * @returns VBox status code.
849 * @retval VERR_NOT_FOUND if the given section has not been found.
850 * @param pCtx Windows driver installer context.
851 * @param hInf Handle of INF file.
852 * @param pwszSection Section within INF file to install.
853 * Can have a platform decoration (e.g. "Foobar.NTx86").
854 */
855static int vboxWinDrvInstallInfSectionEx(PVBOXWINDRVINSTINTERNAL pCtx, HINF hInf, PCRTUTF16 pwszSection)
856{
857 AssertPtrReturn(pwszSection, VERR_INVALID_POINTER);
858
859 int rc = VINF_SUCCESS;
860
861 vboxWinDrvInstLogInfo(pCtx, "Installing INF section \"%ls\" ...", pwszSection);
862
863 VBOXDRVINSTINFCALLBACKCTX CallbackCtx;
864 RT_ZERO(CallbackCtx);
865 CallbackCtx.pThis = pCtx;
866 CallbackCtx.pwszSection = pwszSection;
867 CallbackCtx.pvSetupContext = SetupInitDefaultQueueCallback(NULL);
868
869 BOOL fRc = SetupInstallFromInfSectionW(NULL, // hWndOwner
870 hInf,
871 pwszSection,
872 SPINST_ALL, // Flags
873 NULL, // RelativeKeyRoot
874 NULL, // SourceRootPath
875 SP_COPY_NOSKIP
876 | SP_COPY_IN_USE_NEEDS_REBOOT,
877 vboxDrvInstExecuteInfFileCallback,
878 &CallbackCtx,
879 NULL, // DeviceInfoSet
880 NULL); // DeviceInfoData
881 if (fRc)
882 {
883 vboxWinDrvInstLogInfo(pCtx, "Installing INF section \"%ls\" successful", pwszSection);
884 }
885 else
886 {
887 DWORD const dwErr = GetLastError();
888 /* Seems like newer Windows OSes (seen on Win10) don't like undecorated sections with SetupInstallFromInfSectionW().
889 * So ignore this and continue. */
890 if (dwErr == ERROR_BADKEY)
891 {
892 vboxWinDrvInstLogVerbose(pCtx, 1, "Installing INF section \"%ls\" failed with %#x (%d), ignoring",
893 pwszSection, dwErr, dwErr);
894 }
895 else
896 rc = vboxWinDrvInstLogLastError(pCtx, "Installing INF section \"%ls\" failed", pwszSection);
897 }
898
899 /*
900 * Try install services.
901 */
902 RTUTF16 wszSection[64];
903 ssize_t const cwchSection = RTUtf16Printf(wszSection, RT_ELEMENTS(wszSection),
904 "%ls%ls%s", pwszSection, VBOXWINDRVINF_DECORATION_SEP_UTF16_STR, "Services");
905 if (cwchSection > 0)
906 {
907 /* We always want to be the first service tag in the group order list (if any). */
908 DWORD const fFlags = SPSVCINST_TAGTOFRONT;
909 fRc = SetupInstallServicesFromInfSectionW(hInf, wszSection, fFlags);
910 if (!fRc)
911 {
912 DWORD const dwErr = GetLastError();
913 if (dwErr == ERROR_SECTION_NOT_FOUND)
914 {
915 vboxWinDrvInstLogVerbose(pCtx, 1, "INF section \"%ls\" not found, skipping", wszSection);
916 rc = VERR_NOT_FOUND;
917 }
918 else if (dwErr == ERROR_SERVICE_MARKED_FOR_DELETE)
919 vboxWinDrvInstLogWarn(pCtx, "Service in INF section \"%ls\" already marked for deletion, skipping", wszSection);
920 else if (dwErr == ERROR_SERVICE_CANNOT_ACCEPT_CTRL)
921 vboxWinDrvInstLogWarn(pCtx, "Service in INF section \"%ls\" does not accept any control commands (probably in starting/stopping state), skipping", wszSection);
922 else
923 {
924 rc = vboxWinDrvInstLogLastError(pCtx, "Could not install INF services section \"%ls\"", wszSection);
925 if (rc == VERR_FILE_NOT_FOUND)
926 {
927 /* Hint: Getting VERR_FILE_NOT_FOUND here might mean that an old service entry still is dangling around.
928 * 'sc query <service name> won't show this, however.
929 * Use 'sc delete <service name>' to delete the leftover. */
930 vboxWinDrvInstLogError(pCtx, "An old service (SCM) entry might be dangling around.");
931 vboxWinDrvInstLogInfo (pCtx, "Try removing it via 'sc delete <service name>' and try again.");
932 }
933 }
934 }
935 else
936 vboxWinDrvInstLogInfo(pCtx, "Installing INF services section \"%ls\" successful", wszSection);
937
938 }
939 else
940 {
941 vboxWinDrvInstLogError(pCtx, "Unable to build section string");
942 rc = VERR_BUFFER_OVERFLOW;
943 }
944
945 if (CallbackCtx.pvSetupContext)
946 {
947 SetupTermDefaultQueueCallback(CallbackCtx.pvSetupContext);
948 CallbackCtx.pvSetupContext = NULL;
949 }
950
951 return rc;
952}
953
954/**
955 * Installs a section of a given INF file.
956 *
957 * Only supported for the VBOXWINDRVINSTMODE_INSTALL_INFSECTION + VBOXWINDRVINSTMODE_UNINSTALL_INFSECTION modes.
958 *
959 * @returns VBox status code.
960 * @retval VERR_NOT_FOUND if the given section has not been found.
961 * @param pCtx Windows driver installer context.
962 * @param pParms Windows driver installation parameters to use.
963 */
964static int vboxWinDrvInstallInfSection(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms)
965{
966 AssertReturn( pParms->enmMode == VBOXWINDRVINSTMODE_INSTALL_INFSECTION
967 || pParms->enmMode == VBOXWINDRVINSTMODE_UNINSTALL_INFSECTION, VERR_INVALID_PARAMETER);
968
969 HINF hInf;
970 int rc = VBoxWinDrvInfOpen(pParms->pwszInfFile, &hInf);
971 if (RT_FAILURE(rc))
972 {
973 vboxWinDrvInstLogError(pCtx, "Unable to open INF file: %Rrc\n", rc);
974 return rc;
975 }
976
977 vboxWinDrvInstLogVerbose(pCtx, 1, "INF file \"%ls\" opened", pParms->pwszInfFile);
978
979 rc = vboxWinDrvInstallInfSectionEx(pCtx, hInf, pParms->u.ExecuteInf.pwszSection);
980
981 VBoxWinDrvInfClose(hInf);
982 vboxWinDrvInstLogVerbose(pCtx, 1, "INF file \"%ls\" closed", pParms->pwszInfFile);
983
984 return rc;
985}
986
987/**
988 * Callback implementation for invoking a section for installation.
989 *
990 * @returns VBox status code.
991 * @param hInf Handle of INF file to use.
992 * @param pwszSection Section to invoke.
993 * @param pvCtx User-supplied pointer. Usually PVBOXWINDRVINSTINTERNAL.
994 */
995DECLCALLBACK(int) vboxWinDrvInstallTryInfSectionCallback(HINF hInf, PCRTUTF16 pwszSection, void *pvCtx)
996{
997 PVBOXWINDRVINSTINTERNAL pCtx = (PVBOXWINDRVINSTINTERNAL)pvCtx;
998
999 return vboxWinDrvInstallInfSectionEx(pCtx, hInf, pwszSection);
1000}
1001
1002#ifdef RT_ARCH_X86
1003/** Static pointer to the internal driver installer handle, used by vboxWinDrvInterceptedWinVerifyTrust(). */
1004static PVBOXWINDRVINSTINTERNAL s_vboxWinDrvInterceptedWinVerifyTrustCtx = NULL;
1005
1006/**
1007 * Interceptor WinVerifyTrust function for SetupApi.dll on Windows 2000, XP,
1008 * W2K3 and XP64.
1009 *
1010 * This crudely modifies the driver verification request from a WHQL/logo driver
1011 * check to a simple Authenticode check.
1012 *
1013 * s_vboxWinDrvInterceptedWinVerifyTrustCtx must be set.
1014 */
1015static LONG WINAPI vboxWinDrvInterceptedWinVerifyTrust(HWND hwnd, GUID *pActionId, void *pvData)
1016{
1017 AssertPtrReturn(s_vboxWinDrvInterceptedWinVerifyTrustCtx, TRUST_E_SYSTEM_ERROR);
1018
1019 /*
1020 * Resolve the real WinVerifyTrust function.
1021 */
1022 static decltype(WinVerifyTrust) * volatile s_pfnRealWinVerifyTrust = NULL;
1023 decltype(WinVerifyTrust) *pfnRealWinVerifyTrust = s_pfnRealWinVerifyTrust;
1024 if (!pfnRealWinVerifyTrust)
1025 {
1026 HMODULE hmod = GetModuleHandleW(L"WINTRUST.DLL");
1027 if (!hmod)
1028 hmod = LoadLibraryW(L"WINTRUST.DLL");
1029 if (!hmod)
1030 {
1031 vboxWinDrvInstLogErrorIgn(s_vboxWinDrvInterceptedWinVerifyTrustCtx, "InterceptedWinVerifyTrust: Failed to load wintrust.dll");
1032 return TRUST_E_SYSTEM_ERROR;
1033 }
1034 pfnRealWinVerifyTrust = (decltype(WinVerifyTrust) *)GetProcAddress(hmod, "WinVerifyTrust");
1035 if (!pfnRealWinVerifyTrust)
1036 {
1037 vboxWinDrvInstLogErrorIgn(s_vboxWinDrvInterceptedWinVerifyTrustCtx, "InterceptedWinVerifyTrust: Failed to locate WinVerifyTrust in wintrust.dll");
1038 return TRUST_E_SYSTEM_ERROR;
1039 }
1040 s_pfnRealWinVerifyTrust = pfnRealWinVerifyTrust;
1041 }
1042
1043 /*
1044 * Modify the ID if appropriate.
1045 */
1046 static const GUID s_GuidDriverActionVerify = DRIVER_ACTION_VERIFY;
1047 static const GUID s_GuidActionGenericChainVerify = WINTRUST_ACTION_GENERIC_CHAIN_VERIFY;
1048 static const GUID s_GuidActionGenericVerify2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
1049 if (pActionId)
1050 {
1051 if (memcmp(pActionId, &s_GuidDriverActionVerify, sizeof(*pActionId)) == 0)
1052 {
1053 /** @todo don't apply to obvious NT components... */
1054 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "DRIVER_ACTION_VERIFY: Changing it to WINTRUST_ACTION_GENERIC_VERIFY_V2");
1055 pActionId = (GUID *)&s_GuidActionGenericVerify2;
1056 }
1057 else if (memcmp(pActionId, &s_GuidActionGenericChainVerify, sizeof(*pActionId)) == 0)
1058 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "WINTRUST_ACTION_GENERIC_CHAIN_VERIFY");
1059 else if (memcmp(pActionId, &s_GuidActionGenericVerify2, sizeof(*pActionId)) == 0)
1060 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "WINTRUST_ACTION_GENERIC_VERIFY_V2");
1061 else
1062 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "WINTRUST_ACTION_UNKNOWN");
1063 }
1064
1065 /*
1066 * Log the data.
1067 */
1068 if (pvData)
1069 {
1070 WINTRUST_DATA *pData = (WINTRUST_DATA *)pvData;
1071 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " cbStruct = %ld", pData->cbStruct);
1072# ifdef DEBUG
1073 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " dwUIChoice = %ld", pData->dwUIChoice);
1074 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " fdwRevocationChecks = %ld", pData->fdwRevocationChecks);
1075 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " dwStateAction = %ld", pData->dwStateAction);
1076 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " hWVTStateData = %p", (uintptr_t)pData->hWVTStateData);
1077# endif
1078 if (pData->cbStruct >= 7*sizeof(uint32_t))
1079 {
1080 switch (pData->dwUnionChoice)
1081 {
1082 case WTD_CHOICE_FILE:
1083 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile = %p", (uintptr_t)pData->pFile);
1084 if (RT_VALID_PTR(pData->pFile))
1085 {
1086 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile->cbStruct = %ld", pData->pFile->cbStruct);
1087# ifndef DEBUG
1088 if (pData->pFile->hFile)
1089# endif
1090 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile->hFile = %p", (uintptr_t)pData->pFile->hFile);
1091 if (RT_VALID_PTR(pData->pFile->pcwszFilePath))
1092 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile->pcwszFilePath = %ls", pData->pFile->pcwszFilePath);
1093# ifdef DEBUG
1094 else
1095 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile->pcwszFilePath = %ls", (uintptr_t)pData->pFile->pcwszFilePath);
1096 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pFile->pgKnownSubject = %p", (uintptr_t)pData->pFile->pgKnownSubject);
1097# endif
1098 }
1099 break;
1100
1101 case WTD_CHOICE_CATALOG:
1102 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCatalog = %p", (uintptr_t)pData->pCatalog);
1103 if (RT_VALID_PTR(pData->pCatalog))
1104 {
1105 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->cbStruct = %ld", pData->pCatalog->cbStruct);
1106# ifdef DEBUG
1107 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->dwCatalogVersion = %ld", pData->pCatalog->dwCatalogVersion);
1108# endif
1109 if (RT_VALID_PTR(pData->pCatalog->pcwszCatalogFilePath))
1110 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "pCat->pcwszCatalogFilePath = %ls", pData->pCatalog->pcwszCatalogFilePath);
1111# ifdef DEBUG
1112 else
1113 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "pCat->pcwszCatalogFilePath = %ls", (uintptr_t)pData->pCatalog->pcwszCatalogFilePath);
1114# endif
1115 if (RT_VALID_PTR(pData->pCatalog->pcwszMemberTag))
1116 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->pcwszMemberTag = %ls", pData->pCatalog->pcwszMemberTag);
1117# ifdef DEBUG
1118 else
1119 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->pcwszMemberTag = %ls", (uintptr_t)pData->pCatalog->pcwszMemberTag);
1120# endif
1121 if (RT_VALID_PTR(pData->pCatalog->pcwszMemberFilePath))
1122 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->pcwszMemberFilePath = %ls", pData->pCatalog->pcwszMemberFilePath);
1123# ifdef DEBUG
1124 else
1125 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->pcwszMemberFilePath = %ls", (uintptr_t)pData->pCatalog->pcwszMemberFilePath);
1126# else
1127 if (pData->pCatalog->hMemberFile)
1128# endif
1129 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->hMemberFile = %p", (uintptr_t)pData->pCatalog->hMemberFile);
1130# ifdef DEBUG
1131 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "pCat->pbCalculatedFileHash = %p", (uintptr_t)pData->pCatalog->pbCalculatedFileHash);
1132 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "pCat->cbCalculatedFileHash = %ld", pData->pCatalog->cbCalculatedFileHash);
1133 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCat->pcCatalogContext = %p", (uintptr_t)pData->pCatalog->pcCatalogContext);
1134# endif
1135 }
1136 break;
1137
1138 case WTD_CHOICE_BLOB:
1139 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pBlob = %p\n", (uintptr_t)pData->pBlob);
1140 break;
1141
1142 case WTD_CHOICE_SIGNER:
1143 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pSgnr = %p", (uintptr_t)pData->pSgnr);
1144 break;
1145
1146 case WTD_CHOICE_CERT:
1147 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " pCert = %p", (uintptr_t)pData->pCert);
1148 break;
1149
1150 default:
1151 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, " dwUnionChoice = %ld", pData->dwUnionChoice);
1152 break;
1153 }
1154 }
1155 }
1156
1157 /*
1158 * Make the call.
1159 */
1160 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "Calling WinVerifyTrust ...");
1161 LONG iRet = pfnRealWinVerifyTrust(hwnd, pActionId, pvData);
1162 vboxWinDrvInstLogVerbose(s_vboxWinDrvInterceptedWinVerifyTrustCtx, 1, "WinVerifyTrust returns %ld", iRet);
1163
1164 return iRet;
1165}
1166
1167/**
1168 * Installs an WinVerifyTrust interceptor in setupapi.dll on Windows 2000, XP,
1169 * W2K3 and XP64.
1170 *
1171 * This is a very crude hack to lower the WHQL check to just require a valid
1172 * Authenticode signature by intercepting the verification call.
1173 *
1174 * @returns VBox status code.
1175 * @param pCtx Windows driver installer context.
1176 */
1177static int vboxWinDrvInstallWinVerifyTrustInterceptorInSetupApi(PVBOXWINDRVINSTINTERNAL pCtx)
1178{
1179 /* Check the version: */
1180 OSVERSIONINFOW VerInfo = { sizeof(VerInfo) };
1181 GetVersionExW(&VerInfo);
1182 if (VerInfo.dwMajorVersion != 5)
1183 {
1184 vboxWinDrvInstLogVerbose(pCtx, 1, "OS not supported to intercept WinVerifyTrust, skipping");
1185 return VERR_NOT_SUPPORTED;
1186 }
1187
1188# define PRINT_ERROR_AND_RETURN(a_Msg, ...) \
1189 return vboxWinDrvInstLogErrorRetIgn(pCtx, VERR_NOT_SUPPORTED, a_Msg, __VA_ARGS__);
1190
1191 /* The the target module: */
1192 HMODULE const hModSetupApi = GetModuleHandleW(L"SETUPAPI.DLL");
1193 if (!hModSetupApi)
1194 {
1195 DWORD const dwLastErr = GetLastError();
1196 PRINT_ERROR_AND_RETURN("Failed to locate SETUPAPI.DLL in the process: %ld / %#x", dwLastErr, dwLastErr);
1197 }
1198
1199 /*
1200 * Find the delayed import table (at least that's how it's done in the RTM).
1201 */
1202 IMAGE_DOS_HEADER const *pDosHdr = (IMAGE_DOS_HEADER const *)hModSetupApi;
1203 IMAGE_NT_HEADERS const *pNtHdrs = (IMAGE_NT_HEADERS const *)( (uintptr_t)hModSetupApi
1204 + ( pDosHdr->e_magic == IMAGE_DOS_SIGNATURE
1205 ? pDosHdr->e_lfanew : 0));
1206
1207 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
1208 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #1");
1209 if (pNtHdrs->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
1210 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #2");
1211 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)
1212 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #3");
1213
1214 uint32_t const cbDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size;
1215 if (cbDir < sizeof(IMAGE_DELAYLOAD_DESCRIPTOR))
1216 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #4");
1217 uint32_t const cbImages = pNtHdrs->OptionalHeader.SizeOfImage;
1218 if (cbDir >= cbImages)
1219 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #5");
1220 uint32_t const offDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
1221 if (offDir > cbImages - cbDir)
1222 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #6");
1223
1224 /*
1225 * Scan the entries looking for wintrust.dll.
1226 */
1227 IMAGE_DELAYLOAD_DESCRIPTOR const * const paEntries = (IMAGE_DELAYLOAD_DESCRIPTOR const *)((uintptr_t)hModSetupApi + offDir);
1228 uint32_t const cEntries = cbDir / sizeof(paEntries[0]);
1229 for (uint32_t iImp = 0; iImp < cEntries; iImp++)
1230 {
1231 const char * const pchRva2Ptr = paEntries[iImp].Attributes.RvaBased ? (const char *)hModSetupApi : (const char *)0;
1232 const char * const pszDllName = &pchRva2Ptr[paEntries[iImp].DllNameRVA];
1233 if (RTStrICmpAscii(pszDllName, "WINTRUST.DLL") == 0)
1234 {
1235 /*
1236 * Scan the symbol names.
1237 */
1238 //uint32_t const cbHdrs = pNtHdrs->OptionalHeader.SizeOfHeaders;
1239 uint32_t * const pauNameRvas = (uint32_t *)&pchRva2Ptr[paEntries[iImp].ImportNameTableRVA];
1240 uintptr_t * const paIat = (uintptr_t *)&pchRva2Ptr[paEntries[iImp].ImportAddressTableRVA];
1241 for (uint32_t iSym = 0; pauNameRvas[iSym] != NULL; iSym++)
1242 {
1243 IMAGE_IMPORT_BY_NAME const * const pName = (IMAGE_IMPORT_BY_NAME const *)&pchRva2Ptr[pauNameRvas[iSym]];
1244 if (RTStrCmp(pName->Name, "WinVerifyTrust") == 0)
1245 {
1246 vboxWinDrvInstLogVerbose(pCtx, 1, "Intercepting WinVerifyTrust for SETUPAPI.DLL (old: %p)", paIat[iSym]);
1247 paIat[iSym] = (uintptr_t)vboxWinDrvInterceptedWinVerifyTrust;
1248 return 0;
1249 }
1250 }
1251 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #9");
1252 }
1253 }
1254 PRINT_ERROR_AND_RETURN("Failed to parse SETUPAPI.DLL for WinVerifyTrust interception: #10");
1255
1256# undef PRINT_ERROR_AND_RETURN
1257}
1258#endif /* RT_ARCH_X86 */
1259
1260/**
1261 * Performs the actual driver installation.
1262 *
1263 * @returns VBox status code.
1264 * @param pCtx Windows driver installer context.
1265 * @param pParms Windows driver installation parameters to use.
1266 */
1267static int vboxWinDrvInstallPerform(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms)
1268{
1269 int rc = vboxWinDrvParmsDetermine(pCtx, pParms, false /* fForce */);
1270 if (RT_FAILURE(rc))
1271 return rc;
1272
1273 switch (pParms->enmMode)
1274 {
1275 case VBOXWINDRVINSTMODE_INSTALL:
1276 {
1277 BOOL fRc = FALSE;
1278 BOOL fReboot = FALSE;
1279
1280#ifdef RT_ARCH_X86
1281 s_vboxWinDrvInterceptedWinVerifyTrustCtx = pCtx; /* Hand over the driver installer context. */
1282 vboxWinDrvInstallWinVerifyTrustInterceptorInSetupApi(pCtx);
1283#endif
1284 /*
1285 * Pre-install driver.
1286 */
1287 DWORD dwInstallFlags = 0;
1288 if (pCtx->uOsVer >= RTSYSTEM_MAKE_NT_VERSION(6, 0, 0)) /* for Vista / 2008 Server and up. */
1289 {
1290 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_FORCE)
1291 dwInstallFlags |= DIIRFLAG_FORCE_INF;
1292
1293 vboxWinDrvInstLogVerbose(pCtx, 1, "Using g_pfnDiInstallDriverW(), dwInstallFlags=%#x", dwInstallFlags);
1294
1295 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1296 fRc = g_pfnDiInstallDriverW(NULL /* hWndParent */, pParms->pwszInfFile, dwInstallFlags, &fReboot);
1297 else
1298 fRc = TRUE;
1299 if (!fRc)
1300 {
1301 DWORD const dwErr = GetLastError();
1302
1303 /*
1304 * Work around an error code wich only appears on old(er) Windows Server editions (e.g. 2012 R2 or 2016)
1305 * where SetupAPI tells "unable to mark devices that match new inf", which ultimately results in
1306 * ERROR_LINE_NOT_FOUND. This probably is because of primitive drivers which don't have a PnP ID set in
1307 * the INF file.
1308 *
1309 * pnputil.exe also gives the same error in the SetupAPI log when handling the very same INF file.
1310 *
1311 * So skip this error and pretend everything is fine. */
1312 if (dwErr == ERROR_LINE_NOT_FOUND)
1313 fRc = true;
1314
1315 /*
1316 * Work around an error which occurs on Windows Vista, where DiInstallDriverW() can't handle
1317 * primitive drivers (i.e. [Manufacturer] section is missing). So try installing the detected
1318 * INF section in the next block below.
1319 */
1320 if (dwErr == ERROR_WRONG_INF_TYPE)
1321 fRc = true;
1322
1323 /* For anything else we want to get notified that something isn't working. */
1324 if (!fRc)
1325 {
1326 switch (dwErr)
1327 {
1328 case ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED:
1329 {
1330 /* For silent installs give a clue why this might have failed. */
1331 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_SILENT)
1332 vboxWinDrvInstLogWarn(pCtx, "Silent installation was selected, but required certificates "
1333 "were not pre-installed into the Windows drvier store, so "
1334 "the installation will be rejected automatically");
1335 RT_FALL_THROUGH();
1336 }
1337
1338 default:
1339 rc = vboxWinDrvInstLogLastError(pCtx, "DiInstallDriverW() failed");
1340 break;
1341 }
1342 }
1343 }
1344
1345 if (fRc)
1346 rc = vboxWinDrvTryInfSection(pCtx,
1347 pParms->pwszInfFile, pParms->u.UnInstall.pwszSection,
1348 vboxWinDrvInstallTryInfSectionCallback);
1349 }
1350 else /* For Windows 2000 and below. */
1351 {
1352 if (pParms->u.UnInstall.pwszPnpId)
1353 {
1354 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_SILENT)
1355 {
1356 /* Using INSTALLFLAG_NONINTERACTIVE will trigger an invalid parameter error on Windows 2000. */
1357 if (pCtx->uOsVer >= RTSYSTEM_MAKE_NT_VERSION(5, 1, 0))
1358 dwInstallFlags |= INSTALLFLAG_NONINTERACTIVE;
1359 else
1360 vboxWinDrvInstLogWarn(pCtx, "This version of Windows does not support silent installs");
1361 }
1362
1363 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_FORCE)
1364 dwInstallFlags |= INSTALLFLAG_FORCE;
1365
1366 vboxWinDrvInstLogVerbose(pCtx, 4, "Using g_pfnUpdateDriverForPlugAndPlayDevicesW(), pwszPnpId=%ls, pwszInfFile=%ls, dwInstallFlags=%#x",
1367 pParms->u.UnInstall.pwszPnpId, pParms->pwszInfFile, dwInstallFlags);
1368
1369 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1370 fRc = g_pfnUpdateDriverForPlugAndPlayDevicesW(NULL /* hWndParent */,
1371 pParms->u.UnInstall.pwszPnpId,
1372 pParms->pwszInfFile, dwInstallFlags, &fReboot);
1373 else
1374 fRc = TRUE;
1375
1376 if (!fRc)
1377 {
1378 DWORD const dwErr = GetLastError();
1379 switch (dwErr)
1380 {
1381 case ERROR_NO_SUCH_DEVINST:
1382 {
1383 vboxWinDrvInstLogInfo(pCtx, "Device (\"%ls\") not found (yet), pre-installing driver ...",
1384 pParms->u.UnInstall.pwszPnpId);
1385 break;
1386 }
1387
1388 case ERROR_NO_DRIVER_SELECTED:
1389 {
1390 vboxWinDrvInstLogWarn(pCtx, "Not able to select a driver from the given INF, using given model");
1391 break;
1392 }
1393
1394 case ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED:
1395 {
1396 /* For silent installs give a clue why this might have failed. */
1397 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_SILENT)
1398 vboxWinDrvInstLogWarn(pCtx, "Silent installation was selected, but required certificates "
1399 "were not pre-installed into the Windows drvier store, so "
1400 "the installation will be rejected automatically");
1401 RT_FALL_THROUGH();
1402 }
1403
1404 default:
1405 rc = vboxWinDrvInstLogLastError(pCtx, "Installation(UpdateDriverForPlugAndPlayDevicesW) failed");
1406 break;
1407 }
1408 }
1409 }
1410
1411 if (RT_FAILURE(rc))
1412 break;
1413
1414 /*
1415 * Pre-install driver.
1416 */
1417 RTUTF16 wszInfFileAbs[RTPATH_MAX] = { 0 };
1418 LPWSTR pwszInfFile = NULL;
1419 if ( GetFullPathNameW(pParms->pwszInfFile, RT_ELEMENTS(wszInfFileAbs), wszInfFileAbs, &pwszInfFile)
1420 && pwszInfFile)
1421 {
1422 RTUTF16 wszSrcPathAbs[RTPATH_MAX] = { 0 };
1423 rc = RTUtf16CopyEx(wszSrcPathAbs, RT_ELEMENTS(wszSrcPathAbs), wszInfFileAbs,
1424 RTUtf16Len(wszInfFileAbs) - RTUtf16Len(pwszInfFile));
1425 if (RT_SUCCESS(rc))
1426 {
1427 RTUTF16 wszDstPathAbs[RTPATH_MAX] = { 0 };
1428 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1429 fRc = g_pfnSetupCopyOEMInfW(wszInfFileAbs, wszSrcPathAbs, SPOST_PATH, 0,
1430 wszDstPathAbs, RT_ELEMENTS(wszDstPathAbs), NULL, NULL);
1431 else
1432 fRc = TRUE;
1433
1434 vboxWinDrvInstLogVerbose(pCtx, 1, " INF file: %ls", wszInfFileAbs);
1435 vboxWinDrvInstLogVerbose(pCtx, 1, "Source path: %ls", wszSrcPathAbs);
1436 vboxWinDrvInstLogVerbose(pCtx, 1, " Dest path: %ls", wszDstPathAbs);
1437
1438 if (fRc)
1439 vboxWinDrvInstLogInfo(pCtx, "Copying OEM INF successful");
1440 else
1441 rc = vboxWinDrvInstLogLastError(pCtx, "Installation(SetupCopyOEMInfW) failed");
1442 }
1443 }
1444 else
1445 rc = vboxWinDrvInstLogLastError(pCtx, "GetFullPathNameW() failed");
1446
1447 if (RT_SUCCESS(rc))
1448 rc = vboxWinDrvTryInfSection(pCtx,
1449 pParms->pwszInfFile, pParms->u.UnInstall.pwszSection,
1450 vboxWinDrvInstallTryInfSectionCallback);
1451 }
1452
1453 if (RT_FAILURE(rc))
1454 break;
1455
1456 pCtx->fReboot = RT_BOOL(fReboot);
1457 break;
1458 }
1459
1460 case VBOXWINDRVINSTMODE_INSTALL_INFSECTION:
1461 {
1462 rc = vboxWinDrvInstallInfSection(pCtx, pParms);
1463 break;
1464 }
1465
1466 default:
1467 break;
1468 }
1469
1470 return rc;
1471}
1472
1473/**
1474 * Returns whether the given (in)installation parameters are valid or not.
1475 *
1476 * @returns \c true if valid, \c false if not.
1477 * @param pCtx Windows driver installer context.
1478 * @param pParms Windows driver (un)installation parameters to validate.
1479 */
1480static bool vboxWinDrvParmsAreValid(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms)
1481{
1482 if (pParms->u.UnInstall.pwszPnpId)
1483 {
1484 size_t const cchPnpId = RTUtf16Len(pParms->u.UnInstall.pwszPnpId);
1485 if ( !cchPnpId
1486 || cchPnpId > MAX_DEVICE_ID_LEN)
1487 {
1488 vboxWinDrvInstLogVerbose(pCtx, 1, "PnP ID not specified explicitly or invalid");
1489 return false;
1490 }
1491 }
1492
1493 return true;
1494}
1495
1496/**
1497 * Determines (un)installation parameters from a given set of parameters, logged.
1498 *
1499 * @returns VBox status code.
1500 * @retval VERR_INVALID_PARAMETER if no valid parameters could be determined.
1501 * @param pCtx Windows driver installer context.
1502 * @param pParms Windows driver installation parameters to determine for.
1503 * @param fForce Whether to overwrite already set parameters or not.
1504 *
1505 * @note Only can deal with the first model / PnP ID found for now.
1506 */
1507static int vboxWinDrvParmsDetermine(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms, bool fForce)
1508{
1509 int rc;
1510
1511 /* INF file given? */
1512 if (pParms->pwszInfFile)
1513 {
1514 HINF hInf;
1515 rc = VBoxWinDrvInfOpen(pParms->pwszInfFile, &hInf);
1516 if (RT_SUCCESS(rc))
1517 {
1518 /* Get the INF type first. */
1519 PRTUTF16 pwszMainSection;
1520 VBOXWINDRVINFTYPE enmType = VBoxWinDrvInfGetTypeEx(hInf, &pwszMainSection);
1521 if (enmType != VBOXWINDRVINFTYPE_INVALID)
1522 {
1523 vboxWinDrvInstLogVerbose(pCtx, 1, "INF type is: %s",
1524 enmType == VBOXWINDRVINFTYPE_NORMAL
1525 ? "Normal" : "Primitive");
1526 /*
1527 * Determine model.
1528 */
1529 if ( !pParms->u.UnInstall.pwszModel
1530 || fForce)
1531 {
1532 vboxWinDrvInstLogVerbose(pCtx, 1, "Determining model ...");
1533 if (fForce)
1534 {
1535 RTUtf16Free(pParms->u.UnInstall.pwszModel);
1536 pParms->u.UnInstall.pwszModel = NULL;
1537 }
1538 rc = VBoxWinDrvInfQueryFirstModel(hInf, pwszMainSection, &pParms->u.UnInstall.pwszModel);
1539 if (RT_SUCCESS(rc))
1540 {
1541 RTUtf16Free(pParms->u.UnInstall.pwszSection);
1542 pParms->u.UnInstall.pwszSection = NULL;
1543
1544 /* Now that we have determined the model, try if there is a section in the INF file for this model. */
1545 rc = VBoxWinDrvInfQueryInstallSection(hInf, pParms->u.UnInstall.pwszModel,
1546 &pParms->u.UnInstall.pwszSection);
1547 if (RT_FAILURE(rc))
1548 {
1549 switch (enmType)
1550 {
1551 case VBOXWINDRVINFTYPE_NORMAL:
1552 {
1553 vboxWinDrvInstLogError(pCtx, "No section to install found, can't continue");
1554 break;
1555 }
1556
1557 case VBOXWINDRVINFTYPE_PRIMITIVE:
1558 {
1559 /* If for the given model there is no install section, set the section to main section
1560 * we got when we determined the INF type.
1561 *
1562 * This will be mostly the case for primitive drivers. */
1563 if (rc == VERR_NOT_FOUND)
1564 {
1565 pParms->u.UnInstall.pwszSection = RTUtf16Dup(pwszMainSection);
1566 if (pParms->u.UnInstall.pwszSection)
1567 {
1568 rc = VINF_SUCCESS;
1569 }
1570 else
1571 rc = VERR_NO_MEMORY;
1572 }
1573 break;
1574 }
1575
1576 default:
1577 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
1578 break;
1579 }
1580 }
1581 }
1582 else
1583 {
1584 switch (rc)
1585 {
1586 case VERR_PLATFORM_ARCH_NOT_SUPPORTED:
1587 {
1588 vboxWinDrvInstLogError(pCtx, "Model found, but platform is not supported");
1589 break;
1590 }
1591
1592 case VERR_NOT_FOUND:
1593 {
1594 vboxWinDrvInstLogError(pCtx, "No model found to install found -- buggy driver?");
1595 break;
1596 }
1597
1598 default:
1599 break;
1600 }
1601 }
1602 }
1603
1604 /*
1605 * Determine PnP ID.
1606 *
1607 * Only available in non-primitive drivers.
1608 */
1609 if ( enmType == VBOXWINDRVINFTYPE_NORMAL
1610 && ( !pParms->u.UnInstall.pwszPnpId
1611 || fForce))
1612 {
1613 if (pParms->u.UnInstall.pwszModel)
1614 {
1615 vboxWinDrvInstLogVerbose(pCtx, 1, "Determining PnP ID ...");
1616 if (fForce)
1617 {
1618 RTUtf16Free(pParms->u.UnInstall.pwszPnpId);
1619 pParms->u.UnInstall.pwszPnpId = NULL;
1620 }
1621 /* ignore rc */ VBoxWinDrvInfQueryFirstPnPId(hInf,
1622 pParms->u.UnInstall.pwszModel, &pParms->u.UnInstall.pwszPnpId);
1623 }
1624 else
1625 vboxWinDrvInstLogVerbose(pCtx, 1, "No first model found/set, skipping determining PnP ID");
1626 }
1627
1628 RTUtf16Free(pwszMainSection);
1629 }
1630 else
1631 {
1632 vboxWinDrvInstLogError(pCtx, "INF file is invalid");
1633 rc = VERR_INVALID_PARAMETER;
1634 }
1635
1636 VBoxWinDrvInfClose(hInf);
1637 }
1638 }
1639 /* No INF file given but either the model or the PnP ID? */
1640 else if ( pParms->u.UnInstall.pwszModel
1641 || pParms->u.UnInstall.pwszPnpId)
1642 {
1643 /* Nothing to do for us here. */
1644 rc = VINF_SUCCESS;
1645 }
1646 else
1647 {
1648 vboxWinDrvInstLogError(pCtx, "Neither INF file nor model/PnP ID given; can't continue");
1649 rc = VERR_INVALID_PARAMETER;
1650 }
1651
1652 if (RT_SUCCESS(rc))
1653 {
1654 vboxWinDrvInstLogVerbose(pCtx, 1, "Determined parameters:");
1655 vboxWinDrvInstLogVerbose(pCtx, 1, "\tINF File: %ls",
1656 pParms->pwszInfFile ? pParms->pwszInfFile : L"<None>");
1657 vboxWinDrvInstLogVerbose(pCtx, 1, "\t Model: %ls",
1658 pParms->u.UnInstall.pwszModel ? pParms->u.UnInstall.pwszModel : L"<None>");
1659 vboxWinDrvInstLogVerbose(pCtx, 1, "\t PnP ID: %ls",
1660 pParms->u.UnInstall.pwszPnpId ? pParms->u.UnInstall.pwszPnpId : L"<None>");
1661 vboxWinDrvInstLogVerbose(pCtx, 1, "\t Section: %ls",
1662 pParms->u.UnInstall.pwszSection ? pParms->u.UnInstall.pwszSection : L"<None>");
1663 }
1664
1665 return rc;
1666}
1667
1668/**
1669 * Queries OEM INF files from the driver store.
1670 *
1671 * @returns VBox status code.
1672 * @param pCtx Windows driver installer context.
1673 * @param pParms Windows driver installation parameters to use.
1674 * @param ppList Where to return the list of found Windows driver store entries on success.
1675 * Needs to be destroyed with VBoxWinDrvStoreListFree().
1676 */
1677static int vboxWinDrvQueryFromDriverStore(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms,
1678 PVBOXWINDRVSTORELIST *ppList)
1679{
1680 int rc = vboxWinDrvParmsDetermine(pCtx, pParms, false /* fForce */);
1681 if (RT_SUCCESS(rc))
1682 {
1683 PVBOXWINDRVSTORELIST pList = NULL;
1684 char *pszNeedle = NULL;
1685
1686 if (pParms->u.UnInstall.pwszPnpId)
1687 {
1688 rc = RTUtf16ToUtf8(pParms->u.UnInstall.pwszPnpId, &pszNeedle);
1689 if (RT_SUCCESS(rc))
1690 rc = VBoxWinDrvStoreQueryByPnpId(pCtx->pStore, pszNeedle, &pList);
1691 }
1692 else if (pParms->u.UnInstall.pwszModel)
1693 {
1694 rc = RTUtf16ToUtf8(pParms->u.UnInstall.pwszModel, &pszNeedle);
1695 if (RT_SUCCESS(rc))
1696 rc = VBoxWinDrvStoreQueryByModelName(pCtx->pStore, pszNeedle, &pList);
1697 }
1698 else if (pParms->pwszInfFile)
1699 {
1700 rc = VERR_NOT_IMPLEMENTED;
1701 }
1702
1703 RTStrFree(pszNeedle);
1704 pszNeedle = NULL;
1705
1706 if (RT_SUCCESS(rc))
1707 {
1708 *ppList = pList;
1709 }
1710 else
1711 VBoxWinDrvStoreListFree(pList);
1712 }
1713
1714 return rc;
1715}
1716
1717/**
1718 * Callback implementation for invoking a section for uninstallation.
1719 *
1720 * @returns VBox status code.
1721 * @param hInf Handle to INF file.
1722 * @param pwszSection Section to invoke.
1723 * @param pvCtx User-supplied pointer. Usually PVBOXWINDRVINSTINTERNAL.
1724 */
1725DECLCALLBACK(int) vboxWinDrvUninstallTryInfSectionCallback(HINF hInf, PCRTUTF16 pwszSection, void *pvCtx)
1726{
1727 PVBOXWINDRVINSTINTERNAL pCtx = (PVBOXWINDRVINSTINTERNAL)pvCtx;
1728
1729 return vboxWinDrvUninstallInfSectionEx(pCtx, hInf, pwszSection);
1730}
1731
1732/**
1733 * Removes OEM INF files from the driver store.
1734 *
1735 * @returns VBox status code.
1736 * @param pCtx Windows driver installer context.
1737 * @param pParms Windows driver uninstallation parameters to use.
1738 * @param pList Driver store list with OEM INF entries to remove.
1739 */
1740static int vboxWinDrvUninstallFromDriverStore(PVBOXWINDRVINSTINTERNAL pCtx,
1741 PVBOXWINDRVINSTPARMS pParms, PVBOXWINDRVSTORELIST pList)
1742{
1743
1744 int rc = VINF_SUCCESS;
1745
1746 const char *pszDrvStorePath = VBoxWinDrvStoreBackendGetLocation(pCtx->pStore);
1747
1748 vboxWinDrvInstLogInfo(pCtx, "Uninstalling %zu matching entr%s", pList->cEntries, pList->cEntries == 1 ? "y" : "ies");
1749 PVBOXWINDRVSTOREENTRY pCur;
1750 RTListForEach(&pList->List, pCur, VBOXWINDRVSTOREENTRY, Node)
1751 {
1752 bool fRc = FALSE;
1753
1754 /*
1755 * Running the uninstalling section(s) first before removing the driver from the driver store below.
1756 */
1757 RTUTF16 wszInfPathAbs[RTPATH_MAX];
1758 ssize_t const cwchInfPathAbs = RTUtf16Printf(wszInfPathAbs, RT_ELEMENTS(wszInfPathAbs),
1759 "%s\\%ls", pszDrvStorePath, pCur->wszInfFile);
1760 AssertBreakStmt(cwchInfPathAbs > 0, rc = VERR_BUFFER_OVERFLOW);
1761
1762 vboxWinDrvInstLogInfo(pCtx, "Uninstalling %ls (%ls)", pCur->wszModel, wszInfPathAbs);
1763
1764 /* Only calltry calling the "DefaultUninstall" section here, as there aren't any other section(s)
1765 * to handle for uninstalling a driver via INF files. */
1766 /* rc ignored, keep going */ vboxWinDrvTryInfSection(pCtx, wszInfPathAbs, NULL /* DefaultUninstall */,
1767 vboxWinDrvUninstallTryInfSectionCallback);
1768
1769 /*
1770 * Remove the driver from the driver store.
1771 */
1772 if (g_pfnDiUninstallDriverW)
1773 {
1774 vboxWinDrvInstLogVerbose(pCtx, 1, "Using DiUninstallDriverW()");
1775
1776 BOOL fReboot = FALSE;
1777 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1778 {
1779 /* Takes the fully qualified path of the INF file to uninstall. */
1780 fRc = g_pfnDiUninstallDriverW(NULL /* hWndParent */, wszInfPathAbs, 0 /* Flags */, &fReboot);
1781 }
1782 else
1783 fRc = TRUE;
1784 if (fRc)
1785 pCtx->fReboot = RT_BOOL(fReboot);
1786 else
1787 {
1788 /* Not fatal, try next block. */
1789 DWORD const dwErr = GetLastError();
1790 vboxWinDrvInstLogVerbose(pCtx, 1, "DiUninstallDriverW() failed with %#x (%d)", dwErr, dwErr);
1791 }
1792 }
1793
1794 /* Not (yet) successful? Try harder using an older API. */
1795 if ( !fRc
1796 && g_pfnSetupUninstallOEMInfW)
1797 {
1798 vboxWinDrvInstLogVerbose(pCtx, 1, "Using SetupUninstallOEMInfW()");
1799
1800 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1801 {
1802 DWORD dwUninstallFlags = 0;
1803 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_FORCE)
1804 dwUninstallFlags |= SUOI_FORCEDELETE;
1805
1806 /* Takes the oemXXX.inf file (without a path), as found in the Windows INF directory. */
1807 fRc = g_pfnSetupUninstallOEMInfW(pCur->wszInfFile, dwUninstallFlags, NULL /* pReserved */);
1808 }
1809 }
1810
1811 int rc2 = VINF_SUCCESS;
1812
1813 if (fRc)
1814 vboxWinDrvInstLogInfo(pCtx, "Uninstalling OEM INF \"%ls\" successful", wszInfPathAbs);
1815 else
1816 {
1817 DWORD const dwErr = GetLastError();
1818 if (dwErr == ERROR_INF_IN_USE_BY_DEVICES)
1819 vboxWinDrvInstLogError(pCtx, "Unable to uninstall OEM INF \"%ls\": Driver still in use by device", wszInfPathAbs);
1820 else
1821 rc2 = vboxWinDrvInstLogLastError(pCtx, "Uninstalling OEM INF \"%ls\" failed", wszInfPathAbs);
1822 }
1823
1824 /* If anything failed above, try removing stuff ourselves as good as we can. */
1825 if (RT_FAILURE(rc2))
1826 /* rc ignored, keep going */ vboxWinDrvTryInfSection(pCtx, wszInfPathAbs, pCur->wszModel,
1827 vboxWinDrvUninstallTryInfSectionCallback);
1828
1829 if (RT_SUCCESS(rc)) /* Keep first error if already set. */
1830 rc = rc2;
1831
1832 /* Keep going. */
1833 }
1834
1835 return rc;
1836}
1837
1838/**
1839 * Performs the actual driver uninstallation.
1840 *
1841 * @returns VBox status code.
1842 * @param pCtx Windows driver installer context.
1843 * @param pParms Windows driver installation parameters to use.
1844 */
1845static int vboxWinDrvUninstallPerform(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms)
1846{
1847 int rc;
1848 switch (pParms->enmMode)
1849 {
1850 case VBOXWINDRVINSTMODE_UNINSTALL:
1851 {
1852 PVBOXWINDRVSTORELIST pList = NULL;
1853 rc = vboxWinDrvQueryFromDriverStore(pCtx, pParms, &pList);
1854 if (RT_SUCCESS(rc))
1855 {
1856 rc = vboxWinDrvUninstallFromDriverStore(pCtx, pParms, pList);
1857
1858 VBoxWinDrvStoreListFree(pList);
1859 pList = NULL;
1860 }
1861 break;
1862 }
1863
1864 case VBOXWINDRVINSTMODE_UNINSTALL_INFSECTION:
1865 {
1866 rc = vboxWinDrvInstallInfSection(pCtx, pParms);
1867 break;
1868 }
1869
1870 default:
1871 rc = VINF_SUCCESS;
1872 break;
1873 }
1874
1875 return rc;
1876}
1877
1878/**
1879 * Main function to perform the actual driver [un]installation.
1880 *
1881 * @returns VBox status code.
1882 * @param pCtx Windows driver installer context.
1883 * @param pParms Windows driver installation parameters to use.
1884 */
1885static int vboxWinDrvInstMain(PVBOXWINDRVINSTINTERNAL pCtx, PVBOXWINDRVINSTPARMS pParms)
1886{
1887 /* Note: Other parameters might be optional, depending on the mode. */
1888 AssertReturn(!(pParms->fFlags & ~VBOX_WIN_DRIVERINSTALL_F_VALID_MASK), VERR_INVALID_PARAMETER);
1889
1890 bool const fInstall = pParms->enmMode == VBOXWINDRVINSTMODE_INSTALL
1891 || pParms->enmMode == VBOXWINDRVINSTMODE_INSTALL_INFSECTION;
1892
1893 if (pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN)
1894 vboxWinDrvInstLogWarn(pCtx, "Dry-run mode active -- no installation performed!");
1895
1896 const char * const pszLogAction = fInstall ? "Installing" : "Uninstalling";
1897 if (pParms->pwszInfFile)
1898 vboxWinDrvInstLogInfo(pCtx, "%s driver \"%ls\" ... ", pszLogAction, pParms->pwszInfFile);
1899 else if (pParms->u.UnInstall.pwszModel)
1900 vboxWinDrvInstLogInfo(pCtx, "%s driver model \"%ls\" ... ", pszLogAction, pParms->u.UnInstall.pwszModel);
1901 else if (pParms->u.UnInstall.pwszPnpId)
1902 vboxWinDrvInstLogInfo(pCtx, "%s PnP ID \"%ls\" ... ", pszLogAction, pParms->u.UnInstall.pwszPnpId);
1903
1904 if ( pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_SILENT
1905 && g_pfnSetupSetNonInteractiveMode)
1906 {
1907 vboxWinDrvInstLogInfo(pCtx, "Setting non-interactive mode ...");
1908 if (!(pParms->fFlags & VBOX_WIN_DRIVERINSTALL_F_DRYRUN))
1909 g_pfnSetupSetNonInteractiveMode(TRUE /* fEnable */);
1910 }
1911
1912 if (!vboxWinDrvParmsAreValid(pCtx, pParms))
1913 {
1914 vboxWinDrvInstLogError(pCtx, "%s parameters are invalid, can't continue", fInstall ? "Installation" : "Uninstallation");
1915 return VERR_INVALID_PARAMETER;
1916 }
1917
1918 int rc;
1919 if (fInstall)
1920 rc = vboxWinDrvInstallPerform(pCtx, pParms);
1921 else
1922 rc = vboxWinDrvUninstallPerform(pCtx, pParms);
1923
1924 if (RT_SUCCESS(rc))
1925 {
1926 vboxWinDrvInstLogInfo(pCtx, "Driver was %sinstalled successfully", fInstall ? "" : "un");
1927 if (pCtx->fReboot)
1928 {
1929 vboxWinDrvInstLogRebootNeeded(pCtx, "A reboot is needed in order to complete the driver %sinstallation.",
1930 fInstall ? "" : "un");
1931 rc = VINF_REBOOT_NEEDED;
1932 }
1933 }
1934
1935 /* Note: Call vboxWinDrvInstLogEx() to not increase the error/warn count here. */
1936 if (pCtx->cErrors)
1937 vboxWinDrvInstLogEx(pCtx, VBOXWINDRIVERLOGTYPE_ERROR, "%sstalling driver(s) failed with %u errors, %u warnings (rc=%Rrc)",
1938 fInstall ? "In" : "Unin", pCtx->cErrors, pCtx->cWarnings, rc);
1939 else if (pCtx->cWarnings)
1940 vboxWinDrvInstLogEx(pCtx, VBOXWINDRIVERLOGTYPE_WARN, "%sstalling driver(s) succeeded with %u warnings",
1941 fInstall ? "In" : "Unin", pCtx->cWarnings);
1942
1943 return rc;
1944}
1945
1946/**
1947 * Creates a Windows driver installer instance, extended version.
1948 *
1949 * @returns VBox status code.
1950 * @param phDrvInst where to return the created driver installer handle on success.
1951 * @param uVerbosity Sets the initial verbosity level.
1952 * @param pfnLog Log callback function to set.
1953 * @param pvUser User-supplied pointer to set. Optional and might be NULL.
1954 */
1955int VBoxWinDrvInstCreateEx(PVBOXWINDRVINST phDrvInst, unsigned uVerbosity, PFNVBOXWINDRIVERLOGMSG pfnLog, void *pvUser)
1956{
1957 int rc;
1958
1959 PVBOXWINDRVINSTINTERNAL pCtx = (PVBOXWINDRVINSTINTERNAL)RTMemAllocZ(sizeof(VBOXWINDRVINSTINTERNAL));
1960 if (pCtx)
1961 {
1962 pCtx->u32Magic = VBOXWINDRVINST_MAGIC;
1963 pCtx->uVerbosity = uVerbosity;
1964 pCtx->pfnLog = pfnLog;
1965 pCtx->pvUser = pvUser;
1966
1967 pCtx->uOsVer = RTSystemGetNtVersion(); /* Might be overwritten later via VBoxWinDrvInstSetOsVersion(). */
1968
1969 vboxWinDrvInstLogInfo(pCtx, VBOX_PRODUCT " Version " VBOX_VERSION_STRING " - r%s", RTBldCfgRevisionStr());
1970 vboxWinDrvInstLogInfo(pCtx, "Detected Windows version %d.%d.%d (%s)", RTSYSTEM_NT_VERSION_GET_MAJOR(pCtx->uOsVer),
1971 RTSYSTEM_NT_VERSION_GET_MINOR(pCtx->uOsVer),
1972 RTSYSTEM_NT_VERSION_GET_BUILD(pCtx->uOsVer),
1973 RTBldCfgTargetArch());
1974
1975 rc = RTOnce(&g_vboxWinDrvInstResolveOnce, vboxWinDrvInstResolveOnce, pCtx);
1976 if (RT_SUCCESS(rc))
1977 {
1978 rc = VBoxWinDrvStoreCreate(&pCtx->pStore);
1979 if (RT_SUCCESS(rc))
1980 {
1981 *phDrvInst = (VBOXWINDRVINST)pCtx;
1982 return VINF_SUCCESS;
1983 }
1984 else
1985 vboxWinDrvInstLogError(pCtx, "Creating driver store failed with %Rrc", rc);
1986 }
1987 }
1988 else
1989 rc = VERR_NO_MEMORY;
1990
1991 VBoxWinDrvStoreDestroy(pCtx->pStore);
1992 VBoxWinDrvInstDestroy(pCtx);
1993 return rc;
1994}
1995
1996/**
1997 * Creates a Windows driver installer instance.
1998 *
1999 * @returns VBox status code.
2000 * @param phDrvInst where to return the created driver installer handle on success.
2001 */
2002int VBoxWinDrvInstCreate(PVBOXWINDRVINST phDrvInst)
2003{
2004 return VBoxWinDrvInstCreateEx(phDrvInst, 0 /* uVerbosity */, NULL /* pfnLog */, NULL /* pvUser */);
2005}
2006
2007/**
2008 * Destroys a Windows driver installer instance.
2009 *
2010 * @returns VBox status code.
2011 * @param hDrvInst Windows driver installer handle to destroy.
2012 * The handle will be invalid after calling this function.
2013 */
2014int VBoxWinDrvInstDestroy(VBOXWINDRVINST hDrvInst)
2015{
2016 if (hDrvInst == NIL_VBOXWINDRVINST)
2017 return VINF_SUCCESS;
2018
2019 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2020 VBOXWINDRVINST_VALID_RETURN(pCtx);
2021
2022 vboxWinDrvInstParmsDestroy(&pCtx->Parms);
2023
2024 VBoxWinDrvStoreDestroy(pCtx->pStore);
2025 pCtx->pStore = NULL;
2026
2027 RTMemFree(pCtx);
2028
2029 return VINF_SUCCESS;
2030}
2031
2032/**
2033 * Returns the number of (logged) warnings so far.
2034 *
2035 * @returns Number of (logged) warnings so far.
2036 * @param hDrvInst Windows driver installer handle.
2037 */
2038unsigned VBoxWinDrvInstGetWarnings(VBOXWINDRVINST hDrvInst)
2039{
2040 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2041 VBOXWINDRVINST_VALID_RETURN_RC(pCtx, UINT8_MAX);
2042
2043 return pCtx->cWarnings;
2044}
2045
2046/**
2047 * Returns the number of (logged) errors so far.
2048 *
2049 * @returns Number of (logged) errors so far..
2050 * @param hDrvInst Windows driver installer handle.
2051 */
2052unsigned VBoxWinDrvInstGetErrors(VBOXWINDRVINST hDrvInst)
2053{
2054 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2055 VBOXWINDRVINST_VALID_RETURN_RC(pCtx, UINT8_MAX);
2056
2057 return pCtx->cErrors;
2058}
2059
2060/**
2061 * Sets (overwrites) the current OS version used for the (un)installation code.
2062 *
2063 * @param hDrvInst Windows driver installer handle.
2064 * @param uOsVer OS version to set. RTSYSTEM_MAKE_NT_VERSION style.
2065 */
2066void VBoxWinDrvInstSetOsVersion(VBOXWINDRVINST hDrvInst, uint64_t uOsVer)
2067{
2068 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2069 VBOXWINDRVINST_VALID_RETURN_VOID(pCtx);
2070
2071 pCtx->uOsVer = uOsVer;
2072
2073 vboxWinDrvInstLogInfo(pCtx, "Set OS version to: %u.%u\n", RTSYSTEM_NT_VERSION_GET_MAJOR(pCtx->uOsVer),
2074 RTSYSTEM_NT_VERSION_GET_MINOR(pCtx->uOsVer));
2075}
2076
2077/**
2078 * Sets the verbosity of a Windows driver installer instance.
2079 *
2080 * @returns The old verbosity level.
2081 * @param hDrvInst Windows driver installer handle to set verbosity for.
2082 * @param uVerbosity Verbosity level to set.
2083 */
2084unsigned VBoxWinDrvInstSetVerbosity(VBOXWINDRVINST hDrvInst, unsigned uVerbosity)
2085{
2086 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2087 VBOXWINDRVINST_VALID_RETURN_RC(pCtx, UINT8_MAX);
2088
2089 unsigned const uOldVerbosity = hDrvInst->uVerbosity;
2090 hDrvInst->uVerbosity = uVerbosity;
2091 return uOldVerbosity;
2092}
2093
2094/**
2095 * Sets the log callback of a Windows driver installer instance.
2096 *
2097 * @returns VBox status code.
2098 * @param hDrvInst Windows driver installer handle to set log callback for.
2099 * @param pfnLog Log callback function to set.
2100 * @param pvUser User-supplied pointer to set. Optional and might be NULL.
2101 */
2102void VBoxWinDrvInstSetLogCallback(VBOXWINDRVINST hDrvInst, PFNVBOXWINDRIVERLOGMSG pfnLog, void *pvUser)
2103{
2104 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2105 VBOXWINDRVINST_VALID_RETURN_VOID(pCtx);
2106
2107 pCtx->pfnLog = pfnLog;
2108 pCtx->pvUser = pvUser;
2109}
2110
2111/**
2112 * Installs a driver, extended version.
2113 *
2114 * @returns VBox status code.
2115 * @param hDrvInst Windows driver installer handle to use.
2116 * @param pszInfFile INF file to use.
2117 * @param pszModel Model name to use. Optional and can be NULL.
2118 * @param pszPnpId PnP ID to use. NT-style wildcards supported. Optional and can be NULL.
2119 * @param fFlags Installation flags (of type VBOX_WIN_DRIVERINSTALL_F_XXX) to use.
2120 */
2121int VBoxWinDrvInstInstallEx(VBOXWINDRVINST hDrvInst,
2122 const char *pszInfFile, const char *pszModel, const char *pszPnpId, uint32_t fFlags)
2123{
2124 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2125 VBOXWINDRVINST_VALID_RETURN(pCtx);
2126
2127 AssertPtrReturn(pszInfFile, VERR_INVALID_PARAMETER);
2128
2129 vboxWinDrvInstParmsInit(&pCtx->Parms);
2130
2131 /* Resolve the INF file's absolute path, as as Setup API functions tend to need this. */
2132 char szInfPathAbs[RTPATH_MAX];
2133 int rc = RTPathReal(pszInfFile, szInfPathAbs, sizeof(szInfPathAbs));
2134 if (RT_SUCCESS(rc))
2135 {
2136 rc = RTStrToUtf16(szInfPathAbs, &pCtx->Parms.pwszInfFile);
2137 if (RT_FAILURE(rc))
2138 vboxWinDrvInstLogError(pCtx, "Failed to build path for INF file \"%s\", rc=%Rrc", pszInfFile, rc);
2139 }
2140 else
2141 vboxWinDrvInstLogError(pCtx, "Determining real path for INF file \"%s\" failed, rc=%Rrc", pszInfFile, rc);
2142
2143 if (RT_SUCCESS(rc) && pszModel) /* Model is optional. */
2144 rc = RTStrToUtf16(pszModel, &pCtx->Parms.u.UnInstall.pwszModel);
2145 if (RT_SUCCESS(rc) && pszPnpId) /* Ditto. */
2146 rc = RTStrToUtf16(pszPnpId, &pCtx->Parms.u.UnInstall.pwszPnpId);
2147
2148 if (RT_SUCCESS(rc))
2149 {
2150 pCtx->Parms.enmMode = VBOXWINDRVINSTMODE_INSTALL;
2151 pCtx->Parms.fFlags = fFlags;
2152
2153 rc = vboxWinDrvInstMain(pCtx, &pCtx->Parms);
2154 }
2155
2156 if (!(fFlags & VBOX_WIN_DRIVERINSTALL_F_NO_DESTROY))
2157 vboxWinDrvInstParmsDestroy(&pCtx->Parms);
2158
2159 if (RT_FAILURE(rc))
2160 vboxWinDrvInstLogError(pCtx, "Driver installation failed with %Rrc", rc);
2161
2162 return rc;
2163}
2164
2165/**
2166 * Installs a driver.
2167 *
2168 * @returns VBox status code.
2169 * @param hDrvInst Windows driver installer handle to use.
2170 * @param pszInfFile INF file to use.
2171 * @param fFlags Installation flags (of type VBOX_WIN_DRIVERINSTALL_F_XXX) to use.
2172 *
2173 * @note This function tries determining the model / PnP ID from the given INF file.
2174 * To control the behavior exactly, use VBoxWinDrvInstInstallEx().
2175 */
2176int VBoxWinDrvInstInstall(VBOXWINDRVINST hDrvInst, const char *pszInfFile, uint32_t fFlags)
2177{
2178 return VBoxWinDrvInstInstallEx(hDrvInst, pszInfFile, NULL /* pszModel */, NULL /* pszPnpId */, fFlags);
2179}
2180
2181/**
2182 * Uninstalls a driver.
2183 *
2184 * @returns VBox status code.
2185 * @param hDrvInst Windows driver installer handle to use.
2186 * @param pszInfFile INF file within driver store to uninstall.
2187 * Optional and can be NULL.
2188 * @param pszModel Model to uninstall (e.g. "VBoxUSB.AMD64"). NT-style wildcards supported.
2189 * Optional and can be NULL.
2190 * @param pszPnpId PnP ID to use (e.g. "USB\\VID_80EE&PID_CAFE"). NT-style wildcards supported.
2191 * Optional and can be NULL.
2192 * @param fFlags Installation flags (of type VBOX_WIN_DRIVERINSTALL_F_XXX) to use.
2193 */
2194int VBoxWinDrvInstUninstall(VBOXWINDRVINST hDrvInst, const char *pszInfFile, const char *pszModel, const char *pszPnpId,
2195 uint32_t fFlags)
2196{
2197 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2198 VBOXWINDRVINST_VALID_RETURN(pCtx);
2199
2200 int rc = VINF_SUCCESS;
2201
2202 vboxWinDrvInstParmsInit(&pCtx->Parms);
2203
2204 /* If given, get the sole INF file name (without path), to make it searchable within the driver store.
2205 * Note: This only will work with "oemXXX.inf" files for the (legcy) driver store. */
2206 if (pszInfFile && *pszInfFile)
2207 {
2208 char *pszInfFileName = RTPathFilename(pszInfFile);
2209 if (pszInfFileName)
2210 rc = RTStrToUtf16(pszInfFileName, &pCtx->Parms.pwszInfFile);
2211 else
2212 rc = VERR_FILE_NOT_FOUND;
2213 }
2214
2215 if (RT_SUCCESS(rc) && pszModel && *pszModel)
2216 rc = RTStrToUtf16(pszModel, &pCtx->Parms.u.UnInstall.pwszModel);
2217 if (RT_SUCCESS(rc) && pszPnpId && *pszPnpId)
2218 rc = RTStrToUtf16(pszPnpId, &pCtx->Parms.u.UnInstall.pwszPnpId);
2219
2220 pCtx->Parms.enmMode = VBOXWINDRVINSTMODE_UNINSTALL;
2221 pCtx->Parms.fFlags = fFlags;
2222
2223 if (RT_SUCCESS(rc))
2224 rc = vboxWinDrvInstMain(pCtx, &pCtx->Parms);
2225
2226 if (!(fFlags & VBOX_WIN_DRIVERINSTALL_F_NO_DESTROY))
2227 vboxWinDrvInstParmsDestroy(&pCtx->Parms);
2228
2229 if (RT_FAILURE(rc))
2230 vboxWinDrvInstLogError(pCtx, "Driver uninstallation failed with %Rrc", rc);
2231
2232 return rc;
2233}
2234
2235/**
2236 * Worker function for executing a section of an INF file.
2237 *
2238 * @returns VBox status code.
2239 * @param hDrvInst Windows driver installer handle to use.
2240 * @param fInstall Whether to execute the section to install or uninstall.
2241 * @param pszInfFile INF file to use.
2242 * @param pszSection Section within the INF file to execute.
2243 * @param fFlags Installation flags to use.
2244 */
2245int VBoxWinDrvInstExecuteInfWorker(VBOXWINDRVINST hDrvInst,
2246 bool fInstall, const char *pszInfFile, const char *pszSection, uint32_t fFlags)
2247{
2248 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2249 VBOXWINDRVINST_VALID_RETURN(pCtx);
2250
2251 AssertPtrReturn(pszInfFile, VERR_INVALID_POINTER);
2252
2253 vboxWinDrvInstParmsInit(&pCtx->Parms);
2254
2255 int rc = RTStrToUtf16(pszInfFile, &pCtx->Parms.pwszInfFile);
2256 if (RT_SUCCESS(rc) && pszSection) /* pszSection is optional. */
2257 rc = RTStrToUtf16(pszSection, &pCtx->Parms.u.ExecuteInf.pwszSection);
2258 AssertRCReturn(rc, rc);
2259
2260 pCtx->Parms.enmMode = fInstall ? VBOXWINDRVINSTMODE_INSTALL_INFSECTION : VBOXWINDRVINSTMODE_UNINSTALL_INFSECTION;
2261 pCtx->Parms.fFlags = fFlags;
2262
2263 rc = vboxWinDrvInstMain(pCtx, &pCtx->Parms);
2264
2265 if (!(fFlags & VBOX_WIN_DRIVERINSTALL_F_NO_DESTROY))
2266 vboxWinDrvInstParmsDestroy(&pCtx->Parms);
2267
2268 return rc;
2269}
2270
2271/**
2272 * Executes a section of an INF file for installation.
2273 *
2274 * @returns VBox status code.
2275 * @param hDrvInst Windows driver installer handle to use.
2276 * @param pszInfFile INF file to use.
2277 * @param pszSection Section within the INF file to execute.
2278 * @param fFlags Installation flags to use.
2279 */
2280int VBoxWinDrvInstInstallExecuteInf(VBOXWINDRVINST hDrvInst, const char *pszInfFile, const char *pszSection, uint32_t fFlags)
2281{
2282 return VBoxWinDrvInstExecuteInfWorker(hDrvInst, true /* fInstall */, pszInfFile, pszSection, fFlags);
2283}
2284
2285/**
2286 * Executes a section of an INF file for uninstallation.
2287 *
2288 * @returns VBox status code.
2289 * @param hDrvInst Windows driver installer handle to use.
2290 * @param pszInfFile INF file to use.
2291 * @param pszSection Section within the INF file to execute.
2292 * @param fFlags Installation flags to use.
2293 */
2294int VBoxWinDrvInstUninstallExecuteInf(VBOXWINDRVINST hDrvInst, const char *pszInfFile, const char *pszSection, uint32_t fFlags)
2295{
2296 return VBoxWinDrvInstExecuteInfWorker(hDrvInst, false /* fInstall */, pszInfFile, pszSection, fFlags);
2297}
2298
2299/**
2300 * Controls a Windows service, internal version.
2301 *
2302 * @returns VBox status code.
2303 * @param hDrvInst Windows driver installer handle to use.
2304 * @param pszService Name of service to control.
2305 * @param enmFn Service control function to use.
2306 * VBOXWINDRVSVCFN_RESTART is not implemented and must be composed of
2307 * VBOXWINDRVSVCFN_START + VBOXWINDRVSVCFN_STOP by the caller.
2308 * @param fFlags Service control flags (of type VBOXWINDRVSVCFN_F_XXX) to use.
2309 * @param msTimeout Timeout (in ms) to use. Ignored if VBOXWINDRVSVCFN_F_WAIT is missing in \a fFlags.
2310 */
2311static int vboxWinDrvInstControlServiceEx(PVBOXWINDRVINSTINTERNAL pCtx,
2312 const char *pszService, VBOXWINDRVSVCFN enmFn, uint32_t fFlags, RTMSINTERVAL msTimeout)
2313{
2314 AssertPtrReturn(pszService, VERR_INVALID_POINTER);
2315 AssertReturn(!(fFlags & ~VBOXWINDRVSVCFN_F_VALID_MASK), VERR_INVALID_PARAMETER);
2316 AssertReturn(enmFn > VBOXWINDRVSVCFN_INVALID && enmFn < VBOXWINDRVSVCFN_END, VERR_INVALID_PARAMETER);
2317 AssertReturn(!(fFlags & VBOXWINDRVSVCFN_F_WAIT) || msTimeout, VERR_INVALID_PARAMETER);
2318
2319 PRTUTF16 pwszService;
2320 int rc = RTStrToUtf16(pszService, &pwszService);
2321 if (RT_FAILURE(rc))
2322 return rc;
2323
2324 SC_HANDLE hSvc = NULL;
2325 SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
2326 if (hSCM != NULL)
2327 {
2328 hSvc = OpenServiceW(hSCM, pwszService, SERVICE_ALL_ACCESS | SERVICE_QUERY_STATUS);
2329 if (hSvc == NULL)
2330 {
2331 rc = RTErrConvertFromWin32(GetLastError());
2332 if (rc == VERR_NOT_FOUND)
2333 vboxWinDrvInstLogError(pCtx, "Service '%s' not found", pszService);
2334 else
2335 rc = vboxWinDrvInstLogLastError(pCtx, "Opening service '%s' failed", pszService);
2336 }
2337 }
2338 else
2339 rc = vboxWinDrvInstLogLastError(pCtx, "Opening Service Control Manager (SCM) failed");
2340
2341 if (RT_FAILURE(rc))
2342 {
2343 RTUtf16Free(pwszService);
2344 if (hSvc)
2345 CloseServiceHandle(hSvc);
2346 if (hSCM)
2347 CloseServiceHandle(hSCM);
2348 return rc;
2349 }
2350
2351 SERVICE_STATUS_PROCESS enmSvcSts;
2352
2353 switch (enmFn)
2354 {
2355 case VBOXWINDRVSVCFN_START:
2356 {
2357 if (!StartService(hSvc, 0, NULL))
2358 {
2359 if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
2360 break;
2361
2362 /** @todo Also handle disabled services here? */
2363
2364 rc = vboxWinDrvInstLogLastError(pCtx, "Starting service '%s' failed", pszService);
2365 }
2366 else
2367 vboxWinDrvInstLogInfo(pCtx, "Starting service '%s' ...", pszService);
2368 break;
2369 }
2370
2371 case VBOXWINDRVSVCFN_STOP:
2372 {
2373 if (!ControlService(hSvc, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS)&enmSvcSts))
2374 {
2375 DWORD const dwErr = GetLastError();
2376
2377 /* A not active or disabled service is not an error, so just skip. */
2378 if ( dwErr == ERROR_SERVICE_DISABLED
2379 || dwErr == ERROR_SERVICE_NOT_ACTIVE)
2380 break;
2381
2382 rc = vboxWinDrvInstLogLastError(pCtx, "Stopping service '%s' failed", pszService);
2383 }
2384 else
2385 vboxWinDrvInstLogInfo(pCtx, "Stopping service '%s' ...", pszService);
2386 break;
2387 }
2388
2389 default:
2390 AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
2391 break;
2392 }
2393
2394 if ( RT_SUCCESS(rc)
2395 && (fFlags & VBOXWINDRVSVCFN_F_WAIT))
2396 {
2397 uint64_t const msStartTS = RTTimeMilliTS();
2398
2399 rc = VERR_NO_CHANGE; /* No change yet. */
2400
2401 if (!g_pfnQueryServiceStatusEx)
2402 {
2403 vboxWinDrvInstLogWarn(pCtx, "Waiting for status change of service '%s' not supported on this OS, skipping",
2404 pszService);
2405 rc = VINF_SUCCESS;
2406 }
2407 else
2408 {
2409 vboxWinDrvInstLogInfo(pCtx, "Waiting for status change of service '%s' (%ums timeout) ...", pszService, msTimeout);
2410 for (;;)
2411 {
2412 DWORD dwBytes;
2413 if (!g_pfnQueryServiceStatusEx(hSvc,
2414 SC_STATUS_PROCESS_INFO,
2415 (LPBYTE)&enmSvcSts,
2416 sizeof(SERVICE_STATUS_PROCESS),
2417 &dwBytes))
2418 {
2419 rc = vboxWinDrvInstLogLastError(pCtx, "Failed to query service status");
2420 break;
2421 }
2422
2423 if ((RTTimeMilliTS() - msStartTS) % RT_MS_1SEC == 0) /* Don't spam. */
2424 vboxWinDrvInstLogVerbose(pCtx, 3, "Service '%s' status is %#x: %u",
2425 pszService, enmSvcSts.dwCurrentState, (RTTimeMilliTS() - msStartTS) % 100 == 0);
2426
2427 switch (enmSvcSts.dwCurrentState)
2428 {
2429 case SERVICE_STOP_PENDING:
2430 case SERVICE_START_PENDING:
2431 RTThreadSleep(100); /* Wait a bit before retrying. */
2432 break;
2433
2434 case SERVICE_RUNNING:
2435 {
2436 if (enmFn == VBOXWINDRVSVCFN_START)
2437 rc = VINF_SUCCESS;
2438 break;
2439 }
2440
2441 case SERVICE_STOPPED:
2442 {
2443 if (enmFn == VBOXWINDRVSVCFN_START)
2444 {
2445 vboxWinDrvInstLogError(pCtx, "Service '%s' stopped unexpectedly", pszService);
2446 rc = VERR_INVALID_STATE;
2447 }
2448 else
2449 rc = VINF_SUCCESS;
2450 break;
2451 }
2452
2453 default:
2454 {
2455 vboxWinDrvInstLogError(pCtx, "Service '%s' reported an unexpected state (%#x)",
2456 pszService, enmSvcSts.dwCurrentState);
2457 rc = VERR_INVALID_STATE;
2458 }
2459 }
2460
2461 if ( RT_FAILURE(rc)
2462 && rc != VERR_NO_CHANGE)
2463 break;
2464
2465 if (RT_SUCCESS(rc))
2466 break;
2467
2468 if (RTTimeMilliTS() - msStartTS >= msTimeout)
2469 {
2470 vboxWinDrvInstLogError(pCtx, "Waiting for service '%s' timed out (%ums)", pszService, msTimeout);
2471 rc = VERR_TIMEOUT;
2472 break;
2473 }
2474 }
2475 }
2476
2477 if (RT_SUCCESS(rc))
2478 vboxWinDrvInstLogInfo(pCtx, "Service '%s' successfully %s",
2479 pszService, enmFn == VBOXWINDRVSVCFN_START ? "started" : "stopped");
2480 }
2481 else
2482 vboxWinDrvInstLogVerbose(pCtx, 1, "Service '%s' was %s asynchronously",
2483 pszService, enmFn == VBOXWINDRVSVCFN_START ? "started" : "stopped");
2484
2485 RTUtf16Free(pwszService);
2486 CloseServiceHandle(hSvc);
2487 CloseServiceHandle(hSCM);
2488 return rc;
2489}
2490
2491/**
2492 * Controls a Windows service, extended version.
2493 *
2494 * @returns VBox status code.
2495 * @param hDrvInst Windows driver installer handle to use.
2496 * @param pszService Name of service to control.
2497 * @param enmFn Service control function to use.
2498 * @param fFlags Service control flags (of type VBOXWINDRVSVCFN_F_XXX) to use.
2499 * @param msTimeout Timeout (in ms) to use. Only being used if VBOXWINDRVSVCFN_F_WAIT is specified in \a fFlags.
2500 */
2501int VBoxWinDrvInstControlServiceEx(VBOXWINDRVINST hDrvInst,
2502 const char *pszService, VBOXWINDRVSVCFN enmFn, uint32_t fFlags, RTMSINTERVAL msTimeout)
2503{
2504 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2505 VBOXWINDRVINST_VALID_RETURN(pCtx);
2506
2507#define CONTROL_SERVICE(a_Fn) \
2508 vboxWinDrvInstControlServiceEx(pCtx, pszService, a_Fn, fFlags, msTimeout);
2509
2510 int rc;
2511 if (enmFn == VBOXWINDRVSVCFN_RESTART)
2512 {
2513 rc = CONTROL_SERVICE(VBOXWINDRVSVCFN_STOP);
2514 if (RT_SUCCESS(rc))
2515 rc = CONTROL_SERVICE(VBOXWINDRVSVCFN_START);
2516 }
2517 else
2518 rc = CONTROL_SERVICE(enmFn);
2519
2520#undef CONTROL_SERVICE
2521 return rc;
2522}
2523
2524/**
2525 * Controls a Windows service.
2526 *
2527 * @returns VBox status code.
2528 * @param hDrvInst Windows driver installer handle to use.
2529 * @param pszService Name of service to control.
2530 * @param enmFn Service control function to use.
2531 *
2532 * @note Function waits 30s for the service to reach the desired control function.
2533 * Use VBooxWinDrvInstControlServiceEx() for more flexibility.
2534 */
2535int VBoxWinDrvInstControlService(VBOXWINDRVINST hDrvInst, const char *pszService, VBOXWINDRVSVCFN enmFn)
2536{
2537 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2538 VBOXWINDRVINST_VALID_RETURN(pCtx);
2539
2540 return VBoxWinDrvInstControlServiceEx(pCtx, pszService, enmFn, VBOXWINDRVSVCFN_F_WAIT, RT_MS_30SEC);
2541}
2542
2543#ifdef TESTCASE
2544/**
2545 * Returns the internal parameters of an (un)installation.
2546 *
2547 * @returns Internal parameters of an (un)installation.
2548 * @param hDrvInst Windows driver installer handle to use.
2549 */
2550PVBOXWINDRVINSTPARMS VBoxWinDrvInstTestGetParms(VBOXWINDRVINST hDrvInst)
2551{
2552 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst;
2553 VBOXWINDRVINST_VALID_RETURN_RC((hDrvInst), NULL);
2554
2555 return &pCtx->Parms;
2556}
2557
2558/**
2559 * Detroys internal parameters of an (un)installation.
2560 *
2561 * @param pParms Internal parameters of an (un)installation to destroy.
2562 */
2563void VBoxWinDrvInstTestParmsDestroy(PVBOXWINDRVINSTPARMS pParms)
2564{
2565 vboxWinDrvInstParmsDestroy(pParms);
2566}
2567#endif /* TESTCASE */
2568
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