VirtualBox

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

Last change on this file since 106839 was 106839, checked in by vboxsync, 3 months ago

Windows driver installation: Made it a bit smarter wrt model / PnP ID detection within files. bugref:10762

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