//comp.cpp: ts mmc snapin implementaion of IComponent //Copyright (c) 1999 - 2000 Microsoft Corporation //nadima // #include "stdafx.h" #include "tsmmc.h" #include "compdata.h" #include "comp.h" #include "connode.h" #include "property.h" #define MSTSC_MULTI_HOST_CONTROL L"{85C67146-6932-427C-A6F2-43FDBADF2BFC}" #define IMAGE_MACHINE 1 #define IMAGE_CONNECTED_MACHINE 2 #define IMAGE_MACHINES 3 CComp::CComp() { m_pConsole = NULL; m_pCompdata = NULL; m_bFlag = FALSE; m_pImageResult = NULL; m_pConsoleVerb = NULL; m_pDisplayHelp = NULL; m_bTriggeredFirstAutoConnect = FALSE; } // // Destructor // CComp::~CComp() { } STDMETHODIMP CComp::Initialize( LPCONSOLE pConsole) { HRESULT hr; USES_CONVERSION; if (m_pConsole) { m_pConsole->Release(); } m_pConsole = pConsole; m_pConsole->AddRef(); if (FAILED((hr = m_pConsole->QueryResultImageList( &m_pImageResult )))) { return hr; } if ( FAILED((hr = m_pConsole->QueryConsoleVerb( &m_pConsoleVerb)))) { return hr; } if( FAILED((hr = m_pConsole->QueryInterface( IID_IDisplayHelp, (LPVOID *)&m_pDisplayHelp)))) { return hr; } // // Load connecting text // TCHAR sz[MAX_PATH]; if(!LoadString(_Module.GetResourceInstance(), IDS_STATUS_CONNECTING, sz, SIZE_OF_BUFFER( m_wszConnectingStatus ))) { return E_FAIL; } OLECHAR* wszConnecting = T2OLE(sz); if(wszConnecting) { wcsncpy(m_wszConnectingStatus, wszConnecting, SIZE_OF_BUFFER( m_wszConnectingStatus )); } else { return E_FAIL; } // // Load connected text // if(!LoadString(_Module.GetResourceInstance(), IDS_STATUS_CONNECTED, sz, SIZE_OF_BUFFER( m_wszConnectedStatus ))) { return E_FAIL; } OLECHAR* wszConnected = T2OLE(sz); if(wszConnected) { wcsncpy(m_wszConnectedStatus, wszConnected, SIZE_OF_BUFFER( m_wszConnectedStatus )); } else { return E_FAIL; } // // Load disconnected text // if(!LoadString(_Module.GetResourceInstance(), IDS_STATUS_DISCONNECTED, sz, SIZE_OF_BUFFER( m_wszDisconnectedStatus ))) { return E_FAIL; } OLECHAR* wszDiscon = T2OLE(sz); if(wszDiscon) { wcsncpy(m_wszDisconnectedStatus, wszDiscon, SIZE_OF_BUFFER( m_wszDisconnectedStatus )); } else { return E_FAIL; } return S_OK; } //-------------------------------------------------------------------------------------------------- STDMETHODIMP CComp::Notify( LPDATAOBJECT pDataObj , MMC_NOTIFY_TYPE event, LPARAM arg , LPARAM ) { switch ( event ) { case MMCN_ACTIVATE: ODS( L"IComponent -- MMCN_ACTIVATE\n" ); break; case MMCN_ADD_IMAGES: ODS( L"IComponent -- MMCN_ADD_IMAGES\n" ); OnAddImages( ); break; case MMCN_BTN_CLICK: ODS( L"IComponent -- MMCN_BTN_CLICK\n" ); break; case MMCN_CLICK: ODS( L"IComponent -- MMCN_CLICK\n" ); break; case MMCN_DBLCLICK: ODS( L"IComponent -- MMCN_DBLCLICK\n" ); return S_FALSE; case MMCN_DELETE: ODS( L"IComponent -- MMCN_DELETE\n" ); break; case MMCN_EXPAND: ODS( L"IComponent -- MMCN_EXPAND\n" ); break; case MMCN_MINIMIZED: ODS( L"IComponent -- MMCN_MINIMIZED\n" ); break; case MMCN_PROPERTY_CHANGE: ODS( L"IComponent -- MMCN_PROPERTY_CHANGE\n" ); break; case MMCN_REMOVE_CHILDREN: ODS( L"IComponent -- MMCN_REMOVE_CHILDREN\n" ); break; case MMCN_REFRESH: ODS( L"IComponent -- MMCN_REFRESH\n" ); break; case MMCN_RENAME: ODS( L"IComponent -- MMCN_RENAME\n" ); break; case MMCN_SELECT: ODS( L"IComponent -- MMCN_SELECT\n" ); if(!IS_SPECIAL_DATAOBJECT(pDataObj)) { OnSelect( pDataObj , ( BOOL )LOWORD( arg ) , ( BOOL )HIWORD( arg ) ); } break; case MMCN_SHOW: OnShow( pDataObj , ( BOOL )arg ); ODS( L"IComponent -- MMCN_SHOW\n" ); break; case MMCN_VIEW_CHANGE: ODS( L"IComponent -- MMCN_VIEW_CHANGE\n" ); break; case MMCN_CONTEXTHELP: ODS( L"IComponent -- MMCN_CONTEXTHELP\n" ); OnHelp( pDataObj ); break; case MMCN_SNAPINHELP: ODS( L"IComponent -- MMCN_SNAPINHELP\n" ); break; default: ODS( L"CComp::Notify - event not registered\n" ); } return S_OK; } //-------------------------------------------------------------------------------------------------- STDMETHODIMP CComp::Destroy( MMC_COOKIE ) { if (m_pConsole) { m_pConsole->Release(); m_pConsole = NULL; } if (m_pConsoleVerb) { m_pConsoleVerb->Release(); m_pConsoleVerb = NULL; } if( m_pDisplayHelp != NULL ) { m_pDisplayHelp->Release(); m_pDisplayHelp = NULL; } if (m_pImageResult) { m_pImageResult->Release(); m_pImageResult = NULL; } return S_OK; } //-------------------------------------------------------------------------------------------------- STDMETHODIMP CComp::GetResultViewType( MMC_COOKIE ck , LPOLESTR *ppOlestr , PLONG plView ) { // // For the connection nodes return the MSTSC activex multi-host client. // No view for the root node // CBaseNode* pNode = (CBaseNode*) ck; if (!ck || pNode->GetNodeType() == MAIN_NODE) { // // Root node // *plView = MMC_VIEW_OPTIONS_NONE; // // indicate a standard list view should be used. // return S_FALSE; } else { TCHAR tchGUID[] = MSTSC_MULTI_HOST_CONTROL; *ppOlestr = ( LPOLESTR )CoTaskMemAlloc( sizeof( tchGUID ) + sizeof( TCHAR ) ); ASSERT(*ppOlestr); if(!*ppOlestr) { return E_OUTOFMEMORY; } lstrcpy( ( LPTSTR )*ppOlestr , tchGUID ); *plView = MMC_VIEW_OPTIONS_NOLISTVIEWS; return S_OK; } } //-------------------------------------------------------------------------------------------------- STDMETHODIMP CComp::QueryDataObject( MMC_COOKIE ck , DATA_OBJECT_TYPES dtype , LPDATAOBJECT *ppDataObject ) { if ( dtype == CCT_RESULT ) { *ppDataObject = reinterpret_cast< LPDATAOBJECT >( ck ); if ( *ppDataObject != NULL ) { ( ( LPDATAOBJECT )*ppDataObject)->AddRef( ); } } else if ( m_pCompdata != NULL ) { return m_pCompdata->QueryDataObject( ck , dtype , ppDataObject ); } return S_OK; } //-------------------------------------------------------------------------------------------------- STDMETHODIMP CComp::GetDisplayInfo( LPRESULTDATAITEM pItem ) { CBaseNode* pNode = (CBaseNode*) pItem->lParam; if ( pNode->GetNodeType() == CONNECTION_NODE ) { CConNode* conNode = (CConNode*) pNode; if ( pItem->mask & RDI_STR ) { pItem->str = conNode->GetDescription(); } if (pItem->mask & RDI_IMAGE) { pItem->nImage = IMAGE_MACHINE; } } return S_OK; } //-------------------------------------------------------------------------- BOOL CComp::OnAddImages( ) { HRESULT hr; HICON hiconMachine = LoadIcon( _Module.GetResourceInstance( ) , MAKEINTRESOURCE( IDI_ICON_MACHINE ) ); HICON hiconConnectedMachine = LoadIcon( _Module.GetResourceInstance( ) , MAKEINTRESOURCE( IDI_ICON_CONNECTED_MACHINE ) ); HICON hiconMachines = LoadIcon( _Module.GetResourceInstance( ) , MAKEINTRESOURCE( IDI_ICON_MACHINES ) ); ASSERT(m_pImageResult); if(!m_pImageResult) { return FALSE; } hr = m_pImageResult->ImageListSetIcon( ( PLONG_PTR )hiconMachine , IMAGE_MACHINE ); if (FAILED(hr)) { return FALSE; } hr = m_pImageResult->ImageListSetIcon( ( PLONG_PTR )hiconConnectedMachine , IMAGE_CONNECTED_MACHINE ); if (FAILED(hr)) { return FALSE; } hr = m_pImageResult->ImageListSetIcon( ( PLONG_PTR )hiconMachines , IMAGE_MACHINES ); if (FAILED(hr)) { return FALSE; } return TRUE; } //---------------------------------------------------------------------- BOOL CComp::OnHelp( LPDATAOBJECT pDo ) { TCHAR tchTopic[ 80 ]; HRESULT hr = E_FAIL; if( pDo == NULL || m_pDisplayHelp == NULL ) { return hr; } if(LoadString(_Module.GetResourceInstance(), IDS_TSCMMCHELPTOPIC, tchTopic, SIZE_OF_BUFFER( tchTopic ))) { hr = m_pDisplayHelp->ShowTopic( tchTopic ); } return ( SUCCEEDED( hr ) ? TRUE : FALSE ); } //-------------------------------------------------------------------------------------------------- STDMETHODIMP CComp::CompareObjects( LPDATAOBJECT , LPDATAOBJECT ) { return E_NOTIMPL; } //-------------------------------------------------------------------------------------------------- HRESULT CComp::InsertItemsinResultPane( ) { return E_NOTIMPL; } //-------------------------------------------------------------------------------------------------- HRESULT CComp::AddSettingsinResultPane( ) { return E_NOTIMPL; } //-------------------------------------------------------------------------------------------------- HRESULT CComp::OnSelect( LPDATAOBJECT pdo , BOOL bScope , BOOL bSelected ) { UNREFERENCED_PARAMETER(bScope); CBaseNode *pNode = static_cast< CBaseNode * >( pdo ); if ( pNode == NULL ) { return S_FALSE; } ASSERT(!IS_SPECIAL_DATAOBJECT(pdo)); if(IS_SPECIAL_DATAOBJECT(pdo)) { return E_FAIL; } if ( m_pConsoleVerb == NULL ) { return E_UNEXPECTED; } // Item is being deselected and we're not interested currently if ( !bSelected ) { return S_OK; } if ( pNode->GetNodeType() == CONNECTION_NODE) { // // Enable the delete verb for connection nodes // HRESULT hr; hr=m_pConsoleVerb->SetVerbState( MMC_VERB_DELETE , ENABLED , TRUE ); if (FAILED(hr)) { return hr; } hr=m_pConsoleVerb->SetVerbState( MMC_VERB_PROPERTIES , ENABLED , TRUE ); if (FAILED(hr)) { return hr; } hr=m_pConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES); if (FAILED(hr)) { return hr; } } return S_OK; } //-------------------------------------------------------------------------------------------------- HRESULT CComp::SetCompdata( CCompdata *pCompdata ) { m_pCompdata = pCompdata; return S_OK; } // // Defered callback to async trigger a connection // This works because the DeferredCallBackProc is called on MMC's main // thread and MMC is APARTMENT threaded so we can make calls on MMC // interfaces form this thread. // // This whole DeferredCallBack thing is a hack to fix #203217. Basically // on autolaunch MMC loads the snapin and then maximizes the window which // means we would connect at the wrong size (if option to match container // size was chosen). This Deferred mechanism ensures MMC has the time // to size the result pane correctly first. // // // // OnShow below sneaks a pointer to deferd connection info in idEvent // VOID CALLBACK DeferredCallBackProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { PTSSNAPIN_DEFER_CONNECT pDeferredConnectInfo = NULL; IMsRdpClient* pTs = NULL; HRESULT hr = E_FAIL; KillTimer( hwnd, idEvent); if(idEvent) { pDeferredConnectInfo = (PTSSNAPIN_DEFER_CONNECT) idEvent; if(pDeferredConnectInfo) { ASSERT(pDeferredConnectInfo->pComponent); ASSERT(pDeferredConnectInfo->pConnectionNode); DBGMSG(L"Triggering deferred connection on connode %p", pDeferredConnectInfo->pConnectionNode); pTs = pDeferredConnectInfo->pConnectionNode->GetTsClient(); if(pTs) { hr = pDeferredConnectInfo->pComponent->ConnectWithNewSettings( pTs, pDeferredConnectInfo->pConnectionNode); } // // Done with the defered connection info, free it // LocalFree( pDeferredConnectInfo ); pDeferredConnectInfo = NULL; } } if(pTs) { pTs->Release(); pTs = NULL; } DBGMSG(L"DeferredConnect status: 0x%x",hr); } //-------------------------------------------------------------------------- // Called when a node is selected. Manages activation of new TS client instances // and once they are 'hot' switching back to a running instance if a node is // reselected. // //-------------------------------------------------------------------------- HRESULT CComp::OnShow( LPDATAOBJECT pDataobject , BOOL bSelect ) { HRESULT hr = S_FALSE; IUnknown* pUnk = NULL; IMstscMhst* pTsMultiHost = NULL; IMsRdpClient* pTS = NULL; PTSSNAPIN_DEFER_CONNECT pDeferredConnectInfo = NULL; HWND hwndMain = NULL; USES_CONVERSION; ODS(L"OnShow\n"); if(!bSelect) { // // Don't need to do any processing for deselect // return S_OK; } // // Only do this for connection nodes // if (((CBaseNode*) pDataobject)->GetNodeType() == MAIN_NODE) { return S_FALSE; } CConNode* pConNode = (CConNode*) pDataobject; ASSERT(pConNode); if (!pConNode) { return S_FALSE; } if ( m_pConsole != NULL ) { hr= m_pConsole->QueryResultView( ( LPUNKNOWN * )&pUnk ); if(FAILED(hr)) { goto FN_EXIT_POINT; } pTsMultiHost = pConNode->GetMultiHostCtl(); if(NULL == pTsMultiHost) { hr = pUnk->QueryInterface( __uuidof(IMstscMhst), (LPVOID*) &pTsMultiHost); if(FAILED(hr)) { goto FN_EXIT_POINT; } pConNode->SetMultiHostCtl( pTsMultiHost); } //We're done with the pUnk to the result view pUnk->Release(); pUnk = NULL; ASSERT(NULL != pTsMultiHost); if(NULL == pTsMultiHost) { hr = E_FAIL; goto FN_EXIT_POINT; } // // If the con node is being selected then connect // or switch to already running instance // // // Connect // ODS(L"Connection node Selected...\n"); pTS = pConNode->GetTsClient(); if(NULL == pTS) { //Create new instance hr = pTsMultiHost->Add( &pTS); if(FAILED(hr)) { goto FN_EXIT_POINT; } pConNode->SetTsClient( pTS); // // Initialize the disconnected message // hr = pTS->put_DisconnectedText(m_wszDisconnectedStatus); if(FAILED(hr)) { goto FN_EXIT_POINT; } } ASSERT(NULL != pTS); if(NULL == pTS) { hr = E_FAIL; goto FN_EXIT_POINT; } hr = pTsMultiHost->put_ActiveClient( pTS); if(FAILED(hr)) { goto FN_EXIT_POINT; } // //If this is the first time through and we are not connected //then connect // if(!pConNode->IsConnected() && !pConNode->IsConnInitialized()) { if(m_bTriggeredFirstAutoConnect) { // // Just connect // hr = ConnectWithNewSettings( pTS, pConNode); if(FAILED(hr)) { goto FN_EXIT_POINT; } } else { // HACK! // Queue a defered connection // to work around MMC's annoying behaviour // of loading the snapin before it sizes itself // which means we connect at the wrong window // size. // m_bTriggeredFirstAutoConnect = TRUE; pDeferredConnectInfo = (PTSSNAPIN_DEFER_CONNECT) LocalAlloc(LPTR, sizeof(TSSNAPIN_DEFER_CONNECT)); if(pDeferredConnectInfo) { pDeferredConnectInfo->pComponent = this; pDeferredConnectInfo->pConnectionNode = pConNode; hwndMain = GetMMCMainWindow(); if(hwndMain) { // // Note the delay is arbitrary the key thing // is that timer messages are low priority so the // MMC size messages should make it through first // // // NOTE: THERE IS NO LEAK HERE // pDeferredConnectInfo is freed in the // DeferredCallBack // SetTimer( hwndMain, (UINT_PTR)(pDeferredConnectInfo), 100, //100ms delay DeferredCallBackProc ); } else { ODS(L"Unable to get MMC main window handle"); hr = E_FAIL; if(pDeferredConnectInfo) { LocalFree(pDeferredConnectInfo); pDeferredConnectInfo = NULL; } goto FN_EXIT_POINT; } } else { ODS(L"Alloc for TSSNAPIN_DEFER_CONNECT failed"); hr = E_OUTOFMEMORY; goto FN_EXIT_POINT; } } } hr = S_OK; } FN_EXIT_POINT: if(pTS) { pTS->Release(); pTS = NULL; } if(pUnk) { pUnk->Release(); pUnk = NULL; } if(pTsMultiHost) { pTsMultiHost->Release(); pTsMultiHost = NULL; } return hr; } // // Get the window handle to MMC's main window // HWND CComp::GetMMCMainWindow() { HRESULT hr = E_FAIL; HWND hwnd = NULL; IConsole2* pConsole2; if(m_pConsole) { hr = m_pConsole->GetMainWindow( &hwnd ); if(SUCCEEDED(hr)) { return hwnd; } else { return NULL; } } else { return NULL; } } HRESULT CComp::ConnectWithNewSettings(IMsRdpClient* pTS, CConNode* pConNode) { HRESULT hr = E_FAIL; IMsRdpClientSecuredSettings *pMstscSecured = NULL; IMsRdpClientAdvancedSettings *pAdvSettings = NULL; IMsTscNonScriptable *ptsns = NULL; IMsRdpClient2* pTsc2 = NULL; ASSERT(NULL != pTS); ASSERT(NULL != pConNode); if(NULL == pTS || !pConNode) { return E_POINTER; } // // Init con settings // if (FAILED(hr = pTS->put_Server( pConNode->GetServerName() ))) { DC_QUIT; } if (FAILED(hr = pTS->QueryInterface(IID_IMsRdpClient2, (void**)&pTsc2))) { // // NOT a fatal error it just means we can't use the newer features // DBGMSG( L"QueryInterface IID_IMsRdpClient2 failed: 0x%x\n", hr ); } // // Setup the connection status string // TCHAR szConnectingStatus[MAX_PATH*2]; _stprintf(szConnectingStatus, m_wszConnectingStatus, pConNode->GetServerName()); if(FAILED(hr = pTS->put_ConnectingText( szConnectingStatus))) { DC_QUIT; } if (FAILED(hr = pTS->put_FullScreenTitle( pConNode->GetServerName()))) { DC_QUIT; } // // Connected status text // if (pTsc2) { TCHAR szConnectedStatus[MAX_PATH*2]; _stprintf(szConnectedStatus, m_wszConnectedStatus, pConNode->GetServerName()); if (FAILED(hr = pTsc2->put_ConnectedStatusText(szConnectedStatus))) { DC_QUIT; } } if (pConNode->GetResType() != SCREEN_RES_FILL_MMC && pConNode->GetDesktopWidth() && pConNode->GetDesktopHeight()) { if (FAILED(hr = pTS->put_DesktopWidth( pConNode->GetDesktopWidth()))) { DC_QUIT; } if (FAILED(hr = pTS->put_DesktopHeight( pConNode->GetDesktopHeight()))) { DC_QUIT; } } else if(pConNode->GetResType() == SCREEN_RES_FILL_MMC) { // // Need to fill the MMC result pane so tell the control // to size itself to the container by giving 0 width/height // if (FAILED(hr = pTS->put_DesktopWidth( 0))) { DC_QUIT; } if (FAILED(hr = pTS->put_DesktopHeight( 0))) { DC_QUIT; } } // // Program/Start directory // if(FAILED(hr = pTS->get_SecuredSettings2( &pMstscSecured))) { DC_QUIT; } if (FAILED(hr = pMstscSecured->put_StartProgram( pConNode->GetProgramPath() ))) { DC_QUIT; } if (FAILED(hr = pMstscSecured->put_WorkDir( pConNode->GetWorkDir() ))) { DC_QUIT; } pMstscSecured->Release(); pMstscSecured = NULL; hr = pTS->get_AdvancedSettings2( &pAdvSettings); if(FAILED(hr)) { DC_QUIT; } if (FAILED(hr = pAdvSettings->put_RedirectDrives( BOOL_TO_VB(pConNode->GetRedirectDrives())))) { DC_QUIT; } if (FAILED(hr = pAdvSettings->put_RedirectPrinters( BOOL_TO_VB(TRUE)))) { DC_QUIT; } if (FAILED(hr = pAdvSettings->put_RedirectPorts( BOOL_TO_VB(TRUE)))) { DC_QUIT; } if (FAILED(hr = pAdvSettings->put_RedirectSmartCards( BOOL_TO_VB(TRUE)))) { DC_QUIT; } // // Container handled fullscreen // hr = pAdvSettings->put_ConnectToServerConsole( BOOL_TO_VB(pConNode->GetConnectToConsole())); if(FAILED(hr)) { DC_QUIT; } // // Don't allow the control to grab focus // the snapin will manage giving focus to a node when it switches // to it. This prevents problems where an obscured session steals // focus from another one. // hr = pAdvSettings->put_GrabFocusOnConnect( FALSE ); if(FAILED(hr)) { DC_QUIT; } if (FAILED(hr = pTS->put_UserName( pConNode->GetUserName()))) { DC_QUIT; } if (FAILED(hr = pTS->put_Domain( pConNode->GetDomain()))) { DC_QUIT; } // // Set the password/salt // if ( pConNode->GetPasswordSpecified()) { TCHAR szPass[CL_MAX_PASSWORD_LENGTH_BYTES/sizeof(TCHAR)]; hr = pConNode->GetClearTextPass(szPass, sizeof(szPass)); if (SUCCEEDED(hr)) { BSTR Pass = SysAllocString(szPass); if (Pass) { hr = pAdvSettings->put_ClearTextPassword(Pass); SecureZeroMemory(Pass, SysStringByteLen(Pass)); SysFreeString(Pass); } } SecureZeroMemory(szPass, sizeof(szPass)); } else { //Password is not specified, make sure logon //properties are reset hr = pTS->QueryInterface(IID_IMsTscNonScriptable, (void**)&ptsns); if(SUCCEEDED(hr)) { if (FAILED(hr = ptsns->ResetPassword())) { DC_QUIT; } ptsns->Release(); ptsns = NULL; } else { DC_QUIT; } } pAdvSettings->Release(); pAdvSettings = NULL; pConNode->SetConnectionInitialized(TRUE); // // Release any existing view and connect // pConNode->SetView(NULL); pConNode->SetView(this); hr = pTS->Connect( ); if (FAILED(hr)) { DC_QUIT; } GiveFocusToControl(pTS); pConNode->SetConnected(TRUE); hr = S_OK; DC_EXIT_POINT: if (pMstscSecured) { pMstscSecured->Release(); pMstscSecured = NULL; } if (pAdvSettings) { pAdvSettings->Release(); pAdvSettings = NULL; } if (ptsns) { ptsns->Release(); ptsns = NULL; } if (pTsc2) { pTsc2->Release(); pTsc2 = NULL; } return hr; } BOOL CComp::GiveFocusToControl(IMsRdpClient* pTs) { IOleInPlaceActiveObject* poipa = NULL; HWND hwnd; HRESULT hr = E_FAIL; if(pTs) { hr = pTs->QueryInterface( IID_IOleInPlaceActiveObject, (void**)&poipa ); if( SUCCEEDED(hr) ) { hr = poipa->GetWindow( &hwnd ); if( SUCCEEDED(hr) ) { DBGMSG(L"Giving focus to control wnd: 0%p", hwnd); SetFocus( hwnd ); } else { ODS(L"poipa->GetWindow failed"); } poipa->Release(); } } return SUCCEEDED(hr); } // // menu items // STDMETHODIMP CComp::AddMenuItems( LPDATAOBJECT pNode, LPCONTEXTMENUCALLBACK pCtxMenu, PLONG plInsertion) { TCHAR tchBuffer1[ 128 ]; TCHAR tchBuffer2[ 128 ]; ATLASSERT( pNode != NULL ); ATLASSERT( pCtxMenu != NULL ); ATLASSERT( plInsertion != NULL ); if (!pNode) { return E_FAIL; } if(IS_SPECIAL_DATAOBJECT(pNode)) { return E_FAIL; } CBaseNode *pBaseNode = dynamic_cast< CBaseNode *>( pNode ); if (!pBaseNode) { return E_FAIL; } if (pBaseNode->GetNodeType() == MAIN_NODE) { // // Check that insertion at the View is allowed // if (!(*plInsertion & CCM_INSERTIONALLOWED_VIEW)) { return S_FALSE; } // // Add menu item to root node // CONTEXTMENUITEM ctxmi; if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_NEW_CONNECTION , tchBuffer1 , SIZE_OF_BUFFER( tchBuffer1 ))) { return E_OUTOFMEMORY; } ctxmi.strName = tchBuffer1; if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_STATUS_NEW_CONNECTION , tchBuffer2 , SIZE_OF_BUFFER( tchBuffer2))) { return E_OUTOFMEMORY; } ctxmi.strStatusBarText = tchBuffer2; ctxmi.lCommandID = IDM_CREATECON; ctxmi.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP ; ctxmi.fFlags = 0; ctxmi.fSpecialFlags = 0; if (FAILED(pCtxMenu->AddItem( &ctxmi ))) { return E_FAIL; } } else if(pBaseNode->GetNodeType() == CONNECTION_NODE) { IComponent* pOwningView = NULL; BOOL fBailOut = FALSE; // // Check that insertion at the view is allowed // if (!(*plInsertion & CCM_INSERTIONALLOWED_VIEW)) { return S_FALSE; } // // Add 'Connect' menu item // CConNode* pConNode = (CConNode*) pBaseNode; ASSERT(pConNode); if(!pConNode) { return E_FAIL; } pOwningView = pConNode->GetView(); // // A connected node 'belongs' to a view so don't allow // commands on other views to affect it // // A null pOwningView means an unowned connection // if (pOwningView && pOwningView != this) { fBailOut = TRUE; } if (pOwningView) { pOwningView->Release(); pOwningView = NULL; } if (fBailOut) { return S_OK; } BOOL bIsTSCliConnected = CCompdata::IsTSClientConnected(pConNode); CONTEXTMENUITEM ctxmi; if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_CONNECT , tchBuffer1 , SIZE_OF_BUFFER( tchBuffer1))) { return E_OUTOFMEMORY; } ctxmi.strName = tchBuffer1; if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_STATUS_CONNECT , tchBuffer2 , SIZE_OF_BUFFER( tchBuffer2))) { return E_OUTOFMEMORY; } ctxmi.strStatusBarText = tchBuffer2; ctxmi.lCommandID = IDM_CONNECT; ctxmi.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP; ctxmi.fFlags = bIsTSCliConnected ? MF_GRAYED: MF_ENABLED; ctxmi.fSpecialFlags = 0; if (FAILED(pCtxMenu->AddItem( &ctxmi ))) { return E_FAIL; } // // Add 'Disconnect' menu item // if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_DISCONNECT , tchBuffer1 , SIZE_OF_BUFFER( tchBuffer1 ) ) ) { return E_OUTOFMEMORY; } ctxmi.strName = tchBuffer1; if(!LoadString( _Module.GetResourceInstance( ) , IDS_CTXM_STATUS_DISCONNECT , tchBuffer2 , SIZE_OF_BUFFER( tchBuffer2 ))) { return E_OUTOFMEMORY; } ctxmi.strStatusBarText = tchBuffer2; ctxmi.lCommandID = IDM_DISCONNECT; ctxmi.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP; ctxmi.fFlags = !bIsTSCliConnected ? MF_GRAYED: MF_ENABLED; ctxmi.fSpecialFlags = 0; if (FAILED(pCtxMenu->AddItem( &ctxmi ))) { return E_FAIL; } } return S_OK; } //---------------------------------------------------------------------------------------------------------- // Menu handler //---------------------------------------------------------------------------------------------------------- STDMETHODIMP CComp::Command( LONG lCommand , LPDATAOBJECT pDo) { // // Add a new connection... // CBaseNode *pNode = dynamic_cast< CBaseNode *>( pDo ); HRESULT hr = S_OK; if (IDM_CREATECON == lCommand) { if ( m_pCompdata) { hr = m_pCompdata->AddNewConnection(); } else { hr = E_FAIL; } return hr; } else if (IDM_CONNECT == lCommand) { // // Connect // if(!pNode) { return E_INVALIDARG; } else if(pNode->GetNodeType() != CONNECTION_NODE) { // // Can't receive a connect request for a node other // than a connection node // ASSERT(pNode->GetNodeType() == CONNECTION_NODE); return E_INVALIDARG; } CConNode* pConNode = (CConNode*) pNode; // // Select the scope node, that will call CComp::OnShow which will connect // ASSERT(m_pConsole); if(!m_pConsole) { return E_FAIL; } IMsRdpClient* pTS = pConNode->GetTsClient(); if(NULL != pTS && pConNode->IsConnInitialized()) { // // Only connect directly if the connection settings are initialized // // // Set view ownership // pConNode->SetView( this ); HRESULT hr = pTS->Connect(); if (FAILED(hr)) { return hr; } pConNode->SetConnected(TRUE); pTS->Release(); } // // Selecting the node if the con settings are not initialized // initializes them and connects // if(FAILED(m_pConsole->SelectScopeItem( pConNode->GetScopeID()))) { return E_FAIL; } hr = S_OK; } else if (IDM_DISCONNECT == lCommand) { if(!pNode) { return E_INVALIDARG; } // // Disconnect // if(pNode->GetNodeType() != CONNECTION_NODE) { // // Can't receive a connect request for a node other // than a connection node // ASSERT(pNode->GetNodeType() == CONNECTION_NODE); return E_INVALIDARG; } CConNode* pConNode = (CConNode*) pNode; ASSERT(m_pConsole); if(!m_pConsole) { return E_FAIL; } IMsRdpClient* pTS = pConNode->GetTsClient(); if(NULL != pTS) { HRESULT hr = pTS->Disconnect(); if (FAILED(hr)) { return hr; } pTS->Release(); } pConNode->SetConnected(FALSE); hr = S_OK; } return hr; }