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.

2328 lines
65 KiB

  1. #include "StdAfx.h"
  2. #include <stddef.h>
  3. #include <objidl.h>
  4. #include <objbase.h>
  5. #include <shlobj.h>
  6. #include <wtsapi32.h>
  7. #include <psapi.h>
  8. // Log file created by "winnt32 /checkupgradeonly"
  9. #define TEXT_UPGRADE_LOG TEXT("%SystemRoot%\\Upgrade.txt")
  10. // Value name in registry to keep track of machine state
  11. #define CLMT_MACHINE_STATE_REG_VALUE TEXT("MachineState")
  12. // Read me file name
  13. #define TEXT_README_FILE TEXT("Readme.txt")
  14. // constants used to determine SKU
  15. #define SKU_SRV 1
  16. #define SKU_ADS 2
  17. #define SKU_DTC 3
  18. // Maximum entries for list of applications running on the system
  19. #define MAX_APP_ENTRIES 100
  20. typedef struct _UPGRADE_LOG_PARAM
  21. {
  22. LPVOID lpText;
  23. size_t cbText;
  24. BOOL fUnicode;
  25. } UPGRADE_LOG_PARAM, *PUPGRADE_LOG_PARAM;
  26. typedef struct _stAppListParam
  27. {
  28. DWORD dwNumEntries;
  29. LPTSTR lpAppName[MAX_APP_ENTRIES];
  30. } APPLIST_PARAM, *PAPPLIST_PARAM;
  31. typedef UINT (WINAPI* PFNGETMODULENAME)(HWND, LPTSTR, UINT);
  32. typedef HMODULE (WINAPI* PFNGETMODULEHANDLE)(LPCTSTR);
  33. typedef struct _GETMODULENAME
  34. {
  35. PFNGETMODULENAME pfn;
  36. PFNGETMODULEHANDLE pfnGetModuleHandle;
  37. TCHAR szfname[MAX_PATH];
  38. TCHAR szUser32[8];
  39. HWND hWnd;
  40. PVOID pvCode;
  41. } GETMODULENAME, *PGETMODULENAME;
  42. BOOL LaunchWinnt32(LPCTSTR);
  43. BOOL AskUserForDotNetCDPath(LPTSTR);
  44. BOOL FindUpgradeLog(VOID);
  45. BOOL IsDotNetWinnt32(LPCTSTR);
  46. INT ShowUpgradeLog(VOID);
  47. BOOL CheckUnsupportComponent(LPVOID, BOOL);
  48. BOOL CALLBACK UpgradeLogDlgProc(HWND, UINT, WPARAM, LPARAM);
  49. HRESULT ReadTextFromFile(LPCTSTR, LPVOID*, size_t*, BOOL*);
  50. BOOL IsOperationOK(DWORD, DWORD, LPDWORD, PUINT);
  51. BOOL CALLBACK EnumWindowProc();
  52. BOOL CALLBACK StartUpDlgProc(HWND, UINT, WPARAM, LPARAM);
  53. BOOL StartProcess(LPCTSTR, LPTSTR, LPCTSTR);
  54. LPCTSTR GetWindowModuleFileNameOnly(HWND hWnd, LPTSTR lpszFile, DWORD cchFile);
  55. //-----------------------------------------------------------------------------
  56. //
  57. // Function: CheckSystemCriteria
  58. //
  59. // Synopsis:
  60. //
  61. // Returns: - Ok the continue the tool
  62. // - Not ok to continue the tools
  63. // - Unexpected error occured
  64. //
  65. // History: 09/14/2002 rerkboos created
  66. //
  67. // Notes: none
  68. //
  69. //-----------------------------------------------------------------------------
  70. BOOL CheckSystemCriteria(VOID)
  71. {
  72. HRESULT hr;
  73. LCID lcid;
  74. OSVERSIONINFOEX osviex;
  75. if (IsNEC98())
  76. {
  77. DoMessageBox(GetConsoleWindow(), IDS_NEC98, IDS_MAIN_TITLE, MB_OK);
  78. return FALSE;
  79. }
  80. if (IsIA64())
  81. {
  82. DoMessageBox(GetConsoleWindow(), IDS_IA64, IDS_MAIN_TITLE, MB_OK);
  83. return FALSE;
  84. }
  85. if (g_dwRunningStatus == CLMT_DOMIG)
  86. {
  87. if (!IsNT5())
  88. {
  89. DoMessageBox(GetConsoleWindow(), IDS_NT5, IDS_MAIN_TITLE, MB_OK);
  90. return FALSE;
  91. }
  92. if (IsDomainController())
  93. {
  94. // If this machine is a domain controller, we need W2K SP2
  95. ZeroMemory(&osviex, sizeof(OSVERSIONINFOEX));
  96. osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  97. GetVersionEx((LPOSVERSIONINFO) &osviex);
  98. if (osviex.wServicePackMajor < 2)
  99. {
  100. DoMessageBox(GetConsoleWindow(), IDS_NT5SP2, IDS_MAIN_TITLE, MB_OK);
  101. return FALSE;
  102. }
  103. //
  104. // Also pop up the message asking admin to take machine
  105. // off the network if it is in DC replication servers
  106. //
  107. DoMessageBox(GetConsoleWindow(),
  108. IDS_DC_REPLICA_OFFLINE,
  109. IDS_MAIN_TITLE,
  110. MB_OK);
  111. }
  112. }
  113. else if (g_dwRunningStatus == CLMT_CLEANUP_AFTER_UPGRADE)
  114. {
  115. if (!IsDotNet())
  116. {
  117. return FALSE;
  118. }
  119. }
  120. else
  121. {
  122. // noop
  123. }
  124. if (IsOnTSClient())
  125. {
  126. DoMessageBox(GetConsoleWindow(), IDS_ON_TS_CLIENT, IDS_MAIN_TITLE, MB_OK);
  127. return FALSE;
  128. }
  129. if (IsOtherSessionOnTS())
  130. {
  131. DoMessageBox(GetConsoleWindow(), IDS_TS_CLOSE_SESSION, IDS_MAIN_TITLE, MB_OK);
  132. return FALSE;
  133. }
  134. hr = GetSavedInstallLocale(&lcid);
  135. if (HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND)
  136. {
  137. hr = SaveInstallLocale();
  138. if (FAILED(hr))
  139. {
  140. return FALSE;
  141. }
  142. }
  143. return TRUE;
  144. }
  145. BOOL IsOneInstance(VOID)
  146. {
  147. HRESULT hr;
  148. TCHAR szGlobalText[MAX_PATH];
  149. hr = StringCchPrintf(szGlobalText,
  150. ARRAYSIZE(szGlobalText),
  151. TEXT("Global\\%s"),
  152. TEXT("CLMT Is Running"));
  153. if (FAILED(hr))
  154. {
  155. return FALSE;
  156. }
  157. g_hMutex = CreateMutex(NULL, FALSE, szGlobalText);
  158. if ((g_hMutex == NULL) && (GetLastError() == ERROR_PATH_NOT_FOUND))
  159. {
  160. g_hMutex = CreateMutex(NULL, FALSE, TEXT("CLMT Is Running"));
  161. if (g_hMutex == NULL)
  162. {
  163. //
  164. // An error (like out of memory) has occurred.
  165. // Bail now.
  166. //
  167. DoMessageBox(GetConsoleWindow(), IDS_OUT_OF_MEMORY, IDS_MAIN_TITLE, MB_OK);
  168. return FALSE;
  169. }
  170. }
  171. //
  172. // Make sure we are the only process with a handle to our named mutex.
  173. //
  174. if ((g_hMutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS))
  175. {
  176. DoMessageBox(GetConsoleWindow(), IDS_ALREADY_RUNNING, IDS_MAIN_TITLE, MB_OK);
  177. return FALSE;
  178. }
  179. return TRUE;
  180. }
  181. BOOL CheckAdminPrivilege(VOID)
  182. {
  183. BOOL bIsAdmin;
  184. BOOL bRet = FALSE;
  185. if (!IsAdmin())
  186. {
  187. if (g_dwRunningStatus == CLMT_DOMIG)
  188. {
  189. DoMessageBox(GetConsoleWindow(), IDS_ADMIN, IDS_MAIN_TITLE, MB_OK);
  190. }
  191. else if ( (g_dwRunningStatus == CLMT_CURE_PROGRAM_FILES)
  192. || (g_dwRunningStatus == CLMT_CURE_ALL) )
  193. {
  194. DoMessageBox(GetConsoleWindow(), IDS_ADMIN_RELOGON, IDS_MAIN_TITLE, MB_OK);
  195. }
  196. else if (g_dwRunningStatus == CLMT_CLEANUP_AFTER_UPGRADE)
  197. {
  198. DoMessageBox(GetConsoleWindow(), IDS_ADMIN_LOGON_DOTNET, IDS_MAIN_TITLE, MB_OK);
  199. }
  200. return FALSE;
  201. }
  202. if(!DoesUserHavePrivilege(SE_SHUTDOWN_NAME)
  203. || !DoesUserHavePrivilege(SE_BACKUP_NAME)
  204. || !DoesUserHavePrivilege(SE_RESTORE_NAME)
  205. || !DoesUserHavePrivilege(SE_SYSTEM_ENVIRONMENT_NAME))
  206. {
  207. DoMessageBox(GetConsoleWindow(), IDS_ADMIN, IDS_MAIN_TITLE, MB_OK);
  208. return FALSE;
  209. }
  210. if(!EnablePrivilege(SE_SHUTDOWN_NAME,TRUE)
  211. || !EnablePrivilege(SE_BACKUP_NAME,TRUE)
  212. || !EnablePrivilege(SE_RESTORE_NAME,TRUE)
  213. || !EnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE))
  214. {
  215. DoMessageBox(GetConsoleWindow(), IDS_ADMIN, IDS_MAIN_TITLE, MB_OK);
  216. return FALSE;
  217. }
  218. return TRUE;
  219. }
  220. //-----------------------------------------------------------------------------
  221. //
  222. // Function: CheckCLMTStatus
  223. //
  224. // Synopsis: Check the machine status and CLMT running mode.
  225. //
  226. // Returns: S_OK - Ok the continue the tool
  227. // S_FALSE - Not ok to continue the tools
  228. // Else - Unexpected error occured
  229. //
  230. // History: 03/12/2002 rerkboos created
  231. // 07/09/2002 rerkboos modified
  232. //
  233. // Notes: none
  234. //
  235. //-----------------------------------------------------------------------------
  236. HRESULT CheckCLMTStatus(
  237. LPDWORD lpdwCurrentState, // Current machine state before the operation
  238. LPDWORD lpdwNextState, // Next state if the operation finish successfully
  239. PUINT lpuResourceID // Resource ID of the error string
  240. )
  241. {
  242. HRESULT hr;
  243. BOOL bIsOK;
  244. if (lpdwCurrentState == NULL || lpdwNextState == NULL)
  245. {
  246. return E_INVALIDARG;
  247. }
  248. // Get the current machine state
  249. hr = CLMTGetMachineState(lpdwCurrentState);
  250. if (SUCCEEDED(hr))
  251. {
  252. bIsOK = IsOperationOK(*lpdwCurrentState,
  253. g_dwRunningStatus,
  254. lpdwNextState,
  255. lpuResourceID);
  256. hr = (bIsOK == TRUE ? S_OK : S_FALSE);
  257. }
  258. return hr;
  259. }
  260. //-----------------------------------------------------------------------------
  261. //
  262. // Function: IsOperationOK
  263. //
  264. // Synopsis: Verify that the current operation is okay to perform on current
  265. // state of the system.
  266. //
  267. // Returns: TRUE - ok to perform operation
  268. // FALSE - otherwise
  269. //
  270. // History: 03/12/2002 rerkboos created
  271. //
  272. // Notes: none
  273. //
  274. //-----------------------------------------------------------------------------
  275. BOOL IsOperationOK(
  276. DWORD dwCurrentState, // Current state of the system
  277. DWORD dwAction, // Action to perform
  278. LPDWORD lpdwNextState, // Next state after performing the action
  279. LPUINT lpuResourceID // Resource ID for the error message
  280. )
  281. {
  282. BOOL bRet = FALSE;
  283. int i;
  284. struct CLMT_STATE_MACHINE
  285. {
  286. DWORD dwCurrentState;
  287. DWORD dwAction;
  288. DWORD dwNextState;
  289. };
  290. const struct CLMT_STATE_MACHINE smCLMT[] =
  291. {
  292. CLMT_STATE_ORIGINAL, CLMT_DOMIG, CLMT_STATE_MIGRATION_DONE,
  293. CLMT_STATE_MIGRATION_DONE, CLMT_UNDO_PROGRAM_FILES, CLMT_STATE_PROGRAMFILES_UNDONE,
  294. CLMT_STATE_MIGRATION_DONE, CLMT_UNDO_APPLICATION_DATA, CLMT_STATE_APPDATA_UNDONE,
  295. CLMT_STATE_MIGRATION_DONE, CLMT_UNDO_ALL, CLMT_STATE_ORIGINAL,
  296. CLMT_STATE_MIGRATION_DONE, CLMT_CLEANUP_AFTER_UPGRADE, CLMT_STATE_FINISH,
  297. CLMT_STATE_MIGRATION_DONE, CLMT_CURE_PROGRAM_FILES, CLMT_STATE_PROGRAMFILES_CURED,
  298. CLMT_STATE_MIGRATION_DONE, CLMT_CURE_AND_CLEANUP, CLMT_STATE_MIGRATION_DONE,
  299. CLMT_STATE_MIGRATION_DONE, CLMT_CURE_ALL, CLMT_STATE_PROGRAMFILES_CURED,
  300. CLMT_STATE_PROGRAMFILES_CURED, CLMT_CURE_ALL, CLMT_STATE_PROGRAMFILES_CURED,
  301. CLMT_STATE_PROGRAMFILES_CURED, CLMT_CLEANUP_AFTER_UPGRADE, CLMT_STATE_FINISH,
  302. CLMT_STATE_PROGRAMFILES_CURED, CLMT_CURE_AND_CLEANUP, CLMT_STATE_FINISH,
  303. CLMT_STATE_PROGRAMFILES_UNDONE, CLMT_UNDO_APPLICATION_DATA, CLMT_STATE_ORIGINAL,
  304. CLMT_STATE_PROGRAMFILES_UNDONE, CLMT_UNDO_ALL, CLMT_STATE_ORIGINAL,
  305. CLMT_STATE_PROGRAMFILES_UNDONE, CLMT_DOMIG, CLMT_STATE_MIGRATION_DONE,
  306. CLMT_STATE_APPDATA_UNDONE, CLMT_UNDO_PROGRAM_FILES, CLMT_STATE_ORIGINAL,
  307. CLMT_STATE_APPDATA_UNDONE, CLMT_UNDO_ALL, CLMT_STATE_ORIGINAL,
  308. CLMT_STATE_APPDATA_UNDONE, CLMT_DOMIG, CLMT_STATE_MIGRATION_DONE,
  309. CLMT_STATE_PROGRAMFILES_CURED, CLMT_CURE_PROGRAM_FILES, CLMT_STATE_PROGRAMFILES_CURED,
  310. CLMT_STATE_FINISH, CLMT_CURE_PROGRAM_FILES, CLMT_STATE_FINISH,
  311. CLMT_STATE_FINISH, CLMT_CURE_ALL, CLMT_STATE_FINISH,
  312. 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
  313. };
  314. for (i = 0 ; smCLMT[i].dwCurrentState != 0xFFFFFFFF ; i++)
  315. {
  316. if (smCLMT[i].dwCurrentState == dwCurrentState)
  317. {
  318. if (smCLMT[i].dwAction == dwAction)
  319. {
  320. *lpdwNextState = smCLMT[i].dwNextState;
  321. bRet = TRUE;
  322. }
  323. }
  324. }
  325. if (!bRet)
  326. {
  327. switch (dwCurrentState)
  328. {
  329. case CLMT_STATE_ORIGINAL:
  330. *lpuResourceID = IDS_BAD_OPERATION_ORIGINAL;
  331. break;
  332. case CLMT_STATE_MIGRATION_DONE:
  333. case CLMT_STATE_PROGRAMFILES_CURED:
  334. *lpuResourceID = IDS_BAD_OPERATION_MIGDONE;
  335. break;
  336. case CLMT_STATE_FINISH:
  337. *lpuResourceID = IDS_BAD_OPERATION_FINISH;
  338. break;
  339. default:
  340. *lpuResourceID = IDS_OPERATION_NOT_LEGAL;
  341. }
  342. }
  343. return bRet;
  344. }
  345. //-----------------------------------------------------------------------------
  346. //
  347. // Function: CLMTSetMachineState
  348. //
  349. // Synopsis: Set the machine state to CLMT registry
  350. //
  351. // Returns: S_OK if value is successfully saved in registry
  352. //
  353. // History: 03/13/2002 rerkboos created
  354. //
  355. // Notes: none
  356. //
  357. //-----------------------------------------------------------------------------
  358. HRESULT CLMTSetMachineState(
  359. DWORD dwMachineState // Machine state
  360. )
  361. {
  362. LONG lStatus;
  363. lStatus = SetRegistryValue(HKEY_LOCAL_MACHINE,
  364. CLMT_REGROOT,
  365. CLMT_MACHINE_STATE_REG_VALUE,
  366. REG_DWORD,
  367. (LPBYTE) &dwMachineState,
  368. sizeof(dwMachineState));
  369. return HRESULT_FROM_WIN32(lStatus);
  370. }
  371. //-----------------------------------------------------------------------------
  372. //
  373. // Function: CLMTGetMachineState
  374. //
  375. // Synopsis: Get the machine state from CLMT registry key.
  376. // If the key does not exist, this function will also set the value
  377. // of reg key to ORIGINAL state.
  378. //
  379. // Returns: S_OK if value is successfully retrieved in registry
  380. //
  381. // History: 03/13/2002 rerkboos created
  382. //
  383. // Notes: none
  384. //
  385. //-----------------------------------------------------------------------------
  386. HRESULT CLMTGetMachineState(
  387. LPDWORD lpdwMachineState
  388. )
  389. {
  390. HRESULT hr;
  391. LONG lStatus;
  392. DWORD dwSize;
  393. if (lpdwMachineState == NULL)
  394. {
  395. return E_INVALIDARG;
  396. }
  397. dwSize = sizeof(DWORD);
  398. lStatus = GetRegistryValue(HKEY_LOCAL_MACHINE,
  399. CLMT_REGROOT,
  400. CLMT_MACHINE_STATE_REG_VALUE,
  401. (LPBYTE) lpdwMachineState,
  402. &dwSize);
  403. if (lStatus == ERROR_FILE_NOT_FOUND)
  404. {
  405. // First time running the tool, we don't have the value in registry yet.
  406. // Set the machine state to ORIGINAL
  407. *lpdwMachineState = CLMT_STATE_ORIGINAL;
  408. hr = CLMTSetMachineState(CLMT_STATE_ORIGINAL);
  409. }
  410. else
  411. {
  412. hr = HRESULT_FROM_WIN32(lStatus);
  413. }
  414. return hr;
  415. }
  416. //-----------------------------------------------------------------------------
  417. //
  418. // Function: IsUserOKWithCheckUpgrade
  419. //
  420. // Synopsis:
  421. //
  422. // Returns:
  423. //
  424. // History: 02/07/2002 rerkboos created
  425. //
  426. // Notes: none
  427. //
  428. //-----------------------------------------------------------------------------
  429. BOOL IsUserOKWithCheckUpgrade(VOID)
  430. {
  431. TCHAR szI386Path[MAX_PATH];
  432. BOOL fRet = FALSE;
  433. DoMessageBox(GetConsoleWindow(), IDS_ASKFORWINNT32, IDS_MAIN_TITLE, MB_OK);
  434. // Ask user for path to winnt32.exe
  435. if (AskUserForDotNetCDPath(szI386Path))
  436. {
  437. // Launch Winnt32.exe with checkupgrade switch
  438. if (LaunchWinnt32(szI386Path))
  439. {
  440. // Show upgrade.txt to user, ask them to uninstall
  441. // incompatible components before running CLMT
  442. if (FindUpgradeLog())
  443. {
  444. if (ShowUpgradeLog() == ID_CONTINUE)
  445. {
  446. fRet = TRUE;
  447. }
  448. else
  449. {
  450. DoMessageBox(GetConsoleWindow(), IDS_WINNT32_CANCEL, IDS_MAIN_TITLE, MB_OK);
  451. DPF(dlError, TEXT("User choose to stop the process"));
  452. }
  453. }
  454. else
  455. {
  456. DPF(dlError, TEXT("Upgrade.txt not found"));
  457. }
  458. }
  459. else
  460. {
  461. DPF(dlError, TEXT("Unable to launch Winnt32.exe"));
  462. }
  463. }
  464. else
  465. {
  466. DPF(dlError, TEXT("User does not supply the path of Winnt32.exe"));
  467. }
  468. return fRet;
  469. }
  470. //-----------------------------------------------------------------------------
  471. //
  472. // Function: FindUpgradeLog
  473. //
  474. // Synopsis:
  475. //
  476. // Returns:
  477. //
  478. // History: 02/07/2002 rerkboos created
  479. //
  480. // Notes: none
  481. //
  482. //-----------------------------------------------------------------------------
  483. BOOL FindUpgradeLog(VOID)
  484. {
  485. const TCHAR szUpgradeLog[] = TEXT("%systemroot%\\Upgrade.txt");
  486. TCHAR szExpUpgradeLog[MAX_PATH];
  487. BOOL fRet = FALSE;
  488. SYSTEMTIME stUTC, stNow;
  489. WIN32_FILE_ATTRIBUTE_DATA attFileAttr;
  490. if ( ExpandEnvironmentStrings(szUpgradeLog, szExpUpgradeLog, MAX_PATH) )
  491. {
  492. if ( GetFileAttributesEx(szExpUpgradeLog, GetFileExInfoStandard, &attFileAttr) )
  493. {
  494. // Upgrade.txt exists, check if it's updated today or not
  495. if ( FileTimeToSystemTime(&attFileAttr.ftLastWriteTime, &stUTC) )
  496. {
  497. GetSystemTime(&stNow);
  498. if (stUTC.wYear == stNow.wYear &&
  499. stUTC.wMonth == stNow.wMonth &&
  500. stUTC.wDay == stNow.wDay)
  501. {
  502. fRet = TRUE;
  503. }
  504. }
  505. }
  506. }
  507. return fRet;
  508. }
  509. //-----------------------------------------------------------------------------
  510. //
  511. // Function: LaunchWinnt32
  512. //
  513. // Synopsis: Launch Winnt32.exe with "checkupgradeonly" switch
  514. //
  515. // Returns: TRUE if winnt32.exe is executed successfully
  516. // FALSE otherwise
  517. //
  518. // History: 02/07/2002 rerkboos created
  519. // 05/20/2002 rerkboos change parameter to receive CD path
  520. //
  521. // Notes: none
  522. //
  523. //-----------------------------------------------------------------------------
  524. BOOL LaunchWinnt32(
  525. LPCTSTR lpCDPath // Path to Server 2003 CD
  526. )
  527. {
  528. TCHAR szWinnt32[MAX_PATH];
  529. TCHAR szI386Path[MAX_PATH];
  530. BOOL bRet = FALSE;
  531. HRESULT hr;
  532. STARTUPINFO siWinnt32;
  533. PROCESS_INFORMATION piWinnt32;
  534. TCHAR szCmdLine[] = TEXT("Winnt32.exe /#u:anylocale /checkupgradeonly /unattend /dudisable");
  535. if (lpCDPath == NULL)
  536. {
  537. return FALSE;
  538. }
  539. // Construct absolute path to Winnt32.exe
  540. hr = StringCchCopy(szI386Path, ARRAYSIZE(szI386Path), lpCDPath);
  541. if (SUCCEEDED(hr))
  542. {
  543. ConcatenatePaths(szI386Path, TEXT("i386"), ARRAYSIZE(szI386Path));
  544. hr = StringCchCopy(szWinnt32, ARRAYSIZE(szWinnt32), szI386Path);
  545. if (SUCCEEDED(hr))
  546. {
  547. ConcatenatePaths(szWinnt32, TEXT("winnt32.exe"), ARRAYSIZE(szWinnt32));
  548. }
  549. }
  550. if ( IsDotNetWinnt32(szWinnt32) )
  551. {
  552. ZeroMemory(&siWinnt32, sizeof(STARTUPINFO));
  553. siWinnt32.cb = sizeof(STARTUPINFO);
  554. // CreateProcess call conforms to security guideline
  555. bRet = CreateProcess(szWinnt32,
  556. szCmdLine,
  557. NULL,
  558. NULL,
  559. FALSE,
  560. NORMAL_PRIORITY_CLASS,
  561. NULL,
  562. szI386Path,
  563. &siWinnt32,
  564. &piWinnt32);
  565. if (bRet)
  566. {
  567. // Wait until winnt32.exe finished before return back to CLM tool
  568. WaitForSingleObject(piWinnt32.hProcess, INFINITE);
  569. CloseHandle(piWinnt32.hProcess);
  570. CloseHandle(piWinnt32.hThread);
  571. }
  572. }
  573. return bRet;
  574. }
  575. //-----------------------------------------------------------------------------
  576. //
  577. // Function: AskUserForDotNetCDPath
  578. //
  579. // Synopsis: Ask user to supply the path to Server 2003 CD
  580. //
  581. // Returns: TRUE if the path is valid
  582. // FALSE otherwise
  583. //
  584. // History: 02/07/2002 rerkboos created
  585. // 05/20/2002 rerkboos check for Server 2003 SRV/ADS CD
  586. // 06/10/2002 rerkboos check for Server 2003 DTC cd
  587. //
  588. // Notes: none
  589. //
  590. //-----------------------------------------------------------------------------
  591. BOOL AskUserForDotNetCDPath(
  592. LPTSTR lpCDPath // Buffer to store path to CD
  593. )
  594. {
  595. HRESULT hr;
  596. BOOL fRet = FALSE;
  597. BOOL bDoBrowseDialog;
  598. LPMALLOC piMalloc;
  599. INT iRet;
  600. DWORD dwSKU;
  601. OSVERSIONINFOEX osviex;
  602. if (lpCDPath == NULL)
  603. {
  604. return FALSE;
  605. }
  606. //
  607. // Check the SKU of current system
  608. //
  609. osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  610. GetVersionEx((LPOSVERSIONINFO) &osviex);
  611. if (osviex.wProductType == VER_NT_DOMAIN_CONTROLLER
  612. || osviex.wProductType == VER_NT_SERVER)
  613. {
  614. dwSKU = SKU_SRV;
  615. if (osviex.wSuiteMask & VER_SUITE_ENTERPRISE)
  616. {
  617. dwSKU = SKU_ADS;
  618. }
  619. if (osviex.wSuiteMask & VER_SUITE_DATACENTER)
  620. {
  621. dwSKU = SKU_DTC;
  622. }
  623. }
  624. hr = SHGetMalloc(&piMalloc);
  625. if (SUCCEEDED(hr))
  626. {
  627. BROWSEINFO biCDPath;
  628. LPITEMIDLIST lpiList;
  629. ZeroMemory(&biCDPath, sizeof(BROWSEINFO));
  630. biCDPath.hwndOwner = NULL;
  631. biCDPath.lpszTitle = TEXT("Please supply the Windows Server 2003 CD path");
  632. biCDPath.pszDisplayName = lpCDPath;
  633. biCDPath.ulFlags = BIF_EDITBOX |
  634. BIF_NONEWFOLDERBUTTON |
  635. BIF_RETURNONLYFSDIRS;
  636. bDoBrowseDialog = TRUE;
  637. while (bDoBrowseDialog)
  638. {
  639. // Show the Browse dialog
  640. lpiList = SHBrowseForFolder(&biCDPath);
  641. if (lpiList == NULL)
  642. {
  643. //
  644. // if lpiList == NULL, user click Cancel in browse dialog
  645. //
  646. iRet = MessageBox(GetConsoleWindow(),
  647. TEXT("You did not supply the path to Windows Server 2003 CD.\nDo you want to continue running CLMT?"),
  648. TEXT("CLMT"),
  649. MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2);
  650. if (iRet != IDYES)
  651. {
  652. // User choose not to run CLMT any further
  653. bDoBrowseDialog = FALSE;
  654. }
  655. }
  656. else
  657. {
  658. //
  659. // User supply path in Browse dialog,
  660. // check whether it is valid Server 2003 SRV/ADS CD or not
  661. //
  662. if (SHGetPathFromIDListW(lpiList, lpCDPath))
  663. {
  664. LPTSTR lpFile;
  665. DWORD cchFile;
  666. DWORD dwAttr;
  667. cchFile = lstrlen(lpCDPath) + MAX_PATH;
  668. lpFile = MEMALLOC(cchFile * sizeof(TCHAR));
  669. if (lpFile)
  670. {
  671. switch (dwSKU)
  672. {
  673. case SKU_SRV:
  674. // Check if it is SRV CD or not
  675. hr = StringCchCopy(lpFile, cchFile, lpCDPath);
  676. ConcatenatePaths(lpFile, TEXT("win51is"), cchFile);
  677. dwAttr = GetFileAttributes(lpFile);
  678. if (dwAttr != INVALID_FILE_ATTRIBUTES)
  679. {
  680. // This is SRV CD
  681. fRet = TRUE;
  682. bDoBrowseDialog = FALSE;
  683. }
  684. else
  685. {
  686. // We also allow W2K SRV -> Server 2003 ADS
  687. hr = StringCchCopy(lpFile, cchFile, lpCDPath);
  688. ConcatenatePaths(lpFile, TEXT("win51ia"), cchFile);
  689. dwAttr = GetFileAttributes(lpFile);
  690. if (dwAttr != INVALID_FILE_ATTRIBUTES)
  691. {
  692. // This is ADS CD
  693. fRet = TRUE;
  694. bDoBrowseDialog = FALSE;
  695. }
  696. }
  697. break;
  698. case SKU_ADS:
  699. // Check if it is ADS CD or not
  700. hr = StringCchCopy(lpFile, cchFile, lpCDPath);
  701. ConcatenatePaths(lpFile, TEXT("win51ia"), cchFile);
  702. dwAttr = GetFileAttributes(lpFile);
  703. if (dwAttr != INVALID_FILE_ATTRIBUTES)
  704. {
  705. // This is ADS CD
  706. fRet = TRUE;
  707. bDoBrowseDialog = FALSE;
  708. }
  709. break;
  710. case SKU_DTC:
  711. // Check if it is DTC CD or not
  712. hr = StringCchCopy(lpFile, cchFile, lpCDPath);
  713. ConcatenatePaths(lpFile, TEXT("win51id"), cchFile);
  714. dwAttr = GetFileAttributes(lpFile);
  715. if (dwAttr != INVALID_FILE_ATTRIBUTES)
  716. {
  717. // This is DTC CD
  718. fRet = TRUE;
  719. bDoBrowseDialog = FALSE;
  720. }
  721. break;
  722. default:
  723. fRet = FALSE;
  724. bDoBrowseDialog = TRUE;
  725. }
  726. if (!fRet)
  727. {
  728. TCHAR szErrorMsg[512];
  729. INT iRead;
  730. iRead = LoadString(GetModuleHandle(NULL),
  731. IDS_WRONG_CD,
  732. szErrorMsg,
  733. ARRAYSIZE(szErrorMsg));
  734. if (iRead > 0)
  735. {
  736. MessageBox(GetConsoleWindow(),
  737. szErrorMsg,
  738. TEXT("CLMT"),
  739. MB_OK);
  740. }
  741. }
  742. MEMFREE(lpFile);
  743. }
  744. }
  745. }
  746. }
  747. if (lpiList)
  748. {
  749. IMalloc_Free(piMalloc, lpiList);
  750. }
  751. IMalloc_Release(piMalloc);
  752. }
  753. return fRet;
  754. }
  755. //-----------------------------------------------------------------------------
  756. //
  757. // Function: IsDotNetWinnt32
  758. //
  759. // Synopsis: Check if the specified path is Server 2003 family CD
  760. // lpWinnt32 contains absolute path with winnt32.exe
  761. //
  762. // Returns: TRUE if it is Server 2003 winnt32,
  763. // FALSE otherwise
  764. //
  765. // History: 02/07/2002 rerkboos created
  766. //
  767. // Notes: none
  768. //
  769. //-----------------------------------------------------------------------------
  770. BOOL IsDotNetWinnt32(
  771. LPCTSTR lpWinnt32 // Absolute path to Winnt32.exe
  772. )
  773. {
  774. BOOL fRet = FALSE;
  775. LPVOID lpBuffer;
  776. DWORD cbBuffer;
  777. UINT cbFileInfo;
  778. VS_FIXEDFILEINFO* pFileInfo;
  779. if (lpWinnt32 == NULL)
  780. {
  781. return FALSE;
  782. }
  783. // Get the size needed to allocate buffer
  784. cbBuffer = GetFileVersionInfoSize((LPTSTR) lpWinnt32, NULL);
  785. if (cbBuffer > 0)
  786. {
  787. lpBuffer = MEMALLOC(cbBuffer);
  788. if (lpBuffer)
  789. {
  790. // Get the version info of user's specified winnt32.exe
  791. if (GetFileVersionInfo((LPTSTR) lpWinnt32, 0, cbBuffer, lpBuffer))
  792. {
  793. if (VerQueryValue(lpBuffer,
  794. TEXT("\\"),
  795. (LPVOID*) &pFileInfo,
  796. &cbFileInfo))
  797. {
  798. // Server 2003 Family version is 5.2
  799. if (pFileInfo->dwFileVersionMS == 0x00050002)
  800. {
  801. fRet = TRUE;
  802. }
  803. }
  804. }
  805. MEMFREE(lpBuffer);
  806. }
  807. }
  808. return fRet;
  809. }
  810. //-----------------------------------------------------------------------------
  811. //
  812. // Function: ShowUpgradeLog
  813. //
  814. // Synopsis: Display the content of %SystemRoot%\Upgrade.txt
  815. //
  816. // Returns: User selection to Stop or Continue operation from dialog box
  817. //
  818. // History: 02/07/2002 rerkboos created
  819. //
  820. // Notes: none
  821. //
  822. //-----------------------------------------------------------------------------
  823. INT ShowUpgradeLog(VOID)
  824. {
  825. HRESULT hr;
  826. BOOL fRet;
  827. HMODULE hExe;
  828. LPTSTR lpBuffer;
  829. size_t cchBuffer;
  830. TCHAR szUpgradeLog[MAX_PATH];
  831. INT_PTR nRet = 0;
  832. UPGRADE_LOG_PARAM lParam;
  833. // Get the absolute path name for upgrade.txt
  834. if ( !ExpandEnvironmentStrings(TEXT_UPGRADE_LOG, szUpgradeLog, MAX_PATH) )
  835. {
  836. return 0;
  837. }
  838. // Read content of upgrade.txt
  839. // Caller needs to free the buffer if function succeeded
  840. hr = ReadTextFromFile(szUpgradeLog,
  841. &lParam.lpText,
  842. &lParam.cbText,
  843. &lParam.fUnicode);
  844. if ( SUCCEEDED(hr) )
  845. {
  846. hExe = GetModuleHandle(NULL);
  847. // Display content of Upgrade.txt in modal dialog
  848. // The dialog will ask user to continue or stop operation
  849. nRet = DialogBoxParam(hExe,
  850. MAKEINTRESOURCE(IDD_UPGRADE_LOG_TEXT),
  851. GetConsoleWindow(),
  852. (DLGPROC) UpgradeLogDlgProc,
  853. (LPARAM) &lParam);
  854. MEMFREE(lParam.lpText);
  855. }
  856. return (INT) nRet;
  857. }
  858. //-----------------------------------------------------------------------------
  859. //
  860. // Function: UpgradeLogDlgProc
  861. //
  862. // Synopsis: Dialog box procedure
  863. //
  864. // Returns:
  865. //
  866. // History: 02/07/2002 rerkboos created
  867. //
  868. // Notes: none
  869. //
  870. //-----------------------------------------------------------------------------
  871. BOOL
  872. CALLBACK
  873. UpgradeLogDlgProc(
  874. HWND hwndDlg,
  875. UINT uMsg,
  876. WPARAM wParam,
  877. LPARAM lParam
  878. )
  879. {
  880. BOOL fBlock;
  881. WCHAR wszWarning[512];
  882. switch (uMsg)
  883. {
  884. case WM_INITDIALOG:
  885. // Init the dialog
  886. ShowWindow(hwndDlg, SW_SHOWNORMAL);
  887. // Search for unsupport component in the text context from upgrade.txt
  888. fBlock = CheckUnsupportComponent(
  889. ((PUPGRADE_LOG_PARAM) lParam)->lpText,
  890. ((PUPGRADE_LOG_PARAM) lParam)->fUnicode );
  891. if (fBlock)
  892. {
  893. LoadString(g_hInstDll,
  894. IDS_BLOCKING_WARNING,
  895. wszWarning,
  896. ARRAYSIZE(wszWarning));
  897. SendMessage(GetDlgItem(hwndDlg, ID_CAPTION2),
  898. WM_SETTEXT,
  899. wParam,
  900. (LPARAM) wszWarning);
  901. // Disable 'Continue' button if found the unsupport component
  902. EnableWindow(GetDlgItem(hwndDlg, ID_CONTINUE),
  903. FALSE);
  904. }
  905. else
  906. {
  907. LoadString(g_hInstDll,
  908. IDS_UNLOCALIZED_WARNING,
  909. wszWarning,
  910. ARRAYSIZE(wszWarning));
  911. SendMessage(GetDlgItem(hwndDlg, ID_CAPTION2),
  912. WM_SETTEXT,
  913. wParam,
  914. (LPARAM) wszWarning);
  915. }
  916. // Display text using A or W function depending on type of data
  917. if ( ((PUPGRADE_LOG_PARAM) lParam)->fUnicode )
  918. {
  919. SendMessageW(GetDlgItem(hwndDlg, IDC_TEXT),
  920. WM_SETTEXT,
  921. wParam,
  922. (LPARAM) (((PUPGRADE_LOG_PARAM) lParam)->lpText));
  923. }
  924. else
  925. {
  926. SendMessageA(GetDlgItem(hwndDlg, IDC_TEXT),
  927. WM_SETTEXT,
  928. wParam,
  929. (LPARAM) (((PUPGRADE_LOG_PARAM) lParam)->lpText));
  930. }
  931. SetForegroundWindow(hwndDlg);
  932. break;
  933. case WM_COMMAND:
  934. // Handle command buttons
  935. switch (wParam)
  936. {
  937. case ID_CONTINUE:
  938. EndDialog(hwndDlg, ID_CONTINUE);
  939. break;
  940. case ID_STOP:
  941. EndDialog(hwndDlg, ID_STOP);
  942. break;
  943. }
  944. break;
  945. case WM_CLOSE:
  946. EndDialog(hwndDlg, ID_STOP);
  947. break;
  948. default:
  949. break;
  950. }
  951. return FALSE;
  952. }
  953. //-----------------------------------------------------------------------------
  954. //
  955. // Function: CheckUnsupportComponent
  956. //
  957. // Synopsis: Search for unsupport component in upgrade.txt.
  958. //
  959. // Returns: TRUE if unsupport component is found,
  960. // FALSE otherwise
  961. //
  962. // History: 02/07/2002 rerkboos created
  963. //
  964. // Notes: We determined unsupport component by searching for word
  965. // "must uninstall" in buffer.
  966. //
  967. //-----------------------------------------------------------------------------
  968. BOOL CheckUnsupportComponent(
  969. LPVOID lpBuffer, // Text buffer
  970. BOOL fUnicode // Flag indicate if text is Unicode or ANSI
  971. )
  972. {
  973. BOOL fRet = FALSE;
  974. LPVOID lpStr;
  975. if (fUnicode)
  976. {
  977. lpStr = (LPWSTR) StrStrW((LPCWSTR) lpBuffer, L"must uninstall");
  978. }
  979. else
  980. {
  981. lpStr = (LPSTR) StrStrA((LPCSTR) lpBuffer, "must uninstall");
  982. }
  983. if (lpStr)
  984. {
  985. fRet = TRUE;
  986. }
  987. return fRet;
  988. }
  989. //-----------------------------------------------------------------------------
  990. //
  991. // Function: ReadTextFromFile
  992. //
  993. // Synopsis: Read text from file into buffer
  994. //
  995. // Returns: HRESULT
  996. //
  997. // History: 02/07/2002 rerkboos created
  998. //
  999. // Notes: none
  1000. //
  1001. //-----------------------------------------------------------------------------
  1002. HRESULT ReadTextFromFile(
  1003. LPCTSTR lpTextFile, // Text file name
  1004. LPVOID *lplpText, // Pointer to a newly allocated buffer
  1005. size_t *lpcbText, // Size of allocated buffer in bytes
  1006. BOOL *lpfUnicode // Flag indicates if data is unicode or not (optional)
  1007. )
  1008. {
  1009. HRESULT hr;
  1010. HANDLE hFile;
  1011. DWORD cbRead;
  1012. BOOL fRet = FALSE;
  1013. if (lpTextFile == NULL || lplpText == NULL || lpcbText == NULL)
  1014. {
  1015. return fRet;
  1016. }
  1017. hFile = CreateFile(lpTextFile,
  1018. GENERIC_READ,
  1019. FILE_SHARE_READ,
  1020. NULL,
  1021. OPEN_EXISTING,
  1022. FILE_ATTRIBUTE_NORMAL,
  1023. NULL);
  1024. if (hFile != INVALID_HANDLE_VALUE)
  1025. {
  1026. // Get the size of memory big enough to store text file,
  1027. // plus a null terminator
  1028. *lpcbText = GetFileSize(hFile, NULL) + sizeof(TCHAR);
  1029. *lplpText = MEMALLOC(*lpcbText);
  1030. if (*lplpText != NULL)
  1031. {
  1032. fRet = ReadFile(hFile, *lplpText, *lpcbText, &cbRead, NULL);
  1033. if (fRet)
  1034. {
  1035. // Set the unicode flag if user supplied the pointer
  1036. if (lpfUnicode != NULL)
  1037. {
  1038. *lpfUnicode = IsTextUnicode(*lplpText, cbRead, NULL);
  1039. }
  1040. }
  1041. else
  1042. {
  1043. // Failed to read text file
  1044. MEMFREE(*lplpText);
  1045. *lplpText = NULL;
  1046. *lpcbText = 0;
  1047. }
  1048. }
  1049. else
  1050. {
  1051. // HeapAlloc failed
  1052. *lpcbText = 0;
  1053. }
  1054. CloseHandle(hFile);
  1055. }
  1056. if (fRet)
  1057. {
  1058. hr = S_OK;
  1059. }
  1060. else
  1061. {
  1062. hr = HRESULT_FROM_WIN32(GetLastError());
  1063. }
  1064. return hr;
  1065. }
  1066. //-----------------------------------------------------------------------
  1067. //
  1068. // Function: IsNT5
  1069. //
  1070. // Descrip: Check whether current OS is NT5 (Server class)
  1071. //
  1072. // Returns: BOOL
  1073. //
  1074. // Notes: none
  1075. //
  1076. // History: 09/17/2001 xiaoz created
  1077. // 02/18/2002 rerkboos add code to check more criteria
  1078. // 06/10/2002 rerkboos allow DTC to run
  1079. //
  1080. // Notes: none
  1081. //
  1082. //-----------------------------------------------------------------------
  1083. BOOL IsNT5(VOID)
  1084. {
  1085. OSVERSIONINFOEX osviex;
  1086. ZeroMemory( &osviex,sizeof(OSVERSIONINFOEX) );
  1087. osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1088. if ( GetVersionEx((LPOSVERSIONINFO) &osviex) )
  1089. {
  1090. return ( (osviex.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
  1091. (osviex.dwMajorVersion == 5) &&
  1092. (osviex.dwMinorVersion == 0) &&
  1093. ( (osviex.wSuiteMask & VER_SUITE_ENTERPRISE) ||
  1094. (osviex.wProductType == VER_NT_SERVER) ||
  1095. (osviex.wProductType == VER_NT_DOMAIN_CONTROLLER) ) &&
  1096. (osviex.wProductType != VER_NT_WORKSTATION) );
  1097. }
  1098. return FALSE;
  1099. }
  1100. //-----------------------------------------------------------------------
  1101. //
  1102. // Function: IsDotNet
  1103. //
  1104. // Descrip: Check whether current OS is Windows Server 2003
  1105. //
  1106. // Returns: BOOL
  1107. //
  1108. // Notes: none
  1109. //
  1110. // History: 07/09/2002 rerkboos created
  1111. //
  1112. // Notes: none
  1113. //
  1114. //-----------------------------------------------------------------------
  1115. BOOL IsDotNet(VOID)
  1116. {
  1117. OSVERSIONINFOEX osviex;
  1118. ZeroMemory( &osviex,sizeof(OSVERSIONINFOEX) );
  1119. osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1120. if ( GetVersionEx((LPOSVERSIONINFO) &osviex) )
  1121. {
  1122. return ( (osviex.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
  1123. (osviex.dwMajorVersion == 5) &&
  1124. (osviex.dwMinorVersion == 2) &&
  1125. ( (osviex.wSuiteMask & VER_SUITE_ENTERPRISE) ||
  1126. (osviex.wProductType == VER_NT_SERVER) ||
  1127. (osviex.wProductType == VER_NT_DOMAIN_CONTROLLER) ) &&
  1128. (osviex.wProductType != VER_NT_WORKSTATION) );
  1129. }
  1130. return FALSE;
  1131. }
  1132. //-----------------------------------------------------------------------------
  1133. //
  1134. // Function: IsNEC98
  1135. //
  1136. // Synopsis: Check whether this machine is NEC98 platform or not.
  1137. //
  1138. // Returns: TRUE if it is NEC98 machine, FALSE otherwise
  1139. //
  1140. // History: 02/18/2001 Rerkboos Created
  1141. //
  1142. // Notes: Code is stolen from Winnt32
  1143. //
  1144. //-----------------------------------------------------------------------------
  1145. BOOL IsNEC98(VOID)
  1146. {
  1147. BOOL IsNEC98;
  1148. IsNEC98 = ( (GetKeyboardType(0) == 7) &&
  1149. ((GetKeyboardType(1) & 0xff00) == 0x0d00) );
  1150. return (IsNEC98);
  1151. }
  1152. //-----------------------------------------------------------------------------
  1153. //
  1154. // Function: IsIA64
  1155. //
  1156. // Synopsis: Check whether the program is running on 64-bit machine or not
  1157. //
  1158. // Returns: TRUE if it is running on 64-bit machine, FALSE otherwise
  1159. //
  1160. // History: 02/18/2001 Rerkboos Created
  1161. //
  1162. // Notes: Code is stolen from Winnt32
  1163. //
  1164. //-----------------------------------------------------------------------------
  1165. BOOL IsIA64(VOID)
  1166. {
  1167. ULONG_PTR p;
  1168. NTSTATUS status;
  1169. status = NtQueryInformationProcess(NtCurrentProcess(),
  1170. ProcessWow64Information,
  1171. &p,
  1172. sizeof(p),
  1173. NULL);
  1174. return (NT_SUCCESS(status) && p);
  1175. }
  1176. //-----------------------------------------------------------------------------
  1177. //
  1178. // Function: IsDomainController
  1179. //
  1180. // Synopsis: Check whether the machine is a domain controller or not
  1181. //
  1182. // Returns: BOOL
  1183. //
  1184. // History: 08/13/2002 Rerkboos Created
  1185. //
  1186. // Notes: none
  1187. //
  1188. //-----------------------------------------------------------------------------
  1189. BOOL IsDomainController(VOID)
  1190. {
  1191. HRESULT hr;
  1192. BOOL bIsDC = FALSE;
  1193. TCHAR szDCName[MAX_PATH];
  1194. DWORD cchDCName;
  1195. cchDCName = ARRAYSIZE(szDCName);
  1196. hr = GetDCInfo(&bIsDC, szDCName, &cchDCName);
  1197. return bIsDC;
  1198. }
  1199. //-----------------------------------------------------------------------------
  1200. //
  1201. // Function: IsOnTSClient
  1202. //
  1203. // Synopsis: Check whether the program is running in terminal session or not
  1204. //
  1205. // Returns: TRUE if it is running in terminal session, FALSE otherwise
  1206. //
  1207. // History: 02/18/2001 Rerkboos Created
  1208. //
  1209. // Notes: none
  1210. //
  1211. //-----------------------------------------------------------------------------
  1212. BOOL IsOnTSClient(VOID)
  1213. {
  1214. return GetSystemMetrics(SM_REMOTESESSION);
  1215. }
  1216. //-----------------------------------------------------------------------------
  1217. //
  1218. // Function: IsTSInstalled
  1219. //
  1220. // Synopsis: Check whether Terminal Services is installed
  1221. //
  1222. // Returns: TRUE if TS is installed, FALSE otherwise
  1223. //
  1224. // History: 02/18/2001 Rerkboos Created
  1225. //
  1226. // Notes: none
  1227. //
  1228. //-----------------------------------------------------------------------------
  1229. BOOL IsTSInstalled(VOID)
  1230. {
  1231. ULONGLONG ullConditionMask;
  1232. OSVERSIONINFOEX osviex;
  1233. BOOL fRet = FALSE;
  1234. ullConditionMask = 0;
  1235. ullConditionMask = VerSetConditionMask(ullConditionMask,
  1236. VER_SUITENAME,
  1237. VER_AND);
  1238. ZeroMemory(&osviex, sizeof(osviex));
  1239. osviex.dwOSVersionInfoSize = sizeof(osviex);
  1240. osviex.wSuiteMask = VER_SUITE_TERMINAL;
  1241. fRet = VerifyVersionInfo(&osviex, VER_SUITENAME, ullConditionMask);
  1242. return fRet;
  1243. }
  1244. //-----------------------------------------------------------------------------
  1245. //
  1246. // Function: IsTSConnectionEnabled
  1247. //
  1248. // Synopsis: Check whether the connection to Terminal Services is enabled
  1249. //
  1250. // Returns: TRUE if it is enabled, FALSE otherwise
  1251. //
  1252. // History: 02/18/2001 Rerkboos Created
  1253. //
  1254. // Notes: none
  1255. //
  1256. //-----------------------------------------------------------------------------
  1257. BOOL IsTSConnectionEnabled(VOID)
  1258. {
  1259. HKEY hKey;
  1260. HKEY hConnKey;
  1261. TCHAR szKeyName[MAX_PATH];
  1262. DWORD cchKeyName;
  1263. DWORD dwIndex;
  1264. DWORD dwType;
  1265. DWORD dwfEnableWinStation;
  1266. DWORD cbfEnableWinStation;
  1267. LONG lEnumRet;
  1268. LONG lRet;
  1269. BOOL fRet = FALSE;
  1270. FILETIME ft;
  1271. HRESULT hr;
  1272. cchKeyName = ARRAYSIZE(szKeyName);
  1273. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1274. TEXT_WINSTATION_KEY,
  1275. 0,
  1276. KEY_ENUMERATE_SUB_KEYS,
  1277. &hKey);
  1278. if (ERROR_SUCCESS != lRet)
  1279. {
  1280. return FALSE;
  1281. }
  1282. dwIndex = 0;
  1283. do
  1284. {
  1285. cchKeyName = ARRAYSIZE(szKeyName);
  1286. lEnumRet = RegEnumKeyEx(hKey,
  1287. dwIndex,
  1288. szKeyName,
  1289. &cchKeyName,
  1290. NULL,
  1291. NULL,
  1292. NULL,
  1293. &ft);
  1294. if (ERROR_SUCCESS == lEnumRet)
  1295. {
  1296. // While there is more key to enumerate
  1297. if (CompareString(LOCALE_ENGLISH,
  1298. NORM_IGNORECASE,
  1299. szKeyName,
  1300. -1,
  1301. TEXT("Console"),
  1302. -1)
  1303. != CSTR_EQUAL)
  1304. {
  1305. // Only check for other connection's key, not Console key
  1306. lRet = RegOpenKeyEx(hKey,
  1307. szKeyName,
  1308. 0,
  1309. KEY_READ,
  1310. &hConnKey);
  1311. if (ERROR_SUCCESS != lRet)
  1312. {
  1313. fRet = FALSE;
  1314. break;
  1315. }
  1316. cbfEnableWinStation = sizeof(dwfEnableWinStation);
  1317. lRet = RegQueryValueEx(hConnKey,
  1318. TEXT("fEnableWinStation"),
  1319. NULL,
  1320. &dwType,
  1321. (LPBYTE) &dwfEnableWinStation,
  1322. &cbfEnableWinStation);
  1323. RegCloseKey(hConnKey);
  1324. if (ERROR_SUCCESS == lRet)
  1325. {
  1326. // If there is at lease one of connection have WinStation
  1327. // flag enabled, TS connection can still be made
  1328. if ( dwfEnableWinStation )
  1329. {
  1330. fRet = TRUE;
  1331. break;
  1332. }
  1333. }
  1334. }
  1335. }
  1336. dwIndex++;
  1337. } while(ERROR_SUCCESS == lEnumRet);
  1338. RegCloseKey(hKey);
  1339. return fRet;
  1340. }
  1341. //-----------------------------------------------------------------------------
  1342. //
  1343. // Function: IsTSServiceRunning
  1344. //
  1345. // Synopsis: Check whether the TS service is runnning or not
  1346. //
  1347. // Returns: TRUE if it is running, FALSE otherwise
  1348. //
  1349. // History: 02/18/2001 Rerkboos Created
  1350. //
  1351. // Notes: Stolen from Termsrv test code
  1352. //
  1353. //-----------------------------------------------------------------------------
  1354. BOOL IsTSServiceRunning(VOID)
  1355. {
  1356. BOOL fRet = FALSE;
  1357. SC_HANDLE hServiceController = OpenSCManager(NULL, NULL, GENERIC_READ);
  1358. if (hServiceController)
  1359. {
  1360. SC_HANDLE hTermServ = OpenService(hServiceController,
  1361. TEXT("TermService"),
  1362. SERVICE_QUERY_STATUS);
  1363. if (hTermServ)
  1364. {
  1365. SERVICE_STATUS tTermServStatus;
  1366. if (QueryServiceStatus(hTermServ, &tTermServStatus))
  1367. {
  1368. fRet = (tTermServStatus.dwCurrentState == SERVICE_RUNNING);
  1369. }
  1370. CloseServiceHandle(hTermServ);
  1371. }
  1372. CloseServiceHandle(hServiceController);
  1373. }
  1374. return fRet;
  1375. }
  1376. //-----------------------------------------------------------------------------
  1377. //
  1378. // Function: IsOtherSessionOnTS
  1379. //
  1380. // Synopsis: Check whether there is other TS sessions are connected.
  1381. //
  1382. // Returns: TRUE if there is remote session connected, FALSE otherwise
  1383. //
  1384. // History: 02/18/2001 Rerkboos Created
  1385. // 04/17/2002 Rerkboon Fix bug 558942
  1386. //
  1387. // Notes: none
  1388. //
  1389. //-----------------------------------------------------------------------------
  1390. BOOL IsOtherSessionOnTS(VOID)
  1391. {
  1392. BOOL fRet;
  1393. DWORD dwSessionCount;
  1394. PWTS_SESSION_INFO pwtsSessionInfo;
  1395. fRet = WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE,
  1396. 0,
  1397. 1,
  1398. &pwtsSessionInfo,
  1399. &dwSessionCount);
  1400. if (fRet)
  1401. {
  1402. DWORD i;
  1403. DWORD dwClients = 0;
  1404. for (i = 0 ; i < dwSessionCount ; i++)
  1405. {
  1406. // Check to see how many clients connect to TS server
  1407. if (pwtsSessionInfo[i].State != WTSListen
  1408. && pwtsSessionInfo[i].State != WTSIdle
  1409. && pwtsSessionInfo[i].State != WTSReset
  1410. && pwtsSessionInfo[i].State != WTSDown
  1411. && pwtsSessionInfo[i].State != WTSInit)
  1412. {
  1413. dwClients++;
  1414. }
  1415. }
  1416. fRet = (dwClients > 1 ? TRUE : FALSE);
  1417. // BUG 558942: free the memory
  1418. WTSFreeMemory(pwtsSessionInfo);
  1419. }
  1420. return fRet;
  1421. }
  1422. #define TS_POLICY_SUB_TREE TEXT("Software\\Policies\\Microsoft\\Windows NT\\Terminal Services")
  1423. #define POLICY_DENY_TS_CONNECTIONS TEXT("fDenyTSConnections")
  1424. #define APPLICATION_NAME TEXT("Winlogon")
  1425. #define WINSTATIONS_DISABLED TEXT("WinStationsDisabled")
  1426. HRESULT DisableWinstations(
  1427. DWORD dwDisabled,
  1428. LPDWORD lpdwPrevStatus
  1429. )
  1430. {
  1431. HRESULT hr = S_OK;
  1432. LONG lRet;
  1433. BOOL bRet;
  1434. BOOL bPolicyOK;
  1435. DWORD fDenyTSConnections;
  1436. DWORD cbfDenyTSConnections;
  1437. TCHAR szCurrentState[2];
  1438. LPTSTR lpStopString;
  1439. if (IsTSServiceRunning())
  1440. {
  1441. //
  1442. // Get the current state of WinStations
  1443. //
  1444. if (lpdwPrevStatus)
  1445. {
  1446. GetProfileString(APPLICATION_NAME,
  1447. WINSTATIONS_DISABLED,
  1448. TEXT("0"),
  1449. szCurrentState,
  1450. ARRAYSIZE(szCurrentState));
  1451. *lpdwPrevStatus = _tcstoul(szCurrentState, &lpStopString, 10);
  1452. }
  1453. //
  1454. // Check if group policy has thrown the big switch, if so, inform and refuse any changes
  1455. //
  1456. fDenyTSConnections = 0;
  1457. cbfDenyTSConnections = sizeof(fDenyTSConnections);
  1458. lRet = GetRegistryValue(HKEY_LOCAL_MACHINE,
  1459. TS_POLICY_SUB_TREE,
  1460. POLICY_DENY_TS_CONNECTIONS,
  1461. (LPBYTE) &fDenyTSConnections,
  1462. &cbfDenyTSConnections);
  1463. if (lRet == ERROR_SUCCESS)
  1464. {
  1465. if (fDenyTSConnections)
  1466. {
  1467. // Machine policy deny TS connection
  1468. bPolicyOK = FALSE;
  1469. }
  1470. else
  1471. {
  1472. // Machine policy allows TS connection
  1473. bPolicyOK = TRUE;
  1474. }
  1475. }
  1476. else if (lRet == ERROR_FILE_NOT_FOUND)
  1477. {
  1478. bPolicyOK = TRUE;
  1479. }
  1480. else
  1481. {
  1482. hr = HRESULT_FROM_WIN32(lRet);
  1483. }
  1484. //
  1485. // If policy allows to change connection status
  1486. //
  1487. if (SUCCEEDED(hr) && bPolicyOK)
  1488. {
  1489. if (dwDisabled)
  1490. {
  1491. bRet = WriteProfileString(APPLICATION_NAME,
  1492. WINSTATIONS_DISABLED,
  1493. TEXT("1"));
  1494. }
  1495. else
  1496. {
  1497. bRet = WriteProfileString(APPLICATION_NAME,
  1498. WINSTATIONS_DISABLED,
  1499. TEXT("0"));
  1500. }
  1501. if (!bRet)
  1502. {
  1503. hr = HRESULT_FROM_WIN32(GetLastError());
  1504. }
  1505. }
  1506. }
  1507. return hr;
  1508. }
  1509. //-----------------------------------------------------------------------------
  1510. //
  1511. // Function: DisplayTaskList
  1512. //
  1513. // Synopsis: Display the list of running task on the system
  1514. //
  1515. // Returns: TRUE if there is tasks running
  1516. // FALSE if there is no other tasks running
  1517. //
  1518. // History: 07/09/2002 Rerkboos Created
  1519. //
  1520. // Notes: none
  1521. //
  1522. //-----------------------------------------------------------------------------
  1523. BOOL DisplayTaskList()
  1524. {
  1525. HRESULT hr;
  1526. BOOL bRet = FALSE;
  1527. DWORD i;
  1528. DWORD cchTaskList;
  1529. LPTSTR lpTaskList = NULL;
  1530. DWORD cchTask;
  1531. LPTSTR lpTask = NULL;
  1532. DWORD dwMaxCchLen;
  1533. TCHAR szTemp[512];
  1534. TCHAR szCaption[MAX_PATH];
  1535. TCHAR szHeader[MAX_PATH];
  1536. APPLIST_PARAM AppListParam;
  1537. // Init the AppList structure
  1538. AppListParam.dwNumEntries = 0;
  1539. for (i = 0 ; i < MAX_APP_ENTRIES ; i++)
  1540. {
  1541. AppListParam.lpAppName[i] = NULL;
  1542. }
  1543. if (LoadString(g_hInstDll, IDS_PRODUCT_NAME, szCaption, ARRAYSIZE(szCaption)) <= 0
  1544. || LoadString(g_hInstDll, IDS_CLOSE_APP_TEXT, szHeader, ARRAYSIZE(szHeader)) <= 0)
  1545. {
  1546. goto CLEANUP;
  1547. }
  1548. bRet = EnumDesktopWindows(NULL, (WNDENUMPROC) &EnumWindowProc, (LPARAM) &AppListParam);
  1549. if (AppListParam.dwNumEntries > 0)
  1550. {
  1551. cchTaskList = lstrlen(szHeader);
  1552. dwMaxCchLen = 0;
  1553. for (i = 0 ; i < AppListParam.dwNumEntries ; i++)
  1554. {
  1555. cchTask = lstrlen(AppListParam.lpAppName[i]) + 4;
  1556. if (cchTask > dwMaxCchLen)
  1557. {
  1558. dwMaxCchLen = cchTask;
  1559. }
  1560. cchTaskList += cchTask;
  1561. }
  1562. // Allocate the string long enough to store a Task name
  1563. lpTask = (LPTSTR) MEMALLOC(dwMaxCchLen * sizeof(TCHAR));
  1564. if (lpTask != NULL)
  1565. {
  1566. // Allocate the string for all the tasks
  1567. lpTaskList = (LPTSTR) MEMALLOC(cchTaskList * sizeof(TCHAR));
  1568. if (lpTaskList != NULL)
  1569. {
  1570. hr = StringCchCopy(lpTaskList, cchTaskList, szHeader);
  1571. for (i = 0 ; i < AppListParam.dwNumEntries ; i++)
  1572. {
  1573. hr = StringCchPrintf(lpTask,
  1574. dwMaxCchLen,
  1575. TEXT("- %s\n"),
  1576. AppListParam.lpAppName[i]);
  1577. if (SUCCEEDED(hr))
  1578. {
  1579. hr = StringCchCat(lpTaskList,
  1580. cchTaskList,
  1581. lpTask);
  1582. if (FAILED(hr))
  1583. {
  1584. goto CLEANUP;
  1585. }
  1586. }
  1587. }
  1588. }
  1589. }
  1590. MessageBox(GetConsoleWindow(), lpTaskList, szCaption, MB_OK);
  1591. bRet = TRUE;
  1592. }
  1593. else
  1594. {
  1595. bRet = FALSE;
  1596. }
  1597. CLEANUP:
  1598. if (lpTask != NULL)
  1599. {
  1600. MEMFREE(lpTask);
  1601. }
  1602. if (lpTaskList != NULL)
  1603. {
  1604. MEMFREE(lpTaskList);
  1605. }
  1606. for (i = 0 ; i < MAX_APP_ENTRIES ; i++)
  1607. {
  1608. if (AppListParam.lpAppName[i] != NULL)
  1609. {
  1610. MEMFREE(AppListParam.lpAppName[i]);
  1611. }
  1612. }
  1613. return bRet;
  1614. }
  1615. //-----------------------------------------------------------------------------
  1616. //
  1617. // Function: EnumWindowProc
  1618. //
  1619. // Synopsis: A callback function for EnumDesktopWindows() in
  1620. // DisplayTaskList() function.
  1621. //
  1622. // Returns: TRUE if no error occured
  1623. // FALSE if something was wrong
  1624. //
  1625. // History: 07/09/2002 Rerkboos Created
  1626. //
  1627. // Notes: none
  1628. //
  1629. //-----------------------------------------------------------------------------
  1630. BOOL CALLBACK EnumWindowProc(
  1631. HWND hwnd,
  1632. LPARAM lParam
  1633. )
  1634. {
  1635. BOOL bRet = FALSE;
  1636. HRESULT hr;
  1637. TCHAR szTitle[MAX_PATH];
  1638. TCHAR szOwnerFile[MAX_PATH];
  1639. LPCTSTR lpFileName;
  1640. DWORD dwIndex;
  1641. DWORD cchLen;
  1642. UINT ui;
  1643. PFNGETMODULENAME pfnGetWindowModuleFileName;
  1644. if (GetWindow(hwnd, GW_OWNER) || !IsWindowVisible(hwnd))
  1645. {
  1646. // Skip child windows or invisible windows
  1647. return TRUE;
  1648. }
  1649. GetWindowText(hwnd, szTitle, MAX_PATH);
  1650. if (szTitle[0] == TEXT('\0'))
  1651. {
  1652. return TRUE;
  1653. }
  1654. if (MyStrCmpI(szTitle, TEXT("Program Manager")) == LSTR_EQUAL)
  1655. {
  1656. return TRUE;
  1657. }
  1658. if (hwnd == GetConsoleWindow())
  1659. {
  1660. // Ignore itself
  1661. return TRUE;
  1662. }
  1663. // Ignore Explorer windows
  1664. lpFileName = GetWindowModuleFileNameOnly(hwnd, szOwnerFile, ARRAYSIZE(szOwnerFile));
  1665. if (StrStrI(szOwnerFile, TEXT("browseui")))
  1666. {
  1667. return TRUE;
  1668. }
  1669. dwIndex = ((PAPPLIST_PARAM) lParam)->dwNumEntries;
  1670. hr = DuplicateString(&(((PAPPLIST_PARAM) lParam)->lpAppName[dwIndex]),
  1671. &cchLen,
  1672. szTitle);
  1673. if (SUCCEEDED(hr))
  1674. {
  1675. bRet = TRUE;
  1676. ((PAPPLIST_PARAM) lParam)->dwNumEntries++;
  1677. }
  1678. return bRet;
  1679. }
  1680. //-----------------------------------------------------------------------------
  1681. //
  1682. // Function: ShowStartUpDialog
  1683. //
  1684. // Synopsis: Display startup dialog
  1685. //
  1686. // Returns: none
  1687. //
  1688. // History: 08/14/2002 rerkboos created
  1689. //
  1690. // Notes: none
  1691. //
  1692. //-----------------------------------------------------------------------------
  1693. INT ShowStartUpDialog()
  1694. {
  1695. return (INT) DialogBoxParam(GetModuleHandle(NULL),
  1696. MAKEINTRESOURCE(IDD_STARTUP_DLG),
  1697. GetConsoleWindow(),
  1698. (DLGPROC) StartUpDlgProc,
  1699. (LPARAM) NULL);
  1700. }
  1701. //-----------------------------------------------------------------------------
  1702. //
  1703. // Function: StartUpDlgProc
  1704. //
  1705. // Synopsis: Dialog box procedure
  1706. //
  1707. // Returns:
  1708. //
  1709. // History: 02/07/2002 rerkboos created
  1710. //
  1711. // Notes: none
  1712. //
  1713. //-----------------------------------------------------------------------------
  1714. BOOL
  1715. CALLBACK
  1716. StartUpDlgProc(
  1717. HWND hwndDlg,
  1718. UINT uMsg,
  1719. WPARAM wParam,
  1720. LPARAM lParam
  1721. )
  1722. {
  1723. WCHAR wszInfo[1024];
  1724. switch (uMsg)
  1725. {
  1726. case WM_INITDIALOG:
  1727. // Init the dialog
  1728. ShowWindow(hwndDlg, SW_SHOWNORMAL);
  1729. if (LoadStringW(g_hInstDll,
  1730. IDS_STARTUP_DLG_INFO,
  1731. wszInfo,
  1732. ARRAYSIZE(wszInfo)))
  1733. {
  1734. SendMessage(GetDlgItem(hwndDlg, ID_STARTUP_DLG_INFO),
  1735. WM_SETTEXT,
  1736. wParam,
  1737. (LPARAM) wszInfo);
  1738. }
  1739. case WM_COMMAND:
  1740. // Handle command buttons
  1741. switch (wParam)
  1742. {
  1743. case ID_STARTUP_DLG_NEXT:
  1744. EndDialog(hwndDlg, ID_STARTUP_DLG_NEXT);
  1745. break;
  1746. case ID_STARTUP_DLG_CANCEL:
  1747. EndDialog(hwndDlg, ID_STARTUP_DLG_CANCEL);
  1748. break;
  1749. case ID_STARTUP_DLG_README:
  1750. ShowReadMe();
  1751. break;
  1752. }
  1753. break;
  1754. case WM_CLOSE:
  1755. EndDialog(hwndDlg, ID_STARTUP_DLG_CANCEL);
  1756. break;
  1757. default:
  1758. break;
  1759. }
  1760. return FALSE;
  1761. }
  1762. //-----------------------------------------------------------------------------
  1763. //
  1764. // Function: ShowReadMe
  1765. //
  1766. // Synopsis: Launch notepad to display CLMT readme.txt
  1767. //
  1768. // Returns: none
  1769. //
  1770. // History: 08/14/2002 rerkboos created
  1771. //
  1772. // Notes: none
  1773. //
  1774. //-----------------------------------------------------------------------------
  1775. VOID ShowReadMe()
  1776. {
  1777. HRESULT hr;
  1778. DWORD dwErr;
  1779. DWORD i;
  1780. TCHAR szReadmePath[MAX_PATH];
  1781. TCHAR szNotepad[MAX_PATH];
  1782. TCHAR szCmdLine[MAX_PATH];
  1783. dwErr = GetModuleFileName(NULL, szReadmePath, ARRAYSIZE(szReadmePath));
  1784. if (dwErr == 0)
  1785. {
  1786. szReadmePath[0] = TEXT('\0');
  1787. }
  1788. else
  1789. {
  1790. i = lstrlen(szReadmePath);
  1791. while (i > 0 && szReadmePath[i] != TEXT('\\'))
  1792. {
  1793. i--;
  1794. }
  1795. szReadmePath[i + 1] = TEXT('\0');
  1796. }
  1797. hr = StringCchCat(szReadmePath, ARRAYSIZE(szReadmePath), TEXT_README_FILE);
  1798. dwErr = GetFileAttributes(szReadmePath);
  1799. if (dwErr == INVALID_FILE_ATTRIBUTES)
  1800. {
  1801. DoMessageBox(GetConsoleWindow(), IDS_README_NOT_FOUND, IDS_MAIN_TITLE, MB_OK);
  1802. }
  1803. else
  1804. {
  1805. ExpandEnvironmentStrings(TEXT("%systemroot%\\system32\\Notepad.exe"),
  1806. szNotepad,
  1807. ARRAYSIZE(szNotepad));
  1808. hr = StringCchCopy(szCmdLine, ARRAYSIZE(szCmdLine), szNotepad);
  1809. hr = StringCchCat(szCmdLine, ARRAYSIZE(szCmdLine), TEXT(" "));
  1810. hr = StringCchCat(szCmdLine, ARRAYSIZE(szCmdLine), szReadmePath);
  1811. StartProcess(szNotepad,
  1812. szCmdLine,
  1813. TEXT("."));
  1814. }
  1815. }
  1816. //-----------------------------------------------------------------------------
  1817. //
  1818. // Function: StartProcess
  1819. //
  1820. // Synopsis: Start a Windows application
  1821. //
  1822. // Returns: TRUE if an application is started
  1823. // FALSE otherwise
  1824. //
  1825. // History: 08/14/2002 rerkboos created
  1826. //
  1827. // Notes: none
  1828. //
  1829. //-----------------------------------------------------------------------------
  1830. BOOL StartProcess(
  1831. LPCTSTR lpAppName, // Application name
  1832. LPTSTR lpCmdLine, // Application command line
  1833. LPCTSTR lpCurrentDir // Working directory
  1834. )
  1835. {
  1836. BOOL bRet = FALSE;
  1837. STARTUPINFO siApp;
  1838. PROCESS_INFORMATION piApp;
  1839. ZeroMemory(&siApp, sizeof(STARTUPINFO));
  1840. siApp.cb = sizeof(STARTUPINFO);
  1841. // CreateProcess call conforms to security guideline
  1842. bRet = CreateProcess(lpAppName,
  1843. lpCmdLine,
  1844. NULL,
  1845. NULL,
  1846. FALSE,
  1847. NORMAL_PRIORITY_CLASS,
  1848. NULL,
  1849. lpCurrentDir,
  1850. &siApp,
  1851. &piApp);
  1852. return bRet;
  1853. }
  1854. //-----------------------------------------------------------------------------
  1855. //
  1856. // Function: ThreadProc
  1857. //
  1858. // Synopsis: A procedure that will be run on remote thread
  1859. //
  1860. // Returns:
  1861. //
  1862. // History: 08/20/2002 rerkboos created
  1863. //
  1864. // Notes: Code is copied from Fontspy
  1865. //
  1866. //-----------------------------------------------------------------------------
  1867. DWORD WINAPI ThreadProc(
  1868. PGETMODULENAME pgmn
  1869. )
  1870. {
  1871. pgmn->szfname[0] = 0;
  1872. if (pgmn->pfnGetModuleHandle(pgmn->szUser32))
  1873. {
  1874. pgmn->pfn(pgmn->hWnd, pgmn->szfname, MAX_PATH);
  1875. }
  1876. return 0;
  1877. }
  1878. //-----------------------------------------------------------------------------
  1879. //
  1880. // Function: GetWindowModuleFileNameOnly
  1881. //
  1882. // Synopsis: Get the module name that load the current window
  1883. //
  1884. // Returns:
  1885. //
  1886. // History: 08/20/2002 rerkboos created
  1887. //
  1888. // Notes: Code is copied from FontSpy
  1889. //
  1890. //-----------------------------------------------------------------------------
  1891. LPCTSTR GetWindowModuleFileNameOnly(
  1892. HWND hWnd,
  1893. LPTSTR lpszFile,
  1894. DWORD cchFile
  1895. )
  1896. {
  1897. HRESULT hr;
  1898. DWORD dwProcessID;
  1899. DWORD dwThreadID;
  1900. HANDLE hProcess;
  1901. HANDLE hThread = NULL;
  1902. DWORD dwXfer;
  1903. PBYTE pv = NULL;
  1904. LPCTSTR psz;
  1905. UINT uCodeSize;
  1906. GETMODULENAME gmn;
  1907. uCodeSize = (ULONG) GetWindowModuleFileNameOnly - (ULONG) ThreadProc;
  1908. ZeroMemory(&gmn, sizeof(gmn));
  1909. __try
  1910. {
  1911. GetWindowThreadProcessId(hWnd, &dwProcessID);
  1912. hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
  1913. if (!hProcess)
  1914. {
  1915. hr = StringCchCopy(lpszFile, cchFile, TEXT("Access Denied"));
  1916. __leave;
  1917. }
  1918. gmn.hWnd = hWnd;
  1919. hr = StringCchCopy(gmn.szUser32, ARRAYSIZE(gmn.szUser32), TEXT("user32"));
  1920. if (FAILED(hr))
  1921. {
  1922. __leave;
  1923. }
  1924. gmn.pfn = (PFNGETMODULENAME) GetProcAddress(
  1925. GetModuleHandle(_T("user32")),
  1926. #ifdef UNICODE
  1927. "GetWindowModuleFileNameW"
  1928. #else
  1929. "GetWindowModuleFileNameA"
  1930. #endif
  1931. );
  1932. if (!gmn.pfn)
  1933. {
  1934. __leave;
  1935. }
  1936. gmn.pfnGetModuleHandle = (PFNGETMODULEHANDLE)GetProcAddress(
  1937. GetModuleHandle(_T("kernel32")),
  1938. #ifdef UNICODE
  1939. "GetModuleHandleW"
  1940. #else
  1941. "GetModuleHandleA"
  1942. #endif
  1943. );
  1944. if (!gmn.pfnGetModuleHandle)
  1945. {
  1946. __leave;
  1947. }
  1948. pv = (PBYTE)VirtualAllocEx(
  1949. hProcess,
  1950. 0,
  1951. uCodeSize + sizeof(gmn),
  1952. MEM_COMMIT,
  1953. PAGE_EXECUTE_READWRITE
  1954. );
  1955. if (!pv)
  1956. {
  1957. __leave;
  1958. }
  1959. WriteProcessMemory(
  1960. hProcess,
  1961. pv,
  1962. &gmn,
  1963. sizeof(gmn),
  1964. &dwXfer
  1965. );
  1966. WriteProcessMemory(
  1967. hProcess,
  1968. pv+offsetof(GETMODULENAME, pvCode),
  1969. ThreadProc,
  1970. uCodeSize,
  1971. &dwXfer
  1972. );
  1973. hThread = CreateRemoteThread(
  1974. hProcess,
  1975. NULL,
  1976. 0,
  1977. (LPTHREAD_START_ROUTINE) (pv + offsetof(GETMODULENAME, pvCode)),
  1978. pv,
  1979. 0,
  1980. &dwThreadID
  1981. );
  1982. WaitForSingleObject(hThread, INFINITE);
  1983. ReadProcessMemory(hProcess, pv, &gmn, sizeof(gmn), &dwXfer);
  1984. }
  1985. __finally
  1986. {
  1987. if (pv)
  1988. {
  1989. //VirtualFreeEx(hProcess, pv, uCodeSize+sizeof(gmn), MEM_DECOMMIT);
  1990. VirtualFreeEx(hProcess, pv, 0, MEM_RELEASE);
  1991. }
  1992. if (hProcess != NULL)
  1993. {
  1994. CloseHandle(hProcess);
  1995. }
  1996. if (hThread != NULL)
  1997. {
  1998. CloseHandle(hThread);
  1999. }
  2000. }
  2001. hr = StringCchCopy(lpszFile, cchFile, gmn.szfname);
  2002. psz = _tcsrchr(lpszFile, _T('\\'))+1;
  2003. if (!psz)
  2004. {
  2005. psz = lpszFile;
  2006. }
  2007. return psz;
  2008. }