4 Virtual Floppy Drive for Windows
6 Driver and image control functions
8 Copyright (C) 2003-2005 Ken Kato
12 #pragma message(__FILE__": Compiled as C++ for testing purpose.")
15 #define WIN32_LEAN_AND_MEAN
19 #pragma warning (push, 3)
34 #ifndef IOCTL_DISK_GET_LENGTH_INFO
35 // Old winioctl.h header doesn't define the following
37 #define IOCTL_DISK_GET_LENGTH_INFO CTL_CODE(\
38 IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS)
40 typedef struct _GET_LENGTH_INFORMATION
{
42 } GET_LENGTH_INFORMATION
, *PGET_LENGTH_INFORMATION
;
44 #endif // IOCTL_DISK_GET_LENGTH_INFO
47 // DOS device name (\\.\VirtualFD)
50 #define VFD_DEVICE_TEMPLATE "\\\\.\\" VFD_DEVICE_BASENAME "%u"
52 #define VFD_DEVICE_TEMPLATE "\\\\.\\" VFD_DEVICE_BASENAME "%lu"
54 #define VFD_VOLUME_TEMPLATE "\\\\.\\%c:"
56 #define VFD_INSTALL_DIRECTORY "\\system32\\drivers\\"
60 extern ULONG TraceFlags
= (ULONG
)-1;//0;
61 extern CHAR
*TraceFile
= NULL
;
62 extern ULONG TraceLine
= 0;
64 ULONG TraceFlags
= (ULONG
)-1;//0;
65 CHAR
const * TraceFile
= NULL
;
71 // broadcast a WM_DEVICECHANGE system message to inform
72 // a drive letter creation / removal
74 #define VFD_LINK_CREATED 0
75 #define VFD_LINK_REMOVED 1
77 static void VfdBroadcastLink(
83 DEV_BROADCAST_VOLUME params
;
85 if (!isalpha(cLetter
)) {
87 ("VfdBroadcastLink: invalid parameter"))
91 receipients
= BSM_APPLICATIONS
;
93 device_event
= bRemoved
?
94 DBT_DEVICEREMOVECOMPLETE
: DBT_DEVICEARRIVAL
;
96 ZeroMemory(¶ms
, sizeof(params
));
98 params
.dbcv_size
= sizeof(params
);
99 params
.dbcv_devicetype
= DBT_DEVTYP_VOLUME
;
100 params
.dbcv_reserved
= 0;
101 params
.dbcv_unitmask
= (1 << (toupper(cLetter
) - 'A'));
102 params
.dbcv_flags
= 0;
104 if (BroadcastSystemMessage(
105 BSF_NOHANG
| BSF_FORCEIFHUNG
| BSF_NOTIMEOUTIFNOTHUNG
,
109 (LPARAM
)¶ms
) <= 0) {
112 ("VfdBroadcastLink: BroadcastSystemMessage - %s",
113 SystemMessage(GetLastError())));
118 // Broadcast a VFD notify message
120 static __inline
void VfdNotify(
124 // SendNotifyMessage causes volume locking conflict (I think)
125 // on Windows XP while closing an image with VfdWin
126 // SendNotifyMessage(HWND_BROADCAST, uVfdMsg, wParam, lParam);
127 PostMessage(HWND_BROADCAST
, g_nNotifyMsg
, wParam
, lParam
);
130 #ifdef VFD_EMBED_DRIVER
132 // Restore the VFD driver file in the system directory
135 static DWORD
VfdRestoreDriver(
138 #define FUNC "VfdRestoreDriver"
148 // Prepare driver binary
151 // use embedded driver binary
154 hRes
= FindResource(g_hDllModule
,
155 S(VFD_DRIVER_NAME_ID
), S(VFD_DRIVER_TYPE_ID
));
159 ret
= GetLastError();
162 (FUNC
": FindResource - %s",
163 SystemMessage(ret
)));
168 size
= SizeofResource(g_hDllModule
, hRes
);
171 ret
= GetLastError();
174 (FUNC
": SizeofResource - %s",
175 SystemMessage(ret
)));
180 hDrv
= LoadResource(g_hDllModule
, hRes
);
183 ret
= GetLastError();
186 (FUNC
": LoadResource - %s",
187 SystemMessage(ret
)));
192 pData
= LockResource(hDrv
);
195 ret
= GetLastError();
198 (FUNC
": LockResource - %s",
199 SystemMessage(ret
)));
204 // create the driver file
206 hFile
= CreateFile(sPath
, GENERIC_WRITE
,
207 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
209 if (hFile
== INVALID_HANDLE_VALUE
) {
210 ret
= GetLastError();
213 (FUNC
": CreateFile(%s) - %s",
214 sPath
, SystemMessage(ret
)));
219 if (!WriteFile(hFile
, pData
, size
, &result
, NULL
) ||
221 ret
= GetLastError();
224 (FUNC
": CreateFile - %s",
225 SystemMessage(ret
)));
234 return ERROR_SUCCESS
;
236 #endif // VFD_EMBED_DRIVER
239 // Install the Virtual Floppy Driver
241 DWORD WINAPI
VfdInstallDriver(
246 #define FUNC "VfdInstallDriver"
247 SC_HANDLE hScManager
; // Service Control Manager
248 SC_HANDLE hService
= NULL
; // Service (= Driver)
249 #ifndef VFD_EMBED_DRIVER
250 CHAR file_path
[MAX_PATH
];
252 #endif // VFD_EMBED_DRIVER
253 CHAR system_dir
[MAX_PATH
];
256 DWORD ret
= ERROR_SUCCESS
;
258 // get SystemRoot directory path
260 // len = GetEnvironmentVariable(
261 // "SystemRoot", system_dir, sizeof(system_dir));
262 len
= GetWindowsDirectory(system_dir
, sizeof(system_dir
));
264 if (len
== 0 || len
> sizeof(system_dir
)) {
266 (FUNC
": %%SystemRoot%% is empty or too long.\n"));
268 return ERROR_BAD_ENVIRONMENT
;
271 inst_path
= &system_dir
[len
];
273 #ifdef VFD_EMBED_DRIVER
275 // use embedded driver file
277 strcpy(inst_path
++, VFD_INSTALL_DIRECTORY VFD_DRIVER_FILENAME
);
279 ret
= VfdRestoreDriver(system_dir
);
281 if (ret
!= ERROR_SUCCESS
) {
285 #else // VFD_EMBED_DRIVER
286 // Prepare driver binary's full path
288 if (sFileName
== NULL
|| *sFileName
== '\0') {
290 // default driver file is vfd.sys in the same directory as executable
292 len
= GetModuleFileName(
293 NULL
, file_path
, sizeof(file_path
));
296 ret
= GetLastError();
299 (FUNC
": GetModuleFileName - %s",
300 SystemMessage(ret
)));
305 // search the last '\' character
307 while (len
> 0 && file_path
[len
- 1] != '\\') {
311 // supply the file name (vfd.sys)
313 file_name
= &file_path
[len
];
314 strcpy(file_name
, VFD_DRIVER_FILENAME
);
318 // ensure that tha path is an absolute full path
320 len
= GetFullPathName(
327 ret
= GetLastError();
330 (FUNC
": GetFullPathName(%s) - %s\n",
331 sFileName
, SystemMessage(ret
)));
336 if (GetFileAttributes(file_path
) & FILE_ATTRIBUTE_DIRECTORY
) {
337 // if the specified path is a directory,
338 // supply the file name (vfd.sys)
340 file_name
= &file_path
[len
];
341 strcpy(file_name
++, "\\" VFD_DRIVER_FILENAME
);
345 // Check if the file is a valid Virtual Floppy driver
347 ret
= VfdCheckDriverFile(file_path
, NULL
);
349 if (ret
!= ERROR_SUCCESS
) {
351 (FUNC
": VfdCheckDriverFile(%s)\n", file_path
));
356 // if the path is under the system directory, make it relative
357 // to the system directory
359 len
= strlen(system_dir
);
361 if (!_strnicmp(file_path
, system_dir
, len
)) {
362 inst_path
= &file_path
[len
];
364 while (*inst_path
== '\\') {
369 inst_path
= &file_path
[0];
371 #endif // VFD_EMBED_DRIVER
373 // Connect to the Service Control Manager
375 hScManager
= OpenSCManager(
376 NULL
, // local machine
377 NULL
, // local database
378 SC_MANAGER_CREATE_SERVICE
); // access required
380 if (hScManager
== NULL
) {
381 ret
= GetLastError();
384 (FUNC
": OpenSCManager() - %s",
385 SystemMessage(ret
)));
390 // Create a new service object
392 hService
= CreateService(
393 hScManager
, // service control manager
394 VFD_DEVICE_BASENAME
, // internal service name
395 VFD_DEVICE_BASENAME
, // display name
396 SERVICE_ALL_ACCESS
, // access mode
397 SERVICE_KERNEL_DRIVER
, // service type
398 nStart
, // service start type
399 SERVICE_ERROR_NORMAL
, // start error sevirity
400 inst_path
, // service image file path
401 NULL
, // service group
403 NULL
, // service dependency
404 NULL
, // use LocalSystem account
405 NULL
// password for the account
409 // Failed to create a service object
410 ret
= GetLastError();
413 (FUNC
": CreateService() - %s",
414 SystemMessage(ret
)));
420 // Close the service object handle
423 CloseServiceHandle(hService
);
426 // Close handle to the service control manager.
429 CloseServiceHandle(hScManager
);
432 if (ret
== ERROR_SUCCESS
) {
433 // Broadcast the successful operation
434 VfdNotify(VFD_OPERATION_INSTALL
, 0);
436 #ifdef VFD_EMBED_DRIVER
438 // Delete the restored driver file
439 DeleteFile(system_dir
);
441 #endif // VFD_EMBED_DRIVER
447 // Configure the Virtual Floppy Driver (change the start method)
450 DWORD WINAPI
VfdConfigDriver(
454 #define FUNC "VfdConfigDriver"
455 SC_HANDLE hScManager
; // Service Control Manager
456 SC_HANDLE hService
; // Service (= Driver)
457 DWORD ret
= ERROR_SUCCESS
;
459 // Connect to the Service Control Manager
461 hScManager
= OpenSCManager(NULL
, NULL
, 0);
463 if (hScManager
== NULL
) {
464 ret
= GetLastError();
467 (FUNC
": OpenSCManager() - %s",
468 SystemMessage(ret
)));
473 // Open the VFD driver entry in the service database
475 hService
= OpenService(
476 hScManager
, // Service control manager
477 VFD_DEVICE_BASENAME
, // service name
478 SERVICE_CHANGE_CONFIG
); // service access mode
480 if (hService
== NULL
) {
481 ret
= GetLastError();
484 (FUNC
": OpenService(SERVICE_CHANGE_CONFIG) - %s",
485 SystemMessage(ret
)));
490 // Change the start method of the VFD driver
492 if (!ChangeServiceConfig(
505 ret
= GetLastError();
508 (FUNC
": ChangeServiceConfig() - %s",
509 SystemMessage(ret
)));
515 // Close the service object handle
518 CloseServiceHandle(hService
);
521 // Close handle to the service control manager.
524 CloseServiceHandle(hScManager
);
527 // Broadcast the successful operation
529 if (ret
== ERROR_SUCCESS
) {
530 VfdNotify(VFD_OPERATION_CONFIG
, 0);
537 // Remove the Virtual Floppy Driver entry from the service database
539 DWORD WINAPI
VfdRemoveDriver()
542 #define FUNC "VfdRemoveDriver"
543 SC_HANDLE hScManager
; // Service Control Manager
544 SC_HANDLE hService
; // Service (= Driver)
545 CHAR file_path
[MAX_PATH
];
546 DWORD ret
= ERROR_SUCCESS
;
548 // Get the current driver path
550 ret
= VfdGetDriverConfig(file_path
, NULL
);
552 if (ret
!= ERROR_SUCCESS
) {
556 // Connect to the Service Control Manager
558 hScManager
= OpenSCManager(NULL
, NULL
, 0);
560 if (hScManager
== NULL
) {
561 ret
= GetLastError();
564 (FUNC
": OpenSCManager() - %s",
565 SystemMessage(ret
)));
570 // Open the VFD driver entry in the service database
572 hService
= OpenService(
573 hScManager
, // Service control manager
574 VFD_DEVICE_BASENAME
, // service name
575 DELETE
); // service access mode
577 if (hService
== NULL
) {
578 ret
= GetLastError();
581 (FUNC
": OpenService(DELETE) - %s",
582 SystemMessage(ret
)));
587 // Remove driver entry from registry
589 if (!DeleteService(hService
)) {
590 ret
= GetLastError();
593 (FUNC
": DeleteService() - %s",
594 SystemMessage(ret
)));
600 // Close the service object handle
603 CloseServiceHandle(hService
);
606 // Close handle to the service control manager.
609 CloseServiceHandle(hScManager
);
612 // Broadcast the successful operation
614 if (ret
== ERROR_SUCCESS
) {
615 VfdNotify(VFD_OPERATION_REMOVE
, 0);
617 #ifdef VFD_EMBED_DRIVER
618 // Remove the driver file
619 DeleteFile(file_path
);
620 #endif // VFD_EMBED_DRIVER
627 // Start the Virtual Floppy Driver
629 DWORD WINAPI
VfdStartDriver(
633 #define FUNC "VfdStartDriver"
634 SC_HANDLE hScManager
; // Service Control Manager
635 SC_HANDLE hService
; // Service (= Driver)
637 DWORD ret
= ERROR_SUCCESS
;
645 // Connect to the Service Control Manager
647 hScManager
= OpenSCManager(NULL
, NULL
, 0);
649 if (hScManager
== NULL
) {
650 ret
= GetLastError();
653 (FUNC
": OpenSCManager() - %s",
654 SystemMessage(ret
)));
659 // show an hourglass cursor
661 original
= SetCursor(LoadCursor(NULL
, IDC_WAIT
));
663 // Open the VFD driver entry in the service database
665 hService
= OpenService(
666 hScManager
, // Service control manager
667 VFD_DEVICE_BASENAME
, // service name
669 | SERVICE_QUERY_STATUS
); // service access mode
671 if (hService
== NULL
) {
672 ret
= GetLastError();
675 (FUNC
": OpenService(SERVICE_START) - %s",
676 SystemMessage(ret
)));
683 if (!StartService(hService
, 0, NULL
)) {
684 ret
= GetLastError();
687 (FUNC
": StartService() - %s",
688 SystemMessage(ret
)));
693 // Wait until the driver is properly running
698 if (!QueryServiceStatus(hService
, &stat
)) {
699 ret
= GetLastError();
702 (FUNC
": QueryServiceStatus() - %s",
703 SystemMessage(ret
)));
708 if (stat
.dwCurrentState
== SERVICE_RUNNING
|| ++i
== 5) {
715 if (stat
.dwCurrentState
== SERVICE_RUNNING
) {
717 // Broadcast the successful operation
719 if (ret
== ERROR_SUCCESS
) {
720 VfdNotify(VFD_OPERATION_START
, 0);
723 // broadcast the arrival of VFD drives
724 // otherwise WinXP explorer doesn't recognize the VFD drives
726 for (i
= 0; i
< VFD_MAXIMUM_DEVICES
; i
++) {
730 hDevice
= VfdOpenDevice(i
);
732 if (hDevice
!= INVALID_HANDLE_VALUE
) {
734 VfdGetGlobalLink(hDevice
, &letter
);
736 CloseHandle(hDevice
);
738 if (isalpha(letter
)) {
739 VfdBroadcastLink(letter
, VFD_LINK_CREATED
);
740 VfdNotify(VFD_OPERATION_SETLINK
, i
);
745 (FUNC
": VfdOpenDevice(%d) - %s",
746 i
, SystemMessage(GetLastError())));
751 // somehow failed to start the driver
753 ret
= ERROR_SERVICE_NOT_ACTIVE
;
757 *pState
= stat
.dwCurrentState
;
761 // Close the service object handle
764 CloseServiceHandle(hService
);
767 // Close handle to the service control manager.
770 CloseServiceHandle(hScManager
);
773 // revert to the original cursor
781 // Stop the Virtual Floppy Driver
783 DWORD WINAPI
VfdStopDriver(
787 #define FUNC "VfdStopDriver"
788 SC_HANDLE hScManager
; // Service Control Manager
789 SC_HANDLE hService
; // Service (= Driver)
791 CHAR drive_letters
[VFD_MAXIMUM_DEVICES
];
792 DWORD ret
= ERROR_SUCCESS
;
800 // Connect to the Service Control Manager
802 hScManager
= OpenSCManager(NULL
, NULL
, 0);
804 if (hScManager
== NULL
) {
805 ret
= GetLastError();
808 (FUNC
": OpenSCManager() - %s",
809 SystemMessage(ret
)));
814 // Show the hourglass cursor
816 original
= SetCursor(LoadCursor(NULL
, IDC_WAIT
));
818 // Open the VFD driver entry in the service database
820 hService
= OpenService(
821 hScManager
, // Service control manager
822 VFD_DEVICE_BASENAME
, // service name
824 | SERVICE_QUERY_STATUS
); // service access mode
826 if (hService
== NULL
) {
827 ret
= GetLastError();
830 (FUNC
": OpenService(SERVICE_STOP) - %s",
831 SystemMessage(ret
)));
836 // Get assigned drive letters
838 for (i
= 0; i
< VFD_MAXIMUM_DEVICES
; i
++) {
842 hDevice
= VfdOpenDevice(i
);
844 if (hDevice
!= INVALID_HANDLE_VALUE
) {
846 // remove all session local drive letters
848 while (VfdGetLocalLink(hDevice
, &letter
) == ERROR_SUCCESS
&&
850 VfdSetLocalLink(hDevice
, 0);
853 // store existing persistent drive letters
855 VfdGetGlobalLink(hDevice
, &drive_letters
[i
]);
857 CloseHandle(hDevice
);
861 (FUNC
": VfdOpenDevice(%d) - %s",
862 i
, SystemMessage(GetLastError())));
868 if (!ControlService(hService
, SERVICE_CONTROL_STOP
, &stat
)) {
869 ret
= GetLastError();
872 (FUNC
": ControlService(SERVICE_CONTROL_STOP) - %s",
873 SystemMessage(ret
)));
878 // Wait until the driver is stopped
882 while (stat
.dwCurrentState
!= SERVICE_STOPPED
&& ++i
< 5) {
885 if (!QueryServiceStatus(hService
, &stat
)) {
886 ret
= GetLastError();
889 (FUNC
": QueryServiceStatus() - %s",
890 SystemMessage(ret
)));
896 if (stat
.dwCurrentState
!= SERVICE_RUNNING
) {
898 // broadcast the removal of persistent drive letters
900 for (i
= 0; i
< VFD_MAXIMUM_DEVICES
; i
++) {
901 if (isalpha(drive_letters
[i
])) {
902 VfdBroadcastLink(drive_letters
[i
], VFD_LINK_REMOVED
);
903 VfdNotify(VFD_OPERATION_DELLINK
, i
);
909 *pState
= stat
.dwCurrentState
;
913 // Close the service object handle
916 CloseServiceHandle(hService
);
919 // Close handle to the service control manager.
922 CloseServiceHandle(hScManager
);
925 // Broadcast the successful operation
927 if (ret
== ERROR_SUCCESS
) {
928 VfdNotify(VFD_OPERATION_STOP
, 0);
931 // revert to the original cursor
939 // Get the Virtual Floppy Driver configuration
941 DWORD WINAPI
VfdGetDriverConfig(
946 #define FUNC "VfdGetDriverConfig"
947 SC_HANDLE hScManager
; // Service Control Manager
948 SC_HANDLE hService
; // Service (= Driver)
949 LPQUERY_SERVICE_CONFIG config
= NULL
;
951 DWORD ret
= ERROR_SUCCESS
;
954 ZeroMemory(sFileName
, MAX_PATH
);
961 // Connect to the Service Control Manager
963 hScManager
= OpenSCManager(NULL
, NULL
, 0);
965 if (hScManager
== NULL
) {
966 ret
= GetLastError();
969 (FUNC
": OpenSCManager() - %s", SystemMessage(ret
)));
974 // Open the VFD driver entry in the service database
976 hService
= OpenService(
977 hScManager
, // Service control manager
978 VFD_DEVICE_BASENAME
, // service name
979 SERVICE_QUERY_CONFIG
); // service access mode
981 if (hService
== NULL
) {
982 ret
= GetLastError();
985 (FUNC
": OpenService(SERVICE_QUERY_CONFIG) - %s",
986 SystemMessage(ret
)));
991 // Get the length of config information
993 if (!QueryServiceConfig(hService
, NULL
, 0, &result
)) {
994 ret
= GetLastError();
996 if (ret
== ERROR_INSUFFICIENT_BUFFER
) {
1001 (FUNC
": QueryServiceConfig() - %s",
1002 SystemMessage(ret
)));
1008 // allocate a required buffer
1010 config
= (LPQUERY_SERVICE_CONFIG
)LocalAlloc(LPTR
, result
);
1012 if (config
== NULL
) {
1013 ret
= GetLastError();
1016 (FUNC
": LocalAlloc(%lu) - %s\n",
1017 result
, SystemMessage(ret
)));
1022 // get the config information
1024 if (!QueryServiceConfig(hService
, config
, result
, &result
)) {
1025 ret
= GetLastError();
1028 (FUNC
": QueryServiceConfig() - %s",
1029 SystemMessage(ret
)));
1034 // copy information to output buffer
1037 if (strncmp(config
->lpBinaryPathName
, "\\??\\", 4) == 0) {
1039 // driver path is an absolute UNC path
1042 config
->lpBinaryPathName
+ 4,
1045 else if (config
->lpBinaryPathName
[0] == '\\' ||
1046 (isalpha(config
->lpBinaryPathName
[0]) &&
1047 config
->lpBinaryPathName
[1] == ':')) {
1049 // driver path is an absolute path
1051 config
->lpBinaryPathName
,
1055 // driver path is relative to the SystemRoot
1056 // DWORD len = GetEnvironmentVariable(
1057 // "SystemRoot", sFileName, MAX_PATH);
1059 DWORD len
= GetWindowsDirectory(sFileName
, MAX_PATH
);
1061 if (len
== 0 || len
> MAX_PATH
) {
1063 (FUNC
": %%SystemRoot%% is empty or too long.\n"));
1065 ret
= ERROR_BAD_ENVIRONMENT
;
1069 sprintf((sFileName
+ len
), "\\%s",
1070 config
->lpBinaryPathName
);
1075 *pStart
= config
->dwStartType
;
1079 // Free service config buffer
1085 // Close the service object handle
1088 CloseServiceHandle(hService
);
1091 // Close handle to the service control manager.
1094 CloseServiceHandle(hScManager
);
1101 // Get the Virtual Floppy Driver running state
1103 DWORD WINAPI
VfdGetDriverState(
1107 #define FUNC "VfdGetDriverState"
1108 SC_HANDLE hScManager
= NULL
; // Service Control Manager
1109 SC_HANDLE hService
= NULL
; // Service (= Driver)
1110 SERVICE_STATUS status
;
1111 DWORD ret
= ERROR_SUCCESS
;
1117 // Connect to the Service Control Manager
1119 hScManager
= OpenSCManager(NULL
, NULL
, 0);
1121 if (hScManager
== NULL
) {
1122 ret
= GetLastError();
1125 (FUNC
": OpenSCManager() - %s",
1126 SystemMessage(ret
)));
1131 // Open the VFD driver entry in the service database
1133 hService
= OpenService(
1134 hScManager
, // Service control manager
1135 VFD_DEVICE_BASENAME
, // service name
1136 SERVICE_QUERY_STATUS
); // service access mode
1138 if (hService
== NULL
) {
1140 ret
= GetLastError();
1142 if (ret
== ERROR_SERVICE_DOES_NOT_EXIST
) {
1145 *pState
= VFD_NOT_INSTALLED
;
1148 ret
= ERROR_SUCCESS
;
1152 (FUNC
": OpenService(SERVICE_QUERY_STATUS) - %s",
1153 SystemMessage(ret
)));
1159 // Get current driver status
1161 ZeroMemory(&status
, sizeof(status
));
1163 if (!QueryServiceStatus(hService
, &status
)) {
1164 ret
= GetLastError();
1167 (FUNC
": QueryServiceStatus() - %s",
1168 SystemMessage(ret
)));
1174 *pState
= status
.dwCurrentState
;
1178 // Close the service object handle
1181 CloseServiceHandle(hService
);
1184 // Close handle to the service control manager.
1187 CloseServiceHandle(hScManager
);
1194 // open a Virtual Floppy drive without showing the "Insert Floppy"
1195 // dialog when the drive is empty.
1197 HANDLE WINAPI
VfdOpenDevice(
1198 ULONG nTarget
) // either a drive letter or a device number
1201 #define FUNC "VfdOpenDevice"
1206 // format a device name string
1208 if (isalpha(nTarget
)) {
1209 // nTarget is a drive letter
1212 sprintf(dev_name
, VFD_VOLUME_TEMPLATE
, nTarget
);
1214 sprintf(dev_name
, VFD_VOLUME_TEMPLATE
, (CHAR
)nTarget
);
1217 else if (isdigit(nTarget
)) {
1218 // nTarget is a device number in character
1220 sprintf(dev_name
, VFD_DEVICE_TEMPLATE
, nTarget
- '0');
1223 // nTarget is a device number value
1225 sprintf(dev_name
, VFD_DEVICE_TEMPLATE
, nTarget
);
1228 // change error mode in order to avoid "Insert Floppy" dialog
1230 err_mode
= SetErrorMode(SEM_FAILCRITICALERRORS
);
1232 // open the target drive
1234 hDevice
= CreateFile(
1236 GENERIC_READ
| GENERIC_WRITE
,
1237 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1240 FILE_FLAG_NO_BUFFERING
,
1243 // revert to the original error mode
1245 SetErrorMode(err_mode
);
1247 if (hDevice
!= INVALID_HANDLE_VALUE
) {
1249 // check if the target is a valid VFD drive
1253 if (VfdGetDriverVersion(hDevice
, &version
) != ERROR_SUCCESS
) {
1255 // Failed to get the driver version
1257 CloseHandle(hDevice
);
1258 hDevice
= INVALID_HANDLE_VALUE
;
1260 else if ((version
& ~0x80000000) !=
1261 MAKELONG(VFD_DRIVER_MINOR
, VFD_DRIVER_MAJOR
)) {
1263 // the driver version mismatch
1265 // CloseHandle(hDevice);
1266 // hDevice = INVALID_HANDLE_VALUE;
1268 SetLastError(ERROR_REVISION_MISMATCH
);
1273 "CreateFile(%s) - %s", dev_name
,
1274 SystemMessage(GetLastError())));;
1281 // Open a Virtual Floppy Image
1283 DWORD WINAPI
VfdOpenImage(
1286 VFD_DISKTYPE nDiskType
,
1287 VFD_MEDIA nMediaType
,
1288 VFD_FLAGS nMediaFlags
)
1291 #define FUNC "VfdOpenImage"
1293 CHAR abspath
[MAX_PATH
];
1296 DWORD ret
= ERROR_SUCCESS
;
1298 PVFD_IMAGE_INFO image_info
= NULL
;
1299 PUCHAR image_buf
= NULL
;
1301 VFD_FILETYPE file_type
;
1307 if (hDevice
== NULL
||
1308 hDevice
== INVALID_HANDLE_VALUE
) {
1309 return ERROR_INVALID_HANDLE
;
1312 if (nMediaType
== VFD_MEDIA_NONE
||
1313 nMediaType
>= VFD_MEDIA_MAX
) {
1316 (FUNC
": Invalid MediaType - %u\n", nMediaType
));
1318 return ERROR_INVALID_PARAMETER
;
1322 if (sFileName
&& *sFileName
) {
1324 // check file contents and attributes
1326 HANDLE hFile
= CreateFile(sFileName
, GENERIC_READ
,
1327 FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
1329 if (hFile
== INVALID_HANDLE_VALUE
) {
1330 ret
= GetLastError();
1333 (FUNC
": CreateFile(%s) - %s",
1334 sFileName
, SystemMessage(ret
)));
1339 // try extracting image data from zip compressed file
1341 ExtractZipImage(hFile
, &image_buf
, &image_size
);
1345 file_type
= VFD_FILETYPE_ZIP
;
1347 // imz file must be opened in RAM mode
1349 if (nDiskType
== VFD_DISKTYPE_FILE
) {
1352 (FUNC
": %s is a zip compressed file",
1356 ret
= ERROR_INVALID_PARAMETER
;
1363 file_type
= VFD_FILETYPE_RAW
;
1365 if (nDiskType
== VFD_DISKTYPE_FILE
) {
1367 // direct image file must not be compressed or encrypted
1369 BY_HANDLE_FILE_INFORMATION info
;
1371 if (!GetFileInformationByHandle(hFile
, &info
)) {
1372 ret
= GetLastError();
1375 (FUNC
": GetFileInformationByHandle - %s",
1376 SystemMessage(ret
)));
1383 if (info
.dwFileAttributes
&
1384 (FILE_ATTRIBUTE_COMPRESSED
| FILE_ATTRIBUTE_ENCRYPTED
)) {
1387 (FUNC
": file is compressed/encrypted"));
1391 return ERROR_FILE_ENCRYPTED
;
1394 image_size
= info
.nFileSizeLow
;
1398 // prepare image data for a file based RAM disk
1400 image_size
= GetFileSize(hFile
, NULL
);
1402 if (image_size
== 0 || image_size
== INVALID_FILE_SIZE
) {
1403 ret
= GetLastError();
1406 (FUNC
": GetFileSize - %s",
1407 SystemMessage(ret
)));
1414 image_buf
= (PUCHAR
)LocalAlloc(LPTR
, image_size
);
1416 if (image_buf
== NULL
) {
1417 ret
= GetLastError();
1420 (FUNC
": LocalAlloc - %s",
1421 SystemMessage(ret
)));
1428 if (SetFilePointer(hFile
, 0, NULL
, FILE_BEGIN
) != 0) {
1429 ret
= GetLastError();
1432 (FUNC
": SetFilePointer - %s",
1433 SystemMessage(ret
)));
1440 if (!ReadFile(hFile
, image_buf
, image_size
, &result
, NULL
) ||
1441 image_size
!= result
) {
1443 ret
= GetLastError();
1446 (FUNC
": ReadFile - %s",
1447 SystemMessage(ret
)));
1458 // Prepare absolute path in the kernel namespace
1460 if (*sFileName
== '\\' && *(sFileName
+ 1) == '\\') {
1462 // \\server\share\path\floppy.img
1464 prefix
= "\\??\\UNC";
1465 sFileName
++; // drip the first '\'
1473 if (GetFullPathName(sFileName
,
1474 sizeof(abspath
), abspath
, &file_part
) == 0) {
1476 ret
= GetLastError();
1479 (FUNC
": GetFullPathName(%s) - %s\n",
1480 sFileName
, SystemMessage(ret
)));
1486 sFileName
= abspath
;
1489 name_len
= strlen(prefix
) + strlen(sFileName
);
1493 // filename is not specified -- pure RAM disk
1495 nDiskType
= VFD_DISKTYPE_RAM
;
1496 file_type
= VFD_FILETYPE_NONE
;
1501 // prepare a FAT formatted RAM image
1503 image_size
= VfdGetMediaSize(nMediaType
);
1505 image_buf
= (PUCHAR
)LocalAlloc(LPTR
, image_size
);
1507 if (image_buf
== NULL
) {
1508 ret
= GetLastError();
1511 (FUNC
": LocalAlloc - %s",
1512 SystemMessage(ret
)));
1517 FormatBufferFat(image_buf
, VFD_BYTE_TO_SECTOR(image_size
));
1520 if (image_size
< VfdGetMediaSize(nMediaType
)) {
1522 // image is too small for the specified media type
1525 (FUNC
": Image is too small for the specified media type\n"));
1527 ret
= ERROR_INVALID_PARAMETER
;
1531 // prepare VFD_IMAGE_INFO structure
1533 image_info
= (PVFD_IMAGE_INFO
)LocalAlloc(LPTR
,
1534 sizeof(VFD_IMAGE_INFO
) + name_len
+ 1);
1536 if (image_info
== NULL
) {
1537 ret
= GetLastError();
1540 (FUNC
": LocalAlloc(%lu) - %s\n",
1541 sizeof(VFD_IMAGE_INFO
) + name_len
+ 1,
1542 SystemMessage(ret
)));
1547 ZeroMemory(image_info
,
1548 sizeof(VFD_IMAGE_INFO
) + name_len
+ 1);
1551 sprintf(image_info
->FileName
,
1552 "%s%s", prefix
, sFileName
);
1555 image_info
->NameLength
= (USHORT
)name_len
;
1557 image_info
->DiskType
= nDiskType
;
1558 image_info
->MediaType
= nMediaType
;
1559 image_info
->MediaFlags
= nMediaFlags
;
1560 image_info
->FileType
= file_type
;
1561 image_info
->ImageSize
= image_size
;
1563 if (nDiskType
!= VFD_DISKTYPE_FILE
) {
1564 // protect flag for a RAM disk is set after
1565 // initializing the image buffer
1566 image_info
->MediaFlags
&= ~VFD_FLAG_WRITE_PROTECTED
;
1570 (FUNC
": Opening file \"%s\" (%lu bytes) %s %s %s %s\n",
1571 name_len
? image_info
->FileName
: "<RAM>",
1572 image_info
->ImageSize
,
1573 (file_type
== VFD_FILETYPE_ZIP
) ? "ZIP image" : "RAW image",
1574 VfdMediaTypeName(nMediaType
),
1575 (nDiskType
== VFD_DISKTYPE_FILE
) ? "FILE disk" : "RAM disk",
1576 (nMediaFlags
& VFD_FLAG_WRITE_PROTECTED
) ? "Protected" : "Writable"));
1578 // Open the image file / create a ram disk
1580 if (!DeviceIoControl(
1582 IOCTL_VFD_OPEN_IMAGE
,
1584 sizeof(VFD_IMAGE_INFO
) + name_len
,
1590 ret
= GetLastError();
1593 (FUNC
": DeviceIoControl(IOCTL_VFD_OPEN_FILE) - %s",
1594 SystemMessage(ret
)));
1599 // initialize the RAM disk image
1601 if (nDiskType
!= VFD_DISKTYPE_FILE
) {
1603 image_size
&= ~VFD_SECTOR_ALIGN_MASK
;
1605 if (SetFilePointer(hDevice
, 0, NULL
, FILE_BEGIN
) != 0) {
1606 ret
= GetLastError();
1609 (FUNC
": SetFilePointer - %s",
1610 SystemMessage(ret
)));
1615 if (!WriteFile(hDevice
, image_buf
, image_size
, &result
, NULL
) ||
1616 image_size
!= result
) {
1618 ret
= GetLastError();
1621 (FUNC
": WriteFile - %s",
1622 SystemMessage(ret
)));
1627 if (nMediaFlags
& VFD_FLAG_WRITE_PROTECTED
) {
1628 VfdWriteProtect(hDevice
, TRUE
);
1631 if (!DeviceIoControl(
1633 IOCTL_VFD_RESET_MODIFY
,
1642 (FUNC
": DeviceIoControl(IOCTL_VFD_RESET_MODIFY) - %s",
1643 SystemMessage(GetLastError())));
1647 // Broadcast the successful operation
1649 if (ret
== ERROR_SUCCESS
) {
1651 CHAR root
[] = "A:\\";
1653 if (VfdGetDeviceNumber(hDevice
, &number
) == ERROR_SUCCESS
) {
1654 VfdNotify(VFD_OPERATION_OPEN
, number
);
1657 VfdGetGlobalLink(hDevice
, &root
[0]);
1659 if (isalpha(root
[0])) {
1660 SHChangeNotify(SHCNE_MEDIAINSERTED
, SHCNF_PATH
, root
, NULL
);
1663 while (VfdGetLocalLink(hDevice
, &root
[0]) == ERROR_SUCCESS
&&
1665 SHChangeNotify(SHCNE_MEDIAINSERTED
, SHCNF_PATH
, root
, NULL
);
1671 LocalFree(image_info
);
1675 LocalFree(image_buf
);
1682 // Close the virtual floppy Image
1684 DWORD WINAPI
VfdCloseImage(
1689 #define FUNC "VfdCloseImage"
1691 DWORD ret
= ERROR_SUCCESS
;
1695 if (!DeviceIoControl(
1705 ret
= GetLastError();
1708 (FUNC
": DeviceIoControl(FSCTL_LOCK_VOLUME) - %s",
1709 SystemMessage(ret
)));
1711 if (ret
!= ERROR_ACCESS_DENIED
|| retry
== 5) {
1712 // error other than access denied or
1713 // operation kept failing for 5 seconds
1718 // error is access denied and
1719 // the force flag is not set
1723 // send the MEDIAREMOVED notification to the shell and
1724 // see if the shell releases the target drive
1726 CHAR root
[] = "A:\\";
1728 VfdGetGlobalLink(hDevice
, &root
[0]);
1730 if (isalpha(root
[0])) {
1731 SHChangeNotify(SHCNE_MEDIAREMOVED
, SHCNF_PATH
, root
, NULL
);
1734 while (VfdGetLocalLink(hDevice
, &root
[0]) == ERROR_SUCCESS
&&
1736 SHChangeNotify(SHCNE_MEDIAREMOVED
, SHCNF_PATH
, root
, NULL
);
1747 ret
= ERROR_SUCCESS
;
1749 if (!DeviceIoControl(
1751 FSCTL_DISMOUNT_VOLUME
,
1759 ret
= GetLastError();
1762 (FUNC
": DeviceIoControl(FSCTL_DISMOUNT_VOLUME) - %s",
1763 SystemMessage(ret
)));
1768 if (!DeviceIoControl(
1770 IOCTL_VFD_CLOSE_IMAGE
,
1778 ret
= GetLastError();
1780 if (ret
!= ERROR_NOT_READY
) {
1782 (FUNC
": DeviceIoControl(IOCTL_VFD_CLOSE_FILE) - %s",
1783 SystemMessage(ret
)));
1789 if (!DeviceIoControl(
1791 FSCTL_UNLOCK_VOLUME
,
1799 // This should not be fatal because the volume is unlocked
1800 // when the handle is closed anyway
1802 (FUNC
": DeviceIoControl(FSCTL_UNLOCK_VOLUME) - %s",
1803 SystemMessage(GetLastError())));
1806 // Broadcast the successful operation
1807 if (ret
== ERROR_SUCCESS
) {
1810 if (VfdGetDeviceNumber(hDevice
, &number
) == ERROR_SUCCESS
) {
1811 VfdNotify(VFD_OPERATION_CLOSE
, number
);
1819 // Get Virtual Floppy image info
1821 DWORD WINAPI
VfdGetImageInfo(
1824 PVFD_DISKTYPE pDiskType
,
1825 PVFD_MEDIA pMediaType
,
1826 PVFD_FLAGS pMediaFlags
,
1827 PVFD_FILETYPE pFileType
,
1831 #define FUNC "VfdGetImageInfo"
1832 PVFD_IMAGE_INFO image_info
;
1834 DWORD ret
= ERROR_SUCCESS
;
1836 image_info
= (PVFD_IMAGE_INFO
)LocalAlloc(
1837 LPTR
, sizeof(VFD_IMAGE_INFO
) + MAX_PATH
);
1839 if (image_info
== NULL
) {
1840 ret
= GetLastError();
1843 (FUNC
": LocalAlloc(%lu) - %s\n",
1844 sizeof(VFD_IMAGE_INFO
) + MAX_PATH
, SystemMessage(ret
)));
1849 ZeroMemory(image_info
, sizeof(VFD_IMAGE_INFO
) + MAX_PATH
);
1851 // Query file information
1853 if (!DeviceIoControl(
1855 IOCTL_VFD_QUERY_IMAGE
,
1859 sizeof(VFD_IMAGE_INFO
) + MAX_PATH
,
1863 ret
= GetLastError();
1865 if (ret
!= ERROR_MORE_DATA
) {
1867 (FUNC
": DeviceIoControl(IOCTL_VFD_QUERY_FILE) - %s",
1868 SystemMessage(ret
)));
1874 // copy obtained information to output buffer
1878 // if filename is too long, clip it
1880 if (image_info
->NameLength
>= MAX_PATH
) {
1881 image_info
->NameLength
= MAX_PATH
- 1;
1884 // ensure the name is properly terminated
1886 image_info
->FileName
[image_info
->NameLength
] = '\0';
1888 if (strncmp(image_info
->FileName
, "\\??\\UNC", 7) == 0) {
1890 strcpy(sFileName
+ 1, image_info
->FileName
+ 7);
1892 else if (strncmp(image_info
->FileName
, "\\??\\", 4) == 0) {
1893 strcpy(sFileName
, image_info
->FileName
+ 4);
1896 strcpy(sFileName
, image_info
->FileName
);
1901 *pDiskType
= image_info
->DiskType
;
1905 *pMediaType
= image_info
->MediaType
;
1909 *pMediaFlags
= image_info
->MediaFlags
;
1913 *pFileType
= image_info
->FileType
;
1917 *pImageSize
= image_info
->ImageSize
;
1922 LocalFree(image_info
);
1929 // Get current media state (opened / write protected)
1931 DWORD WINAPI
VfdGetMediaState(
1935 #define FUNC "VfdGetMediaState"
1937 DWORD ret
= ERROR_SUCCESS
;
1939 // Query file information
1941 if (!DeviceIoControl(
1943 IOCTL_DISK_IS_WRITABLE
,
1951 ret
= GetLastError();
1953 if (ret
!= ERROR_NOT_READY
) {
1955 (FUNC
": DeviceIoControl(IOCTL_DISK_IS_WRITABLE) - %s",
1956 SystemMessage(ret
)));
1964 // Set or Delete a global drive letter
1966 DWORD WINAPI
VfdSetGlobalLink(
1971 #define FUNC "VfdSetGlobalLink"
1977 if (isalpha(cLetter
)) {
1979 // make sure the drive does not have a drive letter
1983 VfdGetGlobalLink(hDevice
, &letter
);
1985 if (isalpha(letter
)) {
1987 (FUNC
": Drive already has a drive letter %c\n", letter
));
1988 return ERROR_ALREADY_ASSIGNED
;
1991 VfdGetLocalLink(hDevice
, &letter
);
1993 if (isalpha(letter
)) {
1995 (FUNC
": Drive already has a drive letter %c\n", letter
));
1996 return ERROR_ALREADY_ASSIGNED
;
1999 // make sure drive letter is not in use
2001 cLetter
= (CHAR
)toupper(cLetter
);
2003 if (GetLogicalDrives() & (1 << (cLetter
- 'A'))) {
2005 (FUNC
": Drive letter %c already used\n", cLetter
));
2006 return ERROR_ALREADY_ASSIGNED
;
2009 // Assign a new drive letter
2011 if (!DeviceIoControl(
2021 ret
= GetLastError();
2024 (FUNC
": DeviceIoControl(IOCTL_VFD_SET_LINK) - %s",
2025 SystemMessage(ret
)));
2030 // broadcast system message
2032 VfdBroadcastLink(cLetter
, VFD_LINK_CREATED
);
2034 // broadcast VFD message
2036 if (VfdGetDeviceNumber(hDevice
, &number
) == ERROR_SUCCESS
) {
2037 VfdNotify(VFD_OPERATION_SETLINK
, number
);
2040 return ERROR_SUCCESS
;
2042 else if (!cLetter
) {
2044 // make sure the drive has a global drive letter
2048 VfdGetGlobalLink(hDevice
, &letter
);
2050 if (!isalpha(letter
)) {
2052 (FUNC
": Drive does not have a drive letter\n"));
2053 return ERROR_INVALID_FUNCTION
;
2056 // Remove drive letters
2058 if (!DeviceIoControl(
2068 ret
= GetLastError();
2071 (FUNC
": DeviceIoControl(IOCTL_VFD_SET_LINK) - %s",
2072 SystemMessage(ret
)));
2077 // broadcast system message
2079 VfdBroadcastLink(letter
, VFD_LINK_REMOVED
);
2081 // broadcast VFD message
2082 if (VfdGetDeviceNumber(hDevice
, &number
) == ERROR_SUCCESS
) {
2083 VfdNotify(VFD_OPERATION_DELLINK
, number
);
2086 return ERROR_SUCCESS
;
2089 return ERROR_INVALID_PARAMETER
;
2094 // Get a global drive letter
2096 DWORD WINAPI
VfdGetGlobalLink(
2101 #define FUNC "VfdGetGlobalLinks"
2106 return ERROR_INVALID_PARAMETER
;
2111 if (!DeviceIoControl(
2113 IOCTL_VFD_QUERY_LINK
,
2121 ret
= GetLastError();
2124 (FUNC
": DeviceIoControl(IOCTL_VFD_QUERY_LINK) - %s",
2125 SystemMessage(ret
)));
2130 return ERROR_SUCCESS
;
2134 // Set or remove a local drive letter
2136 DWORD WINAPI
VfdSetLocalLink(
2141 #define FUNC "VfdSetLocalLink"
2143 CHAR dos_name
[] = "A:";
2144 CHAR dev_name
[MAX_PATH
];
2148 if (isalpha(cLetter
)) {
2150 // make sure the drive does not have a drive letter
2154 VfdGetGlobalLink(hDevice
, &letter
);
2156 if (isalpha(letter
)) {
2158 (FUNC
": Drive already has a drive letter %c\n", letter
));
2159 return ERROR_ALREADY_ASSIGNED
;
2162 VfdGetLocalLink(hDevice
, &letter
);
2164 if (isalpha(letter
)) {
2166 (FUNC
": Drive already has a drive letter %c\n", letter
));
2167 return ERROR_ALREADY_ASSIGNED
;
2170 // make sure drive letters are not in use
2172 cLetter
= (CHAR
)toupper(cLetter
);
2174 if (GetLogicalDrives() & (1 << (cLetter
- 'A'))) {
2176 (FUNC
": Drive letter already used\n"));
2178 return ERROR_ALREADY_ASSIGNED
;
2181 // get VFD device name
2183 ret
= VfdGetDeviceName(hDevice
, dev_name
, sizeof(dev_name
));
2185 if (ret
!= ERROR_SUCCESS
) {
2189 // assign a drive letter
2191 dos_name
[0] = cLetter
;
2193 if (!DefineDosDevice(DDD_RAW_TARGET_PATH
, dos_name
, dev_name
)) {
2194 ret
= GetLastError();
2197 (FUNC
": DefineDosDevice(%s,%s) - %s",
2198 dos_name
, dev_name
, SystemMessage(ret
)));
2201 if (ret
== ERROR_SUCCESS
) {
2202 // broadcast VFD message
2204 if (VfdGetDeviceNumber(hDevice
, &number
) == ERROR_SUCCESS
) {
2205 VfdNotify(VFD_OPERATION_SETLINK
, number
);
2211 else if (!cLetter
) {
2213 // make sure the drive has a local drive letter
2217 VfdGetLocalLink(hDevice
, &letter
);
2219 if (!isalpha(letter
)) {
2221 (FUNC
": Drive letter is not assigned to this drive\n"));
2222 return ERROR_INVALID_FUNCTION
;
2225 // get VFD device name
2227 ret
= VfdGetDeviceName(hDevice
, dev_name
, sizeof(dev_name
));
2229 if (ret
!= ERROR_SUCCESS
) {
2233 // remove drive letters
2234 #define DDD_FLAGS (DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE)
2236 dos_name
[0] = (CHAR
)toupper(letter
);
2238 if (!DefineDosDevice(DDD_FLAGS
, dos_name
, dev_name
)) {
2239 ret
= GetLastError();
2242 (FUNC
": DefineDosDevice(%s,%s) - %s",
2243 dos_name
, dev_name
, SystemMessage(ret
)));
2246 if (ret
== ERROR_SUCCESS
) {
2247 // broadcast VFD message
2248 if (VfdGetDeviceNumber(hDevice
, &number
) == ERROR_SUCCESS
) {
2249 VfdNotify(VFD_OPERATION_DELLINK
, number
);
2256 return ERROR_INVALID_PARAMETER
;
2261 // Get local drive letters
2263 DWORD WINAPI
VfdGetLocalLink(
2268 #define FUNC "VfdGetLocalLinks"
2271 CHAR dos_name
[] = "A:";
2272 CHAR dev_name
[MAX_PATH
];
2273 CHAR dos_target
[MAX_PATH
* 2];
2277 return ERROR_INVALID_PARAMETER
;
2280 // Get the VFD device name
2282 ret
= VfdGetDeviceName(hDevice
, dev_name
, sizeof(dev_name
));
2284 if (ret
!= ERROR_SUCCESS
) {
2288 // Get global drive letter
2290 ret
= VfdGetGlobalLink(hDevice
, &global
);
2292 if (ret
!= ERROR_SUCCESS
) {
2296 // Get logical drives
2298 logical
= GetLogicalDrives();
2300 // exclude the global drive letter
2302 if (isalpha(global
)) {
2303 logical
&= ~(1 << (toupper(global
) - 'A'));
2306 // start searching from the next drive letter
2308 if (isalpha(*pLetter
)) {
2309 dos_name
[0] = (CHAR
)(toupper(*pLetter
) + 1);
2310 logical
>>= (dos_name
[0] - 'A');
2313 // Check dos device targets
2318 if (logical
& 0x01) {
2319 if (QueryDosDevice(dos_name
, dos_target
, sizeof(dos_target
))) {
2320 if (_stricmp(dos_target
, dev_name
) == 0) {
2321 *pLetter
= dos_name
[0];
2327 (FUNC
": QueryDosDevice(%s) - %s",
2328 dos_name
, SystemMessage(GetLastError())));
2335 return ERROR_SUCCESS
;
2339 // Get the Virtual Floppy device number
2341 DWORD WINAPI
VfdGetDeviceNumber(
2346 #define FUNC "VfdGetDeviceNumber"
2348 DWORD ret
= ERROR_SUCCESS
;
2351 return ERROR_INVALID_PARAMETER
;
2356 if (!DeviceIoControl(
2358 IOCTL_VFD_QUERY_NUMBER
,
2366 ret
= GetLastError();
2369 (FUNC
": DeviceIoControl(IOCTL_VFD_QUERY_NUMBER) - %s",
2370 SystemMessage(ret
)));
2376 // Get the Virtual Floppy device name
2378 DWORD WINAPI
VfdGetDeviceName(
2384 #define FUNC "VfdGetDeviceName"
2386 WCHAR wname
[MAX_PATH
];
2387 DWORD ret
= ERROR_SUCCESS
;
2389 if (!pName
|| !nLength
) {
2390 return ERROR_INVALID_PARAMETER
;
2393 ZeroMemory(pName
, nLength
);
2395 if (!DeviceIoControl(
2397 IOCTL_VFD_QUERY_NAME
,
2405 ret
= GetLastError();
2408 (FUNC
": DeviceIoControl(IOCTL_VFD_QUERY_NUMBER) - %s",
2409 SystemMessage(ret
)));
2412 if (!WideCharToMultiByte(CP_OEMCP
, 0, &wname
[1],
2413 wname
[0] / sizeof(WCHAR
), pName
, nLength
, NULL
, NULL
)) {
2415 ret
= GetLastError();
2418 (FUNC
": WideCharToMultiByte - %s",
2419 SystemMessage(ret
)));
2426 // Get Virtual Floppy driver version
2428 DWORD WINAPI
VfdGetDriverVersion(
2433 #define FUNC "VfdGetDriverVersion"
2435 DWORD ret
= ERROR_SUCCESS
;
2438 return ERROR_INVALID_PARAMETER
;
2443 if (!DeviceIoControl(
2445 IOCTL_VFD_QUERY_VERSION
,
2453 ret
= GetLastError();
2456 (FUNC
": DeviceIoControl(IOCTL_VFD_QUERY_VERSION) - %s",
2457 SystemMessage(ret
)));
2464 // Change the write protect state of the media
2466 DWORD WINAPI
VfdWriteProtect(
2471 #define FUNC "VfdWriteProtect"
2473 DWORD ret
= ERROR_SUCCESS
;
2475 if (!DeviceIoControl(
2477 bProtect
? IOCTL_VFD_SET_PROTECT
: IOCTL_VFD_CLEAR_PROTECT
,
2485 ret
= GetLastError();
2488 (FUNC
": DeviceIoControl(IOCTL_VFD_SET_PROTECT) - %s",
2489 SystemMessage(ret
)));
2492 if (ret
== ERROR_SUCCESS
) {
2495 if (VfdGetDeviceNumber(hDevice
, &number
) == ERROR_SUCCESS
) {
2496 VfdNotify(VFD_OPERATION_PROTECT
, number
);
2503 // Format the current media with FAT12
2505 DWORD WINAPI
VfdFormatMedia(
2509 #define FUNC "VfdFormatMedia"
2511 DWORD ret
= ERROR_SUCCESS
;
2513 GET_LENGTH_INFORMATION length
;
2515 // Get the media size
2517 if (!DeviceIoControl(
2519 IOCTL_DISK_GET_LENGTH_INFO
,
2527 ret
= GetLastError();
2530 (FUNC
": DeviceIoControl(IOCTL_DISK_GET_LENGTH_INFO) - %s",
2531 SystemMessage(ret
)));
2536 // Prepare a formatted image buffer
2538 buf
= (PUCHAR
)LocalAlloc(LPTR
, length
.Length
.LowPart
);
2541 ret
= GetLastError();
2544 (FUNC
": LocalAlloc - %s",
2545 SystemMessage(ret
)));
2550 // format the buffer
2552 ret
= FormatBufferFat(buf
,
2553 VFD_BYTE_TO_SECTOR(length
.Length
.LowPart
));
2555 if (ret
!= ERROR_SUCCESS
) {
2559 // seek the top of the media
2561 if (SetFilePointer(hDevice
, 0, NULL
, FILE_BEGIN
) != 0) {
2562 ret
= GetLastError();
2565 (FUNC
": SetFilePointer - %s",
2566 SystemMessage(ret
)));
2571 // write the image into the media
2573 if (!WriteFile(hDevice
, buf
, length
.Length
.LowPart
, &result
, NULL
) ||
2574 result
!= length
.Length
.LowPart
) {
2575 ret
= GetLastError();
2578 (FUNC
": WriteFile - %s",
2579 SystemMessage(ret
)));
2585 // unlock the target volume
2586 if (!DeviceIoControl(
2588 FSCTL_UNLOCK_VOLUME
,
2597 (FUNC
": DeviceIoControl(FSCTL_UNLOCK_VOLUME) - %s",
2598 SystemMessage(GetLastError())));
2601 // release the format image buffer
2609 // Dismount the volume (should be called before Save, Format)
2611 DWORD WINAPI
VfdDismountVolume(
2616 #define FUNC "VfdDismountVolume"
2618 DWORD ret
= ERROR_SUCCESS
;
2620 // Lock the target volume
2622 if (!DeviceIoControl(
2632 ret
= GetLastError();
2635 (FUNC
": DeviceIoControl(FSCTL_LOCK_VOLUME) - %s",
2636 SystemMessage(ret
)));
2638 if (ret
!= ERROR_ACCESS_DENIED
|| !bForce
) {
2643 // Dismount the target volume
2645 if (!DeviceIoControl(
2647 FSCTL_DISMOUNT_VOLUME
,
2655 ret
= GetLastError();
2658 (FUNC
": DeviceIoControl(FSCTL_DISMOUNT_VOLUME) - %s",
2659 SystemMessage(ret
)));
2665 // Save the current image into a file
2667 DWORD WINAPI
VfdSaveImage(
2674 #define FUNC "VfdSaveImage"
2675 HANDLE hFile
= INVALID_HANDLE_VALUE
;
2677 DWORD ret
= ERROR_SUCCESS
;
2679 GET_LENGTH_INFORMATION length
;
2682 ret
= ERROR_SUCCESS
;
2684 // Get the media size
2686 if (!DeviceIoControl(
2688 IOCTL_DISK_GET_LENGTH_INFO
,
2696 ret
= GetLastError();
2699 (FUNC
": DeviceIoControl(IOCTL_DISK_GET_LENGTH_INFO) - %s",
2700 SystemMessage(ret
)));
2705 // Prepare an intermediate image buffer
2707 buf
= (PUCHAR
)LocalAlloc(LPTR
, length
.Length
.LowPart
);
2710 ret
= GetLastError();
2713 (FUNC
": LocalAlloc - %s",
2714 SystemMessage(ret
)));
2719 // seek the top of the media
2721 if (SetFilePointer(hDevice
, 0, NULL
, FILE_BEGIN
) != 0) {
2722 ret
= GetLastError();
2725 (FUNC
": SetFilePointer - %s",
2726 SystemMessage(ret
)));
2731 // read the image data
2733 if (!ReadFile(hDevice
, buf
, length
.Length
.LowPart
, &result
, NULL
) ||
2734 result
!= length
.Length
.LowPart
) {
2735 ret
= GetLastError();
2738 (FUNC
": ReadFile - %s",
2739 SystemMessage(ret
)));
2744 // open the destination file
2746 hFile
= CreateFile(sFileName
, GENERIC_WRITE
, 0, NULL
,
2747 bOverWrite
? OPEN_ALWAYS
: CREATE_NEW
, 0, NULL
);
2749 if (hFile
== INVALID_HANDLE_VALUE
) {
2750 ret
= GetLastError();
2753 (FUNC
": CreateFile - %s",
2754 SystemMessage(ret
)));
2759 // seek the top of the file
2761 if (SetFilePointer(hFile
, 0, NULL
, FILE_BEGIN
) != 0) {
2762 ret
= GetLastError();
2765 (FUNC
": SetFilePointer - %s",
2766 SystemMessage(ret
)));
2771 // write the image data
2773 if (!WriteFile(hFile
, buf
, length
.Length
.LowPart
, &result
, NULL
) ||
2774 result
!= length
.Length
.LowPart
) {
2775 ret
= GetLastError();
2778 (FUNC
": WriteFile - %s",
2779 SystemMessage(ret
)));
2784 // truncate the target file
2786 if (bTruncate
&& !SetEndOfFile(hFile
)) {
2787 ret
= GetLastError();
2790 (FUNC
": SetEndOfFile - %s",
2791 SystemMessage(ret
)));
2796 // reset the media modified flag
2798 if (!DeviceIoControl(
2800 IOCTL_VFD_RESET_MODIFY
,
2809 (FUNC
": DeviceIoControl(IOCTL_VFD_RESET_MODIFY) - %s",
2810 SystemMessage(GetLastError())));
2814 // unlock the target volume
2816 if (!DeviceIoControl(
2818 FSCTL_UNLOCK_VOLUME
,
2827 (FUNC
": DeviceIoControl(FSCTL_UNLOCK_VOLUME) - %s",
2828 SystemMessage(GetLastError())));
2831 // release the format image buffer
2837 // close the image file
2839 if (hFile
!= INVALID_HANDLE_VALUE
) {
2847 // Check if specified file is valid VFD driver
2849 DWORD WINAPI
VfdCheckDriverFile(
2851 PULONG pFileVersion
)
2854 #define FUNC "VfdCheckDriverFile"
2858 VS_FIXEDFILEINFO
*fixedinfo
;
2859 DWORD ret
= ERROR_SUCCESS
;
2864 if (!sFileName
|| !*sFileName
) {
2865 return ERROR_INVALID_PARAMETER
;
2872 // check file existence
2874 if (GetFileAttributes(sFileName
) == INVALID_FILE_ATTRIBUTES
) {
2875 ret
= GetLastError();
2878 (FUNC
": GetFileAttributes - %s\n",
2879 SystemMessage(ret
)));
2884 // check file version
2886 result
= GetFileVersionInfoSize((PSTR
)sFileName
, &dummy
);
2890 (FUNC
": GetFileVersionInfoSize == 0\n"));
2892 return ERROR_BAD_DRIVER
;
2895 info
= LocalAlloc(LPTR
, result
);
2898 ret
= GetLastError();
2901 (FUNC
": LocalAlloc(%lu) - %s\n",
2902 result
, SystemMessage(ret
)));
2907 if (!GetFileVersionInfo((PSTR
)sFileName
, 0, result
, info
)) {
2908 ret
= GetLastError();
2911 (FUNC
": GetFileVersionInfo - %s", SystemMessage(ret
)));
2916 result
= sizeof(fixedinfo
);
2918 if (!VerQueryValue(info
, "\\", (PVOID
*)&fixedinfo
, (PUINT
)&result
)) {
2919 ret
= GetLastError();
2922 (FUNC
": VerQueryValue(\"\\\") - %s", SystemMessage(ret
)));
2927 if (fixedinfo
->dwFileOS
!= VOS_NT_WINDOWS32
||
2928 fixedinfo
->dwFileType
!= VFT_DRV
||
2929 fixedinfo
->dwFileSubtype
!= VFT2_DRV_SYSTEM
) {
2933 (FUNC
": Invalid file type flags\n"));
2936 (FUNC
": Invalid file type flags. os: %x (%x), type: %x (%x), subtype: %x (%x)\n",
2937 fixedinfo
->dwFileOS
, VOS_NT_WINDOWS32
, fixedinfo
->dwFileType
, VFT_DRV
,
2938 fixedinfo
->dwFileSubtype
, VFT2_DRV_SYSTEM
));
2941 ret
= ERROR_BAD_DRIVER
;
2947 *pFileVersion
= fixedinfo
->dwFileVersionMS
;
2949 if (fixedinfo
->dwFileFlags
& VS_FF_DEBUG
) {
2950 *pFileVersion
|= 0x80000000;
2954 if (!VerQueryValue(info
,
2955 "\\StringFileInfo\\" VFD_VERSIONINFO_LANG
"\\OriginalFileName",
2956 (PVOID
*)&str
, (PUINT
)&result
)) {
2957 ret
= GetLastError();
2960 (FUNC
": VerQueryValue(\"OriginalFileName\") - %s",
2961 SystemMessage(ret
)));
2966 if (strcmp(str
, VFD_DRIVER_FILENAME
)) {
2968 (FUNC
": Invalid original file name\n"));
2970 ret
= ERROR_BAD_DRIVER
;
2975 if (fixedinfo
->dwFileVersionMS
!= MAKELONG(VFD_DRIVER_MINOR
, VFD_DRIVER_MAJOR
) ||
2976 fixedinfo
->dwProductVersionMS
!= MAKELONG(VFD_PRODUCT_MINOR
, VFD_PRODUCT_MAJOR
)) {
2979 (FUNC
": Invalid version values - file:%08x, prod: %08x\n",
2980 fixedinfo
->dwFileVersionMS
, fixedinfo
->dwProductVersionMS
));
2982 ret
= ERROR_BAD_DRIVER
;
2987 // Ensure that the driver binary is located on a local drive
2988 // because device driver cannot be started on network drives.
2990 if (*sFileName
== '\\' && *(sFileName
+ 1) == '\\') {
2991 // full path is a UNC path -- \\server\dir\...
2994 (FUNC
": Driver is located on a network drive\n"));
2996 return ERROR_NETWORK_ACCESS_DENIED
;
2999 // ensure that the drive letter is not a network drive
3001 CHAR root
[] = " :\\";
3003 root
[0] = *sFileName
;
3005 if (GetDriveType(root
) == DRIVE_REMOTE
) {
3006 // the drive is a network drive
3009 (FUNC
": Driver is located on a network drive\n"));
3011 return ERROR_NETWORK_ACCESS_DENIED
;
3022 // check an image file
3024 DWORD WINAPI
VfdCheckImageFile(
3027 PVFD_FILETYPE pFileType
,
3031 #define FUNC "VfdCheckImageFile"
3033 DWORD ret
= ERROR_SUCCESS
;
3035 if (!sFileName
|| !*sFileName
|| !pAttributes
|| !pImageSize
|| !pFileType
) {
3036 return ERROR_INVALID_PARAMETER
;
3039 // get file attributes
3041 *pAttributes
= GetFileAttributes(sFileName
);
3043 if (*pAttributes
== INVALID_FILE_ATTRIBUTES
) {
3044 ret
= GetLastError();
3046 if (ret
!= ERROR_FILE_NOT_FOUND
) {
3048 (FUNC
": GetFileAttributes(%s) - %s\n",
3049 sFileName
, SystemMessage(ret
)));
3055 // Open the target file
3057 hFile
= CreateFile(sFileName
, GENERIC_READ
| GENERIC_WRITE
,
3058 0, NULL
, OPEN_EXISTING
, 0, NULL
);
3060 if (hFile
== INVALID_HANDLE_VALUE
) {
3064 ret
= GetLastError();
3066 if (ret
!= ERROR_ACCESS_DENIED
) {
3068 (FUNC
": CreateFile(%s) - %s\n",
3069 sFileName
, SystemMessage(ret
)));
3074 // try opening it read-only
3076 hFile
= CreateFile(sFileName
, GENERIC_READ
,
3077 FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
3079 if (hFile
== INVALID_HANDLE_VALUE
) {
3081 // cannot open even read-only
3083 ret
= GetLastError();
3086 (FUNC
": CreateFile(%s) - %s\n",
3087 sFileName
, SystemMessage(ret
)));
3092 // file can be opened read-only
3093 *pAttributes
|= FILE_ATTRIBUTE_READONLY
;
3094 ret
= ERROR_SUCCESS
;
3097 // check if the image is an IMZ file
3099 if (ExtractZipInfo(hFile
, pImageSize
) == ERROR_SUCCESS
) {
3100 *pFileType
= VFD_FILETYPE_ZIP
;
3103 *pImageSize
= GetFileSize(hFile
, NULL
);
3104 *pFileType
= VFD_FILETYPE_RAW
;
3113 // Create a formatted new image file
3115 DWORD WINAPI
VfdCreateImageFile(
3117 VFD_MEDIA nMediaType
,
3118 VFD_FILETYPE nFileType
,
3122 #define FUNC "VfdCreateImageFile"
3125 PUCHAR image_buf
= NULL
;
3127 DWORD ret
= ERROR_SUCCESS
;
3129 if (nFileType
!= VFD_FILETYPE_RAW
) {
3130 return ERROR_INVALID_PARAMETER
;
3133 file_size
= VfdGetMediaSize(nMediaType
);
3135 if (file_size
== 0) {
3136 return ERROR_INVALID_PARAMETER
;
3139 hFile
= CreateFile(sFileName
, GENERIC_WRITE
, 0, NULL
,
3140 bOverWrite
? CREATE_ALWAYS
: CREATE_NEW
, 0, NULL
);
3142 if (hFile
== INVALID_HANDLE_VALUE
) {
3143 ret
= GetLastError();
3146 (FUNC
": CreateFile - %s",
3147 SystemMessage(ret
)));
3152 image_buf
= (PUCHAR
)LocalAlloc(LPTR
, file_size
);
3154 if (image_buf
== NULL
) {
3155 ret
= GetLastError();
3158 (FUNC
": LocalAlloc - %s",
3159 SystemMessage(ret
)));
3164 FormatBufferFat(image_buf
, VFD_BYTE_TO_SECTOR(file_size
));
3166 if (!WriteFile(hFile
, image_buf
, file_size
, &result
, NULL
) ||
3167 file_size
!= result
) {
3169 ret
= GetLastError();
3172 (FUNC
": WriteFile - %s",
3173 SystemMessage(ret
)));
3178 SetEndOfFile(hFile
);
3184 LocalFree(image_buf
);
3192 // choose first available drive letter
3194 CHAR WINAPI
VfdChooseLetter()
3196 DWORD logical_drives
= GetLogicalDrives();
3197 CHAR drive_letter
= 'A';
3199 if (logical_drives
== 0) {
3203 while (logical_drives
& 0x1) {
3204 logical_drives
>>= 1;
3208 if (drive_letter
> 'Z') {
3212 return drive_letter
;
3216 // media type functions
3223 media_tbl
[VFD_MEDIA_MAX
] =
3225 { 0, "" }, // VFD_MEDIA_NONE,
3226 { VFD_SECTOR_TO_BYTE(320), "5.25\" 160KB" }, // VFD_MEDIA_F5_160
3227 { VFD_SECTOR_TO_BYTE(360), "5.25\" 180KB" }, // VFD_MEDIA_F5_180
3228 { VFD_SECTOR_TO_BYTE(640), "5.25\" 320KB" }, // VFD_MEDIA_F5_320
3229 { VFD_SECTOR_TO_BYTE(720), "5.25\" 360KB" }, // VFD_MEDIA_F5_360
3230 { VFD_SECTOR_TO_BYTE(1280), "3.5\" 640KB" }, // VFD_MEDIA_F3_640
3231 { VFD_SECTOR_TO_BYTE(1280), "5.25\" 640KB" }, // VFD_MEDIA_F5_640
3232 { VFD_SECTOR_TO_BYTE(1440), "3.5\" 720KB" }, // VFD_MEDIA_F3_720
3233 { VFD_SECTOR_TO_BYTE(1440), "5.25\" 720KB" }, // VFD_MEDIA_F5_720
3234 { VFD_SECTOR_TO_BYTE(1640), "3.5\" 820KB" }, // VFD_MEDIA_F3_820
3235 { VFD_SECTOR_TO_BYTE(2400), "3.5\" 1.2MB" }, // VFD_MEDIA_F3_1P2
3236 { VFD_SECTOR_TO_BYTE(2400), "5.25\" 1.2MB" }, // VFD_MEDIA_F5_1P2
3237 { VFD_SECTOR_TO_BYTE(2880), "3.5\" 1.44MB" }, // VFD_MEDIA_F3_1P4
3238 { VFD_SECTOR_TO_BYTE(3360), "3.5\" 1.68MB DMF" }, // VFD_MEDIA_F3_1P6
3239 { VFD_SECTOR_TO_BYTE(3444), "3.5\" 1.72MB DMF" }, // VFD_MEDIA_F3_1P7
3240 { VFD_SECTOR_TO_BYTE(5760), "3.5\" 2.88MB"} // VFD_MEDIA_F3_2P8
3243 // Lookup the largest media to fit in a size
3245 VFD_MEDIA WINAPI
VfdLookupMedia(
3250 for (i
= 1; i
< VFD_MEDIA_MAX
; i
++) {
3251 if (nSize
< media_tbl
[i
].Size
) {
3259 // Get media size (in bytes) of a media type
3261 ULONG WINAPI
VfdGetMediaSize(
3262 VFD_MEDIA nMediaType
)
3264 return nMediaType
< VFD_MEDIA_MAX
? media_tbl
[nMediaType
].Size
: 0;
3267 // Get media type name
3269 PCSTR WINAPI
VfdMediaTypeName(
3270 VFD_MEDIA nMediaType
)
3272 return nMediaType
< VFD_MEDIA_MAX
? media_tbl
[nMediaType
].Name
: NULL
;