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
add_subdirectory(applications)
add_subdirectory(demos)
add_subdirectory(drivers)
+add_subdirectory(include)
add_subdirectory(lib)
add_subdirectory(templates)
add_subdirectory(touch)
add_subdirectory(uptime)
add_subdirectory(vcdcli)
+add_subdirectory(vfdcmd)
add_subdirectory(winspool_print)
add_subdirectory(y)
--- /dev/null
+
+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)
--- /dev/null
+/*
+ vfdcmd.c
+
+ Virtual Floppy Drive for Windows
+ Driver control program (console version)
+
+ Copyright (C) 2003-2008 Ken Kato
+*/
+
+#ifdef __cplusplus
+#pragma message(__FILE__": Compiled as C++ for testing purpose.")
+#endif // __cplusplus
+
+#define WIN32_LEAN_AND_MEAN
+#define _CRTDBG_MAP_ALLOC
+#include <windows.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <crtdbg.h>
+
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif // INVALID_FILE_ATTRIBUTES
+
+#include "vfdtypes.h"
+#include "vfdapi.h"
+#include "vfdver.h"
+#include "vfdmsg.h"
+
+//
+// current driver state
+//
+static DWORD driver_state = VFD_NOT_INSTALLED;
+
+//
+// interactive flag
+//
+static const char *help_progname = "VFD.EXE ";
+
+//
+// command functions return value
+//
+#define VFD_OK 0
+#define VFD_NG 1
+
+//
+// operation mode
+//
+#define OPERATION_ASK 0 // ask user on error
+#define OPERATION_QUIT 1 // quits on error
+#define OPERATION_FORCE 2 // force on error
+
+//
+// invalid target number
+//
+#define TARGET_NONE (ULONG)-1
+
+//
+// command processing functions
+//
+typedef int (*cmdfnc)(const char **args);
+
+static int Install(const char **args);
+static int Remove(const char **args);
+static int Config(const char **args);
+static int Start(const char **args);
+static int Stop(const char **args);
+static int Shell(const char **args);
+static int Open(const char **args);
+static int Close(const char **args);
+static int Save(const char **args);
+static int Protect(const char **args);
+static int Format(const char **args);
+static int Link(const char **args);
+static int Unlink(const char **args);
+static int Status(const char **args);
+static int Help(const char **args);
+static int Version(const char **args);
+
+//
+// Command table
+//
+static const struct {
+ char *cmd; // command string
+ int max_args; // maximum allowed number of argc
+ cmdfnc func; // command processing function
+ DWORD hint; // command hint message id
+}
+Commands[] = {
+ {"INSTALL", 2, Install, MSG_HINT_INSTALL},
+ {"REMOVE", 1, Remove, MSG_HINT_REMOVE },
+ {"CONFIG", 1, Config, MSG_HINT_CONFIG },
+ {"START", 0, Start, MSG_HINT_START },
+ {"STOP", 1, Stop, MSG_HINT_STOP },
+ {"SHELL", 1, Shell, MSG_HINT_SHELL },
+ {"OPEN", 6, Open, MSG_HINT_OPEN },
+ {"CLOSE", 2, Close, MSG_HINT_CLOSE },
+ {"SAVE", 3, Save, MSG_HINT_SAVE, },
+ {"PROTECT", 2, Protect, MSG_HINT_PROTECT},
+ {"FORMAT", 2, Format, MSG_HINT_FORMAT },
+ {"LINK", 3, Link, MSG_HINT_LINK },
+ {"ULINK", 1, Unlink, MSG_HINT_ULINK },
+ {"STATUS", 0, Status, MSG_HINT_STATUS },
+ {"HELP", 1, Help, MSG_HELP_HELP },
+ {"?", 1, Help, MSG_HELP_HELP },
+ {"VERSION", 0, Version, MSG_HINT_VERSION},
+ {0, 0, 0, 0}
+};
+
+//
+// Help message table
+//
+static const struct {
+ char *keyword; // help keyword
+ DWORD help; // help message id
+}
+HelpMsg[] = {
+ {"GENERAL", MSG_HELP_GENERAL},
+ {"CONSOLE", MSG_HELP_CONSOLE},
+ {"INSTALL", MSG_HELP_INSTALL},
+ {"REMOVE", MSG_HELP_REMOVE },
+ {"CONFIG", MSG_HELP_CONFIG },
+ {"START", MSG_HELP_START },
+ {"STOP", MSG_HELP_STOP },
+ {"SHELL", MSG_HELP_SHELL },
+ {"OPEN", MSG_HELP_OPEN },
+ {"CLOSE", MSG_HELP_CLOSE },
+ {"SAVE", MSG_HELP_SAVE },
+ {"PROTECT", MSG_HELP_PROTECT},
+ {"FORMAT", MSG_HELP_FORMAT },
+ {"LINK", MSG_HELP_LINK },
+ {"ULINK", MSG_HELP_ULINK },
+ {"STATUS", MSG_HELP_STATUS },
+ {"HELP", MSG_HELP_HELP },
+ {"VERSION", MSG_HINT_VERSION},
+ {0, 0}
+};
+
+//
+// local functions
+//
+static int InteractiveConsole();
+static int ProcessCommandLine(int argc, const char **args);
+static int ParseCommand(const char *cmd);
+static int ParseHelpTopic(const char *topic);
+static int CheckDriver();
+static int InputChar(ULONG msg, PCSTR ans);
+static void PrintImageInfo(HANDLE hDevice);
+static void PrintDriveLetter(HANDLE hDevice, ULONG nDrive);
+static void PrintMessage(UINT msg, ...);
+static BOOL ConsolePager(char *pBuffer, BOOL bReset);
+static const char *SystemError(DWORD err);
+static void ConvertPathCase(char *src, char *dst);
+
+//
+// utility macro
+//
+#define IS_WINDOWS_NT() ((GetVersion() & 0xff) < 5)
+
+//
+// main
+//
+int main(int argc, const char **argv)
+{
+#ifdef _DEBUG
+
+ // output vfd.exe command reference text
+
+ if (*(argv + 1) && !_stricmp(*(argv + 1), "doc")) {
+ int idx = 0;
+ char *buf = "";
+
+ printf("\r\n VFD.EXE Command Reference\r\n");
+
+ while (HelpMsg[idx].keyword) {
+ int len = strlen(HelpMsg[idx].keyword);
+
+ printf(
+ "\r\n\r\n"
+ "====================\r\n"
+ "%*s\r\n"
+ "====================\r\n"
+ "\r\n",
+ (20 + len) / 2, HelpMsg[idx].keyword);
+
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_HMODULE |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ NULL, HelpMsg[idx].help, 0,
+ (LPTSTR)&buf, 0, (va_list *)&help_progname);
+
+ printf("%s", buf);
+
+ LocalFree(buf);
+
+ idx++;
+ }
+
+ return 0;
+ }
+#endif
+
+ // Reports memory leaks at process termination
+
+ _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
+
+ // Check the operating system version
+
+ if (!VfdIsValidPlatform()) {
+ PrintMessage(MSG_WRONG_PLATFORM);
+ return VFD_NG;
+ }
+
+ if (argc < 2) {
+ // If no parameter is given, enter the interactive mode
+
+ return InteractiveConsole();
+ }
+ else {
+ // Perform a single operation
+
+ return ProcessCommandLine(argc - 1, argv + 1);
+ }
+}
+
+//
+// VFD interactive console
+//
+int InteractiveConsole()
+{
+ char input[1024]; // user input buffer
+
+ int argc; // number of args in the user input
+ char *args[10]; // args to pass to command functions
+
+ char sepa; // argument separator
+ char *p; // work pointer
+
+ // Disable the system default Ctrl+C handler
+
+ SetConsoleCtrlHandler(NULL, TRUE);
+
+ // Set the console title
+
+ SetConsoleTitle(VFD_PRODUCT_DESC);
+
+ // print version information and the console hint text
+
+ Version(NULL);
+
+ PrintMessage(MSG_CONSOLE_HINT);
+
+ // set interactive flag to exclude "VFD.EXE" from help text
+
+ help_progname = "";
+
+ // process user input
+
+ for (;;) {
+
+ // print the prompt
+
+ printf("[VFD] ");
+ fflush(stdout);
+
+ // read user input
+
+ fflush(stdin);
+ p = fgets(input, sizeof(input), stdin);
+
+ if (p == NULL) {
+
+ // most likely <ctrl+c>
+
+ printf("exit\n");
+ break;
+ }
+
+ // skip leading blank characters
+
+ while (*p == ' ' || *p == '\t' || *p == '\n') {
+ p++;
+ }
+
+ if (*p == '\0') {
+
+ // empty input
+
+ continue;
+ }
+
+ // handle external commands
+
+ if (!_strnicmp(p, "dir", 3) ||
+ !_strnicmp(p, "attrib", 6)) {
+
+ // special cases - frequently used commands
+ // pass these to system() even without '.'
+
+ system(p);
+ printf("\n");
+ continue;
+ }
+ else if (*p == '.') {
+
+ // external command
+
+ system(p + 1);
+ printf("\n");
+ continue;
+ }
+
+ // split the input line into parameters (10 parameters max)
+
+ argc = 0;
+ ZeroMemory(args, sizeof(args));
+
+ do {
+ // top of a parameter
+
+ args[argc++] = p;
+
+ // is the parameter quoted?
+
+ if (*p == '\"' || *p == '\'') {
+ sepa = *(p++);
+ }
+ else {
+ sepa = ' ';
+ }
+
+ // search the end of the parameter
+
+ while (*p && *p != '\n') {
+ if (sepa == ' ') {
+ if (*p == '\t' || *p == ' ') {
+ break; // tail of a non-quoted parameter
+ }
+ }
+ else {
+ if (*p == sepa) {
+ sepa = ' '; // close quote
+ }
+ }
+ p++;
+ }
+
+ // terminate the parameter
+
+ if (*p) {
+ *(p++) = '\0';
+ }
+
+ // skip trailing blank characters
+
+ while (*p == ' ' || *p == '\t' || *p == '\n') {
+ p++;
+ }
+
+ if (*p == '\0') {
+
+ // end of the input line - no more args
+
+ break;
+ }
+ }
+ while (argc < sizeof(args) / sizeof(args[0]));
+
+ // check the first parameter for special commands
+
+ if (!_stricmp(args[0], "exit") ||
+ !_stricmp(args[0], "quit") ||
+ !_stricmp(args[0], "bye")) {
+
+ // exit command
+
+ break;
+ }
+ else if (!_stricmp(args[0], "cd") ||
+ !_stricmp(args[0], "chdir")) {
+
+ // internal change directory command
+
+ if (args[1]) {
+ char path[MAX_PATH];
+ int i;
+
+ // ignore the /d option (of the standard cd command)
+
+ if (_stricmp(args[1], "/d")) {
+ i = 1;
+ }
+ else {
+ i = 2;
+ }
+
+ p = args[i];
+
+ if (*p == '\"' || *p == '\'') {
+
+ // the parameter is quoted -- remove quotations
+
+ p++;
+
+ while (*p && *p != *args[i]) {
+ p++;
+ }
+
+ args[i]++; // skip a leading quote
+ *p = '\0'; // remove a trailing quote
+ }
+ else {
+
+ // the parameter is not quoted
+ // -- concatenate params to allow spaces in unquoted path
+
+ while (i < argc - 1) {
+ *(args[i] + strlen(args[i])) = ' ';
+ i++;
+ }
+ }
+
+ // Match the case of the path to the name on the disk
+
+ ConvertPathCase(p, path);
+
+ if (!SetCurrentDirectory(path)) {
+ DWORD ret = GetLastError();
+
+ if (ret == ERROR_FILE_NOT_FOUND) {
+ ret = ERROR_PATH_NOT_FOUND;
+ }
+
+ printf("%s", SystemError(ret));
+ }
+ }
+ else {
+ if (!GetCurrentDirectory(sizeof(input), input)) {
+ printf("%s", SystemError(GetLastError()));
+ }
+ else {
+ printf("%s\n", input);
+ }
+ }
+ }
+ else if (isalpha(*args[0]) &&
+ *(args[0] + 1) == ':' &&
+ *(args[0] + 2) == '\0') {
+
+ // internal change drive command
+
+ *args[0] = (char)toupper(*args[0]);
+ *(args[0] + 2) = '\\';
+ *(args[0] + 3) = '\0';
+
+ if (!SetCurrentDirectory(args[0])) {
+ printf("%s", SystemError(GetLastError()));
+ }
+ }
+ else {
+
+ // perform the requested VFD command
+
+ ProcessCommandLine(argc, (const char **)args);
+ }
+
+ printf("\n");
+ }
+
+ return VFD_OK;
+}
+
+//
+// process a single command
+//
+int ProcessCommandLine(int argc, const char **args)
+{
+ int cmd;
+ DWORD ret;
+
+ //
+ // Decide a command to perform
+ //
+ cmd = ParseCommand(*args);
+
+ if (cmd < 0) {
+
+ // no matching command
+
+ return VFD_NG;
+ }
+
+ if (*(++args) &&
+ (!strcmp(*args, "/?") ||
+ !_stricmp(*args, "/h"))) {
+
+ // print a short hint for the command
+
+ PrintMessage(Commands[cmd].hint);
+ return VFD_NG;
+ }
+
+ if (--argc > Commands[cmd].max_args) {
+
+ // too many parameters for the command
+
+ PrintMessage(MSG_TOO_MANY_ARGS);
+ PrintMessage(Commands[cmd].hint);
+ return VFD_NG;
+ }
+
+ // Get the current driver state
+
+ ret = VfdGetDriverState(&driver_state);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_GET_STAT_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ // Perform the requested operation
+
+ return (*Commands[cmd].func)(args);
+}
+
+//
+// Install the Virtual Floppy Driver
+// Command Line Parameters:
+// (optional) driver file path - default to executive's dir
+// (optional) auto start switch - default to demand start
+//
+int Install(const char **args)
+{
+ const char *install_path = NULL;
+ DWORD start_type = SERVICE_DEMAND_START;
+
+ DWORD ret;
+
+ // process parameters
+
+ while (args && *args) {
+
+ if (!_stricmp(*args, "/a") ||
+ !_stricmp(*args, "/auto")) {
+
+ if (start_type != SERVICE_DEMAND_START) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+/*
+ if (IS_WINDOWS_NT()) {
+
+ // On Windows NT, SYSTEM start drivers must be placed
+ // under the winnt\system32 directory. Since I don't
+ // care to handle driver file copying, I use the AUTO
+ // start method for Windows NT.
+
+ start_type = SERVICE_AUTO_START;
+ }
+ else {
+
+ // On Windows XP, the VFD driver must be running when
+ // the shell starts -- otherwise the shell doesn't
+ // recognize the VFD drives. Since Windows XP allows
+ // SYSTEM start drivers to be placed in any local
+ // directories, I use the SYSTEM start method here.
+ //
+ // This is not an issue when the driver is started
+ // manually because in that case VFD.EXE and VFDWIN.EXE
+ // notify the shell of the VFD drives.
+ //
+ // On Windows 2000 both SYSTEM and AUTO work fine.
+
+ start_type = SERVICE_SYSTEM_START;
+ }
+*/
+ // On second thought -- Win2K / XP mount manager assigns
+ // arbitrary drive letters to all drives it finds during
+ // the system start up. There is no way to prevent it
+ // until the driver is fully PnP compatible, so I'd settle
+ // for AUTO start for the time being.
+
+ start_type = SERVICE_AUTO_START;
+ }
+ else if (**args == '/') {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_INSTALL, help_progname);
+ return VFD_NG;
+ }
+ else {
+ if (install_path) {
+ PrintMessage(MSG_DUPLICATE_ARGS, "path");
+ return VFD_NG;
+ }
+
+ install_path = *args;
+ }
+
+ args++;
+ }
+
+ // already installed?
+
+ if (driver_state != VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_DRIVER_EXISTS);
+ return VFD_NG;
+ }
+
+ // install the driver
+
+ ret = VfdInstallDriver(
+ install_path,
+ start_type);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_INSTALL_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ // Get the latest driver state
+
+ ret = VfdGetDriverState(&driver_state);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_GET_STAT_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ // operation successfull
+
+ PrintMessage(MSG_INSTALL_OK);
+
+ return VFD_OK;
+}
+
+//
+// Remove Virtual Floppy Driver from system
+// Command Line Parameters:
+// [/F | /FORCE | /Q | /QUIT]
+// /F forces remove operation if the driver cannot be stopped
+// /Q quits remove operation if the driver cannot be stopped
+//
+int Remove(const char **args)
+{
+ int mode = OPERATION_ASK;
+ const char *stop_params[] = { NULL, NULL };
+ DWORD ret;
+ int idx;
+
+ // parse parameters
+
+ while (args && *args) {
+
+ if (!_stricmp(*args, "/f") ||
+ !_stricmp(*args, "/force")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_FORCE;
+ stop_params[0] = *args;
+ }
+ else if (!_stricmp(*args, "/q") ||
+ !_stricmp(*args, "/quit")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_QUIT;
+ stop_params[0] = *args;
+ }
+ else {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_REMOVE, help_progname);
+ return VFD_NG;
+ }
+
+ args++;
+ }
+
+ // ensure the driver is installed
+
+ if (driver_state == VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_NOT_INSTALLED);
+ return VFD_NG;
+ }
+
+ // ensure the driver is stopped
+
+ if (driver_state == SERVICE_RUNNING) {
+
+ // Try to stop with the same command line option (/F or /Q)
+
+ while (Stop(stop_params) != VFD_OK) {
+
+ // stop failed
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_REMOVE_FORCE);
+ break;
+ }
+ else if (mode == OPERATION_QUIT) {
+ PrintMessage(MSG_REMOVE_QUIT);
+ return VFD_NG;
+ }
+ else {
+ int c;
+
+ PrintMessage(MSG_REMOVE_WARN);
+
+ c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc");
+
+ if (c == 'f') { // force
+ break;
+ }
+ else if (c == 'c') { // cancel
+ return VFD_NG;
+ }
+ }
+ }
+ }
+
+ // remove the driver
+
+ ret = VfdRemoveDriver();
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_REMOVE_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ // Wait for the driver to be actually removed for 3 secs Max.
+
+ for (idx = 0; idx < 10; idx++) {
+
+ ret = VfdGetDriverState(&driver_state);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_GET_STAT_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ if (driver_state == VFD_NOT_INSTALLED) {
+ break;
+ }
+
+ Sleep(300);
+ }
+
+ if (driver_state != VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_REMOVE_PENDING);
+ return VFD_NG;
+ }
+
+ // operation successful
+
+ PrintMessage(MSG_REMOVE_OK);
+
+ return VFD_OK;
+}
+
+//
+// Configure the Virtual Floppy Driver
+// Command Line Parameters:
+// /auto, /manual
+//
+int Config(const char **args)
+{
+ DWORD start_type = SERVICE_DISABLED;
+ DWORD ret;
+
+ while (args && *args) {
+ if (!_stricmp(*args, "/a") ||
+ !_stricmp(*args, "/auto")) {
+
+ if (start_type != SERVICE_DISABLED) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ start_type = SERVICE_AUTO_START;
+ }
+ else if (!_stricmp(*args, "/m") ||
+ !_stricmp(*args, "/manual")) {
+
+ if (start_type != SERVICE_DISABLED) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ start_type = SERVICE_DEMAND_START;
+ }
+ else {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_CONFIG, help_progname);
+ return VFD_NG;
+ }
+
+ args++;
+ }
+
+ if (start_type == SERVICE_DISABLED) {
+ // no parameter is specified
+ PrintMessage(MSG_HINT_CONFIG, help_progname);
+ return VFD_NG;
+ }
+
+ // ensure that the driver is installed
+
+ if (driver_state == VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_NOT_INSTALLED);
+ return VFD_NG;
+ }
+
+ // ensure that the driver is up to date
+
+ if (CheckDriver() != VFD_OK) {
+ return VFD_NG;
+ }
+
+ // configure the driver
+
+ ret = VfdConfigDriver(start_type);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_CONFIG_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ // operation successfull
+
+ PrintMessage(MSG_CONFIG_OK);
+
+ return VFD_OK;
+}
+
+//
+// Start the Virtual Floppy Driver
+// Command Line Parameters: None
+//
+int Start(const char **args)
+{
+ DWORD ret;
+
+ UNREFERENCED_PARAMETER(args);
+
+ // ensure that the driver is installed
+
+ if (driver_state == VFD_NOT_INSTALLED &&
+ Install(NULL) != VFD_OK) {
+ return VFD_NG;
+ }
+
+ // ensure that the driver is up to date
+
+ if (CheckDriver() != VFD_OK) {
+ return VFD_NG;
+ }
+
+ // ensure that the driver is not running
+
+ if (driver_state == SERVICE_RUNNING) {
+ PrintMessage(MSG_ALREADY_RUNNING);
+ return VFD_NG;
+ }
+
+ // start the driver
+
+ ret = VfdStartDriver(&driver_state);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_START_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ // operation successfull
+
+ PrintMessage(MSG_START_OK);
+
+ return VFD_OK;
+}
+
+//
+// Stop the Virtual Floppy Driver
+// Command Line Parameters:
+// /FORCE | /F Forces the operation on error
+// /QUIT | /Q Quits the operation on error
+//
+int Stop(const char **args)
+{
+ int mode = OPERATION_ASK;
+ const char *close_params[] = { "*", NULL, NULL };
+ DWORD ret;
+
+ while (args && *args) {
+ if (!_stricmp(*args, "/f") ||
+ !_stricmp(*args, "/force")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_FORCE;
+
+ // parameter to pass to the Close() function
+ close_params[1] = *args;
+ }
+ else if (!_stricmp(*args, "/q") ||
+ !_stricmp(*args, "/quit")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_QUIT;
+
+ // parameter to pass to the Close() function
+ close_params[1] = *args;
+ }
+ else {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_STOP, help_progname);
+ return VFD_NG;
+ }
+
+ args++;
+ }
+
+ // ensure that the driver is installed
+
+ if (driver_state == VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_NOT_INSTALLED);
+ return VFD_NG;
+ }
+
+ // ensure that the driver is running
+
+ if (driver_state == SERVICE_STOPPED) {
+ PrintMessage(MSG_NOT_STARTED);
+ return VFD_NG;
+ }
+
+ // ensure that all drives are empty
+
+ if (driver_state == SERVICE_RUNNING) {
+
+ // Try to close drives with the same operation mode (/F or /Q)
+
+ while (Close(close_params) != VFD_OK) {
+
+ // close failed
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_STOP_FORCE);
+ break;
+ }
+ else if (mode == OPERATION_QUIT) {
+ PrintMessage(MSG_STOP_QUIT);
+ return VFD_NG;
+ }
+ else {
+ int c;
+
+ PrintMessage(MSG_STOP_WARN);
+
+ c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc");
+
+ if (c == 'f') { // force
+ break;
+ }
+ else if (c == 'c') { // cancel
+ return VFD_NG;
+ }
+ }
+ }
+ }
+
+ // stop the driver
+
+ ret = VfdStopDriver(&driver_state);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_STOP_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ if (driver_state != SERVICE_STOPPED) {
+ PrintMessage(MSG_STOP_PENDING);
+ return VFD_NG;
+ }
+
+ // operation successful
+
+ PrintMessage(MSG_STOP_OK);
+
+ return VFD_OK;
+}
+
+//
+// Enable / Disable the shell extension
+// Command Line Parameters:
+// (optional) /ON or /OFF
+//
+int Shell(const char **args)
+{
+ DWORD ret;
+
+ ret = VfdCheckHandlers();
+
+ if (ret != ERROR_SUCCESS &&
+ ret != ERROR_PATH_NOT_FOUND &&
+ ret != ERROR_FILE_NOT_FOUND) {
+ PrintMessage(MSG_GET_SHELLEXT_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ if (args && *args) {
+ if (_stricmp(*args, "/on") == 0) {
+ if (ret != ERROR_SUCCESS) {
+ ret = VfdRegisterHandlers();
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_SET_SHELLEXT_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+ }
+ }
+ else if (_stricmp(*args, "/off") == 0) {
+ if (ret == ERROR_SUCCESS) {
+ ret = VfdUnregisterHandlers();
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_SET_SHELLEXT_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+ }
+ }
+ else {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_SHELL, help_progname);
+ return VFD_NG;
+ }
+
+ ret = VfdCheckHandlers();
+ }
+
+ if (ret == ERROR_PATH_NOT_FOUND ||
+ ret == ERROR_FILE_NOT_FOUND) {
+ PrintMessage(MSG_SHELLEXT_DISABLED);
+ }
+ else if (ret == ERROR_SUCCESS) {
+ PrintMessage(MSG_SHELLEXT_ENABLED);
+ }
+ else {
+ PrintMessage(MSG_GET_SHELLEXT_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ return VFD_OK;
+}
+
+//
+// Open an image file to a Virtual Floppy Drive
+// Command Line Parameters:
+// [drive:] [file] [/NEW] [/RAM] [/P | /W]
+// [/size] [/media] [/F | /FORCE | /Q | /QUIT]
+
+int Open(const char **args)
+{
+ int mode = OPERATION_ASK;
+ BOOL create = FALSE;
+ ULONG target = TARGET_NONE;
+ PCSTR file_name = NULL;
+ VFD_DISKTYPE disk_type = VFD_DISKTYPE_FILE;
+ CHAR protect = '\0';
+ VFD_MEDIA media_type = VFD_MEDIA_NONE;
+ BOOL five_inch = FALSE;
+ VFD_FLAGS media_flags = 0;
+ HANDLE hDevice;
+ CHAR letter;
+ DWORD ret;
+
+ // process parameters
+
+ while (args && *args) {
+
+ if (!_stricmp(*args, "/f") ||
+ !_stricmp(*args, "/force")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_FORCE;
+ }
+ else if (!_stricmp(*args, "/q") ||
+ !_stricmp(*args, "/quit")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_QUIT;
+ }
+
+ else if (!_stricmp(*args, "/new")) {
+
+ if (create) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ create = TRUE;
+ }
+
+ // Disk type options
+
+ else if (_stricmp(*args, "/ram") == 0) {
+
+ if (disk_type != VFD_DISKTYPE_FILE) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ disk_type = VFD_DISKTYPE_RAM;
+ }
+
+ // Protect options
+ else if (_stricmp(*args, "/p") == 0 ||
+ _stricmp(*args, "/w") == 0) {
+
+ if (protect) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ protect = (CHAR)toupper(*(*args + 1));
+ }
+
+ // media size options
+
+ else if (strcmp(*args, "/160") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F5_160;
+ }
+ else if (strcmp(*args, "/180") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F5_180;
+ }
+ else if (strcmp(*args, "/320") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F5_320;
+ }
+ else if (strcmp(*args, "/360") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F5_360;
+ }
+ else if (strcmp(*args, "/640") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F3_640;
+ }
+ else if (strcmp(*args, "/720") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F3_720;
+ }
+ else if (strcmp(*args, "/820") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F3_820;
+ }
+ else if (strcmp(*args, "/120") == 0 ||
+ strcmp(*args, "/1.20") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F3_1P2;
+ }
+ else if (strcmp(*args, "/144") == 0 ||
+ strcmp(*args, "/1.44") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F3_1P4;
+ }
+ else if (strcmp(*args, "/168") == 0 ||
+ strcmp(*args, "/1.68") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F3_1P6;
+ }
+ else if (strcmp(*args, "/172") == 0 ||
+ strcmp(*args, "/1.72") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F3_1P7;
+ }
+ else if (strcmp(*args, "/288") == 0 ||
+ strcmp(*args, "/2.88") == 0) {
+ if (media_type) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ media_type = VFD_MEDIA_F3_2P8;
+ }
+
+ // 5.25 inch media
+
+ else if (strcmp(*args, "/5") == 0 ||
+ strcmp(*args, "/525") == 0 ||
+ strcmp(*args, "/5.25") == 0) {
+
+ if (five_inch) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ five_inch = TRUE;
+ }
+
+ // target option
+
+ else if (isalnum(**args) &&
+ *(*args + 1) == ':' &&
+ *(*args + 2) == '\0') {
+
+ if (target != TARGET_NONE) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ target = toupper(**args);
+ }
+
+ // filename
+
+ else if (**args != '/') {
+ if (file_name) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ file_name = *args;
+ }
+ else {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_OPEN, help_progname);
+ return VFD_NG;
+ }
+
+ args++;
+ }
+
+ if (target == TARGET_NONE) {
+ // default target
+ target = '0';
+ PrintMessage(MSG_TARGET_NOTICE, target);
+ }
+
+ // check target file
+
+ if (file_name) {
+ DWORD file_attr;
+ VFD_FILETYPE file_type;
+ ULONG image_size;
+ BOOL overwrite = FALSE;
+
+ ret = VfdCheckImageFile(
+ file_name, &file_attr, &file_type, &image_size);
+
+ if (ret == ERROR_FILE_NOT_FOUND) {
+
+ // the target file does not exist
+
+ if (!create) { // create option not specified
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_CREATE_NOTICE);
+ }
+ else {
+ printf("%s", SystemError(ret));
+
+ if (mode == OPERATION_QUIT ||
+ InputChar(MSG_CREATE_CONFIRM, "yn") == 'n') {
+ return VFD_NG;
+ }
+ }
+
+ create = TRUE;
+ }
+ }
+ else if (ret == ERROR_SUCCESS) {
+
+ // the target file exists
+
+ if (create) { // create option is specified
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_OVERWRITE_NOTICE);
+ }
+ else {
+ printf("%s", SystemError(ERROR_FILE_EXISTS));
+
+ if (mode == OPERATION_QUIT ||
+ InputChar(MSG_OVERWRITE_CONFIRM, "yn") == 'n') {
+ return VFD_NG;
+ }
+ }
+
+ overwrite = TRUE;
+ }
+ }
+ else {
+ PrintMessage(MSG_OPEN_NG, file_name);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ //
+ // create or overwrite the target file
+ //
+
+ if (create) {
+
+ if (media_type == VFD_MEDIA_NONE) {
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_CREATE144_NOTICE);
+ }
+ else {
+ PrintMessage(MSG_FILE_MEDIA_UNKNOWN);
+
+ if (mode == OPERATION_QUIT ||
+ InputChar(MSG_CREATE144_CONFIRM, "yn") == 'n') {
+ return VFD_NG;
+ }
+ }
+
+ media_type = VFD_MEDIA_F3_1P4;
+ }
+
+ ret = VfdCreateImageFile(
+ file_name, media_type, VFD_FILETYPE_RAW, overwrite);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_CREATE_NG, file_name);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ PrintMessage(MSG_FILE_CREATED);
+
+ ret = VfdCheckImageFile(
+ file_name, &file_attr, &file_type, &image_size);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_OPEN_NG, file_name);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+ }
+ else {
+ //
+ // use the existing target file
+ // check image size and the media type
+ //
+
+ VFD_MEDIA def_media; // default media for image size
+ ULONG media_size; // specified media size
+
+ media_size = VfdGetMediaSize(media_type);
+
+ if (media_size > image_size) {
+
+ // specified media is too large for the image
+
+ PrintMessage(MSG_IMAGE_TOO_SMALL);
+ return VFD_NG;
+ }
+
+ def_media = VfdLookupMedia(image_size);
+
+ if (def_media == VFD_MEDIA_NONE) {
+
+ // image is too small for the smallest media
+
+ PrintMessage(MSG_IMAGE_TOO_SMALL);
+ return VFD_NG;
+ }
+
+ if (media_type == VFD_MEDIA_NONE) {
+
+ // media type is not specified
+
+ ULONG def_size = VfdGetMediaSize(def_media);
+
+ if (def_size != image_size) {
+
+ // image size does not match the largest media size
+
+ PrintMessage(MSG_NO_MATCHING_MEDIA, image_size);
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_MEDIATYPE_NOTICE,
+ VfdMediaTypeName(def_media), def_size);
+ }
+ else if (mode == OPERATION_QUIT) {
+ return VFD_NG;
+ }
+ else {
+ PrintMessage(MSG_MEDIATYPE_SUGGEST,
+ VfdMediaTypeName(def_media), def_size);
+
+ if (InputChar(MSG_MEDIATYPE_CONFIRM, "yn") == 'n') {
+ return VFD_NG;
+ }
+ }
+ }
+
+ media_type = def_media;
+ }
+ }
+
+ // check file attributes against the disk type
+
+ if (file_type == VFD_FILETYPE_ZIP ||
+ (file_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_ENCRYPTED))) {
+
+ if (disk_type != VFD_DISKTYPE_RAM) {
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_RAM_MODE_NOTICE);
+ }
+ else {
+ PrintMessage(MSG_RAM_MODE_ONLY);
+
+ if (mode == OPERATION_QUIT ||
+ InputChar(MSG_RAM_MODE_CONFIRM, "yn") == 'n') {
+ return VFD_NG;
+ }
+ }
+
+ disk_type = VFD_DISKTYPE_RAM;
+ }
+ }
+
+ if (disk_type != VFD_DISKTYPE_FILE) {
+ if (!protect) {
+ PrintMessage(MSG_DEFAULT_PROTECT);
+ protect = 'P';
+ }
+ }
+ }
+ else {
+ //
+ // pure RAM disk
+ //
+ disk_type = VFD_DISKTYPE_RAM;
+
+ if (media_type == VFD_MEDIA_NONE) {
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_CREATE144_NOTICE);
+ }
+ else {
+ PrintMessage(MSG_RAM_MEDIA_UNKNOWN);
+
+ if (mode == OPERATION_QUIT ||
+ InputChar(MSG_CREATE144_CONFIRM, "yn") == 'n') {
+ return VFD_NG;
+ }
+ }
+
+ media_type = VFD_MEDIA_F3_1P4;
+ }
+ }
+
+ if (protect == 'P') {
+ media_flags |= VFD_FLAG_WRITE_PROTECTED;
+ }
+
+ if (five_inch &&
+ VfdGetMediaSize(media_type) ==
+ VfdGetMediaSize((VFD_MEDIA)(media_type + 1))) {
+ media_type = (VFD_MEDIA)(media_type + 1);
+ }
+
+ // ensure that the driver is installed
+
+ if (driver_state == VFD_NOT_INSTALLED &&
+ Install(NULL) != VFD_OK) {
+ return VFD_NG;
+ }
+
+ // ensure that the driver is up to date
+
+ if (CheckDriver() != VFD_OK) {
+ return VFD_NG;
+ }
+
+ // ensure that the driver is running
+
+ if (driver_state != SERVICE_RUNNING &&
+ Start(NULL) != VFD_OK) {
+ return VFD_NG;
+ }
+
+ // Open the target device
+
+ hDevice = VfdOpenDevice(target);
+
+ if (hDevice == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+ PrintMessage(MSG_ACCESS_NG, target);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ // Ensure that the drive is empty
+
+ ret = VfdGetMediaState(hDevice);
+
+ if (ret != ERROR_NOT_READY) {
+ if (ret == ERROR_SUCCESS ||
+ ret == ERROR_WRITE_PROTECT) {
+ PrintMessage(MSG_DRIVE_BUSY);
+ }
+ else {
+ PrintMessage(MSG_GET_MEDIA_NG);
+ printf("%s", SystemError(ret));
+ }
+
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+
+ // Open the image file
+
+ ret = VfdOpenImage(hDevice, file_name,
+ disk_type, media_type, media_flags);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_OPEN_NG, file_name ? file_name : "<RAM>");
+ printf("%s", SystemError(ret));
+
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+
+ // assign a drive letter if the drive has none
+
+ VfdGetGlobalLink(hDevice, &letter);
+
+ if (!isalpha(letter)) {
+ VfdGetLocalLink(hDevice, &letter);
+ }
+
+ if (!isalpha(letter)) {
+ VfdSetLocalLink(hDevice, VfdChooseLetter());
+ }
+
+ // Get the actually opened image information.
+
+ PrintImageInfo(hDevice);
+
+ CloseHandle(hDevice);
+
+ return VFD_OK;
+}
+
+//
+// Close the current virtual floppy image
+// Command Line Parameters:
+// drive number or drive letter
+// /F | /FORCE | /Q | /QUIT
+//
+int Close(const char **args)
+{
+ ULONG mode = OPERATION_ASK;
+
+ ULONG target_min = TARGET_NONE;
+ ULONG target_max = TARGET_NONE;
+ HANDLE hDevice;
+
+ VFD_MEDIA media_type;
+ VFD_FLAGS media_flags;
+
+ DWORD ret;
+
+ // check parameterS
+
+ while (args && *args) {
+
+ if (!_stricmp(*args, "/f") ||
+ !_stricmp(*args, "/force")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_FORCE;
+ }
+ else if (!_stricmp(*args, "/q") ||
+ !_stricmp(*args, "/quit")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_QUIT;
+ }
+ else if ((isalnum(**args) || **args == '*') &&
+ (*(*args + 1) == ':' || *(*args + 1) == '\0')) {
+
+ if (target_min != TARGET_NONE) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ if (**args == '*') {
+ target_min = '0';
+ target_max = '0' + VFD_MAXIMUM_DEVICES;
+ }
+ else {
+ target_min = toupper(**args);
+ target_max = target_min + 1;
+ }
+ }
+ else {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_CLOSE, help_progname);
+ return VFD_NG;
+ }
+
+ args++;
+ }
+
+ if (target_min == TARGET_NONE) {
+ // default target = drive 0
+ target_min = '0';
+ target_max = '1';
+ PrintMessage(MSG_TARGET_NOTICE, target_min);
+ }
+
+ // ensure that the driver is installed
+
+ if (driver_state == VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_NOT_INSTALLED);
+ return VFD_NG;
+ }
+
+ // ensure that the driver is running
+
+ if (driver_state != SERVICE_RUNNING) {
+ PrintMessage(MSG_NOT_STARTED);
+ return VFD_NG;
+ }
+
+ // Close the drive(s)
+
+ while (target_min < target_max) {
+
+ // open the target device
+
+ hDevice = VfdOpenDevice(target_min);
+
+ if (hDevice == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+
+ PrintMessage(MSG_ACCESS_NG, target_min);
+ printf("%s", SystemError(ret));
+
+ if (mode != OPERATION_FORCE) {
+ return VFD_NG;
+ }
+
+ target_min++;
+ continue;
+ }
+
+ // get the current image information
+
+ ret = VfdGetImageInfo(hDevice, NULL, NULL,
+ &media_type, &media_flags, NULL, NULL);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_ACCESS_NG, target_min);
+ printf("%s", SystemError(ret));
+
+ CloseHandle(hDevice);
+
+ if (mode != OPERATION_FORCE) {
+ return VFD_NG;
+ }
+
+ target_min++;
+ continue;
+ }
+
+ if (media_type == VFD_MEDIA_NONE) {
+
+ // drive is empty
+
+ CloseHandle(hDevice);
+ target_min++;
+ continue;
+ }
+
+ if (media_flags & VFD_FLAG_DATA_MODIFIED) {
+
+ // RAM disk data is modified
+
+ PrintMessage(MSG_MEDIA_MODIFIED, target_min);
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_CLOSE_FORCE);
+ }
+ else if (mode == OPERATION_QUIT) {
+ PrintMessage(MSG_CLOSE_QUIT);
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+ else {
+ if (InputChar(MSG_CLOSE_CONFIRM, "yn") == 'n') {
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+ }
+ }
+
+retry:
+ ret = VfdCloseImage(
+ hDevice, (mode == OPERATION_FORCE));
+
+ if (ret == ERROR_ACCESS_DENIED) {
+
+ PrintMessage(MSG_LOCK_NG, target_min);
+
+ if (mode == OPERATION_QUIT) {
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+ else if (mode == OPERATION_ASK) {
+
+ int c;
+
+ if (IS_WINDOWS_NT()) {
+ c = InputChar(MSG_RETRY_CANCEL, "rc");
+ }
+ else {
+ c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc");
+ }
+
+ if (c == 'f') { // force
+ ret = VfdCloseImage(hDevice, TRUE);
+ }
+ else if (c == 'c') { // cancel
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+ else {
+ goto retry;
+ }
+ }
+ }
+
+ CloseHandle(hDevice);
+
+ if (ret == ERROR_SUCCESS) {
+ PrintMessage(MSG_CLOSE_OK, target_min);
+ }
+ else if (ret != ERROR_NOT_READY) {
+ PrintMessage(MSG_CLOSE_NG, target_min);
+ printf("%s", SystemError(ret));
+
+ if (mode != OPERATION_FORCE) {
+ return VFD_NG;
+ }
+ }
+
+ target_min++;
+ }
+
+ return VFD_OK;
+}
+
+//
+// Save the current image into a file
+//
+int Save(const char **args)
+{
+ int mode = OPERATION_ASK;
+ ULONG target = TARGET_NONE;
+ CHAR file_name[MAX_PATH] = {0};
+ BOOL overwrite = FALSE;
+ BOOL truncate = FALSE;
+
+ HANDLE hDevice;
+ CHAR current[MAX_PATH] = {0};
+ VFD_MEDIA media_type;
+ VFD_FLAGS media_flags;
+ VFD_FILETYPE file_type;
+ DWORD file_attr;
+ ULONG image_size;
+ DWORD ret;
+
+ // check parameters
+
+ while (args && *args) {
+
+ if (!_stricmp(*args, "/f") ||
+ !_stricmp(*args, "/force")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_FORCE;
+ }
+ else if (!_stricmp(*args, "/q") ||
+ !_stricmp(*args, "/quit")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_QUIT;
+ }
+ else if (!_stricmp(*args, "/o") ||
+ !_stricmp(*args, "/over")) {
+
+ if (truncate || overwrite) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ overwrite = TRUE;
+ }
+ else if (!_stricmp(*args, "/t") ||
+ !_stricmp(*args, "/trunc")) {
+
+ if (truncate || overwrite) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ truncate = TRUE;
+ }
+ else if (isalnum(**args) &&
+ *(*args + 1) == ':' &&
+ *(*args + 2) == '\0') {
+
+ if (target != TARGET_NONE) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ target = toupper(**args);
+ }
+ else if (**args == '/') {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_SAVE, help_progname);
+ return VFD_NG;
+ }
+ else {
+ strcpy(file_name, *args);
+ }
+
+ args++;
+ }
+
+ if (target == TARGET_NONE) {
+ target = '0';
+ PrintMessage(MSG_TARGET_NOTICE, target);
+ }
+
+ // ensure that the driver is installed
+
+ if (driver_state == VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_NOT_INSTALLED);
+ return VFD_NG;
+ }
+
+ // ensure that the driver is up to date
+
+ if (CheckDriver() != VFD_OK) {
+ return VFD_NG;
+ }
+
+ // ensure that the driver is running
+
+ if (driver_state != SERVICE_RUNNING) {
+ PrintMessage(MSG_NOT_STARTED);
+ return VFD_NG;
+ }
+
+ // Open the target device
+
+ hDevice = VfdOpenDevice(target);
+
+ if (hDevice == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+ PrintMessage(MSG_ACCESS_NG, target);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ // Get the current image info
+
+ ret = VfdGetImageInfo(hDevice, current, NULL,
+ &media_type, &media_flags, NULL, NULL);
+
+ if (ret != ERROR_SUCCESS) {
+ printf("%s", SystemError(ret));
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+
+ if (media_type == VFD_MEDIA_NONE) {
+ printf("%s", SystemError(ERROR_NOT_READY));
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+
+ if (file_name[0] == '\0') {
+
+ if (current[0] == '\0') {
+
+ PrintMessage(MSG_TARGET_REQUIRED);
+ CloseHandle(hDevice);
+
+ return VFD_NG;
+ }
+
+ strcpy(file_name, current);
+ }
+
+ if (!_stricmp(file_name, current)) {
+
+ // target is the current image file
+
+ if (!(media_flags & VFD_FLAG_DATA_MODIFIED)) {
+
+ // FILE disk (always up to date) or RAM disk is not modified
+
+ PrintMessage(MSG_TARGET_UP_TO_DATE);
+ CloseHandle(hDevice);
+
+ return VFD_OK;
+ }
+
+ overwrite = TRUE;
+ }
+
+ // check target file
+
+ ret = VfdCheckImageFile(file_name,
+ &file_attr, &file_type, &image_size);
+
+ if (ret == ERROR_SUCCESS) {
+
+ if (!overwrite && !truncate) {
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_OVERWRITE_NOTICE);
+ overwrite = TRUE;
+ }
+ else if (mode == OPERATION_QUIT) {
+ printf("%s", SystemError(ERROR_FILE_EXISTS));
+ CloseHandle(hDevice);
+
+ return VFD_NG;
+ }
+ else {
+ int c;
+
+ printf("%s", SystemError(ERROR_FILE_EXISTS));
+
+ c = InputChar(MSG_OVERWRITE_PROMPT, "otc");
+
+ if (c == 'o') {
+ overwrite = TRUE;
+ }
+ else if (c == 't') {
+ truncate = TRUE;
+ }
+ else {
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+ }
+ }
+ }
+ else if (ret != ERROR_FILE_NOT_FOUND) {
+
+ printf("%s", SystemError(ret));
+ CloseHandle(hDevice);
+
+ return VFD_NG;
+ }
+
+ if (file_type == VFD_FILETYPE_ZIP) {
+
+ // Cannot update a zip file
+
+ PrintMessage(MSG_TARGET_IS_ZIP);
+ CloseHandle(hDevice);
+
+ return VFD_NG;
+ }
+
+retry:
+ ret = VfdDismountVolume(
+ hDevice, (mode == OPERATION_FORCE));
+
+ if (ret == ERROR_ACCESS_DENIED) {
+
+ PrintMessage(MSG_LOCK_NG, target);
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_SAVE_FORCE);
+ }
+ else if (mode == OPERATION_QUIT) {
+ PrintMessage(MSG_SAVE_QUIT);
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+ else {
+ int c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc");
+
+ if (c == 'r') { // retry
+ goto retry;
+ }
+ else if (c == 'f') { // force
+ VfdDismountVolume(hDevice, TRUE);
+ }
+ else { // cancel
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+ }
+ }
+ else if (ret != ERROR_SUCCESS) {
+ printf("%s", SystemError(ret));
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+
+ ret = VfdSaveImage(hDevice, file_name,
+ (overwrite || truncate), truncate);
+
+ CloseHandle(hDevice);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_SAVE_NG, target, file_name);
+ printf("%s", SystemError(ret));
+
+ return VFD_NG;
+ }
+
+ PrintMessage(MSG_SAVE_OK, target, file_name);
+
+ return VFD_OK;
+}
+
+//
+// Enable/disable virtual media write protection
+//
+int Protect(const char **args)
+{
+#define PROTECT_NONE 0
+#define PROTECT_ON 1
+#define PROTECT_OFF 2
+ ULONG protect = PROTECT_NONE;
+ ULONG target = TARGET_NONE;
+ HANDLE hDevice;
+ DWORD ret;
+
+ // check parameters
+
+ while (args && *args) {
+
+ // Disk type options
+
+ if (_stricmp(*args, "/on") == 0) {
+
+ if (protect) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ protect = PROTECT_ON;
+ }
+ else if (_stricmp(*args, "/off") == 0) {
+
+ if (protect) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ protect = PROTECT_OFF;
+ }
+ else if (isalnum(**args)) {
+
+ if (target != TARGET_NONE) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ target = toupper(**args);
+ }
+ else {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_PROTECT, help_progname);
+ return VFD_NG;
+ }
+
+ args++;
+ }
+
+ if (target == TARGET_NONE) {
+ target = '0';
+ PrintMessage(MSG_TARGET_NOTICE, target);
+ }
+
+ // ensure that the driver is installed
+
+ if (driver_state == VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_NOT_INSTALLED);
+ return VFD_NG;
+ }
+
+ // ensure that the driver is up to date
+
+ if (CheckDriver() != VFD_OK) {
+ return VFD_NG;
+ }
+
+ // ensure that the driver is running
+
+ if (driver_state != SERVICE_RUNNING) {
+ PrintMessage(MSG_NOT_STARTED);
+ return VFD_NG;
+ }
+
+ // open the target drive
+
+ hDevice = VfdOpenDevice(target);
+
+ if (hDevice == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+ PrintMessage(MSG_ACCESS_NG, target);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ if (protect) {
+ // change protect state
+
+ ret = VfdWriteProtect(
+ hDevice, (protect == PROTECT_ON));
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_PROTECT_NG, target);
+ printf("%s", SystemError(ret));
+
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+ }
+
+ // get the current protect state
+
+ ret = VfdGetMediaState(hDevice);
+
+ CloseHandle(hDevice);
+
+ if (ret == ERROR_SUCCESS) {
+ PrintMessage(MSG_MEDIA_WRITABLE);
+ }
+ else if (ret == ERROR_WRITE_PROTECT) {
+ PrintMessage(MSG_MEDIA_PROTECTED);
+ }
+ else {
+ PrintMessage(MSG_GET_MEDIA_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ return VFD_OK;
+}
+
+//
+// Format the virtual media with FAT12
+//
+int Format(const char **args)
+{
+ int mode = OPERATION_ASK;
+ ULONG target = TARGET_NONE;
+ HANDLE hDevice;
+ DWORD ret;
+
+ // check parameters
+
+ while (args && *args) {
+
+ if (!_stricmp(*args, "/f") ||
+ !_stricmp(*args, "/force")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_FORCE;
+ }
+ else if (!_stricmp(*args, "/q") ||
+ !_stricmp(*args, "/quit")) {
+
+ if (mode != OPERATION_ASK) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ mode = OPERATION_QUIT;
+ }
+ else if (isalnum(**args)) {
+ if (target != TARGET_NONE) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ target = toupper(**args);
+ }
+ else {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_FORMAT, help_progname);
+ return VFD_NG;
+ }
+
+ args++;
+ }
+
+ if (target == TARGET_NONE) {
+ target = '0';
+ PrintMessage(MSG_TARGET_NOTICE, target);
+ }
+
+ // ensure that the driver is installed
+
+ if (driver_state == VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_NOT_INSTALLED);
+ return VFD_NG;
+ }
+
+ // ensure that the driver is up to date
+
+ if (CheckDriver() != VFD_OK) {
+ return VFD_NG;
+ }
+
+ // ensure that the driver is running
+
+ if (driver_state != SERVICE_RUNNING) {
+ PrintMessage(MSG_NOT_STARTED);
+ return VFD_NG;
+ }
+
+ // Open the device
+
+ hDevice = VfdOpenDevice(target);
+
+ if (hDevice == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+ PrintMessage(MSG_ACCESS_NG, target);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ // check if the media is writable
+
+ ret = VfdGetMediaState(hDevice);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_FORMAT_NG, target);
+ printf("%s", SystemError(ret));
+
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+
+ // format the media
+
+retry:
+ ret = VfdDismountVolume(
+ hDevice, (mode == OPERATION_FORCE));
+
+ if (ret == ERROR_ACCESS_DENIED) {
+
+ PrintMessage(MSG_LOCK_NG, target);
+
+ if (mode == OPERATION_FORCE) {
+ PrintMessage(MSG_FORMAT_FORCE);
+ }
+ else if (mode == OPERATION_QUIT) {
+ PrintMessage(MSG_FORMAT_QUIT);
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+ else {
+ int c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc");
+
+ if (c == 'r') { // retry
+ goto retry;
+ }
+ else if (c == 'f') { // force
+ VfdDismountVolume(hDevice, TRUE);
+ }
+ else { // cancel
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+ }
+ }
+ else if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_LOCK_NG, target);
+ CloseHandle(hDevice);
+ return VFD_NG;
+ }
+
+ ret = VfdFormatMedia(hDevice);
+
+ CloseHandle(hDevice);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_FORMAT_NG, target);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ // successful operation
+
+ PrintMessage(MSG_FORMAT_OK);
+
+ return VFD_OK;
+}
+
+//
+// Assign a drive letter to a Virtual Floppy Drive
+//
+int Link(const char **args)
+{
+ ULONG target_min = TARGET_NONE;
+ ULONG target_max = TARGET_NONE;
+ PCSTR letters = NULL;
+ BOOL global = TRUE;
+ HANDLE hDevice;
+ DWORD ret;
+
+ while (args && *args) {
+ if (!_stricmp(*args, "/g")) {
+ global = TRUE;
+ }
+ else if (!_stricmp(*args, "/l")) {
+ global = FALSE;
+ }
+ else if (isdigit(**args) || **args == '*') {
+ if (target_min != TARGET_NONE) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ if (**args == '*') {
+ target_min = '0';
+ target_max = '0' + VFD_MAXIMUM_DEVICES;
+ }
+ else {
+ target_min = **args;
+ target_max = target_min + 1;
+ }
+ }
+ else if (isalpha(**args)) {
+ if (letters) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+ letters = *args;
+ }
+ else {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_LINK, help_progname);
+ return VFD_NG;
+ }
+
+ args++;
+ }
+
+ if (target_min == TARGET_NONE) {
+ // default: drive 0
+ target_min = '0';
+ target_max = '1';
+ PrintMessage(MSG_TARGET_NOTICE, target_min);
+ }
+
+ // ensure that the driver is installed
+
+ if (driver_state == VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_NOT_INSTALLED);
+ return VFD_NG;
+ }
+
+ // ensure that the driver is up to date
+
+ if (CheckDriver() != VFD_OK) {
+ return VFD_NG;
+ }
+
+ // ensure that the driver is running
+
+ if (driver_state != SERVICE_RUNNING) {
+ PrintMessage(MSG_NOT_STARTED);
+ return VFD_NG;
+ }
+
+ while (target_min < target_max) {
+ ULONG number;
+ CHAR letter;
+
+ hDevice = VfdOpenDevice(target_min);
+
+ if (hDevice == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+ PrintMessage(MSG_ACCESS_NG, target_min);
+ printf("%s", SystemError(ret));
+ target_min++;
+ continue;
+ }
+
+ ret = VfdGetDeviceNumber(hDevice, &number);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_ACCESS_NG, target_min);
+ printf("%s", SystemError(ret));
+ CloseHandle(hDevice);
+ target_min++;
+ continue;
+ }
+
+ if (letters && isalpha(*letters)) {
+ letter = (CHAR)toupper(*(letters++));
+ }
+ else {
+ letter = VfdChooseLetter();
+ }
+
+ if (letter) {
+ if (global) {
+ ret = VfdSetGlobalLink(hDevice, letter);
+ }
+ else {
+ ret = VfdSetLocalLink(hDevice, letter);
+ }
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_LINK_NG, number, letter);
+ printf("%s", SystemError(ret));
+ }
+ }
+ else {
+ PrintMessage(MSG_LINK_FULL);
+ }
+
+ PrintDriveLetter(hDevice, number);
+
+ CloseHandle(hDevice);
+
+ target_min++;
+ }
+
+ return VFD_OK;
+}
+
+//
+// Remove a drive letter from a Virtual Floppy Drive
+//
+int Unlink(const char **args)
+{
+ ULONG target_min = TARGET_NONE;
+ ULONG target_max = TARGET_NONE;
+ HANDLE hDevice;
+ DWORD ret;
+
+ while (args && *args) {
+ if ((isalnum(**args) || **args == '*') &&
+ (*(*args + 1) == ':' || *(*args + 1) == '\0')) {
+
+ if (target_min != TARGET_NONE) {
+ PrintMessage(MSG_DUPLICATE_ARGS, *args);
+ return VFD_NG;
+ }
+
+ if (**args == '*') {
+ target_min = '0';
+ target_max = '0' + VFD_MAXIMUM_DEVICES;
+ }
+ else {
+ target_min = **args;
+ target_max = target_min + 1;
+ }
+ }
+ else {
+ PrintMessage(MSG_UNKNOWN_OPTION, *args);
+ PrintMessage(MSG_HINT_ULINK, help_progname);
+ return VFD_NG;
+ }
+
+ args++;
+ }
+
+ if (target_min == TARGET_NONE) {
+ // default: drive 0
+ target_min = '0';
+ target_max = '1';
+ PrintMessage(MSG_TARGET_NOTICE, target_min);
+ }
+
+ // ensure that the driver is installed
+
+ if (driver_state == VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_NOT_INSTALLED);
+ return VFD_NG;
+ }
+
+ // ensure that the driver is up to date
+
+ if (CheckDriver() != VFD_OK) {
+ return VFD_NG;
+ }
+
+ // ensure that the driver is running
+
+ if (driver_state != SERVICE_RUNNING) {
+ PrintMessage(MSG_NOT_STARTED);
+ return VFD_NG;
+ }
+
+ while (target_min < target_max) {
+ ULONG number;
+
+ hDevice = VfdOpenDevice(target_min);
+
+ if (hDevice == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+ PrintMessage(MSG_ACCESS_NG, target_min);
+ printf("%s", SystemError(ret));
+ target_min++;
+ continue;
+ }
+
+ ret = VfdGetDeviceNumber(hDevice, &number);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_ACCESS_NG, target_min);
+ printf("%s", SystemError(ret));
+ CloseHandle(hDevice);
+ target_min++;
+ continue;
+ }
+
+ VfdSetGlobalLink(hDevice, 0);
+ VfdSetLocalLink(hDevice, 0);
+
+ PrintDriveLetter(hDevice, number);
+
+ CloseHandle(hDevice);
+
+ target_min++;
+ }
+
+ return VFD_OK;
+}
+
+//
+// Print current driver state
+// Command Line Parameters: None
+//
+int Status(const char **args)
+{
+ HANDLE hDevice;
+ TCHAR path[MAX_PATH];
+ DWORD start_type;
+ DWORD version;
+ ULONG target;
+ DWORD ret;
+
+ UNREFERENCED_PARAMETER(args);
+
+ if (driver_state == VFD_NOT_INSTALLED) {
+ PrintMessage(MSG_NOT_INSTALLED);
+ }
+ else {
+
+ // get current driver config
+
+ ret = VfdGetDriverConfig(path, &start_type);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_GET_CONFIG_NG);
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ // print driver file path
+
+ PrintMessage(MSG_DRIVER_FILE, path);
+
+ // print driver version
+ version = 0;
+
+ if (driver_state == SERVICE_RUNNING) {
+
+ hDevice = VfdOpenDevice(0);
+
+ if (hDevice != INVALID_HANDLE_VALUE) {
+ ret = VfdGetDriverVersion(hDevice, &version);
+
+ CloseHandle(hDevice);
+ }
+
+ }
+
+ if (version == 0) {
+ ret = VfdCheckDriverFile(path, &version);
+ }
+
+ if (ret == ERROR_SUCCESS) {
+ PrintMessage(MSG_DRIVER_VERSION,
+ HIWORD(version) & 0x7fff,
+ LOWORD(version),
+ (version & 0x80000000) ? "(debug)" : "");
+ }
+ else {
+ PrintMessage(MSG_GET_VERSION_NG);
+ printf("%s", SystemError(ret));
+ }
+
+
+ // print driver start type
+
+ PrintMessage(MSG_START_TYPE);
+
+ switch (start_type) {
+ case SERVICE_AUTO_START:
+ PrintMessage(MSG_START_AUTO);
+ break;
+
+ case SERVICE_BOOT_START:
+ PrintMessage(MSG_START_BOOT);
+ break;
+
+ case SERVICE_DEMAND_START:
+ PrintMessage(MSG_START_DEMAND);
+ break;
+
+ case SERVICE_DISABLED:
+ PrintMessage(MSG_START_DISABLED);
+ break;
+
+ case SERVICE_SYSTEM_START :
+ PrintMessage(MSG_START_SYSTEM);
+ break;
+
+ default:
+ PrintMessage(MSG_UNKNOWN_LONG, start_type);
+ break;
+ }
+
+ // print current driver state
+
+ PrintMessage(MSG_DRIVER_STATUS);
+
+ switch (driver_state) {
+ case SERVICE_STOPPED:
+ PrintMessage(MSG_STATUS_STOPPED);
+ break;
+
+ case SERVICE_START_PENDING:
+ PrintMessage(MSG_STATUS_START_P);
+ break;
+
+ case SERVICE_STOP_PENDING:
+ PrintMessage(MSG_STATUS_STOP_P);
+ break;
+
+ case SERVICE_RUNNING:
+ PrintMessage(MSG_STATUS_RUNNING);
+ break;
+
+ case SERVICE_CONTINUE_PENDING:
+ PrintMessage(MSG_STATUS_CONT_P);
+ break;
+
+ case SERVICE_PAUSE_PENDING:
+ PrintMessage(MSG_STATUS_PAUSE_P);
+ break;
+
+ case SERVICE_PAUSED:
+ PrintMessage(MSG_STATUS_PAUSED);
+ break;
+
+ default:
+ PrintMessage(MSG_UNKNOWN_LONG, driver_state);
+ break;
+ }
+ }
+
+ // print shell extension status
+
+ printf("\n");
+
+ if (VfdCheckHandlers() == ERROR_SUCCESS) {
+ PrintMessage(MSG_SHELLEXT_ENABLED);
+ }
+ else {
+ PrintMessage(MSG_SHELLEXT_DISABLED);
+ }
+
+ // if driver is not running, no more info
+
+ if (driver_state != SERVICE_RUNNING) {
+ return VFD_OK;
+ }
+
+ // print image information
+
+ for (target = 0; target < VFD_MAXIMUM_DEVICES; target++) {
+ HANDLE hDevice = VfdOpenDevice(target);
+
+ if (hDevice == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+ PrintMessage(MSG_ACCESS_NG, target + '0');
+ printf("%s", SystemError(ret));
+ return VFD_NG;
+ }
+
+ PrintImageInfo(hDevice);
+
+ CloseHandle(hDevice);
+ }
+
+ return VFD_OK;
+}
+
+//
+// Print usage help
+//
+int Help(const char **args)
+{
+ DWORD msg = MSG_HELP_GENERAL;
+ char *buf = NULL;
+
+ if (args && *args) {
+ int cmd = ParseHelpTopic(*args);
+
+ if (cmd < 0) {
+ msg = MSG_HELP_HELP;
+ }
+ else {
+ msg = HelpMsg[cmd].help;
+ }
+ }
+
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_HMODULE |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ NULL, msg, 0, (LPTSTR)&buf, 0,
+ (va_list *)&help_progname);
+
+ if (buf == NULL) {
+ printf("%s", SystemError(GetLastError()));
+ return VFD_NG;
+ }
+
+ ConsolePager(buf, TRUE);
+ LocalFree(buf);
+
+ return VFD_OK;
+}
+
+//
+// Print version information
+//
+int Version(const char **args)
+{
+ UNREFERENCED_PARAMETER(args);
+
+ printf(VFD_PRODUCT_DESC "\n" VFD_COPYRIGHT_STR "\n"
+ "http://chitchat.at.infoseek.co.jp/vmware/vfd.html\n");
+
+ return VFD_OK;
+}
+
+//
+// Parse command parameter
+//
+int ParseCommand(const char *cmd)
+{
+#define CMD_MATCH_NONE -1
+#define CMD_MATCH_MULTI -2
+
+ size_t len;
+ int idx;
+ int match;
+
+ // skip a leading '/'
+
+ if (*cmd == '/') {
+ cmd++;
+ }
+
+ if (*cmd == '\0') {
+
+ // empty command
+
+ return CMD_MATCH_NONE;
+ }
+
+ // find a match
+ len = strlen(cmd);
+ idx = 0;
+ match = CMD_MATCH_NONE;
+
+ while (Commands[idx].cmd) {
+
+ if (strlen(Commands[idx].cmd) >= len &&
+ !_strnicmp(cmd, Commands[idx].cmd, len)) {
+
+ if (match == CMD_MATCH_NONE) { // first match
+ match = idx;
+ }
+ else { // multiple matches
+ if (match != CMD_MATCH_MULTI) { // first time
+ PrintMessage(MSG_AMBIGUOUS_COMMAND, cmd);
+ printf("> %s ", Commands[match].cmd);
+ match = CMD_MATCH_MULTI;
+ }
+
+ printf("%s ", Commands[idx].cmd);
+ }
+ }
+
+ idx++;
+ }
+
+ if (match == CMD_MATCH_NONE) { // match not found
+ PrintMessage(MSG_UNKNOWN_COMMAND, cmd);
+ }
+ else if (match == CMD_MATCH_MULTI) { // multiple matches
+ printf("\n");
+ }
+
+ return match;
+}
+
+int ParseHelpTopic(const char *topic)
+{
+ size_t len;
+ int idx;
+ int match;
+
+ if (*topic == '\0') {
+
+ // empty command
+
+ return CMD_MATCH_NONE;
+ }
+
+ // find a match
+ len = strlen(topic);
+ idx = 0;
+ match = CMD_MATCH_NONE;
+
+ while (HelpMsg[idx].keyword) {
+
+ if (strlen(HelpMsg[idx].keyword) >= len &&
+ !_strnicmp(topic, HelpMsg[idx].keyword, len)) {
+
+ if (match == CMD_MATCH_NONE) { // first match
+ match = idx;
+ }
+ else { // multiple matches
+ if (match != CMD_MATCH_MULTI) { // first time
+ PrintMessage(MSG_AMBIGUOUS_COMMAND, topic);
+ printf("> %s ", HelpMsg[match].keyword);
+ match = CMD_MATCH_MULTI;
+ }
+
+ printf("%s ", HelpMsg[idx].keyword);
+ }
+ }
+
+ idx++;
+ }
+
+ if (match == CMD_MATCH_NONE) { // match not found
+ PrintMessage(MSG_UNKNOWN_COMMAND, topic);
+ }
+ else if (match == CMD_MATCH_MULTI) { // multiple matches
+ printf("\n");
+ }
+
+ return match;
+}
+
+//
+// Check driver version and update if necessary
+//
+int CheckDriver()
+{
+ char path[MAX_PATH];
+ DWORD start;
+
+ // check installed driver file version
+
+ if (VfdGetDriverConfig(path, &start) == ERROR_SUCCESS &&
+ VfdCheckDriverFile(path, NULL) == ERROR_SUCCESS) {
+
+ HANDLE hDevice;
+
+ if (driver_state != SERVICE_RUNNING) {
+ return VFD_OK;
+ }
+
+ // check running driver version
+
+ hDevice = VfdOpenDevice(0);
+
+ if (hDevice != INVALID_HANDLE_VALUE) {
+ CloseHandle(hDevice);
+ return VFD_OK;
+ }
+ }
+
+ PrintMessage(MSG_WRONG_DRIVER);
+ return VFD_NG;
+}
+
+//
+// Print a prompt message and accept the reply input
+//
+int InputChar(ULONG msg, PCSTR ans)
+{
+ HANDLE hStdIn;
+ INPUT_RECORD input;
+ DWORD result;
+ int reply;
+
+ PrintMessage(msg);
+ fflush(NULL);
+
+ hStdIn = GetStdHandle(STD_INPUT_HANDLE);
+
+ FlushConsoleInputBuffer(hStdIn);
+
+ for (;;) {
+ ReadConsoleInput(hStdIn, &input, sizeof(input), &result);
+
+ if (input.EventType == KEY_EVENT &&
+ input.Event.KeyEvent.bKeyDown) {
+
+ reply = tolower(input.Event.KeyEvent.uChar.AsciiChar);
+
+ if (strchr(ans, reply)) {
+ break;
+ }
+ }
+ }
+
+ printf("%c\n", reply);
+
+ return reply;
+}
+
+//
+// Print image information on a Virtual Floppy Drive
+//
+void PrintImageInfo(
+ HANDLE hDevice)
+{
+ ULONG device_number;
+ CHAR file_name[MAX_PATH];
+ CHAR file_desc[MAX_PATH];
+ VFD_DISKTYPE disk_type;
+ VFD_MEDIA media_type;
+ VFD_FLAGS media_flags;
+ VFD_FILETYPE file_type;
+ ULONG image_size;
+ DWORD ret;
+
+ printf("\n");
+
+ // get current device number
+
+ ret = VfdGetDeviceNumber(hDevice, &device_number);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_GET_LINK_NG);
+ printf("%s", SystemError(ret));
+ device_number = (ULONG)-1;
+ }
+
+ // get current drive letters
+
+ PrintDriveLetter(hDevice, device_number);
+
+ // image file information
+
+ ret = VfdGetImageInfo(hDevice, file_name, &disk_type,
+ &media_type, &media_flags, &file_type, &image_size);
+
+ if (ret != ERROR_SUCCESS) {
+ PrintMessage(MSG_GET_FILE_NG);
+ printf("%s", SystemError(ret));
+ return;
+ }
+
+ // print image file information
+ if (media_type == VFD_MEDIA_NONE) {
+ PrintMessage(MSG_IMAGE_NONE);
+ return;
+ }
+
+ if (file_name[0]) {
+ PrintMessage(MSG_IMAGE_NAME, file_name);
+
+ VfdMakeFileDesc(file_desc, sizeof(file_desc),
+ file_type, image_size, GetFileAttributes(file_name));
+ }
+ else {
+ PrintMessage(MSG_IMAGE_NAME, "<RAM>");
+
+ VfdMakeFileDesc(file_desc, sizeof(file_desc),
+ VFD_FILETYPE_NONE, image_size, 0);
+ }
+
+ PrintMessage(MSG_FILE_DESC, file_desc);
+
+ if (disk_type == VFD_DISKTYPE_FILE) {
+ PrintMessage(MSG_DISKTYPE_FILE);
+ }
+ else {
+ if (media_flags & VFD_FLAG_DATA_MODIFIED) {
+ PrintMessage(MSG_DISKTYPE_RAM_DIRTY);
+ }
+ else {
+ PrintMessage(MSG_DISKTYPE_RAM_CLEAN);
+ }
+ }
+
+ // print other file info
+
+ PrintMessage(MSG_MEDIA_TYPE, VfdMediaTypeName(media_type));
+
+ if (media_flags & VFD_FLAG_WRITE_PROTECTED) {
+ PrintMessage(MSG_MEDIA_PROTECTED);
+ }
+ else {
+ PrintMessage(MSG_MEDIA_WRITABLE);
+ }
+}
+
+//
+// Print drive letters on a virtual floppy drive
+//
+void PrintDriveLetter(
+ HANDLE hDevice,
+ ULONG nDrive)
+{
+ CHAR letter;
+
+ PrintMessage(MSG_DRIVE_LETTER, nDrive);
+
+ VfdGetGlobalLink(hDevice, &letter);
+
+ if (isalpha(letter)) {
+ PrintMessage(MSG_PERSISTENT, toupper(letter));
+ }
+
+ while (VfdGetLocalLink(hDevice, &letter) == ERROR_SUCCESS &&
+ isalpha(letter)) {
+ PrintMessage(MSG_EPHEMERAL, toupper(letter));
+ }
+
+ printf("\n");
+}
+
+//
+// Prints a text on screen a page a time
+//
+BOOL ConsolePager(char *pBuffer, BOOL bReset)
+{
+ static int rows = 0;
+ char prompt[80];
+ int prompt_len = 0;
+ HANDLE hStdOut;
+ HANDLE hStdIn;
+
+ //
+ // prepare the console input and output handles
+ //
+ hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ hStdIn = GetStdHandle(STD_INPUT_HANDLE);
+
+ for (;;) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ INPUT_RECORD input;
+ DWORD result;
+ DWORD mode;
+ int cols;
+ char *cur;
+ char save;
+
+ //
+ // Get the current console screen information
+ //
+ GetConsoleScreenBufferInfo(hStdOut, &info);
+
+ if (bReset || rows <= 0) {
+ rows = info.srWindow.Bottom - info.srWindow.Top - 1;
+ }
+
+ cols = info.dwSize.X;
+
+ // console window is too small for paging
+
+ if (rows <= 0) {
+ // print all text and exit
+ printf("%s", pBuffer);
+ break;
+ }
+
+ //
+ // find the tail of the text to be printed this time
+ //
+ cur = pBuffer;
+ save = '\0';
+
+ while (*cur) {
+ if (*(cur++) == '\n' || (cols--) == 0) {
+ // reached the end of a line
+ if (--rows == 0) {
+ // reached the end of a page
+ // insert a terminating NULL char
+ save = *cur;
+ *cur = '\0';
+ break;
+ }
+
+ cols = info.dwSize.X;
+ }
+ }
+
+ // print the current page
+ printf("%s", pBuffer);
+
+ // end of the whole text?
+ if (save == '\0') {
+ break;
+ }
+
+ //
+ // prompt for the next page
+ //
+
+ // prepare the prompt text
+
+ if (prompt_len == 0) {
+
+ prompt_len = FormatMessage(
+ FORMAT_MESSAGE_FROM_HMODULE |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, MSG_PAGER_PROMPT, 0,
+ prompt, sizeof(prompt), NULL);
+
+ if (prompt_len == 0) {
+ strcpy(prompt, "Press any key to continue...");
+ prompt_len = strlen(prompt);
+ }
+ }
+
+ // get the current console input mode
+
+ GetConsoleMode(hStdIn, &mode);
+
+ // change the mode to receive Ctrl+C as a regular input
+
+ SetConsoleMode(hStdIn, (mode & ~ENABLE_PROCESSED_INPUT));
+
+ // get the current cursor position
+
+ GetConsoleScreenBufferInfo(hStdOut, &info);
+
+ // print the prompt text
+
+ WriteConsoleOutputCharacter(hStdOut, prompt,
+ prompt_len, info.dwCursorPosition, &result);
+
+ // reverse the text color
+
+ FillConsoleOutputAttribute(hStdOut,
+ (WORD)(info.wAttributes | COMMON_LVB_REVERSE_VIDEO),
+ prompt_len, info.dwCursorPosition, &result);
+
+ // move cursor to the end of the prompt text
+
+ info.dwCursorPosition.X =
+ (short)(info.dwCursorPosition.X + prompt_len);
+
+ SetConsoleCursorPosition(hStdOut, info.dwCursorPosition);
+
+ // wait for a key press event
+
+ FlushConsoleInputBuffer(hStdIn);
+
+ do {
+ ReadConsoleInput(hStdIn, &input, sizeof(input), &result);
+ }
+ while (input.EventType != KEY_EVENT ||
+ !input.Event.KeyEvent.bKeyDown ||
+ !input.Event.KeyEvent.uChar.AsciiChar);
+
+ // restore the original cursor position
+
+ info.dwCursorPosition.X =
+ (short)(info.dwCursorPosition.X - prompt_len);
+
+ SetConsoleCursorPosition(hStdOut, info.dwCursorPosition);
+
+ // delete the prompt text
+
+ FillConsoleOutputCharacter(hStdOut, ' ',
+ prompt_len, info.dwCursorPosition, &result);
+
+ // restore the text attribute to norml
+
+ FillConsoleOutputAttribute(hStdOut, info.wAttributes,
+ prompt_len, info.dwCursorPosition, &result);
+
+ // restore the original console mode
+
+ SetConsoleMode(hStdIn, mode);
+
+ // check if the input was 'q', <esc> or <Ctrl+C> ?
+
+ if (input.Event.KeyEvent.uChar.AsciiChar == VK_CANCEL ||
+ input.Event.KeyEvent.uChar.AsciiChar == VK_ESCAPE ||
+ tolower(input.Event.KeyEvent.uChar.AsciiChar) == 'q') {
+
+ // cancelled by the user
+ return FALSE;
+ }
+
+ //
+ // process the next page
+ //
+ *cur = save;
+ pBuffer = cur;
+ }
+
+ return TRUE;
+}
+
+//
+// Format and print a message text
+//
+void PrintMessage(UINT msg, ...)
+{
+ char *buf = NULL;
+ va_list list;
+
+ va_start(list, msg);
+
+ if (FormatMessage(
+ FORMAT_MESSAGE_FROM_HMODULE |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL, msg, 0, (LPTSTR)&buf, 0, &list)) {
+
+ printf("%s", buf);
+ }
+ else {
+ printf("Unknown Message ID %u\n", msg);
+ }
+
+ va_end(list);
+
+ if (buf) {
+ LocalFree(buf);
+ }
+}
+
+//
+// Return a system error message text
+//
+const char *SystemError(DWORD err)
+{
+ static char msg[256];
+
+ if (!FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, err, 0, msg, sizeof(msg), NULL)) {
+#ifndef __REACTOS__
+ sprintf(msg, "Unknown system error %lu (0x%08x)\n", err, err);
+#else
+ sprintf(msg, "Unknown system error %lu (0x%08lx)\n", err, err);
+#endif
+ }
+
+ return msg;
+}
+
+//
+// Convert a path to match the case of names on the disk
+//
+void ConvertPathCase(char *src, char *dst)
+{
+ HANDLE hFind;
+ WIN32_FIND_DATA find;
+ char *p;
+
+ p = dst;
+
+ if (*src == '\"') {
+ src++;
+ }
+
+ if (*(src + strlen(src) - 1) == '\"') {
+ *(src + strlen(src) - 1) = '\0';
+ }
+
+ //
+ // handle drive / remote server name
+ //
+ if (isalpha(*src) && *(src + 1) == ':') {
+
+ // drive name
+
+ *(p++) = (char)toupper(*src);
+ strcpy(p++, ":\\");
+
+ src += 2;
+ }
+ else if (*src == '\\' || *src == '/') {
+
+ // absolute path or remote name
+
+ if ((*(src + 1) == '\\' || *(src + 1) == '/') &&
+ *(src + 2) && *(src + 2) != '\\' && *(src + 2) != '/') {
+
+ // remote path
+
+ *(p++) = '\\';
+ *(p++) = '\\';
+ src += 2;
+
+ while (*src && *src != '\\' && *src != '/') {
+ *(p++) = *(src++);
+ }
+ }
+
+ strcpy(p, "\\");
+ }
+ else {
+ *p = '\0';
+ }
+
+ // skip redundant '\'
+
+ while (*src == '\\' || *src == '/') {
+ src++;
+ }
+
+ // process the path
+
+ while (*src) {
+
+ char *q = src;
+
+ // separate the next part
+
+ while (*q && *q != '\\' && *q != '/') {
+ q++;
+ }
+
+ if ((q - src) == 2 && !strncmp(src, "..", 2)) {
+ // parent dir - copy as it is
+ if (p != dst) {
+ *p++ = '\\';
+ }
+
+ strcpy(p, "..");
+ p += 2;
+ }
+ else if ((q - src) > 1 || *src != '.') {
+ // path name other than "."
+ if (p != dst) {
+ *(p++) = '\\';
+ }
+
+ strncpy(p, src, (q - src));
+ *(p + (q - src)) = '\0';
+
+ hFind = FindFirstFile(dst, &find);
+
+ if (hFind == INVALID_HANDLE_VALUE) {
+ strcpy(p, src);
+ break;
+ }
+
+ FindClose(hFind);
+
+ strcpy(p, find.cFileName);
+ p += strlen(p);
+ }
+
+ // skip trailing '\'s
+
+ while (*q == '\\' || *q == '/') {
+ q++;
+ }
+
+ src = q;
+ }
+}
--- /dev/null
+#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>
--- /dev/null
+/*
+ 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 \83R\83\93\83\\81[\83\8b"
+#define VFD_PRODUCT_NAME_ALT VFD_PRODUCT_NAME
+
+#include "vfdver.rc"
+
+//
+// Message resource
+//
+#include "vfdmsg.rc"
+
+#endif // not APSTUDIO_INVOKED
--- /dev/null
+;/*
+; vfdmsg.h
+;
+; Virtual Floppy Drive for Windows
+; Driver control program (console version)
+; Message definition
+;
+; Copyright (C) 2003-2005 Ken Kato
+;*/
+;
+;#ifndef _VFDMSG_H_
+;#define _VFDMSG_H_
+;
+
+MessageIdTypedef=DWORD
+LanguageNames=(English=0x409:MSG0409)
+
+;//==============================================
+;// Generic error messages
+;//==============================================
+;
+
+MessageId=
+SymbolicName=MSG_WRONG_PLATFORM
+Language=English
+Virtual Floppy Drive does not run on Windows 95/98/Me.
+.
+
+
+MessageId=
+SymbolicName=MSG_TOO_MANY_ARGS
+Language=English
+Too many command line parameters.
+.
+
+
+MessageId=
+SymbolicName=MSG_UNKNOWN_COMMAND
+Language=English
+Command '%1!s!' is unknown.
+.
+
+
+MessageId=
+SymbolicName=MSG_AMBIGUOUS_COMMAND
+Language=English
+Command '%1!s!' is ambiguous.
+.
+
+
+MessageId=
+SymbolicName=MSG_UNKNOWN_OPTION
+Language=English
+Option '%1!s!' is unknown.
+.
+
+
+MessageId=
+SymbolicName=MSG_DUPLICATE_ARGS
+Language=English
+Parameter %1!s! is used more than once.
+.
+
+
+;//==============================================
+;// Command result message
+;//==============================================
+;
+
+MessageId=
+SymbolicName=MSG_INSTALL_OK
+Language=English
+Installed the Virtual Floppy driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_INSTALL_NG
+Language=English
+Failed to install the Virtual Floppy driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_CONFIG_OK
+Language=English
+Configured the Virtual Floppy driver start method.
+.
+
+
+MessageId=
+SymbolicName=MSG_CONFIG_NG
+Language=English
+Failed to configure the Virtual Floppy driver start method.
+.
+
+
+MessageId=
+SymbolicName=MSG_REMOVE_OK
+Language=English
+Uninstalled the Virtual Floppy driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_REMOVE_NG
+Language=English
+Failed to uninstall the Virtual Floppy driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_REMOVE_PENDING
+Language=English
+The Virtual Floppy driver is going to be removed on the next system start up.
+You may need to restart the system before installing the driver again.
+.
+
+
+MessageId=
+SymbolicName=MSG_START_OK
+Language=English
+Started the Virtual Floppy driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_START_NG
+Language=English
+Failed to start the Virtual Floppy driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_STOP_OK
+Language=English
+Stopped the Virtual Floppy driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_STOP_NG
+Language=English
+Failed to stop the Virtual Floppy driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_STOP_PENDING
+Language=English
+Stop operation has succeeded, but something
+is preventing the driver from actually stopping.
+You may need to reboot the system before restarting the driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_GET_SHELLEXT_NG
+Language=English
+Failed to get the shell extension status.
+.
+
+
+MessageId=
+SymbolicName=MSG_SET_SHELLEXT_NG
+Language=English
+Failed to set the shell extension status.
+.
+
+
+MessageId=
+SymbolicName=MSG_SHELLEXT_ENABLED
+Language=English
+Shell extension is enabled.
+.
+
+
+MessageId=
+SymbolicName=MSG_SHELLEXT_DISABLED
+Language=English
+Shell extension is disabled.
+.
+
+
+MessageId=
+SymbolicName=MSG_OPEN_NG
+Language=English
+Failed to open the image '%1!s!'.
+.
+
+
+MessageId=
+SymbolicName=MSG_CLOSE_OK
+Language=English
+Closed the image on the drive %1!c!.
+.
+
+
+MessageId=
+SymbolicName=MSG_CLOSE_NG
+Language=English
+Failed to close the image on the drive %1!c!.
+.
+
+
+MessageId=
+SymbolicName=MSG_SAVE_OK
+Language=English
+Saved the image on the drive %1!c! into '%2!s!'.
+.
+
+
+MessageId=
+SymbolicName=MSG_SAVE_NG
+Language=English
+Failed to save the image on the drive %1!c! into '%2!s!'.
+.
+
+
+MessageId=
+SymbolicName=MSG_PROTECT_NG
+Language=English
+Failed to set write protect state on the drive %1!c!.
+.
+
+
+MessageId=
+SymbolicName=MSG_FORMAT_OK
+Language=English
+Format complete.
+.
+
+
+MessageId=
+SymbolicName=MSG_FORMAT_NG
+Language=English
+Failed to format the drive %1!c!.
+.
+
+
+MessageId=
+SymbolicName=MSG_LINK_NG
+Language=English
+Failed to assign '%2!c!' to the drive %1!lu!.
+.
+
+
+MessageId=
+SymbolicName=MSG_UNLINK_NG
+Language=English
+Failed to unlink the letter from the drive %1!lu!.
+.
+
+
+;//==============================================
+;// Supplemental result message
+;//==============================================
+;
+
+MessageId=
+SymbolicName=MSG_GET_STAT_NG
+Language=English
+Failed to get the driver status.
+.
+
+
+MessageId=
+SymbolicName=MSG_GET_CONFIG_NG
+Language=English
+Failed to get the driver configuration.
+.
+
+
+MessageId=
+SymbolicName=MSG_GET_VERSION_NG
+Language=English
+Failed to get the driver version.
+.
+
+
+MessageId=
+SymbolicName=MSG_WRONG_DRIVER
+Language=English
+A wrong driver is installed.
+.
+
+
+MessageId=
+SymbolicName=MSG_QUERY_UPDATE
+Language=English
+Update now (y / n) ? %0
+.
+
+
+MessageId=
+SymbolicName=MSG_GET_MEDIA_NG
+Language=English
+Failed to get the current media status.
+.
+
+
+MessageId=
+SymbolicName=MSG_GET_FILE_NG
+Language=English
+Failed to get the image information.
+.
+
+
+MessageId=
+SymbolicName=MSG_GET_LINK_NG
+Language=English
+Failed to get the current drive letter.
+.
+
+
+MessageId=
+SymbolicName=MSG_LINK_FULL
+Language=English
+No drive letter is available.
+.
+
+
+MessageId=
+SymbolicName=MSG_ACCESS_NG
+Language=English
+Failed to access the drive %1!c!.
+.
+
+
+MessageId=
+SymbolicName=MSG_DRIVER_EXISTS
+Language=English
+The Virtual Floppy driver is already installed.
+.
+
+
+MessageId=
+SymbolicName=MSG_NOT_INSTALLED
+Language=English
+The Virtual Floppy driver is not installed.
+.
+
+
+MessageId=
+SymbolicName=MSG_ALREADY_RUNNING
+Language=English
+The Virtual Floppy driver is already running.
+.
+
+
+MessageId=
+SymbolicName=MSG_NOT_STARTED
+Language=English
+The Virtual Floppy driver is not running.
+.
+
+
+MessageId=
+SymbolicName=MSG_TARGET_NOTICE
+Language=English
+Using the default drive (%1!c!).
+.
+
+
+MessageId=
+SymbolicName=MSG_CREATE_NOTICE
+Language=English
+Creating a new image file.
+.
+
+
+MessageId=
+SymbolicName=MSG_CREATE_CONFIRM
+Language=English
+Create a new image file (Y:yes / N:no) ? %0
+.
+
+
+MessageId=
+SymbolicName=MSG_OVERWRITE_NOTICE
+Language=English
+Overwriting the existing file.
+.
+
+
+MessageId=
+SymbolicName=MSG_OVERWRITE_CONFIRM
+Language=English
+Overwrite the existing file (Y:yes / N:no) ? %0
+.
+
+
+MessageId=
+SymbolicName=MSG_CREATE_NG
+Language=English
+Failed to create the new image file '%1!s!'.
+.
+
+
+MessageId=
+SymbolicName=MSG_FILE_CREATED
+Language=English
+Created a new image file.
+.
+
+
+MessageId=
+SymbolicName=MSG_RAM_MEDIA_UNKNOWN
+Language=English
+A size is not specified for a new RAM image.
+.
+
+
+MessageId=
+SymbolicName=MSG_FILE_MEDIA_UNKNOWN
+Language=English
+A size is not specified for a new image file.
+.
+
+
+MessageId=
+SymbolicName=MSG_CREATE144_NOTICE
+Language=English
+Creating a 1.44MB image.
+.
+
+
+MessageId=
+SymbolicName=MSG_CREATE144_CONFIRM
+Language=English
+Create a 1.44MB image (Y:yes / N:no) ? %0
+.
+
+
+MessageId=
+SymbolicName=MSG_IMAGE_TOO_SMALL
+Language=English
+The image is too small.
+.
+
+
+MessageId=
+SymbolicName=MSG_NO_MATCHING_MEDIA
+Language=English
+The image size (%1!lu! bytes) does not match any supported media.
+.
+
+
+MessageId=
+SymbolicName=MSG_MEDIATYPE_NOTICE
+Language=English
+Opening as a %1!s! media (%2!lu! bytes).
+.
+
+
+MessageId=
+SymbolicName=MSG_MEDIATYPE_SUGGEST
+Language=English
+The largest possible media is %1!s! (%2!lu! bytes).
+.
+
+
+MessageId=
+SymbolicName=MSG_MEDIATYPE_CONFIRM
+Language=English
+Open as this media type (Y:yes / N:no) ? %0
+.
+
+
+MessageId=
+SymbolicName=MSG_RAM_MODE_NOTICE
+Language=English
+Opening the image in RAM mode.
+.
+
+
+MessageId=
+SymbolicName=MSG_RAM_MODE_ONLY
+Language=English
+This file must be opened in RAM mode.
+.
+
+
+MessageId=
+SymbolicName=MSG_RAM_MODE_CONFIRM
+Language=English
+Open in RAM mode (Y:yes / N:no) ? %0
+.
+
+
+MessageId=
+SymbolicName=MSG_DEFAULT_PROTECT
+Language=English
+The media will be write protected by default.
+.
+
+
+MessageId=
+SymbolicName=MSG_DRIVE_BUSY
+Language=English
+An image is already opened.
+.
+
+
+MessageId=
+SymbolicName=MSG_TARGET_REQUIRED
+Language=English
+Specify a target file to save.
+.
+
+
+MessageId=
+SymbolicName=MSG_TARGET_UP_TO_DATE
+Language=English
+The image file is up to date.
+.
+
+
+MessageId=
+SymbolicName=MSG_OVERWRITE_PROMPT
+Language=English
+Overwrite the existing file
+(O: just overwrite / T: overwrite & truncate / C: cancel) ? %0
+.
+
+
+MessageId=
+SymbolicName=MSG_TARGET_IS_ZIP
+Language=English
+Cannot overwrite a ZIP compressed file.
+.
+
+
+MessageId=
+SymbolicName=MSG_SAVE_FORCE
+Language=English
+The save operation is forced to continue.
+.
+
+
+MessageId=
+SymbolicName=MSG_SAVE_QUIT
+Language=English
+The save operation is aborted.
+.
+
+
+MessageId=
+SymbolicName=MSG_FORMAT_FORCE
+Language=English
+The format operation is forced to continue.
+.
+
+
+MessageId=
+SymbolicName=MSG_FORMAT_QUIT
+Language=English
+The format operation is aborted.
+.
+
+
+MessageId=
+SymbolicName=MSG_MEDIA_MODIFIED
+Language=English
+RAM disk data on the drive %1!c!: is modified.
+.
+
+
+MessageId=
+SymbolicName=MSG_CLOSE_FORCE
+Language=English
+The close operation is forced to continue.
+.
+
+
+MessageId=
+SymbolicName=MSG_CLOSE_QUIT
+Language=English
+The close operation is aborted.
+.
+
+
+MessageId=
+SymbolicName=MSG_CLOSE_CONFIRM
+Language=English
+Close the image anyway (Y:yes / N:no) ? %0
+.
+
+
+MessageId=
+SymbolicName=MSG_RETRY_FORCE_CANCEL
+Language=English
+R:retry / F:force / C:cancel ? %0
+.
+
+
+MessageId=
+SymbolicName=MSG_RETRY_CANCEL
+Language=English
+R:retry / C:cancel ? %0
+.
+
+
+MessageId=
+SymbolicName=MSG_LOCK_NG
+Language=English
+Failed to lock the drive %1!c!. Some programs may be using the drive.
+.
+
+
+MessageId=
+SymbolicName=MSG_STOP_FORCE
+Language=English
+Failed to close the all drives. The operation is forced to continue.
+.
+
+
+MessageId=
+SymbolicName=MSG_STOP_QUIT
+Language=English
+Failed to close the all drives. The operation is aborted.
+.
+
+
+MessageId=
+SymbolicName=MSG_STOP_WARN
+Language=English
+Failed to close the all drives. The driver may not be able to unload
+properly. Continue the stop operation?
+.
+
+
+MessageId=
+SymbolicName=MSG_REMOVE_FORCE
+Language=English
+Failed to stop the driver. The operation is forced to continue;
+.
+
+
+MessageId=
+SymbolicName=MSG_REMOVE_QUIT
+Language=English
+Failed to stop the driver. The operation is aborted.
+.
+
+
+MessageId=
+SymbolicName=MSG_REMOVE_WARN
+Language=English
+Failed to stop the driver. The driver may not be removed completely
+until the system is restarted. Continue the operation?
+.
+
+
+MessageId=
+SymbolicName=MSG_UNKNOWN_LONG
+Language=English
+Unknown (0x%1!08x!)
+.
+
+
+MessageId=
+SymbolicName=MSG_DRIVER_FILE
+Language=English
+Driver : %1!s!
+.
+
+
+MessageId=
+SymbolicName=MSG_DRIVER_VERSION
+Language=English
+Version : %1!d!.%2!d! %3!s!
+.
+
+
+MessageId=
+SymbolicName=MSG_START_TYPE
+Language=English
+Start Type : %0
+.
+
+
+MessageId=
+SymbolicName=MSG_START_AUTO
+Language=English
+AUTO
+.
+
+
+MessageId=
+SymbolicName=MSG_START_BOOT
+Language=English
+BOOT
+.
+
+
+MessageId=
+SymbolicName=MSG_START_DEMAND
+Language=English
+DEMAND
+.
+
+
+MessageId=
+SymbolicName=MSG_START_DISABLED
+Language=English
+DISABLED
+.
+
+
+MessageId=
+SymbolicName=MSG_START_SYSTEM
+Language=English
+SYSTEM
+.
+
+
+MessageId=
+SymbolicName=MSG_DRIVER_STATUS
+Language=English
+Status : %0
+.
+
+
+MessageId=
+SymbolicName=MSG_STATUS_STOPPED
+Language=English
+STOPPED
+.
+
+
+MessageId=
+SymbolicName=MSG_STATUS_START_P
+Language=English
+START_PENDING
+.
+
+
+MessageId=
+SymbolicName=MSG_STATUS_STOP_P
+Language=English
+STOP_PENDING
+.
+
+
+MessageId=
+SymbolicName=MSG_STATUS_RUNNING
+Language=English
+RUNNING
+.
+
+
+MessageId=
+SymbolicName=MSG_STATUS_CONT_P
+Language=English
+CONTINUE_PENDING
+.
+
+
+MessageId=
+SymbolicName=MSG_STATUS_PAUSE_P
+Language=English
+PAUSE_PENDING
+.
+
+
+MessageId=
+SymbolicName=MSG_STATUS_PAUSED
+Language=English
+PAUSED
+.
+
+
+MessageId=
+SymbolicName=MSG_DRIVE_LETTER
+Language=English
+Drive %1!lu! : %0
+.
+
+
+MessageId=
+SymbolicName=MSG_PERSISTENT
+Language=English
+%1!c! (Persistent) %0
+.
+
+
+MessageId=
+SymbolicName=MSG_EPHEMERAL
+Language=English
+%1!c! (Ephemeral) %0
+.
+
+
+MessageId=
+SymbolicName=MSG_IMAGE_NONE
+Language=English
+Image : <none>
+.
+
+
+MessageId=
+SymbolicName=MSG_IMAGE_NAME
+Language=English
+Image : %1!s!
+.
+
+
+MessageId=
+SymbolicName=MSG_FILE_DESC
+Language=English
+Description: %1!s!
+.
+
+
+MessageId=
+SymbolicName=MSG_DISKTYPE_FILE
+Language=English
+Type : FILE
+.
+
+
+MessageId=
+SymbolicName=MSG_DISKTYPE_RAM_CLEAN
+Language=English
+Type : RAM (not modified)
+.
+
+
+MessageId=
+SymbolicName=MSG_DISKTYPE_RAM_DIRTY
+Language=English
+Type : RAM (modified)
+.
+
+
+MessageId=
+SymbolicName=MSG_MEDIA_TYPE
+Language=English
+Media : %1!s!
+.
+
+
+MessageId=
+SymbolicName=MSG_MEDIA_WRITABLE
+Language=English
+Access : Writable
+.
+
+
+MessageId=
+SymbolicName=MSG_MEDIA_PROTECTED
+Language=English
+Access : Write Protected
+.
+
+
+;//
+;// Help message text
+;//
+MessageId=
+SymbolicName=MSG_HINT_INSTALL
+Language=English
+SYNTAX: %1!s!INSTALL [driver] [/AUTO | /A]
+Try '%1!s!HELP INSTALL' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_REMOVE
+Language=English
+SYNTAX: %1!s!REMOVE [/FORCE | /F | /QUIT | /Q]
+Try '%1!s!HELP REMOVE' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_CONFIG
+Language=English
+SYNTAX: %1!s!CONFIG {/AUTO | /A | /MANUAL | /M}
+Try '%1!s!HELP CONFIG' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_START
+Language=English
+SYNTAX: %1!s!START
+Try '%1!s!HELP START' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_STOP
+Language=English
+SYNTAX: %1!s!STOP [/FORCE | /F | /QUIT | /Q]
+Try '%1!s!HELP STOP' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_SHELL
+Language=English
+SYNTAX: %1!s!SHELL [/ON | /OFF]
+Try '%1!s!HELP SHELL' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_OPEN
+Language=English
+SYNTAX: %1!s!OPEN [drive:] [file] [/NEW] [/RAM] [/P | /W]
+ [ /160 | /180 | /320 | /360 | /640 | /720 | /820 | /120 | /1.20
+ | /144 | /1.44 | /168 | /1.68 | /172 | /1.72 | /288 | /2.88 ]
+ [ /5 | /525 | /5.25 ] [/F | /FORCE | /Q | QUIT]
+Try '%1!s!HELP OPEN' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_CLOSE
+Language=English
+SYNTAX: %1!s!CLOSE [drive:] [/FORCE | /F | /QUIT | /Q]
+Try '%1!s!HELP CLOSE' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_SAVE
+Language=English
+SYNTAX: %1!s!SAVE [drive:] [file] [/OVER | /O | /TRUNC | /T]
+ [/FORCE | /F | /QUIT | /Q]
+Try '%1!s!HELP SAVE' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_PROTECT
+Language=English
+SYNTAX: %1!s!PROTECT [drive:] [/ON | /OFF]
+Try '%1!s!HELP PROTECT' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_FORMAT
+Language=English
+SYNTAX: %1!s!FORMAT [drive:] [/FORCE | /F | /QUIT | /Q]
+Try '%1!s!HELP FORMAT' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_LINK
+Language=English
+SYNTAX: %1!s!LINK [number] [letter] [/L]
+Try '%1!s!HELP LINK' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_ULINK
+Language=English
+SYNTAX: %1!s!ULINK [drive]
+Try '%1!s!HELP ULINK' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_STATUS
+Language=English
+SYNTAX: %1!s!STATUS
+Try '%1!s!HELP STATUS' for more information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HINT_VERSION
+Language=English
+SYNTAX: %1!s!VERSION
+Print version information.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_GENERAL
+Language=English
+Usage:
+ %1!s![command [options...]]
+
+Commands:
+ INSTALL Install the Virtual Floppy driver.
+ REMOVE Uninstall the Virtual Floppy driver.
+ CONFIG Configure the Virtual Floppy driver.
+ START Start the Virtual Floppy driver.
+ STOP Stop the Virtual Floppy driver.
+ SHELL Enable/disable the shell extension.
+ OPEN Open a Virtual Floppy image.
+ CLOSE Close a Virtual Floppy image.
+ SAVE Save the current image into a file.
+ PROTECT Enable/disable drive write protect.
+ FORMAT Format the current Virtual Floppy media.
+ LINK Assign a drive letter to a Virtual Floppy drive.
+ ULINK Remove a drive letter from a Virtual Floppy drive.
+ STATUS Print the current status.
+ HELP | ? Print usage help.
+ VERSION Print version information
+
+If a command is not specified, the interactive console is started.
+Type '%1!s!HELP CONSOLE' for more information about the interactive
+console.
+
+All commands and options are case insensitive.
+
+Shorter command name can be used as long as the command can be
+distinguished uniquely: I for INSTALL, REM for REMOVE, etc. are
+accepted, but ST is invalid because it is ambiguous. You have
+to type as much as STAR, STO or STAT in order to distinguish them.
+
+'%1!s!command {/? | /h}' shows a brief hint about each command.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_INSTALL
+Language=English
+Install the Virtual Floppy driver.
+
+SYNTAX:
+ %1!s!INSTALL [driver] [/AUTO | /A]
+
+OPTIONS:
+ driver Specifies the path to the Virtual Floppy driver file.
+ Default is VFD.SYS in the same directory as the VFD
+ console program (Note: *NOT* current directory).
+
+ /AUTO Configures the driver to start at the system startup.
+ /A (Note: *NOT* to start the driver after installation.)
+ By default the driver has to be started manually.
+
+Administrator rights are required to install a devide driver.
+
+Device drivers cannot be installed from network drives.
+Make sure to place VFD.SYS on a local drive.
+
+It is advised to install the driver with the /AUTO option if the
+Virtual Floppy drive is going to be used by users other than
+Administrators and Power Users, who don't have enough rights to
+start device drivers.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_CONFIG
+Language=English
+Configure the Virtual Floppy driver start method.
+
+SYNTAX:
+ %1!s!CONFIG {/AUTO | /A | /MANUAL | /M}
+
+OPTIONS:
+ /AUTO Configures the driver to start at the system startup.
+ /A
+
+ /MANUAL Configures the driver to start on demand.
+ /M
+
+The change takes effect the next system start up.
+Administrator rights are required to configure a devide driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_REMOVE
+Language=English
+Uninstall the Virtual Floppy driver.
+
+SYNTAX:
+ %1!s!REMOVE [/FORCE | /F | /QUIT | /Q]
+
+OPTIONS:
+ /FORCE Suppress prompting and forces the remove operation when
+ /F the driver cannot be stopped.
+
+ /QUIT Suppress prompting and quits the remove operation when
+ /Q the driver cannot be stopped.
+
+Closes all images and stops the driver if necessary, then removes the
+Virtual Floppy driver entries from the system registry.
+This command does not delete the driver file from the local disk.
+
+There are cases, due to the condition of the system, when
+uninstallation does not complete immediately and restarting of the
+system is required. In such cases you may not be able to install the
+Virtual Floppy driver again until the system is restarted and
+uninstallation process is complete.
+
+Administrator rights are required to uninstall a device driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_START
+Language=English
+Start the Virtual Floppy driver.
+
+SYNTAX:
+ %1!s!START
+
+OPTIONS:
+ NONE
+
+If the driver is not installed, this command attempts to install it
+with thedefault options.
+
+At least Power User rights are required to start a device driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_STOP
+Language=English
+Stop the Virtual Floppy driver
+
+SYNTAX:
+ %1!s!STOP [/FORCE | /F | /QUIT | /Q]
+
+OPTIONS:
+ /FORCE Suppress prompting and forces the stop operation when any
+ /F of the drives are in use and cannot be closed.
+
+ /QUIT Suppress prompting and quits the stop operation when any
+ /Q of the drives are in use and cannot be closed.
+
+This command closes all images before stopping the driver.
+An image cannot be closed if the virtual drive is used by any other
+programs. Forcing the stop operation with a drive in use may leave
+the driver in stop pending state. In such cases the driver cannot be
+restarted until all programs stop using the drive and the driver is
+properly unloaded.
+
+At least Power User rights are required to stop a device driver.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_SHELL
+Language=English
+Enable / disable the Virtual Floppy drive shell extension.
+
+SYNTAX:
+ %1!s!SHELL [/ON | /OFF]
+
+OPTIONS:
+ /ON Enables the shell extension.
+
+ /OFF Disables the shell extension.
+
+If an option is not specified, this command prints the current state
+of the shell extension.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_OPEN
+Language=English
+Open a Virtual Floppy image.
+
+SYNTAX:
+ %1!s!OPEN [drive:] [file] [/NEW] [/RAM] [/P | /W]
+ [/size] [/media] [/F | /FORCE | /Q | /QUIT]
+
+OPTIONS:
+ drive: Specifies a target Virtual Floppy drive, either by a drive
+ number or a drive letter, such as "0:", "1:", "B:", "X:".
+ The trailing ':' is required.
+ The drive 0 is assumed if not specified.
+
+ file Specifies a Virtual Floppy image file to open.
+ An empty RAM disk is created if not specified.
+
+ /NEW Creates a new image file.
+ Ignored if a file is not specified.
+
+ /RAM RAM mode - mounts an on-memory copy of the image, instead
+ of directly mounting the image file.
+ Changes made to the virtual media are lost when the image
+ is closed, unless the image is explicitly saved to a file
+ with the 'SAVE' command.
+ Ignored if a file is not specified.
+
+ /P Opens the image as a write protected media.
+ Write protection state can be chenged later with the
+ 'PROTECT' command.
+
+ /W Opens the image as a writable media.
+ Write protection state can be chenged later with the
+ 'PROTECT' command.
+
+ /size Specifies a media size. Acceptable options are:
+
+ /160 (160KB) /820 (820KB)
+ /180 (180KB) /120 or /1.20 (1.20MB)
+ /320 (320KB) /144 or /1.44 (1.44MB)
+ /360 (360KB) /168 or /1.68 (1.68MB DMF)
+ /640 (640KB) /172 or /1.72 (1.72MB DMF)
+ /720 (720KB) /288 or /2.88 (2.88MB)
+
+ /5 Specifies a 5.25 inch media. Takes effect only with
+ /525 640KB, 720KB and 1.2MB media and otherwise ignored.
+ /5.25 160KB, 180KB, 320KB and 360KB media are always 5.25".
+ 820KB, 1.44MB, 1.68MB, 1.72MB and 2.88MB media are always
+ 3.5".
+
+ /FORCE Suppress prompring on minor conflicts and/or omission of
+ /F necessary parameters and continues the operation as best
+ as possible, employing default values if necessary.
+ See below for details.
+
+ /QUIT Suppress prompring on minor conflicts and/or omission of
+ /Q necessary parameters and quits the operation on the first
+ such occasion.
+ See below for details.
+
+If the target drive does not have a drive letter, this command also
+assigns a local drive letter (see '%1!s!HELP LINK') using the first
+available letter.
+
+Read only files, NTFS encrypted/compressed files and ZIP compressed
+image files (such as WinImage IMZ file) cannot be mounted directly
+and must be opened in RAM mode.
+
+Without a size option, size of a virtual media is decided from the
+actual image size. With an explicit size option you can mount a
+file as a smaller media, in such cases surplus data at the end of
+the image is ignored.
+A virtual media size cannot exceed the actual image size.
+
+The /F and /Q options affect the behavior of the OPEN command in
+many ways:
+
+ When the target file does not exist and the /NEW option
+ is not present
+
+ (none) ask user whether to create the target
+ /F create the target without asking
+ /Q abort the operation without asking
+
+ The target file exists and the /NEW option is present
+
+ (none) ask user whether to overwrite the existing file
+ /F overwrite the file without asking
+ /Q abort the operation without asking
+
+ The target file cannot be mounted directly and the /RAM
+ option is not present
+
+ (none) ask user whether to open in RAM mode
+ /F open in RAM mode without asking
+ /Q abort the operation without asking
+
+ A size option is not present for creating a new image
+
+ (none) ask user whether to create a 1.44MB (default) image
+ /F create a 1.44MB image without asking
+ /Q abort the operation without asking
+
+ A size option is not present and the target file size is
+ not an exact match for any of supported media
+
+ (none) ask user whether to mount as a largest media to fit
+ in the actual image
+ /F mount as a largest media to fit in the actual image
+ without asking
+ /Q abort the operation without asking
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_CLOSE
+Language=English
+Close a Virtual Floppy image.
+
+SYNTAX:
+ %1!s!CLOSE [drive:] [/FORCE | /F | /QUIT | /Q]
+
+OPTIONS:
+ drive: Specifies a target Virtual Floppy drive, either by a drive
+ number or a drive letter, such as "0:", "1:", "B:", "X:".
+ The trailing ':' is optional.
+ "*" stands for both drives.
+ The drive 0 is used if not specified.
+
+ /FORCE Suppress prompting and forces the close operation when RAM
+ /F disk data is modified or the drive is in use.
+ Forcing with the drive in use will work only on Windows
+ 2000 and later (not on NT).
+
+ /QUIT Suppress prompting and quits the close operation when RAM
+ /Q disk data is modified or the drive is in use.
+
+If neither /Q nor /F is specified, the user has to choose whether to
+retry, force, or quit.
+
+Unlike the previous versions of the VFD, this command does *NOT*
+remove the drive letter of the target drive.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_SAVE
+Language=English
+Save the current image data into a file.
+
+SYNTAX:
+ %1!s!SAVE [drive:] [file] [/O | /OVER | /T | /TRUNC]
+ [/FORCE | /F | /QUIT | /Q]
+
+OPTIONS:
+ drive: Specifies a target Virtual Floppy drive, either by a drive
+ number or a drive letter, such as "0:", "1:", "B:", "X:".
+ The trailing ':' is required.
+ The drive 0 is used if not specified.
+
+ file Specifies a file name to save data.
+ If not specified, the current image file name is used.
+ Required if the current image is a pure RAM disk.
+
+ /OVER Overwrite the file if the target file exists.
+ /O If the existing file is larger than the current image,
+ file size is not changed and the surplus data at the end
+ of the file is left unchanged.
+ If the target is the current image file, this is the
+ default behavior of this command.
+ Ignored if the target does not exist.
+
+ /TRUNC Overwrite the file if the target file exists.
+ /T If the existing file is larger than the current image,
+ the file is truncated to the image size and the surplus
+ data at the end of the file is discarded.
+ Ignored if the target does not exist.
+
+ /FORCE Suppress prompting when the target volume can not be
+ /F locked and forces the operation without locking.
+
+ /QUIT Suppress prompting when the target volume can not be
+ /Q locked and quits the operation.
+
+If the target is the current image file, the file is always
+overwritten without a question and the /O option is not necessary.
+Otherwise this command fails if the target file exists and neither
+/O or /T is present.
+
+If the existing file is smaller than the current image, the file
+is always expanded to the current image size either with /O or /T.
+
+This program NEVER overwrites a ZIP compressed file regardless of /O
+or /T option, or even if it is the current image file.
+The SAVE command always fails if the target is a ZIP compressed file.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_PROTECT
+Language=English
+Enable / disable drive write protect.
+
+SYNTAX:
+ %1!s!PROTECT [drive:] [/ON | /OFF]
+
+OPTIONS:
+ drive: Specifies a target Virtual Floppy drive, either by a drive
+ number or a drive letter, such as "0:", "1:", "B:", "X:".
+ The trailing ':' is optional.
+ The drive 0 is used if not specified.
+
+ /ON Enables the drive write protect - the drive becomes read only.
+
+ /OFF Disables the drive write protect - the drive becomes writable.
+
+If an option is not specified, this command prints the current write
+protect state of the drive.
+
+After write protection is disabled with this command, Windows may not
+notice the change immediately and claim that the media is still write
+protected. Refreshing the Explorer or retrying the faild operation
+will fix that.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_FORMAT
+Language=English
+Format a Virtual Floppy media with FAT.
+
+SYNTAX:
+ %1!s!FORMAT [drive:] [/FORCE | /F | /QUIT | /Q]
+
+OPTIONS:
+ drive: Specifies a target Virtual Floppy drive, either by a drive
+ number or a drive letter, such as "0:", "1:", "B:", "X:".
+ The trailing ':' is optional.
+ The drive 0 is used if not specified.
+
+ /FORCE Suppress prompting when the target volume can not be
+ /F locked and forces the operation without locking.
+
+ /QUIT Suppress prompting when the target volume can not be
+ /Q locked and quits the operation.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_LINK
+Language=English
+Assign a drive letter to a Virtual Floppy drive.
+
+SYNTAX:
+ %1!s!LINK [number] [letter] [/L]
+
+OPTIONS:
+ number Specifies a target drive number.
+ If not specified, drive 0 is used.
+ "*" stands for both drives.
+
+ letter Spesifies a drive letter to assign.
+ If not specified, the first available letter is used.
+ If the target is both drives, letters for each drives can
+ be specified like "BF" (B for 0, F for 1).
+
+ /L Assign an ephemeral / local drive letter.
+ The default (without this option) is persistent / global.
+
+Persistent / global drive letters are reclaimed each time the driver
+starts.
+On Windows 2000 SP2 and later they are not deleted on user logoff.
+On Terminal Servers they are globaly visible to all users on the
+system.
+
+Ephemeral / local drive letters are not reclaimed on driver start up.
+On Windows 2000 SP2 and later they are deleted on user logoff.
+On Terminal Servers, they are visible only to the current user and
+each user can assign different drive letter to the same drive.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_ULINK
+Language=English
+Remove a drive letter from a Virtual Floppy drive.
+
+SYNTAX:
+ %1!s!ULINK [drive]
+
+OPTIONS:
+ drive Specifies a target Virtual Floppy drive, either by a drive
+ number or a drive letter.
+ If not specified, drive 0 is used.
+ "*" stands for both drives.
+
+Drive letters can be removed even if the drive is being used.
+Some applications such as Windows Explorer detects it and acts
+accordingly, for example closes folder windows for the drive.
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_STATUS
+Language=English
+Print the current status.
+
+SYNTAX:
+ %1!s!STATUS
+
+OPTIONS:
+ NONE
+
+This command prints the following information:
+
+ Driver file path
+ Driver version
+ Driver start type
+ Driver running state
+
+ Shell extension status
+
+ Drive letter
+ Image name
+ Image description (file type, size, file attributes, etc.)
+ Disk type (RAM or FILE)
+ Write protection
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_HELP
+Language=English
+Print the VFD console help.
+
+SYNTAX:
+ %1!s!HELP [command | topic]
+
+OPTIONS:
+ command Specifies one of the following commands
+
+ INSTALL REMOVE CONFIG START STOP
+ SHELL OPEN CLOSE SAVE PROTECT
+ FORMAT LINK ULINK STATUS HELP
+ VERSION
+
+ topic Specifies one of the following topics
+
+ CONSOLE
+
+If an option is not specified, the general help is printed.
+.
+
+
+MessageId=
+SymbolicName=MSG_CONSOLE_HINT
+Language=English
+
+ ********** the VFD interactive console **********
+
+you can use the following commands in addition to regular VFD commands:
+
+ ATTRIB CD CHDIR <drive>:
+ DIR EXIT QUIT BYE
+ .(period) + Windows command
+
+Type '? CONSOLE' or 'HELP CONSOLE' for more information
+
+.
+
+
+MessageId=
+SymbolicName=MSG_HELP_CONSOLE
+Language=English
+In the interactive console, you can use the following commands in
+addition to regular VFD commands:
+
+ CD | CHDIR
+ Displays the name of or changes the current directory.
+ Similar to the Windows CD/CHDIR command.
+
+ <drive>: Change the current directory to the root of the specified
+ drive. Similar to the Windows drive change command.
+
+ DIR Executes the Windows DIR command.
+ All options for the Windows DIR command are available.
+
+ ATTRIB Executes the Windows ATTRIB command.
+ All options for the Windows ATTRIB command are available.
+
+ EXIT | QUIT | BYE | <Ctrl+C>
+ Quits the VFD interactive console.
+
+A command typed with a leading '.'(period) is executed by the Windows
+command processor (cmd.exe).
+
+ e.g.) .FORMAT [options ...]
+ Executes the Windows format.exe. All options are passed to
+ the format.exe.
+
+ FORMAT [options ...]
+ Executes the VFD 'FORMAT' command.
+
+To execute an external command with spaces in its name, put the
+'.' (period) outside the quoteation.
+
+ e.g.) ."C:\Program Files\My App\My Program.exe" [options ...]
+
+DIR and ATTRIB Windows commands are recognized without a period,
+for they are used very frequently.
+
+Commands to affect current directory and environment variable have
+effects only inside the Windows command processor. You can execute
+them but they have no effect on the VFD console.
+
+ .CD .CHDIR .<drive>: to change the current directory
+ .PUSHD .POPD
+ .PATH to change the search path
+ .PROMPT
+ .SET to change the value of an environment variable
+.
+
+
+MessageId=
+SymbolicName=MSG_PAGER_PROMPT
+Language=English
+Press any key to continue ('Q' or <Ctrl+C> to quit) ...%0
+.
+
+
+;
+;#endif // _VFDMSG_H_
add_subdirectory(green)
add_subdirectory(vcdrom)
+add_subdirectory(vfd)
--- /dev/null
+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)
--- /dev/null
+/*
+ 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_
--- /dev/null
+; 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
--- /dev/null
+/*
+ vfddbg.c
+
+ Virtual Floppy Drive for Windows NT platform
+ Kernel mode driver debug functions
+
+ Copyright (C) 2003-2005 Ken Kato
+*/
+
+#if !DBG
+
+// suppress empty compile unit warning
+#pragma warning (disable: 4206)
+#pragma message ("Debug feature is disabled.")
+
+#else // DBG
+
+#include "imports.h"
+#include "vfddrv.h"
+#include "vfddbg.h"
+
+#define CASE_RETURN_STR(str) case str: return #str;
+
+//
+// Return IRP Major Function name
+//
+#ifndef IRP_MJ_POWER
+#define IRP_MJ_POWER 0x16
+#endif
+#ifndef IRP_MJ_SYSTEM_CONTROL
+#define IRP_MJ_SYSTEM_CONTROL 0x17
+#endif
+#ifndef IRP_MJ_PNP
+#define IRP_MJ_PNP 0x1b
+#endif
+
+PCSTR
+GetMajorFuncName(
+ UCHAR major_code)
+{
+ static char functionName[80];
+
+ switch (major_code) {
+ CASE_RETURN_STR(IRP_MJ_CREATE); // 0x00
+ CASE_RETURN_STR(IRP_MJ_CREATE_NAMED_PIPE); // 0x01
+ CASE_RETURN_STR(IRP_MJ_CLOSE); // 0x02
+ CASE_RETURN_STR(IRP_MJ_READ); // 0x03
+ CASE_RETURN_STR(IRP_MJ_WRITE); // 0x04
+ CASE_RETURN_STR(IRP_MJ_QUERY_INFORMATION); // 0x05
+ CASE_RETURN_STR(IRP_MJ_SET_INFORMATION); // 0x06
+ CASE_RETURN_STR(IRP_MJ_QUERY_EA); // 0x07
+ CASE_RETURN_STR(IRP_MJ_SET_EA); // 0x08
+ CASE_RETURN_STR(IRP_MJ_FLUSH_BUFFERS); // 0x09
+ CASE_RETURN_STR(IRP_MJ_QUERY_VOLUME_INFORMATION); // 0x0a
+ CASE_RETURN_STR(IRP_MJ_SET_VOLUME_INFORMATION); // 0x0b
+ CASE_RETURN_STR(IRP_MJ_DIRECTORY_CONTROL); // 0x0c
+ CASE_RETURN_STR(IRP_MJ_FILE_SYSTEM_CONTROL); // 0x0d
+ CASE_RETURN_STR(IRP_MJ_DEVICE_CONTROL); // 0x0e
+ CASE_RETURN_STR(IRP_MJ_INTERNAL_DEVICE_CONTROL); // 0x0f
+ CASE_RETURN_STR(IRP_MJ_SHUTDOWN); // 0x10
+ CASE_RETURN_STR(IRP_MJ_LOCK_CONTROL); // 0x11
+ CASE_RETURN_STR(IRP_MJ_CLEANUP); // 0x12
+ CASE_RETURN_STR(IRP_MJ_CREATE_MAILSLOT); // 0x13
+ CASE_RETURN_STR(IRP_MJ_QUERY_SECURITY); // 0x14
+ CASE_RETURN_STR(IRP_MJ_SET_SECURITY); // 0x15
+ CASE_RETURN_STR(IRP_MJ_POWER); // 0x16
+ CASE_RETURN_STR(IRP_MJ_SYSTEM_CONTROL); // 0x17
+ CASE_RETURN_STR(IRP_MJ_DEVICE_CHANGE); // 0x18
+ CASE_RETURN_STR(IRP_MJ_QUERY_QUOTA); // 0x19
+ CASE_RETURN_STR(IRP_MJ_SET_QUOTA); // 0x1a
+ CASE_RETURN_STR(IRP_MJ_PNP); // 0x1b
+ default:
+ functionName[sizeof(functionName) - 1] = '\0';
+ _snprintf(functionName, sizeof(functionName) - 1,
+ // sprintf(functionName,
+ "Unknown Major Function (0x%x)", major_code);
+ return functionName;
+ }
+}
+
+#ifdef VFD_PNP
+
+//
+// Return PnP IRP Minor Function Name
+//
+PCSTR
+GetPnpIrpName(ULONG minor_code)
+{
+ static char functionName[80];
+
+ switch (minor_code) {
+ CASE_RETURN_STR(IRP_MN_START_DEVICE); // 0x00
+ CASE_RETURN_STR(IRP_MN_QUERY_REMOVE_DEVICE); // 0x01
+ CASE_RETURN_STR(IRP_MN_REMOVE_DEVICE); // 0x02
+ CASE_RETURN_STR(IRP_MN_CANCEL_REMOVE_DEVICE); // 0x03
+ CASE_RETURN_STR(IRP_MN_STOP_DEVICE); // 0x04
+ CASE_RETURN_STR(IRP_MN_QUERY_STOP_DEVICE); // 0x05
+ CASE_RETURN_STR(IRP_MN_CANCEL_STOP_DEVICE); // 0x06
+ CASE_RETURN_STR(IRP_MN_QUERY_DEVICE_RELATIONS); // 0x07
+ CASE_RETURN_STR(IRP_MN_QUERY_INTERFACE); // 0x08
+ CASE_RETURN_STR(IRP_MN_QUERY_CAPABILITIES); // 0x09
+ CASE_RETURN_STR(IRP_MN_QUERY_RESOURCES); // 0x0A
+ CASE_RETURN_STR(IRP_MN_QUERY_RESOURCE_REQUIREMENTS); // 0x0B
+ CASE_RETURN_STR(IRP_MN_QUERY_DEVICE_TEXT); // 0x0C
+ CASE_RETURN_STR(IRP_MN_FILTER_RESOURCE_REQUIREMENTS); // 0x0D
+ CASE_RETURN_STR(IRP_MN_READ_CONFIG); // 0x0F
+ CASE_RETURN_STR(IRP_MN_WRITE_CONFIG); // 0x10
+ CASE_RETURN_STR(IRP_MN_EJECT); // 0x11
+ CASE_RETURN_STR(IRP_MN_SET_LOCK); // 0x12
+ CASE_RETURN_STR(IRP_MN_QUERY_ID); // 0x13
+ CASE_RETURN_STR(IRP_MN_QUERY_PNP_DEVICE_STATE); // 0x14
+ CASE_RETURN_STR(IRP_MN_QUERY_BUS_INFORMATION); // 0x15
+ CASE_RETURN_STR(IRP_MN_DEVICE_USAGE_NOTIFICATION); // 0x16
+ CASE_RETURN_STR(IRP_MN_SURPRISE_REMOVAL); // 0x17
+ CASE_RETURN_STR(IRP_MN_QUERY_LEGACY_BUS_INFORMATION); // 0x18
+ default:
+ functionName[sizeof(functionName) - 1] = '\0';
+ _snprintf(functionName, sizeof(functionName) - 1,
+ // sprintf(functionName,
+ "Unknown PNP IRP (0x%x)", minor_code);
+ return functionName;
+ }
+}
+
+//
+// Return Power IRP Minor Function Name
+//
+PCSTR
+GetPowerIrpName(ULONG minor_code)
+{
+ static char functionName[80];
+
+ switch (minor_code) {
+ CASE_RETURN_STR(IRP_MN_SET_POWER);
+ CASE_RETURN_STR(IRP_MN_QUERY_POWER);
+ CASE_RETURN_STR(IRP_MN_WAIT_WAKE);
+ CASE_RETURN_STR(IRP_MN_POWER_SEQUENCE);
+ default:
+ functionName[sizeof(functionName) - 1] = '\0';
+ _snprintf(functionName, sizeof(functionName) - 1,
+ // sprintf(functionName,
+ "Unknown Power IRP (0x%x)", minor_code);
+ return functionName;
+ }
+}
+
+//
+// Return System IRP Minor Function Name
+//
+PCSTR
+GetSystemIrpName(ULONG minor_code)
+{
+ static char functionName[80];
+
+ switch (minor_code) {
+ CASE_RETURN_STR(IRP_MN_QUERY_ALL_DATA); // 0x00
+ CASE_RETURN_STR(IRP_MN_QUERY_SINGLE_INSTANCE); // 0x01
+ CASE_RETURN_STR(IRP_MN_CHANGE_SINGLE_INSTANCE); // 0x02
+ CASE_RETURN_STR(IRP_MN_CHANGE_SINGLE_ITEM); // 0x03
+ CASE_RETURN_STR(IRP_MN_ENABLE_EVENTS); // 0x04
+ CASE_RETURN_STR(IRP_MN_DISABLE_EVENTS); // 0x05
+ CASE_RETURN_STR(IRP_MN_ENABLE_COLLECTION); // 0x06
+ CASE_RETURN_STR(IRP_MN_DISABLE_COLLECTION); // 0x07
+ CASE_RETURN_STR(IRP_MN_REGINFO); // 0x08
+ CASE_RETURN_STR(IRP_MN_EXECUTE_METHOD); // 0x09
+ default:
+ functionName[sizeof(functionName) - 1] = '\0';
+ _snprintf(functionName, sizeof(functionName) - 1,
+ // sprintf(functionName,
+ "Unknown System IRP (0x%x)", minor_code);
+ return functionName;
+ }
+}
+
+#endif // VFD_PNP
+
+
+#include <ntdddisk.h>
+#ifndef __REACTOS__
+#include <ntddft.h>
+#endif
+#include <ntddstor.h>
+
+#if (VER_PRODUCTBUILD < 2195)
+//
+// imports from Win2K DDK
+//
+
+// mountmgr.h
+
+#define MOUNTMGRCONTROLTYPE ((ULONG) 'm')
+#define MOUNTDEVCONTROLTYPE ((ULONG) 'M')
+/*
+#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_QUERY_POINTS \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 4, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 5, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 6, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 7, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_MOUNTMGR_CHANGE_NOTIFY \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 8, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 9, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 10, METHOD_BUFFERED, FILE_READ_ACCESS)
+/*
+#define IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 11, METHOD_BUFFERED, FILE_READ_ACCESS)
+*/
+
+// mountdev.h
+/*
+#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)
+*/
+
+// ntdddisk.h
+#define IOCTL_DISK_UPDATE_DRIVE_SIZE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0032, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_GROW_PARTITION \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0034, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_GET_CACHE_INFORMATION \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0035, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_SET_CACHE_INFORMATION \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0036, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_DELETE_DRIVE_LAYOUT \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0040, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_FORMAT_DRIVE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x00f3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_SENSE_DEVICE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x00f8, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_INTERNAL_SET_NOTIFY \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0102, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+// ntddft.h
+#define FT_SECONDARY_READ_ALT \
+ CTL_CODE(FTTYPE, 4, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define FT_PRIMARY_READ_ALT \
+ CTL_CODE(FTTYPE, 5, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define FT_CLUSTER_SET_MEMBER_STATE \
+ CTL_CODE(FTTYPE,11, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FT_CLUSTER_GET_MEMBER_STATE \
+ CTL_CODE(FTTYPE,12, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+// ntddstor.h
+#define IOCTL_STORAGE_LOAD_MEDIA2 \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_EJECTION_CONTROL \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0250, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_MCN_CONTROL \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0251, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_RESET_BUS \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RESET_DEVICE \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_GET_DEVICE_NUMBER \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_PREDICT_FAILURE \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0440, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_QUERY_PROPERTY \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define OBSOLETE_IOCTL_STORAGE_RESET_BUS \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define OBSOLETE_IOCTL_STORAGE_RESET_DEVICE \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+// ntddft2.h
+#define FTCONTROLTYPE ((ULONG) 'g')
+#define FT_CREATE_LOGICAL_DISK \
+ CTL_CODE(FTCONTROLTYPE, 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define FT_BREAK_LOGICAL_DISK \
+ CTL_CODE(FTCONTROLTYPE, 1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define FT_ENUMERATE_LOGICAL_DISKS \
+ CTL_CODE(FTCONTROLTYPE, 2, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define FT_QUERY_LOGICAL_DISK_INFORMATION \
+ CTL_CODE(FTCONTROLTYPE, 3, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define FT_ORPHAN_LOGICAL_DISK_MEMBER \
+ CTL_CODE(FTCONTROLTYPE, 4, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define FT_REPLACE_LOGICAL_DISK_MEMBER \
+ CTL_CODE(FTCONTROLTYPE, 5, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK \
+ CTL_CODE(FTCONTROLTYPE, 6, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define FT_INITIALIZE_LOGICAL_DISK \
+ CTL_CODE(FTCONTROLTYPE, 7, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define FT_QUERY_DRIVE_LETTER_FOR_LOGICAL_DISK \
+ CTL_CODE(FTCONTROLTYPE, 8, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define FT_CHECK_IO \
+ CTL_CODE(FTCONTROLTYPE, 9, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define FT_SET_DRIVE_LETTER_FOR_LOGICAL_DISK \
+ CTL_CODE(FTCONTROLTYPE, 10, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define FT_QUERY_NT_DEVICE_NAME_FOR_PARTITION \
+ CTL_CODE(FTCONTROLTYPE, 12, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define FT_CHANGE_NOTIFY \
+ CTL_CODE(FTCONTROLTYPE, 13, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define FT_STOP_SYNC_OPERATIONS \
+ CTL_CODE(FTCONTROLTYPE, 14, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define FT_QUERY_LOGICAL_DISK_ID \
+ CTL_CODE(FTCONTROLTYPE, 100, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define FT_CREATE_PARTITION_LOGICAL_DISK \
+ CTL_CODE(FTCONTROLTYPE, 101, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+// ntddvol.h
+#define IOCTL_VOLUME_BASE ((ULONG) 'V')
+#define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS \
+ CTL_CODE(IOCTL_VOLUME_BASE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_VOLUME_SUPPORTS_ONLINE_OFFLINE \
+ CTL_CODE(IOCTL_VOLUME_BASE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_VOLUME_ONLINE \
+ CTL_CODE(IOCTL_VOLUME_BASE, 2, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_VOLUME_OFFLINE \
+ CTL_CODE(IOCTL_VOLUME_BASE, 3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_VOLUME_IS_OFFLINE \
+ CTL_CODE(IOCTL_VOLUME_BASE, 4, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_VOLUME_IS_IO_CAPABLE \
+ CTL_CODE(IOCTL_VOLUME_BASE, 5, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_VOLUME_QUERY_FAILOVER_SET \
+ CTL_CODE(IOCTL_VOLUME_BASE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_VOLUME_QUERY_VOLUME_NUMBER \
+ CTL_CODE(IOCTL_VOLUME_BASE, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_VOLUME_LOGICAL_TO_PHYSICAL \
+ CTL_CODE(IOCTL_VOLUME_BASE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_VOLUME_PHYSICAL_TO_LOGICAL \
+ CTL_CODE(IOCTL_VOLUME_BASE, 9, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#else // (VER_PRODUCTBUILD < 2195)
+
+#include <mountmgr.h>
+#include <mountdev.h>
+#ifndef __REACTOS__
+#include <ntddft2.h>
+#endif
+#include <ntddvol.h>
+
+#define FT_SECONDARY_READ_ALT \
+ CTL_CODE(FTTYPE, 4, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+#define FT_PRIMARY_READ_ALT \
+ CTL_CODE(FTTYPE, 5, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+
+#endif // (VER_PRODUCTBUILD < 2195)
+
+#if (VER_PRODUCTBUILD < 2600)
+//
+// imports from WinXP DDK
+//
+
+// mountmgr.h
+#define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS \
+ CTL_CODE(MOUNTMGRCONTROLTYPE, 13, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+// mountdev.h
+/*
+#define IOCTL_MOUNTDEV_QUERY_STABLE_GUID \
+ CTL_CODE(MOUNTDEVCONTROLTYPE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
+*/
+
+// ntdddisk.h
+#define IOCTL_DISK_PERFORMANCE_OFF \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0018, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/*
+#define IOCTL_DISK_GET_PARTITION_INFO_EX \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS)
+*/
+#define IOCTL_DISK_SET_PARTITION_INFO_EX \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_GET_DRIVE_LAYOUT_EX \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0014, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_SET_DRIVE_LAYOUT_EX \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_DISK_CREATE_DISK \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0016, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+/*
+#define IOCTL_DISK_GET_LENGTH_INFO \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS)
+*/
+#define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_GET_WRITE_CACHE_STATE \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0037, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_DISK_UPDATE_PROPERTIES \
+ CTL_CODE(IOCTL_DISK_BASE, 0x0050, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+// ntddstor.h
+#define IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0304, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/*
+#define IOCTL_STORAGE_GET_HOTPLUG_INFO \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0305, METHOD_BUFFERED, FILE_ANY_ACCESS)
+*/
+#define IOCTL_STORAGE_SET_HOTPLUG_INFO \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0306, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_STORAGE_BREAK_RESERVATION \
+ CTL_CODE(IOCTL_STORAGE_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+// ntddvol.h
+#define IOCTL_VOLUME_IS_PARTITION \
+ CTL_CODE(IOCTL_VOLUME_BASE, 10, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_VOLUME_READ_PLEX \
+ CTL_CODE(IOCTL_VOLUME_BASE, 11, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define IOCTL_VOLUME_IS_CLUSTERED \
+ CTL_CODE(IOCTL_VOLUME_BASE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_VOLUME_SET_GPT_ATTRIBUTES \
+ CTL_CODE(IOCTL_VOLUME_BASE, 13, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_VOLUME_GET_GPT_ATTRIBUTES \
+ CTL_CODE(IOCTL_VOLUME_BASE, 14, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#endif // (VER_PRODUCTBUILD < 2600)
+
+PCSTR
+GetIoControlName(
+ ULONG ctrl_code)
+{
+ static CHAR buf[20];
+
+ switch (ctrl_code) {
+ //
+ // VFD control codes
+ //
+ CASE_RETURN_STR(IOCTL_VFD_OPEN_IMAGE);
+ CASE_RETURN_STR(IOCTL_VFD_CLOSE_IMAGE);
+ CASE_RETURN_STR(IOCTL_VFD_QUERY_IMAGE);
+ CASE_RETURN_STR(IOCTL_VFD_SET_LINK);
+ CASE_RETURN_STR(IOCTL_VFD_QUERY_LINK);
+ CASE_RETURN_STR(IOCTL_VFD_SET_PROTECT);
+ CASE_RETURN_STR(IOCTL_VFD_CLEAR_PROTECT);
+ CASE_RETURN_STR(IOCTL_VFD_RESET_MODIFY);
+ CASE_RETURN_STR(IOCTL_VFD_QUERY_NUMBER);
+ CASE_RETURN_STR(IOCTL_VFD_QUERY_NAME);
+ CASE_RETURN_STR(IOCTL_VFD_QUERY_VERSION);
+
+ //
+ // Standard control codes
+ //
+ // mountmgr.h
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_CREATE_POINT);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_DELETE_POINTS);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_QUERY_POINTS);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_CHANGE_NOTIFY);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH);
+ CASE_RETURN_STR(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS);
+ CASE_RETURN_STR(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME);
+
+ // mountdev.h
+ CASE_RETURN_STR(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID);
+ CASE_RETURN_STR(IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY);
+ CASE_RETURN_STR(IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME);
+ CASE_RETURN_STR(IOCTL_MOUNTDEV_LINK_CREATED);
+ CASE_RETURN_STR(IOCTL_MOUNTDEV_LINK_DELETED);
+ CASE_RETURN_STR(IOCTL_MOUNTDEV_QUERY_STABLE_GUID);
+
+ // ntdddisk.h
+ CASE_RETURN_STR(IOCTL_DISK_GET_DRIVE_GEOMETRY);
+ CASE_RETURN_STR(IOCTL_DISK_GET_PARTITION_INFO);
+ CASE_RETURN_STR(IOCTL_DISK_SET_PARTITION_INFO);
+ CASE_RETURN_STR(IOCTL_DISK_GET_DRIVE_LAYOUT);
+ CASE_RETURN_STR(IOCTL_DISK_SET_DRIVE_LAYOUT);
+ CASE_RETURN_STR(IOCTL_DISK_VERIFY);
+ CASE_RETURN_STR(IOCTL_DISK_FORMAT_TRACKS);
+ CASE_RETURN_STR(IOCTL_DISK_REASSIGN_BLOCKS);
+ CASE_RETURN_STR(IOCTL_DISK_PERFORMANCE);
+ CASE_RETURN_STR(IOCTL_DISK_IS_WRITABLE);
+ CASE_RETURN_STR(IOCTL_DISK_LOGGING);
+ CASE_RETURN_STR(IOCTL_DISK_FORMAT_TRACKS_EX);
+ CASE_RETURN_STR(IOCTL_DISK_HISTOGRAM_STRUCTURE);
+ CASE_RETURN_STR(IOCTL_DISK_HISTOGRAM_DATA);
+ CASE_RETURN_STR(IOCTL_DISK_HISTOGRAM_RESET);
+ CASE_RETURN_STR(IOCTL_DISK_REQUEST_STRUCTURE);
+ CASE_RETURN_STR(IOCTL_DISK_REQUEST_DATA);
+ CASE_RETURN_STR(IOCTL_DISK_PERFORMANCE_OFF);
+ CASE_RETURN_STR(IOCTL_DISK_CONTROLLER_NUMBER);
+ CASE_RETURN_STR(SMART_GET_VERSION);
+ CASE_RETURN_STR(SMART_SEND_DRIVE_COMMAND);
+ CASE_RETURN_STR(SMART_RCV_DRIVE_DATA);
+ CASE_RETURN_STR(IOCTL_DISK_GET_PARTITION_INFO_EX);
+ CASE_RETURN_STR(IOCTL_DISK_SET_PARTITION_INFO_EX);
+ CASE_RETURN_STR(IOCTL_DISK_GET_DRIVE_LAYOUT_EX);
+ CASE_RETURN_STR(IOCTL_DISK_SET_DRIVE_LAYOUT_EX);
+ CASE_RETURN_STR(IOCTL_DISK_CREATE_DISK);
+ CASE_RETURN_STR(IOCTL_DISK_GET_LENGTH_INFO);
+ CASE_RETURN_STR(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX);
+ CASE_RETURN_STR(IOCTL_DISK_UPDATE_DRIVE_SIZE);
+ CASE_RETURN_STR(IOCTL_DISK_GROW_PARTITION);
+ CASE_RETURN_STR(IOCTL_DISK_GET_CACHE_INFORMATION);
+ CASE_RETURN_STR(IOCTL_DISK_SET_CACHE_INFORMATION);
+#if (NTDDI_VERSION < NTDDI_WS03)
+ CASE_RETURN_STR(IOCTL_DISK_GET_WRITE_CACHE_STATE);
+#else
+ CASE_RETURN_STR(OBSOLETE_DISK_GET_WRITE_CACHE_STATE);
+#endif
+ CASE_RETURN_STR(IOCTL_DISK_DELETE_DRIVE_LAYOUT);
+ CASE_RETURN_STR(IOCTL_DISK_UPDATE_PROPERTIES);
+ CASE_RETURN_STR(IOCTL_DISK_FORMAT_DRIVE);
+ CASE_RETURN_STR(IOCTL_DISK_SENSE_DEVICE);
+ CASE_RETURN_STR(IOCTL_DISK_INTERNAL_SET_VERIFY);
+ CASE_RETURN_STR(IOCTL_DISK_INTERNAL_CLEAR_VERIFY);
+ CASE_RETURN_STR(IOCTL_DISK_INTERNAL_SET_NOTIFY);
+ CASE_RETURN_STR(IOCTL_DISK_CHECK_VERIFY);
+ CASE_RETURN_STR(IOCTL_DISK_MEDIA_REMOVAL);
+ CASE_RETURN_STR(IOCTL_DISK_EJECT_MEDIA);
+ CASE_RETURN_STR(IOCTL_DISK_LOAD_MEDIA);
+ CASE_RETURN_STR(IOCTL_DISK_RESERVE);
+ CASE_RETURN_STR(IOCTL_DISK_RELEASE);
+ CASE_RETURN_STR(IOCTL_DISK_FIND_NEW_DEVICES);
+ CASE_RETURN_STR(IOCTL_DISK_GET_MEDIA_TYPES);
+ CASE_RETURN_STR(IOCTL_DISK_SIMBAD);
+
+#ifndef __REACTOS__
+ // ntddft.h
+ CASE_RETURN_STR(FT_INITIALIZE_SET);
+ CASE_RETURN_STR(FT_REGENERATE);
+ CASE_RETURN_STR(FT_CONFIGURE);
+ CASE_RETURN_STR(FT_VERIFY);
+ CASE_RETURN_STR(FT_SECONDARY_READ);
+ CASE_RETURN_STR(FT_PRIMARY_READ);
+ CASE_RETURN_STR(FT_BALANCED_READ_MODE);
+ CASE_RETURN_STR(FT_SYNC_REDUNDANT_COPY);
+ CASE_RETURN_STR(FT_SEQUENTIAL_WRITE_MODE);
+ CASE_RETURN_STR(FT_PARALLEL_WRITE_MODE);
+ CASE_RETURN_STR(FT_QUERY_SET_STATE);
+ CASE_RETURN_STR(FT_CLUSTER_SET_MEMBER_STATE);
+ CASE_RETURN_STR(FT_CLUSTER_GET_MEMBER_STATE);
+
+ // ntddft2.h
+ CASE_RETURN_STR(FT_CREATE_LOGICAL_DISK);
+ CASE_RETURN_STR(FT_BREAK_LOGICAL_DISK);
+ CASE_RETURN_STR(FT_ENUMERATE_LOGICAL_DISKS);
+ CASE_RETURN_STR(FT_QUERY_LOGICAL_DISK_INFORMATION);
+ CASE_RETURN_STR(FT_ORPHAN_LOGICAL_DISK_MEMBER);
+ CASE_RETURN_STR(FT_REPLACE_LOGICAL_DISK_MEMBER);
+ CASE_RETURN_STR(FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK);
+ CASE_RETURN_STR(FT_INITIALIZE_LOGICAL_DISK);
+ CASE_RETURN_STR(FT_QUERY_DRIVE_LETTER_FOR_LOGICAL_DISK);
+ CASE_RETURN_STR(FT_CHECK_IO);
+ CASE_RETURN_STR(FT_SET_DRIVE_LETTER_FOR_LOGICAL_DISK);
+ CASE_RETURN_STR(FT_QUERY_NT_DEVICE_NAME_FOR_PARTITION);
+ CASE_RETURN_STR(FT_CHANGE_NOTIFY);
+ CASE_RETURN_STR(FT_STOP_SYNC_OPERATIONS);
+ CASE_RETURN_STR(FT_QUERY_LOGICAL_DISK_ID);
+ CASE_RETURN_STR(FT_CREATE_PARTITION_LOGICAL_DISK);
+#endif
+
+ // ntddstor.h
+ CASE_RETURN_STR(IOCTL_STORAGE_CHECK_VERIFY);
+ CASE_RETURN_STR(IOCTL_STORAGE_CHECK_VERIFY2);
+ CASE_RETURN_STR(IOCTL_STORAGE_MEDIA_REMOVAL);
+ CASE_RETURN_STR(IOCTL_STORAGE_EJECT_MEDIA);
+ CASE_RETURN_STR(IOCTL_STORAGE_LOAD_MEDIA);
+ CASE_RETURN_STR(IOCTL_STORAGE_LOAD_MEDIA2);
+ CASE_RETURN_STR(IOCTL_STORAGE_RESERVE);
+ CASE_RETURN_STR(IOCTL_STORAGE_RELEASE);
+ CASE_RETURN_STR(IOCTL_STORAGE_FIND_NEW_DEVICES);
+ CASE_RETURN_STR(IOCTL_STORAGE_EJECTION_CONTROL);
+ CASE_RETURN_STR(IOCTL_STORAGE_MCN_CONTROL);
+ CASE_RETURN_STR(IOCTL_STORAGE_GET_MEDIA_TYPES);
+ CASE_RETURN_STR(IOCTL_STORAGE_GET_MEDIA_TYPES_EX);
+ CASE_RETURN_STR(IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER);
+ CASE_RETURN_STR(IOCTL_STORAGE_GET_HOTPLUG_INFO);
+ CASE_RETURN_STR(IOCTL_STORAGE_SET_HOTPLUG_INFO);
+ CASE_RETURN_STR(IOCTL_STORAGE_RESET_BUS);
+ CASE_RETURN_STR(IOCTL_STORAGE_RESET_DEVICE);
+ CASE_RETURN_STR(IOCTL_STORAGE_BREAK_RESERVATION);
+ CASE_RETURN_STR(IOCTL_STORAGE_GET_DEVICE_NUMBER);
+ CASE_RETURN_STR(IOCTL_STORAGE_PREDICT_FAILURE);
+ CASE_RETURN_STR(IOCTL_STORAGE_QUERY_PROPERTY);
+ CASE_RETURN_STR(OBSOLETE_IOCTL_STORAGE_RESET_BUS);
+ CASE_RETURN_STR(OBSOLETE_IOCTL_STORAGE_RESET_DEVICE);
+
+ // ntddvol.h
+ CASE_RETURN_STR(IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS);
+ CASE_RETURN_STR(IOCTL_VOLUME_IS_CLUSTERED);
+ CASE_RETURN_STR(IOCTL_VOLUME_SUPPORTS_ONLINE_OFFLINE);
+ CASE_RETURN_STR(IOCTL_VOLUME_ONLINE);
+ CASE_RETURN_STR(IOCTL_VOLUME_OFFLINE);
+ CASE_RETURN_STR(IOCTL_VOLUME_IS_OFFLINE);
+ CASE_RETURN_STR(IOCTL_VOLUME_IS_IO_CAPABLE);
+ CASE_RETURN_STR(IOCTL_VOLUME_QUERY_FAILOVER_SET);
+ CASE_RETURN_STR(IOCTL_VOLUME_QUERY_VOLUME_NUMBER);
+ CASE_RETURN_STR(IOCTL_VOLUME_LOGICAL_TO_PHYSICAL);
+ CASE_RETURN_STR(IOCTL_VOLUME_PHYSICAL_TO_LOGICAL);
+ CASE_RETURN_STR(IOCTL_VOLUME_IS_PARTITION);
+ CASE_RETURN_STR(IOCTL_VOLUME_READ_PLEX);
+ CASE_RETURN_STR(IOCTL_VOLUME_SET_GPT_ATTRIBUTES);
+ CASE_RETURN_STR(IOCTL_VOLUME_GET_GPT_ATTRIBUTES);
+
+ default:
+ buf[sizeof(buf) - 1] = '\0';
+ _snprintf(buf, sizeof(buf) - 1,
+ // sprintf(buf,
+ "Unknown IOCTL: 0x%08x", ctrl_code);
+ return buf;
+ }
+}
+
+#if (VER_PRODUCTBUILD < 2195)
+//
+// from new <ntstatus.h>
+//
+#define FACILITY_USB_ERROR_CODE 0x10
+#define FACILITY_TERMINAL_SERVER 0xA
+#define FACILITY_HID_ERROR_CODE 0x11
+#define FACILITY_FIREWIRE_ERROR_CODE 0x12
+#define FACILITY_DEBUGGER 0x1
+#define FACILITY_CLUSTER_ERROR_CODE 0x13
+#define FACILITY_ACPI_ERROR_CODE 0x14
+#define STATUS_RESOURCE_REQUIREMENTS_CHANGED ((NTSTATUS)0x00000119L)
+#define STATUS_TRANSLATION_COMPLETE ((NTSTATUS)0x00000120L)
+#define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY ((NTSTATUS)0x00000121L)
+#define DBG_EXCEPTION_HANDLED ((NTSTATUS)0x00010001L)
+#define DBG_CONTINUE ((NTSTATUS)0x00010002L)
+#define STATUS_ARBITRATION_UNHANDLED ((NTSTATUS)0x40000026L)
+#define STATUS_CARDBUS_NOT_SUPPORTED ((NTSTATUS)0x40000027L)
+#define STATUS_WX86_CREATEWX86TIB ((NTSTATUS)0x40000028L)
+#define STATUS_MP_PROCESSOR_MISMATCH ((NTSTATUS)0x40000029L)
+#define DBG_REPLY_LATER ((NTSTATUS)0x40010001L)
+#define DBG_UNABLE_TO_PROVIDE_HANDLE ((NTSTATUS)0x40010002L)
+#define DBG_TERMINATE_THREAD ((NTSTATUS)0x40010003L)
+#define DBG_TERMINATE_PROCESS ((NTSTATUS)0x40010004L)
+#define DBG_CONTROL_C ((NTSTATUS)0x40010005L)
+#define DBG_PRINTEXCEPTION_C ((NTSTATUS)0x40010006L)
+#define DBG_RIPEXCEPTION ((NTSTATUS)0x40010007L)
+#define DBG_CONTROL_BREAK ((NTSTATUS)0x40010008L)
+#define DBG_EXCEPTION_NOT_HANDLED ((NTSTATUS)0x80010001L)
+#define STATUS_VALIDATE_CONTINUE ((NTSTATUS)0xC0000271L)
+#define STATUS_NO_MATCH ((NTSTATUS)0xC0000272L)
+#define STATUS_NO_MORE_MATCHES ((NTSTATUS)0xC0000273L)
+#define STATUS_NOT_A_REPARSE_POINT ((NTSTATUS)0xC0000275L)
+#define STATUS_IO_REPARSE_TAG_INVALID ((NTSTATUS)0xC0000276L)
+#define STATUS_IO_REPARSE_TAG_MISMATCH ((NTSTATUS)0xC0000277L)
+#define STATUS_IO_REPARSE_DATA_INVALID ((NTSTATUS)0xC0000278L)
+#define STATUS_IO_REPARSE_TAG_NOT_HANDLED ((NTSTATUS)0xC0000279L)
+#define STATUS_REPARSE_POINT_NOT_RESOLVED ((NTSTATUS)0xC0000280L)
+#define STATUS_DIRECTORY_IS_A_REPARSE_POINT ((NTSTATUS)0xC0000281L)
+#define STATUS_RANGE_LIST_CONFLICT ((NTSTATUS)0xC0000282L)
+#define STATUS_SOURCE_ELEMENT_EMPTY ((NTSTATUS)0xC0000283L)
+#define STATUS_DESTINATION_ELEMENT_FULL ((NTSTATUS)0xC0000284L)
+#define STATUS_ILLEGAL_ELEMENT_ADDRESS ((NTSTATUS)0xC0000285L)
+#define STATUS_MAGAZINE_NOT_PRESENT ((NTSTATUS)0xC0000286L)
+#define STATUS_REINITIALIZATION_NEEDED ((NTSTATUS)0xC0000287L)
+#define STATUS_DEVICE_REQUIRES_CLEANING ((NTSTATUS)0x80000288L)
+#define STATUS_DEVICE_DOOR_OPEN ((NTSTATUS)0x80000289L)
+#define STATUS_ENCRYPTION_FAILED ((NTSTATUS)0xC000028AL)
+#define STATUS_DECRYPTION_FAILED ((NTSTATUS)0xC000028BL)
+#define STATUS_RANGE_NOT_FOUND ((NTSTATUS)0xC000028CL)
+#define STATUS_NO_RECOVERY_POLICY ((NTSTATUS)0xC000028DL)
+#define STATUS_NO_EFS ((NTSTATUS)0xC000028EL)
+#define STATUS_WRONG_EFS ((NTSTATUS)0xC000028FL)
+#define STATUS_NO_USER_KEYS ((NTSTATUS)0xC0000290L)
+#define STATUS_FILE_NOT_ENCRYPTED ((NTSTATUS)0xC0000291L)
+#define STATUS_NOT_EXPORT_FORMAT ((NTSTATUS)0xC0000292L)
+#define STATUS_FILE_ENCRYPTED ((NTSTATUS)0xC0000293L)
+#define STATUS_WAKE_SYSTEM ((NTSTATUS)0x40000294L)
+#define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS)0xC0000295L)
+#define STATUS_WMI_INSTANCE_NOT_FOUND ((NTSTATUS)0xC0000296L)
+#define STATUS_WMI_ITEMID_NOT_FOUND ((NTSTATUS)0xC0000297L)
+#define STATUS_WMI_TRY_AGAIN ((NTSTATUS)0xC0000298L)
+#define STATUS_SHARED_POLICY ((NTSTATUS)0xC0000299L)
+#define STATUS_POLICY_OBJECT_NOT_FOUND ((NTSTATUS)0xC000029AL)
+#define STATUS_POLICY_ONLY_IN_DS ((NTSTATUS)0xC000029BL)
+#define STATUS_VOLUME_NOT_UPGRADED ((NTSTATUS)0xC000029CL)
+#define STATUS_REMOTE_STORAGE_NOT_ACTIVE ((NTSTATUS)0xC000029DL)
+#define STATUS_REMOTE_STORAGE_MEDIA_ERROR ((NTSTATUS)0xC000029EL)
+#define STATUS_NO_TRACKING_SERVICE ((NTSTATUS)0xC000029FL)
+#define STATUS_SERVER_SID_MISMATCH ((NTSTATUS)0xC00002A0L)
+#define STATUS_DS_NO_ATTRIBUTE_OR_VALUE ((NTSTATUS)0xC00002A1L)
+#define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX ((NTSTATUS)0xC00002A2L)
+#define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED ((NTSTATUS)0xC00002A3L)
+#define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS ((NTSTATUS)0xC00002A4L)
+#define STATUS_DS_BUSY ((NTSTATUS)0xC00002A5L)
+#define STATUS_DS_UNAVAILABLE ((NTSTATUS)0xC00002A6L)
+#define STATUS_DS_NO_RIDS_ALLOCATED ((NTSTATUS)0xC00002A7L)
+#define STATUS_DS_NO_MORE_RIDS ((NTSTATUS)0xC00002A8L)
+#define STATUS_DS_INCORRECT_ROLE_OWNER ((NTSTATUS)0xC00002A9L)
+#define STATUS_DS_RIDMGR_INIT_ERROR ((NTSTATUS)0xC00002AAL)
+#define STATUS_DS_OBJ_CLASS_VIOLATION ((NTSTATUS)0xC00002ABL)
+#define STATUS_DS_CANT_ON_NON_LEAF ((NTSTATUS)0xC00002ACL)
+#define STATUS_DS_CANT_ON_RDN ((NTSTATUS)0xC00002ADL)
+#define STATUS_DS_CANT_MOD_OBJ_CLASS ((NTSTATUS)0xC00002AEL)
+#define STATUS_DS_CROSS_DOM_MOVE_FAILED ((NTSTATUS)0xC00002AFL)
+#define STATUS_DS_GC_NOT_AVAILABLE ((NTSTATUS)0xC00002B0L)
+#define STATUS_DIRECTORY_SERVICE_REQUIRED ((NTSTATUS)0xC00002B1L)
+#define STATUS_REPARSE_ATTRIBUTE_CONFLICT ((NTSTATUS)0xC00002B2L)
+#define STATUS_CANT_ENABLE_DENY_ONLY ((NTSTATUS)0xC00002B3L)
+#define STATUS_FLOAT_MULTIPLE_FAULTS ((NTSTATUS)0xC00002B4L)
+#define STATUS_FLOAT_MULTIPLE_TRAPS ((NTSTATUS)0xC00002B5L)
+#define STATUS_DEVICE_REMOVED ((NTSTATUS)0xC00002B6L)
+#define STATUS_JOURNAL_DELETE_IN_PROGRESS ((NTSTATUS)0xC00002B7L)
+#define STATUS_JOURNAL_NOT_ACTIVE ((NTSTATUS)0xC00002B8L)
+#define STATUS_NOINTERFACE ((NTSTATUS)0xC00002B9L)
+#define STATUS_DS_ADMIN_LIMIT_EXCEEDED ((NTSTATUS)0xC00002C1L)
+#define STATUS_DRIVER_FAILED_SLEEP ((NTSTATUS)0xC00002C2L)
+#define STATUS_MUTUAL_AUTHENTICATION_FAILED ((NTSTATUS)0xC00002C3L)
+#define STATUS_CORRUPT_SYSTEM_FILE ((NTSTATUS)0xC00002C4L)
+#define STATUS_DATATYPE_MISALIGNMENT_ERROR ((NTSTATUS)0xC00002C5L)
+#define STATUS_WMI_READ_ONLY ((NTSTATUS)0xC00002C6L)
+#define STATUS_WMI_SET_FAILURE ((NTSTATUS)0xC00002C7L)
+#define STATUS_COMMITMENT_MINIMUM ((NTSTATUS)0xC00002C8L)
+#define STATUS_REG_NAT_CONSUMPTION ((NTSTATUS)0xC00002C9L)
+#define STATUS_TRANSPORT_FULL ((NTSTATUS)0xC00002CAL)
+#define STATUS_DS_SAM_INIT_FAILURE ((NTSTATUS)0xC00002CBL)
+#define STATUS_ONLY_IF_CONNECTED ((NTSTATUS)0xC00002CCL)
+#define STATUS_DS_SENSITIVE_GROUP_VIOLATION ((NTSTATUS)0xC00002CDL)
+#define STATUS_PNP_RESTART_ENUMERATION ((NTSTATUS)0xC00002CEL)
+#define STATUS_JOURNAL_ENTRY_DELETED ((NTSTATUS)0xC00002CFL)
+#define STATUS_DS_CANT_MOD_PRIMARYGROUPID ((NTSTATUS)0xC00002D0L)
+#define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE ((NTSTATUS)0xC00002D1L)
+#define STATUS_PNP_REBOOT_REQUIRED ((NTSTATUS)0xC00002D2L)
+#define STATUS_POWER_STATE_INVALID ((NTSTATUS)0xC00002D3L)
+#define STATUS_DS_INVALID_GROUP_TYPE ((NTSTATUS)0xC00002D4L)
+#define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN ((NTSTATUS)0xC00002D5L)
+#define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN ((NTSTATUS)0xC00002D6L)
+#define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS)0xC00002D7L)
+#define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS)0xC00002D8L)
+#define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS)0xC00002D9L)
+#define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER ((NTSTATUS)0xC00002DAL)
+#define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER ((NTSTATUS)0xC00002DBL)
+#define STATUS_DS_HAVE_PRIMARY_MEMBERS ((NTSTATUS)0xC00002DCL)
+#define STATUS_WMI_NOT_SUPPORTED ((NTSTATUS)0xC00002DDL)
+#define STATUS_INSUFFICIENT_POWER ((NTSTATUS)0xC00002DEL)
+#define STATUS_SAM_NEED_BOOTKEY_PASSWORD ((NTSTATUS)0xC00002DFL)
+#define STATUS_SAM_NEED_BOOTKEY_FLOPPY ((NTSTATUS)0xC00002E0L)
+#define STATUS_DS_CANT_START ((NTSTATUS)0xC00002E1L)
+#define STATUS_DS_INIT_FAILURE ((NTSTATUS)0xC00002E2L)
+#define STATUS_SAM_INIT_FAILURE ((NTSTATUS)0xC00002E3L)
+#define STATUS_DS_GC_REQUIRED ((NTSTATUS)0xC00002E4L)
+#define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY ((NTSTATUS)0xC00002E5L)
+#define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS ((NTSTATUS)0xC00002E6L)
+#define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED ((NTSTATUS)0xC00002E7L)
+#define STATUS_MULTIPLE_FAULT_VIOLATION ((NTSTATUS)0xC00002E8L)
+#define STATUS_NOT_SUPPORTED_ON_SBS ((NTSTATUS)0xC0000300L)
+#define DBG_NO_STATE_CHANGE ((NTSTATUS)0xC0010001L)
+#define DBG_APP_NOT_IDLE ((NTSTATUS)0xC0010002L)
+#define RPC_NT_PIPE_CLOSED ((NTSTATUS)0xC003005FL)
+#define RPC_NT_PIPE_DISCIPLINE_ERROR ((NTSTATUS)0xC0030060L)
+#define RPC_NT_PIPE_EMPTY ((NTSTATUS)0xC0030061L)
+#define RPC_NT_INVALID_ASYNC_HANDLE ((NTSTATUS)0xC0020062L)
+#define RPC_NT_INVALID_ASYNC_CALL ((NTSTATUS)0xC0020063L)
+#define STATUS_ACPI_INVALID_OPCODE ((NTSTATUS)0xC0140001L)
+#define STATUS_ACPI_STACK_OVERFLOW ((NTSTATUS)0xC0140002L)
+#define STATUS_ACPI_ASSERT_FAILED ((NTSTATUS)0xC0140003L)
+#define STATUS_ACPI_INVALID_INDEX ((NTSTATUS)0xC0140004L)
+#define STATUS_ACPI_INVALID_ARGUMENT ((NTSTATUS)0xC0140005L)
+#define STATUS_ACPI_FATAL ((NTSTATUS)0xC0140006L)
+#define STATUS_ACPI_INVALID_SUPERNAME ((NTSTATUS)0xC0140007L)
+#define STATUS_ACPI_INVALID_ARGTYPE ((NTSTATUS)0xC0140008L)
+#define STATUS_ACPI_INVALID_OBJTYPE ((NTSTATUS)0xC0140009L)
+#define STATUS_ACPI_INVALID_TARGETTYPE ((NTSTATUS)0xC014000AL)
+#define STATUS_ACPI_INCORRECT_ARGUMENT_COUNT ((NTSTATUS)0xC014000BL)
+#define STATUS_ACPI_ADDRESS_NOT_MAPPED ((NTSTATUS)0xC014000CL)
+#define STATUS_ACPI_INVALID_EVENTTYPE ((NTSTATUS)0xC014000DL)
+#define STATUS_ACPI_HANDLER_COLLISION ((NTSTATUS)0xC014000EL)
+#define STATUS_ACPI_INVALID_DATA ((NTSTATUS)0xC014000FL)
+#define STATUS_ACPI_INVALID_REGION ((NTSTATUS)0xC0140010L)
+#define STATUS_ACPI_INVALID_ACCESS_SIZE ((NTSTATUS)0xC0140011L)
+#define STATUS_ACPI_ACQUIRE_GLOBAL_LOCK ((NTSTATUS)0xC0140012L)
+#define STATUS_ACPI_ALREADY_INITIALIZED ((NTSTATUS)0xC0140013L)
+#define STATUS_ACPI_NOT_INITIALIZED ((NTSTATUS)0xC0140014L)
+#define STATUS_ACPI_INVALID_MUTEX_LEVEL ((NTSTATUS)0xC0140015L)
+#define STATUS_ACPI_MUTEX_NOT_OWNED ((NTSTATUS)0xC0140016L)
+#define STATUS_ACPI_MUTEX_NOT_OWNER ((NTSTATUS)0xC0140017L)
+#define STATUS_ACPI_RS_ACCESS ((NTSTATUS)0xC0140018L)
+#define STATUS_ACPI_INVALID_TABLE ((NTSTATUS)0xC0140019L)
+#define STATUS_ACPI_REG_HANDLER_FAILED ((NTSTATUS)0xC0140020L)
+#define STATUS_ACPI_POWER_REQUEST_FAILED ((NTSTATUS)0xC0140021L)
+#define STATUS_CTX_WINSTATION_NAME_INVALID ((NTSTATUS)0xC00A0001L)
+#define STATUS_CTX_INVALID_PD ((NTSTATUS)0xC00A0002L)
+#define STATUS_CTX_PD_NOT_FOUND ((NTSTATUS)0xC00A0003L)
+#define STATUS_CTX_CDM_CONNECT ((NTSTATUS)0x400A0004L)
+#define STATUS_CTX_CDM_DISCONNECT ((NTSTATUS)0x400A0005L)
+#define STATUS_CTX_CLOSE_PENDING ((NTSTATUS)0xC00A0006L)
+#define STATUS_CTX_NO_OUTBUF ((NTSTATUS)0xC00A0007L)
+#define STATUS_CTX_MODEM_INF_NOT_FOUND ((NTSTATUS)0xC00A0008L)
+#define STATUS_CTX_INVALID_MODEMNAME ((NTSTATUS)0xC00A0009L)
+#define STATUS_CTX_RESPONSE_ERROR ((NTSTATUS)0xC00A000AL)
+#define STATUS_CTX_MODEM_RESPONSE_TIMEOUT ((NTSTATUS)0xC00A000BL)
+#define STATUS_CTX_MODEM_RESPONSE_NO_CARRIER ((NTSTATUS)0xC00A000CL)
+#define STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE ((NTSTATUS)0xC00A000DL)
+#define STATUS_CTX_MODEM_RESPONSE_BUSY ((NTSTATUS)0xC00A000EL)
+#define STATUS_CTX_MODEM_RESPONSE_VOICE ((NTSTATUS)0xC00A000FL)
+#define STATUS_CTX_TD_ERROR ((NTSTATUS)0xC00A0010L)
+#define STATUS_CTX_LICENSE_CLIENT_INVALID ((NTSTATUS)0xC00A0012L)
+#define STATUS_CTX_LICENSE_NOT_AVAILABLE ((NTSTATUS)0xC00A0013L)
+#define STATUS_CTX_LICENSE_EXPIRED ((NTSTATUS)0xC00A0014L)
+#define STATUS_CTX_WINSTATION_NOT_FOUND ((NTSTATUS)0xC00A0015L)
+#define STATUS_CTX_WINSTATION_NAME_COLLISION ((NTSTATUS)0xC00A0016L)
+#define STATUS_CTX_WINSTATION_BUSY ((NTSTATUS)0xC00A0017L)
+#define STATUS_CTX_BAD_VIDEO_MODE ((NTSTATUS)0xC00A0018L)
+#define STATUS_CTX_GRAPHICS_INVALID ((NTSTATUS)0xC00A0022L)
+#define STATUS_CTX_NOT_CONSOLE ((NTSTATUS)0xC00A0024L)
+#define STATUS_CTX_CLIENT_QUERY_TIMEOUT ((NTSTATUS)0xC00A0026L)
+#define STATUS_CTX_CONSOLE_DISCONNECT ((NTSTATUS)0xC00A0027L)
+#define STATUS_CTX_CONSOLE_CONNECT ((NTSTATUS)0xC00A0028L)
+#define STATUS_CTX_SHADOW_DENIED ((NTSTATUS)0xC00A002AL)
+#define STATUS_CTX_WINSTATION_ACCESS_DENIED ((NTSTATUS)0xC00A002BL)
+#define STATUS_CTX_INVALID_WD ((NTSTATUS)0xC00A002EL)
+#define STATUS_CTX_WD_NOT_FOUND ((NTSTATUS)0xC00A002FL)
+#define STATUS_CTX_SHADOW_INVALID ((NTSTATUS)0xC00A0030L)
+#define STATUS_CTX_SHADOW_DISABLED ((NTSTATUS)0xC00A0031L)
+#define STATUS_RDP_PROTOCOL_ERROR ((NTSTATUS)0xC00A0032L)
+#define STATUS_CTX_CLIENT_LICENSE_NOT_SET ((NTSTATUS)0xC00A0033L)
+#define STATUS_CTX_CLIENT_LICENSE_IN_USE ((NTSTATUS)0xC00A0034L)
+#define STATUS_PNP_BAD_MPS_TABLE ((NTSTATUS)0xC0040035L)
+#define STATUS_PNP_TRANSLATION_FAILED ((NTSTATUS)0xC0040036L)
+#define STATUS_PNP_IRQ_TRANSLATION_FAILED ((NTSTATUS)0xC0040037L)
+#endif // VER_PRODUCTBUILD < 2195
+
+static PCSTR
+NtStatusToStr(
+ NTSTATUS status);
+
+PCSTR
+GetStatusName(
+ NTSTATUS status)
+{
+ static CHAR statusName[80];
+ CHAR severity;
+
+ switch (status & 0xf0000000) {
+ case 0x00000000: severity = 'S'; break;
+ case 0x40000000: severity = 'I'; break;
+ case 0x80000000: severity = 'W'; break;
+ case 0xC0000000: severity = 'E'; break;
+ default: severity = '?';
+ }
+
+ statusName[sizeof(statusName) - 1] = '\0';
+ _snprintf(statusName, sizeof(statusName) - 1,
+ // sprintf(statusName,
+ "(%c)%s", severity, NtStatusToStr(status));
+
+ return statusName;
+}
+
+PCSTR
+NtStatusToStr(
+ NTSTATUS status)
+{
+ switch (status) {
+ CASE_RETURN_STR(STATUS_SUCCESS);
+/*
+ CASE_RETURN_STR(STATUS_WAIT_0);
+*/
+ CASE_RETURN_STR(STATUS_WAIT_1);
+ CASE_RETURN_STR(STATUS_WAIT_2);
+ CASE_RETURN_STR(STATUS_WAIT_3);
+ CASE_RETURN_STR(STATUS_WAIT_63);
+ CASE_RETURN_STR(STATUS_ABANDONED);
+/*
+ CASE_RETURN_STR(STATUS_ABANDONED_WAIT_0);
+*/
+ CASE_RETURN_STR(STATUS_ABANDONED_WAIT_63);
+ CASE_RETURN_STR(STATUS_USER_APC);
+ CASE_RETURN_STR(STATUS_KERNEL_APC);
+ CASE_RETURN_STR(STATUS_ALERTED);
+ CASE_RETURN_STR(STATUS_TIMEOUT);
+ CASE_RETURN_STR(STATUS_PENDING);
+ CASE_RETURN_STR(STATUS_REPARSE);
+ CASE_RETURN_STR(STATUS_MORE_ENTRIES);
+ CASE_RETURN_STR(STATUS_NOT_ALL_ASSIGNED);
+ CASE_RETURN_STR(STATUS_SOME_NOT_MAPPED);
+ CASE_RETURN_STR(STATUS_OPLOCK_BREAK_IN_PROGRESS);
+ CASE_RETURN_STR(STATUS_VOLUME_MOUNTED);
+ CASE_RETURN_STR(STATUS_RXACT_COMMITTED);
+ CASE_RETURN_STR(STATUS_NOTIFY_CLEANUP);
+ CASE_RETURN_STR(STATUS_NOTIFY_ENUM_DIR);
+ CASE_RETURN_STR(STATUS_NO_QUOTAS_FOR_ACCOUNT);
+ CASE_RETURN_STR(STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED);
+ CASE_RETURN_STR(STATUS_PAGE_FAULT_TRANSITION);
+ CASE_RETURN_STR(STATUS_PAGE_FAULT_DEMAND_ZERO);
+ CASE_RETURN_STR(STATUS_PAGE_FAULT_COPY_ON_WRITE);
+ CASE_RETURN_STR(STATUS_PAGE_FAULT_GUARD_PAGE);
+ CASE_RETURN_STR(STATUS_PAGE_FAULT_PAGING_FILE);
+ CASE_RETURN_STR(STATUS_CACHE_PAGE_LOCKED);
+ CASE_RETURN_STR(STATUS_CRASH_DUMP);
+ CASE_RETURN_STR(STATUS_BUFFER_ALL_ZEROS);
+ CASE_RETURN_STR(STATUS_REPARSE_OBJECT);
+ CASE_RETURN_STR(STATUS_RESOURCE_REQUIREMENTS_CHANGED);
+ CASE_RETURN_STR(STATUS_TRANSLATION_COMPLETE);
+ CASE_RETURN_STR(STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY);
+ CASE_RETURN_STR(DBG_EXCEPTION_HANDLED);
+ CASE_RETURN_STR(DBG_CONTINUE);
+ CASE_RETURN_STR(STATUS_OBJECT_NAME_EXISTS);
+ CASE_RETURN_STR(STATUS_THREAD_WAS_SUSPENDED);
+ CASE_RETURN_STR(STATUS_WORKING_SET_LIMIT_RANGE);
+ CASE_RETURN_STR(STATUS_IMAGE_NOT_AT_BASE);
+ CASE_RETURN_STR(STATUS_RXACT_STATE_CREATED);
+ CASE_RETURN_STR(STATUS_SEGMENT_NOTIFICATION);
+ CASE_RETURN_STR(STATUS_LOCAL_USER_SESSION_KEY);
+ CASE_RETURN_STR(STATUS_BAD_CURRENT_DIRECTORY);
+ CASE_RETURN_STR(STATUS_SERIAL_MORE_WRITES);
+ CASE_RETURN_STR(STATUS_REGISTRY_RECOVERED);
+ CASE_RETURN_STR(STATUS_FT_READ_RECOVERY_FROM_BACKUP);
+ CASE_RETURN_STR(STATUS_FT_WRITE_RECOVERY);
+ CASE_RETURN_STR(STATUS_SERIAL_COUNTER_TIMEOUT);
+ CASE_RETURN_STR(STATUS_NULL_LM_PASSWORD);
+ CASE_RETURN_STR(STATUS_IMAGE_MACHINE_TYPE_MISMATCH);
+ CASE_RETURN_STR(STATUS_RECEIVE_PARTIAL);
+ CASE_RETURN_STR(STATUS_RECEIVE_EXPEDITED);
+ CASE_RETURN_STR(STATUS_RECEIVE_PARTIAL_EXPEDITED);
+ CASE_RETURN_STR(STATUS_EVENT_DONE);
+ CASE_RETURN_STR(STATUS_EVENT_PENDING);
+ CASE_RETURN_STR(STATUS_CHECKING_FILE_SYSTEM);
+ CASE_RETURN_STR(STATUS_FATAL_APP_EXIT);
+ CASE_RETURN_STR(STATUS_PREDEFINED_HANDLE);
+ CASE_RETURN_STR(STATUS_WAS_UNLOCKED);
+ CASE_RETURN_STR(STATUS_SERVICE_NOTIFICATION);
+ CASE_RETURN_STR(STATUS_WAS_LOCKED);
+ CASE_RETURN_STR(STATUS_LOG_HARD_ERROR);
+ CASE_RETURN_STR(STATUS_ALREADY_WIN32);
+ CASE_RETURN_STR(STATUS_WX86_UNSIMULATE);
+ CASE_RETURN_STR(STATUS_WX86_CONTINUE);
+ CASE_RETURN_STR(STATUS_WX86_SINGLE_STEP);
+ CASE_RETURN_STR(STATUS_WX86_BREAKPOINT);
+ CASE_RETURN_STR(STATUS_WX86_EXCEPTION_CONTINUE);
+ CASE_RETURN_STR(STATUS_WX86_EXCEPTION_LASTCHANCE);
+ CASE_RETURN_STR(STATUS_WX86_EXCEPTION_CHAIN);
+ CASE_RETURN_STR(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE);
+ CASE_RETURN_STR(STATUS_NO_YIELD_PERFORMED);
+ CASE_RETURN_STR(STATUS_TIMER_RESUME_IGNORED);
+ CASE_RETURN_STR(STATUS_ARBITRATION_UNHANDLED);
+ CASE_RETURN_STR(STATUS_CARDBUS_NOT_SUPPORTED);
+ CASE_RETURN_STR(STATUS_WX86_CREATEWX86TIB);
+ CASE_RETURN_STR(STATUS_MP_PROCESSOR_MISMATCH);
+ CASE_RETURN_STR(DBG_REPLY_LATER);
+ CASE_RETURN_STR(DBG_UNABLE_TO_PROVIDE_HANDLE);
+ CASE_RETURN_STR(DBG_TERMINATE_THREAD);
+ CASE_RETURN_STR(DBG_TERMINATE_PROCESS);
+ CASE_RETURN_STR(DBG_CONTROL_C);
+ CASE_RETURN_STR(DBG_PRINTEXCEPTION_C);
+ CASE_RETURN_STR(DBG_RIPEXCEPTION);
+ CASE_RETURN_STR(DBG_CONTROL_BREAK);
+ CASE_RETURN_STR(STATUS_GUARD_PAGE_VIOLATION);
+ CASE_RETURN_STR(STATUS_DATATYPE_MISALIGNMENT);
+ CASE_RETURN_STR(STATUS_BREAKPOINT);
+ CASE_RETURN_STR(STATUS_SINGLE_STEP);
+ CASE_RETURN_STR(STATUS_BUFFER_OVERFLOW);
+ CASE_RETURN_STR(STATUS_NO_MORE_FILES);
+ CASE_RETURN_STR(STATUS_WAKE_SYSTEM_DEBUGGER);
+ CASE_RETURN_STR(STATUS_HANDLES_CLOSED);
+ CASE_RETURN_STR(STATUS_NO_INHERITANCE);
+ CASE_RETURN_STR(STATUS_GUID_SUBSTITUTION_MADE);
+ CASE_RETURN_STR(STATUS_PARTIAL_COPY);
+ CASE_RETURN_STR(STATUS_DEVICE_PAPER_EMPTY);
+ CASE_RETURN_STR(STATUS_DEVICE_POWERED_OFF);
+ CASE_RETURN_STR(STATUS_DEVICE_OFF_LINE);
+ CASE_RETURN_STR(STATUS_DEVICE_BUSY);
+ CASE_RETURN_STR(STATUS_NO_MORE_EAS);
+ CASE_RETURN_STR(STATUS_INVALID_EA_NAME);
+ CASE_RETURN_STR(STATUS_EA_LIST_INCONSISTENT);
+ CASE_RETURN_STR(STATUS_INVALID_EA_FLAG);
+ CASE_RETURN_STR(STATUS_VERIFY_REQUIRED);
+ CASE_RETURN_STR(STATUS_EXTRANEOUS_INFORMATION);
+ CASE_RETURN_STR(STATUS_RXACT_COMMIT_NECESSARY);
+ CASE_RETURN_STR(STATUS_NO_MORE_ENTRIES);
+ CASE_RETURN_STR(STATUS_FILEMARK_DETECTED);
+ CASE_RETURN_STR(STATUS_MEDIA_CHANGED);
+ CASE_RETURN_STR(STATUS_BUS_RESET);
+ CASE_RETURN_STR(STATUS_END_OF_MEDIA);
+ CASE_RETURN_STR(STATUS_BEGINNING_OF_MEDIA);
+ CASE_RETURN_STR(STATUS_MEDIA_CHECK);
+ CASE_RETURN_STR(STATUS_SETMARK_DETECTED);
+ CASE_RETURN_STR(STATUS_NO_DATA_DETECTED);
+ CASE_RETURN_STR(STATUS_REDIRECTOR_HAS_OPEN_HANDLES);
+ CASE_RETURN_STR(STATUS_SERVER_HAS_OPEN_HANDLES);
+ CASE_RETURN_STR(STATUS_ALREADY_DISCONNECTED);
+ CASE_RETURN_STR(STATUS_LONGJUMP);
+ CASE_RETURN_STR(DBG_EXCEPTION_NOT_HANDLED);
+ CASE_RETURN_STR(STATUS_UNSUCCESSFUL);
+ CASE_RETURN_STR(STATUS_NOT_IMPLEMENTED);
+ CASE_RETURN_STR(STATUS_INVALID_INFO_CLASS);
+ CASE_RETURN_STR(STATUS_INFO_LENGTH_MISMATCH);
+ CASE_RETURN_STR(STATUS_ACCESS_VIOLATION);
+ CASE_RETURN_STR(STATUS_IN_PAGE_ERROR);
+ CASE_RETURN_STR(STATUS_PAGEFILE_QUOTA);
+ CASE_RETURN_STR(STATUS_INVALID_HANDLE);
+ CASE_RETURN_STR(STATUS_BAD_INITIAL_STACK);
+ CASE_RETURN_STR(STATUS_BAD_INITIAL_PC);
+ CASE_RETURN_STR(STATUS_INVALID_CID);
+ CASE_RETURN_STR(STATUS_TIMER_NOT_CANCELED);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER);
+ CASE_RETURN_STR(STATUS_NO_SUCH_DEVICE);
+ CASE_RETURN_STR(STATUS_NO_SUCH_FILE);
+ CASE_RETURN_STR(STATUS_INVALID_DEVICE_REQUEST);
+ CASE_RETURN_STR(STATUS_END_OF_FILE);
+ CASE_RETURN_STR(STATUS_WRONG_VOLUME);
+ CASE_RETURN_STR(STATUS_NO_MEDIA_IN_DEVICE);
+ CASE_RETURN_STR(STATUS_UNRECOGNIZED_MEDIA);
+ CASE_RETURN_STR(STATUS_NONEXISTENT_SECTOR);
+ CASE_RETURN_STR(STATUS_MORE_PROCESSING_REQUIRED);
+ CASE_RETURN_STR(STATUS_NO_MEMORY);
+ CASE_RETURN_STR(STATUS_CONFLICTING_ADDRESSES);
+ CASE_RETURN_STR(STATUS_NOT_MAPPED_VIEW);
+ CASE_RETURN_STR(STATUS_UNABLE_TO_FREE_VM);
+ CASE_RETURN_STR(STATUS_UNABLE_TO_DELETE_SECTION);
+ CASE_RETURN_STR(STATUS_INVALID_SYSTEM_SERVICE);
+ CASE_RETURN_STR(STATUS_ILLEGAL_INSTRUCTION);
+ CASE_RETURN_STR(STATUS_INVALID_LOCK_SEQUENCE);
+ CASE_RETURN_STR(STATUS_INVALID_VIEW_SIZE);
+ CASE_RETURN_STR(STATUS_INVALID_FILE_FOR_SECTION);
+ CASE_RETURN_STR(STATUS_ALREADY_COMMITTED);
+ CASE_RETURN_STR(STATUS_ACCESS_DENIED);
+ CASE_RETURN_STR(STATUS_BUFFER_TOO_SMALL);
+ CASE_RETURN_STR(STATUS_OBJECT_TYPE_MISMATCH);
+ CASE_RETURN_STR(STATUS_NONCONTINUABLE_EXCEPTION);
+ CASE_RETURN_STR(STATUS_INVALID_DISPOSITION);
+ CASE_RETURN_STR(STATUS_UNWIND);
+ CASE_RETURN_STR(STATUS_BAD_STACK);
+ CASE_RETURN_STR(STATUS_INVALID_UNWIND_TARGET);
+ CASE_RETURN_STR(STATUS_NOT_LOCKED);
+ CASE_RETURN_STR(STATUS_PARITY_ERROR);
+ CASE_RETURN_STR(STATUS_UNABLE_TO_DECOMMIT_VM);
+ CASE_RETURN_STR(STATUS_NOT_COMMITTED);
+ CASE_RETURN_STR(STATUS_INVALID_PORT_ATTRIBUTES);
+ CASE_RETURN_STR(STATUS_PORT_MESSAGE_TOO_LONG);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_MIX);
+ CASE_RETURN_STR(STATUS_INVALID_QUOTA_LOWER);
+ CASE_RETURN_STR(STATUS_DISK_CORRUPT_ERROR);
+ CASE_RETURN_STR(STATUS_OBJECT_NAME_INVALID);
+ CASE_RETURN_STR(STATUS_OBJECT_NAME_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_OBJECT_NAME_COLLISION);
+ CASE_RETURN_STR(STATUS_PORT_DISCONNECTED);
+ CASE_RETURN_STR(STATUS_DEVICE_ALREADY_ATTACHED);
+ CASE_RETURN_STR(STATUS_OBJECT_PATH_INVALID);
+ CASE_RETURN_STR(STATUS_OBJECT_PATH_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_OBJECT_PATH_SYNTAX_BAD);
+ CASE_RETURN_STR(STATUS_DATA_OVERRUN);
+ CASE_RETURN_STR(STATUS_DATA_LATE_ERROR);
+ CASE_RETURN_STR(STATUS_DATA_ERROR);
+ CASE_RETURN_STR(STATUS_CRC_ERROR);
+ CASE_RETURN_STR(STATUS_SECTION_TOO_BIG);
+ CASE_RETURN_STR(STATUS_PORT_CONNECTION_REFUSED);
+ CASE_RETURN_STR(STATUS_INVALID_PORT_HANDLE);
+ CASE_RETURN_STR(STATUS_SHARING_VIOLATION);
+ CASE_RETURN_STR(STATUS_QUOTA_EXCEEDED);
+ CASE_RETURN_STR(STATUS_INVALID_PAGE_PROTECTION);
+ CASE_RETURN_STR(STATUS_MUTANT_NOT_OWNED);
+ CASE_RETURN_STR(STATUS_SEMAPHORE_LIMIT_EXCEEDED);
+ CASE_RETURN_STR(STATUS_PORT_ALREADY_SET);
+ CASE_RETURN_STR(STATUS_SECTION_NOT_IMAGE);
+ CASE_RETURN_STR(STATUS_SUSPEND_COUNT_EXCEEDED);
+ CASE_RETURN_STR(STATUS_THREAD_IS_TERMINATING);
+ CASE_RETURN_STR(STATUS_BAD_WORKING_SET_LIMIT);
+ CASE_RETURN_STR(STATUS_INCOMPATIBLE_FILE_MAP);
+ CASE_RETURN_STR(STATUS_SECTION_PROTECTION);
+ CASE_RETURN_STR(STATUS_EAS_NOT_SUPPORTED);
+ CASE_RETURN_STR(STATUS_EA_TOO_LARGE);
+ CASE_RETURN_STR(STATUS_NONEXISTENT_EA_ENTRY);
+ CASE_RETURN_STR(STATUS_NO_EAS_ON_FILE);
+ CASE_RETURN_STR(STATUS_EA_CORRUPT_ERROR);
+ CASE_RETURN_STR(STATUS_FILE_LOCK_CONFLICT);
+ CASE_RETURN_STR(STATUS_LOCK_NOT_GRANTED);
+ CASE_RETURN_STR(STATUS_DELETE_PENDING);
+ CASE_RETURN_STR(STATUS_CTL_FILE_NOT_SUPPORTED);
+ CASE_RETURN_STR(STATUS_UNKNOWN_REVISION);
+ CASE_RETURN_STR(STATUS_REVISION_MISMATCH);
+ CASE_RETURN_STR(STATUS_INVALID_OWNER);
+ CASE_RETURN_STR(STATUS_INVALID_PRIMARY_GROUP);
+ CASE_RETURN_STR(STATUS_NO_IMPERSONATION_TOKEN);
+ CASE_RETURN_STR(STATUS_CANT_DISABLE_MANDATORY);
+ CASE_RETURN_STR(STATUS_NO_LOGON_SERVERS);
+ CASE_RETURN_STR(STATUS_NO_SUCH_LOGON_SESSION);
+ CASE_RETURN_STR(STATUS_NO_SUCH_PRIVILEGE);
+ CASE_RETURN_STR(STATUS_PRIVILEGE_NOT_HELD);
+ CASE_RETURN_STR(STATUS_INVALID_ACCOUNT_NAME);
+ CASE_RETURN_STR(STATUS_USER_EXISTS);
+ CASE_RETURN_STR(STATUS_NO_SUCH_USER);
+ CASE_RETURN_STR(STATUS_GROUP_EXISTS);
+ CASE_RETURN_STR(STATUS_NO_SUCH_GROUP);
+ CASE_RETURN_STR(STATUS_MEMBER_IN_GROUP);
+ CASE_RETURN_STR(STATUS_MEMBER_NOT_IN_GROUP);
+ CASE_RETURN_STR(STATUS_LAST_ADMIN);
+ CASE_RETURN_STR(STATUS_WRONG_PASSWORD);
+ CASE_RETURN_STR(STATUS_ILL_FORMED_PASSWORD);
+ CASE_RETURN_STR(STATUS_PASSWORD_RESTRICTION);
+ CASE_RETURN_STR(STATUS_LOGON_FAILURE);
+ CASE_RETURN_STR(STATUS_ACCOUNT_RESTRICTION);
+ CASE_RETURN_STR(STATUS_INVALID_LOGON_HOURS);
+ CASE_RETURN_STR(STATUS_INVALID_WORKSTATION);
+ CASE_RETURN_STR(STATUS_PASSWORD_EXPIRED);
+ CASE_RETURN_STR(STATUS_ACCOUNT_DISABLED);
+ CASE_RETURN_STR(STATUS_NONE_MAPPED);
+ CASE_RETURN_STR(STATUS_TOO_MANY_LUIDS_REQUESTED);
+ CASE_RETURN_STR(STATUS_LUIDS_EXHAUSTED);
+ CASE_RETURN_STR(STATUS_INVALID_SUB_AUTHORITY);
+ CASE_RETURN_STR(STATUS_INVALID_ACL);
+ CASE_RETURN_STR(STATUS_INVALID_SID);
+ CASE_RETURN_STR(STATUS_INVALID_SECURITY_DESCR);
+ CASE_RETURN_STR(STATUS_PROCEDURE_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_INVALID_IMAGE_FORMAT);
+ CASE_RETURN_STR(STATUS_NO_TOKEN);
+ CASE_RETURN_STR(STATUS_BAD_INHERITANCE_ACL);
+ CASE_RETURN_STR(STATUS_RANGE_NOT_LOCKED);
+ CASE_RETURN_STR(STATUS_DISK_FULL);
+ CASE_RETURN_STR(STATUS_SERVER_DISABLED);
+ CASE_RETURN_STR(STATUS_SERVER_NOT_DISABLED);
+ CASE_RETURN_STR(STATUS_TOO_MANY_GUIDS_REQUESTED);
+ CASE_RETURN_STR(STATUS_GUIDS_EXHAUSTED);
+ CASE_RETURN_STR(STATUS_INVALID_ID_AUTHORITY);
+ CASE_RETURN_STR(STATUS_AGENTS_EXHAUSTED);
+ CASE_RETURN_STR(STATUS_INVALID_VOLUME_LABEL);
+ CASE_RETURN_STR(STATUS_SECTION_NOT_EXTENDED);
+ CASE_RETURN_STR(STATUS_NOT_MAPPED_DATA);
+ CASE_RETURN_STR(STATUS_RESOURCE_DATA_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_RESOURCE_TYPE_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_RESOURCE_NAME_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_ARRAY_BOUNDS_EXCEEDED);
+ CASE_RETURN_STR(STATUS_FLOAT_DENORMAL_OPERAND);
+ CASE_RETURN_STR(STATUS_FLOAT_DIVIDE_BY_ZERO);
+ CASE_RETURN_STR(STATUS_FLOAT_INEXACT_RESULT);
+ CASE_RETURN_STR(STATUS_FLOAT_INVALID_OPERATION);
+ CASE_RETURN_STR(STATUS_FLOAT_OVERFLOW);
+ CASE_RETURN_STR(STATUS_FLOAT_STACK_CHECK);
+ CASE_RETURN_STR(STATUS_FLOAT_UNDERFLOW);
+ CASE_RETURN_STR(STATUS_INTEGER_DIVIDE_BY_ZERO);
+ CASE_RETURN_STR(STATUS_INTEGER_OVERFLOW);
+ CASE_RETURN_STR(STATUS_PRIVILEGED_INSTRUCTION);
+ CASE_RETURN_STR(STATUS_TOO_MANY_PAGING_FILES);
+ CASE_RETURN_STR(STATUS_FILE_INVALID);
+ CASE_RETURN_STR(STATUS_ALLOTTED_SPACE_EXCEEDED);
+ CASE_RETURN_STR(STATUS_INSUFFICIENT_RESOURCES);
+ CASE_RETURN_STR(STATUS_DFS_EXIT_PATH_FOUND);
+ CASE_RETURN_STR(STATUS_DEVICE_DATA_ERROR);
+ CASE_RETURN_STR(STATUS_DEVICE_NOT_CONNECTED);
+ CASE_RETURN_STR(STATUS_DEVICE_POWER_FAILURE);
+ CASE_RETURN_STR(STATUS_FREE_VM_NOT_AT_BASE);
+ CASE_RETURN_STR(STATUS_MEMORY_NOT_ALLOCATED);
+ CASE_RETURN_STR(STATUS_WORKING_SET_QUOTA);
+ CASE_RETURN_STR(STATUS_MEDIA_WRITE_PROTECTED);
+ CASE_RETURN_STR(STATUS_DEVICE_NOT_READY);
+ CASE_RETURN_STR(STATUS_INVALID_GROUP_ATTRIBUTES);
+ CASE_RETURN_STR(STATUS_BAD_IMPERSONATION_LEVEL);
+ CASE_RETURN_STR(STATUS_CANT_OPEN_ANONYMOUS);
+ CASE_RETURN_STR(STATUS_BAD_VALIDATION_CLASS);
+ CASE_RETURN_STR(STATUS_BAD_TOKEN_TYPE);
+ CASE_RETURN_STR(STATUS_BAD_MASTER_BOOT_RECORD);
+ CASE_RETURN_STR(STATUS_INSTRUCTION_MISALIGNMENT);
+ CASE_RETURN_STR(STATUS_INSTANCE_NOT_AVAILABLE);
+ CASE_RETURN_STR(STATUS_PIPE_NOT_AVAILABLE);
+ CASE_RETURN_STR(STATUS_INVALID_PIPE_STATE);
+ CASE_RETURN_STR(STATUS_PIPE_BUSY);
+ CASE_RETURN_STR(STATUS_ILLEGAL_FUNCTION);
+ CASE_RETURN_STR(STATUS_PIPE_DISCONNECTED);
+ CASE_RETURN_STR(STATUS_PIPE_CLOSING);
+ CASE_RETURN_STR(STATUS_PIPE_CONNECTED);
+ CASE_RETURN_STR(STATUS_PIPE_LISTENING);
+ CASE_RETURN_STR(STATUS_INVALID_READ_MODE);
+ CASE_RETURN_STR(STATUS_IO_TIMEOUT);
+ CASE_RETURN_STR(STATUS_FILE_FORCED_CLOSED);
+ CASE_RETURN_STR(STATUS_PROFILING_NOT_STARTED);
+ CASE_RETURN_STR(STATUS_PROFILING_NOT_STOPPED);
+ CASE_RETURN_STR(STATUS_COULD_NOT_INTERPRET);
+ CASE_RETURN_STR(STATUS_FILE_IS_A_DIRECTORY);
+ CASE_RETURN_STR(STATUS_NOT_SUPPORTED);
+ CASE_RETURN_STR(STATUS_REMOTE_NOT_LISTENING);
+ CASE_RETURN_STR(STATUS_DUPLICATE_NAME);
+ CASE_RETURN_STR(STATUS_BAD_NETWORK_PATH);
+ CASE_RETURN_STR(STATUS_NETWORK_BUSY);
+ CASE_RETURN_STR(STATUS_DEVICE_DOES_NOT_EXIST);
+ CASE_RETURN_STR(STATUS_TOO_MANY_COMMANDS);
+ CASE_RETURN_STR(STATUS_ADAPTER_HARDWARE_ERROR);
+ CASE_RETURN_STR(STATUS_INVALID_NETWORK_RESPONSE);
+ CASE_RETURN_STR(STATUS_UNEXPECTED_NETWORK_ERROR);
+ CASE_RETURN_STR(STATUS_BAD_REMOTE_ADAPTER);
+ CASE_RETURN_STR(STATUS_PRINT_QUEUE_FULL);
+ CASE_RETURN_STR(STATUS_NO_SPOOL_SPACE);
+ CASE_RETURN_STR(STATUS_PRINT_CANCELLED);
+ CASE_RETURN_STR(STATUS_NETWORK_NAME_DELETED);
+ CASE_RETURN_STR(STATUS_NETWORK_ACCESS_DENIED);
+ CASE_RETURN_STR(STATUS_BAD_DEVICE_TYPE);
+ CASE_RETURN_STR(STATUS_BAD_NETWORK_NAME);
+ CASE_RETURN_STR(STATUS_TOO_MANY_NAMES);
+ CASE_RETURN_STR(STATUS_TOO_MANY_SESSIONS);
+ CASE_RETURN_STR(STATUS_SHARING_PAUSED);
+ CASE_RETURN_STR(STATUS_REQUEST_NOT_ACCEPTED);
+ CASE_RETURN_STR(STATUS_REDIRECTOR_PAUSED);
+ CASE_RETURN_STR(STATUS_NET_WRITE_FAULT);
+ CASE_RETURN_STR(STATUS_PROFILING_AT_LIMIT);
+ CASE_RETURN_STR(STATUS_NOT_SAME_DEVICE);
+ CASE_RETURN_STR(STATUS_FILE_RENAMED);
+ CASE_RETURN_STR(STATUS_VIRTUAL_CIRCUIT_CLOSED);
+ CASE_RETURN_STR(STATUS_NO_SECURITY_ON_OBJECT);
+ CASE_RETURN_STR(STATUS_CANT_WAIT);
+ CASE_RETURN_STR(STATUS_PIPE_EMPTY);
+ CASE_RETURN_STR(STATUS_CANT_ACCESS_DOMAIN_INFO);
+ CASE_RETURN_STR(STATUS_CANT_TERMINATE_SELF);
+ CASE_RETURN_STR(STATUS_INVALID_SERVER_STATE);
+ CASE_RETURN_STR(STATUS_INVALID_DOMAIN_STATE);
+ CASE_RETURN_STR(STATUS_INVALID_DOMAIN_ROLE);
+ CASE_RETURN_STR(STATUS_NO_SUCH_DOMAIN);
+ CASE_RETURN_STR(STATUS_DOMAIN_EXISTS);
+ CASE_RETURN_STR(STATUS_DOMAIN_LIMIT_EXCEEDED);
+ CASE_RETURN_STR(STATUS_OPLOCK_NOT_GRANTED);
+ CASE_RETURN_STR(STATUS_INVALID_OPLOCK_PROTOCOL);
+ CASE_RETURN_STR(STATUS_INTERNAL_DB_CORRUPTION);
+ CASE_RETURN_STR(STATUS_INTERNAL_ERROR);
+ CASE_RETURN_STR(STATUS_GENERIC_NOT_MAPPED);
+ CASE_RETURN_STR(STATUS_BAD_DESCRIPTOR_FORMAT);
+ CASE_RETURN_STR(STATUS_INVALID_USER_BUFFER);
+ CASE_RETURN_STR(STATUS_UNEXPECTED_IO_ERROR);
+ CASE_RETURN_STR(STATUS_UNEXPECTED_MM_CREATE_ERR);
+ CASE_RETURN_STR(STATUS_UNEXPECTED_MM_MAP_ERROR);
+ CASE_RETURN_STR(STATUS_UNEXPECTED_MM_EXTEND_ERR);
+ CASE_RETURN_STR(STATUS_NOT_LOGON_PROCESS);
+ CASE_RETURN_STR(STATUS_LOGON_SESSION_EXISTS);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_1);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_2);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_3);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_4);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_5);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_6);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_7);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_8);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_9);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_10);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_11);
+ CASE_RETURN_STR(STATUS_INVALID_PARAMETER_12);
+ CASE_RETURN_STR(STATUS_REDIRECTOR_NOT_STARTED);
+ CASE_RETURN_STR(STATUS_REDIRECTOR_STARTED);
+ CASE_RETURN_STR(STATUS_STACK_OVERFLOW);
+ CASE_RETURN_STR(STATUS_NO_SUCH_PACKAGE);
+ CASE_RETURN_STR(STATUS_BAD_FUNCTION_TABLE);
+ CASE_RETURN_STR(STATUS_VARIABLE_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_DIRECTORY_NOT_EMPTY);
+ CASE_RETURN_STR(STATUS_FILE_CORRUPT_ERROR);
+ CASE_RETURN_STR(STATUS_NOT_A_DIRECTORY);
+ CASE_RETURN_STR(STATUS_BAD_LOGON_SESSION_STATE);
+ CASE_RETURN_STR(STATUS_LOGON_SESSION_COLLISION);
+ CASE_RETURN_STR(STATUS_NAME_TOO_LONG);
+ CASE_RETURN_STR(STATUS_FILES_OPEN);
+ CASE_RETURN_STR(STATUS_CONNECTION_IN_USE);
+ CASE_RETURN_STR(STATUS_MESSAGE_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_PROCESS_IS_TERMINATING);
+ CASE_RETURN_STR(STATUS_INVALID_LOGON_TYPE);
+ CASE_RETURN_STR(STATUS_NO_GUID_TRANSLATION);
+ CASE_RETURN_STR(STATUS_CANNOT_IMPERSONATE);
+ CASE_RETURN_STR(STATUS_IMAGE_ALREADY_LOADED);
+ CASE_RETURN_STR(STATUS_ABIOS_NOT_PRESENT);
+ CASE_RETURN_STR(STATUS_ABIOS_LID_NOT_EXIST);
+ CASE_RETURN_STR(STATUS_ABIOS_LID_ALREADY_OWNED);
+ CASE_RETURN_STR(STATUS_ABIOS_NOT_LID_OWNER);
+ CASE_RETURN_STR(STATUS_ABIOS_INVALID_COMMAND);
+ CASE_RETURN_STR(STATUS_ABIOS_INVALID_LID);
+ CASE_RETURN_STR(STATUS_ABIOS_SELECTOR_NOT_AVAILABLE);
+ CASE_RETURN_STR(STATUS_ABIOS_INVALID_SELECTOR);
+ CASE_RETURN_STR(STATUS_NO_LDT);
+ CASE_RETURN_STR(STATUS_INVALID_LDT_SIZE);
+ CASE_RETURN_STR(STATUS_INVALID_LDT_OFFSET);
+ CASE_RETURN_STR(STATUS_INVALID_LDT_DESCRIPTOR);
+ CASE_RETURN_STR(STATUS_INVALID_IMAGE_NE_FORMAT);
+ CASE_RETURN_STR(STATUS_RXACT_INVALID_STATE);
+ CASE_RETURN_STR(STATUS_RXACT_COMMIT_FAILURE);
+ CASE_RETURN_STR(STATUS_MAPPED_FILE_SIZE_ZERO);
+ CASE_RETURN_STR(STATUS_TOO_MANY_OPENED_FILES);
+ CASE_RETURN_STR(STATUS_CANCELLED);
+ CASE_RETURN_STR(STATUS_CANNOT_DELETE);
+ CASE_RETURN_STR(STATUS_INVALID_COMPUTER_NAME);
+ CASE_RETURN_STR(STATUS_FILE_DELETED);
+ CASE_RETURN_STR(STATUS_SPECIAL_ACCOUNT);
+ CASE_RETURN_STR(STATUS_SPECIAL_GROUP);
+ CASE_RETURN_STR(STATUS_SPECIAL_USER);
+ CASE_RETURN_STR(STATUS_MEMBERS_PRIMARY_GROUP);
+ CASE_RETURN_STR(STATUS_FILE_CLOSED);
+ CASE_RETURN_STR(STATUS_TOO_MANY_THREADS);
+ CASE_RETURN_STR(STATUS_THREAD_NOT_IN_PROCESS);
+ CASE_RETURN_STR(STATUS_TOKEN_ALREADY_IN_USE);
+ CASE_RETURN_STR(STATUS_PAGEFILE_QUOTA_EXCEEDED);
+ CASE_RETURN_STR(STATUS_COMMITMENT_LIMIT);
+ CASE_RETURN_STR(STATUS_INVALID_IMAGE_LE_FORMAT);
+ CASE_RETURN_STR(STATUS_INVALID_IMAGE_NOT_MZ);
+ CASE_RETURN_STR(STATUS_INVALID_IMAGE_PROTECT);
+ CASE_RETURN_STR(STATUS_INVALID_IMAGE_WIN_16);
+ CASE_RETURN_STR(STATUS_LOGON_SERVER_CONFLICT);
+ CASE_RETURN_STR(STATUS_TIME_DIFFERENCE_AT_DC);
+ CASE_RETURN_STR(STATUS_SYNCHRONIZATION_REQUIRED);
+ CASE_RETURN_STR(STATUS_DLL_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_OPEN_FAILED);
+ CASE_RETURN_STR(STATUS_IO_PRIVILEGE_FAILED);
+ CASE_RETURN_STR(STATUS_ORDINAL_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_ENTRYPOINT_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_CONTROL_C_EXIT);
+ CASE_RETURN_STR(STATUS_LOCAL_DISCONNECT);
+ CASE_RETURN_STR(STATUS_REMOTE_DISCONNECT);
+ CASE_RETURN_STR(STATUS_REMOTE_RESOURCES);
+ CASE_RETURN_STR(STATUS_LINK_FAILED);
+ CASE_RETURN_STR(STATUS_LINK_TIMEOUT);
+ CASE_RETURN_STR(STATUS_INVALID_CONNECTION);
+ CASE_RETURN_STR(STATUS_INVALID_ADDRESS);
+ CASE_RETURN_STR(STATUS_DLL_INIT_FAILED);
+ CASE_RETURN_STR(STATUS_MISSING_SYSTEMFILE);
+ CASE_RETURN_STR(STATUS_UNHANDLED_EXCEPTION);
+ CASE_RETURN_STR(STATUS_APP_INIT_FAILURE);
+ CASE_RETURN_STR(STATUS_PAGEFILE_CREATE_FAILED);
+ CASE_RETURN_STR(STATUS_NO_PAGEFILE);
+ CASE_RETURN_STR(STATUS_INVALID_LEVEL);
+ CASE_RETURN_STR(STATUS_WRONG_PASSWORD_CORE);
+ CASE_RETURN_STR(STATUS_ILLEGAL_FLOAT_CONTEXT);
+ CASE_RETURN_STR(STATUS_PIPE_BROKEN);
+ CASE_RETURN_STR(STATUS_REGISTRY_CORRUPT);
+ CASE_RETURN_STR(STATUS_REGISTRY_IO_FAILED);
+ CASE_RETURN_STR(STATUS_NO_EVENT_PAIR);
+ CASE_RETURN_STR(STATUS_UNRECOGNIZED_VOLUME);
+ CASE_RETURN_STR(STATUS_SERIAL_NO_DEVICE_INITED);
+ CASE_RETURN_STR(STATUS_NO_SUCH_ALIAS);
+ CASE_RETURN_STR(STATUS_MEMBER_NOT_IN_ALIAS);
+ CASE_RETURN_STR(STATUS_MEMBER_IN_ALIAS);
+ CASE_RETURN_STR(STATUS_ALIAS_EXISTS);
+ CASE_RETURN_STR(STATUS_LOGON_NOT_GRANTED);
+ CASE_RETURN_STR(STATUS_TOO_MANY_SECRETS);
+ CASE_RETURN_STR(STATUS_SECRET_TOO_LONG);
+ CASE_RETURN_STR(STATUS_INTERNAL_DB_ERROR);
+ CASE_RETURN_STR(STATUS_FULLSCREEN_MODE);
+ CASE_RETURN_STR(STATUS_TOO_MANY_CONTEXT_IDS);
+ CASE_RETURN_STR(STATUS_LOGON_TYPE_NOT_GRANTED);
+ CASE_RETURN_STR(STATUS_NOT_REGISTRY_FILE);
+ CASE_RETURN_STR(STATUS_NT_CROSS_ENCRYPTION_REQUIRED);
+ CASE_RETURN_STR(STATUS_DOMAIN_CTRLR_CONFIG_ERROR);
+ CASE_RETURN_STR(STATUS_FT_MISSING_MEMBER);
+ CASE_RETURN_STR(STATUS_ILL_FORMED_SERVICE_ENTRY);
+ CASE_RETURN_STR(STATUS_ILLEGAL_CHARACTER);
+ CASE_RETURN_STR(STATUS_UNMAPPABLE_CHARACTER);
+ CASE_RETURN_STR(STATUS_UNDEFINED_CHARACTER);
+ CASE_RETURN_STR(STATUS_FLOPPY_VOLUME);
+ CASE_RETURN_STR(STATUS_FLOPPY_ID_MARK_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_FLOPPY_WRONG_CYLINDER);
+ CASE_RETURN_STR(STATUS_FLOPPY_UNKNOWN_ERROR);
+ CASE_RETURN_STR(STATUS_FLOPPY_BAD_REGISTERS);
+ CASE_RETURN_STR(STATUS_DISK_RECALIBRATE_FAILED);
+ CASE_RETURN_STR(STATUS_DISK_OPERATION_FAILED);
+ CASE_RETURN_STR(STATUS_DISK_RESET_FAILED);
+ CASE_RETURN_STR(STATUS_SHARED_IRQ_BUSY);
+ CASE_RETURN_STR(STATUS_FT_ORPHANING);
+ CASE_RETURN_STR(STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT);
+ CASE_RETURN_STR(STATUS_PARTITION_FAILURE);
+ CASE_RETURN_STR(STATUS_INVALID_BLOCK_LENGTH);
+ CASE_RETURN_STR(STATUS_DEVICE_NOT_PARTITIONED);
+ CASE_RETURN_STR(STATUS_UNABLE_TO_LOCK_MEDIA);
+ CASE_RETURN_STR(STATUS_UNABLE_TO_UNLOAD_MEDIA);
+ CASE_RETURN_STR(STATUS_EOM_OVERFLOW);
+ CASE_RETURN_STR(STATUS_NO_MEDIA);
+ CASE_RETURN_STR(STATUS_NO_SUCH_MEMBER);
+ CASE_RETURN_STR(STATUS_INVALID_MEMBER);
+ CASE_RETURN_STR(STATUS_KEY_DELETED);
+ CASE_RETURN_STR(STATUS_NO_LOG_SPACE);
+ CASE_RETURN_STR(STATUS_TOO_MANY_SIDS);
+ CASE_RETURN_STR(STATUS_LM_CROSS_ENCRYPTION_REQUIRED);
+ CASE_RETURN_STR(STATUS_KEY_HAS_CHILDREN);
+ CASE_RETURN_STR(STATUS_CHILD_MUST_BE_VOLATILE);
+ CASE_RETURN_STR(STATUS_DEVICE_CONFIGURATION_ERROR);
+ CASE_RETURN_STR(STATUS_DRIVER_INTERNAL_ERROR);
+ CASE_RETURN_STR(STATUS_INVALID_DEVICE_STATE);
+ CASE_RETURN_STR(STATUS_IO_DEVICE_ERROR);
+ CASE_RETURN_STR(STATUS_DEVICE_PROTOCOL_ERROR);
+ CASE_RETURN_STR(STATUS_BACKUP_CONTROLLER);
+ CASE_RETURN_STR(STATUS_LOG_FILE_FULL);
+ CASE_RETURN_STR(STATUS_TOO_LATE);
+ CASE_RETURN_STR(STATUS_NO_TRUST_LSA_SECRET);
+ CASE_RETURN_STR(STATUS_NO_TRUST_SAM_ACCOUNT);
+ CASE_RETURN_STR(STATUS_TRUSTED_DOMAIN_FAILURE);
+ CASE_RETURN_STR(STATUS_TRUSTED_RELATIONSHIP_FAILURE);
+ CASE_RETURN_STR(STATUS_EVENTLOG_FILE_CORRUPT);
+ CASE_RETURN_STR(STATUS_EVENTLOG_CANT_START);
+ CASE_RETURN_STR(STATUS_TRUST_FAILURE);
+ CASE_RETURN_STR(STATUS_MUTANT_LIMIT_EXCEEDED);
+ CASE_RETURN_STR(STATUS_NETLOGON_NOT_STARTED);
+ CASE_RETURN_STR(STATUS_ACCOUNT_EXPIRED);
+ CASE_RETURN_STR(STATUS_POSSIBLE_DEADLOCK);
+ CASE_RETURN_STR(STATUS_NETWORK_CREDENTIAL_CONFLICT);
+ CASE_RETURN_STR(STATUS_REMOTE_SESSION_LIMIT);
+ CASE_RETURN_STR(STATUS_EVENTLOG_FILE_CHANGED);
+ CASE_RETURN_STR(STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT);
+ CASE_RETURN_STR(STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT);
+ CASE_RETURN_STR(STATUS_NOLOGON_SERVER_TRUST_ACCOUNT);
+ CASE_RETURN_STR(STATUS_DOMAIN_TRUST_INCONSISTENT);
+ CASE_RETURN_STR(STATUS_FS_DRIVER_REQUIRED);
+ CASE_RETURN_STR(STATUS_NO_USER_SESSION_KEY);
+ CASE_RETURN_STR(STATUS_USER_SESSION_DELETED);
+ CASE_RETURN_STR(STATUS_RESOURCE_LANG_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_INSUFF_SERVER_RESOURCES);
+ CASE_RETURN_STR(STATUS_INVALID_BUFFER_SIZE);
+ CASE_RETURN_STR(STATUS_INVALID_ADDRESS_COMPONENT);
+ CASE_RETURN_STR(STATUS_INVALID_ADDRESS_WILDCARD);
+ CASE_RETURN_STR(STATUS_TOO_MANY_ADDRESSES);
+ CASE_RETURN_STR(STATUS_ADDRESS_ALREADY_EXISTS);
+ CASE_RETURN_STR(STATUS_ADDRESS_CLOSED);
+ CASE_RETURN_STR(STATUS_CONNECTION_DISCONNECTED);
+ CASE_RETURN_STR(STATUS_CONNECTION_RESET);
+ CASE_RETURN_STR(STATUS_TOO_MANY_NODES);
+ CASE_RETURN_STR(STATUS_TRANSACTION_ABORTED);
+ CASE_RETURN_STR(STATUS_TRANSACTION_TIMED_OUT);
+ CASE_RETURN_STR(STATUS_TRANSACTION_NO_RELEASE);
+ CASE_RETURN_STR(STATUS_TRANSACTION_NO_MATCH);
+ CASE_RETURN_STR(STATUS_TRANSACTION_RESPONDED);
+ CASE_RETURN_STR(STATUS_TRANSACTION_INVALID_ID);
+ CASE_RETURN_STR(STATUS_TRANSACTION_INVALID_TYPE);
+ CASE_RETURN_STR(STATUS_NOT_SERVER_SESSION);
+ CASE_RETURN_STR(STATUS_NOT_CLIENT_SESSION);
+ CASE_RETURN_STR(STATUS_CANNOT_LOAD_REGISTRY_FILE);
+ CASE_RETURN_STR(STATUS_DEBUG_ATTACH_FAILED);
+ CASE_RETURN_STR(STATUS_SYSTEM_PROCESS_TERMINATED);
+ CASE_RETURN_STR(STATUS_DATA_NOT_ACCEPTED);
+ CASE_RETURN_STR(STATUS_NO_BROWSER_SERVERS_FOUND);
+ CASE_RETURN_STR(STATUS_VDM_HARD_ERROR);
+ CASE_RETURN_STR(STATUS_DRIVER_CANCEL_TIMEOUT);
+ CASE_RETURN_STR(STATUS_REPLY_MESSAGE_MISMATCH);
+ CASE_RETURN_STR(STATUS_MAPPED_ALIGNMENT);
+ CASE_RETURN_STR(STATUS_IMAGE_CHECKSUM_MISMATCH);
+ CASE_RETURN_STR(STATUS_LOST_WRITEBEHIND_DATA);
+ CASE_RETURN_STR(STATUS_CLIENT_SERVER_PARAMETERS_INVALID);
+ CASE_RETURN_STR(STATUS_PASSWORD_MUST_CHANGE);
+ CASE_RETURN_STR(STATUS_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_NOT_TINY_STREAM);
+ CASE_RETURN_STR(STATUS_RECOVERY_FAILURE);
+ CASE_RETURN_STR(STATUS_STACK_OVERFLOW_READ);
+ CASE_RETURN_STR(STATUS_FAIL_CHECK);
+ CASE_RETURN_STR(STATUS_DUPLICATE_OBJECTID);
+ CASE_RETURN_STR(STATUS_OBJECTID_EXISTS);
+ CASE_RETURN_STR(STATUS_CONVERT_TO_LARGE);
+ CASE_RETURN_STR(STATUS_RETRY);
+ CASE_RETURN_STR(STATUS_FOUND_OUT_OF_SCOPE);
+ CASE_RETURN_STR(STATUS_ALLOCATE_BUCKET);
+ CASE_RETURN_STR(STATUS_PROPSET_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_MARSHALL_OVERFLOW);
+ CASE_RETURN_STR(STATUS_INVALID_VARIANT);
+ CASE_RETURN_STR(STATUS_DOMAIN_CONTROLLER_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_ACCOUNT_LOCKED_OUT);
+ CASE_RETURN_STR(STATUS_HANDLE_NOT_CLOSABLE);
+ CASE_RETURN_STR(STATUS_CONNECTION_REFUSED);
+ CASE_RETURN_STR(STATUS_GRACEFUL_DISCONNECT);
+ CASE_RETURN_STR(STATUS_ADDRESS_ALREADY_ASSOCIATED);
+ CASE_RETURN_STR(STATUS_ADDRESS_NOT_ASSOCIATED);
+ CASE_RETURN_STR(STATUS_CONNECTION_INVALID);
+ CASE_RETURN_STR(STATUS_CONNECTION_ACTIVE);
+ CASE_RETURN_STR(STATUS_NETWORK_UNREACHABLE);
+ CASE_RETURN_STR(STATUS_HOST_UNREACHABLE);
+ CASE_RETURN_STR(STATUS_PROTOCOL_UNREACHABLE);
+ CASE_RETURN_STR(STATUS_PORT_UNREACHABLE);
+ CASE_RETURN_STR(STATUS_REQUEST_ABORTED);
+ CASE_RETURN_STR(STATUS_CONNECTION_ABORTED);
+ CASE_RETURN_STR(STATUS_BAD_COMPRESSION_BUFFER);
+ CASE_RETURN_STR(STATUS_USER_MAPPED_FILE);
+ CASE_RETURN_STR(STATUS_AUDIT_FAILED);
+ CASE_RETURN_STR(STATUS_TIMER_RESOLUTION_NOT_SET);
+ CASE_RETURN_STR(STATUS_CONNECTION_COUNT_LIMIT);
+ CASE_RETURN_STR(STATUS_LOGIN_TIME_RESTRICTION);
+ CASE_RETURN_STR(STATUS_LOGIN_WKSTA_RESTRICTION);
+ CASE_RETURN_STR(STATUS_IMAGE_MP_UP_MISMATCH);
+ CASE_RETURN_STR(STATUS_INSUFFICIENT_LOGON_INFO);
+ CASE_RETURN_STR(STATUS_BAD_DLL_ENTRYPOINT);
+ CASE_RETURN_STR(STATUS_BAD_SERVICE_ENTRYPOINT);
+ CASE_RETURN_STR(STATUS_LPC_REPLY_LOST);
+ CASE_RETURN_STR(STATUS_IP_ADDRESS_CONFLICT1);
+ CASE_RETURN_STR(STATUS_IP_ADDRESS_CONFLICT2);
+ CASE_RETURN_STR(STATUS_REGISTRY_QUOTA_LIMIT);
+ CASE_RETURN_STR(STATUS_PATH_NOT_COVERED);
+ CASE_RETURN_STR(STATUS_NO_CALLBACK_ACTIVE);
+ CASE_RETURN_STR(STATUS_LICENSE_QUOTA_EXCEEDED);
+ CASE_RETURN_STR(STATUS_PWD_TOO_SHORT);
+ CASE_RETURN_STR(STATUS_PWD_TOO_RECENT);
+ CASE_RETURN_STR(STATUS_PWD_HISTORY_CONFLICT);
+ CASE_RETURN_STR(STATUS_PLUGPLAY_NO_DEVICE);
+ CASE_RETURN_STR(STATUS_UNSUPPORTED_COMPRESSION);
+ CASE_RETURN_STR(STATUS_INVALID_HW_PROFILE);
+ CASE_RETURN_STR(STATUS_INVALID_PLUGPLAY_DEVICE_PATH);
+ CASE_RETURN_STR(STATUS_DRIVER_ORDINAL_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_DRIVER_ENTRYPOINT_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_RESOURCE_NOT_OWNED);
+ CASE_RETURN_STR(STATUS_TOO_MANY_LINKS);
+ CASE_RETURN_STR(STATUS_QUOTA_LIST_INCONSISTENT);
+ CASE_RETURN_STR(STATUS_FILE_IS_OFFLINE);
+ CASE_RETURN_STR(STATUS_EVALUATION_EXPIRATION);
+ CASE_RETURN_STR(STATUS_ILLEGAL_DLL_RELOCATION);
+ CASE_RETURN_STR(STATUS_LICENSE_VIOLATION);
+ CASE_RETURN_STR(STATUS_DLL_INIT_FAILED_LOGOFF);
+ CASE_RETURN_STR(STATUS_DRIVER_UNABLE_TO_LOAD);
+ CASE_RETURN_STR(STATUS_DFS_UNAVAILABLE);
+ CASE_RETURN_STR(STATUS_VOLUME_DISMOUNTED);
+ CASE_RETURN_STR(STATUS_WX86_INTERNAL_ERROR);
+ CASE_RETURN_STR(STATUS_WX86_FLOAT_STACK_CHECK);
+ CASE_RETURN_STR(STATUS_VALIDATE_CONTINUE);
+ CASE_RETURN_STR(STATUS_NO_MATCH);
+ CASE_RETURN_STR(STATUS_NO_MORE_MATCHES);
+ CASE_RETURN_STR(STATUS_NOT_A_REPARSE_POINT);
+ CASE_RETURN_STR(STATUS_IO_REPARSE_TAG_INVALID);
+ CASE_RETURN_STR(STATUS_IO_REPARSE_TAG_MISMATCH);
+ CASE_RETURN_STR(STATUS_IO_REPARSE_DATA_INVALID);
+ CASE_RETURN_STR(STATUS_IO_REPARSE_TAG_NOT_HANDLED);
+ CASE_RETURN_STR(STATUS_REPARSE_POINT_NOT_RESOLVED);
+ CASE_RETURN_STR(STATUS_DIRECTORY_IS_A_REPARSE_POINT);
+ CASE_RETURN_STR(STATUS_RANGE_LIST_CONFLICT);
+ CASE_RETURN_STR(STATUS_SOURCE_ELEMENT_EMPTY);
+ CASE_RETURN_STR(STATUS_DESTINATION_ELEMENT_FULL);
+ CASE_RETURN_STR(STATUS_ILLEGAL_ELEMENT_ADDRESS);
+ CASE_RETURN_STR(STATUS_MAGAZINE_NOT_PRESENT);
+ CASE_RETURN_STR(STATUS_REINITIALIZATION_NEEDED);
+ CASE_RETURN_STR(STATUS_DEVICE_REQUIRES_CLEANING);
+ CASE_RETURN_STR(STATUS_DEVICE_DOOR_OPEN);
+ CASE_RETURN_STR(STATUS_ENCRYPTION_FAILED);
+ CASE_RETURN_STR(STATUS_DECRYPTION_FAILED);
+ CASE_RETURN_STR(STATUS_RANGE_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_NO_RECOVERY_POLICY);
+ CASE_RETURN_STR(STATUS_NO_EFS);
+ CASE_RETURN_STR(STATUS_WRONG_EFS);
+ CASE_RETURN_STR(STATUS_NO_USER_KEYS);
+ CASE_RETURN_STR(STATUS_FILE_NOT_ENCRYPTED);
+ CASE_RETURN_STR(STATUS_NOT_EXPORT_FORMAT);
+ CASE_RETURN_STR(STATUS_FILE_ENCRYPTED);
+ CASE_RETURN_STR(STATUS_WAKE_SYSTEM);
+ CASE_RETURN_STR(STATUS_WMI_GUID_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_WMI_INSTANCE_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_WMI_ITEMID_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_WMI_TRY_AGAIN);
+ CASE_RETURN_STR(STATUS_SHARED_POLICY);
+ CASE_RETURN_STR(STATUS_POLICY_OBJECT_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_POLICY_ONLY_IN_DS);
+ CASE_RETURN_STR(STATUS_VOLUME_NOT_UPGRADED);
+ CASE_RETURN_STR(STATUS_REMOTE_STORAGE_NOT_ACTIVE);
+ CASE_RETURN_STR(STATUS_REMOTE_STORAGE_MEDIA_ERROR);
+ CASE_RETURN_STR(STATUS_NO_TRACKING_SERVICE);
+ CASE_RETURN_STR(STATUS_SERVER_SID_MISMATCH);
+ CASE_RETURN_STR(STATUS_DS_NO_ATTRIBUTE_OR_VALUE);
+ CASE_RETURN_STR(STATUS_DS_INVALID_ATTRIBUTE_SYNTAX);
+ CASE_RETURN_STR(STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED);
+ CASE_RETURN_STR(STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS);
+ CASE_RETURN_STR(STATUS_DS_BUSY);
+ CASE_RETURN_STR(STATUS_DS_UNAVAILABLE);
+ CASE_RETURN_STR(STATUS_DS_NO_RIDS_ALLOCATED);
+ CASE_RETURN_STR(STATUS_DS_NO_MORE_RIDS);
+ CASE_RETURN_STR(STATUS_DS_INCORRECT_ROLE_OWNER);
+ CASE_RETURN_STR(STATUS_DS_RIDMGR_INIT_ERROR);
+ CASE_RETURN_STR(STATUS_DS_OBJ_CLASS_VIOLATION);
+ CASE_RETURN_STR(STATUS_DS_CANT_ON_NON_LEAF);
+ CASE_RETURN_STR(STATUS_DS_CANT_ON_RDN);
+ CASE_RETURN_STR(STATUS_DS_CANT_MOD_OBJ_CLASS);
+ CASE_RETURN_STR(STATUS_DS_CROSS_DOM_MOVE_FAILED);
+ CASE_RETURN_STR(STATUS_DS_GC_NOT_AVAILABLE);
+ CASE_RETURN_STR(STATUS_DIRECTORY_SERVICE_REQUIRED);
+ CASE_RETURN_STR(STATUS_REPARSE_ATTRIBUTE_CONFLICT);
+ CASE_RETURN_STR(STATUS_CANT_ENABLE_DENY_ONLY);
+ CASE_RETURN_STR(STATUS_FLOAT_MULTIPLE_FAULTS);
+ CASE_RETURN_STR(STATUS_FLOAT_MULTIPLE_TRAPS);
+ CASE_RETURN_STR(STATUS_DEVICE_REMOVED);
+ CASE_RETURN_STR(STATUS_JOURNAL_DELETE_IN_PROGRESS);
+ CASE_RETURN_STR(STATUS_JOURNAL_NOT_ACTIVE);
+ CASE_RETURN_STR(STATUS_NOINTERFACE);
+ CASE_RETURN_STR(STATUS_DS_ADMIN_LIMIT_EXCEEDED);
+ CASE_RETURN_STR(STATUS_DRIVER_FAILED_SLEEP);
+ CASE_RETURN_STR(STATUS_MUTUAL_AUTHENTICATION_FAILED);
+ CASE_RETURN_STR(STATUS_CORRUPT_SYSTEM_FILE);
+ CASE_RETURN_STR(STATUS_DATATYPE_MISALIGNMENT_ERROR);
+ CASE_RETURN_STR(STATUS_WMI_READ_ONLY);
+ CASE_RETURN_STR(STATUS_WMI_SET_FAILURE);
+ CASE_RETURN_STR(STATUS_COMMITMENT_MINIMUM);
+ CASE_RETURN_STR(STATUS_REG_NAT_CONSUMPTION);
+ CASE_RETURN_STR(STATUS_TRANSPORT_FULL);
+ CASE_RETURN_STR(STATUS_DS_SAM_INIT_FAILURE);
+ CASE_RETURN_STR(STATUS_ONLY_IF_CONNECTED);
+ CASE_RETURN_STR(STATUS_DS_SENSITIVE_GROUP_VIOLATION);
+ CASE_RETURN_STR(STATUS_PNP_RESTART_ENUMERATION);
+ CASE_RETURN_STR(STATUS_JOURNAL_ENTRY_DELETED);
+ CASE_RETURN_STR(STATUS_DS_CANT_MOD_PRIMARYGROUPID);
+ CASE_RETURN_STR(STATUS_SYSTEM_IMAGE_BAD_SIGNATURE);
+ CASE_RETURN_STR(STATUS_PNP_REBOOT_REQUIRED);
+ CASE_RETURN_STR(STATUS_POWER_STATE_INVALID);
+ CASE_RETURN_STR(STATUS_DS_INVALID_GROUP_TYPE);
+ CASE_RETURN_STR(STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN);
+ CASE_RETURN_STR(STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN);
+ CASE_RETURN_STR(STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER);
+ CASE_RETURN_STR(STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER);
+ CASE_RETURN_STR(STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER);
+ CASE_RETURN_STR(STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER);
+ CASE_RETURN_STR(STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER);
+ CASE_RETURN_STR(STATUS_DS_HAVE_PRIMARY_MEMBERS);
+ CASE_RETURN_STR(STATUS_WMI_NOT_SUPPORTED);
+ CASE_RETURN_STR(STATUS_INSUFFICIENT_POWER);
+ CASE_RETURN_STR(STATUS_SAM_NEED_BOOTKEY_PASSWORD);
+ CASE_RETURN_STR(STATUS_SAM_NEED_BOOTKEY_FLOPPY);
+ CASE_RETURN_STR(STATUS_DS_CANT_START);
+ CASE_RETURN_STR(STATUS_DS_INIT_FAILURE);
+ CASE_RETURN_STR(STATUS_SAM_INIT_FAILURE);
+ CASE_RETURN_STR(STATUS_DS_GC_REQUIRED);
+ CASE_RETURN_STR(STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY);
+ CASE_RETURN_STR(STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS);
+ CASE_RETURN_STR(STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED);
+ CASE_RETURN_STR(STATUS_MULTIPLE_FAULT_VIOLATION);
+ CASE_RETURN_STR(STATUS_NOT_SUPPORTED_ON_SBS);
+ CASE_RETURN_STR(STATUS_WOW_ASSERTION);
+ CASE_RETURN_STR(DBG_NO_STATE_CHANGE);
+ CASE_RETURN_STR(DBG_APP_NOT_IDLE);
+ CASE_RETURN_STR(RPC_NT_INVALID_STRING_BINDING);
+ CASE_RETURN_STR(RPC_NT_WRONG_KIND_OF_BINDING);
+ CASE_RETURN_STR(RPC_NT_INVALID_BINDING);
+ CASE_RETURN_STR(RPC_NT_PROTSEQ_NOT_SUPPORTED);
+ CASE_RETURN_STR(RPC_NT_INVALID_RPC_PROTSEQ);
+ CASE_RETURN_STR(RPC_NT_INVALID_STRING_UUID);
+ CASE_RETURN_STR(RPC_NT_INVALID_ENDPOINT_FORMAT);
+ CASE_RETURN_STR(RPC_NT_INVALID_NET_ADDR);
+ CASE_RETURN_STR(RPC_NT_NO_ENDPOINT_FOUND);
+ CASE_RETURN_STR(RPC_NT_INVALID_TIMEOUT);
+ CASE_RETURN_STR(RPC_NT_OBJECT_NOT_FOUND);
+ CASE_RETURN_STR(RPC_NT_ALREADY_REGISTERED);
+ CASE_RETURN_STR(RPC_NT_TYPE_ALREADY_REGISTERED);
+ CASE_RETURN_STR(RPC_NT_ALREADY_LISTENING);
+ CASE_RETURN_STR(RPC_NT_NO_PROTSEQS_REGISTERED);
+ CASE_RETURN_STR(RPC_NT_NOT_LISTENING);
+ CASE_RETURN_STR(RPC_NT_UNKNOWN_MGR_TYPE);
+ CASE_RETURN_STR(RPC_NT_UNKNOWN_IF);
+ CASE_RETURN_STR(RPC_NT_NO_BINDINGS);
+ CASE_RETURN_STR(RPC_NT_NO_PROTSEQS);
+ CASE_RETURN_STR(RPC_NT_CANT_CREATE_ENDPOINT);
+ CASE_RETURN_STR(RPC_NT_OUT_OF_RESOURCES);
+ CASE_RETURN_STR(RPC_NT_SERVER_UNAVAILABLE);
+ CASE_RETURN_STR(RPC_NT_SERVER_TOO_BUSY);
+ CASE_RETURN_STR(RPC_NT_INVALID_NETWORK_OPTIONS);
+ CASE_RETURN_STR(RPC_NT_NO_CALL_ACTIVE);
+ CASE_RETURN_STR(RPC_NT_CALL_FAILED);
+ CASE_RETURN_STR(RPC_NT_CALL_FAILED_DNE);
+ CASE_RETURN_STR(RPC_NT_PROTOCOL_ERROR);
+ CASE_RETURN_STR(RPC_NT_UNSUPPORTED_TRANS_SYN);
+ CASE_RETURN_STR(RPC_NT_UNSUPPORTED_TYPE);
+ CASE_RETURN_STR(RPC_NT_INVALID_TAG);
+ CASE_RETURN_STR(RPC_NT_INVALID_BOUND);
+ CASE_RETURN_STR(RPC_NT_NO_ENTRY_NAME);
+ CASE_RETURN_STR(RPC_NT_INVALID_NAME_SYNTAX);
+ CASE_RETURN_STR(RPC_NT_UNSUPPORTED_NAME_SYNTAX);
+ CASE_RETURN_STR(RPC_NT_UUID_NO_ADDRESS);
+ CASE_RETURN_STR(RPC_NT_DUPLICATE_ENDPOINT);
+ CASE_RETURN_STR(RPC_NT_UNKNOWN_AUTHN_TYPE);
+ CASE_RETURN_STR(RPC_NT_MAX_CALLS_TOO_SMALL);
+ CASE_RETURN_STR(RPC_NT_STRING_TOO_LONG);
+ CASE_RETURN_STR(RPC_NT_PROTSEQ_NOT_FOUND);
+ CASE_RETURN_STR(RPC_NT_PROCNUM_OUT_OF_RANGE);
+ CASE_RETURN_STR(RPC_NT_BINDING_HAS_NO_AUTH);
+ CASE_RETURN_STR(RPC_NT_UNKNOWN_AUTHN_SERVICE);
+ CASE_RETURN_STR(RPC_NT_UNKNOWN_AUTHN_LEVEL);
+ CASE_RETURN_STR(RPC_NT_INVALID_AUTH_IDENTITY);
+ CASE_RETURN_STR(RPC_NT_UNKNOWN_AUTHZ_SERVICE);
+ CASE_RETURN_STR(EPT_NT_INVALID_ENTRY);
+ CASE_RETURN_STR(EPT_NT_CANT_PERFORM_OP);
+ CASE_RETURN_STR(EPT_NT_NOT_REGISTERED);
+ CASE_RETURN_STR(RPC_NT_NOTHING_TO_EXPORT);
+ CASE_RETURN_STR(RPC_NT_INCOMPLETE_NAME);
+ CASE_RETURN_STR(RPC_NT_INVALID_VERS_OPTION);
+ CASE_RETURN_STR(RPC_NT_NO_MORE_MEMBERS);
+ CASE_RETURN_STR(RPC_NT_NOT_ALL_OBJS_UNEXPORTED);
+ CASE_RETURN_STR(RPC_NT_INTERFACE_NOT_FOUND);
+ CASE_RETURN_STR(RPC_NT_ENTRY_ALREADY_EXISTS);
+ CASE_RETURN_STR(RPC_NT_ENTRY_NOT_FOUND);
+ CASE_RETURN_STR(RPC_NT_NAME_SERVICE_UNAVAILABLE);
+ CASE_RETURN_STR(RPC_NT_INVALID_NAF_ID);
+ CASE_RETURN_STR(RPC_NT_CANNOT_SUPPORT);
+ CASE_RETURN_STR(RPC_NT_NO_CONTEXT_AVAILABLE);
+ CASE_RETURN_STR(RPC_NT_INTERNAL_ERROR);
+ CASE_RETURN_STR(RPC_NT_ZERO_DIVIDE);
+ CASE_RETURN_STR(RPC_NT_ADDRESS_ERROR);
+ CASE_RETURN_STR(RPC_NT_FP_DIV_ZERO);
+ CASE_RETURN_STR(RPC_NT_FP_UNDERFLOW);
+ CASE_RETURN_STR(RPC_NT_FP_OVERFLOW);
+ CASE_RETURN_STR(RPC_NT_NO_MORE_ENTRIES);
+ CASE_RETURN_STR(RPC_NT_SS_CHAR_TRANS_OPEN_FAIL);
+ CASE_RETURN_STR(RPC_NT_SS_CHAR_TRANS_SHORT_FILE);
+ CASE_RETURN_STR(RPC_NT_SS_IN_NULL_CONTEXT);
+ CASE_RETURN_STR(RPC_NT_SS_CONTEXT_MISMATCH);
+ CASE_RETURN_STR(RPC_NT_SS_CONTEXT_DAMAGED);
+ CASE_RETURN_STR(RPC_NT_SS_HANDLES_MISMATCH);
+ CASE_RETURN_STR(RPC_NT_SS_CANNOT_GET_CALL_HANDLE);
+ CASE_RETURN_STR(RPC_NT_NULL_REF_POINTER);
+ CASE_RETURN_STR(RPC_NT_ENUM_VALUE_OUT_OF_RANGE);
+ CASE_RETURN_STR(RPC_NT_BYTE_COUNT_TOO_SMALL);
+ CASE_RETURN_STR(RPC_NT_BAD_STUB_DATA);
+ CASE_RETURN_STR(RPC_NT_CALL_IN_PROGRESS);
+ CASE_RETURN_STR(RPC_NT_NO_MORE_BINDINGS);
+ CASE_RETURN_STR(RPC_NT_GROUP_MEMBER_NOT_FOUND);
+ CASE_RETURN_STR(EPT_NT_CANT_CREATE);
+ CASE_RETURN_STR(RPC_NT_INVALID_OBJECT);
+ CASE_RETURN_STR(RPC_NT_NO_INTERFACES);
+ CASE_RETURN_STR(RPC_NT_CALL_CANCELLED);
+ CASE_RETURN_STR(RPC_NT_BINDING_INCOMPLETE);
+ CASE_RETURN_STR(RPC_NT_COMM_FAILURE);
+ CASE_RETURN_STR(RPC_NT_UNSUPPORTED_AUTHN_LEVEL);
+ CASE_RETURN_STR(RPC_NT_NO_PRINC_NAME);
+ CASE_RETURN_STR(RPC_NT_NOT_RPC_ERROR);
+ CASE_RETURN_STR(RPC_NT_UUID_LOCAL_ONLY);
+ CASE_RETURN_STR(RPC_NT_SEC_PKG_ERROR);
+ CASE_RETURN_STR(RPC_NT_NOT_CANCELLED);
+ CASE_RETURN_STR(RPC_NT_INVALID_ES_ACTION);
+ CASE_RETURN_STR(RPC_NT_WRONG_ES_VERSION);
+ CASE_RETURN_STR(RPC_NT_WRONG_STUB_VERSION);
+ CASE_RETURN_STR(RPC_NT_INVALID_PIPE_OBJECT);
+ CASE_RETURN_STR(RPC_NT_INVALID_PIPE_OPERATION);
+ CASE_RETURN_STR(RPC_NT_WRONG_PIPE_VERSION);
+ CASE_RETURN_STR(RPC_NT_PIPE_CLOSED);
+ CASE_RETURN_STR(RPC_NT_PIPE_DISCIPLINE_ERROR);
+ CASE_RETURN_STR(RPC_NT_PIPE_EMPTY);
+ CASE_RETURN_STR(RPC_NT_INVALID_ASYNC_HANDLE);
+ CASE_RETURN_STR(RPC_NT_INVALID_ASYNC_CALL);
+ CASE_RETURN_STR(RPC_NT_SEND_INCOMPLETE);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_OPCODE);
+ CASE_RETURN_STR(STATUS_ACPI_STACK_OVERFLOW);
+ CASE_RETURN_STR(STATUS_ACPI_ASSERT_FAILED);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_INDEX);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_ARGUMENT);
+ CASE_RETURN_STR(STATUS_ACPI_FATAL);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_SUPERNAME);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_ARGTYPE);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_OBJTYPE);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_TARGETTYPE);
+ CASE_RETURN_STR(STATUS_ACPI_INCORRECT_ARGUMENT_COUNT);
+ CASE_RETURN_STR(STATUS_ACPI_ADDRESS_NOT_MAPPED);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_EVENTTYPE);
+ CASE_RETURN_STR(STATUS_ACPI_HANDLER_COLLISION);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_DATA);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_REGION);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_ACCESS_SIZE);
+ CASE_RETURN_STR(STATUS_ACPI_ACQUIRE_GLOBAL_LOCK);
+ CASE_RETURN_STR(STATUS_ACPI_ALREADY_INITIALIZED);
+ CASE_RETURN_STR(STATUS_ACPI_NOT_INITIALIZED);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_MUTEX_LEVEL);
+ CASE_RETURN_STR(STATUS_ACPI_MUTEX_NOT_OWNED);
+ CASE_RETURN_STR(STATUS_ACPI_MUTEX_NOT_OWNER);
+ CASE_RETURN_STR(STATUS_ACPI_RS_ACCESS);
+ CASE_RETURN_STR(STATUS_ACPI_INVALID_TABLE);
+ CASE_RETURN_STR(STATUS_ACPI_REG_HANDLER_FAILED);
+ CASE_RETURN_STR(STATUS_ACPI_POWER_REQUEST_FAILED);
+ CASE_RETURN_STR(STATUS_CTX_WINSTATION_NAME_INVALID);
+ CASE_RETURN_STR(STATUS_CTX_INVALID_PD);
+ CASE_RETURN_STR(STATUS_CTX_PD_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_CTX_CDM_CONNECT);
+ CASE_RETURN_STR(STATUS_CTX_CDM_DISCONNECT);
+ CASE_RETURN_STR(STATUS_CTX_CLOSE_PENDING);
+ CASE_RETURN_STR(STATUS_CTX_NO_OUTBUF);
+ CASE_RETURN_STR(STATUS_CTX_MODEM_INF_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_CTX_INVALID_MODEMNAME);
+ CASE_RETURN_STR(STATUS_CTX_RESPONSE_ERROR);
+ CASE_RETURN_STR(STATUS_CTX_MODEM_RESPONSE_TIMEOUT);
+ CASE_RETURN_STR(STATUS_CTX_MODEM_RESPONSE_NO_CARRIER);
+ CASE_RETURN_STR(STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE);
+ CASE_RETURN_STR(STATUS_CTX_MODEM_RESPONSE_BUSY);
+ CASE_RETURN_STR(STATUS_CTX_MODEM_RESPONSE_VOICE);
+ CASE_RETURN_STR(STATUS_CTX_TD_ERROR);
+ CASE_RETURN_STR(STATUS_CTX_LICENSE_CLIENT_INVALID);
+ CASE_RETURN_STR(STATUS_CTX_LICENSE_NOT_AVAILABLE);
+ CASE_RETURN_STR(STATUS_CTX_LICENSE_EXPIRED);
+ CASE_RETURN_STR(STATUS_CTX_WINSTATION_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_CTX_WINSTATION_NAME_COLLISION);
+ CASE_RETURN_STR(STATUS_CTX_WINSTATION_BUSY);
+ CASE_RETURN_STR(STATUS_CTX_BAD_VIDEO_MODE);
+ CASE_RETURN_STR(STATUS_CTX_GRAPHICS_INVALID);
+ CASE_RETURN_STR(STATUS_CTX_NOT_CONSOLE);
+ CASE_RETURN_STR(STATUS_CTX_CLIENT_QUERY_TIMEOUT);
+ CASE_RETURN_STR(STATUS_CTX_CONSOLE_DISCONNECT);
+ CASE_RETURN_STR(STATUS_CTX_CONSOLE_CONNECT);
+ CASE_RETURN_STR(STATUS_CTX_SHADOW_DENIED);
+ CASE_RETURN_STR(STATUS_CTX_WINSTATION_ACCESS_DENIED);
+ CASE_RETURN_STR(STATUS_CTX_INVALID_WD);
+ CASE_RETURN_STR(STATUS_CTX_WD_NOT_FOUND);
+ CASE_RETURN_STR(STATUS_CTX_SHADOW_INVALID);
+ CASE_RETURN_STR(STATUS_CTX_SHADOW_DISABLED);
+ CASE_RETURN_STR(STATUS_RDP_PROTOCOL_ERROR);
+ CASE_RETURN_STR(STATUS_CTX_CLIENT_LICENSE_NOT_SET);
+ CASE_RETURN_STR(STATUS_CTX_CLIENT_LICENSE_IN_USE);
+ CASE_RETURN_STR(STATUS_PNP_BAD_MPS_TABLE);
+ CASE_RETURN_STR(STATUS_PNP_TRANSLATION_FAILED);
+ CASE_RETURN_STR(STATUS_PNP_IRQ_TRANSLATION_FAILED);
+ default:
+ return "Unknown";
+ }
+}
+#endif // DBG
--- /dev/null
+/*
+ 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_
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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));
+}
--- /dev/null
+/*
+ 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_
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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
+}
--- /dev/null
+/*
+ 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, ¶ms[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;
+}
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+add_subdirectory(vfd)
--- /dev/null
+/*
+ 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_
--- /dev/null
+/*
+ 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_
--- /dev/null
+/*
+ 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_
--- /dev/null
+/*
+ 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_
--- /dev/null
+/*
+ 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
+add_subdirectory(vfdlib)
add_subdirectory(win32err)
--- /dev/null
+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)
--- /dev/null
+/*
+ vfdctl.c
+
+ Virtual Floppy Drive for Windows
+ Driver control library
+ Driver and image control 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 <dbt.h>
+#ifdef _MSC_VER
+#pragma warning (push, 3)
+#endif
+#include <shlobj.h>
+#include <winioctl.h>
+#ifdef _MSC_VER
+#pragma warning (pop)
+#endif
+#include <stdio.h>
+
+#include "vfdtypes.h"
+#include "vfdio.h"
+#include "vfdapi.h"
+#include "vfdlib.h"
+#include "vfdver.h"
+
+#ifndef IOCTL_DISK_GET_LENGTH_INFO
+// Old winioctl.h header doesn't define the following
+
+#define IOCTL_DISK_GET_LENGTH_INFO CTL_CODE(\
+IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+typedef struct _GET_LENGTH_INFORMATION {
+ LARGE_INTEGER Length;
+} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION;
+
+#endif // IOCTL_DISK_GET_LENGTH_INFO
+
+//
+// DOS device name (\\.\VirtualFD)
+//
+#ifndef __REACTOS__
+#define VFD_DEVICE_TEMPLATE "\\\\.\\" VFD_DEVICE_BASENAME "%u"
+#else
+#define VFD_DEVICE_TEMPLATE "\\\\.\\" VFD_DEVICE_BASENAME "%lu"
+#endif
+#define VFD_VOLUME_TEMPLATE "\\\\.\\%c:"
+
+#define VFD_INSTALL_DIRECTORY "\\system32\\drivers\\"
+
+#ifdef _DEBUG
+#ifndef __REACTOS__
+extern ULONG TraceFlags = (ULONG)-1;//0;
+extern CHAR *TraceFile = NULL;
+extern ULONG TraceLine = 0;
+#else
+ULONG TraceFlags = (ULONG)-1;//0;
+CHAR const * TraceFile = NULL;
+ULONG TraceLine = 0;
+#endif
+#endif
+
+//
+// broadcast a WM_DEVICECHANGE system message to inform
+// a drive letter creation / removal
+//
+#define VFD_LINK_CREATED 0
+#define VFD_LINK_REMOVED 1
+
+static void VfdBroadcastLink(
+ CHAR cLetter,
+ BOOL bRemoved)
+{
+ DWORD receipients;
+ DWORD device_event;
+ DEV_BROADCAST_VOLUME params;
+
+ if (!isalpha(cLetter)) {
+ VFDTRACE(0,
+ ("VfdBroadcastLink: invalid parameter"))
+ return;
+ }
+
+ receipients = BSM_APPLICATIONS;
+
+ device_event = bRemoved ?
+ DBT_DEVICEREMOVECOMPLETE : DBT_DEVICEARRIVAL;
+
+ ZeroMemory(¶ms, sizeof(params));
+
+ params.dbcv_size = sizeof(params);
+ params.dbcv_devicetype = DBT_DEVTYP_VOLUME;
+ params.dbcv_reserved = 0;
+ params.dbcv_unitmask = (1 << (toupper(cLetter) - 'A'));
+ params.dbcv_flags = 0;
+
+ if (BroadcastSystemMessage(
+ BSF_NOHANG | BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG,
+ &receipients,
+ WM_DEVICECHANGE,
+ device_event,
+ (LPARAM)¶ms) <= 0) {
+
+ VFDTRACE(0,
+ ("VfdBroadcastLink: BroadcastSystemMessage - %s",
+ SystemMessage(GetLastError())));
+ }
+}
+
+//
+// Broadcast a VFD notify message
+//
+static __inline void VfdNotify(
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ // SendNotifyMessage causes volume locking conflict (I think)
+ // on Windows XP while closing an image with VfdWin
+// SendNotifyMessage(HWND_BROADCAST, uVfdMsg, wParam, lParam);
+ PostMessage(HWND_BROADCAST, g_nNotifyMsg, wParam, lParam);
+}
+
+#ifdef VFD_EMBED_DRIVER
+//
+// Restore the VFD driver file in the system directory
+//
+
+static DWORD VfdRestoreDriver(
+ PCSTR sPath)
+{
+#define FUNC "VfdRestoreDriver"
+ HRSRC hRes;
+ DWORD size;
+ HGLOBAL hDrv;
+ PVOID pData;
+ DWORD result;
+ HANDLE hFile;
+ DWORD ret;
+
+ //
+ // Prepare driver binary
+ //
+
+ // use embedded driver binary
+
+#define S(s) #s
+ hRes = FindResource(g_hDllModule,
+ S(VFD_DRIVER_NAME_ID), S(VFD_DRIVER_TYPE_ID));
+#undef S
+
+ if (hRes == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": FindResource - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ size = SizeofResource(g_hDllModule, hRes);
+
+ if (size == 0) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": SizeofResource - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ hDrv = LoadResource(g_hDllModule, hRes);
+
+ if (hDrv == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": LoadResource - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ pData = LockResource(hDrv);
+
+ if (pData == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": LockResource - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // create the driver file
+
+ hFile = CreateFile(sPath, GENERIC_WRITE,
+ 0, NULL, OPEN_ALWAYS, 0, NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": CreateFile(%s) - %s",
+ sPath, SystemMessage(ret)));
+
+ return ret;
+ }
+
+ if (!WriteFile(hFile, pData, size, &result, NULL) ||
+ size != result) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": CreateFile - %s",
+ SystemMessage(ret)));
+
+ CloseHandle(hFile);
+ return ret;
+ }
+
+ SetEndOfFile(hFile);
+ CloseHandle(hFile);
+
+ return ERROR_SUCCESS;
+}
+#endif // VFD_EMBED_DRIVER
+
+//
+// Install the Virtual Floppy Driver
+//
+DWORD WINAPI VfdInstallDriver(
+ PCSTR sFileName,
+ DWORD nStart)
+{
+#undef FUNC
+#define FUNC "VfdInstallDriver"
+ SC_HANDLE hScManager; // Service Control Manager
+ SC_HANDLE hService = NULL; // Service (= Driver)
+#ifndef VFD_EMBED_DRIVER
+ CHAR file_path[MAX_PATH];
+ PSTR file_name;
+#endif // VFD_EMBED_DRIVER
+ CHAR system_dir[MAX_PATH];
+ PSTR inst_path;
+ DWORD len;
+ DWORD ret = ERROR_SUCCESS;
+
+ // get SystemRoot directory path
+
+// len = GetEnvironmentVariable(
+// "SystemRoot", system_dir, sizeof(system_dir));
+ len = GetWindowsDirectory(system_dir, sizeof(system_dir));
+
+ if (len == 0 || len > sizeof(system_dir)) {
+ VFDTRACE(0,
+ (FUNC ": %%SystemRoot%% is empty or too long.\n"));
+
+ return ERROR_BAD_ENVIRONMENT;
+ }
+
+ inst_path = &system_dir[len];
+
+#ifdef VFD_EMBED_DRIVER
+ //
+ // use embedded driver file
+ //
+ strcpy(inst_path++, VFD_INSTALL_DIRECTORY VFD_DRIVER_FILENAME);
+
+ ret = VfdRestoreDriver(system_dir);
+
+ if (ret != ERROR_SUCCESS) {
+ return ret;
+ }
+
+#else // VFD_EMBED_DRIVER
+ // Prepare driver binary's full path
+
+ if (sFileName == NULL || *sFileName == '\0') {
+
+ // default driver file is vfd.sys in the same directory as executable
+
+ len = GetModuleFileName(
+ NULL, file_path, sizeof(file_path));
+
+ if (len == 0) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": GetModuleFileName - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // search the last '\' character
+
+ while (len > 0 && file_path[len - 1] != '\\') {
+ len --;
+ }
+
+ // supply the file name (vfd.sys)
+
+ file_name = &file_path[len];
+ strcpy(file_name, VFD_DRIVER_FILENAME);
+ }
+ else {
+
+ // ensure that tha path is an absolute full path
+
+ len = GetFullPathName(
+ sFileName,
+ sizeof(file_path),
+ file_path,
+ &file_name);
+
+ if (len == 0) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": GetFullPathName(%s) - %s\n",
+ sFileName, SystemMessage(ret)));
+
+ return ret;
+ }
+
+ if (GetFileAttributes(file_path) & FILE_ATTRIBUTE_DIRECTORY) {
+ // if the specified path is a directory,
+ // supply the file name (vfd.sys)
+
+ file_name = &file_path[len];
+ strcpy(file_name++, "\\" VFD_DRIVER_FILENAME);
+ }
+ }
+
+ // Check if the file is a valid Virtual Floppy driver
+
+ ret = VfdCheckDriverFile(file_path, NULL);
+
+ if (ret != ERROR_SUCCESS) {
+ VFDTRACE(0,
+ (FUNC ": VfdCheckDriverFile(%s)\n", file_path));
+
+ return ret;
+ }
+
+ // if the path is under the system directory, make it relative
+ // to the system directory
+
+ len = strlen(system_dir);
+
+ if (!_strnicmp(file_path, system_dir, len)) {
+ inst_path = &file_path[len];
+
+ while (*inst_path == '\\') {
+ inst_path++;
+ }
+ }
+ else {
+ inst_path = &file_path[0];
+ }
+#endif // VFD_EMBED_DRIVER
+
+ // Connect to the Service Control Manager
+
+ hScManager = OpenSCManager(
+ NULL, // local machine
+ NULL, // local database
+ SC_MANAGER_CREATE_SERVICE); // access required
+
+ if (hScManager == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenSCManager() - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ // Create a new service object
+
+ hService = CreateService(
+ hScManager, // service control manager
+ VFD_DEVICE_BASENAME, // internal service name
+ VFD_DEVICE_BASENAME, // display name
+ SERVICE_ALL_ACCESS, // access mode
+ SERVICE_KERNEL_DRIVER, // service type
+ nStart, // service start type
+ SERVICE_ERROR_NORMAL, // start error sevirity
+ inst_path, // service image file path
+ NULL, // service group
+ NULL, // service tag
+ NULL, // service dependency
+ NULL, // use LocalSystem account
+ NULL // password for the account
+ );
+
+ if (!hService) {
+ // Failed to create a service object
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": CreateService() - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+cleanup:
+ // Close the service object handle
+
+ if (hService) {
+ CloseServiceHandle(hService);
+ }
+
+ // Close handle to the service control manager.
+
+ if (hScManager) {
+ CloseServiceHandle(hScManager);
+ }
+
+ if (ret == ERROR_SUCCESS) {
+ // Broadcast the successful operation
+ VfdNotify(VFD_OPERATION_INSTALL, 0);
+ }
+#ifdef VFD_EMBED_DRIVER
+ else {
+ // Delete the restored driver file
+ DeleteFile(system_dir);
+ }
+#endif // VFD_EMBED_DRIVER
+
+ return ret;
+}
+
+//
+// Configure the Virtual Floppy Driver (change the start method)
+//
+
+DWORD WINAPI VfdConfigDriver(
+ DWORD nStart)
+{
+#undef FUNC
+#define FUNC "VfdConfigDriver"
+ SC_HANDLE hScManager; // Service Control Manager
+ SC_HANDLE hService; // Service (= Driver)
+ DWORD ret = ERROR_SUCCESS;
+
+ // Connect to the Service Control Manager
+
+ hScManager = OpenSCManager(NULL, NULL, 0);
+
+ if (hScManager == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenSCManager() - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // Open the VFD driver entry in the service database
+
+ hService = OpenService(
+ hScManager, // Service control manager
+ VFD_DEVICE_BASENAME, // service name
+ SERVICE_CHANGE_CONFIG); // service access mode
+
+ if (hService == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenService(SERVICE_CHANGE_CONFIG) - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ // Change the start method of the VFD driver
+
+ if (!ChangeServiceConfig(
+ hService,
+ SERVICE_NO_CHANGE,
+ nStart,
+ SERVICE_NO_CHANGE,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL)) {
+
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": ChangeServiceConfig() - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+cleanup:
+ // Close the service object handle
+
+ if (hService) {
+ CloseServiceHandle(hService);
+ }
+
+ // Close handle to the service control manager.
+
+ if (hScManager) {
+ CloseServiceHandle(hScManager);
+ }
+
+ // Broadcast the successful operation
+
+ if (ret == ERROR_SUCCESS) {
+ VfdNotify(VFD_OPERATION_CONFIG, 0);
+ }
+
+ return ret;
+}
+
+//
+// Remove the Virtual Floppy Driver entry from the service database
+//
+DWORD WINAPI VfdRemoveDriver()
+{
+#undef FUNC
+#define FUNC "VfdRemoveDriver"
+ SC_HANDLE hScManager; // Service Control Manager
+ SC_HANDLE hService; // Service (= Driver)
+ CHAR file_path[MAX_PATH];
+ DWORD ret = ERROR_SUCCESS;
+
+ // Get the current driver path
+
+ ret = VfdGetDriverConfig(file_path, NULL);
+
+ if (ret != ERROR_SUCCESS) {
+ return ret;
+ }
+
+ // Connect to the Service Control Manager
+
+ hScManager = OpenSCManager(NULL, NULL, 0);
+
+ if (hScManager == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenSCManager() - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // Open the VFD driver entry in the service database
+
+ hService = OpenService(
+ hScManager, // Service control manager
+ VFD_DEVICE_BASENAME, // service name
+ DELETE); // service access mode
+
+ if (hService == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenService(DELETE) - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ // Remove driver entry from registry
+
+ if (!DeleteService(hService)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeleteService() - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+cleanup:
+ // Close the service object handle
+
+ if (hService) {
+ CloseServiceHandle(hService);
+ }
+
+ // Close handle to the service control manager.
+
+ if (hScManager) {
+ CloseServiceHandle(hScManager);
+ }
+
+ // Broadcast the successful operation
+
+ if (ret == ERROR_SUCCESS) {
+ VfdNotify(VFD_OPERATION_REMOVE, 0);
+
+#ifdef VFD_EMBED_DRIVER
+ // Remove the driver file
+ DeleteFile(file_path);
+#endif // VFD_EMBED_DRIVER
+ }
+
+ return ret;
+}
+
+//
+// Start the Virtual Floppy Driver
+//
+DWORD WINAPI VfdStartDriver(
+ PDWORD pState)
+{
+#undef FUNC
+#define FUNC "VfdStartDriver"
+ SC_HANDLE hScManager; // Service Control Manager
+ SC_HANDLE hService; // Service (= Driver)
+ SERVICE_STATUS stat;
+ DWORD ret = ERROR_SUCCESS;
+ HCURSOR original;
+ int i;
+
+ if (pState) {
+ *pState = 0;
+ }
+
+ // Connect to the Service Control Manager
+
+ hScManager = OpenSCManager(NULL, NULL, 0);
+
+ if (hScManager == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenSCManager() - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // show an hourglass cursor
+
+ original = SetCursor(LoadCursor(NULL, IDC_WAIT));
+
+ // Open the VFD driver entry in the service database
+
+ hService = OpenService(
+ hScManager, // Service control manager
+ VFD_DEVICE_BASENAME, // service name
+ SERVICE_START
+ | SERVICE_QUERY_STATUS); // service access mode
+
+ if (hService == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenService(SERVICE_START) - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ // Start the driver
+
+ if (!StartService(hService, 0, NULL)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": StartService() - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ // Wait until the driver is properly running
+
+ i = 0;
+
+ for (;;) {
+ if (!QueryServiceStatus(hService, &stat)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": QueryServiceStatus() - %s",
+ SystemMessage(ret)));
+
+ break;
+ }
+
+ if (stat.dwCurrentState == SERVICE_RUNNING || ++i == 5) {
+ break;
+ }
+
+ Sleep(1000);
+ }
+
+ if (stat.dwCurrentState == SERVICE_RUNNING) {
+
+ // Broadcast the successful operation
+
+ if (ret == ERROR_SUCCESS) {
+ VfdNotify(VFD_OPERATION_START, 0);
+ }
+
+ // broadcast the arrival of VFD drives
+ // otherwise WinXP explorer doesn't recognize the VFD drives
+
+ for (i = 0; i < VFD_MAXIMUM_DEVICES; i++) {
+ HANDLE hDevice;
+ CHAR letter = 0;
+
+ hDevice = VfdOpenDevice(i);
+
+ if (hDevice != INVALID_HANDLE_VALUE) {
+
+ VfdGetGlobalLink(hDevice, &letter);
+
+ CloseHandle(hDevice);
+
+ if (isalpha(letter)) {
+ VfdBroadcastLink(letter, VFD_LINK_CREATED);
+ VfdNotify(VFD_OPERATION_SETLINK, i);
+ }
+ }
+ else {
+ VFDTRACE(0,
+ (FUNC ": VfdOpenDevice(%d) - %s",
+ i, SystemMessage(GetLastError())));
+ }
+ }
+ }
+ else {
+ // somehow failed to start the driver
+
+ ret = ERROR_SERVICE_NOT_ACTIVE;
+ }
+
+ if (pState) {
+ *pState = stat.dwCurrentState;
+ }
+
+cleanup:
+ // Close the service object handle
+
+ if (hService) {
+ CloseServiceHandle(hService);
+ }
+
+ // Close handle to the service control manager.
+
+ if (hScManager) {
+ CloseServiceHandle(hScManager);
+ }
+
+ // revert to the original cursor
+
+ SetCursor(original);
+
+ return ret;
+}
+
+//
+// Stop the Virtual Floppy Driver
+//
+DWORD WINAPI VfdStopDriver(
+ PDWORD pState)
+{
+#undef FUNC
+#define FUNC "VfdStopDriver"
+ SC_HANDLE hScManager; // Service Control Manager
+ SC_HANDLE hService; // Service (= Driver)
+ SERVICE_STATUS stat;
+ CHAR drive_letters[VFD_MAXIMUM_DEVICES];
+ DWORD ret = ERROR_SUCCESS;
+ int i;
+ HCURSOR original;
+
+ if (pState) {
+ *pState = 0;
+ }
+
+ // Connect to the Service Control Manager
+
+ hScManager = OpenSCManager(NULL, NULL, 0);
+
+ if (hScManager == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenSCManager() - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // Show the hourglass cursor
+
+ original = SetCursor(LoadCursor(NULL, IDC_WAIT));
+
+ // Open the VFD driver entry in the service database
+
+ hService = OpenService(
+ hScManager, // Service control manager
+ VFD_DEVICE_BASENAME, // service name
+ SERVICE_STOP
+ | SERVICE_QUERY_STATUS); // service access mode
+
+ if (hService == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenService(SERVICE_STOP) - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ // Get assigned drive letters
+
+ for (i = 0; i < VFD_MAXIMUM_DEVICES; i++) {
+ HANDLE hDevice;
+ CHAR letter;
+
+ hDevice = VfdOpenDevice(i);
+
+ if (hDevice != INVALID_HANDLE_VALUE) {
+
+ // remove all session local drive letters
+
+ while (VfdGetLocalLink(hDevice, &letter) == ERROR_SUCCESS &&
+ isalpha(letter)) {
+ VfdSetLocalLink(hDevice, 0);
+ }
+
+ // store existing persistent drive letters
+
+ VfdGetGlobalLink(hDevice, &drive_letters[i]);
+
+ CloseHandle(hDevice);
+ }
+ else {
+ VFDTRACE(0,
+ (FUNC ": VfdOpenDevice(%d) - %s",
+ i, SystemMessage(GetLastError())));
+ }
+ }
+
+ // Stop the driver
+
+ if (!ControlService(hService, SERVICE_CONTROL_STOP, &stat)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": ControlService(SERVICE_CONTROL_STOP) - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ // Wait until the driver is stopped
+
+ i = 0;
+
+ while (stat.dwCurrentState != SERVICE_STOPPED && ++i < 5) {
+ Sleep(1000);
+
+ if (!QueryServiceStatus(hService, &stat)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": QueryServiceStatus() - %s",
+ SystemMessage(ret)));
+
+ break;
+ }
+ }
+
+ if (stat.dwCurrentState != SERVICE_RUNNING) {
+
+ // broadcast the removal of persistent drive letters
+
+ for (i = 0; i < VFD_MAXIMUM_DEVICES; i++) {
+ if (isalpha(drive_letters[i])) {
+ VfdBroadcastLink(drive_letters[i], VFD_LINK_REMOVED);
+ VfdNotify(VFD_OPERATION_DELLINK, i);
+ }
+ }
+ }
+
+ if (pState) {
+ *pState = stat.dwCurrentState;
+ }
+
+cleanup:
+ // Close the service object handle
+
+ if (hService) {
+ CloseServiceHandle(hService);
+ }
+
+ // Close handle to the service control manager.
+
+ if (hScManager) {
+ CloseServiceHandle(hScManager);
+ }
+
+ // Broadcast the successful operation
+
+ if (ret == ERROR_SUCCESS) {
+ VfdNotify(VFD_OPERATION_STOP, 0);
+ }
+
+ // revert to the original cursor
+
+ SetCursor(original);
+
+ return ret;
+}
+
+//
+// Get the Virtual Floppy Driver configuration
+//
+DWORD WINAPI VfdGetDriverConfig(
+ PSTR sFileName,
+ PDWORD pStart)
+{
+#undef FUNC
+#define FUNC "VfdGetDriverConfig"
+ SC_HANDLE hScManager; // Service Control Manager
+ SC_HANDLE hService; // Service (= Driver)
+ LPQUERY_SERVICE_CONFIG config = NULL;
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+
+ if (sFileName) {
+ ZeroMemory(sFileName, MAX_PATH);
+ }
+
+ if (pStart) {
+ *pStart = 0;
+ }
+
+ // Connect to the Service Control Manager
+
+ hScManager = OpenSCManager(NULL, NULL, 0);
+
+ if (hScManager == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenSCManager() - %s", SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // Open the VFD driver entry in the service database
+
+ hService = OpenService(
+ hScManager, // Service control manager
+ VFD_DEVICE_BASENAME, // service name
+ SERVICE_QUERY_CONFIG); // service access mode
+
+ if (hService == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenService(SERVICE_QUERY_CONFIG) - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ // Get the length of config information
+
+ if (!QueryServiceConfig(hService, NULL, 0, &result)) {
+ ret = GetLastError();
+
+ if (ret == ERROR_INSUFFICIENT_BUFFER) {
+ ret = ERROR_SUCCESS;
+ }
+ else {
+ VFDTRACE(0,
+ (FUNC ": QueryServiceConfig() - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+ }
+
+ // allocate a required buffer
+
+ config = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LPTR, result);
+
+ if (config == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": LocalAlloc(%lu) - %s\n",
+ result, SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ // get the config information
+
+ if (!QueryServiceConfig(hService, config, result, &result)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": QueryServiceConfig() - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ // copy information to output buffer
+
+ if (sFileName) {
+ if (strncmp(config->lpBinaryPathName, "\\??\\", 4) == 0) {
+
+ // driver path is an absolute UNC path
+ strncpy(
+ sFileName,
+ config->lpBinaryPathName + 4,
+ MAX_PATH);
+ }
+ else if (config->lpBinaryPathName[0] == '\\' ||
+ (isalpha(config->lpBinaryPathName[0]) &&
+ config->lpBinaryPathName[1] == ':')) {
+
+ // driver path is an absolute path
+ strncpy(sFileName,
+ config->lpBinaryPathName,
+ MAX_PATH);
+ }
+ else {
+ // driver path is relative to the SystemRoot
+// DWORD len = GetEnvironmentVariable(
+// "SystemRoot", sFileName, MAX_PATH);
+
+ DWORD len = GetWindowsDirectory(sFileName, MAX_PATH);
+
+ if (len == 0 || len > MAX_PATH) {
+ VFDTRACE(0,
+ (FUNC ": %%SystemRoot%% is empty or too long.\n"));
+
+ ret = ERROR_BAD_ENVIRONMENT;
+ goto cleanup;
+ }
+
+ sprintf((sFileName + len), "\\%s",
+ config->lpBinaryPathName);
+ }
+ }
+
+ if (pStart) {
+ *pStart = config->dwStartType;
+ }
+
+cleanup:
+ // Free service config buffer
+
+ if (config) {
+ LocalFree(config);
+ }
+
+ // Close the service object handle
+
+ if (hService) {
+ CloseServiceHandle(hService);
+ }
+
+ // Close handle to the service control manager.
+
+ if (hScManager) {
+ CloseServiceHandle(hScManager);
+ }
+
+ return ret;
+}
+
+//
+// Get the Virtual Floppy Driver running state
+//
+DWORD WINAPI VfdGetDriverState(
+ PDWORD pState)
+{
+#undef FUNC
+#define FUNC "VfdGetDriverState"
+ SC_HANDLE hScManager = NULL; // Service Control Manager
+ SC_HANDLE hService = NULL; // Service (= Driver)
+ SERVICE_STATUS status;
+ DWORD ret = ERROR_SUCCESS;
+
+ if (pState) {
+ *pState = 0;
+ }
+
+ // Connect to the Service Control Manager
+
+ hScManager = OpenSCManager(NULL, NULL, 0);
+
+ if (hScManager == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": OpenSCManager() - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // Open the VFD driver entry in the service database
+
+ hService = OpenService(
+ hScManager, // Service control manager
+ VFD_DEVICE_BASENAME, // service name
+ SERVICE_QUERY_STATUS); // service access mode
+
+ if (hService == NULL) {
+
+ ret = GetLastError();
+
+ if (ret == ERROR_SERVICE_DOES_NOT_EXIST) {
+
+ if (pState) {
+ *pState = VFD_NOT_INSTALLED;
+ }
+
+ ret = ERROR_SUCCESS;
+ }
+ else {
+ VFDTRACE(0,
+ (FUNC ": OpenService(SERVICE_QUERY_STATUS) - %s",
+ SystemMessage(ret)));
+ }
+
+ goto cleanup;
+ }
+
+ // Get current driver status
+
+ ZeroMemory(&status, sizeof(status));
+
+ if (!QueryServiceStatus(hService, &status)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": QueryServiceStatus() - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ if (pState) {
+ *pState = status.dwCurrentState;
+ }
+
+cleanup:
+ // Close the service object handle
+
+ if (hService) {
+ CloseServiceHandle(hService);
+ }
+
+ // Close handle to the service control manager.
+
+ if (hScManager) {
+ CloseServiceHandle(hScManager);
+ }
+
+ return ret;
+}
+
+//
+// open a Virtual Floppy drive without showing the "Insert Floppy"
+// dialog when the drive is empty.
+//
+HANDLE WINAPI VfdOpenDevice(
+ ULONG nTarget) // either a drive letter or a device number
+{
+#undef FUNC
+#define FUNC "VfdOpenDevice"
+ CHAR dev_name[20];
+ UINT err_mode;
+ HANDLE hDevice;
+
+ // format a device name string
+
+ if (isalpha(nTarget)) {
+ // nTarget is a drive letter
+ // \\.\<x>:
+#ifndef __REACTOS__
+ sprintf(dev_name, VFD_VOLUME_TEMPLATE, nTarget);
+#else
+ sprintf(dev_name, VFD_VOLUME_TEMPLATE, (CHAR)nTarget);
+#endif
+ }
+ else if (isdigit(nTarget)) {
+ // nTarget is a device number in character
+ // \\.\VirtualFD<n>
+ sprintf(dev_name, VFD_DEVICE_TEMPLATE, nTarget - '0');
+ }
+ else {
+ // nTarget is a device number value
+ // \\.\VirtualFD<n>
+ sprintf(dev_name, VFD_DEVICE_TEMPLATE, nTarget);
+ }
+
+ // change error mode in order to avoid "Insert Floppy" dialog
+
+ err_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ // open the target drive
+
+ hDevice = CreateFile(
+ dev_name,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_NO_BUFFERING,
+ NULL);
+
+ // revert to the original error mode
+
+ SetErrorMode(err_mode);
+
+ if (hDevice != INVALID_HANDLE_VALUE) {
+
+ // check if the target is a valid VFD drive
+
+ ULONG version;
+
+ if (VfdGetDriverVersion(hDevice, &version) != ERROR_SUCCESS) {
+
+ // Failed to get the driver version
+
+ CloseHandle(hDevice);
+ hDevice = INVALID_HANDLE_VALUE;
+ }
+ else if ((version & ~0x80000000) !=
+ MAKELONG(VFD_DRIVER_MINOR, VFD_DRIVER_MAJOR)) {
+
+ // the driver version mismatch
+
+// CloseHandle(hDevice);
+// hDevice = INVALID_HANDLE_VALUE;
+
+ SetLastError(ERROR_REVISION_MISMATCH);
+ }
+ }
+ else {
+ VFDTRACE(0,(
+ "CreateFile(%s) - %s", dev_name,
+ SystemMessage(GetLastError())));;
+ }
+
+ return hDevice;
+}
+
+//
+// Open a Virtual Floppy Image
+//
+DWORD WINAPI VfdOpenImage(
+ HANDLE hDevice,
+ PCSTR sFileName,
+ VFD_DISKTYPE nDiskType,
+ VFD_MEDIA nMediaType,
+ VFD_FLAGS nMediaFlags)
+{
+#undef FUNC
+#define FUNC "VfdOpenImage"
+ PCSTR prefix;
+ CHAR abspath[MAX_PATH];
+ DWORD name_len;
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+
+ PVFD_IMAGE_INFO image_info = NULL;
+ PUCHAR image_buf = NULL;
+ ULONG image_size;
+ VFD_FILETYPE file_type;
+
+ //
+ // Check parameters
+ //
+
+ if (hDevice == NULL ||
+ hDevice == INVALID_HANDLE_VALUE) {
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if (nMediaType == VFD_MEDIA_NONE ||
+ nMediaType >= VFD_MEDIA_MAX) {
+
+ VFDTRACE(0,
+ (FUNC ": Invalid MediaType - %u\n", nMediaType));
+
+ return ERROR_INVALID_PARAMETER;
+ }
+
+
+ if (sFileName && *sFileName) {
+
+ // check file contents and attributes
+
+ HANDLE hFile = CreateFile(sFileName, GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": CreateFile(%s) - %s",
+ sFileName, SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // try extracting image data from zip compressed file
+
+ ExtractZipImage(hFile, &image_buf, &image_size);
+
+ if (image_buf) {
+
+ file_type = VFD_FILETYPE_ZIP;
+
+ // imz file must be opened in RAM mode
+
+ if (nDiskType == VFD_DISKTYPE_FILE) {
+
+ VFDTRACE(0,
+ (FUNC ": %s is a zip compressed file",
+ sFileName));
+
+ CloseHandle(hFile);
+ ret = ERROR_INVALID_PARAMETER;
+
+ goto exit_func;
+ }
+ }
+ else {
+
+ file_type = VFD_FILETYPE_RAW;
+
+ if (nDiskType == VFD_DISKTYPE_FILE) {
+
+ // direct image file must not be compressed or encrypted
+
+ BY_HANDLE_FILE_INFORMATION info;
+
+ if (!GetFileInformationByHandle(hFile, &info)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": GetFileInformationByHandle - %s",
+ SystemMessage(ret)));
+
+ CloseHandle(hFile);
+
+ return ret;
+ }
+
+ if (info.dwFileAttributes &
+ (FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_ENCRYPTED)) {
+
+ VFDTRACE(0,
+ (FUNC ": file is compressed/encrypted"));
+
+ CloseHandle(hFile);
+
+ return ERROR_FILE_ENCRYPTED;
+ }
+
+ image_size = info.nFileSizeLow;
+ }
+ else {
+
+ // prepare image data for a file based RAM disk
+
+ image_size = GetFileSize(hFile, NULL);
+
+ if (image_size == 0 || image_size == INVALID_FILE_SIZE) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": GetFileSize - %s",
+ SystemMessage(ret)));
+
+ CloseHandle(hFile);
+
+ return ret;
+ }
+
+ image_buf = (PUCHAR)LocalAlloc(LPTR, image_size);
+
+ if (image_buf == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": LocalAlloc - %s",
+ SystemMessage(ret)));
+
+ CloseHandle(hFile);
+
+ return ret;
+ }
+
+ if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) != 0) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": SetFilePointer - %s",
+ SystemMessage(ret)));
+
+ CloseHandle(hFile);
+
+ goto exit_func;
+ }
+
+ if (!ReadFile(hFile, image_buf, image_size, &result, NULL) ||
+ image_size != result) {
+
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": ReadFile - %s",
+ SystemMessage(ret)));
+
+ CloseHandle(hFile);
+
+ goto exit_func;
+ }
+ }
+ }
+
+ CloseHandle(hFile);
+
+ // Prepare absolute path in the kernel namespace
+
+ if (*sFileName == '\\' && *(sFileName + 1) == '\\') {
+
+ // \\server\share\path\floppy.img
+
+ prefix = "\\??\\UNC";
+ sFileName++; // drip the first '\'
+ }
+ else {
+
+ // local path
+
+ PSTR file_part;
+
+ if (GetFullPathName(sFileName,
+ sizeof(abspath), abspath, &file_part) == 0) {
+
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": GetFullPathName(%s) - %s\n",
+ sFileName, SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ prefix = "\\??\\";
+ sFileName = abspath;
+ }
+
+ name_len = strlen(prefix) + strlen(sFileName);
+ }
+ else {
+
+ // filename is not specified -- pure RAM disk
+
+ nDiskType = VFD_DISKTYPE_RAM;
+ file_type = VFD_FILETYPE_NONE;
+
+ prefix = NULL;
+ name_len = 0;
+
+ // prepare a FAT formatted RAM image
+
+ image_size = VfdGetMediaSize(nMediaType);
+
+ image_buf = (PUCHAR)LocalAlloc(LPTR, image_size);
+
+ if (image_buf == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": LocalAlloc - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ FormatBufferFat(image_buf, VFD_BYTE_TO_SECTOR(image_size));
+ }
+
+ if (image_size < VfdGetMediaSize(nMediaType)) {
+
+ // image is too small for the specified media type
+
+ VFDTRACE(0,
+ (FUNC ": Image is too small for the specified media type\n"));
+
+ ret = ERROR_INVALID_PARAMETER;
+ goto exit_func;
+ }
+
+ // prepare VFD_IMAGE_INFO structure
+
+ image_info = (PVFD_IMAGE_INFO)LocalAlloc(LPTR,
+ sizeof(VFD_IMAGE_INFO) + name_len + 1);
+
+ if (image_info == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": LocalAlloc(%lu) - %s\n",
+ sizeof(VFD_IMAGE_INFO) + name_len + 1,
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ ZeroMemory(image_info,
+ sizeof(VFD_IMAGE_INFO) + name_len + 1);
+
+ if (name_len) {
+ sprintf(image_info->FileName,
+ "%s%s", prefix, sFileName);
+ }
+
+ image_info->NameLength = (USHORT)name_len;
+
+ image_info->DiskType = nDiskType;
+ image_info->MediaType = nMediaType;
+ image_info->MediaFlags = nMediaFlags;
+ image_info->FileType = file_type;
+ image_info->ImageSize = image_size;
+
+ if (nDiskType != VFD_DISKTYPE_FILE) {
+ // protect flag for a RAM disk is set after
+ // initializing the image buffer
+ image_info->MediaFlags &= ~VFD_FLAG_WRITE_PROTECTED;
+ }
+
+ VFDTRACE(0,
+ (FUNC ": Opening file \"%s\" (%lu bytes) %s %s %s %s\n",
+ name_len ? image_info->FileName : "<RAM>",
+ image_info->ImageSize,
+ (file_type == VFD_FILETYPE_ZIP) ? "ZIP image" : "RAW image",
+ VfdMediaTypeName(nMediaType),
+ (nDiskType == VFD_DISKTYPE_FILE) ? "FILE disk" : "RAM disk",
+ (nMediaFlags & VFD_FLAG_WRITE_PROTECTED) ? "Protected" : "Writable"));
+
+ // Open the image file / create a ram disk
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_VFD_OPEN_IMAGE,
+ image_info,
+ sizeof(VFD_IMAGE_INFO) + name_len,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_OPEN_FILE) - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // initialize the RAM disk image
+
+ if (nDiskType != VFD_DISKTYPE_FILE) {
+
+ image_size &= ~VFD_SECTOR_ALIGN_MASK;
+
+ if (SetFilePointer(hDevice, 0, NULL, FILE_BEGIN) != 0) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": SetFilePointer - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ if (!WriteFile(hDevice, image_buf, image_size, &result, NULL) ||
+ image_size != result) {
+
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": WriteFile - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ if (nMediaFlags & VFD_FLAG_WRITE_PROTECTED) {
+ VfdWriteProtect(hDevice, TRUE);
+ }
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_VFD_RESET_MODIFY,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_RESET_MODIFY) - %s",
+ SystemMessage(GetLastError())));
+ }
+ }
+
+ // Broadcast the successful operation
+
+ if (ret == ERROR_SUCCESS) {
+ ULONG number;
+ CHAR root[] = "A:\\";
+
+ if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) {
+ VfdNotify(VFD_OPERATION_OPEN, number);
+ }
+
+ VfdGetGlobalLink(hDevice, &root[0]);
+
+ if (isalpha(root[0])) {
+ SHChangeNotify(SHCNE_MEDIAINSERTED, SHCNF_PATH, root, NULL);
+ }
+
+ while (VfdGetLocalLink(hDevice, &root[0]) == ERROR_SUCCESS &&
+ isalpha(root[0])) {
+ SHChangeNotify(SHCNE_MEDIAINSERTED, SHCNF_PATH, root, NULL);
+ }
+ }
+
+exit_func:
+ if (image_info) {
+ LocalFree(image_info);
+ }
+
+ if (image_buf) {
+ LocalFree(image_buf);
+ }
+
+ return ret;
+}
+
+//
+// Close the virtual floppy Image
+//
+DWORD WINAPI VfdCloseImage(
+ HANDLE hDevice,
+ BOOL bForce)
+{
+#undef FUNC
+#define FUNC "VfdCloseImage"
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+ int retry = 0;
+
+lock_retry:
+ if (!DeviceIoControl(
+ hDevice,
+ FSCTL_LOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(FSCTL_LOCK_VOLUME) - %s",
+ SystemMessage(ret)));
+
+ if (ret != ERROR_ACCESS_DENIED || retry == 5) {
+ // error other than access denied or
+ // operation kept failing for 5 seconds
+ return ret;
+ }
+
+ if (!bForce) {
+ // error is access denied and
+ // the force flag is not set
+
+ if (retry == 0) {
+
+ // send the MEDIAREMOVED notification to the shell and
+ // see if the shell releases the target drive
+
+ CHAR root[] = "A:\\";
+
+ VfdGetGlobalLink(hDevice, &root[0]);
+
+ if (isalpha(root[0])) {
+ SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATH, root, NULL);
+ }
+
+ while (VfdGetLocalLink(hDevice, &root[0]) == ERROR_SUCCESS &&
+ isalpha(root[0])) {
+ SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATH, root, NULL);
+ }
+ }
+
+ Sleep(1000);
+ retry++;
+
+ goto lock_retry;
+ }
+ }
+
+ ret = ERROR_SUCCESS;
+
+ if (!DeviceIoControl(
+ hDevice,
+ FSCTL_DISMOUNT_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(FSCTL_DISMOUNT_VOLUME) - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_VFD_CLOSE_IMAGE,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ if (ret != ERROR_NOT_READY) {
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_CLOSE_FILE) - %s",
+ SystemMessage(ret)));
+ }
+
+ return ret;
+ }
+
+ if (!DeviceIoControl(
+ hDevice,
+ FSCTL_UNLOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ // This should not be fatal because the volume is unlocked
+ // when the handle is closed anyway
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(FSCTL_UNLOCK_VOLUME) - %s",
+ SystemMessage(GetLastError())));
+ }
+
+ // Broadcast the successful operation
+ if (ret == ERROR_SUCCESS) {
+ ULONG number;
+
+ if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) {
+ VfdNotify(VFD_OPERATION_CLOSE, number);
+ }
+ }
+
+ return ret;
+}
+
+//
+// Get Virtual Floppy image info
+//
+DWORD WINAPI VfdGetImageInfo(
+ HANDLE hDevice,
+ PSTR sFileName,
+ PVFD_DISKTYPE pDiskType,
+ PVFD_MEDIA pMediaType,
+ PVFD_FLAGS pMediaFlags,
+ PVFD_FILETYPE pFileType,
+ PULONG pImageSize)
+{
+#undef FUNC
+#define FUNC "VfdGetImageInfo"
+ PVFD_IMAGE_INFO image_info;
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+
+ image_info = (PVFD_IMAGE_INFO)LocalAlloc(
+ LPTR, sizeof(VFD_IMAGE_INFO) + MAX_PATH);
+
+ if (image_info == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": LocalAlloc(%lu) - %s\n",
+ sizeof(VFD_IMAGE_INFO) + MAX_PATH, SystemMessage(ret)));
+
+ return ret;
+ }
+
+ ZeroMemory(image_info, sizeof(VFD_IMAGE_INFO) + MAX_PATH);
+
+ // Query file information
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_VFD_QUERY_IMAGE,
+ NULL,
+ 0,
+ image_info,
+ sizeof(VFD_IMAGE_INFO) + MAX_PATH,
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ if (ret != ERROR_MORE_DATA) {
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_QUERY_FILE) - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+ }
+
+ // copy obtained information to output buffer
+
+ if (sFileName) {
+
+ // if filename is too long, clip it
+
+ if (image_info->NameLength >= MAX_PATH) {
+ image_info->NameLength = MAX_PATH - 1;
+ }
+
+ // ensure the name is properly terminated
+
+ image_info->FileName[image_info->NameLength] = '\0';
+
+ if (strncmp(image_info->FileName, "\\??\\UNC", 7) == 0) {
+ *sFileName = '\\';
+ strcpy(sFileName + 1, image_info->FileName + 7);
+ }
+ else if (strncmp(image_info->FileName, "\\??\\", 4) == 0) {
+ strcpy(sFileName, image_info->FileName + 4);
+ }
+ else {
+ strcpy(sFileName, image_info->FileName);
+ }
+ }
+
+ if (pDiskType) {
+ *pDiskType = image_info->DiskType;
+ }
+
+ if (pMediaType) {
+ *pMediaType = image_info->MediaType;
+ }
+
+ if (pMediaFlags) {
+ *pMediaFlags = image_info->MediaFlags;
+ }
+
+ if (pFileType) {
+ *pFileType = image_info->FileType;
+ }
+
+ if (pImageSize) {
+ *pImageSize = image_info->ImageSize;
+ }
+
+cleanup:
+ if (image_info) {
+ LocalFree(image_info);
+ }
+
+ return ret;
+}
+
+//
+// Get current media state (opened / write protected)
+//
+DWORD WINAPI VfdGetMediaState(
+ HANDLE hDevice)
+{
+#undef FUNC
+#define FUNC "VfdGetMediaState"
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+
+ // Query file information
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_DISK_IS_WRITABLE,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ if (ret != ERROR_NOT_READY) {
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_DISK_IS_WRITABLE) - %s",
+ SystemMessage(ret)));
+ }
+ }
+
+ return ret;
+}
+
+//
+// Set or Delete a global drive letter
+//
+DWORD WINAPI VfdSetGlobalLink(
+ HANDLE hDevice,
+ CHAR cLetter)
+{
+#undef FUNC
+#define FUNC "VfdSetGlobalLink"
+ CHAR letter;
+ ULONG number;
+ DWORD result;
+ DWORD ret;
+
+ if (isalpha(cLetter)) {
+
+ // make sure the drive does not have a drive letter
+
+ letter = 0;
+
+ VfdGetGlobalLink(hDevice, &letter);
+
+ if (isalpha(letter)) {
+ VFDTRACE(0,
+ (FUNC ": Drive already has a drive letter %c\n", letter));
+ return ERROR_ALREADY_ASSIGNED;
+ }
+
+ VfdGetLocalLink(hDevice, &letter);
+
+ if (isalpha(letter)) {
+ VFDTRACE(0,
+ (FUNC ": Drive already has a drive letter %c\n", letter));
+ return ERROR_ALREADY_ASSIGNED;
+ }
+
+ // make sure drive letter is not in use
+
+ cLetter = (CHAR)toupper(cLetter);
+
+ if (GetLogicalDrives() & (1 << (cLetter - 'A'))) {
+ VFDTRACE(0,
+ (FUNC ": Drive letter %c already used\n", cLetter));
+ return ERROR_ALREADY_ASSIGNED;
+ }
+
+ // Assign a new drive letter
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_VFD_SET_LINK,
+ &cLetter,
+ sizeof(cLetter),
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_SET_LINK) - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // broadcast system message
+
+ VfdBroadcastLink(cLetter, VFD_LINK_CREATED);
+
+ // broadcast VFD message
+
+ if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) {
+ VfdNotify(VFD_OPERATION_SETLINK, number);
+ }
+
+ return ERROR_SUCCESS;
+ }
+ else if (!cLetter) {
+
+ // make sure the drive has a global drive letter
+
+ letter = 0;
+
+ VfdGetGlobalLink(hDevice, &letter);
+
+ if (!isalpha(letter)) {
+ VFDTRACE(0,
+ (FUNC ": Drive does not have a drive letter\n"));
+ return ERROR_INVALID_FUNCTION;
+ }
+
+ // Remove drive letters
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_VFD_SET_LINK,
+ &cLetter,
+ sizeof(cLetter),
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_SET_LINK) - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // broadcast system message
+
+ VfdBroadcastLink(letter, VFD_LINK_REMOVED);
+
+ // broadcast VFD message
+ if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) {
+ VfdNotify(VFD_OPERATION_DELLINK, number);
+ }
+
+ return ERROR_SUCCESS;
+ }
+ else {
+ return ERROR_INVALID_PARAMETER;
+ }
+}
+
+//
+// Get a global drive letter
+//
+DWORD WINAPI VfdGetGlobalLink(
+ HANDLE hDevice,
+ PCHAR pLetter)
+{
+#undef FUNC
+#define FUNC "VfdGetGlobalLinks"
+ DWORD result;
+ DWORD ret;
+
+ if (!pLetter) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ *pLetter = 0;
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_VFD_QUERY_LINK,
+ NULL,
+ 0,
+ pLetter,
+ sizeof(*pLetter),
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_QUERY_LINK) - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+//
+// Set or remove a local drive letter
+//
+DWORD WINAPI VfdSetLocalLink(
+ HANDLE hDevice,
+ CHAR cLetter)
+{
+#undef FUNC
+#define FUNC "VfdSetLocalLink"
+ CHAR letter;
+ CHAR dos_name[] = "A:";
+ CHAR dev_name[MAX_PATH];
+ ULONG number;
+ DWORD ret;
+
+ if (isalpha(cLetter)) {
+
+ // make sure the drive does not have a drive letter
+
+ letter = 0;
+
+ VfdGetGlobalLink(hDevice, &letter);
+
+ if (isalpha(letter)) {
+ VFDTRACE(0,
+ (FUNC ": Drive already has a drive letter %c\n", letter));
+ return ERROR_ALREADY_ASSIGNED;
+ }
+
+ VfdGetLocalLink(hDevice, &letter);
+
+ if (isalpha(letter)) {
+ VFDTRACE(0,
+ (FUNC ": Drive already has a drive letter %c\n", letter));
+ return ERROR_ALREADY_ASSIGNED;
+ }
+
+ // make sure drive letters are not in use
+
+ cLetter = (CHAR)toupper(cLetter);
+
+ if (GetLogicalDrives() & (1 << (cLetter - 'A'))) {
+ VFDTRACE(0,
+ (FUNC ": Drive letter already used\n"));
+
+ return ERROR_ALREADY_ASSIGNED;
+ }
+
+ // get VFD device name
+
+ ret = VfdGetDeviceName(hDevice, dev_name, sizeof(dev_name));
+
+ if (ret != ERROR_SUCCESS) {
+ return ret;
+ }
+
+ // assign a drive letter
+
+ dos_name[0] = cLetter;
+
+ if (!DefineDosDevice(DDD_RAW_TARGET_PATH, dos_name, dev_name)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DefineDosDevice(%s,%s) - %s",
+ dos_name, dev_name, SystemMessage(ret)));
+ }
+
+ if (ret == ERROR_SUCCESS) {
+ // broadcast VFD message
+
+ if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) {
+ VfdNotify(VFD_OPERATION_SETLINK, number);
+ }
+ }
+
+ return ret;
+ }
+ else if (!cLetter) {
+
+ // make sure the drive has a local drive letter
+
+ letter = 0;
+
+ VfdGetLocalLink(hDevice, &letter);
+
+ if (!isalpha(letter)) {
+ VFDTRACE(0,
+ (FUNC ": Drive letter is not assigned to this drive\n"));
+ return ERROR_INVALID_FUNCTION;
+ }
+
+ // get VFD device name
+
+ ret = VfdGetDeviceName(hDevice, dev_name, sizeof(dev_name));
+
+ if (ret != ERROR_SUCCESS) {
+ return ret;
+ }
+
+ // remove drive letters
+#define DDD_FLAGS (DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE)
+
+ dos_name[0] = (CHAR)toupper(letter);
+
+ if (!DefineDosDevice(DDD_FLAGS, dos_name, dev_name)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DefineDosDevice(%s,%s) - %s",
+ dos_name, dev_name, SystemMessage(ret)));
+ }
+
+ if (ret == ERROR_SUCCESS) {
+ // broadcast VFD message
+ if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) {
+ VfdNotify(VFD_OPERATION_DELLINK, number);
+ }
+ }
+
+ return ret;
+ }
+ else {
+ return ERROR_INVALID_PARAMETER;
+ }
+}
+
+//
+// Get local drive letters
+//
+DWORD WINAPI VfdGetLocalLink(
+ HANDLE hDevice,
+ PCHAR pLetter)
+{
+#undef FUNC
+#define FUNC "VfdGetLocalLinks"
+ CHAR global;
+ ULONG logical;
+ CHAR dos_name[] = "A:";
+ CHAR dev_name[MAX_PATH];
+ CHAR dos_target[MAX_PATH * 2];
+ DWORD ret;
+
+ if (!pLetter) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ // Get the VFD device name
+
+ ret = VfdGetDeviceName(hDevice, dev_name, sizeof(dev_name));
+
+ if (ret != ERROR_SUCCESS) {
+ return ret;
+ }
+
+ // Get global drive letter
+
+ ret = VfdGetGlobalLink(hDevice, &global);
+
+ if (ret != ERROR_SUCCESS) {
+ return ret;
+ }
+
+ // Get logical drives
+
+ logical = GetLogicalDrives();
+
+ // exclude the global drive letter
+
+ if (isalpha(global)) {
+ logical &= ~(1 << (toupper(global) - 'A'));
+ }
+
+ // start searching from the next drive letter
+
+ if (isalpha(*pLetter)) {
+ dos_name[0] = (CHAR)(toupper(*pLetter) + 1);
+ logical >>= (dos_name[0] - 'A');
+ }
+
+ // Check dos device targets
+
+ *pLetter = '\0';
+
+ while (logical) {
+ if (logical & 0x01) {
+ if (QueryDosDevice(dos_name, dos_target, sizeof(dos_target))) {
+ if (_stricmp(dos_target, dev_name) == 0) {
+ *pLetter = dos_name[0];
+ break;
+ }
+ }
+ else {
+ VFDTRACE(0,
+ (FUNC ": QueryDosDevice(%s) - %s",
+ dos_name, SystemMessage(GetLastError())));
+ }
+ }
+ logical >>= 1;
+ dos_name[0]++;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+//
+// Get the Virtual Floppy device number
+//
+DWORD WINAPI VfdGetDeviceNumber(
+ HANDLE hDevice,
+ PULONG pNumber)
+{
+#undef FUNC
+#define FUNC "VfdGetDeviceNumber"
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+
+ if (!pNumber) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ *pNumber = 0;
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_VFD_QUERY_NUMBER,
+ NULL,
+ 0,
+ pNumber,
+ sizeof(ULONG),
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_QUERY_NUMBER) - %s",
+ SystemMessage(ret)));
+ }
+
+ return ret;
+}
+
+// Get the Virtual Floppy device name
+
+DWORD WINAPI VfdGetDeviceName(
+ HANDLE hDevice,
+ PCHAR pName,
+ ULONG nLength)
+{
+#undef FUNC
+#define FUNC "VfdGetDeviceName"
+ DWORD result;
+ WCHAR wname[MAX_PATH];
+ DWORD ret = ERROR_SUCCESS;
+
+ if (!pName || !nLength) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ ZeroMemory(pName, nLength);
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_VFD_QUERY_NAME,
+ NULL,
+ 0,
+ wname,
+ sizeof(wname),
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_QUERY_NUMBER) - %s",
+ SystemMessage(ret)));
+ }
+
+ if (!WideCharToMultiByte(CP_OEMCP, 0, &wname[1],
+ wname[0] / sizeof(WCHAR), pName, nLength, NULL, NULL)) {
+
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": WideCharToMultiByte - %s",
+ SystemMessage(ret)));
+ }
+
+ return ret;
+}
+
+//
+// Get Virtual Floppy driver version
+//
+DWORD WINAPI VfdGetDriverVersion(
+ HANDLE hDevice,
+ PULONG pVersion)
+{
+#undef FUNC
+#define FUNC "VfdGetDriverVersion"
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+
+ if (!pVersion) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ *pVersion = '\0';
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_VFD_QUERY_VERSION,
+ NULL,
+ 0,
+ pVersion,
+ sizeof(ULONG),
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_QUERY_VERSION) - %s",
+ SystemMessage(ret)));
+ }
+
+ return ret;
+}
+
+//
+// Change the write protect state of the media
+//
+DWORD WINAPI VfdWriteProtect(
+ HANDLE hDevice,
+ BOOL bProtect)
+{
+#undef FUNC
+#define FUNC "VfdWriteProtect"
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+
+ if (!DeviceIoControl(
+ hDevice,
+ bProtect ? IOCTL_VFD_SET_PROTECT : IOCTL_VFD_CLEAR_PROTECT,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_SET_PROTECT) - %s",
+ SystemMessage(ret)));
+ }
+
+ if (ret == ERROR_SUCCESS) {
+ ULONG number;
+
+ if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) {
+ VfdNotify(VFD_OPERATION_PROTECT, number);
+ }
+ }
+
+ return ret;
+}
+
+// Format the current media with FAT12
+
+DWORD WINAPI VfdFormatMedia(
+ HANDLE hDevice)
+{
+#undef FUNC
+#define FUNC "VfdFormatMedia"
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+ PUCHAR buf = NULL;
+ GET_LENGTH_INFORMATION length;
+
+ // Get the media size
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_DISK_GET_LENGTH_INFO,
+ NULL,
+ 0,
+ &length,
+ sizeof(length),
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_DISK_GET_LENGTH_INFO) - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // Prepare a formatted image buffer
+
+ buf = (PUCHAR)LocalAlloc(LPTR, length.Length.LowPart);
+
+ if (buf == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": LocalAlloc - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // format the buffer
+
+ ret = FormatBufferFat(buf,
+ VFD_BYTE_TO_SECTOR(length.Length.LowPart));
+
+ if (ret != ERROR_SUCCESS) {
+ goto exit_func;
+ }
+
+ // seek the top of the media
+
+ if (SetFilePointer(hDevice, 0, NULL, FILE_BEGIN) != 0) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": SetFilePointer - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // write the image into the media
+
+ if (!WriteFile(hDevice, buf, length.Length.LowPart, &result, NULL) ||
+ result != length.Length.LowPart) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": WriteFile - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+exit_func:
+ // unlock the target volume
+ if (!DeviceIoControl(
+ hDevice,
+ FSCTL_UNLOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(FSCTL_UNLOCK_VOLUME) - %s",
+ SystemMessage(GetLastError())));
+ }
+
+ // release the format image buffer
+ if (buf) {
+ LocalFree(buf);
+ }
+
+ return ret;
+}
+
+// Dismount the volume (should be called before Save, Format)
+
+DWORD WINAPI VfdDismountVolume(
+ HANDLE hDevice,
+ BOOL bForce)
+{
+#undef FUNC
+#define FUNC "VfdDismountVolume"
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+
+ // Lock the target volume
+
+ if (!DeviceIoControl(
+ hDevice,
+ FSCTL_LOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(FSCTL_LOCK_VOLUME) - %s",
+ SystemMessage(ret)));
+
+ if (ret != ERROR_ACCESS_DENIED || !bForce) {
+ return ret;
+ }
+ }
+
+ // Dismount the target volume
+
+ if (!DeviceIoControl(
+ hDevice,
+ FSCTL_DISMOUNT_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(FSCTL_DISMOUNT_VOLUME) - %s",
+ SystemMessage(ret)));
+ }
+
+ return ret;
+}
+
+// Save the current image into a file
+
+DWORD WINAPI VfdSaveImage(
+ HANDLE hDevice,
+ PCSTR sFileName,
+ BOOL bOverWrite,
+ BOOL bTruncate)
+{
+#undef FUNC
+#define FUNC "VfdSaveImage"
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+ PUCHAR buf = NULL;
+ GET_LENGTH_INFORMATION length;
+
+
+ ret = ERROR_SUCCESS;
+
+ // Get the media size
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_DISK_GET_LENGTH_INFO,
+ NULL,
+ 0,
+ &length,
+ sizeof(length),
+ &result,
+ NULL))
+ {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_DISK_GET_LENGTH_INFO) - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // Prepare an intermediate image buffer
+
+ buf = (PUCHAR)LocalAlloc(LPTR, length.Length.LowPart);
+
+ if (buf == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": LocalAlloc - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // seek the top of the media
+
+ if (SetFilePointer(hDevice, 0, NULL, FILE_BEGIN) != 0) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": SetFilePointer - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // read the image data
+
+ if (!ReadFile(hDevice, buf, length.Length.LowPart, &result, NULL) ||
+ result != length.Length.LowPart) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": ReadFile - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // open the destination file
+
+ hFile = CreateFile(sFileName, GENERIC_WRITE, 0, NULL,
+ bOverWrite ? OPEN_ALWAYS : CREATE_NEW, 0, NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": CreateFile - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // seek the top of the file
+
+ if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) != 0) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": SetFilePointer - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // write the image data
+
+ if (!WriteFile(hFile, buf, length.Length.LowPart, &result, NULL) ||
+ result != length.Length.LowPart) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": WriteFile - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // truncate the target file
+
+ if (bTruncate && !SetEndOfFile(hFile)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": SetEndOfFile - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ // reset the media modified flag
+
+ if (!DeviceIoControl(
+ hDevice,
+ IOCTL_VFD_RESET_MODIFY,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(IOCTL_VFD_RESET_MODIFY) - %s",
+ SystemMessage(GetLastError())));
+ }
+
+exit_func:
+ // unlock the target volume
+
+ if (!DeviceIoControl(
+ hDevice,
+ FSCTL_UNLOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &result,
+ NULL))
+ {
+ VFDTRACE(0,
+ (FUNC ": DeviceIoControl(FSCTL_UNLOCK_VOLUME) - %s",
+ SystemMessage(GetLastError())));
+ }
+
+ // release the format image buffer
+
+ if (buf) {
+ LocalFree(buf);
+ }
+
+ // close the image file
+
+ if (hFile != INVALID_HANDLE_VALUE) {
+ CloseHandle(hFile);
+ }
+
+ return ret;
+}
+
+//
+// Check if specified file is valid VFD driver
+//
+DWORD WINAPI VfdCheckDriverFile(
+ PCSTR sFileName,
+ PULONG pFileVersion)
+{
+#undef FUNC
+#define FUNC "VfdCheckDriverFile"
+ DWORD result;
+ DWORD dummy;
+ PVOID info;
+ VS_FIXEDFILEINFO *fixedinfo;
+ DWORD ret = ERROR_SUCCESS;
+ PSTR str;
+
+ // Check parameter
+
+ if (!sFileName || !*sFileName) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (pFileVersion) {
+ *pFileVersion = 0;
+ }
+
+ // check file existence
+
+ if (GetFileAttributes(sFileName) == INVALID_FILE_ATTRIBUTES) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": GetFileAttributes - %s\n",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // check file version
+
+ result = GetFileVersionInfoSize((PSTR)sFileName, &dummy);
+
+ if (result == 0) {
+ VFDTRACE(0,
+ (FUNC ": GetFileVersionInfoSize == 0\n"));
+
+ return ERROR_BAD_DRIVER;
+ }
+
+ info = LocalAlloc(LPTR, result);
+
+ if (info == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": LocalAlloc(%lu) - %s\n",
+ result, SystemMessage(ret)));
+
+ return ret;
+ }
+
+ if (!GetFileVersionInfo((PSTR)sFileName, 0, result, info)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": GetFileVersionInfo - %s", SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ result = sizeof(fixedinfo);
+
+ if (!VerQueryValue(info, "\\", (PVOID *)&fixedinfo, (PUINT)&result)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": VerQueryValue(\"\\\") - %s", SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ if (fixedinfo->dwFileOS != VOS_NT_WINDOWS32 ||
+ fixedinfo->dwFileType != VFT_DRV ||
+ fixedinfo->dwFileSubtype != VFT2_DRV_SYSTEM) {
+
+ VFDTRACE(0,
+#ifndef __REACTOS__
+ (FUNC ": Invalid file type flags\n"));
+#else
+ (FUNC ": Invalid file type flags. os: %x (%x), type: %x (%x), subtype: %x (%x)\n",
+ fixedinfo->dwFileOS, VOS_NT_WINDOWS32, fixedinfo->dwFileType, VFT_DRV,
+ fixedinfo->dwFileSubtype, VFT2_DRV_SYSTEM));
+#endif
+
+ ret = ERROR_BAD_DRIVER;
+
+ goto cleanup;
+ }
+
+ if (pFileVersion) {
+ *pFileVersion = fixedinfo->dwFileVersionMS;
+
+ if (fixedinfo->dwFileFlags & VS_FF_DEBUG) {
+ *pFileVersion |= 0x80000000;
+ }
+ }
+
+ if (!VerQueryValue(info,
+ "\\StringFileInfo\\" VFD_VERSIONINFO_LANG "\\OriginalFileName",
+ (PVOID *)&str, (PUINT)&result)) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": VerQueryValue(\"OriginalFileName\") - %s",
+ SystemMessage(ret)));
+
+ goto cleanup;
+ }
+
+ if (strcmp(str, VFD_DRIVER_FILENAME)) {
+ VFDTRACE(0,
+ (FUNC ": Invalid original file name\n"));
+
+ ret = ERROR_BAD_DRIVER;
+
+ goto cleanup;
+ }
+
+ if (fixedinfo->dwFileVersionMS != MAKELONG(VFD_DRIVER_MINOR, VFD_DRIVER_MAJOR) ||
+ fixedinfo->dwProductVersionMS != MAKELONG(VFD_PRODUCT_MINOR, VFD_PRODUCT_MAJOR)) {
+
+ VFDTRACE(0,
+ (FUNC ": Invalid version values - file:%08x, prod: %08x\n",
+ fixedinfo->dwFileVersionMS, fixedinfo->dwProductVersionMS));
+
+ ret = ERROR_BAD_DRIVER;
+
+ goto cleanup;
+ }
+
+ // Ensure that the driver binary is located on a local drive
+ // because device driver cannot be started on network drives.
+
+ if (*sFileName == '\\' && *(sFileName + 1) == '\\') {
+ // full path is a UNC path -- \\server\dir\...
+
+ VFDTRACE(0,
+ (FUNC ": Driver is located on a network drive\n"));
+
+ return ERROR_NETWORK_ACCESS_DENIED;
+ }
+ else {
+ // ensure that the drive letter is not a network drive
+
+ CHAR root[] = " :\\";
+
+ root[0] = *sFileName;
+
+ if (GetDriveType(root) == DRIVE_REMOTE) {
+ // the drive is a network drive
+
+ VFDTRACE(0,
+ (FUNC ": Driver is located on a network drive\n"));
+
+ return ERROR_NETWORK_ACCESS_DENIED;
+ }
+ }
+
+cleanup:
+ LocalFree(info);
+
+ return ret;
+}
+
+//
+// check an image file
+//
+DWORD WINAPI VfdCheckImageFile(
+ PCSTR sFileName,
+ PDWORD pAttributes,
+ PVFD_FILETYPE pFileType,
+ PULONG pImageSize)
+{
+#undef FUNC
+#define FUNC "VfdCheckImageFile"
+ HANDLE hFile;
+ DWORD ret = ERROR_SUCCESS;
+
+ if (!sFileName || !*sFileName || !pAttributes || !pImageSize || !pFileType) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ // get file attributes
+
+ *pAttributes = GetFileAttributes(sFileName);
+
+ if (*pAttributes == INVALID_FILE_ATTRIBUTES) {
+ ret = GetLastError();
+
+ if (ret != ERROR_FILE_NOT_FOUND) {
+ VFDTRACE(0,
+ (FUNC ": GetFileAttributes(%s) - %s\n",
+ sFileName, SystemMessage(ret)));
+ }
+
+ return ret;
+ }
+
+ // Open the target file
+
+ hFile = CreateFile(sFileName, GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+
+ // failed to open
+
+ ret = GetLastError();
+
+ if (ret != ERROR_ACCESS_DENIED) {
+ VFDTRACE(0,
+ (FUNC ": CreateFile(%s) - %s\n",
+ sFileName, SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // try opening it read-only
+
+ hFile = CreateFile(sFileName, GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+
+ // cannot open even read-only
+
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": CreateFile(%s) - %s\n",
+ sFileName, SystemMessage(ret)));
+
+ return ret;
+ }
+
+ // file can be opened read-only
+ *pAttributes |= FILE_ATTRIBUTE_READONLY;
+ ret = ERROR_SUCCESS;
+ }
+
+ // check if the image is an IMZ file
+
+ if (ExtractZipInfo(hFile, pImageSize) == ERROR_SUCCESS) {
+ *pFileType = VFD_FILETYPE_ZIP;
+ }
+ else {
+ *pImageSize = GetFileSize(hFile, NULL);
+ *pFileType = VFD_FILETYPE_RAW;
+ }
+
+ CloseHandle(hFile);
+
+ return ret;
+}
+
+//
+// Create a formatted new image file
+//
+DWORD WINAPI VfdCreateImageFile(
+ PCSTR sFileName,
+ VFD_MEDIA nMediaType,
+ VFD_FILETYPE nFileType,
+ BOOL bOverWrite)
+{
+#undef FUNC
+#define FUNC "VfdCreateImageFile"
+ HANDLE hFile;
+ ULONG file_size;
+ PUCHAR image_buf = NULL;
+ DWORD result;
+ DWORD ret = ERROR_SUCCESS;
+
+ if (nFileType != VFD_FILETYPE_RAW) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ file_size = VfdGetMediaSize(nMediaType);
+
+ if (file_size == 0) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ hFile = CreateFile(sFileName, GENERIC_WRITE, 0, NULL,
+ bOverWrite ? CREATE_ALWAYS : CREATE_NEW, 0, NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": CreateFile - %s",
+ SystemMessage(ret)));
+
+ return ret;
+ }
+
+ image_buf = (PUCHAR)LocalAlloc(LPTR, file_size);
+
+ if (image_buf == NULL) {
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": LocalAlloc - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ FormatBufferFat(image_buf, VFD_BYTE_TO_SECTOR(file_size));
+
+ if (!WriteFile(hFile, image_buf, file_size, &result, NULL) ||
+ file_size != result) {
+
+ ret = GetLastError();
+
+ VFDTRACE(0,
+ (FUNC ": WriteFile - %s",
+ SystemMessage(ret)));
+
+ goto exit_func;
+ }
+
+ SetEndOfFile(hFile);
+
+exit_func:
+ CloseHandle(hFile);
+
+ if (image_buf) {
+ LocalFree(image_buf);
+ }
+
+ return ret;
+}
+
+
+//
+// choose first available drive letter
+//
+CHAR WINAPI VfdChooseLetter()
+{
+ DWORD logical_drives = GetLogicalDrives();
+ CHAR drive_letter = 'A';
+
+ if (logical_drives == 0) {
+ return '\0';
+ }
+
+ while (logical_drives & 0x1) {
+ logical_drives >>= 1;
+ drive_letter++;
+ }
+
+ if (drive_letter > 'Z') {
+ return '\0';
+ }
+
+ return drive_letter;
+}
+
+//
+// media type functions
+//
+static const struct
+{
+ ULONG Size;
+ PCSTR Name;
+}
+media_tbl[VFD_MEDIA_MAX] =
+{
+ { 0, "" }, // VFD_MEDIA_NONE,
+ { VFD_SECTOR_TO_BYTE(320), "5.25\" 160KB" }, // VFD_MEDIA_F5_160
+ { VFD_SECTOR_TO_BYTE(360), "5.25\" 180KB" }, // VFD_MEDIA_F5_180
+ { VFD_SECTOR_TO_BYTE(640), "5.25\" 320KB" }, // VFD_MEDIA_F5_320
+ { VFD_SECTOR_TO_BYTE(720), "5.25\" 360KB" }, // VFD_MEDIA_F5_360
+ { VFD_SECTOR_TO_BYTE(1280), "3.5\" 640KB" }, // VFD_MEDIA_F3_640
+ { VFD_SECTOR_TO_BYTE(1280), "5.25\" 640KB" }, // VFD_MEDIA_F5_640
+ { VFD_SECTOR_TO_BYTE(1440), "3.5\" 720KB" }, // VFD_MEDIA_F3_720
+ { VFD_SECTOR_TO_BYTE(1440), "5.25\" 720KB" }, // VFD_MEDIA_F5_720
+ { VFD_SECTOR_TO_BYTE(1640), "3.5\" 820KB" }, // VFD_MEDIA_F3_820
+ { VFD_SECTOR_TO_BYTE(2400), "3.5\" 1.2MB" }, // VFD_MEDIA_F3_1P2
+ { VFD_SECTOR_TO_BYTE(2400), "5.25\" 1.2MB" }, // VFD_MEDIA_F5_1P2
+ { VFD_SECTOR_TO_BYTE(2880), "3.5\" 1.44MB" }, // VFD_MEDIA_F3_1P4
+ { VFD_SECTOR_TO_BYTE(3360), "3.5\" 1.68MB DMF" }, // VFD_MEDIA_F3_1P6
+ { VFD_SECTOR_TO_BYTE(3444), "3.5\" 1.72MB DMF" }, // VFD_MEDIA_F3_1P7
+ { VFD_SECTOR_TO_BYTE(5760), "3.5\" 2.88MB"} // VFD_MEDIA_F3_2P8
+};
+
+// Lookup the largest media to fit in a size
+
+VFD_MEDIA WINAPI VfdLookupMedia(
+ ULONG nSize)
+{
+ VFD_MEDIA i;
+
+ for (i = 1; i < VFD_MEDIA_MAX; i++) {
+ if (nSize < media_tbl[i].Size) {
+ break;
+ }
+ }
+
+ return (--i);
+}
+
+// Get media size (in bytes) of a media type
+
+ULONG WINAPI VfdGetMediaSize(
+ VFD_MEDIA nMediaType)
+{
+ return nMediaType < VFD_MEDIA_MAX ? media_tbl[nMediaType].Size : 0;
+}
+
+// Get media type name
+
+PCSTR WINAPI VfdMediaTypeName(
+ VFD_MEDIA nMediaType)
+{
+ return nMediaType < VFD_MEDIA_MAX ? media_tbl[nMediaType].Name : NULL;
+}
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+//{{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
--- /dev/null
+/*
+ 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,
+ ¶m.DiskType,
+ ¶m.MediaType,
+ ¶m.MediaFlags,
+ ¶m.FileType,
+ ¶m.ImageSize);
+
+ if (ret == ERROR_SUCCESS) {
+
+ // show dialog box
+
+ ret = GuiSaveParam(hParent, ¶m);
+ }
+
+ // 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;
+}
--- /dev/null
+/*
+ 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);
+ }
+}
--- /dev/null
+/*
+ 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,
+ ¶m.DiskType,
+ ¶m.MediaType,
+ ¶m.MediaFlags,
+ ¶m.FileType,
+ ¶m.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, ¶m) == 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);
+ }
+}
+
--- /dev/null
+/*
+ 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
--- /dev/null
+/*
+ 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_
--- /dev/null
+//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
--- /dev/null
+/*
+ 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 "\83h\83\89\83C\83o\83o\83C\83i\83\8a\96\84\82ß\8d\9e\82Ý\94Å"
+
+#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 \83\89\83C\83u\83\89\83\8a"
+#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
--- /dev/null
+@ 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()
--- /dev/null
+;/*
+; 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_
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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_
--- /dev/null
+/*
+ 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;
+}
+*/
--- /dev/null
+/*
+ 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_
--- /dev/null
+/*
+ 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_
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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;
+}
--- /dev/null
+/*
+ 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