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.
552 lines
15 KiB
552 lines
15 KiB
//
|
|
// tscapp.cpp
|
|
//
|
|
// Implementation of CTscApp
|
|
// Ts Client Shell app logic
|
|
//
|
|
// Copyright(C) Microsoft Corporation 2000
|
|
// Author: Nadim Abdo (nadima)
|
|
//
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#define TRC_GROUP TRC_GROUP_UI
|
|
#define TRC_FILE "tscapp.cpp"
|
|
#include <atrcapi.h>
|
|
|
|
#include "tscapp.h"
|
|
#include "tscsetting.h"
|
|
#include "rdpfstore.h"
|
|
#include "rmigrate.h"
|
|
#include "sh.h"
|
|
|
|
CTscApp::CTscApp()
|
|
{
|
|
DC_BEGIN_FN("CTscApp");
|
|
_pWnd = NULL;
|
|
_pShellUtil = NULL;
|
|
_pTscSet = NULL;
|
|
_fAutoSaveSettings = FALSE;
|
|
DC_END_FN();
|
|
}
|
|
|
|
CTscApp::~CTscApp()
|
|
{
|
|
DC_BEGIN_FN("~CTscApp");
|
|
|
|
delete _pWnd;
|
|
delete _pShellUtil;
|
|
delete _pTscSet;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// StartShell called to startup the app
|
|
//
|
|
//
|
|
BOOL CTscApp::StartShell(HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPTSTR lpszCmdLine)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
DC_BEGIN_FN("StartShell");
|
|
|
|
_hInst = hInstance;
|
|
TRC_ASSERT(!_pWnd,
|
|
(TB,_T("Calling StartShell while container wnd is up")));
|
|
|
|
//
|
|
// Create the container window
|
|
//
|
|
_pShellUtil = new CSH();
|
|
if(_pShellUtil)
|
|
{
|
|
if(!_pShellUtil->SH_Init( hInstance))
|
|
{
|
|
TRC_ERR((TB,_T("SH_Init failed")));
|
|
return FALSE;
|
|
}
|
|
|
|
dwErr = _pShellUtil->SH_ParseCmdParam( lpszCmdLine);
|
|
|
|
if (SH_PARSECMD_OK != dwErr) {
|
|
TRC_ERR((TB,_T("SH_ParseCmdParam failed on: %s code: 0x%x"),lpszCmdLine, dwErr));
|
|
|
|
//
|
|
// Invalid connection file specified
|
|
//
|
|
if (SH_PARSECMD_ERR_INVALID_CONNECTION_PARAM == dwErr) {
|
|
|
|
_pShellUtil->SH_DisplayErrorBox(NULL,
|
|
UI_IDS_ERR_INVALID_CONNECTION_FILE,
|
|
_pShellUtil->GetRegSession()
|
|
);
|
|
}
|
|
|
|
//
|
|
// Parse failure is fatal
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
if(_pShellUtil->SH_GetCmdMigrate())
|
|
{
|
|
//Only do a migrate and then quit
|
|
CTscRegMigrate mig;
|
|
TCHAR szPath[MAX_PATH];
|
|
if(_pShellUtil->SH_GetRemoteDesktopFolderPath(szPath,
|
|
SIZECHAR(szPath)))
|
|
{
|
|
if(!mig.MigrateAll(szPath))
|
|
{
|
|
TRC_ERR((TB,_T("MigrateAll failed to dir:%s"),szPath));
|
|
}
|
|
//Want to quit the app
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("SH_GetRemoteDesktopFolderPath failed")));
|
|
return FALSE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(!InitSettings(hInstance))
|
|
{
|
|
TRC_ERR((TB,_T("InitSettings returned FALSE")));
|
|
return FALSE;
|
|
}
|
|
|
|
_pWnd = new CContainerWnd();
|
|
if(_pWnd)
|
|
{
|
|
if (_pWnd->Init( hInstance, _pTscSet, _pShellUtil))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Error: pWnd->Init returned FALSE. Exiting\n")));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Could not new CContainerWnd")));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Could not new CSH")));
|
|
return FALSE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
HWND CTscApp::GetTscDialogHandle()
|
|
{
|
|
DC_BEGIN_FN("GetTscDialogHandle");
|
|
HWND hwndDlg = NULL;
|
|
if(_pWnd)
|
|
{
|
|
hwndDlg = _pWnd->GetConnectDialogHandle();
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hwndDlg;
|
|
}
|
|
|
|
|
|
//
|
|
// Setup the settings structures
|
|
// Based on command line options
|
|
//
|
|
// This involves figuring out where to load settings from
|
|
// and then doing it. E.g
|
|
// Load from file
|
|
// Load from registry
|
|
// Load from internal defaults
|
|
//
|
|
BOOL CTscApp::InitSettings(HINSTANCE hInstance)
|
|
{
|
|
CRdpFileStore rdpf;
|
|
LPTSTR szFileName = NULL;
|
|
TCHAR szDefaultFile[MAX_PATH];
|
|
BOOL fLoadedSettings = FALSE;
|
|
|
|
DC_BEGIN_FN("InitSettings");
|
|
|
|
_pTscSet = new CTscSettings();
|
|
if(!_pTscSet)
|
|
{
|
|
TRC_ERR((TB,_T("Could not new CTscSettings")));
|
|
return FALSE;
|
|
}
|
|
|
|
if(_pShellUtil->SH_GetCmdFileForEdit() ||
|
|
_pShellUtil->SH_GetCmdFileForConnect())
|
|
{
|
|
szFileName = _pShellUtil->SH_GetCmdLnFileName();
|
|
if(!_pShellUtil->SH_FileExists(szFileName))
|
|
{
|
|
TCHAR errFileNotFound[MAX_PATH];
|
|
TCHAR szAppName[MAX_PATH];
|
|
|
|
if(LoadString(hInstance,
|
|
UI_IDS_APP_NAME,
|
|
szAppName,
|
|
SIZECHAR(szAppName)))
|
|
{
|
|
if (LoadString(hInstance,
|
|
UI_IDS_ERR_FILEDOESNOTEXIST,
|
|
errFileNotFound,
|
|
SIZECHAR(errFileNotFound)) != 0)
|
|
{
|
|
TCHAR errFormatedFileNotFound[MAX_PATH*3];
|
|
_stprintf(errFormatedFileNotFound, errFileNotFound,
|
|
szFileName);
|
|
MessageBox(NULL, errFormatedFileNotFound, szAppName,
|
|
MB_ICONERROR | MB_OK);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if(_pShellUtil->GetRegSessionSpecified())
|
|
{
|
|
// Automigrate the specified registry
|
|
// session directly to an in-memory settings store
|
|
_fAutoSaveSettings = FALSE;
|
|
rdpf.SetToNullStore();
|
|
|
|
CTscRegMigrate mig;
|
|
TRC_NRM((TB,_T("Automigrating session %s"),
|
|
_pShellUtil->GetRegSession()));
|
|
if(mig.MigrateSession( _pShellUtil->GetRegSession(),
|
|
&rdpf))
|
|
{
|
|
TRC_NRM((TB,_T("Success automigrating reg setting")));
|
|
|
|
HRESULT hr = _pTscSet->LoadFromStore(&rdpf);
|
|
if(FAILED(hr))
|
|
{
|
|
_pShellUtil->SH_DisplayErrorBox(NULL,
|
|
UI_IDS_ERR_INITDEFAULT,
|
|
szFileName);
|
|
return FALSE;
|
|
}
|
|
|
|
_pShellUtil->SetAutoConnect( TRUE );
|
|
fLoadedSettings = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//Something bad happened
|
|
//could not automigrate..indicate failure
|
|
//and use NULL store
|
|
fLoadedSettings = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//No files specified or registry sessions specified
|
|
//Try to use the default.rdp file (create if necessary)
|
|
if(!_pShellUtil->SH_GetPathToDefaultFile(
|
|
szDefaultFile,
|
|
SIZECHAR(szDefaultFile)))
|
|
{
|
|
|
|
TRC_ERR((TB,_T("SH_GetPathToDefaultFile failed")));
|
|
//
|
|
// Display error message to user
|
|
//
|
|
_pShellUtil->SH_DisplayErrorBox(NULL,
|
|
UI_IDS_ERR_GETPATH_TO_DEFAULT_FILE);
|
|
return FALSE;
|
|
}
|
|
|
|
szFileName = szDefaultFile;
|
|
if(!_pShellUtil->SH_FileExists(szFileName))
|
|
{
|
|
//
|
|
// File doesn't exist so create the Remote Desktops
|
|
// directory to ensure the file can be created
|
|
//
|
|
if(!CreateRDdir())
|
|
{
|
|
TRC_ERR((TB,_T("Couldn't create RD dir. Not using %s"),
|
|
szFileName));
|
|
szFileName = NULL;
|
|
}
|
|
|
|
//
|
|
// Now create a hidden default file
|
|
//
|
|
if (szFileName)
|
|
{
|
|
if (!CSH::SH_CreateHiddenFile(szFileName))
|
|
{
|
|
TRC_ERR((TB,_T("Unable to create and hide file %s"),
|
|
szFileName));
|
|
szFileName = NULL;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Auto Save on exit if we're using the default
|
|
// connection file (Default.rdp)
|
|
//
|
|
_fAutoSaveSettings = szFileName ? TRUE : FALSE;
|
|
}
|
|
|
|
if(szFileName)
|
|
{
|
|
//
|
|
//We're loading the settings from a file
|
|
//this is the common case.
|
|
//
|
|
if(rdpf.OpenStore(szFileName))
|
|
{
|
|
HRESULT hr = _pTscSet->LoadFromStore(&rdpf);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
fLoadedSettings = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("LoadFromStore failed")));
|
|
_pShellUtil->SH_DisplayErrorBox(NULL,
|
|
UI_IDS_ERR_LOAD,
|
|
szFileName);
|
|
// We can load NULL file even if you can't load the file
|
|
}
|
|
rdpf.CloseStore();
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("OpenStore (%s) failed"),szFileName));
|
|
_pShellUtil->SH_DisplayErrorBox(NULL,UI_IDS_ERR_OPEN_FILE,
|
|
szFileName);
|
|
|
|
// We can load NULL file even if you can't open the file
|
|
}
|
|
}
|
|
|
|
if(!fLoadedSettings)
|
|
{
|
|
TRC_ERR((TB,_T("Couldn't load settings, using NULL STORE")));
|
|
//Some bad thing happened and we can't get a file to load
|
|
//from (not even the default file). So load from an empty
|
|
//store, this will initialize everything to defaults
|
|
if(rdpf.SetToNullStore())
|
|
{
|
|
HRESULT hr = _pTscSet->LoadFromStore(&rdpf);
|
|
if(FAILED(hr))
|
|
{
|
|
_pShellUtil->SH_DisplayErrorBox(NULL,
|
|
UI_IDS_ERR_INITDEFAULT,
|
|
szFileName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("SetToNullStore Failed")));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//Keep track of the filename
|
|
if(szFileName)
|
|
{
|
|
_pTscSet->SetFileName(szFileName);
|
|
}
|
|
|
|
//
|
|
// Override loaded settings with cmd line settings
|
|
//
|
|
_pShellUtil->SH_ApplyCmdLineSettings(_pTscSet, NULL);
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CTscApp::EndShell()
|
|
{
|
|
DC_BEGIN_FN("EndShell");
|
|
BOOL fRet = FALSE;
|
|
if(!_pTscSet || !_pShellUtil)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
_pShellUtil->SH_Cleanup();
|
|
#endif
|
|
|
|
//
|
|
// Only autosave if
|
|
// the last connection was successful
|
|
//
|
|
if(_fAutoSaveSettings &&
|
|
_pWnd &&
|
|
_pWnd->GetConnectionSuccessFlag())
|
|
{
|
|
//
|
|
// AutoSave the tscsettings
|
|
// (only if the current file is still Default.rdp)
|
|
//
|
|
TCHAR szDefaultFile[MAX_PATH];
|
|
if(!_pShellUtil->SH_GetPathToDefaultFile(
|
|
szDefaultFile,
|
|
SIZECHAR(szDefaultFile)))
|
|
{
|
|
TRC_ERR((TB,_T("SH_GetPathToDefaultFile failed")));
|
|
return FALSE;
|
|
}
|
|
if(!_tcscmp(szDefaultFile, _pTscSet->GetFileName()))
|
|
{
|
|
|
|
CRdpFileStore rdpf;
|
|
if(rdpf.OpenStore(szDefaultFile))
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
hr = _pTscSet->SaveToStore(&rdpf);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
if(rdpf.CommitStore())
|
|
{
|
|
//Save last filename
|
|
_pTscSet->SetFileName(szDefaultFile);
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Unable to CommitStore settings")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Unable to save settings to store %d, %s"),
|
|
hr, szDefaultFile));
|
|
}
|
|
|
|
rdpf.CloseStore();
|
|
if(!fRet)
|
|
{
|
|
_pShellUtil->SH_DisplayErrorBox(NULL,
|
|
UI_IDS_ERR_SAVE,
|
|
szDefaultFile);
|
|
|
|
}
|
|
return fRet;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Unable to OpenStore for save %s"), szDefaultFile));
|
|
_pShellUtil->SH_DisplayErrorBox(NULL,UI_IDS_ERR_OPEN_FILE,
|
|
szDefaultFile);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
//Not a failure, but nothing to do
|
|
TRC_NRM((TB,_T("Current file is no longer default, don't autosave")));
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Creates the Remote Desktops dir (if needed)
|
|
// pops UI on failure
|
|
//
|
|
// Returns:
|
|
// TRUE on success
|
|
//
|
|
//
|
|
BOOL CTscApp::CreateRDdir()
|
|
{
|
|
DC_BEGIN_FN("CreateRDdir");
|
|
|
|
//
|
|
// Make sure the directory exists so that the file
|
|
// can be created by the OpenStore
|
|
//
|
|
TCHAR szDir[MAX_PATH];
|
|
if(_pShellUtil->SH_GetRemoteDesktopFolderPath(szDir,
|
|
SIZECHAR(szDir)))
|
|
{
|
|
if(_pShellUtil->SH_CreateDirectory(szDir))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("SH_CreateDirectory failed %s:%d"),
|
|
szDir, GetLastError()));
|
|
//
|
|
// Display error message to user
|
|
//
|
|
#ifndef OS_WINCE
|
|
TCHAR szMyDocsFolderName[MAX_PATH];
|
|
if(_pShellUtil->SH_GetMyDocumentsDisplayName(
|
|
szMyDocsFolderName,
|
|
SIZECHAR(szMyDocsFolderName)))
|
|
{
|
|
TCHAR errCantCreateRDFolder[MAX_PATH];
|
|
TCHAR szAppName[MAX_PATH];
|
|
|
|
if(LoadString(_hInst,
|
|
UI_IDS_APP_NAME,
|
|
szAppName,
|
|
SIZECHAR(szAppName)))
|
|
{
|
|
if (LoadString(_hInst,
|
|
UI_IDS_ERR_CREATE_REMDESKS_FOLDER,
|
|
errCantCreateRDFolder,
|
|
SIZECHAR(errCantCreateRDFolder)))
|
|
{
|
|
TCHAR errFmtCantCreateRDFolder[MAX_PATH*3];
|
|
_stprintf(errFmtCantCreateRDFolder,
|
|
errCantCreateRDFolder,
|
|
szMyDocsFolderName,
|
|
szDir);
|
|
MessageBox(NULL, errFmtCantCreateRDFolder,
|
|
szAppName,
|
|
MB_ICONERROR | MB_OK);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// This is an error but we'll handle it anyway
|
|
// by loading defaults from a null store
|
|
//
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Guess we can't load from a file after all
|
|
return FALSE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|