Descent3/legacy/D3Launch/D3Launch.cpp
2024-05-23 23:07:26 -04:00

1214 lines
31 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[PSPATHNAME_LEN+1];
char verbuffer[PSPATHNAME_LEN+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, PSPATHNAME_LEN, 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);
}