mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 07:31:40 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
597
Code/Installer/WinMain.cpp
Normal file
597
Code/Installer/WinMain.cpp
Normal file
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
** Command & Conquer Renegade(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Installer *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/Installer/WinMain.cpp $*
|
||||
* *
|
||||
* $Author:: Ian_l $*
|
||||
* *
|
||||
* $Modtime:: 1/22/02 2:17p $*
|
||||
* *
|
||||
* $Revision:: 12 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
// Include files.
|
||||
#include "Argv.h"
|
||||
#include "Bufffile.h"
|
||||
#include "Chunkio.h"
|
||||
#include "ErrorHandler.h"
|
||||
#include "FFactory.h"
|
||||
#include "Installer.h"
|
||||
#include "MixFile.h"
|
||||
#include "Msgloop.h"
|
||||
#include "RAMFileFactory.h"
|
||||
#include "Resource.h"
|
||||
#include "SafeTimer.h"
|
||||
#include "SaveLoad.h"
|
||||
#include "Timer.h"
|
||||
#include "Translator.h"
|
||||
#include "Win.h"
|
||||
#include "WW3D.h"
|
||||
#include "WWFile.h"
|
||||
#include <malloc.h>
|
||||
#include <dbt.h>
|
||||
|
||||
|
||||
// Defines.
|
||||
#define AUTORUN_MUTEX_OBJECT TEXT("01AF9993-3492-11d3-8F6F-0060089C05B1")
|
||||
#define APPLICATION_MUTEX_OBJECT TEXT("C6D925A3-7A9B-4ca3-866D-8B4D506C3665")
|
||||
|
||||
|
||||
// Static variables.
|
||||
|
||||
|
||||
// Foward declarations.
|
||||
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
|
||||
ATOM MyRegisterClass (HINSTANCE hInstance);
|
||||
bool Is_Autorun_Running();
|
||||
bool Is_Application_Running();
|
||||
bool Is_Win_95_Or_Above();
|
||||
bool Is_Win_2K_Or_Above();
|
||||
bool Running_As_Administrator();
|
||||
void Prog_End();
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* WinMain -- Entry point to program. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/22/01 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
int result;
|
||||
|
||||
// Initialize command line parser.
|
||||
ArgvClass::Init (lpCmdLine);
|
||||
TranslateDBClass::Initialize();
|
||||
|
||||
try {
|
||||
|
||||
// Set global copy of program instance.
|
||||
ProgramInstance = hInstance;
|
||||
|
||||
// Ensure Autorun or another instance of this application is not running.
|
||||
if ((!Is_Autorun_Running()) && (!Is_Application_Running())) {
|
||||
|
||||
// WARNING: Can only raise fatal system errors (not fatal application errors) until
|
||||
// the translation table has been loaded.
|
||||
const char *installmixname = "InstallMix.dat";
|
||||
const char *installstringsfilename = "InstallStrings.tdb";
|
||||
|
||||
RAMFileFactoryClass ramfilefactory;
|
||||
MixFileFactoryClass mixfilefactory (installmixname, &ramfilefactory);
|
||||
FileClass *file;
|
||||
|
||||
// Perform application initialization.
|
||||
|
||||
// An invalid mixfile factory indicates a read error.
|
||||
if (!mixfilefactory.Is_Valid()) FATAL_SYSTEM_ERROR;
|
||||
|
||||
_TheFileFactory = &mixfilefactory;
|
||||
|
||||
// Load the translation table.
|
||||
file = _TheFileFactory->Get_File (installstringsfilename);
|
||||
if (file == NULL) {
|
||||
|
||||
// Output an appropriate Windows error message.
|
||||
SetLastError (2);
|
||||
FATAL_SYSTEM_ERROR;
|
||||
}
|
||||
file->Open (FileClass::READ);
|
||||
if (file->Is_Available()) {
|
||||
|
||||
ChunkLoadClass cload (file);
|
||||
|
||||
SaveLoadSystemClass::Load (cload);
|
||||
|
||||
} else {
|
||||
|
||||
// Output an appropriate Windows error message.
|
||||
SetLastError (2);
|
||||
FATAL_SYSTEM_ERROR;
|
||||
}
|
||||
file->Close();
|
||||
_TheFileFactory->Return_File (file);
|
||||
|
||||
// Check for valid OS.
|
||||
if (!(Is_Win_95_Or_Above() || Is_Win_2K_Or_Above())) FATAL_APP_ERROR (IDS_BAD_OS);
|
||||
|
||||
// Check for Administrator rights under Win 2k or above.
|
||||
if (Is_Win_2K_Or_Above()) {
|
||||
if (!Running_As_Administrator()) FATAL_APP_ERROR (IDS_NOT_ADMINISTRATOR);
|
||||
}
|
||||
|
||||
// Register function to be called at exit.
|
||||
atexit (Prog_End);
|
||||
|
||||
MyRegisterClass (hInstance);
|
||||
|
||||
MainWindow = CreateWindow (RxStringClass (IDS_APPLICATION_MAIN_WINDOW),
|
||||
StringClass (TxWideStringClass (IDS_APPLICATION_NAME)),
|
||||
WS_SYSMENU|WS_CAPTION|WS_MINIMIZEBOX|WS_CLIPCHILDREN,
|
||||
0, 0, 0, 0,
|
||||
NULL, NULL,
|
||||
hInstance, NULL);
|
||||
|
||||
if (MainWindow == NULL) FATAL_SYSTEM_ERROR;
|
||||
|
||||
ShowCursor (false);
|
||||
_Installer.Install (&mixfilefactory);
|
||||
ShowCursor (true);
|
||||
}
|
||||
result = 1;
|
||||
|
||||
} catch (const WideStringClass &errormessage) {
|
||||
|
||||
// Catch handler for fatal errors.
|
||||
DestroyWindow (MainWindow);
|
||||
Windows_Message_Handler();
|
||||
Message_Box (TxWideStringClass (IDS_APPLICATION_ERROR), errormessage);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
TranslateDBClass::Shutdown();
|
||||
ArgvClass::Free();
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* MyRegisterClass -- *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/22/01 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
ATOM MyRegisterClass (HINSTANCE hInstance)
|
||||
{
|
||||
static RxStringClass _classname (IDS_APPLICATION_MAIN_WINDOW);
|
||||
|
||||
WNDCLASSEX wcex;
|
||||
|
||||
wcex.cbSize = sizeof (WNDCLASSEX);
|
||||
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = (WNDPROC)WndProc;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = hInstance;
|
||||
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_INSTALLER);
|
||||
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
||||
wcex.lpszMenuName = (LPCSTR)IDS_INSTALLER;
|
||||
wcex.lpszClassName = _classname;
|
||||
wcex.hIconSm = LoadIcon (hInstance, (LPCTSTR)IDI_INSTALLER);
|
||||
|
||||
return RegisterClassEx (&wcex);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* WndProc -- Windows message handler. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/22/01 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// Pass this message through to the input handler. If the message
|
||||
// was processed and requires no further action, then return with
|
||||
// this information.
|
||||
if (_Installer.Get_Input() != NULL) {
|
||||
|
||||
LRESULT result = 0;
|
||||
|
||||
if (_Installer.Get_Input()->ProcessMessage (hWnd, message, wParam, lParam, result)) {
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_ACTIVATEAPP:
|
||||
if (wParam && !GameInFocus) {
|
||||
GameInFocus = true;
|
||||
} else {
|
||||
if (!wParam && GameInFocus) {
|
||||
GameInFocus = false;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
return (1);
|
||||
|
||||
case WM_PAINT:
|
||||
ValidateRect (hWnd, NULL);
|
||||
break;
|
||||
|
||||
case WM_CREATE:
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage (0);
|
||||
break;
|
||||
|
||||
case WM_SYSCOMMAND:
|
||||
|
||||
switch (wParam) {
|
||||
|
||||
case SC_CLOSE:
|
||||
|
||||
// Windows sent us a close message - probably in response to Alt-F4. Ignore it.
|
||||
return (0);
|
||||
|
||||
case SC_SCREENSAVE:
|
||||
|
||||
// Windows is about to start the screen saver. If we just return without passing
|
||||
// this message to DefWindowProc then the screen saver will not be allowed to start.
|
||||
return (0);
|
||||
|
||||
case SC_KEYMENU:
|
||||
|
||||
// Ignore all "menu-activation" commands.
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_KEYUP:
|
||||
|
||||
// Test for SHIFT + ESC.
|
||||
if ((wParam & 0xff) == VK_ESCAPE && ((GetKeyState (VK_SHIFT) & 0x8000) != 0x0)) {
|
||||
_Installer.Cancel_Introduction();
|
||||
}
|
||||
|
||||
#if !NDEBUG
|
||||
// Test for Print Screen (screenshot).
|
||||
if ((wParam & 0xff) == VK_SNAPSHOT) {
|
||||
WW3D::Make_Screen_Shot();
|
||||
}
|
||||
#endif
|
||||
|
||||
case WM_MOUSEWHEEL:
|
||||
{
|
||||
if (_Installer.Get_Input() != NULL) {
|
||||
_Installer.Get_Input()->Add_Mouse_Wheel (HIWORD (wParam));
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_DEVICECHANGE:
|
||||
{
|
||||
PDEV_BROADCAST_HDR pdbch;
|
||||
|
||||
pdbch = (PDEV_BROADCAST_HDR) lParam;
|
||||
if (pdbch != NULL) {
|
||||
if (pdbch->dbch_devicetype == DBT_DEVTYP_VOLUME) {
|
||||
|
||||
// Assume that this is the CD-ROM drive.
|
||||
if (wParam == DBT_DEVICEQUERYREMOVE) {
|
||||
ShowWindow (hWnd, SW_MINIMIZE);
|
||||
} else {
|
||||
if (wParam == DBT_DEVICEARRIVAL) {
|
||||
if (IsIconic (hWnd)) {
|
||||
ShowWindow (hWnd, SW_RESTORE);
|
||||
}
|
||||
SetForegroundWindow (hWnd);
|
||||
}
|
||||
}
|
||||
return (TRUE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (DefWindowProc (hWnd, message, wParam, lParam));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* InstallerClass::Is_Autorun_Running -- Determine whether Autorun (a sister application) is *
|
||||
* running. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/22/01 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Is_Autorun_Running()
|
||||
{
|
||||
HANDLE autorunmutex = OpenMutex (MUTEX_ALL_ACCESS & SYNCHRONIZE, FALSE, AUTORUN_MUTEX_OBJECT);
|
||||
|
||||
if (autorunmutex != NULL) {
|
||||
|
||||
HWND window = FindWindow (RxStringClass (IDS_AUTORUN_MAIN_WINDOW), NULL);
|
||||
if (window) {
|
||||
|
||||
CDTimerClass <SafeTimerClass> delaytimer (10 * 1000);
|
||||
|
||||
// Hang around for a while to see if Autorun is about to quit...
|
||||
while ((delaytimer.Value() > 0) && (window != NULL)) {
|
||||
window = FindWindow (RxStringClass (IDS_AUTORUN_MAIN_WINDOW), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle (autorunmutex);
|
||||
|
||||
// If the Autorun window still exists bring it to the foreground.
|
||||
if (window) {
|
||||
|
||||
if (IsIconic (window)) {
|
||||
ShowWindow (window, SW_RESTORE);
|
||||
}
|
||||
SetForegroundWindow (window);
|
||||
}
|
||||
}
|
||||
|
||||
return (autorunmutex != NULL);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* InstallerClass::Is_Application_Running -- Determine whether this application is running. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/22/01 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Is_Application_Running()
|
||||
{
|
||||
HANDLE appmutex = CreateMutex (NULL, FALSE, APPLICATION_MUTEX_OBJECT);
|
||||
if (appmutex == NULL) FATAL_SYSTEM_ERROR;
|
||||
|
||||
// See if the application was already running.
|
||||
HWND prev = FindWindow (RxStringClass (IDS_APPLICATION_MAIN_WINDOW), NULL);
|
||||
if (prev) {
|
||||
if (IsIconic (prev)) {
|
||||
ShowWindow (prev, SW_RESTORE);
|
||||
}
|
||||
SetForegroundWindow (prev);
|
||||
return (true);
|
||||
} else {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* InstallerClass::Is_Win_95_Or_Above -- *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/22/01 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Is_Win_95_Or_Above()
|
||||
{
|
||||
OSVERSIONINFO versioninfo;
|
||||
BOOL result;
|
||||
bool validos = false;
|
||||
|
||||
versioninfo.dwOSVersionInfoSize = sizeof (versioninfo);
|
||||
result = GetVersionEx (&versioninfo);
|
||||
if (result) {
|
||||
if (versioninfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
|
||||
validos = true;
|
||||
}
|
||||
}
|
||||
return (validos);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* InstallerClass::Is_Win_2K_Or_Above -- *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/22/01 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Is_Win_2K_Or_Above()
|
||||
{
|
||||
OSVERSIONINFO versioninfo;
|
||||
BOOL result;
|
||||
bool validos = false;
|
||||
|
||||
versioninfo.dwOSVersionInfoSize = sizeof (versioninfo);
|
||||
result = GetVersionEx (&versioninfo);
|
||||
if (result) {
|
||||
if (versioninfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
|
||||
validos = (versioninfo.dwMajorVersion >= 5) && (versioninfo.dwMinorVersion >= 0);
|
||||
}
|
||||
}
|
||||
return (validos);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* InstallerClass::Running_As_Administrator -- *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/22/01 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Running_As_Administrator()
|
||||
{
|
||||
bool fAdmin;
|
||||
HANDLE hThread;
|
||||
TOKEN_GROUPS *ptg = NULL;
|
||||
DWORD cbTokenGroups;
|
||||
DWORD dwGroup;
|
||||
PSID psidAdmin;
|
||||
|
||||
SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
|
||||
|
||||
// Open a handle to the access token for this thread.
|
||||
if (!OpenThreadToken (GetCurrentThread(), TOKEN_QUERY, FALSE, &hThread)) {
|
||||
|
||||
if (GetLastError() == ERROR_NO_TOKEN) {
|
||||
|
||||
// If the thread does not have an access token, examine the access token associated with the process.
|
||||
if (! OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hThread)) {
|
||||
return (false);
|
||||
}
|
||||
} else {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
// Query the size of the group information associated with the token. Note that we expect a FALSE result from GetTokenInformation
|
||||
// because we've given it a NULL buffer. On exit cbTokenGroups will tell the size of the group information.
|
||||
if (GetTokenInformation (hThread, TokenGroups, NULL, 0, &cbTokenGroups)) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Verify that GetTokenInformation failed for lack of a large enough buffer.
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Allocate a buffer for the group information. Since _alloca allocates on the stack, we don't have
|
||||
// to explicitly deallocate it. That happens automatically when we exit this function.
|
||||
if (!(ptg = (TOKEN_GROUPS*) _alloca (cbTokenGroups))) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Ask for the group information again. This may fail if an administrator has added this account
|
||||
// to an additional group between our first call to GetTokenInformation and this one.
|
||||
if (!GetTokenInformation (hThread, TokenGroups, ptg, cbTokenGroups, &cbTokenGroups)) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Create a System Identifier for the Admin group.
|
||||
if (!AllocateAndInitializeSid (&SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin)) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Iterate through the list of groups for this access token looking for a match against the SID we created above.
|
||||
fAdmin = false;
|
||||
|
||||
for (dwGroup = 0; dwGroup < ptg->GroupCount; dwGroup++) {
|
||||
if (EqualSid (ptg->Groups[dwGroup].Sid, psidAdmin)) {
|
||||
fAdmin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Explicity deallocate the SID we created.
|
||||
FreeSid (psidAdmin);
|
||||
return (fAdmin);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Prog_End -- *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/22/01 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
void Prog_End()
|
||||
{
|
||||
try {
|
||||
|
||||
_Installer.On_Prog_End();
|
||||
|
||||
} catch (const WideStringClass &errormessage) {
|
||||
|
||||
// Catch handler for fatal errors.
|
||||
DestroyWindow (MainWindow);
|
||||
Windows_Message_Handler();
|
||||
Message_Box (TxWideStringClass (IDS_APPLICATION_ERROR), errormessage);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user