1 /*
2 * PROJECT: ReactOS Virtual CD Control Tool
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: modules/rosapps/applications/vcdcontroltool/vcdcontroltool.c
5 * PURPOSE: main dialog implementation
6 * COPYRIGHT: Copyright 2018 Pierre Schweitzer
7 *
8 */
9
10 #define WIN32_NO_STATUS
11 #include <stdarg.h>
12 #include <windef.h>
13 #include <winbase.h>
14 #include <winuser.h>
15 #include <wingdi.h>
16 #include <winsvc.h>
17 #include <winreg.h>
18 #include <commctrl.h>
19 #include <commdlg.h>
20 #include <wchar.h>
21 #include <ndk/rtltypes.h>
22 #include <ndk/rtlfuncs.h>
23
24 #include <vcdioctl.h>
25 #define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
26 #define IOCTL_CDROM_EJECT_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
27
28 #include "resource.h"
29
30 HWND hWnd;
31 HWND hMountWnd;
32 HWND hDriverWnd;
33 HINSTANCE hInstance;
34 /* FIXME: to improve, ugly hack */
35 WCHAR wMountLetter;
36
37 static
38 HANDLE
OpenMaster(VOID)39 OpenMaster(VOID)
40 {
41 /* Just open the device */
42 return CreateFile(L"\\\\.\\\\VirtualCdRom", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
43 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
44 }
45
46 static
47 HANDLE
OpenLetter(WCHAR Letter)48 OpenLetter(WCHAR Letter)
49 {
50 WCHAR Device[255];
51
52 /* Make name */
53 wsprintf(Device, L"\\\\.\\%c:", Letter);
54
55 /* And open */
56 return CreateFile(Device, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
57 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
58 }
59
60 static
61 VOID
RefreshDevicesList(WCHAR Letter)62 RefreshDevicesList(WCHAR Letter)
63 {
64 HWND hListView;
65 WCHAR szFormat[50];
66 WCHAR szText[MAX_PATH + 50];
67 WCHAR szImage[MAX_PATH];
68 HANDLE hMaster, hLet;
69 DWORD BytesRead, i;
70 DRIVES_LIST Drives;
71 BOOLEAN Res;
72 IMAGE_PATH Image;
73 LVITEMW lvItem;
74 LRESULT lResult;
75 INT iSelected;
76
77 /* Get our list view */
78 hListView = GetDlgItem(hWnd, IDC_MAINDEVICES);
79
80 /* Purge it */
81 SendMessage(hListView, LVM_DELETEALLITEMS, 0, 0);
82
83 /* Now, query the driver for all the devices */
84 hMaster = OpenMaster();
85 if (hMaster != INVALID_HANDLE_VALUE)
86 {
87 Res = DeviceIoControl(hMaster, IOCTL_VCDROM_ENUMERATE_DRIVES, NULL, 0, &Drives, sizeof(Drives), &BytesRead, NULL);
88 CloseHandle(hMaster);
89
90 if (Res)
91 {
92 /* Loop to add all the devices to the list */
93 iSelected = -1;
94 for (i = 0; i < Drives.Count; ++i)
95 {
96 /* We'll query device one by one */
97 hLet = OpenLetter(Drives.Drives[i]);
98 if (hLet != INVALID_HANDLE_VALUE)
99 {
100 /* Get info about the mounted image */
101 Res = DeviceIoControl(hLet, IOCTL_VCDROM_GET_IMAGE_PATH, NULL, 0, &Image, sizeof(Image), &BytesRead, NULL);
102 if (Res)
103 {
104 /* First of all, add our driver letter to the list */
105 ZeroMemory(&lvItem, sizeof(LVITEMW));
106 lvItem.mask = LVIF_TEXT;
107 lvItem.pszText = szText;
108 lvItem.iItem = i;
109 szText[0] = Drives.Drives[i];
110 szText[1] = L':';
111 szText[2] = 0;
112
113 /* If it worked, we'll complete with the info about the device:
114 * (mounted? which image?)
115 */
116 lResult = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&lvItem);
117 if (lResult != -1)
118 {
119 /* If it matches arg, that's the letter to select at the end */
120 if (Drives.Drives[i] == Letter)
121 {
122 iSelected = lResult;
123 }
124
125 /* We'll fill second column with info */
126 lvItem.iSubItem = 1;
127
128 /* Gather the image path */
129 if (Image.Length != 0)
130 {
131 memcpy(szImage, Image.Path, Image.Length);
132 szImage[(Image.Length / sizeof(WCHAR))] = L'\0';
133 }
134
135 /* It's not mounted... */
136 if (Image.Mounted == 0)
137 {
138 /* If we don't have an image, set default text instead */
139 if (Image.Length == 0)
140 {
141 szImage[0] = 0;
142 LoadString(hInstance, IDS_NONE, szImage, sizeof(szImage) / sizeof(WCHAR));
143 szImage[(sizeof(szImage) / sizeof(WCHAR)) - 1] = L'\0';
144 }
145
146 /* Display the last known image */
147 szFormat[0] = 0;
148 LoadString(hInstance, IDS_NOMOUNTED, szFormat, sizeof(szFormat) / sizeof(WCHAR));
149 szFormat[(sizeof(szFormat) / sizeof(WCHAR)) - 1] = L'\0';
150
151 swprintf(szText, szFormat, szImage);
152 lvItem.pszText = szText;
153 }
154 else
155 {
156 /* Mounted, just display the image path */
157 lvItem.pszText = szImage;
158 }
159
160 /* Set text */
161 SendMessage(hListView, LVM_SETITEM, lResult, (LPARAM)&lvItem);
162 }
163 }
164
165 /* Don't leak our device */
166 CloseHandle(hLet);
167 }
168 }
169
170 /* If we had something to select, then just do it */
171 if (iSelected != -1)
172 {
173 ZeroMemory(&lvItem, sizeof(LVITEMW));
174
175 lvItem.mask = LVIF_STATE;
176 lvItem.iItem = iSelected;
177 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
178 lvItem.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
179 SendMessage(hListView, LVM_SETITEMSTATE, iSelected, (LPARAM)&lvItem);
180 }
181 }
182 }
183 }
184
185 VOID
SetServiceState(BOOLEAN Started)186 SetServiceState(BOOLEAN Started)
187 {
188 HWND hControl;
189
190 /* If started, disable start button */
191 hControl = GetDlgItem(hDriverWnd, IDC_DRIVERSTART);
192 EnableWindow(hControl, !Started);
193
194 /* If started, enable stop button */
195 hControl = GetDlgItem(hDriverWnd, IDC_DRIVERSTOP);
196 EnableWindow(hControl, Started);
197 }
198
199 INT_PTR
QueryDriverInfo(HWND hDlg)200 QueryDriverInfo(HWND hDlg)
201 {
202 DWORD dwSize;
203 SC_HANDLE hMgr, hSvc;
204 LPQUERY_SERVICE_CONFIGW pConfig;
205 WCHAR szText[2 * MAX_PATH];
206 HWND hControl;
207 SERVICE_STATUS Status;
208
209 hDriverWnd = hDlg;
210
211 /* Open service manager */
212 hMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
213 if (hMgr != NULL)
214 {
215 /* Open our service */
216 hSvc = OpenService(hMgr, L"Vcdrom", SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS);
217 if (hSvc != NULL)
218 {
219 /* Probe its config size */
220 if (!QueryServiceConfig(hSvc, NULL, 0, &dwSize) &&
221 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
222 {
223 /* And get its config */
224 pConfig = HeapAlloc(GetProcessHeap(), 0, dwSize);
225
226 if (QueryServiceConfig(hSvc, pConfig, dwSize, &dwSize))
227 {
228 /* Display name & driver */
229 wsprintf(szText, L"%s:\n(%s)", pConfig->lpDisplayName, pConfig->lpBinaryPathName);
230 hControl = GetDlgItem(hDriverWnd, IDC_DRIVERINFO);
231 SendMessage(hControl, WM_SETTEXT, 0, (LPARAM)szText);
232 }
233
234 HeapFree(GetProcessHeap(), 0, pConfig);
235 }
236
237 /* Get its status */
238 if (QueryServiceStatus(hSvc, &Status))
239 {
240 if (Status.dwCurrentState != SERVICE_RUNNING &&
241 Status.dwCurrentState != SERVICE_START_PENDING)
242 {
243 SetServiceState(FALSE);
244 }
245 else
246 {
247 SetServiceState(TRUE);
248 }
249 }
250
251 CloseServiceHandle(hSvc);
252 }
253
254 CloseServiceHandle(hMgr);
255 }
256
257 /* FIXME: we don't allow uninstall/install */
258 {
259 hControl = GetDlgItem(hDriverWnd, IDC_DRIVERINSTALL);
260 EnableWindow(hControl, FALSE);
261 hControl = GetDlgItem(hDriverWnd, IDC_DRIVERREMOVE);
262 EnableWindow(hControl, FALSE);
263 }
264
265 /* Display our sub window */
266 ShowWindow(hDlg, SW_SHOW);
267
268 return TRUE;
269 }
270
271 static
272 VOID
StartDriver(VOID)273 StartDriver(VOID)
274 {
275 SC_HANDLE hMgr, hSvc;
276
277 /* Open the SC manager */
278 hMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
279 if (hMgr != NULL)
280 {
281 /* Open the service matching our driver */
282 hSvc = OpenService(hMgr, L"Vcdrom", SERVICE_START);
283 if (hSvc != NULL)
284 {
285 /* Start it */
286 /* FIXME: improve */
287 StartService(hSvc, 0, NULL);
288
289 CloseServiceHandle(hSvc);
290
291 /* Refresh the list in case there were persistent mounts */
292 RefreshDevicesList(0);
293
294 /* Update buttons */
295 SetServiceState(TRUE);
296 }
297
298 CloseServiceHandle(hMgr);
299 }
300 }
301
302 static
303 VOID
StopDriver(VOID)304 StopDriver(VOID)
305 {
306 SC_HANDLE hMgr, hSvc;
307 SERVICE_STATUS Status;
308
309 /* Open the SC manager */
310 hMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
311 if (hMgr != NULL)
312 {
313 /* Open the service matching our driver */
314 hSvc = OpenService(hMgr, L"Vcdrom", SERVICE_STOP);
315 if (hSvc != NULL)
316 {
317 /* Stop it */
318 /* FIXME: improve */
319 ControlService(hSvc, SERVICE_CONTROL_STOP, &Status);
320
321 CloseServiceHandle(hSvc);
322
323 /* Refresh the list to clear it */
324 RefreshDevicesList(0);
325
326 /* Update buttons */
327 SetServiceState(FALSE);
328 }
329
330 CloseServiceHandle(hMgr);
331 }
332 }
333
334 static
335 INT_PTR
HandleDriverCommand(WPARAM wParam,LPARAM lParam)336 HandleDriverCommand(WPARAM wParam,
337 LPARAM lParam)
338 {
339 WORD Msg;
340
341 /* Dispatch the message for the controls we manage */
342 Msg = LOWORD(wParam);
343 switch (Msg)
344 {
345 case IDC_DRIVEROK:
346 DestroyWindow(hDriverWnd);
347 return TRUE;
348
349 case IDC_DRIVERSTART:
350 StartDriver();
351 return TRUE;
352
353 case IDC_DRIVERSTOP:
354 StopDriver();
355 return TRUE;
356 }
357
358 return FALSE;
359 }
360
361 static
362 INT_PTR
363 CALLBACK
DriverDialogProc(HWND hDlg,UINT Message,WPARAM wParam,LPARAM lParam)364 DriverDialogProc(HWND hDlg,
365 UINT Message,
366 WPARAM wParam,
367 LPARAM lParam)
368 {
369 /* Dispatch the message */
370 switch (Message)
371 {
372 case WM_INITDIALOG:
373 return QueryDriverInfo(hDlg);
374
375 case WM_COMMAND:
376 return HandleDriverCommand(wParam, lParam);
377
378 case WM_CLOSE:
379 return DestroyWindow(hDlg);
380 }
381
382 return FALSE;
383 }
384
385 static
386 VOID
DriverControl(VOID)387 DriverControl(VOID)
388 {
389 /* Just create a new window with our driver control dialog */
390 CreateDialogParamW(hInstance,
391 MAKEINTRESOURCE(IDD_DRIVERWINDOW),
392 NULL,
393 DriverDialogProc,
394 0);
395 }
396
397 static
398 INT_PTR
SetMountFileName(HWND hDlg,LPARAM lParam)399 SetMountFileName(HWND hDlg,
400 LPARAM lParam)
401 {
402 HWND hEditText;
403
404 hMountWnd = hDlg;
405
406 /* Set the file name that was passed when creating dialog */
407 hEditText = GetDlgItem(hMountWnd, IDC_MOUNTIMAGE);
408 SendMessage(hEditText, WM_SETTEXT, 0, lParam);
409
410 /* Show our window */
411 ShowWindow(hDlg, SW_SHOW);
412
413 return TRUE;
414 }
415
416 FORCEINLINE
417 DWORD
Min(DWORD a,DWORD b)418 Min(DWORD a, DWORD b)
419 {
420 return (a > b ? b : a);
421 }
422
423 static
424 VOID
PerformMount(VOID)425 PerformMount(VOID)
426 {
427 HWND hControl;
428 WCHAR szFileName[MAX_PATH];
429 MOUNT_PARAMETERS MountParams;
430 UNICODE_STRING NtPathName;
431 HANDLE hLet;
432 DWORD BytesRead;
433 BOOLEAN bPersist, Res;
434 WCHAR szKeyName[256];
435 HKEY hKey;
436
437 /* Zero our input structure */
438 ZeroMemory(&MountParams, sizeof(MOUNT_PARAMETERS));
439
440 /* Do we have to suppress UDF? */
441 hControl = GetDlgItem(hMountWnd, IDC_MOUNTUDF);
442 if (SendMessage(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED)
443 {
444 MountParams.Flags |= MOUNT_FLAG_SUPP_UDF;
445 }
446
447 /* Do we have to suppress Joliet? */
448 hControl = GetDlgItem(hMountWnd, IDC_MOUNTJOLIET);
449 if (SendMessage(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED)
450 {
451 MountParams.Flags |= MOUNT_FLAG_SUPP_JOLIET;
452 }
453
454 /* Should the mount be persistent? */
455 hControl = GetDlgItem(hMountWnd, IDC_MOUNTPERSIST);
456 bPersist = (SendMessage(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED);
457
458 /* Get the file name */
459 hControl = GetDlgItem(hMountWnd, IDC_MOUNTIMAGE);
460 GetWindowText(hControl, szFileName, sizeof(szFileName) / sizeof(WCHAR));
461
462 /* Get NT path for the driver */
463 if (RtlDosPathNameToNtPathName_U(szFileName, &NtPathName, NULL, NULL))
464 {
465 /* Copy it in the parameter structure */
466 wcsncpy(MountParams.Path, NtPathName.Buffer, 255);
467 MountParams.Length = Min(NtPathName.Length, 255 * sizeof(WCHAR));
468 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
469
470 /* Open the device */
471 hLet = OpenLetter(wMountLetter);
472 if (hLet != INVALID_HANDLE_VALUE)
473 {
474 /* And issue the mount IOCTL */
475 Res = DeviceIoControl(hLet, IOCTL_VCDROM_MOUNT_IMAGE, &MountParams, sizeof(MountParams), NULL, 0, &BytesRead, NULL);
476
477 CloseHandle(hLet);
478
479 /* Refresh the list so that our mount appears */
480 RefreshDevicesList(0);
481
482 /* If mount succeed and has to persistent, write it to registry */
483 if (Res && bPersist)
484 {
485 wsprintf(szKeyName, L"SYSTEM\\CurrentControlSet\\Services\\Vcdrom\\Parameters\\Device%c", wMountLetter);
486 if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY | KEY_SET_VALUE, NULL, &hKey, NULL) == ERROR_SUCCESS)
487 {
488 wcsncpy(szKeyName, MountParams.Path, MountParams.Length);
489 szKeyName[MountParams.Length / sizeof(WCHAR)] = 0;
490 RegSetValueExW(hKey, L"IMAGE", 0, REG_SZ, (BYTE *)szKeyName, MountParams.Length);
491
492 szKeyName[0] = wMountLetter;
493 szKeyName[1] = L':';
494 szKeyName[2] = 0;
495 RegSetValueExW(hKey, L"DRIVE", 0, REG_SZ, (BYTE *)szKeyName, 3 * sizeof(WCHAR));
496
497 RegCloseKey(hKey);
498 }
499 }
500 }
501 }
502
503 DestroyWindow(hMountWnd);
504 }
505
506 static
507 INT_PTR
HandleMountCommand(WPARAM wParam,LPARAM lParam)508 HandleMountCommand(WPARAM wParam,
509 LPARAM lParam)
510 {
511 WORD Msg;
512
513 /* Dispatch the message for the controls we manage */
514 Msg = LOWORD(wParam);
515 switch (Msg)
516 {
517 case IDC_MOUNTCANCEL:
518 DestroyWindow(hMountWnd);
519 return TRUE;
520
521 case IDC_MOUNTOK:
522 PerformMount();
523 return TRUE;
524 }
525
526 return FALSE;
527 }
528
529 static
530 INT_PTR
531 CALLBACK
MountDialogProc(HWND hDlg,UINT Message,WPARAM wParam,LPARAM lParam)532 MountDialogProc(HWND hDlg,
533 UINT Message,
534 WPARAM wParam,
535 LPARAM lParam)
536 {
537 /* Dispatch the message */
538 switch (Message)
539 {
540 case WM_INITDIALOG:
541 return SetMountFileName(hDlg, lParam);
542
543 case WM_COMMAND:
544 return HandleMountCommand(wParam, lParam);
545
546 case WM_CLOSE:
547 return DestroyWindow(hDlg);
548 }
549
550 return FALSE;
551 }
552
553 static
554 VOID
AddDrive(VOID)555 AddDrive(VOID)
556 {
557 WCHAR Letter;
558 BOOLEAN Res;
559 DWORD BytesRead;
560 HANDLE hMaster;
561
562 /* Open the driver */
563 hMaster = OpenMaster();
564 if (hMaster != INVALID_HANDLE_VALUE)
565 {
566 /* Issue the create IOCTL */
567 Res = DeviceIoControl(hMaster, IOCTL_VCDROM_CREATE_DRIVE, NULL, 0, &Letter, sizeof(WCHAR), &BytesRead, NULL);
568 CloseHandle(hMaster);
569
570 /* If it failed, reset the drive letter */
571 if (!Res)
572 {
573 Letter = 0;
574 }
575
576 /* Refresh devices list. If it succeed, we pass the created drive letter
577 * So that, user can directly click on "mount" to mount an image, without
578 * needing to select appropriate device.
579 */
580 RefreshDevicesList(Letter);
581 }
582 }
583
584 static
585 WCHAR
GetSelectedDriveLetter(VOID)586 GetSelectedDriveLetter(VOID)
587 {
588 INT iItem;
589 HWND hListView;
590 LVITEM lvItem;
591 WCHAR szText[255];
592
593 /* Get the select device in the list view */
594 hListView = GetDlgItem(hWnd, IDC_MAINDEVICES);
595 iItem = SendMessage(hListView, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
596 /* If there's one... */
597 if (iItem != -1)
598 {
599 ZeroMemory(&lvItem, sizeof(LVITEM));
600 lvItem.pszText = szText;
601 lvItem.cchTextMax = sizeof(szText) / sizeof(WCHAR);
602 szText[0] = 0;
603
604 /* Get the item text, it will be the drive letter */
605 SendMessage(hListView, LVM_GETITEMTEXT, iItem, (LPARAM)&lvItem);
606 return szText[0];
607 }
608
609 /* Nothing selected */
610 return 0;
611 }
612
613 static
614 VOID
MountImage(VOID)615 MountImage(VOID)
616 {
617 WCHAR szFilter[255];
618 WCHAR szFileName[MAX_PATH];
619 OPENFILENAMEW ImageOpen;
620
621 /* Get the selected drive letter
622 * FIXME: I make it global, because I don't know how to pass
623 * it properly to the later involved functions.
624 * Feel free to improve (without breaking ;-))
625 */
626 wMountLetter = GetSelectedDriveLetter();
627 /* We can only mount if we have a device */
628 if (wMountLetter != 0)
629 {
630 /* First of all, we need an image to mount */
631 ZeroMemory(&ImageOpen, sizeof(OPENFILENAMEW));
632
633 ImageOpen.lStructSize = sizeof(ImageOpen);
634 ImageOpen.hwndOwner = NULL;
635 ImageOpen.lpstrFilter = szFilter;
636 ImageOpen.lpstrFile = szFileName;
637 ImageOpen.nMaxFile = MAX_PATH;
638 ImageOpen.Flags = OFN_EXPLORER| OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
639
640 /* Get our filter (only supported images) */
641 szFileName[0] = 0;
642 szFilter[0] = 0;
643 LoadString(hInstance, IDS_FILTER, szFilter, sizeof(szFilter) / sizeof(WCHAR));
644 szFilter[(sizeof(szFilter) / sizeof(WCHAR)) - 1] = L'\0';
645
646 /* Get the image name */
647 if (!GetOpenFileName(&ImageOpen))
648 {
649 /* The user canceled... */
650 return;
651 }
652
653 /* Start the mount dialog, so that user can select mount options */
654 CreateDialogParamW(hInstance,
655 MAKEINTRESOURCE(IDD_MOUNTWINDOW),
656 NULL,
657 MountDialogProc,
658 (LPARAM)szFileName);
659 }
660 }
661
662 static
663 VOID
RemountImage(VOID)664 RemountImage(VOID)
665 {
666 WCHAR Letter;
667 HANDLE hLet;
668 DWORD BytesRead;
669
670 /* Get the select drive letter */
671 Letter = GetSelectedDriveLetter();
672 if (Letter != 0)
673 {
674 /* Open it */
675 hLet = OpenLetter(Letter);
676 if (hLet != INVALID_HANDLE_VALUE)
677 {
678 /* And ask the driver for a remount */
679 DeviceIoControl(hLet, IOCTL_STORAGE_LOAD_MEDIA, NULL, 0, NULL, 0, &BytesRead, NULL);
680
681 CloseHandle(hLet);
682
683 /* Refresh the list, to display the fact the image is now mounted.
684 * Make sure it's selected as it was previously selected.
685 */
686 RefreshDevicesList(Letter);
687 }
688 }
689 }
690
691 static
692 VOID
EjectDrive(VOID)693 EjectDrive(VOID)
694 {
695 WCHAR Letter;
696 HANDLE hLet;
697 DWORD BytesRead;
698
699 /* Get the select drive letter */
700 Letter = GetSelectedDriveLetter();
701 if (Letter != 0)
702 {
703 /* Open it */
704 hLet = OpenLetter(Letter);
705 if (hLet != INVALID_HANDLE_VALUE)
706 {
707 /* And ask the driver for an ejection */
708 DeviceIoControl(hLet, IOCTL_CDROM_EJECT_MEDIA, NULL, 0, NULL, 0, &BytesRead, NULL);
709
710 CloseHandle(hLet);
711
712 /* Refresh the list, to display the fact the image is now unmounted but
713 * still known by the driver
714 * Make sure it's selected as it was previously selected.
715 */
716 RefreshDevicesList(Letter);
717 }
718 }
719 }
720
721 static
722 VOID
RemoveDrive(VOID)723 RemoveDrive(VOID)
724 {
725 WCHAR Letter;
726 HANDLE hLet;
727 DWORD BytesRead;
728
729 /* Get the select drive letter */
730 Letter = GetSelectedDriveLetter();
731 if (Letter != 0)
732 {
733 /* Open it */
734 hLet = OpenLetter(Letter);
735 if (hLet != INVALID_HANDLE_VALUE)
736 {
737 /* And ask the driver for a deletion */
738 DeviceIoControl(hLet, IOCTL_VCDROM_DELETE_DRIVE, NULL, 0, NULL, 0, &BytesRead, NULL);
739
740 CloseHandle(hLet);
741
742 /* Refresh the list, to make the device disappear */
743 RefreshDevicesList(0);
744 }
745 }
746 }
747
748 static
749 INT_PTR
HandleCommand(WPARAM wParam,LPARAM lParam)750 HandleCommand(WPARAM wParam,
751 LPARAM lParam)
752 {
753 WORD Msg;
754
755 /* Dispatch the message for the controls we manage */
756 Msg = LOWORD(wParam);
757 switch (Msg)
758 {
759 case IDC_MAINCONTROL:
760 DriverControl();
761 return TRUE;
762
763 case IDC_MAINOK:
764 DestroyWindow(hWnd);
765 return TRUE;
766
767 case IDC_MAINADD:
768 AddDrive();
769 return TRUE;
770
771 case IDC_MAINMOUNT:
772 MountImage();
773 return TRUE;
774
775 case IDC_MAINREMOUNT:
776 RemountImage();
777 return TRUE;
778
779 case IDC_MAINEJECT:
780 EjectDrive();
781 return TRUE;
782
783 case IDC_MAINREMOVE:
784 RemoveDrive();
785 return TRUE;
786 }
787
788 return FALSE;
789 }
790
791 static
ResetStats(VOID)792 VOID ResetStats(VOID)
793 {
794 HWND hEditText;
795 static const WCHAR szText[] = { L'0', 0 };
796
797 /* Simply set '0' in all the edittext controls we
798 * manage regarding statistics.
799 */
800 hEditText = GetDlgItem(hWnd, IDC_MAINSECTORS);
801 SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
802
803 hEditText = GetDlgItem(hWnd, IDC_MAINSIZE);
804 SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
805
806 hEditText = GetDlgItem(hWnd, IDC_MAINFREE);
807 SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
808
809 hEditText = GetDlgItem(hWnd, IDC_MAINTOTAL);
810 SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
811 }
812
813 static
814 INT_PTR
HandleNotify(LPARAM lParam)815 HandleNotify(LPARAM lParam)
816 {
817 WCHAR Letter;
818 LPNMHDR NmHdr;
819 WCHAR szText[255];
820 HWND hEditText;
821 DWORD ClusterSector, SectorSize, FreeClusters, Clusters, Sectors;
822
823 NmHdr = (LPNMHDR)lParam;
824
825 /* We only want notifications on click on our devices list */
826 if (NmHdr->code == NM_CLICK &&
827 NmHdr->idFrom == IDC_MAINDEVICES)
828 {
829 /* Get the newly selected device */
830 Letter = GetSelectedDriveLetter();
831 if (Letter != 0)
832 {
833 /* Setup its name */
834 szText[0] = Letter;
835 szText[1] = L':';
836 szText[2] = 0;
837
838 /* And get its capacities */
839 if (GetDiskFreeSpace(szText, &ClusterSector, &SectorSize, &FreeClusters, &Clusters))
840 {
841 /* Nota: the application returns the total amount of clusters and sectors
842 * So, compute it
843 */
844 Sectors = ClusterSector * Clusters;
845
846 /* And now, update statistics about the device */
847 hEditText = GetDlgItem(hWnd, IDC_MAINSECTORS);
848 wsprintf(szText, L"%ld", Sectors);
849 SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
850
851 hEditText = GetDlgItem(hWnd, IDC_MAINSIZE);
852 wsprintf(szText, L"%ld", SectorSize);
853 SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
854
855 hEditText = GetDlgItem(hWnd, IDC_MAINFREE);
856 wsprintf(szText, L"%ld", FreeClusters);
857 SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
858
859 hEditText = GetDlgItem(hWnd, IDC_MAINTOTAL);
860 wsprintf(szText, L"%ld", Clusters);
861 SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
862
863 return TRUE;
864 }
865 }
866
867 /* We failed somewhere, make sure we're at 0 */
868 ResetStats();
869
870 return TRUE;
871 }
872
873 return FALSE;
874 }
875
876 static
877 INT_PTR
CreateListViewColumns(HWND hDlg)878 CreateListViewColumns(HWND hDlg)
879 {
880 WCHAR szText[255];
881 LVCOLUMNW lvColumn;
882 HWND hListView;
883
884 hWnd = hDlg;
885 hListView = GetDlgItem(hDlg, IDC_MAINDEVICES);
886
887 /* Select the whole line, not just the first column */
888 SendMessage(hListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
889
890 /* Set up the first column */
891 ZeroMemory(&lvColumn, sizeof(LVCOLUMNW));
892 lvColumn.pszText = szText;
893 lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
894 lvColumn.fmt = LVCFMT_LEFT;
895 lvColumn.cx = 100;
896 szText[0] = 0;
897 LoadString(hInstance, IDS_DRIVE, szText, sizeof(szText) / sizeof(WCHAR));
898 szText[(sizeof(szText) / sizeof(WCHAR)) - 1] = L'\0';
899 SendMessage(hListView, LVM_INSERTCOLUMNW, 0, (LPARAM)&lvColumn);
900
901 /* Set up the second column */
902 szText[0] = 0;
903 lvColumn.cx = 350;
904 LoadString(hInstance, IDS_MAPPEDIMAGE, szText, sizeof(szText) / sizeof(WCHAR));
905 szText[(sizeof(szText) / sizeof(WCHAR)) - 1] = L'\0';
906 SendMessage(hListView, LVM_INSERTCOLUMNW, 1, (LPARAM)&lvColumn);
907
908 /* Make sure stats are at 0 */
909 ResetStats();
910
911 /* And populate our device list */
912 RefreshDevicesList(0);
913
914 return TRUE;
915 }
916
917 static
918 INT_PTR
919 CALLBACK
MainDialogProc(HWND hDlg,UINT Message,WPARAM wParam,LPARAM lParam)920 MainDialogProc(HWND hDlg,
921 UINT Message,
922 WPARAM wParam,
923 LPARAM lParam)
924 {
925 /* Dispatch the message */
926 switch (Message)
927 {
928 case WM_INITDIALOG:
929 return CreateListViewColumns(hDlg);
930
931 case WM_COMMAND:
932 return HandleCommand(wParam, lParam);
933
934 case WM_NOTIFY:
935 return HandleNotify(lParam);
936
937 case WM_CLOSE:
938 return DestroyWindow(hDlg);
939
940 case WM_DESTROY:
941 PostQuitMessage(0);
942 return TRUE;
943 }
944
945 return FALSE;
946 }
947
948 INT
949 WINAPI
wWinMain(HINSTANCE hInst,HINSTANCE hPrev,LPWSTR Cmd,int iCmd)950 wWinMain(HINSTANCE hInst,
951 HINSTANCE hPrev,
952 LPWSTR Cmd,
953 int iCmd)
954 {
955 MSG Msg;
956
957 hInstance = hInst;
958
959 /* Just start our main window */
960 hWnd = CreateDialogParamW(hInst,
961 MAKEINTRESOURCE(IDD_MAINWINDOW),
962 NULL,
963 MainDialogProc,
964 0);
965 /* And dispatch messages in case of a success */
966 if (hWnd != NULL)
967 {
968 while (GetMessageW(&Msg, NULL, 0, 0) != 0)
969 {
970 TranslateMessage(&Msg);
971 DispatchMessageW(&Msg);
972 }
973 }
974
975 return 0;
976 }
977