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.

1316 lines
34 KiB

  1. //comp.cpp: ts mmc snapin implementaion of IComponent
  2. //Copyright (c) 1999 - 2000 Microsoft Corporation
  3. //nadima
  4. //
  5. #include "stdafx.h"
  6. #include "tsmmc.h"
  7. #include "compdata.h"
  8. #include "comp.h"
  9. #include "connode.h"
  10. #include "property.h"
  11. #define MSTSC_MULTI_HOST_CONTROL L"{85C67146-6932-427C-A6F2-43FDBADF2BFC}"
  12. #define IMAGE_MACHINE 1
  13. #define IMAGE_CONNECTED_MACHINE 2
  14. #define IMAGE_MACHINES 3
  15. CComp::CComp()
  16. {
  17. m_pConsole = NULL;
  18. m_pCompdata = NULL;
  19. m_bFlag = FALSE;
  20. m_pImageResult = NULL;
  21. m_pConsoleVerb = NULL;
  22. m_pDisplayHelp = NULL;
  23. m_bTriggeredFirstAutoConnect = FALSE;
  24. }
  25. //
  26. // Destructor
  27. //
  28. CComp::~CComp()
  29. {
  30. }
  31. STDMETHODIMP CComp::Initialize( LPCONSOLE pConsole)
  32. {
  33. HRESULT hr;
  34. USES_CONVERSION;
  35. if (m_pConsole) {
  36. m_pConsole->Release();
  37. }
  38. m_pConsole = pConsole;
  39. m_pConsole->AddRef();
  40. if (FAILED((hr = m_pConsole->QueryResultImageList( &m_pImageResult ))))
  41. {
  42. return hr;
  43. }
  44. if ( FAILED((hr = m_pConsole->QueryConsoleVerb( &m_pConsoleVerb))))
  45. {
  46. return hr;
  47. }
  48. if( FAILED((hr = m_pConsole->QueryInterface( IID_IDisplayHelp, (LPVOID *)&m_pDisplayHelp))))
  49. {
  50. return hr;
  51. }
  52. //
  53. // Load connecting text
  54. //
  55. TCHAR sz[MAX_PATH];
  56. if(!LoadString(_Module.GetResourceInstance(),
  57. IDS_STATUS_CONNECTING,
  58. sz,
  59. SIZE_OF_BUFFER( m_wszConnectingStatus )))
  60. {
  61. return E_FAIL;
  62. }
  63. OLECHAR* wszConnecting = T2OLE(sz);
  64. if(wszConnecting)
  65. {
  66. wcsncpy(m_wszConnectingStatus, wszConnecting,
  67. SIZE_OF_BUFFER( m_wszConnectingStatus ));
  68. }
  69. else
  70. {
  71. return E_FAIL;
  72. }
  73. //
  74. // Load connected text
  75. //
  76. if(!LoadString(_Module.GetResourceInstance(),
  77. IDS_STATUS_CONNECTED,
  78. sz,
  79. SIZE_OF_BUFFER( m_wszConnectedStatus )))
  80. {
  81. return E_FAIL;
  82. }
  83. OLECHAR* wszConnected = T2OLE(sz);
  84. if(wszConnected)
  85. {
  86. wcsncpy(m_wszConnectedStatus, wszConnected,
  87. SIZE_OF_BUFFER( m_wszConnectedStatus ));
  88. }
  89. else
  90. {
  91. return E_FAIL;
  92. }
  93. //
  94. // Load disconnected text
  95. //
  96. if(!LoadString(_Module.GetResourceInstance(),
  97. IDS_STATUS_DISCONNECTED,
  98. sz,
  99. SIZE_OF_BUFFER( m_wszDisconnectedStatus )))
  100. {
  101. return E_FAIL;
  102. }
  103. OLECHAR* wszDiscon = T2OLE(sz);
  104. if(wszDiscon)
  105. {
  106. wcsncpy(m_wszDisconnectedStatus, wszDiscon,
  107. SIZE_OF_BUFFER( m_wszDisconnectedStatus ));
  108. }
  109. else
  110. {
  111. return E_FAIL;
  112. }
  113. return S_OK;
  114. }
  115. //--------------------------------------------------------------------------------------------------
  116. STDMETHODIMP CComp::Notify( LPDATAOBJECT pDataObj , MMC_NOTIFY_TYPE event, LPARAM arg , LPARAM )
  117. {
  118. switch ( event )
  119. {
  120. case MMCN_ACTIVATE:
  121. ODS( L"IComponent -- MMCN_ACTIVATE\n" );
  122. break;
  123. case MMCN_ADD_IMAGES:
  124. ODS( L"IComponent -- MMCN_ADD_IMAGES\n" );
  125. OnAddImages( );
  126. break;
  127. case MMCN_BTN_CLICK:
  128. ODS( L"IComponent -- MMCN_BTN_CLICK\n" );
  129. break;
  130. case MMCN_CLICK:
  131. ODS( L"IComponent -- MMCN_CLICK\n" );
  132. break;
  133. case MMCN_DBLCLICK:
  134. ODS( L"IComponent -- MMCN_DBLCLICK\n" );
  135. return S_FALSE;
  136. case MMCN_DELETE:
  137. ODS( L"IComponent -- MMCN_DELETE\n" );
  138. break;
  139. case MMCN_EXPAND:
  140. ODS( L"IComponent -- MMCN_EXPAND\n" );
  141. break;
  142. case MMCN_MINIMIZED:
  143. ODS( L"IComponent -- MMCN_MINIMIZED\n" );
  144. break;
  145. case MMCN_PROPERTY_CHANGE:
  146. ODS( L"IComponent -- MMCN_PROPERTY_CHANGE\n" );
  147. break;
  148. case MMCN_REMOVE_CHILDREN:
  149. ODS( L"IComponent -- MMCN_REMOVE_CHILDREN\n" );
  150. break;
  151. case MMCN_REFRESH:
  152. ODS( L"IComponent -- MMCN_REFRESH\n" );
  153. break;
  154. case MMCN_RENAME:
  155. ODS( L"IComponent -- MMCN_RENAME\n" );
  156. break;
  157. case MMCN_SELECT:
  158. ODS( L"IComponent -- MMCN_SELECT\n" );
  159. if(!IS_SPECIAL_DATAOBJECT(pDataObj))
  160. {
  161. OnSelect( pDataObj , ( BOOL )LOWORD( arg ) , ( BOOL )HIWORD( arg ) );
  162. }
  163. break;
  164. case MMCN_SHOW:
  165. OnShow( pDataObj , ( BOOL )arg );
  166. ODS( L"IComponent -- MMCN_SHOW\n" );
  167. break;
  168. case MMCN_VIEW_CHANGE:
  169. ODS( L"IComponent -- MMCN_VIEW_CHANGE\n" );
  170. break;
  171. case MMCN_CONTEXTHELP:
  172. ODS( L"IComponent -- MMCN_CONTEXTHELP\n" );
  173. OnHelp( pDataObj );
  174. break;
  175. case MMCN_SNAPINHELP:
  176. ODS( L"IComponent -- MMCN_SNAPINHELP\n" );
  177. break;
  178. default:
  179. ODS( L"CComp::Notify - event not registered\n" );
  180. }
  181. return S_OK;
  182. }
  183. //--------------------------------------------------------------------------------------------------
  184. STDMETHODIMP CComp::Destroy( MMC_COOKIE )
  185. {
  186. if (m_pConsole) {
  187. m_pConsole->Release();
  188. m_pConsole = NULL;
  189. }
  190. if (m_pConsoleVerb) {
  191. m_pConsoleVerb->Release();
  192. m_pConsoleVerb = NULL;
  193. }
  194. if( m_pDisplayHelp != NULL ) {
  195. m_pDisplayHelp->Release();
  196. m_pDisplayHelp = NULL;
  197. }
  198. if (m_pImageResult) {
  199. m_pImageResult->Release();
  200. m_pImageResult = NULL;
  201. }
  202. return S_OK;
  203. }
  204. //--------------------------------------------------------------------------------------------------
  205. STDMETHODIMP CComp::GetResultViewType( MMC_COOKIE ck , LPOLESTR *ppOlestr , PLONG plView )
  206. {
  207. //
  208. // For the connection nodes return the MSTSC activex multi-host client.
  209. // No view for the root node
  210. //
  211. CBaseNode* pNode = (CBaseNode*) ck;
  212. if (!ck || pNode->GetNodeType() == MAIN_NODE)
  213. {
  214. //
  215. // Root node
  216. //
  217. *plView = MMC_VIEW_OPTIONS_NONE;
  218. //
  219. // indicate a standard list view should be used.
  220. //
  221. return S_FALSE;
  222. }
  223. else
  224. {
  225. TCHAR tchGUID[] = MSTSC_MULTI_HOST_CONTROL;
  226. *ppOlestr = ( LPOLESTR )CoTaskMemAlloc( sizeof( tchGUID ) + sizeof( TCHAR ) );
  227. ASSERT(*ppOlestr);
  228. if(!*ppOlestr)
  229. {
  230. return E_OUTOFMEMORY;
  231. }
  232. lstrcpy( ( LPTSTR )*ppOlestr , tchGUID );
  233. *plView = MMC_VIEW_OPTIONS_NOLISTVIEWS;
  234. return S_OK;
  235. }
  236. }
  237. //--------------------------------------------------------------------------------------------------
  238. STDMETHODIMP CComp::QueryDataObject( MMC_COOKIE ck , DATA_OBJECT_TYPES dtype , LPDATAOBJECT *ppDataObject )
  239. {
  240. if ( dtype == CCT_RESULT )
  241. {
  242. *ppDataObject = reinterpret_cast< LPDATAOBJECT >( ck );
  243. if ( *ppDataObject != NULL )
  244. {
  245. ( ( LPDATAOBJECT )*ppDataObject)->AddRef( );
  246. }
  247. }
  248. else if ( m_pCompdata != NULL )
  249. {
  250. return m_pCompdata->QueryDataObject( ck , dtype , ppDataObject );
  251. }
  252. return S_OK;
  253. }
  254. //--------------------------------------------------------------------------------------------------
  255. STDMETHODIMP CComp::GetDisplayInfo( LPRESULTDATAITEM pItem )
  256. {
  257. CBaseNode* pNode = (CBaseNode*) pItem->lParam;
  258. if ( pNode->GetNodeType() == CONNECTION_NODE )
  259. {
  260. CConNode* conNode = (CConNode*) pNode;
  261. if ( pItem->mask & RDI_STR )
  262. {
  263. pItem->str = conNode->GetDescription();
  264. }
  265. if (pItem->mask & RDI_IMAGE)
  266. {
  267. pItem->nImage = IMAGE_MACHINE;
  268. }
  269. }
  270. return S_OK;
  271. }
  272. //--------------------------------------------------------------------------
  273. BOOL CComp::OnAddImages( )
  274. {
  275. HRESULT hr;
  276. HICON hiconMachine = LoadIcon( _Module.GetResourceInstance( ) , MAKEINTRESOURCE( IDI_ICON_MACHINE ) );
  277. HICON hiconConnectedMachine = LoadIcon( _Module.GetResourceInstance( ) , MAKEINTRESOURCE( IDI_ICON_CONNECTED_MACHINE ) );
  278. HICON hiconMachines = LoadIcon( _Module.GetResourceInstance( ) , MAKEINTRESOURCE( IDI_ICON_MACHINES ) );
  279. ASSERT(m_pImageResult);
  280. if(!m_pImageResult)
  281. {
  282. return FALSE;
  283. }
  284. hr = m_pImageResult->ImageListSetIcon( ( PLONG_PTR )hiconMachine , IMAGE_MACHINE );
  285. if (FAILED(hr))
  286. {
  287. return FALSE;
  288. }
  289. hr = m_pImageResult->ImageListSetIcon( ( PLONG_PTR )hiconConnectedMachine , IMAGE_CONNECTED_MACHINE );
  290. if (FAILED(hr))
  291. {
  292. return FALSE;
  293. }
  294. hr = m_pImageResult->ImageListSetIcon( ( PLONG_PTR )hiconMachines , IMAGE_MACHINES );
  295. if (FAILED(hr))
  296. {
  297. return FALSE;
  298. }
  299. return TRUE;
  300. }
  301. //----------------------------------------------------------------------
  302. BOOL CComp::OnHelp( LPDATAOBJECT pDo )
  303. {
  304. TCHAR tchTopic[ 80 ];
  305. HRESULT hr = E_FAIL;
  306. if( pDo == NULL || m_pDisplayHelp == NULL )
  307. {
  308. return hr;
  309. }
  310. if(LoadString(_Module.GetResourceInstance(),
  311. IDS_TSCMMCHELPTOPIC,
  312. tchTopic,
  313. SIZE_OF_BUFFER( tchTopic )))
  314. {
  315. hr = m_pDisplayHelp->ShowTopic( tchTopic );
  316. }
  317. return ( SUCCEEDED( hr ) ? TRUE : FALSE );
  318. }
  319. //--------------------------------------------------------------------------------------------------
  320. STDMETHODIMP CComp::CompareObjects( LPDATAOBJECT , LPDATAOBJECT )
  321. {
  322. return E_NOTIMPL;
  323. }
  324. //--------------------------------------------------------------------------------------------------
  325. HRESULT CComp::InsertItemsinResultPane( )
  326. {
  327. return E_NOTIMPL;
  328. }
  329. //--------------------------------------------------------------------------------------------------
  330. HRESULT CComp::AddSettingsinResultPane( )
  331. {
  332. return E_NOTIMPL;
  333. }
  334. //--------------------------------------------------------------------------------------------------
  335. HRESULT CComp::OnSelect( LPDATAOBJECT pdo , BOOL bScope , BOOL bSelected )
  336. {
  337. UNREFERENCED_PARAMETER(bScope);
  338. CBaseNode *pNode = static_cast< CBaseNode * >( pdo );
  339. if ( pNode == NULL )
  340. {
  341. return S_FALSE;
  342. }
  343. ASSERT(!IS_SPECIAL_DATAOBJECT(pdo));
  344. if(IS_SPECIAL_DATAOBJECT(pdo))
  345. {
  346. return E_FAIL;
  347. }
  348. if ( m_pConsoleVerb == NULL )
  349. {
  350. return E_UNEXPECTED;
  351. }
  352. // Item is being deselected and we're not interested currently
  353. if ( !bSelected )
  354. {
  355. return S_OK;
  356. }
  357. if ( pNode->GetNodeType() == CONNECTION_NODE)
  358. {
  359. //
  360. // Enable the delete verb for connection nodes
  361. //
  362. HRESULT hr;
  363. hr=m_pConsoleVerb->SetVerbState( MMC_VERB_DELETE , ENABLED , TRUE );
  364. if (FAILED(hr))
  365. {
  366. return hr;
  367. }
  368. hr=m_pConsoleVerb->SetVerbState( MMC_VERB_PROPERTIES , ENABLED , TRUE );
  369. if (FAILED(hr))
  370. {
  371. return hr;
  372. }
  373. hr=m_pConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES);
  374. if (FAILED(hr))
  375. {
  376. return hr;
  377. }
  378. }
  379. return S_OK;
  380. }
  381. //--------------------------------------------------------------------------------------------------
  382. HRESULT CComp::SetCompdata( CCompdata *pCompdata )
  383. {
  384. m_pCompdata = pCompdata;
  385. return S_OK;
  386. }
  387. //
  388. // Defered callback to async trigger a connection
  389. // This works because the DeferredCallBackProc is called on MMC's main
  390. // thread and MMC is APARTMENT threaded so we can make calls on MMC
  391. // interfaces form this thread.
  392. //
  393. // This whole DeferredCallBack thing is a hack to fix #203217. Basically
  394. // on autolaunch MMC loads the snapin and then maximizes the window which
  395. // means we would connect at the wrong size (if option to match container
  396. // size was chosen). This Deferred mechanism ensures MMC has the time
  397. // to size the result pane correctly first.
  398. //
  399. //
  400. //
  401. // OnShow below sneaks a pointer to deferd connection info in idEvent
  402. //
  403. VOID CALLBACK DeferredCallBackProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  404. {
  405. PTSSNAPIN_DEFER_CONNECT pDeferredConnectInfo = NULL;
  406. IMsRdpClient* pTs = NULL;
  407. HRESULT hr = E_FAIL;
  408. KillTimer( hwnd, idEvent);
  409. if(idEvent)
  410. {
  411. pDeferredConnectInfo = (PTSSNAPIN_DEFER_CONNECT) idEvent;
  412. if(pDeferredConnectInfo)
  413. {
  414. ASSERT(pDeferredConnectInfo->pComponent);
  415. ASSERT(pDeferredConnectInfo->pConnectionNode);
  416. DBGMSG(L"Triggering deferred connection on connode %p",
  417. pDeferredConnectInfo->pConnectionNode);
  418. pTs = pDeferredConnectInfo->pConnectionNode->GetTsClient();
  419. if(pTs)
  420. {
  421. hr = pDeferredConnectInfo->pComponent->ConnectWithNewSettings(
  422. pTs, pDeferredConnectInfo->pConnectionNode);
  423. }
  424. //
  425. // Done with the defered connection info, free it
  426. //
  427. LocalFree( pDeferredConnectInfo );
  428. pDeferredConnectInfo = NULL;
  429. }
  430. }
  431. if(pTs)
  432. {
  433. pTs->Release();
  434. pTs = NULL;
  435. }
  436. DBGMSG(L"DeferredConnect status: 0x%x",hr);
  437. }
  438. //--------------------------------------------------------------------------
  439. // Called when a node is selected. Manages activation of new TS client instances
  440. // and once they are 'hot' switching back to a running instance if a node is
  441. // reselected.
  442. //
  443. //--------------------------------------------------------------------------
  444. HRESULT CComp::OnShow( LPDATAOBJECT pDataobject , BOOL bSelect )
  445. {
  446. HRESULT hr = S_FALSE;
  447. IUnknown* pUnk = NULL;
  448. IMstscMhst* pTsMultiHost = NULL;
  449. IMsRdpClient* pTS = NULL;
  450. PTSSNAPIN_DEFER_CONNECT pDeferredConnectInfo = NULL;
  451. HWND hwndMain = NULL;
  452. USES_CONVERSION;
  453. ODS(L"OnShow\n");
  454. if(!bSelect)
  455. {
  456. //
  457. // Don't need to do any processing for deselect
  458. //
  459. return S_OK;
  460. }
  461. //
  462. // Only do this for connection nodes
  463. //
  464. if (((CBaseNode*) pDataobject)->GetNodeType() == MAIN_NODE)
  465. {
  466. return S_FALSE;
  467. }
  468. CConNode* pConNode = (CConNode*) pDataobject;
  469. ASSERT(pConNode);
  470. if (!pConNode)
  471. {
  472. return S_FALSE;
  473. }
  474. if ( m_pConsole != NULL )
  475. {
  476. hr= m_pConsole->QueryResultView( ( LPUNKNOWN * )&pUnk );
  477. if(FAILED(hr))
  478. {
  479. goto FN_EXIT_POINT;
  480. }
  481. pTsMultiHost = pConNode->GetMultiHostCtl();
  482. if(NULL == pTsMultiHost)
  483. {
  484. hr = pUnk->QueryInterface( __uuidof(IMstscMhst), (LPVOID*) &pTsMultiHost);
  485. if(FAILED(hr))
  486. {
  487. goto FN_EXIT_POINT;
  488. }
  489. pConNode->SetMultiHostCtl( pTsMultiHost);
  490. }
  491. //We're done with the pUnk to the result view
  492. pUnk->Release();
  493. pUnk = NULL;
  494. ASSERT(NULL != pTsMultiHost);
  495. if(NULL == pTsMultiHost)
  496. {
  497. hr = E_FAIL;
  498. goto FN_EXIT_POINT;
  499. }
  500. //
  501. // If the con node is being selected then connect
  502. // or switch to already running instance
  503. //
  504. //
  505. // Connect
  506. //
  507. ODS(L"Connection node Selected...\n");
  508. pTS = pConNode->GetTsClient();
  509. if(NULL == pTS)
  510. {
  511. //Create new instance
  512. hr = pTsMultiHost->Add( &pTS);
  513. if(FAILED(hr))
  514. {
  515. goto FN_EXIT_POINT;
  516. }
  517. pConNode->SetTsClient( pTS);
  518. //
  519. // Initialize the disconnected message
  520. //
  521. hr = pTS->put_DisconnectedText(m_wszDisconnectedStatus);
  522. if(FAILED(hr))
  523. {
  524. goto FN_EXIT_POINT;
  525. }
  526. }
  527. ASSERT(NULL != pTS);
  528. if(NULL == pTS)
  529. {
  530. hr = E_FAIL;
  531. goto FN_EXIT_POINT;
  532. }
  533. hr = pTsMultiHost->put_ActiveClient( pTS);
  534. if(FAILED(hr))
  535. {
  536. goto FN_EXIT_POINT;
  537. }
  538. //
  539. //If this is the first time through and we are not connected
  540. //then connect
  541. //
  542. if(!pConNode->IsConnected() && !pConNode->IsConnInitialized())
  543. {
  544. if(m_bTriggeredFirstAutoConnect)
  545. {
  546. //
  547. // Just connect
  548. //
  549. hr = ConnectWithNewSettings( pTS, pConNode);
  550. if(FAILED(hr))
  551. {
  552. goto FN_EXIT_POINT;
  553. }
  554. }
  555. else
  556. {
  557. // HACK!
  558. // Queue a defered connection
  559. // to work around MMC's annoying behaviour
  560. // of loading the snapin before it sizes itself
  561. // which means we connect at the wrong window
  562. // size.
  563. //
  564. m_bTriggeredFirstAutoConnect = TRUE;
  565. pDeferredConnectInfo = (PTSSNAPIN_DEFER_CONNECT)
  566. LocalAlloc(LPTR, sizeof(TSSNAPIN_DEFER_CONNECT));
  567. if(pDeferredConnectInfo)
  568. {
  569. pDeferredConnectInfo->pComponent = this;
  570. pDeferredConnectInfo->pConnectionNode = pConNode;
  571. hwndMain = GetMMCMainWindow();
  572. if(hwndMain)
  573. {
  574. //
  575. // Note the delay is arbitrary the key thing
  576. // is that timer messages are low priority so the
  577. // MMC size messages should make it through first
  578. //
  579. //
  580. // NOTE: THERE IS NO LEAK HERE
  581. // pDeferredConnectInfo is freed in the
  582. // DeferredCallBack
  583. //
  584. SetTimer( hwndMain,
  585. (UINT_PTR)(pDeferredConnectInfo),
  586. 100, //100ms delay
  587. DeferredCallBackProc );
  588. }
  589. else
  590. {
  591. ODS(L"Unable to get MMC main window handle");
  592. hr = E_FAIL;
  593. if(pDeferredConnectInfo)
  594. {
  595. LocalFree(pDeferredConnectInfo);
  596. pDeferredConnectInfo = NULL;
  597. }
  598. goto FN_EXIT_POINT;
  599. }
  600. }
  601. else
  602. {
  603. ODS(L"Alloc for TSSNAPIN_DEFER_CONNECT failed");
  604. hr = E_OUTOFMEMORY;
  605. goto FN_EXIT_POINT;
  606. }
  607. }
  608. }
  609. hr = S_OK;
  610. }
  611. FN_EXIT_POINT:
  612. if(pTS)
  613. {
  614. pTS->Release();
  615. pTS = NULL;
  616. }
  617. if(pUnk)
  618. {
  619. pUnk->Release();
  620. pUnk = NULL;
  621. }
  622. if(pTsMultiHost)
  623. {
  624. pTsMultiHost->Release();
  625. pTsMultiHost = NULL;
  626. }
  627. return hr;
  628. }
  629. //
  630. // Get the window handle to MMC's main window
  631. //
  632. HWND CComp::GetMMCMainWindow()
  633. {
  634. HRESULT hr = E_FAIL;
  635. HWND hwnd = NULL;
  636. IConsole2* pConsole2;
  637. if(m_pConsole)
  638. {
  639. hr = m_pConsole->GetMainWindow( &hwnd );
  640. if(SUCCEEDED(hr))
  641. {
  642. return hwnd;
  643. }
  644. else
  645. {
  646. return NULL;
  647. }
  648. }
  649. else
  650. {
  651. return NULL;
  652. }
  653. }
  654. HRESULT CComp::ConnectWithNewSettings(IMsRdpClient* pTS, CConNode* pConNode)
  655. {
  656. HRESULT hr = E_FAIL;
  657. IMsRdpClientSecuredSettings *pMstscSecured = NULL;
  658. IMsRdpClientAdvancedSettings *pAdvSettings = NULL;
  659. IMsTscNonScriptable *ptsns = NULL;
  660. IMsRdpClient2* pTsc2 = NULL;
  661. ASSERT(NULL != pTS);
  662. ASSERT(NULL != pConNode);
  663. if(NULL == pTS || !pConNode)
  664. {
  665. return E_POINTER;
  666. }
  667. //
  668. // Init con settings
  669. //
  670. if (FAILED(hr = pTS->put_Server( pConNode->GetServerName() ))) {
  671. DC_QUIT;
  672. }
  673. if (FAILED(hr = pTS->QueryInterface(IID_IMsRdpClient2, (void**)&pTsc2))) {
  674. //
  675. // NOT a fatal error it just means we can't use the newer features
  676. //
  677. DBGMSG( L"QueryInterface IID_IMsRdpClient2 failed: 0x%x\n", hr );
  678. }
  679. //
  680. // Setup the connection status string
  681. //
  682. TCHAR szConnectingStatus[MAX_PATH*2];
  683. _stprintf(szConnectingStatus, m_wszConnectingStatus,
  684. pConNode->GetServerName());
  685. if(FAILED(hr = pTS->put_ConnectingText( szConnectingStatus))) {
  686. DC_QUIT;
  687. }
  688. if (FAILED(hr = pTS->put_FullScreenTitle( pConNode->GetServerName()))) {
  689. DC_QUIT;
  690. }
  691. //
  692. // Connected status text
  693. //
  694. if (pTsc2) {
  695. TCHAR szConnectedStatus[MAX_PATH*2];
  696. _stprintf(szConnectedStatus, m_wszConnectedStatus,
  697. pConNode->GetServerName());
  698. if (FAILED(hr = pTsc2->put_ConnectedStatusText(szConnectedStatus))) {
  699. DC_QUIT;
  700. }
  701. }
  702. if (pConNode->GetResType() != SCREEN_RES_FILL_MMC &&
  703. pConNode->GetDesktopWidth() && pConNode->GetDesktopHeight()) {
  704. if (FAILED(hr = pTS->put_DesktopWidth( pConNode->GetDesktopWidth()))) {
  705. DC_QUIT;
  706. }
  707. if (FAILED(hr = pTS->put_DesktopHeight( pConNode->GetDesktopHeight()))) {
  708. DC_QUIT;
  709. }
  710. }
  711. else if(pConNode->GetResType() == SCREEN_RES_FILL_MMC) {
  712. //
  713. // Need to fill the MMC result pane so tell the control
  714. // to size itself to the container by giving 0 width/height
  715. //
  716. if (FAILED(hr = pTS->put_DesktopWidth( 0))) {
  717. DC_QUIT;
  718. }
  719. if (FAILED(hr = pTS->put_DesktopHeight( 0))) {
  720. DC_QUIT;
  721. }
  722. }
  723. //
  724. // Program/Start directory
  725. //
  726. if(FAILED(hr = pTS->get_SecuredSettings2( &pMstscSecured))) {
  727. DC_QUIT;
  728. }
  729. if (FAILED(hr = pMstscSecured->put_StartProgram( pConNode->GetProgramPath() ))) {
  730. DC_QUIT;
  731. }
  732. if (FAILED(hr = pMstscSecured->put_WorkDir( pConNode->GetWorkDir() ))) {
  733. DC_QUIT;
  734. }
  735. pMstscSecured->Release();
  736. pMstscSecured = NULL;
  737. hr = pTS->get_AdvancedSettings2( &pAdvSettings);
  738. if(FAILED(hr)) {
  739. DC_QUIT;
  740. }
  741. if (FAILED(hr = pAdvSettings->put_RedirectDrives(
  742. BOOL_TO_VB(pConNode->GetRedirectDrives())))) {
  743. DC_QUIT;
  744. }
  745. if (FAILED(hr = pAdvSettings->put_RedirectPrinters(
  746. BOOL_TO_VB(TRUE)))) {
  747. DC_QUIT;
  748. }
  749. if (FAILED(hr = pAdvSettings->put_RedirectPorts(
  750. BOOL_TO_VB(TRUE)))) {
  751. DC_QUIT;
  752. }
  753. if (FAILED(hr = pAdvSettings->put_RedirectSmartCards(
  754. BOOL_TO_VB(TRUE)))) {
  755. DC_QUIT;
  756. }
  757. //
  758. // Container handled fullscreen
  759. //
  760. hr = pAdvSettings->put_ConnectToServerConsole(
  761. BOOL_TO_VB(pConNode->GetConnectToConsole()));
  762. if(FAILED(hr)) {
  763. DC_QUIT;
  764. }
  765. //
  766. // Don't allow the control to grab focus
  767. // the snapin will manage giving focus to a node when it switches
  768. // to it. This prevents problems where an obscured session steals
  769. // focus from another one.
  770. //
  771. hr = pAdvSettings->put_GrabFocusOnConnect( FALSE );
  772. if(FAILED(hr)) {
  773. DC_QUIT;
  774. }
  775. if (FAILED(hr = pTS->put_UserName( pConNode->GetUserName()))) {
  776. DC_QUIT;
  777. }
  778. if (FAILED(hr = pTS->put_Domain( pConNode->GetDomain()))) {
  779. DC_QUIT;
  780. }
  781. //
  782. // Set the password/salt
  783. //
  784. if ( pConNode->GetPasswordSpecified())
  785. {
  786. TCHAR szPass[CL_MAX_PASSWORD_LENGTH_BYTES/sizeof(TCHAR)];
  787. hr = pConNode->GetClearTextPass(szPass, sizeof(szPass));
  788. if (SUCCEEDED(hr)) {
  789. BSTR Pass = SysAllocString(szPass);
  790. if (Pass) {
  791. hr = pAdvSettings->put_ClearTextPassword(Pass);
  792. SecureZeroMemory(Pass, SysStringByteLen(Pass));
  793. SysFreeString(Pass);
  794. }
  795. }
  796. SecureZeroMemory(szPass, sizeof(szPass));
  797. }
  798. else {
  799. //Password is not specified, make sure logon
  800. //properties are reset
  801. hr = pTS->QueryInterface(IID_IMsTscNonScriptable, (void**)&ptsns);
  802. if(SUCCEEDED(hr)) {
  803. if (FAILED(hr = ptsns->ResetPassword())) {
  804. DC_QUIT;
  805. }
  806. ptsns->Release();
  807. ptsns = NULL;
  808. }
  809. else {
  810. DC_QUIT;
  811. }
  812. }
  813. pAdvSettings->Release();
  814. pAdvSettings = NULL;
  815. pConNode->SetConnectionInitialized(TRUE);
  816. //
  817. // Release any existing view and connect
  818. //
  819. pConNode->SetView(NULL);
  820. pConNode->SetView(this);
  821. hr = pTS->Connect( );
  822. if (FAILED(hr)) {
  823. DC_QUIT;
  824. }
  825. GiveFocusToControl(pTS);
  826. pConNode->SetConnected(TRUE);
  827. hr = S_OK;
  828. DC_EXIT_POINT:
  829. if (pMstscSecured) {
  830. pMstscSecured->Release();
  831. pMstscSecured = NULL;
  832. }
  833. if (pAdvSettings) {
  834. pAdvSettings->Release();
  835. pAdvSettings = NULL;
  836. }
  837. if (ptsns) {
  838. ptsns->Release();
  839. ptsns = NULL;
  840. }
  841. if (pTsc2) {
  842. pTsc2->Release();
  843. pTsc2 = NULL;
  844. }
  845. return hr;
  846. }
  847. BOOL CComp::GiveFocusToControl(IMsRdpClient* pTs)
  848. {
  849. IOleInPlaceActiveObject* poipa = NULL;
  850. HWND hwnd;
  851. HRESULT hr = E_FAIL;
  852. if(pTs)
  853. {
  854. hr = pTs->QueryInterface( IID_IOleInPlaceActiveObject,
  855. (void**)&poipa );
  856. if( SUCCEEDED(hr) )
  857. {
  858. hr = poipa->GetWindow( &hwnd );
  859. if( SUCCEEDED(hr) )
  860. {
  861. DBGMSG(L"Giving focus to control wnd: 0%p",
  862. hwnd);
  863. SetFocus( hwnd );
  864. }
  865. else
  866. {
  867. ODS(L"poipa->GetWindow failed");
  868. }
  869. poipa->Release();
  870. }
  871. }
  872. return SUCCEEDED(hr);
  873. }
  874. //
  875. // menu items
  876. //
  877. STDMETHODIMP CComp::AddMenuItems( LPDATAOBJECT pNode,
  878. LPCONTEXTMENUCALLBACK pCtxMenu,
  879. PLONG plInsertion)
  880. {
  881. TCHAR tchBuffer1[ 128 ];
  882. TCHAR tchBuffer2[ 128 ];
  883. ATLASSERT( pNode != NULL );
  884. ATLASSERT( pCtxMenu != NULL );
  885. ATLASSERT( plInsertion != NULL );
  886. if (!pNode)
  887. {
  888. return E_FAIL;
  889. }
  890. if(IS_SPECIAL_DATAOBJECT(pNode))
  891. {
  892. return E_FAIL;
  893. }
  894. CBaseNode *pBaseNode = dynamic_cast< CBaseNode *>( pNode );
  895. if (!pBaseNode)
  896. {
  897. return E_FAIL;
  898. }
  899. if (pBaseNode->GetNodeType() == MAIN_NODE)
  900. {
  901. //
  902. // Check that insertion at the View is allowed
  903. //
  904. if (!(*plInsertion & CCM_INSERTIONALLOWED_VIEW))
  905. {
  906. return S_FALSE;
  907. }
  908. //
  909. // Add menu item to root node
  910. //
  911. CONTEXTMENUITEM ctxmi;
  912. if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_NEW_CONNECTION ,
  913. tchBuffer1 , SIZE_OF_BUFFER( tchBuffer1 )))
  914. {
  915. return E_OUTOFMEMORY;
  916. }
  917. ctxmi.strName = tchBuffer1;
  918. if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_STATUS_NEW_CONNECTION ,
  919. tchBuffer2 , SIZE_OF_BUFFER( tchBuffer2)))
  920. {
  921. return E_OUTOFMEMORY;
  922. }
  923. ctxmi.strStatusBarText = tchBuffer2;
  924. ctxmi.lCommandID = IDM_CREATECON;
  925. ctxmi.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP ;
  926. ctxmi.fFlags = 0;
  927. ctxmi.fSpecialFlags = 0;
  928. if (FAILED(pCtxMenu->AddItem( &ctxmi )))
  929. {
  930. return E_FAIL;
  931. }
  932. }
  933. else if(pBaseNode->GetNodeType() == CONNECTION_NODE)
  934. {
  935. IComponent* pOwningView = NULL;
  936. BOOL fBailOut = FALSE;
  937. //
  938. // Check that insertion at the view is allowed
  939. //
  940. if (!(*plInsertion & CCM_INSERTIONALLOWED_VIEW))
  941. {
  942. return S_FALSE;
  943. }
  944. //
  945. // Add 'Connect' menu item
  946. //
  947. CConNode* pConNode = (CConNode*) pBaseNode;
  948. ASSERT(pConNode);
  949. if(!pConNode)
  950. {
  951. return E_FAIL;
  952. }
  953. pOwningView = pConNode->GetView();
  954. //
  955. // A connected node 'belongs' to a view so don't allow
  956. // commands on other views to affect it
  957. //
  958. // A null pOwningView means an unowned connection
  959. //
  960. if (pOwningView && pOwningView != this)
  961. {
  962. fBailOut = TRUE;
  963. }
  964. if (pOwningView)
  965. {
  966. pOwningView->Release();
  967. pOwningView = NULL;
  968. }
  969. if (fBailOut)
  970. {
  971. return S_OK;
  972. }
  973. BOOL bIsTSCliConnected = CCompdata::IsTSClientConnected(pConNode);
  974. CONTEXTMENUITEM ctxmi;
  975. if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_CONNECT ,
  976. tchBuffer1 , SIZE_OF_BUFFER( tchBuffer1)))
  977. {
  978. return E_OUTOFMEMORY;
  979. }
  980. ctxmi.strName = tchBuffer1;
  981. if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_STATUS_CONNECT ,
  982. tchBuffer2 , SIZE_OF_BUFFER( tchBuffer2)))
  983. {
  984. return E_OUTOFMEMORY;
  985. }
  986. ctxmi.strStatusBarText = tchBuffer2;
  987. ctxmi.lCommandID = IDM_CONNECT;
  988. ctxmi.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP;
  989. ctxmi.fFlags = bIsTSCliConnected ? MF_GRAYED: MF_ENABLED;
  990. ctxmi.fSpecialFlags = 0;
  991. if (FAILED(pCtxMenu->AddItem( &ctxmi )))
  992. {
  993. return E_FAIL;
  994. }
  995. //
  996. // Add 'Disconnect' menu item
  997. //
  998. if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_DISCONNECT ,
  999. tchBuffer1 , SIZE_OF_BUFFER( tchBuffer1 ) ) )
  1000. {
  1001. return E_OUTOFMEMORY;
  1002. }
  1003. ctxmi.strName = tchBuffer1;
  1004. if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_STATUS_DISCONNECT ,
  1005. tchBuffer2 , SIZE_OF_BUFFER( tchBuffer2 )))
  1006. {
  1007. return E_OUTOFMEMORY;
  1008. }
  1009. ctxmi.strStatusBarText = tchBuffer2;
  1010. ctxmi.lCommandID = IDM_DISCONNECT;
  1011. ctxmi.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP;
  1012. ctxmi.fFlags = !bIsTSCliConnected ? MF_GRAYED: MF_ENABLED;
  1013. ctxmi.fSpecialFlags = 0;
  1014. if (FAILED(pCtxMenu->AddItem( &ctxmi )))
  1015. {
  1016. return E_FAIL;
  1017. }
  1018. }
  1019. return S_OK;
  1020. }
  1021. //----------------------------------------------------------------------------------------------------------
  1022. // Menu handler
  1023. //----------------------------------------------------------------------------------------------------------
  1024. STDMETHODIMP CComp::Command( LONG lCommand , LPDATAOBJECT pDo)
  1025. {
  1026. //
  1027. // Add a new connection...
  1028. //
  1029. CBaseNode *pNode = dynamic_cast< CBaseNode *>( pDo );
  1030. HRESULT hr = S_OK;
  1031. if (IDM_CREATECON == lCommand)
  1032. {
  1033. if ( m_pCompdata)
  1034. {
  1035. hr = m_pCompdata->AddNewConnection();
  1036. }
  1037. else
  1038. {
  1039. hr = E_FAIL;
  1040. }
  1041. return hr;
  1042. }
  1043. else if (IDM_CONNECT == lCommand)
  1044. {
  1045. //
  1046. // Connect
  1047. //
  1048. if(!pNode)
  1049. {
  1050. return E_INVALIDARG;
  1051. }
  1052. else if(pNode->GetNodeType() != CONNECTION_NODE)
  1053. {
  1054. //
  1055. // Can't receive a connect request for a node other
  1056. // than a connection node
  1057. //
  1058. ASSERT(pNode->GetNodeType() == CONNECTION_NODE);
  1059. return E_INVALIDARG;
  1060. }
  1061. CConNode* pConNode = (CConNode*) pNode;
  1062. //
  1063. // Select the scope node, that will call CComp::OnShow which will connect
  1064. //
  1065. ASSERT(m_pConsole);
  1066. if(!m_pConsole)
  1067. {
  1068. return E_FAIL;
  1069. }
  1070. IMsRdpClient* pTS = pConNode->GetTsClient();
  1071. if(NULL != pTS && pConNode->IsConnInitialized())
  1072. {
  1073. //
  1074. // Only connect directly if the connection settings are initialized
  1075. //
  1076. //
  1077. // Set view ownership
  1078. //
  1079. pConNode->SetView( this );
  1080. HRESULT hr = pTS->Connect();
  1081. if (FAILED(hr))
  1082. {
  1083. return hr;
  1084. }
  1085. pConNode->SetConnected(TRUE);
  1086. pTS->Release();
  1087. }
  1088. //
  1089. // Selecting the node if the con settings are not initialized
  1090. // initializes them and connects
  1091. //
  1092. if(FAILED(m_pConsole->SelectScopeItem( pConNode->GetScopeID())))
  1093. {
  1094. return E_FAIL;
  1095. }
  1096. hr = S_OK;
  1097. }
  1098. else if (IDM_DISCONNECT == lCommand)
  1099. {
  1100. if(!pNode)
  1101. {
  1102. return E_INVALIDARG;
  1103. }
  1104. //
  1105. // Disconnect
  1106. //
  1107. if(pNode->GetNodeType() != CONNECTION_NODE)
  1108. {
  1109. //
  1110. // Can't receive a connect request for a node other
  1111. // than a connection node
  1112. //
  1113. ASSERT(pNode->GetNodeType() == CONNECTION_NODE);
  1114. return E_INVALIDARG;
  1115. }
  1116. CConNode* pConNode = (CConNode*) pNode;
  1117. ASSERT(m_pConsole);
  1118. if(!m_pConsole)
  1119. {
  1120. return E_FAIL;
  1121. }
  1122. IMsRdpClient* pTS = pConNode->GetTsClient();
  1123. if(NULL != pTS)
  1124. {
  1125. HRESULT hr = pTS->Disconnect();
  1126. if (FAILED(hr))
  1127. {
  1128. return hr;
  1129. }
  1130. pTS->Release();
  1131. }
  1132. pConNode->SetConnected(FALSE);
  1133. hr = S_OK;
  1134. }
  1135. return hr;
  1136. }