Allegro.cc - Online Community

Allegro.cc Forums » Allegro Development » Native file dialog patch

This thread is locked; no one can reply to it. rss feed Print
Native file dialog patch
Edgar Reynaldo
Major Reynaldo
May 2007
avatar

NiteHackr brought up a bug in the native file dialog on Windows in this thread :
https://www.allegro.cc/forums/thread/614568

I said I would work on it and I finally got time to do it.

The problem was that lpstrFile wasn't being initialized (which prevented you from specifying the open/save file), and lpstrInitialDir was being initialized with a file path and not a folder.

This is a very hacky fix, but it works, and it gives you the idea. I'm not aware of the conventions for handling strings in allegro internals so this is the way I did it. Here's the diff for win_dialog.c :

#SelectExpand
1 2c:\mingw\LIBS\A5GIT\allegro\addons\native_dialog>diff -u win_dialog.c win_dialog.new.c 3--- win_dialog.c 2014-12-22 18:37:54.191842600 -0600 4+++ win_dialog.new.c 2014-12-22 18:41:30.428979100 -0600 5@@ -8,6 +8,8 @@ 6 * 7 */ 8 9+#include <stdio.h> 10+ 11 #include "allegro5/allegro.h" 12 #include "allegro5/allegro_native_dialog.h" 13 #include "allegro5/internal/aintern.h" 14@@ -141,8 +143,10 @@ 15 OPENFILENAME ofn; 16 ALLEGRO_DISPLAY_WIN *win_display; 17 int flags = 0; 18+ int count = 0; 19 bool ret; 20 char buf[4096] = ""; 21+ char dirbuf[4096] = ""; 22 ALLEGRO_USTR *filter_string = NULL; 23 24 win_display = (ALLEGRO_DISPLAY_WIN *)display; 25@@ -170,8 +174,20 @@ 26 ofn.nMaxFile = sizeof(buf); 27 28 if (fd->fc_initial_path) { 29- ofn.lpstrInitialDir = 30- al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP); 31+ 32+ strcpy(buf , al_path_cstr((fd->fc_initial_path) , ALLEGRO_NATIVE_PATH_SEP)); 33+ 34+ // this is wrong - fc_initial_path holds the filename, not the base dir 35+ for (count = 0 ; count < al_get_path_num_components(fd->fc_initial_path) ; ++count) { 36+ char* dirpath = &dirbuf[0]; 37+ int n = 0; 38+ const char* path_comp = al_get_path_component(fd->fc_initial_path , count); 39+ sprintf(dirpath , "%s%c%n" , path_comp , ALLEGRO_NATIVE_PATH_SEP , &n); 40+ dirpath += n; 41+ } 42+ 43+ ofn.lpstrInitialDir = dirbuf; 44+// al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP); 45 } 46 47 if (fd->title) 48 49c:\mingw\LIBS\A5GIT\allegro\addons\native_dialog>

And here's the full al_show_native_file_dialog with the changes made to it so you can see more easily what is different. Whatever changes you wanna make are fine. I'm sure it will need to be edited before being accepted.

