mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-10-04 17:06:25 +00:00
Fix Windows dialog memory management
This commit is contained in:
@@ -34,29 +34,49 @@
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
bool is_save;
|
bool is_save;
|
||||||
const SDL_DialogFileFilter *filters;
|
wchar_t *filters_str;
|
||||||
int nfilters;
|
char* default_file;
|
||||||
const char* default_file;
|
|
||||||
SDL_Window* parent;
|
SDL_Window* parent;
|
||||||
DWORD flags;
|
DWORD flags;
|
||||||
SDL_DialogFileCallback callback;
|
SDL_DialogFileCallback callback;
|
||||||
void* userdata;
|
void* userdata;
|
||||||
const char* title;
|
char* title;
|
||||||
const char* accept;
|
char* accept;
|
||||||
const char* cancel;
|
char* cancel;
|
||||||
} winArgs;
|
} winArgs;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
SDL_Window* parent;
|
SDL_Window* parent;
|
||||||
SDL_DialogFileCallback callback;
|
SDL_DialogFileCallback callback;
|
||||||
const char* default_folder;
|
char* default_folder;
|
||||||
void* userdata;
|
void* userdata;
|
||||||
const char* title;
|
char* title;
|
||||||
const char* accept;
|
char* accept;
|
||||||
const char* cancel;
|
char* cancel;
|
||||||
} winFArgs;
|
} winFArgs;
|
||||||
|
|
||||||
|
void freeWinArgs(winArgs *args)
|
||||||
|
{
|
||||||
|
SDL_free(args->default_file);
|
||||||
|
SDL_free(args->filters_str);
|
||||||
|
SDL_free(args->title);
|
||||||
|
SDL_free(args->accept);
|
||||||
|
SDL_free(args->cancel);
|
||||||
|
|
||||||
|
SDL_free(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeWinFArgs(winFArgs *args)
|
||||||
|
{
|
||||||
|
SDL_free(args->default_folder);
|
||||||
|
SDL_free(args->title);
|
||||||
|
SDL_free(args->accept);
|
||||||
|
SDL_free(args->cancel);
|
||||||
|
|
||||||
|
SDL_free(args);
|
||||||
|
}
|
||||||
|
|
||||||
/** Converts dialog.nFilterIndex to SDL-compatible value */
|
/** Converts dialog.nFilterIndex to SDL-compatible value */
|
||||||
int getFilterIndex(int as_reported_by_windows)
|
int getFilterIndex(int as_reported_by_windows)
|
||||||
{
|
{
|
||||||
@@ -86,14 +106,13 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
{
|
{
|
||||||
winArgs *args = (winArgs *) ptr;
|
winArgs *args = (winArgs *) ptr;
|
||||||
bool is_save = args->is_save;
|
bool is_save = args->is_save;
|
||||||
const SDL_DialogFileFilter *filters = args->filters;
|
|
||||||
int nfilters = args->nfilters;
|
|
||||||
const char* default_file = args->default_file;
|
const char* default_file = args->default_file;
|
||||||
SDL_Window* parent = args->parent;
|
SDL_Window* parent = args->parent;
|
||||||
DWORD flags = args->flags;
|
DWORD flags = args->flags;
|
||||||
SDL_DialogFileCallback callback = args->callback;
|
SDL_DialogFileCallback callback = args->callback;
|
||||||
void* userdata = args->userdata;
|
void* userdata = args->userdata;
|
||||||
const char *title = args->title;
|
const char *title = args->title;
|
||||||
|
wchar_t *filter_wchar = args->filters_str;
|
||||||
|
|
||||||
/* GetOpenFileName and GetSaveFileName have the same signature
|
/* GetOpenFileName and GetSaveFileName have the same signature
|
||||||
(yes, LPOPENFILENAMEW even for the save dialog) */
|
(yes, LPOPENFILENAMEW even for the save dialog) */
|
||||||
@@ -109,18 +128,21 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
} else {
|
} else {
|
||||||
SDL_SetError("Couldn't load Comdlg32.dll");
|
SDL_SetError("Couldn't load Comdlg32.dll");
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
|
freeWinArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pGetAnyFileName) {
|
if (!pGetAnyFileName) {
|
||||||
SDL_SetError("Couldn't load GetOpenFileName/GetSaveFileName from library");
|
SDL_SetError("Couldn't load GetOpenFileName/GetSaveFileName from library");
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
|
freeWinArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pCommDlgExtendedError) {
|
if (!pCommDlgExtendedError) {
|
||||||
SDL_SetError("Couldn't load CommDlgExtendedError from library");
|
SDL_SetError("Couldn't load CommDlgExtendedError from library");
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
|
freeWinArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,43 +196,6 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t *filter_wchar = NULL;
|
|
||||||
|
|
||||||
if (filters) {
|
|
||||||
// '\x01' is used in place of a null byte
|
|
||||||
// suffix needs two null bytes in case the filter list is empty
|
|
||||||
char *filterlist = convert_filters(filters, nfilters, clear_filt_names, "", "",
|
|
||||||
"\x01\x01", "", "\x01", "\x01",
|
|
||||||
"*.", ";*.", "");
|
|
||||||
|
|
||||||
if (!filterlist) {
|
|
||||||
callback(userdata, NULL, -1);
|
|
||||||
SDL_free(filebuffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int filter_len = (int)SDL_strlen(filterlist);
|
|
||||||
|
|
||||||
for (char *c = filterlist; *c; c++) {
|
|
||||||
if (*c == '\x01') {
|
|
||||||
*c = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int filter_wlen = MultiByteToWideChar(CP_UTF8, 0, filterlist, filter_len, NULL, 0);
|
|
||||||
filter_wchar = (wchar_t *)SDL_malloc(filter_wlen * sizeof(wchar_t));
|
|
||||||
if (!filter_wchar) {
|
|
||||||
SDL_free(filterlist);
|
|
||||||
callback(userdata, NULL, -1);
|
|
||||||
SDL_free(filebuffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiByteToWideChar(CP_UTF8, 0, filterlist, filter_len, filter_wchar, filter_wlen);
|
|
||||||
|
|
||||||
SDL_free(filterlist);
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t *title_w = NULL;
|
wchar_t *title_w = NULL;
|
||||||
|
|
||||||
if (title) {
|
if (title) {
|
||||||
@@ -230,9 +215,9 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
title_w = (wchar_t *)SDL_malloc(title_wlen * sizeof(wchar_t));
|
title_w = (wchar_t *)SDL_malloc(title_wlen * sizeof(wchar_t));
|
||||||
|
|
||||||
if (!title_w) {
|
if (!title_w) {
|
||||||
SDL_free(filter_wchar);
|
|
||||||
SDL_free(filebuffer);
|
SDL_free(filebuffer);
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
|
freeWinArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +249,6 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
|
|
||||||
BOOL result = pGetAnyFileName(&dialog);
|
BOOL result = pGetAnyFileName(&dialog);
|
||||||
|
|
||||||
SDL_free(filter_wchar);
|
|
||||||
SDL_free(title_w);
|
SDL_free(title_w);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
@@ -292,6 +276,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
if (!chosen_files_list) {
|
if (!chosen_files_list) {
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
SDL_free(filebuffer);
|
SDL_free(filebuffer);
|
||||||
|
freeWinArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,6 +287,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
SDL_free(chosen_files_list);
|
SDL_free(chosen_files_list);
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
SDL_free(filebuffer);
|
SDL_free(filebuffer);
|
||||||
|
freeWinArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,6 +309,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
SDL_free(chosen_files_list);
|
SDL_free(chosen_files_list);
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
SDL_free(filebuffer);
|
SDL_free(filebuffer);
|
||||||
|
freeWinArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,6 +328,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
SDL_free(chosen_files_list);
|
SDL_free(chosen_files_list);
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
SDL_free(filebuffer);
|
SDL_free(filebuffer);
|
||||||
|
freeWinArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,6 +344,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
SDL_free(chosen_files_list);
|
SDL_free(chosen_files_list);
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
SDL_free(filebuffer);
|
SDL_free(filebuffer);
|
||||||
|
freeWinArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,6 +358,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
SDL_free(chosen_files_list);
|
SDL_free(chosen_files_list);
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
SDL_free(filebuffer);
|
SDL_free(filebuffer);
|
||||||
|
freeWinArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,6 +370,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
SDL_free(chosen_files_list);
|
SDL_free(chosen_files_list);
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
SDL_free(filebuffer);
|
SDL_free(filebuffer);
|
||||||
|
freeWinArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -409,6 +400,7 @@ void windows_ShowFileDialog(void *ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SDL_free(filebuffer);
|
SDL_free(filebuffer);
|
||||||
|
freeWinArgs(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
int windows_file_dialog_thread(void* ptr)
|
int windows_file_dialog_thread(void* ptr)
|
||||||
@@ -469,6 +461,7 @@ void windows_ShowFolderDialog(void* ptr)
|
|||||||
|
|
||||||
if (!title_w) {
|
if (!title_w) {
|
||||||
callback(userdata, NULL, -1);
|
callback(userdata, NULL, -1);
|
||||||
|
freeWinFArgs(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,6 +494,8 @@ void windows_ShowFolderDialog(void* ptr)
|
|||||||
const char *files[1] = { NULL };
|
const char *files[1] = { NULL };
|
||||||
callback(userdata, (const char * const*) files, -1);
|
callback(userdata, (const char * const*) files, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
freeWinFArgs(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
int windows_folder_dialog_thread(void* ptr)
|
int windows_folder_dialog_thread(void* ptr)
|
||||||
@@ -510,10 +505,49 @@ int windows_folder_dialog_thread(void* ptr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wchar_t *win_get_filters(const SDL_DialogFileFilter *filters, int nfilters)
|
||||||
|
{
|
||||||
|
wchar_t *filter_wchar = NULL;
|
||||||
|
|
||||||
|
if (filters) {
|
||||||
|
// '\x01' is used in place of a null byte
|
||||||
|
// suffix needs two null bytes in case the filter list is empty
|
||||||
|
char *filterlist = convert_filters(filters, nfilters, clear_filt_names,
|
||||||
|
"", "", "\x01\x01", "", "\x01",
|
||||||
|
"\x01", "*.", ";*.", "");
|
||||||
|
|
||||||
|
if (!filterlist) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filter_len = (int)SDL_strlen(filterlist);
|
||||||
|
|
||||||
|
for (char *c = filterlist; *c; c++) {
|
||||||
|
if (*c == '\x01') {
|
||||||
|
*c = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int filter_wlen = MultiByteToWideChar(CP_UTF8, 0, filterlist, filter_len, NULL, 0);
|
||||||
|
filter_wchar = (wchar_t *)SDL_malloc(filter_wlen * sizeof(wchar_t));
|
||||||
|
if (!filter_wchar) {
|
||||||
|
SDL_free(filterlist);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, filterlist, filter_len, filter_wchar, filter_wlen);
|
||||||
|
|
||||||
|
SDL_free(filterlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter_wchar;
|
||||||
|
}
|
||||||
|
|
||||||
static void ShowFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, bool allow_many, bool is_save, const char* title, const char* accept, const char* cancel)
|
static void ShowFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, bool allow_many, bool is_save, const char* title, const char* accept, const char* cancel)
|
||||||
{
|
{
|
||||||
winArgs *args;
|
winArgs *args;
|
||||||
SDL_Thread *thread;
|
SDL_Thread *thread;
|
||||||
|
wchar_t *filters_str;
|
||||||
|
|
||||||
if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) {
|
if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) {
|
||||||
SDL_SetError("File dialog driver unsupported");
|
SDL_SetError("File dialog driver unsupported");
|
||||||
@@ -527,17 +561,24 @@ static void ShowFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filters_str = win_get_filters(filters, nfilters);
|
||||||
|
|
||||||
|
if (!filters_str && filters) {
|
||||||
|
callback(userdata, NULL, -1);
|
||||||
|
SDL_free(args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
args->is_save = is_save;
|
args->is_save = is_save;
|
||||||
args->filters = filters;
|
args->filters_str = filters_str;
|
||||||
args->nfilters = nfilters;
|
args->default_file = default_location ? SDL_strdup(default_location) : NULL;
|
||||||
args->default_file = default_location;
|
|
||||||
args->parent = window;
|
args->parent = window;
|
||||||
args->flags = allow_many ? OFN_ALLOWMULTISELECT : 0;
|
args->flags = allow_many ? OFN_ALLOWMULTISELECT : 0;
|
||||||
args->callback = callback;
|
args->callback = callback;
|
||||||
args->userdata = userdata;
|
args->userdata = userdata;
|
||||||
args->title = title;
|
args->title = title ? SDL_strdup(title) : NULL;
|
||||||
args->accept = accept;
|
args->accept = accept ? SDL_strdup(accept) : NULL;
|
||||||
args->cancel = cancel;
|
args->cancel = cancel ? SDL_strdup(cancel) : NULL;
|
||||||
|
|
||||||
thread = SDL_CreateThread(windows_file_dialog_thread, "SDL_Windows_ShowFileDialog", (void *) args);
|
thread = SDL_CreateThread(windows_file_dialog_thread, "SDL_Windows_ShowFileDialog", (void *) args);
|
||||||
|
|
||||||
@@ -569,11 +610,11 @@ void ShowFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Windo
|
|||||||
|
|
||||||
args->parent = window;
|
args->parent = window;
|
||||||
args->callback = callback;
|
args->callback = callback;
|
||||||
args->default_folder = default_location;
|
args->default_folder = default_location ? SDL_strdup(default_location) : NULL;
|
||||||
args->userdata = userdata;
|
args->userdata = userdata;
|
||||||
args->title = title;
|
args->title = title ? SDL_strdup(title) : NULL;
|
||||||
args->accept = accept;
|
args->accept = accept ? SDL_strdup(accept) : NULL;
|
||||||
args->cancel = cancel;
|
args->cancel = cancel ? SDL_strdup(cancel) : NULL;
|
||||||
|
|
||||||
thread = SDL_CreateThread(windows_folder_dialog_thread, "SDL_Windows_ShowFolderDialog", (void *) args);
|
thread = SDL_CreateThread(windows_folder_dialog_thread, "SDL_Windows_ShowFolderDialog", (void *) args);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user