VirtualBox

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

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

Windows Additions: export shared folders and installer to OSE

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