|
25 | 25 | #include "../SDL_runapp.h"
|
26 | 26 | #include "../../core/windows/SDL_windows.h"
|
27 | 27 |
|
28 |
| -/* Win32-specific SDL_RunApp(), which does most of the SDL_main work, |
29 |
| - based on SDL_windows_main.c, placed in the public domain by Sam Lantinga 4/13/98 */ |
30 |
| - |
31 | 28 | #include <shellapi.h> // CommandLineToArgvW()
|
32 | 29 |
|
33 |
| -// Pop up an out of memory message, returns to Windows |
34 | 30 | static int OutOfMemory(void)
|
35 | 31 | {
|
36 | 32 | SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Out of memory - aborting", NULL);
|
37 | 33 | return -1;
|
38 | 34 | }
|
39 | 35 |
|
40 |
| -int MINGW32_FORCEALIGN SDL_RunApp(int _argc, char* _argv[], SDL_main_func mainFunction, void * reserved) |
| 36 | +static int ErrorProcessingCommandLine(void) |
41 | 37 | {
|
42 |
| - /* Gets the arguments with GetCommandLine, converts them to argc and argv |
43 |
| - and calls SDL_main */ |
44 |
| - |
45 |
| - LPWSTR *argvw; |
46 |
| - char **argv; |
47 |
| - int i, argc, result; |
48 |
| - |
49 |
| - (void)_argc; (void)_argv; (void)reserved; |
50 |
| - |
51 |
| - argvw = CommandLineToArgvW(GetCommandLineW(), &argc); |
52 |
| - if (!argvw) { |
53 |
| - return OutOfMemory(); |
54 |
| - } |
55 |
| - |
56 |
| - /* Note that we need to be careful about how we allocate/free memory here. |
57 |
| - * If the application calls SDL_SetMemoryFunctions(), we can't rely on |
58 |
| - * SDL_free() to use the same allocator after SDL_main() returns. |
59 |
| - */ |
| 38 | + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL); |
| 39 | + return -1; |
| 40 | +} |
60 | 41 |
|
61 |
| - // Parse it into argv and argc |
62 |
| - argv = (char **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (argc + 1) * sizeof(*argv)); |
63 |
| - if (!argv) { |
64 |
| - return OutOfMemory(); |
65 |
| - } |
66 |
| - for (i = 0; i < argc; ++i) { |
67 |
| - const int utf8size = WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, NULL, 0, NULL, NULL); |
68 |
| - if (!utf8size) { // uhoh? |
69 |
| - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL); |
70 |
| - return -1; |
| 42 | +int MINGW32_FORCEALIGN SDL_RunApp(int caller_argc, char* caller_argv[], SDL_main_func mainFunction, void * reserved) |
| 43 | +{ |
| 44 | + int result, argc; |
| 45 | + LPWSTR *argvw = NULL; |
| 46 | + char **argv = NULL; |
| 47 | + (void)reserved; |
| 48 | + |
| 49 | + // Note that we need to be careful about how we allocate/free memory in this function. If the application calls |
| 50 | + // SDL_SetMemoryFunctions(), we can't rely on SDL_free() to use the same allocator after SDL_main() returns. |
| 51 | + |
| 52 | + 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 |
| 54 | + // using GetCommandLineW() and convert them to argc and argv before calling mainFunction(). |
| 55 | + |
| 56 | + // Because of how the Windows command line works, we know for sure that the buffer size required to store all |
| 57 | + // 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. |
| 59 | + const int argdata_size = WideCharToMultiByte(CP_UTF8, 0, GetCommandLineW(), -1, NULL, 0, NULL, NULL); // Includes the null terminator |
| 60 | + if (!argdata_size) { |
| 61 | + result = ErrorProcessingCommandLine(); |
| 62 | + goto cleanup; |
71 | 63 | }
|
72 | 64 |
|
73 |
| - argv[i] = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, utf8size); // this size includes the null-terminator character. |
74 |
| - if (!argv[i]) { |
75 |
| - return OutOfMemory(); |
| 65 | + argvw = CommandLineToArgvW(GetCommandLineW(), &argc); |
| 66 | + if (!argvw || argc < 0) { |
| 67 | + result = OutOfMemory(); |
| 68 | + goto cleanup; |
76 | 69 | }
|
77 | 70 |
|
78 |
| - if (WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, argv[i], utf8size, NULL, NULL) == 0) { // failed? uhoh! |
79 |
| - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", "Error processing command line arguments", NULL); |
80 |
| - return -1; |
| 71 | + // Allocate argv followed by the argument string buffer as one contiguous allocation. |
| 72 | + argv = (char **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (argc + 1) * sizeof(*argv) + argdata_size); |
| 73 | + if (!argv) { |
| 74 | + result = OutOfMemory(); |
| 75 | + goto cleanup; |
| 76 | + } |
| 77 | + char *argdata = ((char *)argv) + (argc + 1) * sizeof(*argv); |
| 78 | + int argdata_index = 0; |
| 79 | + |
| 80 | + for (int i = 0; i < argc; ++i) { |
| 81 | + const int bytes_written = WideCharToMultiByte(CP_UTF8, 0, argvw[i], -1, argdata + argdata_index, argdata_size - argdata_index, NULL, NULL); |
| 82 | + if (!bytes_written) { |
| 83 | + result = ErrorProcessingCommandLine(); |
| 84 | + goto cleanup; |
| 85 | + } |
| 86 | + argv[i] = argdata + argdata_index; |
| 87 | + argdata_index += bytes_written; |
81 | 88 | }
|
| 89 | + argv[argc] = NULL; |
| 90 | + |
| 91 | + argvw = NULL; |
| 92 | + |
| 93 | + caller_argc = argc; |
| 94 | + caller_argv = argv; |
82 | 95 | }
|
83 |
| - argv[i] = NULL; |
84 |
| - LocalFree(argvw); |
85 | 96 |
|
86 | 97 | SDL_SetMainReady();
|
87 | 98 |
|
88 |
| - // Run the application main() code |
89 |
| - result = SDL_CallMain(argc, argv, mainFunction); |
| 99 | + result = mainFunction(caller_argc, caller_argv); // No need for SDL_CallMain(); we already know that we have a valid argv |
| 100 | + |
| 101 | +cleanup: |
90 | 102 |
|
91 |
| - // Free argv, to avoid memory leak |
92 |
| - for (i = 0; i < argc; ++i) { |
93 |
| - HeapFree(GetProcessHeap(), 0, argv[i]); |
94 |
| - } |
95 | 103 | HeapFree(GetProcessHeap(), 0, argv);
|
| 104 | + LocalFree(argvw); |
96 | 105 |
|
97 | 106 | return result;
|
98 | 107 | }
|
|
0 commit comments