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.
2133 lines
56 KiB
2133 lines
56 KiB
//
|
|
// shapi.cpp: client shell util functions
|
|
//
|
|
// Copyright(C) Microsoft Corporation 1999-2000
|
|
// Author: Nadim Abdo (nadima)
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
|
|
#define TRC_GROUP TRC_GROUP_UI
|
|
#define TRC_FILE "shapi.cpp"
|
|
#include <atrcapi.h>
|
|
|
|
#include "sh.h"
|
|
#include "aboutdlg.h"
|
|
|
|
#include "commctrl.h"
|
|
#include "autocmpl.h"
|
|
|
|
#include "shlobj.h"
|
|
#include "browsedlg.h"
|
|
#include "commdlg.h"
|
|
|
|
#define DEFAULT_RDP_FILE TEXT("Default.rdp")
|
|
#define CHANNEL_SUBKEY_NAME TEXT("Addins")
|
|
#define CHANNEL_NAME_KEY TEXT("Name")
|
|
//
|
|
// It is necessary to define multimon.h here so that
|
|
// the multimon functions in this file go through the
|
|
// multimon stubs (COMPILE_MULTIMON_STUBS) is defined
|
|
// in contwnd.cpp
|
|
//
|
|
#ifdef OS_WINNT
|
|
#include "multimon.h"
|
|
#endif
|
|
|
|
TCHAR CSH::_szBrowseForMore[SH_DISPLAY_STRING_MAX_LENGTH];
|
|
|
|
CSH::CSH() : _Ut()
|
|
{
|
|
DC_MEMSET(&_SH, 0, sizeof(_SH));
|
|
_tcscpy(_szFileName, TEXT(""));
|
|
_tcscpy(_szAppName, TEXT(""));
|
|
_hAppIcon = NULL;
|
|
_fFileForConnect = FALSE;
|
|
_fFileForEdit = FALSE;
|
|
_fMigrateOnly = FALSE;
|
|
_hInstance = NULL;
|
|
_fConnectToConsole = FALSE;
|
|
_fRegSessionSpecified = FALSE;
|
|
_hModHHCTRL = NULL;
|
|
_pFnHtmlHelp = NULL;
|
|
_hUxTheme = NULL;
|
|
_pFnEnableThemeDialogTexture = NULL;
|
|
_fFailedToGetThemeDll = FALSE;
|
|
}
|
|
|
|
CSH::~CSH()
|
|
{
|
|
DC_BEGIN_FN("~CSH");
|
|
|
|
TRC_ASSERT(_hModHHCTRL == NULL,
|
|
(TB, _T("HtmlHelp was not cleaned up on exit")));
|
|
|
|
TRC_ASSERT(_hUxTheme == NULL,
|
|
(TB, _T("uxtheme was not cleaned up on exit")));
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Init shell utilities
|
|
//
|
|
DCBOOL CSH::SH_Init(HINSTANCE hInstance)
|
|
{
|
|
DC_BEGIN_FN("SH_Init");
|
|
DC_TSTRCPY(_SH.regSession, _T(""));
|
|
_SH.fRegDefault = TRUE;
|
|
|
|
_SH.connectedStringID = UI_IDS_FRAME_TITLE_CONNECTED_DEFAULT;
|
|
_SH.disconnectedStringID = UI_IDS_APP_NAME;
|
|
_hInstance = hInstance;
|
|
|
|
|
|
//
|
|
// Load Frequently used resource strings
|
|
//
|
|
if (!LoadString( hInstance,
|
|
UI_IDS_BROWSE_FOR_COMPUTERS,
|
|
_szBrowseForMore,
|
|
SH_DISPLAY_STRING_MAX_LENGTH))
|
|
{
|
|
TRC_ERR((TB, _T("Failed to load UI_IDS_BROWSE_FOR_COMPUTERS")));
|
|
return FALSE;
|
|
}
|
|
|
|
if(!LoadString(hInstance,
|
|
UI_IDS_APP_NAME,
|
|
_szAppName,
|
|
SIZECHAR(_szAppName)))
|
|
{
|
|
TRC_ERR((TB,_T("LoadString UI_IDS_APP_NAME failed")));
|
|
}
|
|
|
|
|
|
if (LoadString( hInstance,
|
|
_SH.disconnectedStringID,
|
|
_frameTitleStr,
|
|
SH_FRAME_TITLE_RESOURCE_MAX_LENGTH ) != 0)
|
|
{
|
|
//
|
|
// Successfully loaded the string. Now include the registry
|
|
// session name.
|
|
//
|
|
TRC_DBG((TB, _T("UI frame title loaded OK.")));
|
|
if (_SH.fRegDefault)
|
|
{
|
|
TRC_DBG((TB, _T("Default session")));
|
|
DC_TSPRINTF(_fullFrameTitleStr, _frameTitleStr);
|
|
}
|
|
else
|
|
{
|
|
TRC_DBG((TB, _T("Named session")));
|
|
DC_TSPRINTF(_fullFrameTitleStr, _frameTitleStr, _SH.regSession);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Failed to find UI frame title")));
|
|
_fullFrameTitleStr[0] = (DCTCHAR) 0;
|
|
}
|
|
|
|
_hAppIcon = NULL;
|
|
#if defined(OS_WIN32) && !defined(OS_WINCE)
|
|
_Ut.UT_ReadRegistryString(_SH.regSession,
|
|
SH_ICON_FILE,
|
|
_T(""),
|
|
_SH.szIconFile,
|
|
MAX_PATH);
|
|
|
|
_SH.iconIndex = _Ut.UT_ReadRegistryInt(_SH.regSession,
|
|
SH_ICON_INDEX,
|
|
0);
|
|
|
|
_hAppIcon = ::ExtractIcon(hInstance, _SH.szIconFile, _SH.iconIndex);
|
|
|
|
if(NULL == _hAppIcon)
|
|
{
|
|
_hAppIcon = LoadIcon(hInstance, MAKEINTRESOURCE(UI_IDI_ICON));
|
|
}
|
|
#else
|
|
_hAppIcon = LoadIcon(hInstance, MAKEINTRESOURCE(UI_IDI_ICON));
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SH_ParseCmdParam
|
|
/*
|
|
/* Purpose: Parses the supplied cmdline
|
|
/*
|
|
/* Params: IN - lpszCmdParam - cmd line to parse
|
|
/*
|
|
/* Returns: Parsing status code
|
|
/*
|
|
/* SH_PARSECMD_OK - parsed successfully
|
|
/* SH_PARSECMD_ERR_INVALID_CMD_LINE - generic parse error
|
|
/* SH_PARSECMD_ERR_INVALID_CONNECTION_PARAM - invalid connect param
|
|
/*
|
|
/****************************************************************************/
|
|
DWORD CSH::SH_ParseCmdParam(LPTSTR lpszCmdParam)
|
|
{
|
|
DWORD dwRet = SH_PARSECMD_ERR_INVALID_CMD_LINE;
|
|
DC_BEGIN_FN("SHParseCmdParam");
|
|
|
|
DC_TSTRCPY(_SH.regSession, SH_DEFAULT_REG_SESSION);
|
|
if(!lpszCmdParam)
|
|
{
|
|
dwRet = SH_PARSECMD_ERR_INVALID_CMD_LINE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
while (*lpszCmdParam)
|
|
{
|
|
while (*lpszCmdParam == _T(' '))
|
|
lpszCmdParam++;
|
|
|
|
switch (*lpszCmdParam)
|
|
{
|
|
case _T('\0'):
|
|
break;
|
|
|
|
case _T('-'):
|
|
case _T('/'):
|
|
lpszCmdParam = SHGetSwitch(++lpszCmdParam);
|
|
if(!lpszCmdParam) {
|
|
dwRet = SH_PARSECMD_ERR_INVALID_CMD_LINE;
|
|
DC_QUIT;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
lpszCmdParam = SHGetSession(lpszCmdParam);
|
|
break;
|
|
}
|
|
}
|
|
|
|
SHValidateParsedCmdParam();
|
|
|
|
//
|
|
// Figure out if the connection param specified is a file
|
|
// or a reg key
|
|
//
|
|
if (ParseFileOrRegConnectionParam()) {
|
|
dwRet = SH_PARSECMD_OK;
|
|
}
|
|
else {
|
|
dwRet = SH_PARSECMD_ERR_INVALID_CONNECTION_PARAM;
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
DC_EXIT_POINT:
|
|
return dwRet;
|
|
}
|
|
|
|
DCBOOL CSH::SH_ValidateParams(CTscSettings* pTscSet)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fRet = FALSE;
|
|
DC_BEGIN_FN("SH_ValidateParams");
|
|
|
|
//
|
|
// If the Address is empty, the params are invalid
|
|
//
|
|
if(pTscSet)
|
|
{
|
|
if (CRdpConnectionString::ValidateServerPart(
|
|
pTscSet->GetFlatConnectString())) {
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
return fRet;
|
|
}
|
|
|
|
|
|
DCVOID CSH::SetServer(PDCTCHAR szServer)
|
|
{
|
|
DC_BEGIN_FN("SetServer");
|
|
TRC_ASSERT(szServer, (TB,_T("szServer not set")));
|
|
if(szServer)
|
|
{
|
|
DC_TSTRNCPY( _SH.szServer, szServer, sizeof(_SH.szServer)/sizeof(DCTCHAR));
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
HICON CSH::GetAppIcon()
|
|
{
|
|
DC_BEGIN_FN("GetAppIcon");
|
|
return _hAppIcon;
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Read the control version string/cipher strength and store in _SH
|
|
//
|
|
DCBOOL CSH::SH_ReadControlVer(IMsRdpClient* pTsControl)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
BSTR bsVer;
|
|
LONG cipher;
|
|
|
|
USES_CONVERSION;
|
|
|
|
DC_BEGIN_FN("SH_ReadControlVer");
|
|
|
|
TRC_ASSERT(pTsControl, (TB, _T("Null TS CTL\n")));
|
|
if(!pTsControl)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
TRACE_HR(pTsControl->get_CipherStrength(&cipher));
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
_SH.cipherStrength = (DCINT)cipher;
|
|
TRACE_HR(pTsControl->get_Version(&bsVer));
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
if(bsVer)
|
|
{
|
|
LPTSTR szVer = OLE2T(bsVer);
|
|
_tcsncpy(_SH.szControlVer, szVer, SIZECHAR(_SH.szControlVer));
|
|
SysFreeString(bsVer);
|
|
}
|
|
else
|
|
{
|
|
_tcscpy(_SH.szControlVer, _T(""));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Overide the _SH settings with params read in from
|
|
// the command line
|
|
// this should be called right after GetRegConfig is
|
|
// called
|
|
//
|
|
// hwnd is the window we are being called for (used to figure
|
|
// out which multimon screen we are on.)
|
|
//
|
|
DCVOID CSH::SH_ApplyCmdLineSettings(CTscSettings* pTscSet, HWND hwnd)
|
|
{
|
|
DC_BEGIN_FN("SH_ApplyCmdLineSettings");
|
|
#ifdef OS_WINNT
|
|
HMONITOR hMonitor;
|
|
MONITORINFO monInfo;
|
|
#endif // OS_WINNT
|
|
TRC_ASSERT(pTscSet,(TB,_T("pTscSet is NULL")));
|
|
|
|
PDCTCHAR szCmdLineServer = GetCmdLineServer();
|
|
if(szCmdLineServer[0] != 0)
|
|
{
|
|
pTscSet->SetConnectString(szCmdLineServer);
|
|
|
|
//
|
|
// If a command line server is specified
|
|
// it means autoconnect
|
|
//
|
|
SetAutoConnect(TRUE);
|
|
}
|
|
|
|
if (_SH.fCommandStartFullScreen)
|
|
{
|
|
pTscSet->SetStartFullScreen(TRUE);
|
|
}
|
|
|
|
DCUINT desktopWidth = DEFAULT_DESKTOP_WIDTH;
|
|
DCUINT desktopHeight = DEFAULT_DESKTOP_HEIGHT;
|
|
|
|
if (SH_IsScreenResSpecifiedOnCmdLine())
|
|
{
|
|
//
|
|
// User has specified start size on command line
|
|
//
|
|
desktopWidth = GetCmdLineDesktopWidth();
|
|
desktopHeight= GetCmdLineDesktopHeight();
|
|
|
|
if(GetCmdLineStartFullScreen())
|
|
{
|
|
//
|
|
// StartFullScreen is specified
|
|
//
|
|
if(!desktopWidth || !desktopHeight)
|
|
{
|
|
//
|
|
// set the desktop width/height
|
|
// to the screen size
|
|
//
|
|
#ifdef OS_WINNT
|
|
if (GetSystemMetrics(SM_CMONITORS)) {
|
|
hMonitor = MonitorFromWindow( hwnd,
|
|
MONITOR_DEFAULTTONULL);
|
|
if (hMonitor != NULL) {
|
|
monInfo.cbSize = sizeof(MONITORINFO);
|
|
if (GetMonitorInfo(hMonitor, &monInfo)) {
|
|
desktopWidth = monInfo.rcMonitor.right -
|
|
monInfo.rcMonitor.left;
|
|
desktopHeight = monInfo.rcMonitor.bottom -
|
|
monInfo.rcMonitor.top;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
desktopWidth = GetSystemMetrics(SM_CXSCREEN);
|
|
desktopHeight = GetSystemMetrics(SM_CYSCREEN);
|
|
#endif // OS_WINNT
|
|
}
|
|
}
|
|
|
|
if (desktopWidth && desktopHeight)
|
|
{
|
|
pTscSet->SetDesktopWidth(desktopWidth);
|
|
pTscSet->SetDesktopHeight(desktopHeight);
|
|
|
|
if (!_SH.fCommandStartFullScreen)
|
|
{
|
|
//If command line w/h specified and fullscreen
|
|
//not explicitliy stated then disable fullscreen
|
|
pTscSet->SetStartFullScreen(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_fConnectToConsole)
|
|
{
|
|
// Without it we leave it however it was specified in the .rdp file
|
|
pTscSet->SetConnectToConsole(_fConnectToConsole);
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Return true if the screen res was specified
|
|
// on the command line
|
|
//
|
|
DCBOOL CSH::SH_IsScreenResSpecifiedOnCmdLine()
|
|
{
|
|
return (_SH.fCommandStartFullScreen ||
|
|
(_SH.commandLineHeight &&
|
|
_SH.commandLineWidth));
|
|
}
|
|
|
|
DCBOOL CSH::SH_CanonicalizeServerName(PDCTCHAR szServer)
|
|
{
|
|
// Remove leading spaces
|
|
int strLength = DC_TSTRBYTELEN(szServer);
|
|
while (_T(' ') == szServer[0])
|
|
{
|
|
strLength -= sizeof(DCTCHAR);
|
|
memmove(&szServer[0], &szServer[1], strLength);
|
|
}
|
|
|
|
// Remove trailing spaces -- allow for DBCS strings.
|
|
// At this stage, the string cannot consist entirely
|
|
// of spaces. It must have at least one character,
|
|
// followed by zero or more spaces.
|
|
int numChars = _tcslen(szServer);
|
|
while ((numChars != 0) &&
|
|
(_T(' ') == szServer[numChars - 1])
|
|
#ifndef UNICODE
|
|
&& (!IsDBCSLeadByte(szServer[numChars - 2]))
|
|
#endif
|
|
)
|
|
{
|
|
numChars--;
|
|
szServer[numChars] = _T('\0');
|
|
}
|
|
|
|
//check for "\\" before the server address and remove it and
|
|
//store the server address without the "\\" into szServer
|
|
|
|
if((szServer[0] == _T('\\')) && (szServer[1]== _T('\\')))
|
|
{
|
|
strLength = DC_TSTRBYTELEN(szServer) - 2*sizeof(DCTCHAR);
|
|
memmove(&szServer[0], &szServer[2], strLength);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Initializes the combo (hwndSrvCombo) for autocompletion
|
|
// with the MRU server names in the pTscSet collection.
|
|
//
|
|
void CSH::InitServerAutoCmplCombo(CTscSettings* pTscSet, HWND hwndSrvCombo)
|
|
{
|
|
DC_BEGIN_FN("InitServerComboEx");
|
|
|
|
if(pTscSet && hwndSrvCombo)
|
|
{
|
|
SendMessage(hwndSrvCombo,
|
|
CB_LIMITTEXT,
|
|
SH_MAX_ADDRESS_LENGTH-1,
|
|
0);
|
|
|
|
//
|
|
// This call can be used to re-intialize a combo
|
|
// so delete any items first
|
|
//
|
|
#ifndef OS_WINCE
|
|
INT ret = 1;
|
|
while(ret && ret != CB_ERR)
|
|
{
|
|
ret = SendMessage(hwndSrvCombo,
|
|
CBEM_DELETEITEM,
|
|
0,0);
|
|
}
|
|
#else
|
|
SendMessage(hwndSrvCombo, CB_RESETCONTENT, 0, 0);
|
|
#endif
|
|
|
|
for (int i=0; i<=9;++i)
|
|
{
|
|
if( _tcsncmp(pTscSet->GetMRUServer(i),_T(""),
|
|
TSC_MAX_ADDRESS_LENGTH) )
|
|
{
|
|
#ifndef OS_WINCE
|
|
COMBOBOXEXITEM cbItem;
|
|
cbItem.mask = CBEIF_TEXT;
|
|
cbItem.pszText = (PDCTCHAR)pTscSet->GetMRUServer(i);
|
|
cbItem.iItem = -1; //append
|
|
#endif
|
|
if(-1 == SendMessage(hwndSrvCombo,
|
|
#ifdef OS_WINCE
|
|
CB_ADDSTRING,
|
|
0, (LPARAM)(LPCSTR)(PDCTCHAR)pTscSet->GetMRUServer(i)))
|
|
#else
|
|
CBEM_INSERTITEM,
|
|
0,(LPARAM)&cbItem))
|
|
#endif
|
|
{
|
|
TRC_ERR((TB,(_T("Error appending to server dialog box"))));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add browse for more option to server combo
|
|
//
|
|
#ifndef OS_WINCE
|
|
COMBOBOXEXITEM cbItem;
|
|
cbItem.mask = CBEIF_TEXT;
|
|
cbItem.pszText = CSH::_szBrowseForMore;
|
|
cbItem.iItem = -1; //append
|
|
#endif
|
|
if(-1 == SendMessage(hwndSrvCombo,
|
|
#ifdef OS_WINCE
|
|
CB_ADDSTRING,
|
|
0,(LPARAM)CSH::_szBrowseForMore))
|
|
#else
|
|
CBEM_INSERTITEM,
|
|
0,(LPARAM)&cbItem))
|
|
#endif
|
|
{
|
|
TRC_ERR((TB,(_T("Error appending to server dialog box"))));
|
|
}
|
|
|
|
|
|
//
|
|
// Never select the browse for server's item
|
|
//
|
|
int numItems = SendMessage(hwndSrvCombo,
|
|
CB_GETCOUNT,
|
|
0,0);
|
|
|
|
if(numItems != 1)
|
|
{
|
|
SendMessage( hwndSrvCombo, CB_SETCURSEL, (WPARAM)0,0);
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
SendMessage( hwndSrvCombo, CBEM_SETEXTENDEDSTYLE, (WPARAM)0,
|
|
CBES_EX_NOEDITIMAGE );
|
|
//
|
|
// Enable autocomplete
|
|
//
|
|
HWND hwndEdit = (HWND)SendMessage( hwndSrvCombo,
|
|
CBEM_GETEDITCONTROL, 0, 0);
|
|
|
|
CAutoCompl::EnableServerAutoComplete( pTscSet, hwndEdit);
|
|
#endif
|
|
|
|
#ifdef OS_WINCE
|
|
//This is to avoid WinCE quirk(bug??)
|
|
//When the "Browse for more" entry is selected in the combo
|
|
//and the name of the selected server is programmatically set
|
|
//in the edit control with SetWindowText in the CBN_SELCHANGE handler
|
|
//the text is cleared internally because the corresponding entry isnt
|
|
//present in the list box. This is done only if the CBS_HASSTRINGS flag
|
|
//is set. But the CBS_HASSTRINGS is always added when the combo box is
|
|
//created. I am removing the style here so the text isnt cleared by default.
|
|
SetWindowLong(hwndSrvCombo, GWL_STYLE,
|
|
GetWindowLong(hwndSrvCombo, GWL_STYLE) & ~CBS_HASSTRINGS);
|
|
#endif
|
|
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Return the filename that defines connection
|
|
// settings. This may be a temp file that has been
|
|
// automigrated from a reg session.
|
|
//
|
|
LPTSTR CSH::GetCmdLineFileName()
|
|
{
|
|
return _szFileName;
|
|
}
|
|
|
|
|
|
//
|
|
// Return path to default.rdp file
|
|
//
|
|
BOOL CSH::SH_GetPathToDefaultFile(LPTSTR szPath, UINT nLen)
|
|
{
|
|
DC_BEGIN_FN("SH_GetPathToDefaultFile");
|
|
if(nLen >= MAX_PATH)
|
|
{
|
|
if(SH_GetRemoteDesktopFolderPath(szPath, nLen))
|
|
{
|
|
HRESULT hr = StringCchCat(szPath, nLen, DEFAULT_RDP_FILE);
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr));
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Get the path to the remote desktop folder
|
|
// params:
|
|
// szPath - receives path
|
|
// nLen - length of szPath
|
|
// Returns:
|
|
// Success flag
|
|
//
|
|
// Logic:
|
|
// 1) Try reg key lookup of the path (first EXPAND_SZ and then SZ)
|
|
// 2) Ask shell for location of MyDocuments and slap on suffix path
|
|
// 3) If all else fails try current directory as root + suffix path
|
|
//
|
|
//
|
|
BOOL CSH::SH_GetRemoteDesktopFolderPath(LPTSTR szPath, UINT nLen)
|
|
{
|
|
DC_BEGIN_FN("SH_GetRemoteDesktopFolderPath");
|
|
HRESULT hr;
|
|
BOOL fGotPathToMyDocs = FALSE;
|
|
INT cch;
|
|
if(nLen >= MAX_PATH)
|
|
{
|
|
//
|
|
// First see if there is a path specified in the registry
|
|
//
|
|
LPTSTR szRegPath = NULL;
|
|
INT len = (INT)nLen;
|
|
_Ut.UT_ReadRegistryExpandSZ(SH_DEFAULT_REG_SESSION,
|
|
REMOTEDESKTOPFOLDER_REGKEY,
|
|
&szRegPath,
|
|
&len);
|
|
if(szRegPath)
|
|
{
|
|
int cchLen = 0;
|
|
// User provided a reg key to override default
|
|
// path so use that
|
|
hr = StringCchCopy(szPath, nLen - 2, szRegPath);
|
|
|
|
//Free returned buffer
|
|
LocalFree( szRegPath );
|
|
|
|
// Check if the string copy was successful.
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
|
|
return FALSE;
|
|
}
|
|
|
|
cchLen = _tcslen(szPath);
|
|
if(szPath[cchLen-1] != _T('\\'))
|
|
{
|
|
hr = StringCchCat(szPath, nLen, _T("\\"));
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
|
|
return FALSE;
|
|
}
|
|
}
|
|
TRC_NRM((TB,_T("Using path from registry %s"),
|
|
szPath));
|
|
return TRUE;
|
|
}
|
|
|
|
//Next try non expando key
|
|
_Ut.UT_ReadRegistryString(SH_DEFAULT_REG_SESSION,
|
|
REMOTEDESKTOPFOLDER_REGKEY,
|
|
_T(""),
|
|
szPath,
|
|
nLen-2);
|
|
if(szPath[0] != 0)
|
|
{
|
|
int cchLen = 0;
|
|
cchLen = _tcslen(szPath);
|
|
if(szPath[cchLen-1] != _T('\\'))
|
|
{
|
|
hr = StringCchCat(szPath, nLen, _T("\\"));
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
|
|
return FALSE;
|
|
}
|
|
}
|
|
TRC_NRM((TB,_T("Using path from registry %s"),
|
|
szPath));
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Not in registry, fallback on shell
|
|
//
|
|
|
|
#ifndef OS_WINCE
|
|
//
|
|
// It would be cool to use the nice and simple
|
|
// SHGetFolderPath api but that doesn't work with
|
|
// all versions of shell32.dll (i.e if you don't have the
|
|
// IE desktop update you don't get SHGetFolderPath).
|
|
//
|
|
// blah.
|
|
//
|
|
//
|
|
LPITEMIDLIST ppidl = NULL;
|
|
|
|
hr = SHGetSpecialFolderLocation(NULL,
|
|
CSIDL_PERSONAL,
|
|
&ppidl);
|
|
if(SUCCEEDED(hr) && ppidl)
|
|
{
|
|
hr = SHGetPathFromIDList(ppidl,
|
|
szPath);
|
|
TRC_ASSERT(SUCCEEDED(hr),
|
|
(TB,_T("SHGetPathFromIDList failed: %d"),hr));
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
fGotPathToMyDocs = TRUE;
|
|
}
|
|
|
|
IMalloc* pMalloc;
|
|
hr = SHGetMalloc(&pMalloc);
|
|
TRC_ASSERT(SUCCEEDED(hr),
|
|
(TB,_T("SHGetMalloc failed: %d"),hr));
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
pMalloc->Free(ppidl);
|
|
pMalloc->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("SHGetSpecialFolderLocation failed 0x%x"),
|
|
hr));
|
|
}
|
|
|
|
if(!fGotPathToMyDocs)
|
|
{
|
|
TRC_ERR((TB,_T("Get path to my docs failed."),
|
|
_T("Root folder in current directory.")));
|
|
#ifndef OS_WINCE
|
|
//Oh well as a last resort, root the folder
|
|
//in the current directory. Necessary because some early
|
|
//versions of win95 didn't have a MyDocuments folder
|
|
if(!GetCurrentDirectory( nLen, szPath))
|
|
{
|
|
TRC_ERR((TB,_T("GetCurrentDirectory failed - 0x%x"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
}
|
|
#else
|
|
TRC_NRM((TB,_T("Using \\Windows directory 0x%x")));
|
|
_stprintf(szPath,_T("\\windows"));
|
|
#endif
|
|
|
|
//
|
|
// Terminate the path
|
|
//
|
|
cch = _tcslen(szPath);
|
|
if (cch >= 1 && szPath[cch-1] != _T('\\'))
|
|
{
|
|
hr = StringCchCat(szPath, nLen, _T("\\"));
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// A worker function to make life easier in SH_GetPluginDllList. This function
|
|
// takes a source string, cats it to a destination string, and then appends
|
|
// a comma.
|
|
//
|
|
|
|
HRESULT StringCchCatComma(LPTSTR pszDest, size_t cchDest, LPCTSTR pszSrc) {
|
|
HRESULT hr;
|
|
|
|
DC_BEGIN_FN("StringCchCatComma");
|
|
|
|
hr = StringCchCat(pszDest, cchDest, pszSrc);
|
|
if (FAILED(hr)) {
|
|
DC_QUIT;
|
|
}
|
|
hr = StringCchCat(pszDest, cchDest, _T(","));
|
|
if (FAILED(hr)) {
|
|
DC_QUIT;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
DC_END_FN();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Creates a plugindlls list by enumerating all plugin dlls
|
|
// in szSession reg entry
|
|
//
|
|
// Note, entries are APPENDED to szPlugins
|
|
//
|
|
BOOL CSH::SH_GetPluginDllList(LPTSTR szSession, LPTSTR szPlugins, size_t cchSzPlugins)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
DC_BEGIN_FN("GetPluginDllList");
|
|
|
|
TCHAR subKey[UT_MAX_SUBKEY];
|
|
TCHAR sectKey[UT_MAX_SUBKEY];
|
|
TCHAR enumKey[UT_MAX_SUBKEY];
|
|
TCHAR DLLName[UT_MAX_WORKINGDIR_LENGTH];
|
|
BOOL rc;
|
|
DWORD i;
|
|
INT enumKeySize;
|
|
CUT ut;
|
|
HRESULT hr;
|
|
|
|
TRC_ASSERT(szSession && szPlugins,
|
|
(TB,_T("Invalid param(s)")));
|
|
|
|
hr = StringCchPrintf(subKey, SIZECHAR(subKey), _T("%s\\%s"),
|
|
szSession, CHANNEL_SUBKEY_NAME);
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB, _T("String printf failed: hr = 0x%x"), hr));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Enumerate the registered DLLs
|
|
//
|
|
for (i = 0; ; i++)
|
|
{
|
|
enumKeySize = UT_MAX_SUBKEY;
|
|
rc = ut.UT_EnumRegistry(subKey, i, enumKey, &enumKeySize);
|
|
|
|
// If a section name is returned, read the DLL name from it
|
|
if (rc)
|
|
{
|
|
TRC_NRM((TB, _T("Section name %s found"), enumKey));
|
|
|
|
hr = StringCchPrintf(sectKey, SIZECHAR(sectKey), _T("%s\\%s"),
|
|
subKey, enumKey);
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB, _T("String printf failed: hr = 0x%x"), hr));
|
|
return FALSE;
|
|
}
|
|
|
|
TRC_NRM((TB, _T("Section to read: %s"), sectKey));
|
|
|
|
//
|
|
// First try to read as an expandable
|
|
// string (i.e REG_EXPAND_SZ)
|
|
//
|
|
LPTSTR szExpandedName = NULL;
|
|
INT expandedNameLen=0;
|
|
if(ut.UT_ReadRegistryExpandSZ(sectKey,
|
|
CHANNEL_NAME_KEY,
|
|
&szExpandedName,
|
|
&expandedNameLen))
|
|
{
|
|
TRC_NRM((TB, _T("Expanded DLL Name read %s"), szExpandedName));
|
|
// If a DLL name is returned, append it to the list
|
|
if (szExpandedName && szExpandedName[0] != 0)
|
|
{
|
|
hr = StringCchCatComma(szPlugins, cchSzPlugins, szExpandedName);
|
|
|
|
//Must free returned buffer
|
|
LocalFree( szExpandedName );
|
|
|
|
// Check if the string concatenation failed.
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr));
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memset(DLLName, 0, sizeof(DLLName));
|
|
ut.UT_ReadRegistryString(sectKey,
|
|
CHANNEL_NAME_KEY,
|
|
TEXT(""),
|
|
DLLName,
|
|
UT_MAX_WORKINGDIR_LENGTH);
|
|
TRC_NRM((TB, _T("DLL Name read %s"), DLLName));
|
|
|
|
// If a DLL name is returned, append it to the list
|
|
if (DLLName[0] != 0)
|
|
{
|
|
//FIXFIX finite size of szPlugins
|
|
hr = StringCchCatComma(szPlugins, cchSzPlugins, DLLName);
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr));
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// No DLL name returned - end of enumeration
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
TRC_NRM((TB, _T("Passing list of plugins to load: %s"), szPlugins));
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Handle the server combo box drop down
|
|
// for browse for more... functionality.
|
|
// this fn is broken out into sh to avoid code duplication
|
|
// because it is used in both the maindlg and propgeneral
|
|
//
|
|
BOOL CSH::HandleServerComboChange(HWND hwndCombo,
|
|
HWND hwndDlg,
|
|
HINSTANCE hInst,
|
|
LPTSTR szPrevText)
|
|
{
|
|
int numItems = SendMessage(hwndCombo,
|
|
CB_GETCOUNT,
|
|
0,0);
|
|
int curSel = SendMessage(hwndCombo,
|
|
CB_GETCURSEL,
|
|
0,0);
|
|
//
|
|
// If last item is selected
|
|
//
|
|
if(curSel == numItems-1)
|
|
{
|
|
INT_PTR nResult = IDCANCEL;
|
|
|
|
SendMessage( hwndCombo, CB_SETCURSEL,
|
|
(WPARAM)-1,0);
|
|
|
|
CBrowseDlg browseDlg( hwndDlg, hInst);
|
|
nResult = browseDlg.DoModal();
|
|
|
|
if (IDOK == nResult)
|
|
{
|
|
SetWindowText( hwndCombo,
|
|
browseDlg.GetServer());
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Revert to initial
|
|
//
|
|
SetWindowText( hwndCombo,
|
|
szPrevText);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Fill in certain settings in pTsc with system
|
|
// defaults.
|
|
//
|
|
// E.g if the username is blank, fill that in
|
|
// with the current username
|
|
//
|
|
BOOL CSH::SH_AutoFillBlankSettings(CTscSettings* pTsc)
|
|
{
|
|
DC_BEGIN_FN("SH_AutoFillBlankSettings");
|
|
TRC_ASSERT(pTsc,(TB,_T("pTsc is null")));
|
|
|
|
#ifndef OS_WINCE
|
|
//
|
|
// TODO: update with UPN user name when
|
|
// server limit of 20 chars is fixed
|
|
//
|
|
if(!_tcscmp(pTsc->GetLogonUserName(), TEXT("")))
|
|
{
|
|
TCHAR szUserName[TSC_MAX_USERNAME_LENGTH];
|
|
DWORD dwLen = SIZECHAR(szUserName);
|
|
if(::GetUserName(szUserName, &dwLen))
|
|
{
|
|
pTsc->SetLogonUserName( szUserName);
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("GetUserName failed: %d"), GetLastError()));
|
|
return FALSE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Return TRUE if szFileName exists
|
|
//
|
|
BOOL CSH::SH_FileExists(LPTSTR szFileName)
|
|
{
|
|
BOOL fExist = FALSE;
|
|
if(szFileName)
|
|
{
|
|
HANDLE hFile = CreateFile(szFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if(hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
fExist = TRUE;
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
return fExist;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return TRUE if the settings reg key exists
|
|
// under HK{CU|LM}\Software\Microsoft\Terminal Server Client\{szKeyName}
|
|
//
|
|
BOOL
|
|
CSH::SH_TSSettingsRegKeyExists(LPTSTR szKeyName)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
HKEY hRootKey;
|
|
LONG rc;
|
|
TCHAR szFullKeyName[MAX_PATH];
|
|
|
|
DC_BEGIN_FN("SH_TSSettingsRegKeyExists");
|
|
|
|
if (_tcslen(szKeyName) + SIZECHAR(TSC_SETTINGS_REG_ROOT) +1 >=
|
|
SIZECHAR(szFullKeyName)) {
|
|
|
|
TRC_ERR((TB,_T("szKeyName invalid length")));
|
|
fRet = FALSE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// String lengths are pre-validated
|
|
//
|
|
_tcscpy(szFullKeyName,TSC_SETTINGS_REG_ROOT);
|
|
_tcscat(szFullKeyName, szKeyName);
|
|
|
|
|
|
//
|
|
// First try HKLM
|
|
//
|
|
|
|
rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
szFullKeyName,
|
|
0,
|
|
KEY_READ,
|
|
&hRootKey);
|
|
if (ERROR_SUCCESS == rc && hRootKey) {
|
|
|
|
//
|
|
// Key exists undler HKLM
|
|
//
|
|
|
|
RegCloseKey(hRootKey);
|
|
fRet = TRUE;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Try HKCU
|
|
//
|
|
rc = RegOpenKeyEx(HKEY_CURRENT_USER,
|
|
szFullKeyName,
|
|
0,
|
|
KEY_READ,
|
|
&hRootKey);
|
|
if (ERROR_SUCCESS == rc && hRootKey) {
|
|
|
|
RegCloseKey(hRootKey);
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
DC_EXIT_POINT:
|
|
return fRet;
|
|
}
|
|
|
|
BOOL CSH::SH_DisplayErrorBox(HWND hwndParent, INT errStringID)
|
|
{
|
|
DC_BEGIN_FN("SH_DisplayErrorBox");
|
|
|
|
return SH_DisplayMsgBox(hwndParent, errStringID,
|
|
MB_ICONERROR | MB_OK);
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
BOOL CSH::SH_DisplayMsgBox(HWND hwndParent, INT errStringID, INT flags)
|
|
{
|
|
DC_BEGIN_FN("SH_DisplayMsgBox");
|
|
|
|
TCHAR szErr[MAX_PATH];
|
|
if (LoadString(_hInstance,
|
|
errStringID,
|
|
szErr,
|
|
SIZECHAR(szErr)) != 0)
|
|
{
|
|
MessageBox(hwndParent, szErr, _szAppName,
|
|
flags);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
BOOL CSH::SH_DisplayErrorBox(HWND hwndParent, INT errStringID, LPTSTR szParam)
|
|
{
|
|
DC_BEGIN_FN("SH_DisplayErrorBox");
|
|
TRC_ASSERT(szParam,(TB,_T("szParam is null")));
|
|
if(!szParam)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
TCHAR szErr[MAX_PATH];
|
|
if (LoadString(_hInstance,
|
|
errStringID,
|
|
szErr,
|
|
SIZECHAR(szErr)) != 0)
|
|
{
|
|
TCHAR szFormatedErr[MAX_PATH*2];
|
|
_stprintf(szFormatedErr, szErr, szParam);
|
|
MessageBox(hwndParent, szFormatedErr, _szAppName,
|
|
MB_ICONERROR | MB_OK);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
BOOL CSH::SH_GetNameFromPath(LPTSTR szPath, LPTSTR szName, UINT nameLen)
|
|
{
|
|
DC_BEGIN_FN("SH_GetNameFromPath");
|
|
#ifndef OS_WINCE
|
|
if(szPath && szName && nameLen)
|
|
{
|
|
short ret = GetFileTitle(szPath,
|
|
szName,
|
|
(WORD)nameLen);
|
|
if(ret != 0)
|
|
{
|
|
TRC_ERR((TB,_T("SH_GetNameFromPath failed: %d"),GetLastError()));
|
|
szName[0] = 0;
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
//Strip out the extension
|
|
int len = _tcslen(szName);
|
|
LPTSTR szEnd = &szName[len-1];
|
|
while(szEnd >= szName)
|
|
{
|
|
if(*szEnd == L'.')
|
|
{
|
|
*szEnd = 0;
|
|
}
|
|
szEnd--;
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
#else
|
|
// no GetFileTitle on CE so just cheat
|
|
_tcsncpy( szName, szPath, nameLen - 1);
|
|
szName[nameLen-1] = 0;
|
|
return TRUE;
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
//
|
|
// Compute and return the disaplay name of the My Documents folder
|
|
//
|
|
BOOL CSH::SH_GetMyDocumentsDisplayName(LPTSTR szName, UINT nLen)
|
|
{
|
|
IShellFolder* pshf = NULL;
|
|
LPITEMIDLIST pidl = NULL;
|
|
LPITEMIDLIST pidlDocFiles = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
ULONG chEaten;
|
|
STRRET strret;
|
|
|
|
DC_BEGIN_FN("SH_GetMyDocumentsDisplayName");
|
|
|
|
TRC_ASSERT((szName && nLen),(TB,_T("NULL param(s)")));
|
|
if(!szName || !nLen)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//On failure null string
|
|
szName[0] = NULL;
|
|
|
|
//
|
|
// First try the powerful shell way
|
|
// which will return the correctly localized
|
|
// name. If this fails (due to shell issues)
|
|
// then fall back on a technique that is guaranteed
|
|
// to work but may in some cases give the physical
|
|
// path instead.
|
|
//
|
|
|
|
hr = SHGetDesktopFolder( &pshf );
|
|
TRC_ASSERT(SUCCEEDED(hr),
|
|
(TB,_T("SHGetDesktopFolder failed")));
|
|
if(FAILED(hr) || !pshf)
|
|
{
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// GUID to MyDocuments folder taken from
|
|
// MSDN "shell basics - managing the filesystem -"
|
|
// "my documents and my pictures folder"
|
|
//
|
|
hr = pshf->ParseDisplayName( NULL, NULL,
|
|
L"::{450d8fba-ad25-11d0-98a8-0800361b1103}",
|
|
&chEaten, &pidlDocFiles, NULL );
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = pshf->GetDisplayNameOf( pidlDocFiles, SHGDN_INFOLDER, &strret );
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
LPTSTR sz;
|
|
hr = XStrRetToStrW(&strret, pidl, &sz);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
_tcsncpy(szName, sz, nLen);
|
|
szName[nLen-1] = NULL;
|
|
CoTaskMemFree(sz);
|
|
pshf->Release();
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("XStrRetToStrW failed :%d"), hr));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("GetDisplayNameOf failed :%d"), hr));
|
|
//Don't quit, fall back and try the other method
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("ParseDisplayName failed :%d"), hr));
|
|
//Don't quit, fall back and try the other method
|
|
}
|
|
|
|
|
|
hr = SHGetSpecialFolderLocation(NULL,
|
|
CSIDL_PERSONAL,
|
|
&pidl);
|
|
if(SUCCEEDED(hr) && pidl)
|
|
{
|
|
hr = pshf->GetDisplayNameOf(pidl,
|
|
SHGDN_INFOLDER,
|
|
&strret);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
LPTSTR sz;
|
|
hr = XStrRetToStrW(&strret, pidl, &sz);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
_tcsncpy(szName, sz, nLen);
|
|
szName[nLen-1] = NULL;
|
|
CoTaskMemFree(sz);
|
|
pshf->Release();
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("XStrRetToStrW failed :%d"), hr));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("GetDisplayNameOf failed :%d"), hr));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("SHGetSpecialFolderLocation failed 0x%x"),
|
|
hr));
|
|
DC_QUIT;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
if(pshf)
|
|
{
|
|
pshf->Release();
|
|
pshf = NULL;
|
|
}
|
|
DC_END_FN();
|
|
TRC_ERR((TB,_T("failed to get display name")));
|
|
return FALSE;
|
|
}
|
|
#endif //OS_WINCE
|
|
|
|
//
|
|
// On demand loads HTML help and displays the client help
|
|
// if the HTMLHELP is not available, pop a message box to
|
|
// the user.
|
|
// SH_Cleanup cleans up HTML help (unloads lib)
|
|
// on exit
|
|
//
|
|
// Return HWND to help window or NULL on failure
|
|
//
|
|
//
|
|
HWND CSH::SH_DisplayClientHelp(HWND hwndOwner, INT helpCommand)
|
|
{
|
|
BOOL fHtmlHelpAvailable = FALSE;
|
|
DC_BEGIN_FN("SH_DisplayClientHelp");
|
|
|
|
#ifndef OS_WINCE
|
|
if(!_hModHHCTRL)
|
|
{
|
|
_hModHHCTRL = (HMODULE)LoadLibrary(_T("hhctrl.ocx"));
|
|
if(_hModHHCTRL)
|
|
{
|
|
//
|
|
// Use ANSI version of HTML Help so it always works
|
|
// on downlevel platforms without uniwrap
|
|
//
|
|
_pFnHtmlHelp = (PFNHtmlHelp)GetProcAddress(_hModHHCTRL,
|
|
"HtmlHelpA");
|
|
if(_pFnHtmlHelp)
|
|
{
|
|
fHtmlHelpAvailable = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("GetProcAddress failed for HtmlHelpA: 0x%x"),
|
|
GetLastError()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("LoadLibrary failed for hhctrl.ocx: 0x%x"),
|
|
GetLastError()));
|
|
}
|
|
}
|
|
else if (_pFnHtmlHelp)
|
|
{
|
|
fHtmlHelpAvailable = TRUE;
|
|
}
|
|
|
|
if(fHtmlHelpAvailable)
|
|
{
|
|
return _pFnHtmlHelp( hwndOwner, MSTSC_HELP_FILE_ANSI,
|
|
helpCommand, 0L);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Display a message to the user that HTML help is
|
|
// not availalbe on their system.
|
|
//
|
|
SH_DisplayErrorBox( hwndOwner, UI_IDS_NOHTMLHELP);
|
|
return NULL;
|
|
}
|
|
|
|
#else
|
|
if ((GetFileAttributes(PEGHELP_EXE) != -1) &&
|
|
(GetFileAttributes(TSC_HELP_FILE) != -1))
|
|
{
|
|
CreateProcess(PEGHELP_EXE, MSTSC_HELP_FILE, 0,0,0,0,0,0,0,0);
|
|
}
|
|
else
|
|
{
|
|
SH_DisplayErrorBox( hwndOwner, UI_IDS_NOHTMLHELP);
|
|
}
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
#ifdef OS_WINCE
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
BOOL CSH::SH_Cleanup()
|
|
{
|
|
DC_BEGIN_FN("SH_Cleanup");
|
|
|
|
if(_hModHHCTRL)
|
|
{
|
|
FreeLibrary(_hModHHCTRL);
|
|
_pFnHtmlHelp = NULL;
|
|
_hModHHCTRL = NULL;
|
|
}
|
|
|
|
if (_hUxTheme)
|
|
{
|
|
FreeLibrary(_hUxTheme);
|
|
_hUxTheme = NULL;
|
|
_pFnEnableThemeDialogTexture = NULL;
|
|
}
|
|
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Enable or disable an array of dlg controls
|
|
//
|
|
VOID CSH::EnableControls(HWND hwndDlg, PUINT pCtls,
|
|
const UINT numCtls, BOOL fEnable)
|
|
{
|
|
DC_BEGIN_FN("EnableControls");
|
|
|
|
for(UINT i=0;i<numCtls;i++)
|
|
{
|
|
EnableWindow( GetDlgItem( hwndDlg, pCtls[i]),
|
|
fEnable);
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Enable or disable an array of dlg controls
|
|
// with memory. E.g previously disabled controls
|
|
// are not re-enabled.
|
|
//
|
|
VOID CSH::EnableControls(HWND hwndDlg, PCTL_ENABLE pCtls,
|
|
const UINT numCtls, BOOL fEnable)
|
|
{
|
|
DC_BEGIN_FN("EnableControls");
|
|
|
|
if(!fEnable)
|
|
{
|
|
//
|
|
// Disable controls and remember which
|
|
// were previously disabled
|
|
//
|
|
for(UINT i=0;i<numCtls;i++)
|
|
{
|
|
pCtls[i].fPrevDisabled =
|
|
EnableWindow( GetDlgItem( hwndDlg, pCtls[i].ctlID),
|
|
FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Enable controls that were not initially disabled
|
|
for(UINT i=0;i<numCtls;i++)
|
|
{
|
|
if(!pCtls[i].fPrevDisabled)
|
|
{
|
|
EnableWindow( GetDlgItem( hwndDlg, pCtls[i].ctlID),
|
|
TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
//
|
|
// Attempt to create a directory by first
|
|
// creating all the subdirs
|
|
//
|
|
// Params - szPath (path to dir to create)
|
|
// Returns - status
|
|
//
|
|
BOOL CSH::SH_CreateDirectory(LPTSTR szPath)
|
|
{
|
|
BOOL rc = TRUE;
|
|
int i = 0;
|
|
DC_BEGIN_FN("SH_CreateDirectory");
|
|
|
|
if(szPath)
|
|
{
|
|
if(szPath[i] == _T('\\') &&
|
|
szPath[i+1] == _T('\\'))
|
|
{
|
|
//Handle UNC path
|
|
|
|
//Walk until the end of the server name
|
|
i+=2;
|
|
while (szPath[i] && szPath[i++] != _T('\\'));
|
|
if(!szPath[i])
|
|
{
|
|
TRC_ERR((TB,_T("Invalid path %s"), szPath));
|
|
return FALSE;
|
|
}
|
|
|
|
//Walk past drive letter if specified
|
|
//e.g \\myserver\a$\foo
|
|
if (szPath[i] &&
|
|
szPath[i+1] == _T('$') &&
|
|
szPath[i+2] == _T('\\'))
|
|
{
|
|
i+=3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Local path
|
|
#ifndef OS_WINCE
|
|
while(szPath[i] && szPath[i++] != _T(':'));
|
|
#endif
|
|
if(szPath[i] && szPath[i] == _T('\\'))
|
|
{
|
|
i++; //Skip the first '\'
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Invalid (or non local) path %s"),
|
|
szPath));
|
|
return FALSE;
|
|
}
|
|
}
|
|
while (rc && szPath[i] != 0)
|
|
{
|
|
if (szPath[i] == _T('\\'))
|
|
{
|
|
szPath[i] = 0;
|
|
|
|
if (!CreateDirectory(szPath, NULL))
|
|
{
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
|
{
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
szPath[i] = _T('\\');
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if(!rc)
|
|
{
|
|
TRC_ERR((TB,_T("SH_CreateDirectory failed")));
|
|
}
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
UINT CSH::SH_GetScreenBpp()
|
|
{
|
|
HDC hdc;
|
|
int screenBpp;
|
|
DC_BEGIN_FN("UI_GetScreenBpp");
|
|
|
|
hdc = GetDC(NULL);
|
|
if(hdc)
|
|
{
|
|
screenBpp = GetDeviceCaps(hdc, BITSPIXEL);
|
|
TRC_NRM((TB, _T("HDC %p has %u bpp"), hdc, screenBpp));
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
|
|
DC_END_FN();
|
|
return screenBpp;
|
|
}
|
|
|
|
//
|
|
// Crypto API is present on WIN2k+
|
|
//
|
|
BOOL CSH::IsCryptoAPIPresent()
|
|
{
|
|
#ifndef OS_WINCE
|
|
OSVERSIONINFO osVersionInfo;
|
|
osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
|
|
|
|
if (GetVersionEx( &osVersionInfo ))
|
|
{
|
|
if (osVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
|
|
osVersionInfo.dwMajorVersion >= 5)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
#else
|
|
//CryptProtectData and CryptUnprotectData are present in all CE configs.
|
|
//(At least everything with filesys or registry) So return TRUE.always.
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// DataProtect
|
|
// Protect data for persistence using data protection API
|
|
// params:
|
|
// pInData - (in) input bytes to protect
|
|
// pOutData - (out) output data caller must free
|
|
// returns: bool status
|
|
//
|
|
|
|
typedef BOOL (WINAPI* PFNCryptProtectData)(
|
|
IN DATA_BLOB* pDataIn,
|
|
IN LPCWSTR szDataDescr,
|
|
IN OPTIONAL DATA_BLOB* pOptionalEntropy,
|
|
IN PVOID pvReserved,
|
|
IN OPTIONAL CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
|
|
IN DWORD dwFlags,
|
|
OUT DATA_BLOB* pDataOut
|
|
);
|
|
|
|
BOOL CSH::DataProtect(PDATA_BLOB pInData, PDATA_BLOB pOutData)
|
|
{
|
|
#ifndef OS_WINCE
|
|
HMODULE hCryptLib = NULL;
|
|
PFNCryptProtectData fnCryptProtectData = NULL;
|
|
#endif
|
|
BOOL bRet = TRUE;
|
|
|
|
DC_BEGIN_FN("DataProtect");
|
|
|
|
TRC_ASSERT( IsCryptoAPIPresent(),
|
|
(TB,_T("Crytpapi not present shouldn't call DataProtect")));
|
|
|
|
if (pInData && pInData->cbData && pInData->pbData &&
|
|
pOutData)
|
|
{
|
|
#ifndef OS_WINCE
|
|
hCryptLib = (HMODULE) LoadLibrary( _T("crypt32.dll") );
|
|
if (hCryptLib)
|
|
{
|
|
fnCryptProtectData = (PFNCryptProtectData)
|
|
GetProcAddress( hCryptLib, "CryptProtectData");
|
|
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("LoadLib for crypt32.dll failed: 0x%x"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
if (fnCryptProtectData)
|
|
{
|
|
if (fnCryptProtectData( pInData,
|
|
#else
|
|
if (CryptProtectData( pInData,
|
|
#endif
|
|
TEXT("psw"), // DESCRIPTION STRING.
|
|
NULL, // optional entropy
|
|
NULL, // reserved
|
|
NULL, // NO prompting
|
|
CRYPTPROTECT_UI_FORBIDDEN, //don't pop UI
|
|
pOutData ))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwLastErr = GetLastError();
|
|
TRC_ERR((TB,_T("CryptProtectData FAILED error:%d\n"),
|
|
dwLastErr));
|
|
bRet = FALSE;
|
|
}
|
|
#ifndef OS_WINCE
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("GetProcAddress for CryptProtectData failed: 0x%x"),
|
|
GetLastError()));
|
|
bRet = FALSE;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Invalid data")));
|
|
return FALSE;
|
|
}
|
|
#ifndef OS_WINCE
|
|
|
|
if (hCryptLib)
|
|
{
|
|
FreeLibrary(hCryptLib);
|
|
}
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
return bRet;
|
|
}
|
|
|
|
//
|
|
// DataUnprotect
|
|
// UnProtect persisted out data using data protection API
|
|
// params:
|
|
// pInData - (in) input bytes to UN protect
|
|
// cbLen - (in) length of pInData in bytes
|
|
// ppOutData - (out) output bytes
|
|
// pcbOutLen - (out) length of output
|
|
// returns: bool status
|
|
//
|
|
//
|
|
|
|
typedef BOOL (WINAPI* PFNCryptUnprotectData)(
|
|
IN DATA_BLOB* pDataIn,
|
|
IN LPCWSTR szDataDescr,
|
|
IN OPTIONAL DATA_BLOB* pOptionalEntropy,
|
|
IN PVOID pvReserved,
|
|
IN OPTIONAL CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
|
|
IN DWORD dwFlags,
|
|
OUT DATA_BLOB* pDataOut
|
|
);
|
|
|
|
BOOL CSH::DataUnprotect(PDATA_BLOB pInData, PDATA_BLOB pOutData)
|
|
{
|
|
#ifndef OS_WINCE
|
|
HMODULE hCryptLib = NULL;
|
|
PFNCryptUnprotectData fnCryptUnprotectData = NULL;
|
|
#endif
|
|
BOOL bRet = TRUE;
|
|
|
|
DC_BEGIN_FN("DataUnprotect");
|
|
|
|
TRC_ASSERT( IsCryptoAPIPresent(),
|
|
(TB,_T("Crytpapi not present shouldn't call DataUnprotect")));
|
|
|
|
if (pInData && pInData->cbData && pInData->pbData &&
|
|
pOutData)
|
|
{
|
|
#ifndef OS_WINCE
|
|
hCryptLib = (HMODULE) LoadLibrary( _T("crypt32.dll") );
|
|
|
|
if (hCryptLib)
|
|
{
|
|
fnCryptUnprotectData = (PFNCryptUnprotectData)
|
|
GetProcAddress( hCryptLib, "CryptUnprotectData");
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("LoadLib for crypt32.dll failed: 0x%x"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
if (fnCryptUnprotectData)
|
|
{
|
|
if (fnCryptUnprotectData( pInData,
|
|
#else
|
|
if (CryptUnprotectData( pInData,
|
|
#endif
|
|
NULL, // no description
|
|
NULL, // optional entropy
|
|
NULL, // reserved
|
|
NULL, // NO prompting
|
|
CRYPTPROTECT_UI_FORBIDDEN, //don't pop UI
|
|
pOutData ))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwLastErr = GetLastError();
|
|
TRC_ERR((TB,_T("fnCryptUnprotectData FAILED error:%d\n"),
|
|
dwLastErr));
|
|
bRet = FALSE;
|
|
}
|
|
#ifndef OS_WINCE
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("GetProcAddress for CryptUnprotectData failed: 0x%x"),
|
|
GetLastError()));
|
|
bRet = FALSE;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB,_T("Invalid data")));
|
|
return FALSE;
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
if (hCryptLib)
|
|
{
|
|
FreeLibrary(hCryptLib);
|
|
}
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
return bRet;
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
BOOL CALLBACK MaxMonitorSizeEnumProc(HMONITOR hMonitor, HDC hdcMonitor,
|
|
RECT* prc, LPARAM lpUserData)
|
|
{
|
|
LPRECT prcLrg = (LPRECT)lpUserData;
|
|
|
|
if ((prc->right - prc->left) >= (prcLrg->right - prcLrg->left) &&
|
|
(prc->bottom - prc->top) >= (prcLrg->bottom - prcLrg->top))
|
|
{
|
|
*prcLrg = *prc;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif
|
|
|
|
BOOL CSH::GetLargestMonitorRect(LPRECT prc)
|
|
{
|
|
DC_BEGIN_FN("GetLargestMonitorRect");
|
|
if (prc)
|
|
{
|
|
// default screen size
|
|
prc->top = 0;
|
|
prc->left = 0;
|
|
prc->bottom = GetSystemMetrics(SM_CYSCREEN);
|
|
prc->right = GetSystemMetrics(SM_CXSCREEN);
|
|
|
|
#ifndef OS_WINCE //No multimon on CE
|
|
if (GetSystemMetrics(SM_CMONITORS))
|
|
{
|
|
//Enumerate and look for a larger monitor
|
|
EnumDisplayMonitors(NULL, NULL, MaxMonitorSizeEnumProc,
|
|
(LPARAM) prc);
|
|
}
|
|
#endif //OS_WINCE
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
BOOL CSH::MonitorRectFromHwnd(HWND hwnd, LPRECT prc)
|
|
{
|
|
#ifndef OS_WINCE
|
|
HMONITOR hMonitor;
|
|
MONITORINFO monInfo;
|
|
#endif
|
|
|
|
DC_BEGIN_FN("MonitorRectFromHwnd")
|
|
|
|
// default screen size
|
|
prc->top = 0;
|
|
prc->left = 0;
|
|
prc->bottom = GetSystemMetrics(SM_CYSCREEN);
|
|
prc->right = GetSystemMetrics(SM_CXSCREEN);
|
|
|
|
#ifndef OS_WINCE
|
|
// for multi monitor, need to find which monitor the client window
|
|
// resides, then get the correct screen size of the corresponding
|
|
// monitor
|
|
|
|
if (GetSystemMetrics(SM_CMONITORS))
|
|
{
|
|
hMonitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTONULL);
|
|
if (hMonitor != NULL)
|
|
{
|
|
monInfo.cbSize = sizeof(MONITORINFO);
|
|
if (GetMonitorInfo(hMonitor, &monInfo))
|
|
{
|
|
*prc = monInfo.rcMonitor;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CSH::MonitorRectFromNearestRect(LPRECT prcNear, LPRECT prcMonitor)
|
|
{
|
|
#ifndef OS_WINCE
|
|
HMONITOR hMonitor;
|
|
MONITORINFO monInfo;
|
|
#endif
|
|
|
|
DC_BEGIN_FN("MonitorRectFromHwnd")
|
|
|
|
// default screen size
|
|
prcMonitor->top = 0;
|
|
prcMonitor->left = 0;
|
|
prcMonitor->bottom = GetSystemMetrics(SM_CYSCREEN);
|
|
prcMonitor->right = GetSystemMetrics(SM_CXSCREEN);
|
|
|
|
// for multi monitor, need to find which monitor the client window
|
|
// resides, then get the correct screen size of the corresponding
|
|
// monitor
|
|
#ifndef OS_WINCE
|
|
if (GetSystemMetrics(SM_CMONITORS))
|
|
{
|
|
hMonitor = MonitorFromRect(prcNear,
|
|
MONITOR_DEFAULTTONEAREST);
|
|
|
|
if (hMonitor != NULL)
|
|
{
|
|
monInfo.cbSize = sizeof(MONITORINFO);
|
|
if (GetMonitorInfo(hMonitor, &monInfo))
|
|
{
|
|
*prcMonitor = monInfo.rcMonitor;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
LPTSTR CSH::FormatMessageVAList(LPCTSTR pcszFormat, va_list *argList)
|
|
|
|
{
|
|
LPTSTR pszOutput;
|
|
|
|
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
|
|
pcszFormat,
|
|
0, 0,
|
|
reinterpret_cast<LPTSTR>(&pszOutput), 0,
|
|
argList) == 0)
|
|
{
|
|
pszOutput = NULL;
|
|
}
|
|
|
|
return(pszOutput);
|
|
}
|
|
|
|
|
|
LPTSTR CSH::FormatMessageVArgs(LPCTSTR pcszFormat, ...)
|
|
|
|
{
|
|
LPTSTR pszOutput;
|
|
va_list argList;
|
|
|
|
va_start(argList, pcszFormat);
|
|
pszOutput = FormatMessageVAList(pcszFormat, &argList);
|
|
va_end(argList);
|
|
return(pszOutput);
|
|
}
|
|
|
|
|
|
//
|
|
// Create a hidden file
|
|
//
|
|
BOOL CSH::SH_CreateHiddenFile(LPCTSTR szPath)
|
|
{
|
|
HANDLE hFile;
|
|
BOOL fRet = FALSE;
|
|
DC_BEGIN_FN("SH_CreateHiddenFile");
|
|
|
|
hFile = CreateFile( szPath,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_ALWAYS, //Creates if !exist
|
|
FILE_ATTRIBUTE_HIDDEN,
|
|
NULL);
|
|
if (INVALID_HANDLE_VALUE != hFile)
|
|
{
|
|
CloseHandle(hFile);
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB, _T("CreateFile failed: %s - err:%x"),
|
|
szPath, GetLastError()));
|
|
fRet = FALSE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return fRet;
|
|
}
|
|
|
|
BOOL CSH::SH_IsRunningOn9x()
|
|
{
|
|
BOOL fRunningOnWin9x = FALSE;
|
|
DC_BEGIN_FN("SH_IsRunningOn9x");
|
|
|
|
fRunningOnWin9x = FALSE;
|
|
OSVERSIONINFO osVersionInfo;
|
|
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
//call A version to avoid wrapping
|
|
if(GetVersionEx(&osVersionInfo))
|
|
{
|
|
fRunningOnWin9x = (osVersionInfo.dwPlatformId ==
|
|
VER_PLATFORM_WIN32_WINDOWS);
|
|
}
|
|
else
|
|
{
|
|
fRunningOnWin9x = FALSE;
|
|
TRC_ERR((TB,_T("GetVersionEx failed: %d\n"), GetLastError()));
|
|
}
|
|
|
|
DC_END_FN();
|
|
return fRunningOnWin9x;
|
|
}
|
|
|
|
//
|
|
// Dynamically load and call the EnableThemeDialogTexture API
|
|
// (since it is not available on all platforms)
|
|
//
|
|
HRESULT CSH::SH_ThemeDialogWindow(HWND hwnd, DWORD dwFlags)
|
|
{
|
|
HRESULT hr = E_NOTIMPL;
|
|
DC_BEGIN_FN("SH_ThemeDialogWindow");
|
|
|
|
if (_fFailedToGetThemeDll)
|
|
{
|
|
//
|
|
// If failed once then bail out to avoid repeatedly
|
|
// trying to load theme dll that isn't there
|
|
//
|
|
DC_QUIT;
|
|
}
|
|
|
|
if (!_hUxTheme)
|
|
{
|
|
_hUxTheme = (HMODULE)LoadLibrary(_T("uxtheme.dll"));
|
|
if(_hUxTheme)
|
|
{
|
|
_pFnEnableThemeDialogTexture = (PFNEnableThemeDialogTexture)
|
|
#ifndef OS_WINCE
|
|
GetProcAddress( _hUxTheme,
|
|
"EnableThemeDialogTexture");
|
|
#else
|
|
GetProcAddress( _hUxTheme,
|
|
_T("EnableThemeDialogTexture"));
|
|
#endif
|
|
if (NULL == _pFnEnableThemeDialogTexture)
|
|
{
|
|
_fFailedToGetThemeDll = TRUE;
|
|
TRC_ERR((TB,
|
|
_T("Failed to GetProcAddress for EnableThemeDialogTexture")));
|
|
}
|
|
else
|
|
{
|
|
TRC_NRM((TB,_T("Got EnableThemeDialogTexture entry point")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_fFailedToGetThemeDll = TRUE;
|
|
TRC_ERR((TB,_T("LoadLibrary failed for uxtheme: 0x%x"),
|
|
GetLastError()));
|
|
}
|
|
}
|
|
|
|
|
|
if (_pFnEnableThemeDialogTexture)
|
|
{
|
|
hr = _pFnEnableThemeDialogTexture(hwnd, dwFlags);
|
|
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB,_T("_pFnEnableThemeDialogTexture ret 0x%x\n"), hr));
|
|
}
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|