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