Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

437 lines
7.8 KiB

  1. // SetupClasses.cpp : Implementation of CSetupClasses
  2. #include "stdafx.h"
  3. #include "DevCon2.h"
  4. #include "SetupClass.h"
  5. #include "SetupClassEnum.h"
  6. #include "SetupClasses.h"
  7. #include "DeviceConsole.h"
  8. #include "Devices.h"
  9. #include "xStrings.h"
  10. #include "utils.h"
  11. /////////////////////////////////////////////////////////////////////////////
  12. // CSetupClasses
  13. CSetupClasses::~CSetupClasses()
  14. {
  15. DWORD c;
  16. if(pSetupClasses) {
  17. for(c=0;c<Count;c++) {
  18. pSetupClasses[c]->Release();
  19. }
  20. delete [] pSetupClasses;
  21. }
  22. if(pMachine) {
  23. SysFreeString(pMachine);
  24. }
  25. }
  26. STDMETHODIMP CSetupClasses::get_Count(long *pVal)
  27. {
  28. *pVal = (long)Count;
  29. return S_OK;
  30. }
  31. STDMETHODIMP CSetupClasses::Item(long Index, LPDISPATCH *ppVal)
  32. {
  33. *ppVal = NULL;
  34. DWORD i = (DWORD)Index;
  35. if(i<1 || i > Count) {
  36. return E_INVALIDARG;
  37. }
  38. i--;
  39. pSetupClasses[i]->AddRef();
  40. *ppVal = pSetupClasses[i];
  41. return S_OK;
  42. }
  43. STDMETHODIMP CSetupClasses::get__NewEnum(IUnknown **ppUnk)
  44. {
  45. *ppUnk = NULL;
  46. HRESULT hr;
  47. CComObject<CSetupClassEnum> *pEnum = NULL;
  48. hr = CComObject<CSetupClassEnum>::CreateInstance(&pEnum);
  49. if(FAILED(hr)) {
  50. return hr;
  51. }
  52. if(!pEnum) {
  53. return E_OUTOFMEMORY;
  54. }
  55. pEnum->AddRef();
  56. if(!pEnum->CopySetupClasses(pSetupClasses,Count)) {
  57. pEnum->Release();
  58. return E_OUTOFMEMORY;
  59. }
  60. *ppUnk = pEnum;
  61. return S_OK;
  62. }
  63. BOOL CSetupClasses::IncreaseArraySize(DWORD add)
  64. {
  65. CSetupClass** pNewSetupClasses;
  66. DWORD Inc;
  67. DWORD c;
  68. if((ArraySize-Count)>=add) {
  69. return TRUE;
  70. }
  71. Inc = ArraySize + add + 32;
  72. pNewSetupClasses = new CSetupClass*[Inc];
  73. if(!pNewSetupClasses) {
  74. return FALSE;
  75. }
  76. for(c=0;c<Count;c++) {
  77. pNewSetupClasses[c] = pSetupClasses[c];
  78. }
  79. delete [] pSetupClasses;
  80. pSetupClasses = pNewSetupClasses;
  81. ArraySize = Inc;
  82. return TRUE;
  83. }
  84. HRESULT CSetupClasses::Init(LPCWSTR Machine, IDeviceConsole *pDevCon)
  85. {
  86. if(pMachine) {
  87. SysFreeString(pMachine);
  88. }
  89. if(Machine) {
  90. pMachine = SysAllocString(Machine);
  91. if(!pMachine) {
  92. return E_OUTOFMEMORY;
  93. }
  94. } else {
  95. pMachine = NULL;
  96. }
  97. DeviceConsole = pDevCon;
  98. return S_OK;
  99. }
  100. HRESULT CSetupClasses::AppendClass(LPCWSTR Filter)
  101. {
  102. DWORD nClasses;
  103. DWORD nClasses2;
  104. DWORD c;
  105. DWORD Err;
  106. HRESULT hr;
  107. if(Filter[0]==L'{') {
  108. //
  109. // possibly GUID
  110. //
  111. GUID guid;
  112. hr = CLSIDFromString((LPWSTR)Filter,&guid);
  113. if(SUCCEEDED(hr)) {
  114. //
  115. // class is in GUID format
  116. //
  117. if(FindDuplicate(&guid)) {
  118. return S_OK;
  119. }
  120. return AddGuid(&guid);
  121. }
  122. }
  123. //
  124. // class is probably in text format
  125. // obtain list of class id's that match class name
  126. // append all class devices for each class guid
  127. //
  128. if(SetupDiClassGuidsFromNameEx(Filter,NULL,0,&nClasses,pMachine,NULL) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  129. if(!nClasses) {
  130. //
  131. // no classes
  132. //
  133. return S_FALSE;
  134. }
  135. GUID *pList = new GUID[nClasses];
  136. if(!pList) {
  137. return E_OUTOFMEMORY;
  138. }
  139. if(SetupDiClassGuidsFromNameEx(Filter,pList,nClasses,&nClasses2,pMachine,NULL) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  140. //
  141. // count may have changed since last call
  142. //
  143. if(nClasses>nClasses2) {
  144. nClasses = nClasses2;
  145. }
  146. if(!nClasses) {
  147. //
  148. // no classes
  149. //
  150. delete [] pList;
  151. return S_FALSE;
  152. }
  153. for(c=0;c<nClasses;c++) {
  154. if(FindDuplicate(&pList[c])) {
  155. continue;
  156. }
  157. hr = AddGuid(&pList[c]);
  158. if(FAILED(hr)) {
  159. delete [] pList;
  160. return hr;
  161. }
  162. }
  163. delete [] pList;
  164. return hr;
  165. }
  166. }
  167. Err = GetLastError();
  168. return HRESULT_FROM_SETUPAPI(Err);
  169. }
  170. HRESULT CSetupClasses::AddGuid(GUID *pGuid)
  171. {
  172. if(!IncreaseArraySize(1)) {
  173. return E_OUTOFMEMORY;
  174. }
  175. CComObject<CSetupClass> *d;
  176. HRESULT hr;
  177. hr = CComObject<CSetupClass>::CreateInstance(&d);
  178. if(FAILED(hr)) {
  179. return hr;
  180. }
  181. d->AddRef();
  182. hr = d->Init(pGuid,pMachine,DeviceConsole);
  183. if(FAILED(hr)) {
  184. d->Release();
  185. return hr;
  186. }
  187. pSetupClasses[Count++] = d;
  188. return S_OK;
  189. }
  190. STDMETHODIMP CSetupClasses::Add(VARIANT ClassNames)
  191. {
  192. //
  193. // can pass in a collection
  194. //
  195. CComObject<CStrings> *pStrings = NULL;
  196. HRESULT hr;
  197. DWORD c;
  198. BSTR str;
  199. hr = CComObject<CStrings>::CreateInstance(&pStrings);
  200. if(FAILED(hr)) {
  201. return hr;
  202. }
  203. pStrings->AddRef();
  204. hr = pStrings->InternalInsert(0,&ClassNames);
  205. if(FAILED(hr)) {
  206. pStrings->Release();
  207. return hr;
  208. }
  209. for(c=0;pStrings->InternalEnum(c,&str);c++) {
  210. hr = AppendClass(str);
  211. if(FAILED(hr)) {
  212. pStrings->Release();
  213. return hr;
  214. }
  215. }
  216. pStrings->Release();
  217. return c ? S_OK : S_FALSE;
  218. }
  219. BOOL CSetupClasses::FindDuplicate(GUID *pGuid)
  220. {
  221. DWORD c;
  222. for(c=0;c<Count;c++) {
  223. if(pSetupClasses[c]->IsDuplicate(pGuid)) {
  224. return TRUE;
  225. }
  226. }
  227. return FALSE;
  228. }
  229. STDMETHODIMP CSetupClasses::Remove(VARIANT v)
  230. {
  231. // TODO: Add your implementation code here
  232. return S_OK;
  233. }
  234. HRESULT CSetupClasses::GetIndex(LPVARIANT Index, DWORD *pAt)
  235. {
  236. CComVariant v;
  237. HRESULT hr;
  238. if(IsNumericVariant(Index)) {
  239. hr = v.ChangeType(VT_I4,Index);
  240. if(FAILED(hr)) {
  241. return DISP_E_TYPEMISMATCH;
  242. }
  243. if(V_I4(&v)<1) {
  244. return E_INVALIDARG;
  245. }
  246. *pAt = ((DWORD)V_I4(&v))-1;
  247. return S_OK;
  248. }
  249. //
  250. // user actually supplied guid?
  251. //
  252. hr = v.ChangeType(VT_BSTR,Index);
  253. if(FAILED(hr)) {
  254. return DISP_E_TYPEMISMATCH;
  255. }
  256. if(!Count) {
  257. //
  258. // cannot match anything
  259. //
  260. return E_INVALIDARG;
  261. }
  262. BSTR pMatch = V_BSTR(&v);
  263. if(pMatch[0]!=L'{') {
  264. return E_INVALIDARG;
  265. }
  266. //
  267. // obtain GUID
  268. //
  269. GUID guid;
  270. hr = CLSIDFromString((LPWSTR)pMatch,&guid);
  271. if(FAILED(hr)) {
  272. return hr;
  273. }
  274. DWORD c;
  275. for(c=0;c<Count;c++) {
  276. if(pSetupClasses[c]->IsDuplicate(&guid)) {
  277. *pAt = c;
  278. return S_OK;
  279. }
  280. }
  281. //
  282. // still none found
  283. //
  284. return E_INVALIDARG;
  285. }
  286. STDMETHODIMP CSetupClasses::Devices(VARIANT flags, LPDISPATCH *pDevices)
  287. {
  288. //
  289. // combine devices for all classes
  290. //
  291. DWORD diflags = 0;
  292. HRESULT hr;
  293. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  294. HDEVINFO hPrevDevInfo = NULL;
  295. DWORD Err;
  296. DWORD c;
  297. hr = TranslateDeviceFlags(&flags,&diflags);
  298. if(FAILED(hr)) {
  299. return hr;
  300. }
  301. for(c=0;c<Count;c++) {
  302. hDevInfo = SetupDiGetClassDevsEx(pSetupClasses[c]->Guid(),NULL,NULL,diflags,hPrevDevInfo,pMachine,NULL);
  303. if(hDevInfo == INVALID_HANDLE_VALUE) {
  304. Err = GetLastError();
  305. if(hPrevDevInfo) {
  306. SetupDiDestroyDeviceInfoList(hPrevDevInfo);
  307. }
  308. return HRESULT_FROM_SETUPAPI(Err);
  309. }
  310. hPrevDevInfo = hDevInfo;
  311. }
  312. if(hDevInfo == INVALID_HANDLE_VALUE) {
  313. return E_INVALIDARG;
  314. }
  315. CComObject<CDevices> *d;
  316. hr = CComObject<CDevices>::CreateInstance(&d);
  317. if(FAILED(hr)) {
  318. SetupDiDestroyDeviceInfoList(hDevInfo);
  319. return hr;
  320. }
  321. d->AddRef();
  322. hr = d->Init(hDevInfo,DeviceConsole);
  323. if(FAILED(hr)) {
  324. d->Release();
  325. return hr;
  326. }
  327. *pDevices = d;
  328. return S_OK;
  329. }
  330. HRESULT CSetupClasses::AllClasses()
  331. {
  332. DWORD nClasses;
  333. DWORD nClasses2;
  334. DWORD c;
  335. DWORD Err;
  336. HRESULT hr;
  337. //
  338. // start with empty list
  339. //
  340. if(pSetupClasses) {
  341. for(c=0;c<Count;c++) {
  342. pSetupClasses[c]->Release();
  343. }
  344. delete [] pSetupClasses;
  345. }
  346. //
  347. // all classes
  348. //
  349. if(SetupDiBuildClassInfoListEx(0,NULL,0,&nClasses,pMachine,NULL) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  350. if(!nClasses) {
  351. //
  352. // no classes
  353. //
  354. return S_FALSE;
  355. }
  356. GUID *pList = new GUID[nClasses];
  357. if(!pList) {
  358. return E_OUTOFMEMORY;
  359. }
  360. if(SetupDiBuildClassInfoListEx(0,pList,nClasses,&nClasses2,pMachine,NULL) || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  361. //
  362. // count may have changed since last call
  363. //
  364. if(nClasses>nClasses2) {
  365. nClasses = nClasses2;
  366. }
  367. if(!nClasses) {
  368. //
  369. // no classes
  370. //
  371. delete [] pList;
  372. return S_FALSE;
  373. }
  374. for(c=0;c<nClasses;c++) {
  375. hr = AddGuid(&pList[c]);
  376. if(FAILED(hr)) {
  377. delete [] pList;
  378. return hr;
  379. }
  380. }
  381. delete [] pList;
  382. return hr;
  383. }
  384. }
  385. Err = GetLastError();
  386. return HRESULT_FROM_SETUPAPI(Err);
  387. }
  388. STDMETHODIMP CSetupClasses::get_Machine(BSTR *pVal)
  389. {
  390. if((pMachine == NULL) || !pMachine[0]) {
  391. *pVal = SysAllocString(L"");
  392. if(*pVal) {
  393. return S_FALSE;
  394. }
  395. } else {
  396. *pVal = SysAllocString(pMachine);
  397. if(*pVal) {
  398. return S_OK;
  399. }
  400. }
  401. *pVal = NULL;
  402. return E_OUTOFMEMORY;
  403. }