mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-30 08:01:02 +00:00
SDL3: Now works on Windows as well
Refactored the pseudo-custom SDL_main code a bit: SDL_win32_main.c is now only used for SDL1.2, SDL2 and SDL3 have a WinMain() function in win_main.cpp that works pretty much like the SDL2 SDL_main or SDL3 SDL_RunApp() code - except that the argv[] strings passed to the Doom3 main() function (now renamed to SDL_main()) are encoded in ANSI instead of UTF-8, so paths passed as commandline arguments, like dhewm3 +set fs_basepath C:\SüperGämes\Doom3 work with the Win32 ANSI function used by Doom3 to handle paths and files. For this I also moved the stdout/stderr redirection code from SDL_win32_main.c to win_main.cpp and cleaned it up a bit
This commit is contained in:
parent
19f28e3c2d
commit
6181f24c44
4 changed files with 250 additions and 159 deletions
|
@ -1181,9 +1181,13 @@ elseif(WIN32)
|
|||
sys/win32/win_net.cpp
|
||||
sys/win32/win_shared.cpp
|
||||
sys/win32/win_syscon.cpp
|
||||
sys/win32/SDL_win32_main.c
|
||||
)
|
||||
|
||||
if(NOT SDL2 AND NOT SDL3)
|
||||
# only SDL1.2 still uses SDL_win32_main.c
|
||||
set(src_sys_base ${src_sys_base} sys/win32/SDL_win32_main.c)
|
||||
endif()
|
||||
|
||||
# adding the few relevant headers in sys/ manually..
|
||||
set(src_sys_base ${src_sys_base}
|
||||
sys/platform.h
|
||||
|
|
|
@ -47,7 +47,11 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
#if defined(_WIN32) && defined(ID_ALLOW_TOOLS)
|
||||
#include "sys/win32/win_local.h"
|
||||
#include <SDL_syswm.h>
|
||||
|
||||
// SDL3 doesn't have SDL_syswm.h
|
||||
#if ! SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
#include <SDL_syswm.h>
|
||||
#endif
|
||||
|
||||
// from SDL_windowsopengl.h (internal SDL2 header)
|
||||
#ifndef WGL_ARB_pixel_format
|
||||
|
@ -632,6 +636,13 @@ try_again:
|
|||
// then we know we are win32 and we have to include this
|
||||
// config to get the editors to work.
|
||||
|
||||
#if SDL_VERSION_ATLEAST(3, 0, 0)
|
||||
HWND hwnd = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
|
||||
HDC hdc = (HDC)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HDC_POINTER, NULL);
|
||||
if ( hwnd && hdc ) {
|
||||
win32.hWnd = hwnd;
|
||||
win32.hDC = hdc;
|
||||
#else // SDL2
|
||||
// Get the HWND for later use.
|
||||
SDL_SysWMinfo sdlinfo;
|
||||
SDL_version sdlver;
|
||||
|
@ -640,6 +651,7 @@ try_again:
|
|||
if (SDL_GetWindowWMInfo(window, &sdlinfo) && sdlinfo.subsystem == SDL_SYSWM_WINDOWS) {
|
||||
win32.hWnd = sdlinfo.info.win.window;
|
||||
win32.hDC = sdlinfo.info.win.hdc;
|
||||
#endif
|
||||
// NOTE: hInstance is set in main()
|
||||
win32.hGLRC = qwglGetCurrentContext();
|
||||
|
||||
|
|
|
@ -160,154 +160,6 @@ static void cleanup(void)
|
|||
SDL_Quit();
|
||||
}
|
||||
|
||||
/* Remove the output files if there was no output written */
|
||||
static void cleanup_output(void) {
|
||||
FILE *file;
|
||||
int empty;
|
||||
|
||||
/* Flush the output in case anything is queued */
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
|
||||
/* Without redirection we're done */
|
||||
if (!stdioRedirectEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* See if the files have any output in them */
|
||||
if ( stdoutPath[0] ) {
|
||||
file = fopen(stdoutPath, TEXT("rb"));
|
||||
if ( file ) {
|
||||
empty = (fgetc(file) == EOF) ? 1 : 0;
|
||||
fclose(file);
|
||||
if ( empty ) {
|
||||
remove(stdoutPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( stderrPath[0] ) {
|
||||
file = fopen(stderrPath, TEXT("rb"));
|
||||
if ( file ) {
|
||||
empty = (fgetc(file) == EOF) ? 1 : 0;
|
||||
fclose(file);
|
||||
if ( empty ) {
|
||||
remove(stderrPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern int Win_GetHomeDir(char *dst, size_t size);
|
||||
|
||||
/* Redirect the output (stdout and stderr) to a file */
|
||||
static void redirect_output(void)
|
||||
{
|
||||
#ifdef _WIN32_WCE
|
||||
wchar_t path[MAX_PATH];
|
||||
#error "adapt homedir code for wchar_t!"
|
||||
#else
|
||||
char path[MAX_PATH];
|
||||
struct _stat st;
|
||||
|
||||
/* DG: use "My Documents/My Games/dhewm3" to write stdout.txt and stderr.txt
|
||||
* instead of the binary, which might not be writable */
|
||||
Win_GetHomeDir(path, sizeof(path));
|
||||
|
||||
if (_stat(path, &st) == -1) {
|
||||
/* oops, "My Documents/My Games/dhewm3" doesn't exist - does My Games/ at least exist? */
|
||||
char myGamesPath[MAX_PATH];
|
||||
char* lastslash;
|
||||
memcpy(myGamesPath, path, MAX_PATH);
|
||||
lastslash = strrchr(myGamesPath, '/');
|
||||
if (lastslash != NULL) {
|
||||
*lastslash = '\0';
|
||||
}
|
||||
if (_stat(myGamesPath, &st) == -1) {
|
||||
/* if My Documents/My Games/ doesn't exist, create it */
|
||||
_mkdir(myGamesPath);
|
||||
}
|
||||
|
||||
_mkdir(path); /* create My Documents/My Games/dhewm3/ */
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
FILE *newfp;
|
||||
|
||||
#if 0 /* DG: don't do this anymore. */
|
||||
DWORD pathlen;
|
||||
pathlen = GetModuleFileName(NULL, path, SDL_arraysize(path));
|
||||
while ( pathlen > 0 && path[pathlen] != '\\' ) {
|
||||
--pathlen;
|
||||
}
|
||||
path[pathlen] = '\0';
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
wcsncpy( stdoutPath, path, SDL_arraysize(stdoutPath) );
|
||||
wcsncat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) );
|
||||
#else
|
||||
SDL_strlcpy( stdoutPath, path, SDL_arraysize(stdoutPath) );
|
||||
SDL_strlcat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) );
|
||||
#endif
|
||||
|
||||
{ /* DG: rename old stdout log */
|
||||
#ifdef _WIN32_WCE
|
||||
wchar_t stdoutPathBK[MAX_PATH];
|
||||
wcsncpy( stdoutPathBK, path, SDL_arraysize(stdoutPath) );
|
||||
wcsncat( stdoutPathBK, DIR_SEPERATOR TEXT("dhewm3log-old.txt"), SDL_arraysize(stdoutPath) );
|
||||
_wrename( stdoutPath, stdoutpathBK );
|
||||
#else
|
||||
char stdoutPathBK[MAX_PATH];
|
||||
SDL_strlcpy( stdoutPathBK, path, SDL_arraysize(stdoutPath) );
|
||||
SDL_strlcat( stdoutPathBK, DIR_SEPERATOR TEXT("dhewm3log-old.txt"), SDL_arraysize(stdoutPath) );
|
||||
rename( stdoutPath, stdoutPathBK );
|
||||
#endif
|
||||
} /* DG end */
|
||||
|
||||
/* Redirect standard input and standard output */
|
||||
newfp = freopen(stdoutPath, TEXT("w"), stdout);
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
if ( newfp == NULL ) { /* This happens on NT */
|
||||
#if !defined(stdout)
|
||||
stdout = fopen(stdoutPath, TEXT("w"));
|
||||
#else
|
||||
newfp = fopen(stdoutPath, TEXT("w"));
|
||||
if ( newfp ) {
|
||||
*stdout = *newfp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* _WIN32_WCE */
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
wcsncpy( stderrPath, path, SDL_arraysize(stdoutPath) );
|
||||
wcsncat( stderrPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) );
|
||||
#else
|
||||
SDL_strlcpy( stderrPath, path, SDL_arraysize(stderrPath) );
|
||||
SDL_strlcat( stderrPath, DIR_SEPERATOR STDERR_FILE, SDL_arraysize(stderrPath) );
|
||||
#endif
|
||||
|
||||
newfp = freopen(stderrPath, TEXT("w"), stderr);
|
||||
#ifndef _WIN32_WCE
|
||||
if ( newfp == NULL ) { /* This happens on NT */
|
||||
#if !defined(stderr)
|
||||
stderr = fopen(stderrPath, TEXT("w"));
|
||||
#else
|
||||
newfp = fopen(stderrPath, TEXT("w"));
|
||||
if ( newfp ) {
|
||||
*stderr = *newfp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* _WIN32_WCE */
|
||||
|
||||
setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* Line buffered */
|
||||
setbuf(stderr, NULL); /* No buffering */
|
||||
stdioRedirectEnabled = 1;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_WIN32_WCE)
|
||||
/* The VC++ compiler needs main defined */
|
||||
#define console_main main
|
||||
|
@ -397,6 +249,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
|
|||
FreeLibrary(handle);
|
||||
}
|
||||
|
||||
#if 0 // DG: output redirection is now done in dhewm3's main() aka SDL_main()
|
||||
/* Check for stdio redirect settings and do the redirection */
|
||||
if ((env_str = SDL_getenv("SDL_STDIO_REDIRECT"))) {
|
||||
if (SDL_atoi(env_str)) {
|
||||
|
@ -408,6 +261,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
|
|||
redirect_output();
|
||||
}
|
||||
#endif
|
||||
#endif // 0
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
nLen = wcslen(szCmdLine)+128+1;
|
||||
|
|
|
@ -53,7 +53,15 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
#include "tools/edit_public.h"
|
||||
|
||||
#include <SDL_main.h>
|
||||
#include "sys/sys_sdl.h"
|
||||
|
||||
#ifdef D3_SDL3
|
||||
#define SDL_MAIN_HANDLED // dhewm3 implements WinMain() itself
|
||||
#include <SDL3/SDL_main.h>
|
||||
#else // SDL1.2 or SDL2
|
||||
#include <SDL_main.h>
|
||||
#endif
|
||||
|
||||
|
||||
idCVar Win32Vars_t::win_outputDebugString( "win_outputDebugString", "0", CVAR_SYSTEM | CVAR_BOOL, "" );
|
||||
idCVar Win32Vars_t::win_outputEditString( "win_outputEditString", "1", CVAR_SYSTEM | CVAR_BOOL, "" );
|
||||
|
@ -1001,14 +1009,154 @@ int Win_ChoosePixelFormat(HDC hdc)
|
|||
}
|
||||
#endif
|
||||
|
||||
// stdout/stderr redirection, originally from SDL_win32_main.c
|
||||
|
||||
/* The standard output files */
|
||||
#define STDOUT_FILE TEXT("dhewm3log.txt") /* DG: renamed this */
|
||||
#define STDERR_FILE TEXT("stderr.txt")
|
||||
|
||||
/* Set a variable to tell if the stdio redirect has been enabled. */
|
||||
static int stdioRedirectEnabled = 0;
|
||||
static char stdoutPath[MAX_PATH];
|
||||
static char stderrPath[MAX_PATH];
|
||||
#define DIR_SEPERATOR TEXT("/")
|
||||
|
||||
|
||||
/* Remove the output files if there was no output written */
|
||||
static void cleanup_output(void) {
|
||||
FILE *file;
|
||||
int empty;
|
||||
|
||||
/* Flush the output in case anything is queued */
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
|
||||
/* Without redirection we're done */
|
||||
if (!stdioRedirectEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* See if the files have any output in them */
|
||||
if ( stdoutPath[0] ) {
|
||||
file = fopen(stdoutPath, TEXT("rb"));
|
||||
if ( file ) {
|
||||
empty = (fgetc(file) == EOF) ? 1 : 0;
|
||||
fclose(file);
|
||||
if ( empty ) {
|
||||
remove(stdoutPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( stderrPath[0] ) {
|
||||
file = fopen(stderrPath, TEXT("rb"));
|
||||
if ( file ) {
|
||||
empty = (fgetc(file) == EOF) ? 1 : 0;
|
||||
fclose(file);
|
||||
if ( empty ) {
|
||||
remove(stderrPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Redirect the output (stdout and stderr) to a file */
|
||||
static void redirect_output(void)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
struct _stat st;
|
||||
|
||||
/* DG: use "My Documents/My Games/dhewm3" to write stdout.txt and stderr.txt
|
||||
* instead of the binary, which might not be writable */
|
||||
Win_GetHomeDir(path, sizeof(path));
|
||||
|
||||
if (_stat(path, &st) == -1) {
|
||||
/* oops, "My Documents/My Games/dhewm3" doesn't exist - does My Games/ at least exist? */
|
||||
char myGamesPath[MAX_PATH];
|
||||
char* lastslash;
|
||||
memcpy(myGamesPath, path, MAX_PATH);
|
||||
lastslash = strrchr(myGamesPath, '/');
|
||||
if (lastslash != NULL) {
|
||||
*lastslash = '\0';
|
||||
}
|
||||
if (_stat(myGamesPath, &st) == -1) {
|
||||
/* if My Documents/My Games/ doesn't exist, create it */
|
||||
_mkdir(myGamesPath);
|
||||
}
|
||||
|
||||
_mkdir(path); /* create My Documents/My Games/dhewm3/ */
|
||||
}
|
||||
|
||||
FILE *newfp;
|
||||
|
||||
#if 0 /* DG: don't do this anymore. */
|
||||
DWORD pathlen;
|
||||
pathlen = GetModuleFileName(NULL, path, SDL_arraysize(path));
|
||||
while ( pathlen > 0 && path[pathlen] != '\\' ) {
|
||||
--pathlen;
|
||||
}
|
||||
path[pathlen] = '\0';
|
||||
#endif
|
||||
|
||||
SDL_strlcpy( stdoutPath, path, SDL_arraysize(stdoutPath) );
|
||||
SDL_strlcat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) );
|
||||
|
||||
{ /* DG: rename old stdout log */
|
||||
char stdoutPathBK[MAX_PATH];
|
||||
SDL_strlcpy( stdoutPathBK, path, SDL_arraysize(stdoutPath) );
|
||||
SDL_strlcat( stdoutPathBK, DIR_SEPERATOR TEXT("dhewm3log-old.txt"), SDL_arraysize(stdoutPath) );
|
||||
rename( stdoutPath, stdoutPathBK );
|
||||
} /* DG end */
|
||||
|
||||
/* Redirect standard input and standard output */
|
||||
newfp = freopen(stdoutPath, TEXT("w"), stdout);
|
||||
|
||||
if ( newfp == NULL ) { /* This happens on NT */
|
||||
#if !defined(stdout)
|
||||
stdout = fopen(stdoutPath, TEXT("w"));
|
||||
#else
|
||||
newfp = fopen(stdoutPath, TEXT("w"));
|
||||
if ( newfp ) {
|
||||
*stdout = *newfp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SDL_strlcpy( stderrPath, path, SDL_arraysize(stderrPath) );
|
||||
SDL_strlcat( stderrPath, DIR_SEPERATOR STDERR_FILE, SDL_arraysize(stderrPath) );
|
||||
|
||||
newfp = freopen(stderrPath, TEXT("w"), stderr);
|
||||
if ( newfp == NULL ) { /* This happens on NT */
|
||||
#if !defined(stderr)
|
||||
stderr = fopen(stderrPath, TEXT("w"));
|
||||
#else
|
||||
newfp = fopen(stderrPath, TEXT("w"));
|
||||
if ( newfp ) {
|
||||
*stderr = *newfp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* Line buffered */
|
||||
setbuf(stderr, NULL); /* No buffering */
|
||||
stdioRedirectEnabled = 1;
|
||||
}
|
||||
|
||||
// end of stdout/stderr redirection code from old SDL
|
||||
|
||||
/*
|
||||
==================
|
||||
WinMain
|
||||
The pseudo-main function called from real main (either in SDL_win32_main.c or WinMain() below)
|
||||
NOTE: Currently argv[] are ANSI strings, not UTF-8 strings as usual in SDL2 and SDL3!
|
||||
==================
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
// SDL_win32_main.c creates the dhewm3log.txt and redirects stdout into it
|
||||
// so here we can log its (approx.) creation time before anything else is logged:
|
||||
int SDL_main(int argc, char *argv[]) {
|
||||
// as the very first thing, redirect stdout to dhewm3log.txt (and stderr to stderr.txt)
|
||||
// so we can log
|
||||
redirect_output();
|
||||
atexit(cleanup_output);
|
||||
|
||||
// now that stdout is redirected to dhewm3log.txt,
|
||||
// log its (approx.) creation time before anything else is logged:
|
||||
{
|
||||
time_t tt = time(NULL);
|
||||
const struct tm* tms = localtime(&tt);
|
||||
|
@ -1017,8 +1165,6 @@ int main(int argc, char *argv[]) {
|
|||
printf("Opened this log at %s\n", timeStr);
|
||||
}
|
||||
|
||||
const HCURSOR hcurSave = ::SetCursor( LoadCursor( 0, IDC_WAIT ) );
|
||||
|
||||
InitializeCriticalSection( &printfCritSect );
|
||||
|
||||
#ifdef ID_DEDICATED
|
||||
|
@ -1065,8 +1211,6 @@ int main(int argc, char *argv[]) {
|
|||
SetThreadAffinityMask( GetCurrentThread(), 1 );
|
||||
#endif
|
||||
|
||||
// ::SetCursor( hcurSave ); // DG: I think SDL handles the cursor fine..
|
||||
|
||||
// Launch the script debugger
|
||||
if ( strstr( GetCommandLine(), "+debugger" ) ) {
|
||||
|
||||
|
@ -1204,3 +1348,80 @@ void idSysLocal::StartProcess( const char *exePath, bool doexit ) {
|
|||
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit\n" );
|
||||
}
|
||||
}
|
||||
|
||||
// the actual WinMain(), based on SDL2_main and SDL3's SDL_main_impl.h + SDL_RunApp()
|
||||
// but modified to pass ANSI strings to SDL_main() instead of UTF-8,
|
||||
// because dhewm3 doesn't use Unicode internally (except for Dear ImGui,
|
||||
// which doesn't use commandline arguments)
|
||||
// for SDL1.2, SDL_win32_main.c is still used instead
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||
|
||||
/* Pop up an out of memory message, returns to Windows */
|
||||
static BOOL OutOfMemory(void)
|
||||
{
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Out of memory - aborting", NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
|
||||
{
|
||||
(void)hInst;
|
||||
(void)hPrev;
|
||||
(void)szCmdLine;
|
||||
(void)sw;
|
||||
|
||||
LPWSTR *argvw;
|
||||
char **argv;
|
||||
int i, argc, result;
|
||||
|
||||
argvw = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
if (!argvw) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
|
||||
/* Note that we need to be careful about how we allocate/free memory here.
|
||||
* If the application calls SDL_SetMemoryFunctions(), we can't rely on
|
||||
* SDL_free() to use the same allocator after SDL_main() returns.
|
||||
*/
|
||||
|
||||
/* Parse it into argv and argc */
|
||||
argv = (char **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (argc + 1) * sizeof(*argv));
|
||||
if (!argv) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
for (i = 0; i < argc; ++i) {
|
||||
// NOTE: SDL2+ uses CP_UTF8 instead of CP_ACP here (and in the other call below)
|
||||
// but Doom3 needs ANSI strings on Windows (so paths work with the Windows ANSI APIs)
|
||||
const int ansiSize = WideCharToMultiByte(CP_ACP, 0, argvw[i], -1, NULL, 0, NULL, NULL);
|
||||
if (!ansiSize) { // uhoh?
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ansiSize); // this size includes the null-terminator character.
|
||||
if (!argv[i]) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
|
||||
if (WideCharToMultiByte(CP_ACP, 0, argvw[i], -1, argv[i], ansiSize, NULL, NULL) == 0) { // failed? uhoh!
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
argv[i] = NULL;
|
||||
LocalFree(argvw);
|
||||
|
||||
SDL_SetMainReady();
|
||||
|
||||
// Run the application main() code
|
||||
result = SDL_main(argc, argv);
|
||||
|
||||
// Free argv, to avoid memory leak
|
||||
for (i = 0; i < argc; ++i) {
|
||||
HeapFree(GetProcessHeap(), 0, argv[i]);
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, argv);
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue