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.

756 lines
23 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. idevices.cpp
  5. Abstract:
  6. Internal implementation for the devices subfolder.
  7. Environment:
  8. WIN32 User Mode
  9. Author:
  10. Darwin Ouyang (t-darouy) 30-Sept-1997
  11. --*/
  12. #include "StdAfx.h"
  13. #include "inode.h" // base class
  14. #include "iroot.h" // iroot
  15. #include "idevices.h" // devices folder
  16. #include "idevice.h" // a device
  17. #include "faxsnapin.h" // snapin
  18. #include "faxdataobj.h" // dataobject
  19. #include "faxstrt.h" // string table
  20. #pragma hdrstop
  21. extern CStringTable * GlobalStringTable;
  22. // Generated with uuidgen. Each node must have a GUID associated with it.
  23. // This one is for the devices subfolder.
  24. const GUID GUID_DevicesNode = /* 03a815d8-3e9e-11d1-9075-00a0c90ab504 */
  25. {
  26. 0x03a815d8,
  27. 0x3e9e,
  28. 0x11d1,
  29. {0x90, 0x75, 0x00, 0xa0, 0xc9, 0x0a, 0xb5, 0x04}
  30. };
  31. ////////////////////////////////////////////////////////////////////////////////////////////////////
  32. ////////////////////////////////////////////////////////////////////////////////////////////////////
  33. ////////////////////////////////////////////////////////////////////////////////////////////////////
  34. ////////////////////////////////////////////////////////////////////////////////////////////////////
  35. //
  36. //
  37. // Constructor and destructor
  38. //
  39. //
  40. CInternalDevices::CInternalDevices(
  41. CInternalNode * pParent,
  42. CFaxComponentData * pCompData )
  43. : CInternalNode( pParent, pCompData ),
  44. pDevicesInfo( NULL )
  45. /*++
  46. Routine Description:
  47. Constructor
  48. Arguments:
  49. pParent - pointer to parent node, in this case unused
  50. pCompData - pointer to IComponentData implementation for snapin global data
  51. Return Value:
  52. None.
  53. --*/
  54. {
  55. DebugPrint(( TEXT("CInternalDeviceS Created") ));
  56. faxHandle = m_pCompData->m_FaxHandle;
  57. assert( faxHandle != NULL );
  58. }
  59. CInternalDevices::~CInternalDevices( )
  60. /*++
  61. Routine Description:
  62. Destructor
  63. Arguments:
  64. None.
  65. Return Value:
  66. None.
  67. --*/
  68. {
  69. DebugPrint(( TEXT("CInternalDeviceS Destroyed") ));
  70. }
  71. ////////////////////////////////////////////////////////////////////////////////////////////////////
  72. ////////////////////////////////////////////////////////////////////////////////////////////////////
  73. ////////////////////////////////////////////////////////////////////////////////////////////////////
  74. ////////////////////////////////////////////////////////////////////////////////////////////////////
  75. //
  76. //
  77. // Mandatory CInternalNode implementations.
  78. //
  79. //
  80. const GUID *
  81. CInternalDevices::GetNodeGUID()
  82. /*++
  83. Routine Description:
  84. Returns the node's associated GUID.
  85. Arguments:
  86. None.
  87. Return Value:
  88. A const pointer to a binary GUID.
  89. --*/
  90. {
  91. // DebugPrint(( TEXT("Trace: CInternalDevices::GetNodeGUID") ));
  92. return &GUID_DevicesNode;
  93. }
  94. const LPTSTR
  95. CInternalDevices::GetNodeDisplayName()
  96. /*++
  97. Routine Description:
  98. Returns a const TSTR pointer to the node's display name.
  99. Arguments:
  100. None.
  101. Return Value:
  102. A const pointer to a TSTR.
  103. --*/
  104. {
  105. // DebugPrint(( TEXT("Trace: CInternalDevices::GetNodeDisplayName") ));
  106. return ::GlobalStringTable->GetString( IDS_DEVICESNODENAME );
  107. }
  108. const LPTSTR
  109. CInternalDevices::GetNodeDescription()
  110. /*++
  111. Routine Description:
  112. Returns a const TSTR pointer to the node's display description.
  113. Arguments:
  114. None.
  115. Return Value:
  116. A const pointer to a TSTR.
  117. --*/
  118. {
  119. // DebugPrint(( TEXT("Trace: CInternalDevices::GetNodeDisplayName") ));
  120. return ::GlobalStringTable->GetString( IDS_DEVICES_FOLDER_DESC_ROOT );
  121. }
  122. const LONG_PTR
  123. CInternalDevices::GetCookie()
  124. /*++
  125. Routine Description:
  126. Returns the cookie for this node.
  127. Arguments:
  128. None.
  129. Return Value:
  130. A const long containing the cookie for the pointer,
  131. in this case, (long)this.
  132. --*/
  133. {
  134. // DebugPrint(( TEXT("Trace: CInternalDevices::GetCookie") ));
  135. DebugPrint(( TEXT("Devices Node Cookie: 0x%p"), this ));
  136. return (LONG_PTR)this; // status node's cookie is the node id.
  137. }
  138. ////////////////////////////////////////////////////////////////////////////////////////////////////
  139. ////////////////////////////////////////////////////////////////////////////////////////////////////
  140. ////////////////////////////////////////////////////////////////////////////////////////////////////
  141. ////////////////////////////////////////////////////////////////////////////////////////////////////
  142. //
  143. //
  144. // Internal Event Handlers
  145. //
  146. //
  147. HRESULT
  148. CInternalDevices::ResultOnShow(
  149. IN CFaxComponent* pComp,
  150. IN CFaxDataObject * lpDataObject,
  151. IN LPARAM arg,
  152. IN LPARAM param)
  153. /*++
  154. Routine Description:
  155. Event handler for the MMCN_SHOW message for the devices node.
  156. Arguments:
  157. pComp - a pointer to the instance of IComponentData which this root node is associated with.
  158. lpDataObject - a pointer to the data object containing context information for this node.
  159. arg, param - the arguements of the message
  160. Return Value:
  161. HRESULT which indicates SUCCEEDED() or FAILED()
  162. --*/
  163. {
  164. DebugPrint(( TEXT("Trace: CInternalDevices::ResultOnShow") ));
  165. HRESULT hr = S_OK;
  166. unsigned int count;
  167. int iResult;
  168. LPHEADERCTRL pIHeaderCtrl;
  169. if( m_pCompData->QueryRpcError() ) {
  170. return E_UNEXPECTED;
  171. }
  172. if( arg == TRUE ) { // need to display result pane
  173. do {
  174. // get resultdata pointer
  175. pIResultData = pComp->m_pResultData;
  176. assert( pIResultData );
  177. if( pIResultData == NULL ) {
  178. hr = E_UNEXPECTED;
  179. break;
  180. }
  181. // insert the icons into the image list
  182. hr = pComp->InsertIconsIntoImageList();
  183. assert( SUCCEEDED( hr ) );
  184. if( FAILED( hr ) ) {
  185. break;
  186. }
  187. // set headers
  188. pIHeaderCtrl = pComp->m_pHeaderCtrl;
  189. hr = pIHeaderCtrl->InsertColumn( 0,
  190. ::GlobalStringTable->GetString( IDS_DEVICE_NAME ),
  191. LVCFMT_LEFT,
  192. MMCLV_AUTO );
  193. if( FAILED( hr ) ) {
  194. break;
  195. }
  196. hr = pIHeaderCtrl->InsertColumn( 1,
  197. ::GlobalStringTable->GetString( IDS_DEVICE_SEND_EN ),
  198. LVCFMT_LEFT,
  199. MMCLV_AUTO );
  200. if( FAILED( hr ) ) {
  201. break;
  202. }
  203. hr = pIHeaderCtrl->InsertColumn( 2,
  204. ::GlobalStringTable->GetString( IDS_DEVICE_RECV_EN ),
  205. LVCFMT_LEFT,
  206. MMCLV_AUTO );
  207. if( FAILED( hr ) ) {
  208. break;
  209. }
  210. hr = pIHeaderCtrl->InsertColumn( 3,
  211. ::GlobalStringTable->GetString( IDS_DEVICE_TSID ),
  212. LVCFMT_LEFT,
  213. MMCLV_AUTO );
  214. if( FAILED( hr ) ) {
  215. break;
  216. }
  217. hr = pIHeaderCtrl->InsertColumn( 4,
  218. ::GlobalStringTable->GetString( IDS_DEVICE_CSID ),
  219. LVCFMT_LEFT,
  220. MMCLV_AUTO );
  221. if( FAILED( hr ) ) {
  222. break;
  223. }
  224. hr = pIHeaderCtrl->InsertColumn( 5,
  225. ::GlobalStringTable->GetString( IDS_DEVICE_STATUS ),
  226. LVCFMT_LEFT,
  227. MMCLV_AUTO );
  228. if( FAILED( hr ) ) {
  229. break;
  230. }
  231. hr = pIHeaderCtrl->InsertColumn( 6,
  232. ::GlobalStringTable->GetString( IDS_DEVICE_PRI ),
  233. LVCFMT_LEFT,
  234. MMCLV_AUTO );
  235. if( FAILED( hr ) ) {
  236. break;
  237. }
  238. // this is the first time initializing the devices node
  239. if( pComp->pDeviceArray == NULL ) {
  240. // get fax info
  241. try {
  242. if( !FaxEnumPorts( faxHandle, &pDevicesInfo, &pComp->numDevices ) ) {
  243. if (GetLastError() == ERROR_ACCESS_DENIED) {
  244. ::GlobalStringTable->SystemErrorMsg(ERROR_ACCESS_DENIED);
  245. } else {
  246. m_pCompData->NotifyRpcError( TRUE );
  247. hr = m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_RETR_DEV_FAIL ),
  248. ::GlobalStringTable->GetString( IDS_ERR_TITLE ),
  249. MB_OK,
  250. &iResult);
  251. }
  252. hr = E_UNEXPECTED;
  253. break;
  254. }
  255. } catch( ... ) {
  256. m_pCompData->NotifyRpcError( TRUE );
  257. hr = m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_RETR_DEV_FAIL ),
  258. ::GlobalStringTable->GetString( IDS_ERR_TITLE ),
  259. MB_OK,
  260. &iResult);
  261. hr = E_UNEXPECTED;
  262. break;
  263. }
  264. assert( pComp->pDeviceArray == NULL );
  265. pComp->pDeviceArray = new pCInternalDevice[pComp->numDevices];
  266. if (!pComp->pDeviceArray) {
  267. hr = E_OUTOFMEMORY;
  268. break;
  269. }
  270. ZeroMemory( (void *)pComp->pDeviceArray, pComp->numDevices * sizeof( pCInternalDevice ) );
  271. for( count = 0; count < pComp->numDevices; count ++ ) {
  272. pComp->pDeviceArray[count] = new CInternalDevice( this, m_pCompData, faxHandle, pDevicesInfo[count].DeviceId );
  273. if (!pComp->pDeviceArray[count]) {
  274. hr = E_OUTOFMEMORY;
  275. break;
  276. }
  277. }
  278. }
  279. // on each display, insert each device into the devices pane
  280. for( count = 0; count < pComp->numDevices; count++ ) {
  281. hr = InsertItem( &pComp->pDeviceArray[count], &(pDevicesInfo[count]) );
  282. if( FAILED( hr ) ) {
  283. break;
  284. }
  285. }
  286. } while( 0 );
  287. if( pDevicesInfo != NULL ) {
  288. FaxFreeBuffer( (PVOID) pDevicesInfo );
  289. pDevicesInfo = NULL;
  290. }
  291. if (FAILED(hr)) {
  292. if (pComp->pDeviceArray) {
  293. for (count = 0; count < pComp->numDevices; count++ ) {
  294. if (pComp->pDeviceArray[count]) {
  295. delete(pComp->pDeviceArray[count]);
  296. }
  297. }
  298. delete(pComp->pDeviceArray);
  299. pComp->pDeviceArray = NULL;
  300. }
  301. }
  302. }
  303. return hr;
  304. }
  305. HRESULT
  306. CInternalDevices::ResultOnDelete(
  307. IN CFaxComponent* pComp,
  308. IN CFaxDataObject * lpDataObject,
  309. IN LPARAM arg,
  310. IN LPARAM param)
  311. /*++
  312. Routine Description:
  313. Event handler for the MMCN_DELETE message for the devices node.
  314. Arguments:
  315. pComp - a pointer to the instance of IComponentData which this root node is associated with.
  316. lpDataObject - a pointer to the data object containing context information for this node.
  317. pdo - a pointer to the data object associated with this node
  318. arg, param - the arguements of the message
  319. Return Value:
  320. HRESULT which indicates SUCCEEDED() or FAILED()
  321. --*/
  322. {
  323. // unneeded because the per result view data will be deleted by destroying the
  324. // CInternalComponent holding the information
  325. #if 0
  326. DebugPrint(( TEXT("Trace: CInternalDevices::ResultOnDelete") ));
  327. unsigned int count;
  328. for( count = 0; count < pComp->numDevices; count++ ) {
  329. if( pComp->pDeviceArray[count] != NULL ) {
  330. delete pComp->pDeviceArray[count];
  331. pComp->pDeviceArray[count] = NULL;
  332. }
  333. }
  334. delete pComp->pDeviceArray;
  335. pComp->pDeviceArray = NULL;
  336. #endif
  337. return S_OK;
  338. }
  339. ////////////////////////////////////////////////////////////////////////////////////////////////////
  340. ////////////////////////////////////////////////////////////////////////////////////////////////////
  341. ////////////////////////////////////////////////////////////////////////////////////////////////////
  342. ////////////////////////////////////////////////////////////////////////////////////////////////////
  343. //
  344. //
  345. // Internal Functions
  346. //
  347. //
  348. HRESULT
  349. CInternalDevices::CorrectServiceState()
  350. /*++
  351. Routine Description:
  352. Scans the devices to see if any are enabled for receive, and if so,
  353. resets the service's startup state to automatic from manual. If no
  354. devices are enabled for receive, then the service is set from
  355. automatic to manual.
  356. Arguments:
  357. None.
  358. Return Value:
  359. HRESULT which indicates SUCCEEDED() or FAILED()
  360. --*/
  361. {
  362. DWORD i;
  363. PFAX_PORT_INFO pPortInfos = NULL;
  364. DWORD portCount;
  365. int iResult;
  366. BOOL setAuto = FALSE;
  367. HRESULT hr = S_OK;
  368. DebugPrint(( TEXT("Trace: CInternalDevices::CorrectServiceState") ));
  369. do {
  370. // get fax info
  371. try {
  372. if( m_pCompData->QueryRpcError() ) {
  373. hr = E_UNEXPECTED;
  374. break;
  375. }
  376. if( !FaxEnumPorts( faxHandle, &pPortInfos, &portCount ) ) {
  377. if (GetLastError() == ERROR_ACCESS_DENIED) {
  378. ::GlobalStringTable->SystemErrorMsg(ERROR_ACCESS_DENIED);
  379. } else {
  380. m_pCompData->NotifyRpcError( TRUE );
  381. hr = m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_RETR_DEV_FAIL ),
  382. ::GlobalStringTable->GetString( IDS_ERR_TITLE ),
  383. MB_OK,
  384. &iResult);
  385. }
  386. hr = E_UNEXPECTED;
  387. break;
  388. }
  389. } catch( ... ) {
  390. m_pCompData->NotifyRpcError( TRUE );
  391. hr = m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_RETR_DEV_FAIL ),
  392. ::GlobalStringTable->GetString( IDS_ERR_TITLE ),
  393. MB_OK,
  394. &iResult);
  395. hr = E_UNEXPECTED;
  396. break;
  397. }
  398. for( i = 0; i < portCount; i++) {
  399. if( pPortInfos[i].Flags & FPF_RECEIVE ) {
  400. setAuto = TRUE;
  401. break;
  402. }
  403. }
  404. SetServiceState( setAuto );
  405. } while( 0 );
  406. if( pPortInfos != NULL ) {
  407. FaxFreeBuffer( (PVOID) pPortInfos );
  408. pPortInfos = NULL;
  409. }
  410. return hr;
  411. }
  412. HRESULT
  413. CInternalDevices::SetServiceState(
  414. IN BOOL fAutomatic )
  415. /*++
  416. Routine Description:
  417. Opens the Service Manager on the snapin's target machine, and sets
  418. the fax service state according to the fAutomatic parameter.
  419. Arguments:
  420. fAutomatic - if TRUE, sets the service to start automatically.
  421. if FALSE, sets the service to start manually.
  422. Return Value:
  423. HRESULT which indicates SUCCEEDED() or FAILED()
  424. --*/
  425. {
  426. SC_LOCK sclLock;
  427. LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf;
  428. TCHAR buffer[256];
  429. LPTSTR str;
  430. int iResult;
  431. HRESULT hr = S_OK;
  432. SC_HANDLE schSCManager;
  433. SC_HANDLE schService;
  434. DebugPrint(( TEXT("Trace: CInternalDevices::SetServiceState") ));
  435. DWORD dwBytesNeeded, dwStartType;
  436. ZeroMemory( (PVOID)buffer, sizeof( TCHAR ) * 256 );
  437. schSCManager = OpenSCManager( ((CInternalRoot*)m_pParentINode)->GetMachine(),
  438. NULL,
  439. SC_MANAGER_CONNECT | SC_MANAGER_LOCK
  440. | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_ENUMERATE_SERVICE );
  441. if( schSCManager == NULL ) {
  442. ::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_CONNECT_SCM, TRUE, 0 );
  443. assert( FALSE );
  444. return E_UNEXPECTED;
  445. }
  446. // Need to acquire database lock before reconfiguring.
  447. sclLock = LockServiceDatabase(schSCManager);
  448. // If the database cannot be locked, report the details.
  449. if(sclLock == NULL) {
  450. // Exit if the database is not locked by another process.
  451. if(GetLastError() != ERROR_SERVICE_DATABASE_LOCKED) {
  452. ::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_LOCK_SERVICE_DB, TRUE, 0 );
  453. assert( FALSE );
  454. return E_UNEXPECTED;
  455. }
  456. // Allocate a buffer to get details about the lock.
  457. lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS) LocalAlloc( LPTR,
  458. sizeof(QUERY_SERVICE_LOCK_STATUS)+256);
  459. if(lpqslsBuf == NULL) {
  460. ::GlobalStringTable->PopUpMsg( NULL, IDS_OUT_OF_MEMORY, TRUE, 0 );
  461. assert( FALSE );
  462. return E_OUTOFMEMORY;
  463. }
  464. do {
  465. // Get and print the lock status information.
  466. if(!QueryServiceLockStatus( schSCManager,
  467. lpqslsBuf,
  468. sizeof(QUERY_SERVICE_LOCK_STATUS)+256,
  469. &dwBytesNeeded) ) {
  470. ::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_QUERY_LOCK, TRUE, 0 );
  471. assert( FALSE );
  472. break;
  473. }
  474. if(lpqslsBuf->fIsLocked) {
  475. str = ::GlobalStringTable->GetString( IDS_QUERY_LOCK );
  476. _stprintf( buffer, str, lpqslsBuf->lpLockOwner, lpqslsBuf->dwLockDuration );
  477. m_pCompData->m_pConsole->MessageBox( buffer,
  478. ::GlobalStringTable->GetString( IDS_ERR_TITLE ),
  479. MB_OK,
  480. &iResult);
  481. } else {
  482. ::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_LOCK_SERVICE_DB, TRUE, 0 );
  483. }
  484. } while( 0 );
  485. LocalFree(lpqslsBuf);
  486. return E_UNEXPECTED;
  487. }
  488. do {
  489. // The database is locked, so it is safe to make changes.
  490. // Open a handle to the service.
  491. schService = OpenService( schSCManager, // SCManager database
  492. TEXT("Fax"), // name of service
  493. SERVICE_CHANGE_CONFIG ); // need CHANGE access
  494. if(schService == NULL) {
  495. ::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_OPEN_SERVICE, TRUE, 0 );
  496. assert( FALSE );
  497. hr = E_UNEXPECTED;
  498. break;
  499. }
  500. dwStartType = (fAutomatic) ? SERVICE_AUTO_START :
  501. SERVICE_DEMAND_START;
  502. if(! ChangeServiceConfig( schService, // handle of service
  503. SERVICE_NO_CHANGE, // service type: no change
  504. dwStartType, // change service start type
  505. SERVICE_NO_CHANGE, // error control: no change
  506. NULL, // binary path: no change
  507. NULL, // load order group: no change
  508. NULL, // tag ID: no change
  509. NULL, // dependencies: no change
  510. NULL, // account name: no change
  511. NULL, // password: no change
  512. NULL) ) { // display string
  513. ::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_CHANGE_SERVICE, TRUE, 0 );
  514. assert( FALSE );
  515. hr = E_UNEXPECTED;
  516. }
  517. // Close the handle to the service.
  518. CloseServiceHandle(schService);
  519. } while( 0 );
  520. // Release the database lock.
  521. UnlockServiceDatabase(sclLock);
  522. return hr;
  523. }
  524. void
  525. CInternalDevices::NotifyFailure(
  526. CFaxComponent * pComp )
  527. /*++
  528. Routine Description:
  529. If there was a failure in a RPC call anywhere in the child nodes, the result
  530. pane should be cleared. This function clears the result pane.
  531. Arguments:
  532. pComp - a pointer to the instance of IComponentData which this root node is associated with.
  533. Return Value:
  534. None.
  535. --*/
  536. {
  537. assert( pComp != NULL );
  538. assert( pComp->pDeviceArray != NULL );
  539. pComp->m_pResultData->DeleteAllRsltItems();
  540. }
  541. ////////////////////////////////////////////////////////////////////////////////////////////////////
  542. ////////////////////////////////////////////////////////////////////////////////////////////////////
  543. ////////////////////////////////////////////////////////////////////////////////////////////////////
  544. ////////////////////////////////////////////////////////////////////////////////////////////////////
  545. //
  546. //
  547. // Utility Functions
  548. //
  549. //
  550. HRESULT
  551. CInternalDevices::InsertItem(
  552. IN CInternalDevice ** pDevice,
  553. IN PFAX_PORT_INFO pDeviceInfo )
  554. /*++
  555. Routine Description:
  556. Wrapper that inserts an item into the result view pane given some information.
  557. Arguments:
  558. pDevice - the instance of CInternalDevice to insert
  559. pDeviceInfo - the information associated with that log category.
  560. Return Value:
  561. HRESULT which indicates SUCCEEDED() or FAILED()
  562. --*/
  563. {
  564. RESULTDATAITEM rdi;
  565. HRESULT hr = S_OK;
  566. ZeroMemory( &rdi, sizeof( RESULTDATAITEM ) );
  567. rdi.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
  568. rdi.nCol = 0;
  569. rdi.bScopeItem = FALSE;
  570. rdi.lParam = (*pDevice)->GetCookie();
  571. rdi.nImage = (*pDevice)->GetNodeDisplayImage();
  572. rdi.str = MMC_CALLBACK;
  573. hr = pIResultData->InsertItem( &rdi );
  574. assert( SUCCEEDED( hr ) );
  575. (*pDevice)->SetItemID( rdi.itemID );
  576. return hr;
  577. }