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