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.

817 lines
23 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1999.
  5. //
  6. // File: E C O M P . C P P
  7. //
  8. // Contents: Implements the interface to a component's external data.
  9. // External data is that data controlled (or placed) by
  10. // PnP or the network class installer. Everything under a
  11. // component's instance key is considered external data.
  12. // (Internal data is that data we store in the persisted binary
  13. // for the network configuration. See persist.cpp for
  14. // code that deals with internal data.)
  15. //
  16. // Notes:
  17. //
  18. // Author: shaunco 15 Jan 1999
  19. //
  20. //----------------------------------------------------------------------------
  21. #include <pch.h>
  22. #pragma hdrstop
  23. #include "comp.h"
  24. #include "ncsetup.h"
  25. #include "util.h"
  26. // constants
  27. const WCHAR c_szHelpText[] = L"HelpText";
  28. //+---------------------------------------------------------------------------
  29. //
  30. // Function: HrBuildBindNameFromBindForm
  31. //
  32. // Purpose: Build a bindname from a bindform and component parameters.
  33. //
  34. // Arguments:
  35. // pszBindForm [in] The components bindform. This is read from
  36. // the Ndi key. If the component did not specify
  37. // it in its Ndi key, pass NULL.
  38. // Class [in] The class of the component.
  39. // dwCharacteristics [in] The characteristics of the component.
  40. // pszServiceName [in] The components service name.
  41. // pszInfId [in] The component (device) id.
  42. // szInstanceGuid [in] The instance GUID of the component.
  43. // ppszBindName [out] The returned bind string. This must be freed
  44. // with LocalFree.
  45. //
  46. // Returns: HRESULT
  47. //
  48. // Author: shaunco 6 Jun 1997
  49. // Modified: ckotze 21 Dec 2000
  50. //
  51. // Notes: The bindform contains replaceable parameters designed to
  52. // be used with the FormatMessage API.
  53. // %1 = pszServiceName
  54. // %2 = pszInfId
  55. // %3 = szInstanceGuid
  56. //
  57. HRESULT
  58. HrBuildBindNameFromBindForm (
  59. IN PCWSTR pszBindForm,
  60. IN NETCLASS Class,
  61. IN DWORD dwCharacteristics,
  62. IN PCWSTR pszServiceName,
  63. IN PCWSTR pszInfId,
  64. IN const GUID& InstanceGuid,
  65. OUT PWSTR* ppszBindName)
  66. {
  67. static const WCHAR c_szBindFormNet [] = L"%3";
  68. static const WCHAR c_szBindFormNoService [] = L"%2";
  69. static const WCHAR c_szBindFormDefault [] = L"%1";
  70. WCHAR szInstanceGuid [c_cchGuidWithTerm];
  71. INT cch;
  72. DWORD dwRet = 0;
  73. HRESULT hr = S_OK;
  74. Assert (ppszBindName);
  75. Assert (FIsValidNetClass(Class));
  76. cch = StringFromGUID2 (
  77. InstanceGuid,
  78. szInstanceGuid,
  79. c_cchGuidWithTerm);
  80. Assert (c_cchGuidWithTerm == cch);
  81. if (FIsPhysicalAdapter(Class, dwCharacteristics))
  82. {
  83. // netcards use the the instance guid only
  84. // We disregard any bind form sent in.
  85. Assert (szInstanceGuid && *szInstanceGuid);
  86. pszBindForm = c_szBindFormNet;
  87. }
  88. else if (!pszBindForm || !*pszBindForm)
  89. {
  90. // Figure out which bindform to use since it wasn't specified.
  91. //
  92. if (FIsEnumerated(Class))
  93. {
  94. // Virtual adapters use the the instance guid only
  95. Assert (szInstanceGuid && *szInstanceGuid);
  96. pszBindForm = c_szBindFormNet;
  97. }
  98. else if (pszServiceName && *pszServiceName)
  99. {
  100. // use the service name if we have one
  101. pszBindForm = c_szBindFormDefault;
  102. }
  103. else
  104. {
  105. // if no service, then use the component id
  106. Assert (pszInfId && *pszInfId);
  107. pszBindForm = c_szBindFormNoService;
  108. }
  109. }
  110. AssertSz (pszBindForm && *pszBindForm, "Should have pszBindForm by now.");
  111. // dwRet is either 0 or the number of chars in the resulting string. Since
  112. // *ppszBindName is either NULL or a valid string, we get the last error if it's
  113. // a NULL and ignore dwRet.
  114. dwRet = DwFormatStringWithLocalAlloc (
  115. pszBindForm, ppszBindName,
  116. pszServiceName, pszInfId, szInstanceGuid);
  117. if (*ppszBindName)
  118. {
  119. // Underscores are not allowed in the bind name so make a pass
  120. // to remove them.
  121. //
  122. PWSTR pszScan = *ppszBindName;
  123. while (NULL != (pszScan = wcschr (pszScan, L'_')))
  124. {
  125. wcscpy (pszScan, pszScan + 1);
  126. }
  127. }
  128. else
  129. {
  130. DWORD dwErr = GetLastError();
  131. hr = HRESULT_FROM_WIN32(dwErr);
  132. }
  133. AssertSz (*ppszBindName,
  134. "BuildBindNameFromBindForm: DwFormatStringWithLocalAlloc failed.");
  135. return hr;
  136. }
  137. //+---------------------------------------------------------------------------
  138. //
  139. // Function: NcLoadRegUIString
  140. //
  141. // Purpose: Wrapper around SHLoadRegUIString, which is used to support MUI.
  142. //
  143. // Arguments: same as RegQueryValueEx with lpReserved and lpType removed
  144. //
  145. // Returns: If the function succeeds, the return value is ERROR_SUCCESS
  146. //
  147. // Notes: SHLoadRegUIString will read a string of the form
  148. //
  149. // @[path\]<dllname>,-<strId>
  150. //
  151. // The string with id <strId> is loaded from <dllname>. If no explicit
  152. // path is provided then the DLL will be chosen according to pluggable UI
  153. // specifications, if possible.
  154. //
  155. // If the registry string is not of the special form described here,
  156. // SHLoadRegUIString will return the string intact.
  157. //
  158. //
  159. LONG NcLoadRegUIString (
  160. IN HKEY hkey,
  161. IN PCWSTR lpValueName,
  162. IN OUT LPBYTE lpData OPTIONAL,
  163. IN OUT LPDWORD lpcbData)
  164. {
  165. const DWORD cchGrow = 256; // grows at 256 of WCHAR a time
  166. DWORD cchBuffer = 0; // buffer size in number of WCHAR
  167. HRESULT hr = S_OK;
  168. LONG lr = ERROR_SUCCESS;
  169. LPWSTR pwszBuffer = NULL; // buffer for the WCHAR string
  170. DWORD cbBuffer = 0; // the real buffer size in bytes
  171. if ( (NULL == hkey) || (NULL == lpValueName) )
  172. {
  173. return ERROR_BAD_ARGUMENTS;
  174. }
  175. // The lpcbData parameter can be NULL only if lpData is NULL.
  176. if ( (NULL == lpcbData) && (NULL != lpData) )
  177. {
  178. return ERROR_BAD_ARGUMENTS;
  179. }
  180. if ( (NULL == lpcbData) && (lpData == NULL) )
  181. {
  182. // no operation
  183. return ERROR_SUCCESS;
  184. }
  185. Assert (lpcbData);
  186. if ( (*lpcbData > 0) && lpData && IsBadWritePtr(lpData, *lpcbData))
  187. {
  188. return ERROR_BAD_ARGUMENTS;
  189. }
  190. do
  191. {
  192. if (pwszBuffer)
  193. {
  194. // free the last allocated buffer
  195. MemFree((LPVOID) pwszBuffer);
  196. }
  197. // allocate a larger buffer for the string
  198. cchBuffer += cchGrow;
  199. pwszBuffer = (LPWSTR) MemAlloc (cchBuffer * sizeof(WCHAR));
  200. if (pwszBuffer == NULL)
  201. {
  202. return (ERROR_OUTOFMEMORY);
  203. }
  204. // load the MUI enabled string from the registry
  205. // NOTE: for the buffer size, this API takes number of characters including NULL
  206. // character, not number of bytes for the buffer.
  207. // SHLoadRegUIStringW(HKEY hkey, LPCWSTR pszValue, IN OUT LPWSTR pszOutBuf, IN UINT cchOutBuf)
  208. hr = SHLoadRegUIStringW (hkey, lpValueName, (LPWSTR)pwszBuffer, cchBuffer);
  209. if (FAILED(hr))
  210. {
  211. lr = ERROR_FUNCTION_FAILED;
  212. goto Exit;
  213. }
  214. // Unfortunately, SHLoadRegUIString doesn't have a way to query the
  215. // buffer size, so we assume more data available. We'll loop around,
  216. // grow the buffer, and try again.
  217. } while ( wcslen(pwszBuffer) == (cchBuffer - 1) ); // retry if the last buffer is fully used
  218. Assert (ERROR_SUCCESS == lr);
  219. // the actual buffer size requirement in bytes
  220. cbBuffer = (wcslen(pwszBuffer) + 1 ) * sizeof(WCHAR);
  221. // If lpData is NULL, and lpcbData is non-NULL, the function returns ERROR_SUCCESS,
  222. // and stores the size of the data, in bytes, in the variable pointed to by lpcbData.
  223. // This lets an application determine the best way to allocate a buffer for
  224. // the value's data.
  225. if ( (NULL == lpData) && lpcbData )
  226. {
  227. *lpcbData = cbBuffer;
  228. goto Exit;
  229. }
  230. // If the buffer specified by lpData parameter is not large enough to hold the data,
  231. // the function returns the value ERROR_MORE_DATA, and stores the required buffer size,
  232. // in bytes, into the variable pointed to by lpcbData. In this case, the contents of
  233. // the lpValue buffer are undefined.
  234. if (cbBuffer > *lpcbData)
  235. {
  236. *lpcbData = cbBuffer;
  237. lr = ERROR_MORE_DATA;
  238. goto Exit;
  239. }
  240. // transfer values
  241. *lpcbData = cbBuffer;
  242. if (lpData)
  243. {
  244. CopyMemory(lpData, (LPBYTE) pwszBuffer, cbBuffer);
  245. }
  246. Exit:
  247. if (pwszBuffer)
  248. {
  249. MemFree((LPVOID) pwszBuffer);
  250. }
  251. return (lr);
  252. }
  253. //
  254. // Query a value from the registry and ensure it is of the type we expect
  255. // it to be. When calling RegQueryValueEx, we don't care to know what
  256. // the type is, only to know if it doesn't match what we expect it to be.
  257. // If the value is not of dwType, return ERROR_INVALID_DATATYPE.
  258. //
  259. LONG
  260. RegQueryValueType (
  261. IN HKEY hkey,
  262. IN PCWSTR pszValueName,
  263. IN DWORD dwType,
  264. OUT BYTE* pbData OPTIONAL,
  265. IN OUT DWORD* pcbData)
  266. {
  267. LONG lr;
  268. DWORD dwTypeQueried;
  269. lr = RegQueryValueExW (hkey, pszValueName, NULL, &dwTypeQueried, pbData, pcbData);
  270. if (!lr && (dwType != dwTypeQueried))
  271. {
  272. lr = ERROR_INVALID_DATATYPE;
  273. }
  274. return lr;
  275. }
  276. //
  277. // Read a REG_SZ that is expected to represent a GUID and convert it
  278. // to its GUID representation. If the value does not seem to be a GUID,
  279. // return ERROR_INVALID_DATATYPE.
  280. //
  281. // hkey is the parent key to read from and pszValueName is the name of the
  282. // value whose data is expected to be a GUID in string form.
  283. // pguidData points to a buffer to receive the GUID. If pguidData is NULL,
  284. // no data will be returned, but the size of the buffer required will be
  285. // stored at the DWORD pointed to by pcbData.
  286. //
  287. // On input, *pcbData is the size (in bytes) of the buffer pointed to
  288. // by pguidData. On output, *pcbData is the size (in bytes) required to hold
  289. // the data.
  290. //
  291. LONG
  292. RegQueryGuid (
  293. IN HKEY hkey,
  294. IN PCWSTR pszValueName,
  295. OUT GUID* pguidData OPTIONAL,
  296. IN OUT DWORD* pcbData
  297. )
  298. {
  299. LONG lr;
  300. HRESULT hr;
  301. WCHAR szGuid [c_cchGuidWithTerm];
  302. DWORD cbDataIn;
  303. DWORD cbData;
  304. Assert (pcbData);
  305. cbDataIn = *pcbData;
  306. *pcbData = 0;
  307. // Get the string form of the guid and store it in szGuid.
  308. //
  309. cbData = sizeof (szGuid);
  310. lr = RegQueryValueType (hkey, pszValueName, REG_SZ, (PBYTE)szGuid, &cbData);
  311. if (!lr)
  312. {
  313. GUID guid;
  314. // Convert the string to a GUID. If this fails, the data is invalid
  315. // and we will return such.
  316. //
  317. hr = IIDFromString (szGuid, &guid);
  318. if (S_OK != hr)
  319. {
  320. lr = ERROR_INVALID_DATATYPE;
  321. }
  322. if (!lr)
  323. {
  324. // The data looks to be a GUID, so we'll return the size
  325. // and the data if the caller wants it.
  326. //
  327. *pcbData = sizeof(GUID);
  328. if (pguidData)
  329. {
  330. if (cbDataIn >= sizeof(GUID))
  331. {
  332. *pguidData = guid;
  333. }
  334. else
  335. {
  336. lr = ERROR_MORE_DATA;
  337. }
  338. }
  339. }
  340. }
  341. // If querying for the string form of the guid returned ERROR_MORE_DATA,
  342. // it means that the data is not a GUID.
  343. //
  344. else if (ERROR_MORE_DATA == lr)
  345. {
  346. lr = ERROR_INVALID_DATATYPE;
  347. }
  348. return lr;
  349. }
  350. // Used as input to RegQueryValues.
  351. //
  352. struct REGVALINFO
  353. {
  354. // The name of the subkey under which this registry value lives.
  355. // Set this to NULL if this registry value lives under the same key
  356. // as the previous registry value in the array of this structure.
  357. //
  358. PCWSTR pszSubkey;
  359. // The name of the registry value.
  360. //
  361. PCWSTR pszValueName;
  362. // The type of the registry value. One of REG_SZ, REG_DWORD, etc.
  363. // REG_GUID is also supported.
  364. //
  365. DWORD dwType;
  366. // The byte offset of the output pointer within the pbPointers
  367. // array to store the pointer to the queried data.
  368. //
  369. UINT cbOffset;
  370. };
  371. #define REG_GUID ((DWORD)-5)
  372. //
  373. // Query a batch of values from the registry. The number of values to query
  374. // is given by cValues. Information about the values is given through
  375. // an array of REGVALINFO structures. The data for the values is stored
  376. // in the caller-supplied buffer pointed to by pbBuf. The caller also
  377. // supplies an array of pointers which will be set to point within pbBuf
  378. // to the data for each value. This array is must also have cValues elements.
  379. //
  380. // If a value does not exist, its corresponding pointer value in the
  381. // pbPointers array is set to NULL. This allows the caller to know whether
  382. // the value existed or not.
  383. //
  384. LONG
  385. RegQueryValues (
  386. IN HKEY hkeyRoot,
  387. IN ULONG cValues,
  388. IN const REGVALINFO* aValueInfo,
  389. OUT BYTE* pbPointers,
  390. OUT BYTE* pbBuf OPTIONAL,
  391. IN OUT ULONG* pcbBuf)
  392. {
  393. LONG lr;
  394. ULONG cbBufIn;
  395. ULONG cbBufRequired;
  396. ULONG cbData;
  397. ULONG cbPad;
  398. BYTE *pData;
  399. const REGVALINFO* pInfo;
  400. HKEY hkey;
  401. HRESULT hr;
  402. Assert (hkeyRoot);
  403. Assert (pcbBuf);
  404. Assert (((ULONG_PTR)pbBuf & (sizeof(PVOID)-1)) == 0);
  405. // On input, *pcbBuf is the number of bytes available in pbBuf.
  406. //
  407. cbBufIn = *pcbBuf;
  408. cbBufRequired = 0;
  409. hkey = hkeyRoot;
  410. for (pInfo = aValueInfo; cValues; pInfo++, cValues--)
  411. {
  412. // Make sure we have the hkey we want.
  413. //
  414. if (pInfo->pszSubkey)
  415. {
  416. if (hkey != hkeyRoot)
  417. {
  418. RegCloseKey (hkey);
  419. }
  420. lr = RegOpenKeyEx (hkeyRoot, pInfo->pszSubkey, 0, KEY_READ, &hkey);
  421. if (lr)
  422. {
  423. continue;
  424. }
  425. }
  426. cbPad = cbBufRequired & (sizeof(PVOID)-1);
  427. if (cbPad !=0) {
  428. //
  429. // The current buffer offset is misaligned. Increment it so that
  430. // it is properly aligned.
  431. //
  432. cbPad = sizeof(PVOID) - cbPad;
  433. cbBufRequired += cbPad;
  434. }
  435. if (pbBuf != NULL) {
  436. //
  437. // The caller supplied a buffer, so calculate a pointer to the
  438. // current position within it.
  439. //
  440. pData = pbBuf + cbBufRequired;
  441. } else {
  442. pData = NULL;
  443. }
  444. //
  445. // Set cbData to the amount of data remaining in the buffer.
  446. //
  447. if (cbBufIn > cbBufRequired) {
  448. cbData = cbBufIn - cbBufRequired;
  449. } else {
  450. //
  451. // No room left, pass in a NULL buffer pointer too.
  452. //
  453. cbData = 0;
  454. pData = NULL;
  455. }
  456. //
  457. // Perform the query based on the desired type.
  458. //
  459. if (REG_GUID == pInfo->dwType)
  460. {
  461. lr = RegQueryGuid (hkey, pInfo->pszValueName, (GUID*)pData, &cbData);
  462. }
  463. else if ( (REG_SZ == pInfo->dwType) && (!wcscmp(pInfo->pszValueName, c_szHelpText)) )
  464. {
  465. // Bug# 310358, load MUI string if necessary
  466. lr = NcLoadRegUIString(hkey, pInfo->pszValueName, pData, &cbData);
  467. }
  468. else
  469. {
  470. lr = RegQueryValueType (hkey, pInfo->pszValueName,
  471. pInfo->dwType, pData, &cbData);
  472. }
  473. if (ERROR_SUCCESS == lr || ERROR_MORE_DATA == lr) {
  474. //
  475. // cbData contains the amount of data that is available. Update
  476. // the buffer size required to contain all of the data.
  477. //
  478. cbBufRequired += cbData;
  479. } else {
  480. //
  481. // The call failed for some reason other than ERROR_MORE_DATA,
  482. // back out the alignment padding from cbBufRequired.
  483. //
  484. cbBufRequired -= cbPad;
  485. }
  486. if (ERROR_SUCCESS == lr && pData != NULL) {
  487. //
  488. // Data was retrieved into our buffer. Store the pointer to the
  489. // data.
  490. //
  491. *((BYTE**)(pbPointers + pInfo->cbOffset)) = pData;
  492. }
  493. }
  494. if (hkey != hkeyRoot)
  495. {
  496. RegCloseKey (hkey);
  497. }
  498. *pcbBuf = cbBufRequired;
  499. if (cbBufRequired <= cbBufIn)
  500. {
  501. lr = ERROR_SUCCESS;
  502. }
  503. else
  504. {
  505. lr = (pbBuf) ? ERROR_MORE_DATA : ERROR_SUCCESS;
  506. }
  507. return lr;
  508. }
  509. LONG
  510. RegQueryValuesWithAlloc (
  511. IN HKEY hkeyRoot,
  512. IN ULONG cValues,
  513. IN const REGVALINFO* aValueInfo,
  514. OUT BYTE* pbPointers,
  515. OUT BYTE** ppbBuf,
  516. IN OUT ULONG* pcbBuf)
  517. {
  518. LONG lr;
  519. ULONG cbBuf;
  520. ULONG cbBufConfirm;
  521. *ppbBuf = NULL;
  522. *pcbBuf = 0;
  523. cbBuf = 0;
  524. lr = RegQueryValues (hkeyRoot, cValues, aValueInfo,
  525. pbPointers, NULL, &cbBuf);
  526. if (!lr)
  527. {
  528. BYTE* pbBuf;
  529. lr = ERROR_OUTOFMEMORY;
  530. pbBuf = (BYTE*)MemAlloc (cbBuf);
  531. if (pbBuf)
  532. {
  533. cbBufConfirm = cbBuf;
  534. lr = RegQueryValues (hkeyRoot, cValues, aValueInfo,
  535. pbPointers, pbBuf, &cbBufConfirm);
  536. if (!lr)
  537. {
  538. Assert (cbBufConfirm == cbBuf);
  539. *ppbBuf = pbBuf;
  540. *pcbBuf = cbBuf;
  541. }
  542. else
  543. {
  544. MemFree (pbBuf);
  545. }
  546. }
  547. }
  548. return lr;
  549. }
  550. HRESULT
  551. CExternalComponentData::HrEnsureExternalDataLoaded ()
  552. {
  553. if (m_fInitialized)
  554. {
  555. return m_hrLoadResult;
  556. }
  557. //$PERF: We can selectively prune certain rows out of this table under
  558. // certain conditions. e.g. Enumerated components don't have Clsid or
  559. // CoServices.
  560. //
  561. static const REGVALINFO aValues[] =
  562. {
  563. { NULL, L"Description", REG_SZ, ECD_OFFSET(m_pszDescription) },
  564. { L"Ndi",
  565. L"Clsid", REG_GUID, ECD_OFFSET(m_pNotifyObjectClsid) },
  566. { NULL, L"Service", REG_SZ, ECD_OFFSET(m_pszService) },
  567. { NULL, L"CoServices", REG_MULTI_SZ, ECD_OFFSET(m_pmszCoServices) },
  568. { NULL, L"BindForm", REG_SZ, ECD_OFFSET(m_pszBindForm) },
  569. { NULL, c_szHelpText, REG_SZ, ECD_OFFSET(m_pszHelpText) },
  570. { L"Ndi\\Interfaces",
  571. L"LowerRange", REG_SZ, ECD_OFFSET(m_pszLowerRange) },
  572. { NULL, L"LowerExclude", REG_SZ, ECD_OFFSET(m_pszLowerExclude) },
  573. { NULL, L"UpperRange", REG_SZ, ECD_OFFSET(m_pszUpperRange) },
  574. { NULL, L"FilterMediaTypes",REG_SZ, ECD_OFFSET(m_pszFilterMediaTypes) },
  575. };
  576. // Get our containing component pointer so we can open it's
  577. // instance key.
  578. //
  579. CComponent* pThis;
  580. pThis = CONTAINING_RECORD(this, CComponent, Ext);
  581. // Open the instance key of the component.
  582. //
  583. HRESULT hr;
  584. HKEY hkeyInstance;
  585. HDEVINFO hdi;
  586. SP_DEVINFO_DATA deid;
  587. hr = pThis->HrOpenInstanceKey (KEY_READ, &hkeyInstance, &hdi, &deid);
  588. if (S_OK == hr)
  589. {
  590. LONG lr;
  591. PVOID pvBuf;
  592. ULONG cbBuf;
  593. lr = RegQueryValuesWithAlloc (hkeyInstance, celems(aValues), aValues,
  594. (BYTE*)this, (BYTE**)&pvBuf, &cbBuf);
  595. if (!lr)
  596. {
  597. // Set our buffer markers.
  598. //
  599. m_pvBuffer = pvBuf;
  600. m_pvBufferLast = (BYTE*)pvBuf + cbBuf;
  601. // HrOpenInstanceKey may succeed but return a NULL hdi for
  602. // enumerated components when the real instance key does not
  603. // exist. This happens when the class installer removes the
  604. // instance key and calls us to remove its bindings.
  605. //
  606. if (hdi && FIsEnumerated (pThis->Class()))
  607. {
  608. hr = HrSetupDiGetDeviceName (hdi, &deid,
  609. (PWSTR*)&m_pszDescription);
  610. }
  611. if (S_OK == hr)
  612. {
  613. hr = HrBuildBindNameFromBindForm (
  614. m_pszBindForm,
  615. pThis->Class(),
  616. pThis->m_dwCharacter,
  617. m_pszService,
  618. pThis->m_pszInfId,
  619. pThis->m_InstanceGuid,
  620. (PWSTR*)&m_pszBindName);
  621. }
  622. }
  623. else
  624. {
  625. hr = HRESULT_FROM_WIN32(lr);
  626. ZeroMemory (this, sizeof(*this));
  627. }
  628. SetupDiDestroyDeviceInfoListSafe (hdi);
  629. RegCloseKey (hkeyInstance);
  630. }
  631. // Only perform initialization once, regardless of whether it succeeds
  632. // or not.
  633. //
  634. m_fInitialized = TRUE;
  635. m_hrLoadResult = hr;
  636. TraceHr (ttidError, FAL, m_hrLoadResult, FALSE,
  637. "CExternalComponentData::HrEnsureExternalDataLoaded (%S)",
  638. pThis->PszGetPnpIdOrInfId());
  639. return m_hrLoadResult;
  640. }
  641. BOOL
  642. CExternalComponentData::FLoadedOkayIfLoadedAtAll () const
  643. {
  644. // Because m_hrLoadResult is S_OK even if we are not initialized,
  645. // (i.e. if the component's data is not loaded) we can just check
  646. // m_hrLoadResult without needing to check m_fInitialized.
  647. //
  648. return (S_OK == m_hrLoadResult);
  649. }
  650. VOID
  651. CExternalComponentData::FreeDescription ()
  652. {
  653. // If m_pszDescription is not pointing somewhere in our buffer
  654. // it means it is using a separate allocation. (Because it was
  655. // changed.)
  656. //
  657. if ((m_pszDescription < (PCWSTR)m_pvBuffer) ||
  658. (m_pszDescription > (PCWSTR)m_pvBufferLast))
  659. {
  660. MemFree ((VOID*)m_pszDescription);
  661. }
  662. m_pszDescription = NULL;
  663. }
  664. VOID
  665. CExternalComponentData::FreeExternalData ()
  666. {
  667. LocalFree ((VOID*)m_pszBindName);
  668. FreeDescription();
  669. MemFree (m_pvBuffer);
  670. }
  671. HRESULT
  672. CExternalComponentData::HrReloadExternalData ()
  673. {
  674. HRESULT hr;
  675. FreeExternalData ();
  676. ZeroMemory (this, sizeof(*this));
  677. hr = HrEnsureExternalDataLoaded ();
  678. TraceHr (ttidError, FAL, hr, FALSE,
  679. "CExternalComponentData::HrReloadExternalData");
  680. return hr;
  681. }
  682. HRESULT
  683. CExternalComponentData::HrSetDescription (
  684. PCWSTR pszNewDescription)
  685. {
  686. HRESULT hr;
  687. Assert (pszNewDescription);
  688. FreeDescription();
  689. hr = E_OUTOFMEMORY;
  690. m_pszDescription = (PWSTR)MemAlloc (CbOfSzAndTerm(pszNewDescription));
  691. if (m_pszDescription)
  692. {
  693. wcscpy ((PWSTR)m_pszDescription, pszNewDescription);
  694. hr = S_OK;
  695. }
  696. return hr;
  697. }