win_dialog.c#SelectExpand
139 140bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, 141 ALLEGRO_NATIVE_DIALOG *fd) 142{ 143 OPENFILENAME ofn; 144 ALLEGRO_DISPLAY_WIN *win_display; 145 int flags = 0; 146 int count = 0; 147 bool ret; 148 char buf[4096] = ""; 149 char dirbuf[4096] = ""; 150 ALLEGRO_USTR *filter_string = NULL; 151 152 win_display = (ALLEGRO_DISPLAY_WIN *)display; 153 154 if (fd->flags & ALLEGRO_FILECHOOSER_FOLDER) { 155 return select_folder(win_display, fd); 156 } 157 158 /* Selecting a file. */ 159 memset(&ofn, 0, sizeof(OPENFILENAME)); 160 ofn.lStructSize = sizeof(OPENFILENAME); 161 ofn.hwndOwner = (win_display) ? win_display->window : NULL; 162 163 /* Create filter string. */ 164 if (fd->fc_patterns) { 165 filter_string = create_filter_string(fd->fc_patterns); 166 ofn.lpstrFilter = al_cstr(filter_string); 167 } 168 else { 169 /* List all files by default. */ 170 ofn.lpstrFilter = "All Files\0*.*\0\0"; 171 } 172 173 ofn.lpstrFile = buf; 174 ofn.nMaxFile = sizeof(buf); 175 176 if (fd->fc_initial_path) { 177 178 strcpy(buf , al_path_cstr((fd->fc_initial_path) , ALLEGRO_NATIVE_PATH_SEP)); 179 180 // this is wrong - fc_initial_path holds the filename, not the base dir 181 for (count = 0 ; count < al_get_path_num_components(fd->fc_initial_path) ; ++count) { 182 char* dirpath = &dirbuf[0]; 183 int n = 0; 184 const char* path_comp = al_get_path_component(fd->fc_initial_path , count); 185 sprintf(dirpath , "%s%c%n" , path_comp , ALLEGRO_NATIVE_PATH_SEP , &n); 186 dirpath += n; 187 } 188 189 ofn.lpstrInitialDir = dirbuf; 190// al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP); 191 } 192 193 if (fd->title) 194 ofn.lpstrTitle = al_cstr(fd->title); 195 196 flags |= OFN_NOCHANGEDIR | OFN_EXPLORER; 197 if (fd->flags & ALLEGRO_FILECHOOSER_SAVE) { 198 flags |= OFN_OVERWRITEPROMPT; 199 } 200 else { 201 flags |= (fd->flags & ALLEGRO_FILECHOOSER_FILE_MUST_EXIST) ? OFN_FILEMUSTEXIST : 0; 202 } 203 flags |= (fd->flags & ALLEGRO_FILECHOOSER_MULTIPLE) ? OFN_ALLOWMULTISELECT : 0; 204 flags |= (fd->flags & ALLEGRO_FILECHOOSER_SHOW_HIDDEN) ? 0x10000000 : 0; // NOTE: 0x10000000 is FORCESHOWHIDDEN 205 ofn.Flags = flags; 206 207 if (flags & OFN_OVERWRITEPROMPT) { 208 ret = GetSaveFileName(&ofn); 209 } 210 else { 211 ret = GetOpenFileName(&ofn); 212 } 213 214 al_ustr_free(filter_string); 215 216 if (!ret) { 217 DWORD err = GetLastError(); 218 if (err != ERROR_SUCCESS) { 219 char buf[1000]; 220 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buf, sizeof(buf), NULL); 221 ALLEGRO_ERROR("al_show_native_file_dialog failed: %s\n", buf); 222 } 223 return false; 224 } 225 226 if (flags & OFN_ALLOWMULTISELECT) { 227 int i; 228 /* Count number of file names in buf. */ 229 fd->fc_path_count = 0; 230 i = skip_nul_terminated_string(buf); 231 while (1) { 232 if (buf[i] == '\0') { 233 fd->fc_path_count++; 234 if (buf[i+1] == '\0') 235 break; 236 } 237 i++; 238 } 239 } 240 else { 241 fd->fc_path_count = 1; 242 } 243 244 if (fd->fc_path_count == 1) { 245 fd->fc_paths = al_malloc(sizeof(void *)); 246 fd->fc_paths[0] = al_create_path(buf); 247 } 248 else { 249 int i, p; 250 /* If multiple files were selected, the first string in buf is the 251 * directory name, followed by each of the file names terminated by NUL. 252 */ 253 fd->fc_paths = al_malloc(fd->fc_path_count * sizeof(void *)); 254 i = skip_nul_terminated_string(buf); 255 for (p = 0; p < (int)fd->fc_path_count; p++) { 256 fd->fc_paths[p] = al_create_path_for_directory(buf); 257 al_set_path_filename(fd->fc_paths[p], buf+i); 258 i += skip_nul_terminated_string(buf+i); 259 } 260 } 261 262 return true; 263}

Trent Gamblin
Member #261
April 2000
avatar

Could you change this to use al_remove_path_component?

EDIT: nvm, only removes directories...

EDIT2: Try al_set_path_filename with NULL.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Try al_set_path_filename with NULL.

Okay, it works. Just have to keep in mind the file name has been erased from fc_initial_path for future reference.

Here's the new diff :

#SelectExpand
1c:\mingw\LIBS\A5GIT\allegro\addons\native_dialog>diff -u win_dialog.old.c win_dialog.c 2--- win_dialog.old.c 2014-12-22 18:37:54.191842600 -0600 3+++ win_dialog.c 2014-12-22 22:44:16.880748300 -0600 4@@ -17,6 +17,8 @@ 5 6 #include "allegro5/allegro_windows.h" 7 8+#include <string.h> 9+ 10 /* We use RichEdit by default. */ 11 #include <richedit.h> 12 #include <shlobj.h> // for folder selector 13@@ -142,9 +144,12 @@ 14 ALLEGRO_DISPLAY_WIN *win_display; 15 int flags = 0; 16 bool ret; 17- char buf[4096] = ""; 18+ const int BUFSIZE = 4096; 19+ char buf[BUFSIZE]; 20 ALLEGRO_USTR *filter_string = NULL; 21 22+ buf[0] = '\0'; 23+ 24 win_display = (ALLEGRO_DISPLAY_WIN *)display; 25 26 if (fd->flags & ALLEGRO_FILECHOOSER_FOLDER) { 27@@ -166,12 +171,15 @@ 28 ofn.lpstrFilter = "All Files\0*.*\0\0"; 29 } 30 31+ /* Provide buffer for file chosen by dialog. */ 32 ofn.lpstrFile = buf; 33 ofn.nMaxFile = sizeof(buf); 34 35+ /* Initialize file name buffer and starting directory */ 36 if (fd->fc_initial_path) { 37- ofn.lpstrInitialDir = 38- al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP); 39+ strncpy(buf , al_path_cstr(fd->fc_initial_path , ALLEGRO_NATIVE_PATH_SEP) , BUFSIZE - 1); 40+ al_set_path_filename(fd->fc_initial_path , NULL); 41+ ofn.lpstrInitialDir = al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP); 42 } 43 44 if (fd->title) 45 46c:\mingw\LIBS\A5GIT\allegro\addons\native_dialog>

And the function :

win_dialog.new.c#SelectExpand
140bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, 141 ALLEGRO_NATIVE_DIALOG *fd) 142{ 143 OPENFILENAME ofn; 144 ALLEGRO_DISPLAY_WIN *win_display; 145 int flags = 0; 146 bool ret; 147 const int BUFSIZE = 4096; 148 char buf[BUFSIZE]; 149 ALLEGRO_USTR *filter_string = NULL; 150 151 buf[0] = '\0'; 152 153 win_display = (ALLEGRO_DISPLAY_WIN *)display; 154 155 if (fd->flags & ALLEGRO_FILECHOOSER_FOLDER) { 156 return select_folder(win_display, fd); 157 } 158 159 /* Selecting a file. */ 160 memset(&ofn, 0, sizeof(OPENFILENAME)); 161 ofn.lStructSize = sizeof(OPENFILENAME); 162 ofn.hwndOwner = (win_display) ? win_display->window : NULL; 163 164 /* Create filter string. */ 165 if (fd->fc_patterns) { 166 filter_string = create_filter_string(fd->fc_patterns); 167 ofn.lpstrFilter = al_cstr(filter_string); 168 } 169 else { 170 /* List all files by default. */ 171 ofn.lpstrFilter = "All Files\0*.*\0\0"; 172 } 173 174 /* Provide buffer for file chosen by dialog. */ 175 ofn.lpstrFile = buf; 176 ofn.nMaxFile = sizeof(buf); 177 178 /* Initialize file name buffer and starting directory */ 179 if (fd->fc_initial_path) { 180 strncpy(buf , al_path_cstr(fd->fc_initial_path , ALLEGRO_NATIVE_PATH_SEP) , BUFSIZE - 1); 181 al_set_path_filename(fd->fc_initial_path , NULL); 182 ofn.lpstrInitialDir = al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP); 183 } 184 185 if (fd->title) 186 ofn.lpstrTitle = al_cstr(fd->title); 187 188 flags |= OFN_NOCHANGEDIR | OFN_EXPLORER; 189 if (fd->flags & ALLEGRO_FILECHOOSER_SAVE) { 190 flags |= OFN_OVERWRITEPROMPT; 191 } 192 else { 193 flags |= (fd->flags & ALLEGRO_FILECHOOSER_FILE_MUST_EXIST) ? OFN_FILEMUSTEXIST : 0; 194 } 195 flags |= (fd->flags & ALLEGRO_FILECHOOSER_MULTIPLE) ? OFN_ALLOWMULTISELECT : 0; 196 flags |= (fd->flags & ALLEGRO_FILECHOOSER_SHOW_HIDDEN) ? 0x10000000 : 0; // NOTE: 0x10000000 is FORCESHOWHIDDEN 197 ofn.Flags = flags; 198 199 if (flags & OFN_OVERWRITEPROMPT) { 200 ret = GetSaveFileName(&ofn); 201 } 202 else { 203 ret = GetOpenFileName(&ofn); 204 } 205 206 al_ustr_free(filter_string); 207 208 if (!ret) { 209 DWORD err = GetLastError(); 210 if (err != ERROR_SUCCESS) { 211 char buf[1000]; 212 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buf, sizeof(buf), NULL); 213 ALLEGRO_ERROR("al_show_native_file_dialog failed: %s\n", buf); 214 } 215 return false; 216 } 217 218 if (flags & OFN_ALLOWMULTISELECT) { 219 int i; 220 /* Count number of file names in buf. */ 221 fd->fc_path_count = 0; 222 i = skip_nul_terminated_string(buf); 223 while (1) { 224 if (buf[i] == '\0') { 225 fd->fc_path_count++; 226 if (buf[i+1] == '\0') 227 break; 228 } 229 i++; 230 } 231 } 232 else { 233 fd->fc_path_count = 1; 234 } 235 236 if (fd->fc_path_count == 1) { 237 fd->fc_paths = al_malloc(sizeof(void *)); 238 fd->fc_paths[0] = al_create_path(buf); 239 } 240 else { 241 int i, p; 242 /* If multiple files were selected, the first string in buf is the 243 * directory name, followed by each of the file names terminated by NUL. 244 */ 245 fd->fc_paths = al_malloc(fd->fc_path_count * sizeof(void *)); 246 i = skip_nul_terminated_string(buf); 247 for (p = 0; p < (int)fd->fc_path_count; p++) { 248 fd->fc_paths[p] = al_create_path_for_directory(buf); 249 al_set_path_filename(fd->fc_paths[p], buf+i); 250 i += skip_nul_terminated_string(buf+i); 251 } 252 } 253 254 return true; 255}

Trent Gamblin
Member #261
April 2000
avatar

Not sure this is going to work. Shouldn't it check if it's an OPEN dialog before trimming the filename? After all if it's a SAVE dialog you want the filename right?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Well you don't need it. Unless someone tried to re-use a file dialog. We could clone a path, discard the filename, set the directory and then discard the clone after calling GetOpenFileName. Because you don't want the filename in the string for the directory in open or save dialogs.

New patch using a clone of the directory and checking for an empty filename to respect the documentation that states when the path ends with a directory separator then the filename is not specified, but the starting directory is :

#SelectExpand
1 2c:\mingw\LIBS\A5GIT\allegro\addons\native_dialog>diff -u win_dialog.old.c win_dialog.c 3--- win_dialog.old.c 2014-12-22 18:37:54.191842600 -0600 4+++ win_dialog.c 2014-12-23 12:51:26.442877800 -0600 5@@ -17,6 +17,8 @@ 6 7 #include "allegro5/allegro_windows.h" 8 9+#include <string.h> 10+ 11 /* We use RichEdit by default. */ 12 #include <richedit.h> 13 #include <shlobj.h> // for folder selector 14@@ -142,8 +144,12 @@ 15 ALLEGRO_DISPLAY_WIN *win_display; 16 int flags = 0; 17 bool ret; 18- char buf[4096] = ""; 19+ const int BUFSIZE = 4096; 20+ char buf[BUFSIZE]; 21 ALLEGRO_USTR *filter_string = NULL; 22+ ALLEGRO_PATH* initial_dir_path = 0; 23+ 24+ buf[0] = '\0'; 25 26 win_display = (ALLEGRO_DISPLAY_WIN *)display; 27 28@@ -166,12 +172,24 @@ 29 ofn.lpstrFilter = "All Files\0*.*\0\0"; 30 } 31 32+ /* Provide buffer for file chosen by dialog. */ 33 ofn.lpstrFile = buf; 34 ofn.nMaxFile = sizeof(buf); 35 36+ /* Initialize file name buffer and starting directory */ 37 if (fd->fc_initial_path) { 38- ofn.lpstrInitialDir = 39- al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP); 40+ 41+ /* Respect an empty filename */ 42+ if (strlen(al_get_path_filename(fd->fc_initial_path)) > 0) { 43+ strncpy(buf , al_path_cstr(fd->fc_initial_path , ALLEGRO_NATIVE_PATH_SEP) , BUFSIZE - 1); 44+ } 45+ 46+ /* Clone the directory */ 47+ initial_dir_path = al_clone_path(fd->fc_initial_path); 48+ if (initial_dir_path) { 49+ al_set_path_filename(initial_dir_path , NULL); 50+ ofn.lpstrInitialDir = al_path_cstr(initial_dir_path, ALLEGRO_NATIVE_PATH_SEP); 51+ } 52 } 53 54 if (fd->title) 55@@ -194,6 +212,10 @@ 56 else { 57 ret = GetOpenFileName(&ofn); 58 } 59+ 60+ if (initial_dir_path) { 61+ al_destroy_path(initial_dir_path); 62+ } 63 64 al_ustr_free(filter_string); 65 66 67c:\mingw\LIBS\A5GIT\allegro\addons\native_dialog>

win_dialog.new.c#SelectExpand
1 2bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, 3 ALLEGRO_NATIVE_DIALOG *fd) 4{ 5 OPENFILENAME ofn; 6 ALLEGRO_DISPLAY_WIN *win_display; 7 int flags = 0; 8 bool ret; 9 const int BUFSIZE = 4096; 10 char buf[BUFSIZE]; 11 ALLEGRO_USTR *filter_string = NULL; 12 ALLEGRO_PATH* initial_dir_path = 0; 13 14 buf[0] = '\0'; 15 16 win_display = (ALLEGRO_DISPLAY_WIN *)display; 17 18 if (fd->flags & ALLEGRO_FILECHOOSER_FOLDER) { 19 return select_folder(win_display, fd); 20 } 21 22 /* Selecting a file. */ 23 memset(&ofn, 0, sizeof(OPENFILENAME)); 24 ofn.lStructSize = sizeof(OPENFILENAME); 25 ofn.hwndOwner = (win_display) ? win_display->window : NULL; 26 27 /* Create filter string. */ 28 if (fd->fc_patterns) { 29 filter_string = create_filter_string(fd->fc_patterns); 30 ofn.lpstrFilter = al_cstr(filter_string); 31 } 32 else { 33 /* List all files by default. */ 34 ofn.lpstrFilter = "All Files\0*.*\0\0"; 35 } 36 37 /* Provide buffer for file chosen by dialog. */ 38 ofn.lpstrFile = buf; 39 ofn.nMaxFile = sizeof(buf); 40 41 /* Initialize file name buffer and starting directory */ 42 if (fd->fc_initial_path) { 43 44 /* Respect an empty filename */ 45 if (strlen(al_get_path_filename(fd->fc_initial_path)) > 0) { 46 strncpy(buf , al_path_cstr(fd->fc_initial_path , ALLEGRO_NATIVE_PATH_SEP) , BUFSIZE - 1); 47 } 48 49 /* Clone the directory */ 50 initial_dir_path = al_clone_path(fd->fc_initial_path); 51 if (initial_dir_path) { 52 al_set_path_filename(initial_dir_path , NULL); 53 ofn.lpstrInitialDir = al_path_cstr(initial_dir_path, ALLEGRO_NATIVE_PATH_SEP); 54 } 55 } 56 57 if (fd->title) 58 ofn.lpstrTitle = al_cstr(fd->title); 59 60 flags |= OFN_NOCHANGEDIR | OFN_EXPLORER; 61 if (fd->flags & ALLEGRO_FILECHOOSER_SAVE) { 62 flags |= OFN_OVERWRITEPROMPT; 63 } 64 else { 65 flags |= (fd->flags & ALLEGRO_FILECHOOSER_FILE_MUST_EXIST) ? OFN_FILEMUSTEXIST : 0; 66 } 67 flags |= (fd->flags & ALLEGRO_FILECHOOSER_MULTIPLE) ? OFN_ALLOWMULTISELECT : 0; 68 flags |= (fd->flags & ALLEGRO_FILECHOOSER_SHOW_HIDDEN) ? 0x10000000 : 0; // NOTE: 0x10000000 is FORCESHOWHIDDEN 69 ofn.Flags = flags; 70 71 if (flags & OFN_OVERWRITEPROMPT) { 72 ret = GetSaveFileName(&ofn); 73 } 74 else { 75 ret = GetOpenFileName(&ofn); 76 } 77 78 if (initial_dir_path) { 79 al_destroy_path(initial_dir_path); 80 } 81 82 al_ustr_free(filter_string); 83 84 if (!ret) { 85 DWORD err = GetLastError(); 86 if (err != ERROR_SUCCESS) { 87 char buf[1000]; 88 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buf, sizeof(buf), NULL); 89 ALLEGRO_ERROR("al_show_native_file_dialog failed: %s\n", buf); 90 } 91 return false; 92 } 93 94 if (flags & OFN_ALLOWMULTISELECT) { 95 int i; 96 /* Count number of file names in buf. */ 97 fd->fc_path_count = 0; 98 i = skip_nul_terminated_string(buf); 99 while (1) { 100 if (buf[i] == '\0') { 101 fd->fc_path_count++; 102 if (buf[i+1] == '\0') 103 break; 104 } 105 i++; 106 } 107 } 108 else { 109 fd->fc_path_count = 1; 110 } 111 112 if (fd->fc_path_count == 1) { 113 fd->fc_paths = al_malloc(sizeof(void *)); 114 fd->fc_paths[0] = al_create_path(buf); 115 } 116 else { 117 int i, p; 118 /* If multiple files were selected, the first string in buf is the 119 * directory name, followed by each of the file names terminated by NUL. 120 */ 121 fd->fc_paths = al_malloc(fd->fc_path_count * sizeof(void *)); 122 i = skip_nul_terminated_string(buf); 123 for (p = 0; p < (int)fd->fc_path_count; p++) { 124 fd->fc_paths[p] = al_create_path_for_directory(buf); 125 al_set_path_filename(fd->fc_paths[p], buf+i); 126 i += skip_nul_terminated_string(buf+i); 127 } 128 } 129 130 return true; 131}

Trent Gamblin
Member #261
April 2000
avatar

Cloning the string wasn't the problem I had in mind. When you go to save a file sometimes you want a default filename, for examples when you do Save As. How is this specified if not through fc_initial_path?

EDIT: Ok I think you last patch looks good (upon further inspection :P)... let me look closer and I'll let you know.

EDIT2: Here's what I came up with. Your patch fails in some cases. For example if you set the initial path to C:\Users\trent then it assumes trent is a filename. I check if it exists, if it does I check if it's a directory, if it doesn't exist I assume it's a file.

#SelectExpand
1diff --git a/addons/native_dialog/win_dialog.c b/addons/native_dialog/win_dialog.c 2index 1f2ffb0..04bd873 100644 3--- a/addons/native_dialog/win_dialog.c 4+++ b/addons/native_dialog/win_dialog.c 5@@ -17,6 +17,8 @@ 6 7 #include "allegro5/allegro_windows.h" 8 9+#include <string.h> 10+ 11 /* We use RichEdit by default. */ 12 #include <richedit.h> 13 #include <shlobj.h> // for folder selector 14@@ -142,8 +144,12 @@ bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, 15 ALLEGRO_DISPLAY_WIN *win_display; 16 int flags = 0; 17 bool ret; 18- char buf[4096] = ""; 19+ const int BUFSIZE = 4096; 20+ char buf[BUFSIZE]; 21 ALLEGRO_USTR *filter_string = NULL; 22+ ALLEGRO_PATH* initial_dir_path = NULL; 23+ 24+ buf[0] = 0; 25 26 win_display = (ALLEGRO_DISPLAY_WIN *)display; 27 28@@ -166,12 +172,34 @@ bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, 29 ofn.lpstrFilter = "All Files\0*.*\0\0"; 30 } 31 32+ /* Provide buffer for file chosen by dialog. */ 33 ofn.lpstrFile = buf; 34 ofn.nMaxFile = sizeof(buf); 35 36+ /* Initialize file name buffer and starting directory */ 37 if (fd->fc_initial_path) { 38- ofn.lpstrInitialDir = 39- al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP); 40+ bool is_dir; 41+ const char *path = al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP); 42+ 43+ if (al_filename_exists(path)) { 44+ ALLEGRO_FS_ENTRY *fs = al_create_fs_entry(path); 45+ is_dir = al_get_fs_entry_mode(fs) & ALLEGRO_FILEMODE_ISDIR; 46+ al_destroy_fs_entry(fs); 47+ } 48+ else 49+ is_dir = false; 50+ 51+ if (is_dir) 52+ ofn.lpstrInitialDir = al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP); 53+ else { 54+ strncpy(buf, al_path_cstr(fd->fc_initial_path, ALLEGRO_NATIVE_PATH_SEP), BUFSIZE - 1); 55+ /* Clone the directory */ 56+ initial_dir_path = al_clone_path(fd->fc_initial_path); 57+ if (initial_dir_path) { 58+ al_set_path_filename(initial_dir_path, NULL); 59+ ofn.lpstrInitialDir = al_path_cstr(initial_dir_path, ALLEGRO_NATIVE_PATH_SEP); 60+ } 61+ } 62 } 63 64 if (fd->title) 65@@ -195,6 +223,10 @@ bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display, 66 ret = GetOpenFileName(&ofn); 67 } 68 69+ if (initial_dir_path) { 70+ al_destroy_path(initial_dir_path); 71+ } 72+ 73 al_ustr_free(filter_string); 74 75 if (!ret) {

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

EDIT2: Here's what I came up with. Your patch fails in some cases. For example if you set the initial path to C:\Users\trent then it assumes trent is a filename. I check if it exists, if it does I check if it's a directory, if it doesn't exist I assume it's a file.

Okay, yeah, your patch looks fine and it passes my simple test program.

Trent Gamblin
Member #261
April 2000
avatar

Thanks for the patch, it's committed.

tobing
Member #5,213
November 2004
avatar

This needs a small fix to compile on Windows:

diff --git a/addons/native_dialog/win_dialog.c b/addons/native_dialog/win_dialog.c
index 04bd873..a47b9a6 100644
--- a/addons/native_dialog/win_dialog.c
+++ b/addons/native_dialog/win_dialog.c
@@ -144,8 +144,8 @@ bool _al_show_native_file_dialog(ALLEGRO_DISPLAY *display,
    ALLEGRO_DISPLAY_WIN *win_display;
    int flags = 0;
    bool ret;
-   const int BUFSIZE = 4096;
-   char buf[BUFSIZE];
+   char buf[4096];
+   const int BUFSIZE = sizeof(buf);
    ALLEGRO_USTR *filter_string = NULL;
    ALLEGRO_PATH* initial_dir_path = NULL;


or see the attached patch for git HEAD.

SiegeLord
Member #7,827
October 2006
avatar

Applied, thanks (and thanks for using git am, makes hunting down people's emails easier :P).

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

tobing
Member #5,213
November 2004
avatar

Yes, I'm using MSVC 2013 right now.

Go to: