[VFD] Import the VFD project (Virtual Floppy Drive) which allows creating virtual

floppy drives in ReactOS and mount images on them.
Only the cmd got imported. The GUI interface may come later on.
Note that, as for vcdrom, the driver is left disabled and you need to explicitely
start it through vfd command line interface.

CORE-14090
This commit is contained in:
Pierre Schweitzer 2017-12-16 21:48:17 +01:00
parent d82796778f
commit 25c7e1a8d0
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B
58 changed files with 21984 additions and 0 deletions

View file

@ -1,6 +1,7 @@
add_subdirectory(applications)
add_subdirectory(demos)
add_subdirectory(drivers)
add_subdirectory(include)
add_subdirectory(lib)
add_subdirectory(templates)

View file

@ -6,5 +6,6 @@ add_subdirectory(tee)
add_subdirectory(touch)
add_subdirectory(uptime)
add_subdirectory(vcdcli)
add_subdirectory(vfdcmd)
add_subdirectory(winspool_print)
add_subdirectory(y)

View file

@ -0,0 +1,10 @@
add_message_headers(ANSI vfdmsg.mc)
include_directories(${REACTOS_SOURCE_DIR}/modules/rosapps/include/vfd)
add_executable(vfdcmd vfdcmd.c vfdcmd.rc)
set_module_type(vfdcmd win32cui)
add_importlibs(vfdcmd advapi32 vfd user32 msvcrt kernel32 ntdll)
add_dependencies(vfdcmd vfdmsg)
set_target_properties(vfdcmd PROPERTIES OUTPUT_NAME "vfd")
add_cd_file(TARGET vfdcmd DESTINATION reactos/system32 FOR all)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,6 @@
#define REACTOS_STR_FILE_DESCRIPTION "Virtual Floppy Controler"
#define REACTOS_STR_INTERNAL_NAME "vfdcmd"
#define REACTOS_STR_ORIGINAL_FILENAME "vfdcmd.exe"
#include <reactos/version.rc>
#include <vfdmsg.rc>

View file

@ -0,0 +1,49 @@
/*
vfdcmd.rs
Virtual Floppy Drive for Windows
Driver control program (console version)
Resource script
The non-standard extension ".rs" is intentional, so that
Microsoft Visual Studio won't try to open this file with
the resource editor
Copyright (c) 2003-2005 Ken Kato
*/
#ifndef APSTUDIO_INVOKED
//
// version resource
//
#include <winver.h>
#include "vfdver.h"
#define VFD_FILEOS VOS_NT_WINDOWS32
#define VFD_FILETYPE VFT_APP
#define VFD_FILESUBTYPE VFT2_UNKNOWN
#define VFD_DESCRIPTION "Virtual Floppy Drive Console"
#define VFD_INTERNALNAME "vfd.exe"
#define VFD_FILE_MAJOR 2
#define VFD_FILE_MINOR 1
//
// for Japanese version resources
//
#define VFD_VERSIONINFO_ALT "041104B0"
#undef VFD_VERSIONINFO_TRANS
#define VFD_VERSIONINFO_TRANS 0x0409, 0x04B0, 0x0411, 0x04B0
#define VFD_DESCRIPTION_ALT "Virtual Floppy Drive ƒRƒ“ƒ\<EFBFBD>[ƒ‹"
#define VFD_PRODUCT_NAME_ALT VFD_PRODUCT_NAME
#include "vfdver.rc"
//
// Message resource
//
#include "vfdmsg.rc"
#endif // not APSTUDIO_INVOKED

File diff suppressed because it is too large Load diff

View file

@ -1,2 +1,3 @@
add_subdirectory(green)
add_subdirectory(vcdrom)
add_subdirectory(vfd)

View file

@ -0,0 +1,19 @@
list(APPEND SOURCE
vfddbg.c
vfddev.c
vfddrv.c
vfdfmt.c
vfdimg.c
vfdioctl.c
vfdlink.c
vfdmnt.c
vfdpnp.c
vfdrdwr.c)
include_directories(${REACTOS_SOURCE_DIR}/modules/rosapps/include/vfd)
add_library(vfddrv SHARED ${SOURCE} vfddrv.rc)
set_module_type(vfddrv kernelmodedriver)
add_importlibs(vfddrv ntoskrnl hal)
set_target_properties(vfddrv PROPERTIES OUTPUT_NAME "vfd")
add_cd_file(TARGET vfddrv DESTINATION reactos/system32/drivers FOR all)
add_registry_inf(vfd_reg.inf)

View file

@ -0,0 +1,357 @@
/*
imports.h
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: imported elements from various sources
Copyright (C) 2003-2005 Ken Kato
This file contains:
a) #include directive for system headers
b) Stuff imported from newer DDKs so that the driver built with older
DDKs can run on newer Windows.
c) Stuff imported from ntifs.h (http://www.acc.umu.se/~bosse/) so that
the driver can be compiled without it.
d) Prototypes of standard functions which are exported from ntoskrnl.exe
but not declared in regular DDK header files.
*/
#ifndef _IMPORTS_H_
#define _IMPORTS_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#ifdef _MSC_VER
#pragma warning(push,3)
#endif
#include <ntddk.h>
#include <ntdddisk.h>
#include <ntverp.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#ifdef _MSC_VER
// disable unwanted (and trivial) warnings :
// 4054 - type cast from a function pointer to a data pointer
// 4201 - anonymous structure
// 4514 - unreferenced inline function
#pragma warning(disable: 4054 4201 4514)
#endif
#if (VER_PRODUCTBUILD >= 2195)
#include <mountdev.h>
#else // (VER_PRODUCTBUILD < 2195)
//
// Imports from Windows 2000 DDK <ntddk.h>
//
typedef enum _MM_PAGE_PRIORITY {
LowPagePriority = 0,
NormalPagePriority = 16,
HighPagePriority = 32
} MM_PAGE_PRIORITY;
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
#define FILE_DEVICE_MASS_STORAGE 0x0000002d
//
// Imports from Windows 2000 DDK <ntddstor.h>
//
#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE( \
IOCTL_STORAGE_BASE, \
0x0200, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
//
// Imports from Windows 2000 DDK <mountmgr.h>, <mountdev.h>
//
#define MOUNTMGR_DEVICE_NAME L"\\Device\\MountPointManager"
#define MOUNTMGRCONTROLTYPE ((ULONG) 'm')
#define MOUNTDEVCONTROLTYPE ((ULONG) 'M')
#define IOCTL_MOUNTDEV_QUERY_UNIQUE_ID CTL_CODE( \
MOUNTDEVCONTROLTYPE,\
0, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY \
CTL_CODE( \
MOUNTDEVCONTROLTYPE,\
1, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_MOUNTDEV_QUERY_DEVICE_NAME CTL_CODE( \
MOUNTDEVCONTROLTYPE,\
2, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME \
CTL_CODE( \
MOUNTDEVCONTROLTYPE,\
3, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_MOUNTDEV_LINK_CREATED CTL_CODE( \
MOUNTDEVCONTROLTYPE,\
4, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_MOUNTDEV_LINK_DELETED CTL_CODE( \
MOUNTDEVCONTROLTYPE,\
5, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_MOUNTMGR_CREATE_POINT CTL_CODE( \
MOUNTMGRCONTROLTYPE,\
0, \
METHOD_BUFFERED, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_MOUNTMGR_DELETE_POINTS CTL_CODE( \
MOUNTMGRCONTROLTYPE,\
1, \
METHOD_BUFFERED, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION \
CTL_CODE( \
MOUNTMGRCONTROLTYPE,\
11, \
METHOD_BUFFERED, \
FILE_READ_ACCESS)
typedef struct _MOUNTDEV_UNIQUE_ID {
USHORT UniqueIdLength;
UCHAR UniqueId[1];
} MOUNTDEV_UNIQUE_ID, *PMOUNTDEV_UNIQUE_ID;
typedef struct _MOUNTDEV_NAME {
USHORT NameLength;
WCHAR Name[1];
} MOUNTDEV_NAME, *PMOUNTDEV_NAME;
typedef struct _MOUNTDEV_SUGGESTED_LINK_NAME {
BOOLEAN UseOnlyIfThereAreNoOtherLinks;
USHORT NameLength;
WCHAR Name[1];
} MOUNTDEV_SUGGESTED_LINK_NAME, *PMOUNTDEV_SUGGESTED_LINK_NAME;
typedef struct _MOUNTMGR_TARGET_NAME {
USHORT DeviceNameLength;
WCHAR DeviceName[1];
} MOUNTMGR_TARGET_NAME, *PMOUNTMGR_TARGET_NAME;
typedef struct _MOUNTMGR_CREATE_POINT_INPUT {
USHORT SymbolicLinkNameOffset;
USHORT SymbolicLinkNameLength;
USHORT DeviceNameOffset;
USHORT DeviceNameLength;
} MOUNTMGR_CREATE_POINT_INPUT, *PMOUNTMGR_CREATE_POINT_INPUT;
typedef struct _MOUNTMGR_MOUNT_POINT {
ULONG SymbolicLinkNameOffset;
USHORT SymbolicLinkNameLength;
ULONG UniqueIdOffset;
USHORT UniqueIdLength;
ULONG DeviceNameOffset;
USHORT DeviceNameLength;
} MOUNTMGR_MOUNT_POINT, *PMOUNTMGR_MOUNT_POINT;
typedef struct _MOUNTMGR_MOUNT_POINTS {
ULONG Size;
ULONG NumberOfMountPoints;
MOUNTMGR_MOUNT_POINT MountPoints[1];
} MOUNTMGR_MOUNT_POINTS, *PMOUNTMGR_MOUNT_POINTS;
#endif // (VER_PRODUCTBUILD < 2195)
#if (VER_PRODUCTBUILD < 2600)
//
// Imports from Windows XP DDK <ntdddisk.h>
//
#define IOCTL_DISK_GET_PARTITION_INFO_EX CTL_CODE( \
IOCTL_DISK_BASE, \
0x0012, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_DISK_GET_LENGTH_INFO CTL_CODE( \
IOCTL_DISK_BASE, \
0x0017, \
METHOD_BUFFERED, \
FILE_READ_ACCESS)
typedef unsigned __int64 ULONG64, *PULONG64;
typedef enum _PARTITION_STYLE {
PARTITION_STYLE_MBR,
PARTITION_STYLE_GPT
} PARTITION_STYLE;
typedef struct _PARTITION_INFORMATION_MBR {
UCHAR PartitionType;
BOOLEAN BootIndicator;
BOOLEAN RecognizedPartition;
ULONG HiddenSectors;
} PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR;
typedef struct _PARTITION_INFORMATION_GPT {
GUID PartitionType;
GUID PartitionId;
ULONG64 Attributes;
WCHAR Name[36];
} PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT;
typedef struct _PARTITION_INFORMATION_EX {
PARTITION_STYLE PartitionStyle;
LARGE_INTEGER StartingOffset;
LARGE_INTEGER PartitionLength;
ULONG PartitionNumber;
BOOLEAN RewritePartition;
union {
PARTITION_INFORMATION_MBR Mbr;
PARTITION_INFORMATION_GPT Gpt;
};
} PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX;
typedef struct _GET_LENGTH_INFORMATION {
LARGE_INTEGER Length;
} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION;
//
// Imports from Windows XP DDK <ntddstor.h>
//
#define IOCTL_STORAGE_GET_HOTPLUG_INFO CTL_CODE( \
IOCTL_STORAGE_BASE, \
0x0305, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
typedef struct _STORAGE_HOTPLUG_INFO {
ULONG Size;
BOOLEAN MediaRemovable;
BOOLEAN MediaHotplug;
BOOLEAN DeviceHotplug;
BOOLEAN WriteCacheEnableOverride;
} STORAGE_HOTPLUG_INFO, *PSTORAGE_HOTPLUG_INFO;
//
// Imports from Windows XP DDK <mountdev.h>
//
#define IOCTL_MOUNTDEV_QUERY_STABLE_GUID CTL_CODE( \
MOUNTDEVCONTROLTYPE,\
6, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
typedef struct _MOUNTDEV_STABLE_GUID {
GUID StableGuid;
} MOUNTDEV_STABLE_GUID, *PMOUNTDEV_STABLE_GUID;
#endif // (VER_PRODUCTBUILD < 2600)
//
// Imports from ntifs.h
//
#define TOKEN_SOURCE_LENGTH 8
typedef enum _TOKEN_TYPE {
TokenPrimary = 1,
TokenImpersonation
} TOKEN_TYPE;
typedef struct _TOKEN_SOURCE {
CCHAR SourceName[TOKEN_SOURCE_LENGTH];
LUID SourceIdentifier;
} TOKEN_SOURCE, *PTOKEN_SOURCE;
typedef struct _TOKEN_CONTROL {
LUID TokenId;
LUID AuthenticationId;
LUID ModifiedId;
TOKEN_SOURCE TokenSource;
} TOKEN_CONTROL, *PTOKEN_CONTROL;
typedef struct _SECURITY_CLIENT_CONTEXT {
SECURITY_QUALITY_OF_SERVICE SecurityQos;
PACCESS_TOKEN ClientToken;
BOOLEAN DirectlyAccessClientToken;
BOOLEAN DirectAccessEffectiveOnly;
BOOLEAN ServerIsRemote;
TOKEN_CONTROL ClientTokenControl;
} SECURITY_CLIENT_CONTEXT, *PSECURITY_CLIENT_CONTEXT;
#define PsDereferenceImpersonationToken(T) \
if (ARGUMENT_PRESENT(T)) (ObDereferenceObject((T)))
#define PsDereferencePrimaryToken(T) (ObDereferenceObject((T)))
NTKERNELAPI
VOID
NTAPI
PsRevertToSelf (
VOID
);
NTKERNELAPI
NTSTATUS
NTAPI
SeCreateClientSecurity (
IN PETHREAD Thread,
IN PSECURITY_QUALITY_OF_SERVICE QualityOfService,
IN BOOLEAN RemoteClient,
OUT PSECURITY_CLIENT_CONTEXT ClientContext
);
#define SeDeleteClientSecurity(C) \
{ \
if (SeTokenType((C)->ClientToken) == TokenPrimary) { \
PsDereferencePrimaryToken((C)->ClientToken); \
} \
else { \
PsDereferenceImpersonationToken((C)->ClientToken); \
} \
}
NTKERNELAPI
VOID
NTAPI
SeImpersonateClient (
IN PSECURITY_CLIENT_CONTEXT ClientContext,
IN PETHREAD ServerThread OPTIONAL
);
NTKERNELAPI
TOKEN_TYPE
NTAPI
SeTokenType (
IN PACCESS_TOKEN Token
);
//
// Functions exported by ntoskrnl.exe, but not declared in DDK headers
//
int _snprintf(char *buffer, size_t count, const char *format, ...);
int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format, ...);
int sprintf(char *buffer, const char *format, ...);
int _swprintf(wchar_t *buffer, const wchar_t *format, ...);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _IMPORTS_H_

View file

@ -0,0 +1,7 @@
; Virtual floppy class driver
[AddReg]
HKLM,"SYSTEM\CurrentControlSet\Services\VirtualFD","ErrorControl",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\VirtualFD","Group",0x00000000,"SCSI Class"
HKLM,"SYSTEM\CurrentControlSet\Services\VirtualFD","ImagePath",0x00020000,"system32\drivers\vfd.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\VirtualFD","Start",0x00010001,0x00000003
HKLM,"SYSTEM\CurrentControlSet\Services\VirtualFD","Type",0x00010001,0x00000001

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,79 @@
/*
vfddbg.h
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: debug functions header
Copyright (C) 2003-2005 Ken Kato
*/
#ifndef _VFDDBG_H_
#define _VFDDBG_H_
#if DBG
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
PCSTR
GetStatusName(
NTSTATUS status);
PCSTR
GetMajorFuncName(
UCHAR major_code);
PCSTR
GetIoControlName(
ULONG ctrl_code);
#ifdef VFD_PNP
PCSTR
GetPnpIrpName(
ULONG minor_code);
PCSTR
GetPowerIrpName(
ULONG minor_code);
PCSTR
GetSystemIrpName(
ULONG minor_code);
#endif // VFD_PNP
//
// Debug Trace Level Flags
//
#define VFDERR 0x00000000
#define VFDWARN 0x00000001
#define VFDINFO 0x00000003
#define VFDDEV 0x00000004
#define VFDDRV 0x00000008
#define VFDRDWR 0x00000010
#define VFDIMG 0x00000020
#define VFDLINK 0x00000040
#define VFDFMT 0x00000080
#define VFDCTL 0x00000100
#define VFDMNT 0x00000200
#define VFDPNP 0x00000400
#define VFDTRACE(LEVEL,STRING) \
if ((TraceFlags & (LEVEL)) == (LEVEL)) { \
DbgPrint STRING; \
}
extern ULONG TraceFlags;
#else // DBG
#define VFDTRACE(LEVEL,STRING)
#endif // DBG
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _VFDDBG_H_

View file

@ -0,0 +1,407 @@
/*
vfddev.c
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: device create/delete functions
Copyright (C) 2003-2005 Ken Kato
*/
#include "imports.h"
#include "vfddrv.h"
#include "vfddbg.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, VfdCreateDevice)
#pragma alloc_text(PAGE, VfdDeleteDevice)
#endif // ALLOC_PRAGMA
//
// Create a VFD device object
//
NTSTATUS
VfdCreateDevice(
IN PDRIVER_OBJECT DriverObject,
OUT PVOID Parameter)
{
NTSTATUS status;
ULONG physical_num;
UNICODE_STRING unicode_name;
WCHAR name_buffer[40];
PVFD_DRIVER_EXTENSION driver_extension = NULL;
PDEVICE_OBJECT device_object = NULL;
PDEVICE_EXTENSION device_extension = NULL;
HANDLE thread_handle = NULL;
VFDTRACE(VFDINFO | VFDDEV, ("[VFD] VfdCreateDevice - IN\n"));
#ifdef VFD_PNP
// Get the driver device_extension for the driver object
driver_extension = IoGetDriverObjectExtension(
DriverObject, VFD_DRIVER_EXTENSION_ID);
#else // VFD_PNP
// The driver device_extension is passed as the Parameter
driver_extension = (PVFD_DRIVER_EXTENSION)Parameter;
#endif // VFD_PNP
if (driver_extension == NULL) {
VFDTRACE(VFDERR, ("[VFD] Failed to get the driver extension\n"));
return STATUS_DRIVER_INTERNAL_ERROR;
}
//
// Create a device object
// \Device\Floppy<n>
//
physical_num = 0;
do {
name_buffer[sizeof(name_buffer) - 1] = UNICODE_NULL;
_snwprintf(name_buffer, sizeof(name_buffer) - 1,
L"\\Device\\Floppy%lu", physical_num);
RtlInitUnicodeString(&unicode_name, name_buffer);
status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),
&unicode_name,
FILE_DEVICE_DISK,
FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE | FILE_DEVICE_SECURE_OPEN,
FALSE,
&device_object);
if (status != STATUS_OBJECT_NAME_EXISTS &&
status != STATUS_OBJECT_NAME_COLLISION) {
break;
}
}
while (++physical_num < 100);
if (!NT_SUCCESS(status)) {
VFDTRACE(VFDERR,
("[VFD] IoCreateDevice() %s\n",
GetStatusName(status)));
return status;
}
IoGetConfigurationInformation()->FloppyCount++;
VFDTRACE(VFDINFO | VFDDEV,
("[VFD] Created a device object %ws\n", name_buffer));
//
// Initialize the device object / device extension
//
device_object->Flags |= DO_DIRECT_IO;
device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension;
RtlZeroMemory(device_extension, sizeof(DEVICE_EXTENSION));
// Store the back pointer to the device object
device_extension->DeviceObject = device_object;
// Store the logical device number
device_extension->DeviceNumber = driver_extension->NumberOfDevices;
// Store the device name
if (!VfdCopyUnicode(&(device_extension->DeviceName), &unicode_name)) {
VFDTRACE(VFDERR,
("[VFD] Failed to allocate device name buffer\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
// set the default disk geometry (3.5" 1.44M)
device_extension->Geometry = &geom_tbl[0];
// Create the interface link (\??\VirtualFD<n>)
name_buffer[sizeof(name_buffer) - 1] = UNICODE_NULL;
_snwprintf(name_buffer, sizeof(name_buffer) - 1,
L"\\??\\" VFD_DEVICE_BASENAME L"%lu",
device_extension->DeviceNumber);
RtlInitUnicodeString(&unicode_name, name_buffer);
status = IoCreateSymbolicLink(
&unicode_name, &device_extension->DeviceName);
if (!NT_SUCCESS(status)) {
VFDTRACE(VFDERR,
("[VFD] IoCreateSymbolicLink(%ws) %s\n",
name_buffer, GetStatusName(status)));
goto cleanup;
}
VFDTRACE(VFDINFO|VFDDEV,
("[VFD] Created a symbolic link %ws\n", name_buffer));
// Prepare the IRP queue list for the device thread
InitializeListHead(&device_extension->ListHead);
KeInitializeSpinLock(&device_extension->ListLock);
KeInitializeEvent(
&device_extension->RequestEvent,
SynchronizationEvent,
FALSE);
// Create the device thread
device_extension->TerminateThread = FALSE;
status = PsCreateSystemThread(
&thread_handle,
(ACCESS_MASK) 0L,
NULL,
NULL,
NULL,
VfdDeviceThread,
device_object);
if (!NT_SUCCESS(status)) {
VFDTRACE(VFDERR,
("[VFD] PsCreateSystemThread() %s\n",
GetStatusName(status)));
goto cleanup;
}
// get a reference pointer to the thread
status = ObReferenceObjectByHandle(
thread_handle,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&device_extension->ThreadPointer,
NULL);
ZwClose(thread_handle);
if (!NT_SUCCESS(status)) {
VFDTRACE(VFDERR,
("[VFD] ObReferenceObjectByHandle() %s\n",
GetStatusName(status)));
goto cleanup;
}
//
// Load the persistent drive letter from the registry
//
if (driver_extension->RegistryPath.Buffer) {
VfdLoadLink(device_extension,
driver_extension->RegistryPath.Buffer);
// error is not fatal here
}
// increment the number of devices in the driver extension
driver_extension->NumberOfDevices++;
if (DriverObject->DriverUnload) {
// not called from the DriverEntry routine
device_object->Flags &= ~DO_DEVICE_INITIALIZING;
}
#ifdef VFD_PNP
if (Parameter) {
// return the device object pointer
*(PDEVICE_OBJECT *)Parameter = device_object;
}
#else // VFD_PNP
device_extension->DriverExtension = driver_extension;
#endif // VFD_PNP
VFDTRACE(VFDINFO | VFDDEV, ("[VFD] VfdCreateDevice - OK\n"));
return STATUS_SUCCESS;
cleanup:
//
// Something went wrong at one point
// Delete all resources that might be created in this function
//
if (thread_handle) {
// terminate the device thread
device_extension->TerminateThread = TRUE;
KeSetEvent(
&device_extension->RequestEvent,
(KPRIORITY) 0,
FALSE);
if (device_extension->ThreadPointer) {
ObDereferenceObject(device_extension->ThreadPointer);
}
}
VFDTRACE(VFDINFO|VFDDEV,
("[VFD] Deleting symbolic link %ws\n", name_buffer));
IoDeleteSymbolicLink(&unicode_name);
if (device_extension->DeviceName.Buffer) {
VFDTRACE(VFDINFO|VFDDEV, ("[VFD] Deleting device %ws\n",
device_extension->DeviceName.Buffer));
ExFreePool(device_extension->DeviceName.Buffer);
}
IoDeleteDevice(device_object);
IoGetConfigurationInformation()->FloppyCount--;
VFDTRACE(VFDINFO|VFDDEV,
("[VFD] VfdCreateDevice - %s\n",
GetStatusName(status)));
return status;
}
//
// delete a VFD device object
//
VOID
VfdDeleteDevice(
IN PDEVICE_OBJECT DeviceObject)
{
PDEVICE_EXTENSION device_extension;
PVFD_DRIVER_EXTENSION driver_extension;
UNICODE_STRING unicode_name;
WCHAR name_buffer[40];
VFDTRACE(VFDINFO|VFDDEV, ("[VFD] VfdDeleteDevice - IN\n"));
device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// decrement the number of device in the driver extension
//
#ifdef VFD_PNP
driver_extension = IoGetDriverObjectExtension(
DeviceObject->DriverObject, VFD_DRIVER_EXTENSION_ID);
#else // VFD_PNP
driver_extension = device_extension->DriverExtension;
#endif // VFD_PNP
if (driver_extension) {
driver_extension->NumberOfDevices--;
}
//
// cleanup the device object
//
// Terminate the device thread
device_extension->TerminateThread = TRUE;
KeSetEvent(
&device_extension->RequestEvent,
(KPRIORITY) 0,
FALSE);
KeWaitForSingleObject(
device_extension->ThreadPointer,
Executive,
KernelMode,
FALSE,
NULL);
ObDereferenceObject(
device_extension->ThreadPointer);
// Delete security context object
if (device_extension->SecurityContext) {
SeDeleteClientSecurity(device_extension->SecurityContext);
ExFreePool(device_extension->SecurityContext);
}
// Close the image file or free the image buffer
if (device_extension->FileHandle) {
ZwClose(device_extension->FileHandle);
}
if (device_extension->FileBuffer) {
ExFreePool(device_extension->FileBuffer);
}
// Release the image path buffer
if (device_extension->FileName.Buffer) {
ExFreePool(device_extension->FileName.Buffer);
}
// Remove the interface symbolic link
name_buffer[sizeof(name_buffer) - 1] = UNICODE_NULL;
_snwprintf(name_buffer, sizeof(name_buffer) - 1,
L"\\??\\" VFD_DEVICE_BASENAME L"%lu",
device_extension->DeviceNumber);
RtlInitUnicodeString(&unicode_name, name_buffer);
VFDTRACE(VFDINFO|VFDDEV,
("[VFD] Deleting link %ws\n", name_buffer));
IoDeleteSymbolicLink(&unicode_name);
// Remove the persistent drive letter
if (device_extension->DriveLetter) {
#ifdef VFD_MOUNT_MANAGER
if (OsMajorVersion >= 5) {
// Request the mount manager to remove the drive letter.
// This will cause the mount manager to update its database
// and it won't arbitrarily assign the drive letter the next
// time the driver starts.
VfdMountMgrMountPoint(device_extension, 0);
}
else
#endif // VFD_MOUNT_MANAGER
{
// Windows NT style drive letter handling
// Simply remove the symbolic link
VfdSetLink(device_extension, 0);
}
}
// Release the device name buffer
if (device_extension->DeviceName.Buffer) {
VFDTRACE(VFDINFO|VFDDEV,
("[VFD] Deleting device %ws\n",
device_extension->DeviceName.Buffer));
ExFreePool(device_extension->DeviceName.Buffer);
}
// Delete the device object
IoDeleteDevice(DeviceObject);
IoGetConfigurationInformation()->FloppyCount--;
VFDTRACE(VFDINFO|VFDDEV,
("[VFD] VfdDeleteDevice - OUT\n"));
return;
}

View file

@ -0,0 +1,523 @@
/*
vfddrv.c
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: miscellaneous driver functions
Copyright (C) 2003-2005 Ken Kato
*/
#include "imports.h"
#include "vfddrv.h"
#include "vfddbg.h"
//
// driver reinitialize routine
// -- create a drive letter for each device
//
#ifdef __cplusplus
extern "C"
#endif // __cplusplus
static VOID
NTAPI
VfdReinitialize(
IN PDRIVER_OBJECT DriverObject,
IN PVOID Context,
IN ULONG Count);
//
// specify code segment
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, VfdReinitialize)
#pragma alloc_text(PAGE, VfdUnloadDriver)
#pragma alloc_text(PAGE, VfdCreateClose)
#pragma alloc_text(PAGE, VfdCopyUnicode)
#pragma alloc_text(PAGE, VfdFreeUnicode)
#endif // ALLOC_PRAGMA
//
// operating system version
//
#ifndef __REACTOS__
extern ULONG OsMajorVersion = 0;
extern ULONG OsMinorVersion = 0;
extern ULONG OsBuildNumber = 0;
#else
ULONG OsMajorVersion = 0;
ULONG OsMinorVersion = 0;
ULONG OsBuildNumber = 0;
#endif
//
// Trace level flag
//
#if DBG
#ifndef __REACTOS__
extern ULONG TraceFlags = (ULONG)-1;
#else
ULONG TraceFlags = (ULONG)-1;
#endif
#endif // DBG
//
// Driver Entry routine
//
NTSTATUS
NTAPI
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
PVFD_DRIVER_EXTENSION driver_extension;
ULONG number_of_devices = VFD_DEFAULT_DEVICES;
ASSERT(DriverObject);
// Get operating system version
PsGetVersion(&OsMajorVersion, &OsMinorVersion, &OsBuildNumber, NULL);
#ifdef VFD_PNP
#define VFD_PNP_TAG "(Plug & Play version)"
#else
#define VFD_PNP_TAG
#endif
VFDTRACE(0, ("[VFD] %s %s" VFD_PNP_TAG "\n",
VFD_PRODUCT_NAME, VFD_DRIVER_VERSION_STR));
VFDTRACE(0,
("[VFD] Running on Windows NT %lu.%lu build %lu\n",
OsMajorVersion, OsMinorVersion, OsBuildNumber));
VFDTRACE(0,
("[VFD] Build Target Environment: %d\n", VER_PRODUCTBUILD));
#ifdef VFD_PNP
// Create device_extension for the driver object to store driver specific
// information. Device specific information are stored in device extension
// for each device object.
status = IoAllocateDriverObjectExtension(
DriverObject,
VFD_DRIVER_EXTENSION_ID,
sizeof(VFD_DRIVER_EXTENSION),
&driver_extension);
if(!NT_SUCCESS(status)) {
VFDTRACE(0, ("[VFD] IoAllocateDriverObjectExtension - %s\n",
GetStatusName(status)));
return status;
}
#else // VFD_PNP
// Windows NT doesn't have the IoAllocateDriverObjectExtension
// function and I think there's little point in making a non-PnP
// driver incompatible with Windows NT.
driver_extension = (PVFD_DRIVER_EXTENSION)ExAllocatePoolWithTag(
PagedPool, sizeof(VFD_DRIVER_EXTENSION), VFD_POOL_TAG);
if (!driver_extension) {
VFDTRACE(0, ("[VFD] failed to allocate the driver extension.\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
#endif // VFD_PNP
RtlZeroMemory(driver_extension, sizeof(VFD_DRIVER_EXTENSION));
//
// Copy the registry path into the driver extension so we can use it later
//
if (VfdCopyUnicode(&(driver_extension->RegistryPath), RegistryPath)) {
//
// Read config values from the registry
//
RTL_QUERY_REGISTRY_TABLE params[3];
ULONG default_devs = VFD_DEFAULT_DEVICES;
#if DBG
ULONG default_trace = (ULONG)-1;
#endif
RtlZeroMemory(params, sizeof(params));
VFDTRACE(0, ("[VFD] Registry Path: %ws\n",
driver_extension->RegistryPath.Buffer));
params[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
params[0].Name = VFD_REG_DEVICE_NUMBER;
params[0].EntryContext = &number_of_devices;
params[0].DefaultType = REG_DWORD;
params[0].DefaultData = &default_devs;
params[0].DefaultLength = sizeof(ULONG);
#if DBG
params[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
params[1].Name = VFD_REG_TRACE_FLAGS;
params[1].EntryContext = &TraceFlags;
params[1].DefaultType = REG_DWORD;
params[1].DefaultData = &default_trace;
params[1].DefaultLength = sizeof(ULONG);
#endif // DBG
status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
driver_extension->RegistryPath.Buffer,
params, NULL, NULL);
if (!NT_SUCCESS(status) ||
number_of_devices == 0 ||
number_of_devices > VFD_MAXIMUM_DEVICES) {
number_of_devices = VFD_DEFAULT_DEVICES;
}
VFDTRACE(0,("[VFD] NumberOfDevices = %lu\n", number_of_devices));
VFDTRACE(0,("[VFD] TraceFlags = 0x%08x\n", TraceFlags));
}
else {
VFDTRACE(0, ("[VFD] failed to allocate the registry path buffer.\n"));
// this error is not fatal
}
//
// Create VFD device objects
//
do {
#ifdef VFD_PNP
status = VfdCreateDevice(DriverObject, NULL);
#else // VFD_PNP
status = VfdCreateDevice(DriverObject, driver_extension);
#endif // VFD_PNP
if (!NT_SUCCESS(status)) {
break;
}
}
while (driver_extension->NumberOfDevices < number_of_devices);
if (!driver_extension->NumberOfDevices) {
// Failed to create even one device
VfdFreeUnicode(&(driver_extension->RegistryPath));
return status;
}
// Setup dispatch table
DriverObject->MajorFunction[IRP_MJ_CREATE] = VfdCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = VfdCreateClose;
DriverObject->MajorFunction[IRP_MJ_READ] = VfdReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = VfdReadWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VfdDeviceControl;
#ifdef VFD_PNP
DriverObject->MajorFunction[IRP_MJ_PNP] = VfdPlugAndPlay;
DriverObject->MajorFunction[IRP_MJ_POWER] = VfdPowerControl;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = VfdSystemControl;
DriverObject->DriverExtension->AddDevice = VfdAddDevice;
#endif // VFDPNP
DriverObject->DriverUnload = VfdUnloadDriver;
// Register the driver reinitialize routine to be called
// *after* the DriverEntry routine returns
IoRegisterDriverReinitialization(
DriverObject, VfdReinitialize, NULL);
VFDTRACE(VFDINFO,
("[VFD] driver initialized with %lu devices.\n",
driver_extension->NumberOfDevices));
return STATUS_SUCCESS;
}
//
// Driver unload routine
// Cleans up the device objects and other resources
//
VOID
NTAPI
VfdUnloadDriver (
IN PDRIVER_OBJECT DriverObject)
{
PDEVICE_OBJECT device_object;
PVFD_DRIVER_EXTENSION driver_extension;
VFDTRACE(VFDINFO, ("[VFD] VfdUnloadDriver - IN\n"));
device_object = DriverObject->DeviceObject;
#ifdef VFD_PNP
driver_extension = IoGetDriverObjectExtension(
DriverObject, VFD_DRIVER_EXTENSION_ID);
#else
if (device_object && device_object->DeviceExtension) {
driver_extension =
((PDEVICE_EXTENSION)(device_object->DeviceExtension))->DriverExtension;
}
else {
driver_extension = NULL;
}
#endif // VFD_PNP
//
// Delete all remaining device objects
//
while (device_object) {
PDEVICE_OBJECT next_device = device_object->NextDevice;
VfdDeleteDevice(device_object);
device_object = next_device;
}
//
// Release the driver extension and the registry path buffer
//
if (driver_extension) {
if (driver_extension->RegistryPath.Buffer) {
VFDTRACE(0, ("[VFD] Releasing the registry path buffer\n"));
ExFreePool(driver_extension->RegistryPath.Buffer);
}
#ifndef VFD_PNP
// The system takes care of freeing the driver extension
// allocated with IoAllocateDriverObjectExtension in a PnP driver.
VFDTRACE(0, ("[VFD] Releasing the driver extension\n"));
ExFreePool(driver_extension);
#endif // VFD_PNP
}
VFDTRACE(VFDINFO, ("[VFD] VfdUnloadDriver - OUT\n"));
}
//
// IRP_MJ_CREATE and IRP_MJ_CLOSE handler
// Really nothing to do here...
//
NTSTATUS
NTAPI
VfdCreateClose (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
#if DBG
if (DeviceObject && DeviceObject->DeviceExtension &&
((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer) {
VFDTRACE(VFDINFO, ("[VFD] %-40s %ws\n",
GetMajorFuncName(IoGetCurrentIrpStackLocation(Irp)->MajorFunction),
((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer));
}
else {
VFDTRACE(VFDINFO, ("[VFD] %-40s %p\n",
GetMajorFuncName(IoGetCurrentIrpStackLocation(Irp)->MajorFunction),
DeviceObject));
}
#endif // DBG
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = FILE_OPENED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//
// Called after the DriverEntry routine has returned
// (Re)Create a persistent drive letter for each device
//
VOID
NTAPI
VfdReinitialize(
IN PDRIVER_OBJECT DriverObject,
IN PVOID Context,
IN ULONG Count)
{
PDEVICE_OBJECT device_object;
PDEVICE_EXTENSION device_extension;
UNREFERENCED_PARAMETER(Context);
UNREFERENCED_PARAMETER(Count);
VFDTRACE(VFDINFO, ("[VFD] VfdReinitialize - IN\n"));
device_object = DriverObject->DeviceObject;
while (device_object) {
device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension;
#ifdef VFD_MOUNT_MANAGER
if (OsMajorVersion >= 5) {
// Windows 2000 / XP
// Notify the mount manager of a VFD volume arrival
VfdMountMgrNotifyVolume(device_extension);
if (device_extension->DriveLetter) {
// Create a drive letter via the mount manager.
// The mount manager may have created a drive letter
// in response to the volume arrival notification above.
// In that case, the following call just fails.
VfdMountMgrMountPoint(
device_extension, device_extension->DriveLetter);
// ignoring the error for it is not fatal here
}
}
else
#endif // VFD_MOUNT_MANAGER
{
// Windows NT style drive letter assignment
// Simply create a symbolic link here
if (device_extension->DriveLetter) {
VfdSetLink(
device_extension, device_extension->DriveLetter);
// ignoring the error for it is not fatal here
}
}
device_object = device_object->NextDevice;
}
VFDTRACE(VFDINFO, ("[VFD] VfdReinitialize - OUT\n"));
}
//
// Device dedicated thread routine
// Dispatch read, write and device I/O request
// redirected from the driver dispatch routines
//
VOID
NTAPI
VfdDeviceThread (
IN PVOID ThreadContext)
{
PDEVICE_OBJECT device_object;
PDEVICE_EXTENSION device_extension;
PLIST_ENTRY request;
PIRP irp;
PIO_STACK_LOCATION io_stack;
ASSERT(ThreadContext != NULL);
device_object = (PDEVICE_OBJECT)ThreadContext;
device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension;
KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
for (;;) {
// wait for the request event to be signalled
KeWaitForSingleObject(
&device_extension->RequestEvent,
Executive,
KernelMode,
FALSE,
NULL);
// terminate request ?
if (device_extension->TerminateThread) {
VFDTRACE(0, ("[VFD] Exitting the I/O thread\n"));
PsTerminateSystemThread(STATUS_SUCCESS);
}
// perform requested tasks
while ((request = ExInterlockedRemoveHeadList(
&device_extension->ListHead,
&device_extension->ListLock)) != NULL)
{
irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry);
io_stack = IoGetCurrentIrpStackLocation(irp);
irp->IoStatus.Information = 0;
switch (io_stack->MajorFunction) {
case IRP_MJ_READ:
VfdReadData(device_extension, irp,
io_stack->Parameters.Read.Length,
&io_stack->Parameters.Read.ByteOffset);
break;
case IRP_MJ_WRITE:
VfdWriteData(device_extension, irp,
io_stack->Parameters.Write.Length,
&io_stack->Parameters.Write.ByteOffset);
break;
case IRP_MJ_DEVICE_CONTROL:
VfdIoCtlThread(device_extension, irp,
io_stack->Parameters.DeviceIoControl.IoControlCode);
break;
default:
// This shouldn't happen...
VFDTRACE(0,
("[VFD] %s passed to the I/O thread\n",
GetMajorFuncName(io_stack->MajorFunction)));
irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
}
IoCompleteRequest(irp,
(CCHAR)(NT_SUCCESS(irp->IoStatus.Status) ?
IO_DISK_INCREMENT : IO_NO_INCREMENT));
#ifdef VFD_PNP
IoReleaseRemoveLock(&device_extension->RemoveLock, irp);
#endif // VFD_PNP
} // while
} // for (;;)
}
//
// Copy a UNICODE_STRING adding a trailing NULL characer
//
PWSTR VfdCopyUnicode(
PUNICODE_STRING dst,
PUNICODE_STRING src)
{
RtlZeroMemory(dst, sizeof(UNICODE_STRING));
dst->MaximumLength =
(USHORT)(src->MaximumLength + sizeof(UNICODE_NULL));
dst->Buffer = (PWSTR)ExAllocatePoolWithTag(
PagedPool, dst->MaximumLength, VFD_POOL_TAG);
if(dst->Buffer) {
dst->Length = src->Length;
RtlZeroMemory(dst->Buffer, dst->MaximumLength);
if (src->Length) {
RtlCopyMemory(dst->Buffer, src->Buffer, src->Length);
}
}
return dst->Buffer;
}
//
// Free a UNICODE_STRING buffer
//
VOID VfdFreeUnicode(
PUNICODE_STRING str)
{
if (str->Buffer) {
ExFreePool(str->Buffer);
}
RtlZeroMemory(str, sizeof(UNICODE_STRING));
}

View file

@ -0,0 +1,357 @@
/*
vfddrv.h
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: local header
Copyright(C) 2003-2005 Ken Kato
*/
#ifndef _VFDDRV_H_
#define _VFDDRV_H_
#ifdef __cplusplus
extern "C" {
#pragma message("Compiled as C++ for testing purpose.")
#endif // __cplusplus
#include "vfdtypes.h"
#include "vfdio.h"
#include "vfdver.h"
//
// Tag used for ExAllocatePoolWithTag
//
#define VFD_POOL_TAG 'DFVx'
//
// PnP driver specific stuff
//
#ifdef VFD_PNP
#if (VER_PRODUCTBUILD < 2195)
#error Cannot build a PnP version with the Windows NT DDK
#endif // (VER_PRODUCTBUILD < 2195)
//
// device state enumeration
//
typedef enum _DEVICE_STATE
{
VFD_STOPPED, // Dvice stopped
VFD_WORKING, // Started and working
VFD_PENDINGSTOP, // Stop pending
VFD_PENDINGREMOVE, // Remove pending
VFD_SURPRISEREMOVED, // Surprise removed
VFD_REMOVED, // Removed
VFD_MAX_STATE // Unknown state -Some error
}
DEVICE_STATE, *PDEVICE_STATE;
//
// use the address of the DriverEntry functions as the
// driver extension identifier
//
#define VFD_DRIVER_EXTENSION_ID ((PVOID)DriverEntry)
#endif // VFD_PNP
//
// driver extension for the VFD driver
//
typedef struct _VFD_DRIVER_EXTENSION
{
UNICODE_STRING RegistryPath;
ULONG NumberOfDevices;
}
VFD_DRIVER_EXTENSION, *PVFD_DRIVER_EXTENSION;
//
// device extension for Virtual FD device
//
typedef struct _DEVICE_EXTENSION
{
// back pointer to the device object
PDEVICE_OBJECT DeviceObject;
// device information
UNICODE_STRING DeviceName; // \Device\Floppy<n>
ULONG DeviceNumber; // \??\VirtualFD<n>
CHAR DriveLetter; // \DosDevices\<x>:
// Security context to access files on network drive
PSECURITY_CLIENT_CONTEXT SecurityContext;
// IRP queue list
LIST_ENTRY ListHead;
KSPIN_LOCK ListLock;
// device thread
KEVENT RequestEvent;
PVOID ThreadPointer;
BOOLEAN TerminateThread;
// drive information
ULONG MediaChangeCount;
// media information
VFD_MEDIA MediaType;
VFD_FLAGS MediaFlags;
VFD_FILETYPE FileType;
ULONG ImageSize;
ANSI_STRING FileName;
const DISK_GEOMETRY *Geometry;
ULONG Sectors;
HANDLE FileHandle;
PUCHAR FileBuffer;
#ifdef VFD_PNP
DEVICE_STATE DeviceState; // Current device state
IO_REMOVE_LOCK RemoveLock; // avoid abnormal removal
PDEVICE_OBJECT PhysicalDevice;
PDEVICE_OBJECT TargetDevice;
UNICODE_STRING InterfaceName;
#else // VFD_PNP
PVFD_DRIVER_EXTENSION DriverExtension;
#endif // VFD_PNP
}
DEVICE_EXTENSION, *PDEVICE_EXTENSION;
//
// Stanard driver routines
//
NTSTATUS
NTAPI
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath);
VOID
NTAPI
VfdUnloadDriver(
IN PDRIVER_OBJECT DriverObject);
NTSTATUS
NTAPI
VfdCreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS
NTAPI
VfdReadWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS
NTAPI
VfdDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
#ifdef VFD_PNP
NTSTATUS
NTAPI
VfdPlugAndPlay(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS
NTAPI
VfdPowerControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS
NTAPI
VfdSystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp);
NTSTATUS
NTAPI
VfdAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN OUT PDEVICE_OBJECT PhysicalDevice);
#endif // VFD_PNP
//
// Prototypes for private routines
//
//
// vfddrv.c
//
extern ULONG OsMajorVersion;
extern ULONG OsMinorVersion;
extern ULONG OsBuildNumber;
VOID
NTAPI
VfdDeviceThread(
IN PVOID ThreadContext);
PWSTR
VfdCopyUnicode(
OUT PUNICODE_STRING dst,
IN PUNICODE_STRING src);
VOID
VfdFreeUnicode(
IN OUT PUNICODE_STRING str);
//
// vfddev.c
//
NTSTATUS
VfdCreateDevice(
IN PDRIVER_OBJECT DriverObject,
OUT PVOID Parameter);
VOID
VfdDeleteDevice(
IN PDEVICE_OBJECT DeviceObject);
//
// vfdioctl.c
//
VOID
VfdIoCtlThread(
IN PDEVICE_EXTENSION DeviceExtension,
IN PIRP Irp,
IN ULONG ControlCode);
//
// vfdimg.c
//
NTSTATUS
VfdOpenCheck(
IN PDEVICE_EXTENSION DeviceExtension,
IN PVFD_IMAGE_INFO ImageInfo,
IN ULONG InputLength);
NTSTATUS
VfdOpenImage(
IN PDEVICE_EXTENSION DeviceExtension,
IN PVFD_IMAGE_INFO ImageInfo);
VOID
VfdCloseImage(
IN PDEVICE_EXTENSION DeviceExtension);
NTSTATUS
VfdQueryImage(
IN PDEVICE_EXTENSION DeviceExtension,
OUT PVFD_IMAGE_INFO ImageInfo,
IN ULONG BufferLength,
OUT PULONG ReturnLength);
//
// vfdrdwr.c
//
VOID
VfdReadData(
IN PDEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp,
IN ULONG Length,
IN PLARGE_INTEGER Offset);
VOID
VfdWriteData(
IN PDEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp,
IN ULONG Length,
IN PLARGE_INTEGER Offset);
//
// vfdlink.c
//
NTSTATUS
VfdSetLink(
IN PDEVICE_EXTENSION DeviceExtension,
IN CHAR DriveLetter);
NTSTATUS
VfdStoreLink(
IN PDEVICE_EXTENSION DeviceExtension);
NTSTATUS
VfdLoadLink(
IN PDEVICE_EXTENSION DeviceExtension,
IN PWSTR RegistryPath);
//
// vfdfmt.c
//
extern const DISK_GEOMETRY geom_tbl[VFD_MEDIA_MAX];
NTSTATUS
VfdFormatCheck(
IN PDEVICE_EXTENSION DeviceExtension,
IN PFORMAT_PARAMETERS FormatParams,
IN ULONG InputLength,
IN ULONG ControlCode);
NTSTATUS
VfdFormatTrack(
IN PDEVICE_EXTENSION DeviceExtension,
IN PFORMAT_PARAMETERS FormatParams);
//
// vfdmnt.c
//
#ifdef VFD_MOUNT_MANAGER
/*
NTSTATUS
VfdRegisterMountManager(
IN PDEVICE_EXTENSION DeviceExtension);
*/
NTSTATUS
VfdMountMgrNotifyVolume(
IN PDEVICE_EXTENSION DeviceExtension);
NTSTATUS
VfdMountMgrMountPoint(
IN PDEVICE_EXTENSION DeviceExtension,
IN CHAR DriveLetter);
NTSTATUS
VfdMountDevUniqueId(
IN PDEVICE_EXTENSION DeviceExtension,
OUT PMOUNTDEV_UNIQUE_ID UniqueId,
IN ULONG OutputLength,
OUT PIO_STATUS_BLOCK IoStatus);
NTSTATUS
VfdMountDevDeviceName(
IN PDEVICE_EXTENSION DeviceExtension,
OUT PMOUNTDEV_NAME DeviceName,
IN ULONG OutputLength,
OUT PIO_STATUS_BLOCK IoStatus);
NTSTATUS
VfdMountDevSuggestedLink(
IN PDEVICE_EXTENSION DeviceExtension,
OUT PMOUNTDEV_SUGGESTED_LINK_NAME LinkName,
IN ULONG OutputLength,
OUT PIO_STATUS_BLOCK IoStatus);
NTSTATUS
VfdMountDevLinkModified(
IN PDEVICE_EXTENSION DeviceExtension,
IN PMOUNTDEV_NAME LinkName,
IN ULONG InputLength,
IN ULONG ControlCode);
#endif // VFD_MOUNT_MANAGER
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _VFDDRV_H_

View file

@ -0,0 +1,30 @@
/*
vfddrv.rc
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: version resource script
Copyright (C) 2003-2005 Ken Kato
*/
// !!! NOTE !!!
// Editing this file with Microsoft Visual Studio will almost
// certainly mess things up...
#ifndef APSTUDIO_INVOKED
#include <winver.h>
#include "vfdver.h"
#define VFD_FILEOS VOS_NT_WINDOWS32
#define VFD_FILETYPE VFT_DRV
#define VFD_FILESUBTYPE VFT2_DRV_SYSTEM
#define VFD_DESCRIPTION "Virtual Floppy Drive Kernel Mode Driver"
#define VFD_INTERNALNAME VFD_DRIVER_FILENAME
#define VFD_FILE_MAJOR VFD_DRIVER_MAJOR
#define VFD_FILE_MINOR VFD_DRIVER_MINOR
#include "vfdver.rc"
#endif // APSTUDIO_INVOKED

View file

@ -0,0 +1,234 @@
/*
vfdfmt.c
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: disk format functions
Copyright (C) 2003-2005 Ken Kato
*/
#include "imports.h"
#include "vfddrv.h"
#include "vfddbg.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, VfdFormatCheck)
#pragma alloc_text(PAGE, VfdFormatTrack)
#endif // ALLOC_PRAGMA
//
// Media geometry constant table
//
// MediaTypes values added since Win NT DDK
#ifndef F3_640_512
#define F3_640_512 (MEDIA_TYPE)14
#endif
#ifndef F3_1Pt2_512
#define F3_1Pt2_512 (MEDIA_TYPE)17
#endif
#ifndef __REACTOS__
extern DISK_GEOMETRY const geom_tbl[VFD_MEDIA_MAX] = {
DISK_GEOMETRY const geom_tbl[VFD_MEDIA_MAX] = {
{{ 80 }, F3_1Pt44_512, 2, 18, VFD_BYTES_PER_SECTOR }, // default
{{ 40 }, F5_160_512, 1, 8, VFD_BYTES_PER_SECTOR }, // 160K
{{ 40 }, F5_180_512, 1, 9, VFD_BYTES_PER_SECTOR }, // 180K
{{ 40 }, F5_320_512, 2, 8, VFD_BYTES_PER_SECTOR }, // 320K
{{ 40 }, F5_360_512, 2, 9, VFD_BYTES_PER_SECTOR }, // 360K
{{ 80 }, F3_640_512, 2, 8, VFD_BYTES_PER_SECTOR }, // 640k
{{ 80 }, F5_640_512, 2, 8, VFD_BYTES_PER_SECTOR }, // 640k
{{ 80 }, F3_720_512, 2, 9, VFD_BYTES_PER_SECTOR }, // 720K
{{ 80 }, F5_720_512, 2, 9, VFD_BYTES_PER_SECTOR }, // 720K
{{ 82 }, RemovableMedia, 2, 10, VFD_BYTES_PER_SECTOR }, // 820K
{{ 80 }, F3_1Pt2_512, 2, 15, VFD_BYTES_PER_SECTOR }, // 1200K
{{ 80 }, F5_1Pt2_512, 2, 15, VFD_BYTES_PER_SECTOR }, // 1200K
{{ 80 }, F3_1Pt44_512, 2, 18, VFD_BYTES_PER_SECTOR }, // 1440K
{{ 80 }, RemovableMedia, 2, 21, VFD_BYTES_PER_SECTOR }, // 1680K DMF
{{ 82 }, RemovableMedia, 2, 21, VFD_BYTES_PER_SECTOR }, // 1720K DMF
{{ 80 }, F3_2Pt88_512, 2, 36, VFD_BYTES_PER_SECTOR }, // 2880K
#else
DISK_GEOMETRY const geom_tbl[VFD_MEDIA_MAX] = {
{{ .QuadPart = 80 }, F3_1Pt44_512, 2, 18, VFD_BYTES_PER_SECTOR }, // default
{{ .QuadPart = 40 }, F5_160_512, 1, 8, VFD_BYTES_PER_SECTOR }, // 160K
{{ .QuadPart = 40 }, F5_180_512, 1, 9, VFD_BYTES_PER_SECTOR }, // 180K
{{ .QuadPart = 40 }, F5_320_512, 2, 8, VFD_BYTES_PER_SECTOR }, // 320K
{{ .QuadPart = 40 }, F5_360_512, 2, 9, VFD_BYTES_PER_SECTOR }, // 360K
{{ .QuadPart = 80 }, F3_640_512, 2, 8, VFD_BYTES_PER_SECTOR }, // 640k
{{ .QuadPart = 80 }, F5_640_512, 2, 8, VFD_BYTES_PER_SECTOR }, // 640k
{{ .QuadPart = 80 }, F3_720_512, 2, 9, VFD_BYTES_PER_SECTOR }, // 720K
{{ .QuadPart = 80 }, F5_720_512, 2, 9, VFD_BYTES_PER_SECTOR }, // 720K
{{ .QuadPart = 82 }, RemovableMedia, 2, 10, VFD_BYTES_PER_SECTOR }, // 820K
{{ .QuadPart = 80 }, F3_1Pt2_512, 2, 15, VFD_BYTES_PER_SECTOR }, // 1200K
{{ .QuadPart = 80 }, F5_1Pt2_512, 2, 15, VFD_BYTES_PER_SECTOR }, // 1200K
{{ .QuadPart = 80 }, F3_1Pt44_512, 2, 18, VFD_BYTES_PER_SECTOR }, // 1440K
{{ .QuadPart = 80 }, RemovableMedia, 2, 21, VFD_BYTES_PER_SECTOR }, // 1680K DMF
{{ .QuadPart = 82 }, RemovableMedia, 2, 21, VFD_BYTES_PER_SECTOR }, // 1720K DMF
{{ .QuadPart = 80 }, F3_2Pt88_512, 2, 36, VFD_BYTES_PER_SECTOR }, // 2880K
#endif
};
//
// Parameter check for IOCTL_DISK_FORMAT_TRACK and IOCTL_DISK_FORMAT_TRACK_EX
//
NTSTATUS
VfdFormatCheck(
PDEVICE_EXTENSION DeviceExtension,
PFORMAT_PARAMETERS FormatParams,
ULONG InputLength,
ULONG ControlCode)
{
const DISK_GEOMETRY *geometry;
// Check media status
if (!DeviceExtension->FileHandle &&
!DeviceExtension->FileBuffer) {
return STATUS_NO_MEDIA_IN_DEVICE;
}
// Media is writable?
if (DeviceExtension->MediaFlags & VFD_FLAG_WRITE_PROTECTED) {
return STATUS_MEDIA_WRITE_PROTECTED;
}
// Check input parameter size
if (InputLength < sizeof(FORMAT_PARAMETERS)) {
return STATUS_INVALID_PARAMETER;
}
// Choose appropriate DISK_GEOMETRY for current image size
geometry = DeviceExtension->Geometry;
if (!geometry) {
return STATUS_DRIVER_INTERNAL_ERROR;
}
// Input parameter sanity check
if ((FormatParams->StartHeadNumber > geometry->TracksPerCylinder - 1) ||
(FormatParams->EndHeadNumber > geometry->TracksPerCylinder - 1) ||
(FormatParams->StartCylinderNumber > geometry->Cylinders.LowPart) ||
(FormatParams->EndCylinderNumber > geometry->Cylinders.LowPart) ||
(FormatParams->EndCylinderNumber < FormatParams->StartCylinderNumber))
{
return STATUS_INVALID_PARAMETER;
}
// If this is an EX request then make a couple of extra checks
if (ControlCode == IOCTL_DISK_FORMAT_TRACKS_EX) {
PFORMAT_EX_PARAMETERS exparams;
if (InputLength < sizeof(FORMAT_EX_PARAMETERS)) {
return STATUS_INVALID_PARAMETER;
}
exparams = (PFORMAT_EX_PARAMETERS)FormatParams;
if (InputLength <
FIELD_OFFSET(FORMAT_EX_PARAMETERS, SectorNumber) +
exparams->SectorsPerTrack * sizeof(USHORT))
{
return STATUS_INVALID_PARAMETER;
}
if (exparams->FormatGapLength > geometry->SectorsPerTrack ||
exparams->SectorsPerTrack != geometry->SectorsPerTrack)
{
return STATUS_INVALID_PARAMETER;
}
}
return STATUS_SUCCESS;
}
//
// Format tracks
// Actually, just fills specified range of tracks with fill characters
//
NTSTATUS
VfdFormatTrack(
IN PDEVICE_EXTENSION DeviceExtension,
IN PFORMAT_PARAMETERS FormatParams)
{
const DISK_GEOMETRY *geometry;
ULONG track_length;
PUCHAR format_buffer;
LARGE_INTEGER start_offset;
LARGE_INTEGER end_offset;
NTSTATUS status;
VFDTRACE(0, ("[VFD] VfdFormatTrack - IN\n"));
ASSERT(DeviceExtension != NULL);
geometry = DeviceExtension->Geometry;
if (!geometry) {
return STATUS_DRIVER_INTERNAL_ERROR;
}
track_length = geometry->BytesPerSector * geometry->SectorsPerTrack;
format_buffer = (PUCHAR)ExAllocatePoolWithTag(
PagedPool, track_length, VFD_POOL_TAG);
if (format_buffer == NULL) {
VFDTRACE(0, ("[VFD] cannot allocate a format buffer\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlFillMemory(format_buffer, track_length, VFD_FORMAT_FILL_DATA);
start_offset.QuadPart =
FormatParams->StartCylinderNumber * geometry->TracksPerCylinder * track_length +
FormatParams->StartHeadNumber * track_length;
end_offset.QuadPart =
FormatParams->EndCylinderNumber * geometry->TracksPerCylinder * track_length +
FormatParams->EndHeadNumber * track_length;
do {
if (DeviceExtension->FileHandle) {
IO_STATUS_BLOCK io_status;
status = ZwWriteFile(
DeviceExtension->FileHandle,
NULL,
NULL,
NULL,
&io_status,
format_buffer,
track_length,
&start_offset,
NULL);
if (!NT_SUCCESS(status)) {
VFDTRACE(0, ("[VFD] ZwWriteFile - %s\n",
GetStatusName(status)));
break;
}
}
else {
RtlMoveMemory(
DeviceExtension->FileBuffer + start_offset.QuadPart,
format_buffer,
track_length);
status = STATUS_SUCCESS;
}
start_offset.QuadPart += track_length;
}
while (start_offset.QuadPart <= end_offset.QuadPart);
ExFreePool(format_buffer);
VFDTRACE(0, ("[VFD] VfdFormatTrack - OUT\n"));
return status;
}

View file

@ -0,0 +1,527 @@
/*
vfdimg.c
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: Image handling functions
Copyright (C) 2003-2005 Ken Kato
*/
#include "imports.h"
#include "vfddrv.h"
#include "vfddbg.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, VfdOpenCheck)
#pragma alloc_text(PAGE, VfdOpenImage)
#pragma alloc_text(PAGE, VfdCloseImage)
#pragma alloc_text(PAGE, VfdQueryImage)
#endif // ALLOC_PRAGMA
//
// Check IOCTL_VFD_OPEN_IMAGE input parameters
//
NTSTATUS
VfdOpenCheck(
PDEVICE_EXTENSION DeviceExtension,
PVFD_IMAGE_INFO ImageInfo,
ULONG InputLength)
{
// Check media status
if (DeviceExtension->FileHandle ||
DeviceExtension->FileBuffer) {
VFDTRACE(VFDWARN, ("[VFD] image already opened.\n"));
return STATUS_DEVICE_BUSY;
}
// Check input parameter length
if (InputLength < sizeof(VFD_IMAGE_INFO) ||
InputLength < sizeof(VFD_IMAGE_INFO) + ImageInfo->NameLength)
{
return STATUS_INVALID_PARAMETER;
}
// Check input parameters
if (ImageInfo->MediaType == VFD_MEDIA_NONE ||
ImageInfo->MediaType >= VFD_MEDIA_MAX) {
VFDTRACE(VFDWARN, ("[VFD] invalid MediaType - %u.\n",
ImageInfo->MediaType));
return STATUS_INVALID_PARAMETER;
}
if (ImageInfo->DiskType == VFD_DISKTYPE_FILE &&
ImageInfo->NameLength == 0) {
VFDTRACE(VFDWARN,
("[VFD] File name required for VFD_DISKTYPE_FILE.\n"));
return STATUS_INVALID_PARAMETER;
}
// create a security context to match the calling process' context
// the driver thread uses this context to impersonate the client
// to open the specified image file
// if (ImageInfo->DiskType == VFD_DISKTYPE_FILE)
{
SECURITY_QUALITY_OF_SERVICE sqos;
if (DeviceExtension->SecurityContext != NULL) {
SeDeleteClientSecurity(DeviceExtension->SecurityContext);
}
else {
DeviceExtension->SecurityContext =
(PSECURITY_CLIENT_CONTEXT)ExAllocatePoolWithTag(
NonPagedPool, sizeof(SECURITY_CLIENT_CONTEXT), VFD_POOL_TAG);
}
RtlZeroMemory(&sqos, sizeof(SECURITY_QUALITY_OF_SERVICE));
sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
sqos.ImpersonationLevel = SecurityImpersonation;
sqos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
sqos.EffectiveOnly = FALSE;
SeCreateClientSecurity(
PsGetCurrentThread(), &sqos, FALSE,
DeviceExtension->SecurityContext);
}
return STATUS_SUCCESS;
}
//
// Open a virtual floppy image file or create an empty ram disk
//
NTSTATUS
VfdOpenImage (
IN PDEVICE_EXTENSION DeviceExtension,
IN PVFD_IMAGE_INFO ImageInfo)
{
IO_STATUS_BLOCK io_status;
NTSTATUS status = STATUS_SUCCESS;
const DISK_GEOMETRY *geometry;
ULONG sectors;
ULONG alignment;
VFDTRACE(0, ("[VFD] VfdOpenImage - IN\n"));
//
// Store file name in the device extension
//
if (ImageInfo->NameLength) {
if (ImageInfo->NameLength + 1 >
DeviceExtension->FileName.MaximumLength) {
// expand the filename buffer
if (DeviceExtension->FileName.Buffer) {
ExFreePool(DeviceExtension->FileName.Buffer);
RtlZeroMemory(
&DeviceExtension->FileName,
sizeof(ANSI_STRING));
}
DeviceExtension->FileName.Buffer = (PCHAR)ExAllocatePoolWithTag(
NonPagedPool, ImageInfo->NameLength + 1, VFD_POOL_TAG);
if (!DeviceExtension->FileName.Buffer) {
VFDTRACE(0, ("[VFD] Can't allocate memory for image path\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
DeviceExtension->FileName.MaximumLength
= (USHORT)(ImageInfo->NameLength + 1);
RtlZeroMemory(
DeviceExtension->FileName.Buffer,
DeviceExtension->FileName.MaximumLength);
}
if (DeviceExtension->FileName.Buffer) {
RtlCopyMemory(
DeviceExtension->FileName.Buffer,
ImageInfo->FileName,
ImageInfo->NameLength);
DeviceExtension->FileName.Buffer[ImageInfo->NameLength] = '\0';
}
}
DeviceExtension->FileName.Length = ImageInfo->NameLength;
//
// Get DISK_GEOMETRY and calculate the media capacity
// -- validity of the ImageInfo->MediaType value is assured in
// the VfdOpenCheck function
//
geometry = &geom_tbl[ImageInfo->MediaType];
sectors =
geometry->Cylinders.LowPart *
geometry->TracksPerCylinder *
geometry->SectorsPerTrack;
if (ImageInfo->ImageSize != 0 &&
ImageInfo->ImageSize < VFD_SECTOR_TO_BYTE(sectors)) {
VFDTRACE(0, ("[VFD] Image is smaller than the media\n"));
return STATUS_INVALID_PARAMETER;
}
//
// Prepare a virtual media according to the ImageInfo
//
if (ImageInfo->DiskType == VFD_DISKTYPE_FILE) {
//
// open an existing image file
//
HANDLE file_handle;
OBJECT_ATTRIBUTES attributes;
UNICODE_STRING unicode_name;
FILE_STANDARD_INFORMATION file_standard;
FILE_BASIC_INFORMATION file_basic;
FILE_ALIGNMENT_INFORMATION file_alignment;
PFILE_OBJECT file_object;
BOOLEAN network_drive;
// convert the filename into a unicode string
status = RtlAnsiStringToUnicodeString(
&unicode_name, &DeviceExtension->FileName, TRUE);
if (!NT_SUCCESS(status)) {
VFDTRACE(0, ("[VFD] Failed to convert filename to UNICODE\n"));
return status;
}
VFDTRACE(VFDINFO,
("[VFD] Opening %s\n", DeviceExtension->FileName.Buffer));
// prepare an object attribute to open
InitializeObjectAttributes(
&attributes,
&unicode_name,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
// open the target file
status = ZwCreateFile(
&file_handle,
GENERIC_READ | GENERIC_WRITE,
&attributes,
&io_status,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE |
FILE_RANDOM_ACCESS |
FILE_NO_INTERMEDIATE_BUFFERING |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
RtlFreeUnicodeString(&unicode_name);
if (!NT_SUCCESS(status)) {
VFDTRACE(0, ("[VFD] ZwCreateFile - %s\n",
GetStatusName(status)));
return status;
}
// Check the file size
status = ZwQueryInformationFile(
file_handle,
&io_status,
&file_standard,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if (!NT_SUCCESS(status)) {
VFDTRACE(0,
("[VFD] ZwQueryInformationFile - FILE_STANDARD_INFORMATION\n"));
ZwClose(file_handle);
goto exit_func;
}
// Actual file size can be larger than the media capacity
if (file_standard.EndOfFile.QuadPart < VFD_SECTOR_TO_BYTE(sectors)) {
VFDTRACE(0, ("[VFD] file is smaller than the media.\n"));
status = STATUS_INVALID_PARAMETER;
ZwClose(file_handle);
goto exit_func;
}
DeviceExtension->ImageSize = file_standard.EndOfFile.LowPart;
// Find out whether the file is on a local disk or a network drive
network_drive = FALSE;
status = ObReferenceObjectByHandle(
file_handle,
GENERIC_READ,
NULL,
KernelMode,
#ifndef __REACTOS__
&file_object,
#else
(PVOID *)&file_object,
#endif
NULL);
if (NT_SUCCESS(status)) {
if (file_object && file_object->DeviceObject) {
VFDTRACE(VFDINFO, ("[VFD] Device type is 0x%08x\n",
file_object->DeviceObject->DeviceType));
if (file_object->DeviceObject->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM) {
network_drive = TRUE;
}
// how about these types ?
// FILE_DEVICE_NETWORK
// FILE_DEVICE_NETWORK_BROWSER
// FILE_DEVICE_NETWORK_REDIRECTOR
}
else {
VFDTRACE(VFDWARN, ("[VFD Cannot decide the device type\n"));
}
ObDereferenceObject(file_object);
}
else {
VFDTRACE(0, ("[VFD] ObReferenceObjectByHandle - %s\n",
GetStatusName(status)));
}
if (!network_drive) {
// The NT cache manager can deadlock if a filesystem that is using
// the cache manager is used in a virtual disk that stores its file
// on a file systemthat is also using the cache manager, this is
// why we open the file with FILE_NO_INTERMEDIATE_BUFFERING above,
// however if the file is compressed or encrypted NT will not honor
// this request and cache it anyway since it need to store the
// decompressed/unencrypted data somewhere, therefor we put an
// extra check here and don't alow disk images to be compressed/
// encrypted.
status = ZwQueryInformationFile(
file_handle,
&io_status,
&file_basic,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if (!NT_SUCCESS(status)) {
VFDTRACE(0,
("[VFD] ZwQueryInformationFile - FILE_BASIC_INFORMATION\n"));
ZwClose(file_handle);
goto exit_func;
}
if (file_basic.FileAttributes
& (FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_ENCRYPTED))
{
VFDTRACE(0,
("[VFD] Image file is compressed and/or encrypted\n"));
status = STATUS_ACCESS_DENIED;
ZwClose(file_handle);
goto exit_func;
}
}
// Retrieve the file alignment requirement
status = ZwQueryInformationFile(
file_handle,
&io_status,
&file_alignment,
sizeof(FILE_ALIGNMENT_INFORMATION),
FileAlignmentInformation);
if (!NT_SUCCESS(status)) {
VFDTRACE(0,
("[VFD] ZwQueryInformationFile - FILE_ALIGNMENT_INFORMATION\n"));
ZwClose(file_handle);
goto exit_func;
}
DeviceExtension->FileHandle = file_handle;
alignment = file_alignment.AlignmentRequirement;
VFDTRACE(0, ("[VFD] Opened an image file\n"));
}
else {
//
// Create an empty RAM disk
//
DeviceExtension->FileBuffer = (PUCHAR)ExAllocatePoolWithTag(
NonPagedPool,
VFD_SECTOR_TO_BYTE(sectors),
VFD_POOL_TAG);
if (!DeviceExtension->FileBuffer) {
VFDTRACE(0, ("[VFD] Can't allocate memory for RAM disk\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(
DeviceExtension->FileBuffer,
VFD_SECTOR_TO_BYTE(sectors));
if (ImageInfo->ImageSize) {
DeviceExtension->ImageSize = ImageInfo->ImageSize;
}
else {
DeviceExtension->ImageSize = VFD_SECTOR_TO_BYTE(sectors);
}
alignment = FILE_WORD_ALIGNMENT;
VFDTRACE(0, ("[VFD] Created an empty RAM disk\n"));
}
DeviceExtension->MediaChangeCount++;
DeviceExtension->MediaType = ImageInfo->MediaType;
DeviceExtension->MediaFlags = ImageInfo->MediaFlags;
DeviceExtension->FileType = ImageInfo->FileType;
DeviceExtension->Geometry = geometry;
DeviceExtension->Sectors = sectors;
VFDTRACE(0, ("[VFD] Media:%d Flag:0x%02x Size:%lu Capacity:%lu\n",
DeviceExtension->MediaType,
DeviceExtension->MediaFlags,
DeviceExtension->ImageSize,
DeviceExtension->Sectors));
DeviceExtension->DeviceObject->AlignmentRequirement
= alignment;
exit_func:
VFDTRACE(0, ("[VFD] VfdOpenImage - %s\n", GetStatusName(status)));
return status;
}
//
// Close the current image
//
VOID
VfdCloseImage (
IN PDEVICE_EXTENSION DeviceExtension)
{
VFDTRACE(0, ("[VFD] VfdCloseImage - IN\n"));
ASSERT(DeviceExtension);
DeviceExtension->MediaType = VFD_MEDIA_NONE;
DeviceExtension->MediaFlags = 0;
DeviceExtension->FileType = 0;
DeviceExtension->ImageSize = 0;
DeviceExtension->FileName.Length = 0;
DeviceExtension->Sectors = 0;
if (DeviceExtension->FileHandle) {
ZwClose(DeviceExtension->FileHandle);
DeviceExtension->FileHandle = NULL;
}
if (DeviceExtension->FileBuffer) {
ExFreePool(DeviceExtension->FileBuffer);
DeviceExtension->FileBuffer = NULL;
}
VFDTRACE(0, ("[VFD] VfdCloseImage - OUT\n"));
}
//
// Return information about the current image
//
NTSTATUS
VfdQueryImage(
IN PDEVICE_EXTENSION DeviceExtension,
OUT PVFD_IMAGE_INFO ImageInfo,
IN ULONG BufferLength,
OUT PULONG ReturnLength)
{
// Check output buffer length
if (BufferLength < sizeof(VFD_IMAGE_INFO)) {
return STATUS_BUFFER_TOO_SMALL;
}
RtlZeroMemory(ImageInfo, BufferLength);
// Store fixed length image information
ImageInfo->MediaType = DeviceExtension->MediaType;
if (DeviceExtension->MediaType == VFD_MEDIA_NONE) {
*ReturnLength = sizeof(VFD_IMAGE_INFO);
return STATUS_SUCCESS;
}
if (DeviceExtension->FileBuffer) {
ImageInfo->DiskType = VFD_DISKTYPE_RAM;
}
else {
ImageInfo->DiskType = VFD_DISKTYPE_FILE;
}
ImageInfo->MediaFlags = DeviceExtension->MediaFlags;
ImageInfo->FileType = DeviceExtension->FileType;
ImageInfo->ImageSize = DeviceExtension->ImageSize;
ImageInfo->NameLength = DeviceExtension->FileName.Length;
// output buffer is large enough to hold the file name?
if (BufferLength < sizeof(VFD_IMAGE_INFO) +
DeviceExtension->FileName.Length)
{
*ReturnLength = sizeof(VFD_IMAGE_INFO);
return STATUS_BUFFER_OVERFLOW;
}
// copy file name
if (DeviceExtension->FileName.Length &&
DeviceExtension->FileName.Buffer) {
RtlCopyMemory(ImageInfo->FileName,
DeviceExtension->FileName.Buffer,
DeviceExtension->FileName.Length);
}
// store the actually returned data length
*ReturnLength = sizeof(VFD_IMAGE_INFO) +
DeviceExtension->FileName.Length;
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,591 @@
/*
vfdioctl.c
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: I/O control request handling
Copyright (C) 2003-2005 Ken Kato
*/
#include "imports.h"
#include "vfddrv.h"
#include "vfddbg.h"
/*
#include <initguid.h>
DEFINE_GUID(VFD_GUID, 0x4563b3d8L, 0x936a, 0x4692,
0xb6, 0x0c, 0x16, 0xd3, 0xb2, 0x57, 0xbb, 0xf2);
*/
#define IO_INPUTLEN(p) (p)->Parameters.DeviceIoControl.InputBufferLength
#define IO_OUTPUTLEN(p) (p)->Parameters.DeviceIoControl.OutputBufferLength
#define IO_CTRLCODE(p) (p)->Parameters.DeviceIoControl.IoControlCode
//
// IOCTL commands handler
//
NTSTATUS
NTAPI
VfdDeviceControl (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION device_extension;
PIO_STACK_LOCATION io_stack;
NTSTATUS status;
device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
io_stack = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Information = 0;
VFDTRACE(VFDINFO, ("[VFD] %-40s %ws\n",
GetIoControlName(IO_CTRLCODE(io_stack)),
device_extension->DeviceName.Buffer));
#ifdef VFD_PNP
status = IoAcquireRemoveLock(&device_extension->RemoveLock, Irp);
if (!NT_SUCCESS(status)) {
VFDTRACE(0,
("Acquire RemoveLock failed %s\n", NtStatusToStr(status)));
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
#endif // VFD_PNP
/*
// Check if volume verification is required
if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
!(io_stack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
VFDTRACE(VFDWARN,
("[VFD] %-40s - %s\n",
GetIoControlName(IO_CTRLCODE(io_stack)),
GetStatusName(STATUS_VERIFY_REQUIRED)));
Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_VERIFY_REQUIRED;
}
*/
switch (IO_CTRLCODE(io_stack)) {
case IOCTL_VFD_OPEN_IMAGE:
// Open an image file or create an empty RAM disk.
// Only a few checks are done here.
// Actual operation is done in device thread
status = VfdOpenCheck(
device_extension,
(PVFD_IMAGE_INFO)Irp->AssociatedIrp.SystemBuffer,
IO_INPUTLEN(io_stack));
if (!NT_SUCCESS(status)) {
break;
}
// Pass the task to the device thread
status = STATUS_PENDING;
break;
case IOCTL_VFD_CLOSE_IMAGE:
case IOCTL_DISK_EJECT_MEDIA:
case IOCTL_STORAGE_EJECT_MEDIA:
// Close the current image file or delete the RAM disk
// Only status check is done here.
// Actual operation is done in device thread.
if (!device_extension->FileHandle &&
!device_extension->FileBuffer) {
status = STATUS_NO_MEDIA_IN_DEVICE;
break;
}
// Pass the task to the device thread
status = STATUS_PENDING;
break;
case IOCTL_VFD_QUERY_IMAGE:
// Returns current image file information
status = VfdQueryImage(
device_extension,
(PVFD_IMAGE_INFO)Irp->AssociatedIrp.SystemBuffer,
IO_OUTPUTLEN(io_stack),
&Irp->IoStatus.Information);
break;
case IOCTL_VFD_SET_LINK:
// Create / remove a persistent drive letter
// and store it in the registry
if (IO_INPUTLEN(io_stack) < sizeof(CHAR)) {
status = STATUS_INVALID_PARAMETER;
break;
}
#ifdef VFD_MOUNT_MANAGER
if (OsMajorVersion >= 5) {
// Windows 2000/XP
// Create a drive letter via the mount manager
status = VfdMountMgrMountPoint(device_extension,
*(PCHAR)Irp->AssociatedIrp.SystemBuffer);
// The new drive letter will be stored in the device extension
// and the registry when IOCTL_MOUNTDEV_LINK_CREATED or
// IOCTL_MOUNTDEV_LINK_DELETED is issued from the mount manager.
}
else
#else // VFD_MOUNT_MANAGER
{
// Windows NT style drive letter assignment
// Simply create a symbolic link and store the new value
status = VfdSetLink(device_extension,
*(PCHAR)Irp->AssociatedIrp.SystemBuffer);
if (NT_SUCCESS(status)) {
// Store the new drive letter into the registry
status = VfdStoreLink(device_extension);
}
}
#endif // VFD_MOUNT_MANAGER
break;
case IOCTL_VFD_QUERY_LINK:
// Return the current persistent drive letter
if (IO_OUTPUTLEN(io_stack) < sizeof(CHAR)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
*(PCHAR)Irp->AssociatedIrp.SystemBuffer =
device_extension->DriveLetter;
Irp->IoStatus.Information = sizeof(CHAR);
status = STATUS_SUCCESS;
break;
case IOCTL_VFD_SET_PROTECT:
// Set media protect flag
if (!device_extension->FileHandle &&
!device_extension->FileBuffer) {
status = STATUS_NO_MEDIA_IN_DEVICE;
break;
}
device_extension->MediaFlags |= VFD_FLAG_WRITE_PROTECTED;
status = STATUS_SUCCESS;
break;
case IOCTL_VFD_CLEAR_PROTECT:
// Clear media protect flag
if (!device_extension->FileHandle &&
!device_extension->FileBuffer) {
status = STATUS_NO_MEDIA_IN_DEVICE;
break;
}
device_extension->MediaFlags &= ~VFD_FLAG_WRITE_PROTECTED;
status = STATUS_SUCCESS;
break;
case IOCTL_VFD_RESET_MODIFY:
// Reset the data modify flag
if (!device_extension->FileHandle &&
!device_extension->FileBuffer) {
status = STATUS_NO_MEDIA_IN_DEVICE;
break;
}
device_extension->MediaFlags &= ~VFD_FLAG_DATA_MODIFIED;
status = STATUS_SUCCESS;
break;
case IOCTL_VFD_QUERY_NUMBER:
// Return VFD device number (\??\VirtualFD<n>)
if (IO_OUTPUTLEN(io_stack) < sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
*(PULONG)Irp->AssociatedIrp.SystemBuffer=
device_extension->DeviceNumber;
Irp->IoStatus.Information = sizeof(ULONG);
status = STATUS_SUCCESS;
break;
case IOCTL_VFD_QUERY_NAME:
// Return VFD device name (\Device\Floppy<n>)
// counted unicode string (not null terminated)
if (IO_OUTPUTLEN(io_stack) < sizeof(USHORT)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
{
PUSHORT p = (PUSHORT)Irp->AssociatedIrp.SystemBuffer;
*p = device_extension->DeviceName.Length;
if (IO_OUTPUTLEN(io_stack) < sizeof(USHORT) + *p) {
Irp->IoStatus.Information = sizeof(USHORT);
status = STATUS_BUFFER_OVERFLOW;
break;
}
RtlCopyMemory(p + 1, device_extension->DeviceName.Buffer, *p);
Irp->IoStatus.Information = sizeof(USHORT) + *p;
}
status = STATUS_SUCCESS;
break;
case IOCTL_VFD_QUERY_VERSION:
// Return the VFD driver version
if (IO_OUTPUTLEN(io_stack) < sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
*(PULONG)Irp->AssociatedIrp.SystemBuffer =
(VFD_DRIVER_MAJOR << 16) | VFD_DRIVER_MINOR | VFD_DEBUG_FLAG;
Irp->IoStatus.Information = sizeof(ULONG);
status = STATUS_SUCCESS;
break;
//
// standard disk and storage I/O control requests
//
case IOCTL_DISK_CHECK_VERIFY:
case IOCTL_STORAGE_CHECK_VERIFY:
case IOCTL_STORAGE_CHECK_VERIFY2:
if (IO_OUTPUTLEN(io_stack) >= sizeof(ULONG)) {
*(PULONG)Irp->AssociatedIrp.SystemBuffer =
device_extension->MediaChangeCount;
Irp->IoStatus.Information = sizeof(ULONG);
}
status = STATUS_SUCCESS;
break;
case IOCTL_DISK_FORMAT_TRACKS:
case IOCTL_DISK_FORMAT_TRACKS_EX:
// Only parameter checks are performed here
// Actual operation is done by the device thread
status = VfdFormatCheck(
device_extension,
(PFORMAT_PARAMETERS)Irp->AssociatedIrp.SystemBuffer,
IO_INPUTLEN(io_stack),
IO_CTRLCODE(io_stack));
if (!NT_SUCCESS(status)) {
break;
}
// Pass the task to the device thread
status = STATUS_PENDING;
break;
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
// Returns the geometry of current media
if (!device_extension->FileHandle &&
!device_extension->FileBuffer) {
status = STATUS_NO_MEDIA_IN_DEVICE;
break;
}
// fall through
case IOCTL_DISK_GET_MEDIA_TYPES:
case IOCTL_STORAGE_GET_MEDIA_TYPES:
// Return *the last mounted* disk geometry, although xxx_GET_MEDIA_TYPES
// commands are supposed to return all supported media types.
// This makes the matter much simpler...;-)
// If no image has been mounted yet, 1.44MB media is assumed.
if (IO_OUTPUTLEN(io_stack) < sizeof(DISK_GEOMETRY)) {
return STATUS_BUFFER_TOO_SMALL;
}
// Copy appropriate DISK_GEOMETRY into the output buffer
if (device_extension->Geometry) {
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
device_extension->Geometry,
sizeof(DISK_GEOMETRY));
}
else {
// default = 3.5" 1.44 MB media
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
&geom_tbl[VFD_MEDIA_F3_1P4],
sizeof(DISK_GEOMETRY));
}
Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
status = STATUS_SUCCESS;
break;
case IOCTL_DISK_GET_LENGTH_INFO:
// Return disk length information
// (Windows XP requires this request to be handled)
if (!device_extension->FileHandle &&
!device_extension->FileBuffer) {
status = STATUS_NO_MEDIA_IN_DEVICE;
break;
}
if (IO_OUTPUTLEN(io_stack) < sizeof(GET_LENGTH_INFORMATION)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
((PGET_LENGTH_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->Length.QuadPart =
VFD_SECTOR_TO_BYTE(device_extension->Sectors);
Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
status = STATUS_SUCCESS;
break;
case IOCTL_DISK_IS_WRITABLE:
// Checks if current media is writable
if (!device_extension->FileHandle &&
!device_extension->FileBuffer) {
status = STATUS_NO_MEDIA_IN_DEVICE;
}
else if (device_extension->MediaFlags & VFD_FLAG_WRITE_PROTECTED) {
status = STATUS_MEDIA_WRITE_PROTECTED;
}
else {
status = STATUS_SUCCESS;
}
break;
/*
case IOCTL_DISK_MEDIA_REMOVAL:
case IOCTL_STORAGE_MEDIA_REMOVAL:
// Since removal lock is irrelevant for virtual disks,
// there's really nothing to do here...
status = STATUS_SUCCESS;
break;
case IOCTL_STORAGE_GET_HOTPLUG_INFO:
{
PSTORAGE_HOTPLUG_INFO hotplug;
if (IO_OUTPUTLEN(io_stack) < sizeof(STORAGE_HOTPLUG_INFO)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
hotplug = (PSTORAGE_HOTPLUG_INFO)Irp->AssociatedIrp.SystemBuffer;
RtlZeroMemory(hotplug, sizeof(STORAGE_HOTPLUG_INFO));
hotplug->Size = sizeof(STORAGE_HOTPLUG_INFO);
hotplug->MediaRemovable = 1;
Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO);
status = STATUS_SUCCESS;
}
break;
*/
#ifdef VFD_MOUNT_MANAGER
//
// IO control requests received from the mount manager
// (on Windows 2000 / XP)
//
case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
// Returns a unique ID for the target device
status = VfdMountDevUniqueId(
device_extension,
Irp->AssociatedIrp.SystemBuffer,
IO_OUTPUTLEN(io_stack),
&Irp->IoStatus);
break;
// case IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY:
case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
// Returns the device name of the target device
status = VfdMountDevDeviceName(
device_extension,
Irp->AssociatedIrp.SystemBuffer,
IO_OUTPUTLEN(io_stack),
&Irp->IoStatus);
break;
case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:
// Returns the drive letter link which we want the mount manager
// to create. This request is issued in response to the volume
// arrival notification, and the mount manager will create the
// symbolic link.
status = VfdMountDevSuggestedLink(
device_extension,
Irp->AssociatedIrp.SystemBuffer,
IO_OUTPUTLEN(io_stack),
&Irp->IoStatus);
break;
case IOCTL_MOUNTDEV_LINK_CREATED:
case IOCTL_MOUNTDEV_LINK_DELETED:
// Issued after the mount manager created/deleted a symbolic link
status = VfdMountDevLinkModified(
device_extension,
Irp->AssociatedIrp.SystemBuffer,
IO_INPUTLEN(io_stack),
IO_CTRLCODE(io_stack));
break;
/*
case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
{
PMOUNTDEV_STABLE_GUID guid;
if (IO_OUTPUTLEN(io_stack) < sizeof(MOUNTDEV_STABLE_GUID)) {
status = STATUS_INVALID_PARAMETER;
break;
}
guid = Irp->AssociatedIrp.SystemBuffer;
RtlCopyMemory(
&guid->StableGuid, &VFD_GUID, sizeof(GUID));
Irp->IoStatus.Information = sizeof(guid);
status = STATUS_SUCCESS;
}
break;
*/
#endif // VFD_MOUNT_MANAGER
default:
// Unknown IOCTL request
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
#if DBG
if ((NT_SUCCESS(status) && (TraceFlags & VFDINFO) == VFDINFO) ||
(TraceFlags & VFDWARN) == VFDWARN) {
VFDTRACE(0,("[VFD] %-40s - %s\n",
GetIoControlName(IO_CTRLCODE(io_stack)),
GetStatusName(status)));
}
#endif
if (status == STATUS_PENDING) {
// Let the device thread perform the operation
IoMarkIrpPending(Irp);
ExInterlockedInsertTailList(
&device_extension->ListHead,
&Irp->Tail.Overlay.ListEntry,
&device_extension->ListLock);
KeSetEvent(
&device_extension->RequestEvent,
(KPRIORITY) 0,
FALSE);
}
else {
// complete the operation
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
#ifdef VFD_PNP
IoReleaseRemoveLock(&device_extension->RemoveLock, Irp);
#endif // VFD_PNP
}
return status;
}
//
// Handle IO control requests in the device thread
//
VOID
VfdIoCtlThread(
IN PDEVICE_EXTENSION DeviceExtension,
IN PIRP Irp,
IN ULONG ControlCode)
{
switch (ControlCode) {
case IOCTL_VFD_OPEN_IMAGE:
// open the file from the caller's security context
// -- this allows this driver to open network files
if (DeviceExtension->SecurityContext) {
SeImpersonateClient(DeviceExtension->SecurityContext, NULL);
}
Irp->IoStatus.Status = VfdOpenImage(DeviceExtension,
(PVFD_IMAGE_INFO)Irp->AssociatedIrp.SystemBuffer);
PsRevertToSelf();
break;
case IOCTL_VFD_CLOSE_IMAGE:
case IOCTL_DISK_EJECT_MEDIA:
case IOCTL_STORAGE_EJECT_MEDIA:
VfdCloseImage(DeviceExtension);
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IOCTL_DISK_FORMAT_TRACKS:
case IOCTL_DISK_FORMAT_TRACKS_EX:
Irp->IoStatus.Status = VfdFormatTrack(DeviceExtension,
(PFORMAT_PARAMETERS)Irp->AssociatedIrp.SystemBuffer);
break;
default:
// This shouldn't happen...
VFDTRACE(0,
("[VFD] %s passed to the device thread\n",
GetIoControlName(ControlCode)));
Irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
}
#if DBG
if ((NT_SUCCESS(Irp->IoStatus.Status) && (TraceFlags & VFDINFO) == VFDINFO) ||
(TraceFlags & VFDWARN) == VFDWARN) {
VFDTRACE(0,("[VFD] %-40s - %s\n",
GetIoControlName(ControlCode),
GetStatusName(Irp->IoStatus.Status)));
}
#endif
}

View file

@ -0,0 +1,226 @@
/*
vfdlink.c
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: persistent drive letter functions
Copyright (C) 2003-2005 Ken Kato
*/
#include "imports.h"
#include "vfddrv.h"
#include "vfddbg.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, VfdSetLink)
#pragma alloc_text(PAGE, VfdLoadLink)
#pragma alloc_text(PAGE, VfdStoreLink)
#endif // ALLOC_PRAGMA
//
// create or remove the persistent drive letter (Windows NT)
//
NTSTATUS
VfdSetLink(
IN PDEVICE_EXTENSION DeviceExtension,
IN CHAR DriveLetter)
{
UNICODE_STRING unicode_name;
WCHAR name_buf[15];
NTSTATUS status = STATUS_SUCCESS;
VFDTRACE(VFDINFO, ("[VFD] VfdSetLink - IN\n"));
// convert lower case into upper case
if (DriveLetter >= 'a' && DriveLetter <= 'z') {
DriveLetter -= ('a' - 'A');
}
// check the drive letter range
if (DriveLetter != 0 &&
(DriveLetter < 'A' || DriveLetter > 'Z')) {
return STATUS_INVALID_PARAMETER;
}
if (DeviceExtension->DriveLetter &&
DeviceExtension->DriveLetter != DriveLetter) {
//
// Delete the old drive letter
//
name_buf[sizeof(name_buf) - 1] = UNICODE_NULL;
_snwprintf(name_buf, sizeof(name_buf) - 1,
L"\\??\\%wc:", DeviceExtension->DriveLetter);
RtlInitUnicodeString(&unicode_name, name_buf);
status = IoDeleteSymbolicLink(&unicode_name);
if (NT_SUCCESS(status)) {
VFDTRACE(VFDINFO,
("[VFD] Link %ws deleted\n", name_buf));
DeviceExtension->DriveLetter = 0;
}
else if (status != STATUS_OBJECT_NAME_NOT_FOUND) {
// the driver letter did not exist in the first place
VFDTRACE(VFDINFO,
("[VFD] Link %ws not found\n", name_buf));
DeviceExtension->DriveLetter = 0;
status = STATUS_SUCCESS;
}
else {
VFDTRACE(VFDWARN,
("[VFD] IoDeleteSymbolicLink %ws - %s\n",
name_buf, GetStatusName(status)));
}
}
if (NT_SUCCESS(status) && DriveLetter) {
//
// Create a new drive letter
//
name_buf[sizeof(name_buf) - 1] = UNICODE_NULL;
_snwprintf(name_buf, sizeof(name_buf) - 1,
(OsMajorVersion >= 5) ?
L"\\??\\Global\\%wc:" : L"\\??\\%wc:",
DriveLetter);
RtlInitUnicodeString(&unicode_name, name_buf);
status = IoCreateSymbolicLink(
&unicode_name, &(DeviceExtension->DeviceName));
if (NT_SUCCESS(status)) {
VFDTRACE(VFDINFO, ("[VFD] Link %ws created\n", name_buf));
DeviceExtension->DriveLetter = DriveLetter;
}
else {
VFDTRACE(VFDWARN,
("[VFD] IoCreateSymbolicLink %ws - %s\n",
name_buf, GetStatusName(status)));
}
}
VFDTRACE(VFDINFO,
("[VFD] VfdSetLink - %s\n", GetStatusName(status)));
return status;
}
//
// load the persistent drive letter from the registry
//
NTSTATUS
VfdLoadLink(
IN PDEVICE_EXTENSION DeviceExtension,
IN PWSTR RegistryPath)
{
RTL_QUERY_REGISTRY_TABLE params[2];
WCHAR name_buf[20];
ULONG letter;
ULONG zero = 0;
NTSTATUS status;
VFDTRACE(VFDINFO, ("[VFD] VfdLoadLink - IN\n"));
RtlZeroMemory(params, sizeof(params));
name_buf[sizeof(name_buf) - 1] = UNICODE_NULL;
_snwprintf(name_buf, sizeof(name_buf) - 1,
VFD_REG_DRIVE_LETTER L"%lu",
DeviceExtension->DeviceNumber);
params[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
params[0].Name = name_buf;
params[0].EntryContext = &letter;
params[0].DefaultType = REG_DWORD;
params[0].DefaultData = &zero;
params[0].DefaultLength = sizeof(ULONG);
status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
RegistryPath, &params[0], NULL, NULL);
VFDTRACE(VFDINFO,
("[VFD] Drive letter '%wc' loaded from the registry\n",
letter ? letter : ' '));
DeviceExtension->DriveLetter = (CHAR)letter;
VFDTRACE(VFDINFO,
("[VFD] VfdLoadLink - %s\n", GetStatusName(status)));
return status;
}
//
// store the persistent drive letter into the registry
//
NTSTATUS
VfdStoreLink(
IN PDEVICE_EXTENSION DeviceExtension)
{
PVFD_DRIVER_EXTENSION driver_extension;
WCHAR name_buf[20];
ULONG letter;
NTSTATUS status;
VFDTRACE(VFDINFO, ("[VFD] VfdStoreLink - IN\n"));
#ifdef VFD_PNP
driver_extension = IoGetDriverObjectExtension(
DeviceExtension->device_object->DriverObject,
VFD_DRIVER_EXTENSION_ID);
#else // VFD_PNP
driver_extension = DeviceExtension->DriverExtension;
#endif // VFD_PNP
if (!driver_extension ||
!driver_extension->RegistryPath.Buffer) {
VFDTRACE(VFDWARN, ("[VFD] Registry Path not present.\n"));
VFDTRACE(VFDINFO, ("[VFD] VfdStoreLinks - OUT\n"));
return STATUS_DRIVER_INTERNAL_ERROR;
}
name_buf[sizeof(name_buf) - 1] = UNICODE_NULL;
_snwprintf(name_buf, sizeof(name_buf) - 1,
VFD_REG_DRIVE_LETTER L"%lu",
DeviceExtension->DeviceNumber);
letter = DeviceExtension->DriveLetter;
status = RtlWriteRegistryValue(
RTL_REGISTRY_ABSOLUTE,
driver_extension->RegistryPath.Buffer,
name_buf,
REG_DWORD,
&letter,
sizeof(ULONG));
if (!NT_SUCCESS(status)) {
VFDTRACE(VFDWARN,
("[VFD] RtlWriteRegistryValue - %s\n",
GetStatusName(status)));
}
else {
VFDTRACE(VFDINFO,
("[VFD] Drive letter '%wc' stored into the registry\n",
letter ? letter : L' '));
}
VFDTRACE(VFDINFO,
("[VFD] VfdStoreLink - %s\n", GetStatusName(status)));
return status;
}

View file

@ -0,0 +1,665 @@
/*
vfdmnt.c
Virtual Floppy Drive for Windows NT platform
Kernel mode driver mount manager functions
Copyright (C) 2003-2005 Ken Kato
*/
#ifndef VFD_MOUNT_MANAGER
/*
Not in working order for the time being
so DO NOT define VFD_MOUNT_MANAGER macro
unless you know exactly what you are doing...
*/
#ifdef _MSC_VER
// suppress empty compile unit warning
#pragma warning (disable: 4206)
#pragma message ("Mount Manager support feature is disabled.")
#endif
#else // VFD_MOUNT_MANAGER
/*
The flow of the drive letter assignment via the Mount Manager
during the VFD driver start up
1) IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION VFD -> MM
notifies the mount manager of VFD devices.
2) IOCTL_MOUNTDEV_QUERY_DEVICE_NAME VFD <- MM
device name (\Device\Floppy<x>) VFD -> MM
3) IOCTL_MOUNTDEV_QUERY_UNIQUE_ID VFD <- MM
device unique ID (\??\VirtualFD<x>) VFD -> MM
4) IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME VFD <- MM
drive letter link (\DosDevices\<x>:) VFD -> MM
5) The mount manager creates the drive letter link
6) IOCTL_MOUNTDEV_LINK_CREATED VFD <- MM
The driver stores the created drive letter
The flow of the drive letter operation with IOCTL_VFD_SET_LINK
1) IOCTL_MOUNTMGR_CREATE_POINT or
IOCTL_MOUNTMGR_DELETE_POINTS VFD -> MM
2) The mount manager creates/deletes the drive letter link
3) IOCTL_MOUNTDEV_LINK_CREATED or
IOCTL_MOUNTDEV_LINK_DELETED VFD <- MM
The driver stores the created/deleted drive letter
*/
#include "imports.h"
#include "vfddrv.h"
#include "vfddbg.h"
//
// Call the mount manager with an IO control IRP
//
static NTSTATUS
VfdMountMgrSendRequest(
ULONG ControlCode,
PVOID InputBuffer,
ULONG InputLength,
PVOID OutputBuffer,
ULONG OutputLength);
#ifdef ALLOC_PRAGMA
//#pragma alloc_text(PAGE, VfdRegisterMountManager)
#pragma alloc_text(PAGE, VfdMountMgrNotifyVolume)
#pragma alloc_text(PAGE, VfdMountMgrMountPoint)
#pragma alloc_text(PAGE, VfdMountMgrSendRequest)
#pragma alloc_text(PAGE, VfdMountDevUniqueId)
#pragma alloc_text(PAGE, VfdMountDevDeviceName)
#pragma alloc_text(PAGE, VfdMountDevSuggestedLink)
#pragma alloc_text(PAGE, VfdMountDevLinkModified)
#endif // ALLOC_PRAGMA
/*
#include <initguid.h>
#include <mountmgr.h>
//
// register a device to the mount manager interface
// does not work...
//
NTSTATUS
VfdRegisterMountManager(
PDEVICE_EXTENSION DeviceExtension)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING interface;
UNICODE_STRING interface2;
VFDTRACE(VFDINFO,
("[VFD] Registering %ws to the Mount Manager Interface\n",
DeviceExtension->DeviceName.Buffer));
RtlInitUnicodeString(&interface, NULL);
status = IoRegisterDeviceInterface(
DeviceExtension->DeviceObject,
(LPGUID)&MOUNTDEV_MOUNTED_DEVICE_GUID,
NULL,
&interface);
if (!NT_SUCCESS(status)) {
VFDTRACE(0,
("[VFD] IoRegisterDeviceInterface - %s\n",
GetStatusName(status)));
return status;
}
status = IoSetDeviceInterfaceState(&interface, TRUE);
if (NT_SUCCESS(status)) {
if (VfdCopyUnicode(&interface2, &interface)) {
VFDTRACE(VFDINFO,
("[VFD] Interface: %ws\n", interface2.Buffer));
}
else {
VFDTRACE(0,
("[VFD] Failed to allocate an interface name buffer\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else {
VFDTRACE(0,
("[VFD] IoSetDeviceInterfaceState - %s\n",
GetStatusName(status)));
}
RtlFreeUnicodeString(&interface);
VfdFreeUnicode(&interface2);
return status;
}
*/
//
// informs the Mount Manager of a new VFD device
//
NTSTATUS
VfdMountMgrNotifyVolume(
PDEVICE_EXTENSION DeviceExtension)
{
PMOUNTMGR_TARGET_NAME target_name;
USHORT target_name_buf[MAXIMUM_FILENAME_LENGTH];
NTSTATUS status;
VFDTRACE(VFDINFO,
("[VFD] VfdMountMgrNotifyVolume - %ws\n",
DeviceExtension->DeviceName.Buffer));
target_name = (PMOUNTMGR_TARGET_NAME)target_name_buf;
target_name->DeviceNameLength =
DeviceExtension->DeviceName.Length;
RtlCopyMemory(
target_name->DeviceName,
DeviceExtension->DeviceName.Buffer,
DeviceExtension->DeviceName.Length);
status = VfdMountMgrSendRequest(
IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
target_name,
sizeof(target_name->DeviceNameLength) + target_name->DeviceNameLength,
NULL,
0);
VFDTRACE(VFDINFO,
("[VFD] VfdMountMgrNotifyVolume - %s\n",
GetStatusName(status)));
return status;
}
//
// Create / remove a drive letter via the Mount Manager
//
NTSTATUS
VfdMountMgrMountPoint(
PDEVICE_EXTENSION DeviceExtension,
CHAR DriveLetter)
{
ULONG alloc_size;
UNICODE_STRING link_name;
WCHAR link_buf[20];
NTSTATUS status;
VFDTRACE(VFDINFO, ("[VFD] VfdMountMgrMountPoint - IN\n"));
// convert lower case into upper case
if (DriveLetter >= 'a' && DriveLetter <= 'z') {
DriveLetter -= ('a' - 'A');
}
if (DriveLetter >= 'A' && DriveLetter <= 'Z') {
// Create a new drive letter
PMOUNTMGR_CREATE_POINT_INPUT create;
swprintf(link_buf, L"\\DosDevices\\%wc:", DriveLetter);
RtlInitUnicodeString(&link_name, link_buf);
VFDTRACE(VFDINFO,
("[VFD] Creating a link: %ws => %ws\n",
link_buf, DeviceExtension->DeviceName.Buffer));
// allocate buffer for MOUNTMGR_CREATE_POINT_INPUT
alloc_size = sizeof(MOUNTMGR_CREATE_POINT_INPUT) +
link_name.Length + DeviceExtension->DeviceName.Length;
create = (PMOUNTMGR_CREATE_POINT_INPUT)ExAllocatePoolWithTag(
NonPagedPool, alloc_size, VFD_POOL_TAG);
if (!create) {
VFDTRACE(0, ("[VFD] Failed to allocate mount point input\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
// set the symbolic link name
create->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
create->SymbolicLinkNameLength = link_name.Length;
RtlCopyMemory(
(PCHAR)create + create->SymbolicLinkNameOffset,
link_name.Buffer,
link_name.Length);
// set the target device name
create->DeviceNameOffset = (USHORT)
(create->SymbolicLinkNameOffset + create->SymbolicLinkNameLength);
create->DeviceNameLength = DeviceExtension->DeviceName.Length;
RtlCopyMemory(
(PCHAR)create + create->DeviceNameOffset,
DeviceExtension->DeviceName.Buffer,
DeviceExtension->DeviceName.Length);
// call the mount manager with the IO control request
status = VfdMountMgrSendRequest(
IOCTL_MOUNTMGR_CREATE_POINT,
create, alloc_size, NULL, 0);
ExFreePool(create);
// no need to set the new drive letter into the
// DeviceExtension because the mount manager will issue an
// IOCTL_MOUNTDEV_LINK_CREATED and it will be processed then
}
else if (DriveLetter == 0) {
// Delete the existing drive letter
PMOUNTMGR_MOUNT_POINT mount;
PMOUNTMGR_MOUNT_POINTS points;
UNICODE_STRING unique_id;
WCHAR unique_buf[20];
swprintf(link_buf, L"\\DosDevices\\%wc:",
DeviceExtension->DriveLetter);
VFDTRACE(VFDINFO,
("[VFD] Deleting link: %ws\n", link_buf));
RtlInitUnicodeString(&link_name, link_buf);
swprintf(unique_buf, L"\\??\\" VFD_DEVICE_BASENAME L"%lu",
DeviceExtension->DeviceNumber);
RtlInitUnicodeString(&unique_id, unique_buf);
// allocate buffer for MOUNTMGR_MOUNT_POINT
alloc_size = sizeof(MOUNTMGR_MOUNT_POINT) +
link_name.Length +
unique_id.Length +
DeviceExtension->DeviceName.Length;
mount = (PMOUNTMGR_MOUNT_POINT)ExAllocatePoolWithTag(
NonPagedPool, alloc_size, VFD_POOL_TAG);
if (!mount) {
VFDTRACE(0, ("[VFD] Failed to allocate mount point input\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(mount, alloc_size + sizeof(WCHAR));
// set the symbolic link name
mount->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
mount->SymbolicLinkNameLength = link_name.Length;
RtlCopyMemory(
(PCHAR)mount + mount->SymbolicLinkNameOffset,
link_name.Buffer, link_name.Length);
// set the unique id
mount->UniqueIdOffset =
mount->SymbolicLinkNameOffset +
mount->SymbolicLinkNameLength;
mount->UniqueIdLength = unique_id.Length;
RtlCopyMemory(
(PCHAR)mount + mount->UniqueIdOffset,
unique_id.Buffer, unique_id.Length);
// set the target device name
mount->DeviceNameOffset =
mount->UniqueIdOffset +
mount->UniqueIdLength;
mount->DeviceNameLength =
DeviceExtension->DeviceName.Length;
RtlCopyMemory(
(PCHAR)mount + mount->DeviceNameOffset,
DeviceExtension->DeviceName.Buffer,
DeviceExtension->DeviceName.Length);
// prepare the output buffer
points = (PMOUNTMGR_MOUNT_POINTS)ExAllocatePoolWithTag(
NonPagedPool, alloc_size * 2, VFD_POOL_TAG);
status = VfdMountMgrSendRequest(
IOCTL_MOUNTMGR_DELETE_POINTS,
mount, alloc_size, points, alloc_size * 2);
ExFreePool(mount);
ExFreePool(points);
if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
// the drive letter did not exist in the first place
DeviceExtension->DriveLetter = 0;
}
// no need to clear the drive letter in the
// DeviceExtension because the mount manager will issue an
// IOCTL_MOUNTDEV_LINK_DELETED and it will be processed then
}
else {
return STATUS_INVALID_PARAMETER;
}
VFDTRACE(VFDINFO, ("[VFD] VfdMountMgrMountPoint - %s\n",
GetStatusName(status)));
return status;
}
//
// send a request to the Mount Manager
//
NTSTATUS
VfdMountMgrSendRequest(
ULONG ControlCode,
PVOID InputBuffer,
ULONG InputLength,
PVOID OutputBuffer,
ULONG OutputLength)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING mntmgr_name;
PDEVICE_OBJECT mntmgr_dev;
PFILE_OBJECT mntmgr_file;
IO_STATUS_BLOCK io_status;
KEVENT event;
PIRP irp;
// Obtain a pointer to the Mount Manager device object
RtlInitUnicodeString(
&mntmgr_name,
MOUNTMGR_DEVICE_NAME);
status = IoGetDeviceObjectPointer(
&mntmgr_name,
FILE_READ_ATTRIBUTES,
&mntmgr_file,
&mntmgr_dev);
if (!NT_SUCCESS(status)) {
VFDTRACE(VFDWARN,
("[VFD] IoGetDeviceObjectPointer - %s\n", GetStatusName(status)));
return status;
}
KeInitializeEvent(&event, NotificationEvent, FALSE);
// Create an IRP request block
irp = IoBuildDeviceIoControlRequest(
ControlCode,
mntmgr_dev,
InputBuffer,
InputLength,
OutputBuffer,
OutputLength,
FALSE,
&event,
&io_status);
if (!irp) {
VFDTRACE(VFDWARN,
("[VFD] IoBuildDeviceIoControlRequest\n"));
ObDereferenceObject(mntmgr_file);
return STATUS_DRIVER_INTERNAL_ERROR;
}
// Call the mount manager
status = IoCallDriver(mntmgr_dev, irp);
if (!NT_SUCCESS(status)) {
VFDTRACE(VFDWARN,
("[VFD] IoCallDriver - %s\n", GetStatusName(status)));
}
if (status == STATUS_PENDING) {
// Wait for the operation to complete
KeWaitForSingleObject(
&event, Executive, KernelMode, FALSE, NULL);
status = io_status.Status;
if (!NT_SUCCESS(status)) {
VFDTRACE(VFDWARN,
("[VFD] IoCallDriver - %s\n", GetStatusName(status)));
}
}
ObDereferenceObject(mntmgr_file);
return status;
}
//
// IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
// -- use the device interface link (\??\VirtualFD<x>) as the unique ID
//
NTSTATUS
VfdMountDevUniqueId(
PDEVICE_EXTENSION DeviceExtension,
PMOUNTDEV_UNIQUE_ID UniqueId,
ULONG OutputLength,
PIO_STATUS_BLOCK IoStatus)
{
WCHAR buf[20];
UNICODE_STRING unicode;
if (OutputLength < sizeof(MOUNTDEV_UNIQUE_ID)) {
return STATUS_INVALID_PARAMETER;
}
swprintf(buf,
L"\\??\\" VFD_DEVICE_BASENAME L"%lu",
DeviceExtension->DeviceNumber);
RtlInitUnicodeString(&unicode, buf);
UniqueId->UniqueIdLength = unicode.Length;
if (OutputLength <
sizeof(UniqueId->UniqueIdLength) + UniqueId->UniqueIdLength) {
IoStatus->Information = sizeof(MOUNTDEV_UNIQUE_ID);
return STATUS_BUFFER_OVERFLOW;
}
RtlCopyMemory(
UniqueId->UniqueId, buf, unicode.Length);
IoStatus->Information =
sizeof(UniqueId->UniqueIdLength) + UniqueId->UniqueIdLength;
return STATUS_SUCCESS;
}
//
// IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
// Returns the device name of the target device (\Device\Floppy<n>)
//
NTSTATUS
VfdMountDevDeviceName(
PDEVICE_EXTENSION DeviceExtension,
PMOUNTDEV_NAME DeviceName,
ULONG OutputLength,
PIO_STATUS_BLOCK IoStatus)
{
if (OutputLength < sizeof(MOUNTDEV_NAME)) {
return STATUS_INVALID_PARAMETER;
}
DeviceName->NameLength = DeviceExtension->DeviceName.Length;
if (OutputLength <
sizeof(DeviceName->NameLength) + DeviceName->NameLength) {
IoStatus->Information = sizeof(MOUNTDEV_NAME);
return STATUS_BUFFER_OVERFLOW;
}
RtlCopyMemory(
DeviceName->Name,
DeviceExtension->DeviceName.Buffer,
DeviceName->NameLength);
IoStatus->Information =
sizeof(DeviceName->NameLength) + DeviceName->NameLength;
return STATUS_SUCCESS;
}
//
// IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME
// Returns the drive letter link which we want the mount manager
// to create. This request is issued in response to the volume
// arrival notification, and the mount manager will create the
// symbolic link.
//
NTSTATUS
VfdMountDevSuggestedLink(
PDEVICE_EXTENSION DeviceExtension,
PMOUNTDEV_SUGGESTED_LINK_NAME LinkName,
ULONG OutputLength,
PIO_STATUS_BLOCK IoStatus)
{
WCHAR buf[20];
UNICODE_STRING unicode;
if (OutputLength < sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) {
return STATUS_INVALID_PARAMETER;
}
LinkName->UseOnlyIfThereAreNoOtherLinks = TRUE;
if (!DeviceExtension->DriveLetter) {
// No persistent drive letter stored in the registry
VFDTRACE(VFDINFO, ("[VFD] suggested link : none\n"));
LinkName->NameLength = 0;
IoStatus->Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
return STATUS_SUCCESS;
}
// A persistent drive letter exists
swprintf(buf, L"\\DosDevices\\%wc:",
DeviceExtension->DriveLetter);
VFDTRACE(VFDINFO, ("[VFD] suggested link : %ws\n", buf));
RtlInitUnicodeString(&unicode, buf);
LinkName->NameLength = unicode.Length;
if (OutputLength <
sizeof(MOUNTDEV_SUGGESTED_LINK_NAME) +
LinkName->NameLength - sizeof(WCHAR)) {
IoStatus->Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
return STATUS_BUFFER_OVERFLOW;
}
RtlCopyMemory(LinkName->Name, buf, unicode.Length);
IoStatus->Information =
sizeof(MOUNTDEV_SUGGESTED_LINK_NAME) +
LinkName->NameLength - sizeof(WCHAR);
return STATUS_SUCCESS;
}
//
// IOCTL_MOUNTDEV_LINK_CREATED / IOCTL_MOUNTDEV_LINK_DELETED
// Issued after the mount manager created/deleted a symbolic link
// If the link is a drive letter, store the new value into the
// registry as the new drive letter
//
NTSTATUS
VfdMountDevLinkModified(
PDEVICE_EXTENSION DeviceExtension,
PMOUNTDEV_NAME LinkName,
ULONG InputLength,
ULONG ControlCode)
{
if (InputLength < sizeof(MOUNTDEV_NAME)) {
return STATUS_INVALID_PARAMETER;
}
if (InputLength < sizeof(MOUNTDEV_NAME) +
LinkName->NameLength - sizeof(WCHAR)) {
return STATUS_INVALID_PARAMETER;
}
#if DBG
{ // Print the reported link name
PWSTR buf = ExAllocatePoolWithTag(
PagedPool, LinkName->NameLength + sizeof(WCHAR), VFD_POOL_TAG);
if (buf) {
RtlZeroMemory(buf, LinkName->NameLength + sizeof(WCHAR));
RtlCopyMemory(buf, LinkName->Name, LinkName->NameLength);
VFDTRACE(VFDINFO, ("[VFD] %ws\n", buf));
ExFreePool(buf);
}
}
#endif // DBG
if (LinkName->NameLength == 28 &&
LinkName->Name[0] == L'\\' &&
LinkName->Name[1] == L'D' &&
LinkName->Name[2] == L'o' &&
LinkName->Name[3] == L's' &&
LinkName->Name[4] == L'D' &&
LinkName->Name[5] == L'e' &&
LinkName->Name[6] == L'v' &&
LinkName->Name[7] == L'i' &&
LinkName->Name[8] == L'c' &&
LinkName->Name[9] == L'e' &&
LinkName->Name[10] == L's' &&
LinkName->Name[11] == L'\\' &&
LinkName->Name[12] >= L'A' &&
LinkName->Name[12] <= L'Z' &&
LinkName->Name[13] == L':') {
// The link is a drive letter
if (ControlCode == IOCTL_MOUNTDEV_LINK_CREATED) {
// link is created - store the new drive letter
DeviceExtension->DriveLetter = (CHAR)LinkName->Name[12];
}
else {
// link is deleted - clear the drive letter
DeviceExtension->DriveLetter = 0;
}
// Store the value into the registry
VfdStoreLink(DeviceExtension);
}
return STATUS_SUCCESS;
}
#endif // VFD_MOUNT_MANAGER

View file

@ -0,0 +1,474 @@
/*
vfdpnp.c
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: Plug & Play functions
Copyright (C) 2003-2005 Ken Kato
*/
#ifndef VFD_PNP
/*
Not in working order for the time being
so DO NOT define VFD_PNP macro
unless you know exactly what you are doing...
*/
// suppress empty compile unit warning
#ifdef _MSC_VER
#pragma warning (disable: 4206)
#pragma message ("Plug and play support feature is disabled.")
#endif
#else // VFD_PNP
#include "imports.h"
#include "vfddrv.h"
#include "vfddbg.h"
static NTSTATUS
VfdReportDevice(
PDEVICE_EXTENSION device_extension);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, VfdPlugAndPlay)
#pragma alloc_text(PAGE, VfdPowerControl)
#pragma alloc_text(PAGE, VfdSystemControl)
#pragma alloc_text(PAGE, VfdAddDevice)
#pragma alloc_text(PAGE, VfdReportDevice)
#endif // ALLOC_PRAGMA
#define REMLOCK_TAG 'LdfV' // "VfdL"
#define REMLOCK_MAXIMUM 1 // Max minutes system allows lock to be held
#define REMLOCK_HIGHWATER 10 // Max number of irps holding lock at one time
#if DBG
static PCSTR StateTable[] ={
{ "STOPPED" },
{ "WORKING" },
{ "PENDINGSTOP" },
{ "PENDINGREMOVE" },
{ "SURPRISEREMOVED" },
{ "REMOVED" },
{ "UNKNOWN" }
};
#endif // DBG
//
// PnP I/O request dispatch
//
NTSTATUS
VfdPlugAndPlay(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION io_stack;
PDEVICE_EXTENSION device_extension;
NTSTATUS status = STATUS_SUCCESS;
BOOLEAN lockHeld = TRUE;
//
// setup necessary pointers
//
io_stack = IoGetCurrentIrpStackLocation( Irp );
device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
ASSERT(device_extension->DeviceState < VFD_MAX_STATE);
VFDTRACE(VFDINFO, ("[VFD] VfdPlugAndPlay - IN. %ws %s Device State=%s\n",
device_extension->device_name.Buffer,
GetPnpIrpName(io_stack->MinorFunction),
StateTable[device_extension->DeviceState]));
//
// Acquire remove lock
//
status = IoAcquireRemoveLock(&device_extension->RemoveLock, Irp);
if (!NT_SUCCESS(status)) {
VFDTRACE(0, ("Acquire RemoveLock failed - %s\n", NtStatusToStr(status)));
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
//
// Process the PnP I/O request
//
switch (io_stack->MinorFunction) {
case IRP_MN_START_DEVICE: // 0x00
//
// Start the device
//
device_extension->DeviceState = VFD_WORKING;
status = STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
case IRP_MN_QUERY_REMOVE_DEVICE: // 0x01
//
// Prepare device removal
//
device_extension->DeviceState = VFD_PENDINGREMOVE;
status = STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
case IRP_MN_REMOVE_DEVICE: // 0x02
//
// Remove the device
//
status = STATUS_SUCCESS;
// complete the current request
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// Set the device status to REMOVED and wait for other drivers
// to release the lock, then delete the device object
//
device_extension->DeviceState = VFD_REMOVED;
IoReleaseRemoveLockAndWait(&device_extension->RemoveLock, Irp);
lockHeld = FALSE;
VfdRemoveDevice(DeviceObject);
break;
case IRP_MN_CANCEL_REMOVE_DEVICE: // 0x03
//
// Before sending the IRP down make sure we have received
// a IRP_MN_QUERY_REMOVE_DEVICE. We may get Cancel Remove
// without receiving a Query Remove earlier, if the
// driver on top fails a Query Remove and passes down the
// Cancel Remove.
//
if (device_extension->DeviceState == VFD_PENDINGREMOVE) {
device_extension->DeviceState = VFD_WORKING;
}
status = STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
case IRP_MN_STOP_DEVICE: // 0x04
device_extension->DeviceState = VFD_STOPPED;
status = STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
case IRP_MN_QUERY_STOP_DEVICE: // 0x05
device_extension->DeviceState = VFD_PENDINGSTOP;
status = STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
case IRP_MN_CANCEL_STOP_DEVICE: // 0x06
//
// Before sending the IRP down make sure we have received
// a IRP_MN_QUERY_STOP_DEVICE. We may get Cancel Stop
// without receiving a Query Stop earlier, if the
// driver on top fails a Query Stop and passes down the
// Cancel Stop.
//
if (device_extension->DeviceState == VFD_PENDINGSTOP ) {
device_extension->DeviceState = VFD_WORKING;
}
status = STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
case IRP_MN_QUERY_DEVICE_RELATIONS: // 0x07
status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
switch (io_stack->Parameters.QueryDeviceRelations.Type) {
case BusRelations:
VFDTRACE(VFDINFO, ("------- BusRelations Query\n"));
break;
case EjectionRelations:
VFDTRACE(VFDINFO, ("------- EjectionRelations Query\n"));
break;
case PowerRelations:
VFDTRACE(VFDINFO, ("------- PowerRelations Query\n"));
break;
case RemovalRelations:
VFDTRACE(VFDINFO, ("------- RemovalRelations Query\n"));
break;
case TargetDeviceRelation:
VFDTRACE(VFDINFO, ("------- TargetDeviceRelation Query\n"));
Irp->IoStatus.Information = (LONG)ExAllocatePoolWithTag(
PagedPool, sizeof(DEVICE_RELATIONS), VFD_POOL_TAG);
if (Irp->IoStatus.Information) {
PDEVICE_RELATIONS rel = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
rel->Count = 1;
rel->Objects[0] = device_extension->device_object;
status = STATUS_SUCCESS;
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
break;
default:
VFDTRACE(VFDINFO, ("------- Unknown Query\n"));
break;
}
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
// case IRP_MN_QUERY_INTERFACE: // 0x08
// case IRP_MN_QUERY_CAPABILITIES: // 0x09
// case IRP_MN_QUERY_RESOURCES: // 0x0A
// case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: // 0x0B
// case IRP_MN_QUERY_DEVICE_TEXT: // 0x0C
// case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: // 0x0D
// case IRP_MN_READ_CONFIG: // 0x0F
// case IRP_MN_WRITE_CONFIG: // 0x10
// case IRP_MN_EJECT: // 0x11
// case IRP_MN_SET_LOCK: // 0x12
// case IRP_MN_QUERY_ID: // 0x13
// case IRP_MN_QUERY_PNP_DEVICE_STATE: // 0x14
// case IRP_MN_QUERY_BUS_INFORMATION: // 0x15
// case IRP_MN_DEVICE_USAGE_NOTIFICATION: // 0x16
case IRP_MN_SURPRISE_REMOVAL: // 0x17
device_extension->DeviceState = VFD_SURPRISEREMOVED;
status = STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
// case IRP_MN_QUERY_LEGACY_BUS_INFORMATION: // 0x18
default:
//
// unknown request -- simply pass it to the lower device
//
status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
}
//
// Device Extenion is gone if the current IRP is IRP_MN_REMOVE_DEVICE
//
if (lockHeld == TRUE) {
IoReleaseRemoveLock(&device_extension->RemoveLock, Irp);
}
VFDTRACE(VFDINFO, ("[VFD] VfdPlugAndPlay - %s\n", NtStatusToStr(status)));
return status;
}
//
// Power management I/O request dispatch
//
NTSTATUS
VfdPowerControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION io_stack;
PDEVICE_EXTENSION device_extension;
NTSTATUS status;
io_stack = IoGetCurrentIrpStackLocation( Irp );
device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
VFDTRACE(VFDINFO, ("[VFD] VfdPowerControl - IN. %ws %s Device State=%s\n",
device_extension->device_name.Buffer,
GetPnpIrpName(io_stack->MinorFunction),
StateTable[device_extension->DeviceState]));
PoStartNextPowerIrp(Irp);
//
// If the device has been removed, the driver should not pass
// the IRP down to the next lower driver.
//
if (device_extension->DeviceState == VFD_REMOVED) {
status = STATUS_DELETE_PENDING;
}
else {
status = STATUS_SUCCESS;
}
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
VFDTRACE(VFDINFO, ("[VFD] VfdPowerControl - %s\n", NtStatusToStr(status)));
return status;
}
//
// WMI I/O request dispatch
//
NTSTATUS
VfdSystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION io_stack;
PDEVICE_EXTENSION device_extension;
NTSTATUS status;
io_stack = IoGetCurrentIrpStackLocation(Irp);
device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
VFDTRACE(VFDINFO, ("[VFD] VfdSystemControl - IN. %ws %s Device State=%s\n",
device_extension->device_name.Buffer,
GetPnpIrpName(io_stack->MinorFunction),
StateTable[device_extension->DeviceState]));
status = STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
VFDTRACE(VFDINFO, ("[VFD] VfdSystemControl - %s\n", NtStatusToStr(status)));
return status;
}
//
// PnP AddDevice function
//
NTSTATUS
VfdAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN OUT PDEVICE_OBJECT PhysicalDevice)
{
PDEVICE_OBJECT device_object;
PDEVICE_EXTENSION device_extension;
NTSTATUS status;
VFDTRACE(VFDINFO, ("[VFD] VfdAddDevice - IN\n"));
status = VfdCreateDevice(DriverObject, &device_object);
if (NT_SUCCESS(status)) {
device_object->Flags |= DO_POWER_PAGABLE;
device_extension =
(PDEVICE_EXTENSION)device_object->DeviceExtension;
// Device starts in Stopped state
device_extension->DeviceState = VFD_STOPPED;
VFDTRACE(VFDINFO, ("[VFD] Initializing the remove lock\n"));
IoInitializeRemoveLock(
&device_extension->RemoveLock,
REMLOCK_TAG,
REMLOCK_MAXIMUM,
REMLOCK_HIGHWATER);
if (PhysicalDevice) {
device_extension->PhysicalDevice = PhysicalDevice;
}
else {
VfdReportDevice(device_extension);
}
VfdRegisterInterface(device_extension);
VfdMountMgrNotifyVolume(device_extension);
}
return status;
}
//
// Report a VFD device to the PnP manager
//
NTSTATUS
VfdReportDevice(
PDEVICE_EXTENSION device_extension)
{
NTSTATUS status = STATUS_SUCCESS;
CM_RESOURCE_LIST list = {0};
PCM_FULL_RESOURCE_DESCRIPTOR full = &(list.List[0]);
PCM_PARTIAL_RESOURCE_LIST part = &(full->PartialResourceList);
PCM_PARTIAL_RESOURCE_DESCRIPTOR desc = &(part->PartialDescriptors[0]);;
list.Count = 1;
full->InterfaceType = Internal;
full->BusNumber = device_extension->device_number;
part->Version = 1;
part->Revision = 1;
part->Count = 1;
desc->Type = CmResourceTypeDeviceSpecific;
desc->ShareDisposition = CmResourceShareShared;
desc->Flags = 0;
VFDTRACE(VFDINFO,("[VFD] Reporting device %lu to the PnP manager\n",
device_extension->device_number));
status = IoReportDetectedDevice(
device_extension->device_object->DriverObject, // IN PDRIVER_OBJECT DriverObject,
Internal, // IN INTERFACE_TYPE LegacyBusType,
(ULONG)-1, // IN ULONG BusNumber,
(ULONG)-1, // IN ULONG SlotNumber,
&list, // IN PCM_RESOURCE_LIST ResourceList,
NULL, // IN PIO_RESOURCE_REQUIREMENTS_LIST OPTIONAL,
TRUE, // IN BOOLEAN ResourceAssigned,
&(device_extension->PhysicalDevice) // IN OUT PDEVICE_OBJECT *DeviceObject
);
if (!NT_SUCCESS(status)) {
VFDTRACE(0,
("[VFD] IoReportDetectedDevice - %s\n",
NtStatusToStr(status)));
}
device_extension->TargetDevice = IoAttachDeviceToDeviceStack(
device_extension->device_object,
device_extension->PhysicalDevice);
return status;
}
#endif // VFD_PNP

View file

@ -0,0 +1,357 @@
/*
vfdrdwr.c
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: Read and Write functions
Copyright (C) 2003-2005 Ken Kato
*/
#include "imports.h"
#include "vfddrv.h"
#include "vfddbg.h"
//
// IRP_MJ_READ and IRP_MJ_WRITE dispatcher
// Insert the IRP into the IRP queue list.
// Actual operation is performed by the device thread
//
#define IO_READ_OFF(p) (p)->Parameters.Read.ByteOffset.QuadPart
#define IO_READ_LEN(p) (p)->Parameters.Read.Length
NTSTATUS
NTAPI
VfdReadWrite (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION device_extension;
PIO_STACK_LOCATION io_stack;
NTSTATUS status;
device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
io_stack = IoGetCurrentIrpStackLocation(Irp);
#if DBG
if (DeviceObject && DeviceObject->DeviceExtension &&
((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer) {
VFDTRACE(VFDINFO, ("[VFD] %-40s %ws\n",
GetMajorFuncName(io_stack->MajorFunction),
((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer));
}
else {
VFDTRACE(VFDINFO, ("[VFD] %-40s %p\n",
GetMajorFuncName(io_stack->MajorFunction),
DeviceObject));
}
#endif // DBG
#ifdef VFD_PNP
if (device_extension->DeviceState != VFD_WORKING) {
// Device is not yet started or being removed, reject any IO request
// TODO: Queue the IRPs
VFDTRACE(VFDWARN, ("[VFD] Device not ready\n"));
status = STATUS_INVALID_DEVICE_STATE;
goto complete_request;
}
else {
status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
if (!NT_SUCCESS(status)) {
VFDTRACE(0, ("[VFD] Acquire RemoveLock failed: %s\n", GetStatusName(status)));
goto complete_request;
}
}
#endif // VFD_PNP
/*
// Check if volume verification is required
if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
!(io_stack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
status = STATUS_VERIFY_REQUIRED;
goto complete_request;
}
*/
// Check if an image is opened
if (!device_extension->FileHandle &&
!device_extension->FileBuffer) {
status = STATUS_NO_MEDIA_IN_DEVICE;
goto complete_request;
}
// Check if write operation is allowed
if (io_stack->MajorFunction == IRP_MJ_WRITE &&
(device_extension->MediaFlags & VFD_FLAG_WRITE_PROTECTED)) {
status = STATUS_MEDIA_WRITE_PROTECTED;
goto complete_request;
}
// Check for invalid parameters. It is an error for the starting offset
// + length to go past the end of the partition, or for the length or
// offset to not be a proper multiple of the sector size.
//
// Others are possible, but we don't check them since we trust the
// file system and they aren't deadly.
if ((IO_READ_OFF(io_stack) + IO_READ_LEN(io_stack)) >
VFD_SECTOR_TO_BYTE(device_extension->Sectors)) {
VFDTRACE(VFDWARN,
("[VFD] Offset:%I64u + Length:%u goes past the media size %lu\n",
IO_READ_OFF(io_stack), IO_READ_LEN(io_stack),
VFD_SECTOR_TO_BYTE(device_extension->Sectors)));
status = STATUS_INVALID_PARAMETER;
goto complete_request;
}
if (!VFD_SECTOR_ALIGNED((IO_READ_LEN(io_stack))) ||
!VFD_SECTOR_ALIGNED((IO_READ_OFF(io_stack)))) {
VFDTRACE(VFDWARN,
("[VFD] Invalid Alignment Offset:%I64u Length:%u\n",
IO_READ_OFF(io_stack), IO_READ_LEN(io_stack)));
status = STATUS_INVALID_PARAMETER;
goto complete_request;
}
// If read/write data length is 0, we are done
if (IO_READ_LEN(io_stack) == 0) {
status = STATUS_SUCCESS;
goto complete_request;
}
// It seems that actual read/write operation is going to take place
// so mark the IRP as pending, insert the IRP into queue list
// then signal the device thread to perform the operation
IoMarkIrpPending(Irp);
ExInterlockedInsertTailList(
&device_extension->ListHead,
&Irp->Tail.Overlay.ListEntry,
&device_extension->ListLock);
KeSetEvent(
&device_extension->RequestEvent,
(KPRIORITY) 0,
FALSE);
VFDTRACE(VFDINFO,("[VFD] %-40s - STATUS_PENDING\n",
GetMajorFuncName(io_stack->MajorFunction)));
return STATUS_PENDING;
complete_request:
// complete the request immediately
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
VFDTRACE(VFDWARN,("[VFD] %-40s - %s\n",
GetMajorFuncName(io_stack->MajorFunction),
GetStatusName(status)));
return status;
}
//
// Substitute for MmGetSystemAddressForMdlSafe
// for NT 4.0 DDK does not provide its equivqlent
// originally written by Bruce Engle for filedisk
//
static PVOID
MmGetSystemAddressForMdlPrettySafe(
IN PMDL Mdl,
IN MM_PAGE_PRIORITY Priority)
{
#if (VER_PRODUCTBUILD >= 2195)
if (OsMajorVersion >= 5) {
return MmGetSystemAddressForMdlSafe(Mdl, Priority);
}
else {
#endif // (VER_PRODUCTBUILD >= 2195)
CSHORT MdlMappingCanFail;
PVOID MappedSystemVa;
MdlMappingCanFail = (CSHORT)(Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL);
Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
MappedSystemVa = MmGetSystemAddressForMdl(Mdl);
if (!MdlMappingCanFail) {
Mdl->MdlFlags &= ~MDL_MAPPING_CAN_FAIL;
}
return MappedSystemVa;
#if (VER_PRODUCTBUILD >= 2195)
}
#endif // (VER_PRODUCTBUILD >= 2195)
}
//
// Read sectors from image file or RAM disk buffer into read buffer
//
VOID
VfdReadData(
IN PDEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp,
IN ULONG Length,
IN PLARGE_INTEGER Offset)
{
PVOID buf;
VFDTRACE(VFDINFO,("[VFD] VfdReadData - IN\n"));
buf = MmGetSystemAddressForMdlPrettySafe(
Irp->MdlAddress, NormalPagePriority);
if (!buf) {
VFDTRACE(0,
("[VFD] MmGetSystemAddressForMdlPrettySafe\n"));
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
return;
}
if (DeviceExtension->FileHandle) {
// Read from image file
Irp->IoStatus.Status = ZwReadFile(
DeviceExtension->FileHandle,
NULL,
NULL,
NULL,
&Irp->IoStatus,
buf,
Length,
Offset,
NULL);
if (NT_SUCCESS(Irp->IoStatus.Status)) {
Irp->IoStatus.Information = Length;
}
else {
VFDTRACE(0,
("[VFD] ZwReadFile - %s\n",
GetStatusName(Irp->IoStatus.Status)));
}
}
else if (DeviceExtension->FileBuffer) {
// Copy from RAM disk buffer
RtlMoveMemory(
buf,
DeviceExtension->FileBuffer + Offset->QuadPart,
Length);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = Length;
}
else {
// no image opened
Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
}
VFDTRACE(VFDINFO,("[VFD] VfdReadData - %s\n",
GetStatusName(Irp->IoStatus.Status)));
return;
}
//
// Write sectors from write buffer into image file or RAM image buffer
//
VOID
VfdWriteData(
IN PDEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp,
IN ULONG Length,
IN PLARGE_INTEGER Offset)
{
PVOID buf;
VFDTRACE(VFDINFO,("[VFD] VfdWriteData - IN\n"));
buf = MmGetSystemAddressForMdlPrettySafe(
Irp->MdlAddress, NormalPagePriority);
if (!buf) {
VFDTRACE(0,
("[VFD] MmGetSystemAddressForMdlPrettySafe\n"));
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
return;
}
if (DeviceExtension->FileHandle) {
// Write into image file
Irp->IoStatus.Status = ZwWriteFile(
DeviceExtension->FileHandle,
NULL,
NULL,
NULL,
&Irp->IoStatus,
buf,
Length,
Offset,
NULL);
if (NT_SUCCESS(Irp->IoStatus.Status)) {
Irp->IoStatus.Information = Length;
}
else {
VFDTRACE(0,
("[VFD] ZwWriteFile - %s\n",
GetStatusName(Irp->IoStatus.Status)));
}
}
else if (DeviceExtension->FileBuffer) {
// Deal with the modify flag
if (RtlCompareMemory(
DeviceExtension->FileBuffer + Offset->QuadPart,
buf, Length) != Length) {
DeviceExtension->MediaFlags |= VFD_FLAG_DATA_MODIFIED;
}
// Copy into RAM image buffer
RtlMoveMemory(
DeviceExtension->FileBuffer + Offset->QuadPart,
buf, Length);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = Length;
}
else {
// no image opened
Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
}
VFDTRACE(VFDINFO,("[VFD] VfdWriteData - %s\n",
GetStatusName(Irp->IoStatus.Status)));
return;
}

View file

@ -0,0 +1 @@
add_subdirectory(vfd)

View file

@ -0,0 +1,324 @@
/*
vfdapi.h
Virtual Floppy Drive for Windows
Driver control library API header
Copyright (C) 2003-2008 Ken Kato
*/
#ifndef _VFDAPI_H_
#define _VFDAPI_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
//
// custom SERVICE STATE value returned by VfdGetDriverState
//
#define VFD_NOT_INSTALLED 0xffffffff
//
// VFD operation code for VFD notification message
//
typedef enum _VFD_OPERATION {
VFD_OPERATION_NONE, // No operation
VFD_OPERATION_INSTALL, // The driver was installed
VFD_OPERATION_CONFIG, // The driver config was changed
VFD_OPERATION_REMOVE, // The driver was removed
VFD_OPERATION_START, // The driver was started
VFD_OPERATION_STOP, // The driver was stopped
VFD_OPERATION_OPEN, // An image was opened
VFD_OPERATION_SAVE, // An image was saved
VFD_OPERATION_CLOSE, // An image was closed
VFD_OPERATION_SETLINK, // A drive letter was created
VFD_OPERATION_DELLINK, // A drive letter was removed
VFD_OPERATION_PROTECT, // Write protect state was changed
VFD_OPERATION_SHELL, // Shell extension was installed/removed
VFD_OPERATION_MAX // Maximum value place holder
} VFD_OPERATION, *PVFD_OPERATION;
//==============================
// Driver management functions
//==============================
// Install the driver
DWORD WINAPI VfdInstallDriver(
PCSTR sFileName,
DWORD nStart);
// Uninstall the driver
DWORD WINAPI VfdRemoveDriver();
// Configure the driver
DWORD WINAPI VfdConfigDriver(
DWORD nStart);
// Start the driver
DWORD WINAPI VfdStartDriver(
PDWORD pState);
// Stop the driver
DWORD WINAPI VfdStopDriver(
PDWORD pState);
// Get current driver config information
DWORD WINAPI VfdGetDriverConfig(
PSTR sFileName,
PDWORD pStart);
// Get current driver state
DWORD WINAPI VfdGetDriverState(
PDWORD pState);
//==============================
// Device control functions
//==============================
// Open a VFD device
HANDLE WINAPI VfdOpenDevice(
ULONG nTarget);
// Get the device number
DWORD WINAPI VfdGetDeviceNumber(
HANDLE hDevice,
PULONG pNumber);
// Get the device name
DWORD WINAPI VfdGetDeviceName(
HANDLE hDevice,
PCHAR pName,
ULONG nLength);
// Get the driver version
DWORD WINAPI VfdGetDriverVersion(
HANDLE hDevice,
PULONG pVersion);
//==============================
// image functions
//==============================
// Open a virtual floppy image
DWORD WINAPI VfdOpenImage(
HANDLE hDevice,
PCSTR sFileName,
VFD_DISKTYPE nDiskType,
VFD_MEDIA nMediaType,
VFD_FLAGS nMediaFlags);
// Close the current virtual floppy image
DWORD WINAPI VfdCloseImage(
HANDLE hDevice,
BOOL bForce);
// Get the current image information
DWORD WINAPI VfdGetImageInfo(
HANDLE hDevice,
PSTR sFileName,
PVFD_DISKTYPE pDiskType,
PVFD_MEDIA pMediaType,
PVFD_FLAGS pMediaFlags,
PVFD_FILETYPE pFileType,
PULONG pImageSize);
// Save the current image into a file
DWORD WINAPI VfdSaveImage(
HANDLE hDevice,
PCSTR sFileName,
BOOL bOverWrite,
BOOL bTruncate);
// Format the current virtual media
DWORD WINAPI VfdFormatMedia(
HANDLE hDevice);
// Get the current media state (opened / write protected)
DWORD WINAPI VfdGetMediaState(
HANDLE hDevice);
// Set write protect state
DWORD WINAPI VfdWriteProtect(
HANDLE hDevice,
BOOL bProtect);
// Dismount the volume (should be called before Save, Format)
DWORD WINAPI VfdDismountVolume(
HANDLE hDevice,
BOOL bForce);
//==============================
// Drive letter functions
//==============================
// Assign or remove a persistent drive letter
DWORD WINAPI VfdSetGlobalLink(
HANDLE hDevice,
CHAR cLetter);
// Get the current persistent drive letter
DWORD WINAPI VfdGetGlobalLink(
HANDLE hDevice,
PCHAR pLetter);
// Assign or remove an ephemeral drive letter
DWORD WINAPI VfdSetLocalLink(
HANDLE hDevice,
CHAR cLetter);
// Get the first ephemeral drive letter
DWORD WINAPI VfdGetLocalLink(
HANDLE hDevice,
PCHAR pLetter);
// Choose the first available drive letter
CHAR WINAPI VfdChooseLetter();
//==============================
// utility functions
//==============================
// Check running platform
BOOL WINAPI VfdIsValidPlatform();
// Get VFD notification message value
UINT WINAPI VfdGetNotifyMessage();
// Check if specified file is a valid VFD driver
DWORD WINAPI VfdCheckDriverFile(
PCSTR sFileName,
PULONG pFileVersion);
// Check if specified path is a valid image file
DWORD WINAPI VfdCheckImageFile(
PCSTR sFileName,
PDWORD pAttributes,
PVFD_FILETYPE pFileType,
PULONG pImageSize);
// Create a formatted new image file
DWORD WINAPI VfdCreateImageFile(
PCSTR sFileName,
VFD_MEDIA nMediaType,
VFD_FILETYPE nFileType,
BOOL bOverWrite);
// Lookup the largest media to fit in a size
VFD_MEDIA WINAPI VfdLookupMedia(
ULONG nSize);
// Get media size (in bytes) of a media type
ULONG WINAPI VfdGetMediaSize(
VFD_MEDIA nMediaType);
// Get media type name
PCSTR WINAPI VfdMediaTypeName(
VFD_MEDIA nMediaType);
// Make a file description text
void WINAPI VfdMakeFileDesc(
PSTR pBuffer,
ULONG nBufSize,
VFD_FILETYPE nFileType,
ULONG nFileSize,
DWORD nFileAttr);
//==============================
// Shell Extension functions
//==============================
// install the shell extension
DWORD WINAPI VfdRegisterHandlers();
// uninstall the shell extension
DWORD WINAPI VfdUnregisterHandlers();
// check if the shell extension is installed
DWORD WINAPI VfdCheckHandlers();
//==============================
// GUI utility functions
//==============================
// open an existing image file
DWORD WINAPI VfdGuiOpen(
HWND hParent, // parent window
ULONG nDevice); // device number
// Save the current image
DWORD WINAPI VfdGuiSave(
HWND hParent, // parent window
ULONG nDevice); // device number
// close the current image
DWORD WINAPI VfdGuiClose(
HWND hParent, // parent window
ULONG nDevice); // device number
// format the current media
DWORD WINAPI VfdGuiFormat(
HWND hParent, // parent window
ULONG nDevice); // device number
// display a tooltip window
void WINAPI VfdToolTip(
HWND hParent, // parent window
PCSTR sText, // tooltip text
int pos_x, // position x
int pos_y, // position y
BOOL stick); // stick (remain until losing the focus) or
// non-stick (remain until the mouse leaves)
// Show image information tooltip
void WINAPI VfdImageTip(
HWND hParent,
ULONG nDevice);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _VFDAPI_H_

View file

@ -0,0 +1,393 @@
/*
vfdio.h
Virtual Floppy Drive for Windows
Kernel mode driver / user mode program interface header
Copyright (C) 2003-2005 Ken Kato
*/
#ifndef _VFDIO_H_
#define _VFDIO_H_
#ifndef __T
#ifdef _NTDDK_
#define __T(x) L ## x
#else
#define __T(x) x
#endif
#endif
#ifndef _T
#define _T(x) __T(x)
#endif
//
// Device/driver setting registry value names
//
#define VFD_REG_DEVICE_NUMBER _T("NumberOfDisks")
#define VFD_REG_TRACE_FLAGS _T("TraceFlags")
#define VFD_REG_DRIVE_LETTER _T("DriveLetter")
//
// Device object interface base name
//
#define VFD_DEVICE_BASENAME _T("VirtualFD")
//
// sector size constants and macros
//
#define VFD_BYTES_PER_SECTOR 512
#define VFD_SECTOR_ALIGN_MASK (VFD_BYTES_PER_SECTOR - 1)
#define VFD_BYTE_SHIFT_COUNT 9
#define VFD_BYTE_TO_SECTOR(b) ((b) >> VFD_BYTE_SHIFT_COUNT)
#define VFD_SECTOR_TO_BYTE(s) ((s) << VFD_BYTE_SHIFT_COUNT)
#define VFD_SECTOR_ALIGNED(b) (((b) & VFD_SECTOR_ALIGN_MASK) == 0)
//
// Fill character for formatting media
//
#define VFD_FORMAT_FILL_DATA (UCHAR)0xf6
//
// Image information structure
// Used for IOCTL_VFD_OPEN_IMAGE and IOCTL_VFD_QUERY_IMAGE
//
#pragma pack (push,2)
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4200) // Zero sized struct member warning
#endif
typedef struct _VFD_IMAGE_INFO {
VFD_DISKTYPE DiskType; // VFD_DISKTYPE_xxx value in vfdtypes.h
VFD_MEDIA MediaType; // VFD_MEDIA_xxx value in vfdtypes.h
VFD_FLAGS MediaFlags; // VFD_FLAG_xxx value in vfdtypes.h
VFD_FILETYPE FileType; // VFD_FILETYE_xxx value in vfdtypes.h
ULONG ImageSize; // actual image size in bytes
USHORT NameLength; // length in bytes of the file name
CHAR FileName[0]; // variable length file name string
} VFD_IMAGE_INFO, *PVFD_IMAGE_INFO;
#ifdef _MSC_VER
#pragma warning (pop)
#endif
#pragma pack (pop)
//
// Device IO control codes
//
/*
IOCTL_VFD_OPEN_IMAGE
Open an existing floppy image file or create an empty RAM disk
Input:
buffer containing a VFD_IMAGE_INFO structure followed by
an image file name
InputLength:
sizeof(VFD_IMAGE_INFO) plus length of the image file name
Output:
Not used with this operation; set to NULL.
Output Length:
Not used with this operation; set to zero.
Return:
STATUS_INVALID_PARAMETER input buffer size < sizeof(VFD_IMAGE_INFO)
or any other parameter errors
STATUS_DEVICE_BUSY an image is already opened
STATUS_ACCESS_DENIED file access error. returned also when the
file is compressed / encrypted
*/
#define IOCTL_VFD_OPEN_IMAGE CTL_CODE( \
IOCTL_DISK_BASE, \
0x800, \
METHOD_BUFFERED, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
/*
IOCTL_VFD_CLOSE_IMAGE
Close the current virtual floppy image
Input:
Not used with this operation; set to NULL.
Input Length:
Not used with this operation; set to zero.
Output:
Not used with this operation; set to NULL.
Output Length:
Not used with this operation; set to zero.
Return:
STATUS_NO_MEDIA_IN_DEVICE image is not opened
*/
#define IOCTL_VFD_CLOSE_IMAGE CTL_CODE( \
IOCTL_DISK_BASE, \
0x801, \
METHOD_NEITHER, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
/*
IOCTL_VFD_QUERY_IMAGE
Get the current image information
Input:
Not used with this operation; set to NULL.
Input Length:
Not used with this operation; set to zero.
Output:
Buffer to receive a VFD_IMAGE_INFO data structure
Output Length:
must be long enough to hold a VFD_IMAGE_INFO with the image file name
Return:
STATUS_BUFFER_TOO_SMALL buffer length < sizeof(VFD_IMAGE_INFO)
STATUS_BUFFER_OVERFLOW buffer cannot hold the image file name.
NameLength member contains the file name
length (number of bytes). See this value
to decide necessary buffer length.
*/
#define IOCTL_VFD_QUERY_IMAGE CTL_CODE( \
IOCTL_DISK_BASE, \
0x802, \
METHOD_BUFFERED, \
FILE_READ_ACCESS)
/*
IOCTL_VFD_SET_LINK
Create or delete a persistent drive letter
On Windows NT, this command simply creates a symbolic link.
On Windows 2000/XP, the driver calls the Mount Manager to manipulate
a drive letter.
Input:
buffer containing a drive letter 'A' - 'Z' to create a drive letter,
or 0 to delete the current drive letter.
Input Length:
sizeof(CHAR) or larger
Output:
Not used with this operation; set to NULL.
Output Length:
Not used with this operation; set to zero.
Return:
STATUS_INVALID_PARAMETER input length == 0 or
any other parameter errors
*/
#define IOCTL_VFD_SET_LINK CTL_CODE( \
IOCTL_DISK_BASE, \
0x803, \
METHOD_BUFFERED, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
/*
IOCTL_VFD_QUERY_LINK
Get the current persistent drive letter
Input:
Not used with this operation; set to NULL.
Input Length:
Not used with this operation; set to zero.
Output:
buffer to receive the current drive letter.
0 is returned if there is none.
Output Length:
sizeof(CHAR) or larger
Return:
STATUS_BUFFER_TOO_SMALL buffer length < sizeof(CHAR)
*/
#define IOCTL_VFD_QUERY_LINK CTL_CODE( \
IOCTL_DISK_BASE, \
0x804, \
METHOD_BUFFERED, \
FILE_READ_ACCESS)
/*
IOCTL_VFD_SET_PROTECT
Enable the virtual media write protection
Input:
Not used with this operation; set to NULL.
Input Length:
Not used with this operation; set to zero.
Output:
Not used with this operation; set to NULL.
Output Length:
Not used with this operation; set to zero.
Return:
STATUS_NO_MEDIA_IN_DEVICE image is not opened
*/
#define IOCTL_VFD_SET_PROTECT CTL_CODE( \
IOCTL_DISK_BASE, \
0x805, \
METHOD_NEITHER, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
/*
IOCTL_VFD_CLEAR_PROTECT
Disable the virtual media write protection
Input:
Not used with this operation; set to NULL.
Input Length:
Not used with this operation; set to zero.
Output:
Not used with this operation; set to NULL.
Output Length:
Not used with this operation; set to zero.
Return:
STATUS_NO_MEDIA_IN_DEVICE image is not opened
*/
#define IOCTL_VFD_CLEAR_PROTECT CTL_CODE( \
IOCTL_DISK_BASE, \
0x806, \
METHOD_NEITHER, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
/*
IOCTL_VFD_RESET_MODIFY
Reset the data modify flag
Input:
Not used with this operation; set to NULL.
Input Length:
Not used with this operation; set to zero.
Output:
Not used with this operation; set to NULL.
Output Length:
Not used with this operation; set to zero.
Return:
STATUS_NO_MEDIA_IN_DEVICE image is not opened
*/
#define IOCTL_VFD_RESET_MODIFY CTL_CODE( \
IOCTL_DISK_BASE, \
0x807, \
METHOD_NEITHER, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
/*
IOCTL_VFD_QUERY_NUMBER
Get the current device's VFD device number (<n> in "\??\VirtualFD<n>")
Input:
Not used with this operation; set to NULL.
Input Length:
Not used with this operation; set to zero.
Output:
buffer to receive the VFD device number
Output Length:
sizeof(ULONG) or larger
Return:
STATUS_BUFFER_TOO_SMALL buffer length < sizeof(ULONG)
*/
#define IOCTL_VFD_QUERY_NUMBER CTL_CODE( \
IOCTL_DISK_BASE, \
0x80d, \
METHOD_BUFFERED, \
FILE_READ_ACCESS)
/*
IOCTL_VFD_QUERY_NAME
Get the current device's name (\Device\Floppy<n>)
The name is returned in a counted UNICODE string (not NULL terminated)
Input:
Not used with this operation; set to NULL.
Input Length:
Not used with this operation; set to zero.
Output:
buffer to receive the length (USHORT value, number of bytes) followed
by the UNICODE device name.
Output Length:
enough to receive the length and the name
Return:
STATUS_BUFFER_TOO_SMALL buffer length < sizeof(USHORT)
STATUS_BUFFER_OVERFLOW buffer cannot hold the device name.
The first sizeof(USHORT) bytes of the
buffer contains the device name length.
See this value to decide the necessary
buffer length.
*/
#define IOCTL_VFD_QUERY_NAME CTL_CODE( \
IOCTL_DISK_BASE, \
0x80e, \
METHOD_BUFFERED, \
FILE_READ_ACCESS)
/*
IOCTL_VFD_QUERY_VERSION
Get the running VFD driver version
Input:
Not used with this operation; set to NULL.
Input Length:
Not used with this operation; set to zero.
Output:
buffer to receive the VFD version (ULONG value)
High word: major version
Low word: minor version
MSB: debug version flag (1:debug 0:release)
Output Length:
sizeof(ULONG) or larger
Return:
STATUS_BUFFER_TOO_SMALL buffer length < sizeof(ULONG)
*/
#define IOCTL_VFD_QUERY_VERSION CTL_CODE( \
IOCTL_DISK_BASE, \
0x80f, \
METHOD_BUFFERED, \
FILE_READ_ACCESS)
#endif // _VFDIO_H_

View file

@ -0,0 +1,77 @@
/*
vfdtypes.h
Virtual Floppy Drive for Windows
kernel mode / user mode common data types / constants
Copyright (C) 2003-2005 Ken Kato
*/
#ifndef _VFDTYPES_H_
#define _VFDTYPES_H_
//
// Supported disk type enumeration
//
enum _VFD_DISKTYPE
{
VFD_DISKTYPE_FILE = 0, // file disk (direct file access)
VFD_DISKTYPE_RAM // ram disk (on memory image)
};
//
// Supported media type enumeration
//
enum _VFD_MEDIA
{
VFD_MEDIA_NONE = 0, // no media / unknown
VFD_MEDIA_F5_160, // 5.25" 160KB
VFD_MEDIA_F5_180, // 5.25" 180KB
VFD_MEDIA_F5_320, // 5.25" 320KB
VFD_MEDIA_F5_360, // 5.25" 360KB
VFD_MEDIA_F3_640, // 3.5" 640KB
VFD_MEDIA_F5_640, // 5.25" 640KB
VFD_MEDIA_F3_720, // 3.5" 720KB
VFD_MEDIA_F5_720, // 5.25" 720KB
VFD_MEDIA_F3_820, // 3.5" 820KB
VFD_MEDIA_F3_1P2, // 3.5" 1.2MB
VFD_MEDIA_F5_1P2, // 5.25" 1.2MB
VFD_MEDIA_F3_1P4, // 3.5" 1.44MB
VFD_MEDIA_F3_1P6, // 3.5" 1.68MB DMF
VFD_MEDIA_F3_1P7, // 3.5" 1.72MB DMF
VFD_MEDIA_F3_2P8, // 3.5" 2.88MB
VFD_MEDIA_MAX // max value placeholder
};
//
// Supported file type enumeration
//
enum _VFD_FILETYPE
{
VFD_FILETYPE_NONE = 0, // no file
VFD_FILETYPE_RAW, // RAW image file
VFD_FILETYPE_ZIP, // ZIP compressed image
VFD_FILETYPE_MAX // max value place holder
};
//
// Type definition
//
typedef UCHAR VFD_DISKTYPE, *PVFD_DISKTYPE;
typedef UCHAR VFD_MEDIA, *PVFD_MEDIA;
typedef UCHAR VFD_FILETYPE, *PVFD_FILETYPE;
typedef UCHAR VFD_FLAGS, *PVFD_FLAGS;
//
// Image flag values
//
#define VFD_FLAG_WRITE_PROTECTED (VFD_FLAGS)0x01
#define VFD_FLAG_DATA_MODIFIED (VFD_FLAGS)0x02
//
// Default and max number of virtual floppy devices
//
#define VFD_DEFAULT_DEVICES 2
#define VFD_MAXIMUM_DEVICES 2
#endif // _VFDTYPES_H_

View file

@ -0,0 +1,72 @@
/*
vfdver.h
Virtual Floppy Drive for Windows
common version definition
Copyright (c) 2003-2008 Ken Kato
*/
#ifndef _VFDVER_H_
#define _VFDVER_H_
// product version information
#define VFD_PRODUCT_NAME "Virtual Floppy Drive for Windows"
#define VFD_PRODUCT_MAJOR 2
#define VFD_PRODUCT_MINOR 1
// driver file version information
#define VFD_DRIVER_FILENAME "vfd.sys"
#define VFD_DRIVER_MAJOR 2
#define VFD_DRIVER_MINOR 1
// build year and month/date
#define VFD_BUILD_YEAR 2008
#define VFD_BUILD_MDAY 0206
// copyright information
#define VFD_COMPANY_NAME "Ken Kato"
#define VFD_COPYRIGHT_YEARS "2003-2008"
// version information language and code page
// LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP
#define VFD_VERSIONINFO_LANG "040904B0"
#define VFD_VERSIONINFO_TRANS 0x0409, 0x04B0
#if ((DBG) || defined(_DEBUG))
#define VFD_DEBUG_FLAG 0x80000000
#define VFD_DEBUG_TAG " (debug)"
#else
#define VFD_DEBUG_FLAG 0
#define VFD_DEBUG_TAG
#endif
//
// Version manipulation macros
//
#define VFD_PRODUCT_VERSION_VAL \
((ULONG)((USHORT)VFD_PRODUCT_MAJOR<<16)|((USHORT)VFD_PRODUCT_MINOR))
#define VFD_DRIVER_VERSION_VAL \
((ULONG)((USHORT)VFD_DRIVER_MAJOR<<16)|((USHORT)VFD_DRIVER_MINOR))
#define VFD_FILE_VERSION_VAL \
((ULONG)((USHORT)VFD_FILE_MAJOR<<16)|((USHORT)VFD_FILE_MINOR))
#define VFD_VERSION_STR2(a,b) #a "." #b
#define VFD_VERSION_STR(a,b) VFD_VERSION_STR2(a,b)
#define VFD_PRODUCT_VERSION_STR VFD_VERSION_STR(VFD_PRODUCT_MAJOR,VFD_PRODUCT_MINOR)
#define VFD_DRIVER_VERSION_STR VFD_VERSION_STR(VFD_DRIVER_MAJOR,VFD_DRIVER_MINOR)
#define VFD_FILE_VERSION_STR VFD_VERSION_STR(VFD_FILE_MAJOR,VFD_FILE_MINOR)
#define VFD_BUILD_DATE_STR VFD_VERSION_STR(VFD_BUILD_YEAR,VFD_BUILD_MDAY)
//
// Product description
//
#define VFD_PRODUCT_DESC \
VFD_PRODUCT_NAME " " VFD_PRODUCT_VERSION_STR "." VFD_BUILD_DATE_STR VFD_DEBUG_TAG
#define VFD_COPYRIGHT_STR \
"Copyright (c) " VFD_COPYRIGHT_YEARS " " VFD_COMPANY_NAME
#endif // _VFDVER_H_

View file

@ -0,0 +1,79 @@
/*
vfdver.rc
Virtual Floppy Drive for Windows
common version resource script
Copyright (C) 2003-2005 Ken Kato
*/
// !!! NOTE !!!
// Editing this file with Microsoft Visual Studio will almost
// certainly mess things up...
#ifndef APSTUDIO_INVOKED
// Language neutral
LANGUAGE 0, 0
VS_VERSION_INFO VERSIONINFO
FILEVERSION VFD_FILE_MAJOR,VFD_FILE_MINOR,VFD_BUILD_YEAR,VFD_BUILD_MDAY
PRODUCTVERSION VFD_PRODUCT_MAJOR,VFD_PRODUCT_MINOR,VFD_BUILD_YEAR,VFD_BUILD_MDAY
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifndef VFD_SPECIAL_FLAG
#define VFD_SPECIAL_FLAG 0
#endif
#if ((DBG) || defined(_DEBUG))
FILEFLAGS VS_FF_DEBUG | VFD_SPECIAL_FLAG
#else
FILEFLAGS 0 | VFD_SPECIAL_FLAG
#endif
FILEOS VFD_FILEOS
FILETYPE VFD_FILETYPE
FILESUBTYPE VFD_FILESUBTYPE
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK VFD_VERSIONINFO_LANG
BEGIN
VALUE "CompanyName", VFD_COMPANY_NAME
VALUE "FileDescription", VFD_DESCRIPTION VFD_DEBUG_TAG
VALUE "FileVersion", VFD_FILE_VERSION_STR
VALUE "InternalName", VFD_INTERNALNAME
VALUE "LegalCopyright", VFD_COPYRIGHT_STR
VALUE "OriginalFilename", VFD_INTERNALNAME
VALUE "ProductName", VFD_PRODUCT_NAME
VALUE "ProductVersion", VFD_PRODUCT_VERSION_STR
#if VFD_SPECIAL_FLAG
Value "SpecialBuild", VFD_SPECIAL_DESC
#endif
END
#ifdef VFD_VERSIONINFO_ALT
BLOCK VFD_VERSIONINFO_ALT
BEGIN
VALUE "CompanyName", VFD_COMPANY_NAME
VALUE "FileDescription", VFD_DESCRIPTION_ALT VFD_DEBUG_TAG
VALUE "FileVersion", VFD_FILE_VERSION_STR
VALUE "InternalName", VFD_INTERNALNAME
VALUE "LegalCopyright", VFD_COPYRIGHT_STR
VALUE "OriginalFilename", VFD_INTERNALNAME
VALUE "ProductName", VFD_PRODUCT_NAME_ALT
VALUE "ProductVersion", VFD_PRODUCT_VERSION_STR
#if VFD_SPECIAL_FLAG
Value "SpecialBuild", VFD_SPECIAL_DESC_ALT
#endif
END
#endif // VFD_VERSIONINFO_ALT
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", VFD_VERSIONINFO_TRANS
END
END
#endif // APSTUDIO_INVOKED

View file

@ -1 +1,2 @@
add_subdirectory(vfdlib)
add_subdirectory(win32err)

View file

@ -0,0 +1,33 @@
set_cpp(WITH_RUNTIME WITH_EXCEPTIONS WITH_STL)
spec2def(vfd.dll vfdlib.spec ADD_IMPORTLIB)
add_message_headers(ANSI vfdmsg_lib.mc)
list(APPEND SOURCE
vfdctl.c
vfdfat.c
vfdguiopen.c
vfdguisave.c
vfdguitip.c
vfdguiut.c
vfdlib.c
vfdshcfact.cpp
vfdshext.cpp
vfdshmenu.cpp
vfdshprop.cpp
vfdshutil.cpp
vfdzip.c)
add_library(vfd SHARED
${SOURCE}
vfdlib.rc
${CMAKE_CURRENT_BINARY_DIR}/vfdlib.def)
include_directories(${REACTOS_SOURCE_DIR}/modules/rosapps/include/vfd
${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/zlib)
set_module_type(vfd win32dll ENTRYPOINT DllMain 12)
target_link_libraries(vfd zlib_solo uuid)
add_importlibs(vfd advapi32 user32 gdi32 shell32 comdlg32 comctl32 ole32 version psapi msvcrt kernel32 ntdll)
add_dependencies(vfd vfdmsg_lib)
add_cd_file(TARGET vfd DESTINATION reactos/system32 FOR all)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,205 @@
/*
vfdfat.c
Virtual Floppy Drive for Windows
Driver control library
Formats the image with FAT12
Copyright (C) 2003-2005 Ken Kato
*/
#ifdef __cplusplus
#pragma message(__FILE__": Compiled as C++ for testing purpose.")
#endif // __cplusplus
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "vfdtypes.h"
#include "vfdio.h"
#include "vfdlib.h"
#include "vfdver.h"
#pragma pack(1)
//
// BIOS parameter block
//
typedef struct _DOS_BPB
{
USHORT BytesPerSector;
UCHAR SectorsPerCluster;
USHORT ReservedSectors;
UCHAR NumberOfFATs;
USHORT RootEntries;
USHORT SmallSectors;
UCHAR MediaDescriptor;
USHORT SectorsPerFAT;
USHORT SectorsPerTrack;
USHORT NumberOfHeads;
ULONG HiddenSectors;
ULONG LargeSectors;
}
DOS_BPB, *PDOS_BPB;
//
// Extended BIOS parameter block for FAT12/16/HUGE
//
typedef struct _EXBPB
{
UCHAR PhysicalDriveNumber;
UCHAR Reserved;
UCHAR BootSignature;
ULONG VolumeSerialNumber;
CHAR VolumeLabel[11];
CHAR FileSystemType[8];
}
EXBPB, *PEXBPB;
//
// Partition Boot Record
//
typedef struct _DOS_PBR { // Partition Boot Record
UCHAR jump[3]; // Jump Instruction (E9 or EB, xx, 90)
CHAR oemid[8]; // OEM ID (OS type)
DOS_BPB bpb; // BIOS parameter block
EXBPB exbpb; // Extended BIOS parameter block
}
DOS_PBR, *PDOS_PBR;
#pragma pack()
#define FAT_DIR_ENTRY_SIZE 32
// We need to have the 0xeb and 0x90 in the jump code
// because the file system recognizer checks these values
#define VFD_JUMP_CODE "\xeb\x3c\x90"
#define VFD_OEM_NAME "VFD" VFD_DRIVER_VERSION_STR " "
#define VFD_VOLUME_LABEL "NO NAME "
#define VFD_FILESYSTEM "FAT12 "
//
// Select DOS BPB parameters from media size
//
static const DOS_BPB *SelectDosBpb(
USHORT nSectors)
{
static const DOS_BPB bpb_tbl[] = {
// b/s s/c r fat root sec desc s/f s/t h
{VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 320, 0xFE, 1, 8, 1, 0, 0}, // 160KB 5.25"
{VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 360, 0xFC, 1, 9, 1, 0, 0}, // 180KB 5.25"
{VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 640, 0xFF, 1, 8, 2, 0, 0}, // 320KB 5.25"
{VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 720, 0xFD, 2, 9, 2, 0, 0}, // 360KB 5.25"
{VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 1280, 0xFB, 2, 8, 2, 0, 0}, // 640KB 5.25" / 3.5"
{VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 1440, 0xF9, 3, 9, 2, 0, 0}, // 720KB 5.25" / 3.5"
{VFD_BYTES_PER_SECTOR, 2, 1, 2, 112, 1640, 0xF9, 3, 10, 2, 0, 0}, // 820KB 3.5"
{VFD_BYTES_PER_SECTOR, 1, 1, 2, 224, 2400, 0xF9, 7, 15, 2, 0, 0}, // 1.20MB 5.25" / 3.5"
{VFD_BYTES_PER_SECTOR, 1, 1, 2, 224, 2880, 0xF0, 9, 18, 2, 0, 0}, // 1.44MB 3.5"
{VFD_BYTES_PER_SECTOR, 1, 1, 2, 224, 3360, 0xF0, 10, 21, 2, 0, 0}, // 1.68MB 3.5"
{VFD_BYTES_PER_SECTOR, 1, 1, 2, 224, 3444, 0xF0, 10, 21, 2, 0, 0}, // 1.72MB 3.5"
{VFD_BYTES_PER_SECTOR, 2, 1, 2, 240, 5760, 0xF0, 9, 36, 2, 0, 0}, // 2.88MB 3.5"
};
int i;
for (i = 0; i < sizeof(bpb_tbl) / sizeof(bpb_tbl[0]); i++) {
if (nSectors == bpb_tbl[i].SmallSectors) {
return &bpb_tbl[i];
}
}
return NULL;
}
//
// Format the buffer with FAT12
//
DWORD FormatBufferFat(
PUCHAR pBuffer,
ULONG nSectors)
{
const DOS_BPB *bpb; // BIOS Parameter Block
PDOS_PBR pbr; // Partition Boot Record
PUCHAR fat; // File Allocation Table
USHORT idx;
VFDTRACE(0,
("[VFD] VfdFormatImage - IN\n"));
//
// Select DOS BPB parameters from media size
//
bpb = SelectDosBpb((USHORT)nSectors);
if (!bpb) {
VFDTRACE(0,
("[VFD] Unsupported media size %lu\n",
nSectors));
return ERROR_INVALID_PARAMETER;
}
//
// Initialize the whole area with the fill data
//
FillMemory(pBuffer,
VFD_SECTOR_TO_BYTE(nSectors),
VFD_FORMAT_FILL_DATA);
//
// Make up the FAT boot record
//
ZeroMemory(pBuffer, VFD_BYTES_PER_SECTOR);
pbr = (PDOS_PBR)pBuffer;
CopyMemory(pbr->jump, VFD_JUMP_CODE, sizeof(pbr->jump));
CopyMemory(pbr->oemid, VFD_OEM_NAME, sizeof(pbr->oemid));
CopyMemory(&pbr->bpb, bpb, sizeof(pbr->bpb));
// Make up the extended BPB
pbr->exbpb.BootSignature = 0x29;
// use the tick count as the volume serial number
pbr->exbpb.VolumeSerialNumber = GetTickCount();
CopyMemory(pbr->exbpb.VolumeLabel,
VFD_VOLUME_LABEL, sizeof(pbr->exbpb.VolumeLabel));
CopyMemory(pbr->exbpb.FileSystemType,
VFD_FILESYSTEM, sizeof(pbr->exbpb.FileSystemType));
// Set the boot record signature
*(pBuffer + VFD_BYTES_PER_SECTOR - 2) = 0x55;
*(pBuffer + VFD_BYTES_PER_SECTOR - 1) = 0xaa;
//
// Clear FAT areas
//
fat = pBuffer + VFD_SECTOR_TO_BYTE(bpb->ReservedSectors);
ZeroMemory(
fat,
VFD_SECTOR_TO_BYTE(bpb->SectorsPerFAT * bpb->NumberOfFATs));
//
// Make up FAT entries for the root directory
//
for (idx = 0; idx < bpb->NumberOfFATs; idx++) {
*fat = bpb->MediaDescriptor;
*(fat + 1) = 0xff;
*(fat + 2) = 0xff;
fat += VFD_SECTOR_TO_BYTE(bpb->SectorsPerFAT);
}
//
// Clear root directory entries
//
ZeroMemory(fat, bpb->RootEntries * FAT_DIR_ENTRY_SIZE);
VFDTRACE(0,
("[VFD] VfdFormatImage - OUT\n"));
return ERROR_SUCCESS;
}

View file

@ -0,0 +1,562 @@
/*
vfdguiopen.c
Virtual Floppy Drive for Windows
Driver control library
Open image GUI utility function
Copyright (c) 2003-2005 Ken Kato
*/
#ifdef __cplusplus
#pragma message(__FILE__": Compiled as C++ for testing purpose.")
#endif // __cplusplus
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifdef _MSC_VER
#pragma warning(push,3)
#endif
#include <commdlg.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "vfdtypes.h"
#include "vfdapi.h"
#include "vfdlib.h"
#ifndef __REACTOS__
#include "vfdmsg.h"
#else
#include "vfdmsg_lib.h"
#endif
#include "vfdguirc.h"
//
// String constants
//
#define FALLBACK_IMAGE_FILTER \
"Common image files (bin,dat,fdd,flp,ima,img,vfd)\0" \
"*.bin;*.dat;*.fdd;*.flp;*.ima;*.img;*.vfd\0" \
"Zip compressed image (imz,zip)\0*.imz;*.zip\0" \
"All files (*.*)\0*.*\0"
#define FALLBACK_IMAGE_TITLE "Open Virtual Floppy Image"
//
// local functions
//
static INT CALLBACK OpenDialogProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam);
static void OnInit(HWND hDlg, ULONG nDevice);
static void OnImage(HWND hDlg, HWND hEdit);
static void OnBrowse(HWND hDlg);
static void OnDiskType(HWND hDlg, HWND hRadio);
static void OnMediaType(HWND hDlg, HWND hCombo);
static void OnProtect(HWND hDlg, HWND hCheck);
static DWORD OnOK(HWND hDlg);
//
// Show Open Image dialog box
//
DWORD WINAPI VfdGuiOpen(
HWND hParent,
ULONG nDevice)
{
switch (DialogBoxParam(
g_hDllModule,
MAKEINTRESOURCE(IDD_OPENDIALOG),
hParent,
OpenDialogProc,
nDevice))
{
case IDOK:
return ERROR_SUCCESS;
case IDCANCEL:
return ERROR_CANCELLED;
default:
return GetLastError();
}
}
//
// Open image dialog procedure
//
INT CALLBACK OpenDialogProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg) {
case WM_INITDIALOG:
OnInit(hDlg, lParam);
return TRUE;
case WM_COMMAND:
switch (wParam) {
case MAKELONG(IDC_IMAGEFILE, EN_CHANGE):
OnImage(hDlg, (HWND)lParam);
return TRUE;
case IDC_BROWSE:
OnBrowse(hDlg);
return TRUE;
case IDC_DISKTYPE_FILE:
case IDC_DISKTYPE_RAM:
OnDiskType(hDlg, (HWND)lParam);
return TRUE;
case MAKELONG(IDC_MEDIATYPE, CBN_SELCHANGE):
OnMediaType(hDlg, (HWND)lParam);
return TRUE;
case IDC_OPEN_PROTECTED:
OnProtect(hDlg, (HWND)lParam);
return TRUE;
case IDOK:
if (OnOK(hDlg) == ERROR_SUCCESS) {
EndDialog(hDlg, IDOK);
}
return TRUE;
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
return TRUE;
}
break;
case WM_CONTEXTMENU:
ShowContextMenu(hDlg, (HWND)wParam, lParam);
break;
case WM_HELP:
{
LPHELPINFO info = (LPHELPINFO)lParam;
if (info->iContextType == HELPINFO_WINDOW) {
ShowHelpWindow(hDlg, info->iCtrlId);
}
}
return TRUE;
}
return FALSE;
}
//
// Initialize the Open Image dialog
//
void OnInit(
HWND hDlg,
ULONG nDevice)
{
VFD_MEDIA i;
// Store the device number
SetWindowLong(hDlg, GWL_USERDATA, nDevice);
// Store default file size
SetWindowLong(hDlg, DWL_USER, INVALID_FILE_SIZE);
// Set dialog window title
SetControlText(hDlg, 0, MSG_OPEN_TITLE);
// Set control captions
SetControlText(hDlg, IDC_IMAGEFILE_LABEL, MSG_IMAGEFILE_ACCEL);
SetControlText(hDlg, IDC_IMAGEDESC_LABEL, MSG_DESCRIPTION_LABEL);
SetControlText(hDlg, IDC_BROWSE, MSG_BROWSE_BUTTON);
SetControlText(hDlg, IDC_DISKTYPE_LABEL, MSG_DISKTYPE_LABEL);
SetControlText(hDlg, IDC_MEDIATYPE_LABEL, MSG_MEDIATYPE_ACCEL);
SetControlText(hDlg, IDC_OPEN_PROTECTED, MSG_MENU_PROTECT);
SetControlText(hDlg, IDOK, MSG_CREATE_BUTTON);
SetControlText(hDlg, IDCANCEL, MSG_CANCEL_BUTTON);
// select RAM disk as default
CheckRadioButton(hDlg, IDC_DISKTYPE_FILE,
IDC_DISKTYPE_RAM, IDC_DISKTYPE_RAM);
// setup media type combo list
for (i = 1; i < VFD_MEDIA_MAX; i++) {
SendDlgItemMessage(hDlg, IDC_MEDIATYPE,
CB_ADDSTRING, 0, (LPARAM)VfdMediaTypeName(i));
}
// select 1.44MB as the default
SendDlgItemMessage(hDlg, IDC_MEDIATYPE, CB_SELECTSTRING,
(WPARAM)-1, (LPARAM)VfdMediaTypeName(VFD_MEDIA_F3_1P4));
// set up other controls
OnImage(hDlg, GetDlgItem(hDlg, IDC_IMAGEFILE));
}
//
// Path is changed -- check if the file exists
//
void OnImage(
HWND hDlg,
HWND hEdit)
{
CHAR buf[MAX_PATH];
DWORD file_attr;
ULONG image_size;
VFD_FILETYPE file_type;
VFD_MEDIA media_type;
DWORD ret = ERROR_SUCCESS;
// Store default file size
SetWindowLong(hDlg, DWL_USER, INVALID_FILE_SIZE);
// get currently selected media type
media_type = (VFD_MEDIA)(SendDlgItemMessage(
hDlg, IDC_MEDIATYPE, CB_GETCURSEL, 0, 0) + 1);
// clear hint and description text
SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, NULL);
SetDlgItemText(hDlg, IDC_IMAGEFILE_HINT, NULL);
// get file name and file information
if (GetWindowText(hEdit, buf, sizeof(buf))) {
ret = VfdCheckImageFile(
buf, &file_attr, &file_type, &image_size);
if (ret == ERROR_SUCCESS) {
// use media type from image size
media_type = VfdLookupMedia(image_size);
}
else if (ret == ERROR_FILE_NOT_FOUND) {
// new file
// use the parent directory attributes
PSTR p;
if ((p = strrchr(buf, '\\')) != NULL) {
*p = '\0';
}
file_attr = GetFileAttributes(buf);
if (file_attr == INVALID_FILE_ATTRIBUTES) {
// directory access error
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, SystemMessage(ret));
return;
}
file_attr &= ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY);
image_size = INVALID_FILE_SIZE;
file_type = VFD_FILETYPE_RAW;
}
else {
// file access error
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, SystemMessage(ret));
return;
}
// make file description text
VfdMakeFileDesc(buf, sizeof(buf),
file_type, image_size, file_attr);
// set file description
SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, buf);
}
else {
// filename is empty - RAM disk
file_attr = 0;
image_size = INVALID_FILE_SIZE;
file_type = VFD_FILETYPE_NONE;
SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, "RAM");
}
// store the image size
SetWindowLong(hDlg, DWL_USER, image_size);
// setup disktype controls
if (file_type != VFD_FILETYPE_RAW ||
(file_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_ENCRYPTED))) {
// file cannot be opened directly -- RAM mode is forced
CheckRadioButton(hDlg, IDC_DISKTYPE_FILE,
IDC_DISKTYPE_RAM, IDC_DISKTYPE_RAM);
EnableWindow(GetDlgItem(hDlg, IDC_DISKTYPE_FILE), FALSE);
}
else {
EnableWindow(GetDlgItem(hDlg, IDC_DISKTYPE_FILE), TRUE);
}
// set OK button text
if (image_size == INVALID_FILE_SIZE) {
// file does not exist - OK button is "Create"
SetControlText(hDlg, IDOK, MSG_CREATE_BUTTON);
}
else {
// file exists - OK button is "Open"
SetControlText(hDlg, IDOK, MSG_OPEN_BUTTON);
}
// select media type
SendDlgItemMessage(hDlg, IDC_MEDIATYPE,
CB_SETCURSEL, media_type - 1, 0);
OnMediaType(hDlg, GetDlgItem(hDlg, IDC_MEDIATYPE));
}
//
// Show open file dialog box
//
void OnBrowse(
HWND hDlg)
{
OPENFILENAME ofn;
PSTR title;
PSTR filter;
CHAR file[MAX_PATH];
CHAR dir[MAX_PATH];
DWORD len;
// prepare title and filter text
title = ModuleMessage(MSG_OPEN_TITLE);
filter = ModuleMessage(MSG_OPEN_FILTER);
if (filter) {
PSTR p = filter;
do {
if (*p == '|') {
*p = '\0';
}
}
while (*(++p));
}
// get current file name from the control
ZeroMemory(file, sizeof(file));
ZeroMemory(dir, sizeof(dir));
len = GetDlgItemText(hDlg, IDC_IMAGEFILE, file, sizeof(file));
if (len && file[len - 1] == '\\') {
strcpy(dir, file);
ZeroMemory(file, sizeof(file));
}
// prepare OPENFILENAME structure
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = IS_WINDOWS_NT() ?
OPENFILENAME_SIZE_VERSION_400 : sizeof(ofn);
ofn.hwndOwner = hDlg;
ofn.lpstrFilter = filter ? filter : FALLBACK_IMAGE_FILTER;
ofn.lpstrFile = file;
ofn.nMaxFile = sizeof(file);
ofn.lpstrInitialDir = dir;
ofn.lpstrTitle = title ? title : FALLBACK_IMAGE_TITLE;
ofn.Flags = OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
// show the open file dialog box
if (GetOpenFileName(&ofn)) {
SetDlgItemText(hDlg, IDC_IMAGEFILE, file);
SetFocus(GetDlgItem(hDlg, IDC_IMAGEFILE));
}
// release text buffers
if (filter) {
LocalFree(filter);
}
if (title) {
LocalFree(title);
}
}
//
// Disk type is changed
//
void OnDiskType(
HWND hDlg,
HWND hRadio)
{
UNREFERENCED_PARAMETER(hDlg);
UNREFERENCED_PARAMETER(hRadio);
}
//
// Media type is changed
//
void OnMediaType(
HWND hDlg,
HWND hCombo)
{
VFD_MEDIA media_type;
ULONG media_size;
ULONG image_size;
image_size = GetWindowLong(hDlg, DWL_USER);
if (image_size == INVALID_FILE_SIZE) {
return;
}
media_type = (VFD_MEDIA)(SendMessage(
hCombo, CB_GETCURSEL, 0, 0) + 1);
if (media_type == 0) {
return;
}
media_size = VfdGetMediaSize(media_type);
if (media_size > image_size) {
// selected media is too large
SetControlText(hDlg, IDC_IMAGEFILE_HINT, MSG_FILE_TOO_SMALL);
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
return;
}
else if (media_size < image_size) {
SetControlText(hDlg, IDC_IMAGEFILE_HINT, MSG_SIZE_MISMATCH);
}
else {
SetDlgItemText(hDlg, IDC_IMAGEFILE_HINT, NULL);
}
EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
}
//
// Write Protect check box is clicked
//
void OnProtect(
HWND hDlg,
HWND hCheck)
{
UNREFERENCED_PARAMETER(hDlg);
UNREFERENCED_PARAMETER(hCheck);
}
//
// Create / open an image
//
DWORD OnOK(
HWND hDlg)
{
CHAR file_name[MAX_PATH];
VFD_DISKTYPE disk_type;
VFD_MEDIA media_type;
VFD_FLAGS image_flags;
HANDLE hDevice;
DWORD ret;
// get the disk type
if (IsDlgButtonChecked(hDlg, IDC_DISKTYPE_FILE) == BST_CHECKED) {
disk_type = VFD_DISKTYPE_FILE;
}
else {
disk_type = VFD_DISKTYPE_RAM;
}
// get the media type
media_type = (VFD_MEDIA)(SendDlgItemMessage(
hDlg, IDC_MEDIATYPE, CB_GETCURSEL, 0, 0) + 1);
// get the protect flag
if (IsDlgButtonChecked(hDlg, IDC_OPEN_PROTECTED) == BST_CHECKED) {
image_flags = VFD_FLAG_WRITE_PROTECTED;
}
else {
image_flags = 0;
}
// get the image name to create
if (GetDlgItemText(hDlg, IDC_IMAGEFILE, file_name, sizeof(file_name))) {
// file is specified
if (GetWindowLong(hDlg, DWL_USER) == INVALID_FILE_SIZE) {
// create a new image
ret = VfdCreateImageFile(
file_name, media_type, VFD_FILETYPE_RAW, FALSE);
if (ret != ERROR_SUCCESS) {
goto exit_func;
}
}
}
// open the image
hDevice = VfdOpenDevice(GetWindowLong(hDlg, GWL_USERDATA));
if (hDevice == INVALID_HANDLE_VALUE) {
ret = GetLastError();
goto exit_func;
}
ret = VfdOpenImage(
hDevice, file_name, disk_type, media_type, image_flags);
CloseHandle(hDevice);
exit_func:
if (ret != ERROR_SUCCESS) {
// show error message
MessageBox(hDlg, SystemMessage(ret),
VFD_MSGBOX_TITLE, MB_ICONSTOP);
}
return ret;
}

View file

@ -0,0 +1,47 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by vfdlib.rc
//
#define IDD_PROPDIALOG 101
#define IDD_OPENDIALOG 102
#define IDD_SAVEDIALOG 103
#define IDI_VFD_ICON 104
#define IDI_IMAGE_ICON 105
#define IDI_CONFIG_ICON 106
#define IDC_PROPERTY_TITLE 1001
#define IDC_COPYRIGHT_STR 1002
#define IDC_IMAGEFILE_LABEL 1003
#define IDC_IMAGEFILE 1004
#define IDC_IMAGEDESC_LABEL 1005
#define IDC_IMAGEFILE_DESC 1006
#define IDC_IMAGEFILE_HINT 1007
#define IDC_TARGETFILE_LABEL 1008
#define IDC_TARGETFILE 1009
#define IDC_DISKTYPE_LABEL 1010
#define IDC_DISKTYPE 1011
#define IDC_DISKTYPE_FILE 1012
#define IDC_DISKTYPE_RAM 1013
#define IDC_MEDIATYPE_LABEL 1014
#define IDC_MEDIATYPE 1015
#define IDC_WRITE_PROTECTED 1016
#define IDC_OPEN_PROTECTED 1017
#define IDC_BROWSE 1018
#define IDC_OPEN 1019
#define IDC_SAVE 1020
#define IDC_CLOSE 1021
#define IDC_FORMAT 1022
#define IDC_CONTROL 1023
#define IDC_OVERWRITE 1024
#define IDC_TRUNCATE 1025
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 107
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1025
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -0,0 +1,529 @@
/*
vfdguisave.c
Virtual Floppy Drive for Windows
Driver control library
Save image GUI utility function
Copyright (c) 2003-2005 Ken Kato
*/
#ifdef __cplusplus
#pragma message(__FILE__": Compiled as C++ for testing purpose.")
#endif // __cplusplus
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifdef _MSC_VER
#pragma warning(push,3)
#endif
#include <commdlg.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "vfdtypes.h"
#include "vfdapi.h"
#include "vfdlib.h"
#ifndef __REACTOS__
#include "vfdmsg.h"
#else
#include "vfdmsg_lib.h"
#endif
#include "vfdguirc.h"
//
// local functions
//
static INT CALLBACK SaveDialogProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam);
static void OnInit(HWND hDlg, PCSAVE_PARAM pParam);
static void OnTarget(HWND hDlg, HWND hEdit);
static void OnBrowse(HWND hDlg);
static void OnOverwrite(HWND hDlg, HWND hCheck);
static void OnTruncate(HWND hDlg, HWND hCheck);
static DWORD OnOK(HWND hDlg);
//
// Show Save Image dialog box
//
DWORD WINAPI VfdGuiSave(
HWND hParent,
ULONG nDevice)
{
SAVE_PARAM param;
CHAR path[MAX_PATH];
DWORD ret;
// open the source device
param.hDevice = VfdOpenDevice(nDevice);
if (param.hDevice == INVALID_HANDLE_VALUE) {
return GetLastError();
}
// get current image information
param.ImageName = path;
ret = VfdGetImageInfo(
param.hDevice,
param.ImageName,
&param.DiskType,
&param.MediaType,
&param.MediaFlags,
&param.FileType,
&param.ImageSize);
if (ret == ERROR_SUCCESS) {
// show dialog box
ret = GuiSaveParam(hParent, &param);
}
// close the source device
CloseHandle(param.hDevice);
return ret;
}
DWORD GuiSaveParam(
HWND hParent,
PCSAVE_PARAM pParam)
{
switch (DialogBoxParam(
g_hDllModule,
MAKEINTRESOURCE(IDD_SAVEDIALOG),
hParent,
SaveDialogProc,
(LPARAM)pParam))
{
case IDOK:
return ERROR_SUCCESS;
case IDCANCEL:
return ERROR_CANCELLED;
default:
return GetLastError();
}
}
//
// The dialog procedure
//
INT CALLBACK SaveDialogProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg) {
case WM_INITDIALOG:
OnInit(hDlg, (PCSAVE_PARAM)lParam);
return TRUE;
case WM_COMMAND:
switch (wParam) {
case MAKELONG(IDC_TARGETFILE, EN_CHANGE):
OnTarget(hDlg, (HWND)lParam);
return TRUE;
case IDC_BROWSE:
OnBrowse(hDlg);
return TRUE;
case IDC_OVERWRITE:
OnOverwrite(hDlg, (HWND)lParam);
return TRUE;
case IDC_TRUNCATE:
OnTruncate(hDlg, (HWND)lParam);
return TRUE;
case IDOK:
if (OnOK(hDlg) == ERROR_SUCCESS) {
EndDialog(hDlg, IDOK);
}
return TRUE;
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
return TRUE;
}
break;
case WM_CONTEXTMENU:
ShowContextMenu(hDlg, (HWND)wParam, lParam);
break;
case WM_HELP:
{
LPHELPINFO info = (LPHELPINFO)lParam;
if (info->iContextType == HELPINFO_WINDOW) {
ShowHelpWindow(hDlg, info->iCtrlId);
}
}
return TRUE;
}
return FALSE;
}
//
// Initialize the dialog
//
void OnInit(
HWND hDlg,
PCSAVE_PARAM pParam)
{
// Store parameters
SetWindowLong(hDlg, GWL_USERDATA, (ULONG)pParam);
// clear the target existence flag
SetWindowLong(hDlg, DWL_USER, 0);
// Set dialog window title
SetControlText(hDlg, 0, MSG_SAVE_TITLE);
// Set control captions
SetControlText(hDlg, IDC_IMAGEFILE_LABEL, MSG_IMAGEFILE_LABEL);
SetControlText(hDlg, IDC_DISKTYPE_LABEL, MSG_DISKTYPE_LABEL);
SetControlText(hDlg, IDC_MEDIATYPE_LABEL, MSG_MEDIATYPE_LABEL);
SetControlText(hDlg, IDC_TARGETFILE_LABEL, MSG_TARGETFILE_LABEL);
SetControlText(hDlg, IDC_IMAGEDESC_LABEL, MSG_DESCRIPTION_LABEL);
SetControlText(hDlg, IDC_BROWSE, MSG_BROWSE_BUTTON);
SetControlText(hDlg, IDC_OVERWRITE, MSG_OVERWRITE_CHECK);
SetControlText(hDlg, IDC_TRUNCATE, MSG_TRUNCATE_CHECK);
SetControlText(hDlg, IDOK, MSG_SAVE_BUTTON);
SetControlText(hDlg, IDCANCEL, MSG_CANCEL_BUTTON);
// set disk type
if (pParam->DiskType == VFD_DISKTYPE_FILE) {
SetDlgItemText(hDlg, IDC_DISKTYPE, "FILE");
}
else {
SetDlgItemText(hDlg, IDC_DISKTYPE, "RAM");
}
// display media type
SetDlgItemText(hDlg, IDC_MEDIATYPE,
VfdMediaTypeName(pParam->MediaType));
// set current image and initial target
if (pParam->ImageName[0]) {
SetDlgItemText(hDlg, IDC_IMAGEFILE, pParam->ImageName);
SetDlgItemText(hDlg, IDC_TARGETFILE, pParam->ImageName);
}
else if (pParam->DiskType != VFD_DISKTYPE_FILE) {
SetDlgItemText(hDlg, IDC_IMAGEFILE, "<RAM>");
OnTarget(hDlg, GetDlgItem(hDlg, IDC_TARGETFILE));
}
}
//
// Path is changed -- check specified target file
//
void OnTarget(
HWND hDlg,
HWND hEdit)
{
PCSAVE_PARAM param;
CHAR buf[MAX_PATH];
ULONG file_size;
VFD_FILETYPE file_type;
DWORD file_attr;
DWORD ret;
// clear the target existence flag
SetWindowLong(hDlg, DWL_USER, 0);
// clear the description and hint text
SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, NULL);
SetDlgItemText(hDlg, IDC_IMAGEFILE_HINT, NULL);
// get the target file name
if (GetWindowText(hEdit, buf, sizeof(buf)) == 0) {
// target file is blank
EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
return;
}
else {
CHAR full[MAX_PATH];
PSTR file;
// convert into a full path
if (GetFullPathName(buf, sizeof(full), full, &file)) {
strcpy(buf, full);
}
}
//
// get the current image info
//
param = (PCSAVE_PARAM)GetWindowLong(hDlg, GWL_USERDATA);
if (_stricmp(param->ImageName, buf) == 0) {
// target is the current file
char desc[MAX_PATH];
VfdMakeFileDesc(desc, sizeof(desc),
param->FileType, param->ImageSize,
GetFileAttributes(param->ImageName));
SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, desc);
SetControlText(hDlg, IDC_IMAGEFILE_HINT, MSG_CURRENT_FILE);
if (param->DiskType == VFD_DISKTYPE_FILE) {
// cannot overwrite the current FILE disk image
EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
return;
}
}
//
// check target image file
//
ret = VfdCheckImageFile(
buf, &file_attr, &file_type, &file_size);
if (ret == ERROR_FILE_NOT_FOUND) {
// file does not exist
SetControlText(hDlg, IDC_IMAGEFILE_DESC, MSG_DESC_NEW_FILE);
EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
return;
}
else if (ret != ERROR_SUCCESS) {
SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, SystemMessage(ret));
EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
return;
}
// set target file description
VfdMakeFileDesc(buf, sizeof(buf),
file_type, file_size, file_attr);
SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, buf);
// check target file type
if (file_type == VFD_FILETYPE_ZIP) {
SetControlText(hDlg, IDC_IMAGEFILE_HINT, MSG_TARGET_IS_ZIP);
EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
return;
}
// the target is an existing raw file
EnableWindow(GetDlgItem(hDlg, IDC_OVERWRITE), TRUE);
// set truncate box
if (file_size > VfdGetMediaSize(param->MediaType)) {
EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), TRUE);
SetControlText(hDlg, IDC_IMAGEFILE_HINT, MSG_SIZE_MISMATCH);
}
else {
EnableWindow(GetDlgItem(hDlg, IDC_TRUNCATE), FALSE);
}
// check overwrite setting
if (IsDlgButtonChecked(hDlg, IDC_OVERWRITE) != BST_CHECKED) {
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
}
else {
EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
}
// target file exists and overwritable
SetWindowLong(hDlg, DWL_USER, 1);
}
//
// Show save file dialog box
//
void OnBrowse(
HWND hDlg)
{
OPENFILENAME ofn;
PSTR title;
CHAR file[MAX_PATH];
CHAR dir[MAX_PATH];
DWORD len;
title = ModuleMessage(MSG_SAVE_TITLE);
ZeroMemory(&ofn, sizeof(ofn));
ZeroMemory(file, sizeof(file));
ZeroMemory(dir, sizeof(dir));
len = GetDlgItemText(hDlg, IDC_TARGETFILE, file, sizeof(file));
if (len && file[len - 1] == '\\') {
strcpy(dir, file);
ZeroMemory(file, sizeof(file));
}
// Different structure sizes must be used for NT and 2K/XP
ofn.lStructSize = IS_WINDOWS_NT() ?
OPENFILENAME_SIZE_VERSION_400 : sizeof(ofn);
ofn.hwndOwner = hDlg;
ofn.lpstrFile = file;
ofn.nMaxFile = sizeof(file);
ofn.lpstrInitialDir = dir;
ofn.lpstrTitle = title ? title : "Save Image";
ofn.lpstrFilter = "*.*\0*.*\0";
ofn.Flags = OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
if (GetSaveFileName(&ofn)) {
SetDlgItemText(hDlg, IDC_TARGETFILE, file);
SetFocus(GetDlgItem(hDlg, IDC_TARGETFILE));
}
if (title) {
LocalFree(title);
}
}
void OnOverwrite(
HWND hDlg,
HWND hCheck)
{
if (GetWindowLong(hDlg, DWL_USER)) {
// the target file exists and overwritable
if (SendMessage(hCheck, BM_GETCHECK, 0, 0) != BST_CHECKED) {
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
}
else {
EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
}
}
}
void OnTruncate(
HWND hDlg,
HWND hCheck)
{
UNREFERENCED_PARAMETER(hDlg);
UNREFERENCED_PARAMETER(hCheck);
}
//
// Save image
//
DWORD OnOK(
HWND hDlg)
{
PCSAVE_PARAM param;
CHAR path[MAX_PATH];
BOOL overwrite;
BOOL truncate;
DWORD ret;
param = (PCSAVE_PARAM)GetWindowLong(hDlg, GWL_USERDATA);
if (!param) {
return ERROR_INVALID_FUNCTION;
}
// get the target image name
if (GetDlgItemText(hDlg, IDC_TARGETFILE, path, sizeof(path)) == 0) {
return ERROR_INVALID_FUNCTION;
}
if (GetWindowLong(hDlg, DWL_USER)) {
// the target file exists and overwritable
overwrite = (IsDlgButtonChecked(hDlg, IDC_OVERWRITE) == BST_CHECKED);
truncate = (IsDlgButtonChecked(hDlg, IDC_TRUNCATE) == BST_CHECKED);
}
else {
overwrite = FALSE;
truncate = TRUE;
}
retry:
ret = VfdDismountVolume(param->hDevice, FALSE);
if (ret == ERROR_ACCESS_DENIED) {
PSTR msg = ModuleMessage(MSG_UNMOUNT_CONFIRM);
int reply = MessageBox(
hDlg, msg ? msg : "retry", VFD_MSGBOX_TITLE,
MB_ICONEXCLAMATION | MB_CANCELTRYCONTINUE);
if (msg) {
LocalFree(msg);
}
if (reply == IDRETRY) {
goto retry;
}
else if (reply == IDCANCEL) {
return ERROR_CANCELLED;
}
else {
VfdDismountVolume(param->hDevice, TRUE);
}
}
else if (ret != ERROR_SUCCESS) {
MessageBox(hDlg, SystemMessage(ret),
VFD_MSGBOX_TITLE, MB_ICONSTOP);
return ret;
}
ret = VfdSaveImage(param->hDevice, path, overwrite, truncate);
if (ret != ERROR_SUCCESS) {
// show error message
MessageBox(hDlg, SystemMessage(ret),
VFD_MSGBOX_TITLE, MB_ICONSTOP);
}
return ret;
}

View file

@ -0,0 +1,354 @@
/*
vfdguitip.c
Virtual Floppy Drive for Windows
Driver control library
tooltip information GUI utility functions
Copyright (c) 2003-2005 Ken Kato
*/
#ifdef __cplusplus
#pragma message(__FILE__": Compiled as C++ for testing purpose.")
#endif // __cplusplus
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "vfdtypes.h"
#include "vfdapi.h"
#include "vfdlib.h"
#ifndef __REACTOS__
#include "vfdmsg.h"
#else
#include "vfdmsg_lib.h"
#endif
//
// tooltip window class name
//
#define VFD_INFOTIP_WNDCLASS "VfdInfoTip"
//
// the window procedure
//
static LRESULT CALLBACK ToolTipProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg) {
case WM_CREATE:
// Store Font handle
SetWindowLong(hWnd, GWL_USERDATA,
(LONG)((LPCREATESTRUCT)lParam)->lpCreateParams);
return 0;
case WM_PAINT:
{
PAINTSTRUCT paint;
HDC hDC = BeginPaint(hWnd, &paint);
if (hDC) {
char text[MAX_PATH];
int len;
RECT rc;
SelectObject(hDC, (HFONT)GetWindowLong(hWnd, GWL_USERDATA));
SetTextColor(hDC, GetSysColor(COLOR_INFOTEXT));
SetBkMode(hDC, TRANSPARENT);
len = GetWindowText(hWnd, text, sizeof(text));
rc.top = 8;
rc.left = 8;
rc.right = paint.rcPaint.right;
rc.bottom = paint.rcPaint.bottom;
DrawText(hDC, text, len, &rc, DT_LEFT | DT_TOP);
EndPaint(hWnd, &paint);
}
}
return 0;
case WM_KILLFOCUS:
if (!(GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_TOPMOST)) {
// Stick tool tip - Closed on kill focus
DestroyWindow(hWnd);
}
return 0;
case WM_SETCURSOR:
if (GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) {
// Non-stick tool tip - Closed when cursor leaves
TRACKMOUSEEVENT track;
track.cbSize = sizeof(track);
track.dwFlags = TME_LEAVE;
track.hwndTrack = hWnd;
track.dwHoverTime = 0;
TrackMouseEvent(&track);
}
return 0;
case WM_MOUSELEAVE:
// Non-stick tool tip - Closed when cursor leaves
DestroyWindow(hWnd);
return 0;
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
// Both stick and non-stick tool tip
// Closed when clicked
SetCapture(hWnd);
return 0;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
// Both stick and non-stick tool tip
// Closed when clicked
if (GetCapture() == hWnd) {
DestroyWindow(hWnd);
}
return 0;
case WM_DESTROY:
// delete font
DeleteObject((HFONT)GetWindowLong(hWnd, GWL_USERDATA));
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
//
// Create and show tooltip window
//
void WINAPI VfdToolTip(
HWND hParent,
PCSTR sText,
int pos_x,
int pos_y,
BOOL stick)
{
#ifndef __REACTOS__
HWND hWnd;
#endif
WNDCLASS wc = {0};
LOGFONT lf;
HFONT font;
HDC dc;
int len;
SIZE sz;
RECT rc;
int scr_x;
int scr_y;
//
// Register Window Class
//
wc.lpfnWndProc = ToolTipProc;
wc.hInstance = g_hDllModule;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_INFOBK + 1);
wc.lpszClassName = VFD_INFOTIP_WNDCLASS;
RegisterClass(&wc);
//
// Create Tool Tip Font (== Icon title font)
//
SystemParametersInfo(
SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0);
font = CreateFontIndirect(&lf);
//
// Calculate Tool Tip Window size
//
dc = GetDC(hParent);
SelectObject(dc, font);
len = strlen(sText);
GetTextExtentPoint32(dc, sText, len, &sz);
rc.left = 0;
rc.top = 0;
rc.right = sz.cx;
rc.bottom = sz.cy;
DrawText(dc, sText, len, &rc, DT_CALCRECT | DT_LEFT | DT_TOP);
ReleaseDC(hParent, dc);
sz.cx = rc.right - rc.left + 16;
sz.cy = rc.bottom - rc.top + 16;
//
// Decide the window position
//
if (pos_x == -1 || pos_y == -1) {
//
// Use current cursor position
//
POINT pt;
GetCursorPos(&pt);
pos_x = pt.x - (sz.cx / 2);
pos_y = pt.y - (sz.cy / 2);
}
else {
pos_x = pos_x - (sz.cx / 2);
}
//
// make sure the tip window fits in visible area
//
scr_x = GetSystemMetrics(SM_CXSCREEN);
scr_y = GetSystemMetrics(SM_CYSCREEN);
if (pos_x < 0) {
pos_x = 0;
}
if (pos_x + sz.cx > scr_x) {
pos_x = scr_x - sz.cx;
}
if (pos_y < 0) {
pos_y = 0;
}
if (pos_y + sz.cy > scr_y) {
pos_y = scr_y - sz.cy;
}
//
// Create the tool tip window
//
#ifndef __REACTOS__
hWnd = CreateWindowEx(
#else
CreateWindowEx(
#endif
stick ? 0 : WS_EX_TOPMOST,
VFD_INFOTIP_WNDCLASS,
sText,
WS_BORDER | WS_POPUP | WS_VISIBLE,
pos_x, pos_y,
sz.cx, sz.cy,
hParent,
NULL,
NULL,
(PVOID)font);
//
// Give focus if it is not a stick tool-tip
//
if (!stick) {
SetFocus(hParent);
}
}
//
// Show an image information tooltip
//
void WINAPI VfdImageTip(
HWND hParent,
ULONG nDevice)
{
HANDLE hDevice;
PSTR info_str = NULL;
PSTR type_str = NULL;
PSTR prot_str = NULL;
PCSTR media_str = NULL;
CHAR path[MAX_PATH];
CHAR desc[MAX_PATH];
VFD_DISKTYPE disk_type;
VFD_MEDIA media_type;
VFD_FLAGS media_flags;
VFD_FILETYPE file_type;
ULONG image_size;
DWORD file_attr;
ULONG ret;
hDevice = VfdOpenDevice(nDevice);
if (hDevice == INVALID_HANDLE_VALUE) {
VfdToolTip(hParent,
SystemMessage(GetLastError()), -1, -1, FALSE);
return;
}
ret = VfdGetImageInfo(
hDevice,
path,
&disk_type,
&media_type,
&media_flags,
&file_type,
&image_size);
CloseHandle(hDevice);
if (ret != ERROR_SUCCESS) {
VfdToolTip(hParent, SystemMessage(ret), -1, -1, FALSE);
return;
}
if (path[0]) {
file_attr = GetFileAttributes(path);
}
else {
if (disk_type != VFD_DISKTYPE_FILE) {
strcpy(path, "<RAM>");
}
file_attr = 0;
}
VfdMakeFileDesc(desc, sizeof(desc),
file_type, image_size, file_attr);
if (disk_type == VFD_DISKTYPE_FILE) {
type_str = "FILE";
}
else {
type_str = "RAM";
}
media_str = VfdMediaTypeName(media_type);
if (media_flags & VFD_FLAG_WRITE_PROTECTED) {
prot_str = ModuleMessage(MSG_WRITE_PROTECTED);
}
else {
prot_str = ModuleMessage(MSG_WRITE_ALLOWED);
}
info_str = ModuleMessage(
MSG_IMAGE_INFOTIP,
path,
desc,
type_str ? type_str : "",
media_str ? media_str : "",
prot_str ? prot_str : "");
if (info_str) {
VfdToolTip(hParent, info_str, -1, -1, FALSE);
LocalFree(info_str);
}
if (prot_str) {
LocalFree(prot_str);
}
}

View file

@ -0,0 +1,581 @@
/*
vfdguiut.c
Virtual Floppy Drive for Windows
Driver control library
open / close / format GUI utility functions
Copyright (c) 2003-2005 Ken Kato
*/
#ifdef __cplusplus
#pragma message(__FILE__": Compiled as C++ for testing purpose.")
#endif // __cplusplus
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include "vfdtypes.h"
#include "vfdapi.h"
#include "vfdlib.h"
#ifndef __REACTOS__
#include "vfdmsg.h"
#else
#include "vfdmsg_lib.h"
#endif
#include "vfdguirc.h"
//
// message box constants added since Win2K
//
#ifndef MB_CANCELTRYCONTINUE
#define MB_CANCELTRYCONTINUE 0x00000006L
#endif
#ifndef IDTRYAGAIN
#define IDTRYAGAIN 10
#endif
#ifndef IDCONTINUE
#define IDCONTINUE 11
#endif
//
// local funcitons
//
static PSTR FormatSizeBytes(ULONG size, PSTR buf)
{
ULONG comma = 1;
int len;
while ((comma * 1000) < size) {
comma *= 1000;
}
len = sprintf(buf, "%lu", size / comma);
while (comma > 1) {
size %= comma;
comma /= 1000;
len += sprintf(buf + len, ",%03lu", size / comma);
}
return buf;
}
static PSTR FormatSizeUnits(ULONG size, PSTR buf)
{
static const char *name[3] = {
" KB", " MB", " GB"
};
int unit;
double dsize;
if (size < 1000) {
#ifndef __REACTOS__
sprintf(buf, "%u", size);
#else
sprintf(buf, "%lu", size);
#endif
return buf;
}
dsize = size;
dsize /= 1024;
unit = 0;
while (unit < 2 && dsize >= 1000) {
dsize /= 1000;
unit++;
}
if (dsize < 10) {
sprintf(buf, "%3.2f%s", dsize, name[unit]);
}
else if (dsize < 100) {
sprintf(buf, "%3.1f%s", dsize, name[unit]);
}
else if (dsize < 1000) {
sprintf(buf, "%3.0f%s", dsize, name[unit]);
}
else {
FormatSizeBytes((ULONG)dsize, buf);
strcat(buf, name[unit]);
}
return buf;
}
//
// Close the current image
//
DWORD WINAPI VfdGuiClose(
HWND hParent, // parent window
ULONG nDevice) // device number
{
HANDLE hDevice;
SAVE_PARAM param;
CHAR path[MAX_PATH];
HCURSOR hourglass;
DWORD ret;
int reply;
VFDTRACE(0, ("VfdGuiClose()\n"));
hDevice = VfdOpenDevice(nDevice);
if (hDevice == INVALID_HANDLE_VALUE) {
return GetLastError();
}
// get current image information
ret = VfdGetImageInfo(
hDevice,
path,
&param.DiskType,
&param.MediaType,
&param.MediaFlags,
&param.FileType,
&param.ImageSize);
if (ret != ERROR_SUCCESS) {
CloseHandle(hDevice);
return ret;
}
param.hDevice = hDevice;
param.ImageName = path;
// check if RAM image is modified
if (param.MediaFlags & VFD_FLAG_DATA_MODIFIED) {
PSTR msg = ModuleMessage(MSG_MEDIA_MODIFIED);
for (;;) {
reply = MessageBox(hParent, msg ? msg : "save?",
VFD_MSGBOX_TITLE, MB_ICONQUESTION | MB_YESNOCANCEL);
if (reply != IDYES) {
break;
}
if (GuiSaveParam(hParent, &param) == ERROR_SUCCESS) {
break;
}
}
if (msg) {
LocalFree(msg);
}
if (reply == IDCANCEL) {
CloseHandle(hDevice);
return ERROR_CANCELLED;
}
}
// close the image
hourglass = LoadCursor(NULL, IDC_WAIT);
for (;;) {
// show the hourglass cursor
HCURSOR original = SetCursor(hourglass);
// close the current image
ret = VfdCloseImage(hDevice, FALSE);
// restore the original cursor
SetCursor(original);
if (ret != ERROR_ACCESS_DENIED) {
// success or errors other than access denied
break;
}
if (IS_WINDOWS_NT()) {
// Windows NT -- cannot force close
// show retry / cancel message box
PSTR msg = ModuleMessage(MSG_UNMOUNT_FAILED);
reply = MessageBox(
hParent, msg ? msg : "retry", VFD_MSGBOX_TITLE,
MB_ICONEXCLAMATION | MB_RETRYCANCEL);
if (msg) {
LocalFree(msg);
}
}
else {
// Windows 2000 and later -- possible to force
// show cancel / retry / continue message box
PSTR msg = ModuleMessage(MSG_UNMOUNT_CONFIRM);
reply = MessageBox(
hParent, msg ? msg : "retry", VFD_MSGBOX_TITLE,
MB_ICONEXCLAMATION | MB_CANCELTRYCONTINUE);
if (msg) {
LocalFree(msg);
}
if (reply == IDCONTINUE) {
// try forced close
ret = VfdCloseImage(hDevice, TRUE);
}
}
if (reply == IDCANCEL) {
ret = ERROR_CANCELLED;
break;
}
else if (reply == IDCONTINUE) {
// try forced close
ret = VfdCloseImage(hDevice, TRUE);
break;
}
}
CloseHandle(hDevice);
return ret;
}
//
// Format the current media
//
DWORD WINAPI VfdGuiFormat(
HWND hParent, // parent window
ULONG nDevice) // device number
{
HANDLE hDevice;
ULONG ret;
PSTR msg;
msg = ModuleMessage(MSG_FORMAT_WARNING);
ret = MessageBox(hParent,
msg ? msg : "Format?",
VFD_MSGBOX_TITLE,
MB_ICONEXCLAMATION | MB_OKCANCEL);
if (msg) {
LocalFree(msg);
}
if (ret == IDCANCEL) {
MessageBox(hParent,
SystemMessage(ERROR_CANCELLED),
VFD_MSGBOX_TITLE, MB_ICONSTOP);
return ERROR_CANCELLED;
}
hDevice = VfdOpenDevice(nDevice);
if (hDevice == INVALID_HANDLE_VALUE) {
ret = GetLastError();
}
else {
HCURSOR original;
retry:
original = SetCursor(LoadCursor(NULL, IDC_WAIT));
ret = VfdDismountVolume(hDevice, FALSE);
if (ret == ERROR_ACCESS_DENIED) {
PSTR msg;
int reply;
SetCursor(original);
msg = ModuleMessage(MSG_UNMOUNT_CONFIRM);
reply = MessageBox(
hParent, msg ? msg : "retry", VFD_MSGBOX_TITLE,
MB_ICONEXCLAMATION | MB_CANCELTRYCONTINUE);
if (msg) {
LocalFree(msg);
}
if (reply == IDRETRY) {
goto retry;
}
else if (reply == IDCANCEL) {
ret = ERROR_CANCELLED;
}
else {
VfdDismountVolume(hDevice, TRUE);
ret = ERROR_SUCCESS;
}
}
if (ret == ERROR_SUCCESS) {
ret = VfdFormatMedia(hDevice);
}
SetCursor(original);
CloseHandle(hDevice);
}
MessageBox(hParent,
SystemMessage(ret),
VFD_MSGBOX_TITLE,
ret == ERROR_SUCCESS ? MB_ICONINFORMATION : MB_ICONSTOP);
return ret;
}
//
// Set a text to a dialog control
//
void SetControlText(
HWND hWnd,
UINT nCtrl,
DWORD nMsg)
{
PSTR p = NULL;
if (nMsg) {
p = ModuleMessage(nMsg);
}
if (nCtrl) {
SetDlgItemText(hWnd, nCtrl, p);
}
else {
SetWindowText(hWnd, p);
}
if (p) {
LocalFree(p);
}
}
//
// Make file description text
//
void WINAPI VfdMakeFileDesc(
PSTR pBuffer,
ULONG nBufSize,
VFD_FILETYPE nFileType,
ULONG nFileSize,
DWORD nFileAttr)
{
PSTR type_str;
PSTR size_str;
PSTR attr_ro;
PSTR attr_enc;
PSTR attr_cmp;
ZeroMemory(pBuffer, nBufSize);
switch (nFileType) {
case VFD_FILETYPE_RAW:
type_str = ModuleMessage(MSG_FILETYPE_RAW);
break;
case VFD_FILETYPE_ZIP:
type_str = ModuleMessage(MSG_FILETYPE_ZIP);
break;
default:
type_str = NULL;
}
if (nFileSize == INVALID_FILE_SIZE) {
size_str = ModuleMessage(MSG_DESC_NEW_FILE);
}
else {
CHAR buf[20], buf2[20];
size_str = ModuleMessage(MSG_DESC_FILESIZE,
FormatSizeBytes(nFileSize, buf),
FormatSizeUnits(nFileSize, buf2));
}
attr_ro = NULL;
attr_cmp = NULL;
attr_enc = NULL;
if (nFileAttr != INVALID_FILE_ATTRIBUTES) {
if (nFileAttr & FILE_ATTRIBUTE_READONLY) {
attr_ro = ModuleMessage(MSG_ATTR_READONLY);
}
if (nFileAttr & FILE_ATTRIBUTE_COMPRESSED) {
attr_cmp = ModuleMessage(MSG_ATTR_COMPRESSED);
}
if (nFileAttr & FILE_ATTRIBUTE_ENCRYPTED) {
attr_enc = ModuleMessage(MSG_ATTR_ENCRYPTED);
}
}
_snprintf(pBuffer, nBufSize - 1, "%s %s %s %s %s",
type_str ? type_str : "",
size_str ? size_str : "",
attr_ro ? attr_ro : "",
attr_cmp ? attr_cmp : "",
attr_enc ? attr_enc : "");
if (type_str) {
LocalFree(type_str);
}
if (size_str) {
LocalFree(size_str);
}
if (attr_ro) {
LocalFree(attr_ro);
}
if (attr_cmp) {
LocalFree(attr_cmp);
}
if (attr_enc) {
LocalFree(attr_enc);
}
}
void ShowContextMenu(
HWND hDlg,
HWND hCtl,
LPARAM lParam)
{
POINT pt;
UINT id;
HMENU hMenu;
pt.x = ((int)(short)LOWORD(lParam));
pt.y = ((int)(short)HIWORD(lParam));
if (pt.x == -1 || pt.y == -1) {
RECT rc;
GetWindowRect(hCtl, &rc);
pt.x = (rc.left + rc.right) / 2;
pt.y = (rc.top + rc.bottom) / 2;
id = GetDlgCtrlID(hCtl);
}
else {
POINT pt2 = pt;
ScreenToClient(hDlg, &pt2);
id = GetDlgCtrlID(
ChildWindowFromPoint(hDlg, pt2));
}
if (id < IDC_IMAGEFILE_LABEL ||
id > IDC_TRUNCATE) {
return;
}
hMenu = CreatePopupMenu();
AppendMenu(hMenu, MF_STRING, 1, "&What's This");
if (TrackPopupMenu(hMenu, TPM_RETURNCMD,
pt.x, pt.y, 0, hDlg, NULL))
{
ShowHelpWindow(hDlg, id);
}
DestroyMenu(hMenu);
}
//
// Show tool tip help
//
void ShowHelpWindow(
HWND hDlg,
UINT nCtl)
{
UINT msg;
RECT rc;
PSTR help;
switch (nCtl) {
case IDC_IMAGEFILE_LABEL:
case IDC_IMAGEFILE:
msg = MSG_HELP_IMAGEFILE;
break;
case IDC_IMAGEDESC_LABEL:
case IDC_IMAGEFILE_DESC:
msg = MSG_HELP_IMAGEDESC;
break;
case IDC_TARGETFILE_LABEL:
case IDC_TARGETFILE:
msg = MSG_HELP_TARGETFILE;
break;
case IDC_DISKTYPE_LABEL:
case IDC_DISKTYPE:
case IDC_DISKTYPE_FILE:
case IDC_DISKTYPE_RAM:
msg = MSG_HELP_DISKTYPE;
break;
case IDC_MEDIATYPE_LABEL:
case IDC_MEDIATYPE:
msg = MSG_HELP_MEDIATYPE;
break;
case IDC_WRITE_PROTECTED:
msg = MSG_HELP_PROTECT_NOW;
break;
case IDC_OPEN_PROTECTED:
msg = MSG_HELP_PROTECT_OPEN;
break;
case IDC_BROWSE:
msg = MSG_HELP_BROWSE;
break;
case IDC_OPEN:
msg = MSG_HELP_OPEN;
break;
case IDC_SAVE:
msg = MSG_HELP_SAVE;
break;
case IDC_CLOSE:
msg = MSG_HELP_CLOSE;
break;
case IDC_FORMAT:
msg = MSG_HELP_FORMAT;
break;
case IDC_CONTROL:
msg = MSG_HELP_CONTROL;
break;
case IDC_OVERWRITE:
msg = MSG_HELP_OVERWRITE;
break;
case IDC_TRUNCATE:
msg = MSG_HELP_TRUNCATE;
break;
default:
return;
}
GetWindowRect(GetDlgItem(hDlg, nCtl), &rc);
help = ModuleMessage(msg);
if (help) {
VfdToolTip(hDlg, help, rc.left, (rc.top + rc.bottom) / 2, TRUE);
LocalFree(help);
}
}

View file

@ -0,0 +1,184 @@
/*
vfdlib.c
Virtual Floppy Drive for Windows
Driver control library
Miscellaneous functions
Copyright (C) 2003-2008 Ken Kato
*/
#ifdef __cplusplus
#pragma message(__FILE__": Compiled as C++ for testing purpose.")
#endif // __cplusplus
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#ifdef _DEBUG
#include <psapi.h>
#endif // _DEBUG
#include "vfdtypes.h"
#include "vfdapi.h"
#include "vfdlib.h"
//
// DLL Global variables
//
#ifndef __REACTOS__
extern HINSTANCE g_hDllModule = NULL; // Handle to this DLL itself
extern UINT g_cDllRefCnt = 0; // Reference count of this DLL
extern UINT g_nNotifyMsg = 0; // VFD notification message
#else
HINSTANCE g_hDllModule = NULL; // Handle to this DLL itself
UINT g_cDllRefCnt = 0; // Reference count of this DLL
UINT g_nNotifyMsg = 0; // VFD notification message
#endif
//
// DllMain
//
BOOL WINAPI DllMain(
HINSTANCE hInstance,
DWORD dwReason,
LPVOID lpReserved)
{
#ifdef _DEBUG
char name[MAX_PATH];
HMODULE hMod;
DWORD size;
if (EnumProcessModules(GetCurrentProcess(), &hMod, sizeof(hMod), &size)) {
GetModuleBaseName(GetCurrentProcess(), hMod, name, sizeof(name));
}
else {
strcpy(name, "unknown");
}
#endif // _DEBUG
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH) {
VFDTRACE(0, ("DLL_PROCESS_ATTACH - %s\n", name));
// this DLL doesn't need DLL_THREAD_ATTACH and DLL_THREAD_DETACH
DisableThreadLibraryCalls(hInstance);
// store the DLL instance handle
g_hDllModule = hInstance;
// register the VFD notification message
g_nNotifyMsg = RegisterWindowMessage(VFD_NOTIFY_MESSAGE);
}
else if (dwReason == DLL_PROCESS_DETACH) {
VFDTRACE(0, ("DLL_PROCESS_DETACH - %s\n", name));
}
return TRUE;
}
//
// Check running platform
//
BOOL WINAPI VfdIsValidPlatform()
{
BOOL (WINAPI *pfnIsWow64Process)(HANDLE, PBOOL);
BOOL wow64;
if (GetVersion() & 0x80000000) {
return FALSE; // doesn't work on Win9x
}
pfnIsWow64Process = (BOOL (WINAPI *)(HANDLE, PBOOL))
GetProcAddress(GetModuleHandle("kernel32.dll"), "IsWow64Process");
if (pfnIsWow64Process == NULL) {
return TRUE; // NT4 or 2000 -- assured to be 32 bit
}
wow64 = FALSE;
if (!pfnIsWow64Process(GetCurrentProcess(), &wow64)) {
return FALSE;
}
return !wow64;
}
//
// Get VFD notification message value
//
UINT WINAPI VfdGetNotifyMessage()
{
return g_nNotifyMsg;
}
//
// Get message text from this DLL module
//
PSTR ModuleMessage(
DWORD nFormat, ...)
{
PSTR p;
va_list args;
va_start(args, nFormat);
if (!FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
g_hDllModule, nFormat, 0, (LPTSTR)&p, 0, &args)) {
p = NULL;
}
va_end(args);
return p;
}
//
// Get system error message string
//
PCSTR SystemMessage(
DWORD nError)
{
static CHAR msg[256];
if (!FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, nError, 0, msg, sizeof(msg), NULL)) {
_snprintf(msg, sizeof(msg),
"Unknown system error %lu (0x%08x)\n", nError, nError);
}
return msg;
}
#ifdef _DEBUG
//
// Format and output debug string
//
void DebugTrace(
PCSTR sFormat, ...)
{
CHAR buf[512];
int len;
va_list args;
len = _snprintf(buf, sizeof(buf),
"%s(%lu) : ", TraceFile, TraceLine);
va_start(args, sFormat);
_vsnprintf(buf + len, sizeof(buf) - len, sFormat, args);
OutputDebugString(buf);
}
#endif // _DEBUG

View file

@ -0,0 +1,185 @@
/*
vfdlib.h
Virtual Floppy Drive for Windows
Driver control library local header
Copyright (C) 2003-2005 Ken Kato
*/
#ifndef _VFDLIB_H_
#define _VFDLIB_H_
#define VFD_LIBRARY_FILENAME "vfd.dll"
#ifdef VFD_EMBED_DRIVER
#define VFD_DRIVER_NAME_ID VFD_DRIVER
#define VFD_DRIVER_TYPE_ID BINARY
#endif
#ifndef RC_INVOKED
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
//
// DLL instance handle
//
extern HINSTANCE g_hDllModule;
//
// Reference count for the DLL
//
extern UINT g_cDllRefCnt;
//
// VFD notification message value
//
extern UINT g_nNotifyMsg;
//
// VFD notification message register string
//
#define VFD_NOTIFY_MESSAGE "VfdNotifyMessage"
//
// Message box title string
//
#define VFD_MSGBOX_TITLE "Virtual Floppy Drive"
//
// shell extention string constants
//
#define VFDEXT_DESCRIPTION "VFD shell extension"
#define VFDEXT_MENU_REGKEY "Drive\\shellex\\ContextMenuHandlers\\VFD"
#define VFDEXT_DND_REGKEY "Drive\\shellex\\DragDropHandlers\\VFD"
#define VFDEXT_PROP_REGKEY "Drive\\shellex\\PropertySheetHandlers\\VFD"
#define VFDEXT_INFO_REGKEY "Drive\\shellex\\{00021500-0000-0000-C000-000000000046}"
//=====================================
// Image handling functions
//=====================================
// Format a buffer with FAT12
DWORD FormatBufferFat(
PUCHAR pBuffer,
ULONG nSectors);
// Extract image information from a zip compressed file
DWORD ExtractZipInfo(
HANDLE hFile,
ULONG *pSize);
// Extract original image from a zip compressed file
DWORD ExtractZipImage(
HANDLE hFile,
PUCHAR *pBuffer,
PULONG pLength);
//=====================================
// GUI utility functions
//=====================================
typedef struct _SAVE_PARAM {
HANDLE hDevice;
VFD_DISKTYPE DiskType;
VFD_MEDIA MediaType;
VFD_FLAGS MediaFlags;
VFD_FILETYPE FileType;
ULONG ImageSize;
PSTR ImageName;
} SAVE_PARAM, PSAVE_PARAM;
typedef const SAVE_PARAM CSAVE_PARAM, *PCSAVE_PARAM;
DWORD GuiSaveParam(
HWND hParent,
PCSAVE_PARAM pParam);
void ShowContextMenu(
HWND hDlg,
HWND hCtl,
LPARAM lParam);
void ShowHelpWindow(
HWND hDlg,
UINT nCtl);
//
// Set a message to a control window
//
void SetControlText(
HWND hWnd,
UINT nCtrl,
DWORD nMsg);
//==============================
// Message extract functions
//==============================
// Return a system error message
PCSTR SystemMessage(
DWORD nError);
// Return a message from this DLL module
PSTR ModuleMessage(
DWORD nFormat, ...);
//==============================
// utility macros
//==============================
#define IS_WINDOWS_NT() ((GetVersion() & 0xff) < 5)
//==============================
// Debug functions
//==============================
#ifdef _DEBUG
extern ULONG TraceFlags;
#ifndef __REACTOS__
extern PCHAR TraceFile;
#else
extern CHAR const * TraceFile;
#endif
extern ULONG TraceLine;
#define VFDTRACE(LEVEL,STRING) \
if ((TraceFlags & (LEVEL)) == (LEVEL)) { \
TraceFile = __FILE__; \
TraceLine = __LINE__; \
DebugTrace STRING; \
}
void DebugTrace(PCSTR sFormat, ...);
#else // _DEBUG
#define VFDTRACE(LEVEL,STRING)
#endif // _DEBUG
//
// supplement old system headers
//
#ifndef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif // INVALID_FILE_ATTRIBUTES
#if defined(_INC_COMMDLG) && !defined(OPENFILENAME_SIZE_VERSION_400)
// Pre Win2K system header is used
// OPENFILENAME is defined without extra fields.
#define OPENFILENAME_SIZE_VERSION_400 sizeof(OPENFILENAME)
#endif // __INC_COMMDLG && !OPENFILENAME_SIZE_VERSION_400
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // RC_INVOKED
#endif // _VFDLIB_H_

View file

@ -0,0 +1,219 @@
//Microsoft Developer Studio generated resource script.
//
#include "vfdguirc.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Æ­°Ä×Ù resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
#ifdef _WIN32
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
#pragma code_page(932)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"vfdguirc.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_OPENDIALOG DIALOGEX 0, 0, 250, 150
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_CONTEXTHELP
CAPTION "Open Virtual Floppy Image"
FONT 9, "MS Shell Dlg"
BEGIN
LTEXT "&Image File:",IDC_IMAGEFILE_LABEL,7,7,52,12,
SS_CENTERIMAGE
EDITTEXT IDC_IMAGEFILE,60,7,130,12,ES_AUTOHSCROLL
PUSHBUTTON "&Browse...",IDC_BROWSE,193,7,50,14
LTEXT "Description:",IDC_IMAGEDESC_LABEL,7,27,52,8
EDITTEXT IDC_IMAGEFILE_DESC,60,27,183,12,ES_AUTOHSCROLL |
ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
LTEXT "additional information",IDC_IMAGEFILE_HINT,60,43,183,8
LTEXT "Disk Type:",IDC_DISKTYPE_LABEL,7,59,52,10
CONTROL "&FILE",IDC_DISKTYPE_FILE,"Button",BS_AUTORADIOBUTTON |
WS_GROUP | WS_TABSTOP,60,59,38,10
CONTROL "&RAM",IDC_DISKTYPE_RAM,"Button",BS_AUTORADIOBUTTON,99,
59,38,10
LTEXT "&Media Type:",IDC_MEDIATYPE_LABEL,7,75,52,12,
SS_CENTERIMAGE
COMBOBOX IDC_MEDIATYPE,59,75,80,84,CBS_DROPDOWNLIST | WS_VSCROLL |
WS_TABSTOP
DEFPUSHBUTTON "&Open",IDOK,72,129,50,14,WS_GROUP
PUSHBUTTON "Cancel",IDCANCEL,127,129,50,14
CONTROL "&Write Protect",IDC_OPEN_PROTECTED,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,59,95,184,10
END
IDD_PROPDIALOG DIALOGEX 0, 0, 226, 215
STYLE WS_CHILD | WS_VISIBLE
EXSTYLE WS_EX_CONTEXTHELP
FONT 9, "MS Shell Dlg", 0, 0, 0x1
BEGIN
ICON IDI_VFD_ICON,IDC_STATIC,7,7,20,20
CTEXT "Virtual Floppy Drive for Windows",IDC_PROPERTY_TITLE,29,
10,168,8,SS_CENTERIMAGE
CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,7,32,212,1
LTEXT "Image File:",IDC_IMAGEFILE_LABEL,7,40,50,8
EDITTEXT IDC_IMAGEFILE,58,40,161,12,ES_AUTOHSCROLL | ES_READONLY |
NOT WS_BORDER | NOT WS_TABSTOP
LTEXT "Description:",IDC_IMAGEDESC_LABEL,7,58,50,8
EDITTEXT IDC_IMAGEFILE_DESC,58,58,161,12,ES_AUTOHSCROLL |
ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
LTEXT "Disk Type:",IDC_DISKTYPE_LABEL,7,76,50,8
EDITTEXT IDC_DISKTYPE,58,76,161,12,ES_AUTOHSCROLL | ES_READONLY |
NOT WS_BORDER | NOT WS_TABSTOP
LTEXT "Media Type:",IDC_MEDIATYPE_LABEL,7,94,50,8
EDITTEXT IDC_MEDIATYPE,58,94,161,12,ES_AUTOHSCROLL | ES_READONLY |
NOT WS_BORDER | NOT WS_TABSTOP
CONTROL "&Write Protect",IDC_WRITE_PROTECTED,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,58,112,161,8
PUSHBUTTON "&Open",IDC_OPEN,7,127,50,14
PUSHBUTTON "&Save",IDC_SAVE,61,127,50,14
PUSHBUTTON "&Close",IDC_CLOSE,115,127,50,14
PUSHBUTTON "&Format",IDC_FORMAT,169,127,50,14
CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,7,148,212,1
PUSHBUTTON "&VFD Control Panel",IDC_CONTROL,139,192,80,14
CTEXT "Copyright (c) 2003-2008 Ken Kato",IDC_COPYRIGHT_STR,29,
20,168,8,SS_CENTERIMAGE
END
IDD_SAVEDIALOG DIALOGEX 0, 0, 250, 150
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_CONTEXTHELP
CAPTION "Save Virtual Floppy Image"
FONT 9, "MS Shell Dlg", 0, 0, 0x1
BEGIN
LTEXT "Image File:",IDC_IMAGEFILE_LABEL,7,7,52,12
EDITTEXT IDC_IMAGEFILE,60,7,183,12,ES_AUTOHSCROLL | ES_READONLY |
NOT WS_BORDER | NOT WS_TABSTOP
LTEXT "Disk Type:",IDC_DISKTYPE_LABEL,7,25,52,8,SS_NOPREFIX
EDITTEXT IDC_DISKTYPE,60,25,58,12,ES_AUTOHSCROLL | ES_READONLY |
NOT WS_BORDER | NOT WS_TABSTOP
LTEXT "Media Type:",IDC_MEDIATYPE_LABEL,120,25,52,8,
SS_NOPREFIX
EDITTEXT IDC_MEDIATYPE,173,25,70,12,ES_AUTOHSCROLL | ES_READONLY |
NOT WS_BORDER | NOT WS_TABSTOP
LTEXT "Target &File:",IDC_TARGETFILE_LABEL,7,43,52,12,
SS_CENTERIMAGE
EDITTEXT IDC_TARGETFILE,60,43,131,12,ES_AUTOHSCROLL
PUSHBUTTON "&Browse...",IDC_BROWSE,193,43,50,14
LTEXT "Description:",IDC_IMAGEDESC_LABEL,7,64,52,8,SS_NOPREFIX
EDITTEXT IDC_IMAGEFILE_DESC,60,64,183,12,ES_AUTOHSCROLL |
ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
CONTROL "&Overwrite an existing file",IDC_OVERWRITE,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,60,95,183,10
CONTROL "&Truncate an existing file",IDC_TRUNCATE,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,60,111,183,10
DEFPUSHBUTTON "&Save",IDOK,72,129,50,14,WS_DISABLED
PUSHBUTTON "Cancel",IDCANCEL,127,129,50,14
LTEXT "additional information",IDC_IMAGEFILE_HINT,60,80,183,8,
SS_NOPREFIX
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_OPENDIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 243
TOPMARGIN, 7
BOTTOMMARGIN, 143
END
IDD_PROPDIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 219
TOPMARGIN, 7
BOTTOMMARGIN, 206
END
IDD_SAVEDIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 243
TOPMARGIN, 7
BOTTOMMARGIN, 143
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
#ifndef __REACTOS__
IDI_VFD_ICON ICON DISCARDABLE "res\\vfd.ico"
IDI_IMAGE_ICON ICON DISCARDABLE "res\\image.ico"
IDI_CONFIG_ICON ICON DISCARDABLE "res\\config.ico"
#else
IDI_VFD_ICON ICON DISCARDABLE "res/vfd.ico"
IDI_IMAGE_ICON ICON DISCARDABLE "res/image.ico"
IDI_CONFIG_ICON ICON DISCARDABLE "res/config.ico"
#endif
#endif // Æ­°Ä×Ù resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
#ifdef __REACTOS__
#include <vfdmsg_lib.rc>
#endif

View file

@ -0,0 +1,83 @@
/*
vfdlib.rc
Virtual Floppy Drive for Windows
Driver control library
Resource Script
The non-standard extension ".rs" is intentional, so that
Microsoft Visual Studio won't try to open this file with
the resource editor
Copyright (c) 2003-2005 Ken Kato
*/
#ifndef APSTUDIO_INVOKED
//
// version resource constants
//
#include <winver.h>
//
// VFD common version constants
//
#include "vfdver.h"
//
// Library specific version constants
//
#include "vfdlib.h"
#define VFD_FILEOS VOS_NT_WINDOWS32
#define VFD_FILETYPE VFT_DLL
#define VFD_FILESUBTYPE VFT2_UNKNOWN
#define VFD_DESCRIPTION "Virtual Floppy Drive Library"
#define VFD_INTERNALNAME VFD_LIBRARY_FILENAME
#define VFD_FILE_MAJOR 2
#define VFD_FILE_MINOR 1
//
// embedded VFD driver binary
//
#ifdef VFD_EMBED_DRIVER
#define VFD_SPECIAL_FLAG VS_FF_SPECIALBUILD
#define VFD_SPECIAL_DESC "Driver binary embedded version"
#define VFD_SPECIAL_DESC_ALT "ドライババイナリ埋め込み版"
#ifdef _DEBUG
VFD_DRIVER_NAME_ID VFD_DRIVER_TYPE_ID "..\..\sys\objchk\i386\vfd.sys"
#else // _DEBUG
VFD_DRIVER_NAME_ID VFD_DRIVER_TYPE_ID "..\..\sys\objfre\i386\vfd.sys"
#endif // _DEBUG
#endif // VFD_EMBED_DRIVER
//
// Japanese version resource constants
//
#define VFD_VERSIONINFO_ALT "041104B0"
#undef VFD_VERSIONINFO_TRANS
#define VFD_VERSIONINFO_TRANS 0x0409, 0x04B0, 0x0411, 0x04B0
#define VFD_DESCRIPTION_ALT "Virtual Floppy Drive ライブラリ"
#define VFD_PRODUCT_NAME_ALT VFD_PRODUCT_NAME
//
// VFD common version resource
//
#include "vfdver.rc"
//
// GUI resource
//
#include "vfdlib.rc"
//
// Module message resource
//
#include "vfdmsg.rc"
#endif // !APSTUDIO_INVOKED

View file

@ -0,0 +1,55 @@
@ stdcall -private DllCanUnloadNow()
@ stdcall -private DllGetClassObject(ptr ptr ptr)
@ stdcall VfdRegisterHandlers()
@ stdcall VfdUnregisterHandlers()
@ stdcall VfdCheckHandlers()
@ stdcall VfdInstallDriver(str long)
@ stdcall VfdConfigDriver(long)
@ stdcall VfdRemoveDriver()
@ stdcall VfdStartDriver(ptr)
@ stdcall VfdStopDriver(ptr)
@ stdcall VfdGetDriverConfig(str ptr)
@ stdcall VfdGetDriverState(ptr)
@ stdcall VfdOpenDevice(long)
@ stdcall VfdGetDeviceNumber(ptr ptr)
@ stdcall VfdGetDeviceName(ptr str long)
@ stdcall VfdGetDriverVersion(ptr ptr)
@ stdcall VfdOpenImage(ptr str long long long)
@ stdcall VfdCloseImage(ptr long)
@ stdcall VfdGetImageInfo(ptr str ptr ptr ptr ptr ptr)
@ stdcall VfdSaveImage(ptr str long long)
@ stdcall VfdFormatMedia(ptr)
@ stdcall VfdGetMediaState(ptr)
@ stdcall VfdWriteProtect(ptr long)
@ stdcall VfdDismountVolume(ptr long)
@ stdcall VfdSetGlobalLink(ptr long)
@ stdcall VfdGetGlobalLink(ptr str)
@ stdcall VfdSetLocalLink(ptr long)
@ stdcall VfdGetLocalLink(ptr str)
@ stdcall VfdGetNotifyMessage()
@ stdcall VfdChooseLetter()
@ stdcall VfdCheckDriverFile(str ptr)
@ stdcall VfdCheckImageFile(str ptr ptr ptr)
@ stdcall VfdCreateImageFile(str long long long)
@ stdcall VfdLookupMedia(long)
@ stdcall VfdGetMediaSize(long)
@ stdcall VfdMediaTypeName(long)
@ stdcall VfdMakeFileDesc(str long long long long)
@ stdcall VfdGuiOpen(ptr long)
@ stdcall VfdGuiSave(ptr long)
@ stdcall VfdGuiClose(ptr long)
@ stdcall VfdGuiFormat(ptr long)
@ stdcall VfdToolTip(ptr str long long long)
@ stdcall VfdImageTip(ptr long)
@ stdcall VfdIsValidPlatform()

View file

@ -0,0 +1,523 @@
;/*
; vfdmsg.h
;
; Virtual Floppy Drive for Windows
; Driver control library
; Message definition
;
; Copyright (c) 2003-2005 Ken Kato
;*/
;
;#ifndef _VFDMSG_H_
;#define _VFDMSG_H_
;
MessageIdTypedef=DWORD
LanguageNames=(English=0x409:msg0409)
;
;//
;// Context menu text
;//
;
MessageId=
SymbolicName=MSG_MENU_OPEN
Language=English
&Open VFD image...%0
.
MessageId=
SymbolicName=MSG_HELP_OPEN
Language=English
Open a virtual floppy image.%0
.
MessageId=
SymbolicName=MSG_MENU_CLOSE
Language=English
&Close VFD image%0
.
MessageId=
SymbolicName=MSG_HELP_CLOSE
Language=English
Close the current virtual floppy image.%0
.
MessageId=
SymbolicName=MSG_MENU_SAVE
Language=English
&Save VFD image...%0
.
MessageId=
SymbolicName=MSG_HELP_SAVE
Language=English
Save the current image into a file.%0
.
MessageId=
SymbolicName=MSG_MENU_PROTECT
Language=English
&Write Protect%0
.
MessageId=
SymbolicName=MSG_HELP_PROTECT
Language=English
Enable/disable the media write protection.%0
.
MessageId=
SymbolicName=MSG_MENU_PROP
Language=English
VFD &Property%0
.
MessageId=
SymbolicName=MSG_HELP_PROP
Language=English
Display the VFD property page.%0
.
MessageId=
SymbolicName=MSG_MENU_DROP
Language=English
&Open with VFD%0
.
MessageId=
SymbolicName=MSG_HELP_DROP
Language=English
Open the file with VFD.%0
.
;
;//
;// Dialog title text
;//
;
MessageId=
SymbolicName=MSG_OPEN_TITLE
Language=English
Open Virtual Floppy Image%0
.
MessageId=
SymbolicName=MSG_SAVE_TITLE
Language=English
Save Virtual Floppy Image%0
.
;
;//
;// Dialog label text
;//
;
MessageId=
SymbolicName=MSG_IMAGEFILE_LABEL
Language=English
Image File:%0
.
MessageId=
SymbolicName=MSG_IMAGEFILE_ACCEL
Language=English
&Image File:%0
.
MessageId=
SymbolicName=MSG_DESCRIPTION_LABEL
Language=English
Description:%0
.
MessageId=
SymbolicName=MSG_DISKTYPE_LABEL
Language=English
Disk Type:%0
.
MessageId=
SymbolicName=MSG_MEDIATYPE_LABEL
Language=English
Media Type:%0
.
MessageId=
SymbolicName=MSG_MEDIATYPE_ACCEL
Language=English
&Media Type:%0
.
MessageId=
SymbolicName=MSG_TARGETFILE_LABEL
Language=English
&Target File:%0
.
;
;//
;// button text
;//
;
MessageId=
SymbolicName=MSG_OPEN_BUTTON
Language=English
&Open%0
.
MessageId=
SymbolicName=MSG_CREATE_BUTTON
Language=English
&Create%0
.
MessageId=
SymbolicName=MSG_SAVE_BUTTON
Language=English
&Save%0
.
MessageId=
SymbolicName=MSG_CLOSE_BUTTON
Language=English
&Close%0
.
MessageId=
SymbolicName=MSG_FORMAT_BUTTON
Language=English
&Format%0
.
MessageId=
SymbolicName=MSG_CONTROL_BUTTON
Language=English
&VFD Control Panel%0
.
MessageId=
SymbolicName=MSG_BROWSE_BUTTON
Language=English
&Browse...%0
.
MessageId=
SymbolicName=MSG_CANCEL_BUTTON
Language=English
Cancel%0
.
MessageId=
SymbolicName=MSG_OVERWRITE_CHECK
Language=English
Overwrite an existing file.%0
.
MessageId=
SymbolicName=MSG_TRUNCATE_CHECK
Language=English
Truncate an existing file.%0
.
;
;//
;// file description text
;//
;
MessageId=
SymbolicName=MSG_FILETYPE_RAW
Language=English
RAW image%0
.
MessageId=
SymbolicName=MSG_FILETYPE_ZIP
Language=English
ZIP image%0
.
MessageId=
SymbolicName=MSG_DESC_NEW_FILE
Language=English
New file%0
.
MessageId=
SymbolicName=MSG_DESC_FILESIZE
Language=English
%1!s! bytes (%2!s!)%0
.
MessageId=
SymbolicName=MSG_ATTR_READONLY
Language=English
ReadOnly%0
.
MessageId=
SymbolicName=MSG_ATTR_COMPRESSED
Language=English
Compressed%0
.
MessageId=
SymbolicName=MSG_ATTR_ENCRYPTED
Language=English
Encrypted%0
.
;
;//
;// ToolTip
;//
;
MessageId=
SymbolicName=MSG_WRITE_PROTECTED
Language=English
&Write Protected%0
.
MessageId=
SymbolicName=MSG_WRITE_ALLOWED
Language=English
Write Allowed%0
.
MessageId=
SymbolicName=MSG_IMAGE_INFOTIP
Language=English
%1!s!
%2!s!
Type: %3!s! disk
Media: %4!s!
%5!s!%0
.
;
;//
;// Context help text
;//
;
MessageId=
SymbolicName=MSG_HELP_IMAGEFILE
Language=English
Image file name.%0
.
MessageId=
SymbolicName=MSG_HELP_IMAGEDESC
Language=English
Information about the image file.%0
.
MessageId=
SymbolicName=MSG_HELP_TARGETFILE
Language=English
Save target file name.%0
.
MessageId=
SymbolicName=MSG_HELP_DISKTYPE
Language=English
Virtual disk type.%0
.
MessageId=
SymbolicName=MSG_HELP_MEDIATYPE
Language=English
Virtual floppy media type.%0
.
MessageId=
SymbolicName=MSG_HELP_FORMAT
Language=English
Click to format the
current image with FAT.%0
.
MessageId=
SymbolicName=MSG_HELP_CONTROL
Language=English
Start the VFD Control Panel.%0
.
MessageId=
SymbolicName=MSG_HELP_PROTECT_NOW
Language=English
Enable/disable the media write protection.
The change takes effect immediately.%0
.
MessageId=
SymbolicName=MSG_HELP_PROTECT_OPEN
Language=English
Open the image as a
write protected media.%0
.
MessageId=
SymbolicName=MSG_HELP_BROWSE
Language=English
Browse for folders to
find the target file.%0
.
MessageId=
SymbolicName=MSG_HELP_OVERWRITE
Language=English
Overwrite the existing file
to save the current image.%0
.
MessageId=
SymbolicName=MSG_HELP_TRUNCATE
Language=English
Truncate the target file after
saving the current image.%0
.
;
;//
;// Hint text
;//
;
MessageId=
SymbolicName=MSG_CURRENT_FILE
Language=English
Current image file.%0
.
MessageId=
SymbolicName=MSG_FILE_TOO_SMALL
Language=English
The file is too small for the selected media type.%0
.
MessageId=
SymbolicName=MSG_SIZE_MISMATCH
Language=English
The file size does not match the selected media size.%0
.
MessageId=
SymbolicName=MSG_FILE_ACCESS_ERROR
Language=English
Cannot access the file.%0
.
MessageId=
SymbolicName=MSG_TARGET_IS_ZIP
Language=English
Cannot overwrite a ZIP compressed file.%0
.
;
;//
;// Other text
;//
;
MessageId=
SymbolicName=MSG_OPEN_FILTER
Language=English
Common image files (bin,dat,fdd,flp,ima,img,vfd)|*.bin;*.dat;*.fdd;*.flp;*.ima;*.img;*.vfd|ZIP Compressed Image (imz,zip)|*.imz;*.zip|All files (*.*)|*.*|%0
.
MessageId=
SymbolicName=MSG_FORMAT_WARNING
Language=English
Warning: Formatting will erase all data on this disk.
Click [OK] to format the disk, [Cancel] to quit.%0
.
MessageId=
SymbolicName=MSG_MEDIA_MODIFIED
Language=English
Data on the RAM disk is modified.
Save to a file before closing ?%0
.
MessageId=
SymbolicName=MSG_UNMOUNT_CONFIRM
Language=English
Failed to lock the volume.
Make sure that any files are not in use.
Continuing forces all files to be closed.%0
.
MessageId=
SymbolicName=MSG_UNMOUNT_FAILED
Language=English
Failed to unmount the volume.
Make sure that any files are not in use.%0
.
;
;#endif // _VFDMSG_H_

View file

@ -0,0 +1,126 @@
/*
vfdshcfact.cpp
Virtual Floppy Drive for Windows
Driver control library
shell extension COM class factory class
Copyright (c) 2003-2005 Ken Kato
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shlobj.h>
#include "vfdtypes.h"
#include "vfdlib.h"
#include "vfdshext.h"
// class header
#include "vfdshcfact.h"
//
// constructor
//
CVfdFactory::CVfdFactory()
{
VFDTRACE(0, ("CVfdFactory::CVfdFactory()\n"));
m_cRefCnt = 0L;
g_cDllRefCnt++;
}
//
// destructor
//
CVfdFactory::~CVfdFactory()
{
VFDTRACE(0, ("CVfdFactory::~CVfdFactory()\n"));
g_cDllRefCnt--;
}
//
// IUnknown methods
//
STDMETHODIMP CVfdFactory::QueryInterface(
REFIID riid,
LPVOID *ppv)
{
VFDTRACE(0, ("CVfdFactory::QueryInterface()\n"));
*ppv = NULL;
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IClassFactory)) {
*ppv = (LPCLASSFACTORY)this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CVfdFactory::AddRef()
{
VFDTRACE(0, ("CVfdFactory::AddRef()\n"));
return ++m_cRefCnt;
}
STDMETHODIMP_(ULONG) CVfdFactory::Release()
{
VFDTRACE(0, ("CVfdFactory::Release()\n"));
if (--m_cRefCnt) {
return m_cRefCnt;
}
#ifndef __REACTOS__
delete this;
#endif
return 0L;
}
//
// IClassFactory methods
//
STDMETHODIMP CVfdFactory::CreateInstance(
LPUNKNOWN pUnkOuter,
REFIID riid,
LPVOID *ppvObj)
{
VFDTRACE(0, ("CVfdFactory::CreateInstance()\n"));
*ppvObj = NULL;
// Shell extensions typically don't support
// aggregation (inheritance)
if (pUnkOuter) {
return CLASS_E_NOAGGREGATION;
}
// Create the main shell extension object.
// The shell will then call QueryInterface with IID_IShellExtInit
// -- this is how shell extensions are initialized.
LPCVFDSHEXT pVfdShExt = new CVfdShExt;
if (!pVfdShExt) {
return E_OUTOFMEMORY;
}
return pVfdShExt->QueryInterface(riid, ppvObj);
}
STDMETHODIMP CVfdFactory::LockServer(BOOL fLock)
{
VFDTRACE(0, ("CVfdFactory::LockServer()\n"));
UNREFERENCED_PARAMETER(fLock);
return NOERROR;
}

View file

@ -0,0 +1,42 @@
/*
vfdshcfact.h
Virtual Floppy Drive for Windows
Driver control library
shell extension COM class-factory class header
Copyright (c) 2003-2005 Ken Kato
*/
#ifndef _VFDSHCFACT_H_
#define _VFDSHCFACT_H_
//
// CVfdFactory
// class factory class to create the COM shell extension object
//
class CVfdFactory : public IClassFactory
{
protected:
ULONG m_cRefCnt; // Reference count to the object
public:
// Constructor
CVfdFactory();
// Destructor
~CVfdFactory();
// IUnknown inheritance
STDMETHODIMP QueryInterface(REFIID, LPVOID *);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IClassFactory inheritance
STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID *);
STDMETHODIMP LockServer(BOOL);
};
typedef CVfdFactory *LPCVFDFACTORY;
#endif // _VFDSHCFACT_H_

View file

@ -0,0 +1,235 @@
/*
vfdshext.cpp
Virtual Floppy Drive for Windows
Driver control library
shell extension COM shell extension class
Copyright (c) 2003-2005 Ken Kato
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include "vfdtypes.h"
#include "vfdapi.h"
#include "vfdlib.h"
// class header
#include "vfdshext.h"
//
// Constructor
//
CVfdShExt::CVfdShExt()
{
VFDTRACE(0, ("CVfdShExt::CVfdShExt()\n"));
m_cRefCnt = 0L;
m_pDataObj = NULL;
m_nDevice = (ULONG)-1;
m_sTarget[0] = '\0';
m_bDragDrop = FALSE;
g_cDllRefCnt++;
}
//
// Destructor
//
CVfdShExt::~CVfdShExt()
{
VFDTRACE(0, ("CVfdShExt::~CVfdShExt()\n"));
if (m_pDataObj) {
m_pDataObj->Release();
}
g_cDllRefCnt--;
}
// IUnknown members
STDMETHODIMP CVfdShExt::QueryInterface(
REFIID riid,
LPVOID *ppv)
{
*ppv = NULL;
if (IsEqualIID(riid, IID_IShellExtInit) ||
IsEqualIID(riid, IID_IUnknown)) {
VFDTRACE(0,
("CVfdShExt::QueryInterface()==>IID_IShellExtInit\n"));
*ppv = (LPSHELLEXTINIT)this;
}
else if (IsEqualIID(riid, IID_IContextMenu)) {
VFDTRACE(0,
("CVfdShExt::QueryInterface()==>IID_IContextMenu\n"));
*ppv = (LPCONTEXTMENU)this;
}
else if (IsEqualIID(riid, IID_IShellPropSheetExt)) {
VFDTRACE(0,
("CVfdShExt::QueryInterface()==>IID_IShellPropSheetExt\n"));
*ppv = (LPSHELLPROPSHEETEXT)this;
}
if (*ppv) {
AddRef();
return NOERROR;
}
VFDTRACE(0,
("CVfdShExt::QueryInterface()==>Unknown Interface!\n"));
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CVfdShExt::AddRef()
{
VFDTRACE(0, ("CVfdShExt::AddRef()\n"));
return ++m_cRefCnt;
}
STDMETHODIMP_(ULONG) CVfdShExt::Release()
{
VFDTRACE(0, ("CVfdShExt::Release()\n"));
if (--m_cRefCnt) {
return m_cRefCnt;
}
#ifndef __REACTOS__
delete this;
#endif
return 0L;
}
// IShellExtInit members
//
// Initialize
// Called by the shell to initialize the shell extension object
//
STDMETHODIMP CVfdShExt::Initialize(
LPCITEMIDLIST pIDFolder,
LPDATAOBJECT pDataObj,
HKEY hRegKey)
{
CHAR drive = '\0';
VFDTRACE(0, ("CVfdShExt::Initialize()\n"));
UNREFERENCED_PARAMETER(hRegKey);
// Initialize can be called more than once
if (m_pDataObj) {
m_pDataObj->Release();
m_pDataObj = NULL;
}
m_nDevice = (ULONG)-1;
m_sTarget[0] = '\0';
// Get the folder name
if (SHGetPathFromIDList(pIDFolder, m_sTarget)) {
// act as a Drag-and-Drop Handler
VFDTRACE(0, ("Drag-Drop: %s\n", m_sTarget));
if (GetDriveType(m_sTarget) != DRIVE_REMOVABLE) {
VFDTRACE(0, ("Not a VFD drive\n"));
return NOERROR;
}
drive = m_sTarget[0];
m_bDragDrop = TRUE;
}
else {
// act as a context menu handler
VFDTRACE(0, ("Context menu:\n"));
m_bDragDrop = FALSE;
}
// Extract the target object name
if (pDataObj) {
STGMEDIUM medium;
FORMATETC fmt = {
CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL
};
if (SUCCEEDED(pDataObj->GetData(&fmt, &medium))) {
if (DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, NULL, 0)) {
DragQueryFile((HDROP)medium.hGlobal,
0, m_sTarget, sizeof(m_sTarget));
}
ReleaseStgMedium(&medium);
}
}
VFDTRACE(0, ("Target %s\n", m_sTarget));
if (!drive) {
// Contect menu handler
// -- Data object is the target drive
drive = m_sTarget[0];
}
HANDLE hDevice = VfdOpenDevice(drive);
if (hDevice == INVALID_HANDLE_VALUE) {
VFDTRACE(0, ("Not a VFD drive\n"));
return NOERROR;
}
ULONG ret = VfdGetDeviceNumber(hDevice, &m_nDevice);
CloseHandle(hDevice);
if (ret != ERROR_SUCCESS) {
m_nDevice = (ULONG)-1;
return NOERROR;
}
VFDTRACE(0, ("VFD device %d\n", m_nDevice));
// Store the data object
m_pDataObj = pDataObj;
m_pDataObj->AddRef();
return NOERROR;
}
/*
STDMETHODIMP CVfdShExt::GetInfoFlags(
DWORD *pdwFlags)
{
VFDTRACE(0, ("CVfdShExt::GetInfoFlags\n"));
*pdwFlags = 0;
return NOERROR;
}
STDMETHODIMP CVfdShExt::GetInfoTip(
DWORD dwFlags,
LPWSTR *ppwszTip)
{
VFDTRACE(0, ("CVfdShExt::GetInfoTip\n"));
*ppwszTip = NULL;
return NOERROR;
}
*/

View file

@ -0,0 +1,99 @@
/*
vfdshext.h
Virtual Floppy Drive for Windows
Driver control library
shell extension COM class header
Copyright (c) 2003-2005 Ken Kato
*/
#ifndef _VFDSHEXT_H_
#define _VFDSHEXT_H_
//
// CVfdShExt
// COM Shell extension class
//
class CVfdShExt : public IContextMenu,
IShellExtInit,
IShellPropSheetExt
// IQueryInfo
{
protected:
ULONG m_cRefCnt; // reference count
LPDATAOBJECT m_pDataObj; // IDataObject pointer
ULONG m_nDevice; // VFD device number
CHAR m_sTarget[MAX_PATH]; // target path
BOOL m_bDragDrop;
public:
// constructor / destructor
CVfdShExt();
~CVfdShExt();
// perform VFD operations
DWORD DoVfdOpen(HWND hParent);
DWORD DoVfdNew(HWND hParent);
DWORD DoVfdClose(HWND hParent);
DWORD DoVfdSave(HWND hParent);
DWORD DoVfdProtect(HWND hParent);
DWORD DoVfdDrop(HWND hParent);
// get current attributes
ULONG GetDevice() { return m_nDevice; }
PCSTR GetTarget() { return m_sTarget; }
// IUnknown inheritance
STDMETHODIMP QueryInterface(REFIID, LPVOID *);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IShellExtInit inheritance
STDMETHODIMP Initialize(
LPCITEMIDLIST pIDFolder,
LPDATAOBJECT pDataObj,
HKEY hKeyID);
// IContextMenu inheritance
STDMETHODIMP QueryContextMenu(
HMENU hMenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags);
STDMETHODIMP InvokeCommand(
LPCMINVOKECOMMANDINFO lpcmi);
STDMETHODIMP GetCommandString(
UINT idCmd,
UINT uFlags,
UINT *reserved,
LPSTR pszName,
UINT cchMax);
// IShellPropSheetExt inheritance
STDMETHODIMP AddPages(
LPFNADDPROPSHEETPAGE lpfnAddPage,
LPARAM lParam);
STDMETHODIMP ReplacePage(
UINT uPageID,
LPFNADDPROPSHEETPAGE lpfnReplaceWith,
LPARAM lParam);
/*
// IQueryInfo inheritance
STDMETHODIMP GetInfoFlags(
DWORD *pdwFlags);
STDMETHODIMP GetInfoTip(
DWORD dwFlags,
LPWSTR *ppwszTip);
*/
};
typedef CVfdShExt *LPCVFDSHEXT;
#endif // _VFDSHEXT_H_

View file

@ -0,0 +1,17 @@
/*
vfdshguid.h
Virtual Floppy Drive for Windows
Driver control library
shell extension GUID header
Copyright (c) 2003-2005 Ken Kato
*/
#ifndef _VFDSHGUID_H_
#define _VFDSHGUID_H_
DEFINE_GUID(CLSID_VfdShellExt, 0x296c1585L, 0x678f, 0x4584,
0x8f, 0x02, 0x10, 0x39, 0xc1, 0xd1, 0x86, 0x4c);
#endif // _VFDSHGUID_H_

View file

@ -0,0 +1,597 @@
/*
vfdshmenu.cpp
Virtual Floppy Drive for Windows
Driver control library
COM shell extension class context menu functions
Copyright (c) 2003-2005 Ken Kato
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include "vfdtypes.h"
#include "vfdapi.h"
#include "vfdlib.h"
#ifndef __REACTOS__
#include "vfdmsg.h"
#else
#include "vfdmsg_lib.h"
#endif
// class header
#include "vfdshext.h"
//
// Undocumented windows API to handle shell property sheets
//
typedef BOOL (WINAPI *SHOBJECTPROPERTIES)(
HWND hwnd, DWORD dwType, LPCWSTR lpObject, LPCWSTR lpPage);
#ifndef SHOP_FILEPATH
#define SHOP_FILEPATH 0x00000002
#endif
#define SHOP_EXPORT_ORDINAL 178
//
// Context Menu Items
//
enum {
VFD_CMD_OPEN = 0,
VFD_CMD_SAVE,
VFD_CMD_CLOSE,
VFD_CMD_PROTECT,
VFD_CMD_DROP,
VFD_CMD_PROP,
VFD_CMD_MAX
};
static struct _vfd_menu {
UINT textid; // menu item text id
UINT helpid; // menu item help id
#ifndef __REACTOS__
PCHAR verbA; // ansi verb text
PWCHAR verbW; // unicode verb text
#else
LPCSTR verbA; // ansi verb text
LPCWSTR verbW; // unicode verb text
#endif
}
g_VfdMenu[VFD_CMD_MAX] = {
{ MSG_MENU_OPEN, MSG_HELP_OPEN, "vfdopen", L"vfdopen" },
{ MSG_MENU_SAVE, MSG_HELP_SAVE, "vfdsave", L"vfdsave" },
{ MSG_MENU_CLOSE, MSG_HELP_CLOSE, "vfdclose", L"vfdclose" },
{ MSG_MENU_PROTECT, MSG_HELP_PROTECT, "protect", L"protect" },
{ MSG_MENU_DROP, MSG_HELP_DROP, "vfddrop", L"vfddrop" },
{ MSG_MENU_PROP, MSG_HELP_PROP, "vfdprop", L"vfdprop" },
};
//
// local functions
//
static void AddMenuItem(
HMENU hMenu,
UINT uPos,
UINT uFlags,
UINT uCmd,
UINT uText)
{
PSTR text = ModuleMessage(uText);
if (text) {
InsertMenu(hMenu, uPos, uFlags, uCmd, text);
LocalFree(text);
}
}
//
// FUNCTION: CVfdShExt::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT)
//
// PURPOSE: Called by the shell just before the context menu is displayed.
// This is where you add your specific menu items.
//
// PARAMETERS:
// hMenu - Handle to the context menu
// indexMenu - Index of where to begin inserting menu items
// idCmdFirst - Lowest value for new menu ID's
// idCmtLast - Highest value for new menu ID's
// uFlags - Specifies the context of the menu event
//
STDMETHODIMP CVfdShExt::QueryContextMenu(
HMENU hMenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
UNREFERENCED_PARAMETER(idCmdLast);
VFDTRACE(0, ("CVfdShExt::QueryContextMenu()\n"));
//
// Check if menu items should be added
//
if ((CMF_DEFAULTONLY & uFlags) ||
!m_pDataObj || m_nDevice == (ULONG)-1) {
VFDTRACE(0, ("Don't add any items.\n"));
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
}
//
// Drag & Drop handler?
//
if (m_bDragDrop) {
VFDTRACE(0, ("Invoked as the Drop handler.\n"));
if (GetFileAttributes(m_sTarget) & FILE_ATTRIBUTE_DIRECTORY) {
// if the dropped item is a directory, nothing to do here
VFDTRACE(0, ("Dropped object is a directory.\n"));
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
}
// Add a drop context menu item
AddMenuItem(
hMenu,
indexMenu,
MF_BYPOSITION | MF_STRING,
idCmdFirst + VFD_CMD_DROP,
g_VfdMenu[VFD_CMD_DROP].textid);
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, VFD_CMD_DROP + 1);
}
//
// Context menu handler
//
VFDTRACE(0, ("Invoked as the context menu handler.\n"));
//
// Get the VFD media state
//
HANDLE hDevice = VfdOpenDevice(m_nDevice);
if (hDevice == INVALID_HANDLE_VALUE) {
VFDTRACE(0, ("device open failed.\n"));
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
}
DWORD status = VfdGetMediaState(hDevice);
CloseHandle(hDevice);
//
// Add context menu items
//
InsertMenu(hMenu, indexMenu++,
MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
if (status == ERROR_SUCCESS ||
status == ERROR_WRITE_PROTECT) {
// An image is opened
// insert the "save" menu item
AddMenuItem(
hMenu,
indexMenu++,
MF_BYPOSITION | MF_STRING,
idCmdFirst + VFD_CMD_SAVE,
g_VfdMenu[VFD_CMD_SAVE].textid);
// insert the "close" menu item
AddMenuItem(
hMenu,
indexMenu++,
MF_BYPOSITION | MF_STRING,
idCmdFirst + VFD_CMD_CLOSE,
g_VfdMenu[VFD_CMD_CLOSE].textid);
// insert the "protect" menu item
AddMenuItem(
hMenu,
indexMenu++,
MF_BYPOSITION | MF_STRING,
idCmdFirst + VFD_CMD_PROTECT,
g_VfdMenu[VFD_CMD_PROTECT].textid);
// check "protect" menu item
if (status == ERROR_WRITE_PROTECT) {
CheckMenuItem(hMenu, indexMenu - 1,
MF_BYPOSITION | MF_CHECKED);
}
}
else {
// The drive is empty
// insert the "open" menu item
AddMenuItem(
hMenu,
indexMenu++,
MF_BYPOSITION | MF_STRING,
idCmdFirst + VFD_CMD_OPEN,
g_VfdMenu[VFD_CMD_OPEN].textid);
}
// Insert the "proterty" menu item
AddMenuItem(
hMenu,
indexMenu++,
MF_BYPOSITION | MF_STRING,
idCmdFirst + VFD_CMD_PROP,
g_VfdMenu[VFD_CMD_PROP].textid);
// Insert a separator
InsertMenu(hMenu, indexMenu,
MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, VFD_CMD_PROP + 1);
}
//
// FUNCTION: CVfdShExt::GetCommandString(LPCMINVOKECOMMANDINFO)
//
// PURPOSE: Retrieves information about a shortcut menu command,
// including the Help string and the language-independent,
// or canonical, name for the command.
//
// PARAMETERS:
// idCmd - Menu command identifier offset.
// uFlags - Flags specifying the information to return.
// This parameter can have one of the following values.
// GCS_HELPTEXTA Sets pszName to an ANSI string containing the Help text for the command.
// GCS_HELPTEXTW Sets pszName to a Unicode string containing the Help text for the command.
// GCS_VALIDATEA Returns S_OK if the menu item exists, or S_FALSE otherwise.
// GCS_VALIDATEW Returns S_OK if the menu item exists, or S_FALSE otherwise.
// GCS_VERBA Sets pszName to an ANSI string containing the language-independent command name for the menu item.
// GCS_VERBW Sets pszName to a Unicode string containing the language-independent command name for the menu item.
// pwReserved - Reserved. Applications must specify NULL when calling this method, and handlers must ignore this parameter when called.
// pszName - Address of the buffer to receive the null-terminated string being retrieved.
// cchMax - Size of the buffer to receive the null-terminated string.
//
STDMETHODIMP CVfdShExt::GetCommandString(
UINT idCmd,
UINT uFlags,
UINT *reserved,
LPSTR pszName,
UINT cchMax)
{
VFDTRACE(0,
("CVfdShExt::GetCommandString(%u,...)\n", idCmd));
UNREFERENCED_PARAMETER(reserved);
if (idCmd >= sizeof(g_VfdMenu) / sizeof(g_VfdMenu[0])) {
return S_FALSE;
}
switch (uFlags) {
case GCS_HELPTEXTA:
FormatMessageA(
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_IGNORE_INSERTS,
g_hDllModule, g_VfdMenu[idCmd].helpid,
0, pszName, cchMax, NULL);
VFDTRACE(0, ("HELPTEXTA: %s\n", pszName));
break;
case GCS_HELPTEXTW:
FormatMessageW(
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_IGNORE_INSERTS,
g_hDllModule, g_VfdMenu[idCmd].helpid,
0, (LPWSTR)pszName, cchMax, NULL);
VFDTRACE(0, ("HELPTEXTW: %ws\n", pszName));
break;
case GCS_VERBA:
lstrcpynA(pszName, g_VfdMenu[idCmd].verbA, cchMax);
break;
case GCS_VERBW:
lstrcpynW((LPWSTR)pszName, g_VfdMenu[idCmd].verbW, cchMax);
break;
}
return NOERROR;
}
//
// FUNCTION: CVfdShExt::InvokeCommand(LPCMINVOKECOMMANDINFO)
//
// PURPOSE: Called by the shell after the user has selected on of the
// menu items that was added in QueryContextMenu().
//
// PARAMETERS:
// lpcmi - Pointer to an CMINVOKECOMMANDINFO structure
//
STDMETHODIMP CVfdShExt::InvokeCommand(
LPCMINVOKECOMMANDINFO lpcmi)
{
VFDTRACE(0, ("CVfdShExt::InvokeCommand()\n"));
BOOL unicode = FALSE;
UINT id;
DWORD ret;
CMINVOKECOMMANDINFOEX *excmi = (CMINVOKECOMMANDINFOEX *)lpcmi;
if (lpcmi->cbSize >= sizeof(CMINVOKECOMMANDINFOEX) &&
(lpcmi->fMask & CMIC_MASK_UNICODE)) {
unicode = TRUE;
}
if (!unicode && HIWORD(lpcmi->lpVerb)) {
VFDTRACE(0, ("ANSI: %s\n", lpcmi->lpVerb));
// ANSI verb
for (id = 0; id < sizeof(g_VfdMenu) / sizeof(g_VfdMenu[0]); id++) {
if (!lstrcmpi(lpcmi->lpVerb, g_VfdMenu[id].verbA)) {
break;
}
}
}
else if (unicode && HIWORD(excmi->lpVerbW)) {
VFDTRACE(0, ("UNICODE: %ws\n", excmi->lpVerbW));
// UNICODE verb
for (id = 0; id < sizeof(g_VfdMenu) / sizeof(g_VfdMenu[0]); id++) {
if (!lstrcmpiW(excmi->lpVerbW, g_VfdMenu[id].verbW)) {
break;
}
}
}
else {
VFDTRACE(0, ("Command: %u\n", LOWORD(lpcmi->lpVerb)));
// Command ID
id = LOWORD(lpcmi->lpVerb);
}
VFDTRACE(0, ("MenuItem: %u\n", id));
switch (id) {
case VFD_CMD_OPEN:
ret = DoVfdOpen(lpcmi->hwnd);
if (ret == ERROR_SUCCESS) {
VfdImageTip(lpcmi->hwnd, m_nDevice);
}
break;
case VFD_CMD_SAVE:
ret = DoVfdSave(lpcmi->hwnd);
break;
case VFD_CMD_CLOSE:
ret = DoVfdClose(lpcmi->hwnd);
break;
case VFD_CMD_PROTECT:
ret = DoVfdProtect(lpcmi->hwnd);
if (ret == ERROR_SUCCESS) {
VfdImageTip(lpcmi->hwnd, m_nDevice);
}
else if (ret == ERROR_WRITE_PROTECT) {
VfdImageTip(lpcmi->hwnd, m_nDevice);
ret = ERROR_SUCCESS;
}
break;
case VFD_CMD_DROP:
ret = DoVfdDrop(lpcmi->hwnd);
if (ret == ERROR_SUCCESS) {
VfdImageTip(lpcmi->hwnd, m_nDevice);
}
break;
case VFD_CMD_PROP:
{
SHOBJECTPROPERTIES pSHObjectProperties;
WCHAR path[4] = L" :\\";
pSHObjectProperties = (SHOBJECTPROPERTIES)GetProcAddress(
LoadLibrary("shell32"), "SHObjectProperties");
if (!pSHObjectProperties) {
pSHObjectProperties = (SHOBJECTPROPERTIES)GetProcAddress(
LoadLibrary("shell32"), (LPCSTR)SHOP_EXPORT_ORDINAL);
}
if (pSHObjectProperties) {
path[0] = m_sTarget[0];
pSHObjectProperties(lpcmi->hwnd,
SHOP_FILEPATH, path, L"VFD");
}
}
ret = ERROR_SUCCESS;
break;
default:
return E_INVALIDARG;
}
if (ret != ERROR_SUCCESS &&
ret != ERROR_CANCELLED) {
MessageBox(lpcmi->hwnd,
SystemMessage(ret), VFD_MSGBOX_TITLE, MB_ICONSTOP);
}
return NOERROR;
}
//=====================================
// perform VFD menu operation
//=====================================
DWORD CVfdShExt::DoVfdOpen(
HWND hParent)
{
DWORD ret = VfdGuiOpen(hParent, m_nDevice);
if (ret != ERROR_SUCCESS && ret != ERROR_CANCELLED) {
MessageBox(hParent, SystemMessage(ret),
VFD_MSGBOX_TITLE, MB_ICONSTOP);
}
return ret;
}
//
// Save the VFD image
//
DWORD CVfdShExt::DoVfdSave(
HWND hParent)
{
return VfdGuiSave(hParent, m_nDevice);
}
//
// Close current VFD image
//
DWORD CVfdShExt::DoVfdClose(
HWND hParent)
{
return VfdGuiClose(hParent, m_nDevice);
}
//
// Enable/disable media write protection
//
DWORD CVfdShExt::DoVfdProtect(
HWND hParent)
{
HANDLE hDevice;
DWORD ret;
UNREFERENCED_PARAMETER(hParent);
VFDTRACE(0, ("CVfdShExt::DoVfdProtect()\n"));
hDevice = VfdOpenDevice(m_nDevice);
if (hDevice == INVALID_HANDLE_VALUE) {
return GetLastError();
}
ret = VfdGetMediaState(hDevice);
if (ret == ERROR_SUCCESS) {
ret = VfdWriteProtect(hDevice, TRUE);
}
else if (ret == ERROR_WRITE_PROTECT) {
ret = VfdWriteProtect(hDevice, FALSE);
}
if (ret == ERROR_SUCCESS) {
ret = VfdGetMediaState(hDevice);
}
CloseHandle(hDevice);
return ret;
}
//
// Open dropped file with VFD
//
DWORD CVfdShExt::DoVfdDrop(
HWND hParent)
{
HANDLE hDevice;
DWORD file_attr;
ULONG file_size;
VFD_FILETYPE file_type;
VFD_DISKTYPE disk_type;
VFD_MEDIA media_type;
DWORD ret;
VFDTRACE(0, ("CVfdShExt::DoVfdDropOpen()\n"));
// check if dropped file is a valid image
ret = VfdCheckImageFile(
m_sTarget, &file_attr, &file_type, &file_size);
if (ret != ERROR_SUCCESS) {
return ret;
}
// check file size
media_type = VfdLookupMedia(file_size);
if (!media_type) {
PSTR msg = ModuleMessage(MSG_FILE_TOO_SMALL);
MessageBox(hParent, msg ? msg : "Bad size",
VFD_MSGBOX_TITLE, MB_ICONSTOP);
if (msg) {
LocalFree(msg);
}
return ERROR_CANCELLED;
}
if ((file_type == VFD_FILETYPE_ZIP) ||
(file_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_ENCRYPTED))) {
disk_type = VFD_DISKTYPE_RAM;
}
else {
disk_type = VFD_DISKTYPE_FILE;
}
// close current image (if opened)
ret = DoVfdClose(hParent);
if (ret != ERROR_SUCCESS &&
ret != ERROR_NOT_READY) {
return ret;
}
// open dropped file
hDevice = VfdOpenDevice(m_nDevice);
if (hDevice == INVALID_HANDLE_VALUE) {
return GetLastError();
}
ret = VfdOpenImage(
hDevice, m_sTarget, disk_type, media_type, FALSE);
CloseHandle(hDevice);
return ret;
}

View file

@ -0,0 +1,434 @@
/*
vfdshprop.cpp
Virtual Floppy Drive for Windows
Driver control library
COM shell extension class property sheet functions
Copyright (c) 2003-2005 Ken Kato
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include <stdio.h>
#include "vfdtypes.h"
#include "vfdapi.h"
#include "vfdlib.h"
#include "vfdver.h"
#ifndef __REACTOS__
#include "vfdmsg.h"
#else
#include "vfdmsg_lib.h"
#endif
#include "vfdguirc.h"
// class header
#include "vfdshext.h"
// property sheet property ID
#define VFD_PROPERTY_ID "VFD"
//
// local functions
//
static BOOL CALLBACK VfdPageDlgProc(
HWND hDlg,
UINT uMessage,
WPARAM wParam,
LPARAM lParam);
static UINT CALLBACK VfdPageCallback(
HWND hWnd,
UINT uMessage,
LPPROPSHEETPAGE ppsp);
static void OnPropInit(HWND hDlg);
static void OnControl(HWND hDlg);
static void UpdateImageInfo(HWND hDlg, ULONG nDevice);
//
// property sheet callback function
//
UINT CALLBACK VfdPageCallback(
HWND hWnd,
UINT uMessage,
LPPROPSHEETPAGE ppsp)
{
UNREFERENCED_PARAMETER(hWnd);
switch(uMessage) {
case PSPCB_CREATE:
return TRUE;
case PSPCB_RELEASE:
if (ppsp->lParam) {
((LPCVFDSHEXT)(ppsp->lParam))->Release();
}
return TRUE;
}
return TRUE;
}
//
// property page dialog procedure
//
BOOL CALLBACK VfdPageDlgProc(
HWND hDlg,
UINT uMessage,
WPARAM wParam,
LPARAM lParam)
{
LPPROPSHEETPAGE psp;
LPCVFDSHEXT lpcs;
switch (uMessage) {
case WM_INITDIALOG:
SetWindowLong(hDlg, DWL_USER, lParam);
if (lParam) {
lpcs = (LPCVFDSHEXT)((LPPROPSHEETPAGE)lParam)->lParam;
OnPropInit(hDlg);
UpdateImageInfo(hDlg, lpcs->GetDevice());
}
return TRUE;
case WM_COMMAND:
psp = (LPPROPSHEETPAGE)GetWindowLong(hDlg, DWL_USER);
if (!psp) {
break;
}
lpcs = (LPCVFDSHEXT)psp->lParam;
if (!lpcs) {
break;
}
switch (wParam) {
case IDC_OPEN:
if (lpcs->DoVfdOpen(hDlg) == ERROR_SUCCESS) {
SendMessage((HWND)lParam,
BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
}
UpdateImageInfo(hDlg, lpcs->GetDevice());
break;
case IDC_SAVE:
if (lpcs->DoVfdSave(hDlg) == ERROR_SUCCESS) {
SendMessage((HWND)lParam,
BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
}
UpdateImageInfo(hDlg, lpcs->GetDevice());
break;
case IDC_CLOSE:
if (lpcs->DoVfdClose(hDlg) == ERROR_SUCCESS) {
SendMessage((HWND)lParam,
BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
}
UpdateImageInfo(hDlg, lpcs->GetDevice());
break;
case IDC_WRITE_PROTECTED:
lpcs->DoVfdProtect(hDlg);
break;
case IDC_FORMAT:
VfdGuiFormat(hDlg, lpcs->GetDevice());
break;
case IDC_CONTROL:
OnControl(hDlg);
break;
}
break;
case WM_CONTEXTMENU:
ShowContextMenu(hDlg, (HWND)wParam, lParam);
break;
case WM_HELP:
{
LPHELPINFO info = (LPHELPINFO)lParam;
if (info->iContextType == HELPINFO_WINDOW) {
ShowHelpWindow(hDlg, info->iCtrlId);
}
}
return TRUE;
default:
if (uMessage == g_nNotifyMsg) {
psp = (LPPROPSHEETPAGE)GetWindowLong(hDlg, DWL_USER);
if (!psp) {
break;
}
lpcs = (LPCVFDSHEXT)psp->lParam;
if (!lpcs) {
break;
}
UpdateImageInfo(hDlg, lpcs->GetDevice());
}
break;
}
return FALSE;
}
//
// initialize the property page
//
void OnPropInit(
HWND hDlg)
{
// set up control text
SetDlgItemText(hDlg, IDC_PROPERTY_TITLE, VFD_PRODUCT_DESC);
SetDlgItemText(hDlg, IDC_COPYRIGHT_STR, VFD_COPYRIGHT_STR);
SetControlText(hDlg, IDC_IMAGEFILE_LABEL, MSG_IMAGEFILE_LABEL);
SetControlText(hDlg, IDC_IMAGEDESC_LABEL, MSG_DESCRIPTION_LABEL);
SetControlText(hDlg, IDC_DISKTYPE_LABEL, MSG_DISKTYPE_LABEL);
SetControlText(hDlg, IDC_MEDIATYPE_LABEL, MSG_MEDIATYPE_LABEL);
SetControlText(hDlg, IDC_WRITE_PROTECTED, MSG_MENU_PROTECT);
SetControlText(hDlg, IDC_OPEN, MSG_OPEN_BUTTON);
SetControlText(hDlg, IDC_SAVE, MSG_SAVE_BUTTON);
SetControlText(hDlg, IDC_CLOSE, MSG_CLOSE_BUTTON);
SetControlText(hDlg, IDC_FORMAT, MSG_FORMAT_BUTTON);
SetControlText(hDlg, IDC_CONTROL, MSG_CONTROL_BUTTON);
}
//
// Control Panel button is clicked
//
void OnControl(
HWND hDlg)
{
CHAR module_path[MAX_PATH];
CHAR full_path[MAX_PATH];
PSTR file_name;
DWORD ret;
ret = GetModuleFileName(
g_hDllModule, module_path, sizeof(module_path));
if (ret == 0 || ret >= sizeof(module_path)) {
file_name = full_path;
}
else {
ret = GetFullPathName(
module_path, sizeof(full_path), full_path, &file_name);
if (ret == 0 || ret >= sizeof(full_path)) {
file_name = full_path;
}
}
strcpy(file_name, "vfdwin.exe");
VFDTRACE(0, ("Starting %s\n", full_path));
ret = (DWORD)ShellExecute(
hDlg, NULL, full_path, NULL, NULL, SW_SHOW);
if (ret > 32) {
PropSheet_PressButton(GetParent(hDlg), PSBTN_CANCEL);
}
else {
MessageBox(hDlg, SystemMessage(ret),
VFD_MSGBOX_TITLE, MB_ICONSTOP);
}
}
//
// Update image information on the property page
//
void UpdateImageInfo(
HWND hDlg,
ULONG nDevice)
{
HANDLE hDevice;
CHAR buf[MAX_PATH];
VFD_DISKTYPE disk_type;
VFD_MEDIA media_type;
VFD_FLAGS media_flags;
VFD_FILETYPE file_type;
ULONG image_size;
DWORD attrib;
ULONG ret;
hDevice = VfdOpenDevice(nDevice);
if (hDevice == INVALID_HANDLE_VALUE) {
MessageBox(hDlg,
SystemMessage(GetLastError()),
VFD_MSGBOX_TITLE, MB_ICONSTOP);
return;
}
// get current image information
ret = VfdGetImageInfo(
hDevice,
buf,
&disk_type,
&media_type,
&media_flags,
&file_type,
&image_size);
CloseHandle(hDevice);
if (ret != ERROR_SUCCESS) {
MessageBox(hDlg,
SystemMessage(ret),
VFD_MSGBOX_TITLE, MB_ICONSTOP);
return;
}
if (media_type == VFD_MEDIA_NONE) {
// drive is empty
SetDlgItemText(hDlg, IDC_IMAGEFILE, NULL);
SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, NULL);
SetDlgItemText(hDlg, IDC_DISKTYPE, NULL);
SetDlgItemText(hDlg, IDC_MEDIATYPE, NULL);
EnableWindow(GetDlgItem(hDlg, IDC_WRITE_PROTECTED), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_OPEN), TRUE);
EnableWindow(GetDlgItem(hDlg, IDC_SAVE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_CLOSE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_FORMAT), FALSE);
SendMessage(GetDlgItem(hDlg, IDC_OPEN),
BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
SetFocus(GetDlgItem(hDlg, IDC_OPEN));
return;
}
// display image file name
if (buf[0]) {
attrib = GetFileAttributes(buf);
if (attrib == INVALID_FILE_ATTRIBUTES) {
attrib = 0;
}
}
else {
if (disk_type != VFD_DISKTYPE_FILE) {
strcpy(buf, "<RAM>");
}
attrib = 0;
}
SetDlgItemText(hDlg, IDC_IMAGEFILE, buf);
// display image description
VfdMakeFileDesc(buf, sizeof(buf),
file_type, image_size, attrib);
SetDlgItemText(hDlg, IDC_IMAGEFILE_DESC, buf);
// display disk type
if (disk_type == VFD_DISKTYPE_FILE) {
SetDlgItemText(hDlg, IDC_DISKTYPE, "FILE");
}
else {
SetDlgItemText(hDlg, IDC_DISKTYPE, "RAM");
}
// display media type
SetDlgItemText(hDlg, IDC_MEDIATYPE,
VfdMediaTypeName(media_type));
// set write protect check box
if (media_flags & VFD_FLAG_WRITE_PROTECTED) {
CheckDlgButton(hDlg, IDC_WRITE_PROTECTED, BST_CHECKED);
}
else {
CheckDlgButton(hDlg, IDC_WRITE_PROTECTED, BST_UNCHECKED);
}
EnableWindow(GetDlgItem(hDlg, IDC_WRITE_PROTECTED), TRUE);
EnableWindow(GetDlgItem(hDlg, IDC_OPEN), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_SAVE), TRUE);
EnableWindow(GetDlgItem(hDlg, IDC_CLOSE), TRUE);
EnableWindow(GetDlgItem(hDlg, IDC_FORMAT), TRUE);
SendMessage(GetDlgItem(hDlg, IDC_CLOSE),
BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
SetFocus(GetDlgItem(hDlg, IDC_CLOSE));
}
//
// CVfdShExt class members inherited from IShellPropSheetExt
//
// Add property page
STDMETHODIMP CVfdShExt::AddPages(
LPFNADDPROPSHEETPAGE lpfnAddPage,
LPARAM lParam)
{
PROPSHEETPAGE psp;
HPROPSHEETPAGE hpage;
if (!m_pDataObj || m_nDevice == (ULONG)-1) {
// not a VFD drive
VFDTRACE(0, ("PropPage: Not a VFD drive\n"));
return NOERROR;
}
psp.dwSize = sizeof(psp); // no extra data.
psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_USECALLBACK;
psp.hInstance = g_hDllModule;
psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPDIALOG);
psp.hIcon = 0;
psp.pszTitle = "VFD";
psp.pfnDlgProc = VfdPageDlgProc;
psp.pcRefParent = &g_cDllRefCnt;
psp.pfnCallback = VfdPageCallback;
psp.lParam = (LPARAM)this;
AddRef();
hpage = CreatePropertySheetPage(&psp);
if (hpage) {
if (!lpfnAddPage(hpage, lParam)) {
DestroyPropertySheetPage(hpage);
Release();
}
}
return NOERROR;
}
STDMETHODIMP CVfdShExt::ReplacePage(
UINT uPageID,
LPFNADDPROPSHEETPAGE lpfnReplaceWith,
LPARAM lParam)
{
UNREFERENCED_PARAMETER(uPageID);
UNREFERENCED_PARAMETER(lpfnReplaceWith);
UNREFERENCED_PARAMETER(lParam);
return E_FAIL;
}

View file

@ -0,0 +1,419 @@
/*
vfdshutil.cpp
Virtual Floppy Drive for Windows
Driver control library
shell extension utility functions
Copyright (c) 2003-2005 Ken Kato
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <objbase.h>
#include <stdio.h>
#include "vfdtypes.h"
#include "vfdapi.h"
#include "vfdlib.h"
#include "vfdshcfact.h"
//=====================================
// Initialize the GUID instance
//=====================================
#ifdef _MSC_VER
#pragma data_seg(".text")
#endif
#define INITGUID
#include <initguid.h>
#include <shlguid.h>
#include "vfdshguid.h"
#ifdef _MSC_VER
#pragma data_seg()
#endif
//
// Registry path to the approved shell extensions key
//
#define REGKEY_APPROVED \
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"
//=====================================
// Shell extension library requirements
//=====================================
//
// Creates a class factory instance
//
STDAPI DllGetClassObject(
REFCLSID rclsid,
REFIID riid,
LPVOID *ppvOut)
{
VFDTRACE(0,
("DllGetClassObject\n"));
*ppvOut = NULL;
if (IsEqualIID(rclsid, CLSID_VfdShellExt)) {
CVfdFactory *pFactory = new CVfdFactory;
if (!pFactory) {
return E_OUTOFMEMORY;
}
return pFactory->QueryInterface(riid, ppvOut);
}
return CLASS_E_CLASSNOTAVAILABLE;
}
//
// DllCanUnloadNow
//
STDAPI DllCanUnloadNow(void)
{
VFDTRACE(0,
("DllCanUnloadNow - %s\n", (g_cDllRefCnt ? "No" : "Yes")));
return (g_cDllRefCnt ? S_FALSE : S_OK);
}
//=====================================
// Shell extension register functions
//=====================================
static inline void MakeGuidString(LPTSTR str, const GUID &guid)
{
sprintf(str, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1],
guid.Data4[2], guid.Data4[3], guid.Data4[4],
guid.Data4[5], guid.Data4[6], guid.Data4[7]);
}
//
// Regster this dll as shell extention handlers
//
DWORD WINAPI VfdRegisterHandlers()
{
TCHAR buf[MAX_PATH];
TCHAR guid_str[40];
HKEY hKey;
DWORD temp;
DWORD ret;
MakeGuidString(guid_str, CLSID_VfdShellExt);
//
// Register the GUID in the CLSID subtree
//
sprintf(buf, "CLSID\\%s", guid_str);
VFDTRACE(0, ("HKCR\\%s\n", buf));
ret = RegCreateKeyEx(
HKEY_CLASSES_ROOT, buf, 0, NULL,
0, KEY_ALL_ACCESS, NULL, &hKey, &temp);
if (ret != ERROR_SUCCESS) {
return ret;
}
if (temp == REG_OPENED_EXISTING_KEY) {
temp = sizeof(buf);
ret = RegQueryValueEx(
hKey, NULL, NULL, NULL, (PBYTE)buf, &temp);
if (ret != ERROR_SUCCESS) {
RegCloseKey(hKey);
return ret;
}
if (_stricmp(buf, VFDEXT_DESCRIPTION)) {
RegCloseKey(hKey);
return ERROR_FILE_EXISTS;
}
}
else {
VFDTRACE(0, ("@=" VFDEXT_DESCRIPTION "\n"));
ret = RegSetValueEx(hKey, NULL, NULL, REG_SZ,
(PBYTE)VFDEXT_DESCRIPTION, sizeof(VFDEXT_DESCRIPTION));
RegCloseKey(hKey);
if (ret != ERROR_SUCCESS) {
return ret;
}
}
//
// Register the executable path
//
sprintf(buf, "CLSID\\%s\\InProcServer32", guid_str);
VFDTRACE(0, ("HKCR\\%s\n", buf));
ret = RegCreateKeyEx(
HKEY_CLASSES_ROOT, buf, 0, NULL,
0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
if (ret != ERROR_SUCCESS) {
return ret;
}
temp = GetModuleFileName(g_hDllModule, buf, sizeof(buf));
VFDTRACE(0, ("@=%s\n", buf));
ret = RegSetValueEx(
hKey, NULL, NULL, REG_SZ, (PBYTE)buf, temp + 1);
if (ret != ERROR_SUCCESS) {
RegCloseKey(hKey);
return ret;
}
VFDTRACE(0, ("ThreadingModel=Apartment\n"));
ret = RegSetValueEx(hKey, "ThreadingModel", NULL, REG_SZ,
(PBYTE)"Apartment", sizeof("Apartment"));
RegCloseKey(hKey);
if (ret != ERROR_SUCCESS) {
return ret;
}
//
// Register context menu handler
//
VFDTRACE(0, ("HKCR\\" VFDEXT_MENU_REGKEY "\n"));
ret = RegCreateKeyEx(
HKEY_CLASSES_ROOT, VFDEXT_MENU_REGKEY, 0, NULL,
0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
if (ret != ERROR_SUCCESS) {
return ret;
}
VFDTRACE(0, ("@=%s\n", guid_str));
ret = RegSetValueEx(hKey, NULL, NULL, REG_SZ,
(PBYTE)guid_str, strlen(guid_str) + 1);
RegCloseKey(hKey);
if (ret != ERROR_SUCCESS) {
return ret;
}
//
// Register Drag&Drop handler
//
if (!IS_WINDOWS_NT()) {
//
// Windows NT does not support Drag&Drop handlers ???
//
VFDTRACE(0, ("HKCR\\" VFDEXT_DND_REGKEY "\n"));
ret = RegCreateKeyEx(
HKEY_CLASSES_ROOT, VFDEXT_DND_REGKEY, 0, NULL,
0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
if (ret != ERROR_SUCCESS) {
return ret;
}
VFDTRACE(0, ("@=%s\n", guid_str));
ret = RegSetValueEx(hKey, NULL, NULL, REG_SZ,
(PBYTE)guid_str, strlen(guid_str) + 1);
RegCloseKey(hKey);
if (ret != ERROR_SUCCESS) {
return ret;
}
}
//
// Register property sheet handler
//
VFDTRACE(0, ("HKCR\\" VFDEXT_PROP_REGKEY "\n"));
ret = RegCreateKeyEx(
HKEY_CLASSES_ROOT, VFDEXT_PROP_REGKEY, 0, NULL,
0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
if (ret != ERROR_SUCCESS) {
return ret;
}
VFDTRACE(0, ("@=%s\n", guid_str));
ret = RegSetValueEx(hKey, NULL, NULL, REG_SZ,
(PBYTE)guid_str, strlen(guid_str) + 1);
RegCloseKey(hKey);
if (ret != ERROR_SUCCESS) {
return ret;
}
//
// Register approved extensions entry
//
VFDTRACE(0, ("HKLM\\" REGKEY_APPROVED "\n"));
ret = RegCreateKeyEx(
HKEY_LOCAL_MACHINE, REGKEY_APPROVED,
0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
if (ret != ERROR_SUCCESS) {
return ret;
}
VFDTRACE(0,
("%s=" VFDEXT_DESCRIPTION "\n", guid_str));
ret = RegSetValueEx(hKey, guid_str, NULL, REG_SZ,
(PBYTE)VFDEXT_DESCRIPTION, sizeof(VFDEXT_DESCRIPTION));
RegCloseKey(hKey);
return ret;
}
//
// Unregister context menu handler
//
DWORD WINAPI VfdUnregisterHandlers()
{
TCHAR buf[MAX_PATH];
TCHAR guid_str[40];
HKEY hKey;
DWORD temp;
DWORD ret;
MakeGuidString(guid_str, CLSID_VfdShellExt);
sprintf(buf, "CLSID\\%s", guid_str);
VFDTRACE(0, ("HKCR\\%s\n", buf));
temp = sizeof(buf);
ret = RegQueryValue(HKEY_CLASSES_ROOT, buf, buf, (PLONG)&temp);
if (ret != ERROR_SUCCESS) {
return ret;
}
if (_stricmp(buf, VFDEXT_DESCRIPTION)) {
return ERROR_PATH_NOT_FOUND;
}
sprintf(buf, "CLSID\\%s\\InProcServer32", guid_str);
VFDTRACE(0, ("HKCR\\%s\n", buf));
ret = RegDeleteKey(HKEY_CLASSES_ROOT, buf);
if (ret != ERROR_SUCCESS) {
return ret;
}
sprintf(buf, "CLSID\\%s", guid_str);
VFDTRACE(0, ("HKCR\\%s\n", buf));
ret = RegDeleteKey(HKEY_CLASSES_ROOT, buf);
if (ret != ERROR_SUCCESS) {
return ret;
}
VFDTRACE(0, ("HKCR\\" VFDEXT_MENU_REGKEY "\n"));
ret = RegDeleteKey(HKEY_CLASSES_ROOT, VFDEXT_MENU_REGKEY);
if (ret != ERROR_SUCCESS) {
return ret;
}
if (!IS_WINDOWS_NT()) {
// Windows NT doesn't support Drag & Drop handlers ???
VFDTRACE(0, ("HKCR\\" VFDEXT_DND_REGKEY "\n"));
ret = RegDeleteKey(HKEY_CLASSES_ROOT, VFDEXT_DND_REGKEY);
if (ret != ERROR_SUCCESS) {
return ret;
}
}
VFDTRACE(0, ("HKCR\\" VFDEXT_PROP_REGKEY "\n"));
ret = RegDeleteKey(HKEY_CLASSES_ROOT, VFDEXT_PROP_REGKEY);
if (ret != ERROR_SUCCESS) {
return ret;
}
VFDTRACE(0, ("HKLM\\" REGKEY_APPROVED "\n"));
ret = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
REGKEY_APPROVED,
0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL);
if (ret != ERROR_SUCCESS) {
return ret;
}
ret = RegDeleteValue(hKey, guid_str);
RegCloseKey(hKey);
return ret;
}
//
// Check if context menu handler is registered
//
DWORD WINAPI VfdCheckHandlers()
{
TCHAR buf[MAX_PATH];
TCHAR guid_str[40];
DWORD temp;
DWORD ret;
MakeGuidString(guid_str, CLSID_VfdShellExt);
sprintf(buf, "CLSID\\%s", guid_str);
VFDTRACE(0, ("HKCR\\%s\n", buf));
temp = sizeof(buf);
ret = RegQueryValue(HKEY_CLASSES_ROOT, buf, buf, (PLONG)&temp);
if (ret != ERROR_SUCCESS) {
return ret;
}
if (_stricmp(buf, VFDEXT_DESCRIPTION)) {
return ERROR_PATH_NOT_FOUND;
}
return ERROR_SUCCESS;
}

View file

@ -0,0 +1,422 @@
/*
vfdzip.c
Virtual Floppy Drive for Windows
Driver control library
Zip compressed floppy image handling
Copyright (C) 2003-2005 Ken Kato
*/
#ifdef __cplusplus
#pragma message(__FILE__": Compiled as C++ for testing purpose.")
#endif // __cplusplus
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "vfdtypes.h"
#include "vfdio.h"
#include "vfdlib.h"
#ifndef __REACTOS__
#define ZLIB_WINAPI
#else
#define Z_SOLO
#define ZLIB_INTERNAL
#endif
#include "zlib.h"
#ifdef VFD_NO_ZLIB
#pragma message("ZIP image support is disabled.")
DWORD ExtractZipInfo(
HANDLE hFile,
ULONG *pSize)
{
UNREFERENCED_PARAMETER(hFile);
UNREFERENCED_PARAMETER(pSize);
return ERROR_NOT_SUPPORTED;
}
DWORD ExtractZipImage(
HANDLE hFile,
PUCHAR *pBuffer,
PULONG pLength)
{
UNREFERENCED_PARAMETER(hFile);
UNREFERENCED_PARAMETER(pBuffer);
UNREFERENCED_PARAMETER(pLength);
return ERROR_NOT_SUPPORTED;
}
#else // VFD_NO_ZLIB
#ifdef _DEBUG
static const char *ZLIB_ERROR(int err)
{
switch (err) {
case Z_OK : return "Z_OK";
case Z_STREAM_END : return "Z_STREAM_END";
case Z_NEED_DICT : return "Z_NEED_DICT";
case Z_ERRNO : return "Z_ERRNO";
case Z_STREAM_ERROR : return "Z_STREAM_ERROR";
case Z_DATA_ERROR : return "Z_DATA_ERROR";
case Z_MEM_ERROR : return "Z_MEM_ERROR";
case Z_BUF_ERROR : return "Z_BUF_ERROR";
case Z_VERSION_ERROR: return "Z_VERSION_ERROR";
default : return "unknown";
}
}
#endif // _DEBUG
voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size))
{
UNREFERENCED_PARAMETER(opaque);
return LocalAlloc(LPTR, items * size);
}
void zcfree OF((voidpf opaque, voidpf ptr))
{
UNREFERENCED_PARAMETER(opaque);
LocalFree(ptr);
}
#define ZIP_LOCAL_SIGNATURE 0x04034b50
#define ZIP_FLAG_ENCRYPTED 0x01
#define ZIP_FLAG_DEFLATE_NORMAL 0x00
#define ZIP_FLAG_DEFLATE_MAX 0x02
#define ZIP_FLAG_DEFLATE_FAST 0x04
#define ZIP_FLAG_DEFLATE_SUPER 0x06
#define ZIP_FLAG_DEFLATE_MASK 0x06
#define ZIP_FLAG_SIZE_IN_DESC 0x08
#define ZIP_METHOD_STORED 0
#define ZIP_METHOD_SHRUNK 1
#define ZIP_METHOD_REDUCED1 2
#define ZIP_METHOD_REDUCED2 3
#define ZIP_METHOD_REDUCED3 4
#define ZIP_METHOD_REDUCED4 5
#define ZIP_METHOD_IMPLODED 6
#define ZIP_METHOD_TOKENIZED 7
#define ZIP_METHOD_DEFLATED 8
#define ZIP_METHOD_DEFLATE64 9
#define ZIP_METHOD_PKWARE_IMP 10
#define ZIP_METHOD_RESERVED 11
#define ZIP_METHOD_BZIP2 12
#pragma pack(1)
typedef struct _zip_local_file_header {
ULONG header_signature;
USHORT required_version;
USHORT general_flags;
USHORT compression_method;
USHORT last_mod_time;
USHORT last_mod_date;
ULONG crc32;
ULONG compressed_size;
ULONG uncompressed_size;
USHORT file_name_length;
USHORT extra_field_length;
CHAR file_name[1];
// followed by extra field data, then compressed data
}
ZIP_HEADER, *PZIP_HEADER;
//
// Check if the file is ZIP compressed
//
DWORD ExtractZipInfo(
HANDLE hFile,
ULONG *pSize)
{
ZIP_HEADER zip_hdr;
DWORD result;
DWORD ret;
if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) != 0) {
ret = GetLastError();
VFDTRACE(0,
("SetFilePointer() - %s\n",
SystemMessage(ret)));
return ret;
}
if (!ReadFile(hFile, &zip_hdr, sizeof(zip_hdr), &result, NULL)) {
ret = GetLastError();
VFDTRACE(0,
("ReadFile() - %s\n",
SystemMessage(ret)));
return ret;
}
if (result != sizeof(zip_hdr) ||
zip_hdr.header_signature != ZIP_LOCAL_SIGNATURE ||
zip_hdr.compression_method != ZIP_METHOD_DEFLATED ||
(zip_hdr.general_flags & ZIP_FLAG_ENCRYPTED)) {
VFDTRACE(0,
("[VFD] Invalid ZIP file\n"));
return ERROR_INVALID_DATA;
}
// correct (and supported) ZIP header detected
*pSize = zip_hdr.uncompressed_size;
return ERROR_SUCCESS;
}
//
// Extract original data from IMZ file
//
DWORD ExtractZipImage(
HANDLE hFile,
PUCHAR *pBuffer,
PULONG pLength)
{
UCHAR buf[VFD_BYTES_PER_SECTOR];
DWORD result;
DWORD ret;
PZIP_HEADER zip_hdr;
ULONG compressed;
ULONG uncompressed;
PUCHAR file_cache;
z_stream stream;
int zlib_ret;
VFDTRACE(0,
("[VFD] VfdExtractImz - IN\n"));
*pBuffer = NULL;
*pLength = 0;
//
// Read PKZIP local file header of the first file in the file
// -- An IMZ file actually is just a ZIP file with a different
// extension, which contains a single floppy image file
//
if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) != 0) {
ret = GetLastError();
VFDTRACE(0,(
"SetFilePointer - %s", SystemMessage(ret)));;
return ret;
}
if (!ReadFile(hFile, buf, VFD_BYTES_PER_SECTOR, &result, NULL) ||
result < VFD_BYTES_PER_SECTOR) {
ret = GetLastError();
VFDTRACE(0,(
"ReadFile - %s", SystemMessage(ret)));;
return ret;
}
zip_hdr = (PZIP_HEADER)buf;
// check local file header signature
if (zip_hdr->header_signature != ZIP_LOCAL_SIGNATURE) {
VFDTRACE(0,
("[VFD] PKZIP header signature not found.\n"));
return ERROR_INVALID_DATA;
}
// check compression method
if (zip_hdr->compression_method != Z_DEFLATED) {
VFDTRACE(0,
("[VFD] Bad PKZIP compression method.\n"));
return ERROR_NOT_SUPPORTED;
}
if (zip_hdr->general_flags & 0x01) {
// encrypted zip not supported
VFDTRACE(0,
("[VFD] PKZIP encrypted.\n"));
return ERROR_NOT_SUPPORTED;
}
// check uncompressed image size
compressed = zip_hdr->compressed_size;
uncompressed = zip_hdr->uncompressed_size;
switch (uncompressed) {
case VFD_SECTOR_TO_BYTE(320):
case VFD_SECTOR_TO_BYTE(360):
case VFD_SECTOR_TO_BYTE(640):
case VFD_SECTOR_TO_BYTE(720):
case VFD_SECTOR_TO_BYTE(1280):
case VFD_SECTOR_TO_BYTE(1440):
case VFD_SECTOR_TO_BYTE(1640):
case VFD_SECTOR_TO_BYTE(2400):
case VFD_SECTOR_TO_BYTE(2880):
case VFD_SECTOR_TO_BYTE(3360):
case VFD_SECTOR_TO_BYTE(3444):
case VFD_SECTOR_TO_BYTE(5760):
break;
default:
VFDTRACE(0,
("[VFD] Unsupported image size %lu.\n",
uncompressed));
return ERROR_NOT_SUPPORTED;
}
// check local file header length
// -- Just for simplicity, the compressed data must start in the
// first sector in the file: this is not a problem in most cases.
if (FIELD_OFFSET(ZIP_HEADER, file_name) +
zip_hdr->file_name_length +
zip_hdr->extra_field_length >= VFD_BYTES_PER_SECTOR) {
VFDTRACE(0,
("[VFD] PKZIP header too long.\n"));
return ERROR_NOT_SUPPORTED;
}
// allocate memory to store uncompressed data
file_cache = (PUCHAR)LocalAlloc(LPTR, uncompressed);
if (!file_cache) {
VFDTRACE(0,
("[VFD] Failed to allocate file cache.\n"));
return ERROR_OUTOFMEMORY;
}
// initialize the zlib stream
ZeroMemory(&stream, sizeof(stream));
// set initial input data information
stream.next_in = (PUCHAR)zip_hdr->file_name +
zip_hdr->file_name_length + zip_hdr->extra_field_length;
stream.avail_in = VFD_BYTES_PER_SECTOR -
FIELD_OFFSET(ZIP_HEADER, file_name) -
zip_hdr->file_name_length - zip_hdr->extra_field_length;
// set output buffer information
stream.next_out = file_cache;
stream.avail_out = uncompressed;
zlib_ret = inflateInit2(&stream, -MAX_WBITS);
// negative MAX_WBITS value passed to the inflateInit2() function
// indicates that there is no zlib header.
// In this case inflate() function requires an extra "dummy" byte
// after the compressed stream in order to complete decompression
// and return Z_STREAM_END. However, both compressed and uncompressed
// data size are already known from the pkzip header, Z_STREAM_END
// is not absolutely necessary to know the completion of the operation.
if (zlib_ret != Z_OK) {
LocalFree(file_cache);
VFDTRACE(0,
("[VFD] inflateInit2() failed - %s.\n",
ZLIB_ERROR(zlib_ret)));
return ERROR_INVALID_FUNCTION;
}
for (;;) {
// uncompress current block
zlib_ret = inflate(&stream, Z_NO_FLUSH);
if (zlib_ret != Z_OK) {
if (zlib_ret == Z_STREAM_END) {
ret = ERROR_SUCCESS;
}
else {
VFDTRACE(0,
("[VFD] inflate() failed - %s.\n",
ZLIB_ERROR(zlib_ret)));
ret = ERROR_INVALID_FUNCTION;
}
break;
}
if (stream.total_out >= uncompressed) {
// uncompress completed - no need to wait for Z_STREAM_END
// (inflate() would return Z_STREAM_END on the next call)
ret = ERROR_SUCCESS;
break;
}
if (stream.total_in >= compressed) {
// somehow there is not enought compressed data
ret = ERROR_INVALID_FUNCTION;
break;
}
// read next block from file
if (!ReadFile(hFile, buf, VFD_BYTES_PER_SECTOR, &result, NULL) ||
result <= 0) {
ret = GetLastError();
VFDTRACE(0,
("[VFD] Read compressed data - %s.\n",
SystemMessage(ret)));
break;
}
stream.avail_in = result;
stream.next_in = buf;
}
// cleanup the zlib stream
inflateEnd(&stream);
// set the return information
if (ret == ERROR_SUCCESS) {
*pBuffer = file_cache;
*pLength = uncompressed;
}
else {
LocalFree(file_cache);
}
VFDTRACE(0,
("[VFD] VfdExtractImz - OUT\n"));
return ret;
}
#endif // VFD_NO_ZLIB