Skip to content

Commit 1812547

Browse files
committed
main: Move Windows and GDK argv handling to a common function
1 parent c6f979f commit 1812547

File tree

6 files changed

+49
-84
lines changed

6 files changed

+49
-84
lines changed

VisualC-GDK/SDL/SDL.vcxproj

+2-1
Original file line numberDiff line numberDiff line change
@@ -544,8 +544,9 @@
544544
<ClCompile Include="..\..\src\io\generic\SDL_asyncio_generic.c" />
545545
<ClCompile Include="..\..\src\io\SDL_asyncio.c" />
546546
<ClCompile Include="..\..\src\io\windows\SDL_asyncio_windows_ioring.c" />
547-
<ClCompile Include="..\..\src\main\gdk\SDL_sysmain_runapp.cpp" />
548547
<ClCompile Include="..\..\src\main\generic\SDL_sysmain_callbacks.c" />
548+
<ClCompile Include="..\..\src\main\gdk\SDL_sysmain_runapp.cpp" />
549+
<ClCompile Include="..\..\src\main\windows\SDL_sysmain_runapp.c" />
549550
<ClCompile Include="..\..\src\main\SDL_main_callbacks.c" />
550551
<ClCompile Include="..\..\src\main\SDL_runapp.c" />
551552
<ClCompile Include="..\..\src\SDL_guid.c" />

VisualC-GDK/SDL/SDL.vcxproj.filters

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
<ClCompile Include="..\..\src\render\direct3d12\SDL_shaders_d3d12_xboxone.cpp" />
99
<ClCompile Include="..\..\src\render\direct3d12\SDL_shaders_d3d12_xboxseries.cpp" />
1010
<ClCompile Include="..\..\src\main\generic\SDL_sysmain_callbacks.c" />
11-
<ClCompile Include="..\..\src\main\SDL_main_callbacks.c" />
1211
<ClCompile Include="..\..\src\main\gdk\SDL_sysmain_runapp.cpp" />
12+
<ClCompile Include="..\..\src\main\windows\SDL_sysmain_runapp.c" />
13+
<ClCompile Include="..\..\src\main\SDL_main_callbacks.c" />
1314
<ClCompile Include="..\..\src\main\SDL_runapp.c" />
1415
<ClCompile Include="..\..\src\SDL_guid.c" />
1516
<ClCompile Include="..\..\src\atomic\SDL_atomic.c" />

src/main/SDL_runapp.c

+12-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
#include "SDL_internal.h"
2222
#include "SDL_runapp.h"
2323

24-
/* Most platforms that use/need SDL_main have their own SDL_RunApp() implementation.
25-
* If not, you can special case it here by appending || defined(__YOUR_PLATFORM__) */
24+
// Most platforms that use/need SDL_main have their own SDL_RunApp() implementations.
25+
// If not, you can special case it here by appending '|| defined(__YOUR_PLATFORM__)'.
2626
#if ( !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE) ) || defined(SDL_PLATFORM_ANDROID)
2727

2828
int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
@@ -34,6 +34,14 @@ int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserv
3434

3535
#endif
3636

37+
// Most platforms receive a standard argv via their native entry points
38+
// and don't provide any other (reliable) ways of getting the command-line arguments.
39+
// For those platforms, we only try to ensure that the argv is not NULL
40+
// (which it might be if the user calls SDL_RunApp() directly instead of using SDL_main).
41+
// Platforms that don't use standard argc/argv entry points but provide other ways of
42+
// getting the command-line arguments have their own SDL_CallMain() implementations.
43+
#ifndef SDL_PLATFORM_WINDOWS
44+
3745
int SDL_CallMain(int argc, char* argv[], SDL_main_func mainFunction)
3846
{
3947
char dummyargv0[] = { 'S', 'D', 'L', '_', 'a', 'p', 'p', '\0' };
@@ -46,3 +54,5 @@ int SDL_CallMain(int argc, char* argv[], SDL_main_func mainFunction)
4654

4755
return mainFunction(argc, argv);
4856
}
57+
58+
#endif

src/main/SDL_runapp.h

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
#ifndef SDL_runapp_h_
2323
#define SDL_runapp_h_
2424

