]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Plugson/src/main_windows.c
1. Fix the issue that Ventoy2Disk_X64.exe can not run under altexe directory.
[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 #define UTF8_Log(fmt, wstr) \
86 {\
87 memset(TmpPathA, 0, sizeof(TmpPathA));\
88 WideCharToMultiByte(CP_UTF8, 0, wstr, -1, TmpPathA, sizeof(TmpPathA), NULL, NULL);\
89 vlog(fmt, TmpPathA);\
90 }
91
92
93 const WCHAR **g_msg_lang = NULL;
94
95 HINSTANCE g_hInst;
96
97 char g_log_file[MAX_PATH];
98 char g_cur_dir[MAX_PATH];
99
100 int ventoy_log_init(void);
101 void ventoy_log_exit(void);
102
103 static BOOL OnDestroyDialog()
104 {
105 ventoy_http_exit();
106 ventoy_disk_exit();
107 #ifndef VENTOY_SIM
108 ventoy_www_exit();
109 #endif
110 ventoy_log_exit();
111 return TRUE;
112 }
113
114
115 static void OpenURL(void)
116 {
117 int i;
118 char url[128];
119 const static char * Browsers[] =
120 {
121 "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
122 "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
123 "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe",
124 "C:\\Program Files\\Mozilla Firefox\\firefox.exe",
125 NULL
126 };
127
128 sprintf_s(url, sizeof(url), "http://%s:%s/index.html", g_sysinfo.ip, g_sysinfo.port);
129
130 if (g_ChromeFirst)
131 {
132 for (i = 0; Browsers[i] != NULL; i++)
133 {
134 if (ventoy_is_file_exist("%s", Browsers[i]))
135 {
136 ShellExecuteA(NULL, "open", Browsers[i], url, NULL, SW_SHOW);
137 return;
138 }
139 }
140 }
141
142 ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOW);
143 }
144
145
146 static void FillCombox(HWND hWnd)
147 {
148 int i = 0;
149 int num = 0;
150 const ventoy_disk *list = NULL;
151 CHAR DeviceName[256];
152
153 // delete all items
154 SendMessage(g_ComboxHwnd, CB_RESETCONTENT, 0, 0);
155
156 list = ventoy_get_disk_list(&num);
157 if (NULL == list || num <= 0)
158 {
159 return;
160 }
161
162 for (i = 0; i < num; i++)
163 {
164 sprintf_s(DeviceName, sizeof(DeviceName),
165 "%C: [%s] %s",
166 list[i].devname[0],
167 list[i].cur_capacity,
168 list[i].cur_model);
169 SendMessageA(g_ComboxHwnd, CB_ADDSTRING, 0, (LPARAM)DeviceName);
170 }
171 SendMessage(g_ComboxHwnd, CB_SETCURSEL, 0, 0);
172 }
173
174
175 static BOOL InitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
176 {
177 HICON hIcon;
178
179 g_ComboxHwnd = GetDlgItem(hWnd, IDC_COMBO1);
180 g_refresh_button = GetDlgItem(hWnd, IDC_BUTTON1);
181 g_start_button = GetDlgItem(hWnd, IDC_BUTTON2);
182 g_openlink_button = GetDlgItem(hWnd, IDC_BUTTON3);
183 g_exit_button = GetDlgItem(hWnd, IDC_BUTTON4);
184
185 hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ICON1));
186 SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
187 SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
188
189 SetWindowTextW(g_refresh_button, g_msg_lang[MSGID_BTN_REFRESH]);
190 SetWindowTextW(g_start_button, g_msg_lang[MSGID_BTN_START]);
191 SetWindowTextW(g_openlink_button, g_msg_lang[MSGID_BTN_LINK]);
192 SetWindowTextW(g_exit_button, g_msg_lang[MSGID_BTN_EXIT]);
193
194 EnableWindow(g_openlink_button, FALSE);
195
196 FillCombox(hWnd);
197
198 return TRUE;
199 }
200
201 static void VentoyStopService()
202 {
203 ventoy_http_stop();
204 }
205
206 static int VentoyStartService(int sel)
207 {
208 int rc;
209 BOOL bRet;
210 char Path[128];
211 char CurDir[MAX_PATH];
212 const ventoy_disk *disk = NULL;
213
214 vlog("VentoyStartService ...\n");
215
216 disk = ventoy_get_disk_node(sel);
217 if (disk == NULL)
218 {
219 return 1;
220 }
221
222 vlog("Start service at %C: %s %s ...\n", disk->devname[0], disk->cur_model, disk->cur_ventoy_ver);
223
224 g_cur_dir[0] = disk->devname[0];
225 g_cur_dir[1] = ':';
226 g_cur_dir[2] = '\\';
227 g_cur_dir[3] = 0;
228
229 g_sysinfo.pathcase = disk->pathcase;
230 g_sysinfo.cur_secureboot = disk->cur_secureboot;
231 g_sysinfo.cur_part_style = disk->cur_part_style;
232 strlcpy(g_sysinfo.cur_fsname, disk->cur_fsname);
233 strlcpy(g_sysinfo.cur_capacity, disk->cur_capacity);
234 strlcpy(g_sysinfo.cur_model, disk->cur_model);
235 strlcpy(g_sysinfo.cur_ventoy_ver, disk->cur_ventoy_ver);
236
237 bRet = SetCurrentDirectoryA(g_cur_dir);
238 vlog("SetCurrentDirectoryA %u <%s>\n", bRet, g_cur_dir);
239
240 CurDir[0] = 0;
241 GetCurrentDirectoryA(sizeof(CurDir), CurDir);
242 vlog("CurDir=<%s>\n", CurDir);
243
244 if (strcmp(g_cur_dir, CurDir))
245 {
246 vlog("Failed to change current directory.");
247 }
248
249 g_cur_dir[2] = 0;
250
251 if (ventoy_is_directory_exist("ventoy"))
252 {
253 if (g_sysinfo.pathcase)
254 {
255 vlog("ventoy directory already exist, check case sensitive.\n");
256 strlcpy(Path, "ventoy");
257
258 rc = ventoy_path_case(Path, 0);
259 vlog("ventoy_path_case actual path is <%s> <count:%d>\n", Path, rc);
260
261 if (rc)
262 {
263 vlog("ventoy directory case mismatch, rename<%s>--><%s>\n", Path, "ventoy");
264 if (MoveFileA(Path, "ventoy"))
265 {
266 vlog("Rename <%s>--><%s> success\n", Path, "ventoy");
267 }
268 else
269 {
270 vlog("Rename <%s>--><%s> failed %u\n", Path, "ventoy", LASTERR);
271 MessageBoxW(NULL, g_msg_lang[MSGID_RENAME_VENTOY], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
272 return 1;
273 }
274 }
275 }
276 else
277 {
278 vlog("ventoy directory already exist, no need to check case sensitive.\n");
279 }
280 }
281 else
282 {
283 if (CreateDirectoryA("ventoy", NULL))
284 {
285 vlog("Create ventoy directory success.\n");
286 }
287 else
288 {
289 vlog("Create ventoy directory failed %u.\n", LASTERR);
290 MessageBoxW(NULL, g_msg_lang[MSGID_NEW_DIR_FAIL], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
291 return 1;
292 }
293 }
294
295 return ventoy_http_start(g_sysinfo.ip, g_sysinfo.port);
296 }
297
298 INT_PTR CALLBACK DialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
299 {
300 int rc;
301 int nCurSel;
302 WORD NotifyCode;
303 WORD CtrlID;
304
305 switch (Message)
306 {
307 case WM_NOTIFY:
308 {
309 UINT code = 0;
310 UINT_PTR idFrom = 0;
311
312 if (lParam)
313 {
314 code = ((LPNMHDR)lParam)->code;
315 idFrom = ((LPNMHDR)lParam)->idFrom;
316 }
317
318 if (idFrom == IDC_SYSLINK1 && (NM_CLICK == code || NM_RETURN == code))
319 {
320 OpenURL();
321 }
322 break;
323 }
324 case WM_COMMAND:
325 {
326 NotifyCode = HIWORD(wParam);
327 CtrlID = LOWORD(wParam);
328
329 if (NotifyCode == BN_CLICKED)
330 {
331 if (CtrlID == IDC_BUTTON1)
332 {
333 if (!g_running)
334 {
335 //refresh
336 ventoy_disk_exit();
337 ventoy_disk_init();
338 FillCombox(hWnd);
339 }
340 }
341 else if (CtrlID == IDC_BUTTON2)
342 {
343 if (g_running)
344 {
345 if (IDYES == MessageBoxW(NULL, g_msg_lang[MSGID_BTN_STOP_TIP], g_msg_lang[MSGID_INFO], MB_YESNO | MB_ICONINFORMATION))
346 {
347 VentoyStopService();
348
349 g_running = FALSE;
350 SetWindowTextW(g_start_button, g_msg_lang[MSGID_BTN_START]);
351 EnableWindow(g_ComboxHwnd, TRUE);
352 EnableWindow(g_refresh_button, TRUE);
353 EnableWindow(g_openlink_button, FALSE);
354 }
355 }
356 else
357 {
358 nCurSel = (int)SendMessage(g_ComboxHwnd, CB_GETCURSEL, 0, 0);
359 if (CB_ERR != nCurSel)
360 {
361 rc = VentoyStartService(nCurSel);
362 if (rc)
363 {
364 vlog("Ventoy failed to start http server, check %s for detail\n", g_log_file);
365 MessageBoxW(NULL, g_msg_lang[MSGID_INTERNAL_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
366 }
367 else
368 {
369 g_running = TRUE;
370 SetWindowTextW(g_start_button, g_msg_lang[MSGID_BTN_STOP]);
371
372 EnableWindow(g_ComboxHwnd, FALSE);
373 EnableWindow(g_refresh_button, FALSE);
374 EnableWindow(g_openlink_button, TRUE);
375
376 OpenURL();
377 }
378 }
379 }
380 }
381 else if (CtrlID == IDC_BUTTON3)
382 {
383 if (g_running)
384 {
385 OpenURL();
386 }
387 }
388 else if (CtrlID == IDC_BUTTON4)
389 {
390 if (g_running)
391 {
392 if (IDYES != MessageBoxW(NULL, g_msg_lang[MSGID_BTN_EXIT_TIP], g_msg_lang[MSGID_INFO], MB_YESNO | MB_ICONINFORMATION))
393 {
394 return 0;
395 }
396
397 ventoy_http_stop();
398 }
399
400 OnDestroyDialog();
401 EndDialog(hWnd, 0);
402 }
403 }
404 break;
405 }
406 case WM_INITDIALOG:
407 {
408 InitDialog(hWnd, wParam, lParam);
409 break;
410 }
411 case WM_CLOSE:
412 {
413 if (g_running)
414 {
415 if (IDYES != MessageBoxW(NULL, g_msg_lang[MSGID_BTN_EXIT_TIP], g_msg_lang[MSGID_INFO], MB_YESNO | MB_ICONINFORMATION))
416 {
417 return 0;
418 }
419
420 VentoyStopService();
421 }
422
423 OnDestroyDialog();
424 EndDialog(hWnd, 0);
425 break;
426 }
427 }
428
429 return 0;
430 }
431
432 static int ParseCmdLine(LPSTR lpCmdLine, char *ip, char *port)
433 {
434 int portnum;
435 char *ipstart = ip;
436 char *pos;
437
438
439 if (!lpCmdLine)
440 {
441 return 0;
442 }
443
444 pos = strstr(lpCmdLine, "-H");
445 if (!pos)
446 {
447 pos = strstr(lpCmdLine, "-h");
448 }
449
450 if (pos)
451 {
452 pos += 2;
453 while (*pos == ' ' || *pos == '\t')
454 {
455 pos++;
456 }
457
458 while (isdigit(*pos) || *pos == '.')
459 {
460 *ipstart++ = *pos++;
461 }
462 }
463
464
465 pos = strstr(lpCmdLine, "-P");
466 if (!pos)
467 {
468 pos = strstr(lpCmdLine, "-p");
469 }
470
471 if (pos)
472 {
473 portnum = (int)strtol(pos + 3, NULL, 10);
474 sprintf_s(port, 16, "%d", portnum);
475 }
476
477 return 0;
478 }
479
480
481
482 //
483 //copy from Rufus
484 //Copyright © 2011-2021 Pete Batard <pete@akeo.ie>
485 //
486 #include <delayimp.h>
487 // For delay-loaded DLLs, use LOAD_LIBRARY_SEARCH_SYSTEM32 to avoid DLL search order hijacking.
488 FARPROC WINAPI dllDelayLoadHook(unsigned dliNotify, PDelayLoadInfo pdli)
489 {
490 if (dliNotify == dliNotePreLoadLibrary) {
491 // Windows 7 without KB2533623 does not support the LOAD_LIBRARY_SEARCH_SYSTEM32 flag.
492 // That is is OK, because the delay load handler will interrupt the NULL return value
493 // to mean that it should perform a normal LoadLibrary.
494 return (FARPROC)LoadLibraryExA(pdli->szDll, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
495 }
496 return NULL;
497 }
498
499 #if defined(_MSC_VER)
500 // By default the Windows SDK headers have a `const` while MinGW does not.
501 const
502 #endif
503 PfnDliHook __pfnDliNotifyHook2 = dllDelayLoadHook;
504
505 typedef BOOL(WINAPI* SetDefaultDllDirectories_t)(DWORD);
506 static void DllProtect(void)
507 {
508 SetDefaultDllDirectories_t pfSetDefaultDllDirectories = NULL;
509
510 // Disable loading system DLLs from the current directory (sideloading mitigation)
511 // PS: You know that official MSDN documentation for SetDllDirectory() that explicitly
512 // indicates that "If the parameter is an empty string (""), the call removes the current
513 // directory from the default DLL search order"? Yeah, that doesn't work. At all.
514 // Still, we invoke it, for platforms where the following call might actually work...
515 SetDllDirectoryA("");
516
517 // For libraries on the KnownDLLs list, the system will always load them from System32.
518 // For other DLLs we link directly to, we can delay load the DLL and use a delay load
519 // hook to load them from System32. Note that, for this to work, something like:
520 // 'somelib.dll;%(DelayLoadDLLs)' must be added to the 'Delay Loaded Dlls' option of
521 // the linker properties in Visual Studio (which means this won't work with MinGW).
522 // For all other DLLs, use SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32).
523 // Finally, we need to perform the whole gymkhana below, where we can't call on
524 // SetDefaultDllDirectories() directly, because Windows 7 doesn't have the API exposed.
525 // Also, no, Coverity, we never need to care about freeing kernel32 as a library.
526 // coverity[leaked_storage]
527
528 pfSetDefaultDllDirectories = (SetDefaultDllDirectories_t)
529 GetProcAddress(LoadLibraryW(L"kernel32.dll"), "SetDefaultDllDirectories");
530 if (pfSetDefaultDllDirectories != NULL)
531 pfSetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32);
532 }
533
534
535 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
536 {
537 int i;
538 int rc;
539 int status = 0;
540 HANDLE hMutex;
541 WCHAR* Pos = NULL;
542 WCHAR CurDir[MAX_PATH];
543 WCHAR ExePath[MAX_PATH];
544 WCHAR CurDirBk[MAX_PATH];
545 WCHAR ExePathBk[MAX_PATH];
546 CHAR TmpPathA[MAX_PATH];
547
548 UNREFERENCED_PARAMETER(hPrevInstance);
549
550 for (i = 0; i < __argc; i++)
551 {
552 if (__argv[i] && _stricmp(__argv[i], "/F") == 0)
553 {
554 g_ChromeFirst = FALSE;
555 break;
556 }
557 }
558
559 DllProtect();
560
561 if (GetUserDefaultUILanguage() == 0x0804)
562 {
563 g_sysinfo.language = LANGUAGE_CN;
564 g_msg_lang = g_msg_cn;
565 }
566 else
567 {
568 g_sysinfo.language = LANGUAGE_EN;
569 g_msg_lang = g_msg_en;
570 }
571
572 hMutex = CreateMutexA(NULL, TRUE, "PlugsonMUTEX");
573 if ((hMutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS))
574 {
575 MessageBoxW(NULL, g_msg_lang[MSGID_RUNNING_TIP], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
576 return 1;
577 }
578
579 GetCurrentDirectoryW(MAX_PATH, CurDir);
580 GetCurrentDirectoryW(MAX_PATH, CurDirBk);
581 GetModuleFileNameW(NULL, ExePath, MAX_PATH);
582 GetModuleFileNameW(NULL, ExePathBk, MAX_PATH);
583
584 for (Pos = NULL, i = 0; i < MAX_PATH && ExePath[i]; i++)
585 {
586 if (ExePath[i] == '\\' || ExePath[i] == '/')
587 {
588 Pos = ExePath + i;
589 }
590 }
591
592 if (Pos)
593 {
594 *Pos = 0;
595 if (wcscmp(CurDir, ExePath))
596 {
597 status |= 1;
598 SetCurrentDirectoryW(ExePath);
599 GetCurrentDirectoryW(MAX_PATH, CurDir);
600 }
601 else
602 {
603 status |= 2;
604 }
605 }
606
607 Pos = wcsstr(CurDir, L"\\altexe");
608 if (Pos)
609 {
610 *Pos = 0;
611 status |= 4;
612 SetCurrentDirectoryW(CurDir);
613 }
614
615
616 WideCharToMultiByte(CP_UTF8, 0, CurDir, -1, g_cur_dir, MAX_PATH, NULL, 0);
617
618 sprintf_s(g_ventoy_dir, sizeof(g_ventoy_dir), "%s", g_cur_dir);
619 sprintf_s(g_log_file, sizeof(g_log_file), "%s", LOG_FILE);
620 ventoy_log_init();
621
622 vlog("====================== Ventoy Plugson =========================\n");
623
624 UTF8_Log("Current Directory <%s>\n", CurDirBk);
625 UTF8_Log("Exe file path <%s>\n", ExePathBk);
626
627 if (status & 1)
628 {
629 UTF8_Log("Change current dir to exe <%s>\n", ExePath);
630 }
631 if (status & 2)
632 {
633 vlog("Current directory check OK.\n");
634 }
635 if (status & 4)
636 {
637 UTF8_Log("altexe detected, change current dir to <%s>\n", CurDir);
638 }
639
640
641 if (!ventoy_is_file_exist("%s\\ventoy\\%s", g_ventoy_dir, PLUGSON_TXZ))
642 {
643 MessageBoxW(NULL, g_msg_lang[MSGID_NO_TARXZ_TIP], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
644 return 1;
645 }
646
647 ParseCmdLine(lpCmdLine, g_sysinfo.ip, g_sysinfo.port);
648 if (g_sysinfo.ip[0] == 0)
649 {
650 strlcpy(g_sysinfo.ip, "127.0.0.1");
651 }
652 if (g_sysinfo.port[0] == 0)
653 {
654 strlcpy(g_sysinfo.port, "24681");
655 }
656
657 vlog("===============================================\n");
658 vlog("========= Ventoy Plugson %s:%s =========\n", g_sysinfo.ip, g_sysinfo.port);
659 vlog("===============================================\n");
660
661
662 ventoy_disk_init();
663 #ifndef VENTOY_SIM
664 rc = ventoy_www_init();
665 if (rc)
666 {
667 vlog("Failed to init www\n");
668 MessageBoxW(NULL, g_msg_lang[MSGID_INTERNAL_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
669
670 ventoy_disk_exit();
671 ventoy_log_exit();
672 return 1;
673 }
674 #endif
675 ventoy_http_init();
676
677 g_hInst = hInstance;
678 DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc);
679
680 return 0;
681 }
682