mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 01:15:09 +00:00

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
597 lines
12 KiB
C++
597 lines
12 KiB
C++
/*
|
|
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;
|
|
}
|