25+
// Call the provided main function.
26+
// If the provided argv is non-NULL, SDL will pass it forward to mainFunction as-is.
27+
// If the provided argv is NULL, the behavior is platform-dependent.
28+
// SDL may try to get the command-line arguments for the current process and use those instead,
29+
// or it may fall back on a simple dummy argv.
2530
int SDL_CallMain(int argc, char* argv[], SDL_main_func mainFunction);
2631

2732
#endif // SDL_runapp_h_

src/main/gdk/SDL_sysmain_runapp.cpp

+4-70
Original file line numberDiff line numberDiff line change
@@ -31,75 +31,12 @@ extern "C" {
3131
#include <shellapi.h> // CommandLineToArgvW()
3232
#include <appnotify.h>
3333

34-
static int OutOfMemory(void)
35-
{
36-
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Out of memory - aborting", NULL);
37-
return -1;
38-
}
39-
40-
static int ErrorProcessingCommandLine(void)
41-
{
42-
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL);
43-
return -1;
44-
}
45-
4634
extern "C"
47-
int SDL_RunApp(int caller_argc, char* caller_argv[], SDL_main_func mainFunction, void *)
35+
int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void *)
4836
{
49-
int result, argc;
50-
LPWSTR *argvw = NULL;
51-
char **argv = NULL;
5237
HRESULT hr;
5338
XTaskQueueHandle taskQueue;
5439

55-
// Note that we need to be careful about how we allocate/free memory in this function. If the application calls
56-
// SDL_SetMemoryFunctions(), we can't rely on SDL_free() to use the same allocator after SDL_main() returns.
57-
58-
if (!caller_argv || caller_argc < 0) {
59-
// If the passed argv is NULL or argc is negative, the user expects SDL to get the command line arguments
60-
// using GetCommandLineW() and convert them to argc and argv before calling mainFunction().
61-
62-
// Because of how the Windows command line works, we know for sure that the buffer size required to store all
63-
// argument strings converted to UTF-8 (with null terminators) is guaranteed to be less than or equal to the
64-
// size of the original command line string converted to UTF-8.
65-
const int argdata_size = WideCharToMultiByte(CP_UTF8, 0, GetCommandLineW(), -1, NULL, 0, NULL, NULL); // Includes the null terminator
66-
if (!argdata_size) {
67-
result = ErrorProcessingCommandLine();
68-
goto cleanup;
69-
}
70-
71-
argvw = CommandLineToArgvW(GetCommandLineW(), &argc);
72-
if (!argvw || argc < 0) {
73-
result = OutOfMemory();
74-
goto cleanup;
75-
}
76-
77-
// Allocate argv followed by the argument string buffer as one contiguous allocation.
78-
argv = (char **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (argc + 1) * sizeof(*argv) + argdata_size);
79-
if (!argv) {
80-
result = OutOfMemory();
81-
goto cleanup;
82-
}
83-
char *argdata = ((char *)argv) + (argc + 1) * sizeof(*argv);
84-
int argdata_index = 0;
85-
86-
for (int i = 0; i < argc; ++i) {
87-
const int bytes_written = WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, argdata + argdata_index, argdata_size - argdata_index, NULL, NULL);
88-
if (!bytes_written) {
89-
result = ErrorProcessingCommandLine();
90-
goto cleanup;
91-
}
92-
argv[i] = argdata + argdata_index;
93-
argdata_index += bytes_written;
94-
}
95-
argv[argc] = NULL;
96-
97-
argvw = NULL;
98-
99-
caller_argc = argc;
100-
caller_argv = argv;
101-
}
102-
10340
// !!! FIXME: This function does not currently properly deinitialize GDK resources on failure.
10441

10542
hr = XGameRuntimeInitialize();
@@ -130,7 +67,9 @@ int SDL_RunApp(int caller_argc, char* caller_argv[], SDL_main_func mainFunction,
13067
return -1;
13168
}
13269

133-
result = mainFunction(caller_argc, caller_argv); // No need for SDL_CallMain(); we already know that we have a valid argv
70+
// The common Windows SDL_CallMain() implementation is responsible for handling the argv
71+
// and substituting it with a new argv parsed from the command-line string, if needed.
72+
result = SDL_CallMain(argc, argv, mainFunction);
13473

