435 lines
9.9 KiB
C
435 lines
9.9 KiB
C
|
|
#include "qe3.h"
|
|
|
|
|
|
struct ClientS
|
|
{
|
|
DWORD ConnectTime,ProcessTime,StartTime;
|
|
BOOL TaskRunning;
|
|
HANDLE OutputReadPipe,OutputWritePipe;
|
|
PROCESS_INFORMATION pi;
|
|
};
|
|
|
|
|
|
static struct ClientS Client;
|
|
static HWND hwndBsp = 0;
|
|
|
|
static void SetCancelButton (char *text, ...)
|
|
{
|
|
va_list argptr;
|
|
char buf[32768];
|
|
char *out;
|
|
HWND h;
|
|
|
|
h=GetDlgItem(hwndBsp, IDCANCEL);
|
|
|
|
if (!h)
|
|
{
|
|
// Error("Couldn't find BSP Cancel Button");
|
|
return;
|
|
}
|
|
|
|
va_start (argptr,text);
|
|
vsprintf (buf, text,argptr);
|
|
va_end (argptr);
|
|
|
|
out = TranslateString (buf);
|
|
|
|
SendMessage (h,
|
|
WM_SETTEXT,
|
|
0,
|
|
(LPARAM)out);
|
|
}
|
|
|
|
static void CleanProcess(DWORD exitcode)
|
|
{
|
|
CloseHandle(Client.pi.hThread);
|
|
CloseHandle(Client.pi.hProcess);
|
|
|
|
CloseHandle(Client.OutputReadPipe);
|
|
CloseHandle(Client.OutputWritePipe);
|
|
|
|
Client.TaskRunning = false;
|
|
Client.StartTime = 0;
|
|
|
|
|
|
SetCancelButton("Continue");
|
|
bsp_process = 0;
|
|
if (exitcode == ERROR_CANCELLED)
|
|
{
|
|
Sys_Printf ("\nBsp process cancelled.\n");
|
|
}
|
|
else
|
|
{
|
|
if (exitcode)
|
|
{
|
|
Sys_Printf ("\nBsp process quit, exitcode: %d.\n",exitcode);
|
|
}
|
|
else
|
|
{
|
|
Sys_Printf ("\nBsp process completed.\n",exitcode);
|
|
}
|
|
}
|
|
Sys_Beep ();
|
|
Pointfile_Check ();
|
|
}
|
|
|
|
|
|
static void bsp_Printf (char *text, ...)
|
|
{
|
|
va_list argptr;
|
|
char buf[32768];
|
|
char *out;
|
|
HWND h;
|
|
|
|
h=GetDlgItem(hwndBsp, IDC_BSPTEXT);
|
|
|
|
va_start (argptr,text);
|
|
vsprintf (buf, text,argptr);
|
|
va_end (argptr);
|
|
|
|
out = TranslateString (buf);
|
|
|
|
// if (!h)//uh oh, no bsp dialog window--just throw it into the console
|
|
// {
|
|
// Error("Couldn't find BSP Output Window");
|
|
Sys_Printf(out);// seein it in the console annoys me, personally
|
|
return;
|
|
// }
|
|
|
|
|
|
// SendMessage (h,
|
|
// EM_REPLACESEL,
|
|
// 0,
|
|
// (LPARAM)out);
|
|
}
|
|
|
|
// this should run only on a separate thread!!
|
|
void ReadNFeed_Thread (int i)
|
|
{
|
|
char buffer[1024];
|
|
DWORD ReadAmount;
|
|
BOOL Success;
|
|
BOOL ret;
|
|
DWORD exitcode;
|
|
|
|
int threadDone = false;
|
|
|
|
Sleep (100); // give output window a chance to show up
|
|
|
|
while(!threadDone) // hmmm...well, this thread may get trapped in the ReadFile call, and stick around until qe exits.
|
|
{
|
|
if (!bsp_process)
|
|
{
|
|
threadDone = true;
|
|
break;
|
|
}
|
|
|
|
ret = GetExitCodeProcess (bsp_process, &exitcode);
|
|
if (!ret)
|
|
Error ("GetExitCodeProcess failed");
|
|
if (exitcode != STILL_ACTIVE)
|
|
{
|
|
Client.TaskRunning = false;
|
|
// should be safe to try & read whatever's left in the pipe--the ReadFile call should fail when thread's parent cleans up after bsp proc
|
|
|
|
break;//egad, this bites! there still might be shit in the pipe
|
|
//but, i gotta doit or the ReadFile will hang. afaik. --ss
|
|
}
|
|
|
|
Success = ReadFile(Client.OutputReadPipe, buffer, sizeof(buffer)-1, &ReadAmount, NULL);
|
|
if (!Success && (GetLastError() == ERROR_BROKEN_PIPE))
|
|
{
|
|
threadDone = true;
|
|
break;
|
|
}
|
|
|
|
if (Success && ReadAmount)
|
|
{// it should be safe to keep looping--since this is a separate thread, the pipe should just break instead of hanging around
|
|
buffer[ReadAmount] = 0;
|
|
// now throw this into a dialog window
|
|
bsp_Printf(buffer);
|
|
}
|
|
}
|
|
|
|
ExitThread(0);
|
|
}
|
|
|
|
|
|
static void bsp_StartTask(char *Task)
|
|
{
|
|
DWORD Mode;
|
|
SECURITY_ATTRIBUTES saPipe;
|
|
STARTUPINFO si;
|
|
BOOL Success;
|
|
char *CD;
|
|
char FinalTask[1024],TempTask[1024],ComSpec[1024];
|
|
DWORD myThreadId;//id for the read'n'feed thread
|
|
int threadParam;
|
|
|
|
threadParam = 1;
|
|
|
|
Mode = PIPE_READMODE_BYTE|PIPE_WAIT;
|
|
|
|
saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
saPipe.lpSecurityDescriptor = NULL;
|
|
saPipe.bInheritHandle = TRUE;
|
|
|
|
CreatePipe(&Client.OutputReadPipe,&Client.OutputWritePipe,&saPipe,0);
|
|
|
|
SetNamedPipeHandleState(Client.OutputReadPipe,&Mode,NULL,NULL);
|
|
SetNamedPipeHandleState(Client.OutputWritePipe,&Mode,NULL,NULL);
|
|
|
|
|
|
Success = DuplicateHandle(GetCurrentProcess(),Client.OutputReadPipe,
|
|
GetCurrentProcess(),NULL,0,FALSE,DUPLICATE_SAME_ACCESS);
|
|
|
|
if (!Success)
|
|
Error("unable to read from child process!");
|
|
|
|
memset(&si, 0, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
|
|
si.wShowWindow = SW_SHOWMINNOACTIVE;
|
|
si.hStdOutput = Client.OutputWritePipe;
|
|
si.hStdError = Client.OutputWritePipe;
|
|
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
|
|
|
CD = NULL;
|
|
|
|
if (Task[0] == '\"')
|
|
strcpy(TempTask,Task+1);
|
|
else
|
|
strcpy(TempTask,Task);
|
|
if (TempTask[strlen(TempTask)-1] == '\"')
|
|
TempTask[strlen(TempTask)-1] = 0;
|
|
|
|
strcpy(FinalTask,TempTask);
|
|
strlwr(FinalTask);
|
|
if (strstr(FinalTask,".bat"))
|
|
{
|
|
GetEnvironmentVariable("comspec",ComSpec,sizeof(ComSpec));
|
|
sprintf(FinalTask,"%s /c %s",ComSpec,TempTask);
|
|
}
|
|
else
|
|
strcpy(FinalTask,TempTask);
|
|
|
|
if (!CreateProcess(NULL,FinalTask,NULL,NULL,TRUE,0,NULL,CD,&si,&Client.pi))
|
|
{
|
|
Error("Could not find bsp task");
|
|
}
|
|
|
|
// CloseHandle(OutputWritePipe);
|
|
|
|
Client.TaskRunning = true;
|
|
Client.StartTime = Sys_DoubleTime();
|
|
bsp_process = Client.pi.hProcess;
|
|
|
|
// now create the thread to handle the bsp task output
|
|
|
|
if (!CreateThread( NULL, // pointer to thread security attributes
|
|
0, // initial thread stack size, in bytes
|
|
(LPTHREAD_START_ROUTINE) ReadNFeed_Thread, // pointer to thread function--will start up simple read'n'feed loop
|
|
(LPVOID) &threadParam, // argument for new thread
|
|
0, // creation flags
|
|
&myThreadId // pointer to returned thread identifier
|
|
))
|
|
{
|
|
Error("Couldn't Start up Bsp Communication");
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void bsp_CheckTask(void)
|
|
{
|
|
BOOL ret;
|
|
DWORD exitcode;
|
|
|
|
if (!bsp_process)
|
|
return;
|
|
|
|
Client.ProcessTime = Sys_DoubleTime();
|
|
|
|
ret = GetExitCodeProcess (bsp_process, &exitcode);
|
|
if (!ret)
|
|
Error ("GetExitCodeProcess failed");
|
|
|
|
if (exitcode != STILL_ACTIVE)
|
|
{
|
|
Client.TaskRunning = false;
|
|
}
|
|
|
|
if (!Client.TaskRunning)//should be able to figure out whether we finished ok or not
|
|
{
|
|
CleanProcess(exitcode);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
===================================================
|
|
|
|
bsp window
|
|
|
|
===================================================
|
|
*/
|
|
|
|
BOOL CALLBACK BspDlgProc (
|
|
HWND hwndDlg, // handle to dialog box
|
|
UINT uMsg, // message
|
|
WPARAM wParam, // first message parameter
|
|
LPARAM lParam // second message parameter
|
|
)
|
|
{
|
|
char temppath[512];
|
|
char outputpath[1024];
|
|
STARTUPINFO si;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
return FALSE;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDCANCEL:
|
|
if (!bsp_process)
|
|
{
|
|
DestroyWindow(hwndDlg);
|
|
}
|
|
else // abort bsp process--warning: this is a yucky hard-coded mess.
|
|
{
|
|
// alert! TerminateProcess won't work with ts--will just cancel the ts process, and not the batch process!
|
|
|
|
//yee-ha! start up a kill process just like starting up a bsp (no read'n'feed creation cuz it should be there arready)
|
|
|
|
// check whether i'm running locally or using the task server
|
|
strcpy (temppath, ValueForKey(g_qeglobals.d_project_entity, "rshcmd"));
|
|
|
|
if (temppath[0]==0)// bsping locally, just smash the process and return.
|
|
{
|
|
TerminateProcess(bsp_process, ERROR_CANCELLED);
|
|
return TRUE;
|
|
}
|
|
|
|
// clear the current process out of the way so the kill process can take over
|
|
TerminateProcess(bsp_process, ERROR_CANCELLED);
|
|
bsp_process = 0;
|
|
|
|
// now create the killer process.
|
|
|
|
// let the task server know this is a kill process
|
|
sprintf (outputpath, "%s -kill", temppath);
|
|
|
|
memset(&si, 0, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
|
|
// OutputWritePipe should be valid from the old bsp_process
|
|
si.wShowWindow = SW_SHOWMINNOACTIVE;
|
|
si.hStdOutput = Client.OutputWritePipe;
|
|
si.hStdError = Client.OutputWritePipe;
|
|
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
|
|
|
// actual spawning of killer proc--this will change what's in Client.pi
|
|
if (!CreateProcess(NULL,outputpath,NULL,NULL,TRUE,0,NULL,NULL,&si,&Client.pi))
|
|
{
|
|
Error("Could not kill Bsp process");
|
|
}
|
|
|
|
Client.TaskRunning = true;
|
|
Client.StartTime = Sys_DoubleTime();
|
|
bsp_process = Client.pi.hProcess;
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
void bsp_StartBsp (char *command)
|
|
{
|
|
char sys[1024];
|
|
char batpath[1024];
|
|
char outputpath[1024];
|
|
char temppath[512];
|
|
char name[1024];
|
|
FILE *hFile;
|
|
|
|
SetInspectorMode (W_CONSOLE);
|
|
|
|
if (bsp_process)
|
|
{
|
|
Sys_Printf ("BSP is still going...\n");
|
|
return;
|
|
}
|
|
|
|
GetTempPath(512, temppath);
|
|
sprintf (outputpath, "%sjunk.txt", temppath);
|
|
|
|
strcpy (name, currentmap);
|
|
if (region_active)
|
|
{
|
|
Map_SaveFile (name, false);
|
|
StripExtension (name);
|
|
strcat (name, ".reg");
|
|
}
|
|
|
|
Map_SaveFile (name, region_active);
|
|
|
|
|
|
QE_ExpandBspString (command, sys, name);
|
|
|
|
Sys_ClearPrintf ();
|
|
Sys_Printf ("======================================\nRunning bsp command...\n");
|
|
Sys_Printf ("\n%s\n", sys);
|
|
|
|
WriteUserLog("BSP: %s on %s", command, name);
|
|
|
|
//
|
|
// write qe3bsp.bat
|
|
//
|
|
sprintf (batpath, "%sqe3bsp.bat", temppath);
|
|
hFile = fopen(batpath, "w");
|
|
if (!hFile)
|
|
Error ("Can't write to %s", batpath);
|
|
fprintf (hFile, sys);
|
|
fclose (hFile);
|
|
|
|
//
|
|
// write qe3bsp2.bat
|
|
//
|
|
sprintf (batpath, "%sqe3bsp2.bat", temppath);
|
|
hFile = fopen(batpath, "w");
|
|
if (!hFile)
|
|
Error ("Can't write to %s", batpath);
|
|
fprintf (hFile, "%sqe3bsp.bat", temppath);
|
|
// fprintf (hFile, "%sqe3bsp.bat > %s", temppath, outputpath);
|
|
fclose (hFile);
|
|
|
|
Pointfile_Delete ();
|
|
|
|
if (hwndBsp)
|
|
DestroyWindow(hwndBsp);
|
|
|
|
bsp_StartTask(batpath);
|
|
// i removed these next two lines and changed the bsp_printf to send bsp output to console
|
|
// hwndBsp=CreateDialog(g_qeglobals.d_hInstance, (char *)IDD_BSP, g_qeglobals.d_hwndMain, BspDlgProc);
|
|
// SetCancelButton("Abort");
|
|
|
|
// Sleep (100); // give the new process a chance to open its window
|
|
|
|
// BringWindowToTop( hwndBsp ); // pop us back on top
|
|
// SetFocus (hwndBsp);
|
|
}
|
|
|