VirtualBox

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

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

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

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

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