VirtualBox

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

Last change on this file since 33540 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

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

© 2023 Oracle
ContactPrivacy policyTerms of Use