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.
2329 lines
65 KiB
2329 lines
65 KiB
#include "StdAfx.h"
|
|
#include <stddef.h>
|
|
#include <objidl.h>
|
|
#include <objbase.h>
|
|
#include <shlobj.h>
|
|
#include <wtsapi32.h>
|
|
#include <psapi.h>
|
|
|
|
|
|
// Log file created by "winnt32 /checkupgradeonly"
|
|
#define TEXT_UPGRADE_LOG TEXT("%SystemRoot%\\Upgrade.txt")
|
|
|
|
// Value name in registry to keep track of machine state
|
|
#define CLMT_MACHINE_STATE_REG_VALUE TEXT("MachineState")
|
|
|
|
// Read me file name
|
|
#define TEXT_README_FILE TEXT("Readme.txt")
|
|
|
|
// constants used to determine SKU
|
|
#define SKU_SRV 1
|
|
#define SKU_ADS 2
|
|
#define SKU_DTC 3
|
|
|
|
// Maximum entries for list of applications running on the system
|
|
#define MAX_APP_ENTRIES 100
|
|
|
|
typedef struct _UPGRADE_LOG_PARAM
|
|
{
|
|
LPVOID lpText;
|
|
size_t cbText;
|
|
BOOL fUnicode;
|
|
} UPGRADE_LOG_PARAM, *PUPGRADE_LOG_PARAM;
|
|
|
|
typedef struct _stAppListParam
|
|
{
|
|
DWORD dwNumEntries;
|
|
LPTSTR lpAppName[MAX_APP_ENTRIES];
|
|
} APPLIST_PARAM, *PAPPLIST_PARAM;
|
|
|
|
typedef UINT (WINAPI* PFNGETMODULENAME)(HWND, LPTSTR, UINT);
|
|
typedef HMODULE (WINAPI* PFNGETMODULEHANDLE)(LPCTSTR);
|
|
|
|
typedef struct _GETMODULENAME
|
|
{
|
|
PFNGETMODULENAME pfn;
|
|
PFNGETMODULEHANDLE pfnGetModuleHandle;
|
|
TCHAR szfname[MAX_PATH];
|
|
TCHAR szUser32[8];
|
|
HWND hWnd;
|
|
PVOID pvCode;
|
|
} GETMODULENAME, *PGETMODULENAME;
|
|
|
|
|
|
BOOL LaunchWinnt32(LPCTSTR);
|
|
BOOL AskUserForDotNetCDPath(LPTSTR);
|
|
BOOL FindUpgradeLog(VOID);
|
|
BOOL IsDotNetWinnt32(LPCTSTR);
|
|
INT ShowUpgradeLog(VOID);
|
|
BOOL CheckUnsupportComponent(LPVOID, BOOL);
|
|
BOOL CALLBACK UpgradeLogDlgProc(HWND, UINT, WPARAM, LPARAM);
|
|
HRESULT ReadTextFromFile(LPCTSTR, LPVOID*, size_t*, BOOL*);
|
|
BOOL IsOperationOK(DWORD, DWORD, LPDWORD, PUINT);
|
|
BOOL CALLBACK EnumWindowProc();
|
|
BOOL CALLBACK StartUpDlgProc(HWND, UINT, WPARAM, LPARAM);
|
|
BOOL StartProcess(LPCTSTR, LPTSTR, LPCTSTR);
|
|
|
|
|
|
LPCTSTR GetWindowModuleFileNameOnly(HWND hWnd, LPTSTR lpszFile, DWORD cchFile);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: CheckSystemCriteria
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Returns: - Ok the continue the tool
|
|
// - Not ok to continue the tools
|
|
// - Unexpected error occured
|
|
//
|
|
// History: 09/14/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CheckSystemCriteria(VOID)
|
|
{
|
|
HRESULT hr;
|
|
LCID lcid;
|
|
OSVERSIONINFOEX osviex;
|
|
|
|
if (IsNEC98())
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_NEC98, IDS_MAIN_TITLE, MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
if (IsIA64())
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_IA64, IDS_MAIN_TITLE, MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_dwRunningStatus == CLMT_DOMIG)
|
|
{
|
|
if (!IsNT5())
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_NT5, IDS_MAIN_TITLE, MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
if (IsDomainController())
|
|
{
|
|
// If this machine is a domain controller, we need W2K SP2
|
|
ZeroMemory(&osviex, sizeof(OSVERSIONINFOEX));
|
|
osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
GetVersionEx((LPOSVERSIONINFO) &osviex);
|
|
|
|
if (osviex.wServicePackMajor < 2)
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_NT5SP2, IDS_MAIN_TITLE, MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Also pop up the message asking admin to take machine
|
|
// off the network if it is in DC replication servers
|
|
//
|
|
DoMessageBox(GetConsoleWindow(),
|
|
IDS_DC_REPLICA_OFFLINE,
|
|
IDS_MAIN_TITLE,
|
|
MB_OK);
|
|
}
|
|
|
|
}
|
|
else if (g_dwRunningStatus == CLMT_CLEANUP_AFTER_UPGRADE)
|
|
{
|
|
if (!IsDotNet())
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// noop
|
|
}
|
|
|
|
if (IsOnTSClient())
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_ON_TS_CLIENT, IDS_MAIN_TITLE, MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
if (IsOtherSessionOnTS())
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_TS_CLOSE_SESSION, IDS_MAIN_TITLE, MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
hr = GetSavedInstallLocale(&lcid);
|
|
if (HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
hr = SaveInstallLocale();
|
|
if (FAILED(hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL IsOneInstance(VOID)
|
|
{
|
|
HRESULT hr;
|
|
TCHAR szGlobalText[MAX_PATH];
|
|
|
|
hr = StringCchPrintf(szGlobalText,
|
|
ARRAYSIZE(szGlobalText),
|
|
TEXT("Global\\%s"),
|
|
TEXT("CLMT Is Running"));
|
|
if (FAILED(hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
g_hMutex = CreateMutex(NULL, FALSE, szGlobalText);
|
|
if ((g_hMutex == NULL) && (GetLastError() == ERROR_PATH_NOT_FOUND))
|
|
{
|
|
g_hMutex = CreateMutex(NULL, FALSE, TEXT("CLMT Is Running"));
|
|
if (g_hMutex == NULL)
|
|
{
|
|
//
|
|
// An error (like out of memory) has occurred.
|
|
// Bail now.
|
|
//
|
|
DoMessageBox(GetConsoleWindow(), IDS_OUT_OF_MEMORY, IDS_MAIN_TITLE, MB_OK);
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure we are the only process with a handle to our named mutex.
|
|
//
|
|
if ((g_hMutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS))
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_ALREADY_RUNNING, IDS_MAIN_TITLE, MB_OK);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL CheckAdminPrivilege(VOID)
|
|
{
|
|
BOOL bIsAdmin;
|
|
BOOL bRet = FALSE;
|
|
|
|
if (!IsAdmin())
|
|
{
|
|
if (g_dwRunningStatus == CLMT_DOMIG)
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_ADMIN, IDS_MAIN_TITLE, MB_OK);
|
|
}
|
|
else if ( (g_dwRunningStatus == CLMT_CURE_PROGRAM_FILES)
|
|
|| (g_dwRunningStatus == CLMT_CURE_ALL) )
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_ADMIN_RELOGON, IDS_MAIN_TITLE, MB_OK);
|
|
}
|
|
else if (g_dwRunningStatus == CLMT_CLEANUP_AFTER_UPGRADE)
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_ADMIN_LOGON_DOTNET, IDS_MAIN_TITLE, MB_OK);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if(!DoesUserHavePrivilege(SE_SHUTDOWN_NAME)
|
|
|| !DoesUserHavePrivilege(SE_BACKUP_NAME)
|
|
|| !DoesUserHavePrivilege(SE_RESTORE_NAME)
|
|
|| !DoesUserHavePrivilege(SE_SYSTEM_ENVIRONMENT_NAME))
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_ADMIN, IDS_MAIN_TITLE, MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
if(!EnablePrivilege(SE_SHUTDOWN_NAME,TRUE)
|
|
|| !EnablePrivilege(SE_BACKUP_NAME,TRUE)
|
|
|| !EnablePrivilege(SE_RESTORE_NAME,TRUE)
|
|
|| !EnablePrivilege(SE_SYSTEM_ENVIRONMENT_NAME,TRUE))
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_ADMIN, IDS_MAIN_TITLE, MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: CheckCLMTStatus
|
|
//
|
|
// Synopsis: Check the machine status and CLMT running mode.
|
|
//
|
|
// Returns: S_OK - Ok the continue the tool
|
|
// S_FALSE - Not ok to continue the tools
|
|
// Else - Unexpected error occured
|
|
//
|
|
// History: 03/12/2002 rerkboos created
|
|
// 07/09/2002 rerkboos modified
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CheckCLMTStatus(
|
|
LPDWORD lpdwCurrentState, // Current machine state before the operation
|
|
LPDWORD lpdwNextState, // Next state if the operation finish successfully
|
|
PUINT lpuResourceID // Resource ID of the error string
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
BOOL bIsOK;
|
|
|
|
if (lpdwCurrentState == NULL || lpdwNextState == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// Get the current machine state
|
|
hr = CLMTGetMachineState(lpdwCurrentState);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
bIsOK = IsOperationOK(*lpdwCurrentState,
|
|
g_dwRunningStatus,
|
|
lpdwNextState,
|
|
lpuResourceID);
|
|
|
|
hr = (bIsOK == TRUE ? S_OK : S_FALSE);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsOperationOK
|
|
//
|
|
// Synopsis: Verify that the current operation is okay to perform on current
|
|
// state of the system.
|
|
//
|
|
// Returns: TRUE - ok to perform operation
|
|
// FALSE - otherwise
|
|
//
|
|
// History: 03/12/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL IsOperationOK(
|
|
DWORD dwCurrentState, // Current state of the system
|
|
DWORD dwAction, // Action to perform
|
|
LPDWORD lpdwNextState, // Next state after performing the action
|
|
LPUINT lpuResourceID // Resource ID for the error message
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
int i;
|
|
|
|
struct CLMT_STATE_MACHINE
|
|
{
|
|
DWORD dwCurrentState;
|
|
DWORD dwAction;
|
|
DWORD dwNextState;
|
|
};
|
|
|
|
const struct CLMT_STATE_MACHINE smCLMT[] =
|
|
{
|
|
CLMT_STATE_ORIGINAL, CLMT_DOMIG, CLMT_STATE_MIGRATION_DONE,
|
|
|
|
CLMT_STATE_MIGRATION_DONE, CLMT_UNDO_PROGRAM_FILES, CLMT_STATE_PROGRAMFILES_UNDONE,
|
|
CLMT_STATE_MIGRATION_DONE, CLMT_UNDO_APPLICATION_DATA, CLMT_STATE_APPDATA_UNDONE,
|
|
CLMT_STATE_MIGRATION_DONE, CLMT_UNDO_ALL, CLMT_STATE_ORIGINAL,
|
|
CLMT_STATE_MIGRATION_DONE, CLMT_CLEANUP_AFTER_UPGRADE, CLMT_STATE_FINISH,
|
|
CLMT_STATE_MIGRATION_DONE, CLMT_CURE_PROGRAM_FILES, CLMT_STATE_PROGRAMFILES_CURED,
|
|
CLMT_STATE_MIGRATION_DONE, CLMT_CURE_AND_CLEANUP, CLMT_STATE_MIGRATION_DONE,
|
|
|
|
CLMT_STATE_MIGRATION_DONE, CLMT_CURE_ALL, CLMT_STATE_PROGRAMFILES_CURED,
|
|
CLMT_STATE_PROGRAMFILES_CURED, CLMT_CURE_ALL, CLMT_STATE_PROGRAMFILES_CURED,
|
|
|
|
CLMT_STATE_PROGRAMFILES_CURED, CLMT_CLEANUP_AFTER_UPGRADE, CLMT_STATE_FINISH,
|
|
CLMT_STATE_PROGRAMFILES_CURED, CLMT_CURE_AND_CLEANUP, CLMT_STATE_FINISH,
|
|
|
|
CLMT_STATE_PROGRAMFILES_UNDONE, CLMT_UNDO_APPLICATION_DATA, CLMT_STATE_ORIGINAL,
|
|
CLMT_STATE_PROGRAMFILES_UNDONE, CLMT_UNDO_ALL, CLMT_STATE_ORIGINAL,
|
|
CLMT_STATE_PROGRAMFILES_UNDONE, CLMT_DOMIG, CLMT_STATE_MIGRATION_DONE,
|
|
|
|
CLMT_STATE_APPDATA_UNDONE, CLMT_UNDO_PROGRAM_FILES, CLMT_STATE_ORIGINAL,
|
|
CLMT_STATE_APPDATA_UNDONE, CLMT_UNDO_ALL, CLMT_STATE_ORIGINAL,
|
|
CLMT_STATE_APPDATA_UNDONE, CLMT_DOMIG, CLMT_STATE_MIGRATION_DONE,
|
|
|
|
CLMT_STATE_PROGRAMFILES_CURED, CLMT_CURE_PROGRAM_FILES, CLMT_STATE_PROGRAMFILES_CURED,
|
|
CLMT_STATE_FINISH, CLMT_CURE_PROGRAM_FILES, CLMT_STATE_FINISH,
|
|
|
|
CLMT_STATE_FINISH, CLMT_CURE_ALL, CLMT_STATE_FINISH,
|
|
|
|
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
|
|
};
|
|
|
|
for (i = 0 ; smCLMT[i].dwCurrentState != 0xFFFFFFFF ; i++)
|
|
{
|
|
if (smCLMT[i].dwCurrentState == dwCurrentState)
|
|
{
|
|
if (smCLMT[i].dwAction == dwAction)
|
|
{
|
|
*lpdwNextState = smCLMT[i].dwNextState;
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
switch (dwCurrentState)
|
|
{
|
|
case CLMT_STATE_ORIGINAL:
|
|
*lpuResourceID = IDS_BAD_OPERATION_ORIGINAL;
|
|
break;
|
|
|
|
case CLMT_STATE_MIGRATION_DONE:
|
|
case CLMT_STATE_PROGRAMFILES_CURED:
|
|
*lpuResourceID = IDS_BAD_OPERATION_MIGDONE;
|
|
break;
|
|
|
|
case CLMT_STATE_FINISH:
|
|
*lpuResourceID = IDS_BAD_OPERATION_FINISH;
|
|
break;
|
|
|
|
default:
|
|
*lpuResourceID = IDS_OPERATION_NOT_LEGAL;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: CLMTSetMachineState
|
|
//
|
|
// Synopsis: Set the machine state to CLMT registry
|
|
//
|
|
// Returns: S_OK if value is successfully saved in registry
|
|
//
|
|
// History: 03/13/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CLMTSetMachineState(
|
|
DWORD dwMachineState // Machine state
|
|
)
|
|
{
|
|
LONG lStatus;
|
|
|
|
lStatus = SetRegistryValue(HKEY_LOCAL_MACHINE,
|
|
CLMT_REGROOT,
|
|
CLMT_MACHINE_STATE_REG_VALUE,
|
|
REG_DWORD,
|
|
(LPBYTE) &dwMachineState,
|
|
sizeof(dwMachineState));
|
|
|
|
return HRESULT_FROM_WIN32(lStatus);
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: CLMTGetMachineState
|
|
//
|
|
// Synopsis: Get the machine state from CLMT registry key.
|
|
// If the key does not exist, this function will also set the value
|
|
// of reg key to ORIGINAL state.
|
|
//
|
|
// Returns: S_OK if value is successfully retrieved in registry
|
|
//
|
|
// History: 03/13/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CLMTGetMachineState(
|
|
LPDWORD lpdwMachineState
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
LONG lStatus;
|
|
DWORD dwSize;
|
|
|
|
if (lpdwMachineState == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
dwSize = sizeof(DWORD);
|
|
lStatus = GetRegistryValue(HKEY_LOCAL_MACHINE,
|
|
CLMT_REGROOT,
|
|
CLMT_MACHINE_STATE_REG_VALUE,
|
|
(LPBYTE) lpdwMachineState,
|
|
&dwSize);
|
|
if (lStatus == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
// First time running the tool, we don't have the value in registry yet.
|
|
// Set the machine state to ORIGINAL
|
|
*lpdwMachineState = CLMT_STATE_ORIGINAL;
|
|
hr = CLMTSetMachineState(CLMT_STATE_ORIGINAL);
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(lStatus);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsUserOKWithCheckUpgrade
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 02/07/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL IsUserOKWithCheckUpgrade(VOID)
|
|
{
|
|
TCHAR szI386Path[MAX_PATH];
|
|
BOOL fRet = FALSE;
|
|
|
|
DoMessageBox(GetConsoleWindow(), IDS_ASKFORWINNT32, IDS_MAIN_TITLE, MB_OK);
|
|
|
|
// Ask user for path to winnt32.exe
|
|
if (AskUserForDotNetCDPath(szI386Path))
|
|
{
|
|
// Launch Winnt32.exe with checkupgrade switch
|
|
if (LaunchWinnt32(szI386Path))
|
|
{
|
|
// Show upgrade.txt to user, ask them to uninstall
|
|
// incompatible components before running CLMT
|
|
if (FindUpgradeLog())
|
|
{
|
|
if (ShowUpgradeLog() == ID_CONTINUE)
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_WINNT32_CANCEL, IDS_MAIN_TITLE, MB_OK);
|
|
DPF(dlError, TEXT("User choose to stop the process"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF(dlError, TEXT("Upgrade.txt not found"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF(dlError, TEXT("Unable to launch Winnt32.exe"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF(dlError, TEXT("User does not supply the path of Winnt32.exe"));
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: FindUpgradeLog
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 02/07/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL FindUpgradeLog(VOID)
|
|
{
|
|
const TCHAR szUpgradeLog[] = TEXT("%systemroot%\\Upgrade.txt");
|
|
TCHAR szExpUpgradeLog[MAX_PATH];
|
|
BOOL fRet = FALSE;
|
|
SYSTEMTIME stUTC, stNow;
|
|
WIN32_FILE_ATTRIBUTE_DATA attFileAttr;
|
|
|
|
if ( ExpandEnvironmentStrings(szUpgradeLog, szExpUpgradeLog, MAX_PATH) )
|
|
{
|
|
if ( GetFileAttributesEx(szExpUpgradeLog, GetFileExInfoStandard, &attFileAttr) )
|
|
{
|
|
// Upgrade.txt exists, check if it's updated today or not
|
|
if ( FileTimeToSystemTime(&attFileAttr.ftLastWriteTime, &stUTC) )
|
|
{
|
|
GetSystemTime(&stNow);
|
|
|
|
if (stUTC.wYear == stNow.wYear &&
|
|
stUTC.wMonth == stNow.wMonth &&
|
|
stUTC.wDay == stNow.wDay)
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: LaunchWinnt32
|
|
//
|
|
// Synopsis: Launch Winnt32.exe with "checkupgradeonly" switch
|
|
//
|
|
// Returns: TRUE if winnt32.exe is executed successfully
|
|
// FALSE otherwise
|
|
//
|
|
// History: 02/07/2002 rerkboos created
|
|
// 05/20/2002 rerkboos change parameter to receive CD path
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL LaunchWinnt32(
|
|
LPCTSTR lpCDPath // Path to Server 2003 CD
|
|
)
|
|
{
|
|
TCHAR szWinnt32[MAX_PATH];
|
|
TCHAR szI386Path[MAX_PATH];
|
|
BOOL bRet = FALSE;
|
|
HRESULT hr;
|
|
STARTUPINFO siWinnt32;
|
|
PROCESS_INFORMATION piWinnt32;
|
|
|
|
TCHAR szCmdLine[] = TEXT("Winnt32.exe /#u:anylocale /checkupgradeonly /unattend /dudisable");
|
|
|
|
if (lpCDPath == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Construct absolute path to Winnt32.exe
|
|
hr = StringCchCopy(szI386Path, ARRAYSIZE(szI386Path), lpCDPath);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ConcatenatePaths(szI386Path, TEXT("i386"), ARRAYSIZE(szI386Path));
|
|
hr = StringCchCopy(szWinnt32, ARRAYSIZE(szWinnt32), szI386Path);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ConcatenatePaths(szWinnt32, TEXT("winnt32.exe"), ARRAYSIZE(szWinnt32));
|
|
}
|
|
}
|
|
|
|
if ( IsDotNetWinnt32(szWinnt32) )
|
|
{
|
|
ZeroMemory(&siWinnt32, sizeof(STARTUPINFO));
|
|
siWinnt32.cb = sizeof(STARTUPINFO);
|
|
|
|
// CreateProcess call conforms to security guideline
|
|
bRet = CreateProcess(szWinnt32,
|
|
szCmdLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
NORMAL_PRIORITY_CLASS,
|
|
NULL,
|
|
szI386Path,
|
|
&siWinnt32,
|
|
&piWinnt32);
|
|
if (bRet)
|
|
{
|
|
// Wait until winnt32.exe finished before return back to CLM tool
|
|
WaitForSingleObject(piWinnt32.hProcess, INFINITE);
|
|
CloseHandle(piWinnt32.hProcess);
|
|
CloseHandle(piWinnt32.hThread);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: AskUserForDotNetCDPath
|
|
//
|
|
// Synopsis: Ask user to supply the path to Server 2003 CD
|
|
//
|
|
// Returns: TRUE if the path is valid
|
|
// FALSE otherwise
|
|
//
|
|
// History: 02/07/2002 rerkboos created
|
|
// 05/20/2002 rerkboos check for Server 2003 SRV/ADS CD
|
|
// 06/10/2002 rerkboos check for Server 2003 DTC cd
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL AskUserForDotNetCDPath(
|
|
LPTSTR lpCDPath // Buffer to store path to CD
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fRet = FALSE;
|
|
BOOL bDoBrowseDialog;
|
|
LPMALLOC piMalloc;
|
|
INT iRet;
|
|
DWORD dwSKU;
|
|
OSVERSIONINFOEX osviex;
|
|
|
|
if (lpCDPath == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check the SKU of current system
|
|
//
|
|
osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
GetVersionEx((LPOSVERSIONINFO) &osviex);
|
|
if (osviex.wProductType == VER_NT_DOMAIN_CONTROLLER
|
|
|| osviex.wProductType == VER_NT_SERVER)
|
|
{
|
|
dwSKU = SKU_SRV;
|
|
|
|
if (osviex.wSuiteMask & VER_SUITE_ENTERPRISE)
|
|
{
|
|
dwSKU = SKU_ADS;
|
|
}
|
|
|
|
if (osviex.wSuiteMask & VER_SUITE_DATACENTER)
|
|
{
|
|
dwSKU = SKU_DTC;
|
|
}
|
|
}
|
|
|
|
hr = SHGetMalloc(&piMalloc);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BROWSEINFO biCDPath;
|
|
LPITEMIDLIST lpiList;
|
|
|
|
ZeroMemory(&biCDPath, sizeof(BROWSEINFO));
|
|
|
|
biCDPath.hwndOwner = NULL;
|
|
biCDPath.lpszTitle = TEXT("Please supply the Windows Server 2003 CD path");
|
|
biCDPath.pszDisplayName = lpCDPath;
|
|
biCDPath.ulFlags = BIF_EDITBOX |
|
|
BIF_NONEWFOLDERBUTTON |
|
|
BIF_RETURNONLYFSDIRS;
|
|
|
|
bDoBrowseDialog = TRUE;
|
|
while (bDoBrowseDialog)
|
|
{
|
|
// Show the Browse dialog
|
|
lpiList = SHBrowseForFolder(&biCDPath);
|
|
|
|
if (lpiList == NULL)
|
|
{
|
|
//
|
|
// if lpiList == NULL, user click Cancel in browse dialog
|
|
//
|
|
iRet = MessageBox(GetConsoleWindow(),
|
|
TEXT("You did not supply the path to Windows Server 2003 CD.\nDo you want to continue running CLMT?"),
|
|
TEXT("CLMT"),
|
|
MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2);
|
|
|
|
if (iRet != IDYES)
|
|
{
|
|
// User choose not to run CLMT any further
|
|
bDoBrowseDialog = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// User supply path in Browse dialog,
|
|
// check whether it is valid Server 2003 SRV/ADS CD or not
|
|
//
|
|
if (SHGetPathFromIDListW(lpiList, lpCDPath))
|
|
{
|
|
LPTSTR lpFile;
|
|
DWORD cchFile;
|
|
DWORD dwAttr;
|
|
|
|
cchFile = lstrlen(lpCDPath) + MAX_PATH;
|
|
lpFile = MEMALLOC(cchFile * sizeof(TCHAR));
|
|
if (lpFile)
|
|
{
|
|
switch (dwSKU)
|
|
{
|
|
case SKU_SRV:
|
|
// Check if it is SRV CD or not
|
|
hr = StringCchCopy(lpFile, cchFile, lpCDPath);
|
|
ConcatenatePaths(lpFile, TEXT("win51is"), cchFile);
|
|
dwAttr = GetFileAttributes(lpFile);
|
|
if (dwAttr != INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
// This is SRV CD
|
|
fRet = TRUE;
|
|
bDoBrowseDialog = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// We also allow W2K SRV -> Server 2003 ADS
|
|
hr = StringCchCopy(lpFile, cchFile, lpCDPath);
|
|
ConcatenatePaths(lpFile, TEXT("win51ia"), cchFile);
|
|
dwAttr = GetFileAttributes(lpFile);
|
|
if (dwAttr != INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
// This is ADS CD
|
|
fRet = TRUE;
|
|
bDoBrowseDialog = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SKU_ADS:
|
|
// Check if it is ADS CD or not
|
|
hr = StringCchCopy(lpFile, cchFile, lpCDPath);
|
|
ConcatenatePaths(lpFile, TEXT("win51ia"), cchFile);
|
|
dwAttr = GetFileAttributes(lpFile);
|
|
if (dwAttr != INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
// This is ADS CD
|
|
fRet = TRUE;
|
|
bDoBrowseDialog = FALSE;
|
|
}
|
|
break;
|
|
|
|
case SKU_DTC:
|
|
// Check if it is DTC CD or not
|
|
hr = StringCchCopy(lpFile, cchFile, lpCDPath);
|
|
ConcatenatePaths(lpFile, TEXT("win51id"), cchFile);
|
|
dwAttr = GetFileAttributes(lpFile);
|
|
if (dwAttr != INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
// This is DTC CD
|
|
fRet = TRUE;
|
|
bDoBrowseDialog = FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fRet = FALSE;
|
|
bDoBrowseDialog = TRUE;
|
|
}
|
|
|
|
if (!fRet)
|
|
{
|
|
TCHAR szErrorMsg[512];
|
|
INT iRead;
|
|
|
|
iRead = LoadString(GetModuleHandle(NULL),
|
|
IDS_WRONG_CD,
|
|
szErrorMsg,
|
|
ARRAYSIZE(szErrorMsg));
|
|
if (iRead > 0)
|
|
{
|
|
MessageBox(GetConsoleWindow(),
|
|
szErrorMsg,
|
|
TEXT("CLMT"),
|
|
MB_OK);
|
|
}
|
|
}
|
|
|
|
MEMFREE(lpFile);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lpiList)
|
|
{
|
|
IMalloc_Free(piMalloc, lpiList);
|
|
}
|
|
|
|
IMalloc_Release(piMalloc);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsDotNetWinnt32
|
|
//
|
|
// Synopsis: Check if the specified path is Server 2003 family CD
|
|
// lpWinnt32 contains absolute path with winnt32.exe
|
|
//
|
|
// Returns: TRUE if it is Server 2003 winnt32,
|
|
// FALSE otherwise
|
|
//
|
|
// History: 02/07/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL IsDotNetWinnt32(
|
|
LPCTSTR lpWinnt32 // Absolute path to Winnt32.exe
|
|
)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
LPVOID lpBuffer;
|
|
DWORD cbBuffer;
|
|
UINT cbFileInfo;
|
|
VS_FIXEDFILEINFO* pFileInfo;
|
|
|
|
if (lpWinnt32 == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the size needed to allocate buffer
|
|
cbBuffer = GetFileVersionInfoSize((LPTSTR) lpWinnt32, NULL);
|
|
if (cbBuffer > 0)
|
|
{
|
|
lpBuffer = MEMALLOC(cbBuffer);
|
|
if (lpBuffer)
|
|
{
|
|
// Get the version info of user's specified winnt32.exe
|
|
if (GetFileVersionInfo((LPTSTR) lpWinnt32, 0, cbBuffer, lpBuffer))
|
|
{
|
|
if (VerQueryValue(lpBuffer,
|
|
TEXT("\\"),
|
|
(LPVOID*) &pFileInfo,
|
|
&cbFileInfo))
|
|
{
|
|
// Server 2003 Family version is 5.2
|
|
if (pFileInfo->dwFileVersionMS == 0x00050002)
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
MEMFREE(lpBuffer);
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: ShowUpgradeLog
|
|
//
|
|
// Synopsis: Display the content of %SystemRoot%\Upgrade.txt
|
|
//
|
|
// Returns: User selection to Stop or Continue operation from dialog box
|
|
//
|
|
// History: 02/07/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
INT ShowUpgradeLog(VOID)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fRet;
|
|
HMODULE hExe;
|
|
LPTSTR lpBuffer;
|
|
size_t cchBuffer;
|
|
TCHAR szUpgradeLog[MAX_PATH];
|
|
INT_PTR nRet = 0;
|
|
UPGRADE_LOG_PARAM lParam;
|
|
|
|
// Get the absolute path name for upgrade.txt
|
|
if ( !ExpandEnvironmentStrings(TEXT_UPGRADE_LOG, szUpgradeLog, MAX_PATH) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Read content of upgrade.txt
|
|
// Caller needs to free the buffer if function succeeded
|
|
hr = ReadTextFromFile(szUpgradeLog,
|
|
&lParam.lpText,
|
|
&lParam.cbText,
|
|
&lParam.fUnicode);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hExe = GetModuleHandle(NULL);
|
|
|
|
// Display content of Upgrade.txt in modal dialog
|
|
// The dialog will ask user to continue or stop operation
|
|
nRet = DialogBoxParam(hExe,
|
|
MAKEINTRESOURCE(IDD_UPGRADE_LOG_TEXT),
|
|
GetConsoleWindow(),
|
|
(DLGPROC) UpgradeLogDlgProc,
|
|
(LPARAM) &lParam);
|
|
|
|
MEMFREE(lParam.lpText);
|
|
}
|
|
|
|
return (INT) nRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: UpgradeLogDlgProc
|
|
//
|
|
// Synopsis: Dialog box procedure
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 02/07/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
CALLBACK
|
|
UpgradeLogDlgProc(
|
|
HWND hwndDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
BOOL fBlock;
|
|
WCHAR wszWarning[512];
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
// Init the dialog
|
|
ShowWindow(hwndDlg, SW_SHOWNORMAL);
|
|
|
|
// Search for unsupport component in the text context from upgrade.txt
|
|
fBlock = CheckUnsupportComponent(
|
|
((PUPGRADE_LOG_PARAM) lParam)->lpText,
|
|
((PUPGRADE_LOG_PARAM) lParam)->fUnicode );
|
|
if (fBlock)
|
|
{
|
|
LoadString(g_hInstDll,
|
|
IDS_BLOCKING_WARNING,
|
|
wszWarning,
|
|
ARRAYSIZE(wszWarning));
|
|
SendMessage(GetDlgItem(hwndDlg, ID_CAPTION2),
|
|
WM_SETTEXT,
|
|
wParam,
|
|
(LPARAM) wszWarning);
|
|
|
|
// Disable 'Continue' button if found the unsupport component
|
|
EnableWindow(GetDlgItem(hwndDlg, ID_CONTINUE),
|
|
FALSE);
|
|
}
|
|
else
|
|
{
|
|
LoadString(g_hInstDll,
|
|
IDS_UNLOCALIZED_WARNING,
|
|
wszWarning,
|
|
ARRAYSIZE(wszWarning));
|
|
SendMessage(GetDlgItem(hwndDlg, ID_CAPTION2),
|
|
WM_SETTEXT,
|
|
wParam,
|
|
(LPARAM) wszWarning);
|
|
}
|
|
|
|
// Display text using A or W function depending on type of data
|
|
if ( ((PUPGRADE_LOG_PARAM) lParam)->fUnicode )
|
|
{
|
|
SendMessageW(GetDlgItem(hwndDlg, IDC_TEXT),
|
|
WM_SETTEXT,
|
|
wParam,
|
|
(LPARAM) (((PUPGRADE_LOG_PARAM) lParam)->lpText));
|
|
}
|
|
else
|
|
{
|
|
SendMessageA(GetDlgItem(hwndDlg, IDC_TEXT),
|
|
WM_SETTEXT,
|
|
wParam,
|
|
(LPARAM) (((PUPGRADE_LOG_PARAM) lParam)->lpText));
|
|
}
|
|
|
|
SetForegroundWindow(hwndDlg);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
// Handle command buttons
|
|
switch (wParam)
|
|
{
|
|
case ID_CONTINUE:
|
|
EndDialog(hwndDlg, ID_CONTINUE);
|
|
break;
|
|
|
|
case ID_STOP:
|
|
EndDialog(hwndDlg, ID_STOP);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
EndDialog(hwndDlg, ID_STOP);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: CheckUnsupportComponent
|
|
//
|
|
// Synopsis: Search for unsupport component in upgrade.txt.
|
|
//
|
|
// Returns: TRUE if unsupport component is found,
|
|
// FALSE otherwise
|
|
//
|
|
// History: 02/07/2002 rerkboos created
|
|
//
|
|
// Notes: We determined unsupport component by searching for word
|
|
// "must uninstall" in buffer.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CheckUnsupportComponent(
|
|
LPVOID lpBuffer, // Text buffer
|
|
BOOL fUnicode // Flag indicate if text is Unicode or ANSI
|
|
)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
LPVOID lpStr;
|
|
|
|
if (fUnicode)
|
|
{
|
|
lpStr = (LPWSTR) StrStrW((LPCWSTR) lpBuffer, L"must uninstall");
|
|
}
|
|
else
|
|
{
|
|
lpStr = (LPSTR) StrStrA((LPCSTR) lpBuffer, "must uninstall");
|
|
}
|
|
|
|
if (lpStr)
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: ReadTextFromFile
|
|
//
|
|
// Synopsis: Read text from file into buffer
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// History: 02/07/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT ReadTextFromFile(
|
|
LPCTSTR lpTextFile, // Text file name
|
|
LPVOID *lplpText, // Pointer to a newly allocated buffer
|
|
size_t *lpcbText, // Size of allocated buffer in bytes
|
|
BOOL *lpfUnicode // Flag indicates if data is unicode or not (optional)
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
HANDLE hFile;
|
|
DWORD cbRead;
|
|
BOOL fRet = FALSE;
|
|
|
|
if (lpTextFile == NULL || lplpText == NULL || lpcbText == NULL)
|
|
{
|
|
return fRet;
|
|
}
|
|
|
|
hFile = CreateFile(lpTextFile,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
// Get the size of memory big enough to store text file,
|
|
// plus a null terminator
|
|
*lpcbText = GetFileSize(hFile, NULL) + sizeof(TCHAR);
|
|
|
|
*lplpText = MEMALLOC(*lpcbText);
|
|
if (*lplpText != NULL)
|
|
{
|
|
fRet = ReadFile(hFile, *lplpText, *lpcbText, &cbRead, NULL);
|
|
if (fRet)
|
|
{
|
|
// Set the unicode flag if user supplied the pointer
|
|
if (lpfUnicode != NULL)
|
|
{
|
|
*lpfUnicode = IsTextUnicode(*lplpText, cbRead, NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Failed to read text file
|
|
MEMFREE(*lplpText);
|
|
*lplpText = NULL;
|
|
*lpcbText = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// HeapAlloc failed
|
|
*lpcbText = 0;
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
if (fRet)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// Function: IsNT5
|
|
//
|
|
// Descrip: Check whether current OS is NT5 (Server class)
|
|
//
|
|
// Returns: BOOL
|
|
//
|
|
// Notes: none
|
|
//
|
|
// History: 09/17/2001 xiaoz created
|
|
// 02/18/2002 rerkboos add code to check more criteria
|
|
// 06/10/2002 rerkboos allow DTC to run
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
BOOL IsNT5(VOID)
|
|
{
|
|
OSVERSIONINFOEX osviex;
|
|
|
|
ZeroMemory( &osviex,sizeof(OSVERSIONINFOEX) );
|
|
|
|
osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
|
|
if ( GetVersionEx((LPOSVERSIONINFO) &osviex) )
|
|
{
|
|
return ( (osviex.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
|
|
(osviex.dwMajorVersion == 5) &&
|
|
(osviex.dwMinorVersion == 0) &&
|
|
( (osviex.wSuiteMask & VER_SUITE_ENTERPRISE) ||
|
|
(osviex.wProductType == VER_NT_SERVER) ||
|
|
(osviex.wProductType == VER_NT_DOMAIN_CONTROLLER) ) &&
|
|
(osviex.wProductType != VER_NT_WORKSTATION) );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// Function: IsDotNet
|
|
//
|
|
// Descrip: Check whether current OS is Windows Server 2003
|
|
//
|
|
// Returns: BOOL
|
|
//
|
|
// Notes: none
|
|
//
|
|
// History: 07/09/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
BOOL IsDotNet(VOID)
|
|
{
|
|
OSVERSIONINFOEX osviex;
|
|
|
|
ZeroMemory( &osviex,sizeof(OSVERSIONINFOEX) );
|
|
|
|
osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
|
|
if ( GetVersionEx((LPOSVERSIONINFO) &osviex) )
|
|
{
|
|
return ( (osviex.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
|
|
(osviex.dwMajorVersion == 5) &&
|
|
(osviex.dwMinorVersion == 2) &&
|
|
( (osviex.wSuiteMask & VER_SUITE_ENTERPRISE) ||
|
|
(osviex.wProductType == VER_NT_SERVER) ||
|
|
(osviex.wProductType == VER_NT_DOMAIN_CONTROLLER) ) &&
|
|
(osviex.wProductType != VER_NT_WORKSTATION) );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsNEC98
|
|
//
|
|
// Synopsis: Check whether this machine is NEC98 platform or not.
|
|
//
|
|
// Returns: TRUE if it is NEC98 machine, FALSE otherwise
|
|
//
|
|
// History: 02/18/2001 Rerkboos Created
|
|
//
|
|
// Notes: Code is stolen from Winnt32
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL IsNEC98(VOID)
|
|
{
|
|
BOOL IsNEC98;
|
|
|
|
IsNEC98 = ( (GetKeyboardType(0) == 7) &&
|
|
((GetKeyboardType(1) & 0xff00) == 0x0d00) );
|
|
|
|
return (IsNEC98);
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsIA64
|
|
//
|
|
// Synopsis: Check whether the program is running on 64-bit machine or not
|
|
//
|
|
// Returns: TRUE if it is running on 64-bit machine, FALSE otherwise
|
|
//
|
|
// History: 02/18/2001 Rerkboos Created
|
|
//
|
|
// Notes: Code is stolen from Winnt32
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL IsIA64(VOID)
|
|
{
|
|
ULONG_PTR p;
|
|
NTSTATUS status;
|
|
|
|
status = NtQueryInformationProcess(NtCurrentProcess(),
|
|
ProcessWow64Information,
|
|
&p,
|
|
sizeof(p),
|
|
NULL);
|
|
|
|
return (NT_SUCCESS(status) && p);
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsDomainController
|
|
//
|
|
// Synopsis: Check whether the machine is a domain controller or not
|
|
//
|
|
// Returns: BOOL
|
|
//
|
|
// History: 08/13/2002 Rerkboos Created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL IsDomainController(VOID)
|
|
{
|
|
HRESULT hr;
|
|
BOOL bIsDC = FALSE;
|
|
TCHAR szDCName[MAX_PATH];
|
|
DWORD cchDCName;
|
|
|
|
cchDCName = ARRAYSIZE(szDCName);
|
|
hr = GetDCInfo(&bIsDC, szDCName, &cchDCName);
|
|
|
|
return bIsDC;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsOnTSClient
|
|
//
|
|
// Synopsis: Check whether the program is running in terminal session or not
|
|
//
|
|
// Returns: TRUE if it is running in terminal session, FALSE otherwise
|
|
//
|
|
// History: 02/18/2001 Rerkboos Created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL IsOnTSClient(VOID)
|
|
{
|
|
return GetSystemMetrics(SM_REMOTESESSION);
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsTSInstalled
|
|
//
|
|
// Synopsis: Check whether Terminal Services is installed
|
|
//
|
|
// Returns: TRUE if TS is installed, FALSE otherwise
|
|
//
|
|
// History: 02/18/2001 Rerkboos Created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL IsTSInstalled(VOID)
|
|
{
|
|
ULONGLONG ullConditionMask;
|
|
OSVERSIONINFOEX osviex;
|
|
BOOL fRet = FALSE;
|
|
|
|
ullConditionMask = 0;
|
|
ullConditionMask = VerSetConditionMask(ullConditionMask,
|
|
VER_SUITENAME,
|
|
VER_AND);
|
|
|
|
ZeroMemory(&osviex, sizeof(osviex));
|
|
osviex.dwOSVersionInfoSize = sizeof(osviex);
|
|
osviex.wSuiteMask = VER_SUITE_TERMINAL;
|
|
|
|
fRet = VerifyVersionInfo(&osviex, VER_SUITENAME, ullConditionMask);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsTSConnectionEnabled
|
|
//
|
|
// Synopsis: Check whether the connection to Terminal Services is enabled
|
|
//
|
|
// Returns: TRUE if it is enabled, FALSE otherwise
|
|
//
|
|
// History: 02/18/2001 Rerkboos Created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL IsTSConnectionEnabled(VOID)
|
|
{
|
|
HKEY hKey;
|
|
HKEY hConnKey;
|
|
TCHAR szKeyName[MAX_PATH];
|
|
DWORD cchKeyName;
|
|
DWORD dwIndex;
|
|
DWORD dwType;
|
|
DWORD dwfEnableWinStation;
|
|
DWORD cbfEnableWinStation;
|
|
LONG lEnumRet;
|
|
LONG lRet;
|
|
BOOL fRet = FALSE;
|
|
FILETIME ft;
|
|
HRESULT hr;
|
|
|
|
cchKeyName = ARRAYSIZE(szKeyName);
|
|
|
|
lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT_WINSTATION_KEY,
|
|
0,
|
|
KEY_ENUMERATE_SUB_KEYS,
|
|
&hKey);
|
|
if (ERROR_SUCCESS != lRet)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
dwIndex = 0;
|
|
do
|
|
{
|
|
cchKeyName = ARRAYSIZE(szKeyName);
|
|
|
|
lEnumRet = RegEnumKeyEx(hKey,
|
|
dwIndex,
|
|
szKeyName,
|
|
&cchKeyName,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ft);
|
|
if (ERROR_SUCCESS == lEnumRet)
|
|
{
|
|
// While there is more key to enumerate
|
|
if (CompareString(LOCALE_ENGLISH,
|
|
NORM_IGNORECASE,
|
|
szKeyName,
|
|
-1,
|
|
TEXT("Console"),
|
|
-1)
|
|
!= CSTR_EQUAL)
|
|
{
|
|
// Only check for other connection's key, not Console key
|
|
lRet = RegOpenKeyEx(hKey,
|
|
szKeyName,
|
|
0,
|
|
KEY_READ,
|
|
&hConnKey);
|
|
if (ERROR_SUCCESS != lRet)
|
|
{
|
|
fRet = FALSE;
|
|
break;
|
|
}
|
|
|
|
cbfEnableWinStation = sizeof(dwfEnableWinStation);
|
|
lRet = RegQueryValueEx(hConnKey,
|
|
TEXT("fEnableWinStation"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwfEnableWinStation,
|
|
&cbfEnableWinStation);
|
|
|
|
RegCloseKey(hConnKey);
|
|
|
|
if (ERROR_SUCCESS == lRet)
|
|
{
|
|
// If there is at lease one of connection have WinStation
|
|
// flag enabled, TS connection can still be made
|
|
if ( dwfEnableWinStation )
|
|
{
|
|
fRet = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
dwIndex++;
|
|
|
|
} while(ERROR_SUCCESS == lEnumRet);
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsTSServiceRunning
|
|
//
|
|
// Synopsis: Check whether the TS service is runnning or not
|
|
//
|
|
// Returns: TRUE if it is running, FALSE otherwise
|
|
//
|
|
// History: 02/18/2001 Rerkboos Created
|
|
//
|
|
// Notes: Stolen from Termsrv test code
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL IsTSServiceRunning(VOID)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
SC_HANDLE hServiceController = OpenSCManager(NULL, NULL, GENERIC_READ);
|
|
if (hServiceController)
|
|
{
|
|
SC_HANDLE hTermServ = OpenService(hServiceController,
|
|
TEXT("TermService"),
|
|
SERVICE_QUERY_STATUS);
|
|
if (hTermServ)
|
|
{
|
|
SERVICE_STATUS tTermServStatus;
|
|
if (QueryServiceStatus(hTermServ, &tTermServStatus))
|
|
{
|
|
fRet = (tTermServStatus.dwCurrentState == SERVICE_RUNNING);
|
|
}
|
|
|
|
CloseServiceHandle(hTermServ);
|
|
}
|
|
|
|
CloseServiceHandle(hServiceController);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsOtherSessionOnTS
|
|
//
|
|
// Synopsis: Check whether there is other TS sessions are connected.
|
|
//
|
|
// Returns: TRUE if there is remote session connected, FALSE otherwise
|
|
//
|
|
// History: 02/18/2001 Rerkboos Created
|
|
// 04/17/2002 Rerkboon Fix bug 558942
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL IsOtherSessionOnTS(VOID)
|
|
{
|
|
BOOL fRet;
|
|
DWORD dwSessionCount;
|
|
PWTS_SESSION_INFO pwtsSessionInfo;
|
|
|
|
fRet = WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE,
|
|
0,
|
|
1,
|
|
&pwtsSessionInfo,
|
|
&dwSessionCount);
|
|
if (fRet)
|
|
{
|
|
DWORD i;
|
|
DWORD dwClients = 0;
|
|
|
|
for (i = 0 ; i < dwSessionCount ; i++)
|
|
{
|
|
// Check to see how many clients connect to TS server
|
|
if (pwtsSessionInfo[i].State != WTSListen
|
|
&& pwtsSessionInfo[i].State != WTSIdle
|
|
&& pwtsSessionInfo[i].State != WTSReset
|
|
&& pwtsSessionInfo[i].State != WTSDown
|
|
&& pwtsSessionInfo[i].State != WTSInit)
|
|
{
|
|
dwClients++;
|
|
}
|
|
}
|
|
|
|
fRet = (dwClients > 1 ? TRUE : FALSE);
|
|
|
|
// BUG 558942: free the memory
|
|
WTSFreeMemory(pwtsSessionInfo);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
#define TS_POLICY_SUB_TREE TEXT("Software\\Policies\\Microsoft\\Windows NT\\Terminal Services")
|
|
#define POLICY_DENY_TS_CONNECTIONS TEXT("fDenyTSConnections")
|
|
#define APPLICATION_NAME TEXT("Winlogon")
|
|
#define WINSTATIONS_DISABLED TEXT("WinStationsDisabled")
|
|
|
|
HRESULT DisableWinstations(
|
|
DWORD dwDisabled,
|
|
LPDWORD lpdwPrevStatus
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG lRet;
|
|
BOOL bRet;
|
|
BOOL bPolicyOK;
|
|
DWORD fDenyTSConnections;
|
|
DWORD cbfDenyTSConnections;
|
|
TCHAR szCurrentState[2];
|
|
LPTSTR lpStopString;
|
|
|
|
if (IsTSServiceRunning())
|
|
{
|
|
//
|
|
// Get the current state of WinStations
|
|
//
|
|
if (lpdwPrevStatus)
|
|
{
|
|
GetProfileString(APPLICATION_NAME,
|
|
WINSTATIONS_DISABLED,
|
|
TEXT("0"),
|
|
szCurrentState,
|
|
ARRAYSIZE(szCurrentState));
|
|
*lpdwPrevStatus = _tcstoul(szCurrentState, &lpStopString, 10);
|
|
}
|
|
|
|
//
|
|
// Check if group policy has thrown the big switch, if so, inform and refuse any changes
|
|
//
|
|
fDenyTSConnections = 0;
|
|
cbfDenyTSConnections = sizeof(fDenyTSConnections);
|
|
|
|
lRet = GetRegistryValue(HKEY_LOCAL_MACHINE,
|
|
TS_POLICY_SUB_TREE,
|
|
POLICY_DENY_TS_CONNECTIONS,
|
|
(LPBYTE) &fDenyTSConnections,
|
|
&cbfDenyTSConnections);
|
|
if (lRet == ERROR_SUCCESS)
|
|
{
|
|
if (fDenyTSConnections)
|
|
{
|
|
// Machine policy deny TS connection
|
|
bPolicyOK = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Machine policy allows TS connection
|
|
bPolicyOK = TRUE;
|
|
}
|
|
}
|
|
else if (lRet == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
bPolicyOK = TRUE;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(lRet);
|
|
}
|
|
|
|
//
|
|
// If policy allows to change connection status
|
|
//
|
|
if (SUCCEEDED(hr) && bPolicyOK)
|
|
{
|
|
if (dwDisabled)
|
|
{
|
|
bRet = WriteProfileString(APPLICATION_NAME,
|
|
WINSTATIONS_DISABLED,
|
|
TEXT("1"));
|
|
}
|
|
else
|
|
{
|
|
bRet = WriteProfileString(APPLICATION_NAME,
|
|
WINSTATIONS_DISABLED,
|
|
TEXT("0"));
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: DisplayTaskList
|
|
//
|
|
// Synopsis: Display the list of running task on the system
|
|
//
|
|
// Returns: TRUE if there is tasks running
|
|
// FALSE if there is no other tasks running
|
|
//
|
|
// History: 07/09/2002 Rerkboos Created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL DisplayTaskList()
|
|
{
|
|
HRESULT hr;
|
|
BOOL bRet = FALSE;
|
|
DWORD i;
|
|
DWORD cchTaskList;
|
|
LPTSTR lpTaskList = NULL;
|
|
DWORD cchTask;
|
|
LPTSTR lpTask = NULL;
|
|
DWORD dwMaxCchLen;
|
|
TCHAR szTemp[512];
|
|
TCHAR szCaption[MAX_PATH];
|
|
TCHAR szHeader[MAX_PATH];
|
|
APPLIST_PARAM AppListParam;
|
|
|
|
// Init the AppList structure
|
|
AppListParam.dwNumEntries = 0;
|
|
for (i = 0 ; i < MAX_APP_ENTRIES ; i++)
|
|
{
|
|
AppListParam.lpAppName[i] = NULL;
|
|
}
|
|
|
|
if (LoadString(g_hInstDll, IDS_PRODUCT_NAME, szCaption, ARRAYSIZE(szCaption)) <= 0
|
|
|| LoadString(g_hInstDll, IDS_CLOSE_APP_TEXT, szHeader, ARRAYSIZE(szHeader)) <= 0)
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
|
|
bRet = EnumDesktopWindows(NULL, (WNDENUMPROC) &EnumWindowProc, (LPARAM) &AppListParam);
|
|
if (AppListParam.dwNumEntries > 0)
|
|
{
|
|
cchTaskList = lstrlen(szHeader);
|
|
dwMaxCchLen = 0;
|
|
for (i = 0 ; i < AppListParam.dwNumEntries ; i++)
|
|
{
|
|
cchTask = lstrlen(AppListParam.lpAppName[i]) + 4;
|
|
if (cchTask > dwMaxCchLen)
|
|
{
|
|
dwMaxCchLen = cchTask;
|
|
}
|
|
|
|
cchTaskList += cchTask;
|
|
}
|
|
|
|
// Allocate the string long enough to store a Task name
|
|
lpTask = (LPTSTR) MEMALLOC(dwMaxCchLen * sizeof(TCHAR));
|
|
if (lpTask != NULL)
|
|
{
|
|
// Allocate the string for all the tasks
|
|
lpTaskList = (LPTSTR) MEMALLOC(cchTaskList * sizeof(TCHAR));
|
|
if (lpTaskList != NULL)
|
|
{
|
|
hr = StringCchCopy(lpTaskList, cchTaskList, szHeader);
|
|
for (i = 0 ; i < AppListParam.dwNumEntries ; i++)
|
|
{
|
|
hr = StringCchPrintf(lpTask,
|
|
dwMaxCchLen,
|
|
TEXT("- %s\n"),
|
|
AppListParam.lpAppName[i]);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = StringCchCat(lpTaskList,
|
|
cchTaskList,
|
|
lpTask);
|
|
if (FAILED(hr))
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MessageBox(GetConsoleWindow(), lpTaskList, szCaption, MB_OK);
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
|
|
CLEANUP:
|
|
|
|
if (lpTask != NULL)
|
|
{
|
|
MEMFREE(lpTask);
|
|
}
|
|
|
|
if (lpTaskList != NULL)
|
|
{
|
|
MEMFREE(lpTaskList);
|
|
}
|
|
|
|
for (i = 0 ; i < MAX_APP_ENTRIES ; i++)
|
|
{
|
|
if (AppListParam.lpAppName[i] != NULL)
|
|
{
|
|
MEMFREE(AppListParam.lpAppName[i]);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: EnumWindowProc
|
|
//
|
|
// Synopsis: A callback function for EnumDesktopWindows() in
|
|
// DisplayTaskList() function.
|
|
//
|
|
// Returns: TRUE if no error occured
|
|
// FALSE if something was wrong
|
|
//
|
|
// History: 07/09/2002 Rerkboos Created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CALLBACK EnumWindowProc(
|
|
HWND hwnd,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
HRESULT hr;
|
|
TCHAR szTitle[MAX_PATH];
|
|
TCHAR szOwnerFile[MAX_PATH];
|
|
LPCTSTR lpFileName;
|
|
DWORD dwIndex;
|
|
DWORD cchLen;
|
|
UINT ui;
|
|
PFNGETMODULENAME pfnGetWindowModuleFileName;
|
|
|
|
if (GetWindow(hwnd, GW_OWNER) || !IsWindowVisible(hwnd))
|
|
{
|
|
// Skip child windows or invisible windows
|
|
return TRUE;
|
|
}
|
|
|
|
GetWindowText(hwnd, szTitle, MAX_PATH);
|
|
|
|
if (szTitle[0] == TEXT('\0'))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (MyStrCmpI(szTitle, TEXT("Program Manager")) == LSTR_EQUAL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (hwnd == GetConsoleWindow())
|
|
{
|
|
// Ignore itself
|
|
return TRUE;
|
|
}
|
|
|
|
// Ignore Explorer windows
|
|
lpFileName = GetWindowModuleFileNameOnly(hwnd, szOwnerFile, ARRAYSIZE(szOwnerFile));
|
|
if (StrStrI(szOwnerFile, TEXT("browseui")))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
dwIndex = ((PAPPLIST_PARAM) lParam)->dwNumEntries;
|
|
hr = DuplicateString(&(((PAPPLIST_PARAM) lParam)->lpAppName[dwIndex]),
|
|
&cchLen,
|
|
szTitle);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
bRet = TRUE;
|
|
((PAPPLIST_PARAM) lParam)->dwNumEntries++;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: ShowStartUpDialog
|
|
//
|
|
// Synopsis: Display startup dialog
|
|
//
|
|
// Returns: none
|
|
//
|
|
// History: 08/14/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
INT ShowStartUpDialog()
|
|
{
|
|
return (INT) DialogBoxParam(GetModuleHandle(NULL),
|
|
MAKEINTRESOURCE(IDD_STARTUP_DLG),
|
|
GetConsoleWindow(),
|
|
(DLGPROC) StartUpDlgProc,
|
|
(LPARAM) NULL);
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: StartUpDlgProc
|
|
//
|
|
// Synopsis: Dialog box procedure
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 02/07/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
CALLBACK
|
|
StartUpDlgProc(
|
|
HWND hwndDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
WCHAR wszInfo[1024];
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
// Init the dialog
|
|
ShowWindow(hwndDlg, SW_SHOWNORMAL);
|
|
|
|
if (LoadStringW(g_hInstDll,
|
|
IDS_STARTUP_DLG_INFO,
|
|
wszInfo,
|
|
ARRAYSIZE(wszInfo)))
|
|
{
|
|
SendMessage(GetDlgItem(hwndDlg, ID_STARTUP_DLG_INFO),
|
|
WM_SETTEXT,
|
|
wParam,
|
|
(LPARAM) wszInfo);
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
// Handle command buttons
|
|
switch (wParam)
|
|
{
|
|
case ID_STARTUP_DLG_NEXT:
|
|
EndDialog(hwndDlg, ID_STARTUP_DLG_NEXT);
|
|
break;
|
|
|
|
case ID_STARTUP_DLG_CANCEL:
|
|
EndDialog(hwndDlg, ID_STARTUP_DLG_CANCEL);
|
|
break;
|
|
|
|
case ID_STARTUP_DLG_README:
|
|
ShowReadMe();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
EndDialog(hwndDlg, ID_STARTUP_DLG_CANCEL);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: ShowReadMe
|
|
//
|
|
// Synopsis: Launch notepad to display CLMT readme.txt
|
|
//
|
|
// Returns: none
|
|
//
|
|
// History: 08/14/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
VOID ShowReadMe()
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwErr;
|
|
DWORD i;
|
|
TCHAR szReadmePath[MAX_PATH];
|
|
TCHAR szNotepad[MAX_PATH];
|
|
TCHAR szCmdLine[MAX_PATH];
|
|
|
|
dwErr = GetModuleFileName(NULL, szReadmePath, ARRAYSIZE(szReadmePath));
|
|
if (dwErr == 0)
|
|
{
|
|
szReadmePath[0] = TEXT('\0');
|
|
}
|
|
else
|
|
{
|
|
i = lstrlen(szReadmePath);
|
|
while (i > 0 && szReadmePath[i] != TEXT('\\'))
|
|
{
|
|
i--;
|
|
}
|
|
szReadmePath[i + 1] = TEXT('\0');
|
|
}
|
|
|
|
hr = StringCchCat(szReadmePath, ARRAYSIZE(szReadmePath), TEXT_README_FILE);
|
|
|
|
dwErr = GetFileAttributes(szReadmePath);
|
|
if (dwErr == INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
DoMessageBox(GetConsoleWindow(), IDS_README_NOT_FOUND, IDS_MAIN_TITLE, MB_OK);
|
|
}
|
|
else
|
|
{
|
|
ExpandEnvironmentStrings(TEXT("%systemroot%\\system32\\Notepad.exe"),
|
|
szNotepad,
|
|
ARRAYSIZE(szNotepad));
|
|
|
|
hr = StringCchCopy(szCmdLine, ARRAYSIZE(szCmdLine), szNotepad);
|
|
hr = StringCchCat(szCmdLine, ARRAYSIZE(szCmdLine), TEXT(" "));
|
|
hr = StringCchCat(szCmdLine, ARRAYSIZE(szCmdLine), szReadmePath);
|
|
|
|
StartProcess(szNotepad,
|
|
szCmdLine,
|
|
TEXT("."));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: StartProcess
|
|
//
|
|
// Synopsis: Start a Windows application
|
|
//
|
|
// Returns: TRUE if an application is started
|
|
// FALSE otherwise
|
|
//
|
|
// History: 08/14/2002 rerkboos created
|
|
//
|
|
// Notes: none
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL StartProcess(
|
|
LPCTSTR lpAppName, // Application name
|
|
LPTSTR lpCmdLine, // Application command line
|
|
LPCTSTR lpCurrentDir // Working directory
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
STARTUPINFO siApp;
|
|
PROCESS_INFORMATION piApp;
|
|
|
|
ZeroMemory(&siApp, sizeof(STARTUPINFO));
|
|
siApp.cb = sizeof(STARTUPINFO);
|
|
|
|
// CreateProcess call conforms to security guideline
|
|
bRet = CreateProcess(lpAppName,
|
|
lpCmdLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
NORMAL_PRIORITY_CLASS,
|
|
NULL,
|
|
lpCurrentDir,
|
|
&siApp,
|
|
&piApp);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: ThreadProc
|
|
//
|
|
// Synopsis: A procedure that will be run on remote thread
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 08/20/2002 rerkboos created
|
|
//
|
|
// Notes: Code is copied from Fontspy
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD WINAPI ThreadProc(
|
|
PGETMODULENAME pgmn
|
|
)
|
|
{
|
|
pgmn->szfname[0] = 0;
|
|
if (pgmn->pfnGetModuleHandle(pgmn->szUser32))
|
|
{
|
|
pgmn->pfn(pgmn->hWnd, pgmn->szfname, MAX_PATH);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Function: GetWindowModuleFileNameOnly
|
|
//
|
|
// Synopsis: Get the module name that load the current window
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 08/20/2002 rerkboos created
|
|
//
|
|
// Notes: Code is copied from FontSpy
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
LPCTSTR GetWindowModuleFileNameOnly(
|
|
HWND hWnd,
|
|
LPTSTR lpszFile,
|
|
DWORD cchFile
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwProcessID;
|
|
DWORD dwThreadID;
|
|
HANDLE hProcess;
|
|
HANDLE hThread = NULL;
|
|
DWORD dwXfer;
|
|
PBYTE pv = NULL;
|
|
LPCTSTR psz;
|
|
UINT uCodeSize;
|
|
GETMODULENAME gmn;
|
|
|
|
uCodeSize = (ULONG) GetWindowModuleFileNameOnly - (ULONG) ThreadProc;
|
|
|
|
ZeroMemory(&gmn, sizeof(gmn));
|
|
|
|
__try
|
|
{
|
|
GetWindowThreadProcessId(hWnd, &dwProcessID);
|
|
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
|
|
if (!hProcess)
|
|
{
|
|
hr = StringCchCopy(lpszFile, cchFile, TEXT("Access Denied"));
|
|
__leave;
|
|
}
|
|
|
|
gmn.hWnd = hWnd;
|
|
|
|
hr = StringCchCopy(gmn.szUser32, ARRAYSIZE(gmn.szUser32), TEXT("user32"));
|
|
if (FAILED(hr))
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
gmn.pfn = (PFNGETMODULENAME) GetProcAddress(
|
|
GetModuleHandle(_T("user32")),
|
|
#ifdef UNICODE
|
|
"GetWindowModuleFileNameW"
|
|
#else
|
|
"GetWindowModuleFileNameA"
|
|
#endif
|
|
);
|
|
if (!gmn.pfn)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
gmn.pfnGetModuleHandle = (PFNGETMODULEHANDLE)GetProcAddress(
|
|
GetModuleHandle(_T("kernel32")),
|
|
#ifdef UNICODE
|
|
"GetModuleHandleW"
|
|
#else
|
|
"GetModuleHandleA"
|
|
#endif
|
|
);
|
|
if (!gmn.pfnGetModuleHandle)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
pv = (PBYTE)VirtualAllocEx(
|
|
hProcess,
|
|
0,
|
|
uCodeSize + sizeof(gmn),
|
|
MEM_COMMIT,
|
|
PAGE_EXECUTE_READWRITE
|
|
);
|
|
if (!pv)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
WriteProcessMemory(
|
|
hProcess,
|
|
pv,
|
|
&gmn,
|
|
sizeof(gmn),
|
|
&dwXfer
|
|
);
|
|
|
|
WriteProcessMemory(
|
|
hProcess,
|
|
pv+offsetof(GETMODULENAME, pvCode),
|
|
ThreadProc,
|
|
uCodeSize,
|
|
&dwXfer
|
|
);
|
|
|
|
hThread = CreateRemoteThread(
|
|
hProcess,
|
|
NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) (pv + offsetof(GETMODULENAME, pvCode)),
|
|
pv,
|
|
0,
|
|
&dwThreadID
|
|
);
|
|
|
|
WaitForSingleObject(hThread, INFINITE);
|
|
ReadProcessMemory(hProcess, pv, &gmn, sizeof(gmn), &dwXfer);
|
|
}
|
|
__finally
|
|
{
|
|
if (pv)
|
|
{
|
|
//VirtualFreeEx(hProcess, pv, uCodeSize+sizeof(gmn), MEM_DECOMMIT);
|
|
VirtualFreeEx(hProcess, pv, 0, MEM_RELEASE);
|
|
}
|
|
|
|
if (hProcess != NULL)
|
|
{
|
|
CloseHandle(hProcess);
|
|
}
|
|
|
|
if (hThread != NULL)
|
|
{
|
|
CloseHandle(hThread);
|
|
}
|
|
}
|
|
|
|
hr = StringCchCopy(lpszFile, cchFile, gmn.szfname);
|
|
|
|
psz = _tcsrchr(lpszFile, _T('\\'))+1;
|
|
if (!psz)
|
|
{
|
|
psz = lpszFile;
|
|
}
|
|
|
|
return psz;
|
|
}
|