1797 lines
41 KiB
C++
1797 lines
41 KiB
C++
/*
|
|
** Command & Conquer Generals Zero Hour(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/>.
|
|
*/
|
|
|
|
//
|
|
// This module takes care of all the Chat API stuff
|
|
//
|
|
|
|
#include <list>
|
|
#include "GameSpy/ghttp/ghttp.h"
|
|
#include "downloadManager.h"
|
|
|
|
#include "chatapi.h"
|
|
|
|
//#include "api/wolapi_i.c" // This should only be in one .cpp file
|
|
#include <objbase.h>
|
|
#include <windows.h>
|
|
#include <initguid.h>
|
|
#include <olectl.h>
|
|
#include <mapicode.h>
|
|
#include "resource.h"
|
|
#include "winblows.h"
|
|
#include <crtdbg.h>
|
|
#include "process.h"
|
|
#include "WWDownload/registry.h"
|
|
#include "WWDownload/urlBuilder.h"
|
|
#include "debug.h"
|
|
|
|
enum EVENT_TYPES
|
|
{
|
|
NOUPDATE_EVENT=0, // don't need to update
|
|
ABORT_EVENT,
|
|
NUM_EVENTS // keep last
|
|
};
|
|
|
|
#define GAME_NAME "Command & Conquer"
|
|
|
|
HANDLE Events[NUM_EVENTS];
|
|
|
|
char g_UpdateString[256]; // for the filename
|
|
char g_DLTimeRem[80];
|
|
char g_DLBytesLeft[80];
|
|
char g_DLBPS[80];
|
|
|
|
int g_Finished=0;
|
|
|
|
|
|
HWND g_DownloadWindow;
|
|
HWND g_ContactWindow;
|
|
HWND g_PrimaryWindow;
|
|
|
|
static bool checkingForPatch = false;
|
|
static int checksLeft = 0;
|
|
static bool cantConnect = false;
|
|
static std::list<QueuedDownload> queuedDownloads;
|
|
|
|
BOOL CALLBACK downloadDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam );
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void startOnline( void );
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
QueuedDownload TheDownload;
|
|
|
|
class DownloadManagerMunkee : public DownloadManager
|
|
{
|
|
public:
|
|
DownloadManagerMunkee() { }
|
|
virtual HRESULT OnError( int error );
|
|
virtual HRESULT OnEnd();
|
|
virtual HRESULT OnProgressUpdate( int bytesread, int totalsize, int timetaken, int timeleft );
|
|
virtual HRESULT OnStatusUpdate( int status );
|
|
virtual HRESULT downloadFile( std::string server, std::string username, std::string password, std::string file, std::string localfile, std::string regkey, bool tryResume );
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT DownloadManagerMunkee::downloadFile( std::string server, std::string username, std::string password, std::string file, std::string localfile, std::string regkey, bool tryResume )
|
|
{
|
|
/*
|
|
if (staticTextFile)
|
|
{
|
|
UnicodeString fileString;
|
|
fileString.translate(file);
|
|
GadgetStaticTextSetText(staticTextFile, fileString);
|
|
}
|
|
*/
|
|
return DownloadManager::downloadFile( server, username, password, file, localfile, regkey, tryResume );
|
|
}
|
|
HRESULT DownloadManagerMunkee::OnError( int error )
|
|
{
|
|
HRESULT ret = DownloadManager::OnError( error );
|
|
g_Finished = -1;
|
|
return ret;
|
|
}
|
|
HRESULT DownloadManagerMunkee::OnEnd()
|
|
{
|
|
HRESULT ret = DownloadManager::OnEnd();
|
|
g_Finished = 1;
|
|
return ret;
|
|
}
|
|
HRESULT DownloadManagerMunkee::OnProgressUpdate( int bytesread, int totalsize, int timetaken, int timeleft )
|
|
{
|
|
HRESULT ret = DownloadManager::OnProgressUpdate( bytesread, totalsize, timetaken, timeleft );
|
|
|
|
SendDlgItemMessage( g_DownloadWindow, IDC_PROGRESS, PBM_SETPOS, (WPARAM)(bytesread * 100) / totalsize, 0 );
|
|
char temp[256];
|
|
|
|
if( timeleft > 0 )
|
|
{
|
|
//DBGMSG("Bytes read: "<<bytesread<<". Time left: "<<timeleft<<" seconds");
|
|
LoadString(Global_instance, TXT_TIME_REMAIN, temp, sizeof(temp));
|
|
sprintf(g_DLTimeRem,temp,(timeleft/60),(timeleft%60));
|
|
|
|
LoadString(Global_instance, TXT_BPS, temp, sizeof(temp));
|
|
sprintf(g_DLBPS,temp,bytesread/timetaken);
|
|
}
|
|
LoadString(Global_instance, TXT_BYTES_READ, temp, sizeof(temp));
|
|
sprintf(g_DLBytesLeft,temp,bytesread,totalsize);
|
|
return ret;
|
|
}
|
|
HRESULT DownloadManagerMunkee::OnStatusUpdate( int status )
|
|
{
|
|
HRESULT ret = DownloadManager::OnStatusUpdate( status );
|
|
SetWindowText(g_DownloadWindow, getStatusString().c_str());
|
|
return ret;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
BOOL CALLBACK simpleDialogProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
switch( uMsg )
|
|
{
|
|
case WM_INITDIALOG:
|
|
return(TRUE);
|
|
break;
|
|
case WM_CLOSE:
|
|
DestroyWindow(hwnd);
|
|
PostQuitMessage(0);
|
|
exit(0);
|
|
break;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
static void startOnline( void )
|
|
{
|
|
checkingForPatch = false;
|
|
|
|
// Close that contacting window
|
|
DestroyWindow(g_ContactWindow);
|
|
g_ContactWindow=NULL;
|
|
|
|
if (cantConnect)
|
|
{
|
|
MessageBox(NULL, "Can't Connect", GAME_NAME, MB_OK);
|
|
exit(0);
|
|
}
|
|
else if (queuedDownloads.size())
|
|
{
|
|
if (MessageBox(NULL, "Patches Available. Download?", GAME_NAME, MB_YESNO) == IDYES)
|
|
{
|
|
DEBUG_LOG(("Downloading patches\n"));
|
|
while (queuedDownloads.size())
|
|
{
|
|
TheDownload = queuedDownloads.front();
|
|
queuedDownloads.pop_front();
|
|
TheDownloadManager = new DownloadManagerMunkee;
|
|
/**/
|
|
int retVal = DialogBox(Global_instance, MAKEINTRESOURCE(IDD_DOWNLOAD_DIALOG), g_PrimaryWindow, downloadDialogProc);
|
|
if (retVal)
|
|
{
|
|
DEBUG_LOG(("Error %d\n", GetLastError()));
|
|
}
|
|
/**/
|
|
/*
|
|
{
|
|
//char *res = MAKEINTRESOURCE(IDD_CONNECTING);
|
|
char *res = MAKEINTRESOURCE(IDD_DOWNLOAD_DIALOG1);
|
|
g_DownloadWindow=CreateDialog(Global_instance,res,g_PrimaryWindow,simpleDialogProc);
|
|
ShowWindow(g_DownloadWindow,SW_SHOWNORMAL);
|
|
SetForegroundWindow(g_DownloadWindow);
|
|
}
|
|
*/
|
|
delete TheDownloadManager;
|
|
TheDownloadManager = NULL;
|
|
|
|
if (g_Finished != 1)
|
|
{
|
|
// Download failed
|
|
//DBGMSG("Download failed: "<<retval);
|
|
SetEvent(Events[ABORT_EVENT]);
|
|
return;
|
|
}
|
|
}
|
|
exit(0);
|
|
}
|
|
else
|
|
{
|
|
exit(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MessageBox(NULL, "No Patches Available", GAME_NAME, MB_OK);
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::string trim(std::string s, const std::string& delim)
|
|
{
|
|
unsigned int i;
|
|
i = s.find_first_not_of(delim);
|
|
if (i != s.npos)
|
|
{
|
|
s = s.substr(i);
|
|
}
|
|
|
|
i = s.find_last_not_of(delim);
|
|
if (i>=0 && i<s.npos)
|
|
{
|
|
s = s.substr(0, i+1);
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::string getNextLine(std::string in, std::string& remainder)
|
|
{
|
|
int lineEnd;
|
|
lineEnd = in.find_first_of("\n\r", 0);
|
|
if (lineEnd < 1)
|
|
{
|
|
remainder = "";
|
|
return in;
|
|
}
|
|
|
|
std::string out = in.substr(0, lineEnd);
|
|
remainder = in.substr(lineEnd+1);
|
|
|
|
remainder = trim(remainder, "\r\n\t ");
|
|
out = trim(out, "\r\t\n ");
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------------
|
|
inline const char* skipSeps(const char* p, const char* seps)
|
|
{
|
|
while (*p && strchr(seps, *p) != NULL)
|
|
++p;
|
|
return p;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
inline const char* skipNonSeps(const char* p, const char* seps)
|
|
{
|
|
while (*p && strchr(seps, *p) == NULL)
|
|
++p;
|
|
return p;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool nextToken(std::string& base, std::string& tok, const char* seps = NULL)
|
|
{
|
|
if (base.empty())
|
|
return false;
|
|
|
|
if (seps == NULL)
|
|
seps = " \n\r\t";
|
|
|
|
const char* start = skipSeps(base.c_str(), seps);
|
|
const char* end = skipNonSeps(start, seps);
|
|
|
|
if (end > start)
|
|
{
|
|
int len = end - start;
|
|
char* tmp = new char[len+1];
|
|
memcpy(tmp, start, len);
|
|
tmp[len] = 0;
|
|
|
|
tok = tmp;
|
|
delete[] tmp;
|
|
|
|
base = end;
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
base = tok = "";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void queuePatch(bool mandatory, std::string downloadURL)
|
|
{
|
|
// downloadURL is of the form "ftp://ftp.ea.com:user@pass/pub/munkee/bananna.rtp"
|
|
QueuedDownload q;
|
|
bool success = true;
|
|
|
|
std::string connectionType;
|
|
success = success && nextToken(downloadURL, connectionType, ":");
|
|
|
|
std::string server;
|
|
success = success && nextToken(downloadURL, server, ":/");
|
|
|
|
std::string user;
|
|
success = success && nextToken(downloadURL, user, ":@");
|
|
|
|
std::string pass;
|
|
success = success && nextToken(downloadURL, pass, "@/");
|
|
|
|
std::string filePath;
|
|
success = success && nextToken(downloadURL, filePath, "");
|
|
|
|
if (!success && !user.empty())
|
|
{
|
|
// no user/pass combo - move the file into it's proper place
|
|
filePath = user;
|
|
user = ""; // LFeenanEA - Credentials removed as per Security requirements
|
|
pass = "";
|
|
success = true;
|
|
}
|
|
|
|
std::string fileStr = filePath;
|
|
unsigned int slashPos = filePath.find_last_of('/');
|
|
std::string fileDir = "patches\\";
|
|
std::string fileName = "";
|
|
if (slashPos == filePath.npos)
|
|
{
|
|
fileName = filePath;
|
|
}
|
|
else
|
|
{
|
|
fileName = filePath.substr(slashPos+1);
|
|
}
|
|
fileDir.append(fileName);
|
|
|
|
DEBUG_LOG(("download URL split: %d [%s] [%s] [%s] [%s] [%s] [%s] [%s]\n",
|
|
success, connectionType.c_str(), server.c_str(), user.c_str(), pass.c_str(),
|
|
filePath.c_str(), fileName.c_str(), fileDir.c_str()));
|
|
|
|
if (!success)
|
|
return;
|
|
|
|
q.file = filePath;
|
|
q.localFile = fileDir;
|
|
q.password = pass;
|
|
q.regKey = "";
|
|
q.server = server;
|
|
q.tryResume = true;
|
|
q.userName = user;
|
|
|
|
std::list<QueuedDownload>::iterator it = queuedDownloads.begin();
|
|
while (it != queuedDownloads.end())
|
|
{
|
|
if (it->localFile == q.localFile)
|
|
return; // don't add it if it exists already (because we can check multiple times)
|
|
++it;
|
|
}
|
|
|
|
queuedDownloads.push_back(q);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static GHTTPBool patchCheckCallback( GHTTPRequest request, GHTTPResult result, char * buffer, int bufferLen, void * param )
|
|
{
|
|
--checksLeft;
|
|
DEBUG_ASSERTCRASH(checksLeft>=0, ("Too many callbacks"));
|
|
|
|
DEBUG_LOG(("Result=%d, buffer=[%s], len=%d\n", result, buffer, bufferLen));
|
|
if (result != GHTTPSuccess)
|
|
{
|
|
cantConnect = true;
|
|
if (!checksLeft)
|
|
{
|
|
startOnline();
|
|
}
|
|
return GHTTPTrue;
|
|
}
|
|
|
|
std::string message = buffer;
|
|
std::string line;
|
|
while (nextToken(message, line, "\r\n"))
|
|
{
|
|
std::string type, req, url;
|
|
bool ok = true;
|
|
ok = ok && nextToken(line, type, " ");
|
|
ok = ok && nextToken(line, req, " ");
|
|
ok = ok && nextToken(line, url, " ");
|
|
if (ok && type == "patch")
|
|
{
|
|
DEBUG_LOG(("Saw a patch: %d/[%s]\n", atoi(req.c_str()), url.c_str()));
|
|
queuePatch( atoi(req.c_str()), url );
|
|
}
|
|
else if (ok && type == "server")
|
|
{
|
|
}
|
|
}
|
|
|
|
if (!checksLeft)
|
|
{
|
|
startOnline();
|
|
}
|
|
|
|
return GHTTPTrue;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void StartPatchCheck( void )
|
|
{
|
|
checkingForPatch = true;
|
|
std::string gameURL, mapURL;
|
|
std::string configURL, motdURL;
|
|
|
|
FormatURLFromRegistry(gameURL, mapURL, configURL, motdURL);
|
|
|
|
std::string proxy;
|
|
if (GetStringFromRegistry("", "Proxy", proxy))
|
|
{
|
|
if (!proxy.empty())
|
|
{
|
|
ghttpSetProxy(proxy.c_str());
|
|
}
|
|
}
|
|
|
|
// check for a patch first
|
|
checksLeft = 2;
|
|
cantConnect = false;
|
|
ghttpGet(gameURL.c_str(), GHTTPFalse, patchCheckCallback, NULL);
|
|
ghttpGet(mapURL.c_str(), GHTTPFalse, patchCheckCallback, NULL);
|
|
|
|
DEBUG_LOG(("Started looking for patches at '%s' && '%s'\n", gameURL.c_str(), mapURL.c_str()));
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
BOOL CALLBACK downloadDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
// HRESULT res;
|
|
|
|
int cmd = LOWORD(wParam);
|
|
switch( uMsg )
|
|
{
|
|
case WM_COMMAND:
|
|
if ( cmd == IDC_DLABORT )
|
|
{
|
|
|
|
char abort[128];
|
|
char abortdload[256];
|
|
LoadString(Global_instance, TXT_ABORT_DOWNLOAD, abortdload, sizeof(abortdload));
|
|
LoadString(Global_instance, TXT_ABORT, abort, sizeof(abort));
|
|
|
|
if (MessageBox(g_PrimaryWindow,abortdload,abort,MB_YESNO)==IDYES)
|
|
{
|
|
TheDownloadManager->reset();
|
|
|
|
EndDialog( hwndDlg, g_Finished );
|
|
DestroyWindow(hwndDlg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
//SetupDownload();
|
|
|
|
SendMessage(hwndDlg, WM_SETICON,(WPARAM)ICON_SMALL,
|
|
(LPARAM)LoadIcon(Global_instance, MAKEINTRESOURCE(IDI_ICON1)));
|
|
|
|
g_DLTimeRem[0]=0;
|
|
g_DLBytesLeft[0]=0;
|
|
g_DLBPS[0]=0;
|
|
|
|
//SetDlgItemText( hwndDlg, IDC_DOWNLOADTITLE, g_UpdateString);
|
|
//SetWindowText(hwndDlg, g_UpdateString);
|
|
|
|
SetDlgItemText( hwndDlg, IDC_TIMEREM, g_DLTimeRem);
|
|
SetDlgItemText( hwndDlg, IDC_BYTESLEFT, g_DLBytesLeft);
|
|
// SetDlgItemText( hwndDlg, IDC_BPS, g_DLBPS );
|
|
|
|
// Work out the full file name
|
|
//char fullpath[_MAX_PATH];
|
|
//char localfile[_MAX_PATH];
|
|
//sprintf( fullpath, "%s/%s", g_Update->patchpath,g_Update->patchfile);
|
|
//sprintf(localfile,"%s\\%s",g_Update->localpath,g_Update->patchfile);
|
|
|
|
// Create the directory
|
|
//CreateDirectory((char *)g_Update->localpath, NULL );
|
|
|
|
TheDownloadManager->downloadFile(TheDownload.server, TheDownload.userName, TheDownload.password,
|
|
TheDownload.file, TheDownload.localFile, TheDownload.regKey, TheDownload.tryResume);
|
|
/*
|
|
res=pDownload->DownloadFile((char *)g_Update->server, (char *)g_Update->login, (char *)g_Update->password,
|
|
fullpath, localfile, APP_REG_KEY);
|
|
|
|
*/
|
|
g_DownloadWindow = hwndDlg;
|
|
g_Finished = 0;
|
|
SetTimer( hwndDlg, 1, 200, NULL ); // was 50
|
|
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
DEBUG_LOG(("TIMER\n"));
|
|
if( g_Finished == 0 )
|
|
{
|
|
DEBUG_LOG(("Entering PumpMsgs\n"));
|
|
TheDownloadManager->update();
|
|
/*
|
|
pDownload->PumpMessages();
|
|
*/
|
|
DEBUG_LOG(("Done with PumpMsgs\n"));
|
|
if (strlen(g_DLTimeRem))
|
|
SetDlgItemText( hwndDlg, IDC_TIMEREM, g_DLTimeRem );
|
|
if (strlen(g_DLBytesLeft))
|
|
SetDlgItemText( hwndDlg, IDC_BYTESLEFT, g_DLBytesLeft );
|
|
//if (strlen(g_DLBPS))
|
|
// SetDlgItemText( hwndDlg, IDC_BPS, g_DLBPS );
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(("TIMER: Finished\n"));
|
|
EndDialog( hwndDlg, g_Finished );
|
|
DestroyWindow( hwndDlg );
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
KillTimer( hwndDlg, 1 );
|
|
//ClosedownDownload();
|
|
|
|
//DBGMSG("WM_DESTROY");
|
|
break;
|
|
|
|
case WM_SETFONT:
|
|
return TRUE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
DWORD dwChatAdvise;
|
|
DWORD dwDownloadAdvise;
|
|
|
|
//Update *g_Update;
|
|
|
|
uint32 g_AppVer=-1;
|
|
|
|
|
|
BOOL CALLBACK Download_Dialog_Proc( HWND hwndDlg, UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam );
|
|
|
|
BOOL CALLBACK Simple_Dialog_Proc( HWND hwndDlg, UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam );
|
|
|
|
HWND CreatePrimaryWin(void);
|
|
|
|
char const * Fetch_String(int id);
|
|
|
|
|
|
//
|
|
// Create a primary window
|
|
//
|
|
HWND CreatePrimaryWin(void)
|
|
{
|
|
HWND hwnd;
|
|
WNDCLASS wc;
|
|
char name[256];
|
|
|
|
sprintf(name,Fetch_String(TXT_TITLE));
|
|
|
|
//DBGMSG("CreatePrimary: "<<name);
|
|
|
|
/*
|
|
** set up and register window class
|
|
*/
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = DefWindowProc;
|
|
wc.cbClsExtra = 0; // Don't need any extra class data
|
|
wc.cbWndExtra = 0; // No extra win data
|
|
wc.hInstance = Global_instance;
|
|
wc.hIcon=LoadIcon(Global_instance, MAKEINTRESOURCE(IDI_ICON1));
|
|
wc.hCursor = NULL; /////////LoadCursor( NULL, IDC_ARROW );
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = name;
|
|
wc.lpszClassName = name;
|
|
RegisterClass( &wc );
|
|
|
|
/*
|
|
** create a window
|
|
*/
|
|
hwnd = CreateWindowEx(
|
|
WS_EX_APPWINDOW,
|
|
name,
|
|
name,
|
|
WS_POPUP,
|
|
0, 0,
|
|
|
|
//GetSystemMetrics( SM_CXSCREEN ),
|
|
//GetSystemMetrics( SM_CYSCREEN ),
|
|
0,0,
|
|
|
|
NULL,
|
|
NULL,
|
|
Global_instance,
|
|
NULL );
|
|
|
|
SendMessage(hwnd,WM_SETICON,(WPARAM)ICON_SMALL,
|
|
(LPARAM)LoadIcon(Global_instance, MAKEINTRESOURCE(IDI_ICON1)));
|
|
|
|
ShowWindow(hwnd,SW_SHOWNORMAL);
|
|
|
|
return(hwnd);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Dispatch pending windows events
|
|
//
|
|
void DispatchEvents(void)
|
|
{
|
|
MSG msg;
|
|
int counter=0;
|
|
while(PeekMessage(&msg,NULL,0,0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
counter++;
|
|
if (counter==256) // just in case
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check for patches
|
|
//
|
|
int main(int argc, char *argv[])
|
|
{
|
|
InitCommonControls();
|
|
|
|
/*
|
|
g_PrimaryWindow=CreatePrimaryWin(); // Create the main window
|
|
DispatchEvents(); // process some win messages
|
|
*/
|
|
|
|
/*
|
|
// Check if they've registered before, if not ask them if they want to
|
|
bool have_registered=false;
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,REGISTER_REG_KEY,0,KEY_READ,&rKey)==ERROR_SUCCESS)
|
|
{
|
|
char username[64];
|
|
valuesize=sizeof(username);
|
|
if (RegQueryValueEx(rKey,"UserName",NULL,&type,(uint8 *)username,&valuesize)==ERROR_SUCCESS)
|
|
have_registered=true;
|
|
RegCloseKey(rKey);
|
|
}
|
|
if (!have_registered)
|
|
{
|
|
if (RegOpenKeyEx(HKEY_CLASSES_ROOT,NICK_REG_KEY,0,KEY_READ,&rKey)==ERROR_SUCCESS)
|
|
{
|
|
have_registered=true;
|
|
RegCloseKey(rKey);
|
|
}
|
|
}
|
|
|
|
if (!have_registered)
|
|
{
|
|
if (MessageBox(NULL,Fetch_String(TXT_REGNOW),Fetch_String(TXT_TITLE),MB_YESNO)==IDNO)
|
|
have_registered=true; // pretend they've alredy registered
|
|
}
|
|
|
|
if (!have_registered)
|
|
{
|
|
// figure out where the registration app is installed & launch it, continue
|
|
// after it exits.
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,REGISTER_REG_APP,0,KEY_READ,&rKey)==ERROR_SUCCESS)
|
|
{
|
|
char regapp[300];
|
|
valuesize=sizeof(regapp);
|
|
if ((RegQueryValueEx(rKey,"InstallPath",NULL,&type,(uint8 *)regapp,&valuesize)==ERROR_SUCCESS)&&
|
|
(strlen(regapp) > 8))
|
|
{
|
|
// Launch the process
|
|
SHELLEXECUTEINFO info;
|
|
memset(&info,0,sizeof(info));
|
|
info.cbSize=sizeof(info);
|
|
info.fMask=SEE_MASK_NOCLOSEPROCESS;
|
|
info.hwnd=g_PrimaryWindow;
|
|
info.lpVerb=NULL;
|
|
info.lpFile=regapp;
|
|
info.lpParameters=NULL;
|
|
info.lpDirectory=".";
|
|
info.nShow=SW_SHOW;
|
|
ShellExecuteEx(&info);
|
|
|
|
// Can't wait infinite or the other process will never create its window
|
|
// Only Bill himself knows why this is happening
|
|
while(1) // Wait for completion
|
|
{
|
|
DispatchEvents();
|
|
if (WaitForSingleObject(info.hProcess,500)!=WAIT_TIMEOUT)
|
|
break;
|
|
}
|
|
}
|
|
RegCloseKey(rKey);
|
|
}
|
|
}
|
|
// OK, done with that crap go on to the task at hand now....
|
|
*/
|
|
|
|
|
|
// Find the game version
|
|
g_AppVer = -1;
|
|
if (!GetUnsignedIntFromRegistry("", "Version", g_AppVer))
|
|
{
|
|
MessageBox(g_PrimaryWindow,Fetch_String(TXT_INSTALL_PROBLEM),Fetch_String(TXT_ERROR),MB_OK);
|
|
exit(0);
|
|
}
|
|
// OK, have the current game version now
|
|
|
|
g_PrimaryWindow=CreatePrimaryWin(); // Create the main window
|
|
DispatchEvents(); // process some win messages
|
|
|
|
// Popup the "contacting" window
|
|
g_ContactWindow=CreateDialog(Global_instance,MAKEINTRESOURCE(IDD_CONNECTING),g_PrimaryWindow,Simple_Dialog_Proc);
|
|
ShowWindow(g_ContactWindow,SW_SHOWNORMAL);
|
|
SetForegroundWindow(g_ContactWindow);
|
|
DispatchEvents(); // process some win messages
|
|
|
|
|
|
// Setup the Westwood Online stuff
|
|
Startup_Chat();
|
|
|
|
Update_If_Required();
|
|
|
|
Shutdown_Chat();
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
typedef struct SRecord {
|
|
int ID; // ID number of the string resource.
|
|
int TimeStamp; // 'Time' that this string was last requested.
|
|
char String[2048]; // Copy of string resource.
|
|
|
|
SRecord(void) : ID(-1), TimeStamp(-1) {}
|
|
} SRecord;
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Fetch_String -- Fetches a string resource. *
|
|
* *
|
|
* Fetches a string resource and returns a pointer to its text. *
|
|
* *
|
|
* INPUT: id -- The ID number of the string resource to fetch. *
|
|
* *
|
|
* OUTPUT: Returns with a pointer to the actual text of the string resource. *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/25/1996 JLB : Created. *
|
|
*=============================================================================================*/
|
|
char const * Fetch_String(int id)
|
|
{
|
|
static SRecord _buffers[64];
|
|
static int _time = 0;
|
|
|
|
/*
|
|
** Determine if the string ID requested is valid. If not then return an empty string pointer.
|
|
*/
|
|
if (id == -1 || id == TXT_NONE) return("");
|
|
|
|
/*
|
|
** Adjust the 'time stamp' tracking value. This is an artificial value used merely to track
|
|
** the relative age of the strings requested.
|
|
*/
|
|
_time = _time+1;
|
|
|
|
/*
|
|
** Check to see if the requested string has already been fetched into a buffer. If so, then
|
|
** return a pointer to that string (update the time stamp as well).
|
|
*/
|
|
for (int index = 0; index < ARRAY_SIZE(_buffers); index++) {
|
|
if (_buffers[index].ID == id) {
|
|
_buffers[index].TimeStamp = _time;
|
|
return(_buffers[index].String);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Find a suitable buffer to hold the string to be fetched. The buffer should either be
|
|
** empty or have the oldest fetched string.
|
|
*/
|
|
int oldest = -1;
|
|
int oldtime = -1;
|
|
for (int text = 0; text < ARRAY_SIZE(_buffers); text++) {
|
|
if (oldest == -1 || oldtime > _buffers[text].TimeStamp) {
|
|
oldest = text;
|
|
oldtime = _buffers[text].TimeStamp;
|
|
if (oldtime == -1 || _buffers[text].ID == -1) break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** A suitable buffer has been found so fetch the string resource and then return a pointer
|
|
** to the string.
|
|
*/
|
|
char * stringptr = _buffers[oldest].String;
|
|
_buffers[oldest].ID = id;
|
|
_buffers[oldest].TimeStamp = _time;
|
|
|
|
|
|
if (LoadString(Global_instance, id, stringptr, sizeof(_buffers[oldest].String)) == 0) {
|
|
return("");
|
|
}
|
|
|
|
/******
|
|
char resname[32];
|
|
sprintf(resname,"#%d",id);
|
|
HMODULE hmod=GetModuleHandle(NULL);
|
|
HRSRC hrsrc=FindResourceEx(hmod, RT_STRING, MAKEINTRESOURCE(id), LANGID);
|
|
if (hrsrc==0)
|
|
{
|
|
char message_buffer[256];
|
|
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &message_buffer[0], 256, NULL );
|
|
|
|
}
|
|
HGLOBAL resdata=LoadResource(NULL,hrsrc);
|
|
LPVOID vdata=LockResource(resdata);
|
|
strcpy(stringptr,(char *)vdata);
|
|
*********/
|
|
|
|
stringptr[sizeof(_buffers[oldest].String)-1] = '\0';
|
|
return(stringptr);
|
|
}
|
|
|
|
|
|
|
|
|
|
void LogMsg(char *msg)
|
|
{
|
|
#ifdef _DEBUG
|
|
FILE *out=fopen("register.log","a");
|
|
fprintf(out,"%s\n",msg);
|
|
fflush(out);
|
|
fclose(out);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
void Startup_Chat(void)
|
|
{
|
|
/*
|
|
//////CComObject<CChatEventSink>* g_pChatSink;
|
|
HRESULT hRes;
|
|
g_pChatSink=NULL;
|
|
|
|
CoCreateInstance(CLSID_Chat, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IChat, (void**)&pChat);
|
|
|
|
|
|
if (pChat==NULL)
|
|
{
|
|
char error[128];
|
|
char apimissing[256];
|
|
LoadString(Global_instance, TXT_API_MISSING, apimissing, sizeof(apimissing));
|
|
LoadString(Global_instance, TXT_ERROR, error, sizeof(error));
|
|
MessageBox(g_PrimaryWindow,apimissing,error,MB_OK);
|
|
exit(-5);
|
|
}
|
|
|
|
g_pChatSink=new CChatEventSink;
|
|
|
|
// Get a connection point from the chat class
|
|
IConnectionPoint *pConnectionPoint=NULL;
|
|
IConnectionPointContainer *pContainer=NULL;
|
|
|
|
dwChatAdvise=0;
|
|
hRes=pChat->QueryInterface(IID_IConnectionPointContainer,(void**)&pContainer);
|
|
_ASSERTE(SUCCEEDED(hRes));
|
|
hRes=pContainer->FindConnectionPoint(IID_IChatEvent,&pConnectionPoint);
|
|
_ASSERTE(SUCCEEDED(hRes));
|
|
hRes=pConnectionPoint->Advise((IChatEvent *)g_pChatSink,&dwChatAdvise);
|
|
_ASSERTE(SUCCEEDED(hRes));
|
|
|
|
|
|
pChat->SetAttributeValue("RegPath",APP_REG_KEY);
|
|
|
|
// ADD pConnectionPoint->Release();
|
|
*/
|
|
}
|
|
|
|
void Shutdown_Chat(void)
|
|
{
|
|
/*
|
|
/////AtlUnadvise(pChat, IID_IChatEvent, dwChatAdvise);
|
|
|
|
IConnectionPoint *pConnectionPoint=NULL;
|
|
IConnectionPointContainer *pContainer=NULL;
|
|
HRESULT hRes;
|
|
|
|
hRes=pChat->QueryInterface(IID_IConnectionPointContainer,(void**)&pContainer);
|
|
_ASSERTE(SUCCEEDED(hRes));
|
|
hRes=pContainer->FindConnectionPoint(IID_IChatEvent,&pConnectionPoint);
|
|
_ASSERTE(SUCCEEDED(hRes));
|
|
pConnectionPoint->Unadvise(dwChatAdvise);
|
|
|
|
pChat->Release();
|
|
|
|
/////delete(g_pChatSink); This appears to be bad....
|
|
// ADD g_pChatSink->Release();
|
|
// ADD pConnectionPoint->Release();
|
|
// ADD pContainer->Release();
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Download a patch for the registration client if required
|
|
// This uses the chat API for ver checking and FTP.
|
|
//
|
|
void Update_If_Required(void)
|
|
{
|
|
int retval;
|
|
int i;
|
|
// Create the events
|
|
for (i=0; i<NUM_EVENTS; i++)
|
|
Events[i]=CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
|
|
StartPatchCheck();
|
|
|
|
while (1)
|
|
{
|
|
ghttpThink();
|
|
MSG msg;
|
|
while(PeekMessage(&msg,NULL,0,0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
retval=WaitForMultipleObjectsEx(NUM_EVENTS,Events,FALSE,50,FALSE);
|
|
if (retval==WAIT_TIMEOUT)
|
|
continue;
|
|
//DBGMSG("An event was set");
|
|
retval-=WAIT_OBJECT_0;
|
|
break;
|
|
}
|
|
|
|
//DBGMSG("Out of the loop")
|
|
|
|
if (retval==ABORT_EVENT)
|
|
{
|
|
exit(0);
|
|
}
|
|
else
|
|
{
|
|
//DBGMSG("NO update required");
|
|
}
|
|
|
|
//DBGMSG("Shutting down");
|
|
|
|
// close all the event objects
|
|
for (i=0; i<NUM_EVENTS; i++)
|
|
CloseHandle(Events[i]);
|
|
|
|
/*
|
|
Startup_Chat();
|
|
int retval;
|
|
int i;
|
|
|
|
|
|
// Create the events
|
|
for (i=0; i<NUM_EVENTS; i++)
|
|
Events[i]=CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
|
|
/// For Testing....
|
|
///pChat->RequestServerList(1000,262364,"register","regpas98",15);
|
|
///pChat->RequestServerList(1000,300,"register","regpas98",15);
|
|
|
|
pChat->RequestServerList(g_AppSku,g_AppVer,"register","regpas98",40);
|
|
|
|
while(1)
|
|
{
|
|
pChat->PumpMessages();
|
|
MSG msg;
|
|
while(PeekMessage(&msg,NULL,0,0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
retval=WaitForMultipleObjectsEx(NUM_EVENTS,Events,FALSE,50,FALSE);
|
|
if (retval==WAIT_TIMEOUT)
|
|
continue;
|
|
//DBGMSG("An event was set");
|
|
retval-=WAIT_OBJECT_0;
|
|
break;
|
|
}
|
|
|
|
//DBGMSG("Out of the loop")
|
|
|
|
if (retval==ABORT_EVENT)
|
|
{
|
|
exit(0);
|
|
}
|
|
else
|
|
{
|
|
//DBGMSG("NO update required");
|
|
}
|
|
|
|
//DBGMSG("Shutting down");
|
|
|
|
// close all the event objects
|
|
for (i=0; i<NUM_EVENTS; i++)
|
|
CloseHandle(Events[i]);
|
|
|
|
Shutdown_Chat();
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
CChatEventSink::CChatEventSink()
|
|
{
|
|
m_cRef=0; // init the refrence count
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// Interface IUnknown Methods
|
|
//
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// QueryInterface
|
|
//
|
|
HRESULT __stdcall
|
|
CChatEventSink::QueryInterface(const IID& iid, void** ppv)
|
|
{
|
|
if ((iid == IID_IUnknown) ||(iid == IID_IChatEvent))
|
|
{
|
|
*ppv = static_cast<IChatEvent*>(this) ;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
(reinterpret_cast<IUnknown*>(*ppv))->AddRef() ;
|
|
return S_OK ;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// AddRef
|
|
//
|
|
ULONG __stdcall
|
|
CChatEventSink::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef) ;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// Release
|
|
//
|
|
ULONG __stdcall
|
|
CChatEventSink::Release()
|
|
{
|
|
if (InterlockedDecrement(&m_cRef) == 0)
|
|
{
|
|
delete this ;
|
|
return 0 ;
|
|
}
|
|
return m_cRef;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///// DOWNLOAD
|
|
|
|
CDownloadEventSink::CDownloadEventSink()
|
|
{
|
|
m_cRef=0; // Ref counter
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// Interface IUnknown Methods
|
|
//
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// QueryInterface
|
|
//
|
|
HRESULT __stdcall
|
|
CDownloadEventSink::QueryInterface(const IID& iid, void** ppv)
|
|
{
|
|
if ((iid == IID_IUnknown) ||(iid == IID_IDownloadEvent))
|
|
{
|
|
*ppv = static_cast<IDownloadEvent*>(this) ;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
(reinterpret_cast<IUnknown*>(*ppv))->AddRef() ;
|
|
return S_OK ;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// AddRef
|
|
//
|
|
ULONG __stdcall
|
|
CDownloadEventSink::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef) ;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// Release
|
|
//
|
|
ULONG __stdcall
|
|
CDownloadEventSink::Release()
|
|
{
|
|
if (InterlockedDecrement(&m_cRef) == 0)
|
|
{
|
|
delete this ;
|
|
return 0 ;
|
|
}
|
|
return m_cRef;
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//// FTP Download stuff
|
|
|
|
|
|
void SetupDownload( void )
|
|
{
|
|
/*
|
|
HRESULT hRes;
|
|
|
|
g_pDownloadSink=NULL;
|
|
|
|
CoCreateInstance(CLSID_Download, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IDownload, (void**)&pDownload);
|
|
_ASSERTE(pDownload);
|
|
g_pDownloadSink=new CDownloadEventSink;
|
|
|
|
// Get a connection point from the chat class
|
|
IConnectionPoint *pConnectionPoint=NULL;
|
|
IConnectionPointContainer *pContainer=NULL;
|
|
dwDownloadAdvise = 0;
|
|
|
|
hRes=pDownload->QueryInterface(IID_IConnectionPointContainer,(void**)&pContainer);
|
|
_ASSERTE(SUCCEEDED(hRes));
|
|
hRes=pContainer->FindConnectionPoint(IID_IDownloadEvent,&pConnectionPoint);
|
|
_ASSERTE(SUCCEEDED(hRes));
|
|
hRes=pConnectionPoint->Advise((IDownloadEvent *)g_pDownloadSink,&dwDownloadAdvise);
|
|
_ASSERTE(SUCCEEDED(hRes));
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
void ClosedownDownload( void )
|
|
{
|
|
/*
|
|
// AtlUnadvise(pDownload, IID_IDownloadEvent, dwDownloadAdvise);
|
|
|
|
IConnectionPoint *pConnectionPoint=NULL;
|
|
IConnectionPointContainer *pContainer=NULL;
|
|
HRESULT hRes;
|
|
|
|
hRes=pDownload->QueryInterface(IID_IConnectionPointContainer,(void**)&pContainer);
|
|
_ASSERTE(SUCCEEDED(hRes));
|
|
hRes=pContainer->FindConnectionPoint(IID_IDownloadEvent,&pConnectionPoint);
|
|
_ASSERTE(SUCCEEDED(hRes));
|
|
pConnectionPoint->Unadvise(dwDownloadAdvise);
|
|
|
|
pDownload->Release();
|
|
|
|
//////delete(g_pDownloadSink); This appears to be bad....
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
BOOL CALLBACK Download_Dialog_Proc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
// char fullpath[ 256 ];
|
|
// char localfile[ 256];
|
|
// HRESULT res;
|
|
|
|
switch( uMsg )
|
|
{
|
|
case WM_COMMAND:
|
|
switch( LOWORD( wParam ) )
|
|
{
|
|
case IDC_DLABORT:
|
|
{
|
|
|
|
char abort[128];
|
|
char abortdload[256];
|
|
LoadString(Global_instance, TXT_ABORT_DOWNLOAD, abortdload, sizeof(abortdload));
|
|
LoadString(Global_instance, TXT_ABORT, abort, sizeof(abort));
|
|
|
|
if (MessageBox(g_PrimaryWindow,abortdload,abort,MB_YESNO)==IDYES)
|
|
{
|
|
/*
|
|
pDownload->Abort();
|
|
*/
|
|
EndDialog( hwndDlg, g_Finished );
|
|
DestroyWindow(hwndDlg);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
SetupDownload();
|
|
|
|
SendMessage(hwndDlg, WM_SETICON,(WPARAM)ICON_SMALL,
|
|
(LPARAM)LoadIcon(Global_instance, MAKEINTRESOURCE(IDI_ICON1)));
|
|
|
|
g_DLTimeRem[0]=0;
|
|
g_DLBytesLeft[0]=0;
|
|
g_DLBPS[0]=0;
|
|
|
|
//SetDlgItemText( hwndDlg, IDC_DOWNLOADTITLE, g_UpdateString);
|
|
//SetWindowText(hwndDlg, g_UpdateString);
|
|
|
|
SetDlgItemText( hwndDlg, IDC_TIMEREM, g_DLTimeRem);
|
|
SetDlgItemText( hwndDlg, IDC_BYTESLEFT, g_DLBytesLeft);
|
|
// SetDlgItemText( hwndDlg, IDC_BPS, g_DLBPS );
|
|
|
|
/*
|
|
// Work out the full file name
|
|
sprintf( fullpath, "%s/%s", g_Update->patchpath,g_Update->patchfile);
|
|
sprintf(localfile,"%s\\%s",g_Update->localpath,g_Update->patchfile);
|
|
|
|
// Create the directory
|
|
CreateDirectory((char *)g_Update->localpath, NULL );
|
|
|
|
res=pDownload->DownloadFile((char *)g_Update->server, (char *)g_Update->login, (char *)g_Update->password,
|
|
fullpath, localfile, APP_REG_KEY);
|
|
|
|
*/
|
|
g_DownloadWindow = hwndDlg;
|
|
g_Finished = 0;
|
|
SetTimer( hwndDlg, 1, 200, NULL ); // was 50
|
|
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
LogMsg("TIMER");
|
|
if( g_Finished == 0 )
|
|
{
|
|
LogMsg("Entering PumpMsgs");
|
|
/*
|
|
pDownload->PumpMessages();
|
|
*/
|
|
LogMsg("Done with PumpMsgs");
|
|
if (strlen(g_DLTimeRem))
|
|
SetDlgItemText( hwndDlg, IDC_TIMEREM, g_DLTimeRem );
|
|
if (strlen(g_DLBytesLeft))
|
|
SetDlgItemText( hwndDlg, IDC_BYTESLEFT, g_DLBytesLeft );
|
|
//if (strlen(g_DLBPS))
|
|
// SetDlgItemText( hwndDlg, IDC_BPS, g_DLBPS );
|
|
}
|
|
else
|
|
{
|
|
LogMsg("TIMER: Finished");
|
|
EndDialog( hwndDlg, g_Finished );
|
|
DestroyWindow( hwndDlg );
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
KillTimer( hwndDlg, 1 );
|
|
ClosedownDownload();
|
|
|
|
//DBGMSG("WM_DESTROY");
|
|
break;
|
|
|
|
case WM_SETFONT:
|
|
return TRUE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
// Whoeee this is an exciting one...
|
|
BOOL CALLBACK Simple_Dialog_Proc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
switch( uMsg )
|
|
{
|
|
case WM_INITDIALOG:
|
|
return(TRUE);
|
|
break;
|
|
case WM_CLOSE:
|
|
DestroyWindow(hwnd);
|
|
PostQuitMessage(0);
|
|
exit(0);
|
|
break;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDownloadEventSink
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
|
|
STDMETHODIMP CDownloadEventSink::OnEnd(void)
|
|
{
|
|
LogMsg("Finished!");
|
|
g_Finished = 1;
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CDownloadEventSink::OnError(int error)
|
|
{
|
|
LogMsg("ERROR");
|
|
g_Finished = -1;
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDownloadEventSink::OnProgressUpdate(int bytesread, int totalsize,
|
|
int timetaken, int timeleft)
|
|
{
|
|
SendDlgItemMessage( g_DownloadWindow, IDC_PROGRESS, PBM_SETPOS, (WPARAM)(bytesread * 100) / totalsize, 0 );
|
|
char temp[256];
|
|
|
|
if( timeleft > 0 )
|
|
{
|
|
//DBGMSG("Bytes read: "<<bytesread<<". Time left: "<<timeleft<<" seconds");
|
|
LoadString(Global_instance, TXT_TIME_REMAIN, temp, sizeof(temp));
|
|
sprintf(g_DLTimeRem,temp,(timeleft/60),(timeleft%60));
|
|
|
|
LoadString(Global_instance, TXT_BPS, temp, sizeof(temp));
|
|
sprintf(g_DLBPS,temp,bytesread/timetaken);
|
|
}
|
|
LoadString(Global_instance, TXT_BYTES_READ, temp, sizeof(temp));
|
|
sprintf(g_DLBytesLeft,temp,bytesread,totalsize);
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDownloadEventSink::OnStatusUpdate(int status)
|
|
{
|
|
switch( status )
|
|
{
|
|
case DOWNLOADSTATUS_CONNECTING:
|
|
{
|
|
//LogMsg( "Connecting..." );
|
|
SetWindowText(g_DownloadWindow, Fetch_String(TXT_CONNECTING));
|
|
}
|
|
break;
|
|
|
|
case DOWNLOADSTATUS_FINDINGFILE:
|
|
//LogMsg( "Finding patch..." );
|
|
SetWindowText(g_DownloadWindow, g_UpdateString);
|
|
break;
|
|
|
|
case DOWNLOADSTATUS_DOWNLOADING:
|
|
//LogMsg( "Downloading patch..." );
|
|
SetWindowText(g_DownloadWindow, g_UpdateString);
|
|
break;
|
|
|
|
default:
|
|
//LogMsg("Unknown status update!");
|
|
break;
|
|
}
|
|
return(S_OK);
|
|
}
|
|
|
|
//
|
|
// Just tell the FTP module to go ahead and resume
|
|
//
|
|
STDMETHODIMP CDownloadEventSink::OnQueryResume(void)
|
|
{
|
|
return(DOWNLOADEVENT_RESUME);
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CChatEventSink
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnServerList(HRESULT res, Server* servers)
|
|
{
|
|
// If we get this, then we don't need to patch
|
|
// Close that contacting window
|
|
DestroyWindow(g_ContactWindow);
|
|
g_ContactWindow=NULL;
|
|
|
|
LogMsg("Server List");
|
|
|
|
MessageBox(g_PrimaryWindow,Fetch_String(TXT_NO_PATCHES),Fetch_String(TXT_AUTO_UPDATE),MB_OK);
|
|
|
|
SetEvent(Events[NOUPDATE_EVENT]);
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnServerBannedYou(HRESULT, time_t)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnPageSend(HRESULT)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnPaged(HRESULT, User *, LPCSTR)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnFind(HRESULT, Channel *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnLogout(HRESULT, User *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnBusy(HRESULT)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnIdle(HRESULT)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnConnection(HRESULT, LPCSTR)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnUserFlags(HRESULT,LPCSTR,unsigned int, unsigned int)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnChannelCreate(HRESULT, Channel *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnChannelModify(HRESULT, Channel *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnChannelJoin(HRESULT, Channel *, User *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnChannelLeave(HRESULT, Channel *, User *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnChannelTopic(HRESULT, Channel *, LPCSTR)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnChannelBan(HRESULT, LPCSTR, int)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnGroupList(HRESULT, Group *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnPublicMessage(HRESULT, Channel *, User *, LPCSTR)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnPrivateMessage(HRESULT, User *,LPCSTR)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnSystemMessage(HRESULT, LPCSTR)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnUserLocale(long, struct User *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnUserTeam(long, struct User *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnSetLocale(long, enum Locale)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnSetTeam(long, int)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnNetStatus(HRESULT hr)
|
|
{
|
|
char string[60];
|
|
sprintf(string,"NetStatus %ld",hr);
|
|
LogMsg(string);
|
|
|
|
if ((hr==CHAT_E_CON_NETDOWN)||(hr==CHAT_E_CON_LOOKUP_FAILED)||
|
|
(hr==CHAT_E_CON_ERROR)||(hr==CHAT_E_TIMEOUT))
|
|
{
|
|
char error[128];
|
|
char cantconn[256];
|
|
LoadString(Global_instance, TXT_CANT_CONTACT, cantconn, sizeof(cantconn));
|
|
LoadString(Global_instance, TXT_ERROR, error, sizeof(error));
|
|
MessageBox(g_PrimaryWindow,cantconn,error,MB_OK);
|
|
exit(-1);
|
|
}
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnChannelList(HRESULT, Channel*)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnUserList(HRESULT, Channel*, User*)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// We got a list of updates to apply
|
|
//
|
|
STDMETHODIMP CChatEventSink::OnUpdateList(HRESULT r, Update * updates)
|
|
{
|
|
Update *tmp;
|
|
int numupdates=0;
|
|
int i=0;
|
|
int retval;
|
|
|
|
static int alreadyGotOne=0;
|
|
|
|
LogMsg("Update list");
|
|
|
|
// Close that contacting window
|
|
DestroyWindow(g_ContactWindow);
|
|
g_ContactWindow=NULL;
|
|
|
|
if( FAILED(r) )
|
|
{
|
|
LogMsg("Failed");
|
|
SetEvent(Events[ABORT_EVENT]); // An error occurred, bail out
|
|
}
|
|
|
|
if( updates == NULL ) // shouldn't happen
|
|
return S_OK;
|
|
|
|
|
|
if (alreadyGotOne) // Should only get one update list
|
|
return(S_OK);
|
|
alreadyGotOne=1;
|
|
|
|
|
|
// Count the updates;
|
|
tmp = updates;
|
|
while( tmp != NULL )
|
|
{
|
|
tmp = tmp->next;
|
|
numupdates++;
|
|
}
|
|
|
|
// Got a list of updates - If an update is required, the user must either
|
|
// patch or quit.
|
|
|
|
tmp = updates;
|
|
|
|
LogMsg("Found an update");
|
|
|
|
// We have a required update
|
|
|
|
char upreq[256];
|
|
char title[128];
|
|
|
|
LoadString(Global_instance, TXT_AN_UPGRADE_AVAILABLE, upreq, sizeof(upreq));
|
|
strcat(upreq,"\n");
|
|
LoadString(Global_instance, TXT_DOWNLOAD_NOW, upreq+strlen(upreq), sizeof(upreq));
|
|
LoadString(Global_instance, TXT_UPGRADE_AVAILABLE, title, sizeof(title));
|
|
|
|
if( MessageBox(g_PrimaryWindow,upreq,title, MB_YESNO ) == IDNO )
|
|
{
|
|
// If they don't want to patch now, just exit...
|
|
//DBGMSG("Must patch to continue, so exit");
|
|
exit(0);
|
|
}
|
|
|
|
// Do the downloads
|
|
while( tmp != NULL )
|
|
{
|
|
g_Update = tmp;
|
|
|
|
char dloading[256];
|
|
LoadString(Global_instance, TXT_DOWNLOADING_FILE, dloading, sizeof(dloading));
|
|
sprintf( g_UpdateString, dloading, ++i, numupdates );
|
|
|
|
LogMsg("Creating Download dialog box");
|
|
//if( (retval=DialogBox(Global_instance, MAKEINTRESOURCE(IDD_DOWNLOAD_DIALOG), g_PrimaryWindow,
|
|
// (DLGPROC)Download_Dialog_Proc)) != 1 )
|
|
|
|
retval=DialogBox(Global_instance, MAKEINTRESOURCE(IDD_DOWNLOAD_DIALOG), g_PrimaryWindow,(DLGPROC)Download_Dialog_Proc);
|
|
|
|
if (g_Finished != 1)
|
|
{
|
|
// Download failed
|
|
//DBGMSG("Download failed: "<<retval);
|
|
SetEvent(Events[ABORT_EVENT]);
|
|
return(E_FAIL);
|
|
}
|
|
tmp = tmp->next;
|
|
}
|
|
// Quit so the launcher can apply the patches
|
|
exit(0);
|
|
return(S_OK); // make silly compiler happy
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnServerError(HRESULT, LPCSTR)
|
|
{
|
|
LogMsg("Server Error");
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnMessageOfTheDay(HRESULT, LPCSTR)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnPrivateAction(HRESULT, User *, LPCSTR)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnPublicAction(HRESULT, Channel *, User *, LPCSTR)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnPrivateGameOptions(HRESULT, User *, LPCSTR)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnPublicGameOptions(HRESULT, Channel *, User *, LPCSTR)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnGameStart(HRESULT, Channel *, User *, int)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnUserKick(HRESULT, Channel *, User *, User *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CChatEventSink::OnUserIP(HRESULT, User *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CChatEventSink::OnSquadInfo(HRESULT, unsigned long, Squad *)
|
|
{
|
|
return(S_OK);
|
|
}
|
|
|
|
*/
|