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.

2086 lines
56 KiB

  1. //
  2. // Copyright (c) Microsoft Corporation 1993-1995
  3. //
  4. // rovdi.c
  5. //
  6. // This files contains Device Installer wrappers that we commonly use.
  7. //
  8. // History:
  9. // 11-13-95 ScottH Separated from NT modem class installer
  10. //
  11. #define REENUMERATE_PORT
  12. #include "proj.h"
  13. #include "rovcomm.h"
  14. #include <cfgmgr32.h>
  15. #include <debugmem.h>
  16. #define MAX_REG_KEY_LEN 128
  17. #define CB_MAX_REG_KEY_LEN (MAX_REG_KEY_LEN * sizeof(TCHAR))
  18. //-----------------------------------------------------------------------------------
  19. // Port mapping functions
  20. //-----------------------------------------------------------------------------------
  21. #define CPORTPAIR 8
  22. #ifdef REENUMERATE_PORT
  23. typedef struct tagPORTPAIR
  24. {
  25. DEVNODE devNode;
  26. WCHAR szPortName[MAX_BUF];
  27. WCHAR szFriendlyName[MAX_BUF];
  28. } PORTPAIR, FAR * LPPORTPAIR;
  29. #else // REENUMERATE_PORT not defined
  30. typedef struct tagPORTPAIR
  31. {
  32. CHAR szPortName[MAX_BUF];
  33. CHAR szFriendlyName[MAX_BUF];
  34. } PORTPAIR, FAR * LPPORTPAIR;
  35. #endif // REENUMERATE_PORT
  36. typedef struct tagPORTMAP
  37. {
  38. LPPORTPAIR rgports; // Alloc
  39. int cports;
  40. } PORTMAP, FAR * LPPORTMAP;
  41. /*----------------------------------------------------------
  42. Purpose: Performs a local realloc my way
  43. Returns: TRUE on success
  44. Cond: --
  45. */
  46. BOOL PRIVATE MyReAlloc(
  47. LPVOID FAR * ppv,
  48. int cbOld,
  49. int cbNew)
  50. {
  51. LPVOID pv = (LPVOID)ALLOCATE_MEMORY( cbNew);
  52. if (pv)
  53. {
  54. CopyMemory(pv, *ppv, min(cbOld, cbNew));
  55. FREE_MEMORY(*ppv);
  56. *ppv = pv;
  57. }
  58. return (NULL != pv);
  59. }
  60. #ifdef REENUMERATE_PORT
  61. /*----------------------------------------------------------
  62. Purpose: Device enumerator callback. Adds another device to the
  63. map table.
  64. Returns: TRUE to continue enumeration
  65. Cond: --
  66. */
  67. BOOL
  68. CALLBACK
  69. PortMap_Add (
  70. HPORTDATA hportdata,
  71. LPARAM lParam)
  72. {
  73. BOOL bRet;
  74. PORTDATA pd;
  75. pd.cbSize = sizeof(pd);
  76. bRet = PortData_GetProperties (hportdata, &pd);
  77. if (bRet)
  78. {
  79. LPPORTMAP pmap = (LPPORTMAP)lParam;
  80. LPPORTPAIR ppair;
  81. int cb;
  82. int cbUsed;
  83. // Time to reallocate the table?
  84. cb = (int)SIZE_OF_MEMORY(pmap->rgports);
  85. cbUsed = pmap->cports * sizeof(*ppair);
  86. if (cbUsed >= cb)
  87. {
  88. // Yes
  89. cb += (CPORTPAIR * sizeof(*ppair));
  90. bRet = MyReAlloc((LPVOID FAR *)&pmap->rgports, cbUsed, cb);
  91. }
  92. if (bRet)
  93. {
  94. ppair = &pmap->rgports[pmap->cports++];
  95. #ifdef UNICODE
  96. lstrcpy(ppair->szPortName, pd.szPort);
  97. lstrcpy(ppair->szFriendlyName, pd.szFriendly);
  98. #else
  99. WideCharToMultiByte(CP_ACP, 0, pd.szPort, -1, ppair->szPortName, SIZECHARS(ppair->szPortName), 0, 0);
  100. WideCharToMultiByte(CP_ACP, 0, pd.szFriendly, -1, ppair->szFriendlyName, SIZECHARS(ppair->szFriendlyName), 0, 0);
  101. #endif
  102. DEBUG_CODE( TRACE_MSG(TF_GENERAL, "Added %s <-> %s to portmap",
  103. ppair->szPortName, ppair->szFriendlyName); )
  104. }
  105. }
  106. return bRet;
  107. }
  108. #else //REENUMERATE_PORT not defined
  109. /*----------------------------------------------------------
  110. Purpose: Device enumerator callback. Adds another device to the
  111. map table.
  112. Returns: TRUE to continue enumeration
  113. Cond: --
  114. */
  115. BOOL
  116. CALLBACK
  117. PortMap_Add(
  118. HPORTDATA hportdata,
  119. LPARAM lParam)
  120. {
  121. BOOL bRet;
  122. PORTDATA pd;
  123. pd.cbSize = sizeof(pd);
  124. bRet = PortData_GetProperties(hportdata, &pd);
  125. if (bRet)
  126. {
  127. LPPORTMAP pmap = (LPPORTMAP)lParam;
  128. LPPORTPAIR ppair;
  129. int cb;
  130. int cbUsed;
  131. // Time to reallocate the table?
  132. cb = SIZE_OF_MEMORY(pmap->rgports);
  133. cbUsed = pmap->cports * sizeof(*ppair);
  134. if (cbUsed >= cb)
  135. {
  136. // Yes
  137. cb += (CPORTPAIR * sizeof(*ppair));
  138. bRet = MyReAlloc((LPVOID FAR *)&pmap->rgports, cbUsed, cb);
  139. }
  140. if (bRet)
  141. {
  142. ppair = &pmap->rgports[pmap->cports++];
  143. #ifdef UNICODE
  144. // Fields of LPPORTPAIR are always ANSI
  145. WideCharToMultiByte(CP_ACP, 0, pd.szPort, -1, ppair->szPortName, SIZECHARS(ppair->szPortName), 0, 0);
  146. WideCharToMultiByte(CP_ACP, 0, pd.szFriendly, -1, ppair->szFriendlyName, SIZECHARS(ppair->szFriendlyName), 0, 0);
  147. #else
  148. lstrcpy(ppair->szPortName, pd.szPort);
  149. lstrcpy(ppair->szFriendlyName, pd.szFriendly);
  150. #endif
  151. DEBUG_CODE( TRACE_MSG(TF_GENERAL, "Added %s <-> %s to portmap",
  152. ppair->szPortName, ppair->szFriendlyName); )
  153. }
  154. }
  155. return bRet;
  156. }
  157. #endif // REENUMERATE_PORT
  158. #ifdef REENUMERATE_PORT
  159. void
  160. PortMap_InitDevInst (LPPORTMAP pmap)
  161. {
  162. DWORD dwDeviceIDListSize = 4*1024; // start with 4k TCHAR space
  163. TCHAR *szDeviceIDList = NULL;
  164. CONFIGRET cr;
  165. if (NULL == pmap ||
  166. 0 >= pmap->cports)
  167. {
  168. // BRL 9/4/98, bug 217715
  169. // ASSERT(0);
  170. return;
  171. }
  172. // First, get the list of all devices
  173. do
  174. {
  175. szDeviceIDList = ALLOCATE_MEMORY(
  176. dwDeviceIDListSize*sizeof(TCHAR));
  177. if (NULL == szDeviceIDList)
  178. {
  179. break;
  180. }
  181. cr = CM_Get_Device_ID_List (NULL,
  182. szDeviceIDList,
  183. dwDeviceIDListSize,
  184. CM_GETIDLIST_FILTER_NONE);
  185. if (CR_SUCCESS != cr)
  186. {
  187. FREE_MEMORY(szDeviceIDList);
  188. szDeviceIDList = NULL;
  189. if (CR_BUFFER_SMALL != cr ||
  190. CR_SUCCESS != CM_Get_Device_ID_List_Size (&dwDeviceIDListSize,
  191. NULL,
  192. CM_GETIDLIST_FILTER_NONE))
  193. {
  194. break;
  195. }
  196. }
  197. } while (CR_SUCCESS != cr);
  198. // If we got the list, look for all
  199. // devices that have a port name, and
  200. // update the port map
  201. if (NULL != szDeviceIDList)
  202. {
  203. DEVINST devInst;
  204. DWORD cbData;
  205. DWORD dwRet;
  206. int cbRemaining = pmap->cports;
  207. //int i;
  208. HKEY hKey;
  209. LPPORTPAIR pPort, pLast = pmap->rgports + (pmap->cports-1);
  210. TCHAR *szDeviceID;
  211. PORTPAIR portTemp;
  212. TCHAR szPort[MAX_BUF];
  213. for (szDeviceID = szDeviceIDList;
  214. *szDeviceID && 0 < cbRemaining;
  215. szDeviceID += lstrlen(szDeviceID)+1)
  216. {
  217. // First, locate the devinst
  218. if (CR_SUCCESS != CM_Locate_DevInst (&devInst,
  219. szDeviceID,
  220. CM_LOCATE_DEVNODE_NORMAL))
  221. {
  222. // We couldn't locate this devnode;
  223. // go to the next one;
  224. TRACE_MSG(TF_ERROR, "Could not locate devnode for %s.", szDeviceID);
  225. continue;
  226. }
  227. // Then, open the registry key for the devinst
  228. if (CR_SUCCESS != CM_Open_DevNode_Key (devInst,
  229. KEY_QUERY_VALUE,
  230. 0,
  231. RegDisposition_OpenExisting,
  232. &hKey,
  233. CM_REGISTRY_HARDWARE))
  234. {
  235. TRACE_MSG(TF_ERROR, "Could not open hardware key for %s.", szDeviceID);
  236. continue;
  237. }
  238. // Now, try to read the "PortName"
  239. cbData = sizeof (szPort);
  240. dwRet = RegQueryValueEx (hKey,
  241. REGSTR_VAL_PORTNAME,
  242. NULL,
  243. NULL,
  244. (PBYTE)szPort,
  245. &cbData);
  246. RegCloseKey (hKey);
  247. if (ERROR_SUCCESS != dwRet)
  248. {
  249. TRACE_MSG(TF_ERROR, "Could not read PortName for %s.", szDeviceID);
  250. continue;
  251. }
  252. // If we got here, we have a PortName;
  253. // look for it in our map, and if we find
  254. // it, update the devNode and FriendlyName
  255. for (/*i = 0, */pPort = pmap->rgports;
  256. /*i < cbRemaining*/pPort <= pLast;
  257. /*i++, */pPort++)
  258. {
  259. if (0 == lstrcmpiW (szPort, pPort->szPortName))
  260. {
  261. // Found the port;
  262. // first, initialize the DevInst
  263. pPort->devNode = devInst;
  264. // then, if possible, update the friendly name
  265. cbData = sizeof(szPort);
  266. if (CR_SUCCESS ==
  267. CM_Get_DevNode_Registry_Property (devInst,
  268. CM_DRP_FRIENDLYNAME,
  269. NULL,
  270. (PVOID)szPort,
  271. &cbData,
  272. 0))
  273. {
  274. lstrcpyW (pPort->szFriendlyName, szPort);
  275. }
  276. // This is an optimization, so that next time
  277. // we don't cycle throught the whole list
  278. if (0 < --cbRemaining)
  279. {
  280. // move this item to the
  281. // end of the array
  282. portTemp = *pPort;
  283. *pPort = *pLast;
  284. *pLast = portTemp;
  285. pLast--;
  286. }
  287. break;
  288. }
  289. }
  290. }
  291. FREE_MEMORY(szDeviceIDList);
  292. }
  293. }
  294. /*----------------------------------------------------------
  295. Purpose: Wide-char version. This function creates a port map
  296. table that maps port names to friendly names, and
  297. vice-versa.
  298. Returns: TRUE on success
  299. Cond: --
  300. */
  301. BOOL
  302. APIENTRY
  303. PortMap_Create (
  304. OUT HPORTMAP FAR * phportmap)
  305. {
  306. LPPORTMAP pmap;
  307. pmap = (LPPORTMAP)ALLOCATE_MEMORY( sizeof(*pmap));
  308. if (pmap)
  309. {
  310. // Initially alloc 8 entries
  311. pmap->rgports = (LPPORTPAIR)ALLOCATE_MEMORY( CPORTPAIR*sizeof(*pmap->rgports));
  312. if (pmap->rgports)
  313. {
  314. // Fill the map table
  315. EnumeratePorts (PortMap_Add, (LPARAM)pmap);
  316. PortMap_InitDevInst (pmap);
  317. }
  318. else
  319. {
  320. // Error
  321. FREE_MEMORY(pmap);
  322. pmap = NULL;
  323. }
  324. }
  325. *phportmap = (HPORTMAP)pmap;
  326. return (NULL != pmap);
  327. }
  328. #else // REENUMERATE_PORT not defined
  329. BOOL
  330. APIENTRY
  331. PortMap_Create(
  332. OUT HPORTMAP FAR * phportmap)
  333. {
  334. LPPORTMAP pmap;
  335. pmap = (LPPORTMAP)ALLOCATE_MEMORY( sizeof(*pmap));
  336. if (pmap)
  337. {
  338. // Initially alloc 8 entries
  339. pmap->rgports = (LPPORTPAIR)ALLOCATE_MEMORY( CPORTPAIR*sizeof(*pmap->rgports));
  340. if (pmap->rgports)
  341. {
  342. // Fill the map table
  343. EnumeratePorts(PortMap_Add, (LPARAM)pmap);
  344. }
  345. else
  346. {
  347. // Error
  348. FREE_MEMORY(pmap);
  349. pmap = NULL;
  350. }
  351. }
  352. *phportmap = (HPORTMAP)pmap;
  353. return (NULL != pmap);
  354. }
  355. #endif // REENUMERATE_PORT
  356. /*----------------------------------------------------------
  357. Purpose: Gets the count of ports on the system.
  358. Returns: see above
  359. Cond: --
  360. */
  361. DWORD
  362. APIENTRY
  363. PortMap_GetCount(
  364. IN HPORTMAP hportmap)
  365. {
  366. DWORD dwRet;
  367. LPPORTMAP pmap = (LPPORTMAP)hportmap;
  368. try
  369. {
  370. dwRet = pmap->cports;
  371. }
  372. except (EXCEPTION_EXECUTE_HANDLER)
  373. {
  374. dwRet = 0;
  375. }
  376. return dwRet;
  377. }
  378. #ifdef REENUMERATE_PORT
  379. /*----------------------------------------------------------
  380. Purpose: Gets the friendly name given the port name and places
  381. a copy in the supplied buffer.
  382. If no port name is found, the contents of the supplied
  383. buffer is not changed.
  384. Wide-char version.
  385. Returns: TRUE on success
  386. FALSE if the port name is not found
  387. Cond: --
  388. */
  389. BOOL
  390. APIENTRY
  391. PortMap_GetFriendlyW (
  392. IN HPORTMAP hportmap,
  393. IN LPCWSTR pwszPortName,
  394. OUT LPWSTR pwszBuf,
  395. IN DWORD cchBuf)
  396. {
  397. LPPORTMAP pmap = (LPPORTMAP)hportmap;
  398. ASSERT(pmap);
  399. ASSERT(pwszPortName);
  400. ASSERT(pwszBuf);
  401. try
  402. {
  403. LPPORTPAIR pport = pmap->rgports;
  404. int cports = pmap->cports;
  405. int i;
  406. for (i = 0; i < cports; i++, pport++)
  407. {
  408. if (0 == lstrcmpiW (pwszPortName, pport->szPortName))
  409. {
  410. lstrcpynW (pwszBuf, pport->szFriendlyName, cchBuf);
  411. return TRUE;
  412. }
  413. }
  414. }
  415. except (EXCEPTION_EXECUTE_HANDLER)
  416. {
  417. SetLastError(ERROR_INVALID_PARAMETER);
  418. }
  419. return FALSE;
  420. }
  421. /*----------------------------------------------------------
  422. Purpose: Gets the friendly name given the port name and places
  423. a copy in the supplied buffer.
  424. If no port name is found, the contents of the supplied
  425. buffer is not changed.
  426. Returns: TRUE on success
  427. FALSE if the port name is not found
  428. Cond: --
  429. */
  430. BOOL
  431. APIENTRY
  432. PortMap_GetFriendlyA (
  433. IN HPORTMAP hportmap,
  434. IN LPCSTR pszPortName,
  435. OUT LPSTR pszBuf,
  436. IN DWORD cchBuf)
  437. {
  438. BOOL bRet;
  439. ASSERT(pszPortName);
  440. ASSERT(pszBuf);
  441. try
  442. {
  443. WCHAR szPort[MAX_BUF_MED];
  444. WCHAR szBuf[MAX_BUF];
  445. MultiByteToWideChar (CP_ACP, 0, pszPortName, -1, szPort, SIZECHARS(szPort));
  446. bRet = PortMap_GetFriendlyW (hportmap, szPort, szBuf, SIZECHARS(szBuf));
  447. if (bRet)
  448. {
  449. WideCharToMultiByte (CP_ACP, 0, szBuf, -1, pszBuf, cchBuf, 0, 0);
  450. }
  451. }
  452. except (EXCEPTION_EXECUTE_HANDLER)
  453. {
  454. SetLastError (ERROR_INVALID_PARAMETER);
  455. bRet = FALSE;
  456. }
  457. return bRet;
  458. }
  459. /*----------------------------------------------------------
  460. Purpose: Gets the port name given the friendly name and places
  461. a copy in the supplied buffer.
  462. If no friendly name is found, the contents of the supplied
  463. buffer is not changed.
  464. Wide-char version.
  465. Returns: TRUE on success
  466. FALSE if the friendly name is not found
  467. Cond: --
  468. */
  469. BOOL
  470. APIENTRY
  471. PortMap_GetPortNameW (
  472. IN HPORTMAP hportmap,
  473. IN LPCWSTR pwszFriendly,
  474. OUT LPWSTR pwszBuf,
  475. IN DWORD cchBuf)
  476. {
  477. LPPORTMAP pmap = (LPPORTMAP)hportmap;
  478. ASSERT(pmap);
  479. ASSERT(pwszFriendly);
  480. ASSERT(pwszBuf);
  481. try
  482. {
  483. LPPORTPAIR pport = pmap->rgports;
  484. int cports = pmap->cports;
  485. int i;
  486. for (i = 0; i < cports; i++, pport++)
  487. {
  488. if (0 == lstrcmpiW (pwszFriendly, pport->szFriendlyName))
  489. {
  490. lstrcpynW (pwszBuf, pport->szPortName, cchBuf);
  491. return TRUE;
  492. }
  493. }
  494. }
  495. except (EXCEPTION_EXECUTE_HANDLER)
  496. {
  497. SetLastError(ERROR_INVALID_PARAMETER);
  498. }
  499. return FALSE;
  500. }
  501. /*----------------------------------------------------------
  502. Purpose: Gets the port name given the friendly name and places
  503. a copy in the supplied buffer.
  504. If no friendly name is found, the contents of the supplied
  505. buffer is not changed.
  506. Returns: TRUE
  507. FALSE if the friendly name is not found
  508. Cond: --
  509. */
  510. BOOL
  511. APIENTRY
  512. PortMap_GetPortNameA (
  513. IN HPORTMAP hportmap,
  514. IN LPCSTR pszFriendly,
  515. OUT LPSTR pszBuf,
  516. IN DWORD cchBuf)
  517. {
  518. BOOL bRet;
  519. ASSERT(pszFriendly);
  520. ASSERT(pszBuf);
  521. try
  522. {
  523. WCHAR szFriendly[MAX_BUF];
  524. WCHAR szBuf[MAX_BUF_MED];
  525. MultiByteToWideChar(CP_ACP, 0, pszFriendly, -1, szFriendly, SIZECHARS(szFriendly));
  526. bRet = PortMap_GetPortNameW (hportmap, szFriendly, szBuf, SIZECHARS(szBuf));
  527. if (bRet)
  528. {
  529. WideCharToMultiByte(CP_ACP, 0, szBuf, -1, pszBuf, cchBuf, 0, 0);
  530. }
  531. }
  532. except (EXCEPTION_EXECUTE_HANDLER)
  533. {
  534. bRet = FALSE;
  535. SetLastError(ERROR_INVALID_PARAMETER);
  536. }
  537. return bRet;
  538. }
  539. /*----------------------------------------------------------
  540. Purpose: Gets the device instance, given the port name
  541. Returns: TRUE
  542. FALSE if the friendly name is not found
  543. Cond: --
  544. */
  545. BOOL
  546. APIENTRY
  547. PortMap_GetDevNodeW (
  548. IN HPORTMAP hportmap,
  549. IN LPCWSTR pszPortName,
  550. OUT LPDWORD pdwDevNode)
  551. {
  552. LPPORTMAP pmap = (LPPORTMAP)hportmap;
  553. ASSERT(pmap);
  554. ASSERT(pszPortName);
  555. ASSERT(pdwDevNode);
  556. try
  557. {
  558. LPPORTPAIR pport = pmap->rgports;
  559. int cports = pmap->cports;
  560. int i;
  561. for (i = 0; i < cports; i++, pport++)
  562. {
  563. if (0 == lstrcmpiW (pszPortName, pport->szPortName))
  564. {
  565. *pdwDevNode = pport->devNode;
  566. return TRUE;
  567. }
  568. }
  569. }
  570. except (EXCEPTION_EXECUTE_HANDLER)
  571. {
  572. SetLastError(ERROR_INVALID_PARAMETER);
  573. }
  574. return FALSE;
  575. }
  576. BOOL
  577. APIENTRY
  578. PortMap_GetDevNodeA (
  579. IN HPORTMAP hportmap,
  580. IN LPCSTR pszPortName,
  581. OUT LPDWORD pdwDevNode)
  582. {
  583. BOOL bRet;
  584. ASSERT(pszPortName);
  585. ASSERT(pdwDevNode);
  586. try
  587. {
  588. WCHAR szPort[MAX_BUF];
  589. MultiByteToWideChar(CP_ACP, 0, pszPortName, -1, szPort, SIZECHARS(szPort));
  590. bRet = PortMap_GetDevNodeW (hportmap, szPort, pdwDevNode);
  591. }
  592. except (EXCEPTION_EXECUTE_HANDLER)
  593. {
  594. bRet = FALSE;
  595. SetLastError(ERROR_INVALID_PARAMETER);
  596. }
  597. return bRet;
  598. }
  599. #else // REENUMERATE_PORT not defined
  600. /*----------------------------------------------------------
  601. Purpose: Gets the friendly name given the port name and places
  602. a copy in the supplied buffer.
  603. If no port name is found, the contents of the supplied
  604. buffer is not changed.
  605. Wide-char version.
  606. Returns: TRUE on success
  607. FALSE if the port name is not found
  608. Cond: --
  609. */
  610. BOOL
  611. APIENTRY
  612. PortMap_GetFriendlyW(
  613. IN HPORTMAP hportmap,
  614. IN LPCWSTR pwszPortName,
  615. OUT LPWSTR pwszBuf,
  616. IN DWORD cchBuf)
  617. {
  618. BOOL bRet;
  619. ASSERT(pwszPortName);
  620. ASSERT(pwszBuf);
  621. try
  622. {
  623. CHAR szPort[MAX_BUF_MED];
  624. CHAR szBuf[MAX_BUF];
  625. WideCharToMultiByte(CP_ACP, 0, pwszPortName, -1, szPort, SIZECHARS(szPort), 0, 0);
  626. bRet = PortMap_GetFriendlyA(hportmap, szPort, szBuf, SIZECHARS(szBuf));
  627. if (bRet)
  628. {
  629. MultiByteToWideChar(CP_ACP, 0, szBuf, -1, pwszBuf, cchBuf);
  630. }
  631. }
  632. except (EXCEPTION_EXECUTE_HANDLER)
  633. {
  634. SetLastError(ERROR_INVALID_PARAMETER);
  635. bRet = FALSE;
  636. }
  637. return bRet;
  638. }
  639. /*----------------------------------------------------------
  640. Purpose: Gets the friendly name given the port name and places
  641. a copy in the supplied buffer.
  642. If no port name is found, the contents of the supplied
  643. buffer is not changed.
  644. Returns: TRUE on success
  645. FALSE if the port name is not found
  646. Cond: --
  647. */
  648. BOOL
  649. APIENTRY
  650. PortMap_GetFriendlyA(
  651. IN HPORTMAP hportmap,
  652. IN LPCSTR pszPortName,
  653. OUT LPSTR pszBuf,
  654. IN DWORD cchBuf)
  655. {
  656. LPPORTMAP pmap = (LPPORTMAP)hportmap;
  657. ASSERT(pmap);
  658. ASSERT(pszPortName);
  659. ASSERT(pszBuf);
  660. try
  661. {
  662. LPPORTPAIR pport = pmap->rgports;
  663. int cports = pmap->cports;
  664. int i;
  665. for (i = 0; i < cports; i++, pport++)
  666. {
  667. if (0 == lstrcmpiA(pszPortName, pport->szPortName))
  668. {
  669. lstrcpynA(pszBuf, pport->szFriendlyName, cchBuf);
  670. return TRUE;
  671. }
  672. }
  673. }
  674. except (EXCEPTION_EXECUTE_HANDLER)
  675. {
  676. SetLastError(ERROR_INVALID_PARAMETER);
  677. }
  678. return FALSE;
  679. }
  680. /*----------------------------------------------------------
  681. Purpose: Gets the port name given the friendly name and places
  682. a copy in the supplied buffer.
  683. If no friendly name is found, the contents of the supplied
  684. buffer is not changed.
  685. Wide-char version.
  686. Returns: TRUE on success
  687. FALSE if the friendly name is not found
  688. Cond: --
  689. */
  690. BOOL
  691. APIENTRY
  692. PortMap_GetPortNameW(
  693. IN HPORTMAP hportmap,
  694. IN LPCWSTR pwszFriendly,
  695. OUT LPWSTR pwszBuf,
  696. IN DWORD cchBuf)
  697. {
  698. BOOL bRet;
  699. ASSERT(pwszFriendly);
  700. ASSERT(pwszBuf);
  701. try
  702. {
  703. CHAR szFriendly[MAX_BUF];
  704. CHAR szBuf[MAX_BUF_MED];
  705. WideCharToMultiByte(CP_ACP, 0, pwszFriendly, -1, szFriendly, SIZECHARS(szFriendly), 0, 0);
  706. bRet = PortMap_GetPortNameA(hportmap, szFriendly, szBuf, SIZECHARS(szBuf));
  707. if (bRet)
  708. {
  709. MultiByteToWideChar(CP_ACP, 0, szBuf, -1, pwszBuf, cchBuf);
  710. }
  711. }
  712. except (EXCEPTION_EXECUTE_HANDLER)
  713. {
  714. bRet = FALSE;
  715. SetLastError(ERROR_INVALID_PARAMETER);
  716. }
  717. return bRet;
  718. }
  719. /*----------------------------------------------------------
  720. Purpose: Gets the port name given the friendly name and places
  721. a copy in the supplied buffer.
  722. If no friendly name is found, the contents of the supplied
  723. buffer is not changed.
  724. Returns: TRUE
  725. FALSE if the friendly name is not found
  726. Cond: --
  727. */
  728. BOOL
  729. APIENTRY
  730. PortMap_GetPortNameA(
  731. IN HPORTMAP hportmap,
  732. IN LPCSTR pszFriendly,
  733. OUT LPSTR pszBuf,
  734. IN DWORD cchBuf)
  735. {
  736. LPPORTMAP pmap = (LPPORTMAP)hportmap;
  737. ASSERT(pmap);
  738. ASSERT(pszFriendly);
  739. ASSERT(pszBuf);
  740. try
  741. {
  742. LPPORTPAIR pport = pmap->rgports;
  743. int cports = pmap->cports;
  744. int i;
  745. for (i = 0; i < cports; i++, pport++)
  746. {
  747. if (0 == lstrcmpiA(pszFriendly, pport->szFriendlyName))
  748. {
  749. lstrcpynA(pszBuf, pport->szPortName, cchBuf);
  750. return TRUE;
  751. }
  752. }
  753. }
  754. except (EXCEPTION_EXECUTE_HANDLER)
  755. {
  756. SetLastError(ERROR_INVALID_PARAMETER);
  757. }
  758. return FALSE;
  759. }
  760. #endif // REENUMERATE_PORT
  761. /*----------------------------------------------------------
  762. Purpose: Frees a port map
  763. Returns: --
  764. Cond: --
  765. */
  766. BOOL
  767. APIENTRY
  768. PortMap_Free(
  769. IN HPORTMAP hportmap)
  770. {
  771. LPPORTMAP pmap = (LPPORTMAP)hportmap;
  772. if (pmap)
  773. {
  774. if (pmap->rgports)
  775. FREE_MEMORY(pmap->rgports);
  776. FREE_MEMORY(pmap);
  777. }
  778. return TRUE;
  779. }
  780. //-----------------------------------------------------------------------------------
  781. // Port enumeration functions
  782. //-----------------------------------------------------------------------------------
  783. #pragma data_seg(DATASEG_READONLY)
  784. TCHAR const FAR c_szSerialComm[] = TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM");
  785. #pragma data_seg()
  786. /*----------------------------------------------------------
  787. Purpose: Enumerates all the ports on the system and calls pfnDevice.
  788. pfnDevice can terminate the enumeration by returning FALSE.
  789. Returns: NO_ERROR if at least one port was found
  790. Cond: --
  791. */
  792. #ifdef _USE_SERIAL_INTERFACE
  793. DWORD
  794. APIENTRY
  795. EnumeratePorts(
  796. IN ENUMPORTPROC pfnDevice,
  797. IN LPARAM lParam) OPTIONAL
  798. {
  799. DWORD dwRet = NO_ERROR;
  800. HDEVINFO hdi;
  801. GUID guidSerialInterface = {0xB115ED80L, 0x46DF, 0x11D0, 0xB4, 0x65, 0x00,
  802. 0x00, 0x1A, 0x18, 0x18, 0xE6};
  803. DWORD dwIndex = 0;
  804. SP_DEVICE_INTERFACE_DATA devInterfaceData;
  805. SP_DEVINFO_DATA devInfoData;
  806. HKEY hKeyDev = INVALID_HANDLE_VALUE;
  807. PORTDATA pd;
  808. BOOL bContinue;
  809. DWORD dwType;
  810. DWORD cbData;
  811. // First build a list of all the device that suppoort serial port interface
  812. hdi = SetupDiGetClassDevs (&guidSerialInterface, NULL, NULL, DIGCF_DEVICEINTERFACE);
  813. if (INVALID_HANDLE_VALUE == hdi)
  814. {
  815. dwRet = GetLastError ();
  816. goto _ErrRet;
  817. }
  818. pd.cbSize = sizeof (PORTDATA);
  819. devInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
  820. devInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
  821. // Enumerate the interface devices
  822. for (dwIndex = 0;
  823. SetupDiEnumInterfaceDevice (hdi, NULL, &guidSerialInterface, dwIndex, &devInterfaceData);
  824. dwIndex++)
  825. {
  826. // For each interface device, get the parent device node
  827. if (SetupDiGetDeviceInterfaceDetail (hdi, &devInterfaceData, NULL, 0, NULL, &devInfoData) ||
  828. ERROR_INSUFFICIENT_BUFFER == GetLastError ())
  829. {
  830. // open the registry key for the node ...
  831. hKeyDev = SetupDiOpenDevRegKey (hdi, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
  832. if (INVALID_HANDLE_VALUE == hKeyDev)
  833. {
  834. dwRet = GetLastError ();
  835. continue;
  836. }
  837. // ... and get the value for PortName
  838. cbData = sizeof(pd.szPort);
  839. dwRet = RegQueryValueEx (hKeyDev, TEXT("PortName"), NULL, &dwType, &pd.szPort, &cbData);
  840. RegCloseKey(hKeyDev);
  841. if (ERROR_SUCCESS == dwRet)
  842. {
  843. pd.nSubclass = PORT_SUBCLASS_SERIAL;
  844. // now, try to get the friendly name from the dev node
  845. if (!SetupDiGetDeviceRegistryProperty (hdi, &devInfoData, SPDRP_FRIENDLYNAME,
  846. NULL, &pd.szFriendly, sizeof (pd.szFriendly), NULL))
  847. {
  848. // if unsuccessfull, just copy the port name
  849. // to the friendly name
  850. lstrcpy(pd.szFriendly, pd.szPort);
  851. }
  852. // call the callback
  853. bContinue = pfnDevice((HPORTDATA)&pd, lParam);
  854. // Continue?
  855. if ( !bContinue )
  856. {
  857. // No
  858. break;
  859. }
  860. }
  861. }
  862. else
  863. {
  864. dwRet = GetLastError ();
  865. }
  866. }
  867. _ErrRet:
  868. if (INVALID_HANDLE_VALUE != hdi)
  869. {
  870. SetupDiDestroyDeviceInfoList (hdi);
  871. }
  872. return dwRet;
  873. }
  874. #else // not defined _USE_SERIAL_INTERFACE
  875. DWORD
  876. APIENTRY
  877. EnumeratePorts(
  878. IN ENUMPORTPROC pfnDevice,
  879. IN LPARAM lParam) OPTIONAL
  880. {
  881. DWORD dwRet;
  882. HKEY hkeyEnum;
  883. dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, c_szSerialComm, &hkeyEnum);
  884. if (NO_ERROR == dwRet)
  885. {
  886. BOOL bContinue;
  887. PORTDATA pd;
  888. DWORD iSubKey;
  889. TCHAR szValue[MAX_BUF];
  890. DWORD cbValue;
  891. DWORD cbData;
  892. DWORD dwType;
  893. dwRet = ERROR_PATH_NOT_FOUND; // assume no ports
  894. iSubKey = 0;
  895. cbValue = sizeof(szValue) / sizeof(TCHAR);
  896. cbData = sizeof(pd.szPort);
  897. while (NO_ERROR == RegEnumValue(hkeyEnum, iSubKey++, szValue, &cbValue,
  898. NULL, &dwType, (LPBYTE)pd.szPort, &cbData))
  899. {
  900. if (REG_SZ == dwType)
  901. {
  902. // Friendly name is the same as the port name right now
  903. dwRet = NO_ERROR;
  904. pd.nSubclass = PORT_SUBCLASS_SERIAL;
  905. lstrcpy(pd.szFriendly, pd.szPort);
  906. bContinue = pfnDevice((HPORTDATA)&pd, lParam);
  907. // Continue?
  908. if ( !bContinue )
  909. {
  910. // No
  911. break;
  912. }
  913. }
  914. cbValue = sizeof(szValue);
  915. cbData = sizeof(pd.szPort);
  916. }
  917. RegCloseKey(hkeyEnum);
  918. }
  919. return dwRet;
  920. }
  921. #endif // _USE_SERIAL_INTERFACE
  922. /*----------------------------------------------------------
  923. Purpose: This function fills the given buffer with the properties
  924. of the particular port.
  925. Wide-char version.
  926. Returns: TRUE on success
  927. Cond: --
  928. */
  929. BOOL
  930. APIENTRY
  931. PortData_GetPropertiesW(
  932. IN HPORTDATA hportdata,
  933. OUT LPPORTDATA_W pdataBuf)
  934. {
  935. BOOL bRet = FALSE;
  936. ASSERT(hportdata);
  937. ASSERT(pdataBuf);
  938. if (hportdata && pdataBuf)
  939. {
  940. // Is the handle to a Widechar version?
  941. if (sizeof(PORTDATA_W) == pdataBuf->cbSize)
  942. {
  943. // Yes
  944. LPPORTDATA_W ppd = (LPPORTDATA_W)hportdata;
  945. pdataBuf->nSubclass = ppd->nSubclass;
  946. lstrcpynW(pdataBuf->szPort, ppd->szPort, SIZECHARS(pdataBuf->szPort));
  947. lstrcpynW(pdataBuf->szFriendly, ppd->szFriendly, SIZECHARS(pdataBuf->szFriendly));
  948. bRet = TRUE;
  949. }
  950. else if (sizeof(PORTDATA_A) == pdataBuf->cbSize)
  951. {
  952. // No; this is the Ansi version
  953. LPPORTDATA_A ppd = (LPPORTDATA_A)hportdata;
  954. pdataBuf->nSubclass = ppd->nSubclass;
  955. MultiByteToWideChar(CP_ACP, 0, ppd->szPort, -1, pdataBuf->szPort, SIZECHARS(pdataBuf->szPort));
  956. MultiByteToWideChar(CP_ACP, 0, ppd->szFriendly, -1, pdataBuf->szFriendly, SIZECHARS(pdataBuf->szFriendly));
  957. bRet = TRUE;
  958. }
  959. else
  960. {
  961. // Some invalid size
  962. ASSERT(0);
  963. }
  964. }
  965. return bRet;
  966. }
  967. /*----------------------------------------------------------
  968. Purpose: This function fills the given buffer with the properties
  969. of the particular port.
  970. Returns: TRUE on success
  971. Cond: --
  972. */
  973. BOOL
  974. APIENTRY
  975. PortData_GetPropertiesA(
  976. IN HPORTDATA hportdata,
  977. OUT LPPORTDATA_A pdataBuf)
  978. {
  979. BOOL bRet = FALSE;
  980. ASSERT(hportdata);
  981. ASSERT(pdataBuf);
  982. if (hportdata && pdataBuf)
  983. {
  984. // Is the handle to a Widechar version?
  985. if (sizeof(PORTDATA_W) == pdataBuf->cbSize)
  986. {
  987. // Yes
  988. LPPORTDATA_W ppd = (LPPORTDATA_W)hportdata;
  989. pdataBuf->nSubclass = ppd->nSubclass;
  990. WideCharToMultiByte(CP_ACP, 0, ppd->szPort, -1, pdataBuf->szPort, SIZECHARS(pdataBuf->szPort), NULL, NULL);
  991. WideCharToMultiByte(CP_ACP, 0, ppd->szFriendly, -1, pdataBuf->szFriendly, SIZECHARS(pdataBuf->szFriendly), NULL, NULL);
  992. bRet = TRUE;
  993. }
  994. else if (sizeof(PORTDATA_A) == pdataBuf->cbSize)
  995. {
  996. // No; this is the Ansi version
  997. LPPORTDATA_A ppd = (LPPORTDATA_A)hportdata;
  998. pdataBuf->nSubclass = ppd->nSubclass;
  999. lstrcpynA(pdataBuf->szPort, ppd->szPort, SIZECHARS(pdataBuf->szPort));
  1000. lstrcpynA(pdataBuf->szFriendly, ppd->szFriendly, SIZECHARS(pdataBuf->szFriendly));
  1001. bRet = TRUE;
  1002. }
  1003. else
  1004. {
  1005. // Some invalid size
  1006. ASSERT(0);
  1007. }
  1008. }
  1009. return bRet;
  1010. }
  1011. //-----------------------------------------------------------------------------------
  1012. // DeviceInstaller wrappers and support functions
  1013. //-----------------------------------------------------------------------------------
  1014. #pragma data_seg(DATASEG_READONLY)
  1015. static TCHAR const c_szBackslash[] = TEXT("\\");
  1016. static TCHAR const c_szSeparator[] = TEXT("::");
  1017. static TCHAR const c_szFriendlyName[] = TEXT("FriendlyName"); // REGSTR_VAL_FRIENDLYNAME
  1018. static TCHAR const c_szDeviceType[] = TEXT("DeviceType"); // REGSTR_VAL_DEVTYPE
  1019. static TCHAR const c_szAttachedTo[] = TEXT("AttachedTo");
  1020. static TCHAR const c_szPnPAttachedTo[] = TEXT("PnPAttachedTo");
  1021. static TCHAR const c_szDriverDesc[] = TEXT("DriverDesc"); // REGSTR_VAL_DRVDESC
  1022. static TCHAR const c_szManufacturer[] = TEXT("Manufacturer");
  1023. static TCHAR const c_szRespKeyName[] = TEXT("ResponsesKeyName");
  1024. TCHAR const c_szRefCount[] = TEXT("RefCount");
  1025. TCHAR const c_szResponses[] = TEXT("Responses");
  1026. #define DRIVER_KEY REGSTR_PATH_SETUP TEXT("\\Unimodem\\DeviceSpecific")
  1027. #define RESPONSES_KEY TEXT("\\Responses")
  1028. #pragma data_seg()
  1029. /*----------------------------------------------------------
  1030. Purpose: This function returns the bus type on which the device
  1031. can be enumerated.
  1032. Returns: TRUE on success
  1033. Cond: --
  1034. */
  1035. #include <initguid.h>
  1036. #include <wdmguid.h>
  1037. BOOL
  1038. PUBLIC
  1039. CplDiGetBusType(
  1040. IN HDEVINFO hdi,
  1041. IN PSP_DEVINFO_DATA pdevData, OPTIONAL
  1042. OUT LPDWORD pdwBusType)
  1043. {
  1044. BOOL bRet = TRUE;
  1045. ULONG ulStatus, ulProblem = 0;
  1046. #ifdef DEBUG
  1047. CONFIGRET cr;
  1048. #endif
  1049. #ifdef DEBUG
  1050. TCHAR *szBuses[] = {TEXT("BUS_TYPE_UNKNOWN"),
  1051. TEXT("BUS_TYPE_ROOT"),
  1052. TEXT("BUS_TYPE_PCMCIA"),
  1053. TEXT("BUS_TYPE_SERENUM"),
  1054. TEXT("BUS_TYPE_LPTENUM"),
  1055. TEXT("BUS_TYPE_OTHER"),
  1056. TEXT("BUS_TYPE_ISAPNP")};
  1057. #endif // DEBUG
  1058. DBG_ENTER(CplDiGetBusType);
  1059. ASSERT(hdi && INVALID_HANDLE_VALUE != hdi);
  1060. ASSERT(pdwBusType);
  1061. #ifdef DEBUG
  1062. cr = CM_Get_DevInst_Status (&ulStatus, &ulProblem, pdevData->DevInst, 0);
  1063. if ((CR_SUCCESS == cr) &&
  1064. #else
  1065. if (CR_SUCCESS == CM_Get_DevInst_Status (&ulStatus, &ulProblem, pdevData->DevInst, 0) &&
  1066. #endif
  1067. (ulStatus & DN_ROOT_ENUMERATED))
  1068. {
  1069. *pdwBusType = BUS_TYPE_ROOT;
  1070. TRACE_MSG(TF_GENERAL, "CplDiGetBusType: BUS_TYPE_ROOT");
  1071. }
  1072. else
  1073. {
  1074. GUID guid;
  1075. #ifdef DEBUG
  1076. if (CR_SUCCESS != cr)
  1077. {
  1078. TRACE_MSG(TF_ERROR, "CM_Get_DevInst_Status failed: %#lx.", cr);
  1079. }
  1080. #endif
  1081. // either CM_Get_DevInst_Status failed, which means that the device
  1082. // is plug & play and not present (i.e. plugged out),
  1083. // or the device is not root-enumerated;
  1084. // either way, it's a plug & play device.
  1085. *pdwBusType = BUS_TYPE_OTHER; // the default
  1086. // If the next call fails, it means that the device is
  1087. // BIOS / firmware enumerated; this is OK - we just return BUT_TYPE_OTHER
  1088. if (SetupDiGetDeviceRegistryProperty (hdi, pdevData, SPDRP_BUSTYPEGUID, NULL,
  1089. (PBYTE)&guid, sizeof(guid), NULL))
  1090. {
  1091. int i;
  1092. struct
  1093. {
  1094. GUID const *pguid;
  1095. DWORD dwBusType;
  1096. } BusTypes[] = {{&GUID_BUS_TYPE_SERENUM, BUS_TYPE_SERENUM},
  1097. {&GUID_BUS_TYPE_PCMCIA, BUS_TYPE_PCMCIA},
  1098. {&GUID_BUS_TYPE_ISAPNP, BUS_TYPE_ISAPNP}};
  1099. TRACE_MSG(TF_GENERAL, "Bus GUID is {%lX-%lX-%lX-%02lX%02lX-%02lX%02lX%02lX%02lX%02lX%02lX}.",
  1100. guid.Data1, (LONG)guid.Data2, (LONG)guid.Data3, (LONG)guid.Data4[0],
  1101. (LONG)guid.Data4[1], (LONG)guid.Data4[2], (LONG)guid.Data4[3],
  1102. (LONG)guid.Data4[4], (LONG)guid.Data4[5], (LONG)guid.Data4[6], (LONG)guid.Data4[7]);
  1103. for (i = 0;
  1104. i < sizeof (BusTypes) / sizeof (BusTypes[0]);
  1105. i ++)
  1106. {
  1107. if (IsEqualGUID (BusTypes[i].pguid, &guid))
  1108. {
  1109. *pdwBusType = BusTypes[i].dwBusType;
  1110. break;
  1111. }
  1112. }
  1113. }
  1114. #ifdef DEBUG
  1115. else
  1116. {
  1117. TRACE_MSG (TF_ERROR, "SetupDiGetDeviceRegistryProperty failed: %#lx.", GetLastError ());
  1118. }
  1119. #endif
  1120. }
  1121. #ifdef DEBUG
  1122. TRACE_MSG(TF_GENERAL, "CplDiGetBusType: bus is %s", szBuses[*pdwBusType]);
  1123. #endif //DEBUG
  1124. DBG_EXIT_BOOL(CplDiGetBusType, bRet);
  1125. return bRet;
  1126. }
  1127. /*----------------------------------------------------------
  1128. Purpose: This function returns the name of the common driver
  1129. type key for the given driver. We'll use the
  1130. driver description string, since it's unique per
  1131. driver but not per installation (the friendly name
  1132. is the latter).
  1133. Returns: TRUE on success
  1134. FALSE on error
  1135. Cond: --
  1136. */
  1137. BOOL
  1138. PRIVATE
  1139. OLD_GetCommonDriverKeyName(
  1140. IN HKEY hkeyDrv,
  1141. IN DWORD cbKeyName,
  1142. OUT LPTSTR pszKeyName)
  1143. {
  1144. BOOL bRet = FALSE; // assume failure
  1145. LONG lErr;
  1146. lErr = RegQueryValueEx(hkeyDrv, c_szDriverDesc, NULL, NULL,
  1147. (LPBYTE)pszKeyName, &cbKeyName);
  1148. if (lErr != ERROR_SUCCESS)
  1149. {
  1150. TRACE_MSG(TF_WARNING, "RegQueryValueEx(DriverDesc) failed: %#08lx.", lErr);
  1151. goto exit;
  1152. }
  1153. bRet = TRUE;
  1154. exit:
  1155. return(bRet);
  1156. }
  1157. /*----------------------------------------------------------
  1158. Purpose: This function tries to open the *old style* common
  1159. Responses key for the given driver, which used only
  1160. the driver description string for a key name.
  1161. The key is opened with READ access.
  1162. Returns: TRUE on success
  1163. FALSE on error
  1164. Cond: --
  1165. */
  1166. BOOL
  1167. PRIVATE
  1168. OLD_OpenCommonResponsesKey(
  1169. IN HKEY hkeyDrv,
  1170. OUT PHKEY phkeyResp)
  1171. {
  1172. BOOL bRet = FALSE; // assume failure
  1173. LONG lErr;
  1174. TCHAR szComDrv[MAX_REG_KEY_LEN];
  1175. TCHAR szPath[2*MAX_REG_KEY_LEN];
  1176. *phkeyResp = NULL;
  1177. // Get the name (*old style*) of the common driver key.
  1178. if (!OLD_GetCommonDriverKeyName(hkeyDrv, sizeof(szComDrv), szComDrv))
  1179. {
  1180. TRACE_MSG(TF_ERROR, "OLD_GetCommonDriverKeyName() failed.");
  1181. goto exit;
  1182. }
  1183. TRACE_MSG(TF_WARNING, "OLD_GetCommonDriverKeyName(): %s", szComDrv);
  1184. // Construct the path to the (*old style*) Responses key.
  1185. lstrcpy(szPath, DRIVER_KEY TEXT("\\"));
  1186. lstrcat(szPath, szComDrv);
  1187. lstrcat(szPath, RESPONSES_KEY);
  1188. // Open the (*old style*) Responses key.
  1189. lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szPath, 0, KEY_READ, phkeyResp);
  1190. if (lErr != ERROR_SUCCESS)
  1191. {
  1192. TRACE_MSG(TF_ERROR, "RegOpenKeyEx(Responses) failed: %#08lx.", lErr);
  1193. goto exit;
  1194. }
  1195. bRet = TRUE;
  1196. exit:
  1197. return(bRet);
  1198. }
  1199. /*----------------------------------------------------------
  1200. Purpose: This function finds the name of the common driver
  1201. type key for the given driver. First it'll look for
  1202. the new style key name ("ResponsesKeyName" value),
  1203. and if that doesn't exist then it'll look for the
  1204. old style key name ("Description" value), both of
  1205. which are stored in the driver node.
  1206. NOTE: The given driver key handle is assumed to contain
  1207. at least the Description value.
  1208. Returns: TRUE on success
  1209. FALSE on error
  1210. Cond: --
  1211. */
  1212. BOOL
  1213. PUBLIC
  1214. FindCommonDriverKeyName(
  1215. IN HKEY hkeyDrv,
  1216. IN DWORD cbKeyName,
  1217. OUT LPTSTR pszKeyName)
  1218. {
  1219. BOOL bRet = TRUE; // assume *success*
  1220. LONG lErr;
  1221. // Is the (new style) key name is registered in the driver node?
  1222. lErr = RegQueryValueEx(hkeyDrv, c_szRespKeyName, NULL, NULL,
  1223. (LPBYTE)pszKeyName, &cbKeyName);
  1224. if (lErr == ERROR_SUCCESS)
  1225. {
  1226. goto exit;
  1227. }
  1228. // No. The key name will be in the old style: just the Description.
  1229. lErr = RegQueryValueEx(hkeyDrv, c_szDriverDesc, NULL, NULL,
  1230. (LPBYTE)pszKeyName, &cbKeyName);
  1231. if (lErr == ERROR_SUCCESS)
  1232. {
  1233. goto exit;
  1234. }
  1235. // Couldn't get a key name!! Something's wrong....
  1236. ASSERT(0);
  1237. bRet = FALSE;
  1238. exit:
  1239. return(bRet);
  1240. }
  1241. /*----------------------------------------------------------
  1242. Purpose: This function returns the name of the common driver
  1243. type key for the given driver. The key name is the
  1244. concatenation of 3 strings found in the driver node
  1245. of the registry: the driver description, the manu-
  1246. facturer, and the provider. (The driver description
  1247. is used since it's unique per driver but not per
  1248. installation (the "friendly" name is the latter).
  1249. NOTE: The component substrings are either read from the
  1250. driver's registry key, or from the given driver info
  1251. data. If pdrvData is given, the strings it contains
  1252. are assumed to be valid (non-NULL).
  1253. Returns: TRUE on success
  1254. FALSE on error
  1255. Cond: --
  1256. */
  1257. BOOL
  1258. PUBLIC
  1259. GetCommonDriverKeyName(
  1260. IN HKEY hkeyDrv, OPTIONAL
  1261. IN PSP_DRVINFO_DATA pdrvData, OPTIONAL
  1262. IN DWORD cbKeyName,
  1263. OUT LPTSTR pszKeyName)
  1264. {
  1265. BOOL bRet = FALSE; // assume failure
  1266. LONG lErr;
  1267. DWORD dwByteCount, cbData;
  1268. TCHAR szDescription[MAX_REG_KEY_LEN];
  1269. TCHAR szManufacturer[MAX_REG_KEY_LEN];
  1270. TCHAR szProvider[MAX_REG_KEY_LEN];
  1271. LPTSTR lpszDesc, lpszMfct, lpszProv;
  1272. dwByteCount = 0;
  1273. lpszDesc = NULL;
  1274. lpszMfct = NULL;
  1275. lpszProv = NULL;
  1276. if (hkeyDrv)
  1277. {
  1278. // First see if it's already been registered in the driver node.
  1279. lErr = RegQueryValueEx(hkeyDrv, c_szRespKeyName, NULL, NULL,
  1280. (LPBYTE)pszKeyName, &cbKeyName);
  1281. if (lErr == ERROR_SUCCESS)
  1282. {
  1283. bRet = TRUE;
  1284. goto exit;
  1285. }
  1286. // Responses key doesn't exist - read its components from the registry.
  1287. cbData = sizeof(szDescription);
  1288. lErr = RegQueryValueEx(hkeyDrv, c_szDriverDesc, NULL, NULL,
  1289. (LPBYTE)szDescription, &cbData);
  1290. if (lErr == ERROR_SUCCESS)
  1291. {
  1292. // Is the Description string *alone* too long to be a key name?
  1293. // If so then we're hosed - fail the call.
  1294. if (cbData > CB_MAX_REG_KEY_LEN)
  1295. {
  1296. goto exit;
  1297. }
  1298. dwByteCount = cbData;
  1299. lpszDesc = szDescription;
  1300. cbData = sizeof(szManufacturer);
  1301. lErr = RegQueryValueEx(hkeyDrv, c_szManufacturer, NULL, NULL,
  1302. (LPBYTE)szManufacturer, &cbData);
  1303. if (lErr == ERROR_SUCCESS)
  1304. {
  1305. // only use the manufacturer name if total string size is ok
  1306. cbData += sizeof(c_szSeparator);
  1307. if ((dwByteCount + cbData) <= CB_MAX_REG_KEY_LEN)
  1308. {
  1309. dwByteCount += cbData;
  1310. lpszMfct = szManufacturer;
  1311. }
  1312. }
  1313. cbData = sizeof(szProvider);
  1314. lErr = RegQueryValueEx(hkeyDrv, REGSTR_VAL_PROVIDER_NAME, NULL, NULL,
  1315. (LPBYTE)szProvider, &cbData);
  1316. if (lErr == ERROR_SUCCESS)
  1317. {
  1318. // only use the provider name if total string size is ok
  1319. cbData += sizeof(c_szSeparator);
  1320. if ((dwByteCount + cbData) <= CB_MAX_REG_KEY_LEN)
  1321. {
  1322. dwByteCount += cbData;
  1323. lpszProv = szProvider;
  1324. }
  1325. }
  1326. }
  1327. }
  1328. // Weren't able to read key name components out of the driver node.
  1329. // Get them from the driver info data if one was given.
  1330. if (pdrvData && !dwByteCount)
  1331. {
  1332. lpszDesc = pdrvData->Description;
  1333. if (!lpszDesc || !lpszDesc[0])
  1334. {
  1335. // Didn't get a Description string. Fail the call.
  1336. goto exit;
  1337. }
  1338. dwByteCount = CbFromCch(lstrlen(lpszDesc)+1);
  1339. // Is the Description string *alone* too long to be a key name?
  1340. // If so then we're hosed - fail the call.
  1341. if (dwByteCount > CB_MAX_REG_KEY_LEN)
  1342. {
  1343. goto exit;
  1344. }
  1345. cbData = sizeof(c_szSeparator)
  1346. + CbFromCch(lstrlen(pdrvData->MfgName)+1);
  1347. if ((dwByteCount + cbData) <= CB_MAX_REG_KEY_LEN)
  1348. {
  1349. dwByteCount += cbData;
  1350. lpszMfct = pdrvData->MfgName;
  1351. }
  1352. cbData = sizeof(c_szSeparator)
  1353. + CbFromCch(lstrlen(pdrvData->ProviderName)+1);
  1354. if ((dwByteCount + cbData) <= CB_MAX_REG_KEY_LEN)
  1355. {
  1356. dwByteCount += cbData;
  1357. lpszProv = pdrvData->ProviderName;
  1358. }
  1359. }
  1360. // By now we should have a Description string. If not, fail the call.
  1361. if (!lpszDesc || !lpszDesc[0])
  1362. {
  1363. goto exit;
  1364. }
  1365. // Construct the key name string out of its components.
  1366. lstrcpy(pszKeyName, lpszDesc);
  1367. if (lpszMfct && *lpszMfct)
  1368. {
  1369. lstrcat(pszKeyName, c_szSeparator);
  1370. lstrcat(pszKeyName, lpszMfct);
  1371. }
  1372. if (lpszProv && *lpszProv)
  1373. {
  1374. lstrcat(pszKeyName, c_szSeparator);
  1375. lstrcat(pszKeyName, lpszProv);
  1376. }
  1377. // Write the key name to the driver node (we know it's not there already).
  1378. if (hkeyDrv)
  1379. {
  1380. lErr = RegSetValueEx(hkeyDrv, c_szRespKeyName, 0, REG_SZ,
  1381. (LPBYTE)pszKeyName, CbFromCch(lstrlen(pszKeyName)+1));
  1382. if (lErr != ERROR_SUCCESS)
  1383. {
  1384. TRACE_MSG(TF_ERROR, "RegSetValueEx(RespKeyName) failed: %#08lx.", lErr);
  1385. ASSERT(0);
  1386. }
  1387. }
  1388. bRet = TRUE;
  1389. exit:
  1390. return(bRet);
  1391. }
  1392. /*----------------------------------------------------------
  1393. Purpose: This function creates the common driver type key
  1394. for the given driver, or opens it if it already
  1395. exists, with the requested access.
  1396. NOTE: Either hkeyDrv or pdrvData must be provided.
  1397. Returns: TRUE on success
  1398. FALSE on error
  1399. Cond: --
  1400. */
  1401. BOOL
  1402. PUBLIC
  1403. OpenCommonDriverKey(
  1404. IN HKEY hkeyDrv, OPTIONAL
  1405. IN PSP_DRVINFO_DATA pdrvData, OPTIONAL
  1406. IN REGSAM samAccess,
  1407. OUT PHKEY phkeyComDrv)
  1408. {
  1409. BOOL bRet = FALSE; // assume failure
  1410. LONG lErr;
  1411. HKEY hkeyDrvInfo = NULL;
  1412. TCHAR szComDrv[MAX_REG_KEY_LEN];
  1413. TCHAR szPath[2*MAX_REG_KEY_LEN];
  1414. DWORD dwDisp;
  1415. if (!GetCommonDriverKeyName(hkeyDrv, pdrvData, sizeof(szComDrv), szComDrv))
  1416. {
  1417. TRACE_MSG(TF_ERROR, "GetCommonDriverKeyName() failed.");
  1418. goto exit;
  1419. }
  1420. TRACE_MSG(TF_WARNING, "GetCommonDriverKeyName(): %s", szComDrv);
  1421. // Construct the path to the common driver key.
  1422. lstrcpy(szPath, DRIVER_KEY TEXT("\\"));
  1423. lstrcat(szPath, szComDrv);
  1424. // Create the common driver key - it'll be opened if it already exists.
  1425. lErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szPath, 0, NULL,
  1426. REG_OPTION_NON_VOLATILE, samAccess, NULL, phkeyComDrv, &dwDisp);
  1427. if (lErr != ERROR_SUCCESS)
  1428. {
  1429. TRACE_MSG(TF_ERROR, "RegCreateKeyEx(%s) failed: %#08lx.", szPath, lErr);
  1430. goto exit;
  1431. }
  1432. bRet = TRUE;
  1433. exit:
  1434. return(bRet);
  1435. }
  1436. /*----------------------------------------------------------
  1437. Purpose: This function opens or creates the common Responses
  1438. key for the given driver, based on the given flags.
  1439. Returns: TRUE on success
  1440. FALSE on error
  1441. Cond: --
  1442. */
  1443. BOOL
  1444. PUBLIC
  1445. OpenCommonResponsesKey(
  1446. IN HKEY hkeyDrv,
  1447. IN CKFLAGS ckFlags,
  1448. IN REGSAM samAccess,
  1449. OUT PHKEY phkeyResp,
  1450. OUT LPDWORD lpdwExisted)
  1451. {
  1452. BOOL bRet = FALSE; // assume failure
  1453. LONG lErr;
  1454. HKEY hkeyComDrv = NULL;
  1455. DWORD dwRefCount, cbData;
  1456. *phkeyResp = NULL;
  1457. if (!OpenCommonDriverKey(hkeyDrv, NULL, KEY_ALL_ACCESS, &hkeyComDrv))
  1458. {
  1459. TRACE_MSG(TF_ERROR, "OpenCommonDriverKey() failed.");
  1460. goto exit;
  1461. }
  1462. if ((CKFLAG_OPEN | CKFLAG_CREATE) == (ckFlags & (CKFLAG_OPEN | CKFLAG_CREATE)))
  1463. {
  1464. ckFlags &= ~CKFLAG_CREATE;
  1465. }
  1466. // Create or open the common Responses key.
  1467. if (ckFlags & CKFLAG_OPEN)
  1468. {
  1469. lErr = RegOpenKeyEx(hkeyComDrv, c_szResponses, 0, samAccess, phkeyResp);
  1470. if (lErr != ERROR_SUCCESS)
  1471. {
  1472. TRACE_MSG(TF_ERROR, "RegOpenKeyEx(common drv) failed: %#08lx.", lErr);
  1473. ckFlags &= ~CKFLAG_OPEN;
  1474. ckFlags |= CKFLAG_CREATE;
  1475. }
  1476. }
  1477. if (ckFlags & CKFLAG_CREATE)
  1478. {
  1479. lErr = RegCreateKeyEx(hkeyComDrv, c_szResponses, 0, NULL,
  1480. REG_OPTION_NON_VOLATILE, samAccess, NULL, phkeyResp, lpdwExisted);
  1481. if (lErr != ERROR_SUCCESS)
  1482. {
  1483. TRACE_MSG(TF_ERROR, "RegCreateKeyEx(%s) failed: %#08lx.", c_szResponses, lErr);
  1484. ASSERT(0);
  1485. goto exit;
  1486. }
  1487. // Create or increment a common Responses key reference count value.
  1488. cbData = sizeof(dwRefCount);
  1489. if (*lpdwExisted == REG_OPENED_EXISTING_KEY)
  1490. {
  1491. lErr = RegQueryValueEx(hkeyComDrv, c_szRefCount, NULL, NULL,
  1492. (LPBYTE)&dwRefCount, &cbData);
  1493. // To accomodate modems installed before this reference count
  1494. // mechanism was added (post-Beta2), if the reference count doesn't
  1495. // exist then just ignore it & install anyways. In this case the
  1496. // shared Responses key will never be removed.
  1497. if (lErr == ERROR_SUCCESS)
  1498. {
  1499. ASSERT(dwRefCount); // expecting non-0 ref count
  1500. ASSERT(cbData == sizeof(DWORD)); // expecting DWORD ref count
  1501. dwRefCount++; // increment ref count
  1502. }
  1503. else
  1504. {
  1505. if (lErr == ERROR_FILE_NOT_FOUND)
  1506. dwRefCount = 0;
  1507. else
  1508. {
  1509. // some error other than key doesn't exist
  1510. TRACE_MSG(TF_ERROR, "RegQueryValueEx(RefCount) failed: %#08lx.", lErr);
  1511. goto exit;
  1512. }
  1513. }
  1514. }
  1515. else dwRefCount = 1;
  1516. if (dwRefCount)
  1517. {
  1518. lErr = RegSetValueEx(hkeyComDrv, c_szRefCount, 0, REG_DWORD,
  1519. (LPBYTE)&dwRefCount, cbData);
  1520. if (lErr != ERROR_SUCCESS)
  1521. {
  1522. TRACE_MSG(TF_ERROR, "RegSetValueEx(RefCount) failed: %#08lx.", lErr);
  1523. ASSERT(0);
  1524. goto exit;
  1525. }
  1526. }
  1527. }
  1528. bRet = TRUE;
  1529. exit:
  1530. if (!bRet)
  1531. {
  1532. // something failed - close any open Responses key
  1533. if (*phkeyResp)
  1534. RegCloseKey(*phkeyResp);
  1535. }
  1536. if (hkeyComDrv)
  1537. RegCloseKey(hkeyComDrv);
  1538. return(bRet);
  1539. }
  1540. /*----------------------------------------------------------
  1541. Purpose: This function finds the Responses key for the given
  1542. modem driver and returns an open hkey to it. The
  1543. Responses key may exist in the common driver type
  1544. key, or it may be in the individual driver key.
  1545. The key is opened with READ access.
  1546. Returns: TRUE on success
  1547. FALSE on error
  1548. Cond: --
  1549. */
  1550. BOOL
  1551. PUBLIC
  1552. OpenResponsesKey(
  1553. IN HKEY hkeyDrv,
  1554. OUT PHKEY phkeyResp)
  1555. {
  1556. LONG lErr;
  1557. // Try to open the common Responses subkey.
  1558. if (!OpenCommonResponsesKey(hkeyDrv, CKFLAG_OPEN, KEY_READ, phkeyResp, NULL))
  1559. {
  1560. TRACE_MSG(TF_ERROR, "OpenCommonResponsesKey() failed, assume non-existent.");
  1561. // Failing that, open the *old style* common Responses subkey.
  1562. if (!OLD_OpenCommonResponsesKey(hkeyDrv, phkeyResp))
  1563. {
  1564. // Failing that, try to open a Responses subkey in the driver node.
  1565. lErr = RegOpenKeyEx(hkeyDrv, c_szResponses, 0, KEY_READ, phkeyResp);
  1566. if (lErr != ERROR_SUCCESS)
  1567. {
  1568. TRACE_MSG(TF_ERROR, "RegOpenKeyEx() failed: %#08lx.", lErr);
  1569. return (FALSE);
  1570. }
  1571. }
  1572. }
  1573. return(TRUE);
  1574. }
  1575. /*----------------------------------------------------------
  1576. Purpose: This function deletes a registry key and all of
  1577. its subkeys. A registry key that is opened by an
  1578. application can be deleted without error by another
  1579. application in both Windows 95 and Windows NT.
  1580. This is by design. This code makes no attempt to
  1581. check or recover from partial deletions.
  1582. NOTE: Adapted from sample code in the MSDN Knowledge Base
  1583. article #Q142491.
  1584. Returns: ERROR_SUCCESS on success
  1585. WIN32 error code on error
  1586. Cond: --
  1587. */
  1588. DWORD
  1589. PRIVATE
  1590. RegDeleteKeyNT(
  1591. IN HKEY hStartKey,
  1592. IN LPTSTR pKeyName)
  1593. {
  1594. DWORD dwRtn, dwSubKeyLength;
  1595. LPTSTR pSubKey = NULL;
  1596. TCHAR szSubKey[MAX_REG_KEY_LEN]; // this should be dynamic.
  1597. HKEY hKey;
  1598. // do not allow NULL or empty key name
  1599. if (pKeyName && lstrlen(pKeyName))
  1600. {
  1601. if ((dwRtn = RegOpenKeyEx(hStartKey, pKeyName,
  1602. 0, KEY_ALL_ACCESS, &hKey)) == ERROR_SUCCESS)
  1603. {
  1604. while (dwRtn == ERROR_SUCCESS)
  1605. {
  1606. dwSubKeyLength = sizeof(szSubKey) / sizeof(TCHAR);
  1607. dwRtn = RegEnumKeyEx( hKey,
  1608. 0, // always index zero
  1609. szSubKey,
  1610. &dwSubKeyLength,
  1611. NULL,
  1612. NULL,
  1613. NULL,
  1614. NULL );
  1615. if (dwRtn == ERROR_NO_MORE_ITEMS)
  1616. {
  1617. dwRtn = RegDeleteKey(hStartKey, pKeyName);
  1618. break;
  1619. }
  1620. else if (dwRtn == ERROR_SUCCESS)
  1621. dwRtn = RegDeleteKeyNT(hKey, szSubKey);
  1622. }
  1623. RegCloseKey(hKey);
  1624. // Do not save return code because error
  1625. // has already occurred
  1626. }
  1627. }
  1628. else
  1629. dwRtn = ERROR_BADKEY;
  1630. return dwRtn;
  1631. }
  1632. /*----------------------------------------------------------
  1633. Purpose: This function deletes the common driver key (or
  1634. decrements its reference count) associated with the
  1635. driver given by name.
  1636. Returns: TRUE on success
  1637. FALSE on error
  1638. Cond: --
  1639. */
  1640. BOOL
  1641. PUBLIC
  1642. DeleteCommonDriverKeyByName(
  1643. IN LPTSTR pszKeyName)
  1644. {
  1645. BOOL bRet = FALSE; // assume failure
  1646. LONG lErr;
  1647. TCHAR szPath[2*MAX_REG_KEY_LEN];
  1648. HKEY hkeyComDrv, hkeyPrnt;
  1649. DWORD dwRefCount, cbData;
  1650. // Construct the path to the driver's common key and open it.
  1651. lstrcpy(szPath, DRIVER_KEY TEXT("\\"));
  1652. lstrcat(szPath, pszKeyName);
  1653. lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szPath, 0, KEY_ALL_ACCESS,
  1654. &hkeyComDrv);
  1655. if (lErr != ERROR_SUCCESS)
  1656. {
  1657. TRACE_MSG(TF_ERROR, "RegOpenKeyEx() failed: %#08lx.", lErr);
  1658. goto exit;
  1659. }
  1660. // Check the common driver key reference count and decrement
  1661. // it or delete the key (& the Responses subkey).
  1662. cbData = sizeof(dwRefCount);
  1663. lErr = RegQueryValueEx(hkeyComDrv, c_szRefCount, NULL, NULL,
  1664. (LPBYTE)&dwRefCount, &cbData);
  1665. // To accomodate modems installed before this reference count
  1666. // mechanism was added (post-Beta2), if the reference count doesn't
  1667. // exist then just ignore it. In this case the shared Responses key
  1668. // will never be removed.
  1669. if (lErr == ERROR_SUCCESS)
  1670. {
  1671. ASSERT(dwRefCount); // expecting non-0 ref count
  1672. if (--dwRefCount)
  1673. {
  1674. lErr = RegSetValueEx(hkeyComDrv, c_szRefCount, 0, REG_DWORD,
  1675. (LPBYTE)&dwRefCount, cbData);
  1676. if (lErr != ERROR_SUCCESS)
  1677. {
  1678. TRACE_MSG(TF_ERROR, "RegSetValueEx(RefCount) failed: %#08lx.", lErr);
  1679. ASSERT(0);
  1680. goto exit;
  1681. }
  1682. }
  1683. else
  1684. {
  1685. lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, DRIVER_KEY, 0,
  1686. KEY_ENUMERATE_SUB_KEYS, &hkeyPrnt);
  1687. if (lErr != ERROR_SUCCESS)
  1688. {
  1689. TRACE_MSG(TF_ERROR, "RegOpenKeyEx(Prnt) failed: %#08lx.", lErr);
  1690. goto exit;
  1691. }
  1692. lErr = RegDeleteKeyNT(hkeyPrnt, pszKeyName);
  1693. if (lErr != ERROR_SUCCESS)
  1694. {
  1695. TRACE_MSG(TF_ERROR, "RegDeleteKeyNT(ComDrv) failed: %#08lx.", lErr);
  1696. goto exit;
  1697. }
  1698. }
  1699. }
  1700. else if (lErr != ERROR_FILE_NOT_FOUND)
  1701. {
  1702. // some error other than key doesn't exist
  1703. TRACE_MSG(TF_ERROR, "RegQueryValueEx(RefCount) failed: %#08lx.", lErr);
  1704. goto exit;
  1705. }
  1706. bRet = TRUE;
  1707. exit:
  1708. return(bRet);
  1709. }
  1710. /*----------------------------------------------------------
  1711. Purpose: This function deletes the common driver key (or
  1712. decrements its reference count) associated with the
  1713. driver given by driver key.
  1714. Returns: TRUE on success
  1715. FALSE on error
  1716. Cond: --
  1717. */
  1718. BOOL
  1719. PUBLIC
  1720. DeleteCommonDriverKey(
  1721. IN HKEY hkeyDrv)
  1722. {
  1723. BOOL bRet = FALSE;
  1724. TCHAR szComDrv[MAX_REG_KEY_LEN];
  1725. // Get the name of the common driver key for this driver.
  1726. if (!GetCommonDriverKeyName(hkeyDrv, NULL, sizeof(szComDrv), szComDrv))
  1727. {
  1728. TRACE_MSG(TF_ERROR, "GetCommonDriverKeyName() failed.");
  1729. goto exit;
  1730. }
  1731. if (!DeleteCommonDriverKeyByName(szComDrv))
  1732. {
  1733. TRACE_MSG(TF_ERROR, "DeleteCommonDriverKey() failed.");
  1734. }
  1735. bRet = TRUE;
  1736. exit:
  1737. return(bRet);
  1738. }