20 #include "common/cvar.h"
21 #include "common/field.h"
22 #include "common/prompt.h"
31 HANDLE mainProcessThread;
32 LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter;
38 static SERVICE_STATUS_HANDLE statusHandle;
56 #pragma comment(linker,"\"/manifestdependency:type='win32' \
57 name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
58 processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
70 #define MAX_CONSOLE_INPUT_EVENTS 16
72 static HANDLE hinput = INVALID_HANDLE_VALUE;
73 static HANDLE houtput = INVALID_HANDLE_VALUE;
76 static cvar_t *sys_viewlog;
79 static commandPrompt_t sys_con;
80 static int sys_hidden;
81 static CONSOLE_SCREEN_BUFFER_INFO sbinfo;
82 static qboolean gotConsole;
84 static void write_console_data(
void *data,
size_t len)
88 WriteFile(houtput, data, len, &dummy, NULL);
91 static void hide_console_input(
void)
96 for (i = 0; i <= sys_con.inputLine.cursorPos; i++) {
97 write_console_data(
"\b \b", 3);
103 static void show_console_input(
void)
111 write_console_data(
"]", 1);
112 write_console_data(sys_con.inputLine.text, sys_con.inputLine.cursorPos);
121 void Sys_RunConsole(
void)
123 INPUT_RECORD recs[MAX_CONSOLE_INPUT_EVENTS];
125 DWORD numread, numevents;
130 if (hinput == INVALID_HANDLE_VALUE) {
138 f = &sys_con.inputLine;
140 if (!GetNumberOfConsoleInputEvents(hinput, &numevents)) {
141 Com_EPrintf(
"Error %lu getting number of console events.\n", GetLastError());
148 if (numevents > MAX_CONSOLE_INPUT_EVENTS) {
149 numevents = MAX_CONSOLE_INPUT_EVENTS;
152 if (!ReadConsoleInput(hinput, recs, numevents, &numread)) {
153 Com_EPrintf(
"Error %lu reading console input.\n", GetLastError());
158 for (i = 0; i < numread; i++) {
159 if (recs[i].EventType == WINDOW_BUFFER_SIZE_EVENT) {
161 size_t width = recs[i].Event.WindowBufferSizeEvent.dwSize.X;
164 Com_EPrintf(
"Invalid console buffer width.\n");
169 sys_con.widthInChars =
width;
173 if (
width > MAX_FIELD_TEXT - 1) {
174 width = MAX_FIELD_TEXT - 1;
177 hide_console_input();
179 show_console_input();
182 if (recs[i].EventType != KEY_EVENT) {
186 if (!recs[i].Event.KeyEvent.bKeyDown) {
190 switch (recs[i].Event.KeyEvent.wVirtualKeyCode) {
192 hide_console_input();
194 show_console_input();
197 hide_console_input();
199 show_console_input();
202 hide_console_input();
205 if (*s ==
'\\' || *s ==
'/') {
208 Sys_Printf(
"]%s\n", s);
212 write_console_data(
"\n", 1);
214 show_console_input();
218 f->text[--f->cursorPos] = 0;
219 write_console_data(
"\b \b", 3);
223 hide_console_input();
225 f->cursorPos = strlen(f->text);
226 show_console_input();
229 ch = recs[i].Event.KeyEvent.uChar.AsciiChar;
233 if (f->cursorPos < f->maxChars - 1) {
234 write_console_data(&ch, 1);
235 f->text[f->cursorPos] = ch;
236 f->text[++f->cursorPos] = 0;
244 #define FOREGROUND_BLACK 0
245 #define FOREGROUND_WHITE (FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED)
247 static const WORD textColors[8] = {
251 FOREGROUND_RED | FOREGROUND_GREEN,
253 FOREGROUND_BLUE | FOREGROUND_GREEN,
254 FOREGROUND_RED | FOREGROUND_BLUE,
258 void Sys_SetConsoleColor(color_index_t
color)
262 if (houtput == INVALID_HANDLE_VALUE) {
270 attr = sbinfo.wAttributes & ~FOREGROUND_WHITE;
274 w = sbinfo.wAttributes;
277 w = attr | FOREGROUND_GREEN;
280 w = attr | textColors[
color];
284 if (
color != COLOR_NONE) {
285 hide_console_input();
287 SetConsoleTextAttribute(houtput, w);
288 if (
color == COLOR_NONE) {
289 show_console_input();
293 static void write_console_output(
const char *text)
295 char buf[MAXPRINTMSG];
298 for (len = 0; len < MAXPRINTMSG; len++) {
303 buf[len] = Q_charascii(
c);
306 write_console_data(buf, len);
316 void Sys_ConsoleOutput(
const char *text)
318 if (houtput == INVALID_HANDLE_VALUE) {
323 write_console_output(text);
325 hide_console_input();
326 write_console_output(text);
327 show_console_input();
331 void Sys_SetConsoleTitle(
const char *title)
334 SetConsoleTitle(title);
338 static BOOL WINAPI Sys_ConsoleCtrlHandler(DWORD dwCtrlType)
347 static void Sys_ConsoleInit(
void)
353 if (!AllocConsole()) {
354 Com_EPrintf(
"Couldn't create system console.\n");
363 hinput = GetStdHandle(STD_INPUT_HANDLE);
364 houtput = GetStdHandle(STD_OUTPUT_HANDLE);
365 if (!GetConsoleScreenBufferInfo(houtput, &sbinfo)) {
366 Com_EPrintf(
"Couldn't get console buffer info.\n");
371 width = sbinfo.dwSize.X;
373 Com_EPrintf(
"Invalid console buffer width.\n");
376 sys_con.widthInChars =
width;
377 sys_con.printf = Sys_Printf;
380 SetConsoleTitle(PRODUCT
" console");
381 SetConsoleCtrlHandler(Sys_ConsoleCtrlHandler, TRUE);
382 GetConsoleMode(hinput, &mode);
383 mode |= ENABLE_WINDOW_INPUT;
384 SetConsoleMode(hinput, mode);
388 if (
width > MAX_FIELD_TEXT - 1) {
389 width = MAX_FIELD_TEXT - 1;
393 Com_DPrintf(
"System console initialized (%d cols, %d rows).\n",
394 sbinfo.dwSize.X, sbinfo.dwSize.Y);
409 static void Sys_InstallService_f(
void)
411 char servicePath[256];
412 char serviceName[1024];
413 SC_HANDLE scm, service;
418 Com_Printf(
"Usage: %s <servicename> <+command> [...]\n"
419 "Example: %s test +set net_port 27910 +map q2dm1\n",
424 scm = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
426 error = GetLastError();
427 if (error == ERROR_ACCESS_DENIED) {
428 Com_Printf(
"Insufficient privileges for opening Service Control Manager.\n");
430 Com_EPrintf(
"%#lx opening Service Control Manager.\n", error);
437 length = GetModuleFileName(NULL, servicePath, MAX_PATH);
439 error = GetLastError();
440 Com_EPrintf(
"%#lx getting module file name.\n", error);
444 if (length + strlen(commandline) + 10 >
sizeof(servicePath) - 1) {
445 Com_Printf(
"Oversize service command line.\n");
448 strcpy(servicePath + length,
" -service ");
449 strcpy(servicePath + length + 10, commandline);
451 service = CreateService(
456 SERVICE_WIN32_OWN_PROCESS,
458 SERVICE_ERROR_IGNORE,
467 error = GetLastError();
468 if (error == ERROR_SERVICE_EXISTS || error == ERROR_DUPLICATE_SERVICE_NAME) {
469 Com_Printf(
"Service already exists.\n");
471 Com_EPrintf(
"%#lx creating service.\n", error);
476 Com_Printf(
"Service created successfully.\n");
478 CloseServiceHandle(service);
481 CloseServiceHandle(scm);
484 static void Sys_DeleteService_f(
void)
486 char serviceName[256];
487 SC_HANDLE scm, service;
491 Com_Printf(
"Usage: %s <servicename>\n",
Cmd_Argv(0));
495 scm = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
497 error = GetLastError();
498 if (error == ERROR_ACCESS_DENIED) {
499 Com_Printf(
"Insufficient privileges for opening Service Control Manager.\n");
501 Com_EPrintf(
"%#lx opening Service Control Manager.\n", error);
508 service = OpenService(
514 error = GetLastError();
515 if (error == ERROR_SERVICE_DOES_NOT_EXIST) {
516 Com_Printf(
"Service doesn't exist.\n");
518 Com_EPrintf(
"%#lx opening service.\n", error);
523 if (!DeleteService(service)) {
524 error = GetLastError();
525 if (error == ERROR_SERVICE_MARKED_FOR_DELETE) {
526 Com_Printf(
"Service has already been marked for deletion.\n");
528 Com_EPrintf(
"%#lx deleting service.\n", error);
531 Com_Printf(
"Service deleted successfully.\n");
534 CloseServiceHandle(service);
537 CloseServiceHandle(scm);
556 void Sys_Printf(
const char *fmt, ...)
559 char msg[MAXPRINTMSG];
561 va_start(argptr, fmt);
565 Sys_ConsoleOutput(
msg);
577 char text[MAXERRORMSG];
579 va_start(argptr, error);
590 Sys_SetConsoleColor(COLOR_RED);
591 Sys_Printf(
"********************\n"
593 "********************\n", text);
594 Sys_SetConsoleColor(COLOR_NONE);
606 MessageBoxA(NULL, text, PRODUCT
" Fatal Error", MB_ICONERROR | MB_OK);
646 return timeGetTime();
661 WCHAR wpath[MAX_OSPATH] = { 0 };
662 MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_OSPATH);
664 DWORD fileAttributes = GetFileAttributesW(wpath);
665 if (fileAttributes == INVALID_FILE_ATTRIBUTES)
670 return (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
676 WCHAR wpath[MAX_OSPATH] = { 0 };
677 MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_OSPATH);
679 DWORD fileAttributes = GetFileAttributesW(wpath);
680 if (fileAttributes == INVALID_FILE_ATTRIBUTES)
687 return (fileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0;
700 BOOL (WINAPI * pSetProcessDEPPolicy)(DWORD);
707 vinfo.dwOSVersionInfoSize =
sizeof(vinfo);
708 #pragma warning(push)
709 #pragma warning(disable: 4996) // warning C4996: 'GetVersionExA': was declared deprecated
710 if (!GetVersionEx(&vinfo)) {
714 if (vinfo.dwPlatformId != VER_PLATFORM_WIN32_NT) {
715 Sys_Error(PRODUCT
" requires Windows NT");
717 if (vinfo.dwMajorVersion < 5) {
718 Sys_Error(PRODUCT
" requires Windows 2000 or greater");
738 houtput = GetStdHandle(STD_OUTPUT_HANDLE);
740 sys_viewlog =
Cvar_Get(
"sys_viewlog",
"0", CVAR_NOSET);
742 if (
dedicated->integer || sys_viewlog->integer)
748 var =
Cvar_Get(
"sys_disablecrashdump",
"0", CVAR_NOSET);
752 mainProcessThread = GetCurrentThread();
753 prevExceptionFilter = SetUnhandledExceptionFilter(
759 module = GetModuleHandle(
"kernel32.dll");
761 pSetProcessDEPPolicy = (PVOID)GetProcAddress(module,
762 "SetProcessDEPPolicy");
763 if (pSetProcessDEPPolicy) {
764 var =
Cvar_Get(
"sys_disabledep",
"0", CVAR_NOSET);
768 pSetProcessDEPPolicy(
771 }
else if (var->integer == 2) {
772 pSetProcessDEPPolicy(0);
804 path, GetLastError()));
809 entry = GetProcAddress(module, sym);
812 path, sym, GetLastError()));
828 entry = GetProcAddress(
handle, sym);
831 sym, GetLastError()));
846 ULARGE_INTEGER u = *(ULARGE_INTEGER *)f;
847 return (time_t)((u.QuadPart - 116444736000000000ULL) / 10000000);
850 static void *
copy_info(
const char *name,
const LPWIN32_FIND_DATAA data)
855 return FS_CopyInfo(name, data->nFileSizeLow, ctime, mtime);
876 WIN32_FIND_DATAA data;
878 char fullpath[MAX_OSPATH], *name;
884 if (!(flags & FS_SEARCH_BYFILTER) &&
885 filter && !strchr(filter,
';')) {
886 if (*filter ==
'.') {
889 len =
Q_concat(fullpath,
sizeof(fullpath),
890 path,
"\\*.", filter, NULL);
893 len =
Q_concat(fullpath,
sizeof(fullpath),
897 if (len >=
sizeof(fullpath)) {
908 if (
handle == INVALID_HANDLE_VALUE) {
913 pathlen = strlen(path) + 1;
916 if (!strcmp(data.cFileName,
".") ||
917 !strcmp(data.cFileName,
"..")) {
922 len = strlen(data.cFileName);
923 if (pathlen + len >=
sizeof(fullpath)) {
927 memcpy(fullpath + pathlen, data.cFileName, len + 1);
929 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
930 mask = FS_SEARCH_DIRSONLY;
936 if ((flags & FS_SEARCH_BYFILTER) && mask &&
937 depth < MAX_LISTED_DEPTH) {
939 count_p, files, depth + 1);
942 if (*count_p >= MAX_LISTED_FILES) {
948 if ((flags & FS_SEARCH_DIRSONLY) != mask) {
954 if (flags & FS_SEARCH_BYFILTER) {
955 if (!
FS_WildCmp(filter, fullpath + baselen)) {
959 if (!
FS_ExtCmp(filter, data.cFileName)) {
966 if (flags & FS_SEARCH_SAVEPATH) {
967 name = fullpath + baselen;
969 name = data.cFileName;
976 if (flags & FS_SEARCH_STRIPEXT) {
985 if (flags & FS_SEARCH_EXTRAINFO) {
988 info = FS_CopyString(name);
991 files[(*count_p)++] = info;
992 }
while (*count_p < MAX_LISTED_FILES &&
1027 #if (_MSC_VER >= 1400)
1028 static void msvcrt_sucks(
const wchar_t *expr,
const wchar_t *func,
1029 const wchar_t *file,
unsigned int line, uintptr_t unused)
1041 #if (_MSC_VER >= 1400)
1044 _set_invalid_parameter_handler(msvcrt_sucks);
1067 #define MAX_LINE_TOKENS 128
1069 static char *sys_argv[MAX_LINE_TOKENS];
1070 static int sys_argc;
1078 static void Sys_ParseCommandLine(
char *line)
1081 sys_argv[0] = APPLICATION;
1083 while (*line && *line <= 32) {
1089 sys_argv[sys_argc++] = line;
1090 while (*line > 32) {
1097 if (sys_argc == MAX_LINE_TOKENS) {
1110 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine,
int nCmdShow)
1113 if (hPrevInstance) {
1120 Sys_ParseCommandLine(lpCmdLine);
1122 return Sys_Main(sys_argc, sys_argv);
1129 static char **sys_argv;
1130 static int sys_argc;
1132 static VOID WINAPI ServiceHandler(DWORD fdwControl)
1134 if (fdwControl == SERVICE_CONTROL_STOP) {
1139 static VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
1141 SERVICE_STATUS status;
1143 statusHandle = RegisterServiceCtrlHandler(APPLICATION, ServiceHandler);
1144 if (!statusHandle) {
1148 memset(&status, 0,
sizeof(status));
1149 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1150 status.dwCurrentState = SERVICE_RUNNING;
1151 status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
1152 SetServiceStatus(statusHandle, &status);
1156 status.dwCurrentState = SERVICE_STOPPED;
1157 status.dwControlsAccepted = 0;
1158 SetServiceStatus(statusHandle, &status);
1161 static SERVICE_TABLE_ENTRY serviceTable[] = {
1162 { APPLICATION, ServiceMain },
1166 #endif // USE_WINSVC
1183 for (i = 1; i < argc; i++) {
1184 if (!strcmp(argv[i],
"-service")) {
1188 if (StartServiceCtrlDispatcher(serviceTable)) {
1191 if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
1202 #endif // !USE_CLIENT