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.

876 lines
25 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 2000
  6. //
  7. // File: miscutil.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "HotPlug.h"
  11. #include <initguid.h>
  12. #include <ntddstor.h>
  13. #include <wdmguid.h>
  14. LPTSTR
  15. FormatString(
  16. LPCTSTR format,
  17. ...
  18. )
  19. {
  20. LPTSTR str = NULL;
  21. va_list arglist;
  22. va_start(arglist, format);
  23. if (FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  24. format,
  25. 0,
  26. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
  27. (LPTSTR)&str,
  28. 0,
  29. &arglist
  30. ) == 0) {
  31. str = NULL;
  32. }
  33. va_end(arglist);
  34. return str;
  35. }
  36. PTCHAR
  37. BuildLocationInformation(
  38. DEVINST DevInst,
  39. HMACHINE hMachine
  40. )
  41. {
  42. CONFIGRET ConfigRet;
  43. ULONG ulSize;
  44. DWORD UINumber;
  45. PTCHAR Location = NULL;
  46. PTCHAR ParentName;
  47. DEVINST DevInstParent;
  48. int BusLocationStringId;
  49. TCHAR szBuffer[MAX_PATH];
  50. TCHAR UINumberDescFormat[MAX_PATH];
  51. TCHAR szFormat[MAX_PATH];
  52. HKEY hKey;
  53. DWORD Type = REG_SZ;
  54. szBuffer[0] = TEXT('\0');
  55. //
  56. // We will first get any LocationInformation for the device. This will either
  57. // be in the LocationInformationOverride value in the devices driver (software) key
  58. // or if that is not present we will look for the LocationInformation value in
  59. // the devices device (hardware) key.
  60. //
  61. ulSize = sizeof(szBuffer);
  62. if (CR_SUCCESS == CM_Open_DevNode_Key_Ex(DevInst,
  63. KEY_READ,
  64. 0,
  65. RegDisposition_OpenExisting,
  66. &hKey,
  67. CM_REGISTRY_SOFTWARE,
  68. hMachine
  69. )) {
  70. RegQueryValueEx(hKey,
  71. REGSTR_VAL_LOCATION_INFORMATION_OVERRIDE,
  72. NULL,
  73. &Type,
  74. (const PBYTE)szBuffer,
  75. &ulSize
  76. );
  77. RegCloseKey(hKey);
  78. }
  79. //
  80. // If the buffer is empty then we didn't get the LocationInformationOverride
  81. // value in the device's software key. So, we will see if their is a
  82. // LocationInformation value in the device's hardware key.
  83. //
  84. if (szBuffer[0] == TEXT('\0')) {
  85. //
  86. // Get the LocationInformation for this device.
  87. //
  88. ulSize = sizeof(szBuffer);
  89. CM_Get_DevNode_Registry_Property_Ex(DevInst,
  90. CM_DRP_LOCATION_INFORMATION,
  91. NULL,
  92. szBuffer,
  93. &ulSize,
  94. 0,
  95. hMachine
  96. );
  97. }
  98. //
  99. // UINumber has precedence over all other location information so check if this
  100. // device has a UINumber
  101. //
  102. ulSize = sizeof(UINumber);
  103. if ((CM_Get_DevNode_Registry_Property_Ex(DevInst,
  104. CM_DRP_UI_NUMBER,
  105. NULL,
  106. &UINumber,
  107. &ulSize,
  108. 0,
  109. hMachine
  110. ) == CR_SUCCESS) &&
  111. (ulSize > 0)) {
  112. UINumberDescFormat[0] = TEXT('\0');
  113. ulSize = sizeof(UINumberDescFormat);
  114. //
  115. // Get the UINumber description format string from the device's parent,
  116. // if there is one, otherwise default to 'Location %1'
  117. if ((CM_Get_Parent_Ex(&DevInstParent, DevInst, 0, hMachine) == CR_SUCCESS) &&
  118. (CM_Get_DevNode_Registry_Property_Ex(DevInstParent,
  119. CM_DRP_UI_NUMBER_DESC_FORMAT,
  120. NULL,
  121. UINumberDescFormat,
  122. &ulSize,
  123. 0,
  124. hMachine) == CR_SUCCESS) &&
  125. *UINumberDescFormat) {
  126. } else {
  127. LoadString(hHotPlug, IDS_UI_NUMBER_DESC_FORMAT, UINumberDescFormat, sizeof(UINumberDescFormat)/sizeof(TCHAR));
  128. }
  129. //
  130. // Prepend "at " to the begining of the UINumber string.
  131. //
  132. LoadString(hHotPlug, IDS_AT, szFormat, sizeof(szFormat)/sizeof(TCHAR));
  133. lstrcat(szFormat, UINumberDescFormat);
  134. //
  135. // Fill in the UINumber string
  136. //
  137. Location = FormatString(szFormat, UINumber);
  138. }
  139. //
  140. // We don't have a UINumber but we do have LocationInformation
  141. //
  142. else if (*szBuffer) {
  143. LoadString(hHotPlug, IDS_LOCATION, szFormat, sizeof(szFormat)/sizeof(TCHAR));
  144. Location = (PTCHAR)LocalAlloc(LPTR, lstrlen(szBuffer)*sizeof(TCHAR) + sizeof(szFormat) + sizeof(TCHAR));
  145. if (Location) {
  146. wsprintf(Location, szFormat, szBuffer);
  147. }
  148. }
  149. //
  150. // We don't have a UINumber or LocationInformation so we need to get a description
  151. // of the parent of this device.
  152. //
  153. else {
  154. ConfigRet = CM_Get_Parent_Ex(&DevInstParent, DevInst, 0, hMachine);
  155. if (ConfigRet == CR_SUCCESS) {
  156. //
  157. // Try the registry for FRIENDLYNAME
  158. //
  159. ulSize = sizeof(szBuffer);
  160. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInstParent,
  161. CM_DRP_FRIENDLYNAME,
  162. NULL,
  163. szBuffer,
  164. &ulSize,
  165. 0,
  166. hMachine
  167. );
  168. if (ConfigRet != CR_SUCCESS || !*szBuffer) {
  169. //
  170. // Try the registry for DEVICEDESC
  171. //
  172. ulSize = sizeof(szBuffer);
  173. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInstParent,
  174. CM_DRP_DEVICEDESC,
  175. NULL,
  176. szBuffer,
  177. &ulSize,
  178. 0,
  179. hMachine
  180. );
  181. if (ConfigRet != CR_SUCCESS || !*szBuffer) {
  182. GUID ClassGuid;
  183. //
  184. // Initialize ClassGuid to GUID_NULL
  185. //
  186. CopyMemory(&ClassGuid,
  187. &GUID_NULL,
  188. sizeof(GUID)
  189. );
  190. //
  191. // Try the registry for CLASSNAME
  192. //
  193. ulSize = sizeof(szBuffer);
  194. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInstParent,
  195. CM_DRP_CLASSGUID,
  196. NULL,
  197. szBuffer,
  198. &ulSize,
  199. 0,
  200. hMachine
  201. );
  202. if (ConfigRet == CR_SUCCESS) {
  203. pSetupGuidFromString(szBuffer, &ClassGuid);
  204. }
  205. if (!IsEqualGUID(ClassGuid, GUID_NULL) &&
  206. !IsEqualGUID(ClassGuid, GUID_DEVCLASS_UNKNOWN))
  207. {
  208. ulSize = sizeof(szBuffer);
  209. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInstParent,
  210. CM_DRP_CLASS,
  211. NULL,
  212. szBuffer,
  213. &ulSize,
  214. 0,
  215. hMachine
  216. );
  217. }
  218. else {
  219. ConfigRet = ~CR_SUCCESS;
  220. }
  221. }
  222. }
  223. }
  224. if (*szBuffer) {
  225. LoadString(hHotPlug, IDS_LOCATION_NOUINUMBER, szFormat, sizeof(szFormat)/sizeof(TCHAR));
  226. Location = (PTCHAR)LocalAlloc(LPTR, lstrlen(szBuffer)*sizeof(TCHAR) + sizeof(szFormat) + sizeof(TCHAR));
  227. if (Location) {
  228. wsprintf(Location, szFormat, szBuffer);
  229. }
  230. }
  231. }
  232. return Location;
  233. }
  234. PTCHAR
  235. BuildFriendlyName(
  236. DEVINST DevInst,
  237. HMACHINE hMachine
  238. )
  239. {
  240. PTCHAR FriendlyName;
  241. CONFIGRET ConfigRet;
  242. ULONG ulSize;
  243. TCHAR szBuffer[MAX_PATH];
  244. //
  245. // Try the registry for FRIENDLYNAME
  246. //
  247. ulSize = sizeof(szBuffer);
  248. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
  249. CM_DRP_FRIENDLYNAME,
  250. NULL,
  251. szBuffer,
  252. &ulSize,
  253. 0,
  254. hMachine
  255. );
  256. if (ConfigRet != CR_SUCCESS || !*szBuffer) {
  257. //
  258. // Try the registry for DEVICEDESC
  259. //
  260. ulSize = sizeof(szBuffer);
  261. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
  262. CM_DRP_DEVICEDESC,
  263. NULL,
  264. szBuffer,
  265. &ulSize,
  266. 0,
  267. hMachine
  268. );
  269. if (ConfigRet != CR_SUCCESS || !*szBuffer) {
  270. GUID ClassGuid;
  271. //
  272. // Initialize ClassGuid to GUID_NULL
  273. //
  274. CopyMemory(&ClassGuid,
  275. &GUID_NULL,
  276. sizeof(GUID)
  277. );
  278. //
  279. // Try the registry for CLASSNAME
  280. //
  281. ulSize = sizeof(szBuffer);
  282. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
  283. CM_DRP_CLASSGUID,
  284. NULL,
  285. szBuffer,
  286. &ulSize,
  287. 0,
  288. hMachine
  289. );
  290. if (ConfigRet == CR_SUCCESS) {
  291. pSetupGuidFromString(szBuffer, &ClassGuid);
  292. }
  293. if (!IsEqualGUID(ClassGuid, GUID_NULL) &&
  294. !IsEqualGUID(ClassGuid, GUID_DEVCLASS_UNKNOWN))
  295. {
  296. ulSize = sizeof(szBuffer);
  297. ConfigRet = CM_Get_DevNode_Registry_Property_Ex(DevInst,
  298. CM_DRP_CLASS,
  299. NULL,
  300. szBuffer,
  301. &ulSize,
  302. 0,
  303. hMachine
  304. );
  305. }
  306. else {
  307. ConfigRet = ~CR_SUCCESS;
  308. }
  309. }
  310. }
  311. if (ConfigRet == CR_SUCCESS && *szBuffer) {
  312. FriendlyName = (PTCHAR)LocalAlloc(LPTR, ulSize);
  313. if (FriendlyName) {
  314. memcpy(FriendlyName, szBuffer, ulSize);
  315. }
  316. }
  317. else {
  318. FriendlyName = NULL;
  319. }
  320. return FriendlyName;
  321. }
  322. /* ----------------------------------------------------------------------
  323. * SetDlgText - Set Dialog Text Field
  324. *
  325. * Concatenates a number of string resources and does a SetWindowText()
  326. * for a dialog text control.
  327. *
  328. * Parameters:
  329. *
  330. * hDlg - Dialog handle
  331. * iControl - Dialog control ID to receive text
  332. * nStartString - ID of first string resource to concatenate
  333. * nEndString - ID of last string resource to concatenate
  334. *
  335. * Note: the string IDs must be consecutive.
  336. */
  337. void
  338. SetDlgText(HWND hDlg, int iControl, int nStartString, int nEndString)
  339. {
  340. int iX;
  341. TCHAR szText[MAX_PATH];
  342. szText[0] = '\0';
  343. for (iX = nStartString; iX<= nEndString; iX++) {
  344. LoadString(hHotPlug,
  345. iX,
  346. szText + lstrlen(szText),
  347. sizeof(szText)/sizeof(TCHAR) - lstrlen(szText)
  348. );
  349. }
  350. if (iControl) {
  351. SetDlgItemText(hDlg, iControl, szText);
  352. }
  353. else {
  354. SetWindowText(hDlg, szText);
  355. }
  356. }
  357. VOID
  358. HotPlugPropagateMessage(
  359. HWND hWnd,
  360. UINT uMessage,
  361. WPARAM wParam,
  362. LPARAM lParam
  363. )
  364. {
  365. while ((hWnd = GetWindow(hWnd, GW_CHILD))) {
  366. SendMessage(hWnd, uMessage, wParam, lParam);
  367. }
  368. }
  369. BOOL
  370. RemovalPermission(
  371. void
  372. )
  373. {
  374. return TRUE;
  375. }
  376. int
  377. HPMessageBox(
  378. HWND hWnd,
  379. int IdText,
  380. int IdCaption,
  381. UINT Type
  382. )
  383. {
  384. TCHAR szText[MAX_PATH];
  385. TCHAR szCaption[MAX_PATH];
  386. if (LoadString(hHotPlug, IdText, szText, MAX_PATH) &&
  387. LoadString(hHotPlug, IdCaption, szCaption, MAX_PATH))
  388. {
  389. return MessageBox(hWnd, szText, szCaption, Type);
  390. }
  391. return IDIGNORE;
  392. }
  393. void
  394. InvalidateTreeItemRect(
  395. HWND hwndTree,
  396. HTREEITEM hTreeItem
  397. )
  398. {
  399. RECT rect;
  400. if (hTreeItem && TreeView_GetItemRect(hwndTree, hTreeItem, &rect, FALSE)) {
  401. InvalidateRect(hwndTree, &rect, FALSE);
  402. }
  403. }
  404. DWORD
  405. GetHotPlugFlags(
  406. PHKEY phKey
  407. )
  408. {
  409. HKEY hKey;
  410. LONG Error;
  411. DWORD HotPlugFlags, cbHotPlugFlags;
  412. Error = RegCreateKey(HKEY_CURRENT_USER, REGSTR_PATH_SYSTRAY, &hKey);
  413. if (Error == ERROR_SUCCESS) {
  414. cbHotPlugFlags = sizeof(HotPlugFlags);
  415. Error = RegQueryValueEx(hKey,
  416. szHotPlugFlags,
  417. NULL,
  418. NULL,
  419. (LPBYTE)&HotPlugFlags,
  420. &cbHotPlugFlags
  421. );
  422. if (phKey) {
  423. *phKey = hKey;
  424. }
  425. else {
  426. RegCloseKey(hKey);
  427. }
  428. }
  429. if (Error != ERROR_SUCCESS) {
  430. HotPlugFlags = 0;
  431. }
  432. return HotPlugFlags;
  433. }
  434. //
  435. // This function determines if the device is a boot storage device.
  436. // We spit out a warning when users are trying to remove or disable
  437. // a boot storage device(or a device contains a boot storage device).
  438. //
  439. // INPUT:
  440. // NONE
  441. // OUTPUT:
  442. // TRUE if the device is a boot device
  443. // FALSE if the device is not a boot device
  444. LPTSTR
  445. DevNodeToDriveLetter(
  446. DEVINST DevInst
  447. )
  448. {
  449. ULONG ulSize;
  450. TCHAR szBuffer[MAX_PATH];
  451. TCHAR DeviceID[MAX_DEVICE_ID_LEN];
  452. PTSTR DriveString = NULL;
  453. PTSTR DeviceInterface = NULL;
  454. if (CM_Get_Device_ID_Ex(DevInst,
  455. DeviceID,
  456. sizeof(DeviceID)/sizeof(TCHAR),
  457. 0,
  458. NULL
  459. ) != CR_SUCCESS) {
  460. return FALSE;
  461. }
  462. // create a device info list contains all the interface classed
  463. // exposed by this device.
  464. ulSize = 0;
  465. if ((CM_Get_Device_Interface_List_Size(&ulSize,
  466. (LPGUID)&VolumeClassGuid,
  467. DeviceID,
  468. 0) == CR_SUCCESS) &&
  469. (ulSize > 1) &&
  470. ((DeviceInterface = (PTSTR)LocalAlloc(LPTR, ulSize*sizeof(TCHAR))) != NULL) &&
  471. (CM_Get_Device_Interface_List((LPGUID)&VolumeClassGuid,
  472. DeviceID,
  473. DeviceInterface,
  474. ulSize,
  475. 0
  476. ) == CR_SUCCESS) &&
  477. *DeviceInterface)
  478. {
  479. PTSTR devicePath, p;
  480. TCHAR thisVolumeName[MAX_PATH];
  481. TCHAR enumVolumeName[MAX_PATH];
  482. TCHAR driveName[4];
  483. ULONG length;
  484. BOOL bResult;
  485. length = lstrlen(DeviceInterface);
  486. devicePath = (PTSTR)LocalAlloc(LPTR, (length + 1) * sizeof(TCHAR) + sizeof(UNICODE_NULL));
  487. if (devicePath) {
  488. lstrcpyn(devicePath, DeviceInterface, length + 1);
  489. p = wcschr(&(devicePath[4]), TEXT('\\'));
  490. if (!p) {
  491. //
  492. // No refstring is present in the symbolic link; add a trailing
  493. // '\' char (as required by GetVolumeNameForVolumeMountPoint).
  494. //
  495. p = devicePath + length;
  496. *p = TEXT('\\');
  497. }
  498. p++;
  499. *p = UNICODE_NULL;
  500. thisVolumeName[0] = UNICODE_NULL;
  501. bResult = GetVolumeNameForVolumeMountPoint(devicePath,
  502. thisVolumeName,
  503. MAX_PATH
  504. );
  505. LocalFree(devicePath);
  506. if (bResult && thisVolumeName[0]) {
  507. driveName[1] = TEXT(':');
  508. driveName[2] = TEXT('\\');
  509. driveName[3] = TEXT('\0');
  510. for (driveName[0] = TEXT('A'); driveName[0] <= TEXT('Z'); driveName[0]++) {
  511. enumVolumeName[0] = TEXT('\0');
  512. GetVolumeNameForVolumeMountPoint(driveName, enumVolumeName, MAX_PATH);
  513. if (!lstrcmpi(thisVolumeName, enumVolumeName)) {
  514. driveName[2] = TEXT('\0');
  515. wsprintf(szBuffer, TEXT(" - (%s)"), driveName);
  516. DriveString = (PTSTR)LocalAlloc(LPTR, (lstrlen(szBuffer) + 1) * sizeof(TCHAR));
  517. if (DriveString) {
  518. lstrcpy(DriveString, szBuffer);
  519. }
  520. break;
  521. }
  522. }
  523. }
  524. }
  525. }
  526. if (DeviceInterface) {
  527. LocalFree(DeviceInterface);
  528. }
  529. return DriveString;
  530. }
  531. BOOL
  532. IsHotPlugDevice(
  533. DEVINST DevInst,
  534. HMACHINE hMachine
  535. )
  536. /**+
  537. A device is considered a HotPlug device if the following are TRUE:
  538. - has Capability CM_DEVCAP_REMOVABLE
  539. - does NOT have Capability CM_DEVCAP_SURPRISEREMOVALOK
  540. - does NOT have Capability CM_DEVCAP_DOCKDEVICE
  541. - must be started (have the DN_STARTED devnode flag)
  542. - unless has capability CM_DEVCAP_EJECTSUPPORTED
  543. - or unless has capability CM_DEVCAP_RAWDEVICEOK
  544. Returns:
  545. TRUE if this is a HotPlug device
  546. FALSE if this is not a HotPlug device.
  547. -**/
  548. {
  549. DWORD Capabilities;
  550. DWORD Len;
  551. DWORD Status, Problem;
  552. Capabilities = Status = Problem = 0;
  553. Len = sizeof(Capabilities);
  554. if (CM_Get_DevNode_Registry_Property_Ex(DevInst,
  555. CM_DRP_CAPABILITIES,
  556. NULL,
  557. (PVOID)&Capabilities,
  558. &Len,
  559. 0,
  560. hMachine) != CR_SUCCESS) {
  561. return FALSE;
  562. }
  563. if (CM_Get_DevNode_Status_Ex(&Status,
  564. &Problem,
  565. DevInst,
  566. 0,
  567. hMachine) != CR_SUCCESS) {
  568. return FALSE;
  569. }
  570. //
  571. // If this device is not removable, or it is surprise removal ok, or
  572. // it is a dock device, then it is not a hotplug device.
  573. //
  574. if ((!(Capabilities & CM_DEVCAP_REMOVABLE)) ||
  575. (Capabilities & CM_DEVCAP_SURPRISEREMOVALOK) ||
  576. (Capabilities & CM_DEVCAP_DOCKDEVICE)) {
  577. return FALSE;
  578. }
  579. //
  580. // We won't consider a device to be a hotplug device if it is not started,
  581. // unless it is either RAW capabile or an eject capable device.
  582. //
  583. // The reason for this test is that a bus driver might set the
  584. // CM_DEVCAP_REMOVABLE capability, but if the PDO doesn't get loaded then
  585. // it can't set the CM_DEVCAP_SURPRISEREMOVALOK. So we won't trust the
  586. // CM_DEVCAP_REMOVABLE capability if the PDO is not started.
  587. //
  588. if ((!(Capabilities & CM_DEVCAP_EJECTSUPPORTED)) &&
  589. (!(Status & DN_STARTED))) {
  590. return FALSE;
  591. }
  592. return TRUE;
  593. }
  594. BOOL
  595. OpenPipeAndEventHandles(
  596. IN LPWSTR szCmd,
  597. OUT LPHANDLE lphHotPlugPipe,
  598. OUT LPHANDLE lphHotPlugEvent
  599. )
  600. {
  601. BOOL status = FALSE;
  602. HANDLE hPipe = INVALID_HANDLE_VALUE;
  603. HANDLE hEvent = NULL;
  604. ULONG ulEventNameSize;
  605. WCHAR szEventName[MAX_PATH];
  606. DWORD dwBytesRead;
  607. __try {
  608. //
  609. // Validate supplied arguments.
  610. //
  611. if (!lphHotPlugPipe || !lphHotPlugEvent) {
  612. return FALSE;
  613. }
  614. //
  615. // Make sure that a named pipe was specified in the cmd line.
  616. //
  617. if(!szCmd || !*szCmd) {
  618. return FALSE;
  619. }
  620. //
  621. // Wait for the specified named pipe to become available from the server.
  622. //
  623. if (!WaitNamedPipe(szCmd,
  624. 180000) // BUGBUG-2000/07/10-jamesca: How long should we wait?
  625. ) {
  626. return FALSE;
  627. }
  628. //
  629. // Open a handle to the specified named pipe
  630. //
  631. hPipe = CreateFile(szCmd,
  632. GENERIC_READ,
  633. 0,
  634. NULL,
  635. OPEN_EXISTING,
  636. 0,
  637. NULL);
  638. if (hPipe == INVALID_HANDLE_VALUE) {
  639. return FALSE;
  640. }
  641. //
  642. // The very first thing in the pipe should be the size of the event name.
  643. //
  644. if (ReadFile(hPipe,
  645. (LPVOID)&ulEventNameSize,
  646. sizeof(ULONG),
  647. &dwBytesRead,
  648. NULL)) {
  649. ASSERT(ulEventNameSize != 0);
  650. if ((ulEventNameSize == 0) ||
  651. (ulEventNameSize > MAX_PATH)) {
  652. goto clean0;
  653. }
  654. //
  655. // The next thing in the pipe should be the name of the event.
  656. //
  657. if (!ReadFile(hPipe,
  658. (LPVOID)&szEventName,
  659. ulEventNameSize,
  660. &dwBytesRead,
  661. NULL)) {
  662. goto clean0;
  663. }
  664. } else {
  665. if (GetLastError() == ERROR_INVALID_HANDLE) {
  666. //
  667. // The handle to the named pipe is not valid. Make sure we don't
  668. // try to close it on exit.
  669. //
  670. hPipe = INVALID_HANDLE_VALUE;
  671. }
  672. goto clean0;
  673. }
  674. //
  675. // Open a handle to the specified named event that we can set and wait on.
  676. //
  677. hEvent = OpenEventW(EVENT_MODIFY_STATE | SYNCHRONIZE,
  678. FALSE,
  679. szEventName);
  680. if (hEvent == NULL) {
  681. goto clean0;
  682. }
  683. //
  684. // We should now have valid handles to both the pipe and the event.
  685. //
  686. status = TRUE;
  687. ASSERT((hPipe != INVALID_HANDLE_VALUE) && hEvent);
  688. clean0:
  689. ;
  690. } __except(EXCEPTION_EXECUTE_HANDLER) {
  691. status = FALSE;
  692. }
  693. if (status) {
  694. *lphHotPlugPipe = hPipe;
  695. *lphHotPlugEvent = hEvent;
  696. } else {
  697. if (hPipe != INVALID_HANDLE_VALUE) {
  698. CloseHandle(hPipe);
  699. }
  700. if (hEvent) {
  701. CloseHandle(hEvent);
  702. }
  703. }
  704. return status;
  705. }