📄 mirrordrive95.cpp
字号:
/***********************************************************************
Copyright 2002 Ben Rudiak-Gould.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
or visit <http://www.gnu.org/copyleft/gpl.html>.
***********************************************************************/
#define WIN32_LEAN_AND_MEAN
#define _WIN32_IE 0x300
// winbase.h defines an unrelated struct called "DCB". Rather than rename
// the kernel one I'm hacking around the problem, at least for now.
#define DCB SOME_OTHER_DCB
#include <windows.h>
#undef DCB
#include <commctrl.h>
#include "resource.h"
#include "../include/dvdsynth-device.h"
#include "kernel-io.h"
#include <stdio.h>
HINSTANCE g_hinstance;
DvsDockingBayGlobal* g_callback;
dvs_driver_handle g_driver_handle;
struct AdapterInfo {
DEVNODE devnode;
int num_devices;
};
AdapterInfo g_adapters[16];
int g_num_adapters;
struct DeviceInfo {
unsigned adapter, bus, target, lun;
DCB* dcb;
unsigned char drive_letter;
unsigned char type;
char model[27];
};
const int MAX_DEVICES = 64;
DeviceInfo g_device_info[MAX_DEVICES];
int g_num_devices;
HWND g_hlistview;
inline scsi_result_t SendScsiCommand(DCB* dcb, const unsigned char* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) {
// note the final dummy argument specifying the size of the SenseData buffer
return (scsi_result_t)g_callback->Driver_Call(g_driver_handle, "SendScsiCommand", "p>i>&i>i", dcb, cdb, cdblen, buffer, pbuflen, inout, sense, sizeof(SenseData));
}
inline DEVNODE GetDevnodeParent(DEVNODE dn) {
DEVNODE result = 0;
if (CR_SUCCESS == (CONFIGRET)g_callback->Driver_Call(g_driver_handle, "CONFIGMG_Get_Parent", "&pi", &result, dn, 0)) {
return result;
} else {
return 0;
}
}
inline DCB* GetNextDCB(DCB* dcb) {
return (DCB*)g_callback->Driver_Call(g_driver_handle, "GetNextDCB", "p", dcb);
}
bool GetRegString(HKEY base, const char* subkey, const char* value, char* buf, ULONG* pbuflen) {
HKEY hkey;
if (ERROR_SUCCESS != RegOpenKeyEx(base, subkey, 0, KEY_READ, &hkey)) {
return false;
}
long query_error = RegQueryValueEx(hkey, value, NULL, NULL, (unsigned char*)buf, pbuflen);
RegCloseKey(hkey);
return (query_error == ERROR_SUCCESS);
}
bool GetDevNodeHardwareKey(DEVNODE dn, char* buf, ULONG buflen) {
char dyn_data_key[32];
wsprintf(dyn_data_key, "Config Manager\\Enum\\%08X", dn);
lstrcpy(buf, "Enum\\");
ULONG len = buflen-6;
if (!GetRegString(HKEY_DYN_DATA, dyn_data_key, "HardWareKey", buf+5, &len)) {
return false;
}
buf[5+len] = 0;
return true;
}
bool GetDevNodeRegString(DEVNODE dn, const char* name, char* buf, ULONG buflen) {
char hardware_key[256];
if (!GetDevNodeHardwareKey(dn, hardware_key, 256)) {
return false;
}
ULONG len = buflen;
if (!GetRegString(HKEY_LOCAL_MACHINE, hardware_key, name, buf, &len)) {
return false;
}
buf[min(len,buflen-1)] = 0;
return true;
}
char GetDevnodeDriveLetter(DEVNODE dn) {
char buf[64];
if (GetDevNodeRegString(dn, "CurrentDriveLetterAssignment", buf, 64)) {
return buf[0];
} else {
return 0;
}
}
void SetModelField(char* dst, const unsigned char* src) {
// copy vendor ID field
memcpy(dst, src, 8);
char* p;
// lop off trailing spaces
p = dst+8;
while (p > dst && p[-1] == ' ')
--p;
// copy product ID field, with delimiting space
*p++ = ' ';
memcpy(p, src+8, 16);
// lop off trailing spaces
p += 16;
while (p > dst && p[-1] == ' ')
--p;
*p = 0;
}
void ScanForDevices() {
DEVNODE dvdproxy_devnode = (DEVNODE)g_callback->GetDvdsynthDevicesID();
DCB* dcb = 0;
while ((dcb = GetNextDCB(dcb)) != 0 && g_num_devices < MAX_DEVICES) {
printf("DCB = %08X\n", dcb);
// skip logical devices
if (!(dcb->DCB_cmn.DCB_device_flags & DCB_DEV_PHYSICAL)) {
continue;
}
// only consider SCSI/IDE devices (is this wise?)
if (dcb->DCB_bus_type != DCB_BUS_SCSI && dcb->DCB_bus_type != DCB_BUS_ESDI) {
printf("A\n");
continue;
}
// the parent devnode is the adapter controlling this device
DEVNODE adapter_devnode = GetDevnodeParent(dcb->DCB_dev_node);
printf("parent = %08X\n", adapter_devnode);
if (adapter_devnode == 0 || adapter_devnode == dvdproxy_devnode) {
printf("B\n");
continue;
}
int adapter_number;
for (adapter_number=0; adapter_number<g_num_adapters; ++adapter_number) {
if (g_adapters[adapter_number].devnode == adapter_devnode)
break;
}
if (adapter_number == sizeof(g_adapters)/sizeof(g_adapters[0])) {
// out of space for adapter info; ignore this adapter
printf("C\n");
continue;
}
g_adapters[adapter_number].devnode = adapter_devnode;
++g_adapters[adapter_number].num_devices;
if (adapter_number == g_num_adapters) {
++g_num_adapters;
}
int bus, target, lun;
if (dcb->DCB_cmn.DCB_device_flags2 & DCB_DEV2_ATAPI_DEVICE) {
// For ATAPI devices, count number of previous devices on this bus
bus = 0;
target = g_adapters[adapter_number].num_devices - 1;
lun = 0;
} else if (dcb->DCB_bus_type == DCB_BUS_SCSI) {
// For SCSI devices, SCSI address is stored in the DCB.
bus = dcb->DCB_bus_number;
target = dcb->DCB_scsi_target_id;
lun = dcb->DCB_scsi_lun;
} else {
// Don't consider IDE devices any further.
printf("D\n");
continue;
}
/*
static const unsigned char cdb_inquiry[6] = { 0x12, 0, 0, 0, 36, 0 };
unsigned char inquiry_buf[36];
memset(inquiry_buf, 0, sizeof(inquiry_buf));
unsigned long buflen = 36;
SenseData sense;
if (SCSIRESULT_SUCCESS != SendScsiCommand(dcb, cdb_inquiry, 6, inquiry_buf, &buflen, 1, &sense)) {
printf("E\n");
continue;
}
*/
DeviceInfo& di = g_device_info[g_num_devices++];
memset(&di, 0, sizeof(DeviceInfo));
di.adapter = adapter_number;
di.bus = bus;
di.target = target;
di.lun = lun;
di.dcb = dcb;
di.drive_letter = GetDevnodeDriveLetter(dcb->DCB_dev_node);
di.type = dcb->DCB_inquiry_flags[0];
SetModelField(di.model, dcb->DCB_vendor_id);
// di.type = inquiry_buf[0];
// SetModelField(di.model, inquiry_buf+8);
}
}
void AddListViewColumn(HWND hlv, int index, const char* text, int width) {
LVCOLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvc.fmt = 0;
lvc.cx = width;
lvc.pszText = (LPTSTR)text;
ListView_InsertColumn(hlv, index, &lvc);
}
BOOL NewInstanceDialog_InitDialog(HWND hdlg) {
HWND hlist = GetDlgItem(hdlg, IDC_DEVICELIST);
ListView_SetExtendedListViewStyle(hlist, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);
// get the width of the list view and size its columns proportionally
RECT r;
GetClientRect(hlist, &r);
unsigned width = r.right;
unsigned divider1 = width*14/32;
unsigned divider2 = width*21/32;
unsigned divider3 = width*27/32;
AddListViewColumn(hlist, 0, "Make and model", divider1);
AddListViewColumn(hlist, 1, "Type", divider2-divider1);
AddListViewColumn(hlist, 2, "Letter", divider3-divider2);
AddListViewColumn(hlist, 3, "Address", width-divider3);
g_hlistview = hlist;
g_num_devices = 0;
g_num_adapters = 0;
ScanForDevices();
// ListView_SetItemCount does not work!!!
LVITEM new_item;
memset(&new_item, 0, sizeof(new_item));
for (int i=0; i<g_num_devices; ++i) {
new_item.iItem = i;
ListView_InsertItem(hlist, &new_item);
}
return TRUE;
}
int GetLVSelection(HWND hlv) {
return ListView_GetNextItem(hlv, (unsigned)-1, LVNI_SELECTED);
}
const char* scsi_device_type[] = {
"Disk drive",
"Tape drive",
"Printer",
"Processor",
"WORM drive",
"CD/DVD drive",
"Scanner",
"Optical drive",
"Medium changer",
"Network device",
"ASCIT8",
"ASCIT8",
"Array",
"Enclosure",
"RBC",
"Card reader",
"Bridge"
};
void GetDispInfo(LVITEM* plvi) {
if (!(plvi->mask & LVIF_TEXT))
return;
int i = plvi->iItem, c = plvi->iSubItem;
if (i < 0 || i >= g_num_devices || i >= MAX_DEVICES)
return;
char buf[32];
const char* text;
const DeviceInfo& di = g_device_info[i];
switch (c) {
case 0:
text = di.model;
break;
case 1:
if (di.type <= sizeof(scsi_device_type)/sizeof(scsi_device_type[0])) {
text = scsi_device_type[di.type];
} else {
wsprintf(buf, "unknown (0x%02X)", di.type);
text = buf;
}
break;
case 2:
wsprintf(buf, "%c:", di.drive_letter);
text = buf;
break;
case 3:
if (di.bus) {
wsprintf(buf, "%d.%d:%d:%d", di.adapter, di.bus, di.target, di.lun);
} else {
wsprintf(buf, "%d:%d:%d", di.adapter, di.target, di.lun);
}
text = buf;
break;
default:
return;
}
lstrcpyn(plvi->pszText, text, plvi->cchTextMax);
plvi->pszText[plvi->cchTextMax-1] = 0;
}
BOOL CALLBACK NewInstanceDialogProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) {
// printf("NewInstanceDialogProc(%X, %d, %d, %d)\n", hdlg, msg, wparam, lparam);
switch (msg) {
case WM_INITDIALOG:
return NewInstanceDialog_InitDialog(hdlg);
case WM_COMMAND:
switch (LOWORD(wparam)) {
case IDOK:
EndDialog(hdlg, GetLVSelection(GetDlgItem(hdlg, IDC_DEVICELIST)));
return TRUE;
case IDCANCEL:
EndDialog(hdlg, -1);
return TRUE;
}
break;
case WM_NOTIFY:
if (wparam == IDC_DEVICELIST) {
LPNMHDR pnmh = (LPNMHDR)lparam;
// printf("code = %d\n", pnmh->code);
if (pnmh->code == LVN_GETDISPINFO) {
GetDispInfo(&((LV_DISPINFO*)pnmh)->item);
return TRUE;
} else if (pnmh->code == LVN_ITEMCHANGED) {
EnableWindow(GetDlgItem(hdlg, IDOK), ListView_GetSelectedCount(pnmh->hwndFrom));
return TRUE;
} else if (pnmh->code == LVN_ITEMACTIVATE) {
EndDialog(hdlg, GetLVSelection(GetDlgItem(hdlg, IDC_DEVICELIST)));
return TRUE;
}
}
break;
}
return FALSE;
}
DvsDeviceUser_vtable mirror_drive_user_vtable = {
0, // AddDeviceMenuItems
0, // QueryUnplug
0, // Delete
};
DvsDeviceUser mirror_drive_user = { &mirror_drive_user_vtable };
void CreateNewInstance(void*, int) {
DvsDockingBay* bay = g_callback->ReserveDockingBay();
if (!bay) return;
int selection = DialogBox(g_hinstance, MAKEINTRESOURCE(IDD_CHOOSEDEVICE), NULL, NewInstanceDialogProc);
if (selection >= 0 && selection < g_num_devices) {
MirrorDriveKernel* k = (MirrorDriveKernel*)bay->vtable->SharedPool_Alloc(bay, sizeof(MirrorDriveKernel));
k->ScsiCommand = (dvs_scsi_func*)g_callback->Driver_Call(g_driver_handle, "GetDispatchFunc", "");
k->dcb = g_device_info[selection].dcb;
bay->vtable->SetHandlers(bay, &mirror_drive_user, k);
}
}
void AddNewMenuItems(DvsMenu* menu) {
menu->vtable->AddItem(menu, "Mirror Drive", false, CreateNewInstance, 0, 0);
}
void AddAboutMenuItems(DvsMenu* menu) {}
DvsDeviceGlobal global_funcs = {
AddNewMenuItems,
AddAboutMenuItems,
0,//AddMainMenuItems,
0
};
extern "C"
DvsDeviceGlobal* DvdsynthDevicePluginEntry(DvsDockingBayGlobal* bays) {
if (!bays->Is95())
return 0;
g_callback = bays;
if (g_driver_handle == 0) {
g_driver_handle = g_callback->Driver_Load("MirrorDrive95.kll");
}
return g_driver_handle ? &global_funcs : 0;
}
extern "C"
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID) {
g_hinstance = hinst;
// don't ever unload the driver because we registered with IOS
/*
if (dwReason == DLL_PROCESS_DETACH && g_driver_handle != 0 && g_callback != 0) {
g_callback->Driver_Unload(g_driver_handle);
g_driver_handle = 0;
}
*/
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -