diff --git a/include/SDL3/SDL.h b/include/SDL3/SDL.h index e69242e45..5f44e5e61 100644 --- a/include/SDL3/SDL.h +++ b/include/SDL3/SDL.h @@ -29,7 +29,6 @@ #ifndef SDL_h_ #define SDL_h_ -#include #include #include #include diff --git a/include/SDL3/SDL_main.h b/include/SDL3/SDL_main.h index 25818b820..d90c0ecb4 100644 --- a/include/SDL3/SDL_main.h +++ b/include/SDL3/SDL_main.h @@ -207,6 +207,21 @@ extern DECLSPEC void SDLCALL SDL_UnregisterApp(void); #endif /* defined(__WIN32__) || defined(__GDK__) */ +#ifdef __WIN32__ + +/** + * Initialize and launch an SDL/Win32 (classic WinAPI) application. + * + * \param mainFunction the SDL app's C-style main(), an SDL_main_func + * \param reserved reserved for future use; should be NULL + * \returns 0 on success or -1 on failure; call SDL_GetError() to retrieve + * more information on the failure. + * + * \since This function is available since SDL 3.0.0. + */ +extern DECLSPEC int SDLCALL SDL_Win32RunApp(SDL_main_func mainFunction, void * reserved); + +#endif /* __WIN32__ */ #ifdef __WINRT__ @@ -266,8 +281,16 @@ extern DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void); #ifdef __cplusplus } #endif + #include +#if !defined(SDL_MAIN_HANDLED) && !defined(_SDL_MAIN_NOIMPL) +/* include header-only SDL_main implementations */ +#if defined(__WIN32__) || defined(__GDK__) /* TODO: other platforms */ +#include +#endif +#endif /* SDL_MAIN_HANDLED */ + #endif /* SDL_main_h_ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/include/SDL3/SDL_main_impl.h b/include/SDL3/SDL_main_impl.h new file mode 100644 index 000000000..de4e8d972 --- /dev/null +++ b/include/SDL3/SDL_main_impl.h @@ -0,0 +1,107 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_main_windows_h_ +#define SDL_main_windows_h_ + +#if !defined(SDL_main_h_) +#error "This header should not be included directly, but only via SDL_main.h!" +#endif + +/* if someone wants to include SDL_main.h but doesn't want the main handing magic, + (maybe to call SDL_RegisterApp()) they can #define SDL_MAIN_HANDLED first + _SDL_MAIN_NOIMPL is for SDL-internal usage (only affects implementation, + not definition of SDL_MAIN_AVAILABLE etc in SDL_main.h) */ +#if !defined(SDL_MAIN_HANDLED) && !defined(_SDL_MAIN_NOIMPL) + +#if defined(__WIN32__) + +/* these defines/typedefs are needed for the WinMain() definition */ +#ifndef WINAPI +#define WINAPI __stdcall +#endif + +typedef struct HINSTANCE__ * HINSTANCE; +typedef char* LPSTR; + +#ifdef main +# undef main +#endif /* main */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#if defined(_MSC_VER) +/* The VC++ compiler needs main/wmain defined */ +# define console_ansi_main main +# if defined(UNICODE) && UNICODE +# define console_wmain wmain +# endif +#endif + +#if defined( UNICODE ) && UNICODE +/* This is where execution begins [console apps, unicode] */ +int +console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp) +{ + return SDL_Win32RunApp(SDL_main, NULL); +} + +#else /* ANSI */ + +/* This is where execution begins [console apps, ansi] */ +int +console_ansi_main(int argc, char *argv[]) +{ + return SDL_Win32RunApp(SDL_main, NULL); +} +#endif /* UNICODE/ANSI */ + +/* This is where execution begins [windowed apps] */ +int WINAPI +WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) +{ + return SDL_Win32RunApp(SDL_main, NULL); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include + +/* rename users main() function to SDL_main() so it can be called from the wrapper above */ +#define main SDL_main + + +#elif 1 /* end of __WIN32__ impl - TODO: other platforms */ + +#endif /* __WIN32__ etc */ + +#endif /* SDL_MAIN_HANDLED */ + +#endif /* SDL_main_windows_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/SDL_internal.h b/src/SDL_internal.h index 11470af8d..855aa0c03 100644 --- a/src/SDL_internal.h +++ b/src/SDL_internal.h @@ -181,6 +181,8 @@ #endif #include +#define _SDL_MAIN_NOIMPL /* don't drag in header-only implementation of SDL_main */ +#include /* The internal implementations of these functions have up to nanosecond precision. We can expose these functions as part of the API if we want to later. diff --git a/src/core/windows/SDL_windows.c b/src/core/windows/SDL_windows.c index 3dbe23cfc..5d417774b 100644 --- a/src/core/windows/SDL_windows.c +++ b/src/core/windows/SDL_windows.c @@ -331,6 +331,78 @@ void WIN_RectToRECT(const SDL_Rect *sdlrect, RECT *winrect) winrect->bottom = sdlrect->y + sdlrect->h - 1; } +/* SDL_Win32RunApp(), which does most of the SDL_main work for Win32 */ +#ifdef __WIN32__ + +#include /* CommandLineToArgvW() */ + +/* Pop up an out of memory message, returns to Windows */ +static int +OutOfMemory(void) +{ + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Out of memory - aborting", NULL); + return -1; +} + +DECLSPEC int +SDL_Win32RunApp(SDL_main_func mainFunction, void * xamlBackgroundPanel) +{ + + /* Gets the arguments with GetCommandLine, converts them to argc and argv + and calls SDL_main */ + + LPWSTR *argvw; + char **argv; + int i, argc, result; + + argvw = CommandLineToArgvW(GetCommandLineW(), &argc); + if (argvw == NULL) { + 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 == NULL) { + return OutOfMemory(); + } + for (i = 0; i < argc; ++i) { + DWORD len; + char *arg = WIN_StringToUTF8W(argvw[i]); + if (arg == NULL) { + return OutOfMemory(); + } + len = (DWORD)SDL_strlen(arg); + argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 1); + if (!argv[i]) { + return OutOfMemory(); + } + SDL_memcpy(argv[i], arg, len); + SDL_free(arg); + } + argv[i] = NULL; + LocalFree(argvw); + + SDL_SetMainReady(); + + /* Run the application main() code */ + result = mainFunction(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 /* __WIN32__ */ + #endif /* defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__) */ /* diff --git a/src/dynapi/SDL_dynapi.c b/src/dynapi/SDL_dynapi.c index 62625049c..d1f627b59 100644 --- a/src/dynapi/SDL_dynapi.c +++ b/src/dynapi/SDL_dynapi.c @@ -31,6 +31,9 @@ #endif #include +#define _SDL_MAIN_NOIMPL /* don't drag in header-only implementation of SDL_main */ +#include + /* These headers have system specific definitions, so aren't included above */ #include diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index a3ebfd3df..785c1515b 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -861,6 +861,7 @@ SDL3_0.0.0 { SDL_DelayNS; SDL_GetEventState; SDL_GetRenderDriver; + SDL_Win32RunApp; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 230abdb68..44575201c 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -885,3 +885,4 @@ #define SDL_DelayNS SDL_DelayNS_REAL #define SDL_GetEventState SDL_GetEventState_REAL #define SDL_GetRenderDriver SDL_GetRenderDriver_REAL +#define SDL_Win32RunApp SDL_Win32RunApp_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 7915e6c9e..dd7707b50 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -961,3 +961,6 @@ SDL_DYNAPI_PROC(Uint64,SDL_GetTicksNS,(void),(),return) SDL_DYNAPI_PROC(void,SDL_DelayNS,(Uint64 a),(a),) SDL_DYNAPI_PROC(Uint8,SDL_GetEventState,(Uint32 a),(a),return) SDL_DYNAPI_PROC(const char*,SDL_GetRenderDriver,(int a),(a),return) +#if defined(__WIN32__) +SDL_DYNAPI_PROC(int,SDL_Win32RunApp,(SDL_main_func a, void *b),(a,b),return) +#endif diff --git a/src/main/windows/SDL_windows_main.c b/src/main/windows/SDL_windows_main.c index 5f65d5b03..36bad6ea4 100644 --- a/src/main/windows/SDL_windows_main.c +++ b/src/main/windows/SDL_windows_main.c @@ -1,110 +1,8 @@ /* SDL_windows_main.c, placed in the public domain by Sam Lantinga 4/13/98 - The WinMain function -- calls your program's main() function + Nothing to do here, the code moved into SDL_main_impl.h and SDL_windows.c (SDL_Win32RunApp()) + TODO: remove this file */ -#include - -#ifdef __WIN32__ - -/* Include this so we define UNICODE properly */ -#include "../../core/windows/SDL_windows.h" -#include /* CommandLineToArgvW() */ - -#ifdef main -#undef main -#endif /* main */ - -/* 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 FALSE; -} - -#if defined(_MSC_VER) -/* The VC++ compiler needs main/wmain defined */ -#define console_ansi_main main -#if UNICODE -#define console_wmain wmain -#endif -#endif - -/* Gets the arguments with GetCommandLine, converts them to argc and argv - and calls SDL_main */ -static int main_getcmdline(void) -{ - LPWSTR *argvw; - char **argv; - int i, argc, result; - - argvw = CommandLineToArgvW(GetCommandLineW(), &argc); - if (argvw == NULL) { - 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 == NULL) { - return OutOfMemory(); - } - for (i = 0; i < argc; ++i) { - DWORD len; - char *arg = WIN_StringToUTF8W(argvw[i]); - if (arg == NULL) { - return OutOfMemory(); - } - len = (DWORD)SDL_strlen(arg); - argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (size_t)len + 1); - if (!argv[i]) { - return OutOfMemory(); - } - SDL_memcpy(argv[i], arg, len); - SDL_free(arg); - } - 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; -} - -/* This is where execution begins [console apps, ansi] */ -int console_ansi_main(int argc, char *argv[]) -{ - return main_getcmdline(); -} - -#if UNICODE -/* This is where execution begins [console apps, unicode] */ -int console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp) -{ - return main_getcmdline(); -} -#endif - -/* This is where execution begins [windowed apps] */ -int WINAPI -WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) /* NOLINT(readability-inconsistent-declaration-parameter-name) */ -{ - return main_getcmdline(); -} - -#endif /* __WIN32__ */ /* vi: set ts=4 sw=4 expandtab: */