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.

410 lines
19 KiB

  1. //=============================================================================
  2. // Contains the refresh function for a simple query function (a simple query
  3. // is one which involves a single WMI class and little post processing).
  4. //=============================================================================
  5. #include "stdafx.h"
  6. #include "category.h"
  7. #include "dataset.h"
  8. #include "wmiabstraction.h"
  9. #include "resourcemap.h"
  10. //-----------------------------------------------------------------------------
  11. // These functions implement features found in the new versions of MFC (new
  12. // than what we're currently building with).
  13. //-----------------------------------------------------------------------------
  14. void StringReplace(CString & str, LPCTSTR szLookFor, LPCTSTR szReplaceWith)
  15. {
  16. CString strWorking(str);
  17. CString strReturn;
  18. CString strLookFor(szLookFor);
  19. CString strReplaceWith(szReplaceWith);
  20. int iLookFor = strLookFor.GetLength();
  21. int iNext;
  22. while (!strWorking.IsEmpty())
  23. {
  24. iNext = strWorking.Find(strLookFor);
  25. if (iNext == -1)
  26. {
  27. strReturn += strWorking;
  28. strWorking.Empty();
  29. }
  30. else
  31. {
  32. strReturn += strWorking.Left(iNext);
  33. strReturn += strReplaceWith;
  34. strWorking = strWorking.Right(strWorking.GetLength() - (iNext + iLookFor));
  35. }
  36. }
  37. str = strReturn;
  38. }
  39. //-----------------------------------------------------------------------------
  40. // The CSimpleQuery class encapsulates the simple query data. An array of these
  41. // is created containing an element for each category to use this refresh
  42. // function.
  43. //-----------------------------------------------------------------------------
  44. class CSimpleQuery
  45. {
  46. public:
  47. CSimpleQuery(DWORD dwIndex, LPCTSTR szClass, LPCTSTR szProperties, UINT uiColumns, BOOL fShowResources = FALSE, BOOL fBlankDividers = FALSE) :
  48. m_dwIndex(dwIndex),
  49. m_strClass(szClass),
  50. m_strProperties(szProperties),
  51. m_uiColumns(uiColumns),
  52. m_fBlankDividers(fBlankDividers),
  53. m_fShowResources(fShowResources) {};
  54. ~CSimpleQuery() {};
  55. public:
  56. DWORD m_dwIndex; // the index of this particular query
  57. CString m_strClass; // name of WMI class to enumerate
  58. CString m_strProperties; // properties to enumerate (in order displayed, comma delimited)
  59. BOOL m_fShowResources; // show resources used (must be two column "item|value" format)
  60. UINT m_uiColumns; // resource ID for the string containing the data to go in columns
  61. BOOL m_fBlankDividers; // insert a blank line between each instance
  62. };
  63. // TBD - need to mark some items as advanced
  64. CSimpleQuery aSimpleQueries[] =
  65. {
  66. CSimpleQuery(QUERY_CDROM, _T("Win32_CDRomDrive"), _T("Drive, Description, MediaLoaded, MediaType, Name, Manufacturer, Status, TransferRate, MSIAdvancedSCSITargetId, MSIAdvancedPNPDeviceID"), IDS_CDROMCOLUMNS, TRUE, TRUE),
  67. CSimpleQuery(QUERY_SERVICES, _T("Win32_Service"), _T("DisplayName, Name, State, StartMode, ServiceType, PathName, ErrorControl, StartName, TagId"), IDS_SERVICES1, FALSE),
  68. CSimpleQuery(QUERY_PROGRAMGROUP, _T("Win32_ProgramGroup"), _T("GroupName, Name, UserName"), IDS_PROGRAMGROUP1, FALSE),
  69. CSimpleQuery(QUERY_STARTUP, _T("Win32_StartupCommand"), _T("Caption, Command, User, Location"), IDS_STARTUP1, FALSE),
  70. CSimpleQuery(QUERY_KEYBOARD, _T("Win32_Keyboard"), _T("Description, Name, Layout, MSIAdvancedPNPDeviceID, NumberOfFunctionKeys"), IDS_KEYBOARD1, TRUE, TRUE),
  71. CSimpleQuery(QUERY_POINTDEV, _T("Win32_PointingDevice"), _T("HardwareType, NumberOfButtons, Status, MSIAdvancedPNPDeviceID, MSIAdvancedPowerManagementSupported, MSIAdvancedDoubleSpeedThreshold, MSIAdvancedHandedness"), IDS_POINTDEV1, TRUE, TRUE),
  72. CSimpleQuery(QUERY_MODEM, _T("Win32_POTSModem"), _T("Caption, Description, DeviceID, DeviceType, AttachedTo, AnswerMode, MSIAdvancedPNPDeviceID, MSIAdvancedProviderName, MSIAdvancedModemInfPath, MSIAdvancedModemInfSection, MSIAdvancedBlindOff, MSIAdvancedBlindOn, CompressionOff, CompressionOn, ErrorControlForced, ErrorControlOff, ErrorControlOn, MSIAdvancedFlowControlHard, MSIAdvancedFlowControlOff, MSIAdvancedFlowControlSoft, MSIAdvancedDCB, MSIAdvancedDefault, MSIAdvancedInactivityTimeout, MSIAdvancedModulationBell, MSIAdvancedModulationCCITT, MSIAdvancedPrefix, MSIAdvancedPulse, MSIAdvancedReset, MSIAdvancedResponsesKeyName, SpeakerModeDial, SpeakerModeOff, SpeakerModeOn, SpeakerModeSetup, SpeakerVolumeHigh, SpeakerVolumeLow, SpeakerVolumeMed, MSIAdvancedStringFormat, MSIAdvancedTerminator, MSIAdvancedTone"), IDS_MODEM1, TRUE, TRUE),
  73. CSimpleQuery(QUERY_NETPROT, _T("Win32_NetworkProtocol"), _T("Name, ConnectionlessService, GuaranteesDelivery, GuaranteesSequencing, MSIAdvancedMaximumAddressSize, MSIAdvancedMaximumMessageSize, MSIAdvancedMessageOriented, MSIAdvancedMinimumAddressSize, MSIAdvancedPseudoStreamOriented, MSIAdvancedSupportsBroadcasting, MSIAdvancedSupportsConnectData, MSIAdvancedSupportsDisconnectData, MSIAdvancedSupportsEncryption, MSIAdvancedSupportsExpeditedData, MSIAdvancedSupportsGracefulClosing, MSIAdvancedSupportsGuaranteedBandwidth, MSIAdvancedSupportsMulticasting"), IDS_NETPROT1, FALSE, TRUE),
  74. CSimpleQuery(QUERY_ENVVAR, _T("Win32_Environment"), _T("Name, VariableValue, UserName"), IDS_ENVVAR1, FALSE),
  75. CSimpleQuery(QUERY_SOUNDDEV, _T("Win32_SoundDevice"), _T("Caption, Manufacturer, Status, MSIAdvancedPNPDeviceID"), IDS_SOUNDDEV1, TRUE, TRUE),
  76. CSimpleQuery(QUERY_DISPLAY, _T("Win32_VideoController"), _T("Name, MSIAdvancedPNPDeviceID, VideoProcessor, AdapterCompatibility, MSIAdvancedDescription, MSIAdvancedAdapterRAM, MSIAdvancedInstalledDisplayDrivers, DriverVersion, MSIAdvancedInfFilename, MSIAdvancedInfSection, MSIAdvancedNumberOfColorPlanes, MSIAdvancedCurrentNumberOfColors, CurrentHorizontalResolution, CurrentVerticalResolution, CurrentRefreshRate, CurrentBitsPerPixel"), IDS_DISPLAY1, TRUE, TRUE),
  77. CSimpleQuery(QUERY_INFRARED, _T("Win32_InfraredDevice"), _T("Caption"), IDS_INFRARED1, TRUE, TRUE),
  78. CSimpleQuery(QUERY_PARALLEL, _T("Win32_ParallelPort"), _T("Name, MSIAdvancedPNPDeviceID"), IDS_PARALLEL1, TRUE, TRUE),
  79. CSimpleQuery(QUERY_PRINTER, _T("Win32_Printer"), _T("Name, DriverName, PortName, ServerName"), IDS_PRINTER1, FALSE),
  80. CSimpleQuery(QUERY_NETCONNECTION, _T("Win32_NetworkConnection"), _T("LocalName, RemoteName, ResourceType, ConnectionType, UserName"), IDS_NETCONNECTION1, FALSE),
  81. CSimpleQuery(QUERY_DRIVER, _T("Win32_SystemDriver"), _T("Name, Description, PathName, ServiceType, Started, StartMode, State, Status, ErrorControl, AcceptPause, AcceptStop"), IDS_DRIVER1, FALSE),
  82. CSimpleQuery(QUERY_SIGNEDDRIVER, _T("Win32_PnPSignedDriver"), _T("DeviceName, IsSigned, DeviceClass, DriverVersion, DriverDate, Manufacturer, InfName, DriverName, DeviceID"), IDS_SIGNEDDRIVER1, FALSE),
  83. CSimpleQuery(QUERY_IDE, _T("Win32_IDEController"), _T("Caption, Manufacturer, Status, PNPDeviceID"), IDS_IDE1, TRUE, TRUE),
  84. CSimpleQuery(QUERY_SCSI, _T("Win32_SCSIController"), _T("Caption, Manufacturer, Status, MSIAdvancedPNPDeviceID"), IDS_SCSI1, TRUE, TRUE),
  85. CSimpleQuery(QUERY_PRINTJOBS, _T("Win32_PrintJob"), _T("Document, Size, Owner, Notify, Status, TimeSubmitted, StartTime, UntilTime, ElapsedTime, PagesPrinted, JobId, Priority, Parameters, DriverName, PrintProcessor, HostPrintQueue, DataType, Name"), IDS_PRINTJOBS1, FALSE),
  86. CSimpleQuery(0, _T(""), _T(""), 0)
  87. };
  88. //-----------------------------------------------------------------------------
  89. // The refresh function which processes the simple query. The correct query
  90. // is found in the query array. For each instance of the class, the column
  91. // data will be inserted into the array of column values, and the format
  92. // flags will be replaced with the actual data.
  93. //-----------------------------------------------------------------------------
  94. BOOL ProcessColumnString(CMSIValue * pValue, CWMIObject * pObject, CString * pstrProperties);
  95. BOOL GetResourcesFromPNPID(CWMIHelper * pWMI, CResourceMap * pResourceMap, LPCTSTR szPNPID, CPtrList * aColValues);
  96. HRESULT NetAdapter(CWMIHelper * pWMI, volatile BOOL * pfCancel, CPtrList * aColValues, int iColCount, CResourceMap * pResourceMap);
  97. HRESULT SerialPort(CWMIHelper * pWMI, volatile BOOL * pfCancel, CPtrList * aColValues, int iColCount, CResourceMap * pResourceMap);
  98. HRESULT SimpleQuery(CWMIHelper * pWMI, DWORD dwIndex, volatile BOOL * pfCancel, CPtrList * aColValues, int iColCount, void ** ppCache)
  99. {
  100. HRESULT hr = S_OK;
  101. // Find the correct query.
  102. CSimpleQuery * pQuery = aSimpleQueries;
  103. while (pQuery->m_dwIndex && pQuery->m_dwIndex != dwIndex)
  104. pQuery++;
  105. if (pQuery->m_dwIndex != dwIndex && dwIndex != QUERY_NETADAPTER && dwIndex != QUERY_SERIALPORT)
  106. {
  107. ASSERT(0 && "bad dwIndex to SimpleQuery()");
  108. return E_FAIL;
  109. }
  110. // Make sure we have a resource map (or can create one).
  111. if (ppCache)
  112. {
  113. if (pWMI && *ppCache == NULL)
  114. {
  115. *ppCache = (void *) new CResourceMap;
  116. if (*ppCache)
  117. {
  118. hr = ((CResourceMap *) *ppCache)->Initialize(pWMI);
  119. if (FAILED(hr))
  120. {
  121. delete ((CResourceMap *) *ppCache);
  122. *ppCache = (void *) NULL;
  123. }
  124. }
  125. }
  126. else if (pWMI == NULL && *ppCache)
  127. {
  128. delete ((CResourceMap *) *ppCache);
  129. return S_OK;
  130. }
  131. }
  132. CResourceMap * pResourceMap = (CResourceMap *) *ppCache;
  133. // This is a nice way to cache to resource map for multiple functions, but it's
  134. // a monumental pain when we remote to a different machine:
  135. //
  136. // CResourceMap * pResourceMap = gResourceMap.GetResourceMap(pWMI);
  137. // if (pResourceMap == NULL)
  138. // return hr;
  139. // Check to see if this is one of the special case queries.
  140. if (dwIndex == QUERY_NETADAPTER)
  141. return NetAdapter(pWMI, pfCancel, aColValues, iColCount, pResourceMap);
  142. if (dwIndex == QUERY_SERIALPORT)
  143. return SerialPort(pWMI, pfCancel, aColValues, iColCount, pResourceMap);
  144. // Enumerate the requested class.
  145. CWMIObjectCollection * pCollection = NULL;
  146. hr = pWMI->Enumerate(pQuery->m_strClass, &pCollection, pQuery->m_strProperties);
  147. if (SUCCEEDED(hr))
  148. {
  149. CWMIObject * pObject = NULL;
  150. while (S_OK == pCollection->GetNext(&pObject))
  151. {
  152. CString strProperties = pQuery->m_strProperties;
  153. // If this is the second or later iteration, then we should add a blank
  154. // set of entries to the columns.
  155. if (pQuery->m_fBlankDividers)
  156. pWMI->AppendBlankLine(aColValues, iColCount);
  157. pWMI->AddObjectToOutput(aColValues, iColCount, pObject, strProperties, pQuery->m_uiColumns);
  158. // If so marked, we should see what resources (drivers, IRQs, etc.) are
  159. // associated with this object and add them to the list.
  160. if (pQuery->m_fShowResources)
  161. {
  162. ASSERT(iColCount == 2);
  163. CString strPNPID = pObject->GetString(_T("PNPDeviceID"));
  164. if (!strPNPID.IsEmpty())
  165. GetResourcesFromPNPID(pWMI, pResourceMap, strPNPID, aColValues);
  166. }
  167. }
  168. delete pObject;
  169. delete pCollection;
  170. }
  171. return hr;
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Given a resource map and a PNP ID string, this function will add all the
  175. // resources used by that PNP device (IRQs, drivers, etc.) to a two column
  176. // array of string lists.
  177. //-----------------------------------------------------------------------------
  178. BOOL GetResourcesFromPNPID(CWMIHelper * pWMI, CResourceMap * pResourceMap, LPCTSTR szPNPID, CPtrList * aColValues)
  179. {
  180. CString strPath, strResourcePath;
  181. CString strPNPDeviceID(szPNPID);
  182. StringReplace(strPNPDeviceID, _T("\\"), _T("\\\\"));
  183. strPath.Format(_T("Win32_PnPEntity.DeviceID=\"%s\""), strPNPDeviceID);
  184. CStringList * pResourceList = pResourceMap->Lookup(strPath);
  185. if (pResourceList)
  186. {
  187. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  188. for (POSITION pos = pResourceList->GetHeadPosition(); pos != NULL;)
  189. {
  190. strResourcePath = pResourceList->GetNext(pos);
  191. CWMIObject * pResourceObject;
  192. if (SUCCEEDED(pWMI->GetObject(strResourcePath, &pResourceObject)))
  193. {
  194. CString strClass;
  195. if (SUCCEEDED(pResourceObject->GetValueString(_T("__CLASS"), &strClass)))
  196. {
  197. CString strItem;
  198. if (strClass == _T("Win32_IRQResource"))
  199. strItem.LoadString(IDS_IRQCHANNEL);
  200. else if (strClass == _T("Win32_PortResource"))
  201. strItem.LoadString(IDS_IOPORT);
  202. else if (strClass == _T("Win32_DMAChannel"))
  203. strItem.LoadString(IDS_DMACHANNEL);
  204. else if (strClass == _T("Win32_DeviceMemoryAddress"))
  205. strItem.LoadString(IDS_MEMORYADDRESS);
  206. else if (strClass == _T("CIM_DataFile"))
  207. strItem.LoadString(IDS_DRIVER);
  208. if (!strItem.IsEmpty())
  209. {
  210. CString strValue;
  211. if (SUCCEEDED(pResourceObject->GetValueString(_T("Caption"), &strValue)))
  212. {
  213. if (strClass == _T("CIM_DataFile"))
  214. {
  215. CString strVersion, strDate, strSize;
  216. pResourceObject->GetInterpretedValue(_T("FileSize"), _T("%z"), _T('z'), &strSize, NULL);
  217. pResourceObject->GetValueString(_T("Version"), &strVersion);
  218. pResourceObject->GetInterpretedValue(_T("CreationDate"), _T("%t"), _T('t'), &strDate, NULL);
  219. if (!strVersion.IsEmpty() || !strDate.IsEmpty() || !strSize.IsEmpty())
  220. strValue += CString(_T(" (")) + strVersion + CString(_T(", ")) + strSize + CString(_T(", ")) + strDate + CString(_T(")"));
  221. }
  222. pWMI->AppendCell(aColValues[0], strItem, 0);
  223. pWMI->AppendCell(aColValues[1], strValue, 0);
  224. }
  225. }
  226. }
  227. delete pResourceObject;
  228. } // if we could get the object
  229. } // for enumerating through the list
  230. } // if there is a list
  231. return TRUE;
  232. }
  233. //-----------------------------------------------------------------------------
  234. // The specific query for the network adapter class.
  235. //-----------------------------------------------------------------------------
  236. HRESULT NetAdapter(CWMIHelper * pWMI, volatile BOOL * pfCancel, CPtrList * aColValues, int iColCount, CResourceMap * pResourceMap)
  237. {
  238. HRESULT hr = S_OK;
  239. LPCTSTR szNetworkAdapterProperties = _T("Caption, AdapterType, MSIAdvancedProductName, MSIAdvancedInstalled, MSIAdvancedPNPDeviceID, MSIAdvancedTimeOfLastReset, MSIAdvancedIndex");
  240. LPCTSTR szNetworkAdapterConfigProperties = _T("ServiceName, IPAddress, IPSubnet, DefaultIPGateway, DHCPEnabled, MSIAdvancedDHCPServer, MSIAdvancedDHCPLeaseExpires, MSIAdvancedDHCPLeaseObtained, MACAddress, Index");
  241. CPtrList listNetAdapterConfig;
  242. CWMIObjectCollection * pCollection = NULL;
  243. hr = pWMI->Enumerate(_T("Win32_NetworkAdapter"), &pCollection, szNetworkAdapterProperties);
  244. if (SUCCEEDED(hr))
  245. {
  246. CWMIObject * pObject = NULL;
  247. while (S_OK == pCollection->GetNext(&pObject))
  248. {
  249. pWMI->AppendBlankLine(aColValues, iColCount);
  250. pWMI->AddObjectToOutput(aColValues, iColCount, pObject, szNetworkAdapterProperties, IDS_NETWORKADAPTER1);
  251. DWORD dwIndex;
  252. if (SUCCEEDED(pObject->GetValueDWORD(_T("Index"), &dwIndex)))
  253. {
  254. if (listNetAdapterConfig.IsEmpty())
  255. {
  256. // Enumerate the class and cache the objects.
  257. CWMIObjectCollection * pConfigCollection = NULL;
  258. if (SUCCEEDED(pWMI->Enumerate(_T("Win32_NetworkAdapterConfiguration"), &pConfigCollection, szNetworkAdapterConfigProperties)))
  259. {
  260. CWMIObject * pConfigObject = NULL;
  261. while (S_OK == pConfigCollection->GetNext(&pConfigObject))
  262. {
  263. DWORD dwConfigIndex;
  264. if (SUCCEEDED(pConfigObject->GetValueDWORD(_T("Index"), &dwConfigIndex)))
  265. if (dwConfigIndex == dwIndex)
  266. pWMI->AddObjectToOutput(aColValues, iColCount, pConfigObject, szNetworkAdapterConfigProperties, IDS_NETWORKADAPTER2);
  267. listNetAdapterConfig.AddTail((void *)pConfigObject);
  268. pConfigObject = NULL;
  269. }
  270. delete pConfigObject;
  271. delete pConfigCollection;
  272. }
  273. }
  274. else
  275. {
  276. // Look through the list of cached objects.
  277. for (POSITION pos = listNetAdapterConfig.GetHeadPosition(); pos != NULL;)
  278. {
  279. CWMIObject * pConfigObject = (CWMIObject *)listNetAdapterConfig.GetNext(pos);
  280. DWORD dwConfigIndex;
  281. if (pConfigObject && SUCCEEDED(pConfigObject->GetValueDWORD(_T("Index"), &dwConfigIndex)))
  282. if (dwConfigIndex == dwIndex)
  283. pWMI->AddObjectToOutput(aColValues, iColCount, pConfigObject, szNetworkAdapterConfigProperties, IDS_NETWORKADAPTER2);
  284. }
  285. }
  286. }
  287. CString strPNPID = pObject->GetString(_T("PNPDeviceID"));
  288. if (!strPNPID.IsEmpty())
  289. GetResourcesFromPNPID(pWMI, pResourceMap, strPNPID, aColValues);
  290. }
  291. delete pObject;
  292. delete pCollection;
  293. while (!listNetAdapterConfig.IsEmpty())
  294. {
  295. CWMIObject * pDeleteObject = (CWMIObject *)listNetAdapterConfig.RemoveHead();
  296. if (pDeleteObject)
  297. delete pDeleteObject;
  298. }
  299. }
  300. return hr;
  301. }
  302. //-----------------------------------------------------------------------------
  303. // The specific query for the serial port class.
  304. //
  305. // TBD - cache the config values to save re-enumerating.
  306. //-----------------------------------------------------------------------------
  307. HRESULT SerialPort(CWMIHelper * pWMI, volatile BOOL * pfCancel, CPtrList * aColValues, int iColCount, CResourceMap * pResourceMap)
  308. {
  309. HRESULT hr = S_OK;
  310. LPCTSTR szSerialPortProperties = _T("Name, Status, MSIAdvancedPNPDeviceID, MSIAdvancedMaximumInputBufferSize, MSIAdvancedMaximumOutputBufferSize, MSIAdvancedSettableBaudRate, MSIAdvancedSettableDataBits, MSIAdvancedSettableFlowControl, MSIAdvancedSettableParity, MSIAdvancedSettableParityCheck, MSIAdvancedSettableStopBits, MSIAdvancedSettableRLSD, MSIAdvancedSupportsRLSD, MSIAdvancedSupports16BitMode, MSIAdvancedSupportsSpecialCharacters, MSIAdvancedDeviceID");
  311. LPCTSTR szSerialPortConfigProperties = _T("BaudRate, BitsPerByte, StopBits, Parity, IsBusy, MSIAdvancedAbortReadWriteOnError, MSIAdvancedBinaryModeEnabled, MSIAdvancedContinueXMitOnXOff, MSIAdvancedCTSOutflowControl, MSIAdvancedDiscardNULLBytes, MSIAdvancedDSROutflowControl, MSIAdvancedDSRSensitivity, MSIAdvancedDTRFlowControlType, MSIAdvancedEOFCharacter, MSIAdvancedErrorReplaceCharacter, MSIAdvancedErrorReplacementEnabled, MSIAdvancedEventCharacter, MSIAdvancedParityCheckEnabled, MSIAdvancedRTSFlowControlType, MSIAdvancedXOffCharacter, MSIAdvancedXOffXMitThreshold, MSIAdvancedXOnCharacter, MSIAdvancedXOnXMitThreshold, MSIAdvancedXOnXOffInFlowControl, MSIAdvancedXOnXOffOutFlowControl, Name");
  312. CWMIObjectCollection * pCollection = NULL;
  313. hr = pWMI->Enumerate(_T("Win32_SerialPort"), &pCollection, szSerialPortProperties);
  314. if (SUCCEEDED(hr))
  315. {
  316. CWMIObject * pObject = NULL;
  317. while (S_OK == pCollection->GetNext(&pObject))
  318. {
  319. pWMI->AppendBlankLine(aColValues, iColCount);
  320. pWMI->AddObjectToOutput(aColValues, iColCount, pObject, szSerialPortProperties, IDS_SERIALPORT1);
  321. CString strDeviceID;
  322. if (SUCCEEDED(pObject->GetValueString(_T("DeviceID"), &strDeviceID)))
  323. {
  324. CWMIObjectCollection * pConfigCollection = NULL;
  325. if (SUCCEEDED(pWMI->Enumerate(_T("Win32_SerialPortConfiguration"), &pConfigCollection, szSerialPortConfigProperties)))
  326. {
  327. CWMIObject * pConfigObject = NULL;
  328. while (S_OK == pConfigCollection->GetNext(&pConfigObject))
  329. {
  330. CString strConfigDeviceID;
  331. if (SUCCEEDED(pConfigObject->GetValueString(_T("Name"), &strConfigDeviceID)))
  332. if (strDeviceID.CompareNoCase(strConfigDeviceID) == 0)
  333. pWMI->AddObjectToOutput(aColValues, iColCount, pConfigObject, szSerialPortConfigProperties, IDS_SERIALPORT2);
  334. }
  335. delete pConfigObject;
  336. delete pConfigCollection;
  337. }
  338. }
  339. CString strPNPID = pObject->GetString(_T("PNPDeviceID"));
  340. if (!strPNPID.IsEmpty())
  341. GetResourcesFromPNPID(pWMI, pResourceMap, strPNPID, aColValues);
  342. }
  343. delete pObject;
  344. delete pCollection;
  345. }
  346. return hr;
  347. }