Descent3/legacy/D3Launch/D3Launch.cpp
2024-06-15 20:13:59 +02:00

1175 lines
33 KiB
C++

/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* 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/>.
--- HISTORICAL COMMENTS FOLLOW ---
* $Logfile: /DescentIII/Main/D3Launch/D3Launch.cpp $
* $Revision: 1.1.1.1 $
* $Date: 2003-08-26 03:56:51 $
* $Author: kevinb $
*
*
*
* $Log: not supported by cvs2svn $
*
* 45 8/20/99 9:54a Nate
* Full OEM Release now calls Ereg
*
* 44 8/19/99 6:13p Samir
* detect vortex1 chipsets.
*
* 43 6/17/99 5:52p Nate
* Fixed bug with Italian Help File copying
*
* 42 6/09/99 2:46p Nate
* Minor changes for different builds
*
* 41 5/26/99 5:07a Nate
* Fixed static OLE dll linking problem
*
* 40 5/23/99 11:44a Nate
* Added change to make sure the DDraw dll gets freed when launcher exits.
*
* 39 5/21/99 3:38p Nate
* Added changes for Rest of World release (new update directory path)
*
* 38 5/19/99 12:29p Nate
* Fixed openGL crash, changed Network speed default, changed OpenGL
* detection to default to unchecked, and removed config file parsing from
* US version
*
* 37 5/07/99 11:23a Nate
* Added support for a launcher config file
*
* 36 4/27/99 10:42p Nate
* Added vsync enabling when direct3d is chosen
*
* 35 4/15/99 12:03p Nate
* Added "Descent 3 Demo 2" build type
*
* 34 4/08/99 1:13p Nate
* Added Pentium III detection
*
* 33 3/19/99 10:18a Nate
* Added OEM_GENERIC compile type
*
* 32 3/15/99 3:05p Nate
* Added fix to multi-language help system
*
* 31 3/12/99 3:29p Nate
* Added more multi-language support
*
* 30 3/02/99 5:45p Nate
* Lots of little changes/fixes
*
* 29 2/26/99 12:50p Nate
* Changed OEM_Voodoo3 names
*
* 28 2/24/99 8:37p Nate
* Various little dialog changes, added "Install Drivers" dialog
*
* 27 2/24/99 1:46p Nate
* Added multi-language support
*
* 26 2/22/99 4:05p Nate
* Made GLU32 fix only for demo version
*
* 25 2/15/99 5:46p Nate
* Made StraightToSetup default to TRUE if it's not in registry at all
*
* 24 2/15/99 1:41p Nate
* Added DirectX installation through DirectSetup
*
* 23 2/12/99 5:00p Nate
* Added some satellite resource DLL test code
*
* 22 1/21/99 11:12a Nate
* Added hacked fix to the Glu32.dll problem
*
* 21 11/30/98 3:00p Nate
* Added StringToLower()
*
* 20 10/21/98 12:10p Nate
*
* 19 10/16/98 3:26p Nate
*
* 18 10/15/98 7:30p Nate
*
* 17 10/15/98 11:31a Nate
* Added Launcher Sound toggling
*
* 16 10/14/98 11:37a Nate
* Added CoInitialize() call for App
*
* 15 10/08/98 6:23p Nate
* Fixed a few bugs.
*
* 14 9/30/98 1:59p Nate
* Added Version constants for demo and full builds
*
* 13 9/29/98 6:05p Nate
* Added the functionality to update the game version from a text file.
*
* 12 9/21/98 5:40p Nate
* Incorporated the new HTML help system
*
* 11 9/16/98 3:23p Nate
* Added m_straight_to_setup detection
*
* 10 9/14/98 3:47p Nate
* Added deletion of memDC's after use.
*
* 9 9/13/98 2:40p Nate
* Added re-selecting of default bitmaps and palettes for the device
* contexts.
*
* 8 9/03/98 6:57p Nate
* Fixed StretchBlt() problem by doing some 256 color conversions
*
* 7 9/02/98 6:42p Nate
* Added improved sound support.
*
* 6 9/01/98 7:15p Nate
* Major Revision #2
*
* 5 8/31/98 6:44p Nate
* Major Revision
*
* 4 8/24/98 7:06p Nate
* Added new AutoUpdate features, and fixed display glitches
*
* 3 8/10/98 10:44a Nate
* Added Language selection support
*
* 2 8/05/98 11:54a Nate
* Initial Version
*
* $NoKeywords: $
*/
// D3Launch.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "mmsystem.h"
#include "D3Launch.h"
#include "D3LaunchDlg.h"
#include "LaunchNames.h"
#include "3D_detect.h"
#include "OS_Config.h"
#include <direct.h>
#include <io.h>
#include <objbase.h>
#include <assert.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Launcher config file options
bool LanguageSelectionEnabled;
bool EregEnabled;
// Launcher sound on/off flag
int LauncherSoundEnabled;
// Declare setup flags
bool VideoCardsDetected;
bool DetailLevelConfigured;
bool NewLanguageSelected;
bool RenderersDetected;
// Flag which indicates if grGlideInit() has been called
bool GlideInited;
// Global storage for DirectX version number
int Dx_version;
// Global storage for DDraw handle
HINSTANCE Dd_dll_handle = NULL;
// Global storage for OpenGL library
HINSTANCE opengl_dll_handle = NULL;
// Values to scale the bitmaps to match the dialog size
double DlgWidthModifier;
double DlgHeightModifier;
// Function to update the game Version after a manual patch
bool ProcessUpdatedVersionFile(void);
// Function to see if user needs Glu32.dll
bool ProcessGlu32DLL(void);
/////////////////////////////////////////////////////////////////////////////
// CD3LaunchApp
BEGIN_MESSAGE_MAP(CD3LaunchApp, CWinApp)
//{{AFX_MSG_MAP(CD3LaunchApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CD3LaunchApp construction
CD3LaunchApp::CD3LaunchApp() {
// TODO: add construction code here,
// Place all significant initialization in InitInstance
m_straight_to_update = 0;
m_hResInst = NULL;
m_hDefResInst = NULL;
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CD3LaunchApp object
CD3LaunchApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CD3LaunchApp initialization
BOOL CD3LaunchApp::FirstInstance() {
HANDLE hnd;
// See if the D3 Launcher mutex has already been created
hnd = OpenMutex(MUTEX_ALL_ACCESS, FALSE, D3_LAUNCHER_MUTEX_NAME);
if (hnd == NULL)
return TRUE; // Nope, this is the first instance
// close the mutex handle
CloseHandle(hnd);
// Determine if another window with our title exists...
CWnd *pWndPrev, *pWndChild;
pWndPrev = CWnd::FindWindow(NULL, szTitle);
if (pWndPrev) {
// if so, does it have any popups?
pWndChild = pWndPrev->GetLastActivePopup();
// If iconic, restore the main window
if (pWndPrev->IsIconic())
pWndPrev->ShowWindow(SW_RESTORE);
// Bring the main window or its popup to
// the foreground
pWndChild->SetForegroundWindow();
}
// and we are done activating the previous one.
return FALSE;
}
// parse for special (outrage) command-line arguments
void CD3LaunchApp::OutrageParseCommandLine() {
// right now all we do is a direct string compare on the
// application object's
// command line var, for the "straight to update" argument
if (!strcmp(m_lpCmdLine, "-straight_to_update")) {
m_straight_to_update = 1;
}
}
BOOL CD3LaunchApp::InitInstance() {
// AfxEnableControlContainer();
// Get a handle for the executable's resources (english)
m_hDefResInst = AfxGetResourceHandle();
// Get the title of the launcher
SetLauncherTitleString();
// If a previous instance of the application is already running,
// then activate it and return FALSE from InitInstance to
// end the execution of this instance.
if (!FirstInstance()) {
return FALSE;
}
// Create the Mutex to signal that the Launcher is currently running
if (CreateMutex(NULL, TRUE, D3_LAUNCHER_MUTEX_NAME) == NULL) {
return FALSE;
}
// Initialize the com object for this ap
CoInitialize(NULL);
// parse the command line
OutrageParseCommandLine();
// check to see if the Setup dialog should be displayed right away
m_straight_to_setup = (UINT)os_config_read_uint(szSectionName, "StraightToSetup", 1);
// check to see if the launcher sound is enabled
LauncherSoundEnabled = os_config_read_uint(szSectionName, "LauncherSoundEnabled", 1);
// check for an updated version text file
ProcessUpdatedVersionFile();
// Setup Config Defaults for Releases
#if (defined(FULL_US_RELEASE) || defined(FULL_AUSSIE_RELEASE) || defined(OEM_GENERIC))
LanguageSelectionEnabled = FALSE;
EregEnabled = TRUE;
#elif (defined(FULL_ROW_RELEASE) && !defined(INITIAL_UK_RELEASE))
LanguageSelectionEnabled = TRUE;
EregEnabled = FALSE;
#elif (defined(FULL_ROW_RELEASE) && defined(INITIAL_UK_RELEASE))
LanguageSelectionEnabled = FALSE;
EregEnabled = FALSE;
#else
LanguageSelectionEnabled = FALSE;
EregEnabled = FALSE;
#endif
#ifdef DEMO
// see if user needs Glu32.dll
ProcessGlu32DLL();
#endif
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
BOOL ret;
/*
// Get the application palette
ret = GetBitmapAndPalette(IDB_PALETTE_BITMAP,&m_bkBmap,&m_palette);
if ( !ret ) return TRUE;
// Get the background bitmap
ret = GetBitmapAndPalette(IDB_D3LAUNCH_BG,&m_bkBmap,NULL);
if ( !ret ) return TRUE;
*/
// Get the background bitmap
ret = GetBitmapAndPalette(IDB_D3LAUNCH_BG, &m_bkBmap, &m_palette);
if (!ret)
return TRUE;
// Nothing has been detected yet
VideoCardsDetected = FALSE;
DetailLevelConfigured = FALSE;
NewLanguageSelected = FALSE;
RenderersDetected = FALSE;
GlideInited = FALSE;
Dx_version = 0;
Dd_dll_handle = NULL;
opengl_dll_handle = NULL;
// Display the main menu dialog
CD3LaunchDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK) {
// TODO: Place code here to handle when the dialog is
// dismissed with OK
} else if (nResponse == IDCANCEL) {
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
int CD3LaunchApp::ExitInstance() {
// If glide has been initialized, shut it down before we exit
// shutdown_glide(); // don't need this now (it shuts it down in 3D_detect)
if (m_hResInst != NULL) {
FreeLibrary(m_hResInst);
m_hResInst = NULL;
}
if (opengl_dll_handle != NULL) {
FreeLibrary(opengl_dll_handle);
opengl_dll_handle = NULL;
}
// Just in case, make sure the DDraw DLL has been freed
if (Dd_dll_handle != NULL) {
FreeLibrary(Dd_dll_handle);
Dd_dll_handle = NULL;
}
return CWinApp::ExitInstance();
}
// Launches user's web browser with appropriate file
#define HELP_DIR "hlp\\"
void help_launch(char *help_filename) {
char curr_dir[_MAX_PATH + 1];
char file_path[_MAX_PATH + 1];
if (_getcwd(curr_dir, _MAX_PATH) == NULL)
return;
sprintf(file_path, "%s\\%s%s", curr_dir, HELP_DIR, help_filename);
// Make sure the help file exist
if (_access(file_path, 0x00) == -1) {
CString nohelp_msg;
nohelp_msg.Format(IDS_D3LAUNCH_NO_HELP, file_path);
AfxMessageBox(nohelp_msg, MB_OK | MB_ICONEXCLAMATION);
return;
}
// Display the help file
url_launch(file_path);
}
// Starts up user's web browser with the given URL
void url_launch(char *url) {
int r;
r = (int)ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOW);
if (r < 32) {
CString txt;
switch (r) {
case 0:
txt.LoadString(IDS_D3LAUNCH_URL_ERR1);
break;
case ERROR_BAD_FORMAT:
txt.LoadString(IDS_D3LAUNCH_URL_ERR2);
break;
case SE_ERR_ACCESSDENIED:
txt.LoadString(IDS_D3LAUNCH_URL_ERR3);
break;
case SE_ERR_ASSOCINCOMPLETE:
txt.LoadString(IDS_D3LAUNCH_URL_ERR4);
break;
case SE_ERR_DDEBUSY:
txt.LoadString(IDS_D3LAUNCH_URL_ERR5);
break;
case SE_ERR_DDEFAIL:
txt.LoadString(IDS_D3LAUNCH_URL_ERR6);
break;
case SE_ERR_DDETIMEOUT:
txt.LoadString(IDS_D3LAUNCH_URL_ERR7);
break;
case SE_ERR_DLLNOTFOUND:
txt.LoadString(IDS_D3LAUNCH_URL_ERR8);
break;
case SE_ERR_OOM:
txt.LoadString(IDS_D3LAUNCH_URL_ERR9);
break;
case SE_ERR_SHARE:
txt.LoadString(IDS_D3LAUNCH_URL_ERR10);
break;
// No browser installed message
case SE_ERR_NOASSOC:
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
txt.LoadString(IDS_D3LAUNCH_URL_ERR11);
break;
default:
txt.LoadString(IDS_D3LAUNCH_URL_ERR12);
break;
}
AfxMessageBox(txt, MB_OK | MB_ICONERROR);
}
}
// Plays a sound (.wav resource)
BOOL PlayResource(LPSTR lpName, bool WaitUntilDone) {
BOOL bRtn;
LPSTR lpRes;
HANDLE hRes;
HRSRC hResInfo;
HINSTANCE Nl = AfxGetResourceHandle();
/* Find the WAVE resource. */
hResInfo = FindResource(Nl, lpName, "WAVE");
if (hResInfo == NULL)
return FALSE;
/* Load the WAVE resource. */
hRes = LoadResource(Nl, hResInfo);
if (hRes == NULL)
return FALSE;
/* Lock the WAVE resource and play it. */
lpRes = (LPSTR)LockResource(hRes);
if (lpRes == NULL)
return FALSE;
int play_type = (WaitUntilDone) ? SND_SYNC : SND_ASYNC;
bRtn = sndPlaySound(lpRes, SND_MEMORY | play_type);
if (bRtn == NULL)
return FALSE;
/* Free the WAVE resource and return success or failure. */
FreeResource(hRes);
return TRUE;
}
// Assigns RGB values to a palette entry
BOOL SetPaletteEntry(PALETTEENTRY *pal_entry, BYTE red, BYTE green, BYTE blue) {
pal_entry->peRed = red;
pal_entry->peGreen = green;
pal_entry->peBlue = blue;
pal_entry->peFlags = 0;
return TRUE;
}
// Loads a bitmap and palette from a given resource ID
BOOL GetBitmapAndPalette(UINT nIDResource, CBitmap *bitmap, CPalette *pal) {
LPCTSTR lpszResourceName = (LPCTSTR)nIDResource;
return (GetBitmapAndPalette(lpszResourceName, bitmap, pal));
}
// Loads a bitmap and palette from a given resource name
BOOL GetBitmapAndPalette(LPCTSTR lpszResourceName, CBitmap *bitmap, CPalette *pal) {
// Make sure a bitmap is given
if (bitmap == NULL)
return TRUE;
// Load in the bitmap resource
HBITMAP hBmp =
(HBITMAP)::LoadImage(AfxGetResourceHandle(), lpszResourceName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
if (hBmp == NULL)
return FALSE;
// Delete any attached objects from the bitmap
if (!bitmap->DeleteObject()) {
// OutputDebugString("DeleteObject() failed.\n");
}
// Attach the bitmap handle to the bitmap
bitmap->Attach(hBmp);
// If no palette is desired, get outta here
if (pal == NULL)
return TRUE;
// Delete any attached objects from the palette
if (!pal->DeleteObject()) {
// OutputDebugString("DeleteObject() failed.\n");
}
// Create a logical palette for the bitmap
DIBSECTION ds;
BITMAPINFOHEADER &bmInfo = ds.dsBmih;
bitmap->GetObject(sizeof(ds), &ds);
int nColors = bmInfo.biClrUsed ? bmInfo.biClrUsed : 1 << bmInfo.biBitCount;
// Create a halftone palette if colors > 256.
CClientDC dc(NULL); // Desktop DC
if (nColors > 256)
pal->CreateHalftonePalette(&dc);
else { // Create the palette
RGBQUAD *pRGB = new RGBQUAD[nColors];
if (pRGB == NULL)
return FALSE;
CDC memDC;
CBitmap *old_bitmap = NULL;
memDC.CreateCompatibleDC(&dc);
old_bitmap = memDC.SelectObject(bitmap);
::GetDIBColorTable(memDC, 0, nColors, pRGB);
if (old_bitmap != NULL)
memDC.SelectObject(old_bitmap);
if (memDC.DeleteDC() == 0)
OutputDebugString("DeleteDC() failed!\n");
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256);
LOGPALETTE *pLP = (LOGPALETTE *)new BYTE[nSize];
if (pLP == NULL) {
delete[] pRGB;
return FALSE;
}
pLP->palVersion = 0x300;
pLP->palNumEntries = 256;
// Set the first 10 entries to default windows colors
SetPaletteEntry(&(pLP->palPalEntry[0]), 0, 0, 0); // Black
SetPaletteEntry(&(pLP->palPalEntry[1]), 128, 0, 0); // Dark Red
SetPaletteEntry(&(pLP->palPalEntry[2]), 0, 128, 0); // Dark Green
SetPaletteEntry(&(pLP->palPalEntry[3]), 128, 128, 0); // Dark Yellow
SetPaletteEntry(&(pLP->palPalEntry[4]), 0, 0, 128); // Dark Blue
SetPaletteEntry(&(pLP->palPalEntry[5]), 128, 0, 128); // Dark Magenta
SetPaletteEntry(&(pLP->palPalEntry[6]), 0, 128, 128); // Dark Cyan
SetPaletteEntry(&(pLP->palPalEntry[7]), 192, 192, 192); // Light Gray
SetPaletteEntry(&(pLP->palPalEntry[8]), 192, 220, 192); // "money" Green
SetPaletteEntry(&(pLP->palPalEntry[9]), 166, 202, 240); // "sky" Blue
// Set the middle 236 entries to the first 236 entries of the palette
for (int i = 0; i < 236; i++) {
if (i < nColors) {
pLP->palPalEntry[i + 10].peRed = pRGB[i].rgbRed;
pLP->palPalEntry[i + 10].peGreen = pRGB[i].rgbGreen;
pLP->palPalEntry[i + 10].peBlue = pRGB[i].rgbBlue;
pLP->palPalEntry[i + 10].peFlags = 0;
} else {
SetPaletteEntry(&(pLP->palPalEntry[i + 10]), 0, 0, 0);
}
}
// Set the last 10 entries to default windows colors
SetPaletteEntry(&(pLP->palPalEntry[246]), 255, 251, 240); // Cream
SetPaletteEntry(&(pLP->palPalEntry[247]), 160, 160, 164); // Medium Gray
SetPaletteEntry(&(pLP->palPalEntry[248]), 128, 128, 128); // Dark Gray
SetPaletteEntry(&(pLP->palPalEntry[249]), 255, 0, 0); // Red
SetPaletteEntry(&(pLP->palPalEntry[250]), 0, 255, 0); // Green
SetPaletteEntry(&(pLP->palPalEntry[251]), 255, 255, 0); // Yellow
SetPaletteEntry(&(pLP->palPalEntry[252]), 0, 0, 255); // Blue
SetPaletteEntry(&(pLP->palPalEntry[253]), 255, 0, 255); // Magenta
SetPaletteEntry(&(pLP->palPalEntry[254]), 0, 255, 255); // Cyan
SetPaletteEntry(&(pLP->palPalEntry[255]), 255, 255, 255); // White
// Create the palette
pal->CreatePalette(pLP);
delete[] pLP;
delete[] pRGB;
}
return TRUE;
}
#define MAX_MESSAGES 10 // max messages to process during a message deferral
// Processes and waiting messages
void DeferMessages(void) {
MSG msg;
for (int MsgCount = MAX_MESSAGES; MsgCount && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); MsgCount--) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Function to see if user needs Glu32.dll
bool ProcessGlu32DLL(void) {
// First, see if Glu32.xyz is even in the directory
if (_access("Glu32.xyz", 0) == -1)
return FALSE;
// Second, see if user's system already has access to a Glu32.dll
HINSTANCE dll_handle;
dll_handle = LoadLibrary("Glu32.dll");
if (dll_handle != NULL) {
FreeLibrary(dll_handle);
DeleteFile("Glu32.xyz");
return FALSE;
}
// Ok, user doesn't have it, so rename ours
rename("Glu32.xyz", "Glu32.dll");
return TRUE;
}
// Checks to see if a new version text file exists (such a file should
// only be created if the user does a manual patch update). If one is
// found, the version info is read from it. If this version is newer
// than the version stored in the registry, it is then written into
// the registry as the new game version.
bool ProcessUpdatedVersionFile(void) {
FILE *f;
uint32_t cur_major, cur_minor, cur_build;
uint32_t new_major, new_minor, new_build;
char buffer[_MAX_PATH + 1];
char verbuffer[_MAX_PATH + 1];
// See if the updated version text file exists
f = fopen(UPDATED_VERSION_FNAME, "rt");
if (f == NULL) {
return FALSE;
}
// Read in the Version info from the text file
new_major = 0;
new_minor = 0;
new_build = 0;
strcpy(buffer, "");
while (!feof(f)) {
// Read the line into a temporary buffer
fgets(buffer, _MAX_PATH, f);
// take the \n off the end of it
if (strlen(buffer) > 0 && buffer[strlen(buffer) - 1] == '\n')
buffer[strlen(buffer) - 1] = 0;
// If the line is empty, go get another one
if (strlen(buffer) == 0)
continue;
// If the line is a comment, go get another one
if (buffer[0] == VERSION_FILE_COMMENT_CHAR)
continue;
// Read in the version line
strcpy(verbuffer, buffer);
sscanf(verbuffer, "%i %i %i", &new_major, &new_minor, &new_build);
}
fclose(f);
if (VER(new_major, new_minor, new_build) == 0) {
DeleteFile(UPDATED_VERSION_FNAME);
return FALSE;
}
// Read in the current version values from the registry
cur_major = os_config_read_uint("Version", "Major", 0);
cur_minor = os_config_read_uint("Version", "Minor", 0);
cur_build = os_config_read_uint("Version", "Build", 0);
// Is the version found in the text file newer than the current version?
if (VER(new_major, new_minor, new_build) <= VER(cur_major, cur_minor, cur_build)) {
DeleteFile(UPDATED_VERSION_FNAME);
return FALSE;
}
// Write the new version into the registry
os_config_write_uint("Version", "Major", new_major);
os_config_write_uint("Version", "Minor", new_minor);
os_config_write_uint("Version", "Build", new_build);
// Get rid of the file
DeleteFile(UPDATED_VERSION_FNAME);
return TRUE;
}
// This function simply returns the interger version value of DirectX
// installed on the user's system
int GetDirectXVersion(void) {
LONG lResult;
HKEY hKey = NULL;
int version_num = 0;
if (Dd_dll_handle) {
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Where it is
"Software\\Microsoft\\DirectX", // name of key
NULL, // DWORD reserved
KEY_QUERY_VALUE, // Allows all changes
&hKey // Location to store key
);
if (lResult == ERROR_SUCCESS) {
char version[32];
DWORD dwType, dwLen;
dwLen = 32;
lResult = RegQueryValueEx(hKey, // Handle to key
"Version", // The values name
NULL, // DWORD reserved
&dwType, // What kind it is
(uint8_t *)version, // value to set
&dwLen // How many bytes to set
);
if (lResult == ERROR_SUCCESS) {
CString str;
version_num = atoi(strstr(version, ".") + 1);
} else {
int val;
DWORD dwType, dwLen;
dwLen = 4;
lResult = RegQueryValueEx(hKey, // Handle to key
"InstalledVersion", // The values name
NULL, // DWORD reserved
&dwType, // What kind it is
(uint8_t *)&val, // value to set
&dwLen // How many bytes to set
);
if (lResult == ERROR_SUCCESS) {
CString str;
version_num = val;
}
}
RegCloseKey(hKey);
}
}
return (version_num);
}
typedef int(CALLBACK *LPFN_DIRECTXSETUPGETVERSION)(DWORD *, DWORD *);
// Attempts to obtain the DirectX version and revision number via the dsetup.dll
bool GetDirectXVersionViaDLL(DWORD *version, DWORD *revision) {
HINSTANCE dsetup_dll_handle = NULL;
LPFN_DIRECTXSETUPGETVERSION pfn_DirectXSetupGetVersion = NULL;
version = 0;
revision = 0;
// Check for the DSetup dll, and open it
dsetup_dll_handle = LoadLibrary("dsetup.dll");
if (dsetup_dll_handle == NULL) {
return FALSE;
}
// Get the DirectXSetup function
pfn_DirectXSetupGetVersion =
(LPFN_DIRECTXSETUPGETVERSION)GetProcAddress(dsetup_dll_handle, "DirectXSetupGetVersionA");
if (pfn_DirectXSetupGetVersion == NULL) {
FreeLibrary(dsetup_dll_handle);
dsetup_dll_handle = NULL;
return FALSE;
}
int rc = pfn_DirectXSetupGetVersion(version, revision);
FreeLibrary(dsetup_dll_handle);
dsetup_dll_handle = NULL;
if (rc == 0)
return FALSE;
return TRUE;
}
// Converts the given string to lower case
void StringToLower(char *string) {
int j;
for (j = 0; string[j] != '\0'; j++)
if (isalpha(string[j]))
string[j] = tolower(string[j]);
}
// Set the launcher dialog title
void SetLauncherTitleString(void) {
#if defined(DEMO)
szTitle.Format(IDS_D3LAUNCH_DEMO_DLGTITLE);
#elif defined(DEMO2)
szTitle.Format(IDS_D3LAUNCH_DEMO2_DLGTITLE);
#elif defined(OEM_GENERIC)
szTitle.Format(IDS_D3LAUNCH_OEM_DLGTITLE);
#elif (defined(OEM_VOODOO3) && !defined(USE_ALL_VIDEO_OPTIONS))
szTitle.Format(IDS_D3LAUNCH_OEMV3_DLGTITLE);
#elif (defined(OEM_VOODOO3) && defined(USE_ALL_VIDEO_OPTIONS))
szTitle.Format(IDS_D3LAUNCH_OEM_DLGTITLE);
#elif defined(OEM_KATMAI)
szTitle.Format(IDS_D3LAUNCH_OEMKM_DLGTITLE);
#else
szTitle.Format(IDS_D3LAUNCH_DLGTITLE);
#endif
}
// Starts up the online registration program
void Register(bool wait_until_done) {
char original_path[_MAX_PATH + 1];
char ereg_path[_MAX_PATH + 1];
_getcwd(original_path, _MAX_PATH);
strcpy(ereg_path, original_path);
strcat(ereg_path, "\\ereg");
_chdir(ereg_path);
// launch the ereg app
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(si);
BOOL ret = CreateProcess("reg32a.exe", // pointer to name of executable module
NULL, // pointer to command line string
NULL, // pointer to process security attributes
NULL, // pointer to thread security attributes
FALSE, // handle inheritance flag
CREATE_DEFAULT_ERROR_MODE, // creation flags
NULL, // pointer to new environment block
NULL, // pointer to current directory name
&si, // pointer to STARTUPINFO
&pi // pointer to PROCESS_INFORMATION
);
// If it was started ok, wait for it to finish before continuing
if (ret && wait_until_done) {
WaitForSingleObject(pi.hProcess, INFINITE);
}
SetCurrentDirectory(original_path);
}
// Copies the appropriate help files into the root directory based
// upon what language is currently selected
void CopyHelpFiles(bool should_overwrite) {
char src_hlp_fname[_MAX_PATH + 1];
char src_cnt_fname[_MAX_PATH + 1];
char hlp_filename[_MAX_PATH + 1];
char cnt_filename[_MAX_PATH + 1];
char hlp_ext[_MAX_EXT + 1];
char cnt_ext[_MAX_EXT + 1];
// Check if files already exist
if (!should_overwrite) {
if (_access(HELP_HLP_FNAME, 0x00) != -1 && _access(HELP_CNT_FNAME, 0x00) != -1)
return;
}
// Build the source help filenames
_splitpath(HELP_HLP_FNAME, NULL, NULL, hlp_filename, hlp_ext);
_splitpath(HELP_CNT_FNAME, NULL, NULL, cnt_filename, cnt_ext);
int lang_type = os_config_read_uint(szSectionName, "LanguageType", LANGUAGE_ENGLISH);
switch (lang_type) {
case LANGUAGE_FRENCH:
sprintf(src_hlp_fname, "%s%s%s%s", LANGUAGE_HELP_PATH, hlp_filename, FRENCH_EXT, hlp_ext);
sprintf(src_cnt_fname, "%s%s%s%s", LANGUAGE_HELP_PATH, cnt_filename, FRENCH_EXT, cnt_ext);
break;
case LANGUAGE_GERMAN:
sprintf(src_hlp_fname, "%s%s%s%s", LANGUAGE_HELP_PATH, hlp_filename, GERMAN_EXT, hlp_ext);
sprintf(src_cnt_fname, "%s%s%s%s", LANGUAGE_HELP_PATH, cnt_filename, GERMAN_EXT, cnt_ext);
break;
case LANGUAGE_ITALIAN:
sprintf(src_hlp_fname, "%s%s%s%s", LANGUAGE_HELP_PATH, hlp_filename, ITALIAN_EXT, hlp_ext);
sprintf(src_cnt_fname, "%s%s%s%s", LANGUAGE_HELP_PATH, cnt_filename, ITALIAN_EXT, cnt_ext);
break;
case LANGUAGE_SPANISH:
sprintf(src_hlp_fname, "%s%s%s%s", LANGUAGE_HELP_PATH, hlp_filename, SPANISH_EXT, hlp_ext);
sprintf(src_cnt_fname, "%s%s%s%s", LANGUAGE_HELP_PATH, cnt_filename, SPANISH_EXT, cnt_ext);
break;
default:
sprintf(src_hlp_fname, "%s%s%s", LANGUAGE_HELP_PATH, hlp_filename, hlp_ext);
sprintf(src_cnt_fname, "%s%s%s", LANGUAGE_HELP_PATH, cnt_filename, cnt_ext);
break;
}
// If any of the source files don't exist, get outta here
if (_access(src_hlp_fname, 0x00) == -1 || _access(src_cnt_fname, 0x00) == -1) {
// Try the english files instead
sprintf(src_hlp_fname, "%s%s%s", LANGUAGE_HELP_PATH, hlp_filename, hlp_ext);
sprintf(src_cnt_fname, "%s%s%s", LANGUAGE_HELP_PATH, cnt_filename, cnt_ext);
if (_access(src_hlp_fname, 0x00) == -1 || _access(src_cnt_fname, 0x00) == -1)
return;
}
// Delete current help files (and their created files)
DeleteFile(HELP_HLP_FNAME);
DeleteFile(HELP_CNT_FNAME);
DeleteFile(HELP_GID_FNAME);
DeleteFile(HELP_FTS_FNAME);
// Copy over the correct files
CopyFile(src_hlp_fname, HELP_HLP_FNAME, FALSE);
CopyFile(src_cnt_fname, HELP_CNT_FNAME, FALSE);
}
// Returns true if this machine can support the CPUID instruction
bool SupportsCPUID() {
bool enabled = true;
__try {
_asm {
pushad
__emit 0x0f // CPUID
__emit 0xa2 // CPUID
popad
}
} __except (1) {
enabled = false;
}
return enabled;
}
// Returns true if this machine can support katmai instructions
bool SupportsKatmai() {
int result = 0;
if (SupportsCPUID()) {
_asm
{
pushad
xor eax,eax;
inc eax;
__emit 0x0f // CPUID
__emit 0xa2 // CPUID
and edx,0x02000000;
je THE_END;
inc result;
THE_END:
popad
}
if (!result) return 0;
} else
return 0;
return 1;
}
// Removes any whitespace padding from the end of a string
void RemoveTrailingWhitespace(char *s) {
int last_char_pos;
last_char_pos = strlen(s) - 1;
while (last_char_pos >= 0 && isspace(s[last_char_pos])) {
s[last_char_pos] = '\0';
last_char_pos--;
}
}
// Returns a pointer to the first non-whitespace char in given string
char *SkipInitialWhitespace(char *s) {
while ((*s) != '\0' && isspace(*s))
s++;
return (s);
}
// Parses the launcher config file and sets appropriate values
void ReadConfigFile(void) {
char path[_MAX_PATH + 1];
char filebuffer[4096 + 1];
char *line, *parm;
FILE *f;
bool done;
// Setup Config Defaults
LanguageSelectionEnabled = TRUE;
EregEnabled = FALSE;
// Try and open the config file
sprintf(path, "%s%s", LANGUAGE_LAUNCHER_PATH, LAUNCHER_CONFIG_FNAME);
f = fopen(path, "rt");
if (f == NULL)
return;
// Read in config file
done = FALSE;
while (!done && !feof(f)) {
strcpy(filebuffer, "");
fgets(filebuffer, 4096, f);
// Get rid of whitespace padding
RemoveTrailingWhitespace(filebuffer);
line = SkipInitialWhitespace(filebuffer);
// If it's an empty line or a comment, skip it
if (strlen(line) == 0 || strncmp(line, "//", 2) == 0)
continue;
// split off line's parameter
line = strtok(line, "=");
if (line == NULL)
continue;
parm = strtok(NULL, "");
if (parm == NULL)
continue;
RemoveTrailingWhitespace(line);
parm = SkipInitialWhitespace(parm);
// Process config file directives
if (stricmp(line, "LANGUAGE_SELECTION") == 0) {
if (stricmp(parm, "ON") == 0) {
LanguageSelectionEnabled = TRUE;
} else {
LanguageSelectionEnabled = FALSE;
}
} else if (stricmp(line, "EREG") == 0) {
if (stricmp(parm, "ON") == 0) {
EregEnabled = TRUE;
} else {
EregEnabled = FALSE;
}
}
}
fclose(f);
}
// Constructs a path in the local file system's syntax
// newPath: stores the constructed path
// absolutePathHeader: absolute path on which the sub directories will be appended
// (specified in local file system syntax)
// takes a variable number of subdirectories which will be concatenated on to the path
// the last argument in the list of sub dirs *MUST* be NULL to terminate the list
void ddio_MakePath(char *newPath, const char *absolutePathHeader, const char *subDir, ...) {
const char delimiter = '\\';
va_list args;
char *currentDir = NULL;
int pathLength = 0;
assert(newPath);
assert(absolutePathHeader);
assert(subDir);
if (newPath != absolutePathHeader) {
strcpy(newPath, absolutePathHeader);
}
// Add the first sub directory
pathLength = strlen(newPath);
if (newPath[pathLength - 1] != delimiter) {
newPath[pathLength] = delimiter; // add the delimiter
newPath[pathLength + 1] = 0; // terminate the string
}
strcat(newPath, subDir);
// Add the additional subdirectories
va_start(args, subDir);
while ((currentDir = va_arg(args, char *)) != NULL) {
pathLength = strlen(newPath);
if (newPath[pathLength - 1] != delimiter) {
newPath[pathLength] = delimiter; // add the delimiter
newPath[pathLength + 1] = 0; // terminate the string
}
strcat(newPath, currentDir);
}
va_end(args);
}
// Split a pathname into its component parts
void ddio_SplitPath(const char *srcPath, char *path, char *filename, char *ext) {
char drivename[_MAX_DRIVE], dirname[_MAX_DIR];
_splitpath(srcPath, drivename, dirname, filename, ext);
if (path)
sprintf(path, "%s%s", drivename, dirname);
}