heretic2-sdk/Toolkit/Programming/Tools/qe4/win_bsp.c
1998-11-24 00:00:00 +00:00

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);
}