/*********************************************************************** 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 . ***********************************************************************/ #define WIN32_LEAN_AND_MEAN #define STRICT #include #include #include "miniport.h" #include "ConfigMgr.h" typedef void* DEVNODE; typedef unsigned long ULONG; typedef ULONG CONFIGRET; #define CR_SUCCESS 0 #define CM_REENUMERATE_SYNCHRONOUS 1 #define CM_QUERY_REMOVE_UI_NOT_OK 1 #define CM_REMOVE_UI_NOT_OK 1 inline CONFIGRET CM_Locate_DevNode(DEVNODE* pdn, void* device_id = 0, ULONG flags = 0) { return (CONFIGRET)Miniport::DriverCall(miniport_handle, (char*)mpdfunc_CONFIGMG_Locate_DevNode, "&pi", pdn, device_id, flags); } inline CONFIGRET CM_Get_Child(DEVNODE* pdn, DEVNODE dn, ULONG flags = 0) { return (CONFIGRET)Miniport::DriverCall(miniport_handle, (char*)mpdfunc_CONFIGMG_Get_Child, "&pi", pdn, dn, flags); } inline CONFIGRET CM_Get_Sibling(DEVNODE* pdn, DEVNODE dn, ULONG flags = 0) { return (CONFIGRET)Miniport::DriverCall(miniport_handle, (char*)mpdfunc_CONFIGMG_Get_Sibling, "&pi", pdn, dn, flags); } inline CONFIGRET CM_Query_Remove_SubTree(DEVNODE dnAncestor, ULONG flags) { return (CONFIGRET)Miniport::DriverCall(miniport_handle, (char*)mpdfunc_CONFIGMG_Query_Remove_SubTree, "pi", dnAncestor, flags); } inline CONFIGRET CM_Remove_SubTree(DEVNODE dnAncestor, ULONG flags) { return (CONFIGRET)Miniport::DriverCall(miniport_handle, (char*)mpdfunc_CONFIGMG_Remove_SubTree, "pi", dnAncestor, flags); } inline CONFIGRET CM_Reenumerate_DevNode(DEVNODE dn, ULONG synchronous) { return (CONFIGRET)Miniport::DriverCall(miniport_handle, (char*)mpdfunc_CONFIGMG_Reenumerate_DevNode, "pi", dn, synchronous); } 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 SetRegString(HKEY base, const char* subkey, const char* value, const char* contents) { HKEY hkey; if (ERROR_SUCCESS != RegOpenKeyEx(base, subkey, 0, KEY_READ, &hkey)) { return false; } long query_error = RegSetValueEx(hkey, value, 0, REG_SZ, (const BYTE*)contents, lstrlen(contents)+1); 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; } bool SetDevNodeRegString(DEVNODE dn, const char* name, const char* contents) { char hardware_key[256]; return GetDevNodeHardwareKey(dn, hardware_key, 256) && SetRegString(HKEY_LOCAL_MACHINE, hardware_key, name, contents); } namespace ConfigManager { DEVNODE dvdproxy_devnode; bool Init() { DEVNODE i; if (CR_SUCCESS == CM_Locate_DevNode(&i, 0, 0) && CR_SUCCESS == CM_Get_Child(&i, i, 0)) { do { char buf[256]; if (GetDevNodeRegString(i, "DeviceDesc", buf, 256)) { if (0 == lstrcmp(buf, "DVDSynth virtual SCSI card")) { dvdproxy_devnode = i; return true; } } } while (CR_SUCCESS == CM_Get_Sibling(&i, i, 0)); MessageBox(NULL, "Could not find the DVDSynth virtual SCSI controller.", "DVDSynth", MB_OK); } else { MessageBox(NULL, "Could not enumerate the Configuration Manager's device tree.", "DVDSynth", MB_OK); } return false; } unsigned GetDvdproxyDevnode() { return (unsigned)dvdproxy_devnode; } int GetDevnodeTargetID(DEVNODE node) { char buf[32]; // The SCSITargetID entry exists only under Win95/98/Me. if (!GetDevNodeRegString(node, "ScsiTargetID", buf, 32)) return -1; if (unsigned(buf[0] - '0') > 9) return -1; int id = 0; const char* p = buf; do { id = id*10 + (*p - '0'); ++p; } while (unsigned(*p - '0') <= 9); return id; } DEVNODE GetTargetDevnode(int target_id) { DEVNODE i; if (CR_SUCCESS == CM_Get_Child(&i, dvdproxy_devnode, 0)) { do { if (GetDevnodeTargetID(i) == target_id) { return i; } } while (CR_SUCCESS == CM_Get_Sibling(&i, i, 0)); } return 0; } void Reenumerate(bool synchronous) { printf("Reenumerate ->\n"); CM_Reenumerate_DevNode(dvdproxy_devnode, synchronous*CM_REENUMERATE_SYNCHRONOUS); printf("<- Reenumerate\n"); } bool QueryRemoveTarget2(int target) { DEVNODE devnode = GetTargetDevnode(target); if (!devnode) { // If the device doesn't even exist in Device Manager, unplugging // it without warning is unlikely to cause problems. return true; } else { return CR_SUCCESS == CM_Query_Remove_SubTree(devnode, CM_QUERY_REMOVE_UI_NOT_OK); } } bool QueryRemoveTarget(int target) { printf("QueryRemoveTarget(%d)\n", target); bool result = QueryRemoveTarget2(target); printf(" -> %d\n", result); return result; } void RemoveTarget2(int target) { DEVNODE devnode = GetTargetDevnode(target); printf("DEVNODE = %X\n", devnode); while (getchar() != '\n'); if (devnode) { CM_Remove_SubTree(devnode, 0/*CM_REMOVE_UI_NOT_OK*/); } } void RemoveTarget(int target) { printf("RemoveTarget(%d)\n", target); RemoveTarget2(target); printf(" -> done\n"); } unsigned GetDriveLetters(int target) { char buf[64]; unsigned letters = 0; if (GetTargetRegString(target, "CurrentDriveLetterAssignment", buf, 64)) { for (int i=0; buf[i]; ++i) { unsigned letter = buf[i] - 'A'; if (letter < 26) { letters |= 1 << letter; } } } return letters; } bool GetTargetRegString(int target, const char* name, char* buf, ULONG buflen) { DEVNODE devnode = GetTargetDevnode(target); return (devnode && GetDevNodeRegString(devnode, name, buf, buflen)); } bool SetTargetRegString(int target, const char* name, const char* contents) { DEVNODE devnode = GetTargetDevnode(target); return (devnode && SetDevNodeRegString(devnode, name, contents)); } /* bool RemoveTargetWithUI(int target) { DEVNODE dn = GetTargetDevnode(target); if (!dn) { return (IDYES == MessageBox(NULL, "Could not find this device in Device Manager! Force stop?", "DVDSynth", MB_YESNO|MB_DEFBUTTON2)); } CONFIGRET ret = My_CM_Query_And_Remove_SubTree(dn); if (ret == CR_SUCCESS) { return true; } else if (ret == CR_REMOVE_VETOED || ret == CR_QUERY_VETOED) { if (IDYES != MessageBox(NULL, "Windows indicates that it cannot safely unplug this device. There may be a file or folder still open on it.\n\nForcibly unplugging the device may cause applications to crash or make the system unstable.\n\nDo you want to forcibly unplug the device?", "DVDSynth", MB_YESNO|MB_DEFBUTTON2)) { return false; } } else { if (IDYES != MessageBox(NULL, "Windows has indicated that it cannot safely unplug this device. There may be a file or folder still open on it.\n\nYou can forcibly unplug the device, but this may cause applications to crash or make your system unstable.\n\nDo you want to forcibly unplug the device?" bool StopTargetWithUI(int target) { if (dn) { if (CR_SUCCESS == My_CM_Disable_DevNode(dn, CM_DISABLE_POLITE)) { return true; } if (IDYES != MessageBox(NULL, "Stop failed. Force stop?", "DVDSynth", MB_YESNO|MB_DEFBUTTON2)) { return false; } My_CM_Disable_DevNode(dn, CM_DISABLE_ABSOLUTE); return true; } else { return (IDYES == MessageBox(NULL, "Could not find this device in Device Manager! Force stop?", "DVDSynth", MB_YESNO|MB_DEFBUTTON2)); } } bool RemoveTargetWithUI(int target) { DEVNODE dn = GetTargetDevnode(target); if (dn) { PNP_VETO_TYPE veto_type; if (CR_SUCCESS == CM_Query_And_Remove_SubTreeW(dn, &veto_type, NULL, 0, 0)) { return true; } if (IDYES == MessageBox(NULL, "Stop failed. Force stop?", "DVDSynth", MB_YESNO|MB_DEFBUTTON2)) { return true; } else { return false; } } else { return (IDYES == MessageBox(NULL, "Could not find this device in Device Manager! Force stop?", "DVDSynth", MB_YESNO|MB_DEFBUTTON2)); } } */ }