WinDevice.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337
  1. /*
  2. This software is subject to the license described in the License.txt file
  3. included with this software distribution. You may not use this file except
  4. in compliance with this license.
  5. Copyright (c) Dynastream Innovations Inc. 2016
  6. All rights reserved.
  7. */
  8. #include "types.h"
  9. #if defined(DSI_TYPES_WINDOWS)
  10. #include "WinDevice.h"
  11. #include "macros.h"
  12. #include <tchar.h>
  13. #include <ctype.h>
  14. #include <setupapi.h>
  15. #include <cfgmgr32.h>
  16. #include <stdlib.h>
  17. // Prototypes for functions found in the SetupAPI dll.
  18. typedef BOOL (WINAPI* SetupAPI_CallClassInstaller_t)(DI_FUNCTION,HDEVINFO,PSP_DEVINFO_DATA);
  19. typedef BOOL (WINAPI* SetupAPI_EnumDeviceInfo_t)(HDEVINFO,DWORD,PSP_DEVINFO_DATA);
  20. typedef BOOL (WINAPI* SetupAPI_DestroyDeviceInfoList_t)(HDEVINFO);
  21. typedef BOOL (WINAPI* SetupAPI_GetDeviceRegistryProperty_t)(HDEVINFO,PSP_DEVINFO_DATA,DWORD,PDWORD,PBYTE,DWORD,PDWORD);
  22. typedef BOOL (WINAPI* SetupAPI_SetClassInstallParams_t)(HDEVINFO,PSP_DEVINFO_DATA,PSP_CLASSINSTALL_HEADER,DWORD);
  23. #ifdef UNICODE
  24. typedef BOOL (WINAPI* SetupAPI_GetDeviceInstallParams_t)(HDEVINFO,PSP_DEVINFO_DATA,PSP_DEVINSTALL_PARAMS_W);
  25. typedef BOOL (WINAPI* SetupAPI_ClassGuidsFromNameEx_t)(PCWSTR,LPGUID,DWORD,PDWORD,PCWSTR,PVOID);
  26. typedef HDEVINFO (WINAPI* SetupAPI_GetClassDevsEx_t)(CONST GUID*,PCWSTR,HWND,DWORD,HDEVINFO,PCWSTR,PVOID);
  27. typedef HDEVINFO (WINAPI* SetupAPI_CreateDeviceInfoListEx_t)(CONST GUID*,HWND,PCWSTR,PVOID);
  28. typedef BOOL (WINAPI* SetupAPI_OpenDeviceInfo_t)(HDEVINFO,PCWSTR,HWND,DWORD,PSP_DEVINFO_DATA);
  29. typedef BOOL (WINAPI* SetupAPI_GetDeviceInfoListDetail_t)(HDEVINFO,PSP_DEVINFO_LIST_DETAIL_DATA_W);
  30. #else
  31. typedef BOOL (WINAPI* SetupAPI_GetDeviceInstallParams_t)(HDEVINFO,PSP_DEVINFO_DATA,PSP_DEVINSTALL_PARAMS_A);
  32. typedef BOOL (WINAPI* SetupAPI_ClassGuidsFromNameEx_t)(PCSTR,LPGUID,DWORD,PDWORD,PCSTR,PVOID);
  33. typedef HDEVINFO (WINAPI* SetupAPI_GetClassDevsEx_t)(CONST GUID*,PCSTR,HWND,DWORD,HDEVINFO,PCSTR,PVOID);
  34. typedef HDEVINFO (WINAPI* SetupAPI_CreateDeviceInfoListEx_t)(CONST GUID*,HWND,PCSTR,PVOID);
  35. typedef BOOL (WINAPI* SetupAPI_OpenDeviceInfo_t)(HDEVINFO,PCSTR,HWND,DWORD,PSP_DEVINFO_DATA);
  36. typedef BOOL (WINAPI* SetupAPI_GetDeviceInfoListDetail_t)(HDEVINFO,PSP_DEVINFO_LIST_DETAIL_DATA_A);
  37. #endif
  38. // Function pointers for functions found in the SetupAPI dll.
  39. SetupAPI_SetClassInstallParams_t SetupAPI_SetClassInstallParams;
  40. SetupAPI_CallClassInstaller_t SetupAPI_CallClassInstaller;
  41. SetupAPI_GetDeviceInstallParams_t SetupAPI_GetDeviceInstallParams;
  42. SetupAPI_GetDeviceRegistryProperty_t SetupAPI_GetDeviceRegistryProperty;
  43. SetupAPI_ClassGuidsFromNameEx_t SetupAPI_ClassGuidsFromNameEx;
  44. SetupAPI_GetClassDevsEx_t SetupAPI_GetClassDevsEx;
  45. SetupAPI_CreateDeviceInfoListEx_t SetupAPI_CreateDeviceInfoListEx;
  46. SetupAPI_OpenDeviceInfo_t SetupAPI_OpenDeviceInfo;
  47. SetupAPI_GetDeviceInfoListDetail_t SetupAPI_GetDeviceInfoListDetail;
  48. SetupAPI_EnumDeviceInfo_t SetupAPI_EnumDeviceInfo;
  49. SetupAPI_DestroyDeviceInfoList_t SetupAPI_DestroyDeviceInfoList;
  50. // Prototypes for functions found in the cfgmgr32 dll.
  51. #ifdef UNICODE
  52. typedef CONFIGRET (WINAPI* CfgMgr32_Get_Device_ID_Ex_t)(DEVINST dnDevInst, PWCHAR Buffer, ULONG BufferLen, ULONG ulFlags, HMACHINE hMachine);
  53. #else
  54. typedef CONFIGRET (WINAPI* CfgMgr32_Get_Device_ID_Ex_t)(DEVINST dnDevInst, PCHAR Buffer, ULONG BufferLen, ULONG ulFlags, HMACHINE hMachine);
  55. #endif
  56. // Function pointers for functions found in the cfgmgr32 dll.
  57. CfgMgr32_Get_Device_ID_Ex_t CfgMgr32_Get_Device_ID_Ex;
  58. typedef int (*CallbackFunc)(HDEVINFO Devs,PSP_DEVINFO_DATA DevInfo,LPVOID Context);
  59. int ControlCallback(HDEVINFO Devs,PSP_DEVINFO_DATA DevInfo,LPVOID Context);
  60. //DLL Definitions
  61. BOOL LoadSetupDLLFunctions();
  62. void FreeSetupDLLFunctions();
  63. HMODULE hSetupDll;
  64. HMODULE hCfgMgrDll;
  65. int EnumerateDevices(LPCTSTR Machine,DWORD Flags,int argc,LPTSTR argv[],CallbackFunc Callback,LPVOID Context);
  66. LPTSTR GetDeviceStringProperty(HDEVINFO Devs,PSP_DEVINFO_DATA DevInfo,DWORD Prop);
  67. LPTSTR GetDeviceDescription(HDEVINFO Devs,PSP_DEVINFO_DATA DevInfo);
  68. LPTSTR * GetDevMultiSz(HDEVINFO Devs,PSP_DEVINFO_DATA DevInfo,DWORD Prop);
  69. LPTSTR * GetRegMultiSz(HKEY hKey,LPCTSTR Val);
  70. LPTSTR * GetMultiSzIndexArray(LPTSTR MultiSz);
  71. void DelMultiSz(LPTSTR * Array);
  72. LPTSTR * CopyMultiSz(LPTSTR * Array);
  73. typedef struct
  74. {
  75. LPCTSTR String; // string looking for
  76. LPCTSTR Wild; // first wild character if any
  77. BOOL InstanceId;
  78. } IdEntry;
  79. typedef struct
  80. {
  81. DWORD count;
  82. DWORD control;
  83. BOOL reboot;
  84. } GenericContext;
  85. typedef struct
  86. {
  87. int argc_right;
  88. LPTSTR * argv_right;
  89. DWORD prop;
  90. int skipped;
  91. int modified;
  92. } SetHwidContext;
  93. int WinDevice_Enable(int argc,TCHAR* argv[])
  94. /*++
  95. Routine Description:
  96. ENABLE <id> ...
  97. use EnumerateDevices to do hardwareID matching
  98. for each match, attempt to enable global, and if needed, config specific
  99. Arguments:
  100. argc/argv - remaining parameters - passed into EnumerateDevices
  101. Return Value:
  102. EXIT_xxxx (EXIT_REBOOT if reboot is required)
  103. --*/
  104. {
  105. GenericContext context;
  106. int failcode = EXIT_FAIL;
  107. if(!LoadSetupDLLFunctions())
  108. return EXIT_FAIL;
  109. if(!argc)
  110. {
  111. //
  112. // arguments required
  113. //
  114. FreeSetupDLLFunctions();
  115. return EXIT_USAGE;
  116. }
  117. context.control = DICS_ENABLE; // DICS_PROPCHANGE DICS_ENABLE DICS_DISABLE
  118. context.reboot = FALSE;
  119. context.count = 0;
  120. failcode = EnumerateDevices(NULL,DIGCF_PRESENT,argc,argv,ControlCallback,&context);
  121. if(failcode == EXIT_OK)
  122. {
  123. if((context.count) && (context.reboot))
  124. failcode = EXIT_REBOOT;
  125. }
  126. FreeSetupDLLFunctions();
  127. return failcode;
  128. }
  129. int WinDevice_Disable(int argc,TCHAR* argv[])
  130. /*++
  131. Routine Description:
  132. DISABLE <id> ...
  133. use EnumerateDevices to do hardwareID matching
  134. for each match, attempt to disable global
  135. Arguments:
  136. argc/argv - remaining parameters - passed into EnumerateDevices
  137. Return Value:
  138. EXIT_xxxx (EXIT_REBOOT if reboot is required)
  139. --*/
  140. {
  141. GenericContext context;
  142. int failcode = EXIT_FAIL;
  143. if(!LoadSetupDLLFunctions())
  144. return EXIT_FAIL;
  145. if(!argc)
  146. {
  147. //
  148. // arguments required
  149. //
  150. FreeSetupDLLFunctions();
  151. return EXIT_USAGE;
  152. }
  153. context.control = DICS_DISABLE; // DICS_PROPCHANGE DICS_ENABLE DICS_DISABLE
  154. context.reboot = FALSE;
  155. context.count = 0;
  156. failcode = EnumerateDevices(NULL,DIGCF_PRESENT,argc,argv,ControlCallback,&context);
  157. if(failcode == EXIT_OK)
  158. {
  159. if((context.count) && (context.reboot))
  160. failcode = EXIT_REBOOT;
  161. }
  162. FreeSetupDLLFunctions();
  163. return failcode;
  164. }
  165. int WinDevice_Restart(int argc,TCHAR* argv[])
  166. /*++
  167. Routine Description:
  168. RESTART <id> ...
  169. use EnumerateDevices to do hardwareID matching
  170. for each match, attempt to restart by issueing a PROPCHANGE
  171. Arguments:
  172. argc/argv - remaining parameters - passed into EnumerateDevices
  173. Return Value:
  174. EXIT_xxxx (EXIT_REBOOT if reboot is required)
  175. --*/
  176. {
  177. GenericContext context;
  178. int failcode = EXIT_FAIL;
  179. if(!LoadSetupDLLFunctions())
  180. return EXIT_FAIL;
  181. if(!argc)
  182. {
  183. //
  184. // arguments required
  185. //
  186. FreeSetupDLLFunctions();
  187. return EXIT_USAGE;
  188. }
  189. context.control = DICS_PROPCHANGE;
  190. context.reboot = FALSE;
  191. context.count = 0;
  192. failcode = EnumerateDevices(NULL,DIGCF_PRESENT,argc,argv,ControlCallback,&context);
  193. if(failcode == EXIT_OK)
  194. {
  195. if((context.count) && (context.reboot))
  196. failcode = EXIT_REBOOT;
  197. }
  198. FreeSetupDLLFunctions();
  199. return failcode;
  200. }
  201. int ControlCallback(HDEVINFO Devs,PSP_DEVINFO_DATA DevInfo,LPVOID Context)
  202. /*++
  203. Routine Description:
  204. Callback for use by Enable/Disable/Restart
  205. Invokes DIF_PROPERTYCHANGE with correct parameters
  206. uses SetupDiCallClassInstaller so cannot be done for remote devices
  207. Don't use CM_xxx API's, they bypass class/co-installers and this is bad.
  208. In Enable case, we try global first, and if still disabled, enable local
  209. Arguments:
  210. Devs )_ uniquely identify the device
  211. DevInfo )
  212. Context - GenericContext
  213. Return Value:
  214. EXIT_xxxx
  215. --*/
  216. {
  217. SP_PROPCHANGE_PARAMS pcp;
  218. GenericContext *pControlContext = (GenericContext*)Context;
  219. SP_DEVINSTALL_PARAMS devParams;
  220. switch(pControlContext->control)
  221. {
  222. case DICS_ENABLE:
  223. //
  224. // enable both on global and config-specific profile
  225. // do global first and see if that succeeded in enabling the device
  226. // (global enable doesn't mark reboot required if device is still
  227. // disabled on current config whereas vice-versa isn't true)
  228. //
  229. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  230. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  231. pcp.StateChange = pControlContext->control;
  232. pcp.Scope = DICS_FLAG_GLOBAL;
  233. pcp.HwProfile = 0;
  234. //
  235. // don't worry if this fails, we'll get an error when we try config-
  236. // specific.
  237. if(SetupAPI_SetClassInstallParams(Devs,DevInfo,&pcp.ClassInstallHeader,sizeof(pcp)))
  238. {
  239. SetupAPI_CallClassInstaller(DIF_PROPERTYCHANGE,Devs,DevInfo);
  240. }
  241. //
  242. // now enable on config-specific
  243. //
  244. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  245. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  246. pcp.StateChange = pControlContext->control;
  247. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  248. pcp.HwProfile = 0;
  249. break;
  250. default:
  251. //
  252. // operate on config-specific profile
  253. //
  254. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  255. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  256. pcp.StateChange = pControlContext->control;
  257. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  258. pcp.HwProfile = 0;
  259. break;
  260. }
  261. if(!SetupAPI_SetClassInstallParams(Devs,DevInfo,&pcp.ClassInstallHeader,sizeof(pcp)) ||
  262. !SetupAPI_CallClassInstaller(DIF_PROPERTYCHANGE,Devs,DevInfo))
  263. {
  264. //
  265. // failed to invoke DIF_PROPERTYCHANGE
  266. //
  267. }
  268. else
  269. {
  270. //
  271. // see if device needs reboot
  272. //
  273. devParams.cbSize = sizeof(devParams);
  274. if(SetupAPI_GetDeviceInstallParams(Devs,DevInfo,&devParams) && (devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)))
  275. {
  276. pControlContext->reboot = TRUE;
  277. }
  278. else
  279. {
  280. //
  281. // appears to have succeeded
  282. //
  283. }
  284. pControlContext->count++;
  285. }
  286. return EXIT_OK;
  287. }
  288. ///////////////////////////////////////////////////////////////////////
  289. // Loads Setup API functions from the DLL.
  290. ///////////////////////////////////////////////////////////////////////
  291. BOOL LoadSetupDLLFunctions(void)
  292. {
  293. BOOL bStatus = TRUE;
  294. FreeSetupDLLFunctions(); // Guarantee the library functions are freed.
  295. char acSystemDirectory[MAX_PATH];
  296. char asSetupAPI[255];
  297. char asConfig[255];
  298. if(GetSystemDirectory(acSystemDirectory, MAX_PATH) == 0)
  299. return FALSE;
  300. if(acSystemDirectory == NULL)
  301. return FALSE;
  302. SNPRINTF(asSetupAPI, 255, "%s/setupapi.dll", acSystemDirectory);
  303. SNPRINTF(asConfig, 255, "%s/cfgmgr32.dll", acSystemDirectory);
  304. hSetupDll = LoadLibrary(asSetupAPI);
  305. hCfgMgrDll = LoadLibrary(asConfig);
  306. if(hSetupDll == NULL || hCfgMgrDll == NULL)
  307. {
  308. bStatus = FALSE;
  309. }
  310. else
  311. {
  312. //Functions from SetupAPI DLL.
  313. SetupAPI_CallClassInstaller = (SetupAPI_CallClassInstaller_t) GetProcAddress(hSetupDll, "SetupDiCallClassInstaller");
  314. if(SetupAPI_CallClassInstaller == NULL)
  315. bStatus = FALSE;
  316. SetupAPI_EnumDeviceInfo = (SetupAPI_EnumDeviceInfo_t) GetProcAddress(hSetupDll, "SetupDiEnumDeviceInfo");
  317. if(SetupAPI_EnumDeviceInfo == NULL)
  318. bStatus = FALSE;
  319. SetupAPI_DestroyDeviceInfoList = (SetupAPI_DestroyDeviceInfoList_t) GetProcAddress(hSetupDll, "SetupDiDestroyDeviceInfoList");
  320. if(SetupAPI_DestroyDeviceInfoList == NULL)
  321. bStatus = FALSE;
  322. #ifdef UNICODE
  323. SetupAPI_SetClassInstallParams = (SetupAPI_SetClassInstallParams_t) GetProcAddress(hSetupDll, "SetupDiSetClassInstallParamsW");
  324. if(SetupAPI_SetClassInstallParams == NULL)
  325. bStatus = FALSE;
  326. SetupAPI_GetDeviceInstallParams = (SetupAPI_GetDeviceInstallParams_t) GetProcAddress(hSetupDll, "SetupDiGetDeviceInstallParamsW");
  327. if(SetupAPI_GetDeviceInstallParams == NULL)
  328. bStatus = FALSE;
  329. SetupAPI_GetDeviceRegistryProperty = (SetupAPI_GetDeviceRegistryProperty_t) GetProcAddress(hSetupDll, "SetupDiGetDeviceRegistryPropertyW");
  330. if(SetupAPI_GetDeviceRegistryProperty == NULL)
  331. bStatus = FALSE;
  332. SetupAPI_ClassGuidsFromNameEx = (SetupAPI_ClassGuidsFromNameEx_t) GetProcAddress(hSetupDll, "SetupDiClassGuidsFromNameExW");
  333. if(SetupAPI_ClassGuidsFromNameEx == NULL)
  334. bStatus = FALSE;
  335. SetupAPI_GetClassDevsEx = (SetupAPI_GetClassDevsEx_t) GetProcAddress(hSetupDll, "SetupDiGetClassDevsExW");
  336. if(SetupAPI_GetClassDevsEx == NULL)
  337. bStatus = FALSE;
  338. SetupAPI_CreateDeviceInfoListEx = (SetupAPI_CreateDeviceInfoListEx_t) GetProcAddress(hSetupDll, "SetupDiCreateDeviceInfoListExW");
  339. if(SetupAPI_CreateDeviceInfoListEx == NULL)
  340. bStatus = FALSE;
  341. SetupAPI_OpenDeviceInfo = (SetupAPI_OpenDeviceInfo_t) GetProcAddress(hSetupDll, "SetupDiOpenDeviceInfoW");
  342. if(SetupAPI_OpenDeviceInfo == NULL)
  343. bStatus = FALSE;
  344. SetupAPI_GetDeviceInfoListDetail = (SetupAPI_GetDeviceInfoListDetail_t) GetProcAddress(hSetupDll, "SetupDiGetDeviceInfoListDetailW");
  345. if(SetupAPI_GetDeviceInfoListDetail == NULL)
  346. bStatus = FALSE;
  347. #else
  348. SetupAPI_SetClassInstallParams = (SetupAPI_SetClassInstallParams_t) GetProcAddress(hSetupDll, "SetupDiSetClassInstallParamsA");
  349. if(SetupAPI_SetClassInstallParams == NULL)
  350. bStatus = FALSE;
  351. SetupAPI_GetDeviceInstallParams = (SetupAPI_GetDeviceInstallParams_t) GetProcAddress(hSetupDll, "SetupDiGetDeviceInstallParamsA");
  352. if(SetupAPI_GetDeviceInstallParams == NULL)
  353. bStatus = FALSE;
  354. SetupAPI_GetDeviceRegistryProperty = (SetupAPI_GetDeviceRegistryProperty_t) GetProcAddress(hSetupDll, "SetupDiGetDeviceRegistryPropertyA");
  355. if(SetupAPI_GetDeviceRegistryProperty == NULL)
  356. bStatus = FALSE;
  357. SetupAPI_ClassGuidsFromNameEx = (SetupAPI_ClassGuidsFromNameEx_t) GetProcAddress(hSetupDll, "SetupDiClassGuidsFromNameExA");
  358. if(SetupAPI_ClassGuidsFromNameEx == NULL)
  359. bStatus = FALSE;
  360. SetupAPI_GetClassDevsEx = (SetupAPI_GetClassDevsEx_t) GetProcAddress(hSetupDll, "SetupDiGetClassDevsExA");
  361. if(SetupAPI_GetClassDevsEx == NULL)
  362. bStatus = FALSE;
  363. SetupAPI_CreateDeviceInfoListEx = (SetupAPI_CreateDeviceInfoListEx_t) GetProcAddress(hSetupDll, "SetupDiCreateDeviceInfoListExA");
  364. if(SetupAPI_CreateDeviceInfoListEx == NULL)
  365. bStatus = FALSE;
  366. SetupAPI_OpenDeviceInfo = (SetupAPI_OpenDeviceInfo_t) GetProcAddress(hSetupDll, "SetupDiOpenDeviceInfoA");
  367. if(SetupAPI_OpenDeviceInfo == NULL)
  368. bStatus = FALSE;
  369. SetupAPI_GetDeviceInfoListDetail = (SetupAPI_GetDeviceInfoListDetail_t) GetProcAddress(hSetupDll, "SetupDiGetDeviceInfoListDetailA");
  370. if(SetupAPI_GetDeviceInfoListDetail == NULL)
  371. bStatus = FALSE;
  372. #endif
  373. //Functions from CfgMgr32 DLL.
  374. #ifdef UNICODE
  375. SetupAPI_Get_Device_ID_Ex = (SetupAPI_Get_Device_ID_Ex_t) GetProcAddress(hSetupDll, "CM_Get_Device_ID_ExW");
  376. if(SetupAPI_Get_Device_ID_Ex == NULL)
  377. bStatus = FALSE;
  378. #else
  379. CfgMgr32_Get_Device_ID_Ex = (CfgMgr32_Get_Device_ID_Ex_t) GetProcAddress(hCfgMgrDll, "CM_Get_Device_ID_ExA");
  380. if(CfgMgr32_Get_Device_ID_Ex == NULL)
  381. bStatus = FALSE;
  382. #endif
  383. }
  384. if (!bStatus)
  385. FreeSetupDLLFunctions();
  386. return bStatus;
  387. }
  388. ///////////////////////////////////////////////////////////////////////
  389. // Unloads Setup API DLL.
  390. ///////////////////////////////////////////////////////////////////////
  391. void FreeSetupDLLFunctions(void)
  392. {
  393. if (hSetupDll != NULL)
  394. {
  395. FreeLibrary(hSetupDll);
  396. hSetupDll = NULL;
  397. }
  398. if(hCfgMgrDll != NULL)
  399. {
  400. FreeLibrary(hCfgMgrDll);
  401. hCfgMgrDll = NULL;
  402. }
  403. }
  404. LPTSTR GetDeviceStringProperty(HDEVINFO Devs,PSP_DEVINFO_DATA DevInfo,DWORD Prop)
  405. /*++
  406. Routine Description:
  407. Return a string property for a device, otherwise NULL
  408. Arguments:
  409. Devs )_ uniquely identify device
  410. DevInfo )
  411. Prop - string property to obtain
  412. Return Value:
  413. string containing description
  414. --*/
  415. {
  416. LPTSTR buffer;
  417. DWORD size;
  418. DWORD reqSize;
  419. DWORD dataType;
  420. DWORD szChars;
  421. size = 1024; // initial guess
  422. buffer = new TCHAR[(size/sizeof(TCHAR))+1];
  423. if(!buffer)
  424. {
  425. return NULL;
  426. }
  427. while(!SetupAPI_GetDeviceRegistryProperty(Devs,DevInfo,Prop,&dataType,(LPBYTE)buffer,size,&reqSize))
  428. {
  429. if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  430. {
  431. goto failed;
  432. }
  433. if(dataType != REG_SZ)
  434. {
  435. goto failed;
  436. }
  437. size = reqSize;
  438. delete [] buffer;
  439. buffer = new TCHAR[(size/sizeof(TCHAR))+1];
  440. if(!buffer)
  441. {
  442. goto failed;
  443. }
  444. }
  445. szChars = reqSize/sizeof(TCHAR);
  446. buffer[szChars] = TEXT('\0');
  447. return buffer;
  448. failed:
  449. if(buffer)
  450. {
  451. delete [] buffer;
  452. }
  453. return NULL;
  454. }
  455. LPTSTR GetDeviceDescription(HDEVINFO Devs,PSP_DEVINFO_DATA DevInfo)
  456. /*++
  457. Routine Description:
  458. Return a string containing a description of the device, otherwise NULL
  459. Always try friendly name first
  460. Arguments:
  461. Devs )_ uniquely identify device
  462. DevInfo )
  463. Return Value:
  464. string containing description
  465. --*/
  466. {
  467. LPTSTR desc;
  468. desc = GetDeviceStringProperty(Devs,DevInfo,SPDRP_FRIENDLYNAME);
  469. if(!desc)
  470. {
  471. desc = GetDeviceStringProperty(Devs,DevInfo,SPDRP_DEVICEDESC);
  472. }
  473. return desc;
  474. }
  475. IdEntry GetIdType(LPCTSTR Id)
  476. /*++
  477. Routine Description:
  478. Determine if this is instance id or hardware id and if there's any wildcards
  479. instance ID is prefixed by '@'
  480. wildcards are '*'
  481. Arguments:
  482. Id - ptr to string to check
  483. Return Value:
  484. IdEntry
  485. --*/
  486. {
  487. IdEntry Entry;
  488. Entry.InstanceId = FALSE;
  489. Entry.Wild = NULL;
  490. Entry.String = Id;
  491. if(Entry.String[0] == INSTANCEID_PREFIX_CHAR)
  492. {
  493. Entry.InstanceId = TRUE;
  494. Entry.String = CharNext(Entry.String);
  495. }
  496. if(Entry.String[0] == QUOTE_PREFIX_CHAR)
  497. {
  498. //
  499. // prefix to treat rest of string literally
  500. //
  501. Entry.String = CharNext(Entry.String);
  502. }
  503. else
  504. {
  505. //
  506. // see if any wild characters exist
  507. //
  508. Entry.Wild = _tcschr(Entry.String,WILD_CHAR);
  509. }
  510. return Entry;
  511. }
  512. LPTSTR * GetMultiSzIndexArray(LPTSTR MultiSz)
  513. /*++
  514. Routine Description:
  515. Get an index array pointing to the MultiSz passed in
  516. Arguments:
  517. MultiSz - well formed multi-sz string
  518. Return Value:
  519. array of strings. last entry+1 of array contains NULL
  520. returns NULL on failure
  521. --*/
  522. {
  523. LPTSTR scan;
  524. LPTSTR * array;
  525. int elements;
  526. for(scan = MultiSz, elements = 0; scan[0] ;elements++)
  527. {
  528. scan += lstrlen(scan)+1;
  529. }
  530. array = new LPTSTR[elements+2];
  531. if(!array) {
  532. return NULL;
  533. }
  534. array[0] = MultiSz;
  535. array++;
  536. if(elements)
  537. {
  538. for(scan = MultiSz, elements = 0; scan[0]; elements++)
  539. {
  540. array[elements] = scan;
  541. scan += lstrlen(scan)+1;
  542. }
  543. }
  544. array[elements] = NULL;
  545. return array;
  546. }
  547. LPTSTR * CopyMultiSz(LPTSTR * Array)
  548. /*++
  549. Routine Description:
  550. Creates a new array from old
  551. old array need not have been allocated by GetMultiSzIndexArray
  552. Arguments:
  553. Array - array of strings, last entry is NULL
  554. Return Value:
  555. MultiSz array allocated by GetMultiSzIndexArray
  556. --*/
  557. {
  558. LPTSTR multiSz = NULL;
  559. int len = 0;
  560. int c;
  561. if(Array)
  562. {
  563. for(c=0;Array[c];c++)
  564. {
  565. len+=lstrlen(Array[c])+1;
  566. }
  567. }
  568. len+=1; // final Null
  569. multiSz = new TCHAR[len];
  570. if(!multiSz)
  571. {
  572. return NULL;
  573. }
  574. len = 0;
  575. if(Array)
  576. {
  577. for(c=0;Array[c];c++)
  578. {
  579. lstrcpy(multiSz+len,Array[c]);
  580. len+=lstrlen(multiSz+len)+1;
  581. }
  582. }
  583. multiSz[len] = TEXT('\0');
  584. LPTSTR * pRes = GetMultiSzIndexArray(multiSz);
  585. if(pRes)
  586. {
  587. return pRes;
  588. }
  589. delete [] multiSz;
  590. return NULL;
  591. }
  592. void DelMultiSz(LPTSTR * Array)
  593. /*++
  594. Routine Description:
  595. Deletes the string array allocated by GetDevMultiSz/GetRegMultiSz/GetMultiSzIndexArray
  596. Arguments:
  597. Array - pointer returned by GetMultiSzIndexArray
  598. Return Value:
  599. None
  600. --*/
  601. {
  602. if(Array)
  603. {
  604. Array--;
  605. if(Array[0])
  606. {
  607. delete [] Array[0];
  608. }
  609. delete [] Array;
  610. }
  611. }
  612. LPTSTR * GetDevMultiSz(HDEVINFO Devs,PSP_DEVINFO_DATA DevInfo,DWORD Prop)
  613. /*++
  614. Routine Description:
  615. Get a multi-sz device property
  616. and return as an array of strings
  617. Arguments:
  618. Devs - HDEVINFO containing DevInfo
  619. DevInfo - Specific device
  620. Prop - SPDRP_HARDWAREID or SPDRP_COMPATIBLEIDS
  621. Return Value:
  622. array of strings. last entry+1 of array contains NULL
  623. returns NULL on failure
  624. --*/
  625. {
  626. LPTSTR buffer;
  627. DWORD size;
  628. DWORD reqSize;
  629. DWORD dataType;
  630. LPTSTR * array;
  631. DWORD szChars;
  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(!SetupAPI_GetDeviceRegistryProperty(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. failed:
  665. if(buffer)
  666. {
  667. delete [] buffer;
  668. }
  669. return NULL;
  670. }
  671. LPTSTR * GetRegMultiSz(HKEY hKey,LPCTSTR Val)
  672. /*++
  673. Routine Description:
  674. Get a multi-sz from registry
  675. and return as an array of strings
  676. Arguments:
  677. hKey - Registry Key
  678. Val - Value to query
  679. Return Value:
  680. array of strings. last entry+1 of array contains NULL
  681. returns NULL on failure
  682. --*/
  683. {
  684. LPTSTR buffer;
  685. DWORD size;
  686. DWORD reqSize;
  687. DWORD dataType;
  688. LPTSTR * array;
  689. DWORD szChars;
  690. size = 8192; // initial guess, nothing magic about this
  691. buffer = new TCHAR[(size/sizeof(TCHAR))+2];
  692. if(!buffer)
  693. {
  694. return NULL;
  695. }
  696. reqSize = size;
  697. while(RegQueryValueEx(hKey,Val,NULL,&dataType,(PBYTE)buffer,&reqSize) != NO_ERROR)
  698. {
  699. if(GetLastError() != ERROR_MORE_DATA)
  700. {
  701. goto failed;
  702. }
  703. if(dataType != REG_MULTI_SZ)
  704. {
  705. goto failed;
  706. }
  707. size = reqSize;
  708. delete [] buffer;
  709. buffer = new TCHAR[(size/sizeof(TCHAR))+2];
  710. if(!buffer)
  711. {
  712. goto failed;
  713. }
  714. }
  715. szChars = reqSize/sizeof(TCHAR);
  716. buffer[szChars] = TEXT('\0');
  717. buffer[szChars+1] = TEXT('\0');
  718. array = GetMultiSzIndexArray(buffer);
  719. if(array)
  720. {
  721. return array;
  722. }
  723. failed:
  724. if(buffer)
  725. {
  726. delete [] buffer;
  727. }
  728. return NULL;
  729. }
  730. BOOL WildCardMatch(LPCTSTR Item,const IdEntry & MatchEntry)
  731. /*++
  732. Routine Description:
  733. Compare a single item against wildcard
  734. I'm sure there's better ways of implementing this
  735. Other than a command-line management tools
  736. it's a bad idea to use wildcards as it implies
  737. assumptions about the hardware/instance ID
  738. eg, it might be tempting to enumerate root\* to
  739. find all root devices, however there is a CfgMgr
  740. API to query status and determine if a device is
  741. root enumerated, which doesn't rely on implementation
  742. details.
  743. Arguments:
  744. Item - item to find match for eg a\abcd\c
  745. MatchEntry - eg *\*bc*\*
  746. Return Value:
  747. TRUE if any match, otherwise FALSE
  748. --*/
  749. {
  750. LPCTSTR scanItem;
  751. LPCTSTR wildMark;
  752. LPCTSTR nextWild;
  753. size_t matchlen;
  754. //
  755. // before attempting anything else
  756. // try and compare everything up to first wild
  757. //
  758. if(!MatchEntry.Wild)
  759. {
  760. return _tcsicmp(Item,MatchEntry.String) ? FALSE : TRUE;
  761. }
  762. if(_tcsnicmp(Item,MatchEntry.String,MatchEntry.Wild-MatchEntry.String) != 0)
  763. {
  764. return FALSE;
  765. }
  766. wildMark = MatchEntry.Wild;
  767. scanItem = Item + (MatchEntry.Wild-MatchEntry.String);
  768. for(;wildMark[0];)
  769. {
  770. //
  771. // if we get here, we're either at or past a wildcard
  772. //
  773. if(wildMark[0] == WILD_CHAR)
  774. {
  775. //
  776. // so skip wild chars
  777. //
  778. wildMark = CharNext(wildMark);
  779. continue;
  780. }
  781. //
  782. // find next wild-card
  783. //
  784. nextWild = _tcschr(wildMark,WILD_CHAR);
  785. if(nextWild)
  786. {
  787. //
  788. // substring
  789. //
  790. matchlen = nextWild-wildMark;
  791. }
  792. else
  793. {
  794. //
  795. // last portion of match
  796. //
  797. size_t scanlen = lstrlen(scanItem);
  798. matchlen = lstrlen(wildMark);
  799. if(scanlen < matchlen)
  800. {
  801. return FALSE;
  802. }
  803. return _tcsicmp(scanItem+scanlen-matchlen,wildMark) ? FALSE : TRUE;
  804. }
  805. if(_istalpha(wildMark[0]))
  806. {
  807. //
  808. // scan for either lower or uppercase version of first character
  809. //
  810. TCHAR u = (TCHAR)_totupper(wildMark[0]);
  811. TCHAR l = (TCHAR)_totlower(wildMark[0]);
  812. while(scanItem[0] && scanItem[0]!=u && scanItem[0]!=l)
  813. {
  814. scanItem = CharNext(scanItem);
  815. }
  816. if(!scanItem[0])
  817. {
  818. //
  819. // ran out of string
  820. //
  821. return FALSE;
  822. }
  823. }
  824. else
  825. {
  826. //
  827. // scan for first character (no case)
  828. //
  829. scanItem = _tcschr(scanItem,wildMark[0]);
  830. if(!scanItem)
  831. {
  832. //
  833. // ran out of string
  834. //
  835. return FALSE;
  836. }
  837. }
  838. //
  839. // try and match the sub-string at wildMark against scanItem
  840. //
  841. if(_tcsnicmp(scanItem,wildMark,matchlen)!=0)
  842. {
  843. //
  844. // nope, try again
  845. //
  846. scanItem = CharNext(scanItem);
  847. continue;
  848. }
  849. //
  850. // substring matched
  851. //
  852. scanItem += matchlen;
  853. wildMark += matchlen;
  854. }
  855. return (wildMark[0] ? FALSE : TRUE);
  856. }
  857. BOOL WildCompareHwIds(LPTSTR * Array,const IdEntry & MatchEntry)
  858. /*++
  859. Routine Description:
  860. Compares all strings in Array against Id
  861. Use WildCardMatch to do real compare
  862. Arguments:
  863. Array - pointer returned by GetDevMultiSz
  864. MatchEntry - string to compare against
  865. Return Value:
  866. TRUE if any match, otherwise FALSE
  867. --*/
  868. {
  869. if(Array)
  870. {
  871. while(Array[0])
  872. {
  873. if(WildCardMatch(Array[0],MatchEntry))
  874. {
  875. return TRUE;
  876. }
  877. Array++;
  878. }
  879. }
  880. return FALSE;
  881. }
  882. int EnumerateDevices(LPCTSTR Machine,DWORD Flags,int argc,LPTSTR argv[],CallbackFunc Callback,LPVOID Context)
  883. /*++
  884. Routine Description:
  885. Generic enumerator for devices that will be passed the following arguments:
  886. <id> [<id>...]
  887. =<class> [<id>...]
  888. where <id> can either be @instance-id, or hardware-id and may contain wildcards
  889. <class> is a class name
  890. Arguments:
  891. Machine - name of machine to enumerate
  892. Flags - extra enumeration flags (eg DIGCF_PRESENT)
  893. argc/argv - remaining arguments on command line
  894. Callback - function to call for each hit
  895. Context - data to pass function for each hit
  896. Return Value:
  897. EXIT_xxxx
  898. --*/
  899. {
  900. HDEVINFO devs = INVALID_HANDLE_VALUE;
  901. IdEntry * templ = NULL;
  902. int failcode = EXIT_FAIL;
  903. int retcode;
  904. int argIndex;
  905. DWORD devIndex;
  906. SP_DEVINFO_DATA devInfo;
  907. SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
  908. BOOL doSearch = FALSE;
  909. BOOL match;
  910. BOOL all = FALSE;
  911. GUID cls;
  912. DWORD numClass = 0;
  913. int skip = 0;
  914. if(!argc)
  915. {
  916. return EXIT_USAGE;
  917. }
  918. templ = new IdEntry[argc];
  919. if(!templ)
  920. {
  921. goto final;
  922. }
  923. //
  924. // determine if a class is specified
  925. //
  926. if(argc>skip && argv[skip][0]==CLASS_PREFIX_CHAR && argv[skip][1])
  927. {
  928. if(!SetupAPI_ClassGuidsFromNameEx(argv[skip]+1,&cls,1,&numClass,Machine,NULL) &&
  929. GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  930. {
  931. goto final;
  932. }
  933. if(!numClass)
  934. {
  935. failcode = EXIT_OK;
  936. goto final;
  937. }
  938. skip++;
  939. }
  940. if(argc>skip && argv[skip][0]==WILD_CHAR && !argv[skip][1])
  941. {
  942. //
  943. // catch convinient case of specifying a single argument '*'
  944. //
  945. all = TRUE;
  946. skip++;
  947. }
  948. else if(argc<=skip)
  949. {
  950. //
  951. // at least one parameter, but no <id>'s
  952. //
  953. all = TRUE;
  954. }
  955. //
  956. // determine if any instance id's were specified
  957. //
  958. // note, if =<class> was specified with no id's
  959. // we'll mark it as not doSearch
  960. // but will go ahead and add them all
  961. //
  962. for(argIndex=skip;argIndex<argc;argIndex++)
  963. {
  964. templ[argIndex] = GetIdType(argv[argIndex]);
  965. if(templ[argIndex].Wild || !templ[argIndex].InstanceId)
  966. {
  967. //
  968. // anything other than simple InstanceId's require a search
  969. //
  970. doSearch = TRUE;
  971. }
  972. }
  973. if(doSearch || all)
  974. {
  975. //
  976. // add all id's to list
  977. // if there's a class, filter on specified class
  978. //
  979. devs = SetupAPI_GetClassDevsEx(numClass ? &cls : NULL,
  980. NULL,
  981. NULL,
  982. (numClass ? 0 : DIGCF_ALLCLASSES) | Flags,
  983. NULL,
  984. Machine,
  985. NULL);
  986. }
  987. else
  988. {
  989. //
  990. // blank list, we'll add instance id's by hand
  991. //
  992. devs = SetupAPI_CreateDeviceInfoListEx(numClass ? &cls : NULL,
  993. NULL,
  994. Machine,
  995. NULL);
  996. }
  997. if(devs == INVALID_HANDLE_VALUE)
  998. {
  999. goto final;
  1000. }
  1001. for(argIndex=skip;argIndex<argc;argIndex++)
  1002. {
  1003. //
  1004. // add explicit instances to list (even if enumerated all,
  1005. // this gets around DIGCF_PRESENT)
  1006. // do this even if wildcards appear to be detected since they
  1007. // might actually be part of the instance ID of a non-present device
  1008. //
  1009. if(templ[argIndex].InstanceId)
  1010. {
  1011. SetupAPI_OpenDeviceInfo(devs,templ[argIndex].String,NULL,0,NULL);
  1012. }
  1013. }
  1014. devInfoListDetail.cbSize = sizeof(devInfoListDetail);
  1015. if(!SetupAPI_GetDeviceInfoListDetail(devs,&devInfoListDetail))
  1016. {
  1017. goto final;
  1018. }
  1019. //
  1020. // now enumerate them
  1021. //
  1022. if(all)
  1023. {
  1024. doSearch = FALSE;
  1025. }
  1026. devInfo.cbSize = sizeof(devInfo);
  1027. for(devIndex=0;SetupAPI_EnumDeviceInfo(devs,devIndex,&devInfo);devIndex++)
  1028. {
  1029. if(doSearch)
  1030. {
  1031. for(argIndex=skip,match=FALSE;(argIndex<argc) && !match;argIndex++)
  1032. {
  1033. TCHAR devID[MAX_DEVICE_ID_LEN];
  1034. LPTSTR *hwIds = NULL;
  1035. LPTSTR *compatIds = NULL;
  1036. //
  1037. // determine instance ID
  1038. //
  1039. if(CfgMgr32_Get_Device_ID_Ex(devInfo.DevInst,devID,MAX_DEVICE_ID_LEN,0,devInfoListDetail.RemoteMachineHandle)!=CR_SUCCESS)
  1040. {
  1041. devID[0] = TEXT('\0');
  1042. }
  1043. if(templ[argIndex].InstanceId)
  1044. {
  1045. //
  1046. // match on the instance ID
  1047. //
  1048. if(WildCardMatch(devID,templ[argIndex]))
  1049. {
  1050. match = TRUE;
  1051. }
  1052. }
  1053. else
  1054. {
  1055. //
  1056. // determine hardware ID's
  1057. // and search for matches
  1058. //
  1059. hwIds = GetDevMultiSz(devs,&devInfo,SPDRP_HARDWAREID);
  1060. compatIds = GetDevMultiSz(devs,&devInfo,SPDRP_COMPATIBLEIDS);
  1061. if(WildCompareHwIds(hwIds,templ[argIndex]) ||
  1062. WildCompareHwIds(compatIds,templ[argIndex]))
  1063. {
  1064. match = TRUE;
  1065. }
  1066. }
  1067. DelMultiSz(hwIds);
  1068. DelMultiSz(compatIds);
  1069. }
  1070. }
  1071. else
  1072. {
  1073. match = TRUE;
  1074. }
  1075. if(match)
  1076. {
  1077. retcode = Callback(devs,&devInfo,Context);
  1078. if(retcode)
  1079. {
  1080. failcode = retcode;
  1081. goto final;
  1082. }
  1083. }
  1084. }
  1085. failcode = EXIT_OK;
  1086. final:
  1087. if(templ)
  1088. {
  1089. delete [] templ;
  1090. }
  1091. if(devs != INVALID_HANDLE_VALUE)
  1092. {
  1093. SetupAPI_DestroyDeviceInfoList(devs);
  1094. }
  1095. return failcode;
  1096. }
  1097. #endif //defined(DSI_TYPES_WINDOWS)