Leaked source code of windows server 2003
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.

2027 lines
56 KiB

  1. // Device.cpp : Implementation of CDevice
  2. #include "stdafx.h"
  3. #include "DevCon2.h"
  4. #include "Device.h"
  5. #include "xStrings.h"
  6. #include "Driver.h"
  7. #include "Drivers.h"
  8. #include "DrvSearchSet.h"
  9. #include "utils.h"
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CDevice
  12. CDevice::~CDevice()
  13. {
  14. //
  15. // when this is destroyed, yank the entry out of HDEVINFO
  16. //
  17. if(DevInfoData.cbSize) {
  18. HDEVINFO hDevInfo = GetDevInfoSet();
  19. if(hDevInfo != INVALID_HANDLE_VALUE) {
  20. SetupDiDeleteDeviceInfo(hDevInfo,&DevInfoData);
  21. }
  22. }
  23. }
  24. HRESULT CDevice::Init(IDevInfoSet *pDevInfoSet, LPCWSTR pInstance,IDeviceConsole *pDevCon)
  25. {
  26. //
  27. // init a new device (DeviceConsole/DevInfoSet are smart pointers)
  28. //
  29. DevInfoSet = pDevInfoSet;
  30. HDEVINFO hDevInfo = GetDevInfoSet();
  31. HRESULT hr;
  32. DWORD err;
  33. if(hDevInfo == INVALID_HANDLE_VALUE) {
  34. return E_UNEXPECTED;
  35. }
  36. DeviceConsole = pDevCon;
  37. DevInfoData.cbSize = sizeof(DevInfoData);
  38. if(SetupDiOpenDeviceInfo(hDevInfo,pInstance,NULL,0,&DevInfoData)) {
  39. return S_OK;
  40. }
  41. err = GetLastError();
  42. hr = HRESULT_FROM_SETUPAPI(err);
  43. DevInfoData.cbSize = 0;
  44. return hr;
  45. }
  46. HRESULT CDevice::Init(IDevInfoSet *pDevInfoSet, PSP_DEVINFO_DATA pData,IDeviceConsole *pDevCon)
  47. {
  48. //
  49. // init an existing device (DeviceConsole/DevInfoSet are smart pointers)
  50. //
  51. DevInfoSet = pDevInfoSet;
  52. DevInfoData = *pData;
  53. DeviceConsole = pDevCon;
  54. return S_OK;
  55. }
  56. HDEVINFO CDevice::GetDevInfoSet()
  57. {
  58. ULONGLONG h;
  59. HRESULT hr;
  60. if(!DevInfoSet) {
  61. return (HDEVINFO)INVALID_HANDLE_VALUE;
  62. }
  63. hr = DevInfoSet->get_Handle(&h);
  64. if(FAILED(hr)) {
  65. return (HDEVINFO)INVALID_HANDLE_VALUE;
  66. }
  67. return (HDEVINFO)h;
  68. }
  69. STDMETHODIMP CDevice::get_InstanceId(BSTR *pVal)
  70. {
  71. if(!DevInfoData.cbSize) {
  72. return E_UNEXPECTED;
  73. }
  74. HDEVINFO hDevInfo = GetDevInfoSet();
  75. if(hDevInfo == INVALID_HANDLE_VALUE) {
  76. return E_UNEXPECTED;
  77. }
  78. //
  79. // get instance string given hDevInfo and DevInfoData
  80. //
  81. WCHAR devID[MAX_DEVICE_ID_LEN];
  82. SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
  83. devInfoListDetail.cbSize = sizeof(devInfoListDetail);
  84. if((!SetupDiGetDeviceInfoListDetail(hDevInfo,&devInfoListDetail)) ||
  85. (CM_Get_Device_ID_Ex(DevInfoData.DevInst,devID,MAX_DEVICE_ID_LEN,0,devInfoListDetail.RemoteMachineHandle)!=CR_SUCCESS)) {
  86. return E_UNEXPECTED;
  87. }
  88. *pVal = SysAllocString(devID);
  89. if(!*pVal) {
  90. return E_OUTOFMEMORY;
  91. }
  92. return S_OK;
  93. }
  94. BOOL CDevice::SameAs(CDevice *pOther)
  95. {
  96. //
  97. // only works if pOther is in same set as us
  98. //
  99. if(pOther == this) {
  100. return TRUE;
  101. }
  102. if(!pOther) {
  103. return FALSE;
  104. }
  105. if(DevInfoData.cbSize != pOther->DevInfoData.cbSize) {
  106. return FALSE;
  107. }
  108. if(DevInfoData.DevInst != pOther->DevInfoData.DevInst) {
  109. return FALSE;
  110. }
  111. return TRUE;
  112. }
  113. STDMETHODIMP CDevice::Delete()
  114. {
  115. if(!DevInfoData.cbSize) {
  116. return E_INVALIDARG;
  117. }
  118. HDEVINFO hDevInfo = GetDevInfoSet();
  119. if(hDevInfo == INVALID_HANDLE_VALUE) {
  120. return E_UNEXPECTED;
  121. }
  122. SP_REMOVEDEVICE_PARAMS rmdParams;
  123. ZeroMemory(&rmdParams,sizeof(rmdParams));
  124. rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  125. rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
  126. rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
  127. rmdParams.HwProfile = 0;
  128. if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&rmdParams.ClassInstallHeader,sizeof(rmdParams))
  129. || !SetupDiCallClassInstaller(DIF_REMOVE,hDevInfo,&DevInfoData)) {
  130. DWORD Err = GetLastError();
  131. return HRESULT_FROM_SETUPAPI(Err);
  132. }
  133. return CheckNoReboot();
  134. }
  135. STDMETHODIMP CDevice::Enable()
  136. {
  137. if(!DevInfoData.cbSize) {
  138. return E_INVALIDARG;
  139. }
  140. HDEVINFO hDevInfo = GetDevInfoSet();
  141. if(hDevInfo == INVALID_HANDLE_VALUE) {
  142. return E_UNEXPECTED;
  143. }
  144. SP_PROPCHANGE_PARAMS pcp;
  145. VARIANT_BOOL NeedReboot;
  146. VARIANT_BOOL NowNeedReboot;
  147. HRESULT hr;
  148. //
  149. // remember current reboot status
  150. //
  151. hr = get_RebootRequired(&NeedReboot);
  152. if(FAILED(hr)) {
  153. return hr;
  154. }
  155. //
  156. // attempt to enable globally
  157. //
  158. ZeroMemory(&pcp,sizeof(pcp));
  159. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  160. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  161. pcp.StateChange = DICS_ENABLE;
  162. pcp.Scope = DICS_FLAG_GLOBAL;
  163. pcp.HwProfile = 0;
  164. if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp)) ||
  165. !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) {
  166. //
  167. // failed to invoke DIF_PROPERTYCHANGE
  168. //
  169. DWORD Err = GetLastError();
  170. return HRESULT_FROM_SETUPAPI(Err);
  171. }
  172. hr = get_RebootRequired(&NowNeedReboot);
  173. if(FAILED(hr)) {
  174. return hr;
  175. }
  176. if(!(NeedReboot || NowNeedReboot)) {
  177. //
  178. // reboot not required, we must have enabled the device
  179. //
  180. return S_OK;
  181. }
  182. if(!NeedReboot) {
  183. //
  184. // reset reboot status back to how it was originally
  185. //
  186. put_RebootRequired(VARIANT_FALSE);
  187. }
  188. //
  189. // also do config specific enable
  190. //
  191. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  192. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  193. pcp.StateChange = DICS_ENABLE;
  194. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  195. pcp.HwProfile = 0;
  196. if(SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp))
  197. && SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) {
  198. //
  199. // succeeded to invoke config-specific
  200. //
  201. if(NeedReboot) {
  202. //
  203. // set back original status if reboot was required
  204. //
  205. put_RebootRequired(VARIANT_TRUE);
  206. }
  207. return CheckNoReboot();
  208. }
  209. //
  210. // if this failed, just imply reboot (our first result)
  211. //
  212. put_RebootRequired(VARIANT_TRUE);
  213. return CheckNoReboot();
  214. }
  215. STDMETHODIMP CDevice::Disable()
  216. {
  217. if(!DevInfoData.cbSize) {
  218. return E_INVALIDARG;
  219. }
  220. HDEVINFO hDevInfo = GetDevInfoSet();
  221. if(hDevInfo == INVALID_HANDLE_VALUE) {
  222. return E_UNEXPECTED;
  223. }
  224. SP_PROPCHANGE_PARAMS pcp;
  225. //
  226. // attempt to disable globally
  227. //
  228. ZeroMemory(&pcp,sizeof(pcp));
  229. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  230. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  231. pcp.StateChange = DICS_DISABLE;
  232. pcp.Scope = DICS_FLAG_GLOBAL;
  233. pcp.HwProfile = 0;
  234. if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp)) ||
  235. !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) {
  236. //
  237. // failed to invoke DIF_PROPERTYCHANGE
  238. //
  239. DWORD Err = GetLastError();
  240. return HRESULT_FROM_SETUPAPI(Err);
  241. }
  242. return CheckNoReboot();
  243. }
  244. STDMETHODIMP CDevice::Start()
  245. {
  246. if(!DevInfoData.cbSize) {
  247. return E_INVALIDARG;
  248. }
  249. HDEVINFO hDevInfo = GetDevInfoSet();
  250. if(hDevInfo == INVALID_HANDLE_VALUE) {
  251. return E_UNEXPECTED;
  252. }
  253. SP_PROPCHANGE_PARAMS pcp;
  254. //
  255. // attempt to start (can only be for this config)
  256. //
  257. ZeroMemory(&pcp,sizeof(pcp));
  258. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  259. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  260. pcp.StateChange = DICS_ENABLE;
  261. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  262. pcp.HwProfile = 0;
  263. if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp)) ||
  264. !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) {
  265. //
  266. // failed to invoke DIF_PROPERTYCHANGE
  267. //
  268. DWORD Err = GetLastError();
  269. return HRESULT_FROM_SETUPAPI(Err);
  270. }
  271. return CheckNoReboot();
  272. }
  273. STDMETHODIMP CDevice::Stop()
  274. {
  275. if(!DevInfoData.cbSize) {
  276. return E_INVALIDARG;
  277. }
  278. HDEVINFO hDevInfo = GetDevInfoSet();
  279. if(hDevInfo == INVALID_HANDLE_VALUE) {
  280. return E_UNEXPECTED;
  281. }
  282. SP_PROPCHANGE_PARAMS pcp;
  283. //
  284. // attempt to start (can only be for this config)
  285. //
  286. ZeroMemory(&pcp,sizeof(pcp));
  287. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  288. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  289. pcp.StateChange = DICS_STOP;
  290. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  291. pcp.HwProfile = 0;
  292. if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp)) ||
  293. !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) {
  294. //
  295. // failed to invoke DIF_PROPERTYCHANGE
  296. //
  297. DWORD Err = GetLastError();
  298. return HRESULT_FROM_SETUPAPI(Err);
  299. }
  300. return CheckNoReboot();
  301. }
  302. STDMETHODIMP CDevice::Restart()
  303. {
  304. if(!DevInfoData.cbSize) {
  305. return E_INVALIDARG;
  306. }
  307. HDEVINFO hDevInfo = GetDevInfoSet();
  308. if(hDevInfo == INVALID_HANDLE_VALUE) {
  309. return E_UNEXPECTED;
  310. }
  311. SP_PROPCHANGE_PARAMS pcp;
  312. //
  313. // attempt to stop then start (restart) (can only be for this config)
  314. //
  315. ZeroMemory(&pcp,sizeof(pcp));
  316. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  317. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  318. pcp.StateChange = DICS_PROPCHANGE;
  319. pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
  320. pcp.HwProfile = 0;
  321. if(!SetupDiSetClassInstallParams(hDevInfo,&DevInfoData,&pcp.ClassInstallHeader,sizeof(pcp)) ||
  322. !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,hDevInfo,&DevInfoData)) {
  323. //
  324. // failed to invoke DIF_PROPERTYCHANGE
  325. //
  326. DWORD Err = GetLastError();
  327. return HRESULT_FROM_SETUPAPI(Err);
  328. }
  329. return CheckNoReboot();
  330. }
  331. HRESULT CDevice::CheckNoReboot()
  332. {
  333. VARIANT_BOOL NeedReboot;
  334. HRESULT hr = get_RebootRequired(&NeedReboot);
  335. if(FAILED(hr)) {
  336. return hr;
  337. }
  338. if(NeedReboot) {
  339. if(DeviceConsole) {
  340. //
  341. // set reboot required in device console too
  342. //
  343. DeviceConsole->put_RebootRequired(VARIANT_TRUE);
  344. }
  345. return S_FALSE;
  346. }
  347. return S_OK;
  348. }
  349. STDMETHODIMP CDevice::get_RebootRequired(VARIANT_BOOL *pVal)
  350. {
  351. if(!DevInfoData.cbSize) {
  352. return E_INVALIDARG;
  353. }
  354. HDEVINFO hDevInfo = GetDevInfoSet();
  355. if(hDevInfo == INVALID_HANDLE_VALUE) {
  356. return E_UNEXPECTED;
  357. }
  358. SP_DEVINSTALL_PARAMS devParams;
  359. ZeroMemory(&devParams,sizeof(devParams));
  360. devParams.cbSize = sizeof(devParams);
  361. if(!SetupDiGetDeviceInstallParams(hDevInfo,&DevInfoData,&devParams)) {
  362. DWORD Err = GetLastError();
  363. return HRESULT_FROM_SETUPAPI(Err);
  364. }
  365. *pVal = (devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) ? VARIANT_TRUE : VARIANT_FALSE;
  366. return S_OK;
  367. }
  368. STDMETHODIMP CDevice::put_RebootRequired(VARIANT_BOOL newVal)
  369. {
  370. if(!DevInfoData.cbSize) {
  371. return E_INVALIDARG;
  372. }
  373. HDEVINFO hDevInfo = GetDevInfoSet();
  374. if(hDevInfo == INVALID_HANDLE_VALUE) {
  375. return E_UNEXPECTED;
  376. }
  377. BOOL changed = FALSE;
  378. SP_DEVINSTALL_PARAMS devParams;
  379. ZeroMemory(&devParams,sizeof(devParams));
  380. devParams.cbSize = sizeof(devParams);
  381. if(!SetupDiGetDeviceInstallParams(hDevInfo,&DevInfoData,&devParams)) {
  382. DWORD Err = GetLastError();
  383. return HRESULT_FROM_SETUPAPI(Err);
  384. }
  385. if(newVal) {
  386. if((devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) == 0) {
  387. devParams.Flags |= DI_NEEDREBOOT|DI_NEEDRESTART;
  388. changed = TRUE;
  389. if(DeviceConsole) {
  390. //
  391. // set reboot required in device console too
  392. //
  393. DeviceConsole->put_RebootRequired(VARIANT_TRUE);
  394. }
  395. }
  396. } else {
  397. if((devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) != 0) {
  398. devParams.Flags &= ~DI_NEEDREBOOT|DI_NEEDRESTART;
  399. changed = TRUE;
  400. }
  401. }
  402. if(changed) {
  403. if(!SetupDiSetDeviceInstallParams(hDevInfo,&DevInfoData,&devParams)) {
  404. DWORD Err = GetLastError();
  405. return HRESULT_FROM_SETUPAPI(Err);
  406. }
  407. }
  408. return S_OK;
  409. }
  410. STDMETHODIMP CDevice::get_Description(BSTR *pVal)
  411. {
  412. //
  413. // obtain a description for the device
  414. //
  415. HRESULT hr;
  416. CComVariant v;
  417. VARIANT final;
  418. VariantInit(&final);
  419. hr = GetDeviceProperty(SPDRP_FRIENDLYNAME,&v);
  420. if(SUCCEEDED(hr)) {
  421. hr = v.ChangeType(VT_BSTR);
  422. if(SUCCEEDED(hr)) {
  423. if(V_BSTR(&v)!=NULL && V_BSTR(&v)[0]) {
  424. v.Detach(&final);
  425. *pVal = V_BSTR(&final);
  426. return S_OK;
  427. }
  428. }
  429. }
  430. v.Clear();
  431. hr = GetDeviceProperty(SPDRP_DEVICEDESC,&v);
  432. if(SUCCEEDED(hr)) {
  433. hr = v.ChangeType(VT_BSTR);
  434. if(SUCCEEDED(hr)) {
  435. if(V_BSTR(&v)!=NULL && V_BSTR(&v)[0]) {
  436. v.Detach(&final);
  437. *pVal = V_BSTR(&final);
  438. return S_OK;
  439. }
  440. }
  441. }
  442. v.Clear();
  443. *pVal = SysAllocString(L"");
  444. if(!*pVal) {
  445. return E_OUTOFMEMORY;
  446. }
  447. return S_OK;
  448. }
  449. STDMETHODIMP CDevice::get_HardwareIds(VARIANT *pVal)
  450. {
  451. return GetDeviceProperty(SPDRP_HARDWAREID,pVal);
  452. }
  453. STDMETHODIMP CDevice::put_HardwareIds(VARIANT newVal)
  454. {
  455. return PutDevicePropertyMultiSz(SPDRP_HARDWAREID,&newVal);
  456. }
  457. STDMETHODIMP CDevice::get_CompatibleIds(VARIANT *pVal)
  458. {
  459. return GetDeviceProperty(SPDRP_COMPATIBLEIDS,pVal);
  460. }
  461. STDMETHODIMP CDevice::put_CompatibleIds(VARIANT newVal)
  462. {
  463. return PutDevicePropertyMultiSz(SPDRP_COMPATIBLEIDS,&newVal);
  464. }
  465. STDMETHODIMP CDevice::get_ServiceName(VARIANT *pVal)
  466. {
  467. return GetDeviceProperty(SPDRP_SERVICE,pVal);
  468. }
  469. STDMETHODIMP CDevice::get_Class(VARIANT *pVal)
  470. {
  471. return GetDeviceProperty(SPDRP_CLASS,pVal);
  472. }
  473. STDMETHODIMP CDevice::get_Manufacturer(VARIANT *pVal)
  474. {
  475. return GetDeviceProperty(SPDRP_MFG,pVal);
  476. }
  477. STDMETHODIMP CDevice::get_FriendlyName(VARIANT *pVal)
  478. {
  479. return GetDeviceProperty(SPDRP_FRIENDLYNAME,pVal);
  480. }
  481. STDMETHODIMP CDevice::put_FriendlyName(VARIANT newVal)
  482. {
  483. return PutDevicePropertyString(SPDRP_FRIENDLYNAME,&newVal);
  484. }
  485. STDMETHODIMP CDevice::get_LocationInformation(VARIANT *pVal)
  486. {
  487. return GetDeviceProperty(SPDRP_LOCATION_INFORMATION,pVal);
  488. }
  489. STDMETHODIMP CDevice::put_LocationInformation(VARIANT newVal)
  490. {
  491. return PutDevicePropertyString(SPDRP_LOCATION_INFORMATION,&newVal);
  492. }
  493. STDMETHODIMP CDevice::get_UpperFilters(VARIANT *pVal)
  494. {
  495. return GetDeviceProperty(SPDRP_UPPERFILTERS,pVal);
  496. }
  497. STDMETHODIMP CDevice::put_UpperFilters(VARIANT newVal)
  498. {
  499. return PutDevicePropertyMultiSz(SPDRP_UPPERFILTERS,&newVal);
  500. }
  501. STDMETHODIMP CDevice::get_LowerFilters(VARIANT *pVal)
  502. {
  503. return GetDeviceProperty(SPDRP_LOWERFILTERS,pVal);
  504. }
  505. STDMETHODIMP CDevice::put_LowerFilters(VARIANT newVal)
  506. {
  507. return PutDevicePropertyMultiSz(SPDRP_LOWERFILTERS,&newVal);
  508. }
  509. STDMETHODIMP CDevice::get_EnumeratorName(VARIANT *pVal)
  510. {
  511. return GetDeviceProperty(SPDRP_ENUMERATOR_NAME,pVal);
  512. }
  513. STDMETHODIMP CDevice::get_Security(VARIANT *pVal)
  514. {
  515. return GetDeviceProperty(SPDRP_SECURITY_SDS,pVal);
  516. }
  517. STDMETHODIMP CDevice::put_Security(VARIANT newVal)
  518. {
  519. return PutDevicePropertyString(SPDRP_SECURITY_SDS,&newVal);
  520. }
  521. STDMETHODIMP CDevice::get_DeviceTypeOverride(VARIANT *pVal)
  522. {
  523. return GetDeviceProperty(SPDRP_DEVTYPE,pVal);
  524. }
  525. STDMETHODIMP CDevice::put_DeviceTypeOverride(VARIANT newVal)
  526. {
  527. return PutDevicePropertyDword(SPDRP_DEVTYPE,&newVal);
  528. }
  529. STDMETHODIMP CDevice::get_ForceExclusive(VARIANT *pVal)
  530. {
  531. return GetDeviceProperty(SPDRP_EXCLUSIVE,pVal);
  532. }
  533. STDMETHODIMP CDevice::put_ForceExclusive(VARIANT newVal)
  534. {
  535. return PutDevicePropertyDword(SPDRP_EXCLUSIVE,&newVal);
  536. }
  537. STDMETHODIMP CDevice::get_CharacteristicsOverride(VARIANT *pVal)
  538. {
  539. return GetDeviceProperty(SPDRP_CHARACTERISTICS,pVal);
  540. }
  541. STDMETHODIMP CDevice::put_CharacteristicsOverride(VARIANT newVal)
  542. {
  543. return PutDevicePropertyDword(SPDRP_CHARACTERISTICS,&newVal);
  544. }
  545. HRESULT CDevice::GetDeviceProperty(DWORD prop, VARIANT *pVal)
  546. {
  547. if(!DevInfoData.cbSize) {
  548. return E_INVALIDARG;
  549. }
  550. HDEVINFO hDevInfo = GetDevInfoSet();
  551. if(hDevInfo == INVALID_HANDLE_VALUE) {
  552. return E_UNEXPECTED;
  553. }
  554. //
  555. // first obtain raw registry data
  556. //
  557. LPBYTE buffer = NULL;
  558. DWORD size = 1024;
  559. DWORD bufsize;
  560. DWORD reqSize;
  561. DWORD dataType;
  562. HRESULT hr;
  563. for(;;) {
  564. if(buffer) {
  565. delete [] buffer;
  566. }
  567. bufsize = size + sizeof(WCHAR)*2;
  568. buffer = new BYTE[bufsize];
  569. if(!buffer) {
  570. return E_OUTOFMEMORY;
  571. }
  572. if(SetupDiGetDeviceRegistryProperty(hDevInfo,&DevInfoData,prop,&dataType,buffer,size,&reqSize)) {
  573. break;
  574. }
  575. DWORD Err = GetLastError();
  576. if(Err != ERROR_INSUFFICIENT_BUFFER) {
  577. delete [] buffer;
  578. hr = HRESULT_FROM_SETUPAPI(Err);
  579. return hr;
  580. }
  581. }
  582. //
  583. // now determine how to parcel it to caller
  584. //
  585. switch(dataType) {
  586. case REG_DWORD: {
  587. //
  588. // package value as a long
  589. //
  590. if(size != sizeof(DWORD)) {
  591. hr = E_INVALIDARG;
  592. } else {
  593. VariantClear(pVal);
  594. V_VT(pVal) = VT_I4;
  595. V_I4(pVal) = (long)*((DWORD*)buffer);
  596. hr = S_OK;
  597. }
  598. }
  599. break;
  600. case REG_SZ: {
  601. //
  602. // package value as string
  603. //
  604. VariantClear(pVal);
  605. ZeroMemory(buffer+size,sizeof(WCHAR));
  606. BSTR pString = SysAllocString((LPWSTR)buffer);
  607. if(!pString) {
  608. hr = E_OUTOFMEMORY;
  609. } else {
  610. V_VT(pVal) = VT_BSTR;
  611. V_BSTR(pVal) = pString;
  612. hr = S_OK;
  613. }
  614. }
  615. break;
  616. case REG_MULTI_SZ: {
  617. //
  618. // package as string-list
  619. //
  620. VariantClear(pVal);
  621. ZeroMemory(buffer+size,sizeof(WCHAR)*2);
  622. CComObject<CStrings> *strings;
  623. hr = CComObject<CStrings>::CreateInstance(&strings);
  624. if(FAILED(hr)) {
  625. break;
  626. }
  627. CComPtr<IStrings> stringsPtr = strings;
  628. LPWSTR p;
  629. UINT len = 0;
  630. for(p = (LPWSTR)buffer;*p;p+=len+1) {
  631. len = wcslen(p);
  632. hr = strings->InternalAdd(p,len);
  633. if(FAILED(hr)) {
  634. break;
  635. }
  636. }
  637. V_VT(pVal) = VT_DISPATCH;
  638. V_DISPATCH(pVal) = stringsPtr.Detach();
  639. hr = S_OK;
  640. }
  641. break;
  642. default:
  643. hr = E_INVALIDARG;
  644. break;
  645. }
  646. delete [] buffer;
  647. return hr;
  648. }
  649. HRESULT CDevice::PutDevicePropertyString(DWORD prop, VARIANT *pVal)
  650. {
  651. if(!DevInfoData.cbSize) {
  652. return E_INVALIDARG;
  653. }
  654. HDEVINFO hDevInfo = GetDevInfoSet();
  655. if(hDevInfo == INVALID_HANDLE_VALUE) {
  656. return E_UNEXPECTED;
  657. }
  658. HRESULT hr;
  659. DWORD len = 0;
  660. PBYTE data = NULL;
  661. CComVariant v;
  662. if(!IsBlank(pVal)) {
  663. hr = v.ChangeType(VT_BSTR,pVal);
  664. if(FAILED(hr)) {
  665. return hr;
  666. }
  667. len = (SysStringLen(V_BSTR(&v))+1)*sizeof(WCHAR);
  668. data = (PBYTE)V_BSTR(&v);
  669. }
  670. if(SetupDiSetDeviceRegistryProperty(hDevInfo,
  671. &DevInfoData,
  672. prop,
  673. data,
  674. len)) {
  675. return S_OK;
  676. }
  677. DWORD Err = GetLastError();
  678. return HRESULT_FROM_SETUPAPI(Err);
  679. }
  680. HRESULT CDevice::PutDevicePropertyDword(DWORD prop, VARIANT *pVal)
  681. {
  682. if(!DevInfoData.cbSize) {
  683. return E_INVALIDARG;
  684. }
  685. HDEVINFO hDevInfo = GetDevInfoSet();
  686. if(hDevInfo == INVALID_HANDLE_VALUE) {
  687. return E_UNEXPECTED;
  688. }
  689. CComVariant v;
  690. HRESULT hr;
  691. DWORD len = 0;
  692. PBYTE data = NULL;
  693. if(!IsBlank(pVal)) {
  694. hr = v.ChangeType(VT_I4,pVal);
  695. if(FAILED(hr)) {
  696. return hr;
  697. }
  698. len = sizeof(V_I4(&v));
  699. data = (PBYTE)&V_I4(&v);
  700. }
  701. if(SetupDiSetDeviceRegistryProperty(hDevInfo,
  702. &DevInfoData,
  703. prop,
  704. data,
  705. len)) {
  706. return S_OK;
  707. }
  708. DWORD Err = GetLastError();
  709. return HRESULT_FROM_SETUPAPI(Err);
  710. }
  711. HRESULT CDevice::PutDevicePropertyMultiSz(DWORD prop, VARIANT *pVal)
  712. {
  713. if(!DevInfoData.cbSize) {
  714. return E_INVALIDARG;
  715. }
  716. HDEVINFO hDevInfo = GetDevInfoSet();
  717. if(hDevInfo == INVALID_HANDLE_VALUE) {
  718. return E_UNEXPECTED;
  719. }
  720. //
  721. // build a CStrings collection
  722. //
  723. HRESULT hr;
  724. CComObject<CStrings> *strings = NULL;
  725. CComPtr<IStrings> stringsPtr;
  726. DWORD len = 0;
  727. PBYTE data = NULL;
  728. LPWSTR multisz;
  729. if(!IsBlank(pVal)) {
  730. hr = CComObject<CStrings>::CreateInstance(&strings);
  731. if(FAILED(hr)) {
  732. return hr;
  733. }
  734. stringsPtr = strings; // handle ref-counting
  735. hr = strings->Add(*pVal);
  736. if(FAILED(hr)) {
  737. return hr;
  738. }
  739. //
  740. // now obtain multisz from the collection
  741. //
  742. hr = strings->GetMultiSz(&multisz,&len);
  743. if(FAILED(hr)) {
  744. return hr;
  745. }
  746. //
  747. // now write the multi-sz value to device registry
  748. //
  749. len *= sizeof(WCHAR);
  750. data = (PBYTE)multisz;
  751. }
  752. if(SetupDiSetDeviceRegistryProperty(hDevInfo,
  753. &DevInfoData,
  754. prop,
  755. (PBYTE)multisz,
  756. len)) {
  757. if(multisz) {
  758. delete [] multisz;
  759. }
  760. return S_OK;
  761. }
  762. DWORD Err = GetLastError();
  763. if(multisz) {
  764. delete [] multisz;
  765. }
  766. return HRESULT_FROM_SETUPAPI(Err);
  767. }
  768. HRESULT CDevice::GetRemoteMachine(HANDLE *hMachine)
  769. {
  770. if(!DevInfoData.cbSize) {
  771. return E_INVALIDARG;
  772. }
  773. HDEVINFO hDevInfo = GetDevInfoSet();
  774. if(hDevInfo == INVALID_HANDLE_VALUE) {
  775. return E_UNEXPECTED;
  776. }
  777. SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
  778. devInfoListDetail.cbSize = sizeof(devInfoListDetail);
  779. if(!SetupDiGetDeviceInfoListDetail(hDevInfo,&devInfoListDetail)) {
  780. DWORD Err = GetLastError();
  781. return HRESULT_FROM_SETUPAPI(Err);
  782. }
  783. *hMachine = devInfoListDetail.RemoteMachineHandle;
  784. return S_OK;
  785. }
  786. STDMETHODIMP CDevice::get_IsRunning(VARIANT_BOOL *pVal)
  787. {
  788. HANDLE hMachine;
  789. ULONG status = 0;
  790. ULONG problem = 0;
  791. HRESULT hr = GetRemoteMachine(&hMachine);
  792. if(FAILED(hr)) {
  793. return hr;
  794. }
  795. if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) {
  796. return E_UNEXPECTED;
  797. }
  798. if(status & DN_STARTED) {
  799. *pVal = VARIANT_TRUE;
  800. } else {
  801. *pVal = VARIANT_FALSE;
  802. }
  803. return S_OK;
  804. }
  805. STDMETHODIMP CDevice::get_IsDisabled(VARIANT_BOOL *pVal)
  806. {
  807. HANDLE hMachine;
  808. ULONG status = 0;
  809. ULONG problem = 0;
  810. HRESULT hr = GetRemoteMachine(&hMachine);
  811. if(FAILED(hr)) {
  812. return hr;
  813. }
  814. if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) {
  815. return E_UNEXPECTED;
  816. }
  817. if(status & DN_HAS_PROBLEM) {
  818. if((problem == CM_PROB_DISABLED) || (problem == CM_PROB_HARDWARE_DISABLED)) {
  819. *pVal = VARIANT_TRUE;
  820. return S_OK;
  821. }
  822. }
  823. *pVal = VARIANT_FALSE;
  824. return S_OK;
  825. }
  826. STDMETHODIMP CDevice::get_HasProblem(VARIANT_BOOL *pVal)
  827. {
  828. HANDLE hMachine;
  829. ULONG status = 0;
  830. ULONG problem = 0;
  831. HRESULT hr = GetRemoteMachine(&hMachine);
  832. if(FAILED(hr)) {
  833. return hr;
  834. }
  835. if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) {
  836. return E_UNEXPECTED;
  837. }
  838. if(status & (DN_HAS_PROBLEM|DN_PRIVATE_PROBLEM)) {
  839. *pVal = VARIANT_TRUE;
  840. } else {
  841. *pVal = VARIANT_FALSE;
  842. }
  843. return S_OK;
  844. }
  845. STDMETHODIMP CDevice::get_ProblemCode(long *pVal)
  846. {
  847. HANDLE hMachine;
  848. ULONG status = 0;
  849. ULONG problem = 0;
  850. HRESULT hr = GetRemoteMachine(&hMachine);
  851. if(FAILED(hr)) {
  852. return hr;
  853. }
  854. if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) {
  855. return E_UNEXPECTED;
  856. }
  857. if(status & DN_HAS_PROBLEM) {
  858. *pVal = (long)problem;
  859. } else {
  860. *pVal = 0;
  861. }
  862. return S_OK;
  863. }
  864. STDMETHODIMP CDevice::get_HasPrivateProblem(VARIANT_BOOL *pVal)
  865. {
  866. HANDLE hMachine;
  867. ULONG status = 0;
  868. ULONG problem = 0;
  869. HRESULT hr = GetRemoteMachine(&hMachine);
  870. if(FAILED(hr)) {
  871. return hr;
  872. }
  873. if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) {
  874. return E_UNEXPECTED;
  875. }
  876. if(status & DN_PRIVATE_PROBLEM) {
  877. *pVal = VARIANT_TRUE;
  878. } else {
  879. *pVal = VARIANT_FALSE;
  880. }
  881. return S_OK;
  882. }
  883. STDMETHODIMP CDevice::get_IsRootEnumerated(VARIANT_BOOL *pVal)
  884. {
  885. HANDLE hMachine;
  886. ULONG status = 0;
  887. ULONG problem = 0;
  888. HRESULT hr = GetRemoteMachine(&hMachine);
  889. if(FAILED(hr)) {
  890. return hr;
  891. }
  892. if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) {
  893. return E_UNEXPECTED;
  894. }
  895. if(status & DN_ROOT_ENUMERATED) {
  896. *pVal = VARIANT_TRUE;
  897. } else {
  898. *pVal = VARIANT_FALSE;
  899. }
  900. return S_OK;
  901. }
  902. STDMETHODIMP CDevice::get_IsDisableable(VARIANT_BOOL *pVal)
  903. {
  904. HANDLE hMachine;
  905. ULONG status = 0;
  906. ULONG problem = 0;
  907. HRESULT hr = GetRemoteMachine(&hMachine);
  908. if(FAILED(hr)) {
  909. return hr;
  910. }
  911. if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) {
  912. return E_UNEXPECTED;
  913. }
  914. if(status & DN_DISABLEABLE) {
  915. *pVal = VARIANT_TRUE;
  916. } else {
  917. *pVal = VARIANT_FALSE;
  918. }
  919. return S_OK;
  920. }
  921. STDMETHODIMP CDevice::get_IsRemovable(VARIANT_BOOL *pVal)
  922. {
  923. HANDLE hMachine;
  924. ULONG status = 0;
  925. ULONG problem = 0;
  926. HRESULT hr = GetRemoteMachine(&hMachine);
  927. if(FAILED(hr)) {
  928. return hr;
  929. }
  930. if(CM_Get_DevNode_Status_Ex(&status,&problem,DevInfoData.DevInst,0,hMachine)!=CR_SUCCESS) {
  931. return E_UNEXPECTED;
  932. }
  933. if(status & DN_REMOVABLE) {
  934. *pVal = VARIANT_TRUE;
  935. } else {
  936. *pVal = VARIANT_FALSE;
  937. }
  938. return S_OK;
  939. }
  940. BOOL CDevice::SameAs(LPWSTR str)
  941. {
  942. BSTR pThisStr;
  943. HRESULT hr = get_InstanceId(&pThisStr);
  944. if(FAILED(hr)) {
  945. return FALSE;
  946. }
  947. BOOL f = _wcsicmp(str,pThisStr)==0;
  948. SysFreeString(pThisStr);
  949. return f;
  950. }
  951. STDMETHODIMP CDevice::RegRead(BSTR key,VARIANT * pValue)
  952. {
  953. HKEY hParentKey;
  954. HKEY hKey;
  955. LPCWSTR val;
  956. LPWSTR subkey;
  957. LONG regerr;
  958. DWORD regType;
  959. DWORD regSize;
  960. LPBYTE pByte;
  961. if(!pValue) {
  962. return E_INVALIDARG;
  963. }
  964. VariantInit(pValue);
  965. HRESULT hr = SubKeyInfo(key,&hParentKey,&subkey,&val,FALSE);
  966. if(FAILED(hr)) {
  967. return hr;
  968. }
  969. //
  970. // now work out and marshell data
  971. //
  972. if(subkey) {
  973. regerr = RegOpenKeyEx(hParentKey,subkey,0,KEY_READ,&hKey);
  974. delete [] subkey;
  975. RegCloseKey(hParentKey);
  976. if(regerr != NO_ERROR) {
  977. return HRESULT_FROM_SETUPAPI(regerr);
  978. }
  979. } else {
  980. hKey = hParentKey;
  981. }
  982. regSize = 0;
  983. regerr = RegQueryValueEx(hKey,val,NULL,&regType,NULL,&regSize);
  984. if(regerr != NO_ERROR) {
  985. RegCloseKey(hKey);
  986. return HRESULT_FROM_SETUPAPI(regerr);
  987. }
  988. pByte = new BYTE[regSize+sizeof(WCHAR)*2];
  989. if(!pByte) {
  990. RegCloseKey(hKey);
  991. return E_OUTOFMEMORY;
  992. }
  993. regerr = RegQueryValueEx(hKey,val,NULL,&regType,pByte,&regSize);
  994. RegCloseKey(hKey);
  995. if(regerr != NO_ERROR) {
  996. delete [] pByte;
  997. return HRESULT_FROM_SETUPAPI(regerr);
  998. }
  999. switch(regType) {
  1000. case REG_DWORD:
  1001. if(regSize != 4) {
  1002. delete [] pByte;
  1003. return DISP_E_TYPEMISMATCH;
  1004. }
  1005. V_VT(pValue) = VT_UI4;
  1006. V_UI4(pValue) = *(DWORD*)pByte;
  1007. break;
  1008. case REG_BINARY:
  1009. switch(regSize) {
  1010. case 1:
  1011. V_VT(pValue) = VT_UI1;
  1012. V_UI1(pValue) = *((BYTE*)pByte);
  1013. break;
  1014. case 2:
  1015. V_VT(pValue) = VT_UI2;
  1016. V_UI2(pValue) = *((WORD*)pByte);
  1017. break;
  1018. case 4:
  1019. V_VT(pValue) = VT_UI4;
  1020. V_UI4(pValue) = *((DWORD*)pByte);
  1021. break;
  1022. default:
  1023. delete [] pByte;
  1024. return DISP_E_TYPEMISMATCH;
  1025. }
  1026. break;
  1027. case REG_SZ:
  1028. ZeroMemory(pByte+regSize,sizeof(WCHAR)*1);
  1029. V_VT(pValue) = VT_BSTR;
  1030. V_BSTR(pValue) = SysAllocString((LPWSTR)pByte);
  1031. if(!V_BSTR(pValue)) {
  1032. delete [] pByte;
  1033. return E_OUTOFMEMORY;
  1034. }
  1035. break;
  1036. case REG_MULTI_SZ: {
  1037. ZeroMemory(pByte+regSize,sizeof(WCHAR)*2);
  1038. CComObject<CStrings> *pStringTemp = NULL;
  1039. hr = CComObject<CStrings>::CreateInstance(&pStringTemp);
  1040. if(FAILED(hr)) {
  1041. delete [] pByte;
  1042. return hr;
  1043. }
  1044. CComPtr<IStrings> stringTempPtr = pStringTemp; // handle ref-counting
  1045. hr = pStringTemp->FromMultiSz((LPWSTR)pByte);
  1046. if(FAILED(hr)) {
  1047. delete [] pByte;
  1048. return hr;
  1049. }
  1050. V_VT(pValue) = VT_DISPATCH;
  1051. V_DISPATCH(pValue) = stringTempPtr.Detach();
  1052. }
  1053. break;
  1054. case REG_EXPAND_SZ:
  1055. ZeroMemory(pByte+regSize,sizeof(WCHAR)*1);
  1056. regSize = ExpandEnvironmentStrings((LPWSTR)pByte,NULL,0);
  1057. if(regSize == 0) {
  1058. V_VT(pValue) = VT_BSTR;
  1059. V_BSTR(pValue) = SysAllocString((LPWSTR)pByte);
  1060. } else {
  1061. LPWSTR pExp = new WCHAR[regSize+1];
  1062. if(!pExp) {
  1063. delete [] pByte;
  1064. return E_OUTOFMEMORY;
  1065. }
  1066. regSize = ExpandEnvironmentStrings((LPWSTR)pByte,NULL,regSize);
  1067. V_VT(pValue) = VT_BSTR;
  1068. V_BSTR(pValue) = SysAllocString(pExp);
  1069. delete [] pExp;
  1070. }
  1071. if(!V_BSTR(pValue)) {
  1072. delete [] pByte;
  1073. return E_OUTOFMEMORY;
  1074. }
  1075. break;
  1076. default:
  1077. delete [] pByte;
  1078. return HRESULT_FROM_SETUPAPI(regerr);
  1079. }
  1080. delete [] pByte;
  1081. return S_OK;
  1082. }
  1083. STDMETHODIMP CDevice::RegWrite(BSTR key, VARIANT val, VARIANT strType)
  1084. {
  1085. HKEY hParentKey;
  1086. HKEY hKey;
  1087. LPCWSTR valname;
  1088. LPWSTR subkey;
  1089. LONG regerr;
  1090. CComVariant strType_v;
  1091. CComVariant val_v;
  1092. LPCWSTR pType;
  1093. HRESULT hr;
  1094. DWORD dwType;
  1095. BOOL DetermineType = FALSE;
  1096. LPBYTE pData = NULL;
  1097. LPWSTR pString = NULL;
  1098. DWORD DataSize = 0;
  1099. BYTE SimpleData[4];
  1100. LPVARIANT pVal = &val;
  1101. while(V_VT(pVal) == (VT_BYREF|VT_VARIANT)) {
  1102. pVal = V_VARIANTREF(pVal);
  1103. }
  1104. //
  1105. // validate strType
  1106. //
  1107. hr = GetOptionalString(&strType,strType_v,&pType);
  1108. if(FAILED(hr)) {
  1109. return hr;
  1110. }
  1111. if((pType == NULL) || !pType[0]) {
  1112. //
  1113. // determine type of variant
  1114. //
  1115. if(IsNumericVariant(pVal)) {
  1116. dwType = REG_DWORD;
  1117. } else if(IsMultiValueVariant(pVal)) {
  1118. dwType = REG_MULTI_SZ;
  1119. } else {
  1120. dwType = REG_SZ;
  1121. }
  1122. } else if(_wcsicmp(pType,L"REG_DWORD")==0) {
  1123. dwType = REG_DWORD;
  1124. } else if(_wcsicmp(pType,L"REG_SZ")==0) {
  1125. dwType = REG_SZ;
  1126. } else if(_wcsicmp(pType,L"REG_EXPAND_SZ")==0) {
  1127. dwType = REG_EXPAND_SZ;
  1128. } else if(_wcsicmp(pType,L"REG_MULTI_SZ")==0) {
  1129. dwType = REG_MULTI_SZ;
  1130. } else if(_wcsicmp(pType,L"REG_BINARY")==0) {
  1131. dwType = REG_BINARY;
  1132. } else {
  1133. return DISP_E_TYPEMISMATCH;
  1134. }
  1135. //
  1136. // build up value data
  1137. //
  1138. switch(dwType) {
  1139. case REG_BINARY:
  1140. pData = SimpleData;
  1141. switch V_VT(pVal) {
  1142. case VT_I1:
  1143. case VT_UI1:
  1144. *(LPBYTE)pData = V_UI1(pVal);
  1145. DataSize = 1;
  1146. break;
  1147. case VT_I1|VT_BYREF:
  1148. case VT_UI1|VT_BYREF:
  1149. *(LPBYTE)pData = *V_UI1REF(pVal);
  1150. DataSize = 1;
  1151. break;
  1152. case VT_I2:
  1153. case VT_UI2:
  1154. *(LPWORD)pData = V_UI2(pVal);
  1155. DataSize = 2;
  1156. break;
  1157. case VT_I2|VT_BYREF:
  1158. case VT_UI2|VT_BYREF:
  1159. *(LPWORD)pData = *V_UI2REF(pVal);
  1160. DataSize = 2;
  1161. break;
  1162. case VT_I4:
  1163. case VT_UI4:
  1164. *(LPDWORD)pData = V_UI4(pVal);
  1165. DataSize = 4;
  1166. break;
  1167. case VT_I4|VT_BYREF:
  1168. case VT_UI4|VT_BYREF:
  1169. *(LPDWORD)pData = *V_UI4REF(pVal);
  1170. DataSize = 4;
  1171. break;
  1172. default:
  1173. return DISP_E_TYPEMISMATCH;
  1174. }
  1175. break;
  1176. case REG_DWORD:
  1177. pData = SimpleData;
  1178. hr = val_v.ChangeType(VT_UI4,pVal);
  1179. if(FAILED(hr)) {
  1180. return DISP_E_TYPEMISMATCH;
  1181. }
  1182. *(LPDWORD)pData = V_UI4(pVal);
  1183. DataSize = 4;
  1184. break;
  1185. case REG_SZ:
  1186. case REG_EXPAND_SZ:
  1187. hr = val_v.ChangeType(VT_BSTR,pVal);
  1188. if(FAILED(hr)) {
  1189. return DISP_E_TYPEMISMATCH;
  1190. }
  1191. DataSize = (SysStringLen(V_BSTR(&val_v))+1);
  1192. pString = new WCHAR[DataSize];
  1193. if(!pString) {
  1194. return E_OUTOFMEMORY;
  1195. }
  1196. pData = (LPBYTE)pString;
  1197. DataSize *= sizeof(WCHAR);
  1198. memcpy(pData,V_BSTR(&val_v),DataSize);
  1199. break;
  1200. case REG_MULTI_SZ: {
  1201. CComObject<CStrings> *pStringTemp = NULL;
  1202. hr = CComObject<CStrings>::CreateInstance(&pStringTemp);
  1203. if(FAILED(hr)) {
  1204. return hr;
  1205. }
  1206. CComPtr<IStrings> pStringTempPtr = pStringTemp; // for ref-counting
  1207. hr = pStringTemp->InternalInsert(0,pVal);
  1208. if(FAILED(hr)) {
  1209. return hr;
  1210. }
  1211. hr = pStringTemp->GetMultiSz(&pString,&DataSize);
  1212. if(FAILED(hr)) {
  1213. return hr;
  1214. }
  1215. pData = (LPBYTE)pString;
  1216. DataSize *= sizeof(WCHAR);
  1217. }
  1218. break;
  1219. default:
  1220. return DISP_E_TYPEMISMATCH;
  1221. }
  1222. hr = SubKeyInfo(key,&hParentKey,&subkey,&valname,TRUE);
  1223. if(FAILED(hr)) {
  1224. if(pString) {
  1225. delete [] pString;
  1226. }
  1227. return hr;
  1228. }
  1229. if(subkey) {
  1230. regerr = RegCreateKeyEx(hParentKey,subkey,0,NULL,0,KEY_WRITE,NULL,&hKey,NULL);
  1231. delete [] subkey;
  1232. RegCloseKey(hParentKey);
  1233. if(regerr != NO_ERROR) {
  1234. if(pString) {
  1235. delete [] pString;
  1236. }
  1237. return HRESULT_FROM_SETUPAPI(regerr);
  1238. }
  1239. } else {
  1240. hKey = hParentKey;
  1241. }
  1242. regerr = RegSetValueEx(hKey,valname,0,dwType,pData,DataSize);
  1243. if(pString) {
  1244. delete [] pString;
  1245. }
  1246. RegCloseKey(hKey);
  1247. if(regerr != NO_ERROR) {
  1248. return HRESULT_FROM_SETUPAPI(regerr);
  1249. }
  1250. return S_OK;
  1251. }
  1252. STDMETHODIMP CDevice::RegDelete(BSTR key)
  1253. {
  1254. HKEY hParentKey;
  1255. HKEY hKey;
  1256. LPCWSTR valname;
  1257. LPWSTR subkey;
  1258. LONG regerr;
  1259. HRESULT hr = SubKeyInfo(key,&hParentKey,&subkey,&valname,TRUE);
  1260. if(FAILED(hr)) {
  1261. return hr;
  1262. }
  1263. if(subkey) {
  1264. regerr = RegOpenKeyEx(hParentKey,subkey,0,KEY_WRITE,&hKey);
  1265. delete [] subkey;
  1266. RegCloseKey(hParentKey);
  1267. if(regerr != NO_ERROR) {
  1268. return HRESULT_FROM_SETUPAPI(regerr);
  1269. }
  1270. } else {
  1271. hKey = hParentKey;
  1272. }
  1273. regerr = RegDeleteValue(hKey,valname);
  1274. RegCloseKey(hKey);
  1275. if(regerr != NO_ERROR) {
  1276. return HRESULT_FROM_SETUPAPI(regerr);
  1277. }
  1278. return S_OK;
  1279. }
  1280. HRESULT CDevice::SubKeyInfo(LPCWSTR subkey, HKEY *hKey, LPWSTR *pSubKey,LPCWSTR *pKeyVal,BOOL writeable)
  1281. {
  1282. //
  1283. // first 3 chars of subkey can be "SW\" or "HW\"
  1284. //
  1285. LPCWSTR partkey;
  1286. DWORD Scope = DICS_FLAG_GLOBAL;
  1287. DWORD HwProfile = 0;
  1288. DWORD KeyType;
  1289. HKEY hParentKey;
  1290. LPWSTR keyname;
  1291. LPCWSTR keyval;
  1292. size_t len;
  1293. if(!DevInfoData.cbSize) {
  1294. return E_INVALIDARG;
  1295. }
  1296. HDEVINFO hDevInfo = GetDevInfoSet();
  1297. if(hDevInfo == INVALID_HANDLE_VALUE) {
  1298. return E_UNEXPECTED;
  1299. }
  1300. if((subkey[0] == L'S' || subkey[0] == L's')
  1301. &&(subkey[1] == L'W' || subkey[1] == L'w')
  1302. &&(subkey[2] == L'\\')) {
  1303. partkey = subkey+3;
  1304. KeyType = DIREG_DRV;
  1305. } else if((subkey[0] == L'H' || subkey[0] == L'h')
  1306. &&(subkey[1] == L'W' || subkey[1] == L'w')
  1307. &&(subkey[2] == L'\\')) {
  1308. partkey = subkey+3;
  1309. KeyType = DIREG_DEV;
  1310. } else {
  1311. return E_INVALIDARG;
  1312. }
  1313. hParentKey = SetupDiOpenDevRegKey(hDevInfo,
  1314. &DevInfoData,
  1315. Scope,
  1316. HwProfile,
  1317. KeyType,
  1318. writeable ? KEY_WRITE: KEY_READ
  1319. );
  1320. if((hParentKey == NULL) || (hParentKey == INVALID_HANDLE_VALUE)) {
  1321. DWORD Err = GetLastError();
  1322. return HRESULT_FROM_SETUPAPI(Err);
  1323. }
  1324. //
  1325. // determine value part of key
  1326. //
  1327. keyval = wcsrchr(partkey,L'\\');
  1328. if(!keyval) {
  1329. *hKey = hParentKey;
  1330. *pKeyVal = partkey[0] ? partkey : NULL;
  1331. *pSubKey = NULL;
  1332. return S_OK;
  1333. }
  1334. len = keyval-partkey+1;
  1335. keyname = new WCHAR[len];
  1336. if(!keyname) {
  1337. RegCloseKey(hParentKey);
  1338. return E_OUTOFMEMORY;
  1339. }
  1340. wcsncpy(keyname,partkey,len);
  1341. keyname[len-1] = 0;
  1342. keyval++;
  1343. if(!keyval[0]) {
  1344. keyval = NULL;
  1345. }
  1346. *hKey = hParentKey;
  1347. *pSubKey = keyname;
  1348. *pKeyVal = keyval;
  1349. return S_OK;
  1350. }
  1351. STDMETHODIMP CDevice::CurrentDriverPackage(LPDISPATCH *pDriver)
  1352. {
  1353. *pDriver = NULL;
  1354. //
  1355. // create a search set for finding current driver
  1356. //
  1357. HRESULT hr;
  1358. if(!DevInfoData.cbSize) {
  1359. return E_INVALIDARG;
  1360. }
  1361. HDEVINFO hDevInfo = GetDevInfoSet();
  1362. if(hDevInfo == INVALID_HANDLE_VALUE) {
  1363. return E_UNEXPECTED;
  1364. }
  1365. HANDLE remote;
  1366. if(SUCCEEDED(GetRemoteMachine(&remote)) && remote) {
  1367. //
  1368. // remote driver search not implemented
  1369. //
  1370. return E_NOTIMPL;
  1371. }
  1372. CComObject<CDrvSearchSet> *pSet = NULL;
  1373. hr = CComObject<CDrvSearchSet>::CreateInstance(&pSet);
  1374. if(FAILED(hr)) {
  1375. return hr;
  1376. }
  1377. CComPtr<IDrvSearchSet> pSetPtr = pSet; // for ref-counting
  1378. hr = pSet->Init(this,SPDIT_CLASSDRIVER);
  1379. if(FAILED(hr)) {
  1380. return hr;
  1381. }
  1382. //
  1383. // use temporary device information
  1384. //
  1385. HDEVINFO SetDevInfo = pSet->GetDevInfoSet();
  1386. PSP_DEVINFO_DATA SetDevInfoData = pSet->GetDevInfoData();
  1387. //
  1388. // WinXP has a nice feature for obtaining current driver
  1389. //
  1390. DWORD Err;
  1391. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  1392. SP_DRVINFO_DATA DriverInfoData;
  1393. ZeroMemory(&DeviceInstallParams, sizeof(DeviceInstallParams));
  1394. ZeroMemory(&DriverInfoData, sizeof(DriverInfoData));
  1395. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1396. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  1397. if(!SetupDiGetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams)) {
  1398. Err = GetLastError();
  1399. return HRESULT_FROM_SETUPAPI(Err);
  1400. }
  1401. //
  1402. // Set the flags that tell SetupDiBuildDriverInfoList to just put the currently installed
  1403. // driver node in the list, and that it should allow excluded drivers.
  1404. //
  1405. DeviceInstallParams.FlagsEx |= (DI_FLAGSEX_INSTALLEDDRIVER | DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
  1406. if(SetupDiSetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams)
  1407. && SetupDiBuildDriverInfoList(SetDevInfo, SetDevInfoData, SPDIT_CLASSDRIVER)) {
  1408. if(!SetupDiEnumDriverInfo(SetDevInfo,SetDevInfoData,SPDIT_CLASSDRIVER,0,&DriverInfoData)) {
  1409. //
  1410. // flag recognized, but no driver
  1411. //
  1412. return S_OK;
  1413. }
  1414. //
  1415. // DriverInfoData contains driver
  1416. //
  1417. } else {
  1418. //
  1419. // get information about a driver to do a full search
  1420. //
  1421. WCHAR SectionName[LINE_LEN];
  1422. WCHAR DrvDescription[LINE_LEN];
  1423. HKEY hKey = NULL;
  1424. DWORD RegDataLength;
  1425. DWORD RegDataType;
  1426. long regerr;
  1427. //
  1428. // get driver key - if it doesn't exist, no driver
  1429. //
  1430. hKey = SetupDiOpenDevRegKey(SetDevInfo,
  1431. SetDevInfoData,
  1432. DICS_FLAG_GLOBAL,
  1433. 0,
  1434. DIREG_DRV,
  1435. KEY_READ
  1436. );
  1437. if(hKey == INVALID_HANDLE_VALUE) {
  1438. //
  1439. // no such value exists, so we haven't an associated driver
  1440. //
  1441. RegCloseKey(hKey);
  1442. return S_OK;
  1443. }
  1444. //
  1445. // obtain path of INF
  1446. //
  1447. RegDataLength = sizeof(DeviceInstallParams.DriverPath); // want in bytes, not chars
  1448. regerr = RegQueryValueEx(hKey,
  1449. REGSTR_VAL_INFPATH,
  1450. NULL,
  1451. &RegDataType,
  1452. (PBYTE)DeviceInstallParams.DriverPath,
  1453. &RegDataLength
  1454. );
  1455. if((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) {
  1456. //
  1457. // no such value exists, so we haven't an associated driver
  1458. //
  1459. RegCloseKey(hKey);
  1460. return S_OK;
  1461. }
  1462. RegDataLength = sizeof(DriverInfoData.ProviderName);
  1463. regerr = RegQueryValueEx(hKey,
  1464. REGSTR_VAL_PROVIDER_NAME,
  1465. NULL,
  1466. &RegDataType,
  1467. (PBYTE)DriverInfoData.ProviderName,
  1468. &RegDataLength
  1469. );
  1470. if((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) {
  1471. //
  1472. // no such value exists, so we don't have a valid associated driver
  1473. //
  1474. RegCloseKey(hKey);
  1475. return S_OK;
  1476. }
  1477. RegDataLength = sizeof(SectionName);
  1478. regerr = RegQueryValueEx(hKey,
  1479. REGSTR_VAL_INFSECTION,
  1480. NULL,
  1481. &RegDataType,
  1482. (PBYTE)SectionName,
  1483. &RegDataLength
  1484. );
  1485. if((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) {
  1486. //
  1487. // no such value exists, so we don't have a valid associated driver
  1488. //
  1489. RegCloseKey(hKey);
  1490. return S_OK;
  1491. }
  1492. //
  1493. // driver description is usually same as original device description
  1494. // but sometimes obtained from strings section
  1495. //
  1496. RegDataLength = sizeof(DrvDescription);
  1497. regerr = RegQueryValueEx(hKey,
  1498. REGSTR_VAL_DRVDESC,
  1499. NULL,
  1500. &RegDataType,
  1501. (PBYTE)DrvDescription,
  1502. &RegDataLength
  1503. );
  1504. RegCloseKey(hKey);
  1505. if((regerr != ERROR_SUCCESS) || (RegDataType != REG_SZ)) {
  1506. //
  1507. // no such value exists, so we don't have a valid associated driver
  1508. //
  1509. return S_OK;
  1510. }
  1511. //
  1512. // Manufacturer
  1513. //
  1514. if(!SetupDiGetDeviceRegistryProperty(SetDevInfo,
  1515. SetDevInfoData,
  1516. SPDRP_MFG,
  1517. NULL, // datatype is guaranteed to always be REG_SZ.
  1518. (PBYTE)DriverInfoData.MfgName,
  1519. sizeof(DriverInfoData.MfgName),
  1520. NULL)) {
  1521. //
  1522. // no such value exists, so we don't have a valid associated driver
  1523. //
  1524. return S_OK;
  1525. }
  1526. //
  1527. // Description
  1528. //
  1529. if(!SetupDiGetDeviceRegistryProperty(SetDevInfo,
  1530. SetDevInfoData,
  1531. SPDRP_DEVICEDESC,
  1532. NULL, // datatype is guaranteed to always be REG_SZ.
  1533. (PBYTE)DriverInfoData.Description,
  1534. sizeof(DriverInfoData.Description),
  1535. NULL)) {
  1536. //
  1537. // no such value exists, so we don't have a valid associated driver
  1538. //
  1539. return S_OK;
  1540. }
  1541. //
  1542. // now search for drivers listed in the INF
  1543. //
  1544. //
  1545. DeviceInstallParams.Flags |= DI_ENUMSINGLEINF;
  1546. DeviceInstallParams.FlagsEx &= ~DI_FLAGSEX_INSTALLEDDRIVER;
  1547. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
  1548. if(!SetupDiSetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams)) {
  1549. Err = GetLastError();
  1550. return HRESULT_FROM_SETUPAPI(Err);
  1551. }
  1552. if(!SetupDiBuildDriverInfoList(SetDevInfo, SetDevInfoData, SPDIT_CLASSDRIVER)) {
  1553. return S_OK;
  1554. }
  1555. //
  1556. // enumerate drivers to find a good match
  1557. //
  1558. SP_DRVINFO_DATA ThisDriverInfoData;
  1559. ZeroMemory(&ThisDriverInfoData, sizeof(ThisDriverInfoData));
  1560. ThisDriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  1561. DWORD c;
  1562. BOOL match = FALSE;
  1563. for(c=0;SetupDiEnumDriverInfo(SetDevInfo,SetDevInfoData,SPDIT_CLASSDRIVER,c,&ThisDriverInfoData);c++) {
  1564. if((_wcsicmp(DriverInfoData.MfgName,ThisDriverInfoData.MfgName)==0)
  1565. &&(_wcsicmp(DriverInfoData.ProviderName,ThisDriverInfoData.ProviderName)==0)) {
  1566. //
  1567. // these two fields match, try more detailed info
  1568. //
  1569. SP_DRVINFO_DETAIL_DATA detail;
  1570. detail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  1571. if(!SetupDiGetDriverInfoDetail(SetDevInfo,SetDevInfoData,&ThisDriverInfoData,&detail,sizeof(detail),NULL)) {
  1572. Err = GetLastError();
  1573. if((Err != NO_ERROR) && (Err != ERROR_INSUFFICIENT_BUFFER)) {
  1574. continue;
  1575. }
  1576. }
  1577. if((_wcsicmp(SectionName,detail.SectionName)==0) &&
  1578. (_wcsicmp(DrvDescription,detail.DrvDescription)==0)) {
  1579. DriverInfoData = ThisDriverInfoData;
  1580. match = TRUE;
  1581. break;
  1582. }
  1583. }
  1584. }
  1585. if(!match) {
  1586. return S_OK;
  1587. }
  1588. }
  1589. //
  1590. // create the driver object
  1591. //
  1592. CComObject<CDriverPackage> *driver = NULL;
  1593. hr = CComObject<CDriverPackage>::CreateInstance(&driver);
  1594. if(FAILED(hr)) {
  1595. return hr;
  1596. }
  1597. CComPtr<IDriverPackage> driverPtr = driver; // for ref-counting
  1598. hr = driver->Init(pSet,&DriverInfoData);
  1599. if(FAILED(hr)) {
  1600. return hr;
  1601. }
  1602. *pDriver = driverPtr.Detach();
  1603. return S_OK;
  1604. }
  1605. STDMETHODIMP CDevice::FindDriverPackages(VARIANT ScriptPath, LPDISPATCH *pDriversOut)
  1606. {
  1607. *pDriversOut = NULL;
  1608. //
  1609. // Treat variant as a multi-sz array if it exists
  1610. //
  1611. CComObject<CStrings> *pStrings = NULL;
  1612. CComPtr<IStrings> pStringsPtr;
  1613. CComObject<CDrvSearchSet> *pSet = NULL;
  1614. CComPtr<IDrvSearchSet> pSetPtr;
  1615. CComObject<CDriverPackages> *pDrivers = NULL;
  1616. CComPtr<IDriverPackages> pDriversPtr;
  1617. CComObject<CDriverPackage> *pDriver = NULL;
  1618. CComPtr<IDriverPackage> pDriverPtr;
  1619. HRESULT hr;
  1620. if(!IsNoArg(&ScriptPath)) {
  1621. hr = CComObject<CStrings>::CreateInstance(&pStrings);
  1622. if(FAILED(hr)) {
  1623. return hr;
  1624. }
  1625. pStringsPtr = pStrings;
  1626. hr = pStrings->InternalInsert(0,&ScriptPath);
  1627. if(FAILED(hr)) {
  1628. return hr;
  1629. }
  1630. }
  1631. //
  1632. // create context for driver search
  1633. //
  1634. hr = CComObject<CDrvSearchSet>::CreateInstance(&pSet);
  1635. if(FAILED(hr)) {
  1636. return hr;
  1637. }
  1638. pSetPtr = pSet;
  1639. hr = pSet->Init(this,SPDIT_COMPATDRIVER);
  1640. if(FAILED(hr)) {
  1641. return hr;
  1642. }
  1643. //
  1644. // use temporary device information
  1645. //
  1646. HDEVINFO SetDevInfo = pSet->GetDevInfoSet();
  1647. PSP_DEVINFO_DATA SetDevInfoData = pSet->GetDevInfoData();
  1648. DWORD Err;
  1649. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  1650. SP_DRVINFO_DATA DriverInfoData;
  1651. DWORD c;
  1652. ZeroMemory(&DeviceInstallParams, sizeof(DeviceInstallParams));
  1653. ZeroMemory(&DriverInfoData, sizeof(DriverInfoData));
  1654. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1655. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  1656. if(!SetupDiGetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams)) {
  1657. Err = GetLastError();
  1658. return HRESULT_FROM_SETUPAPI(Err);
  1659. }
  1660. //
  1661. // Do a search in standard directories.
  1662. //
  1663. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
  1664. BOOL done_wild = FALSE;
  1665. BSTR str;
  1666. for(c=0,str=NULL;(pStrings==NULL) || (pStrings->InternalEnum(c,&str));c++) {
  1667. if(str && str[0] && ((str[0] != '*') || str[1])) {
  1668. DWORD attr = GetFileAttributes(str);
  1669. if(attr == (DWORD)(-1)) {
  1670. continue;
  1671. }
  1672. DWORD sz = GetFullPathName(str,MAX_PATH,DeviceInstallParams.DriverPath,NULL);
  1673. if(sz >= MAX_PATH) {
  1674. DeviceInstallParams.DriverPath[0] = '\0';
  1675. continue;
  1676. }
  1677. if(!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
  1678. DeviceInstallParams.FlagsEx |= DI_ENUMSINGLEINF;
  1679. }
  1680. } else if(done_wild) {
  1681. continue;
  1682. } else {
  1683. done_wild = TRUE;
  1684. }
  1685. if(!SetupDiSetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams)) {
  1686. Err = GetLastError();
  1687. hr = HRESULT_FROM_SETUPAPI(Err);
  1688. goto final;
  1689. }
  1690. if(!SetupDiBuildDriverInfoList(SetDevInfo, SetDevInfoData, SPDIT_COMPATDRIVER)) {
  1691. Err = GetLastError();
  1692. hr = HRESULT_FROM_SETUPAPI(Err);
  1693. goto final;
  1694. }
  1695. SetupDiGetDeviceInstallParams(SetDevInfo, SetDevInfoData, &DeviceInstallParams);
  1696. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_APPENDDRIVERLIST;
  1697. DeviceInstallParams.FlagsEx &= ~DI_ENUMSINGLEINF;
  1698. DeviceInstallParams.DriverPath[0] = '\0';
  1699. }
  1700. //
  1701. // now create the collection to hold search results
  1702. //
  1703. hr = CComObject<CDriverPackages>::CreateInstance(&pDrivers);
  1704. if(FAILED(hr)) {
  1705. pDrivers = NULL;
  1706. goto final;
  1707. }
  1708. pDriversPtr = pDrivers;
  1709. hr = pDrivers->Init(pSet);
  1710. if(FAILED(hr)) {
  1711. goto final;
  1712. }
  1713. for(c=0;SetupDiEnumDriverInfo(SetDevInfo,SetDevInfoData,SPDIT_COMPATDRIVER,c,&DriverInfoData);c++) {
  1714. //
  1715. // create the driver object
  1716. //
  1717. hr = CComObject<CDriverPackage>::CreateInstance(&pDriver);
  1718. if(FAILED(hr)) {
  1719. goto final;
  1720. }
  1721. pDriverPtr = pDriver;
  1722. hr = pDriver->Init(pSet,&DriverInfoData);
  1723. if(FAILED(hr)) {
  1724. goto final;
  1725. }
  1726. hr = pDrivers->InternalAdd(pDriver);
  1727. if(FAILED(hr)) {
  1728. goto final;
  1729. }
  1730. }
  1731. final:
  1732. if(FAILED(hr)) {
  1733. return hr;
  1734. }
  1735. *pDriversOut = pDriversPtr.Detach();
  1736. return S_OK;
  1737. }
  1738. STDMETHODIMP CDevice::HasInterface(BSTR Interface, VARIANT_BOOL *pFlag)
  1739. {
  1740. //
  1741. // create a search set for finding current driver
  1742. //
  1743. HRESULT hr;
  1744. if(!DevInfoData.cbSize) {
  1745. return E_INVALIDARG;
  1746. }
  1747. HDEVINFO hDevInfo = GetDevInfoSet();
  1748. if(hDevInfo == INVALID_HANDLE_VALUE) {
  1749. return E_UNEXPECTED;
  1750. }
  1751. GUID guid;
  1752. hr = CLSIDFromString(Interface,&guid);
  1753. if(FAILED(hr)) {
  1754. return hr;
  1755. }
  1756. SP_DEVICE_INTERFACE_DATA data;
  1757. ZeroMemory(&data,sizeof(data));
  1758. data.cbSize = sizeof(data);
  1759. BOOL f = SetupDiEnumDeviceInterfaces(hDevInfo,&DevInfoData,&guid,0,&data);
  1760. DWORD Err = GetLastError();
  1761. *pFlag = f? VARIANT_TRUE: VARIANT_FALSE;
  1762. return S_OK;
  1763. }
  1764. STDMETHODIMP CDevice::get_Machine(BSTR *pVal)
  1765. {
  1766. *pVal = NULL;
  1767. HDEVINFO hDevInfo = GetDevInfoSet();
  1768. if(hDevInfo == INVALID_HANDLE_VALUE) {
  1769. return E_UNEXPECTED;
  1770. }
  1771. SP_DEVINFO_LIST_DETAIL_DATA devInfoListDetail;
  1772. devInfoListDetail.cbSize = sizeof(devInfoListDetail);
  1773. if(!SetupDiGetDeviceInfoListDetail(hDevInfo,&devInfoListDetail)) {
  1774. DWORD Err = GetLastError();
  1775. return HRESULT_FROM_SETUPAPI(Err);
  1776. }
  1777. if((devInfoListDetail.RemoteMachineHandle == NULL) || !devInfoListDetail.RemoteMachineName[0]) {
  1778. *pVal = SysAllocString(L"");
  1779. if(*pVal) {
  1780. return S_FALSE;
  1781. }
  1782. } else {
  1783. *pVal = SysAllocString(devInfoListDetail.RemoteMachineName);
  1784. if(*pVal) {
  1785. return S_OK;
  1786. }
  1787. }
  1788. return E_OUTOFMEMORY;
  1789. }
  1790. STDMETHODIMP CDevice::get__ClassGuid(GUID *pVal)
  1791. {
  1792. WCHAR ClassGuid[40];
  1793. HRESULT hr;
  1794. if(!DevInfoData.cbSize) {
  1795. return E_INVALIDARG;
  1796. }
  1797. HDEVINFO hDevInfo = GetDevInfoSet();
  1798. if(hDevInfo == INVALID_HANDLE_VALUE) {
  1799. return E_UNEXPECTED;
  1800. }
  1801. DWORD reqSize;
  1802. if(!SetupDiGetDeviceRegistryProperty(hDevInfo,
  1803. &DevInfoData,
  1804. SPDRP_CLASSGUID,
  1805. NULL,
  1806. (LPBYTE)ClassGuid,
  1807. sizeof(ClassGuid),
  1808. &reqSize)) {
  1809. DWORD Err = GetLastError();
  1810. return HRESULT_FROM_SETUPAPI(Err);
  1811. }
  1812. hr = CLSIDFromString(ClassGuid,pVal);
  1813. if(FAILED(hr)) {
  1814. return hr;
  1815. }
  1816. return S_OK;
  1817. }
  1818. STDMETHODIMP CDevice::get__Machine(BSTR *pVal)
  1819. {
  1820. return get_Machine(pVal);
  1821. }