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.

2133 lines
56 KiB

  1. //
  2. // shapi.cpp: client shell util functions
  3. //
  4. // Copyright(C) Microsoft Corporation 1999-2000
  5. // Author: Nadim Abdo (nadima)
  6. //
  7. #include "stdafx.h"
  8. #define TRC_GROUP TRC_GROUP_UI
  9. #define TRC_FILE "shapi.cpp"
  10. #include <atrcapi.h>
  11. #include "sh.h"
  12. #include "aboutdlg.h"
  13. #include "commctrl.h"
  14. #include "autocmpl.h"
  15. #include "shlobj.h"
  16. #include "browsedlg.h"
  17. #include "commdlg.h"
  18. #define DEFAULT_RDP_FILE TEXT("Default.rdp")
  19. #define CHANNEL_SUBKEY_NAME TEXT("Addins")
  20. #define CHANNEL_NAME_KEY TEXT("Name")
  21. //
  22. // It is necessary to define multimon.h here so that
  23. // the multimon functions in this file go through the
  24. // multimon stubs (COMPILE_MULTIMON_STUBS) is defined
  25. // in contwnd.cpp
  26. //
  27. #ifdef OS_WINNT
  28. #include "multimon.h"
  29. #endif
  30. TCHAR CSH::_szBrowseForMore[SH_DISPLAY_STRING_MAX_LENGTH];
  31. CSH::CSH() : _Ut()
  32. {
  33. DC_MEMSET(&_SH, 0, sizeof(_SH));
  34. _tcscpy(_szFileName, TEXT(""));
  35. _tcscpy(_szAppName, TEXT(""));
  36. _hAppIcon = NULL;
  37. _fFileForConnect = FALSE;
  38. _fFileForEdit = FALSE;
  39. _fMigrateOnly = FALSE;
  40. _hInstance = NULL;
  41. _fConnectToConsole = FALSE;
  42. _fRegSessionSpecified = FALSE;
  43. _hModHHCTRL = NULL;
  44. _pFnHtmlHelp = NULL;
  45. _hUxTheme = NULL;
  46. _pFnEnableThemeDialogTexture = NULL;
  47. _fFailedToGetThemeDll = FALSE;
  48. }
  49. CSH::~CSH()
  50. {
  51. DC_BEGIN_FN("~CSH");
  52. TRC_ASSERT(_hModHHCTRL == NULL,
  53. (TB, _T("HtmlHelp was not cleaned up on exit")));
  54. TRC_ASSERT(_hUxTheme == NULL,
  55. (TB, _T("uxtheme was not cleaned up on exit")));
  56. DC_END_FN();
  57. }
  58. //
  59. // Init shell utilities
  60. //
  61. DCBOOL CSH::SH_Init(HINSTANCE hInstance)
  62. {
  63. DC_BEGIN_FN("SH_Init");
  64. DC_TSTRCPY(_SH.regSession, _T(""));
  65. _SH.fRegDefault = TRUE;
  66. _SH.connectedStringID = UI_IDS_FRAME_TITLE_CONNECTED_DEFAULT;
  67. _SH.disconnectedStringID = UI_IDS_APP_NAME;
  68. _hInstance = hInstance;
  69. //
  70. // Load Frequently used resource strings
  71. //
  72. if (!LoadString( hInstance,
  73. UI_IDS_BROWSE_FOR_COMPUTERS,
  74. _szBrowseForMore,
  75. SH_DISPLAY_STRING_MAX_LENGTH))
  76. {
  77. TRC_ERR((TB, _T("Failed to load UI_IDS_BROWSE_FOR_COMPUTERS")));
  78. return FALSE;
  79. }
  80. if(!LoadString(hInstance,
  81. UI_IDS_APP_NAME,
  82. _szAppName,
  83. SIZECHAR(_szAppName)))
  84. {
  85. TRC_ERR((TB,_T("LoadString UI_IDS_APP_NAME failed")));
  86. }
  87. if (LoadString( hInstance,
  88. _SH.disconnectedStringID,
  89. _frameTitleStr,
  90. SH_FRAME_TITLE_RESOURCE_MAX_LENGTH ) != 0)
  91. {
  92. //
  93. // Successfully loaded the string. Now include the registry
  94. // session name.
  95. //
  96. TRC_DBG((TB, _T("UI frame title loaded OK.")));
  97. if (_SH.fRegDefault)
  98. {
  99. TRC_DBG((TB, _T("Default session")));
  100. DC_TSPRINTF(_fullFrameTitleStr, _frameTitleStr);
  101. }
  102. else
  103. {
  104. TRC_DBG((TB, _T("Named session")));
  105. DC_TSPRINTF(_fullFrameTitleStr, _frameTitleStr, _SH.regSession);
  106. }
  107. }
  108. else
  109. {
  110. TRC_ERR((TB,_T("Failed to find UI frame title")));
  111. _fullFrameTitleStr[0] = (DCTCHAR) 0;
  112. }
  113. _hAppIcon = NULL;
  114. #if defined(OS_WIN32) && !defined(OS_WINCE)
  115. _Ut.UT_ReadRegistryString(_SH.regSession,
  116. SH_ICON_FILE,
  117. _T(""),
  118. _SH.szIconFile,
  119. MAX_PATH);
  120. _SH.iconIndex = _Ut.UT_ReadRegistryInt(_SH.regSession,
  121. SH_ICON_INDEX,
  122. 0);
  123. _hAppIcon = ::ExtractIcon(hInstance, _SH.szIconFile, _SH.iconIndex);
  124. if(NULL == _hAppIcon)
  125. {
  126. _hAppIcon = LoadIcon(hInstance, MAKEINTRESOURCE(UI_IDI_ICON));
  127. }
  128. #else
  129. _hAppIcon = LoadIcon(hInstance, MAKEINTRESOURCE(UI_IDI_ICON));
  130. #endif
  131. DC_END_FN();
  132. return TRUE;
  133. }
  134. /****************************************************************************/
  135. /* Name: SH_ParseCmdParam
  136. /*
  137. /* Purpose: Parses the supplied cmdline
  138. /*
  139. /* Params: IN - lpszCmdParam - cmd line to parse
  140. /*
  141. /* Returns: Parsing status code
  142. /*
  143. /* SH_PARSECMD_OK - parsed successfully
  144. /* SH_PARSECMD_ERR_INVALID_CMD_LINE - generic parse error
  145. /* SH_PARSECMD_ERR_INVALID_CONNECTION_PARAM - invalid connect param
  146. /*
  147. /****************************************************************************/
  148. DWORD CSH::SH_ParseCmdParam(LPTSTR lpszCmdParam)
  149. {
  150. DWORD dwRet = SH_PARSECMD_ERR_INVALID_CMD_LINE;
  151. DC_BEGIN_FN("SHParseCmdParam");
  152. DC_TSTRCPY(_SH.regSession, SH_DEFAULT_REG_SESSION);
  153. if(!lpszCmdParam)
  154. {
  155. dwRet = SH_PARSECMD_ERR_INVALID_CMD_LINE;
  156. DC_QUIT;
  157. }
  158. while (*lpszCmdParam)
  159. {
  160. while (*lpszCmdParam == _T(' '))
  161. lpszCmdParam++;
  162. switch (*lpszCmdParam)
  163. {
  164. case _T('\0'):
  165. break;
  166. case _T('-'):
  167. case _T('/'):
  168. lpszCmdParam = SHGetSwitch(++lpszCmdParam);
  169. if(!lpszCmdParam) {
  170. dwRet = SH_PARSECMD_ERR_INVALID_CMD_LINE;
  171. DC_QUIT;
  172. }
  173. break;
  174. default:
  175. lpszCmdParam = SHGetSession(lpszCmdParam);
  176. break;
  177. }
  178. }
  179. SHValidateParsedCmdParam();
  180. //
  181. // Figure out if the connection param specified is a file
  182. // or a reg key
  183. //
  184. if (ParseFileOrRegConnectionParam()) {
  185. dwRet = SH_PARSECMD_OK;
  186. }
  187. else {
  188. dwRet = SH_PARSECMD_ERR_INVALID_CONNECTION_PARAM;
  189. }
  190. DC_END_FN();
  191. DC_EXIT_POINT:
  192. return dwRet;
  193. }
  194. DCBOOL CSH::SH_ValidateParams(CTscSettings* pTscSet)
  195. {
  196. HRESULT hr;
  197. BOOL fRet = FALSE;
  198. DC_BEGIN_FN("SH_ValidateParams");
  199. //
  200. // If the Address is empty, the params are invalid
  201. //
  202. if(pTscSet)
  203. {
  204. if (CRdpConnectionString::ValidateServerPart(
  205. pTscSet->GetFlatConnectString())) {
  206. fRet = TRUE;
  207. }
  208. }
  209. DC_END_FN();
  210. return fRet;
  211. }
  212. DCVOID CSH::SetServer(PDCTCHAR szServer)
  213. {
  214. DC_BEGIN_FN("SetServer");
  215. TRC_ASSERT(szServer, (TB,_T("szServer not set")));
  216. if(szServer)
  217. {
  218. DC_TSTRNCPY( _SH.szServer, szServer, sizeof(_SH.szServer)/sizeof(DCTCHAR));
  219. }
  220. DC_END_FN();
  221. }
  222. HICON CSH::GetAppIcon()
  223. {
  224. DC_BEGIN_FN("GetAppIcon");
  225. return _hAppIcon;
  226. DC_END_FN();
  227. }
  228. //
  229. // Read the control version string/cipher strength and store in _SH
  230. //
  231. DCBOOL CSH::SH_ReadControlVer(IMsRdpClient* pTsControl)
  232. {
  233. HRESULT hr = E_FAIL;
  234. BSTR bsVer;
  235. LONG cipher;
  236. USES_CONVERSION;
  237. DC_BEGIN_FN("SH_ReadControlVer");
  238. TRC_ASSERT(pTsControl, (TB, _T("Null TS CTL\n")));
  239. if(!pTsControl)
  240. {
  241. return FALSE;
  242. }
  243. TRACE_HR(pTsControl->get_CipherStrength(&cipher));
  244. if(SUCCEEDED(hr))
  245. {
  246. _SH.cipherStrength = (DCINT)cipher;
  247. TRACE_HR(pTsControl->get_Version(&bsVer));
  248. if(SUCCEEDED(hr))
  249. {
  250. if(bsVer)
  251. {
  252. LPTSTR szVer = OLE2T(bsVer);
  253. _tcsncpy(_SH.szControlVer, szVer, SIZECHAR(_SH.szControlVer));
  254. SysFreeString(bsVer);
  255. }
  256. else
  257. {
  258. _tcscpy(_SH.szControlVer, _T(""));
  259. }
  260. }
  261. else
  262. {
  263. return FALSE;
  264. }
  265. }
  266. else
  267. {
  268. return FALSE;
  269. }
  270. DC_END_FN();
  271. return TRUE;
  272. }
  273. //
  274. // Overide the _SH settings with params read in from
  275. // the command line
  276. // this should be called right after GetRegConfig is
  277. // called
  278. //
  279. // hwnd is the window we are being called for (used to figure
  280. // out which multimon screen we are on.)
  281. //
  282. DCVOID CSH::SH_ApplyCmdLineSettings(CTscSettings* pTscSet, HWND hwnd)
  283. {
  284. DC_BEGIN_FN("SH_ApplyCmdLineSettings");
  285. #ifdef OS_WINNT
  286. HMONITOR hMonitor;
  287. MONITORINFO monInfo;
  288. #endif // OS_WINNT
  289. TRC_ASSERT(pTscSet,(TB,_T("pTscSet is NULL")));
  290. PDCTCHAR szCmdLineServer = GetCmdLineServer();
  291. if(szCmdLineServer[0] != 0)
  292. {
  293. pTscSet->SetConnectString(szCmdLineServer);
  294. //
  295. // If a command line server is specified
  296. // it means autoconnect
  297. //
  298. SetAutoConnect(TRUE);
  299. }
  300. if (_SH.fCommandStartFullScreen)
  301. {
  302. pTscSet->SetStartFullScreen(TRUE);
  303. }
  304. DCUINT desktopWidth = DEFAULT_DESKTOP_WIDTH;
  305. DCUINT desktopHeight = DEFAULT_DESKTOP_HEIGHT;
  306. if (SH_IsScreenResSpecifiedOnCmdLine())
  307. {
  308. //
  309. // User has specified start size on command line
  310. //
  311. desktopWidth = GetCmdLineDesktopWidth();
  312. desktopHeight= GetCmdLineDesktopHeight();
  313. if(GetCmdLineStartFullScreen())
  314. {
  315. //
  316. // StartFullScreen is specified
  317. //
  318. if(!desktopWidth || !desktopHeight)
  319. {
  320. //
  321. // set the desktop width/height
  322. // to the screen size
  323. //
  324. #ifdef OS_WINNT
  325. if (GetSystemMetrics(SM_CMONITORS)) {
  326. hMonitor = MonitorFromWindow( hwnd,
  327. MONITOR_DEFAULTTONULL);
  328. if (hMonitor != NULL) {
  329. monInfo.cbSize = sizeof(MONITORINFO);
  330. if (GetMonitorInfo(hMonitor, &monInfo)) {
  331. desktopWidth = monInfo.rcMonitor.right -
  332. monInfo.rcMonitor.left;
  333. desktopHeight = monInfo.rcMonitor.bottom -
  334. monInfo.rcMonitor.top;
  335. }
  336. }
  337. }
  338. #else
  339. desktopWidth = GetSystemMetrics(SM_CXSCREEN);
  340. desktopHeight = GetSystemMetrics(SM_CYSCREEN);
  341. #endif // OS_WINNT
  342. }
  343. }
  344. if (desktopWidth && desktopHeight)
  345. {
  346. pTscSet->SetDesktopWidth(desktopWidth);
  347. pTscSet->SetDesktopHeight(desktopHeight);
  348. if (!_SH.fCommandStartFullScreen)
  349. {
  350. //If command line w/h specified and fullscreen
  351. //not explicitliy stated then disable fullscreen
  352. pTscSet->SetStartFullScreen(FALSE);
  353. }
  354. }
  355. }
  356. if (_fConnectToConsole)
  357. {
  358. // Without it we leave it however it was specified in the .rdp file
  359. pTscSet->SetConnectToConsole(_fConnectToConsole);
  360. }
  361. DC_END_FN();
  362. }
  363. //
  364. // Return true if the screen res was specified
  365. // on the command line
  366. //
  367. DCBOOL CSH::SH_IsScreenResSpecifiedOnCmdLine()
  368. {
  369. return (_SH.fCommandStartFullScreen ||
  370. (_SH.commandLineHeight &&
  371. _SH.commandLineWidth));
  372. }
  373. DCBOOL CSH::SH_CanonicalizeServerName(PDCTCHAR szServer)
  374. {
  375. // Remove leading spaces
  376. int strLength = DC_TSTRBYTELEN(szServer);
  377. while (_T(' ') == szServer[0])
  378. {
  379. strLength -= sizeof(DCTCHAR);
  380. memmove(&szServer[0], &szServer[1], strLength);
  381. }
  382. // Remove trailing spaces -- allow for DBCS strings.
  383. // At this stage, the string cannot consist entirely
  384. // of spaces. It must have at least one character,
  385. // followed by zero or more spaces.
  386. int numChars = _tcslen(szServer);
  387. while ((numChars != 0) &&
  388. (_T(' ') == szServer[numChars - 1])
  389. #ifndef UNICODE
  390. && (!IsDBCSLeadByte(szServer[numChars - 2]))
  391. #endif
  392. )
  393. {
  394. numChars--;
  395. szServer[numChars] = _T('\0');
  396. }
  397. //check for "\\" before the server address and remove it and
  398. //store the server address without the "\\" into szServer
  399. if((szServer[0] == _T('\\')) && (szServer[1]== _T('\\')))
  400. {
  401. strLength = DC_TSTRBYTELEN(szServer) - 2*sizeof(DCTCHAR);
  402. memmove(&szServer[0], &szServer[2], strLength);
  403. }
  404. return TRUE;
  405. }
  406. //
  407. // Initializes the combo (hwndSrvCombo) for autocompletion
  408. // with the MRU server names in the pTscSet collection.
  409. //
  410. void CSH::InitServerAutoCmplCombo(CTscSettings* pTscSet, HWND hwndSrvCombo)
  411. {
  412. DC_BEGIN_FN("InitServerComboEx");
  413. if(pTscSet && hwndSrvCombo)
  414. {
  415. SendMessage(hwndSrvCombo,
  416. CB_LIMITTEXT,
  417. SH_MAX_ADDRESS_LENGTH-1,
  418. 0);
  419. //
  420. // This call can be used to re-intialize a combo
  421. // so delete any items first
  422. //
  423. #ifndef OS_WINCE
  424. INT ret = 1;
  425. while(ret && ret != CB_ERR)
  426. {
  427. ret = SendMessage(hwndSrvCombo,
  428. CBEM_DELETEITEM,
  429. 0,0);
  430. }
  431. #else
  432. SendMessage(hwndSrvCombo, CB_RESETCONTENT, 0, 0);
  433. #endif
  434. for (int i=0; i<=9;++i)
  435. {
  436. if( _tcsncmp(pTscSet->GetMRUServer(i),_T(""),
  437. TSC_MAX_ADDRESS_LENGTH) )
  438. {
  439. #ifndef OS_WINCE
  440. COMBOBOXEXITEM cbItem;
  441. cbItem.mask = CBEIF_TEXT;
  442. cbItem.pszText = (PDCTCHAR)pTscSet->GetMRUServer(i);
  443. cbItem.iItem = -1; //append
  444. #endif
  445. if(-1 == SendMessage(hwndSrvCombo,
  446. #ifdef OS_WINCE
  447. CB_ADDSTRING,
  448. 0, (LPARAM)(LPCSTR)(PDCTCHAR)pTscSet->GetMRUServer(i)))
  449. #else
  450. CBEM_INSERTITEM,
  451. 0,(LPARAM)&cbItem))
  452. #endif
  453. {
  454. TRC_ERR((TB,(_T("Error appending to server dialog box"))));
  455. }
  456. }
  457. }
  458. //
  459. // Add browse for more option to server combo
  460. //
  461. #ifndef OS_WINCE
  462. COMBOBOXEXITEM cbItem;
  463. cbItem.mask = CBEIF_TEXT;
  464. cbItem.pszText = CSH::_szBrowseForMore;
  465. cbItem.iItem = -1; //append
  466. #endif
  467. if(-1 == SendMessage(hwndSrvCombo,
  468. #ifdef OS_WINCE
  469. CB_ADDSTRING,
  470. 0,(LPARAM)CSH::_szBrowseForMore))
  471. #else
  472. CBEM_INSERTITEM,
  473. 0,(LPARAM)&cbItem))
  474. #endif
  475. {
  476. TRC_ERR((TB,(_T("Error appending to server dialog box"))));
  477. }
  478. //
  479. // Never select the browse for server's item
  480. //
  481. int numItems = SendMessage(hwndSrvCombo,
  482. CB_GETCOUNT,
  483. 0,0);
  484. if(numItems != 1)
  485. {
  486. SendMessage( hwndSrvCombo, CB_SETCURSEL, (WPARAM)0,0);
  487. }
  488. #ifndef OS_WINCE
  489. SendMessage( hwndSrvCombo, CBEM_SETEXTENDEDSTYLE, (WPARAM)0,
  490. CBES_EX_NOEDITIMAGE );
  491. //
  492. // Enable autocomplete
  493. //
  494. HWND hwndEdit = (HWND)SendMessage( hwndSrvCombo,
  495. CBEM_GETEDITCONTROL, 0, 0);
  496. CAutoCompl::EnableServerAutoComplete( pTscSet, hwndEdit);
  497. #endif
  498. #ifdef OS_WINCE
  499. //This is to avoid WinCE quirk(bug??)
  500. //When the "Browse for more" entry is selected in the combo
  501. //and the name of the selected server is programmatically set
  502. //in the edit control with SetWindowText in the CBN_SELCHANGE handler
  503. //the text is cleared internally because the corresponding entry isnt
  504. //present in the list box. This is done only if the CBS_HASSTRINGS flag
  505. //is set. But the CBS_HASSTRINGS is always added when the combo box is
  506. //created. I am removing the style here so the text isnt cleared by default.
  507. SetWindowLong(hwndSrvCombo, GWL_STYLE,
  508. GetWindowLong(hwndSrvCombo, GWL_STYLE) & ~CBS_HASSTRINGS);
  509. #endif
  510. }
  511. DC_END_FN();
  512. }
  513. //
  514. // Return the filename that defines connection
  515. // settings. This may be a temp file that has been
  516. // automigrated from a reg session.
  517. //
  518. LPTSTR CSH::GetCmdLineFileName()
  519. {
  520. return _szFileName;
  521. }
  522. //
  523. // Return path to default.rdp file
  524. //
  525. BOOL CSH::SH_GetPathToDefaultFile(LPTSTR szPath, UINT nLen)
  526. {
  527. DC_BEGIN_FN("SH_GetPathToDefaultFile");
  528. if(nLen >= MAX_PATH)
  529. {
  530. if(SH_GetRemoteDesktopFolderPath(szPath, nLen))
  531. {
  532. HRESULT hr = StringCchCat(szPath, nLen, DEFAULT_RDP_FILE);
  533. if (FAILED(hr)) {
  534. TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr));
  535. return FALSE;
  536. }
  537. return TRUE;
  538. }
  539. else
  540. {
  541. return FALSE;
  542. }
  543. }
  544. else
  545. {
  546. return FALSE;
  547. }
  548. DC_END_FN();
  549. }
  550. //
  551. // Get the path to the remote desktop folder
  552. // params:
  553. // szPath - receives path
  554. // nLen - length of szPath
  555. // Returns:
  556. // Success flag
  557. //
  558. // Logic:
  559. // 1) Try reg key lookup of the path (first EXPAND_SZ and then SZ)
  560. // 2) Ask shell for location of MyDocuments and slap on suffix path
  561. // 3) If all else fails try current directory as root + suffix path
  562. //
  563. //
  564. BOOL CSH::SH_GetRemoteDesktopFolderPath(LPTSTR szPath, UINT nLen)
  565. {
  566. DC_BEGIN_FN("SH_GetRemoteDesktopFolderPath");
  567. HRESULT hr;
  568. BOOL fGotPathToMyDocs = FALSE;
  569. INT cch;
  570. if(nLen >= MAX_PATH)
  571. {
  572. //
  573. // First see if there is a path specified in the registry
  574. //
  575. LPTSTR szRegPath = NULL;
  576. INT len = (INT)nLen;
  577. _Ut.UT_ReadRegistryExpandSZ(SH_DEFAULT_REG_SESSION,
  578. REMOTEDESKTOPFOLDER_REGKEY,
  579. &szRegPath,
  580. &len);
  581. if(szRegPath)
  582. {
  583. int cchLen = 0;
  584. // User provided a reg key to override default
  585. // path so use that
  586. hr = StringCchCopy(szPath, nLen - 2, szRegPath);
  587. //Free returned buffer
  588. LocalFree( szRegPath );
  589. // Check if the string copy was successful.
  590. if (FAILED(hr)) {
  591. TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
  592. return FALSE;
  593. }
  594. cchLen = _tcslen(szPath);
  595. if(szPath[cchLen-1] != _T('\\'))
  596. {
  597. hr = StringCchCat(szPath, nLen, _T("\\"));
  598. if (FAILED(hr)) {
  599. TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
  600. return FALSE;
  601. }
  602. }
  603. TRC_NRM((TB,_T("Using path from registry %s"),
  604. szPath));
  605. return TRUE;
  606. }
  607. //Next try non expando key
  608. _Ut.UT_ReadRegistryString(SH_DEFAULT_REG_SESSION,
  609. REMOTEDESKTOPFOLDER_REGKEY,
  610. _T(""),
  611. szPath,
  612. nLen-2);
  613. if(szPath[0] != 0)
  614. {
  615. int cchLen = 0;
  616. cchLen = _tcslen(szPath);
  617. if(szPath[cchLen-1] != _T('\\'))
  618. {
  619. hr = StringCchCat(szPath, nLen, _T("\\"));
  620. if (FAILED(hr)) {
  621. TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
  622. return FALSE;
  623. }
  624. }
  625. TRC_NRM((TB,_T("Using path from registry %s"),
  626. szPath));
  627. return TRUE;
  628. }
  629. //
  630. // Not in registry, fallback on shell
  631. //
  632. #ifndef OS_WINCE
  633. //
  634. // It would be cool to use the nice and simple
  635. // SHGetFolderPath api but that doesn't work with
  636. // all versions of shell32.dll (i.e if you don't have the
  637. // IE desktop update you don't get SHGetFolderPath).
  638. //
  639. // blah.
  640. //
  641. //
  642. LPITEMIDLIST ppidl = NULL;
  643. hr = SHGetSpecialFolderLocation(NULL,
  644. CSIDL_PERSONAL,
  645. &ppidl);
  646. if(SUCCEEDED(hr) && ppidl)
  647. {
  648. hr = SHGetPathFromIDList(ppidl,
  649. szPath);
  650. TRC_ASSERT(SUCCEEDED(hr),
  651. (TB,_T("SHGetPathFromIDList failed: %d"),hr));
  652. if(SUCCEEDED(hr))
  653. {
  654. fGotPathToMyDocs = TRUE;
  655. }
  656. IMalloc* pMalloc;
  657. hr = SHGetMalloc(&pMalloc);
  658. TRC_ASSERT(SUCCEEDED(hr),
  659. (TB,_T("SHGetMalloc failed: %d"),hr));
  660. if(SUCCEEDED(hr))
  661. {
  662. pMalloc->Free(ppidl);
  663. pMalloc->Release();
  664. }
  665. }
  666. else
  667. {
  668. TRC_ERR((TB,_T("SHGetSpecialFolderLocation failed 0x%x"),
  669. hr));
  670. }
  671. if(!fGotPathToMyDocs)
  672. {
  673. TRC_ERR((TB,_T("Get path to my docs failed."),
  674. _T("Root folder in current directory.")));
  675. #ifndef OS_WINCE
  676. //Oh well as a last resort, root the folder
  677. //in the current directory. Necessary because some early
  678. //versions of win95 didn't have a MyDocuments folder
  679. if(!GetCurrentDirectory( nLen, szPath))
  680. {
  681. TRC_ERR((TB,_T("GetCurrentDirectory failed - 0x%x"),
  682. GetLastError()));
  683. return FALSE;
  684. }
  685. #endif
  686. }
  687. #else
  688. TRC_NRM((TB,_T("Using \\Windows directory 0x%x")));
  689. _stprintf(szPath,_T("\\windows"));
  690. #endif
  691. //
  692. // Terminate the path
  693. //
  694. cch = _tcslen(szPath);
  695. if (cch >= 1 && szPath[cch-1] != _T('\\'))
  696. {
  697. hr = StringCchCat(szPath, nLen, _T("\\"));
  698. if (FAILED(hr)) {
  699. TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr));
  700. return FALSE;
  701. }
  702. }
  703. return TRUE;
  704. }
  705. else
  706. {
  707. return FALSE;
  708. }
  709. DC_END_FN();
  710. }
  711. //
  712. // A worker function to make life easier in SH_GetPluginDllList. This function
  713. // takes a source string, cats it to a destination string, and then appends
  714. // a comma.
  715. //
  716. HRESULT StringCchCatComma(LPTSTR pszDest, size_t cchDest, LPCTSTR pszSrc) {
  717. HRESULT hr;
  718. DC_BEGIN_FN("StringCchCatComma");
  719. hr = StringCchCat(pszDest, cchDest, pszSrc);
  720. if (FAILED(hr)) {
  721. DC_QUIT;
  722. }
  723. hr = StringCchCat(pszDest, cchDest, _T(","));
  724. if (FAILED(hr)) {
  725. DC_QUIT;
  726. }
  727. DC_EXIT_POINT:
  728. DC_END_FN();
  729. return hr;
  730. }
  731. //
  732. // Creates a plugindlls list by enumerating all plugin dlls
  733. // in szSession reg entry
  734. //
  735. // Note, entries are APPENDED to szPlugins
  736. //
  737. BOOL CSH::SH_GetPluginDllList(LPTSTR szSession, LPTSTR szPlugins, size_t cchSzPlugins)
  738. {
  739. USES_CONVERSION;
  740. DC_BEGIN_FN("GetPluginDllList");
  741. TCHAR subKey[UT_MAX_SUBKEY];
  742. TCHAR sectKey[UT_MAX_SUBKEY];
  743. TCHAR enumKey[UT_MAX_SUBKEY];
  744. TCHAR DLLName[UT_MAX_WORKINGDIR_LENGTH];
  745. BOOL rc;
  746. DWORD i;
  747. INT enumKeySize;
  748. CUT ut;
  749. HRESULT hr;
  750. TRC_ASSERT(szSession && szPlugins,
  751. (TB,_T("Invalid param(s)")));
  752. hr = StringCchPrintf(subKey, SIZECHAR(subKey), _T("%s\\%s"),
  753. szSession, CHANNEL_SUBKEY_NAME);
  754. if (FAILED(hr)) {
  755. TRC_ERR((TB, _T("String printf failed: hr = 0x%x"), hr));
  756. return FALSE;
  757. }
  758. //
  759. // Enumerate the registered DLLs
  760. //
  761. for (i = 0; ; i++)
  762. {
  763. enumKeySize = UT_MAX_SUBKEY;
  764. rc = ut.UT_EnumRegistry(subKey, i, enumKey, &enumKeySize);
  765. // If a section name is returned, read the DLL name from it
  766. if (rc)
  767. {
  768. TRC_NRM((TB, _T("Section name %s found"), enumKey));
  769. hr = StringCchPrintf(sectKey, SIZECHAR(sectKey), _T("%s\\%s"),
  770. subKey, enumKey);
  771. if (FAILED(hr)) {
  772. TRC_ERR((TB, _T("String printf failed: hr = 0x%x"), hr));
  773. return FALSE;
  774. }
  775. TRC_NRM((TB, _T("Section to read: %s"), sectKey));
  776. //
  777. // First try to read as an expandable
  778. // string (i.e REG_EXPAND_SZ)
  779. //
  780. LPTSTR szExpandedName = NULL;
  781. INT expandedNameLen=0;
  782. if(ut.UT_ReadRegistryExpandSZ(sectKey,
  783. CHANNEL_NAME_KEY,
  784. &szExpandedName,
  785. &expandedNameLen))
  786. {
  787. TRC_NRM((TB, _T("Expanded DLL Name read %s"), szExpandedName));
  788. // If a DLL name is returned, append it to the list
  789. if (szExpandedName && szExpandedName[0] != 0)
  790. {
  791. hr = StringCchCatComma(szPlugins, cchSzPlugins, szExpandedName);
  792. //Must free returned buffer
  793. LocalFree( szExpandedName );
  794. // Check if the string concatenation failed.
  795. if (FAILED(hr)) {
  796. TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr));
  797. return FALSE;
  798. }
  799. }
  800. }
  801. else
  802. {
  803. memset(DLLName, 0, sizeof(DLLName));
  804. ut.UT_ReadRegistryString(sectKey,
  805. CHANNEL_NAME_KEY,
  806. TEXT(""),
  807. DLLName,
  808. UT_MAX_WORKINGDIR_LENGTH);
  809. TRC_NRM((TB, _T("DLL Name read %s"), DLLName));
  810. // If a DLL name is returned, append it to the list
  811. if (DLLName[0] != 0)
  812. {
  813. //FIXFIX finite size of szPlugins
  814. hr = StringCchCatComma(szPlugins, cchSzPlugins, DLLName);
  815. if (FAILED(hr)) {
  816. TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr));
  817. return FALSE;
  818. }
  819. }
  820. }
  821. }
  822. else
  823. {
  824. //
  825. // No DLL name returned - end of enumeration
  826. //
  827. break;
  828. }
  829. }
  830. TRC_NRM((TB, _T("Passing list of plugins to load: %s"), szPlugins));
  831. return TRUE;
  832. }
  833. //
  834. // Handle the server combo box drop down
  835. // for browse for more... functionality.
  836. // this fn is broken out into sh to avoid code duplication
  837. // because it is used in both the maindlg and propgeneral
  838. //
  839. BOOL CSH::HandleServerComboChange(HWND hwndCombo,
  840. HWND hwndDlg,
  841. HINSTANCE hInst,
  842. LPTSTR szPrevText)
  843. {
  844. int numItems = SendMessage(hwndCombo,
  845. CB_GETCOUNT,
  846. 0,0);
  847. int curSel = SendMessage(hwndCombo,
  848. CB_GETCURSEL,
  849. 0,0);
  850. //
  851. // If last item is selected
  852. //
  853. if(curSel == numItems-1)
  854. {
  855. INT_PTR nResult = IDCANCEL;
  856. SendMessage( hwndCombo, CB_SETCURSEL,
  857. (WPARAM)-1,0);
  858. CBrowseDlg browseDlg( hwndDlg, hInst);
  859. nResult = browseDlg.DoModal();
  860. if (IDOK == nResult)
  861. {
  862. SetWindowText( hwndCombo,
  863. browseDlg.GetServer());
  864. }
  865. else
  866. {
  867. //
  868. // Revert to initial
  869. //
  870. SetWindowText( hwndCombo,
  871. szPrevText);
  872. }
  873. }
  874. return TRUE;
  875. }
  876. //
  877. // Fill in certain settings in pTsc with system
  878. // defaults.
  879. //
  880. // E.g if the username is blank, fill that in
  881. // with the current username
  882. //
  883. BOOL CSH::SH_AutoFillBlankSettings(CTscSettings* pTsc)
  884. {
  885. DC_BEGIN_FN("SH_AutoFillBlankSettings");
  886. TRC_ASSERT(pTsc,(TB,_T("pTsc is null")));
  887. #ifndef OS_WINCE
  888. //
  889. // TODO: update with UPN user name when
  890. // server limit of 20 chars is fixed
  891. //
  892. if(!_tcscmp(pTsc->GetLogonUserName(), TEXT("")))
  893. {
  894. TCHAR szUserName[TSC_MAX_USERNAME_LENGTH];
  895. DWORD dwLen = SIZECHAR(szUserName);
  896. if(::GetUserName(szUserName, &dwLen))
  897. {
  898. pTsc->SetLogonUserName( szUserName);
  899. }
  900. else
  901. {
  902. TRC_ERR((TB,_T("GetUserName failed: %d"), GetLastError()));
  903. return FALSE;
  904. }
  905. }
  906. #endif
  907. DC_END_FN();
  908. return TRUE;
  909. }
  910. //
  911. // Return TRUE if szFileName exists
  912. //
  913. BOOL CSH::SH_FileExists(LPTSTR szFileName)
  914. {
  915. BOOL fExist = FALSE;
  916. if(szFileName)
  917. {
  918. HANDLE hFile = CreateFile(szFileName,
  919. GENERIC_READ,
  920. FILE_SHARE_READ,
  921. NULL,
  922. OPEN_EXISTING,
  923. FILE_ATTRIBUTE_NORMAL,
  924. NULL);
  925. if(hFile != INVALID_HANDLE_VALUE)
  926. {
  927. fExist = TRUE;
  928. }
  929. CloseHandle(hFile);
  930. return fExist;
  931. }
  932. else
  933. {
  934. return FALSE;
  935. }
  936. }
  937. //
  938. // Return TRUE if the settings reg key exists
  939. // under HK{CU|LM}\Software\Microsoft\Terminal Server Client\{szKeyName}
  940. //
  941. BOOL
  942. CSH::SH_TSSettingsRegKeyExists(LPTSTR szKeyName)
  943. {
  944. BOOL fRet = FALSE;
  945. HKEY hRootKey;
  946. LONG rc;
  947. TCHAR szFullKeyName[MAX_PATH];
  948. DC_BEGIN_FN("SH_TSSettingsRegKeyExists");
  949. if (_tcslen(szKeyName) + SIZECHAR(TSC_SETTINGS_REG_ROOT) +1 >=
  950. SIZECHAR(szFullKeyName)) {
  951. TRC_ERR((TB,_T("szKeyName invalid length")));
  952. fRet = FALSE;
  953. DC_QUIT;
  954. }
  955. //
  956. // String lengths are pre-validated
  957. //
  958. _tcscpy(szFullKeyName,TSC_SETTINGS_REG_ROOT);
  959. _tcscat(szFullKeyName, szKeyName);
  960. //
  961. // First try HKLM
  962. //
  963. rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  964. szFullKeyName,
  965. 0,
  966. KEY_READ,
  967. &hRootKey);
  968. if (ERROR_SUCCESS == rc && hRootKey) {
  969. //
  970. // Key exists undler HKLM
  971. //
  972. RegCloseKey(hRootKey);
  973. fRet = TRUE;
  974. }
  975. else {
  976. //
  977. // Try HKCU
  978. //
  979. rc = RegOpenKeyEx(HKEY_CURRENT_USER,
  980. szFullKeyName,
  981. 0,
  982. KEY_READ,
  983. &hRootKey);
  984. if (ERROR_SUCCESS == rc && hRootKey) {
  985. RegCloseKey(hRootKey);
  986. fRet = TRUE;
  987. }
  988. }
  989. DC_END_FN();
  990. DC_EXIT_POINT:
  991. return fRet;
  992. }
  993. BOOL CSH::SH_DisplayErrorBox(HWND hwndParent, INT errStringID)
  994. {
  995. DC_BEGIN_FN("SH_DisplayErrorBox");
  996. return SH_DisplayMsgBox(hwndParent, errStringID,
  997. MB_ICONERROR | MB_OK);
  998. DC_END_FN();
  999. }
  1000. BOOL CSH::SH_DisplayMsgBox(HWND hwndParent, INT errStringID, INT flags)
  1001. {
  1002. DC_BEGIN_FN("SH_DisplayMsgBox");
  1003. TCHAR szErr[MAX_PATH];
  1004. if (LoadString(_hInstance,
  1005. errStringID,
  1006. szErr,
  1007. SIZECHAR(szErr)) != 0)
  1008. {
  1009. MessageBox(hwndParent, szErr, _szAppName,
  1010. flags);
  1011. return TRUE;
  1012. }
  1013. else
  1014. {
  1015. return FALSE;
  1016. }
  1017. DC_END_FN();
  1018. }
  1019. BOOL CSH::SH_DisplayErrorBox(HWND hwndParent, INT errStringID, LPTSTR szParam)
  1020. {
  1021. DC_BEGIN_FN("SH_DisplayErrorBox");
  1022. TRC_ASSERT(szParam,(TB,_T("szParam is null")));
  1023. if(!szParam)
  1024. {
  1025. return FALSE;
  1026. }
  1027. TCHAR szErr[MAX_PATH];
  1028. if (LoadString(_hInstance,
  1029. errStringID,
  1030. szErr,
  1031. SIZECHAR(szErr)) != 0)
  1032. {
  1033. TCHAR szFormatedErr[MAX_PATH*2];
  1034. _stprintf(szFormatedErr, szErr, szParam);
  1035. MessageBox(hwndParent, szFormatedErr, _szAppName,
  1036. MB_ICONERROR | MB_OK);
  1037. return TRUE;
  1038. }
  1039. else
  1040. {
  1041. return FALSE;
  1042. }
  1043. DC_END_FN();
  1044. }
  1045. BOOL CSH::SH_GetNameFromPath(LPTSTR szPath, LPTSTR szName, UINT nameLen)
  1046. {
  1047. DC_BEGIN_FN("SH_GetNameFromPath");
  1048. #ifndef OS_WINCE
  1049. if(szPath && szName && nameLen)
  1050. {
  1051. short ret = GetFileTitle(szPath,
  1052. szName,
  1053. (WORD)nameLen);
  1054. if(ret != 0)
  1055. {
  1056. TRC_ERR((TB,_T("SH_GetNameFromPath failed: %d"),GetLastError()));
  1057. szName[0] = 0;
  1058. return FALSE;
  1059. }
  1060. else
  1061. {
  1062. //Strip out the extension
  1063. int len = _tcslen(szName);
  1064. LPTSTR szEnd = &szName[len-1];
  1065. while(szEnd >= szName)
  1066. {
  1067. if(*szEnd == L'.')
  1068. {
  1069. *szEnd = 0;
  1070. }
  1071. szEnd--;
  1072. }
  1073. return TRUE;
  1074. }
  1075. }
  1076. else
  1077. {
  1078. return FALSE;
  1079. }
  1080. #else
  1081. // no GetFileTitle on CE so just cheat
  1082. _tcsncpy( szName, szPath, nameLen - 1);
  1083. szName[nameLen-1] = 0;
  1084. return TRUE;
  1085. #endif
  1086. DC_END_FN();
  1087. }
  1088. #ifndef OS_WINCE
  1089. //
  1090. // Compute and return the disaplay name of the My Documents folder
  1091. //
  1092. BOOL CSH::SH_GetMyDocumentsDisplayName(LPTSTR szName, UINT nLen)
  1093. {
  1094. IShellFolder* pshf = NULL;
  1095. LPITEMIDLIST pidl = NULL;
  1096. LPITEMIDLIST pidlDocFiles = NULL;
  1097. HRESULT hr = E_FAIL;
  1098. ULONG chEaten;
  1099. STRRET strret;
  1100. DC_BEGIN_FN("SH_GetMyDocumentsDisplayName");
  1101. TRC_ASSERT((szName && nLen),(TB,_T("NULL param(s)")));
  1102. if(!szName || !nLen)
  1103. {
  1104. return FALSE;
  1105. }
  1106. //On failure null string
  1107. szName[0] = NULL;
  1108. //
  1109. // First try the powerful shell way
  1110. // which will return the correctly localized
  1111. // name. If this fails (due to shell issues)
  1112. // then fall back on a technique that is guaranteed
  1113. // to work but may in some cases give the physical
  1114. // path instead.
  1115. //
  1116. hr = SHGetDesktopFolder( &pshf );
  1117. TRC_ASSERT(SUCCEEDED(hr),
  1118. (TB,_T("SHGetDesktopFolder failed")));
  1119. if(FAILED(hr) || !pshf)
  1120. {
  1121. DC_QUIT;
  1122. }
  1123. //
  1124. // GUID to MyDocuments folder taken from
  1125. // MSDN "shell basics - managing the filesystem -"
  1126. // "my documents and my pictures folder"
  1127. //
  1128. hr = pshf->ParseDisplayName( NULL, NULL,
  1129. L"::{450d8fba-ad25-11d0-98a8-0800361b1103}",
  1130. &chEaten, &pidlDocFiles, NULL );
  1131. if(SUCCEEDED(hr))
  1132. {
  1133. hr = pshf->GetDisplayNameOf( pidlDocFiles, SHGDN_INFOLDER, &strret );
  1134. if(SUCCEEDED(hr))
  1135. {
  1136. LPTSTR sz;
  1137. hr = XStrRetToStrW(&strret, pidl, &sz);
  1138. if(SUCCEEDED(hr))
  1139. {
  1140. _tcsncpy(szName, sz, nLen);
  1141. szName[nLen-1] = NULL;
  1142. CoTaskMemFree(sz);
  1143. pshf->Release();
  1144. return TRUE;
  1145. }
  1146. else
  1147. {
  1148. TRC_ERR((TB,_T("XStrRetToStrW failed :%d"), hr));
  1149. DC_QUIT;
  1150. }
  1151. }
  1152. else
  1153. {
  1154. TRC_ERR((TB,_T("GetDisplayNameOf failed :%d"), hr));
  1155. //Don't quit, fall back and try the other method
  1156. }
  1157. }
  1158. else
  1159. {
  1160. TRC_ERR((TB,_T("ParseDisplayName failed :%d"), hr));
  1161. //Don't quit, fall back and try the other method
  1162. }
  1163. hr = SHGetSpecialFolderLocation(NULL,
  1164. CSIDL_PERSONAL,
  1165. &pidl);
  1166. if(SUCCEEDED(hr) && pidl)
  1167. {
  1168. hr = pshf->GetDisplayNameOf(pidl,
  1169. SHGDN_INFOLDER,
  1170. &strret);
  1171. if(SUCCEEDED(hr))
  1172. {
  1173. LPTSTR sz;
  1174. hr = XStrRetToStrW(&strret, pidl, &sz);
  1175. if(SUCCEEDED(hr))
  1176. {
  1177. _tcsncpy(szName, sz, nLen);
  1178. szName[nLen-1] = NULL;
  1179. CoTaskMemFree(sz);
  1180. pshf->Release();
  1181. return TRUE;
  1182. }
  1183. else
  1184. {
  1185. TRC_ERR((TB,_T("XStrRetToStrW failed :%d"), hr));
  1186. DC_QUIT;
  1187. }
  1188. }
  1189. else
  1190. {
  1191. TRC_ERR((TB,_T("GetDisplayNameOf failed :%d"), hr));
  1192. DC_QUIT;
  1193. }
  1194. }
  1195. else
  1196. {
  1197. TRC_ERR((TB,_T("SHGetSpecialFolderLocation failed 0x%x"),
  1198. hr));
  1199. DC_QUIT;
  1200. }
  1201. DC_EXIT_POINT:
  1202. if(pshf)
  1203. {
  1204. pshf->Release();
  1205. pshf = NULL;
  1206. }
  1207. DC_END_FN();
  1208. TRC_ERR((TB,_T("failed to get display name")));
  1209. return FALSE;
  1210. }
  1211. #endif //OS_WINCE
  1212. //
  1213. // On demand loads HTML help and displays the client help
  1214. // if the HTMLHELP is not available, pop a message box to
  1215. // the user.
  1216. // SH_Cleanup cleans up HTML help (unloads lib)
  1217. // on exit
  1218. //
  1219. // Return HWND to help window or NULL on failure
  1220. //
  1221. //
  1222. HWND CSH::SH_DisplayClientHelp(HWND hwndOwner, INT helpCommand)
  1223. {
  1224. BOOL fHtmlHelpAvailable = FALSE;
  1225. DC_BEGIN_FN("SH_DisplayClientHelp");
  1226. #ifndef OS_WINCE
  1227. if(!_hModHHCTRL)
  1228. {
  1229. _hModHHCTRL = (HMODULE)LoadLibrary(_T("hhctrl.ocx"));
  1230. if(_hModHHCTRL)
  1231. {
  1232. //
  1233. // Use ANSI version of HTML Help so it always works
  1234. // on downlevel platforms without uniwrap
  1235. //
  1236. _pFnHtmlHelp = (PFNHtmlHelp)GetProcAddress(_hModHHCTRL,
  1237. "HtmlHelpA");
  1238. if(_pFnHtmlHelp)
  1239. {
  1240. fHtmlHelpAvailable = TRUE;
  1241. }
  1242. else
  1243. {
  1244. TRC_ERR((TB,_T("GetProcAddress failed for HtmlHelpA: 0x%x"),
  1245. GetLastError()));
  1246. }
  1247. }
  1248. else
  1249. {
  1250. TRC_ERR((TB,_T("LoadLibrary failed for hhctrl.ocx: 0x%x"),
  1251. GetLastError()));
  1252. }
  1253. }
  1254. else if (_pFnHtmlHelp)
  1255. {
  1256. fHtmlHelpAvailable = TRUE;
  1257. }
  1258. if(fHtmlHelpAvailable)
  1259. {
  1260. return _pFnHtmlHelp( hwndOwner, MSTSC_HELP_FILE_ANSI,
  1261. helpCommand, 0L);
  1262. }
  1263. else
  1264. {
  1265. //
  1266. // Display a message to the user that HTML help is
  1267. // not availalbe on their system.
  1268. //
  1269. SH_DisplayErrorBox( hwndOwner, UI_IDS_NOHTMLHELP);
  1270. return NULL;
  1271. }
  1272. #else
  1273. if ((GetFileAttributes(PEGHELP_EXE) != -1) &&
  1274. (GetFileAttributes(TSC_HELP_FILE) != -1))
  1275. {
  1276. CreateProcess(PEGHELP_EXE, MSTSC_HELP_FILE, 0,0,0,0,0,0,0,0);
  1277. }
  1278. else
  1279. {
  1280. SH_DisplayErrorBox( hwndOwner, UI_IDS_NOHTMLHELP);
  1281. }
  1282. #endif
  1283. DC_END_FN();
  1284. #ifdef OS_WINCE
  1285. return NULL;
  1286. #endif
  1287. }
  1288. BOOL CSH::SH_Cleanup()
  1289. {
  1290. DC_BEGIN_FN("SH_Cleanup");
  1291. if(_hModHHCTRL)
  1292. {
  1293. FreeLibrary(_hModHHCTRL);
  1294. _pFnHtmlHelp = NULL;
  1295. _hModHHCTRL = NULL;
  1296. }
  1297. if (_hUxTheme)
  1298. {
  1299. FreeLibrary(_hUxTheme);
  1300. _hUxTheme = NULL;
  1301. _pFnEnableThemeDialogTexture = NULL;
  1302. }
  1303. DC_END_FN();
  1304. return TRUE;
  1305. }
  1306. //
  1307. // Enable or disable an array of dlg controls
  1308. //
  1309. VOID CSH::EnableControls(HWND hwndDlg, PUINT pCtls,
  1310. const UINT numCtls, BOOL fEnable)
  1311. {
  1312. DC_BEGIN_FN("EnableControls");
  1313. for(UINT i=0;i<numCtls;i++)
  1314. {
  1315. EnableWindow( GetDlgItem( hwndDlg, pCtls[i]),
  1316. fEnable);
  1317. }
  1318. DC_END_FN();
  1319. }
  1320. //
  1321. // Enable or disable an array of dlg controls
  1322. // with memory. E.g previously disabled controls
  1323. // are not re-enabled.
  1324. //
  1325. VOID CSH::EnableControls(HWND hwndDlg, PCTL_ENABLE pCtls,
  1326. const UINT numCtls, BOOL fEnable)
  1327. {
  1328. DC_BEGIN_FN("EnableControls");
  1329. if(!fEnable)
  1330. {
  1331. //
  1332. // Disable controls and remember which
  1333. // were previously disabled
  1334. //
  1335. for(UINT i=0;i<numCtls;i++)
  1336. {
  1337. pCtls[i].fPrevDisabled =
  1338. EnableWindow( GetDlgItem( hwndDlg, pCtls[i].ctlID),
  1339. FALSE);
  1340. }
  1341. }
  1342. else
  1343. {
  1344. //Enable controls that were not initially disabled
  1345. for(UINT i=0;i<numCtls;i++)
  1346. {
  1347. if(!pCtls[i].fPrevDisabled)
  1348. {
  1349. EnableWindow( GetDlgItem( hwndDlg, pCtls[i].ctlID),
  1350. TRUE);
  1351. }
  1352. }
  1353. }
  1354. DC_END_FN();
  1355. }
  1356. //
  1357. // Attempt to create a directory by first
  1358. // creating all the subdirs
  1359. //
  1360. // Params - szPath (path to dir to create)
  1361. // Returns - status
  1362. //
  1363. BOOL CSH::SH_CreateDirectory(LPTSTR szPath)
  1364. {
  1365. BOOL rc = TRUE;
  1366. int i = 0;
  1367. DC_BEGIN_FN("SH_CreateDirectory");
  1368. if(szPath)
  1369. {
  1370. if(szPath[i] == _T('\\') &&
  1371. szPath[i+1] == _T('\\'))
  1372. {
  1373. //Handle UNC path
  1374. //Walk until the end of the server name
  1375. i+=2;
  1376. while (szPath[i] && szPath[i++] != _T('\\'));
  1377. if(!szPath[i])
  1378. {
  1379. TRC_ERR((TB,_T("Invalid path %s"), szPath));
  1380. return FALSE;
  1381. }
  1382. //Walk past drive letter if specified
  1383. //e.g \\myserver\a$\foo
  1384. if (szPath[i] &&
  1385. szPath[i+1] == _T('$') &&
  1386. szPath[i+2] == _T('\\'))
  1387. {
  1388. i+=3;
  1389. }
  1390. }
  1391. else
  1392. {
  1393. //Local path
  1394. #ifndef OS_WINCE
  1395. while(szPath[i] && szPath[i++] != _T(':'));
  1396. #endif
  1397. if(szPath[i] && szPath[i] == _T('\\'))
  1398. {
  1399. i++; //Skip the first '\'
  1400. }
  1401. else
  1402. {
  1403. TRC_ERR((TB,_T("Invalid (or non local) path %s"),
  1404. szPath));
  1405. return FALSE;
  1406. }
  1407. }
  1408. while (rc && szPath[i] != 0)
  1409. {
  1410. if (szPath[i] == _T('\\'))
  1411. {
  1412. szPath[i] = 0;
  1413. if (!CreateDirectory(szPath, NULL))
  1414. {
  1415. if (GetLastError() != ERROR_ALREADY_EXISTS)
  1416. {
  1417. rc = FALSE;
  1418. }
  1419. }
  1420. szPath[i] = _T('\\');
  1421. }
  1422. i++;
  1423. }
  1424. }
  1425. if(!rc)
  1426. {
  1427. TRC_ERR((TB,_T("SH_CreateDirectory failed")));
  1428. }
  1429. DC_END_FN();
  1430. return rc;
  1431. }
  1432. UINT CSH::SH_GetScreenBpp()
  1433. {
  1434. HDC hdc;
  1435. int screenBpp;
  1436. DC_BEGIN_FN("UI_GetScreenBpp");
  1437. hdc = GetDC(NULL);
  1438. if(hdc)
  1439. {
  1440. screenBpp = GetDeviceCaps(hdc, BITSPIXEL);
  1441. TRC_NRM((TB, _T("HDC %p has %u bpp"), hdc, screenBpp));
  1442. ReleaseDC(NULL, hdc);
  1443. }
  1444. DC_END_FN();
  1445. return screenBpp;
  1446. }
  1447. //
  1448. // Crypto API is present on WIN2k+
  1449. //
  1450. BOOL CSH::IsCryptoAPIPresent()
  1451. {
  1452. #ifndef OS_WINCE
  1453. OSVERSIONINFO osVersionInfo;
  1454. osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
  1455. if (GetVersionEx( &osVersionInfo ))
  1456. {
  1457. if (osVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
  1458. osVersionInfo.dwMajorVersion >= 5)
  1459. {
  1460. return TRUE;
  1461. }
  1462. }
  1463. return FALSE;
  1464. #else
  1465. //CryptProtectData and CryptUnprotectData are present in all CE configs.
  1466. //(At least everything with filesys or registry) So return TRUE.always.
  1467. return TRUE;
  1468. #endif
  1469. }
  1470. //
  1471. // DataProtect
  1472. // Protect data for persistence using data protection API
  1473. // params:
  1474. // pInData - (in) input bytes to protect
  1475. // pOutData - (out) output data caller must free
  1476. // returns: bool status
  1477. //
  1478. typedef BOOL (WINAPI* PFNCryptProtectData)(
  1479. IN DATA_BLOB* pDataIn,
  1480. IN LPCWSTR szDataDescr,
  1481. IN OPTIONAL DATA_BLOB* pOptionalEntropy,
  1482. IN PVOID pvReserved,
  1483. IN OPTIONAL CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
  1484. IN DWORD dwFlags,
  1485. OUT DATA_BLOB* pDataOut
  1486. );
  1487. BOOL CSH::DataProtect(PDATA_BLOB pInData, PDATA_BLOB pOutData)
  1488. {
  1489. #ifndef OS_WINCE
  1490. HMODULE hCryptLib = NULL;
  1491. PFNCryptProtectData fnCryptProtectData = NULL;
  1492. #endif
  1493. BOOL bRet = TRUE;
  1494. DC_BEGIN_FN("DataProtect");
  1495. TRC_ASSERT( IsCryptoAPIPresent(),
  1496. (TB,_T("Crytpapi not present shouldn't call DataProtect")));
  1497. if (pInData && pInData->cbData && pInData->pbData &&
  1498. pOutData)
  1499. {
  1500. #ifndef OS_WINCE
  1501. hCryptLib = (HMODULE) LoadLibrary( _T("crypt32.dll") );
  1502. if (hCryptLib)
  1503. {
  1504. fnCryptProtectData = (PFNCryptProtectData)
  1505. GetProcAddress( hCryptLib, "CryptProtectData");
  1506. }
  1507. else
  1508. {
  1509. TRC_ERR((TB,_T("LoadLib for crypt32.dll failed: 0x%x"),
  1510. GetLastError()));
  1511. return FALSE;
  1512. }
  1513. if (fnCryptProtectData)
  1514. {
  1515. if (fnCryptProtectData( pInData,
  1516. #else
  1517. if (CryptProtectData( pInData,
  1518. #endif
  1519. TEXT("psw"), // DESCRIPTION STRING.
  1520. NULL, // optional entropy
  1521. NULL, // reserved
  1522. NULL, // NO prompting
  1523. CRYPTPROTECT_UI_FORBIDDEN, //don't pop UI
  1524. pOutData ))
  1525. {
  1526. bRet = TRUE;
  1527. }
  1528. else
  1529. {
  1530. DWORD dwLastErr = GetLastError();
  1531. TRC_ERR((TB,_T("CryptProtectData FAILED error:%d\n"),
  1532. dwLastErr));
  1533. bRet = FALSE;
  1534. }
  1535. #ifndef OS_WINCE
  1536. }
  1537. else
  1538. {
  1539. TRC_ERR((TB,_T("GetProcAddress for CryptProtectData failed: 0x%x"),
  1540. GetLastError()));
  1541. bRet = FALSE;
  1542. }
  1543. #endif
  1544. }
  1545. else
  1546. {
  1547. TRC_ERR((TB,_T("Invalid data")));
  1548. return FALSE;
  1549. }
  1550. #ifndef OS_WINCE
  1551. if (hCryptLib)
  1552. {
  1553. FreeLibrary(hCryptLib);
  1554. }
  1555. #endif
  1556. DC_END_FN();
  1557. return bRet;
  1558. }
  1559. //
  1560. // DataUnprotect
  1561. // UnProtect persisted out data using data protection API
  1562. // params:
  1563. // pInData - (in) input bytes to UN protect
  1564. // cbLen - (in) length of pInData in bytes
  1565. // ppOutData - (out) output bytes
  1566. // pcbOutLen - (out) length of output
  1567. // returns: bool status
  1568. //
  1569. //
  1570. typedef BOOL (WINAPI* PFNCryptUnprotectData)(
  1571. IN DATA_BLOB* pDataIn,
  1572. IN LPCWSTR szDataDescr,
  1573. IN OPTIONAL DATA_BLOB* pOptionalEntropy,
  1574. IN PVOID pvReserved,
  1575. IN OPTIONAL CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
  1576. IN DWORD dwFlags,
  1577. OUT DATA_BLOB* pDataOut
  1578. );
  1579. BOOL CSH::DataUnprotect(PDATA_BLOB pInData, PDATA_BLOB pOutData)
  1580. {
  1581. #ifndef OS_WINCE
  1582. HMODULE hCryptLib = NULL;
  1583. PFNCryptUnprotectData fnCryptUnprotectData = NULL;
  1584. #endif
  1585. BOOL bRet = TRUE;
  1586. DC_BEGIN_FN("DataUnprotect");
  1587. TRC_ASSERT( IsCryptoAPIPresent(),
  1588. (TB,_T("Crytpapi not present shouldn't call DataUnprotect")));
  1589. if (pInData && pInData->cbData && pInData->pbData &&
  1590. pOutData)
  1591. {
  1592. #ifndef OS_WINCE
  1593. hCryptLib = (HMODULE) LoadLibrary( _T("crypt32.dll") );
  1594. if (hCryptLib)
  1595. {
  1596. fnCryptUnprotectData = (PFNCryptUnprotectData)
  1597. GetProcAddress( hCryptLib, "CryptUnprotectData");
  1598. }
  1599. else
  1600. {
  1601. TRC_ERR((TB,_T("LoadLib for crypt32.dll failed: 0x%x"),
  1602. GetLastError()));
  1603. return FALSE;
  1604. }
  1605. if (fnCryptUnprotectData)
  1606. {
  1607. if (fnCryptUnprotectData( pInData,
  1608. #else
  1609. if (CryptUnprotectData( pInData,
  1610. #endif
  1611. NULL, // no description
  1612. NULL, // optional entropy
  1613. NULL, // reserved
  1614. NULL, // NO prompting
  1615. CRYPTPROTECT_UI_FORBIDDEN, //don't pop UI
  1616. pOutData ))
  1617. {
  1618. bRet = TRUE;
  1619. }
  1620. else
  1621. {
  1622. DWORD dwLastErr = GetLastError();
  1623. TRC_ERR((TB,_T("fnCryptUnprotectData FAILED error:%d\n"),
  1624. dwLastErr));
  1625. bRet = FALSE;
  1626. }
  1627. #ifndef OS_WINCE
  1628. }
  1629. else
  1630. {
  1631. TRC_ERR((TB,_T("GetProcAddress for CryptUnprotectData failed: 0x%x"),
  1632. GetLastError()));
  1633. bRet = FALSE;
  1634. }
  1635. #endif
  1636. }
  1637. else
  1638. {
  1639. TRC_ERR((TB,_T("Invalid data")));
  1640. return FALSE;
  1641. }
  1642. #ifndef OS_WINCE
  1643. if (hCryptLib)
  1644. {
  1645. FreeLibrary(hCryptLib);
  1646. }
  1647. #endif
  1648. DC_END_FN();
  1649. return bRet;
  1650. }
  1651. #ifndef OS_WINCE
  1652. BOOL CALLBACK MaxMonitorSizeEnumProc(HMONITOR hMonitor, HDC hdcMonitor,
  1653. RECT* prc, LPARAM lpUserData)
  1654. {
  1655. LPRECT prcLrg = (LPRECT)lpUserData;
  1656. if ((prc->right - prc->left) >= (prcLrg->right - prcLrg->left) &&
  1657. (prc->bottom - prc->top) >= (prcLrg->bottom - prcLrg->top))
  1658. {
  1659. *prcLrg = *prc;
  1660. }
  1661. return TRUE;
  1662. }
  1663. #endif
  1664. BOOL CSH::GetLargestMonitorRect(LPRECT prc)
  1665. {
  1666. DC_BEGIN_FN("GetLargestMonitorRect");
  1667. if (prc)
  1668. {
  1669. // default screen size
  1670. prc->top = 0;
  1671. prc->left = 0;
  1672. prc->bottom = GetSystemMetrics(SM_CYSCREEN);
  1673. prc->right = GetSystemMetrics(SM_CXSCREEN);
  1674. #ifndef OS_WINCE //No multimon on CE
  1675. if (GetSystemMetrics(SM_CMONITORS))
  1676. {
  1677. //Enumerate and look for a larger monitor
  1678. EnumDisplayMonitors(NULL, NULL, MaxMonitorSizeEnumProc,
  1679. (LPARAM) prc);
  1680. }
  1681. #endif //OS_WINCE
  1682. return TRUE;
  1683. }
  1684. else
  1685. {
  1686. return FALSE;
  1687. }
  1688. DC_END_FN();
  1689. }
  1690. BOOL CSH::MonitorRectFromHwnd(HWND hwnd, LPRECT prc)
  1691. {
  1692. #ifndef OS_WINCE
  1693. HMONITOR hMonitor;
  1694. MONITORINFO monInfo;
  1695. #endif
  1696. DC_BEGIN_FN("MonitorRectFromHwnd")
  1697. // default screen size
  1698. prc->top = 0;
  1699. prc->left = 0;
  1700. prc->bottom = GetSystemMetrics(SM_CYSCREEN);
  1701. prc->right = GetSystemMetrics(SM_CXSCREEN);
  1702. #ifndef OS_WINCE
  1703. // for multi monitor, need to find which monitor the client window
  1704. // resides, then get the correct screen size of the corresponding
  1705. // monitor
  1706. if (GetSystemMetrics(SM_CMONITORS))
  1707. {
  1708. hMonitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTONULL);
  1709. if (hMonitor != NULL)
  1710. {
  1711. monInfo.cbSize = sizeof(MONITORINFO);
  1712. if (GetMonitorInfo(hMonitor, &monInfo))
  1713. {
  1714. *prc = monInfo.rcMonitor;
  1715. }
  1716. }
  1717. }
  1718. #endif
  1719. DC_END_FN();
  1720. return TRUE;
  1721. }
  1722. BOOL CSH::MonitorRectFromNearestRect(LPRECT prcNear, LPRECT prcMonitor)
  1723. {
  1724. #ifndef OS_WINCE
  1725. HMONITOR hMonitor;
  1726. MONITORINFO monInfo;
  1727. #endif
  1728. DC_BEGIN_FN("MonitorRectFromHwnd")
  1729. // default screen size
  1730. prcMonitor->top = 0;
  1731. prcMonitor->left = 0;
  1732. prcMonitor->bottom = GetSystemMetrics(SM_CYSCREEN);
  1733. prcMonitor->right = GetSystemMetrics(SM_CXSCREEN);
  1734. // for multi monitor, need to find which monitor the client window
  1735. // resides, then get the correct screen size of the corresponding
  1736. // monitor
  1737. #ifndef OS_WINCE
  1738. if (GetSystemMetrics(SM_CMONITORS))
  1739. {
  1740. hMonitor = MonitorFromRect(prcNear,
  1741. MONITOR_DEFAULTTONEAREST);
  1742. if (hMonitor != NULL)
  1743. {
  1744. monInfo.cbSize = sizeof(MONITORINFO);
  1745. if (GetMonitorInfo(hMonitor, &monInfo))
  1746. {
  1747. *prcMonitor = monInfo.rcMonitor;
  1748. }
  1749. }
  1750. }
  1751. #endif
  1752. DC_END_FN();
  1753. return TRUE;
  1754. }
  1755. LPTSTR CSH::FormatMessageVAList(LPCTSTR pcszFormat, va_list *argList)
  1756. {
  1757. LPTSTR pszOutput;
  1758. if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  1759. pcszFormat,
  1760. 0, 0,
  1761. reinterpret_cast<LPTSTR>(&pszOutput), 0,
  1762. argList) == 0)
  1763. {
  1764. pszOutput = NULL;
  1765. }
  1766. return(pszOutput);
  1767. }
  1768. LPTSTR CSH::FormatMessageVArgs(LPCTSTR pcszFormat, ...)
  1769. {
  1770. LPTSTR pszOutput;
  1771. va_list argList;
  1772. va_start(argList, pcszFormat);
  1773. pszOutput = FormatMessageVAList(pcszFormat, &argList);
  1774. va_end(argList);
  1775. return(pszOutput);
  1776. }
  1777. //
  1778. // Create a hidden file
  1779. //
  1780. BOOL CSH::SH_CreateHiddenFile(LPCTSTR szPath)
  1781. {
  1782. HANDLE hFile;
  1783. BOOL fRet = FALSE;
  1784. DC_BEGIN_FN("SH_CreateHiddenFile");
  1785. hFile = CreateFile( szPath,
  1786. GENERIC_READ | GENERIC_WRITE,
  1787. FILE_SHARE_READ,
  1788. NULL,
  1789. OPEN_ALWAYS, //Creates if !exist
  1790. FILE_ATTRIBUTE_HIDDEN,
  1791. NULL);
  1792. if (INVALID_HANDLE_VALUE != hFile)
  1793. {
  1794. CloseHandle(hFile);
  1795. fRet = TRUE;
  1796. }
  1797. else
  1798. {
  1799. TRC_ERR((TB, _T("CreateFile failed: %s - err:%x"),
  1800. szPath, GetLastError()));
  1801. fRet = FALSE;
  1802. }
  1803. DC_END_FN();
  1804. return fRet;
  1805. }
  1806. BOOL CSH::SH_IsRunningOn9x()
  1807. {
  1808. BOOL fRunningOnWin9x = FALSE;
  1809. DC_BEGIN_FN("SH_IsRunningOn9x");
  1810. fRunningOnWin9x = FALSE;
  1811. OSVERSIONINFO osVersionInfo;
  1812. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1813. //call A version to avoid wrapping
  1814. if(GetVersionEx(&osVersionInfo))
  1815. {
  1816. fRunningOnWin9x = (osVersionInfo.dwPlatformId ==
  1817. VER_PLATFORM_WIN32_WINDOWS);
  1818. }
  1819. else
  1820. {
  1821. fRunningOnWin9x = FALSE;
  1822. TRC_ERR((TB,_T("GetVersionEx failed: %d\n"), GetLastError()));
  1823. }
  1824. DC_END_FN();
  1825. return fRunningOnWin9x;
  1826. }
  1827. //
  1828. // Dynamically load and call the EnableThemeDialogTexture API
  1829. // (since it is not available on all platforms)
  1830. //
  1831. HRESULT CSH::SH_ThemeDialogWindow(HWND hwnd, DWORD dwFlags)
  1832. {
  1833. HRESULT hr = E_NOTIMPL;
  1834. DC_BEGIN_FN("SH_ThemeDialogWindow");
  1835. if (_fFailedToGetThemeDll)
  1836. {
  1837. //
  1838. // If failed once then bail out to avoid repeatedly
  1839. // trying to load theme dll that isn't there
  1840. //
  1841. DC_QUIT;
  1842. }
  1843. if (!_hUxTheme)
  1844. {
  1845. _hUxTheme = (HMODULE)LoadLibrary(_T("uxtheme.dll"));
  1846. if(_hUxTheme)
  1847. {
  1848. _pFnEnableThemeDialogTexture = (PFNEnableThemeDialogTexture)
  1849. #ifndef OS_WINCE
  1850. GetProcAddress( _hUxTheme,
  1851. "EnableThemeDialogTexture");
  1852. #else
  1853. GetProcAddress( _hUxTheme,
  1854. _T("EnableThemeDialogTexture"));
  1855. #endif
  1856. if (NULL == _pFnEnableThemeDialogTexture)
  1857. {
  1858. _fFailedToGetThemeDll = TRUE;
  1859. TRC_ERR((TB,
  1860. _T("Failed to GetProcAddress for EnableThemeDialogTexture")));
  1861. }
  1862. else
  1863. {
  1864. TRC_NRM((TB,_T("Got EnableThemeDialogTexture entry point")));
  1865. }
  1866. }
  1867. else
  1868. {
  1869. _fFailedToGetThemeDll = TRUE;
  1870. TRC_ERR((TB,_T("LoadLibrary failed for uxtheme: 0x%x"),
  1871. GetLastError()));
  1872. }
  1873. }
  1874. if (_pFnEnableThemeDialogTexture)
  1875. {
  1876. hr = _pFnEnableThemeDialogTexture(hwnd, dwFlags);
  1877. if (FAILED(hr)) {
  1878. TRC_ERR((TB,_T("_pFnEnableThemeDialogTexture ret 0x%x\n"), hr));
  1879. }
  1880. }
  1881. DC_EXIT_POINT:
  1882. DC_END_FN();
  1883. return hr;
  1884. }