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 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 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 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 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 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 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 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 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 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 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 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 418 Min(DWORD a, DWORD b) 419 { 420 return (a > b ? b : a); 421 } 422 423 static 424 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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