/* * 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 . --- 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 #include #include #include #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; uint cur_major, cur_minor, cur_build; uint 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 (ubyte *) 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 (ubyte *) &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); }