13574
GDK_UnregisterChangeNotifications();
13675

@@ -156,10 +95,5 @@ int SDL_RunApp(int caller_argc, char* caller_argv[], SDL_main_func mainFunction,
15695
result = -1;
15796
}
15897

159-
cleanup:
160-
161-
HeapFree(GetProcessHeap(), 0, argv);
162-
LocalFree(argvw);
163-
16498
return result;
16599
}

src/main/windows/SDL_sysmain_runapp.c

+24-10
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*/
2121
#include "SDL_internal.h"
2222

23-
#ifdef SDL_PLATFORM_WIN32
23+
#ifdef SDL_PLATFORM_WINDOWS
2424

2525
#include "../SDL_runapp.h"
2626
#include "../../core/windows/SDL_windows.h"
@@ -39,23 +39,25 @@ static int ErrorProcessingCommandLine(void)
3939
return -1;
4040
}
4141

42-
int MINGW32_FORCEALIGN SDL_RunApp(int caller_argc, char* caller_argv[], SDL_main_func mainFunction, void * reserved)
42+
// If the provided argv is NULL (which it will be when using SDL_main), this function parses
43+
// the command-line string for the current process into an argv and uses that instead.
44+
// Otherwise, the provided argv is used as-is (since that's probably what the user wants).
45+
int SDL_CallMain(int caller_argc, char* caller_argv[], SDL_main_func mainFunction)
4346
{
4447
int result, argc;
4548
LPWSTR *argvw = NULL;
4649
char **argv = NULL;
47-
(void)reserved;
4850

4951
// Note that we need to be careful about how we allocate/free memory in this function. If the application calls
5052
// SDL_SetMemoryFunctions(), we can't rely on SDL_free() to use the same allocator after SDL_main() returns.
5153

5254
if (!caller_argv || caller_argc < 0) {
53-
// If the passed argv is NULL or argc is negative, the user expects SDL to get the command line arguments
55+
// If the passed argv is NULL (or argc is negative), SDL should get the command-line arguments
5456
// using GetCommandLineW() and convert them to argc and argv before calling mainFunction().
5557

56-
// Because of how the Windows command line works, we know for sure that the buffer size required to store all
58+
// Because of how the Windows command-line works, we know for sure that the buffer size required to store all
5759
// argument strings converted to UTF-8 (with null terminators) is guaranteed to be less than or equal to the
58-
// size of the original command line string converted to UTF-8.
60+
// size of the original command-line string converted to UTF-8.
5961
const int argdata_size = WideCharToMultiByte(CP_UTF8, 0, GetCommandLineW(), -1, NULL, 0, NULL, NULL); // Includes the null terminator
6062
if (!argdata_size) {
6163
result = ErrorProcessingCommandLine();
@@ -94,9 +96,7 @@ int MINGW32_FORCEALIGN SDL_RunApp(int caller_argc, char* caller_argv[], SDL_main
9496
caller_argv = argv;
9597
}
9698

97-
SDL_SetMainReady();
98-
99-
result = mainFunction(caller_argc, caller_argv); // No need for SDL_CallMain(); we already know that we have a valid argv
99+
result = mainFunction(caller_argc, caller_argv);
100100

101101
cleanup:
102102

@@ -106,4 +106,18 @@ int MINGW32_FORCEALIGN SDL_RunApp(int caller_argc, char* caller_argv[], SDL_main
106106
return result;
107107
}
108108

109-
#endif // SDL_PLATFORM_WIN32
109+
// GDK uses the same SDL_CallMain() implementation as desktop Windows but has its own SDL_RunApp() implementation.
110+
#ifndef SDL_PLATFORM_GDK
111+
112+
int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
113+
{
114+
(void)reserved;
115+
116+
SDL_SetMainReady();
117+
118+
return SDL_CallMain(argc, argv, mainFunction);
119+
}
120+
121+
#endif // !SDL_PLATFORM_GDK
122+
123+
#endif // SDL_PLATFORM_WINDOWS

0 commit comments

Comments
 (0)