]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Vlnk/src/main_windows.c
1.1.07 release
[Ventoy.git] / Vlnk / src / main_windows.c
1 #include <Windows.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdint.h>
6 #include <time.h>
7 #include <resource.h>
8 #include <vlnk.h>
9
10 static WCHAR g_CurDirW[MAX_PATH];
11 static CHAR g_CurDirA[MAX_PATH];
12 static CHAR g_LogFile[MAX_PATH];
13 static HWND g_create_button;
14 static HWND g_parse_button;
15
16 static BOOL g_ShowHelp = FALSE;
17 static BOOL g_SaveAs = FALSE;
18 static WCHAR g_CmdInFile[MAX_PATH];
19 static WCHAR g_CmdOutFile[MAX_PATH];
20
21 typedef enum MSGID
22 {
23 MSGID_ERROR = 0,
24 MSGID_INFO,
25 MSGID_BTN_CREATE,
26 MSGID_BTN_PARSE,
27 MSGID_SRC_NONEXIST,
28 MSGID_SRC_UNSUPPORTED,
29 MSGID_FS_UNSUPPORTED,
30 MSGID_SUFFIX_UNSUPPORTED,
31 MSGID_DISK_INFO_ERR,
32 MSGID_VLNK_SUCCESS,
33 MSGID_RUNNING_TIP,
34 MSGID_CREATE_FILE_ERR,
35 MSGID_ALREADY_VLNK,
36 MSGID_INVALID_VLNK,
37 MSGID_VLNK_POINT_TO,
38 MSGID_VLNK_NO_DST,
39 MSGID_FILE_NAME_TOO_LONG,
40 MSGID_INVALID_SUFFIX,
41
42 MSGID_BUTT
43 }MSGID;
44
45
46 const WCHAR *g_msg_cn[MSGID_BUTT] =
47 {
48 L"错误",
49 L"提醒",
50 L"创建",
51 L"解析",
52 L"指定的文件不存在",
53 L"不支持为此文件创建vlnk",
54 L"不支持的文件系统",
55 L"不支持的文件后缀名",
56 L"获取磁盘信息时发生错误",
57 L"Vlnk 文件创建成功。",
58 L"请先关闭正在运行的 VentoyVlnk 程序!",
59 L"创建文件失败",
60 L"此文件已经是一个vlnk文件了!",
61 L"非法的vlnk文件!",
62 L"此 vlnk 文件指向 ",
63 L"此 vlnk 指向的文件不存在!",
64 L"文件路径太长!",
65 L"非法的vlnk文件后缀名!",
66 };
67 const WCHAR *g_msg_en[MSGID_BUTT] =
68 {
69 L"Error",
70 L"Info",
71 L"Create",
72 L"Parse",
73 L"The specified file is not exist!",
74 L"This file is not supported for vlnk",
75 L"Unsupported file system!",
76 L"Unsupported file suffix!",
77 L"Error when getting disk info",
78 L"Vlnk file successfully created!",
79 L"Please close another running VentoyVlnk instance!",
80 L"Failed to create file!",
81 L"This file is already a vlnk file!",
82 L"Invalid vlnk file!",
83 L"The vlnk file point to ",
84 L"The file pointed by the vlnk does NOT exist!",
85 L"The file full path is too long!",
86 L"Invalid vlnk file suffix!",
87 };
88
89 const WCHAR **g_msg_lang = NULL;
90
91 HINSTANCE g_hInst;
92
93 static int VtoyMessageBox
94 (
95 _In_opt_ HWND hWnd,
96 _In_opt_ LPCWSTR lpText,
97 _In_opt_ LPCWSTR lpCaption,
98 _In_ UINT uType
99 )
100 {
101 if (g_CmdInFile[0] && g_CmdOutFile[0])
102 {
103 return 0;
104 }
105
106 return MessageBox(hWnd, lpText, lpCaption, uType);
107 }
108
109 static void Log2File(const char *log)
110 {
111 time_t stamp;
112 struct tm ttm;
113 FILE *fp;
114
115 time(&stamp);
116 localtime_s(&ttm, &stamp);
117
118 fopen_s(&fp, g_LogFile, "a+");
119 if (fp)
120 {
121 fprintf_s(fp, "[%04u/%02u/%02u %02u:%02u:%02u] %s",
122 ttm.tm_year + 1900, ttm.tm_mon + 1, ttm.tm_mday,
123 ttm.tm_hour, ttm.tm_min, ttm.tm_sec, log);
124 fclose(fp);
125 }
126 }
127
128 void LogW(const WCHAR *Fmt, ...)
129 {
130 WCHAR log[512];
131 CHAR alog[2048];
132 va_list arg;
133
134 if (g_LogFile[0] == 0)
135 {
136 return;
137 }
138
139 va_start(arg, Fmt);
140 vswprintf_s(log, 512, Fmt, arg);
141 va_end(arg);
142
143 WideCharToMultiByte(CP_UTF8, 0, log, -1, alog, 2048, 0, 0);
144
145 Log2File(alog);
146 }
147
148
149 void LogA(const CHAR *Fmt, ...)
150 {
151 CHAR log[512];
152 va_list arg;
153
154 if (g_LogFile[0] == 0)
155 {
156 return;
157 }
158
159 va_start(arg, Fmt);
160 vsprintf_s(log, 512, Fmt, arg);
161 va_end(arg);
162
163 Log2File(log);
164 }
165
166 static int Utf8ToUtf16(const char* src, WCHAR * dst)
167 {
168 int size = MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, 0);
169 return MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size + 1);
170 }
171
172 static BOOL OnDestroyDialog()
173 {
174 return TRUE;
175 }
176
177
178 static BOOL InitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
179 {
180 HICON hIcon;
181
182 g_create_button = GetDlgItem(hWnd, IDC_BUTTON1);
183 g_parse_button = GetDlgItem(hWnd, IDC_BUTTON2);
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_create_button, g_msg_lang[MSGID_BTN_CREATE]);
190 SetWindowTextW(g_parse_button, g_msg_lang[MSGID_BTN_PARSE]);
191
192 return TRUE;
193 }
194
195 static int GetPhyDiskInfo(const char LogicalDrive, UINT32 *DiskSig, DISK_EXTENT *DiskExtent)
196 {
197 BOOL Ret;
198 DWORD dwSize;
199 HANDLE Handle;
200 VOLUME_DISK_EXTENTS DiskExtents;
201 CHAR PhyPath[128];
202 UINT8 SectorBuf[512];
203
204 LogA("GetPhyDiskInfo %C\n", LogicalDrive);
205
206 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\%C:", LogicalDrive);
207 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
208 if (Handle == INVALID_HANDLE_VALUE)
209 {
210 LogA("Could not open the disk %C: error:%u\n", LogicalDrive, GetLastError());
211 return 1;
212 }
213
214 Ret = DeviceIoControl(Handle,
215 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
216 NULL,
217 0,
218 &DiskExtents,
219 (DWORD)(sizeof(DiskExtents)),
220 (LPDWORD)&dwSize,
221 NULL);
222 if (!Ret || DiskExtents.NumberOfDiskExtents == 0)
223 {
224 LogA("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed, error:%u\n", GetLastError());
225 CloseHandle(Handle);
226 return 1;
227 }
228 CloseHandle(Handle);
229
230 memcpy(DiskExtent, DiskExtents.Extents, sizeof(DISK_EXTENT));
231 LogA("%C: is in PhysicalDrive%d Offset:%llu\n", LogicalDrive, DiskExtents.Extents[0].DiskNumber,
232 (ULONGLONG)(DiskExtents.Extents[0].StartingOffset.QuadPart));
233
234 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", DiskExtents.Extents[0].DiskNumber);
235 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
236 if (Handle == INVALID_HANDLE_VALUE)
237 {
238 LogA("Could not open the disk<PhysicalDrive%d>, error:%u\n", DiskExtents.Extents[0].DiskNumber, GetLastError());
239 return 1;
240 }
241
242 if (!ReadFile(Handle, SectorBuf, sizeof(SectorBuf), &dwSize, NULL))
243 {
244 LogA("ReadFile failed, dwSize:%u error:%u\n", dwSize, GetLastError());
245 CloseHandle(Handle);
246 return 1;
247 }
248
249 memcpy(DiskSig, SectorBuf + 0x1B8, 4);
250
251 CloseHandle(Handle);
252 return 0;
253 }
254
255
256 static int SaveBuffer2File(const WCHAR *Fullpath, void *Buffer, DWORD Length)
257 {
258 int rc = 1;
259 DWORD dwSize;
260 HANDLE Handle;
261
262 LogW(L"SaveBuffer2File <%ls> len:%u\n", Fullpath, Length);
263
264 Handle = CreateFileW(Fullpath, GENERIC_READ | GENERIC_WRITE,
265 FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);
266 if (Handle == INVALID_HANDLE_VALUE)
267 {
268 LogA("Could not create new file, error:%u\n", GetLastError());
269 goto End;
270 }
271
272 WriteFile(Handle, Buffer, Length, &dwSize, NULL);
273
274 rc = 0;
275
276 End:
277
278 if (Handle != INVALID_HANDLE_VALUE)
279 {
280 CloseHandle(Handle);
281 }
282
283
284 return rc;
285 }
286
287 static int DefaultVlnkDstFullPath(WCHAR *Src, WCHAR *Dir, WCHAR *Dst)
288 {
289 int i, j;
290 int len;
291 int wrlen;
292 WCHAR C;
293
294 len = (int)lstrlen(Src);
295 for (i = len - 1; i >= 0; i--)
296 {
297 if (Src[i] == '.')
298 {
299 C = Src[i];
300 Src[i] = 0;
301 wrlen = swprintf_s(Dst, MAX_PATH, L"%ls\\%ls.vlnk.%ls", Dir, Src, Src + i + 1);
302 Src[i] = C;
303
304 for (j = wrlen - (len - i); j < wrlen; j++)
305 {
306 if (Dst[j] >= 'A' && Dst[j] <= 'Z')
307 {
308 Dst[j] = 'a' + (Dst[j] - 'A');
309 }
310 }
311
312 break;
313 }
314 }
315
316 return 0;
317 }
318
319 static BOOL IsVlnkFile(WCHAR *path, ventoy_vlnk *outvlnk)
320 {
321 BOOL bRet;
322 BOOL bVlnk = FALSE;
323 DWORD dwSize;
324 LARGE_INTEGER FileSize;
325 HANDLE Handle;
326 ventoy_vlnk vlnk;
327
328 Handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
329 if (Handle == INVALID_HANDLE_VALUE)
330 {
331 LogA("Could not open this file, error:%u\n", GetLastError());
332 return FALSE;
333 }
334
335 if (!GetFileSizeEx(Handle, &FileSize))
336 {
337 LogA("Failed to get vlnk file size\n");
338 goto End;
339 }
340
341 if (FileSize.QuadPart != VLNK_FILE_LEN)
342 {
343 LogA("Invalid vlnk file length %llu\n", (unsigned long long)FileSize.QuadPart);
344 goto End;
345 }
346
347 memset(&vlnk, 0, sizeof(vlnk));
348 bRet = ReadFile(Handle, &vlnk, sizeof(vlnk), &dwSize, NULL);
349 if (bRet && CheckVlnkData(&vlnk))
350 {
351 if (outvlnk)
352 {
353 memcpy(outvlnk, &vlnk, sizeof(vlnk));
354 }
355
356 bVlnk = TRUE;
357 }
358
359 End:
360
361 if (Handle != INVALID_HANDLE_VALUE)
362 {
363 CloseHandle(Handle);
364 }
365
366 return bVlnk;
367 }
368
369
370 static BOOL VentoyGetSaveFileName(HWND hWnd, WCHAR *szFile)
371 {
372 OPENFILENAME ofn = { 0 };
373
374 ofn.lStructSize = sizeof(ofn);
375 ofn.hwndOwner = hWnd;
376 ofn.lpstrFilter = L"Vlnk File\0*.vlnk.iso;*.vlnk.img;*.vlnk.wim;*.vlnk.efi;*.vlnk.vhd;*.vlnk.vhdx;*.vlnk.vtoy;*.vlnk.dat\0";
377 ofn.nFilterIndex = 1;
378 ofn.lpstrFile = szFile;
379 ofn.nMaxFile = MAX_PATH;
380 ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
381 ofn.lpstrFileTitle = NULL;
382 ofn.nMaxFileTitle = 0;
383 ofn.lpstrInitialDir = NULL;
384
385 return GetSaveFileName(&ofn);
386 }
387
388 static BOOL IsSupportedVlnkSuffix(WCHAR *FileName)
389 {
390 int len;
391
392 len = lstrlen(FileName);
393
394 if (len > 9)
395 {
396 if (lstrcmp(FileName + len - 9, L".vlnk.iso") == 0 ||
397 lstrcmp(FileName + len - 9, L".vlnk.img") == 0 ||
398 lstrcmp(FileName + len - 9, L".vlnk.wim") == 0 ||
399 lstrcmp(FileName + len - 9, L".vlnk.vhd") == 0 ||
400 lstrcmp(FileName + len - 9, L".vlnk.efi") == 0 ||
401 lstrcmp(FileName + len - 9, L".vlnk.dat") == 0)
402 {
403 return TRUE;
404 }
405 }
406
407
408 if (len > 10)
409 {
410 if (lstrcmp(FileName + len - 10, L".vlnk.vhdx") == 0 ||
411 lstrcmp(FileName + len - 10, L".vlnk.vtoy") == 0)
412 {
413 return TRUE;
414 }
415 }
416
417 return FALSE;
418 }
419
420 static int CreateVlnk(HWND hWnd, WCHAR *Dir, WCHAR *InFile, WCHAR *OutFile)
421 {
422 int i;
423 int end;
424 int len;
425 BOOL SetOutFile = FALSE;
426 UINT32 DiskSig;
427 DISK_EXTENT DiskExtend;
428 OPENFILENAME ofn = { 0 };
429 CHAR UTF8Path[MAX_PATH];
430 WCHAR DstFullPath[MAX_PATH];
431 WCHAR szFile[MAX_PATH] = { 0 };
432 CHAR suffix[8] = { 0 };
433 CHAR Drive[8] = { 0 };
434 CHAR FsName[64] = { 0 };
435 CHAR *Buf = NULL;
436 WCHAR *Pos = NULL;
437 ventoy_vlnk *vlnk = NULL;
438
439 if (InFile)
440 {
441 wcscpy_s(szFile, MAX_PATH, InFile);
442 }
443 else
444 {
445 ofn.lStructSize = sizeof(ofn);
446 ofn.hwndOwner = hWnd;
447 ofn.lpstrFile = szFile;
448 ofn.nMaxFile = sizeof(szFile);
449 ofn.lpstrFilter = L"Vlnk Source File\0*.iso;*.img;*.wim;*.vhd;*.vhdx;*.vtoy;*.efi;*.dat\0";
450 ofn.nFilterIndex = 1;
451 ofn.lpstrFileTitle = NULL;
452 ofn.nMaxFileTitle = 0;
453 ofn.lpstrInitialDir = NULL;
454 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
455
456 if (GetOpenFileName(&ofn) != TRUE)
457 {
458 return 1;
459 }
460 }
461
462 LogW(L"Create vlnk for <%ls>\n", szFile);
463
464 len = lstrlen(szFile);
465
466 if (len < 5 || szFile[0] == '.' || szFile[1] != ':')
467 {
468 VtoyMessageBox(hWnd, g_msg_lang[MSGID_SRC_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
469 return 1;
470 }
471
472 Drive[0] = (CHAR)szFile[0];
473 Drive[1] = ':';
474 Drive[2] = '\\';
475 if (0 == GetVolumeInformationA(Drive, NULL, 0, NULL, NULL, NULL, FsName, sizeof(FsName) - 1))
476 {
477 LogA("GetVolumeInformationA failed %u\n", GetLastError());
478 return 1;
479 }
480
481 LogA("Partition filesystem of <%s> is <%s>\n", Drive, FsName);
482 if (_stricmp(FsName, "NTFS") == 0 ||
483 _stricmp(FsName, "exFAT") == 0 ||
484 _stricmp(FsName, "FAT") == 0 ||
485 _stricmp(FsName, "FAT32") == 0 ||
486 _stricmp(FsName, "FAT16") == 0 ||
487 _stricmp(FsName, "FAT12") == 0 ||
488 _stricmp(FsName, "UDF") == 0)
489 {
490 LogA("FS Check OK\n");
491 }
492 else
493 {
494 VtoyMessageBox(hWnd, g_msg_lang[MSGID_FS_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
495 return 1;
496 }
497
498
499 end = (szFile[len - 5] == '.') ? 5 : 4;
500 for (i = 0; i < end; i++)
501 {
502 suffix[i] = (CHAR)szFile[len - (end - i)];
503 }
504
505 if (!IsSupportedImgSuffix(suffix))
506 {
507 VtoyMessageBox(hWnd, g_msg_lang[MSGID_SUFFIX_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
508 return 1;
509 }
510
511 if (IsVlnkFile(szFile, NULL))
512 {
513 VtoyMessageBox(hWnd, g_msg_lang[MSGID_ALREADY_VLNK], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
514 return 1;
515 }
516
517 for (i = 0; i < MAX_PATH && szFile[i]; i++)
518 {
519 if (szFile[i] == '\\' || szFile[i] == '/')
520 {
521 Pos = szFile + i;
522 }
523 }
524
525 if (!Pos)
526 {
527 LogA("name part not found\n");
528 return 1;
529 }
530 LogW(L"File Name is <%ls>\n", Pos + 1);
531
532 memset(UTF8Path, 0, sizeof(UTF8Path));
533 WideCharToMultiByte(CP_UTF8, 0, szFile + 2, -1, UTF8Path, MAX_PATH, NULL, 0);
534
535 for (i = 0; i < MAX_PATH && UTF8Path[i]; i++)
536 {
537 if (UTF8Path[i] == '\\')
538 {
539 UTF8Path[i] = '/';
540 }
541 }
542
543 len = (int)strlen(UTF8Path);
544 if (len >= VLNK_NAME_MAX)
545 {
546 LogA("File name length %d overflow\n", len);
547 VtoyMessageBox(hWnd, g_msg_lang[MSGID_FILE_NAME_TOO_LONG], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
548 return 1;
549 }
550
551 DiskExtend.StartingOffset.QuadPart = 0;
552 if (GetPhyDiskInfo((char)szFile[0], &DiskSig, &DiskExtend))
553 {
554 VtoyMessageBox(hWnd, g_msg_lang[MSGID_DISK_INFO_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
555 return 1;
556 }
557
558
559 Buf = malloc(VLNK_FILE_LEN);
560 if (Buf)
561 {
562 memset(Buf, 0, VLNK_FILE_LEN);
563 vlnk = (ventoy_vlnk *)Buf;
564 ventoy_create_vlnk(DiskSig, (uint64_t)DiskExtend.StartingOffset.QuadPart, UTF8Path, vlnk);
565
566 if (OutFile)
567 {
568 wcscpy_s(DstFullPath, MAX_PATH, OutFile);
569 SetOutFile = TRUE;
570 }
571 else
572 {
573 DefaultVlnkDstFullPath(Pos + 1, Dir, DstFullPath);
574
575 if (g_SaveAs)
576 {
577 wcscpy_s(szFile, MAX_PATH, DstFullPath);
578 if (VentoyGetSaveFileName(hWnd, szFile))
579 {
580 if (IsSupportedVlnkSuffix(szFile))
581 {
582 wcscpy_s(DstFullPath, MAX_PATH, szFile);
583 SetOutFile = TRUE;
584 }
585 else
586 {
587 VtoyMessageBox(hWnd, g_msg_lang[MSGID_INVALID_SUFFIX], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
588 LogA("Invalid vlnk suffix\n");
589 goto end;
590 }
591 }
592 else
593 {
594 LogA("User cancel the save as diaglog, use default name\n");
595 }
596 }
597 }
598
599 LogW(L"vlnk output file path is <%ls>\n", DstFullPath);
600
601 if (SaveBuffer2File(DstFullPath, Buf, VLNK_FILE_LEN) == 0)
602 {
603 WCHAR Msg[1024];
604
605 LogW(L"Vlnk file create success <%ls>\n", DstFullPath);
606
607 if (SetOutFile)
608 {
609 swprintf_s(Msg, 1024, L"%ls\r\n\r\n%ls", g_msg_lang[MSGID_VLNK_SUCCESS], DstFullPath);
610 VtoyMessageBox(hWnd, Msg, g_msg_lang[MSGID_INFO], MB_OK | MB_ICONINFORMATION);
611 }
612 else
613 {
614 swprintf_s(Msg, 1024, L"%ls\r\n\r\n%ls", g_msg_lang[MSGID_VLNK_SUCCESS], DstFullPath + lstrlen(Dir) + 1);
615 VtoyMessageBox(hWnd, Msg, g_msg_lang[MSGID_INFO], MB_OK | MB_ICONINFORMATION);
616 }
617 }
618 else
619 {
620 LogA("Vlnk file save failed\n");
621 VtoyMessageBox(hWnd, g_msg_lang[MSGID_CREATE_FILE_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
622 }
623
624 end:
625 free(Buf);
626 }
627
628 return 0;
629 }
630
631 static CHAR GetDriveLetter(UINT32 disksig, UINT64 PartOffset)
632 {
633 CHAR Letter;
634 DWORD Drives;
635 UINT32 Sig;
636 DISK_EXTENT DiskExtent;
637
638 Letter = 'A';
639 Drives = GetLogicalDrives();
640 LogA("Logic Drives: 0x%x", Drives);
641
642 while (Drives)
643 {
644 if (Drives & 0x01)
645 {
646 Sig = 0;
647 DiskExtent.StartingOffset.QuadPart = 0;
648 if (GetPhyDiskInfo(Letter, &Sig, &DiskExtent) == 0)
649 {
650 if (Sig == disksig && DiskExtent.StartingOffset.QuadPart == PartOffset)
651 {
652 return Letter;
653 }
654 }
655 }
656
657 Drives >>= 1;
658 Letter++;
659 }
660
661 return 0;
662 }
663
664 static int ParseVlnk(HWND hWnd)
665 {
666 int i;
667 CHAR Letter;
668 ventoy_vlnk vlnk;
669 OPENFILENAME ofn = { 0 };
670 WCHAR szFile[MAX_PATH] = { 0 };
671 WCHAR szDst[MAX_PATH + 2] = { 0 };
672 WCHAR Msg[1024];
673 CHAR *suffix = NULL;
674 HANDLE hFile;
675
676 ofn.lStructSize = sizeof(ofn);
677 ofn.hwndOwner = hWnd;
678 ofn.lpstrFile = szFile;
679 ofn.nMaxFile = sizeof(szFile);
680 ofn.lpstrFilter = L"Vlnk File\0*.vlnk.iso;*.vlnk.img;*.vlnk.wim;*.vlnk.efi;*.vlnk.vhd;*.vlnk.vhdx;*.vlnk.vtoy;*.vlnk.dat\0";
681 ofn.nFilterIndex = 1;
682 ofn.lpstrFileTitle = NULL;
683 ofn.nMaxFileTitle = 0;
684 ofn.lpstrInitialDir = NULL;
685 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
686
687 if (GetOpenFileName(&ofn) != TRUE)
688 {
689 return 1;
690 }
691
692 LogW(L"Parse vlnk for <%ls>\n", szFile);
693
694 if (!IsVlnkFile(szFile, &vlnk))
695 {
696 VtoyMessageBox(hWnd, g_msg_lang[MSGID_INVALID_VLNK], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
697 return 1;
698 }
699
700 for (i = 0; i < sizeof(vlnk.filepath) && vlnk.filepath[i]; i++)
701 {
702 if (vlnk.filepath[i] == '.')
703 {
704 suffix = vlnk.filepath + i;
705 }
706 }
707
708 if (!IsSupportedImgSuffix(suffix))
709 {
710 VtoyMessageBox(hWnd, g_msg_lang[MSGID_SUFFIX_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
711 return 1;
712 }
713
714 Utf8ToUtf16(vlnk.filepath, szDst + 2);
715 for (i = 2; i < MAX_PATH && szDst[i]; i++)
716 {
717 if (szDst[i] == '/')
718 {
719 szDst[i] = '\\';
720 }
721 }
722
723
724 Letter = GetDriveLetter(vlnk.disk_signature, vlnk.part_offset);
725 if (Letter == 0)
726 {
727 VtoyMessageBox(hWnd, g_msg_lang[MSGID_VLNK_NO_DST], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
728 return 1;
729 }
730
731 szDst[0] = toupper(Letter);
732 szDst[1] = ':';
733 LogW(L"vlnk dst is %ls\n", szDst);
734
735 hFile = CreateFileW(szDst, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
736 if (INVALID_HANDLE_VALUE == hFile)
737 {
738 VtoyMessageBox(hWnd, g_msg_lang[MSGID_VLNK_NO_DST], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
739 return 1;
740 }
741 CloseHandle(hFile);
742
743 swprintf_s(Msg, 1024, L"%ls %ls", g_msg_lang[MSGID_VLNK_POINT_TO], szDst);
744 VtoyMessageBox(hWnd, Msg, g_msg_lang[MSGID_INFO], MB_OK | MB_ICONINFORMATION);
745
746 return 0;
747 }
748
749 INT_PTR CALLBACK DialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
750 {
751 WORD NotifyCode;
752 WORD CtrlID;
753
754 switch (Message)
755 {
756 case WM_COMMAND:
757 {
758 NotifyCode = HIWORD(wParam);
759 CtrlID = LOWORD(wParam);
760
761 if (NotifyCode == BN_CLICKED)
762 {
763 if (CtrlID == IDC_BUTTON1)
764 {
765 EnableWindow(g_create_button, FALSE);
766 CreateVlnk(hWnd, g_CurDirW, NULL, NULL);
767 EnableWindow(g_create_button, TRUE);
768 }
769 else if (CtrlID == IDC_BUTTON2)
770 {
771 EnableWindow(g_parse_button, FALSE);
772 ParseVlnk(hWnd);
773 EnableWindow(g_parse_button, TRUE);
774 }
775 }
776 break;
777 }
778 case WM_INITDIALOG:
779 {
780 InitDialog(hWnd, wParam, lParam);
781 break;
782 }
783 case WM_CLOSE:
784 {
785 OnDestroyDialog();
786 EndDialog(hWnd, 0);
787 }
788 }
789
790 return 0;
791 }
792
793 static int ParseCmdLine(LPSTR lpCmdLine)
794 {
795 int i;
796 int argc = 0;
797 LPWSTR *lpszArgv = NULL;
798
799 lpszArgv = CommandLineToArgvW(GetCommandLineW(), &argc);
800
801 for (i = 0; i < argc; i++)
802 {
803 if (lstrcmp(lpszArgv[i], L"-q") == 0 || lstrcmp(lpszArgv[i], L"-Q") == 0)
804 {
805 g_LogFile[0] = 0;
806 }
807 else if (lstrcmp(lpszArgv[i], L"-h") == 0 || lstrcmp(lpszArgv[i], L"-H") == 0)
808 {
809 g_ShowHelp = TRUE;
810 }
811 else if (lstrcmp(lpszArgv[i], L"-s") == 0 || lstrcmp(lpszArgv[i], L"-S") == 0)
812 {
813 g_SaveAs = TRUE;
814 }
815 else if (lstrcmp(lpszArgv[i], L"-i") == 0 || lstrcmp(lpszArgv[i], L"-I") == 0)
816 {
817 if (i + 1 < argc)
818 {
819 wcscpy_s(g_CmdInFile, MAX_PATH, lpszArgv[i + 1]);
820 }
821 }
822 else if (lstrcmp(lpszArgv[i], L"-o") == 0 || lstrcmp(lpszArgv[i], L"-O") == 0)
823 {
824 if (i + 1 < argc)
825 {
826 wcscpy_s(g_CmdOutFile, MAX_PATH, lpszArgv[i + 1]);
827 }
828 }
829 }
830
831 return argc;
832 }
833
834
835 //
836 //copy from Rufus
837 //Copyright © 2011-2021 Pete Batard <pete@akeo.ie>
838 //
839 #include <delayimp.h>
840 // For delay-loaded DLLs, use LOAD_LIBRARY_SEARCH_SYSTEM32 to avoid DLL search order hijacking.
841 FARPROC WINAPI dllDelayLoadHook(unsigned dliNotify, PDelayLoadInfo pdli)
842 {
843 if (dliNotify == dliNotePreLoadLibrary) {
844 // Windows 7 without KB2533623 does not support the LOAD_LIBRARY_SEARCH_SYSTEM32 flag.
845 // That is is OK, because the delay load handler will interrupt the NULL return value
846 // to mean that it should perform a normal LoadLibrary.
847 return (FARPROC)LoadLibraryExA(pdli->szDll, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
848 }
849 return NULL;
850 }
851
852 #if defined(_MSC_VER)
853 // By default the Windows SDK headers have a `const` while MinGW does not.
854 const
855 #endif
856 PfnDliHook __pfnDliNotifyHook2 = dllDelayLoadHook;
857
858 typedef BOOL(WINAPI *SetDefaultDllDirectories_t)(DWORD);
859 static void DllProtect(void)
860 {
861 SetDefaultDllDirectories_t pfSetDefaultDllDirectories = NULL;
862
863 // Disable loading system DLLs from the current directory (sideloading mitigation)
864 // PS: You know that official MSDN documentation for SetDllDirectory() that explicitly
865 // indicates that "If the parameter is an empty string (""), the call removes the current
866 // directory from the default DLL search order"? Yeah, that doesn't work. At all.
867 // Still, we invoke it, for platforms where the following call might actually work...
868 SetDllDirectoryA("");
869
870 // For libraries on the KnownDLLs list, the system will always load them from System32.
871 // For other DLLs we link directly to, we can delay load the DLL and use a delay load
872 // hook to load them from System32. Note that, for this to work, something like:
873 // 'somelib.dll;%(DelayLoadDLLs)' must be added to the 'Delay Loaded Dlls' option of
874 // the linker properties in Visual Studio (which means this won't work with MinGW).
875 // For all other DLLs, use SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32).
876 // Finally, we need to perform the whole gymkhana below, where we can't call on
877 // SetDefaultDllDirectories() directly, because Windows 7 doesn't have the API exposed.
878 // Also, no, Coverity, we never need to care about freeing kernel32 as a library.
879 // coverity[leaked_storage]
880
881 pfSetDefaultDllDirectories = (SetDefaultDllDirectories_t)
882 GetProcAddress(LoadLibraryW(L"kernel32.dll"), "SetDefaultDllDirectories");
883 if (pfSetDefaultDllDirectories != NULL)
884 pfSetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32);
885 }
886
887 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
888 {
889 DWORD dwAttrib;
890 HANDLE hMutex;
891
892 UNREFERENCED_PARAMETER(hPrevInstance);
893
894 DllProtect();
895
896 if (GetUserDefaultUILanguage() == 0x0804)
897 {
898 g_msg_lang = g_msg_cn;
899 }
900 else
901 {
902 g_msg_lang = g_msg_en;
903 }
904
905 hMutex = CreateMutexA(NULL, TRUE, "VtoyVlnkMUTEX");
906 if ((hMutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS))
907 {
908 MessageBoxW(NULL, g_msg_lang[MSGID_RUNNING_TIP], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
909 return 1;
910 }
911
912 GetCurrentDirectoryA(MAX_PATH, g_CurDirA);
913 GetCurrentDirectoryW(MAX_PATH, g_CurDirW);
914 sprintf_s(g_LogFile, sizeof(g_LogFile), "%s\\VentoyVlnk.log", g_CurDirA);
915
916 ParseCmdLine(lpCmdLine);
917
918 g_hInst = hInstance;
919
920 if (g_ShowHelp)
921 {
922 VtoyMessageBox(NULL, L"VentoyVlnk.exe CMD\r\n -i Input file path\r\n -o Output vlnk file path\r\n -q Quite mode (no log)", L"Tip", MB_OK);
923 return 0;
924 }
925 else if (g_CmdInFile[0] && g_CmdOutFile[0])
926 {
927 LogA("========= VentoyVlnk Cmdline Mode =========\n");
928
929 dwAttrib = GetFileAttributesW(g_CmdInFile);
930 if (dwAttrib == INVALID_FILE_ATTRIBUTES || (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))
931 {
932 LogW(L"File <<%ls>> does not exist!\n", g_CmdInFile);
933 VtoyMessageBox(NULL, g_msg_lang[MSGID_SRC_NONEXIST], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
934 return 1;
935 }
936
937 if (!IsSupportedVlnkSuffix(g_CmdOutFile))
938 {
939 LogW(L"File <<%ls>> contains invalid vlnk suffix!\n", g_CmdOutFile);
940 VtoyMessageBox(NULL, g_msg_lang[MSGID_INVALID_SUFFIX], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
941 return 1;
942 }
943
944 return CreateVlnk(NULL, g_CurDirW, g_CmdInFile, g_CmdOutFile);
945 }
946 else
947 {
948 LogA("========= VentoyVlnk GUI Mode =========\n");
949
950 DialogBoxA(hInstance, MAKEINTRESOURCEA(IDD_DIALOG1), NULL, DialogProc);
951 return 0;
952 }
953 }