VirtualBox

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

Last change on this file since 107767 was 107767, checked in by vboxsync, 6 weeks ago

Windows driver installation/VBoxDrvInst: Added crude hack from r153608 to suppress the WHQL dialog on windows 2000 and XP. ​bugref:10261 ​bugref:8691

Needs some more work later.

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