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

442 lines
13 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998.
  5. //
  6. // File: F R I E N D L Y . C P P
  7. //
  8. // Contents: Creates indexes for device installs and sets friendly
  9. // name descriptions based on the indexes.
  10. //
  11. // Notes:
  12. //
  13. // Author: billbe 6 Nov 1998
  14. //
  15. //---------------------------------------------------------------------------
  16. #include "pch.h"
  17. #pragma hdrstop
  18. #include "adapter.h"
  19. #include "classinst.h"
  20. #include "ncmsz.h"
  21. #include "ncreg.h"
  22. #include "ncsetup.h"
  23. #include "util.h"
  24. const WCHAR c_szRegValueInstanceIndex[] = L"InstanceIndex";
  25. const DWORD c_cchIndexValueNameLen = 6;
  26. const ULONG c_cMaxDescriptions = 10001; // SetupDi only allows 0-9999
  27. const WCHAR c_szRegKeyDescriptions[] = L"Descriptions";
  28. //+--------------------------------------------------------------------------
  29. //
  30. // Function: HrCiAddNextAvailableIndex
  31. //
  32. // Purpose: Adds the next available index to a multi-sz of indexes.
  33. //
  34. // Arguments:
  35. // pmszIndexesIn [in] MultiSz of current indexes.
  36. // pulIndex [inout] The index added.
  37. // ppmszIndexesOut[out] New multiSz with the added index.
  38. //
  39. // Returns: HRESULT. S_OK is successful, a converted Win32 error otherwise
  40. //
  41. // Author: billbe 30 Oct 1998
  42. //
  43. // Notes:
  44. //
  45. HRESULT
  46. HrCiAddNextAvailableIndex(PWSTR pmszIndexesIn, ULONG* pIndex,
  47. PWSTR* ppmszIndexesOut)
  48. {
  49. Assert(pmszIndexesIn);
  50. Assert(ppmszIndexesOut);
  51. HRESULT hr = S_OK;
  52. WCHAR szIndex[c_cchIndexValueNameLen];
  53. // clear out param.
  54. *ppmszIndexesOut = NULL;
  55. // We are adding a new index. Find the first available
  56. // index.
  57. //
  58. ULONG Index;
  59. ULONG NextIndex;
  60. PWSTR pszStopString;
  61. PWSTR pszCurrentIndex = pmszIndexesIn;
  62. DWORD PositionInMultiSz = 0;
  63. for (NextIndex = 1; NextIndex < c_cMaxDescriptions;
  64. ++NextIndex)
  65. {
  66. Index = wcstoul(pszCurrentIndex, &pszStopString, c_nBase10);
  67. if (Index != NextIndex)
  68. {
  69. // We found an available index. Now we insert it.
  70. //
  71. swprintf(szIndex, L"%u", NextIndex);
  72. BOOL fChanged;
  73. hr = HrAddSzToMultiSz(szIndex, pmszIndexesIn,
  74. STRING_FLAG_ENSURE_AT_INDEX, PositionInMultiSz,
  75. ppmszIndexesOut, &fChanged);
  76. AssertSz(fChanged,
  77. "We were adding a new index. Something had to change!");
  78. break;
  79. }
  80. ++PositionInMultiSz;
  81. // Try the next index.
  82. pszCurrentIndex += wcslen(pszCurrentIndex) + 1;
  83. }
  84. // If we succeeded, set the output param.
  85. if (S_OK == hr)
  86. {
  87. *pIndex = NextIndex;
  88. }
  89. TraceHr (ttidError, FAL, hr, FALSE, "HrCiAddNextAvailableIndex");
  90. return hr;
  91. }
  92. //+--------------------------------------------------------------------------
  93. //
  94. // Function: HrCiCreateAndWaitForIndexListMutex
  95. //
  96. // Purpose: Creates Updates the description map by adding or removing
  97. // entries for pszDescription.
  98. //
  99. // Arguments:
  100. // pszName [in] The name for this mutex.
  101. // phMutex [out] The created mutex.
  102. //
  103. // Returns: HRESULT. S_OK is successful, a converted Win32 error otherwise
  104. //
  105. // Author: billbe 30 Oct 1998
  106. //
  107. // Notes:
  108. //
  109. HRESULT
  110. HrCiCreateAndWaitForIndexListMutex(HANDLE* phMutex)
  111. {
  112. Assert(phMutex);
  113. const WCHAR c_szMutexName[] = L"Global\\{84b06608-8026-11d2-b1f2-00c04fd912b2}";
  114. HRESULT hr = S_OK;
  115. // Create the mutex.
  116. hr = HrCreateMutexWithWorldAccess(c_szMutexName, FALSE,
  117. NULL, phMutex);
  118. if (S_OK == hr)
  119. {
  120. // Wait until the mutex is free or cMaxWaitMilliseconds seconds
  121. // have passed.
  122. //
  123. while (1)
  124. {
  125. const DWORD cMaxWaitMilliseconds = 30000; // 30 seconds
  126. DWORD dwWait = MsgWaitForMultipleObjects (1, phMutex, FALSE,
  127. cMaxWaitMilliseconds, QS_ALLINPUT);
  128. if ((WAIT_OBJECT_0 + 1) == dwWait)
  129. {
  130. // We have messages to pump.
  131. //
  132. MSG msg;
  133. while (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
  134. {
  135. DispatchMessage (&msg);
  136. }
  137. }
  138. else
  139. {
  140. // Wait is satisfied, or we had a timeout, or an error.
  141. //
  142. if (WAIT_TIMEOUT == dwWait)
  143. {
  144. hr = HRESULT_FROM_WIN32 (ERROR_TIMEOUT);
  145. }
  146. else if (0xFFFFFFFF == dwWait)
  147. {
  148. hr = HrFromLastWin32Error ();
  149. }
  150. break;
  151. }
  152. }
  153. }
  154. TraceHr (ttidError, FAL, hr, FALSE, "HrCiCreateAndWaitForIndexListMutex");
  155. return hr;
  156. }
  157. //+--------------------------------------------------------------------------
  158. //
  159. // Function: HrCiUpdateDescriptionIndexList
  160. //
  161. // Purpose: Updates the description map by adding or removing
  162. // entries for pszDescription.
  163. //
  164. // Arguments:
  165. // pguidClass [in] The device's class guid
  166. // pszDescription [in] Description of the adapter
  167. // eOp [in] The operation to perform. DM_ADD to add
  168. // an index, DM_DELETE to delete an index.
  169. // pulIndex [inout] The index added if eOp was DM_ADD.
  170. // The index to delete if eOp was DM_DELETE.
  171. //
  172. // Returns: HRESULT. S_OK is successful, a converted Win32 error otherwise
  173. //
  174. // Author: billbe 30 Oct 1998
  175. //
  176. // Notes:
  177. //
  178. HRESULT
  179. HrCiUpdateDescriptionIndexList (
  180. IN NETCLASS Class,
  181. IN PCWSTR pszDescription,
  182. IN DM_OP eOp,
  183. IN OUT ULONG* pIndex)
  184. {
  185. Assert(pszDescription);
  186. Assert(pIndex);
  187. Assert(FIsEnumerated(Class));
  188. // We don't want to update a decription's index list at the same time
  189. // as another process, so create a mutex and wait until it is available.
  190. //
  191. HANDLE hMutex = NULL;
  192. HRESULT hr = HrCiCreateAndWaitForIndexListMutex(&hMutex);
  193. if (S_OK == hr)
  194. {
  195. // Build the path to the description key
  196. // e.g. ...\Network\<net/infrared guid>\c_szRegKeyDescriptions
  197. //
  198. WCHAR szPath[_MAX_PATH];
  199. PCWSTR pszNetworkSubtreePath;
  200. pszNetworkSubtreePath = MAP_NETCLASS_TO_NETWORK_SUBTREE[Class];
  201. AssertSz (pszNetworkSubtreePath,
  202. "This class does not use the network subtree.");
  203. wcscpy (szPath, pszNetworkSubtreePath);
  204. wcscat (szPath, L"\\");
  205. wcscat (szPath, c_szRegKeyDescriptions);
  206. // Open/Create the description key
  207. //
  208. HKEY hkeyDescription;
  209. hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE,
  210. szPath, 0, KEY_READ_WRITE_DELETE, NULL, &hkeyDescription, NULL);
  211. if (S_OK == hr)
  212. {
  213. // Get the description index list if it exists.
  214. //
  215. PWSTR pmszIndexesOld;
  216. hr = HrRegQueryMultiSzWithAlloc(
  217. hkeyDescription,
  218. pszDescription,
  219. &pmszIndexesOld);
  220. // If we have the list...
  221. if (S_OK == hr)
  222. {
  223. // Perform the requested operation on the list.
  224. //
  225. PWSTR pmszBufferToSet = NULL;
  226. PWSTR pmszIndexesNew = NULL;
  227. if (DM_ADD == eOp)
  228. {
  229. // We need to add a new index.
  230. hr = HrCiAddNextAvailableIndex(pmszIndexesOld,
  231. pIndex, &pmszIndexesNew);
  232. pmszBufferToSet = pmszIndexesNew;
  233. }
  234. else if (DM_DELETE == eOp)
  235. {
  236. // Delete the index from the list.
  237. //
  238. WCHAR szDelete[c_cchIndexValueNameLen];
  239. BOOL fRemoved;
  240. swprintf(szDelete, L"%u", *pIndex);
  241. RemoveSzFromMultiSz(szDelete, pmszIndexesOld,
  242. STRING_FLAG_REMOVE_SINGLE, &fRemoved);
  243. // If something was removed, check to see if the
  244. // index list is empty. If it is, delete the
  245. // registry value.
  246. //
  247. if (fRemoved)
  248. {
  249. ULONG cchIndexes = CchOfMultiSzSafe(pmszIndexesOld);
  250. if (!cchIndexes)
  251. {
  252. // Index list is empty, delete the value.
  253. HrRegDeleteValue(hkeyDescription, pszDescription);
  254. }
  255. else
  256. {
  257. // Something was removed and there are still
  258. // index entries so we have a buffer to set in the
  259. // registry.
  260. pmszBufferToSet = pmszIndexesOld;
  261. }
  262. }
  263. }
  264. // If we succeeded and have a new list to set...
  265. //
  266. if ((S_OK == hr) && pmszBufferToSet)
  267. {
  268. // Set the map back in the registry.
  269. hr = HrRegSetMultiSz(hkeyDescription,
  270. pszDescription, pmszBufferToSet);
  271. }
  272. MemFree(pmszIndexesNew);
  273. MemFree(pmszIndexesOld);
  274. }
  275. else if ((HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) &&
  276. (DM_ADD == eOp))
  277. {
  278. // There was no entry for this description so we need to
  279. // create one.
  280. //
  281. hr = HrRegAddStringToMultiSz(L"1", hkeyDescription,
  282. NULL, pszDescription, STRING_FLAG_ENSURE_AT_FRONT, 0);
  283. if (S_OK == hr)
  284. {
  285. *pIndex = 1;
  286. }
  287. }
  288. RegCloseKey(hkeyDescription);
  289. }
  290. ReleaseMutex(hMutex);
  291. CloseHandle(hMutex);
  292. }
  293. TraceHr (ttidError, FAL, hr, FALSE, "HrCiUpdateDescriptionIndexList");
  294. return hr;
  295. }
  296. //+--------------------------------------------------------------------------
  297. //
  298. // Function: CiSetFriendlyNameIfNeeded
  299. //
  300. // Purpose: Sets an instance index for the adapter. If this adapter's
  301. // description already exists (i.e. another similar adapter
  302. // is installed), then a friendly name for this adapter will be
  303. // set using the current description appened with the instance
  304. // index.
  305. //
  306. // Arguments:
  307. // cii [in] See classinst.h
  308. //
  309. // Returns: nothing
  310. //
  311. // Author: billbe 30 Oct 1998
  312. //
  313. // Notes: If previous adapter descriptions were Foo, Foo, Foo
  314. // They will have friendly names Foo, Foo #2, Foo #3
  315. //
  316. VOID
  317. CiSetFriendlyNameIfNeeded(IN const COMPONENT_INSTALL_INFO& cii)
  318. {
  319. Assert(IsValidHandle(cii.hdi));
  320. Assert(cii.pdeid);
  321. Assert(FIsEnumerated(cii.Class));
  322. Assert(cii.pszDescription);
  323. // Open the device parameters key.
  324. //
  325. HKEY hkeyDevice;
  326. HRESULT hr;
  327. hr = HrSetupDiCreateDevRegKey(cii.hdi, cii.pdeid,
  328. DICS_FLAG_GLOBAL, 0, DIREG_DEV, NULL, NULL, &hkeyDevice);
  329. if (S_OK == hr)
  330. {
  331. // Does this device already have an index?
  332. //
  333. DWORD Index;
  334. hr = HrRegQueryDword(hkeyDevice, c_szRegValueInstanceIndex, &Index);
  335. // This device doesn't have an index, so we need to give it one.
  336. //
  337. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  338. {
  339. // Update the description map and get the new index.
  340. hr = HrCiUpdateDescriptionIndexList(cii.Class,
  341. cii.pszDescription, DM_ADD, &Index);
  342. if (S_OK == hr)
  343. {
  344. // Store the index there so we can retrieve it when
  345. // the device is uninstalled and delete the index from
  346. // out table of indexes in use.
  347. (void) HrRegSetDword(hkeyDevice, c_szRegValueInstanceIndex,
  348. Index);
  349. }
  350. }
  351. // The first index doesn't get a new name.
  352. // i.e. the following same named devices:
  353. //
  354. // foo, foo, foo
  355. //
  356. // become
  357. //
  358. // foo, foo #2, foo #3
  359. //
  360. if ((S_OK == hr) && (1 != Index) && !FIsFilterDevice(cii.hdi, cii.pdeid))
  361. {
  362. // Now build the new name of this device using the index
  363. // number.
  364. //
  365. // Note: It doesn't matter if we failed to open the driver key
  366. // above; we can still continue. It only means that this index
  367. // cannot be reused if the device is deleted.
  368. //
  369. WCHAR szIndex[c_cchIndexValueNameLen];
  370. swprintf(szIndex, L"%u", Index);
  371. WCHAR szNewName[LINE_LEN + 1] = {0};
  372. wcsncpy(szNewName, cii.pszDescription,
  373. LINE_LEN - c_cchIndexValueNameLen);
  374. wcscat(szNewName, L" #");
  375. wcscat(szNewName, szIndex);
  376. // Set the new name as the friendly name of the device
  377. hr = HrSetupDiSetDeviceRegistryProperty(cii.hdi,
  378. cii.pdeid,
  379. SPDRP_FRIENDLYNAME,
  380. reinterpret_cast<const BYTE*>(szNewName),
  381. CbOfSzAndTerm(szNewName));
  382. }
  383. RegCloseKey(hkeyDevice);
  384. }
  385. TraceHr (ttidError, FAL, hr, FALSE, "FCiSetFriendlyNameIfNeeded");
  386. }