]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Plugson/src/main_windows.c
Add /F option for VentoyPlugson.exe to use the system default browser.
[Ventoy.git] / Plugson / src / main_windows.c
1 #include <Windows.h>
2 #include <Shlobj.h>
3 #include <tlhelp32.h>
4 #include <Psapi.h>
5 #include <commctrl.h>
6 #include <resource.h>
7 #include <ventoy_define.h>
8 #include <ventoy_util.h>
9 #include <ventoy_json.h>
10 #include <ventoy_disk.h>
11 #include <ventoy_http.h>
12
13 char g_ventoy_dir[MAX_PATH];
14
15 static BOOL g_ChromeFirst = TRUE;
16 static BOOL g_running = FALSE;
17 static HWND g_refresh_button;
18 static HWND g_start_button;
19 static HWND g_openlink_button;
20 static HWND g_exit_button;
21 static HWND g_ComboxHwnd;
22
23 typedef enum MSGID
24 {
25 MSGID_ERROR = 0,
26 MSGID_INFO,
27 MSGID_INVALID_DIR,
28 MSGID_NEW_DIR_FAIL,
29 MSGID_RENAME_VENTOY,
30 MSGID_INTERNAL_ERR,
31 MSGID_BTN_REFRESH,
32 MSGID_BTN_START,
33 MSGID_BTN_STOP,
34 MSGID_BTN_LINK,
35 MSGID_BTN_EXIT,
36
37 MSGID_BTN_STOP_TIP,
38 MSGID_BTN_EXIT_TIP,
39 MSGID_RUNNING_TIP,
40 MSGID_NO_TARXZ_TIP,
41
42 MSGID_BUTT
43 }MSGID;
44
45
46 const WCHAR *g_msg_cn[MSGID_BUTT] =
47 {
48 L"错误",
49 L"提醒",
50 L"请在 Ventoy 盘根目录下运行本程序!(存放ISO文件的位置)",
51 L"创建 ventoy 目录失败,无法继续!",
52 L"ventoy 目录存在,但是大小写不匹配,请先将其重命名!",
53 L"内部错误,程序即将退出!",
54 L"刷新",
55 L"启动",
56 L"停止",
57 L"链接",
58 L"退出",
59
60 L"停止运行后浏览器页面将会关闭,是否继续?",
61 L"当前服务正在运行,是否退出?",
62 L"请先关闭正在运行的 VentoyPlugson 程序!",
63 L"ventoy\\plugson.tar.xz 文件不存在,请在正确的目录下运行!",
64 };
65 const WCHAR *g_msg_en[MSGID_BUTT] =
66 {
67 L"Error",
68 L"Info",
69 L"Please run me at the root of Ventoy partition.",
70 L"Failed to create ventoy directory!",
71 L"ventoy directory case mismatch, please rename it first!",
72 L"Internal error, the program will exit!",
73 L"Refresh",
74 L"Start",
75 L"Stop",
76 L"Link",
77 L"Exit",
78
79 L"The browser page will close after stop, continue?",
80 L"Service is running, continue?",
81 L"Please close another running VentoyPlugson instance!",
82 L"ventoy\\plugson.tar.xz does not exist, please run under the correct directory!",
83 };
84
85 const WCHAR **g_msg_lang = NULL;
86
87 HINSTANCE g_hInst;
88
89 char g_log_file[MAX_PATH];
90 char g_cur_dir[MAX_PATH];
91
92 int ventoy_log_init(void);
93 void ventoy_log_exit(void);
94
95 static BOOL OnDestroyDialog()
96 {
97 ventoy_http_exit();
98 ventoy_disk_exit();
99 #ifndef VENTOY_SIM
100 ventoy_www_exit();
101 #endif
102 ventoy_log_exit();
103 return TRUE;
104 }
105
106
107 static void OpenURL(void)
108 {
109 int i;
110 char url[128];
111 const static char * Browsers[] =
112 {
113 "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
114 "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
115 "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe",
116 "C:\\Program Files\\Mozilla Firefox\\firefox.exe",
117 NULL
118 };
119
120 sprintf_s(url, sizeof(url), "http://%s:%s/index.html", g_sysinfo.ip, g_sysinfo.port);
121
122 if (g_ChromeFirst)
123 {
124 for (i = 0; Browsers[i] != NULL; i++)
125 {
126 if (ventoy_is_file_exist("%s", Browsers[i]))
127 {
128 ShellExecuteA(NULL, "open", Browsers[i], url, NULL, SW_SHOW);
129 return;
130 }
131 }
132 }
133
134 ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOW);
135 }
136
137
138 static void FillCombox(HWND hWnd)
139 {
140 int i = 0;
141 int num = 0;
142 const ventoy_disk *list = NULL;
143 CHAR DeviceName[256];
144
145 // delete all items
146 SendMessage(g_ComboxHwnd, CB_RESETCONTENT, 0, 0);
147
148 list = ventoy_get_disk_list(&num);
149 if (NULL == list || num <= 0)
150 {
151 return;
152 }
153
154 for (i = 0; i < num; i++)
155 {
156 sprintf_s(DeviceName, sizeof(DeviceName),
157 "%C: [%s] %s",
158 list[i].devname[0],
159 list[i].cur_capacity,
160 list[i].cur_model);
161 SendMessageA(g_ComboxHwnd, CB_ADDSTRING, 0, (LPARAM)DeviceName);
162 }
163 SendMessage(g_ComboxHwnd, CB_SETCURSEL, 0, 0);
164 }
165
166
167 static BOOL InitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
168 {
169 HICON hIcon;
170
171 g_ComboxHwnd = GetDlgItem(hWnd, IDC_COMBO1);
172 g_refresh_button = GetDlgItem(hWnd, IDC_BUTTON1);
173 g_start_button = GetDlgItem(hWnd, IDC_BUTTON2);
174 g_openlink_button = GetDlgItem(hWnd, IDC_BUTTON3);
175 g_exit_button = GetDlgItem(hWnd, IDC_BUTTON4);
176
177 hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ICON1));
178 SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
179 SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
180
181 SetWindowTextW(g_refresh_button, g_msg_lang[MSGID_BTN_REFRESH]);
182 SetWindowTextW(g_start_button, g_msg_lang[MSGID_BTN_START]);
183 SetWindowTextW(g_openlink_button, g_msg_lang[MSGID_BTN_LINK]);
184 SetWindowTextW(g_exit_button, g_msg_lang[MSGID_BTN_EXIT]);
185
186 EnableWindow(g_openlink_button, FALSE);
187
188 FillCombox(hWnd);
189
190 return TRUE;
191 }
192
193 static void VentoyStopService()
194 {
195 ventoy_http_stop();
196 }
197
198 static int VentoyStartService(int sel)
199 {
200 int rc;
201 BOOL bRet;
202 char Path[128];
203 char CurDir[MAX_PATH];
204 const ventoy_disk *disk = NULL;
205
206 vlog("VentoyStartService ...\n");
207
208 disk = ventoy_get_disk_node(sel);
209 if (disk == NULL)
210 {
211 return 1;
212 }
213
214 vlog("Start service at %C: %s %s ...\n", disk->devname[0], disk->cur_model, disk->cur_ventoy_ver);
215
216 g_cur_dir[0] = disk->devname[0];
217 g_cur_dir[1] = ':';
218 g_cur_dir[2] = '\\';
219 g_cur_dir[3] = 0;
220
221 g_sysinfo.pathcase = disk->pathcase;
222 g_sysinfo.cur_secureboot = disk->cur_secureboot;
223 g_sysinfo.cur_part_style = disk->cur_part_style;
224 strlcpy(g_sysinfo.cur_fsname, disk->cur_fsname);
225 strlcpy(g_sysinfo.cur_capacity, disk->cur_capacity);
226 strlcpy(g_sysinfo.cur_model, disk->cur_model);
227 strlcpy(g_sysinfo.cur_ventoy_ver, disk->cur_ventoy_ver);
228
229 bRet = SetCurrentDirectoryA(g_cur_dir);
230 vlog("SetCurrentDirectoryA %u <%s>\n", bRet, g_cur_dir);
231
232 CurDir[0] = 0;
233 GetCurrentDirectoryA(sizeof(CurDir), CurDir);
234 vlog("CurDir=<%s>\n", CurDir);
235
236 if (strcmp(g_cur_dir, CurDir))
237 {
238 vlog("Failed to change current directory.");
239 }
240
241 g_cur_dir[2] = 0;
242
243 if (ventoy_is_directory_exist("ventoy"))
244 {
245 if (g_sysinfo.pathcase)
246 {
247 vlog("ventoy directory already exist, check case sensitive.\n");
248 strlcpy(Path, "ventoy");
249
250 rc = ventoy_path_case(Path, 0);
251 vlog("ventoy_path_case actual path is <%s> <count:%d>\n", Path, rc);
252
253 if (rc)
254 {
255 vlog("ventoy directory case mismatch, rename<%s>--><%s>\n", Path, "ventoy");
256 if (MoveFileA(Path, "ventoy"))
257 {
258 vlog("Rename <%s>--><%s> success\n", Path, "ventoy");
259 }
260 else
261 {
262 vlog("Rename <%s>--><%s> failed %u\n", Path, "ventoy", LASTERR);
263 MessageBoxW(NULL, g_msg_lang[MSGID_RENAME_VENTOY], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
264 return 1;
265 }
266 }
267 }
268 else
269 {
270 vlog("ventoy directory already exist, no need to check case sensitive.\n");
271 }
272 }
273 else
274 {
275 if (CreateDirectoryA("ventoy", NULL))
276 {
277 vlog("Create ventoy directory success.\n");
278 }
279 else
280 {
281 vlog("Create ventoy directory failed %u.\n", LASTERR);
282 MessageBoxW(NULL, g_msg_lang[MSGID_NEW_DIR_FAIL], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
283 return 1;
284 }
285 }
286
287 return ventoy_http_start(g_sysinfo.ip, g_sysinfo.port);
288 }
289
290 INT_PTR CALLBACK DialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
291 {
292 int rc;
293 int nCurSel;
294 WORD NotifyCode;
295 WORD CtrlID;
296
297 switch (Message)
298 {
299 case WM_NOTIFY:
300 {
301 UINT code = 0;
302 UINT_PTR idFrom = 0;
303
304 if (lParam)
305 {
306 code = ((LPNMHDR)lParam)->code;
307 idFrom = ((LPNMHDR)lParam)->idFrom;
308 }
309
310 if (idFrom == IDC_SYSLINK1 && (NM_CLICK == code || NM_RETURN == code))
311 {
312 OpenURL();
313 }
314 break;
315 }
316 case WM_COMMAND:
317 {
318 NotifyCode = HIWORD(wParam);
319 CtrlID = LOWORD(wParam);
320
321 if (NotifyCode == BN_CLICKED)
322 {
323 if (CtrlID == IDC_BUTTON1)
324 {
325 if (!g_running)
326 {
327 //refresh
328 ventoy_disk_exit();
329 ventoy_disk_init();
330 FillCombox(hWnd);
331 }
332 }
333 else if (CtrlID == IDC_BUTTON2)
334 {
335 if (g_running)
336 {
337 if (IDYES == MessageBoxW(NULL, g_msg_lang[MSGID_BTN_STOP_TIP], g_msg_lang[MSGID_INFO], MB_YESNO | MB_ICONINFORMATION))
338 {
339 VentoyStopService();
340
341 g_running = FALSE;
342 SetWindowTextW(g_start_button, g_msg_lang[MSGID_BTN_START]);
343 EnableWindow(g_ComboxHwnd, TRUE);
344 EnableWindow(g_refresh_button, TRUE);
345 EnableWindow(g_openlink_button, FALSE);
346 }
347 }
348 else
349 {
350 nCurSel = (int)SendMessage(g_ComboxHwnd, CB_GETCURSEL, 0, 0);
351 if (CB_ERR != nCurSel)
352 {
353 rc = VentoyStartService(nCurSel);
354 if (rc)
355 {
356 vlog("Ventoy failed to start http server, check %s for detail\n", g_log_file);
357 MessageBoxW(NULL, g_msg_lang[MSGID_INTERNAL_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
358 }
359 else
360 {
361 g_running = TRUE;
362 SetWindowTextW(g_start_button, g_msg_lang[MSGID_BTN_STOP]);
363
364 EnableWindow(g_ComboxHwnd, FALSE);
365 EnableWindow(g_refresh_button, FALSE);
366 EnableWindow(g_openlink_button, TRUE);
367
368 OpenURL();
369 }
370 }
371 }
372 }
373 else if (CtrlID == IDC_BUTTON3)
374 {
375 if (g_running)
376 {
377 OpenURL();
378 }
379 }
380 else if (CtrlID == IDC_BUTTON4)
381 {
382 if (g_running)
383 {
384 if (IDYES != MessageBoxW(NULL, g_msg_lang[MSGID_BTN_EXIT_TIP], g_msg_lang[MSGID_INFO], MB_YESNO | MB_ICONINFORMATION))
385 {
386 return 0;
387 }
388
389 ventoy_http_stop();
390 }
391
392 OnDestroyDialog();
393 EndDialog(hWnd, 0);
394 }
395 }
396 break;
397 }
398 case WM_INITDIALOG:
399 {
400 InitDialog(hWnd, wParam, lParam);
401 break;
402 }
403 case WM_CLOSE:
404 {
405 if (g_running)
406 {
407 if (IDYES != MessageBoxW(NULL, g_msg_lang[MSGID_BTN_EXIT_TIP], g_msg_lang[MSGID_INFO], MB_YESNO | MB_ICONINFORMATION))
408 {
409 return 0;
410 }
411
412 VentoyStopService();
413 }
414
415 OnDestroyDialog();
416 EndDialog(hWnd, 0);
417 }
418 }
419
420 return 0;
421 }
422
423 static int ParseCmdLine(LPSTR lpCmdLine, char *ip, char *port)
424 {
425 int portnum;
426 char *ipstart = ip;
427 char *pos;
428
429
430 if (!lpCmdLine)
431 {
432 return 0;
433 }
434
435 pos = strstr(lpCmdLine, "-H");
436 if (!pos)
437 {
438 pos = strstr(lpCmdLine, "-h");
439 }
440
441 if (pos)
442 {
443 pos += 2;
444 while (*pos == ' ' || *pos == '\t')
445 {
446 pos++;
447 }
448
449 while (isdigit(*pos) || *pos == '.')
450 {
451 *ipstart++ = *pos++;
452 }
453 }
454
455
456 pos = strstr(lpCmdLine, "-P");
457 if (!pos)
458 {
459 pos = strstr(lpCmdLine, "-p");
460 }
461
462 if (pos)
463 {
464 portnum = (int)strtol(pos + 3, NULL, 10);
465 sprintf_s(port, 16, "%d", portnum);
466 }
467
468 return 0;
469 }
470
471
472
473 //
474 //copy from Rufus
475 //Copyright © 2011-2021 Pete Batard <pete@akeo.ie>
476 //
477 #include <delayimp.h>
478 // For delay-loaded DLLs, use LOAD_LIBRARY_SEARCH_SYSTEM32 to avoid DLL search order hijacking.
479 FARPROC WINAPI dllDelayLoadHook(unsigned dliNotify, PDelayLoadInfo pdli)
480 {
481 if (dliNotify == dliNotePreLoadLibrary) {
482 // Windows 7 without KB2533623 does not support the LOAD_LIBRARY_SEARCH_SYSTEM32 flag.
483 // That is is OK, because the delay load handler will interrupt the NULL return value
484 // to mean that it should perform a normal LoadLibrary.
485 return (FARPROC)LoadLibraryExA(pdli->szDll, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
486 }
487 return NULL;
488 }
489
490 #if defined(_MSC_VER)
491 // By default the Windows SDK headers have a `const` while MinGW does not.
492 const
493 #endif
494 PfnDliHook __pfnDliNotifyHook2 = dllDelayLoadHook;
495
496 typedef BOOL(WINAPI* SetDefaultDllDirectories_t)(DWORD);
497 static void DllProtect(void)
498 {
499 SetDefaultDllDirectories_t pfSetDefaultDllDirectories = NULL;
500
501 // Disable loading system DLLs from the current directory (sideloading mitigation)
502 // PS: You know that official MSDN documentation for SetDllDirectory() that explicitly
503 // indicates that "If the parameter is an empty string (""), the call removes the current
504 // directory from the default DLL search order"? Yeah, that doesn't work. At all.
505 // Still, we invoke it, for platforms where the following call might actually work...
506 SetDllDirectoryA("");
507
508 // For libraries on the KnownDLLs list, the system will always load them from System32.
509 // For other DLLs we link directly to, we can delay load the DLL and use a delay load
510 // hook to load them from System32. Note that, for this to work, something like:
511 // 'somelib.dll;%(DelayLoadDLLs)' must be added to the 'Delay Loaded Dlls' option of
512 // the linker properties in Visual Studio (which means this won't work with MinGW).
513 // For all other DLLs, use SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32).
514 // Finally, we need to perform the whole gymkhana below, where we can't call on
515 // SetDefaultDllDirectories() directly, because Windows 7 doesn't have the API exposed.
516 // Also, no, Coverity, we never need to care about freeing kernel32 as a library.
517 // coverity[leaked_storage]
518
519 pfSetDefaultDllDirectories = (SetDefaultDllDirectories_t)
520 GetProcAddress(LoadLibraryW(L"kernel32.dll"), "SetDefaultDllDirectories");
521 if (pfSetDefaultDllDirectories != NULL)
522 pfSetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32);
523 }
524
525
526 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
527 {
528 int i;
529 int rc;
530 HANDLE hMutex;
531 WCHAR CurDir[MAX_PATH];
532
533 UNREFERENCED_PARAMETER(hPrevInstance);
534
535 for (i = 0; i < __argc; i++)
536 {
537 if (__argv[i] && _stricmp(__argv[i], "/F") == 0)
538 {
539 g_ChromeFirst = FALSE;
540 break;
541 }
542 }
543
544 DllProtect();
545
546 if (GetUserDefaultUILanguage() == 0x0804)
547 {
548 g_sysinfo.language = LANGUAGE_CN;
549 g_msg_lang = g_msg_cn;
550 }
551 else
552 {
553 g_sysinfo.language = LANGUAGE_EN;
554 g_msg_lang = g_msg_en;
555 }
556
557 hMutex = CreateMutexA(NULL, TRUE, "PlugsonMUTEX");
558 if ((hMutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS))
559 {
560 MessageBoxW(NULL, g_msg_lang[MSGID_RUNNING_TIP], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
561 return 1;
562 }
563
564 GetCurrentDirectoryW(MAX_PATH, CurDir);
565 WideCharToMultiByte(CP_UTF8, 0, CurDir, -1, g_cur_dir, MAX_PATH, NULL, 0);
566
567 sprintf_s(g_ventoy_dir, sizeof(g_ventoy_dir), "%s", g_cur_dir);
568 sprintf_s(g_log_file, sizeof(g_log_file), "%s\\%s", g_cur_dir, LOG_FILE);
569 ventoy_log_init();
570
571 if (!ventoy_is_file_exist("%s\\ventoy\\%s", g_ventoy_dir, PLUGSON_TXZ))
572 {
573 MessageBoxW(NULL, g_msg_lang[MSGID_NO_TARXZ_TIP], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
574 return 1;
575 }
576
577 ParseCmdLine(lpCmdLine, g_sysinfo.ip, g_sysinfo.port);
578 if (g_sysinfo.ip[0] == 0)
579 {
580 strlcpy(g_sysinfo.ip, "127.0.0.1");
581 }
582 if (g_sysinfo.port[0] == 0)
583 {
584 strlcpy(g_sysinfo.port, "24681");
585 }
586
587 vlog("===============================================\n");
588 vlog("===== Ventoy Plugson %s:%s =====\n", g_sysinfo.ip, g_sysinfo.port);
589 vlog("===============================================\n");
590
591
592 ventoy_disk_init();
593 #ifndef VENTOY_SIM
594 rc = ventoy_www_init();
595 if (rc)
596 {
597 vlog("Failed to init www\n");
598 MessageBoxW(NULL, g_msg_lang[MSGID_INTERNAL_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
599
600 ventoy_disk_exit();
601 ventoy_log_exit();
602 return 1;
603 }
604 #endif
605 ventoy_http_init();
606
607 g_hInst = hInstance;
608 DialogBoxA(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc);
609
610 return 0;
611 }
612