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.

1503 lines
38 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation
  3. Module Name:
  4. api.cpp
  5. Abstract:
  6. This module implements Device Manager exported APIs.
  7. Author:
  8. William Hsieh (williamh) created
  9. Revision History:
  10. --*/
  11. #include "devmgr.h"
  12. #include "devgenpg.h"
  13. #include "devdrvpg.h"
  14. #include "devpopg.h"
  15. #include "api.h"
  16. #include "printer.h"
  17. #include "tswizard.h"
  18. STDAPI_(BOOL)
  19. DeviceManager_ExecuteA(
  20. HWND hwndStub,
  21. HINSTANCE hAppInstance,
  22. LPCWSTR lpMachineName,
  23. int nCmdShow
  24. )
  25. /*++
  26. See DeviceManager_Execute function below.
  27. --*/
  28. {
  29. try
  30. {
  31. CTString tstrMachineName(lpMachineName);
  32. return DeviceManager_Execute(hwndStub,
  33. hAppInstance,
  34. (LPCTSTR)tstrMachineName,
  35. nCmdShow
  36. );
  37. }
  38. catch(CMemoryException* e)
  39. {
  40. e->Delete();
  41. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  42. }
  43. return FALSE;
  44. }
  45. STDAPI_(BOOL)
  46. DeviceManager_ExecuteW(
  47. HWND hwndStub,
  48. HINSTANCE hAppInstance,
  49. LPCWSTR lpMachineName,
  50. int nCmdShow
  51. )
  52. /*++
  53. See DeviceManager_Execute function below.
  54. --*/
  55. {
  56. try
  57. {
  58. CTString tstrMachineName(lpMachineName);
  59. return DeviceManager_Execute(hwndStub,
  60. hAppInstance,
  61. (LPCTSTR)tstrMachineName,
  62. nCmdShow
  63. );
  64. }
  65. catch(CMemoryException* e)
  66. {
  67. e->Delete();
  68. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  69. }
  70. return FALSE;
  71. }
  72. BOOL
  73. DeviceManager_Execute(
  74. HWND hwndStub,
  75. HINSTANCE hAppInstance,
  76. LPCTSTR lpMachineName,
  77. int nCmdShow
  78. )
  79. /*++
  80. Routine Description:
  81. This function is executed via a rundll command line and can have the
  82. following form:
  83. rundll32.exe devmgr.dll, DeviceManager_Execute
  84. rundll32.exe devmgr.dll, DeviceManager_Execute <remote machine name>
  85. This function will call ShelExecuteEx to create a new device manager process,
  86. where the new device manager can be for the local machine or for a machine
  87. name that is passed in on the rundll command line.
  88. Arguments:
  89. hwndStub - Windows handle to receive any message boxes that might be
  90. displayed.
  91. hAppInstance - HINSTANCE.
  92. lpMachineName - Name of a remote machine that the new device manager
  93. process should connect to and show it's devices.
  94. nCmdShow - Flag that specifies how device manager should be shown when
  95. it is opened. It can be one of the SW_ values (i.e. SW_SHOW).
  96. Return Value:
  97. returns TRUE if the device manager process was successfully created, or
  98. FALSE otherwise.
  99. --*/
  100. {
  101. SHELLEXECUTEINFO sei;
  102. TCHAR Parameters[MAX_PATH];
  103. String strMachineOptions;
  104. String strParameters;
  105. if (lpMachineName &&
  106. !VerifyMachineName(lpMachineName)) {
  107. //
  108. // We were unable to connect to the remote machine either because it
  109. // doesn't exist, or because we don't have the proper access.
  110. // The VerifyMachineName API sets the appropriate last error code.
  111. //
  112. return FALSE;
  113. }
  114. if (lpMachineName == NULL) {
  115. //
  116. // The lpMachineName was NULL so don't add a machine name to the command
  117. // line.
  118. //
  119. strMachineOptions.Empty();
  120. } else {
  121. strMachineOptions.Format(DEVMGR_MACHINENAME_OPTION, lpMachineName);
  122. }
  123. WCHAR* FilePart;
  124. DWORD Size;
  125. Size = SearchPath(NULL, DEVMGR_MSC_FILE, NULL, ARRAYLEN(Parameters), Parameters, &FilePart);
  126. if (Size && (Size <= MAX_PATH)) {
  127. strParameters = Parameters;
  128. } else {
  129. strParameters = DEVMGR_MSC_FILE;
  130. }
  131. //
  132. // If we have a machine name then add it onto the end.
  133. //
  134. if (!strMachineOptions.IsEmpty()) {
  135. strParameters += MMC_COMMAND_LINE;
  136. strParameters += strMachineOptions;
  137. }
  138. memset(&sei, 0, sizeof(sei));
  139. sei.cbSize = sizeof(sei);
  140. sei.hwnd = hwndStub;
  141. sei.nShow = nCmdShow;
  142. sei.hInstApp = hAppInstance;
  143. sei.lpFile = MMC_FILE;
  144. sei.lpParameters = (LPTSTR)strParameters;
  145. return ShellExecuteEx(&sei);
  146. }
  147. BOOL
  148. AddPageCallback(
  149. HPROPSHEETPAGE hPage,
  150. LPARAM lParam
  151. )
  152. {
  153. CPropSheetData* ppsData = (CPropSheetData*)lParam;
  154. ASSERT(ppsData);
  155. return ppsData->InsertPage(hPage);
  156. }
  157. void
  158. ReportCmdLineError(
  159. HWND hwndParent,
  160. int ErrorStringID,
  161. LPCTSTR Caption
  162. )
  163. {
  164. String strTitle, strMsg;
  165. strMsg.LoadString(g_hInstance, ErrorStringID);
  166. if (!Caption)
  167. {
  168. strTitle.LoadString(g_hInstance, IDS_NAME_DEVMGR);
  169. Caption = (LPTSTR)strTitle;
  170. }
  171. MessageBox(hwndParent, (LPTSTR)strMsg, Caption, MB_OK | MB_ICONERROR);
  172. }
  173. STDAPI_(void)
  174. DeviceProperties_RunDLLA(
  175. HWND hwndStub,
  176. HINSTANCE hAppInstance,
  177. LPSTR lpCmdLine,
  178. int nCmdShow
  179. )
  180. /*++
  181. See DeviceProperties_RunDLL function below.
  182. --*/
  183. {
  184. try
  185. {
  186. CTString tstrCmdLine(lpCmdLine);
  187. DeviceProperties_RunDLL(hwndStub,
  188. hAppInstance,
  189. (LPCTSTR)tstrCmdLine,
  190. nCmdShow
  191. );
  192. }
  193. catch (CMemoryException* e)
  194. {
  195. e->ReportError();
  196. e->Delete();
  197. }
  198. }
  199. STDAPI_(void)
  200. DeviceProperties_RunDLLW(
  201. HWND hwndStub,
  202. HINSTANCE hAppInstance,
  203. LPWSTR lpCmdLine,
  204. int nCmdShow
  205. )
  206. /*++
  207. See DeviceProperties_RunDLL function below.
  208. --*/
  209. {
  210. try
  211. {
  212. CTString tstrCmdLine(lpCmdLine);
  213. DeviceProperties_RunDLL(hwndStub,
  214. hAppInstance,
  215. (LPCTSTR)tstrCmdLine,
  216. nCmdShow
  217. );
  218. }
  219. catch (CMemoryException* e)
  220. {
  221. e->ReportError();
  222. e->Delete();
  223. }
  224. }
  225. void
  226. DeviceProperties_RunDLL(
  227. HWND hwndStub,
  228. HINSTANCE hAppInstance,
  229. LPCTSTR lpCmdLine,
  230. int nCmdShow
  231. )
  232. /*++
  233. Routine Description:
  234. This API will bring up the property pages for the specified device. Other
  235. options, such as the remote machine name, whether the device manager tree
  236. should be shown or not, whether the resource tab should be shows, and
  237. whether the troubleshooter should be automatically launched, can also be
  238. specified.
  239. This function is executed via a rundll command line and can have the
  240. following form:
  241. rundll32.exe devmgr.dll, DeviceProperties_RunDLL <options>
  242. Additional command line options that are excepted are:
  243. /MachineName <machine name>
  244. If this option is specified then the API will bring up the properties
  245. for the specified device on this remote machine.
  246. /DeviceId <device instance Id>
  247. If this option is specified then this will be the device for which
  248. the properties will be displayed for.
  249. NOTE: The caller must either specify a DeviceId or use the
  250. ShowDeviceTree command line option.
  251. /ShowDeviceTree
  252. If this command line option is specified then the property sheet
  253. will be displayed in front of the entire device manager tree.
  254. /Flags <flags>
  255. The following flags are supported:
  256. DEVPROP_SHOW_RESOURCE_TAB 0x00000001
  257. DEVPROP_LAUNCH_TROUBLESHOOTER 0x00000002
  258. Arguments:
  259. hwndStub - Windows handle to receive any message boxes that might be
  260. displayed.
  261. hAppInstance - HINSTANCE.
  262. lpCmdLine - Name of a remote machine that the new device manager
  263. process should connect to and show it's devices.
  264. nCmdShow - Flag that specifies how device manager should be shown when
  265. it is opened. It can be one of the SW_ values (i.e. SW_SHOW).
  266. Return Value:
  267. none
  268. --*/
  269. {
  270. UNREFERENCED_PARAMETER(hAppInstance);
  271. UNREFERENCED_PARAMETER(nCmdShow);
  272. try
  273. {
  274. CRunDLLCommandLine CmdLine;
  275. CmdLine.ParseCommandLine(lpCmdLine);
  276. if (NULL == CmdLine.GetDeviceID())
  277. {
  278. ReportCmdLineError(hwndStub, IDS_NO_DEVICEID);
  279. return;
  280. }
  281. //
  282. // Let the DevicePropertiesEx API do all the appropriate error checking.
  283. //
  284. DevicePropertiesEx(hwndStub,
  285. CmdLine.GetMachineName(),
  286. CmdLine.GetDeviceID(),
  287. CmdLine.GetFlags(),
  288. CmdLine.ToShowDeviceTree()
  289. );
  290. }
  291. catch (CMemoryException* e)
  292. {
  293. e->ReportError();
  294. e->Delete();
  295. return;
  296. }
  297. }
  298. STDAPI_(int)
  299. DevicePropertiesA(
  300. HWND hwndParent,
  301. LPCSTR MachineName,
  302. LPCSTR DeviceID,
  303. BOOL ShowDeviceTree
  304. )
  305. /*++
  306. See DevicePropertiesEx function below.
  307. --*/
  308. {
  309. try
  310. {
  311. CTString tstrMachineName(MachineName);
  312. CTString tstrDeviceID(DeviceID);
  313. return DevicePropertiesEx(hwndParent,
  314. (LPCTSTR)tstrMachineName,
  315. (LPCTSTR)tstrDeviceID,
  316. DEVPROP_SHOW_RESOURCE_TAB,
  317. ShowDeviceTree
  318. );
  319. }
  320. catch (CMemoryException* e)
  321. {
  322. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  323. e->Delete();
  324. }
  325. return 0;
  326. }
  327. STDAPI_(int)
  328. DevicePropertiesW(
  329. HWND hwndParent,
  330. LPCWSTR MachineName,
  331. LPCWSTR DeviceID,
  332. BOOL ShowDeviceTree
  333. )
  334. /*++
  335. See DevicePropertiesEx function below.
  336. --*/
  337. {
  338. try
  339. {
  340. CTString tstrMachineName(MachineName);
  341. CTString tstrDeviceID(DeviceID);
  342. return DevicePropertiesEx(hwndParent,
  343. (LPCTSTR)tstrMachineName,
  344. (LPCTSTR)tstrDeviceID,
  345. DEVPROP_SHOW_RESOURCE_TAB,
  346. ShowDeviceTree
  347. );
  348. }
  349. catch (CMemoryException* e)
  350. {
  351. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  352. e->Delete();
  353. }
  354. return 0;
  355. }
  356. STDAPI_(int)
  357. DevicePropertiesExA(
  358. HWND hwndParent,
  359. LPCSTR MachineName,
  360. LPCSTR DeviceID,
  361. DWORD Flags,
  362. BOOL ShowDeviceTree
  363. )
  364. /*++
  365. See DevicePropertiesEx function below.
  366. --*/
  367. {
  368. try
  369. {
  370. CTString tstrMachineName(MachineName);
  371. CTString tstrDeviceID(DeviceID);
  372. return DevicePropertiesEx(hwndParent,
  373. (LPCTSTR)tstrMachineName,
  374. (LPCTSTR)tstrDeviceID,
  375. Flags,
  376. ShowDeviceTree
  377. );
  378. }
  379. catch (CMemoryException* e)
  380. {
  381. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  382. e->Delete();
  383. }
  384. return 0;
  385. }
  386. STDAPI_(int)
  387. DevicePropertiesExW(
  388. HWND hwndParent,
  389. LPCWSTR MachineName,
  390. LPCWSTR DeviceID,
  391. DWORD Flags,
  392. BOOL ShowDeviceTree
  393. )
  394. /*++
  395. See DevicePropertiesEx function below.
  396. --*/
  397. {
  398. try
  399. {
  400. CTString tstrMachineName(MachineName);
  401. CTString tstrDeviceID(DeviceID);
  402. return DevicePropertiesEx(hwndParent,
  403. (LPCTSTR)tstrMachineName,
  404. (LPCTSTR)tstrDeviceID,
  405. Flags,
  406. ShowDeviceTree
  407. );
  408. }
  409. catch (CMemoryException* e)
  410. {
  411. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  412. e->Delete();
  413. }
  414. return 0;
  415. }
  416. int
  417. DevicePropertiesEx(
  418. HWND hwndParent,
  419. LPCTSTR MachineName,
  420. LPCTSTR DeviceID,
  421. DWORD Flags,
  422. BOOL ShowDeviceTree
  423. )
  424. /*++
  425. Routine Description:
  426. This API will bring up the property page for the specified device.
  427. Arguments:
  428. hwndParent - the caller's window handle to be used as the owner window
  429. of the property page and any other windows this API may create.
  430. MachineName - optional machine name. If given, it must be in its fully
  431. qualified form. NULL means local machine
  432. DeviceId - device instance id of the device that this API should create
  433. the property sheet for.
  434. Flags - the following flags are supported:
  435. DEVPROP_SHOW_RESOURCE_TAB 0x00000001 - show the resource tab, by
  436. default the resource tab
  437. is not shown.
  438. DEVPROP_LAUNCH_TROUBLESHOOTER 0x00000002 - Automatically launch the
  439. troubleshooter for this
  440. device.
  441. ShowDeviceTree - If specified then the device manager tree is shown. If
  442. the DeviceID is specified then only that device is shown
  443. in the tree, otherwise all devices are shown.
  444. Return Value:
  445. The return value from PropertySheet, including ID_PSREBOOTSYSTEM if
  446. a reboot is needed due to any user actions.
  447. -1 is returned in case of an error.
  448. --*/
  449. {
  450. HPROPSHEETPAGE hPage;
  451. DWORD DiFlags;
  452. DWORD DiFlagsEx;
  453. //
  454. // Verify that a DeviceID was passed in unless they want to show the
  455. // whole device tree.
  456. //
  457. if ((!DeviceID || (TEXT('\0') == *DeviceID)) && !ShowDeviceTree) {
  458. SetLastError(ERROR_INVALID_PARAMETER);
  459. return -1;
  460. }
  461. //
  462. // Verify that valid flags are passed in
  463. //
  464. if (Flags &~ DEVPROP_BITS) {
  465. SetLastError(ERROR_INVALID_FLAGS);
  466. return -1;
  467. }
  468. if (MachineName &&
  469. !VerifyMachineName(MachineName)) {
  470. //
  471. // We were unable to connect to the remote machine either because it
  472. // doesn't exist, or because we don't have the proper access.
  473. // The VerifyMachineName API sets the appropriate last error code.
  474. //
  475. return -1;
  476. }
  477. if (ShowDeviceTree) {
  478. return PropertyRunDeviceTree(hwndParent, MachineName, DeviceID);
  479. }
  480. int Result = -1;
  481. CDevice* pDevice;
  482. PVOID Context;
  483. try {
  484. CMachine TheMachine(MachineName);
  485. // create the machine just for this device
  486. if (!TheMachine.Initialize(hwndParent, DeviceID)) {
  487. SetLastError(ERROR_NO_SUCH_DEVINST);
  488. return -1;
  489. }
  490. if (!TheMachine.GetFirstDevice(&pDevice, Context)) {
  491. SetLastError(ERROR_NO_SUCH_DEVINST);
  492. return -1;
  493. }
  494. //
  495. // If the troubleshooter should be launched then set the appropriate
  496. // BOOL inside of the pDevice class.
  497. //
  498. if (Flags & DEVPROP_LAUNCH_TROUBLESHOOTER) {
  499. pDevice->m_bLaunchTroubleShooter = TRUE;
  500. }
  501. CPropSheetData& psd = pDevice->m_psd;
  502. //
  503. // Initialize CPropSheetData without ConsoleHandle
  504. //
  505. if (psd.Create(g_hInstance, hwndParent, MAX_PROP_PAGES, 0l)) {
  506. psd.m_psh.pszCaption = pDevice->GetDisplayName();
  507. //
  508. // Add any class/device specific property pages.
  509. //
  510. TheMachine.DiGetClassDevPropertySheet(*pDevice, &psd.m_psh,
  511. MAX_PROP_PAGES,
  512. TheMachine.IsLocal() ?
  513. DIGCDP_FLAG_ADVANCED :
  514. DIGCDP_FLAG_REMOTE_ADVANCED);
  515. //
  516. // Add the general tab
  517. //
  518. DiFlags = TheMachine.DiGetFlags(*pDevice);
  519. DiFlagsEx = TheMachine.DiGetExFlags(*pDevice);
  520. if (DiFlags & DI_GENERALPAGE_ADDED) {
  521. String strWarning;
  522. strWarning.LoadString(g_hInstance, IDS_GENERAL_PAGE_WARNING);
  523. MessageBox(hwndParent, (LPTSTR)strWarning, pDevice->GetDisplayName(),
  524. MB_ICONEXCLAMATION | MB_OK);
  525. //
  526. // fall through to create our general page.
  527. //
  528. }
  529. SafePtr<CDeviceGeneralPage> GenPagePtr;
  530. CDeviceGeneralPage* pGeneralPage = new CDeviceGeneralPage();
  531. GenPagePtr.Attach(pGeneralPage);
  532. hPage = pGeneralPage->Create(pDevice);
  533. if (hPage) {
  534. if (psd.InsertPage(hPage, 0)) {
  535. GenPagePtr.Detach();
  536. }
  537. else {
  538. ::DestroyPropertySheetPage(hPage);
  539. }
  540. }
  541. //
  542. // Add the driver tab
  543. //
  544. if (!(DiFlags & DI_DRIVERPAGE_ADDED)) {
  545. SafePtr<CDeviceDriverPage> DrvPagePtr;
  546. CDeviceDriverPage* pDriverPage = new CDeviceDriverPage();
  547. DrvPagePtr.Attach(pDriverPage);
  548. hPage = pDriverPage->Create(pDevice);
  549. if (hPage) {
  550. if (psd.InsertPage(hPage)) {
  551. DrvPagePtr.Detach();
  552. }
  553. else {
  554. ::DestroyPropertySheetPage(hPage);
  555. }
  556. }
  557. }
  558. //
  559. // Add the resource tab
  560. //
  561. if ((Flags & DEVPROP_SHOW_RESOURCE_TAB) &&
  562. pDevice->HasResources() &&
  563. !(DiFlags & DI_RESOURCEPAGE_ADDED)) {
  564. TheMachine.DiGetExtensionPropSheetPage(*pDevice,
  565. AddPageCallback,
  566. SPPSR_SELECT_DEVICE_RESOURCES,
  567. (LPARAM)&psd
  568. );
  569. }
  570. #ifndef _WIN64
  571. //
  572. // Add the power tab if this is the local machine
  573. //
  574. if (TheMachine.IsLocal() && !(DiFlagsEx & DI_FLAGSEX_POWERPAGE_ADDED))
  575. {
  576. //
  577. // Check if the device support power management
  578. //
  579. CPowerShutdownEnable ShutdownEnable;
  580. CPowerWakeEnable WakeEnable;
  581. if (ShutdownEnable.Open(pDevice->GetDeviceID()) || WakeEnable.Open(pDevice->GetDeviceID())) {
  582. ShutdownEnable.Close();
  583. WakeEnable.Close();
  584. SafePtr<CDevicePowerMgmtPage> PowerMgmtPagePtr;
  585. CDevicePowerMgmtPage* pPowerPage = new CDevicePowerMgmtPage;
  586. PowerMgmtPagePtr.Attach(pPowerPage);
  587. hPage = pPowerPage->Create(pDevice);
  588. if (hPage) {
  589. if (psd.InsertPage(hPage)) {
  590. PowerMgmtPagePtr.Detach();
  591. }
  592. else {
  593. ::DestroyPropertySheetPage(hPage);
  594. }
  595. }
  596. }
  597. }
  598. #endif
  599. //
  600. // Add any Bus property pages if this is the local machine
  601. //
  602. if (TheMachine.IsLocal())
  603. {
  604. CBusPropPageProvider* pBusPropPageProvider = new CBusPropPageProvider();
  605. SafePtr<CBusPropPageProvider> ProviderPtr;
  606. ProviderPtr.Attach(pBusPropPageProvider);
  607. if (pBusPropPageProvider->EnumPages(pDevice, &psd)) {
  608. psd.AddProvider(pBusPropPageProvider);
  609. ProviderPtr.Detach();
  610. }
  611. }
  612. Result = (int)psd.DoSheet();
  613. if (-1 != Result) {
  614. if (TheMachine.DiGetExFlags(*pDevice) & DI_FLAGSEX_PROPCHANGE_PENDING) {
  615. //
  616. // property change pending, issue a DICS_PROPERTYCHANGE
  617. // to the class installer
  618. //
  619. SP_PROPCHANGE_PARAMS pcp;
  620. pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  621. pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  622. pcp.Scope = DICS_FLAG_GLOBAL;
  623. pcp.StateChange = DICS_PROPCHANGE;
  624. TheMachine.DiSetClassInstallParams(*pDevice,
  625. &pcp.ClassInstallHeader,
  626. sizeof(pcp)
  627. );
  628. TheMachine.DiCallClassInstaller(DIF_PROPERTYCHANGE, *pDevice);
  629. TheMachine.DiTurnOnDiFlags(*pDevice, DI_PROPERTIES_CHANGE);
  630. TheMachine.DiTurnOffDiExFlags(*pDevice, DI_FLAGSEX_PROPCHANGE_PENDING);
  631. }
  632. //
  633. // Merge restart/reboot flags
  634. //
  635. DiFlags = TheMachine.DiGetFlags(*pDevice);
  636. if (DI_NEEDREBOOT & DiFlags) {
  637. Result |= ID_PSREBOOTSYSTEM;
  638. }
  639. if (DI_NEEDRESTART & DiFlags) {
  640. Result |= ID_PSRESTARTWINDOWS;
  641. }
  642. }
  643. }
  644. }
  645. catch (CMemoryException* e) {
  646. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  647. e->Delete();
  648. }
  649. return -1;
  650. }
  651. STDAPI_(UINT)
  652. DeviceProblemTextA(
  653. HMACHINE hMachine,
  654. DEVNODE DevNode,
  655. ULONG ProblemNumber,
  656. LPSTR Buffer,
  657. UINT BufferSize
  658. )
  659. /*++
  660. Routine Description:
  661. This API gets the problem description associated with the specified
  662. problem code.
  663. Arguments:
  664. hMachine - not used.
  665. DevNode - not used.
  666. ProblemNumber - CM problem code to get the problem text for.
  667. Buffer - Buffer to receive the problem text.
  668. BufferSize - size of Buffer in characters. This can be 0 if the caller
  669. wants to know how large of a buffer they should allocate.
  670. Return Value:
  671. UINT required size to hold the problem text string, or 0 in case of
  672. an error. Use GetLastError() for extended error information.
  673. --*/
  674. {
  675. UNREFERENCED_PARAMETER(hMachine);
  676. UNREFERENCED_PARAMETER(DevNode);
  677. WCHAR* wchBuffer = NULL;
  678. UINT RealSize = 0;
  679. if (BufferSize && !Buffer)
  680. {
  681. SetLastError(ERROR_INVALID_PARAMETER);
  682. return 0;
  683. }
  684. if (BufferSize)
  685. {
  686. try
  687. {
  688. wchBuffer = new WCHAR[BufferSize];
  689. }
  690. catch (CMemoryException* e)
  691. {
  692. e->Delete();
  693. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  694. return 0;
  695. }
  696. }
  697. RealSize = GetDeviceProblemText(ProblemNumber, wchBuffer, BufferSize);
  698. if (RealSize && BufferSize > RealSize)
  699. {
  700. ASSERT(wchBuffer);
  701. RealSize = WideCharToMultiByte(CP_ACP, 0, wchBuffer, RealSize,
  702. Buffer, BufferSize, NULL, NULL);
  703. Buffer[RealSize] = '\0';
  704. }
  705. if (wchBuffer)
  706. {
  707. delete [] wchBuffer;
  708. }
  709. return RealSize;
  710. }
  711. STDAPI_(UINT)
  712. DeviceProblemTextW(
  713. HMACHINE hMachine,
  714. DEVNODE DevNode,
  715. ULONG ProblemNumber,
  716. LPWSTR Buffer,
  717. UINT BufferSize
  718. )
  719. /*++
  720. Routine Description:
  721. This API gets the problem description associated with the specified
  722. problem code.
  723. Arguments:
  724. hMachine - not used.
  725. DevNode - not used.
  726. ProblemNumber - CM problem code to get the problem text for.
  727. Buffer - Buffer to receive the problem text.
  728. BufferSize - size of Buffer in characters. This can be 0 if the caller
  729. wants to know how large of a buffer they should allocate.
  730. Return Value:
  731. UINT required size to hold the problem text string, or 0 in case of
  732. an error. Use GetLastError() for extended error information.
  733. --*/
  734. {
  735. UNREFERENCED_PARAMETER(hMachine);
  736. UNREFERENCED_PARAMETER(DevNode);
  737. return GetDeviceProblemText(ProblemNumber, Buffer, BufferSize);
  738. }
  739. int
  740. PropertyRunDeviceTree(
  741. HWND hwndParent,
  742. LPCTSTR MachineName,
  743. LPCTSTR DeviceID
  744. )
  745. {
  746. SHELLEXECUTEINFOW sei;
  747. TCHAR Parameters[MAX_PATH];
  748. String strParameters;
  749. String strMachineOptions;
  750. String strDeviceIdOptions;
  751. String strCommandOptions;
  752. TCHAR* FilePart;
  753. DWORD Size;
  754. Size = SearchPath(NULL, DEVMGR_MSC_FILE, NULL, MAX_PATH, Parameters, &FilePart);
  755. if (Size && Size <= MAX_PATH) {
  756. strParameters = Parameters;
  757. } else {
  758. strParameters = DEVMGR_MSC_FILE;
  759. }
  760. strParameters += MMC_COMMAND_LINE;
  761. if (MachineName != NULL) {
  762. strMachineOptions.Format(DEVMGR_MACHINENAME_OPTION, MachineName);
  763. strParameters += strMachineOptions;
  764. }
  765. if (DeviceID != NULL) {
  766. strDeviceIdOptions.Format(DEVMGR_DEVICEID_OPTION, DeviceID);
  767. strParameters += strDeviceIdOptions;
  768. strCommandOptions.Format(DEVMGR_COMMAND_OPTION, DEVMGR_CMD_PROPERTY);
  769. strParameters += strCommandOptions;
  770. }
  771. memset(&sei, 0, sizeof(sei));
  772. sei.cbSize = sizeof(sei);
  773. sei.hwnd = hwndParent;
  774. sei.nShow = SW_NORMAL;
  775. sei.hInstApp = g_hInstance;
  776. sei.lpFile = MMC_FILE;
  777. sei.fMask = SEE_MASK_NOCLOSEPROCESS;
  778. sei.lpParameters = (LPTSTR)strParameters;
  779. if (ShellExecuteEx(&sei) && sei.hProcess)
  780. {
  781. WaitForSingleObject(sei.hProcess, INFINITE);
  782. CloseHandle(sei.hProcess);
  783. return 1;
  784. }
  785. return 0;
  786. }
  787. STDAPI_(void)
  788. DeviceProblenWizard_RunDLLA(
  789. HWND hwndStub,
  790. HINSTANCE hAppInstance,
  791. LPSTR lpCmdLine,
  792. int nCmdShow
  793. )
  794. /*++
  795. See DeviceProblemWizard_RunDLL function below.
  796. --*/
  797. {
  798. try
  799. {
  800. CTString tstrCmdLine(lpCmdLine);
  801. DeviceProblenWizard_RunDLL(hwndStub,
  802. hAppInstance,
  803. (LPCTSTR)tstrCmdLine,
  804. nCmdShow
  805. );
  806. }
  807. catch (CMemoryException* e)
  808. {
  809. e->ReportError();
  810. e->Delete();
  811. }
  812. }
  813. STDAPI_(void)
  814. DeviceProblenWizard_RunDLLW(
  815. HWND hwndStub,
  816. HINSTANCE hAppInstance,
  817. LPWSTR lpCmdLine,
  818. int nCmdShow
  819. )
  820. /*++
  821. See DeviceProblemWizard_RunDLL function below.
  822. --*/
  823. {
  824. try
  825. {
  826. CTString tstrCmdLine(lpCmdLine);
  827. DeviceProblenWizard_RunDLL(hwndStub,
  828. hAppInstance,
  829. (LPCTSTR)tstrCmdLine,
  830. nCmdShow
  831. );
  832. }
  833. catch (CMemoryException* e)
  834. {
  835. e->ReportError();
  836. e->Delete();
  837. }
  838. }
  839. void
  840. DeviceProblenWizard_RunDLL(
  841. HWND hwndStub,
  842. HINSTANCE hAppInstance,
  843. LPCTSTR lpCmdLine,
  844. int nCmdShow
  845. )
  846. /*++
  847. Routine Description:
  848. This API will bring up the problem wizard (troubleshooter) for the
  849. specified device.
  850. This function is executed via a rundll command line and can have the
  851. following form:
  852. rundll32.exe devmgr.dll, DeviceProblemWizard_RunDLL /DeviceId <device instance Id>
  853. Arguments:
  854. hwndStub - Windows handle to receive any message boxes that might be
  855. displayed.
  856. hAppInstance - HINSTANCE.
  857. lpCmdLine - Name of a remote machine that the new device manager
  858. process should connect to and show it's devices.
  859. nCmdShow - Flag that specifies how device manager should be shown when
  860. it is opened. It can be one of the SW_ values (i.e. SW_SHOW).
  861. Return Value:
  862. none
  863. --*/
  864. {
  865. UNREFERENCED_PARAMETER(hAppInstance);
  866. UNREFERENCED_PARAMETER(nCmdShow);
  867. try
  868. {
  869. CRunDLLCommandLine CmdLine;
  870. CmdLine.ParseCommandLine(lpCmdLine);
  871. //
  872. // Let the DeviceProblemWizard handle all of the parameter validation.
  873. //
  874. DeviceProblemWizard(hwndStub,
  875. CmdLine.GetMachineName(),
  876. CmdLine.GetDeviceID()
  877. );
  878. }
  879. catch (CMemoryException* e)
  880. {
  881. e->ReportError();
  882. e->Delete();
  883. return;
  884. }
  885. }
  886. STDAPI_(int)
  887. DeviceProblemWizardA(
  888. HWND hwndParent,
  889. LPCSTR MachineName,
  890. LPCSTR DeviceId
  891. )
  892. /*++
  893. See DeviceProblemWizard function below.
  894. --*/
  895. {
  896. try
  897. {
  898. CTString tstrMachineName(MachineName);
  899. CTString tstrDeviceId(DeviceId);
  900. return DeviceProblemWizard(hwndParent, tstrMachineName, tstrDeviceId);
  901. }
  902. catch(CMemoryException* e)
  903. {
  904. e->Delete();
  905. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  906. }
  907. return 0;
  908. }
  909. STDAPI_(int)
  910. DeviceProblemWizardW(
  911. HWND hwndParent,
  912. LPCWSTR MachineName,
  913. LPCWSTR DeviceId
  914. )
  915. /*++
  916. See DeviceProblemWizard function below.
  917. --*/
  918. {
  919. try
  920. {
  921. CTString tstrMachineName(MachineName);
  922. CTString tstrDeviceId(DeviceId);
  923. return DeviceProblemWizard(hwndParent, tstrMachineName, tstrDeviceId);
  924. }
  925. catch (CMemoryException* e)
  926. {
  927. e->Delete();
  928. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  929. }
  930. return 0;
  931. }
  932. int
  933. DeviceProblemWizard(
  934. HWND hwndParent,
  935. LPCTSTR MachineName,
  936. LPCTSTR DeviceId
  937. )
  938. /*++
  939. Routine Description:
  940. This API will launch the device troubleshooter for the specified
  941. device instance Id.
  942. The troubleshooter can have any form, including HTML help, help center
  943. pages, or an actual Win32 troubleshooter. The troubleshooter also should
  944. be specific to the CM Problem code that the device has, but if no
  945. troubleshooter exists for the CM Problem code, then a more generic
  946. troubleshooter will be launched.
  947. Arguments:
  948. hwndParent - the caller's window handle to be used as the owner window
  949. of the property page and any other windows this API may create.
  950. MachineName - Must be NULL. Currently there is no support for remote
  951. troubleshooters
  952. DeviceId - device instance id of the device that this API should launch
  953. the troubleshooter.
  954. Return Value:
  955. 1 if a troubleshooter is successfully launched, 0 otherwise. Use
  956. GetLastError to get extended error information if 0 is returned.
  957. --*/
  958. {
  959. int iRet = 0;
  960. DWORD Problem, Status;
  961. if (!DeviceId) {
  962. SetLastError(ERROR_INVALID_PARAMETER);
  963. return 0;
  964. }
  965. if (MachineName) {
  966. //
  967. // Currently getting troubleshooters are remote machines is not
  968. // implemented.
  969. //
  970. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  971. return 0;
  972. }
  973. try
  974. {
  975. CMachine TheMachine(NULL);
  976. //
  977. // create the machine just for this device
  978. //
  979. if (!TheMachine.Initialize(hwndParent, DeviceId))
  980. {
  981. SetLastError(ERROR_NO_SUCH_DEVINST);
  982. iRet = 0;
  983. goto clean0;
  984. }
  985. PVOID Context;
  986. CDevice* pDevice;
  987. if (!TheMachine.GetFirstDevice(&pDevice, Context))
  988. {
  989. SetLastError(ERROR_NO_SUCH_DEVINST);
  990. iRet = 0;
  991. goto clean0;
  992. }
  993. if (pDevice->GetStatus(&Status, &Problem)) {
  994. //
  995. // if the device is a phantom device, use the CM_PROB_PHANTOM
  996. //
  997. if (pDevice->IsPhantom()) {
  998. Problem = CM_PROB_PHANTOM;
  999. }
  1000. //
  1001. // if the device is not started and no problem is assigned to it
  1002. // fake the problem number to be failed start.
  1003. //
  1004. if (!(Status & DN_STARTED) && !Problem && pDevice->IsRAW()) {
  1005. Problem = CM_PROB_FAILED_START;
  1006. }
  1007. }
  1008. CProblemAgent* pProblemAgent = new CProblemAgent(pDevice, Problem, TRUE);
  1009. if (pProblemAgent) {
  1010. pProblemAgent->FixIt(hwndParent);
  1011. }
  1012. iRet = 1;
  1013. clean0:;
  1014. } catch(CMemoryException* e) {
  1015. e->Delete();
  1016. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1017. }
  1018. return iRet;
  1019. }
  1020. STDAPI_(int)
  1021. DeviceAdvancedPropertiesA(
  1022. HWND hwndParent,
  1023. LPTSTR MachineName,
  1024. LPTSTR DeviceId
  1025. )
  1026. /*++
  1027. See DeviceAdvancedProperties function below.
  1028. --*/
  1029. {
  1030. try
  1031. {
  1032. CTString tstrMachineName(MachineName);
  1033. CTString tstrDeviceID(DeviceId);
  1034. return DeviceAdvancedProperties(hwndParent,
  1035. (LPCTSTR)tstrMachineName,
  1036. (LPCTSTR)tstrDeviceID
  1037. );
  1038. }
  1039. catch (CMemoryException* e)
  1040. {
  1041. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1042. e->Delete();
  1043. }
  1044. return 0;
  1045. }
  1046. STDAPI_(int)
  1047. DeviceAdvancedPropertiesW(
  1048. HWND hwndParent,
  1049. LPCWSTR MachineName,
  1050. LPCWSTR DeviceId
  1051. )
  1052. /*++
  1053. See DeviceAdvancedProperties function below.
  1054. --*/
  1055. {
  1056. try
  1057. {
  1058. CTString tstrMachineName(MachineName);
  1059. CTString tstrDeviceID(DeviceId);
  1060. return DeviceAdvancedProperties(hwndParent,
  1061. (LPCTSTR)tstrMachineName,
  1062. (LPCTSTR)tstrDeviceID
  1063. );
  1064. }
  1065. catch (CMemoryException* e)
  1066. {
  1067. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1068. e->Delete();
  1069. }
  1070. return 0;
  1071. }
  1072. int DeviceAdvancedProperties(
  1073. HWND hwndParent,
  1074. LPCTSTR MachineName,
  1075. LPCTSTR DeviceId
  1076. )
  1077. /*++
  1078. Routine Description:
  1079. This API creates a property sheet and asks the given device's property
  1080. page provider to add any advanced pages to the property sheet.
  1081. The purpose of this API is for an application to manage device advanced
  1082. properties only. Standard property pages (General, Driver, Resource,
  1083. Power, Bus pages) are not added.
  1084. We get these advanced pages by calling SetupDiGetClassDevPropertySheet
  1085. with DIGCDP_FLAG_ADVANCED, for the local machine case, and
  1086. DIGCDP_FLAG_REMOTE_ADVANCED if a remote MachineName is passed in.
  1087. NOTE: If the device does not have any advanced property pages, then no UI
  1088. is displayed.
  1089. Arguments:
  1090. hwndParent - the caller's window handle to be used as the owner window
  1091. of the property page and any other windows this API may create.
  1092. MachineName - optional machine name. If given, it must be in its fully
  1093. qualified form. NULL means local machine
  1094. DeviceId - device instance id of the device that this API should create
  1095. the property sheet for.
  1096. Return Value:
  1097. The return value from PropertySheet, including ID_PSREBOOTSYSTEM if
  1098. a reboot is needed due to any user actions.
  1099. -1 is returned in case of an error.
  1100. --*/
  1101. {
  1102. if (!DeviceId)
  1103. {
  1104. SetLastError(ERROR_INVALID_PARAMETER);
  1105. return -1;
  1106. }
  1107. if (MachineName &&
  1108. !VerifyMachineName(MachineName)) {
  1109. //
  1110. // We were unable to connect to the remote machine either because it
  1111. // doesn't exist, or because we don't have the proper access.
  1112. // The VerifyMachineName API sets the appropriate last error code.
  1113. //
  1114. return -1;
  1115. }
  1116. CMachine TheMachine(MachineName);
  1117. CDevice* pDevice;
  1118. PVOID Context;
  1119. try
  1120. {
  1121. if (TheMachine.Initialize(hwndParent, DeviceId) &&
  1122. TheMachine.GetFirstDevice(&pDevice, Context))
  1123. {
  1124. TheMachine.EnableRefresh(FALSE);
  1125. CPropSheetData& psd = pDevice->m_psd;
  1126. //initialize CPropSheetData without ConsoleHandle
  1127. if (psd.Create(g_hInstance, hwndParent, MAX_PROP_PAGES, 0l))
  1128. {
  1129. psd.m_psh.pszCaption = pDevice->GetDisplayName();
  1130. if (TheMachine.DiGetClassDevPropertySheet(*pDevice, &psd.m_psh,
  1131. MAX_PROP_PAGES,
  1132. TheMachine.IsLocal() ?
  1133. DIGCDP_FLAG_ADVANCED :
  1134. DIGCDP_FLAG_REMOTE_ADVANCED))
  1135. {
  1136. int Result = (int)psd.DoSheet();
  1137. if (-1 != Result)
  1138. {
  1139. // merge restart/reboot flags
  1140. DWORD DiFlags = TheMachine.DiGetFlags(*pDevice);
  1141. if (DI_NEEDREBOOT & DiFlags)
  1142. {
  1143. Result |= ID_PSREBOOTSYSTEM;
  1144. }
  1145. if (DI_NEEDRESTART & DiFlags)
  1146. {
  1147. Result |= ID_PSRESTARTWINDOWS;
  1148. }
  1149. }
  1150. return Result;
  1151. }
  1152. }
  1153. }
  1154. }
  1155. catch (CMemoryException* e)
  1156. {
  1157. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1158. e->Delete();
  1159. }
  1160. return -1;
  1161. }