Home | History | Annotate | Download | only in win32
      1 /*
      2     SDL_main.c, placed in the public domain by Sam Lantinga  4/13/98
      3 
      4     The WinMain function -- calls your program's main() function
      5 */
      6 
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 
     10 #define WIN32_LEAN_AND_MEAN
     11 #include <windows.h>
     12 
     13 #ifdef _WIN32_WCE
     14 # define DIR_SEPERATOR TEXT("\\")
     15 # undef _getcwd
     16 # define _getcwd(str,len)	wcscpy(str,TEXT(""))
     17 # define setbuf(f,b)
     18 # define setvbuf(w,x,y,z)
     19 # define fopen		_wfopen
     20 # define freopen	_wfreopen
     21 # define remove(x)	DeleteFile(x)
     22 #else
     23 # define DIR_SEPERATOR TEXT("/")
     24 # include <direct.h>
     25 #endif
     26 
     27 /* Include the SDL main definition header */
     28 #include "SDL.h"
     29 #include "SDL_main.h"
     30 
     31 #ifdef main
     32 # ifndef _WIN32_WCE_EMULATION
     33 #  undef main
     34 # endif /* _WIN32_WCE_EMULATION */
     35 #endif /* main */
     36 
     37 /* The standard output files */
     38 #define STDOUT_FILE	TEXT("stdout.txt")
     39 #define STDERR_FILE	TEXT("stderr.txt")
     40 
     41 /* Set a variable to tell if the stdio redirect has been enabled. */
     42 static int stdioRedirectEnabled = 0;
     43 
     44 #ifdef _WIN32_WCE
     45   static wchar_t stdoutPath[MAX_PATH];
     46   static wchar_t stderrPath[MAX_PATH];
     47 #else
     48   static char stdoutPath[MAX_PATH];
     49   static char stderrPath[MAX_PATH];
     50 #endif
     51 
     52 #if defined(_WIN32_WCE) && _WIN32_WCE < 300
     53 /* seems to be undefined in Win CE although in online help */
     54 #define isspace(a) (((CHAR)a == ' ') || ((CHAR)a == '\t'))
     55 #endif /* _WIN32_WCE < 300 */
     56 
     57 static void UnEscapeQuotes( char *arg )
     58 {
     59 	char *last = NULL;
     60 
     61 	while( *arg ) {
     62 		if( *arg == '"' && *last == '\\' ) {
     63 			char *c_curr = arg;
     64 			char *c_last = last;
     65 
     66 			while( *c_curr ) {
     67 				*c_last = *c_curr;
     68 				c_last = c_curr;
     69 				c_curr++;
     70 			}
     71 			*c_last = '\0';
     72 		}
     73 		last = arg;
     74 		arg++;
     75 	}
     76 }
     77 
     78 /* Parse a command line buffer into arguments */
     79 static int ParseCommandLine(char *cmdline, char **argv)
     80 {
     81 	char *bufp;
     82 	char *lastp = NULL;
     83 	int argc, last_argc;
     84 
     85 	argc = last_argc = 0;
     86 	for ( bufp = cmdline; *bufp; ) {
     87 		/* Skip leading whitespace */
     88 		while ( isspace(*bufp) ) {
     89 			++bufp;
     90 		}
     91 		/* Skip over argument */
     92 		if ( *bufp == '"' ) {
     93 			++bufp;
     94 			if ( *bufp ) {
     95 				if ( argv ) {
     96 					argv[argc] = bufp;
     97 				}
     98 				++argc;
     99 			}
    100 			/* Skip over word */
    101 			while ( *bufp && ( *bufp != '"' || (lastp && *lastp == '\\') ) ) {
    102 				lastp = bufp;
    103 				++bufp;
    104 			}
    105 		} else {
    106 			if ( *bufp ) {
    107 				if ( argv ) {
    108 					argv[argc] = bufp;
    109 				}
    110 				++argc;
    111 			}
    112 			/* Skip over word */
    113 			while ( *bufp && ! isspace(*bufp) ) {
    114 				++bufp;
    115 			}
    116 		}
    117 		if ( *bufp ) {
    118 			if ( argv ) {
    119 				*bufp = '\0';
    120 			}
    121 			++bufp;
    122 		}
    123 
    124 		/* Strip out \ from \" sequences */
    125 		if( argv && last_argc != argc ) {
    126 			UnEscapeQuotes( argv[last_argc] );
    127 		}
    128 		last_argc = argc;
    129 	}
    130 	if ( argv ) {
    131 		argv[argc] = NULL;
    132 	}
    133 	return(argc);
    134 }
    135 
    136 /* Show an error message */
    137 static void ShowError(const char *title, const char *message)
    138 {
    139 /* If USE_MESSAGEBOX is defined, you need to link with user32.lib */
    140 #ifdef USE_MESSAGEBOX
    141 	MessageBox(NULL, message, title, MB_ICONEXCLAMATION|MB_OK);
    142 #else
    143 	fprintf(stderr, "%s: %s\n", title, message);
    144 #endif
    145 }
    146 
    147 /* Pop up an out of memory message, returns to Windows */
    148 static BOOL OutOfMemory(void)
    149 {
    150 	ShowError("Fatal Error", "Out of memory - aborting");
    151 	return FALSE;
    152 }
    153 
    154 /* SDL_Quit() shouldn't be used with atexit() directly because
    155    calling conventions may differ... */
    156 static void cleanup(void)
    157 {
    158 	SDL_Quit();
    159 }
    160 
    161 /* Remove the output files if there was no output written */
    162 static void cleanup_output(void) {
    163 	FILE *file;
    164 	int empty;
    165 
    166 	/* Flush the output in case anything is queued */
    167 	fclose(stdout);
    168 	fclose(stderr);
    169 
    170 	/* Without redirection we're done */
    171 	if (!stdioRedirectEnabled) {
    172 		return;
    173 	}
    174 
    175 	/* See if the files have any output in them */
    176 	if ( stdoutPath[0] ) {
    177 		file = fopen(stdoutPath, TEXT("rb"));
    178 		if ( file ) {
    179 			empty = (fgetc(file) == EOF) ? 1 : 0;
    180 			fclose(file);
    181 			if ( empty ) {
    182 				remove(stdoutPath);
    183 			}
    184 		}
    185 	}
    186 	if ( stderrPath[0] ) {
    187 		file = fopen(stderrPath, TEXT("rb"));
    188 		if ( file ) {
    189 			empty = (fgetc(file) == EOF) ? 1 : 0;
    190 			fclose(file);
    191 			if ( empty ) {
    192 				remove(stderrPath);
    193 			}
    194 		}
    195 	}
    196 }
    197 
    198 /* Redirect the output (stdout and stderr) to a file */
    199 static void redirect_output(void)
    200 {
    201 	DWORD pathlen;
    202 #ifdef _WIN32_WCE
    203 	wchar_t path[MAX_PATH];
    204 #else
    205 	char path[MAX_PATH];
    206 #endif
    207 	FILE *newfp;
    208 
    209 	pathlen = GetModuleFileName(NULL, path, SDL_arraysize(path));
    210 	while ( pathlen > 0 && path[pathlen] != '\\' ) {
    211 		--pathlen;
    212 	}
    213 	path[pathlen] = '\0';
    214 
    215 #ifdef _WIN32_WCE
    216 	wcsncpy( stdoutPath, path, SDL_arraysize(stdoutPath) );
    217 	wcsncat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) );
    218 #else
    219 	SDL_strlcpy( stdoutPath, path, SDL_arraysize(stdoutPath) );
    220 	SDL_strlcat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) );
    221 #endif
    222 
    223 	/* Redirect standard input and standard output */
    224 	newfp = freopen(stdoutPath, TEXT("w"), stdout);
    225 
    226 #ifndef _WIN32_WCE
    227 	if ( newfp == NULL ) {	/* This happens on NT */
    228 #if !defined(stdout)
    229 		stdout = fopen(stdoutPath, TEXT("w"));
    230 #else
    231 		newfp = fopen(stdoutPath, TEXT("w"));
    232 		if ( newfp ) {
    233 			*stdout = *newfp;
    234 		}
    235 #endif
    236 	}
    237 #endif /* _WIN32_WCE */
    238 
    239 #ifdef _WIN32_WCE
    240 	wcsncpy( stderrPath, path, SDL_arraysize(stdoutPath) );
    241 	wcsncat( stderrPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) );
    242 #else
    243 	SDL_strlcpy( stderrPath, path, SDL_arraysize(stderrPath) );
    244 	SDL_strlcat( stderrPath, DIR_SEPERATOR STDERR_FILE, SDL_arraysize(stderrPath) );
    245 #endif
    246 
    247 	newfp = freopen(stderrPath, TEXT("w"), stderr);
    248 #ifndef _WIN32_WCE
    249 	if ( newfp == NULL ) {	/* This happens on NT */
    250 #if !defined(stderr)
    251 		stderr = fopen(stderrPath, TEXT("w"));
    252 #else
    253 		newfp = fopen(stderrPath, TEXT("w"));
    254 		if ( newfp ) {
    255 			*stderr = *newfp;
    256 		}
    257 #endif
    258 	}
    259 #endif /* _WIN32_WCE */
    260 
    261 	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);	/* Line buffered */
    262 	setbuf(stderr, NULL);			/* No buffering */
    263 	stdioRedirectEnabled = 1;
    264 }
    265 
    266 #if defined(_MSC_VER) && !defined(_WIN32_WCE)
    267 /* The VC++ compiler needs main defined */
    268 #define console_main main
    269 #endif
    270 
    271 /* This is where execution begins [console apps] */
    272 int console_main(int argc, char *argv[])
    273 {
    274 	size_t n;
    275 	char *bufp, *appname;
    276 	int status;
    277 
    278 	/* Get the class name from argv[0] */
    279 	appname = argv[0];
    280 	if ( (bufp=SDL_strrchr(argv[0], '\\')) != NULL ) {
    281 		appname = bufp+1;
    282 	} else
    283 	if ( (bufp=SDL_strrchr(argv[0], '/')) != NULL ) {
    284 		appname = bufp+1;
    285 	}
    286 
    287 	if ( (bufp=SDL_strrchr(appname, '.')) == NULL )
    288 		n = SDL_strlen(appname);
    289 	else
    290 		n = (bufp-appname);
    291 
    292 	bufp = SDL_stack_alloc(char, n+1);
    293 	if ( bufp == NULL ) {
    294 		return OutOfMemory();
    295 	}
    296 	SDL_strlcpy(bufp, appname, n+1);
    297 	appname = bufp;
    298 
    299 	/* Load SDL dynamic link library */
    300 	if ( SDL_Init(SDL_INIT_NOPARACHUTE) < 0 ) {
    301 		ShowError("WinMain() error", SDL_GetError());
    302 		return(FALSE);
    303 	}
    304 	atexit(cleanup_output);
    305 	atexit(cleanup);
    306 
    307 	/* Sam:
    308 	   We still need to pass in the application handle so that
    309 	   DirectInput will initialize properly when SDL_RegisterApp()
    310 	   is called later in the video initialization.
    311 	 */
    312 	SDL_SetModuleHandle(GetModuleHandle(NULL));
    313 
    314 	/* Run the application main() code */
    315 	status = SDL_main(argc, argv);
    316 
    317 	/* Exit cleanly, calling atexit() functions */
    318 	exit(status);
    319 
    320 	/* Hush little compiler, don't you cry... */
    321 	return 0;
    322 }
    323 
    324 /* This is where execution begins [windowed apps] */
    325 #ifdef _WIN32_WCE
    326 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int sw)
    327 #else
    328 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
    329 #endif
    330 {
    331 	HMODULE handle;
    332 	char **argv;
    333 	int argc;
    334 	char *cmdline;
    335 	char *env_str;
    336 #ifdef _WIN32_WCE
    337 	wchar_t *bufp;
    338 	int nLen;
    339 #else
    340 	char *bufp;
    341 	size_t nLen;
    342 #endif
    343 
    344 	/* Start up DDHELP.EXE before opening any files, so DDHELP doesn't
    345 	   keep them open.  This is a hack.. hopefully it will be fixed
    346 	   someday.  DDHELP.EXE starts up the first time DDRAW.DLL is loaded.
    347 	 */
    348 	handle = LoadLibrary(TEXT("DDRAW.DLL"));
    349 	if ( handle != NULL ) {
    350 		FreeLibrary(handle);
    351 	}
    352 
    353 	/* Check for stdio redirect settings and do the redirection */
    354 	if ((env_str = SDL_getenv("SDL_STDIO_REDIRECT"))) {
    355 		if (SDL_atoi(env_str)) {
    356 			redirect_output();
    357 		}
    358 	}
    359 #ifndef NO_STDIO_REDIRECT
    360 	else {
    361 		redirect_output();
    362 	}
    363 #endif
    364 
    365 #ifdef _WIN32_WCE
    366 	nLen = wcslen(szCmdLine)+128+1;
    367 	bufp = SDL_stack_alloc(wchar_t, nLen*2);
    368 	wcscpy (bufp, TEXT("\""));
    369 	GetModuleFileName(NULL, bufp+1, 128-3);
    370 	wcscpy (bufp+wcslen(bufp), TEXT("\" "));
    371 	wcsncpy(bufp+wcslen(bufp), szCmdLine,nLen-wcslen(bufp));
    372 	nLen = wcslen(bufp)+1;
    373 	cmdline = SDL_stack_alloc(char, nLen);
    374 	if ( cmdline == NULL ) {
    375 		return OutOfMemory();
    376 	}
    377 	WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL);
    378 #else
    379 	/* Grab the command line */
    380 	bufp = GetCommandLine();
    381 	nLen = SDL_strlen(bufp)+1;
    382 	cmdline = SDL_stack_alloc(char, nLen);
    383 	if ( cmdline == NULL ) {
    384 		return OutOfMemory();
    385 	}
    386 	SDL_strlcpy(cmdline, bufp, nLen);
    387 #endif
    388 
    389 	/* Parse it into argv and argc */
    390 	argc = ParseCommandLine(cmdline, NULL);
    391 	argv = SDL_stack_alloc(char*, argc+1);
    392 	if ( argv == NULL ) {
    393 		return OutOfMemory();
    394 	}
    395 	ParseCommandLine(cmdline, argv);
    396 
    397 	/* Run the main program (after a little SDL initialization) */
    398 	console_main(argc, argv);
    399 
    400 	/* Hush little compiler, don't you cry... */
    401 	return 0;
    402 }
    403