VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Installer/VBoxDrvInst.cpp@ 32250

Last change on this file since 32250 was 32250, checked in by vboxsync, 15 years ago

wddm: 1. guest installer uninstall 2. dev/vga saved state fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 72.6 KB
Line 
1/*++
2
3 Copyright (c) Microsoft Corporation. All rights reserved.
4
5 Module Name:
6
7 VBoxDrvInst.cpp
8
9 Abstract:
10
11 Command-line interface for installing / uninstalling device drivers
12 with a given Hardware-ID (and .INF-file).
13
14 --*/
15
16#ifndef UNICODE
17#define UNICODE
18#endif
19
20#include <VBox/version.h>
21
22#include <windows.h>
23#include <setupapi.h>
24#include <newdev.h>
25#include <regstr.h>
26#include <cfgmgr32.h>
27#include <devguid.h>
28#include <stdio.h>
29#include <tchar.h>
30#include <string.h>
31
32/*#define _DEBUG*/
33
34typedef int (*fnCallback) (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context);
35
36struct IdEntry
37{
38 LPCTSTR szString; /* string looking for */
39 LPCTSTR szWild; /* first wild character if any */
40 BOOL bInstanceId;
41};
42
43#define INSTANCEID_PREFIX_CHAR TEXT('@') /* character used to prefix instance ID's */
44#define CLASS_PREFIX_CHAR TEXT('=') /* character used to prefix class name */
45#define WILD_CHAR TEXT('*') /* wild character */
46#define QUOTE_PREFIX_CHAR TEXT('\'') /* prefix character to ignore wild characters */
47#define SPLIT_COMMAND_SEP TEXT(":=") /* whole word, indicates end of id's */
48
49/* @todo Split this program into several modules:
50
51 - Main
52 - Utility functions
53 - Dynamic API loading
54 - Installation / uninstallation routines
55 - ...
56 */
57
58/* Exit codes */
59#define EXIT_OK (0)
60#define EXIT_REBOOT (1)
61#define EXIT_FAIL (2)
62#define EXIT_USAGE (3)
63#ifdef VBOXWDDM
64#define EXIT_FALSE (4)
65#endif
66
67/* Dynamic loaded libs */
68HMODULE g_hSetupAPI = NULL;
69HMODULE g_hNewDev = NULL;
70HMODULE g_hCfgMgr = NULL;
71
72/* Function pointers for dynamic loading of some API calls NT4 hasn't ... */
73typedef BOOL (WINAPI *fnSetupDiCreateDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceName, LPGUID ClassGuid, PCTSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
74 PSP_DEVINFO_DATA DeviceInfoData);
75fnSetupDiCreateDeviceInfo g_pfnSetupDiCreateDeviceInfo = NULL;
76
77typedef BOOL (WINAPI *fnSetupDiOpenDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceInstanceId, HWND hwndParent, DWORD OpenFlags, PSP_DEVINFO_DATA DeviceInfoData);
78fnSetupDiOpenDeviceInfo g_pfnSetupDiOpenDeviceInfo = NULL;
79
80typedef BOOL (WINAPI *fnSetupDiEnumDeviceInfo) (HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData);
81fnSetupDiEnumDeviceInfo g_pfnSetupDiEnumDeviceInfo = NULL;
82
83/***/
84
85typedef HDEVINFO (WINAPI *fnSetupDiCreateDeviceInfoList) (LPGUID ClassGuid, HWND hwndParent);
86fnSetupDiCreateDeviceInfoList g_pfnSetupDiCreateDeviceInfoList = NULL;
87
88typedef HDEVINFO (WINAPI *fnSetupDiCreateDeviceInfoListEx) (LPGUID ClassGuid, HWND hwndParent, PCTSTR MachineName, PVOID Reserved);
89fnSetupDiCreateDeviceInfoListEx g_pfnSetupDiCreateDeviceInfoListEx = NULL;
90
91typedef BOOL (WINAPI *fnSetupDiDestroyDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType);
92fnSetupDiDestroyDriverInfoList g_pfnSetupDiDestroyDriverInfoList = NULL;
93
94typedef BOOL (WINAPI *fnSetupDiDestroyDeviceInfoList) (HDEVINFO DeviceInfoSet);
95fnSetupDiDestroyDeviceInfoList g_pfnSetupDiDestroyDeviceInfoList = NULL;
96
97typedef BOOL (WINAPI *fnSetupDiGetDeviceInfoListDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_LIST_DETAIL_DATA DeviceInfoSetDetailData);
98fnSetupDiGetDeviceInfoListDetail g_pfnSetupDiGetDeviceInfoListDetail = NULL;
99
100/***/
101
102typedef BOOL (WINAPI *fnSetupDiSetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, CONST BYTE *PropertyBuffer, DWORD PropertyBufferSize);
103fnSetupDiSetDeviceRegistryProperty g_pfnSetupDiSetDeviceRegistryProperty = NULL;
104
105typedef BOOL (WINAPI *fnSetupDiGetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer,
106 DWORD PropertyBufferSize, PDWORD RequiredSize);
107fnSetupDiGetDeviceRegistryProperty g_pfnSetupDiGetDeviceRegistryProperty = NULL;
108
109/***/
110
111typedef BOOL (WINAPI *fnSetupDiCallClassInstaller) (DI_FUNCTION InstallFunction, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData);
112fnSetupDiCallClassInstaller g_pfnSetupDiCallClassInstaller = NULL;
113
114typedef BOOL (WINAPI *fnSetupDiClassGuidsFromNameEx) (PCTSTR ClassName, LPGUID ClassGuidList, DWORD ClassGuidListSize, PDWORD RequiredSize, PCTSTR MachineName, PVOID Reserved);
115fnSetupDiClassGuidsFromNameEx g_pfnSetupDiClassGuidsFromNameEx = NULL;
116
117typedef HDEVINFO (WINAPI *fnSetupDiGetClassDevsEx) (LPGUID ClassGuid, PCTSTR Enumerator, HWND hwndParent, DWORD Flags, HDEVINFO DeviceInfoSet, PCTSTR MachineName, PVOID Reserved);
118fnSetupDiGetClassDevsEx g_pfnSetupDiGetClassDevsEx = NULL;
119
120typedef BOOL (WINAPI *fnSetupDiSetClassInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_CLASSINSTALL_HEADER ClassInstallParams, DWORD ClassInstallParamsSize);
121fnSetupDiSetClassInstallParams g_pfnSetupDiSetClassInstallParams = NULL;
122
123typedef BOOL (WINAPI *fnSetupDiGetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams);
124fnSetupDiGetDeviceInstallParams g_pfnSetupDiGetDeviceInstallParams = NULL;
125
126typedef HKEY (WINAPI *fnSetupDiOpenDevRegKey) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired);
127fnSetupDiOpenDevRegKey g_pfnSetupDiOpenDevRegKey = NULL;
128
129typedef BOOL (WINAPI *fnSetupDiBuildDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType);
130fnSetupDiBuildDriverInfoList g_pfnSetupDiBuildDriverInfoList = NULL;
131
132typedef BOOL (WINAPI *fnSetupDiEnumDriverInfo) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType, DWORD MemberIndex, PSP_DRVINFO_DATA DriverInfoData);
133fnSetupDiEnumDriverInfo g_pfnSetupDiEnumDriverInfo = NULL;
134
135typedef BOOL (WINAPI *fnSetupDiGetDriverInfoDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData, PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData,
136 DWORD DriverInfoDetailDataSize, PDWORD RequiredSize);
137fnSetupDiGetDriverInfoDetail g_pfnSetupDiGetDriverInfoDetail = NULL;
138
139typedef BOOL (WINAPI *fnSetupDiSetSelectedDriver) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData);
140fnSetupDiSetSelectedDriver g_pfnSetupDiSetSelectedDriver = NULL;
141
142typedef BOOL (WINAPI *fnSetupDiSetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams);
143fnSetupDiSetDeviceInstallParams g_pfnSetupDiSetDeviceInstallParams = NULL;
144
145typedef CONFIGRET (WINAPI *fnCM_Get_Device_ID_Ex) (DEVINST dnDevInst, PTCHAR Buffer, ULONG BufferLen, ULONG ulFlags, HMACHINE hMachine);
146fnCM_Get_Device_ID_Ex g_pfnCM_Get_Device_ID_Ex = NULL;
147
148typedef BOOL (WINAPI* fnSetupCopyOEMInf) (PCTSTR SourceInfFileName, PCTSTR OEMSourceMediaLocation, DWORD OEMSourceMediaType, DWORD CopyStyle, PTSTR DestinationInfFileName,
149 DWORD DestinationInfFileNameSize, PDWORD RequiredSize, PTSTR DestinationInfFileNameComponent);
150fnSetupCopyOEMInf g_pfnSetupCopyOEMInf = NULL;
151
152typedef BOOL (WINAPI* fnUpdateDriverForPlugAndPlayDevices) (HWND hwndParent, LPCTSTR HardwareId, LPCTSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired);
153fnUpdateDriverForPlugAndPlayDevices g_pfnUpdateDriverForPlugAndPlayDevices = NULL;
154
155#define VBOX_LOAD_API( a_hModule, a_Func ) \
156{ \
157 g_pfn##a_Func = (fn##a_Func)GetProcAddress(a_hModule, "##a_Func"); \
158 _tprintf (_T("API call ##a_Func loaded: %p\n"), g_pfn##a_Func); \
159}
160
161int LoadAPICalls ()
162{
163 int rc = ERROR_SUCCESS;
164 OSVERSIONINFO OSinfo;
165 OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
166 GetVersionEx(&OSinfo);
167
168#ifdef _DEBUG
169 _tprintf (_T("Loading API calls ...\n"));
170#endif
171
172 /* Use unicode calls where available. */
173 if (OSinfo.dwMajorVersion >= 5) /* APIs available only on W2K and up! */
174 {
175 g_hSetupAPI = LoadLibrary(_T("SetupAPI"));
176 if (NULL == g_hSetupAPI)
177 {
178 _tprintf(_T("ERROR: SetupAPI.dll not found! Return code: %d\n"), GetLastError());
179 rc = ERROR_NOT_INSTALLED;
180 }
181 else
182 {
183 g_pfnSetupDiCreateDeviceInfoList = (fnSetupDiCreateDeviceInfoList)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoList");
184 g_pfnSetupDiCreateDeviceInfo = (fnSetupDiCreateDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoW");
185 g_pfnSetupDiSetDeviceRegistryProperty = (fnSetupDiSetDeviceRegistryProperty)GetProcAddress(g_hSetupAPI, "SetupDiSetDeviceRegistryPropertyW");
186 g_pfnSetupDiCallClassInstaller = (fnSetupDiCallClassInstaller)GetProcAddress(g_hSetupAPI, "SetupDiCallClassInstaller");
187 g_pfnSetupDiDestroyDeviceInfoList = (fnSetupDiDestroyDeviceInfoList)GetProcAddress(g_hSetupAPI, "SetupDiDestroyDeviceInfoList");
188 g_pfnSetupDiClassGuidsFromNameEx = (fnSetupDiClassGuidsFromNameEx)GetProcAddress(g_hSetupAPI, "SetupDiClassGuidsFromNameExW");
189 g_pfnSetupDiGetDeviceRegistryProperty = (fnSetupDiGetDeviceRegistryProperty)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceRegistryPropertyW");
190 g_pfnSetupDiGetClassDevsEx = (fnSetupDiGetClassDevsEx)GetProcAddress(g_hSetupAPI, "SetupDiGetClassDevsExW");
191 g_pfnSetupDiCreateDeviceInfoListEx = (fnSetupDiCreateDeviceInfoListEx)GetProcAddress(g_hSetupAPI, "SetupDiCreateDeviceInfoListExW");
192 g_pfnSetupDiOpenDeviceInfo = (fnSetupDiOpenDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiOpenDeviceInfoW");
193 g_pfnSetupDiGetDeviceInfoListDetail = (fnSetupDiGetDeviceInfoListDetail)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceInfoListDetailW");
194 g_pfnSetupDiEnumDeviceInfo = (fnSetupDiEnumDeviceInfo)GetProcAddress(g_hSetupAPI, "SetupDiEnumDeviceInfo");
195 g_pfnSetupDiSetClassInstallParams = (fnSetupDiSetClassInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiSetClassInstallParamsW");
196 g_pfnSetupDiGetDeviceInstallParams = (fnSetupDiGetDeviceInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiGetDeviceInstallParamsW");
197 g_pfnSetupDiOpenDevRegKey = (fnSetupDiOpenDevRegKey)GetProcAddress(g_hSetupAPI, "SetupDiOpenDevRegKey");
198 g_pfnSetupDiBuildDriverInfoList = (fnSetupDiBuildDriverInfoList)GetProcAddress(g_hSetupAPI, "SetupDiBuildDriverInfoList");
199 g_pfnSetupDiEnumDriverInfo = (fnSetupDiEnumDriverInfo)GetProcAddress(g_hSetupAPI, "SetupDiEnumDriverInfoW");
200 g_pfnSetupDiGetDriverInfoDetail = (fnSetupDiGetDriverInfoDetail)GetProcAddress(g_hSetupAPI, "SetupDiGetDriverInfoDetailW");
201 g_pfnSetupDiDestroyDriverInfoList = (fnSetupDiDestroyDriverInfoList)GetProcAddress(g_hSetupAPI, "SetupDiDestroyDriverInfoList");
202 g_pfnSetupDiSetSelectedDriver = (fnSetupDiSetSelectedDriver)GetProcAddress(g_hSetupAPI, "SetupDiSetSelectedDriverW");
203 g_pfnSetupDiSetDeviceInstallParams = (fnSetupDiSetDeviceInstallParams)GetProcAddress(g_hSetupAPI, "SetupDiSetDeviceInstallParamsW");
204 g_pfnSetupCopyOEMInf = (fnSetupCopyOEMInf)GetProcAddress(g_hSetupAPI, "SetupCopyOEMInfW");
205 }
206
207 if (rc == ERROR_SUCCESS)
208 {
209 g_hNewDev = LoadLibrary(_T("NewDev"));
210 if (NULL != g_hNewDev)
211 {
212 g_pfnUpdateDriverForPlugAndPlayDevices = (fnUpdateDriverForPlugAndPlayDevices)GetProcAddress(g_hNewDev, "UpdateDriverForPlugAndPlayDevicesW");
213 }
214 else
215 {
216 _tprintf(_T("ERROR: NewDev.dll not found! Return code: %d\n"), GetLastError());
217 rc = ERROR_FILE_NOT_FOUND;
218 }
219 }
220
221 if (rc == ERROR_SUCCESS)
222 {
223 g_hCfgMgr = LoadLibrary(_T("CfgMgr32"));
224 if (NULL != g_hCfgMgr)
225 {
226 g_pfnCM_Get_Device_ID_Ex = (fnCM_Get_Device_ID_Ex)GetProcAddress(g_hCfgMgr, "CM_Get_Device_ID_ExW");
227 }
228 else
229 {
230 _tprintf(_T("ERROR: NewDev.dll not found! Return code: %d\n"), GetLastError());
231 rc = ERROR_FILE_NOT_FOUND;
232 }
233 }
234 }
235 else if (OSinfo.dwMajorVersion <= 4) /* Windows NT 4.0. */
236 {
237 /* Nothing to do here yet. */
238 }
239 else /* Other platforms */
240 {
241 _tprintf(_T("ERROR: Platform not supported yet!\n"));
242 rc = ERROR_NOT_SUPPORTED;
243 }
244
245 return rc;
246}
247
248void FreeAPICalls ()
249{
250#ifdef _DEBUG
251 _tprintf (_T("Freeing API calls ...\n"));
252#endif
253
254 if (NULL != g_hSetupAPI)
255 FreeLibrary(g_hSetupAPI);
256
257 if (NULL != g_hNewDev)
258 FreeLibrary(g_hNewDev);
259
260 if (NULL != g_hCfgMgr)
261 FreeLibrary(g_hCfgMgr);
262}
263
264bool GetErrorMsg (DWORD a_dwLastError, _TCHAR* a_pszMsg, DWORD a_dwBufSize)
265{
266 if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, a_dwLastError, 0, a_pszMsg, a_dwBufSize, NULL) == 0)
267 {
268 _stprintf(a_pszMsg, _T("Unknown error!\n"), a_dwLastError);
269 return false;
270 }
271 else
272 {
273 _TCHAR* p = _tcschr(a_pszMsg, _T('\r'));
274
275 if (p != NULL)
276 *p = _T('\0');
277 }
278
279 return true;
280}
281
282/* @todo Add exception handling instead of crappy goto's! */
283
284int CreateDevice (_TCHAR* a_pszHwID, GUID a_devClass)
285{
286 int iRet = EXIT_OK;
287 HDEVINFO devInfoSet;
288 SP_DEVINFO_DATA devInfoData;
289 DWORD dwErr = 0;
290 _TCHAR szErrMsg[_MAX_PATH + 1] = { 0 };
291
292 _tprintf(_T("Creating device ...\n"));
293
294 devInfoSet = g_pfnSetupDiCreateDeviceInfoList(&a_devClass, NULL);
295 if (devInfoSet == INVALID_HANDLE_VALUE)
296 {
297 _tprintf(_T("Could not build device info list!\n"));
298 return EXIT_FAIL;
299 }
300
301 devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
302 if (FALSE == g_pfnSetupDiCreateDeviceInfo(devInfoSet, a_pszHwID, &a_devClass, NULL, NULL, DICD_GENERATE_ID, &devInfoData))
303 {
304 dwErr = GetLastError();
305
306 switch (dwErr)
307 {
308
309 case ERROR_DEVINST_ALREADY_EXISTS:
310
311 _tprintf(_T("Device already exists.\n"));
312 break;
313
314 case ERROR_CLASS_MISMATCH:
315
316 _tprintf(_T("ERROR: Device does not match to class ID!\n"));
317 break;
318
319 case ERROR_INVALID_USER_BUFFER:
320
321 _tprintf(_T("ERROR: Invalid user buffer!\n"));
322 break;
323
324 case ERROR_INVALID_DEVINST_NAME:
325
326 _tprintf(_T("ERROR: Invalid device instance name!\n"));
327 break;
328
329 default:
330
331 GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg));
332 _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg);
333 break;
334 }
335
336 iRet = EXIT_FAIL;
337 goto InstallCleanup;
338 }
339
340 if (FALSE == g_pfnSetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID, (LPBYTE)a_pszHwID, (DWORD)((_tcsclen(a_pszHwID) + 2) * sizeof(_TCHAR))))
341 {
342 dwErr = GetLastError();
343 _tprintf(_T("Could not set device registry info!\n"));
344 iRet = EXIT_FAIL;
345 goto InstallCleanup;
346 }
347
348 if (FALSE == g_pfnSetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfoSet, &devInfoData))
349 {
350 dwErr = GetLastError();
351 _tprintf(_T("Could not register device!\n"));
352 iRet = EXIT_FAIL;
353 goto InstallCleanup;
354 }
355
356 InstallCleanup: g_pfnSetupDiDestroyDeviceInfoList(devInfoSet);
357
358 return iRet;
359}
360
361int InstallDriver (_TCHAR* a_pszInfFile, _TCHAR* a_pszHwID, _TCHAR* a_pszDevClass)
362{
363 DWORD dwErr = 0;
364 BOOL bReboot = FALSE;
365
366 _TCHAR szInf[_MAX_PATH] = { 0 }; /* Full path + .INF file */
367 _TCHAR szInfPath[_MAX_PATH] = { 0 }; /* Full path to .INF file */
368 GUID devClassArr[32]; /* The device class GUID array */
369 DWORD dwReqSize = 0; /* Number of GUIDs in array after lookup */
370
371 _tprintf(_T("Installing driver ...\n"));
372 _tprintf(_T("HardwareID: %ws\n"), a_pszHwID);
373 _tprintf(_T("Device class name: %ws\n"), a_pszDevClass);
374
375 /* Retrieve GUID of device class */
376 /* Not used here: g_pfnSetupDiClassNameFromGuidEx( ... ) */
377 if (FALSE == g_pfnSetupDiClassGuidsFromNameEx(a_pszDevClass, devClassArr, 32, &dwReqSize, NULL, NULL))
378 {
379 _tprintf(_T("Could not retrieve device class GUID! Error: %ld\n"), GetLastError());
380 return EXIT_FAIL;
381 }
382 else
383 {
384 /* Do not fail if dwReqSize is 0. For whatever reason Windows Server 2008 Core does not have the "Media"
385 device class installed. Maybe they stripped down too much? :-/ */
386 if (dwReqSize <= 0)
387 {
388 _tprintf(_T("WARNING: No device class with this name found! ReqSize: %ld, Error: %ld\n"), dwReqSize, GetLastError());
389 }
390 else
391 {
392 _tprintf(_T("Number of GUIDs found: %ld\n"), dwReqSize);
393 }
394
395 /* Not needed for now!
396 if (EXIT_FAIL == CreateDevice (a_pszHwID, devClassArr[0]))
397 return EXIT_FAIL;*/
398 }
399
400 _TCHAR* pcFile = NULL;
401 if (0 == GetFullPathName(a_pszInfFile, _MAX_PATH, szInf, &pcFile))
402 {
403 dwErr = GetLastError();
404
405 _tprintf(_T("ERROR: INF-Path too long / could not be retrieved!\n"));
406 return EXIT_FAIL;
407 }
408
409 /* Extract path from path+INF */
410 if (pcFile != NULL)
411 _tcsnccpy(szInfPath, szInf, pcFile - szInf);
412
413 _tprintf(_T("INF-File: %ws\n"), szInf);
414 _tprintf(_T("INF-Path: %ws\n"), szInfPath);
415
416 _tprintf(_T("Updating driver for plug'n play devices ...\n"));
417 if (!g_pfnUpdateDriverForPlugAndPlayDevices(NULL, a_pszHwID, szInf, INSTALLFLAG_FORCE, &bReboot))
418 {
419 DWORD dwErr = GetLastError();
420 _TCHAR szErrMsg[_MAX_PATH + 1] = { 0 };
421
422 if (dwErr == ERROR_NO_SUCH_DEVINST)
423 {
424 _TCHAR szDestInf[_MAX_PATH] = { 0 };
425 _tprintf(_T("The device is not plugged in (yet), pre-installing drivers ...\n"));
426
427 if (FALSE == g_pfnSetupCopyOEMInf(szInf, szInfPath, SPOST_PATH, 0, szDestInf, sizeof(szDestInf), NULL, NULL))
428 {
429 dwErr = GetLastError();
430 GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg));
431 _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg);
432 return EXIT_FAIL;
433 }
434
435 _tprintf(_T("OK. Installed to: %ws\n"), szDestInf);
436 return EXIT_OK;
437 }
438
439 switch (dwErr)
440 {
441
442 case ERROR_INVALID_FLAGS:
443
444 _tprintf(_T("ERROR: The value specified for InstallFlags is invalid!\n"));
445 break;
446
447 case ERROR_NO_MORE_ITEMS:
448
449 _tprintf(
450 _T(
451 "ERROR: The function found a match for the HardwareId value, but the specified driver was not a better match than the current driver and the caller did not specify the INSTALLFLAG_FORCE flag!\n"));
452 break;
453
454 case ERROR_FILE_NOT_FOUND:
455
456 _tprintf(_T("ERROR: File not found!\n"));
457 break;
458
459 case ERROR_IN_WOW64:
460
461 _tprintf(_T("ERROR: The calling application is a 32-bit application attempting to execute in a 64-bit environment, which is not allowed!"));
462 break;
463
464 case ERROR_NO_DRIVER_SELECTED:
465
466 _tprintf(_T("ERROR: No driver in .INF-file selected!\n"));
467 break;
468
469 case ERROR_SECTION_NOT_FOUND:
470
471 _tprintf(_T("ERROR: Section in .INF-file was not found!\n"));
472 break;
473
474 default:
475
476 /* Try error lookup with GetErrorMsg() */
477 GetErrorMsg(dwErr, szErrMsg, sizeof(szErrMsg));
478 _tprintf(_T("ERROR (%08x): %ws\n"), dwErr, szErrMsg);
479 break;
480 }
481
482 return EXIT_FAIL;
483 }
484
485 _tprintf(_T("Installation successful.\n"));
486
487 return EXIT_OK;
488}
489
490/*++
491
492 Routine Description:
493
494 Determine if this is instance id or hardware id and if there's any wildcards
495 instance ID is prefixed by '@'
496 wildcards are '*'
497
498
499 Arguments:
500
501 Id - ptr to string to check
502
503 Return Value:
504
505 IdEntry
506
507 --*/
508IdEntry GetIdType (LPCTSTR Id)
509{
510 IdEntry Entry;
511
512 Entry.bInstanceId = FALSE;
513 Entry.szWild = NULL;
514 Entry.szString = Id;
515
516 if (Entry.szString[0] == INSTANCEID_PREFIX_CHAR)
517 {
518 Entry.bInstanceId = TRUE;
519 Entry.szString = CharNext(Entry.szString);
520 }
521 if (Entry.szString[0] == QUOTE_PREFIX_CHAR)
522 {
523 /* prefix to treat rest of string literally */
524 Entry.szString = CharNext(Entry.szString);
525 }
526 else
527 {
528 /* see if any wild characters exist */
529 Entry.szWild = _tcschr(Entry.szString, WILD_CHAR);
530 }
531 return Entry;
532}
533
534/*++
535
536 Routine Description:
537
538 Get an index array pointing to the MultiSz passed in
539
540 Arguments:
541
542 MultiSz - well formed multi-sz string
543
544 Return Value:
545
546 array of strings. last entry+1 of array contains NULL
547 returns NULL on failure
548
549 --*/
550LPTSTR * GetMultiSzIndexArray (LPTSTR MultiSz)
551{
552 LPTSTR scan;
553 LPTSTR * array;
554 int elements;
555
556 for (scan = MultiSz, elements = 0; scan[0]; elements++)
557 {
558 scan += lstrlen(scan) + 1;
559 }
560 array = new LPTSTR[elements + 2];
561 if (!array)
562 {
563 return NULL;
564 }
565 array[0] = MultiSz;
566 array++;
567 if (elements)
568 {
569 for (scan = MultiSz, elements = 0; scan[0]; elements++)
570 {
571 array[elements] = scan;
572 scan += lstrlen(scan) + 1;
573 }
574 }
575 array[elements] = NULL;
576 return array;
577}
578
579/*++
580
581 Routine Description:
582
583 Deletes the string array allocated by GetDevMultiSz/GetRegMultiSz/GetMultiSzIndexArray
584
585 Arguments:
586
587 Array - pointer returned by GetMultiSzIndexArray
588
589 Return Value:
590
591 None
592
593 --*/
594void DelMultiSz (LPTSTR * Array)
595{
596 if (Array)
597 {
598 Array--;
599 if (Array[0])
600 {
601 delete[] Array[0];
602 }
603 delete[] Array;
604 }
605}
606
607/*++
608
609 Routine Description:
610
611 Get a multi-sz device property
612 and return as an array of strings
613
614 Arguments:
615
616 Devs - HDEVINFO containing DevInfo
617 DevInfo - Specific device
618 Prop - SPDRP_HARDWAREID or SPDRP_COMPATIBLEIDS
619
620 Return Value:
621
622 array of strings. last entry+1 of array contains NULL
623 returns NULL on failure
624
625 --*/
626LPTSTR * GetDevMultiSz (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Prop)
627{
628 LPTSTR buffer;
629 DWORD size;
630 DWORD reqSize;
631 DWORD dataType;
632 LPTSTR * array;
633 DWORD szChars;
634
635 size = 8192; /* initial guess, nothing magic about this */
636 buffer = new TCHAR[(size / sizeof(TCHAR)) + 2];
637 if (!buffer)
638 {
639 return NULL;
640 }
641 while (!g_pfnSetupDiGetDeviceRegistryProperty(Devs, DevInfo, Prop, &dataType, (LPBYTE)buffer, size, &reqSize))
642 {
643 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
644 {
645 goto failed;
646 }
647 if (dataType != REG_MULTI_SZ)
648 {
649 goto failed;
650 }
651 size = reqSize;
652 delete[] buffer;
653 buffer = new TCHAR[(size / sizeof(TCHAR)) + 2];
654 if (!buffer)
655 {
656 goto failed;
657 }
658 }
659 szChars = reqSize / sizeof(TCHAR);
660 buffer[szChars] = TEXT('\0');
661 buffer[szChars + 1] = TEXT('\0');
662 array = GetMultiSzIndexArray(buffer);
663 if (array)
664 {
665 return array;
666 }
667
668 failed: if (buffer)
669 {
670 delete[] buffer;
671 }
672 return NULL;
673}
674
675/*++
676
677 Routine Description:
678
679 Compare a single item against wildcard
680 I'm sure there's better ways of implementing this
681 Other than a command-line management tools
682 it's a bad idea to use wildcards as it implies
683 assumptions about the hardware/instance ID
684 eg, it might be tempting to enumerate root\* to
685 find all root devices, however there is a CfgMgr
686 API to query status and determine if a device is
687 root enumerated, which doesn't rely on implementation
688 details.
689
690 Arguments:
691
692 Item - item to find match for eg a\abcd\c
693 MatchEntry - eg *\*bc*\*
694
695 Return Value:
696
697 TRUE if any match, otherwise FALSE
698
699 --*/
700BOOL WildCardMatch (LPCTSTR Item, const IdEntry & MatchEntry)
701{
702 LPCTSTR scanItem;
703 LPCTSTR wildMark;
704 LPCTSTR nextWild;
705 size_t matchlen;
706
707 /* Before attempting anything else,
708 try and compare everything up to first wild */
709 //
710 if (!MatchEntry.szWild)
711 {
712 return _tcsicmp(Item, MatchEntry.szString) ? FALSE : TRUE;
713 }
714 if (_tcsnicmp(Item, MatchEntry.szString, MatchEntry.szWild - MatchEntry.szString) != 0)
715 {
716 return FALSE;
717 }
718 wildMark = MatchEntry.szWild;
719 scanItem = Item + (MatchEntry.szWild - MatchEntry.szString);
720
721 for (; wildMark[0];)
722 {
723 /* If we get here, we're either at or past a wildcard */
724 if (wildMark[0] == WILD_CHAR)
725 {
726 /* So skip wild chars */
727 wildMark = CharNext(wildMark);
728 continue;
729 }
730
731 /* Find next wild-card */
732 nextWild = _tcschr(wildMark, WILD_CHAR);
733
734 if (nextWild)
735 {
736 /* Substring */
737 matchlen = nextWild - wildMark;
738 }
739 else
740 {
741 /* Last portion of match */
742 size_t scanlen = lstrlen(scanItem);
743 matchlen = lstrlen(wildMark);
744
745 if (scanlen < matchlen)
746 {
747 return FALSE;
748 }
749
750 return _tcsicmp(scanItem + scanlen - matchlen, wildMark) ? FALSE : TRUE;
751 }
752
753 if (_istalpha(wildMark[0]))
754 {
755 /* Scan for either lower or uppercase version of first character */
756 TCHAR u = _totupper(wildMark[0]);
757 TCHAR l = _totlower(wildMark[0]);
758 while (scanItem[0] && scanItem[0] != u && scanItem[0] != l)
759 {
760 scanItem = CharNext(scanItem);
761 }
762
763 if (!scanItem[0])
764 {
765 /* Ran out of string */
766 return FALSE;
767 }
768 }
769 else
770 {
771 /* Scan for first character (no case) */
772 scanItem = _tcschr(scanItem, wildMark[0]);
773 if (!scanItem)
774 {
775 /* Ran out of string */
776 return FALSE;
777 }
778 }
779
780 /* Try and match the sub-string at wildMark against scanItem */
781 if (_tcsnicmp(scanItem, wildMark, matchlen) != 0)
782 {
783 /* Nope, try again */
784 scanItem = CharNext(scanItem);
785 continue;
786 }
787
788 /* Substring matched */
789 scanItem += matchlen;
790 wildMark += matchlen;
791 }
792 return (wildMark[0] ? FALSE : TRUE);
793}
794
795/*++
796
797 Routine Description:
798
799 Compares all strings in Array against Id
800 Use WildCardMatch to do real compare
801
802 Arguments:
803
804 Array - pointer returned by GetDevMultiSz
805 MatchEntry - string to compare against
806
807 Return Value:
808
809 TRUE if any match, otherwise FALSE
810
811 --*/
812BOOL WildCompareHwIds (LPTSTR * Array, const IdEntry & MatchEntry)
813{
814 if (Array)
815 {
816 while (Array[0])
817 {
818 if (WildCardMatch(Array[0], MatchEntry))
819 {
820 return TRUE;
821 }
822 Array++;
823 }
824 }
825 return FALSE;
826}
827
828/*++
829
830 Routine Description:
831
832 Generic enumerator for devices that will be passed the following arguments:
833 <id> [<id>...]
834 =<class> [<id>...]
835 where <id> can either be @instance-id, or hardware-id and may contain wildcards
836 <class> is a class name
837
838 Arguments:
839
840 BaseName - name of executable
841 Machine - name of machine to enumerate
842 Flags - extra enumeration flags (eg DIGCF_PRESENT)
843 argc/argv - remaining arguments on command line
844 Callback - function to call for each hit
845 Context - data to pass function for each hit
846
847 Return Value:
848
849 EXIT_xxxx
850
851 --*/
852int EnumerateDevices (LPCTSTR BaseName, LPCTSTR Machine, DWORD Flags, int argc, LPTSTR argv[], fnCallback Callback, LPVOID Context)
853{
854 HDEVINFO devs = INVALID_HANDLE_VALUE;
855 IdEntry * templ = NULL;
856 int failcode = EXIT_FAIL;
857 int retcode;
858 int argIndex;
859 DWORD devIndex;
860 SP_DEVINFO_DATA devInfo;
861 SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
862 BOOL doSearch = FALSE;
863 BOOL match;
864 BOOL all = FALSE;
865 GUID cls;
866 DWORD numClass = 0;
867 int skip = 0;
868
869 if (!argc)
870 {
871 return EXIT_USAGE;
872 }
873
874 templ = new IdEntry[argc];
875 if (!templ)
876 {
877 goto final;
878 }
879
880 /* Determine if a class is specified */
881 if (argc > skip && argv[skip][0] == CLASS_PREFIX_CHAR && argv[skip][1])
882 {
883 if (!g_pfnSetupDiClassGuidsFromNameEx(argv[skip] + 1, &cls, 1, &numClass, Machine, NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
884 {
885 goto final;
886 }
887 if (!numClass)
888 {
889 failcode = EXIT_OK;
890 goto final;
891 }
892 skip++;
893 }
894
895 if (argc > skip && argv[skip][0] == WILD_CHAR && !argv[skip][1])
896 {
897 /* Catch convinient case of specifying a single argument '*' */
898 all = TRUE;
899 skip++;
900 }
901 else if (argc <= skip)
902 {
903 /* At least one parameter, but no <id>'s */
904 all = TRUE;
905 }
906
907 /* Determine if any instance id's were specified */
908
909 /* Note, if =<class> was specified with no id's
910 we'll mark it as not doSearch
911 but will go ahead and add them all */
912 for (argIndex = skip; argIndex < argc; argIndex++)
913 {
914 templ[argIndex] = GetIdType(argv[argIndex]);
915 if (templ[argIndex].szWild || !templ[argIndex].bInstanceId)
916 {
917 /* Anything other than simple bInstanceId's require a search */
918 doSearch = TRUE;
919 }
920 }
921 if (doSearch || all)
922 {
923 /* Add all id's to list
924 If there's a class, filter on specified class */
925 devs = g_pfnSetupDiGetClassDevsEx(numClass ? &cls : NULL, NULL, NULL, (numClass ? 0 : DIGCF_ALLCLASSES) | Flags, NULL, Machine, NULL);
926
927 }
928 else
929 {
930 /* Blank list, we'll add instance id's by hand */
931 devs = g_pfnSetupDiCreateDeviceInfoListEx(numClass ? &cls : NULL, NULL, Machine, NULL);
932 }
933 if (devs == INVALID_HANDLE_VALUE)
934 {
935 goto final;
936 }
937 for (argIndex = skip; argIndex < argc; argIndex++)
938 {
939 /* Add explicit instances to list (even if enumerated all,
940 this gets around DIGCF_PRESENT)
941 do this even if wildcards appear to be detected since they
942 might actually be part of the instance ID of a non-present device */
943 if (templ[argIndex].bInstanceId)
944 {
945 g_pfnSetupDiOpenDeviceInfo(devs, templ[argIndex].szString, NULL, 0, NULL);
946 }
947 }
948
949 devInfoListDetail.cbSize = sizeof(devInfoListDetail);
950 if (!g_pfnSetupDiGetDeviceInfoListDetail(devs, &devInfoListDetail))
951 {
952 goto final;
953 }
954
955 /* Now enumerate them */
956 if (all)
957 {
958 doSearch = FALSE;
959 }
960
961 devInfo.cbSize = sizeof(devInfo);
962 for (devIndex = 0; g_pfnSetupDiEnumDeviceInfo(devs, devIndex, &devInfo); devIndex++)
963 {
964
965 if (doSearch)
966 {
967 for (argIndex = skip, match = FALSE; (argIndex < argc) && !match; argIndex++)
968 {
969 TCHAR devID[MAX_DEVICE_ID_LEN];
970 LPTSTR *hwIds = NULL;
971 LPTSTR *compatIds = NULL;
972
973 /* Determine instance ID */
974 if (g_pfnCM_Get_Device_ID_Ex(devInfo.DevInst, devID, MAX_DEVICE_ID_LEN, 0, devInfoListDetail.RemoteMachineHandle) != CR_SUCCESS)
975 {
976 devID[0] = TEXT('\0');
977 }
978
979 if (templ[argIndex].bInstanceId)
980 {
981 /* Match on the instance ID */
982 if (WildCardMatch(devID, templ[argIndex]))
983 match = TRUE;
984
985 }
986 else
987 {
988 /* Determine hardware ID's and search for matches */
989 hwIds = GetDevMultiSz(devs, &devInfo, SPDRP_HARDWAREID);
990 compatIds = GetDevMultiSz(devs, &devInfo, SPDRP_COMPATIBLEIDS);
991
992 if (WildCompareHwIds(hwIds, templ[argIndex]) || WildCompareHwIds(compatIds, templ[argIndex]))
993 {
994 match = TRUE;
995 }
996 }
997 DelMultiSz(hwIds);
998 DelMultiSz(compatIds);
999 }
1000 }
1001 else
1002 {
1003 match = TRUE;
1004 }
1005 if (match)
1006 {
1007 retcode = Callback(devs, &devInfo, devIndex, Context);
1008 if (retcode)
1009 {
1010 failcode = retcode;
1011 goto final;
1012 }
1013 }
1014 }
1015
1016 failcode = EXIT_OK;
1017
1018 final: if (templ)
1019 {
1020 delete[] templ;
1021 }
1022 if (devs != INVALID_HANDLE_VALUE)
1023 {
1024 g_pfnSetupDiDestroyDeviceInfoList(devs);
1025 }
1026 return failcode;
1027
1028}
1029
1030/*++
1031
1032 Routine Description:
1033
1034 Callback for use by Remove
1035 Invokes DIF_REMOVE
1036 uses g_pfnSetupDiCallClassInstaller so cannot be done for remote devices
1037 Don't use CM_xxx API's, they bypass class/co-installers and this is bad.
1038
1039 Arguments:
1040
1041 Devs )_ uniquely identify the device
1042 DevInfo )
1043 Index - index of device
1044 Context - GenericContext
1045
1046 Return Value:
1047
1048 EXIT_xxxx
1049
1050 --*/
1051int UninstallCallback (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context)
1052{
1053 SP_REMOVEDEVICE_PARAMS rmdParams;
1054 SP_DEVINSTALL_PARAMS devParams;
1055 LPCTSTR action = NULL;
1056
1057 /* Need hardware ID before trying to remove, as we wont have it after */
1058 TCHAR devID[MAX_DEVICE_ID_LEN];
1059 SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
1060
1061 devInfoListDetail.cbSize = sizeof(devInfoListDetail);
1062
1063 if ((!g_pfnSetupDiGetDeviceInfoListDetail(Devs, &devInfoListDetail)) || (g_pfnCM_Get_Device_ID_Ex(DevInfo->DevInst, devID, MAX_DEVICE_ID_LEN, 0, devInfoListDetail.RemoteMachineHandle)
1064 != CR_SUCCESS))
1065 {
1066 /* Skip this */
1067 return EXIT_OK;
1068 }
1069
1070 rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
1071 rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
1072 rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
1073 rmdParams.HwProfile = 0;
1074
1075 if (!g_pfnSetupDiSetClassInstallParams(Devs, DevInfo, &rmdParams.ClassInstallHeader, sizeof(rmdParams)) || !g_pfnSetupDiCallClassInstaller(DIF_REMOVE, Devs, DevInfo))
1076 {
1077 /* Failed to invoke DIF_REMOVE, TODO! */
1078 _tprintf(_T("Failed to invoke interface!\n"));
1079 return EXIT_FAIL;
1080 }
1081
1082 /* See if device needs reboot */
1083 devParams.cbSize = sizeof(devParams);
1084 if (g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &devParams) && (devParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)))
1085 {
1086 /* Reboot required */
1087 _tprintf(_T("To fully uninstall, a reboot is required!\n"));
1088 }
1089 else
1090 {
1091 /* Appears to have succeeded */
1092 _tprintf(_T("Uninstall succeeded!\n"));
1093 }
1094
1095 return EXIT_OK;
1096}
1097
1098/*++
1099
1100 Routine Description:
1101
1102 Find the driver that is associated with the current device
1103 We can do this either the quick way (available in WinXP)
1104 or the long way that works in Win2k.
1105
1106 Arguments:
1107
1108 Devs )_ uniquely identify device
1109 DevInfo )
1110
1111 Return Value:
1112
1113 TRUE if we managed to determine and select current driver
1114
1115 --*/
1116BOOL FindCurrentDriver (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, PSP_DRVINFO_DATA DriverInfoData)
1117{
1118 SP_DEVINSTALL_PARAMS deviceInstallParams;
1119 WCHAR SectionName[LINE_LEN];
1120 WCHAR DrvDescription[LINE_LEN];
1121 WCHAR MfgName[LINE_LEN];
1122 WCHAR ProviderName[LINE_LEN];
1123 HKEY hKey = NULL;
1124 DWORD RegDataLength;
1125 DWORD RegDataType;
1126 DWORD c;
1127 BOOL match = FALSE;
1128 long regerr;
1129
1130 ZeroMemory(&deviceInstallParams, sizeof(deviceInstallParams));
1131 deviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
1132
1133 if (!g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
1134 {
1135 printf("Could not retrieve install params!");
1136 return FALSE;
1137 }
1138
1139#ifdef DI_FLAGSEX_INSTALLEDDRIVER
1140
1141 /* Set the flags that tell g_pfnSetupDiBuildDriverInfoList to just put the
1142 currently installed driver node in the list, and that it should allow
1143 excluded drivers. This flag introduced in WinXP. */
1144 deviceInstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
1145
1146 if (g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
1147 {
1148 /* We were able to specify this flag, so proceed the easy way
1149 We should get a list of no more than 1 driver */
1150 if (!g_pfnSetupDiBuildDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER))
1151 {
1152 return FALSE;
1153 }
1154 if (!g_pfnSetupDiEnumDriverInfo(Devs, DevInfo, SPDIT_CLASSDRIVER, 0, DriverInfoData))
1155 {
1156 return FALSE;
1157 }
1158
1159 /* We've selected the current driver */
1160 return TRUE;
1161 }
1162
1163 deviceInstallParams.FlagsEx &= ~(DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
1164
1165#endif
1166
1167 /* The following method works in Win2k, but it's slow and painful.
1168 First, get driver key - if it doesn't exist, no driver */
1169 hKey = g_pfnSetupDiOpenDevRegKey(Devs, DevInfo, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ
1170 );
1171
1172 if (hKey == INVALID_HANDLE_VALUE)
1173 {
1174
1175 _tprintf(_T("No associated driver found in registry!"));
1176
1177 /* No such value exists, so there can't be an associated driver */
1178 RegCloseKey(hKey);
1179 return FALSE;
1180 }
1181
1182 /* Obtain path of INF - we'll do a search on this specific INF */
1183 RegDataLength = sizeof(deviceInstallParams.DriverPath); /* Bytes!!! */
1184 regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFPATH, NULL, &RegDataType, (PBYTE)deviceInstallParams.DriverPath, &RegDataLength);
1185
1186 if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
1187 {
1188
1189 _tprintf(_T("No associated .inf path found in registry!"));
1190
1191 /* No such value exists, so no associated driver */
1192 RegCloseKey(hKey);
1193 return FALSE;
1194 }
1195
1196 /* Obtain name of Provider to fill into DriverInfoData */
1197 RegDataLength = sizeof(ProviderName); /* Bytes!!! */
1198 regerr = RegQueryValueEx(hKey, REGSTR_VAL_PROVIDER_NAME, NULL, &RegDataType, (PBYTE)ProviderName, &RegDataLength);
1199
1200 if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
1201 {
1202 /* No such value exists, so we don't have a valid associated driver */
1203 RegCloseKey(hKey);
1204 return FALSE;
1205 }
1206
1207 /* Obtain name of section - for final verification */
1208 RegDataLength = sizeof(SectionName); /* Bytes!!! */
1209 regerr = RegQueryValueEx(hKey, REGSTR_VAL_INFSECTION, NULL, &RegDataType, (PBYTE)SectionName, &RegDataLength);
1210
1211 if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
1212 {
1213 /* No such value exists, so we don't have a valid associated driver */
1214 RegCloseKey(hKey);
1215 return FALSE;
1216 }
1217
1218 /* Driver description (need not be same as device description) - for final verification */
1219 RegDataLength = sizeof(DrvDescription); /* Bytes!!! */
1220 regerr = RegQueryValueEx(hKey, REGSTR_VAL_DRVDESC, NULL, &RegDataType, (PBYTE)DrvDescription, &RegDataLength);
1221
1222 RegCloseKey(hKey);
1223
1224 if ((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ))
1225 {
1226 /* No such value exists, so we don't have a valid associated driver */
1227 return FALSE;
1228 }
1229
1230 /* Manufacturer (via SPDRP_MFG, don't access registry directly!) */
1231 if (!g_pfnSetupDiGetDeviceRegistryProperty(Devs, DevInfo, SPDRP_MFG, NULL, /* Datatype is guaranteed to always be REG_SZ */
1232 (PBYTE)MfgName, sizeof(MfgName), /* Bytes!!! */
1233 NULL))
1234 {
1235 /* No such value exists, so we don't have a valid associated driver */
1236 return FALSE;
1237 }
1238
1239 /* Now search for drivers listed in the INF */
1240 deviceInstallParams.Flags |= DI_ENUMSINGLEINF;
1241 deviceInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
1242
1243 if (!g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
1244 {
1245 return FALSE;
1246 }
1247 if (!g_pfnSetupDiBuildDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER))
1248 {
1249 return FALSE;
1250 }
1251
1252 /* Find the entry in the INF that was used to install the driver for this device */
1253 for (c = 0; g_pfnSetupDiEnumDriverInfo(Devs, DevInfo, SPDIT_CLASSDRIVER, c, DriverInfoData); c++)
1254 {
1255 if ((_tcscmp(DriverInfoData->MfgName, MfgName) == 0) && (_tcscmp(DriverInfoData->ProviderName, ProviderName) == 0))
1256 {
1257 /* These two fields match, try more detailed info to ensure we have the exact driver entry used */
1258 SP_DRVINFO_DETAIL_DATA detail;
1259 detail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
1260 if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, DriverInfoData, &detail, sizeof(detail), NULL) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
1261 {
1262 continue;
1263 }
1264 if ((_tcscmp(detail.SectionName, SectionName) == 0) && (_tcscmp(detail.DrvDescription, DrvDescription) == 0))
1265 {
1266 match = TRUE;
1267 break;
1268 }
1269 }
1270 }
1271 if (!match)
1272 {
1273 g_pfnSetupDiDestroyDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER);
1274 }
1275 return match;
1276}
1277
1278/*++
1279
1280 Routine Description:
1281
1282 if Context provided, Simply count
1283 otherwise dump files indented 2
1284
1285 Arguments:
1286
1287 Context - DWORD Count
1288 Notification - SPFILENOTIFY_QUEUESCAN
1289 Param1 - scan
1290
1291 Return Value:
1292
1293 none
1294
1295 --*/
1296UINT DumpDeviceDriversCallback (IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2)
1297{
1298 LPDWORD count = (LPDWORD)Context;
1299 LPTSTR file = (LPTSTR)Param1;
1300 if (count)
1301 {
1302 count[0]++;
1303 }
1304 else
1305 {
1306 _tprintf(TEXT("%s\n"), file);
1307 }
1308
1309 return NO_ERROR;
1310}
1311
1312/*++
1313
1314 Routine Description:
1315
1316 Dump information about what files were installed for driver package
1317 <tab>Installed using OEM123.INF section [abc.NT]
1318 <tab><tab>file...
1319
1320 Arguments:
1321
1322 Devs )_ uniquely identify device
1323 DevInfo )
1324
1325 Return Value:
1326
1327 none
1328
1329 --*/
1330int DeleteOEMInfCallback (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context)
1331{
1332 /* Do this by 'searching' for the current driver
1333 mimmicing a copy-only install to our own file queue
1334 and then parsing that file queue */
1335 SP_DEVINSTALL_PARAMS deviceInstallParams;
1336 SP_DRVINFO_DATA driverInfoData;
1337 SP_DRVINFO_DETAIL_DATA driverInfoDetail;
1338 HSPFILEQ queueHandle = INVALID_HANDLE_VALUE;
1339 DWORD count;
1340 DWORD scanResult;
1341 int success = EXIT_FAIL;
1342
1343 ZeroMemory(&driverInfoData,sizeof(driverInfoData));
1344 driverInfoData.cbSize = sizeof(driverInfoData);
1345
1346 if (!FindCurrentDriver(Devs, DevInfo, &driverInfoData))
1347 return EXIT_FAIL;
1348
1349 _tprintf(_T("Driver files found!\n"));
1350
1351 /* Get useful driver information */
1352 driverInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
1353 if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, &driverInfoData, &driverInfoDetail, sizeof(SP_DRVINFO_DETAIL_DATA), NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1354 {
1355 /* No information about driver or section */
1356 _tprintf(_T("No information about driver or section!\n"));
1357 goto final;
1358 }
1359
1360 if (!driverInfoDetail.InfFileName[0] || !driverInfoDetail.SectionName[0])
1361 {
1362 _tprintf(_T("Driver or section name is empty!\n"));
1363 goto final;
1364 }
1365
1366 _tprintf(_T("Desc: %s\n"), driverInfoDetail.DrvDescription);
1367 _tprintf(_T("SecName: %s\n"), driverInfoDetail.SectionName);
1368 _tprintf(_T("INF-File: %s\n"), driverInfoDetail.InfFileName);
1369
1370 /* Pretend to do the file-copy part of a driver install
1371 to determine what files are used
1372 the specified driver must be selected as the active driver */
1373 if (!g_pfnSetupDiSetSelectedDriver(Devs, DevInfo, &driverInfoData))
1374 goto final;
1375
1376 /* Create a file queue so we can look at this queue later */
1377 queueHandle = SetupOpenFileQueue();
1378
1379 if (queueHandle == (HSPFILEQ)INVALID_HANDLE_VALUE)
1380 {
1381 goto final;
1382 }
1383
1384 /* Modify flags to indicate we're providing our own queue */
1385 ZeroMemory(&deviceInstallParams, sizeof(deviceInstallParams));
1386 deviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
1387 if (!g_pfnSetupDiGetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
1388 goto final;
1389
1390 /* We want to add the files to the file queue, not install them! */
1391 deviceInstallParams.FileQueue = queueHandle;
1392 deviceInstallParams.Flags |= DI_NOVCP;
1393
1394 if (!g_pfnSetupDiSetDeviceInstallParams(Devs, DevInfo, &deviceInstallParams))
1395 goto final;
1396
1397 /* Now fill queue with files that are to be installed this involves all class/co-installers */
1398 if (!g_pfnSetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES, Devs, DevInfo))
1399 goto final;
1400
1401 /* We now have a list of delete/rename/copy files
1402 iterate the copy queue twice - 1st time to get # of files
1403 2nd time to get files (WinXP has API to get # of files, but we want this to work
1404 on Win2k too */
1405 count = 0;
1406 scanResult = 0;
1407
1408 /* Call once to count (NOT YET IMPLEMENTED!) */
1409 //SetupScanFileQueue(queueHandle,SPQ_SCAN_USE_CALLBACK,NULL,DumpDeviceDriversCallback,&count,&scanResult);
1410 //FormatToStream(stdout, count ? MSG_DUMP_DRIVER_FILES : MSG_DUMP_NO_DRIVER_FILES, count, driverInfoDetail.InfFileName, driverInfoDetail.SectionName);
1411
1412 /* Call again to dump the files (NOT YET IMPLEMENTED!) */
1413 //SetupScanFileQueue(queueHandle,SPQ_SCAN_USE_CALLBACK,NULL,DumpDeviceDriversCallback,NULL,&scanResult);
1414
1415 if (!DeleteFile(driverInfoDetail.InfFileName))
1416 scanResult = GetLastError();
1417 else
1418 {
1419 DWORD index = 0;
1420
1421 index = lstrlen(driverInfoDetail.InfFileName);
1422 if (index > 3)
1423 {
1424 lstrcpy(driverInfoDetail.InfFileName + index - 3, TEXT( "pnf" ) );
1425
1426 if (!DeleteFile(driverInfoDetail.InfFileName))
1427 scanResult = GetLastError();
1428 }
1429 }
1430
1431 success = EXIT_OK;
1432
1433 final:
1434
1435 g_pfnSetupDiDestroyDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER);
1436
1437 if (queueHandle != (HSPFILEQ)INVALID_HANDLE_VALUE)
1438 {
1439 SetupCloseFileQueue(queueHandle);
1440 }
1441
1442 if (EXIT_OK != success)
1443 {
1444 _tprintf(_T("Something went wrong while delete the OEM INF-files!\n\n"));
1445 }
1446
1447 return success;
1448
1449}
1450
1451int UninstallDriver (_TCHAR* a_pszHwID)
1452{
1453 _tprintf(_T("Uninstalling device: %ws\n"), a_pszHwID);
1454
1455 _tprintf(_T("Removing driver files ...\n\n"));
1456 int iRet = EnumerateDevices(NULL, NULL, DIGCF_PRESENT, 1, &a_pszHwID, DeleteOEMInfCallback, NULL);
1457
1458 if (EXIT_OK != iRet)
1459 return iRet;
1460
1461 _tprintf(_T("Uninstalling driver ...\n\n"));
1462 iRet = EnumerateDevices(NULL, NULL, DIGCF_PRESENT, 1, &a_pszHwID, UninstallCallback, NULL);
1463
1464 return iRet;
1465}
1466
1467#ifdef VBOXWDDM
1468/*++
1469
1470 Routine Description:
1471
1472 Dump information about what files were installed for driver package
1473 <tab>Installed using OEM123.INF section [abc.NT]
1474 <tab><tab>file...
1475
1476 Arguments:
1477
1478 Devs )_ uniquely identify device
1479 DevInfo )
1480
1481 Return Value:
1482
1483 none
1484
1485 --*/
1486int MatchDriverCallback (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context)
1487{
1488 /* Do this by 'searching' for the current driver
1489 mimmicing a copy-only install to our own file queue
1490 and then parsing that file queue */
1491 SP_DRVINFO_DATA driverInfoData;
1492 SP_DRVINFO_DETAIL_DATA driverInfoDetail;
1493 LPCTSTR pStr = (LPCTSTR)Context;
1494 int success = EXIT_FAIL;
1495
1496 ZeroMemory(&driverInfoData,sizeof(driverInfoData));
1497 driverInfoData.cbSize = sizeof(driverInfoData);
1498
1499 if (!FindCurrentDriver(Devs, DevInfo, &driverInfoData))
1500 return EXIT_FAIL;
1501
1502 _tprintf(_T("Driver files found!\n"));
1503
1504 /* Get useful driver information */
1505 driverInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
1506 if (!g_pfnSetupDiGetDriverInfoDetail(Devs, DevInfo, &driverInfoData, &driverInfoDetail, sizeof(SP_DRVINFO_DETAIL_DATA), NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1507 {
1508 /* No information about driver or section */
1509 _tprintf(_T("No information about driver or section!\n"));
1510 goto final;
1511 }
1512
1513 if (!driverInfoDetail.InfFileName[0] || !driverInfoDetail.SectionName[0])
1514 {
1515 _tprintf(_T("Driver or section name is empty!\n"));
1516 goto final;
1517 }
1518
1519 _tprintf(_T("Desc: %s\n"), driverInfoDetail.DrvDescription);
1520 _tprintf(_T("SecName: %s\n"), driverInfoDetail.SectionName);
1521 _tprintf(_T("INF-File: %s\n"), driverInfoDetail.InfFileName);
1522
1523 if (_tcsstr(driverInfoDetail.DrvDescription, pStr))
1524 {
1525 _tprintf(_T("Driver name matched\n"));
1526 success = EXIT_OK;
1527 }
1528 else
1529 {
1530 _tprintf(_T("Driver name NOT matched\n"));
1531 success = EXIT_FALSE;
1532 }
1533
1534 final:
1535
1536 g_pfnSetupDiDestroyDriverInfoList(Devs, DevInfo, SPDIT_CLASSDRIVER);
1537
1538 if (EXIT_OK != success && EXIT_FALSE != success)
1539 {
1540 _tprintf(_T("Something went wrong while delete the OEM INF-files!\n\n"));
1541 }
1542
1543 return success;
1544}
1545
1546int MatchDriver (_TCHAR* a_pszHwID, _TCHAR* a_pszDrvName)
1547{
1548 _tprintf(_T("Checking Device: %ws ; for driver desc string %ws\n"), a_pszHwID, a_pszDrvName);
1549
1550 int iRet = EnumerateDevices(NULL, NULL, DIGCF_PRESENT, 1, &a_pszHwID, MatchDriverCallback, a_pszDrvName);
1551
1552 return iRet;
1553}
1554#endif
1555
1556int ExecuteInfFile (_TCHAR* a_pszSection, int a_iMode, _TCHAR* a_pszInf)
1557{
1558 _tprintf(_T("Executing INF-File: %ws (%ws) ...\n"), a_pszInf, a_pszSection);
1559
1560 /* Executed by the installer that already has proper privileges. */
1561 _TCHAR szCommandLine[_MAX_PATH + 1] = { 0 };
1562 swprintf(szCommandLine, sizeof(szCommandLine), TEXT( "%ws %d %ws" ), a_pszSection, a_iMode, a_pszInf);
1563
1564#ifdef _DEBUG
1565 _tprintf (_T( "Commandline: %ws\n"), szCommandLine);
1566#endif
1567
1568 InstallHinfSection(NULL, NULL, szCommandLine, SW_SHOW);
1569
1570 return EXIT_OK;
1571}
1572
1573int AddNetworkProvider (TCHAR* a_pszProvider, int a_iOrder)
1574{
1575 TCHAR szKeyValue[512] = { 0 };
1576 TCHAR szNewKeyValue[512] = { 0 };
1577 HKEY hKey = NULL;
1578 DWORD disp, dwType;
1579 int rc;
1580
1581 _tprintf(_T("Adding network provider: %ws (Order = %d)\n"), a_pszProvider, a_iOrder);
1582
1583 /* Note: HWOrder is not accessible in Windows 2000; it is updated automatically anyway. */
1584 TCHAR *pszKey = _T("System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
1585
1586 rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
1587 if (rc != ERROR_SUCCESS)
1588 {
1589 _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), pszKey, rc);
1590 return EXIT_FAIL;
1591 }
1592 DWORD cbKeyValue = sizeof(szKeyValue);
1593
1594 rc = RegQueryValueEx(hKey, _T("ProviderOrder"), NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
1595 if (rc != ERROR_SUCCESS || dwType != REG_SZ)
1596 {
1597 _tprintf(_T("RegQueryValueEx failed with %d dwType = 0x%x!\n"), rc, dwType);
1598 return EXIT_FAIL;
1599 }
1600
1601#ifdef _DEBUG
1602 _tprintf(_T("Key value: %ws\n"), szKeyValue);
1603#endif
1604
1605 /* Create entire new list. */
1606 int iPos = 0;
1607
1608 TCHAR* pszToken = wcstok(szKeyValue, _T(","));
1609 TCHAR* pszNewToken = NULL;
1610 while (pszToken != NULL)
1611 {
1612 pszNewToken = wcstok(NULL, _T(","));
1613
1614 /* Append new provider name (at beginning if a_iOrder=0). */
1615 if (iPos == a_iOrder)
1616 {
1617 wcscat(szNewKeyValue, a_pszProvider);
1618 wcscat(szNewKeyValue, _T(","));
1619 iPos++;
1620 }
1621
1622 if (0 != wcsicmp(pszToken, a_pszProvider))
1623 {
1624 wcscat(szNewKeyValue, pszToken);
1625 wcscat(szNewKeyValue, _T(","));
1626 iPos++;
1627 }
1628
1629#ifdef _DEBUG
1630 _tprintf (_T("Temp new key value: %ws\n"), szNewKeyValue);
1631#endif
1632
1633 pszToken = pszNewToken;
1634 }
1635
1636 /* Append as last item if needed. */
1637 if (a_iOrder >= iPos)
1638 wcscat(szNewKeyValue, a_pszProvider);
1639
1640 /* Last char a delimiter? Cut off ... */
1641 if (szNewKeyValue[wcslen(szNewKeyValue) - 1] == ',')
1642 szNewKeyValue[wcslen(szNewKeyValue) - 1] = '\0';
1643
1644 size_t iNewLen = (wcslen(szNewKeyValue) * sizeof(WCHAR)) + sizeof(WCHAR);
1645
1646 _tprintf(_T("New provider list (%u bytes): %ws\n"), iNewLen, szNewKeyValue);
1647
1648 rc = RegSetValueExW(hKey, _T("ProviderOrder"), 0, REG_SZ, (LPBYTE)szNewKeyValue, (DWORD)iNewLen);
1649
1650 if (rc != ERROR_SUCCESS)
1651 {
1652 _tprintf(_T("RegSetValueEx failed with %d!\n"), rc);
1653 return EXIT_FAIL;
1654 }
1655
1656 rc = RegCloseKey(hKey);
1657
1658 if (rc == ERROR_SUCCESS)
1659 {
1660 _tprintf(_T("Network provider successfully installed!\n"), rc);
1661 rc = EXIT_OK;
1662 }
1663
1664 return rc;
1665}
1666
1667int AddStringToMultiSZ (TCHAR* a_pszSubKey, TCHAR* a_pszKeyValue, TCHAR* a_pszValueToAdd, int a_iOrder)
1668{
1669 TCHAR szKeyValue[512] = { 0 };
1670 TCHAR szNewKeyValue[512] = { 0 };
1671 HKEY hKey = NULL;
1672 DWORD disp, dwType;
1673 int rc = 0;
1674
1675 _tprintf(_T("Adding MULTI_SZ string: %ws to %ws\\%ws (Order = %d)\n"), a_pszValueToAdd, a_pszSubKey, a_pszKeyValue, a_iOrder);
1676
1677 rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, a_pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &disp);
1678 if (rc != ERROR_SUCCESS)
1679 {
1680 _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), a_pszSubKey, rc);
1681 return EXIT_FAIL;
1682 }
1683 DWORD cbKeyValue = sizeof(szKeyValue);
1684
1685 rc = RegQueryValueEx(hKey, a_pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
1686 if (rc != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
1687 {
1688 _tprintf(_T("RegQueryValueEx failed with %d, dwType = 0x%x!\n"), rc, dwType);
1689 return EXIT_FAIL;
1690 }
1691
1692 /* Look if the network provider is already in the list. */
1693 int iPos = 0;
1694 size_t cb = 0;
1695
1696 /* Replace delimiting "\0"'s with "," to make tokenizing work. */
1697 for (int i=0; i<cbKeyValue/sizeof(TCHAR);i++)
1698 if (szKeyValue[i] == '\0') szKeyValue[i] = ',';
1699
1700 TCHAR* pszToken = wcstok(szKeyValue, _T(","));
1701 TCHAR* pszNewToken = NULL;
1702 TCHAR* pNewKeyValuePos = szNewKeyValue;
1703 while (pszToken != NULL)
1704 {
1705 pszNewToken = wcstok(NULL, _T(","));
1706
1707 /* Append new value (at beginning if a_iOrder=0). */
1708 if (iPos == a_iOrder)
1709 {
1710 memcpy(pNewKeyValuePos, a_pszValueToAdd, wcslen(a_pszValueToAdd)*sizeof(TCHAR));
1711
1712 cb += (wcslen(a_pszValueToAdd) + 1) * sizeof(TCHAR); /* Add trailing zero as well. */
1713 pNewKeyValuePos += wcslen(a_pszValueToAdd) + 1;
1714 iPos++;
1715 }
1716
1717 if (0 != wcsicmp(pszToken, a_pszValueToAdd))
1718 {
1719 memcpy(pNewKeyValuePos, pszToken, wcslen(pszToken)*sizeof(TCHAR));
1720 cb += (wcslen(pszToken) + 1) * sizeof(TCHAR); /* Add trailing zero as well. */
1721 pNewKeyValuePos += wcslen(pszToken) + 1;
1722 iPos++;
1723 }
1724
1725 pszToken = pszNewToken;
1726 }
1727
1728 /* Append as last item if needed. */
1729 if (a_iOrder >= iPos)
1730 {
1731 memcpy(pNewKeyValuePos, a_pszValueToAdd, wcslen(a_pszValueToAdd)*sizeof(TCHAR));
1732 cb += wcslen(a_pszValueToAdd) * sizeof(TCHAR); /* Add trailing zero as well. */
1733 }
1734
1735 rc = RegSetValueExW(hKey, a_pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szNewKeyValue, (DWORD)cb);
1736
1737 if (rc != ERROR_SUCCESS)
1738 {
1739 _tprintf(_T("RegSetValueEx failed with %d!\n"), rc);
1740 return EXIT_FAIL;
1741 }
1742
1743 rc = RegCloseKey(hKey);
1744
1745 if (rc == ERROR_SUCCESS)
1746 {
1747 _tprintf(_T("Value successfully written (%u bytes)!\n"), cb);
1748 rc = EXIT_OK;
1749 }
1750
1751 return rc;
1752}
1753
1754int RemoveStringFromMultiSZ (TCHAR* a_pszSubKey, TCHAR* a_pszKeyValue, TCHAR* a_pszValueToRemove)
1755{
1756 // @todo Make string sizes dynamically allocated!
1757
1758 TCHAR szKeyValue[1024];
1759 HKEY hkey;
1760 DWORD disp, dwType;
1761 int rc;
1762
1763 TCHAR *pszKey = a_pszSubKey;
1764
1765 _tprintf(_T("Removing MULTI_SZ string: %ws from %ws\\%ws ...\n"), a_pszValueToRemove, a_pszSubKey, a_pszKeyValue);
1766
1767 rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkey, &disp);
1768 if (rc != ERROR_SUCCESS)
1769 {
1770 _tprintf(_T("RegCreateKeyEx %ts failed with %d!\n"), pszKey, rc);
1771 return EXIT_FAIL;
1772 }
1773 DWORD cbKeyValue = sizeof(szKeyValue);
1774
1775 rc = RegQueryValueEx(hkey, a_pszKeyValue, NULL, &dwType, (LPBYTE)szKeyValue, &cbKeyValue);
1776 if (rc != ERROR_SUCCESS || dwType != REG_MULTI_SZ)
1777 {
1778 _tprintf(_T("RegQueryValueEx failed with %d dwType = 0x%x!\n"), rc, dwType);
1779 return EXIT_FAIL;
1780 }
1781
1782#ifdef _DEBUG
1783 _tprintf(_T("Current key len: %d\n"), cbKeyValue);
1784#endif
1785
1786 TCHAR szCurString[1024] = { 0 };
1787 TCHAR szFinalString[1024] = { 0 };
1788 int iIndex = 0;
1789 int iNewIndex = 0;
1790 for (int i = 0; i < cbKeyValue / sizeof(TCHAR); i++)
1791 {
1792 if (szKeyValue[i] != _T('\0'))
1793 szCurString[iIndex++] = szKeyValue[i];
1794
1795 if ((!szKeyValue[i] == _T('\0')) && szKeyValue[i + 1] == _T('\0'))
1796 {
1797 if (NULL == wcsstr(szCurString, a_pszValueToRemove))
1798 {
1799 wcscat(&szFinalString[iNewIndex], szCurString);
1800
1801 if (iNewIndex == 0)
1802 iNewIndex = iIndex;
1803 else iNewIndex += iIndex;
1804
1805 szFinalString[++iNewIndex] = _T('\0');
1806 }
1807
1808 iIndex = 0;
1809 ZeroMemory( szCurString, sizeof(szCurString));
1810 }
1811 }
1812
1813 szFinalString[++iNewIndex] = _T('\0');
1814
1815#ifdef _DEBUG
1816 _tprintf(_T("New key len: %d\n"), iNewIndex * sizeof(TCHAR));
1817 _tprintf(_T("New key value: %ws\n"), szFinalString);
1818#endif
1819
1820 rc = RegSetValueExW(hkey, a_pszKeyValue, 0, REG_MULTI_SZ, (LPBYTE)szFinalString, iNewIndex * sizeof(TCHAR));
1821
1822 if (rc != ERROR_SUCCESS)
1823 {
1824 _tprintf(_T("RegSetValueEx failed with %d!\n"), rc);
1825 return EXIT_FAIL;
1826 }
1827
1828 rc = RegCloseKey(hkey);
1829
1830 if (rc == ERROR_SUCCESS)
1831 {
1832 _tprintf(_T("Value successfully removed!\n"), rc);
1833 rc = EXIT_OK;
1834 }
1835
1836 return rc;
1837}
1838
1839int CreateService (TCHAR* a_pszStartStopName,
1840 TCHAR* a_pszDisplayName,
1841 int a_iServiceType,
1842 int a_iStartType,
1843 TCHAR* a_pszBinPath,
1844 TCHAR* a_pszLoadOrderGroup,
1845 TCHAR* a_pszDependencies,
1846 TCHAR* a_pszLogonUser,
1847 TCHAR* a_pszLogonPw)
1848{
1849 int rc = ERROR_SUCCESS;
1850
1851 _tprintf(_T("Installing service %ws (%ws) ...\n"), a_pszDisplayName, a_pszStartStopName);
1852
1853 SC_HANDLE hSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
1854 if (hSCManager == NULL)
1855 {
1856 _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError());
1857 return EXIT_FAIL;
1858 }
1859
1860 /* Fixup end of multistring */
1861 TCHAR szDepend[ _MAX_PATH ] = { 0 }; /* @todo Use dynamically allocated string here! */
1862 if (a_pszDependencies != NULL)
1863 {
1864 _tcsnccpy (szDepend, a_pszDependencies, wcslen(a_pszDependencies));
1865 DWORD len = (DWORD)wcslen (szDepend);
1866 szDepend [len + 1] = 0;
1867
1868 /* Replace comma separator on null separator */
1869 for (DWORD i = 0; i < len; i++)
1870 {
1871 if (',' == szDepend [i])
1872 szDepend [i] = 0;
1873 }
1874 }
1875
1876 DWORD dwTag = 0xDEADBEAF;
1877 SC_HANDLE hService = CreateService (hSCManager, // SCManager database
1878 a_pszStartStopName, // name of service
1879 a_pszDisplayName, // name to display
1880 SERVICE_ALL_ACCESS, // desired access
1881 a_iServiceType, // service type
1882 a_iStartType, // start type
1883 SERVICE_ERROR_NORMAL, // error control type
1884 a_pszBinPath, // service's binary
1885 a_pszLoadOrderGroup, // ordering group
1886 (a_pszLoadOrderGroup != NULL) ? &dwTag : NULL, // tag identifier
1887 (a_pszDependencies != NULL) ? szDepend : NULL, // dependencies
1888 (a_pszLogonUser != NULL) ? a_pszLogonUser: NULL, // account
1889 (a_pszLogonPw != NULL) ? a_pszLogonPw : NULL); // password
1890 if (NULL == hService)
1891 {
1892 DWORD dwErr = GetLastError();
1893 switch (dwErr)
1894 {
1895
1896 case ERROR_SERVICE_EXISTS:
1897 {
1898 _tprintf(_T("Service already exists. No installation required. Updating the service config.\n"));
1899
1900 hService = OpenService (hSCManager, // SCManager database
1901 a_pszStartStopName, // name of service
1902 SERVICE_ALL_ACCESS); // desired access
1903 if (NULL == hService)
1904 {
1905 dwErr = GetLastError();
1906 _tprintf(_T("Could not open service! Error: %ld\n"), dwErr);
1907 }
1908 else
1909 {
1910 BOOL Result = ChangeServiceConfig (hService, // service handle
1911 a_iServiceType, // service type
1912 a_iStartType, // start type
1913 SERVICE_ERROR_NORMAL, // error control type
1914 a_pszBinPath, // service's binary
1915 a_pszLoadOrderGroup, // ordering group
1916 (a_pszLoadOrderGroup != NULL) ? &dwTag : NULL, // tag identifier
1917 (a_pszDependencies != NULL) ? szDepend : NULL, // dependencies
1918 (a_pszLogonUser != NULL) ? a_pszLogonUser: NULL, // account
1919 (a_pszLogonPw != NULL) ? a_pszLogonPw : NULL, // password
1920 a_pszDisplayName); // name to display
1921 if (Result)
1922 {
1923 _tprintf(_T("The service config has been successfully updated.\n"));
1924 }
1925 else
1926 {
1927 dwErr = GetLastError();
1928 _tprintf(_T("Could not change service config! Error: %ld\n"), dwErr);
1929 }
1930
1931 CloseServiceHandle (hService);
1932 }
1933
1934 /* This entire branch do not return an error to avoid installations failures,
1935 * if updating service parameters. Better to have a running system with old
1936 * parameters and the failure information in the installation log.
1937 */
1938 break;
1939 }
1940
1941 case ERROR_INVALID_PARAMETER:
1942
1943 _tprintf(_T("Invalid parameter specified!\n"));
1944 rc = EXIT_FAIL;
1945 break;
1946
1947 default:
1948
1949 _tprintf(_T("Could not create service! Error: %ld\n"), dwErr);
1950 rc = EXIT_FAIL;
1951 break;
1952 }
1953
1954 if (rc == EXIT_FAIL)
1955 goto cleanup;
1956 }
1957 else
1958 {
1959 CloseServiceHandle (hService);
1960 _tprintf(_T("Installation of service successful!\n"));
1961 }
1962
1963cleanup:
1964
1965 if (hSCManager != NULL)
1966 CloseServiceHandle (hSCManager);
1967
1968 return rc;
1969}
1970
1971int DelService (TCHAR* a_pszStartStopName)
1972{
1973 int rc = ERROR_SUCCESS;
1974
1975 _tprintf(_T("Deleting service '%ws' ...\n"), a_pszStartStopName);
1976
1977 SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1978 SC_HANDLE hService = NULL;
1979 if (hSCManager == NULL)
1980 {
1981 _tprintf(_T("Could not get handle to SCM! Error: %ld\n"), GetLastError());
1982 rc = EXIT_FAIL;
1983 }
1984 else
1985 {
1986 hService = OpenService(hSCManager, a_pszStartStopName, SERVICE_ALL_ACCESS);
1987 if (NULL == hService)
1988 {
1989 _tprintf(_T("Could not open service '%ws'! Error: %ld\n"), a_pszStartStopName, GetLastError());
1990 rc = EXIT_FAIL;
1991 }
1992 }
1993
1994 if (hService != NULL)
1995 {
1996 if (LockServiceDatabase(hSCManager))
1997 {
1998 if (FALSE == DeleteService(hService))
1999 {
2000 DWORD dwErr = GetLastError();
2001 switch (dwErr)
2002 {
2003
2004 case ERROR_SERVICE_MARKED_FOR_DELETE:
2005
2006 _tprintf(_T("Service '%ws' already marked for deletion.\n"), a_pszStartStopName);
2007 break;
2008
2009 default:
2010
2011 _tprintf(_T("Could not delete service '%ws'! Error: %ld\n"), a_pszStartStopName, GetLastError());
2012 rc = EXIT_FAIL;
2013 break;
2014 }
2015 }
2016 else
2017 {
2018 _tprintf(_T("Service '%ws' successfully removed!\n"), a_pszStartStopName);
2019 }
2020 UnlockServiceDatabase(hSCManager);
2021 }
2022 else
2023 {
2024 _tprintf(_T("Unable to lock service database! Error: %ld\n"), GetLastError());
2025 rc = EXIT_FAIL;
2026 }
2027 CloseServiceHandle(hService);
2028 }
2029
2030 if (hSCManager != NULL)
2031 CloseServiceHandle(hSCManager);
2032
2033 return rc;
2034}
2035
2036DWORD RegistryWrite(HKEY hRootKey,
2037 const _TCHAR *pszSubKey,
2038 const _TCHAR *pszValueName,
2039 DWORD dwType,
2040 const BYTE *pbData,
2041 DWORD cbData)
2042{
2043 DWORD lRet;
2044 HKEY hKey;
2045 lRet = RegCreateKeyEx (hRootKey,
2046 pszSubKey,
2047 0, /* Reserved */
2048 NULL, /* lpClass [in, optional] */
2049 0, /* dwOptions [in] */
2050 KEY_WRITE,
2051 NULL, /* lpSecurityAttributes [in, optional] */
2052 &hKey,
2053 NULL); /* lpdwDisposition [out, optional] */
2054 if (lRet != ERROR_SUCCESS)
2055 {
2056 _tprintf(_T("Could not open registry key! Error: %ld\n"), GetLastError());
2057 }
2058 else
2059 {
2060 lRet = RegSetValueEx(hKey, pszValueName, 0, dwType, (BYTE*)pbData, cbData);
2061 if (lRet != ERROR_SUCCESS)
2062 _tprintf(_T("Could not write to registry! Error: %ld\n"), GetLastError());
2063 RegCloseKey(hKey);
2064
2065 }
2066 return lRet;
2067}
2068
2069void PrintHelp (void)
2070{
2071 _tprintf(_T("Installs / Uninstalls VirtualBox drivers for Windows XP/2K/Vista\n"));
2072 _tprintf(_T("Version: %d.%d.%d.%d\n\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
2073 _tprintf(_T("Syntax:\n"));
2074 _tprintf(_T("\tTo install: VBoxDrvInst /i <HardwareID> <INF-File> <Device Class>\n"));
2075 _tprintf(_T("\tTo uninstall: VBoxDrvInst /u <HardwareID>\n"));
2076 _tprintf(_T("\tTo execute an INF-File: VBoxDrvInst /inf <INF-File>\n"));
2077 _tprintf(_T("\tTo add a network provider: VBoxDrvInst /addnetprovider <Name> [Order]\n\n"));
2078 _tprintf(_T("\tTo write registry values: VBoxDrvInst /registry write <root> <sub key> <key name> <key type> <value> [type] [size]\n\n"));
2079 _tprintf(_T("Examples:\n"));
2080 _tprintf(_T("\tVBoxDrvInst /i \"PCI\\VEN_80EE&DEV_BEEF&SUBSYS_00000000&REV_00\" VBoxVideo.inf Display\n"));
2081 _tprintf(_T("\tVBoxDrvInst /addnetprovider VboxSF 1\n\n"));
2082}
2083
2084int __cdecl _tmain (int argc, _TCHAR* argv[])
2085{
2086 int rc;
2087 OSVERSIONINFO OSinfo;
2088
2089 _TCHAR szHwID[_MAX_PATH] = { 0 }; /* Hardware ID. */
2090 _TCHAR szINF[_MAX_PATH] = { 0 }; /* Complete path to INF file.*/
2091 _TCHAR szDevClass[_MAX_PATH] = { 0 }; /* Device class. */
2092 _TCHAR szProvider[_MAX_PATH] = { 0 }; /* The network provider name for the registry. */
2093
2094 rc = LoadAPICalls();
2095 if ( rc == ERROR_SUCCESS
2096 && argc >= 2)
2097 {
2098 OSinfo.dwOSVersionInfoSize = sizeof(OSinfo);
2099 GetVersionEx(&OSinfo);
2100
2101 if (0 == _tcsicmp(argv[1], _T("/i")))
2102 {
2103 if (argc < 5)
2104 {
2105 rc = EXIT_USAGE;
2106 }
2107 else
2108 {
2109 if (OSinfo.dwMajorVersion < 5)
2110 {
2111 _tprintf(_T("ERROR: Platform not supported yet!\n"));
2112 rc = ERROR_NOT_SUPPORTED;
2113 }
2114
2115 if (rc == ERROR_SUCCESS)
2116 {
2117 _stprintf(szHwID, _T("%ws"), argv[2]);
2118 _stprintf(szINF, _T("%ws"), argv[3]);
2119 _stprintf(szDevClass, _T("%ws"), argv[4]);
2120
2121 rc = InstallDriver(szINF, szHwID, szDevClass);
2122 }
2123 }
2124 }
2125 else if (0 == _tcsicmp(argv[1], _T("/u")))
2126 {
2127 if (argc < 3)
2128 {
2129 rc = EXIT_USAGE;
2130 }
2131 else
2132 {
2133 if (OSinfo.dwMajorVersion < 5)
2134 {
2135 _tprintf(_T("ERROR: Platform not supported yet!\n"));
2136 rc = ERROR_NOT_SUPPORTED;
2137 }
2138
2139 if (rc == ERROR_SUCCESS)
2140 {
2141 _stprintf(szHwID, _T("%ws"), argv[2]);
2142 rc = UninstallDriver(szHwID);
2143 }
2144 }
2145 }
2146 else if (0 == _tcsicmp(argv[1], _T("/inf")))
2147 {
2148 if (argc < 3)
2149 {
2150 rc = EXIT_USAGE;
2151 }
2152 else
2153 {
2154 if (OSinfo.dwMajorVersion < 5)
2155 {
2156 _tprintf(_T("ERROR: Platform not supported yet!\n"));
2157 rc = ERROR_NOT_SUPPORTED;
2158 }
2159
2160 if (rc == ERROR_SUCCESS)
2161 {
2162 _stprintf(szINF, _T("%ws"), argv[2]);
2163 rc = ExecuteInfFile(_T("DefaultInstall"), 132, szINF);
2164 }
2165 }
2166 }
2167 else if (0 == _tcsicmp(argv[1], _T("/addnetprovider")))
2168 {
2169 if (argc < 3)
2170 {
2171 rc = EXIT_USAGE;
2172 }
2173 else
2174 {
2175
2176 int iOrder = 0;
2177 if (argc > 3)
2178 iOrder = _ttoi(argv[3]);
2179 _stprintf(szProvider, _T("%ws"), argv[2]);
2180 rc = AddNetworkProvider(szProvider, iOrder);
2181 }
2182 }
2183 else if (0 == _tcsicmp(argv[1], _T("/reg_addmultisz")))
2184 {
2185 if (argc < 6)
2186 {
2187 rc = EXIT_USAGE;
2188 }
2189 else
2190 {
2191 rc = AddStringToMultiSZ(argv[2], argv[3], argv[4], _ttoi(argv[5]));
2192 }
2193 }
2194 else if (0 == _tcsicmp(argv[1], _T("/reg_delmultisz")))
2195 {
2196 if (argc < 5)
2197 {
2198 rc = EXIT_USAGE;
2199 }
2200 else
2201 {
2202 rc = RemoveStringFromMultiSZ(argv[2], argv[3], argv[4]);
2203 }
2204 }
2205 else if (0 == _tcsicmp(argv[1], _T("/createsvc")))
2206 {
2207 if (argc < 7)
2208 {
2209 rc = EXIT_USAGE;
2210 }
2211 else
2212 {
2213 rc = CreateService(
2214 argv[2],
2215 argv[3],
2216 _ttoi(argv[4]),
2217 _ttoi(argv[5]),
2218 argv[6],
2219 (argc > 7) ? argv[7] : NULL,
2220 (argc > 8) ? argv[8] : NULL,
2221 (argc > 9) ? argv[9] : NULL,
2222 (argc > 10) ? argv[10] : NULL);
2223 }
2224 }
2225 else if (0 == _tcsicmp(argv[1], _T("/delsvc")))
2226 {
2227 if (argc < 3)
2228 {
2229 rc = EXIT_USAGE;
2230 }
2231 else
2232 {
2233 rc = DelService(argv[2]);
2234 }
2235 }
2236 else if (0 == _tcsicmp(argv[1], _T("/registry")))
2237 {
2238 if (argc < 8)
2239 {
2240 rc = EXIT_USAGE;
2241 }
2242 else
2243 {
2244 /** @todo add a handleRegistry(argc, argv) method to keep things cleaner */
2245 if (0 == _tcsicmp(argv[2], _T("write")))
2246 {
2247 HKEY hRootKey = HKEY_LOCAL_MACHINE; /** @todo needs to be expanded (argv[3]) */
2248 DWORD dwValSize;
2249 BYTE *pbVal = NULL;
2250 DWORD dwVal;
2251
2252 if (argc > 8)
2253 {
2254 if (0 == _tcsicmp(argv[8], _T("dword")))
2255 {
2256 dwVal = _ttol(argv[7]);
2257 pbVal = (BYTE*)&dwVal;
2258 dwValSize = sizeof(DWORD);
2259 }
2260 }
2261 if (pbVal == NULL) /* By default interpret value as string */
2262 {
2263 pbVal = (BYTE*)argv[7];
2264 dwValSize = _tcslen(argv[7]);
2265 }
2266 if (argc > 9)
2267 dwValSize = _ttol(argv[9]); /* Get the size in bytes of the value we want to write */
2268 rc = RegistryWrite(hRootKey,
2269 argv[4], /* Sub key */
2270 argv[5], /* Value name */
2271 REG_BINARY, /** @todo needs to be expanded (argv[6]) */
2272 pbVal, /* The value itself */
2273 dwValSize); /* Size of the value */
2274 }
2275 /*else if (0 == _tcsicmp(argv[2], _T("read")))
2276 {
2277 }
2278 else if (0 == _tcsicmp(argv[2], _T("del")))
2279 {
2280 }*/
2281 else
2282 rc = EXIT_USAGE;
2283 }
2284 }
2285#ifdef VBOXWDDM
2286 else if (0 == _tcsicmp(argv[1], _T("/matchdrv")))
2287 {
2288 if (argc < 4)
2289 {
2290 rc = EXIT_USAGE;
2291 }
2292 else
2293 {
2294 if (OSinfo.dwMajorVersion < 5)
2295 {
2296 _tprintf(_T("ERROR: Platform not supported yet!\n"));
2297 rc = ERROR_NOT_SUPPORTED;
2298 }
2299
2300 if (rc == ERROR_SUCCESS)
2301 {
2302 _stprintf(szHwID, _T("%ws"), argv[2]);
2303 rc = MatchDriver(szHwID, argv[3]);
2304 }
2305 }
2306 }
2307#endif
2308 }
2309
2310 if (rc == EXIT_USAGE)
2311 PrintHelp();
2312
2313 FreeAPICalls();
2314 return rc;
2315}
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