1 /////////////////////////////////////////////////////////////////////////
2 // $Id: win32config.cc 14204 2021-03-27 17:23:31Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 //  Copyright (C) 2003-2021  The Bochs Project
6 //
7 //  This library is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU Lesser General Public
9 //  License as published by the Free Software Foundation; either
10 //  version 2 of the License, or (at your option) any later version.
11 //
12 //  This library is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 //  Lesser General Public License for more details.
16 //
17 //  You should have received a copy of the GNU Lesser General Public
18 //  License along with this library; if not, write to the Free Software
19 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20 
21 // Define BX_PLUGGABLE in files that can be compiled into plugins.  For
22 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
23 // is used to know when we are exporting symbols and when we are importing.
24 #define BX_PLUGGABLE
25 
26 #include "win32dialog.h"
27 #include "bochs.h"
28 #include "bx_debug/debug.h"
29 #include "param_names.h"
30 #include "gui.h"
31 #include "win32res.h"
32 #include "win32paramdlg.h"
33 #include "plugin.h"
34 
35 #if BX_USE_WIN32CONFIG
36 
37 static int win32_ci_callback(void *userdata, ci_command_t command);
38 static BxEvent* win32_notify_callback(void *unused, BxEvent *event);
39 
PLUGIN_ENTRY_FOR_MODULE(win32config)40 PLUGIN_ENTRY_FOR_MODULE(win32config)
41 {
42   if (mode == PLUGIN_INIT) {
43     SIM->register_configuration_interface("win32config", win32_ci_callback, NULL);
44     SIM->set_notify_callback(win32_notify_callback, NULL);
45   } else if (mode == PLUGIN_PROBE) {
46     return (int)PLUGTYPE_CI;
47   }
48   return 0; // Success
49 }
50 
51 const char log_choices[N_ACT+1][16] = {"ignore", "log", "warn user", "ask user", "end simulation", "no change"};
52 
GetBochsWindow()53 HWND GetBochsWindow()
54 {
55   HWND hwnd;
56 
57   hwnd = FindWindow("Bochs for Windows", NULL);
58   if (hwnd == NULL) {
59     hwnd = GetForegroundWindow();
60   }
61   return hwnd;
62 }
63 
BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM lpData)64 int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
65 {
66   char path[MAX_PATH];
67 
68   if (uMsg == BFFM_INITIALIZED) {
69     GetCurrentDirectory(MAX_PATH, path);
70     SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)path);
71   }
72   return 0;
73 }
74 
75 #ifndef BIF_NEWDIALOGSTYLE
76 #define BIF_NEWDIALOGSTYLE 0
77 #endif
78 
BrowseDir(const char * Title,char * result)79 int BrowseDir(const char *Title, char *result)
80 {
81   BROWSEINFO browseInfo;
82   LPITEMIDLIST ItemIDList;
83   int r = -1;
84 
85   memset(&browseInfo,0,sizeof(BROWSEINFO));
86   browseInfo.hwndOwner = GetBochsWindow();
87   browseInfo.pszDisplayName = result;
88   browseInfo.lpszTitle = (LPCSTR)Title;
89   browseInfo.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS;
90   browseInfo.lpfn = BrowseCallbackProc;
91   ItemIDList = SHBrowseForFolder(&browseInfo);
92   if (ItemIDList != NULL) {
93     *result = 0;
94     if (SHGetPathFromIDList(ItemIDList, result)) {
95       if (result[0]) r = 0;
96     }
97     // free memory used
98     IMalloc * imalloc = 0;
99     if (SUCCEEDED(SHGetMalloc(&imalloc))) {
100       imalloc->Free(ItemIDList);
101       imalloc->Release();
102     }
103   }
104   return r;
105 }
106 
LogAskProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)107 static BOOL CALLBACK LogAskProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
108 {
109   BxEvent *event;
110   int level;
111 
112   switch (msg) {
113     case WM_INITDIALOG:
114       event = (BxEvent*)lParam;
115       level = event->u.logmsg.level;
116       SetWindowText(hDlg, SIM->get_log_level_name(level));
117       SetWindowText(GetDlgItem(hDlg, IDASKDEV), event->u.logmsg.prefix);
118       SetWindowText(GetDlgItem(hDlg, IDASKMSG), event->u.logmsg.msg);
119       SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Continue");
120       SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Continue and don't ask again");
121       if (event->u.logmsg.mode == BX_LOG_DLG_ASK) {
122         SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Kill simulation");
123         SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Abort (dump core)");
124 #if BX_DEBUGGER
125         SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_ADDSTRING, 0, (LPARAM)"Continue and return to debugger");
126 #endif
127         SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_SETCURSEL, 2, 0);
128       } else {
129         SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_SETCURSEL, 0, 0);
130       }
131       SetFocus(GetDlgItem(hDlg, IDASKLIST));
132       return FALSE;
133     case WM_CLOSE:
134       EndDialog(hDlg, BX_LOG_ASK_CHOICE_DIE);
135       break;
136     case WM_COMMAND:
137       switch (LOWORD(wParam)) {
138         case IDOK:
139           EndDialog(hDlg, SendMessage(GetDlgItem(hDlg, IDASKLIST), LB_GETCURSEL, 0, 0));
140           break;
141         case IDCANCEL:
142           EndDialog(hDlg, BX_LOG_ASK_CHOICE_DIE);
143           break;
144       }
145   }
146   return FALSE;
147 }
148 
StringParamProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)149 static BOOL CALLBACK StringParamProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
150 {
151   static bx_param_string_c *param;
152   char buffer[512];
153   const char *title;
154 
155   switch (msg) {
156     case WM_INITDIALOG:
157       param = (bx_param_string_c *)lParam;
158       title = param->get_label();
159       if ((title == NULL) || (strlen(title) == 0)) {
160         title = param->get_name();
161       }
162       SetWindowText(hDlg, title);
163       SetWindowText(GetDlgItem(hDlg, IDSTRING), param->getptr());
164       SendMessage(GetDlgItem(hDlg, IDSTRING), EM_SETLIMITTEXT, param->get_maxsize(), 0);
165       return TRUE;
166     case WM_CLOSE:
167       EndDialog(hDlg, -1);
168       break;
169     case WM_COMMAND:
170       switch (LOWORD(wParam)) {
171         case IDOK:
172           GetDlgItemText(hDlg, IDSTRING, buffer, param->get_maxsize() + 1);
173           param->set(buffer);
174           EndDialog(hDlg, 1);
175           break;
176         case IDCANCEL:
177           EndDialog(hDlg, -1);
178           break;
179       }
180   }
181   return FALSE;
182 }
183 
SetStandardLogOptions(HWND hDlg)184 void SetStandardLogOptions(HWND hDlg)
185 {
186   int level, idx;
187   int defchoice[5];
188 
189   for (level=0; level<N_LOGLEV; level++) {
190     int mod = 0;
191     int first = SIM->get_log_action (mod, level);
192     BOOL consensus = true;
193     // now compare all others to first.  If all match, then use "first" as
194     // the initial value.
195     for (mod=1; mod<SIM->get_n_log_modules(); mod++) {
196       if (first != SIM->get_log_action (mod, level)) {
197         consensus = false;
198         break;
199       }
200     }
201     if (consensus)
202       defchoice[level] = first;
203     else
204       defchoice[level] = 4;
205   }
206   for (level=0; level<N_LOGLEV; level++) {
207     idx = 0;
208     SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_RESETCONTENT, 0, 0);
209     for (int action=0; action<5; action++) {
210       // the exclude expression allows some choices not being available if they
211       // don't make any sense.  For example, it would be stupid to ignore a panic.
212       if (!BX_LOG_OPTS_EXCLUDE(level, action)) {
213         SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_ADDSTRING, 0, (LPARAM)log_choices[action]);
214         SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_SETITEMDATA, idx, action);
215         if (action == defchoice[level]) {
216           SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_SETCURSEL, idx, 0);
217         }
218         idx++;
219       }
220     }
221   }
222   EnableWindow(GetDlgItem(hDlg, IDDEVLIST), FALSE);
223 }
224 
SetAdvancedLogOptions(HWND hDlg)225 void SetAdvancedLogOptions(HWND hDlg)
226 {
227   int idx, level, mod;
228 
229   idx = SendMessage(GetDlgItem(hDlg, IDDEVLIST), LB_GETCURSEL, 0, 0);
230   mod = SendMessage(GetDlgItem(hDlg, IDDEVLIST), LB_GETITEMDATA, idx, 0);
231   for (level=0; level<N_LOGLEV; level++) {
232     idx = 0;
233     SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_RESETCONTENT, 0, 0);
234     for (int action=0; action<4; action++) {
235       // exclude some action / level combinations (see above)
236       if (!BX_LOG_OPTS_EXCLUDE(level, action)) {
237         SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_ADDSTRING, 0, (LPARAM)log_choices[action]);
238         SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_SETITEMDATA, idx, action);
239         if (action == SIM->get_log_action (mod, level)) {
240           SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_SETCURSEL, idx, 0);
241         }
242         idx++;
243       }
244     }
245   }
246 }
247 
InitLogOptionsDialog(HWND hDlg,BOOL advanced)248 void InitLogOptionsDialog(HWND hDlg, BOOL advanced)
249 {
250   int idx, mod;
251   char name[32];
252 
253   for (mod=0; mod<SIM->get_n_log_modules(); mod++) {
254     if (lstrcmp(SIM->get_logfn_name(mod), "?")) {
255       lstrcpyn(name, SIM->get_logfn_name(mod), 32);
256       idx = SendMessage(GetDlgItem(hDlg, IDDEVLIST), LB_ADDSTRING, 0, (LPARAM)name);
257       SendMessage(GetDlgItem(hDlg, IDDEVLIST), LB_SETITEMDATA, idx, mod);
258     }
259   }
260   if (advanced) {
261     SendMessage(GetDlgItem(hDlg, IDADVLOGOPT), BM_SETCHECK, BST_CHECKED, 0);
262     SendMessage(GetDlgItem(hDlg, IDDEVLIST), LB_SETCURSEL, 0, 0);
263     SetAdvancedLogOptions(hDlg);
264   } else {
265     SetStandardLogOptions(hDlg);
266   }
267 }
268 
ApplyLogOptions(HWND hDlg,BOOL advanced)269 void ApplyLogOptions(HWND hDlg, BOOL advanced)
270 {
271   int idx, level, mod, value;
272 
273   if (advanced) {
274     idx = SendMessage(GetDlgItem(hDlg, IDDEVLIST), LB_GETCURSEL, 0, 0);
275     mod = SendMessage(GetDlgItem(hDlg, IDDEVLIST), LB_GETITEMDATA, idx, 0);
276     for (level=0; level<N_LOGLEV; level++) {
277       idx = SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_GETCURSEL, 0, 0);
278       value = SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_GETITEMDATA, idx, 0);
279       SIM->set_log_action(mod, level, value);
280     }
281     EnableWindow(GetDlgItem(hDlg, IDDEVLIST), TRUE);
282   } else {
283     for (level=0; level<N_LOGLEV; level++) {
284       idx = SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_GETCURSEL, 0, 0);
285       value = SendMessage(GetDlgItem(hDlg, IDLOGEVT1+level), CB_GETITEMDATA, idx, 0);
286       if (value < 4) {
287         // set new default
288         SIM->set_default_log_action(level, value);
289         // apply that action to all modules (devices)
290         SIM->set_log_action(-1, level, value);
291       }
292     }
293   }
294   EnableWindow(GetDlgItem(hDlg, IDADVLOGOPT), TRUE);
295 }
296 
LogOptDlgProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)297 static BOOL CALLBACK LogOptDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
298 {
299   static BOOL advanced;
300   static BOOL changed;
301   long noticode;
302 
303   switch (msg) {
304     case WM_INITDIALOG:
305       advanced = (BOOL)lParam;
306       InitLogOptionsDialog(hDlg, advanced);
307       changed = FALSE;
308       EnableWindow(GetDlgItem(hDlg, IDAPPLY), FALSE);
309       return TRUE;
310     case WM_CLOSE:
311       EndDialog(hDlg, 0);
312       break;
313     case WM_COMMAND:
314       noticode = HIWORD(wParam);
315       switch(noticode) {
316         case CBN_SELCHANGE: /* LBN_SELCHANGE is the same value */
317           switch (LOWORD(wParam)) {
318             case IDDEVLIST:
319               SetAdvancedLogOptions(hDlg);
320               break;
321             case IDLOGEVT1:
322             case IDLOGEVT2:
323             case IDLOGEVT3:
324             case IDLOGEVT4:
325             case IDLOGEVT5:
326               if (!changed) {
327                 EnableWindow(GetDlgItem(hDlg, IDADVLOGOPT), FALSE);
328                 if (advanced) {
329                   EnableWindow(GetDlgItem(hDlg, IDDEVLIST), FALSE);
330                 }
331                 changed = TRUE;
332                 EnableWindow(GetDlgItem(hDlg, IDAPPLY), TRUE);
333               }
334               break;
335           }
336           break;
337         default:
338           switch (LOWORD(wParam)) {
339             case IDADVLOGOPT:
340               if (SendMessage(GetDlgItem(hDlg, IDADVLOGOPT), BM_GETCHECK, 0, 0) == BST_CHECKED) {
341                 EnableWindow(GetDlgItem(hDlg, IDDEVLIST), TRUE);
342                 SendMessage(GetDlgItem(hDlg, IDDEVLIST), LB_SETCURSEL, 0, 0);
343                 SetAdvancedLogOptions(hDlg);
344                 advanced = TRUE;
345               } else {
346                 SendMessage(GetDlgItem(hDlg, IDDEVLIST), LB_SETCURSEL, (WPARAM)-1, 0);
347                 SetStandardLogOptions(hDlg);
348                 advanced = FALSE;
349               }
350               break;
351             case IDAPPLY:
352               ApplyLogOptions(hDlg, advanced);
353               EnableWindow(GetDlgItem(hDlg, IDAPPLY), FALSE);
354               changed = FALSE;
355               break;
356             case IDOK:
357               if (changed) {
358                 ApplyLogOptions(hDlg, advanced);
359               }
360               EndDialog(hDlg, 1);
361               break;
362             case IDCANCEL:
363               EndDialog(hDlg, 0);
364               break;
365           }
366       }
367       break;
368   }
369   return FALSE;
370 }
371 
LogOptionsDialog(HWND hwnd,bool runtime)372 void LogOptionsDialog(HWND hwnd, bool runtime)
373 {
374   DialogBoxParam(NULL, MAKEINTRESOURCE(LOGOPT_DLG), hwnd, (DLGPROC)LogOptDlgProc, (LPARAM)runtime);
375 }
376 
PluginCtrlDlgProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)377 static BOOL CALLBACK PluginCtrlDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
378 {
379   int count, i;
380   long code;
381   bx_list_c *plugin_ctrl;
382   bx_param_bool_c *plugin;
383   char plugname[20], message[80];
384 
385   switch (msg) {
386     case WM_INITDIALOG:
387       plugin_ctrl = (bx_list_c*) SIM->get_param(BXPN_PLUGIN_CTRL);
388       count = plugin_ctrl->get_size();
389       for (i = 0; i < count; i++) {
390         plugin = (bx_param_bool_c*)plugin_ctrl->get(i);
391         if (plugin->get()) {
392           SendMessage(GetDlgItem(hDlg, IDPLUGLIST2), LB_ADDSTRING, 0, (LPARAM)plugin->get_name());
393         } else {
394           SendMessage(GetDlgItem(hDlg, IDPLUGLIST1), LB_ADDSTRING, 0, (LPARAM)plugin->get_name());
395         }
396       }
397       EnableWindow(GetDlgItem(hDlg, IDLOAD), FALSE);
398       EnableWindow(GetDlgItem(hDlg, IDUNLOAD), FALSE);
399       return TRUE;
400     case WM_CLOSE:
401       EndDialog(hDlg, 0);
402       break;
403     case WM_COMMAND:
404       code = HIWORD(wParam);
405       switch (LOWORD(wParam)) {
406         case IDPLUGLIST1:
407           if (code == LBN_SELCHANGE) {
408             SendMessage(GetDlgItem(hDlg, IDPLUGLIST2), LB_SETCURSEL, -1, 0);
409             EnableWindow(GetDlgItem(hDlg, IDLOAD), TRUE);
410             EnableWindow(GetDlgItem(hDlg, IDUNLOAD), FALSE);
411           }
412           break;
413         case IDPLUGLIST2:
414           if (code == LBN_SELCHANGE) {
415             SendMessage(GetDlgItem(hDlg, IDPLUGLIST1), LB_SETCURSEL, -1, 0);
416             EnableWindow(GetDlgItem(hDlg, IDLOAD), FALSE);
417             EnableWindow(GetDlgItem(hDlg, IDUNLOAD), TRUE);
418           }
419           break;
420         case IDLOAD:
421           i = SendMessage(GetDlgItem(hDlg, IDPLUGLIST1), LB_GETCURSEL, 0, 0);
422           SendMessage(GetDlgItem(hDlg, IDPLUGLIST1), LB_GETTEXT, i, (LPARAM)plugname);
423           if (SIM->opt_plugin_ctrl(plugname, 1)) {
424             wsprintf(message, "Plugin '%s' loaded", plugname);
425             MessageBox(hDlg, message, "Plugin Control", MB_ICONINFORMATION);
426             SendMessage(GetDlgItem(hDlg, IDPLUGLIST1), LB_DELETESTRING, i, 0);
427             SendMessage(GetDlgItem(hDlg, IDPLUGLIST2), LB_ADDSTRING, 0, (LPARAM)plugname);
428             EnableWindow(GetDlgItem(hDlg, IDLOAD), FALSE);
429           }
430           break;
431         case IDUNLOAD:
432           i = SendMessage(GetDlgItem(hDlg, IDPLUGLIST2), LB_GETCURSEL, 0, 0);
433           SendMessage(GetDlgItem(hDlg, IDPLUGLIST2), LB_GETTEXT, i, (LPARAM)plugname);
434           if (SIM->opt_plugin_ctrl(plugname, 0)) {
435             wsprintf(message, "Plugin '%s' unloaded", plugname);
436             MessageBox(hDlg, message, "Plugin Control", MB_ICONINFORMATION);
437             SendMessage(GetDlgItem(hDlg, IDPLUGLIST1), LB_ADDSTRING, 0, (LPARAM)plugname);
438             SendMessage(GetDlgItem(hDlg, IDPLUGLIST2), LB_DELETESTRING, i, 0);
439             EnableWindow(GetDlgItem(hDlg, IDUNLOAD), FALSE);
440           }
441           break;
442         case IDOK:
443           EndDialog(hDlg, 1);
444           break;
445       }
446       break;
447   }
448   return FALSE;
449 }
450 
PluginCtrlDialog(HWND hwnd)451 void PluginCtrlDialog(HWND hwnd)
452 {
453   DialogBox(NULL, MAKEINTRESOURCE(PLUGIN_CTRL_DLG), hwnd, (DLGPROC)PluginCtrlDlgProc);
454 }
455 
456 typedef struct {
457   const char *label;
458   const char *param;
459 } edit_opts_t;
460 
461 edit_opts_t start_options[] = {
462   {"Plugin Control", "#plugins"},
463   {"Logfile", "log"},
464   {"Log Options", "#logopts"},
465   {"CPU", "cpu"},
466 #if BX_CPU_LEVEL >= 4
467   {"CPUID", "cpuid"},
468 #endif
469   {"Memory", "memory"},
470   {"Clock & CMOS", "clock_cmos"},
471   {"PCI", "pci"},
472   {"Display & Interface", "display"},
473   {"Keyboard & Mouse", "keyboard_mouse"},
474   {"Disk & Boot", BXPN_MENU_DISK_WIN32},
475   {"Serial / Parallel / USB", "ports"},
476   {"Network card", "network"},
477   {"Sound card", "sound"},
478   {"Other", "misc"},
479 #if BX_PLUGINS
480   {"User-defined Options", "user"},
481 #endif
482   {NULL, NULL}
483 };
484 
485 edit_opts_t runtime_options[] = {
486   {"CD-ROM", BXPN_MENU_RUNTIME_CDROM},
487   {"USB", BXPN_MENU_RUNTIME_USB},
488   {"Misc", BXPN_MENU_RUNTIME_MISC},
489   {"Log Options", "#logopts"},
490   {NULL, NULL}
491 };
MainMenuDlgProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)492 static BOOL CALLBACK MainMenuDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
493 {
494   static bool runtime;
495   int choice, code, i;
496   bx_param_filename_c *rcfile;
497   char path[BX_PATHNAME_LEN];
498   const char *pname;
499 
500   switch (msg) {
501     case WM_INITDIALOG:
502       runtime = (bool)lParam;
503       EnableWindow(GetDlgItem(hDlg, IDEDITCFG), FALSE);
504       if (runtime) {
505         SetWindowText(hDlg, "Bochs Runtime Menu");
506         EnableWindow(GetDlgItem(hDlg, IDREADRC), FALSE);
507         EnableWindow(GetDlgItem(hDlg, IDRESETCFG), FALSE);
508         EnableWindow(GetDlgItem(hDlg, IDRESTORE), FALSE);
509         SetWindowText(GetDlgItem(hDlg, IDOK), "&Continue");
510         i = 0;
511         while (runtime_options[i].label != NULL) {
512           SendMessage(GetDlgItem(hDlg, IDEDITBOX), LB_ADDSTRING, 0, (LPARAM)runtime_options[i].label);
513           i++;
514         }
515         choice = IDOK;
516       } else {
517         i = 0;
518         while (start_options[i].label != NULL) {
519           SendMessage(GetDlgItem(hDlg, IDEDITBOX), LB_ADDSTRING, 0, (LPARAM)start_options[i].label);
520           i++;
521         }
522         if (SIM->get_param_enum(BXPN_BOCHS_START)->get() == BX_LOAD_START) {
523           choice = IDREADRC;
524         } else {
525           choice = IDOK;
526         }
527       }
528       SetFocus(GetDlgItem(hDlg, choice));
529       return FALSE;
530     case WM_CLOSE:
531       if (runtime) {
532         EndDialog(hDlg, 1);
533       } else {
534         bx_user_quit = 1;
535         EndDialog(hDlg, -1);
536       }
537       break;
538     case WM_COMMAND:
539       code = HIWORD(wParam);
540       switch (LOWORD(wParam)) {
541         case IDREADRC:
542           rcfile = new bx_param_filename_c(NULL, "rcfile", "Load Bochs Config File",
543                                            "", "bochsrc.bxrc", BX_PATHNAME_LEN);
544           rcfile->set_extension("bxrc");
545           if (AskFilename(hDlg, rcfile, NULL) > 0) {
546             SIM->reset_all_param();
547             SIM->read_rc(rcfile->getptr());
548           }
549           delete rcfile;
550           break;
551         case IDWRITERC:
552           rcfile = new bx_param_filename_c(NULL, "rcfile", "Save Bochs Config File",
553                                            "", "bochsrc.bxrc", BX_PATHNAME_LEN);
554           rcfile->set_extension("bxrc");
555           rcfile->set_options(rcfile->SAVE_FILE_DIALOG);
556           if (AskFilename(hDlg, rcfile, NULL) > 0) {
557             SIM->write_rc(rcfile->getptr(), 1);
558           }
559           delete rcfile;
560           break;
561         case IDEDITBOX:
562           if ((code == LBN_SELCHANGE) ||
563               (code == LBN_DBLCLK)) {
564             EnableWindow(GetDlgItem(hDlg, IDEDITCFG), TRUE);
565           }
566           if (code != LBN_DBLCLK) {
567             break;
568           }
569         case IDEDITCFG:
570           i = SendMessage(GetDlgItem(hDlg, IDEDITBOX), LB_GETCURSEL, 0, 0);
571           if (runtime) {
572             pname = runtime_options[i].param;
573           } else {
574             pname = start_options[i].param;
575           }
576           if (pname[0] != '#') {
577             bx_list_c *list = (bx_list_c*)SIM->get_param(pname);
578             if (list != NULL) {
579               if (list->get_size() > 0) {
580                 win32ParamDialog(hDlg, pname);
581               } else {
582                 MessageBox(hDlg, "Nothing to configure in this section", "Warning", MB_ICONEXCLAMATION);
583               }
584             } else {
585               MessageBox(hDlg, "Nothing to configure in this section", "Warning", MB_ICONEXCLAMATION);
586             }
587           } else {
588             if (!lstrcmp(pname, "#logopts")) {
589               LogOptionsDialog(hDlg, runtime);
590             } else if (!lstrcmp(pname, "#plugins")) {
591               PluginCtrlDialog(hDlg);
592             } else {
593               MessageBox(hDlg, "Unknown keyword", "Warning", MB_ICONEXCLAMATION);
594             }
595           }
596           break;
597         case IDRESETCFG:
598           if (MessageBox(hDlg, "Reset all options back to their factory defaults ?",
599                          "Reset Configuration", MB_ICONEXCLAMATION | MB_YESNO) == IDYES) {
600             SIM->reset_all_param();
601           }
602           break;
603         case IDRESTORE:
604           path[0] = 0;
605           if (BrowseDir("Restore Bochs state from...", path) >= 0) {
606             SIM->get_param_bool(BXPN_RESTORE_FLAG)->set(1);
607             SIM->get_param_string(BXPN_RESTORE_PATH)->set(path);
608             EndDialog(hDlg, 1);
609           }
610           break;
611         case IDOK:
612           if (runtime) {
613             SIM->update_runtime_options();
614           }
615           EndDialog(hDlg, 1);
616           break;
617         case IDCANCEL:
618           if (runtime) {
619             EndDialog(hDlg, 1);
620             break;
621           }
622         case IDQUIT:
623           bx_user_quit = 1;
624           EndDialog(hDlg, -1);
625           break;
626       }
627   }
628   return FALSE;
629 }
630 
LogAskDialog(BxEvent * event)631 void LogAskDialog(BxEvent *event)
632 {
633   event->retcode = (Bit32s) DialogBoxParam(NULL, MAKEINTRESOURCE(ASK_DLG), GetBochsWindow(),
634                                   (DLGPROC)LogAskProc, (LPARAM)event);
635 }
636 
AskString(bx_param_string_c * param)637 int AskString(bx_param_string_c *param)
638 {
639   return (int) DialogBoxParam(NULL, MAKEINTRESOURCE(STRING_DLG), GetBochsWindow(),
640                         (DLGPROC)StringParamProc, (LPARAM)param);
641 }
642 
MainMenuDialog(HWND hwnd,bool runtime)643 int MainMenuDialog(HWND hwnd, bool runtime)
644 {
645   return (int) DialogBoxParam(NULL, MAKEINTRESOURCE(MAINMENU_DLG), hwnd,
646                         (DLGPROC)MainMenuDlgProc, (LPARAM)runtime);
647 }
648 
win32_notify_callback(void * unused,BxEvent * event)649 BxEvent* win32_notify_callback(void *unused, BxEvent *event)
650 {
651   int opts;
652   bx_param_c *param;
653   bx_param_string_c *sparam;
654   char pname[BX_PATHNAME_LEN];
655 
656   event->retcode = -1;
657   switch (event->type)
658   {
659     case BX_SYNC_EVT_LOG_DLG:
660       LogAskDialog(event);
661       return event;
662     case BX_SYNC_EVT_MSG_BOX:
663       MessageBox(GetBochsWindow(), event->u.logmsg.msg, event->u.logmsg.prefix, MB_ICONERROR);
664       return event;
665     case BX_SYNC_EVT_ASK_PARAM:
666       param = event->u.param.param;
667       if (param->get_type() == BXT_PARAM_STRING || param->get_type() == BXT_PARAM_BYTESTRING) {
668         sparam = (bx_param_string_c *)param;
669         opts = sparam->get_options();
670         if (opts & sparam->IS_FILENAME) {
671           if (opts & sparam->SELECT_FOLDER_DLG) {
672             event->retcode = BrowseDir(sparam->get_label(), sparam->getptr());
673           } else {
674             event->retcode = AskFilename(GetBochsWindow(), (bx_param_filename_c *)sparam, NULL);
675           }
676           return event;
677         } else {
678           event->retcode = AskString(sparam);
679           return event;
680         }
681       } else if (param->get_type() == BXT_LIST) {
682         param->get_param_path(pname, BX_PATHNAME_LEN);
683         if (!strncmp(pname, "floppy", 6)) {
684           event->retcode = (Bit32s) win32FloppyParamDialog(GetBochsWindow(), pname);
685         } else {
686           event->retcode = (Bit32s) win32ParamDialog(GetBochsWindow(), pname);
687         }
688         return event;
689       } else if (param->get_type() == BXT_PARAM_BOOL) {
690         UINT flag = MB_YESNO | MB_SETFOREGROUND;
691         if (((bx_param_bool_c *)param)->get() == 0) {
692           flag |= MB_DEFBUTTON2;
693         }
694         ((bx_param_bool_c *)param)->set(MessageBox(GetActiveWindow(), param->get_description(), param->get_label(), flag) == IDYES);
695         event->retcode = 0;
696         return event;
697       }
698     case BX_SYNC_EVT_TICK: // called periodically by siminterface.
699       event->retcode = 0;
700       // fall into default case
701     default:
702       return event;
703   }
704 }
705 
win32_ci_callback(void * userdata,ci_command_t command)706 static int win32_ci_callback(void *userdata, ci_command_t command)
707 {
708   switch (command)
709   {
710     case CI_START:
711       if (SIM->get_param_enum(BXPN_BOCHS_START)->get() == BX_QUICK_START) {
712         SIM->begin_simulation(bx_startup_flags.argc, bx_startup_flags.argv);
713         // we don't expect it to return, but if it does, quit
714         SIM->quit_sim(1);
715       } else {
716         if (MainMenuDialog(GetActiveWindow(), 0) == 1) {
717           SIM->begin_simulation(bx_startup_flags.argc, bx_startup_flags.argv);
718         }
719         SIM->quit_sim(1);
720       }
721       break;
722     case CI_RUNTIME_CONFIG:
723       if (!bx_gui->has_gui_console()) {
724         if (MainMenuDialog(GetBochsWindow(), 1) < 0) {
725           bx_user_quit = 1;
726 #if !BX_DEBUGGER
727           bx_atexit();
728           SIM->quit_sim(1);
729 #else
730           bx_dbg_exit(1);
731 #endif
732           return -1;
733         }
734       }
735       break;
736     case CI_SHUTDOWN:
737       break;
738   }
739   return 0;
740 }
741 
742 #endif // BX_USE_WIN32CONFIG
743