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 |
|
---|
34 | typedef int (*fnCallback) (HDEVINFO Devs, PSP_DEVINFO_DATA DevInfo, DWORD Index, LPVOID Context);
|
---|
35 |
|
---|
36 | struct 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 */
|
---|
65 | HMODULE g_hSetupAPI = NULL;
|
---|
66 | HMODULE g_hNewDev = NULL;
|
---|
67 | HMODULE g_hCfgMgr = NULL;
|
---|
68 |
|
---|
69 | /* Function pointers for dynamic loading of some API calls NT4 hasn't ... */
|
---|
70 | typedef BOOL (WINAPI *fnSetupDiCreateDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceName, LPGUID ClassGuid, PCTSTR DeviceDescription, HWND hwndParent, DWORD CreationFlags,
|
---|
71 | PSP_DEVINFO_DATA DeviceInfoData);
|
---|
72 | fnSetupDiCreateDeviceInfo g_pfnSetupDiCreateDeviceInfo = NULL;
|
---|
73 |
|
---|
74 | typedef BOOL (WINAPI *fnSetupDiOpenDeviceInfo) (HDEVINFO DeviceInfoSet, PCTSTR DeviceInstanceId, HWND hwndParent, DWORD OpenFlags, PSP_DEVINFO_DATA DeviceInfoData);
|
---|
75 | fnSetupDiOpenDeviceInfo g_pfnSetupDiOpenDeviceInfo = NULL;
|
---|
76 |
|
---|
77 | typedef BOOL (WINAPI *fnSetupDiEnumDeviceInfo) (HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData);
|
---|
78 | fnSetupDiEnumDeviceInfo g_pfnSetupDiEnumDeviceInfo = NULL;
|
---|
79 |
|
---|
80 | /***/
|
---|
81 |
|
---|
82 | typedef HDEVINFO (WINAPI *fnSetupDiCreateDeviceInfoList) (LPGUID ClassGuid, HWND hwndParent);
|
---|
83 | fnSetupDiCreateDeviceInfoList g_pfnSetupDiCreateDeviceInfoList = NULL;
|
---|
84 |
|
---|
85 | typedef HDEVINFO (WINAPI *fnSetupDiCreateDeviceInfoListEx) (LPGUID ClassGuid, HWND hwndParent, PCTSTR MachineName, PVOID Reserved);
|
---|
86 | fnSetupDiCreateDeviceInfoListEx g_pfnSetupDiCreateDeviceInfoListEx = NULL;
|
---|
87 |
|
---|
88 | typedef BOOL (WINAPI *fnSetupDiDestroyDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType);
|
---|
89 | fnSetupDiDestroyDriverInfoList g_pfnSetupDiDestroyDriverInfoList = NULL;
|
---|
90 |
|
---|
91 | typedef BOOL (WINAPI *fnSetupDiDestroyDeviceInfoList) (HDEVINFO DeviceInfoSet);
|
---|
92 | fnSetupDiDestroyDeviceInfoList g_pfnSetupDiDestroyDeviceInfoList = NULL;
|
---|
93 |
|
---|
94 | typedef BOOL (WINAPI *fnSetupDiGetDeviceInfoListDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_LIST_DETAIL_DATA DeviceInfoSetDetailData);
|
---|
95 | fnSetupDiGetDeviceInfoListDetail g_pfnSetupDiGetDeviceInfoListDetail = NULL;
|
---|
96 |
|
---|
97 | /***/
|
---|
98 |
|
---|
99 | typedef BOOL (WINAPI *fnSetupDiSetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, CONST BYTE *PropertyBuffer, DWORD PropertyBufferSize);
|
---|
100 | fnSetupDiSetDeviceRegistryProperty g_pfnSetupDiSetDeviceRegistryProperty = NULL;
|
---|
101 |
|
---|
102 | typedef BOOL (WINAPI *fnSetupDiGetDeviceRegistryProperty) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer,
|
---|
103 | DWORD PropertyBufferSize, PDWORD RequiredSize);
|
---|
104 | fnSetupDiGetDeviceRegistryProperty g_pfnSetupDiGetDeviceRegistryProperty = NULL;
|
---|
105 |
|
---|
106 | /***/
|
---|
107 |
|
---|
108 | typedef BOOL (WINAPI *fnSetupDiCallClassInstaller) (DI_FUNCTION InstallFunction, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData);
|
---|
109 | fnSetupDiCallClassInstaller g_pfnSetupDiCallClassInstaller = NULL;
|
---|
110 |
|
---|
111 | typedef BOOL (WINAPI *fnSetupDiClassGuidsFromNameEx) (PCTSTR ClassName, LPGUID ClassGuidList, DWORD ClassGuidListSize, PDWORD RequiredSize, PCTSTR MachineName, PVOID Reserved);
|
---|
112 | fnSetupDiClassGuidsFromNameEx g_pfnSetupDiClassGuidsFromNameEx = NULL;
|
---|
113 |
|
---|
114 | typedef HDEVINFO (WINAPI *fnSetupDiGetClassDevsEx) (LPGUID ClassGuid, PCTSTR Enumerator, HWND hwndParent, DWORD Flags, HDEVINFO DeviceInfoSet, PCTSTR MachineName, PVOID Reserved);
|
---|
115 | fnSetupDiGetClassDevsEx g_pfnSetupDiGetClassDevsEx = NULL;
|
---|
116 |
|
---|
117 | typedef BOOL (WINAPI *fnSetupDiSetClassInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_CLASSINSTALL_HEADER ClassInstallParams, DWORD ClassInstallParamsSize);
|
---|
118 | fnSetupDiSetClassInstallParams g_pfnSetupDiSetClassInstallParams = NULL;
|
---|
119 |
|
---|
120 | typedef BOOL (WINAPI *fnSetupDiGetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams);
|
---|
121 | fnSetupDiGetDeviceInstallParams g_pfnSetupDiGetDeviceInstallParams = NULL;
|
---|
122 |
|
---|
123 | typedef HKEY (WINAPI *fnSetupDiOpenDevRegKey) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Scope, DWORD HwProfile, DWORD KeyType, REGSAM samDesired);
|
---|
124 | fnSetupDiOpenDevRegKey g_pfnSetupDiOpenDevRegKey = NULL;
|
---|
125 |
|
---|
126 | typedef BOOL (WINAPI *fnSetupDiBuildDriverInfoList) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType);
|
---|
127 | fnSetupDiBuildDriverInfoList g_pfnSetupDiBuildDriverInfoList = NULL;
|
---|
128 |
|
---|
129 | typedef BOOL (WINAPI *fnSetupDiEnumDriverInfo) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD DriverType, DWORD MemberIndex, PSP_DRVINFO_DATA DriverInfoData);
|
---|
130 | fnSetupDiEnumDriverInfo g_pfnSetupDiEnumDriverInfo = NULL;
|
---|
131 |
|
---|
132 | typedef BOOL (WINAPI *fnSetupDiGetDriverInfoDetail) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData, PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData,
|
---|
133 | DWORD DriverInfoDetailDataSize, PDWORD RequiredSize);
|
---|
134 | fnSetupDiGetDriverInfoDetail g_pfnSetupDiGetDriverInfoDetail = NULL;
|
---|
135 |
|
---|
136 | typedef BOOL (WINAPI *fnSetupDiSetSelectedDriver) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DRVINFO_DATA DriverInfoData);
|
---|
137 | fnSetupDiSetSelectedDriver g_pfnSetupDiSetSelectedDriver = NULL;
|
---|
138 |
|
---|
139 | typedef BOOL (WINAPI *fnSetupDiSetDeviceInstallParams) (HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PSP_DEVINSTALL_PARAMS DeviceInstallParams);
|
---|
140 | fnSetupDiSetDeviceInstallParams g_pfnSetupDiSetDeviceInstallParams = NULL;
|
---|
141 |
|
---|
142 | typedef CONFIGRET (WINAPI *fnCM_Get_Device_ID_Ex) (DEVINST dnDevInst, PTCHAR Buffer, ULONG BufferLen, ULONG ulFlags, HMACHINE hMachine);
|
---|
143 | fnCM_Get_Device_ID_Ex g_pfnCM_Get_Device_ID_Ex = NULL;
|
---|
144 |
|
---|
145 | typedef BOOL (WINAPI* fnSetupCopyOEMInf) (PCTSTR SourceInfFileName, PCTSTR OEMSourceMediaLocation, DWORD OEMSourceMediaType, DWORD CopyStyle, PTSTR DestinationInfFileName,
|
---|
146 | DWORD DestinationInfFileNameSize, PDWORD RequiredSize, PTSTR DestinationInfFileNameComponent);
|
---|
147 | fnSetupCopyOEMInf g_pfnSetupCopyOEMInf = NULL;
|
---|
148 |
|
---|
149 | typedef BOOL (WINAPI* fnUpdateDriverForPlugAndPlayDevices) (HWND hwndParent, LPCTSTR HardwareId, LPCTSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired);
|
---|
150 | fnUpdateDriverForPlugAndPlayDevices 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 |
|
---|
158 | int 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 |
|
---|
245 | void 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 |
|
---|
261 | bool 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 |
|
---|
281 | int 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 |
|
---|
358 | int 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 | --*/
|
---|
505 | IdEntry 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 | --*/
|
---|
547 | LPTSTR * 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 | --*/
|
---|
591 | void 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 | --*/
|
---|
623 | LPTSTR * 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 | --*/
|
---|
697 | BOOL 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 | --*/
|
---|
809 | BOOL 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 | --*/
|
---|
849 | int 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 | --*/
|
---|
1048 | int 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 | --*/
|
---|
1113 | BOOL 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 | --*/
|
---|
1293 | UINT 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 | --*/
|
---|
1327 | int 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 |
|
---|
1448 | int 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 |
|
---|
1464 | int 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 |
|
---|
1481 | int 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 |
|
---|
1575 | int 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 |
|
---|
1662 | int 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 |
|
---|
1747 | int 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 |
|
---|
1871 | cleanup:
|
---|
1872 |
|
---|
1873 | if (hSCManager != NULL)
|
---|
1874 | CloseServiceHandle (hSCManager);
|
---|
1875 |
|
---|
1876 | return rc;
|
---|
1877 | }
|
---|
1878 |
|
---|
1879 | int 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 |
|
---|
1944 | DWORD 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 |
|
---|
1977 | void 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 |
|
---|
1992 | int __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 | }
|
---|