--- /dev/null
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+IDD_MAINWINDOW DIALOGEX 0, 0, 320, 200
+STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "Virtual CDRom Control Panel"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ PUSHBUTTON "OK", IDC_MAINOK, 211, 179, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ CONTROL "", IDC_MAINDEVICES, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 7, 7, 306, 83
+ GROUPBOX "Drive Geometry", IDC_STATIC, 7, 101, 153, 74, BS_GROUPBOX | WS_CHILD | WS_VISIBLE
+ LTEXT "Number of sectors", IDC_STATIC, 15, 115, 60, 9, WS_CHILD | WS_VISIBLE | WS_GROUP
+ LTEXT "Sector Size", IDC_STATIC, 15, 127, 49, 9, WS_CHILD | WS_VISIBLE | WS_GROUP
+ LTEXT "Free Clusters", IDC_STATIC, 15, 139, 49, 9, WS_CHILD | WS_VISIBLE | WS_GROUP
+ LTEXT "Total Clusters", IDC_STATIC, 15, 151, 49, 9, WS_CHILD | WS_VISIBLE | WS_GROUP
+ EDITTEXT IDC_MAINSECTORS, 88, 115, 49, 12, ES_LEFT | ES_AUTOHSCROLL | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP
+ EDITTEXT IDC_MAINSIZE, 88, 127, 49, 12, ES_LEFT | ES_AUTOHSCROLL | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP
+ EDITTEXT IDC_MAINFREE, 88, 139, 49, 12, ES_LEFT | ES_AUTOHSCROLL | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP
+ EDITTEXT IDC_MAINTOTAL, 88, 151, 49, 12, ES_LEFT | ES_AUTOHSCROLL | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP
+ PUSHBUTTON "&Add Drive", IDC_MAINADD, 183, 123, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ PUSHBUTTON "&Remove Drive", IDC_MAINREMOVE, 242, 123, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ PUSHBUTTON "Mount", IDC_MAINMOUNT, 183, 142, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ PUSHBUTTON "Eject", IDC_MAINEJECT, 183, 161, 109, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ PUSHBUTTON "Remount", IDC_MAINREMOUNT, 242, 142, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ PUSHBUTTON "Driver Control ...", IDC_MAINCONTROL, 183, 105, 109, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+END
+
+IDD_MOUNTWINDOW DIALOG 0, 0, 187, 97
+STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Special Mount Options"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ PUSHBUTTON "OK", IDC_MOUNTOK, 130, 59, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ PUSHBUTTON "Cancel", IDC_MOUNTCANCEL, 130, 76, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ EDITTEXT IDC_MOUNTIMAGE, 7, 17, 173, 14, ES_LEFT | ES_AUTOHSCROLL | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP
+ LTEXT "Image to be mounted", IDC_STATIC, 7, 7, 173, 10, SS_LEFT | SS_SUNKEN | WS_CHILD | WS_VISIBLE | WS_GROUP
+ AUTOCHECKBOX "Suppress UDF", IDC_MOUNTUDF, 7, 40, 114, 10, BS_FLAT | WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ AUTOCHECKBOX "Suppress Joliet", IDC_MOUNTJOLIET, 7, 56, 111, 9, BS_FLAT | WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ AUTOCHECKBOX "Persistent mount", IDC_MOUNTPERSIST, 7, 71, 111, 9, BS_FLAT | WS_CHILD | WS_VISIBLE | WS_TABSTOP
+END
+
+IDD_DRIVERWINDOW DIALOG 0, 0, 189, 123
+STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Virtual CD-ROM Driver Control"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ PUSHBUTTON "OK", IDC_DRIVEROK, 43, 98, 103, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ PUSHBUTTON "Install Driver ...", IDC_DRIVERINSTALL, 43, 61, 51, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ PUSHBUTTON "Start", IDC_DRIVERSTART, 43, 79, 51, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ PUSHBUTTON "Stop", IDC_DRIVERSTOP, 96, 79, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ PUSHBUTTON "Remove Driver", IDC_DRIVERREMOVE, 96, 61, 50, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+ EDITTEXT IDC_DRIVERINFO, 7, 7, 175, 50, ES_CENTER | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP
+END
+
+STRINGTABLE
+BEGIN
+ IDS_DRIVE "Drive"
+ IDS_MAPPEDIMAGE "Mapped Image"
+ IDS_NOMOUNTED "No Image Mounted. Last one was - %s"
+ IDS_NONE "None"
+ IDS_FILTER "All Supported Image (*.udf; *.cdfs; *.jo; *.iso; *.rock)\0*.udf;*.cdfs;*.jo;*.iso;*.rock\0"
+END
--- /dev/null
+/*
+ * PROJECT: ReactOS Virtual CD Control Tool
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: modules/rosapps/applications/vcdcontroltool/vcdcontroltool.c
+ * PURPOSE: main dialog implementation
+ * COPYRIGHT: Copyright 2018 Pierre Schweitzer
+ *
+ */
+
+#define WIN32_NO_STATUS
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <winuser.h>
+#include <wingdi.h>
+#include <winsvc.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include <wchar.h>
+#include <ndk/rtltypes.h>
+#include <ndk/rtlfuncs.h>
+
+#include <vcdioctl.h>
+#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
+#define IOCTL_CDROM_EJECT_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#include "resource.h"
+
+HWND hWnd;
+HWND hMountWnd;
+HWND hDriverWnd;
+HINSTANCE hInstance;
+/* FIXME: to improve, ugly hack */
+WCHAR wMountLetter;
+
+static
+HANDLE
+OpenMaster(VOID)
+{
+ /* Just open the device */
+ return CreateFile(L"\\\\.\\\\VirtualCdRom", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+}
+
+static
+HANDLE
+OpenLetter(WCHAR Letter)
+{
+ WCHAR Device[255];
+
+ /* Make name */
+ wsprintf(Device, L"\\\\.\\%c:", Letter);
+
+ /* And open */
+ return CreateFile(Device, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+}
+
+static
+VOID
+RefreshDevicesList(WCHAR Letter)
+{
+ HWND hListView;
+ WCHAR szFormat[50];
+ WCHAR szText[MAX_PATH + 50];
+ WCHAR szImage[MAX_PATH];
+ HANDLE hMaster, hLet;
+ DWORD BytesRead, i;
+ DRIVES_LIST Drives;
+ BOOLEAN Res;
+ IMAGE_PATH Image;
+ LVITEMW lvItem;
+ LRESULT lResult;
+ INT iSelected;
+
+ /* Get our list view */
+ hListView = GetDlgItem(hWnd, IDC_MAINDEVICES);
+
+ /* Purge it */
+ SendMessage(hListView, LVM_DELETEALLITEMS, 0, 0);
+
+ /* Now, query the driver for all the devices */
+ hMaster = OpenMaster();
+ if (hMaster != INVALID_HANDLE_VALUE)
+ {
+ Res = DeviceIoControl(hMaster, IOCTL_VCDROM_ENUMERATE_DRIVES, NULL, 0, &Drives, sizeof(Drives), &BytesRead, NULL);
+ CloseHandle(hMaster);
+
+ if (Res)
+ {
+ /* Loop to add all the devices to the list */
+ iSelected = -1;
+ for (i = 0; i < Drives.Count; ++i)
+ {
+ /* We'll query device one by one */
+ hLet = OpenLetter(Drives.Drives[i]);
+ if (hLet != INVALID_HANDLE_VALUE)
+ {
+ /* Get info about the mounted image */
+ Res = DeviceIoControl(hLet, IOCTL_VCDROM_GET_IMAGE_PATH, NULL, 0, &Image, sizeof(Image), &BytesRead, NULL);
+ if (Res)
+ {
+ /* First of all, add our driver letter to the list */
+ ZeroMemory(&lvItem, sizeof(LVITEMW));
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = szText;
+ lvItem.iItem = i;
+ szText[0] = Drives.Drives[i];
+ szText[1] = L':';
+ szText[2] = 0;
+
+ /* If it worked, we'll complete with the info about the device:
+ * (mounted? which image?)
+ */
+ lResult = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&lvItem);
+ if (lResult != -1)
+ {
+ /* If it matches arg, that's the letter to select at the end */
+ if (Drives.Drives[i] == Letter)
+ {
+ iSelected = lResult;
+ }
+
+ /* We'll fill second column with info */
+ lvItem.iSubItem = 1;
+
+ /* Gather the image path */
+ if (Image.Length != 0)
+ {
+ memcpy(szImage, Image.Path, Image.Length);
+ szImage[(Image.Length / sizeof(WCHAR))] = L'\0';
+ }
+
+ /* It's not mounted... */
+ if (Image.Mounted == 0)
+ {
+ /* If we don't have an image, set default text instead */
+ if (Image.Length == 0)
+ {
+ szImage[0] = 0;
+ LoadString(hInstance, IDS_NONE, szImage, sizeof(szImage) / sizeof(WCHAR));
+ szImage[(sizeof(szImage) / sizeof(WCHAR)) - 1] = L'\0';
+ }
+
+ /* Display the last known image */
+ szFormat[0] = 0;
+ LoadString(hInstance, IDS_NOMOUNTED, szFormat, sizeof(szFormat) / sizeof(WCHAR));
+ szFormat[(sizeof(szFormat) / sizeof(WCHAR)) - 1] = L'\0';
+
+ swprintf(szText, szFormat, szImage);
+ lvItem.pszText = szText;
+ }
+ else
+ {
+ /* Mounted, just display the image path */
+ lvItem.pszText = szImage;
+ }
+
+ /* Set text */
+ SendMessage(hListView, LVM_SETITEM, lResult, (LPARAM)&lvItem);
+ }
+ }
+
+ /* Don't leak our device */
+ CloseHandle(hLet);
+ }
+ }
+
+ /* If we had something to select, then just do it */
+ if (iSelected != -1)
+ {
+ ZeroMemory(&lvItem, sizeof(LVITEMW));
+
+ lvItem.mask = LVIF_STATE;
+ lvItem.iItem = iSelected;
+ lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
+ lvItem.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
+ SendMessage(hListView, LVM_SETITEMSTATE, iSelected, (LPARAM)&lvItem);
+ }
+ }
+ }
+}
+
+INT_PTR
+QueryDriverInfo(HWND hDlg)
+{
+ DWORD dwSize;
+ SC_HANDLE hMgr, hSvc;
+ LPQUERY_SERVICE_CONFIGW pConfig;
+ WCHAR szText[2 * MAX_PATH];
+ HWND hControl;
+
+ hDriverWnd = hDlg;
+
+ /* Open service manager */
+ hMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+ if (hMgr != NULL)
+ {
+ /* Open our service */
+ hSvc = OpenService(hMgr, L"Vcdrom", SERVICE_QUERY_CONFIG);
+ if (hSvc != NULL)
+ {
+ /* Probe its config size */
+ if (!QueryServiceConfig(hSvc, NULL, 0, &dwSize) &&
+ GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ {
+ /* And get its config */
+ pConfig = HeapAlloc(GetProcessHeap(), 0, dwSize);
+
+ if (QueryServiceConfig(hSvc, pConfig, dwSize, &dwSize))
+ {
+ /* Display name & driver */
+ wsprintf(szText, L"%s:\n(%s)", pConfig->lpDisplayName, pConfig->lpBinaryPathName);
+ hControl = GetDlgItem(hDriverWnd, IDC_DRIVERINFO);
+ SendMessage(hControl, WM_SETTEXT, 0, (LPARAM)szText);
+ }
+
+ HeapFree(GetProcessHeap(), 0, pConfig);
+ }
+
+ CloseServiceHandle(hSvc);
+ }
+
+ CloseServiceHandle(hMgr);
+ }
+
+ /* FIXME: we don't allow uninstall/install */
+ {
+ hControl = GetDlgItem(hDriverWnd, IDC_DRIVERINSTALL);
+ EnableWindow(hControl, FALSE);
+ hControl = GetDlgItem(hDriverWnd, IDC_DRIVERREMOVE);
+ EnableWindow(hControl, FALSE);
+ }
+
+ /* Display our sub window */
+ ShowWindow(hDlg, SW_SHOW);
+
+ return TRUE;
+}
+
+static
+VOID
+StartDriver(VOID)
+{
+ SC_HANDLE hMgr, hSvc;
+
+ /* Open the SC manager */
+ hMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+ if (hMgr != NULL)
+ {
+ /* Open the service matching our driver */
+ hSvc = OpenService(hMgr, L"Vcdrom", SERVICE_START);
+ if (hSvc != NULL)
+ {
+ /* Start it */
+ /* FIXME: improve */
+ StartService(hSvc, 0, NULL);
+
+ CloseServiceHandle(hSvc);
+
+ /* Refresh the list in case there were persistent mounts */
+ RefreshDevicesList(0);
+ }
+
+ CloseServiceHandle(hMgr);
+ }
+}
+
+static
+VOID
+StopDriver(VOID)
+{
+ SC_HANDLE hMgr, hSvc;
+ SERVICE_STATUS Status;
+
+ /* Open the SC manager */
+ hMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+ if (hMgr != NULL)
+ {
+ /* Open the service matching our driver */
+ hSvc = OpenService(hMgr, L"Vcdrom", SERVICE_STOP);
+ if (hSvc != NULL)
+ {
+ /* Stop it */
+ /* FIXME: improve */
+ ControlService(hSvc, SERVICE_CONTROL_STOP, &Status);
+
+ CloseServiceHandle(hSvc);
+
+ /* Refresh the list to clear it */
+ RefreshDevicesList(0);
+ }
+
+ CloseServiceHandle(hMgr);
+ }
+}
+
+static
+INT_PTR
+HandleDriverCommand(WPARAM wParam,
+ LPARAM lParam)
+{
+ WORD Msg;
+
+ /* Dispatch the message for the controls we manage */
+ Msg = LOWORD(wParam);
+ switch (Msg)
+ {
+ case IDC_DRIVEROK:
+ DestroyWindow(hDriverWnd);
+ return TRUE;
+
+ case IDC_DRIVERSTART:
+ StartDriver();
+ return TRUE;
+
+ case IDC_DRIVERSTOP:
+ StopDriver();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static
+INT_PTR
+CALLBACK
+DriverDialogProc(HWND hDlg,
+ UINT Message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ /* Dispatch the message */
+ switch (Message)
+ {
+ case WM_INITDIALOG:
+ return QueryDriverInfo(hDlg);
+
+ case WM_COMMAND:
+ return HandleDriverCommand(wParam, lParam);
+
+ case WM_CLOSE:
+ return DestroyWindow(hDlg);
+ }
+
+ return FALSE;
+}
+
+static
+VOID
+DriverControl(VOID)
+{
+ /* Just create a new window with our driver control dialog */
+ CreateDialogParamW(hInstance,
+ MAKEINTRESOURCE(IDD_DRIVERWINDOW),
+ NULL,
+ DriverDialogProc,
+ 0);
+}
+
+static
+INT_PTR
+SetMountFileName(HWND hDlg,
+ LPARAM lParam)
+{
+ HWND hEditText;
+
+ hMountWnd = hDlg;
+
+ /* Set the file name that was passed when creating dialog */
+ hEditText = GetDlgItem(hMountWnd, IDC_MOUNTIMAGE);
+ SendMessage(hEditText, WM_SETTEXT, 0, lParam);
+
+ /* FIXME: we don't support persistent mounts yet*/
+ {
+ hEditText = GetDlgItem(hMountWnd, IDC_MOUNTPERSIST);
+ EnableWindow(hEditText, FALSE);
+ }
+
+ /* Show our window */
+ ShowWindow(hDlg, SW_SHOW);
+
+ return TRUE;
+}
+
+FORCEINLINE
+DWORD
+Min(DWORD a, DWORD b)
+{
+ return (a > b ? b : a);
+}
+
+static
+VOID
+PerformMount(VOID)
+{
+ HWND hControl;
+ WCHAR szFileName[MAX_PATH];
+ MOUNT_PARAMETERS MountParams;
+ UNICODE_STRING NtPathName;
+ HANDLE hLet;
+ DWORD BytesRead;
+
+ /* Zero our input structure */
+ ZeroMemory(&MountParams, sizeof(MOUNT_PARAMETERS));
+
+ /* Do we have to suppress UDF? */
+ hControl = GetDlgItem(hMountWnd, IDC_MOUNTUDF);
+ if (SendMessage(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED)
+ {
+ MountParams.Flags |= MOUNT_FLAG_SUPP_UDF;
+ }
+
+ /* Do we have to suppress Joliet? */
+ hControl = GetDlgItem(hMountWnd, IDC_MOUNTJOLIET);
+ if (SendMessage(hControl, BM_GETCHECK, 0, 0) == BST_CHECKED)
+ {
+ MountParams.Flags |= MOUNT_FLAG_SUPP_JOLIET;
+ }
+
+ /* Get the file name */
+ hControl = GetDlgItem(hMountWnd, IDC_MOUNTIMAGE);
+ GetWindowText(hControl, szFileName, sizeof(szFileName) / sizeof(WCHAR));
+
+ /* Get NT path for the driver */
+ if (RtlDosPathNameToNtPathName_U(szFileName, &NtPathName, NULL, NULL))
+ {
+ /* Copy it in the parameter structure */
+ wcsncpy(MountParams.Path, NtPathName.Buffer, 255);
+ MountParams.Length = Min(NtPathName.Length, 255 * sizeof(WCHAR));
+ RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathName.Buffer);
+
+ /* Open the device */
+ hLet = OpenLetter(wMountLetter);
+ if (hLet != INVALID_HANDLE_VALUE)
+ {
+ /* And issue the mount IOCTL */
+ DeviceIoControl(hLet, IOCTL_VCDROM_MOUNT_IMAGE, &MountParams, sizeof(MountParams), NULL, 0, &BytesRead, NULL);
+
+ CloseHandle(hLet);
+
+ /* Refresh the list so that our mount appears */
+ RefreshDevicesList(0);
+ }
+ }
+
+ DestroyWindow(hMountWnd);
+}
+
+static
+INT_PTR
+HandleMountCommand(WPARAM wParam,
+ LPARAM lParam)
+{
+ WORD Msg;
+
+ /* Dispatch the message for the controls we manage */
+ Msg = LOWORD(wParam);
+ switch (Msg)
+ {
+ case IDC_MOUNTCANCEL:
+ DestroyWindow(hMountWnd);
+ return TRUE;
+
+ case IDC_MOUNTOK:
+ PerformMount();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static
+INT_PTR
+CALLBACK
+MountDialogProc(HWND hDlg,
+ UINT Message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ /* Dispatch the message */
+ switch (Message)
+ {
+ case WM_INITDIALOG:
+ return SetMountFileName(hDlg, lParam);
+
+ case WM_COMMAND:
+ return HandleMountCommand(wParam, lParam);
+
+ case WM_CLOSE:
+ return DestroyWindow(hDlg);
+ }
+
+ return FALSE;
+}
+
+static
+VOID
+AddDrive(VOID)
+{
+ WCHAR Letter;
+ BOOLEAN Res;
+ DWORD BytesRead;
+ HANDLE hMaster;
+
+ /* Open the driver */
+ hMaster = OpenMaster();
+ if (hMaster != INVALID_HANDLE_VALUE)
+ {
+ /* Issue the create IOCTL */
+ Res = DeviceIoControl(hMaster, IOCTL_VCDROM_CREATE_DRIVE, NULL, 0, &Letter, sizeof(WCHAR), &BytesRead, NULL);
+ CloseHandle(hMaster);
+
+ /* If it failed, reset the drive letter */
+ if (!Res)
+ {
+ Letter = 0;
+ }
+
+ /* Refresh devices list. If it succeed, we pass the created drive letter
+ * So that, user can directly click on "mount" to mount an image, without
+ * needing to select appropriate device.
+ */
+ RefreshDevicesList(Letter);
+ }
+}
+
+static
+WCHAR
+GetSelectedDriveLetter(VOID)
+{
+ INT iItem;
+ HWND hListView;
+ LVITEM lvItem;
+ WCHAR szText[255];
+
+ /* Get the select device in the list view */
+ hListView = GetDlgItem(hWnd, IDC_MAINDEVICES);
+ iItem = SendMessage(hListView, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
+ /* If there's one... */
+ if (iItem != -1)
+ {
+ ZeroMemory(&lvItem, sizeof(LVITEM));
+ lvItem.pszText = szText;
+ lvItem.cchTextMax = sizeof(szText) / sizeof(WCHAR);
+ szText[0] = 0;
+
+ /* Get the item text, it will be the drive letter */
+ SendMessage(hListView, LVM_GETITEMTEXT, iItem, (LPARAM)&lvItem);
+ return szText[0];
+ }
+
+ /* Nothing selected */
+ return 0;
+}
+
+static
+VOID
+MountImage(VOID)
+{
+ WCHAR szFilter[255];
+ WCHAR szFileName[MAX_PATH];
+ OPENFILENAMEW ImageOpen;
+
+ /* Get the selected drive letter
+ * FIXME: I make it global, because I don't know how to pass
+ * it properly to the later involved functions.
+ * Feel free to improve (without breaking ;-))
+ */
+ wMountLetter = GetSelectedDriveLetter();
+ /* We can only mount if we have a device */
+ if (wMountLetter != 0)
+ {
+ /* First of all, we need an image to mount */
+ ZeroMemory(&ImageOpen, sizeof(OPENFILENAMEW));
+
+ ImageOpen.lStructSize = sizeof(ImageOpen);
+ ImageOpen.hwndOwner = NULL;
+ ImageOpen.lpstrFilter = szFilter;
+ ImageOpen.lpstrFile = szFileName;
+ ImageOpen.nMaxFile = MAX_PATH;
+ ImageOpen.Flags = OFN_EXPLORER| OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+
+ /* Get our filter (only supported images) */
+ szFileName[0] = 0;
+ szFilter[0] = 0;
+ LoadString(hInstance, IDS_FILTER, szFilter, sizeof(szFilter) / sizeof(WCHAR));
+ szFilter[(sizeof(szFilter) / sizeof(WCHAR)) - 1] = L'\0';
+
+ /* Get the image name */
+ if (!GetOpenFileName(&ImageOpen))
+ {
+ /* The user canceled... */
+ return;
+ }
+
+ /* Start the mount dialog, so that user can select mount options */
+ CreateDialogParamW(hInstance,
+ MAKEINTRESOURCE(IDD_MOUNTWINDOW),
+ NULL,
+ MountDialogProc,
+ (LPARAM)szFileName);
+ }
+}
+
+static
+VOID
+RemountImage(VOID)
+{
+ WCHAR Letter;
+ HANDLE hLet;
+ DWORD BytesRead;
+
+ /* Get the select drive letter */
+ Letter = GetSelectedDriveLetter();
+ if (Letter != 0)
+ {
+ /* Open it */
+ hLet = OpenLetter(Letter);
+ if (hLet != INVALID_HANDLE_VALUE)
+ {
+ /* And ask the driver for a remount */
+ DeviceIoControl(hLet, IOCTL_STORAGE_LOAD_MEDIA, NULL, 0, NULL, 0, &BytesRead, NULL);
+
+ CloseHandle(hLet);
+
+ /* Refresh the list, to display the fact the image is now mounted.
+ * Make sure it's selected as it was previously selected.
+ */
+ RefreshDevicesList(Letter);
+ }
+ }
+}
+
+static
+VOID
+EjectDrive(VOID)
+{
+ WCHAR Letter;
+ HANDLE hLet;
+ DWORD BytesRead;
+
+ /* Get the select drive letter */
+ Letter = GetSelectedDriveLetter();
+ if (Letter != 0)
+ {
+ /* Open it */
+ hLet = OpenLetter(Letter);
+ if (hLet != INVALID_HANDLE_VALUE)
+ {
+ /* And ask the driver for an ejection */
+ DeviceIoControl(hLet, IOCTL_CDROM_EJECT_MEDIA, NULL, 0, NULL, 0, &BytesRead, NULL);
+
+ CloseHandle(hLet);
+
+ /* Refresh the list, to display the fact the image is now unmounted but
+ * still known by the driver
+ * Make sure it's selected as it was previously selected.
+ */
+ RefreshDevicesList(Letter);
+ }
+ }
+}
+
+static
+VOID
+RemoveDrive(VOID)
+{
+ WCHAR Letter;
+ HANDLE hLet;
+ DWORD BytesRead;
+
+ /* Get the select drive letter */
+ Letter = GetSelectedDriveLetter();
+ if (Letter != 0)
+ {
+ /* Open it */
+ hLet = OpenLetter(Letter);
+ if (hLet != INVALID_HANDLE_VALUE)
+ {
+ /* And ask the driver for a deletion */
+ DeviceIoControl(hLet, IOCTL_VCDROM_DELETE_DRIVE, NULL, 0, NULL, 0, &BytesRead, NULL);
+
+ CloseHandle(hLet);
+
+ /* Refresh the list, to make the device disappear */
+ RefreshDevicesList(0);
+ }
+ }
+}
+
+static
+INT_PTR
+HandleCommand(WPARAM wParam,
+ LPARAM lParam)
+{
+ WORD Msg;
+
+ /* Dispatch the message for the controls we manage */
+ Msg = LOWORD(wParam);
+ switch (Msg)
+ {
+ case IDC_MAINCONTROL:
+ DriverControl();
+ return TRUE;
+
+ case IDC_MAINOK:
+ DestroyWindow(hWnd);
+ return TRUE;
+
+ case IDC_MAINADD:
+ AddDrive();
+ return TRUE;
+
+ case IDC_MAINMOUNT:
+ MountImage();
+ return TRUE;
+
+ case IDC_MAINREMOUNT:
+ RemountImage();
+ return TRUE;
+
+ case IDC_MAINEJECT:
+ EjectDrive();
+ return TRUE;
+
+ case IDC_MAINREMOVE:
+ RemoveDrive();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static
+VOID ResetStats(VOID)
+{
+ HWND hEditText;
+ static const WCHAR szText[] = { L'0', 0 };
+
+ /* Simply set '0' in all the edittext controls we
+ * manage regarding statistics.
+ */
+ hEditText = GetDlgItem(hWnd, IDC_MAINSECTORS);
+ SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
+
+ hEditText = GetDlgItem(hWnd, IDC_MAINSIZE);
+ SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
+
+ hEditText = GetDlgItem(hWnd, IDC_MAINFREE);
+ SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
+
+ hEditText = GetDlgItem(hWnd, IDC_MAINTOTAL);
+ SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
+}
+
+static
+INT_PTR
+HandleNotify(LPARAM lParam)
+{
+ WCHAR Letter;
+ LPNMHDR NmHdr;
+ WCHAR szText[255];
+ HWND hEditText;
+ DWORD ClusterSector, SectorSize, FreeClusters, Clusters, Sectors;
+
+ NmHdr = (LPNMHDR)lParam;
+
+ /* We only want notifications on click on our devices list */
+ if (NmHdr->code == NM_CLICK &&
+ NmHdr->idFrom == IDC_MAINDEVICES)
+ {
+ /* Get the newly selected device */
+ Letter = GetSelectedDriveLetter();
+ if (Letter != 0)
+ {
+ /* Setup its name */
+ szText[0] = Letter;
+ szText[1] = L':';
+ szText[2] = 0;
+
+ /* And get its capacities */
+ if (GetDiskFreeSpace(szText, &ClusterSector, &SectorSize, &FreeClusters, &Clusters))
+ {
+ /* Nota: the application returns the total amount of clusters and sectors
+ * So, compute it
+ */
+ Sectors = ClusterSector * Clusters;
+
+ /* And now, update statistics about the device */
+ hEditText = GetDlgItem(hWnd, IDC_MAINSECTORS);
+ wsprintf(szText, L"%ld", Sectors);
+ SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
+
+ hEditText = GetDlgItem(hWnd, IDC_MAINSIZE);
+ wsprintf(szText, L"%ld", SectorSize);
+ SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
+
+ hEditText = GetDlgItem(hWnd, IDC_MAINFREE);
+ wsprintf(szText, L"%ld", FreeClusters);
+ SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
+
+ hEditText = GetDlgItem(hWnd, IDC_MAINTOTAL);
+ wsprintf(szText, L"%ld", Clusters);
+ SendMessage(hEditText, WM_SETTEXT, 0, (LPARAM)szText);
+
+ return TRUE;
+ }
+ }
+
+ /* We failed somewhere, make sure we're at 0 */
+ ResetStats();
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static
+INT_PTR
+CreateListViewColumns(HWND hDlg)
+{
+ WCHAR szText[255];
+ LVCOLUMNW lvColumn;
+ HWND hListView;
+
+ hWnd = hDlg;
+ hListView = GetDlgItem(hDlg, IDC_MAINDEVICES);
+
+ /* Select the whole line, not just the first column */
+ SendMessage(hListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
+
+ /* Set up the first column */
+ ZeroMemory(&lvColumn, sizeof(LVCOLUMNW));
+ lvColumn.pszText = szText;
+ lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
+ lvColumn.fmt = LVCFMT_LEFT;
+ lvColumn.cx = 100;
+ szText[0] = 0;
+ LoadString(hInstance, IDS_DRIVE, szText, sizeof(szText) / sizeof(WCHAR));
+ szText[(sizeof(szText) / sizeof(WCHAR)) - 1] = L'\0';
+ SendMessage(hListView, LVM_INSERTCOLUMNW, 0, (LPARAM)&lvColumn);
+
+ /* Set up the second column */
+ szText[0] = 0;
+ lvColumn.cx = 350;
+ LoadString(hInstance, IDS_MAPPEDIMAGE, szText, sizeof(szText) / sizeof(WCHAR));
+ szText[(sizeof(szText) / sizeof(WCHAR)) - 1] = L'\0';
+ SendMessage(hListView, LVM_INSERTCOLUMNW, 1, (LPARAM)&lvColumn);
+
+ /* Make sure stats are at 0 */
+ ResetStats();
+
+ /* And populate our device list */
+ RefreshDevicesList(0);
+
+ return TRUE;
+}
+
+static
+INT_PTR
+CALLBACK
+MainDialogProc(HWND hDlg,
+ UINT Message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ /* Dispatch the message */
+ switch (Message)
+ {
+ case WM_INITDIALOG:
+ return CreateListViewColumns(hDlg);
+
+ case WM_COMMAND:
+ return HandleCommand(wParam, lParam);
+
+ case WM_NOTIFY:
+ return HandleNotify(lParam);
+
+ case WM_CLOSE:
+ return DestroyWindow(hDlg);
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+INT
+WINAPI
+wWinMain(HINSTANCE hInst,
+ HINSTANCE hPrev,
+ LPWSTR Cmd,
+ int iCmd)
+{
+ MSG Msg;
+
+ hInstance = hInst;
+
+ /* Just start our main window */
+ hWnd = CreateDialogParamW(hInst,
+ MAKEINTRESOURCE(IDD_MAINWINDOW),
+ NULL,
+ MainDialogProc,
+ 0);
+ /* And dispatch messages in case of a success */
+ if (hWnd != NULL)
+ {
+ while (GetMessageW(&Msg, NULL, 0, 0) != 0)
+ {
+ TranslateMessage(&Msg);
+ DispatchMessageW(&Msg);
+ }
+ }
+
+ return 0;
+}