]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Vlnk/src/main_windows.c
Add commad line option -s in VentoyVlnk.exe.
[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
41 MSGID_BUTT
42 }MSGID;
43
44
45 const WCHAR *g_msg_cn[MSGID_BUTT] =
46 {
47 L"´íÎó",
48 L"ÌáÐÑ",
49 L"´´½¨",
50 L"½âÎö",
51 L"Ö¸¶¨µÄÎļþ²»´æÔÚ",
52 L"²»Ö§³ÖΪ´ËÎļþ´´½¨vlnk",
53 L"²»Ö§³ÖµÄÎļþϵͳ",
54 L"²»Ö§³ÖµÄÎļþºó׺Ãû",
55 L"»ñÈ¡´ÅÅÌÐÅϢʱ·¢Éú´íÎó",
56 L"Vlnk Îļþ´´½¨³É¹¦¡£",
57 L"ÇëÏȹرÕÕýÔÚÔËÐÐµÄ VentoyVlnk ³ÌÐò£¡",
58 L"´´½¨Îļþʧ°Ü",
59 L"´ËÎļþÒѾ­ÊÇÒ»¸övlnkÎļþÁË£¡",
60 L"·Ç·¨µÄvlnkÎļþ!",
61 L"´Ë vlnk ÎļþÖ¸Ïò ",
62 L"´Ë vlnk Ö¸ÏòµÄÎļþ²»´æÔÚ£¡",
63 L"Îļþ·¾¶Ì«³¤£¡",
64 };
65 const WCHAR *g_msg_en[MSGID_BUTT] =
66 {
67 L"Error",
68 L"Info",
69 L"Create",
70 L"Parse",
71 L"The specified file is not exist!",
72 L"This file is not supported for vlnk",
73 L"Unsupported file system!",
74 L"Unsupported file suffix!",
75 L"Error when getting disk info",
76 L"Vlnk file successfully created!",
77 L"Please close another running VentoyVlnk instance!",
78 L"Failed to create file!",
79 L"This file is already a vlnk file!",
80 L"Invalid vlnk file!",
81 L"The vlnk file point to ",
82 L"The file pointed by the vlnk does NOT exist!",
83 L"The file full path is too long!",
84 };
85
86 const WCHAR **g_msg_lang = NULL;
87
88 HINSTANCE g_hInst;
89
90 static int VtoyMessageBox
91 (
92 _In_opt_ HWND hWnd,
93 _In_opt_ LPCWSTR lpText,
94 _In_opt_ LPCWSTR lpCaption,
95 _In_ UINT uType
96 )
97 {
98 if (g_CmdInFile[0] && g_CmdOutFile[0])
99 {
100 return 0;
101 }
102
103 return MessageBox(hWnd, lpText, lpCaption, uType);
104 }
105
106 static void Log2File(const char *log)
107 {
108 time_t stamp;
109 struct tm ttm;
110 FILE *fp;
111
112 time(&stamp);
113 localtime_s(&ttm, &stamp);
114
115 fopen_s(&fp, g_LogFile, "a+");
116 if (fp)
117 {
118 fprintf_s(fp, "[%04u/%02u/%02u %02u:%02u:%02u] %s",
119 ttm.tm_year + 1900, ttm.tm_mon + 1, ttm.tm_mday,
120 ttm.tm_hour, ttm.tm_min, ttm.tm_sec, log);
121 fclose(fp);
122 }
123 }
124
125 void LogW(const WCHAR *Fmt, ...)
126 {
127 WCHAR log[512];
128 CHAR alog[2048];
129 va_list arg;
130
131 if (g_LogFile[0] == 0)
132 {
133 return;
134 }
135
136 va_start(arg, Fmt);
137 vswprintf_s(log, 512, Fmt, arg);
138 va_end(arg);
139
140 WideCharToMultiByte(CP_UTF8, 0, log, -1, alog, 2048, 0, 0);
141
142 Log2File(alog);
143 }
144
145
146 void LogA(const CHAR *Fmt, ...)
147 {
148 CHAR log[512];
149 va_list arg;
150
151 if (g_LogFile[0] == 0)
152 {
153 return;
154 }
155
156 va_start(arg, Fmt);
157 vsprintf_s(log, 512, Fmt, arg);
158 va_end(arg);
159
160 Log2File(log);
161 }
162
163 static int Utf8ToUtf16(const char* src, WCHAR * dst)
164 {
165 int size = MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, 0);
166 return MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size + 1);
167 }
168
169 static BOOL OnDestroyDialog()
170 {
171 return TRUE;
172 }
173
174
175 static BOOL InitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
176 {
177 HICON hIcon;
178
179 g_create_button = GetDlgItem(hWnd, IDC_BUTTON1);
180 g_parse_button = GetDlgItem(hWnd, IDC_BUTTON2);
181
182 hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ICON1));
183 SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
184 SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
185
186 SetWindowTextW(g_create_button, g_msg_lang[MSGID_BTN_CREATE]);
187 SetWindowTextW(g_parse_button, g_msg_lang[MSGID_BTN_PARSE]);
188
189 return TRUE;
190 }
191
192 static int GetPhyDiskInfo(const char LogicalDrive, UINT32 *DiskSig, DISK_EXTENT *DiskExtent)
193 {
194 BOOL Ret;
195 DWORD dwSize;
196 HANDLE Handle;
197 VOLUME_DISK_EXTENTS DiskExtents;
198 CHAR PhyPath[128];
199 UINT8 SectorBuf[512];
200
201 LogA("GetPhyDiskInfo %C\n", LogicalDrive);
202
203 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\%C:", LogicalDrive);
204 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
205 if (Handle == INVALID_HANDLE_VALUE)
206 {
207 LogA("Could not open the disk %C: error:%u\n", LogicalDrive, GetLastError());
208 return 1;
209 }
210
211 Ret = DeviceIoControl(Handle,
212 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
213 NULL,
214 0,
215 &DiskExtents,
216 (DWORD)(sizeof(DiskExtents)),
217 (LPDWORD)&dwSize,
218 NULL);
219 if (!Ret || DiskExtents.NumberOfDiskExtents == 0)
220 {
221 LogA("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed, error:%u\n", GetLastError());
222 CloseHandle(Handle);
223 return 1;
224 }
225 CloseHandle(Handle);
226
227 memcpy(DiskExtent, DiskExtents.Extents, sizeof(DISK_EXTENT));
228 LogA("%C: is in PhysicalDrive%d Offset:%llu\n", LogicalDrive, DiskExtents.Extents[0].DiskNumber,
229 (ULONGLONG)(DiskExtents.Extents[0].StartingOffset.QuadPart));
230
231 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", DiskExtents.Extents[0].DiskNumber);
232 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
233 if (Handle == INVALID_HANDLE_VALUE)
234 {
235 LogA("Could not open the disk<PhysicalDrive%d>, error:%u\n", DiskExtents.Extents[0].DiskNumber, GetLastError());
236 return 1;
237 }
238
239 if (!ReadFile(Handle, SectorBuf, sizeof(SectorBuf), &dwSize, NULL))
240 {
241 LogA("ReadFile failed, dwSize:%u error:%u\n", dwSize, GetLastError());
242 CloseHandle(Handle);
243 return 1;
244 }
245
246 memcpy(DiskSig, SectorBuf + 0x1B8, 4);
247
248 CloseHandle(Handle);
249 return 0;
250 }
251
252
253 static int SaveBuffer2File(const WCHAR *Fullpath, void *Buffer, DWORD Length)
254 {
255 int rc = 1;
256 DWORD dwSize;
257 HANDLE Handle;
258
259 LogW(L"SaveBuffer2File <%ls> len:%u\n", Fullpath, Length);
260
261 Handle = CreateFileW(Fullpath, GENERIC_READ | GENERIC_WRITE,
262 FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);
263 if (Handle == INVALID_HANDLE_VALUE)
264 {
265 LogA("Could not create new file, error:%u\n", GetLastError());
266 goto End;
267 }
268
269 WriteFile(Handle, Buffer, Length, &dwSize, NULL);
270
271 rc = 0;
272
273 End:
274
275 if (Handle != INVALID_HANDLE_VALUE)
276 {
277 CloseHandle(Handle);
278 }
279
280
281 return rc;
282 }
283
284 static int DefaultVlnkDstFullPath(WCHAR *Src, WCHAR *Dir, WCHAR *Dst)
285 {
286 int i, j;
287 int len;
288 int wrlen;
289 WCHAR C;
290
291 len = (int)lstrlen(Src);
292 for (i = len - 1; i >= 0; i--)
293 {
294 if (Src[i] == '.')
295 {
296 C = Src[i];
297 Src[i] = 0;
298 wrlen = swprintf_s(Dst, MAX_PATH, L"%ls\\%ls.vlnk.%ls", Dir, Src, Src + i + 1);
299 Src[i] = C;
300
301 for (j = wrlen - (len - i); j < wrlen; j++)
302 {
303 if (Dst[j] >= 'A' && Dst[j] <= 'Z')
304 {
305 Dst[j] = 'a' + (Dst[j] - 'A');
306 }
307 }
308
309 break;
310 }
311 }
312
313 return 0;
314 }
315
316 static BOOL IsVlnkFile(WCHAR *path, ventoy_vlnk *outvlnk)
317 {
318 BOOL bRet;
319 BOOL bVlnk = FALSE;
320 DWORD dwSize;
321 LARGE_INTEGER FileSize;
322 HANDLE Handle;
323 ventoy_vlnk vlnk;
324
325 Handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
326 if (Handle == INVALID_HANDLE_VALUE)
327 {
328 LogA("Could not open this file, error:%u\n", GetLastError());
329 return FALSE;
330 }
331
332 if (!GetFileSizeEx(Handle, &FileSize))
333 {
334 LogA("Failed to get vlnk file size\n");
335 goto End;
336 }
337
338 if (FileSize.QuadPart != VLNK_FILE_LEN)
339 {
340 LogA("Invalid vlnk file length %llu\n", (unsigned long long)FileSize.QuadPart);
341 goto End;
342 }
343
344 memset(&vlnk, 0, sizeof(vlnk));
345 bRet = ReadFile(Handle, &vlnk, sizeof(vlnk), &dwSize, NULL);
346 if (bRet && CheckVlnkData(&vlnk))
347 {
348 if (outvlnk)
349 {
350 memcpy(outvlnk, &vlnk, sizeof(vlnk));
351 }
352
353 bVlnk = TRUE;
354 }
355
356 End:
357
358 if (Handle != INVALID_HANDLE_VALUE)
359 {
360 CloseHandle(Handle);
361 }
362
363 return bVlnk;
364 }
365
366
367 static BOOL VentoyGetSaveFileName(HWND hWnd, WCHAR *szFile)
368 {
369 OPENFILENAME ofn = { 0 };
370
371 ofn.lStructSize = sizeof(ofn);
372 ofn.hwndOwner = hWnd;
373 ofn.lpstrFilter = L"Vlnk File\0*.vlnk.iso;*.vlnk.img;*.vlnk.wim;*.vlnk.efi;*.vlnk.vhd;*.vlnk.vhdx;*.vlnk.vtoy;*.vlnk.dat\0";
374 ofn.nFilterIndex = 1;
375 ofn.lpstrFile = szFile;
376 ofn.nMaxFile = MAX_PATH;
377 ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
378 ofn.lpstrFileTitle = NULL;
379 ofn.nMaxFileTitle = 0;
380 ofn.lpstrInitialDir = NULL;
381
382 return GetSaveFileName(&ofn);
383 }
384
385 static int CreateVlnk(HWND hWnd, WCHAR *Dir, WCHAR *InFile, WCHAR *OutFile)
386 {
387 int i;
388 int end;
389 int len;
390 BOOL SetOutFile = FALSE;
391 UINT32 DiskSig;
392 DISK_EXTENT DiskExtend;
393 OPENFILENAME ofn = { 0 };
394 CHAR UTF8Path[MAX_PATH];
395 WCHAR DstFullPath[MAX_PATH];
396 WCHAR szFile[MAX_PATH] = { 0 };
397 CHAR suffix[8] = { 0 };
398 CHAR Drive[8] = { 0 };
399 CHAR FsName[64] = { 0 };
400 CHAR *Buf = NULL;
401 WCHAR *Pos = NULL;
402 ventoy_vlnk *vlnk = NULL;
403
404 if (InFile)
405 {
406 wcscpy_s(szFile, MAX_PATH, InFile);
407 }
408 else
409 {
410 ofn.lStructSize = sizeof(ofn);
411 ofn.hwndOwner = hWnd;
412 ofn.lpstrFile = szFile;
413 ofn.nMaxFile = sizeof(szFile);
414 ofn.lpstrFilter = L"Vlnk Source File\0*.iso;*.img;*.wim;*.vhd;*.vhdx;*.vtoy;*.efi;*.dat\0";
415 ofn.nFilterIndex = 1;
416 ofn.lpstrFileTitle = NULL;
417 ofn.nMaxFileTitle = 0;
418 ofn.lpstrInitialDir = NULL;
419 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
420
421 if (GetOpenFileName(&ofn) != TRUE)
422 {
423 return 1;
424 }
425 }
426
427 LogW(L"Create vlnk for <%ls>\n", szFile);
428
429 len = lstrlen(szFile);
430
431 if (len < 5 || szFile[0] == '.' || szFile[1] != ':')
432 {
433 VtoyMessageBox(hWnd, g_msg_lang[MSGID_SRC_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
434 return 1;
435 }
436
437 Drive[0] = (CHAR)szFile[0];
438 Drive[1] = ':';
439 Drive[2] = '\\';
440 if (0 == GetVolumeInformationA(Drive, NULL, 0, NULL, NULL, NULL, FsName, sizeof(FsName) - 1))
441 {
442 LogA("GetVolumeInformationA failed %u\n", GetLastError());
443 return 1;
444 }
445
446 LogA("Partition filesystem of <%s> is <%s>\n", Drive, FsName);
447 if (_stricmp(FsName, "NTFS") == 0 ||
448 _stricmp(FsName, "exFAT") == 0 ||
449 _stricmp(FsName, "FAT") == 0 ||
450 _stricmp(FsName, "FAT32") == 0 ||
451 _stricmp(FsName, "FAT16") == 0 ||
452 _stricmp(FsName, "FAT12") == 0 ||
453 _stricmp(FsName, "UDF") == 0)
454 {
455 LogA("FS Check OK\n");
456 }
457 else
458 {
459 VtoyMessageBox(hWnd, g_msg_lang[MSGID_FS_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
460 return 1;
461 }
462
463
464 end = (szFile[len - 5] == '.') ? 5 : 4;
465 for (i = 0; i < end; i++)
466 {
467 suffix[i] = (CHAR)szFile[len - (end - i)];
468 }
469
470 if (!IsSupportedImgSuffix(suffix))
471 {
472 VtoyMessageBox(hWnd, g_msg_lang[MSGID_SUFFIX_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
473 return 1;
474 }
475
476 if (IsVlnkFile(szFile, NULL))
477 {
478 VtoyMessageBox(hWnd, g_msg_lang[MSGID_ALREADY_VLNK], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
479 return 1;
480 }
481
482 for (i = 0; i < MAX_PATH && szFile[i]; i++)
483 {
484 if (szFile[i] == '\\' || szFile[i] == '/')
485 {
486 Pos = szFile + i;
487 }
488 }
489
490 if (!Pos)
491 {
492 LogA("name part not found\n");
493 return 1;
494 }
495 LogW(L"File Name is <%ls>\n", Pos + 1);
496
497 memset(UTF8Path, 0, sizeof(UTF8Path));
498 WideCharToMultiByte(CP_UTF8, 0, szFile + 2, -1, UTF8Path, MAX_PATH, NULL, 0);
499
500 for (i = 0; i < MAX_PATH && UTF8Path[i]; i++)
501 {
502 if (UTF8Path[i] == '\\')
503 {
504 UTF8Path[i] = '/';
505 }
506 }
507
508 len = (int)strlen(UTF8Path);
509 if (len >= VLNK_NAME_MAX)
510 {
511 LogA("File name length %d overflow\n", len);
512 VtoyMessageBox(hWnd, g_msg_lang[MSGID_FILE_NAME_TOO_LONG], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
513 return 1;
514 }
515
516 DiskExtend.StartingOffset.QuadPart = 0;
517 if (GetPhyDiskInfo((char)szFile[0], &DiskSig, &DiskExtend))
518 {
519 VtoyMessageBox(hWnd, g_msg_lang[MSGID_DISK_INFO_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
520 return 1;
521 }
522
523
524 Buf = malloc(VLNK_FILE_LEN);
525 if (Buf)
526 {
527 memset(Buf, 0, VLNK_FILE_LEN);
528 vlnk = (ventoy_vlnk *)Buf;
529 ventoy_create_vlnk(DiskSig, (uint64_t)DiskExtend.StartingOffset.QuadPart, UTF8Path, vlnk);
530
531 if (OutFile)
532 {
533 wcscpy_s(DstFullPath, MAX_PATH, OutFile);
534 SetOutFile = TRUE;
535 }
536 else
537 {
538 DefaultVlnkDstFullPath(Pos + 1, Dir, DstFullPath);
539
540 if (g_SaveAs)
541 {
542 wcscpy_s(szFile, MAX_PATH, DstFullPath);
543 if (VentoyGetSaveFileName(hWnd, szFile))
544 {
545 wcscpy_s(DstFullPath, MAX_PATH, szFile);
546 SetOutFile = TRUE;
547 }
548 else
549 {
550 LogA("User cancel the save as diaglog, use default name\n");
551 }
552 }
553 }
554
555 LogW(L"vlnk output file path is <%ls>\n", DstFullPath);
556
557 if (SaveBuffer2File(DstFullPath, Buf, VLNK_FILE_LEN) == 0)
558 {
559 WCHAR Msg[1024];
560
561 LogW(L"Vlnk file create success <%ls>\n", DstFullPath);
562
563 if (SetOutFile)
564 {
565 swprintf_s(Msg, 1024, L"%ls\r\n\r\n%ls", g_msg_lang[MSGID_VLNK_SUCCESS], DstFullPath);
566 VtoyMessageBox(hWnd, Msg, g_msg_lang[MSGID_INFO], MB_OK | MB_ICONINFORMATION);
567 }
568 else
569 {
570 swprintf_s(Msg, 1024, L"%ls\r\n\r\n%ls", g_msg_lang[MSGID_VLNK_SUCCESS], DstFullPath + lstrlen(Dir) + 1);
571 VtoyMessageBox(hWnd, Msg, g_msg_lang[MSGID_INFO], MB_OK | MB_ICONINFORMATION);
572 }
573 }
574 else
575 {
576 LogA("Vlnk file save failed\n");
577 VtoyMessageBox(hWnd, g_msg_lang[MSGID_CREATE_FILE_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
578 }
579
580 free(Buf);
581 }
582
583 return 0;
584 }
585
586 static CHAR GetDriveLetter(UINT32 disksig, UINT64 PartOffset)
587 {
588 CHAR Letter;
589 DWORD Drives;
590 UINT32 Sig;
591 DISK_EXTENT DiskExtent;
592
593 Letter = 'A';
594 Drives = GetLogicalDrives();
595 LogA("Logic Drives: 0x%x", Drives);
596
597 while (Drives)
598 {
599 if (Drives & 0x01)
600 {
601 Sig = 0;
602 DiskExtent.StartingOffset.QuadPart = 0;
603 if (GetPhyDiskInfo(Letter, &Sig, &DiskExtent) == 0)
604 {
605 if (Sig == disksig && DiskExtent.StartingOffset.QuadPart == PartOffset)
606 {
607 return Letter;
608 }
609 }
610 }
611
612 Drives >>= 1;
613 Letter++;
614 }
615
616 return 0;
617 }
618
619 static int ParseVlnk(HWND hWnd)
620 {
621 int i;
622 CHAR Letter;
623 ventoy_vlnk vlnk;
624 OPENFILENAME ofn = { 0 };
625 WCHAR szFile[MAX_PATH] = { 0 };
626 WCHAR szDst[MAX_PATH + 2] = { 0 };
627 WCHAR Msg[1024];
628 CHAR *suffix = NULL;
629 HANDLE hFile;
630
631 ofn.lStructSize = sizeof(ofn);
632 ofn.hwndOwner = hWnd;
633 ofn.lpstrFile = szFile;
634 ofn.nMaxFile = sizeof(szFile);
635 ofn.lpstrFilter = L"Vlnk File\0*.vlnk.iso;*.vlnk.img;*.vlnk.wim;*.vlnk.efi;*.vlnk.vhd;*.vlnk.vhdx;*.vlnk.vtoy;*.vlnk.dat\0";
636 ofn.nFilterIndex = 1;
637 ofn.lpstrFileTitle = NULL;
638 ofn.nMaxFileTitle = 0;
639 ofn.lpstrInitialDir = NULL;
640 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
641
642 if (GetOpenFileName(&ofn) != TRUE)
643 {
644 return 1;
645 }
646
647 LogW(L"Parse vlnk for <%ls>\n", szFile);
648
649 if (!IsVlnkFile(szFile, &vlnk))
650 {
651 VtoyMessageBox(hWnd, g_msg_lang[MSGID_INVALID_VLNK], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
652 return 1;
653 }
654
655 for (i = 0; i < sizeof(vlnk.filepath) && vlnk.filepath[i]; i++)
656 {
657 if (vlnk.filepath[i] == '.')
658 {
659 suffix = vlnk.filepath + i;
660 }
661 }
662
663 if (!IsSupportedImgSuffix(suffix))
664 {
665 VtoyMessageBox(hWnd, g_msg_lang[MSGID_SUFFIX_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
666 return 1;
667 }
668
669 Utf8ToUtf16(vlnk.filepath, szDst + 2);
670 for (i = 2; i < MAX_PATH && szDst[i]; i++)
671 {
672 if (szDst[i] == '/')
673 {
674 szDst[i] = '\\';
675 }
676 }
677
678
679 Letter = GetDriveLetter(vlnk.disk_signature, vlnk.part_offset);
680 if (Letter == 0)
681 {
682 VtoyMessageBox(hWnd, g_msg_lang[MSGID_VLNK_NO_DST], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
683 return 1;
684 }
685
686 szDst[0] = toupper(Letter);
687 szDst[1] = ':';
688 LogW(L"vlnk dst is %ls\n", szDst);
689
690 hFile = CreateFileW(szDst, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
691 if (INVALID_HANDLE_VALUE == hFile)
692 {
693 VtoyMessageBox(hWnd, g_msg_lang[MSGID_VLNK_NO_DST], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
694 return 1;
695 }
696 CloseHandle(hFile);
697
698 swprintf_s(Msg, 1024, L"%ls %ls", g_msg_lang[MSGID_VLNK_POINT_TO], szDst);
699 VtoyMessageBox(hWnd, Msg, g_msg_lang[MSGID_INFO], MB_OK | MB_ICONINFORMATION);
700
701 return 0;
702 }
703
704 INT_PTR CALLBACK DialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
705 {
706 WORD NotifyCode;
707 WORD CtrlID;
708
709 switch (Message)
710 {
711 case WM_COMMAND:
712 {
713 NotifyCode = HIWORD(wParam);
714 CtrlID = LOWORD(wParam);
715
716 if (NotifyCode == BN_CLICKED)
717 {
718 if (CtrlID == IDC_BUTTON1)
719 {
720 EnableWindow(g_create_button, FALSE);
721 CreateVlnk(hWnd, g_CurDirW, NULL, NULL);
722 EnableWindow(g_create_button, TRUE);
723 }
724 else if (CtrlID == IDC_BUTTON2)
725 {
726 EnableWindow(g_parse_button, FALSE);
727 ParseVlnk(hWnd);
728 EnableWindow(g_parse_button, TRUE);
729 }
730 }
731 break;
732 }
733 case WM_INITDIALOG:
734 {
735 InitDialog(hWnd, wParam, lParam);
736 break;
737 }
738 case WM_CLOSE:
739 {
740 OnDestroyDialog();
741 EndDialog(hWnd, 0);
742 }
743 }
744
745 return 0;
746 }
747
748 static int ParseCmdLine(LPSTR lpCmdLine)
749 {
750 int i;
751 int argc = 0;
752 LPWSTR *lpszArgv = NULL;
753
754 lpszArgv = CommandLineToArgvW(GetCommandLineW(), &argc);
755
756 for (i = 0; i < argc; i++)
757 {
758 if (lstrcmp(lpszArgv[i], L"-q") == 0 || lstrcmp(lpszArgv[i], L"-Q") == 0)
759 {
760 g_LogFile[0] = 0;
761 }
762 else if (lstrcmp(lpszArgv[i], L"-h") == 0 || lstrcmp(lpszArgv[i], L"-H") == 0)
763 {
764 g_ShowHelp = TRUE;
765 }
766 else if (lstrcmp(lpszArgv[i], L"-s") == 0 || lstrcmp(lpszArgv[i], L"-S") == 0)
767 {
768 g_SaveAs = TRUE;
769 }
770 else if (lstrcmp(lpszArgv[i], L"-i") == 0 || lstrcmp(lpszArgv[i], L"-I") == 0)
771 {
772 if (i + 1 < argc)
773 {
774 wcscpy_s(g_CmdInFile, MAX_PATH, lpszArgv[i + 1]);
775 }
776 }
777 else if (lstrcmp(lpszArgv[i], L"-o") == 0 || lstrcmp(lpszArgv[i], L"-O") == 0)
778 {
779 if (i + 1 < argc)
780 {
781 wcscpy_s(g_CmdOutFile, MAX_PATH, lpszArgv[i + 1]);
782 }
783 }
784 }
785
786 return argc;
787 }
788
789 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
790 {
791 DWORD dwAttrib;
792 HANDLE hMutex;
793
794 UNREFERENCED_PARAMETER(hPrevInstance);
795
796 if (GetUserDefaultUILanguage() == 0x0804)
797 {
798 g_msg_lang = g_msg_cn;
799 }
800 else
801 {
802 g_msg_lang = g_msg_en;
803 }
804
805 hMutex = CreateMutexA(NULL, TRUE, "VtoyVlnkMUTEX");
806 if ((hMutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS))
807 {
808 MessageBoxW(NULL, g_msg_lang[MSGID_RUNNING_TIP], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
809 return 1;
810 }
811
812 GetCurrentDirectoryA(MAX_PATH, g_CurDirA);
813 GetCurrentDirectoryW(MAX_PATH, g_CurDirW);
814 sprintf_s(g_LogFile, sizeof(g_LogFile), "%s\\VentoyVlnk.log", g_CurDirA);
815
816 ParseCmdLine(lpCmdLine);
817
818 g_hInst = hInstance;
819
820 if (g_ShowHelp)
821 {
822 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);
823 return 0;
824 }
825 else if (g_CmdInFile[0] && g_CmdOutFile[0])
826 {
827 LogA("========= VentoyVlnk Cmdline Mode =========\n");
828
829 dwAttrib = GetFileAttributesW(g_CmdInFile);
830 if (dwAttrib == INVALID_FILE_ATTRIBUTES || (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))
831 {
832 LogW(L"File <<%ls>> does not exist!\n", g_CmdInFile);
833 VtoyMessageBox(NULL, g_msg_lang[MSGID_SRC_NONEXIST], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
834 return 1;
835 }
836
837 return CreateVlnk(NULL, g_CurDirW, g_CmdInFile, g_CmdOutFile);
838 }
839 else
840 {
841 LogA("========= VentoyVlnk GUI Mode =========\n");
842
843 DialogBoxA(hInstance, MAKEINTRESOURCEA(IDD_DIALOG1), NULL, DialogProc);
844 return 0;
845 }
846 }