📄 deveject.cpp
字号:
// DevEject.cpp
// Plug&Play-Ger鋞e automatisch abmelden, f黵 Windows 2000/XP/2003
// 躡ersetzen mit Visual C++:
// cl deveject.cpp advapi32.lib
// 2003 c't/Matthias Withopf
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
class TDeviceEject
{
public:
typedef enum
{
deec_Ok = 0,
deec_UnsupportedOS = 1,
deec_ErrorLoadingLibrary = 2,
deec_LibraryFunctionMissing = 3,
deec_DeviceNotFound = 4,
deec_DeviceNotRemovable = 5,
deec_DeviceHasProblem = 6,
deec_NativeError = 7,
deec_ErrorGettingDevNodeStatus = 8,
deec_ErrorGettingDeviceIdSize = 9,
deec_ErrorGettingDeviceId = 10,
deec_ErrorGettingChild = 11,
deec_ErrorGettingSibling = 12,
deec_ErrorLocatingDevNode = 13,
deec_ErrorDeviceEject = 14,
deec_ErrorEjectVetoed = 15,
deec_LAST
} TDeviceEjectErrorCode;
TDeviceEjectErrorCode DeviceEjectErrorCode;
// Fehlercodes des Configuration Managers
enum
{
CR_SUCCESS = 0x00,
CR_DEFAULT = 0x01,
CR_OUT_OF_MEMORY = 0x02,
CR_INVALID_POINTER = 0x03,
CR_INVALID_FLAG = 0x04,
CR_INVALID_DEVNODE = 0x05,
CR_INVALID_RES_DES = 0x06,
CR_INVALID_LOG_CONF = 0x07,
CR_INVALID_ARBITRATOR = 0x08,
CR_INVALID_NODELIST = 0x09,
CR_DEVNODE_HAS_REQS = 0x0A,
CR_INVALID_RESOURCEID = 0x0B,
CR_DLVXD_NOT_FOUND = 0x0C,
CR_NO_SUCH_DEVNODE = 0x0D,
CR_NO_MORE_LOG_CONF = 0x0E,
CR_NO_MORE_RES_DES = 0x0F,
CR_ALREADY_SUCH_DEVNODE = 0x10,
CR_INVALID_RANGE_LIST = 0x11,
CR_INVALID_RANGE = 0x12,
CR_FAILURE = 0x13,
CR_NO_SUCH_LOGICAL_DEV = 0x14,
CR_CREATE_BLOCKED = 0x15,
CR_NOT_SYSTEM_VM = 0x16,
CR_REMOVE_VETOED = 0x17,
CR_APM_VETOED = 0x18,
CR_INVALID_LOAD_TYPE = 0x19,
CR_BUFFER_SMALL = 0x1A,
CR_NO_ARBITRATOR = 0x1B,
CR_NO_REGISTRY_HANDLE = 0x1C,
CR_REGISTRY_ERROR = 0x1D,
CR_INVALID_DEVICE_ID = 0x1E,
CR_INVALID_DATA = 0x1F,
CR_INVALID_API = 0x20,
CR_DEVLOADER_NOT_READY = 0x21,
CR_NEED_RESTART = 0x22,
CR_NO_MORE_HW_PROFILES = 0x23,
CR_DEVICE_NOT_THERE = 0x24,
CR_NO_SUCH_VALUE = 0x25,
CR_WRONG_TYPE = 0x26,
CR_INVALID_PRIORITY = 0x27,
CR_NOT_DISABLEABLE = 0x28,
CR_FREE_RESOURCES = 0x29,
CR_QUERY_VETOED = 0x2A,
CR_CANT_SHARE_IRQ = 0x2B,
CR_NO_DEPENDENT = 0x2C,
CR_SAME_RESOURCES = 0x2D,
CR_NO_SUCH_REGISTRY_KEY = 0x2E,
CR_INVALID_MACHINENAME = 0x2F,
CR_REMOTE_COMM_FAILURE = 0x30,
CR_MACHINE_UNAVAILABLE = 0x31,
CR_NO_CM_SERVICES = 0x32,
CR_ACCESS_DENIED = 0x33,
CR_CALL_NOT_IMPLEMENTED = 0x34,
CR_INVALID_PROPERTY = 0x35,
CR_DEVICE_INTERFACE_ACTIVE = 0x36,
CR_NO_SUCH_DEVICE_INTERFACE = 0x37,
CR_INVALID_REFERENCE_STRING = 0x38,
CR_INVALID_CONFLICT_LIST = 0x39,
CR_INVALID_INDEX = 0x3A,
CR_INVALID_STRUCTURE_SIZE = 0x3B
};
DWORD NativeErrorCode;
TDeviceEject(BOOL AVerbose,BOOL ADebug);
~TDeviceEject();
TDeviceEjectErrorCode Eject(PCHAR EjectDevSpec,BOOL EjectDevSpecIsName,PDWORD NativeErrorCode,PDWORD EjectedCount);
static BOOL GetDriveDeviceId(PCHAR DriveSpec,PCHAR DeviceId,DWORD MaxDeviceIdSize);
private:
BOOL Verbose;
BOOL Debug;
HMODULE Lib;
BOOL UnloadLib;
typedef DWORD DEVINST,*PDEVINST;
typedef CHAR *DEVINSTID_A;
typedef enum
{
PNP_VetoTypeUnknown,
PNP_VetoLegacyDevice,
PNP_VetoPendingClose,
PNP_VetoWindowsApp,
PNP_VetoWindowsService,
PNP_VetoOutstandingOpen,
PNP_VetoDevice,
PNP_VetoDriver,
PNP_VetoIllegalDeviceRequest,
PNP_VetoInsufficientPower,
PNP_VetoNonDisableable,
PNP_VetoLegacyDriver,
PNP_VetoInsufficientRights
} PNP_VETO_TYPE,* PPNP_VETO_TYPE;
enum
{
DN_REMOVABLE = 0x00004000
};
typedef DWORD CONFIGRET;
typedef CONFIGRET (WINAPI *TCM_Locate_DevNodeA) (OUT PDEVINST pdnDevInst,IN DEVINSTID_A pDeviceID,OPTIONAL IN ULONG ulFlags);
typedef CONFIGRET (WINAPI *TCM_Get_Child) (OUT PDEVINST pdnDevInst,IN DEVINST dnDevInst,IN ULONG ulFlags);
typedef CONFIGRET (WINAPI *TCM_Get_Sibling) (OUT PDEVINST pdnDevInst,IN DEVINST DevInst,IN ULONG ulFlags);
typedef CONFIGRET (WINAPI *TCM_Get_DevNode_Status) (OUT PULONG pulStatus,OUT PULONG pulProblemNumber,IN DEVINST dnDevInst,IN ULONG ulFlags);
typedef CONFIGRET (WINAPI *TCM_Get_Device_ID_Size) (OUT PULONG pulLen,IN DEVINST dnDevInst,IN ULONG ulFlags);
typedef CONFIGRET (WINAPI *TCM_Get_Device_IDA) (IN DEVINST dnDevInst,OUT PCHAR Buffer,IN ULONG BufferLen,IN ULONG ulFlags);
typedef CONFIGRET (WINAPI *TCM_Request_Device_EjectA)(IN DEVINST dnDevInst,OUT PPNP_VETO_TYPE pVetoType,OUT LPSTR pszVetoName,IN ULONG ulNameLength,IN ULONG ulFlags);
TCM_Locate_DevNodeA Func_LocateDevNode;
TCM_Get_Child Func_GetChild;
TCM_Get_Sibling Func_GetSibling;
TCM_Get_DevNode_Status Func_GetDevNodeStatus;
TCM_Get_Device_ID_Size Func_GetDeviceIDSize;
TCM_Get_Device_IDA Func_GetDeviceID;
TCM_Request_Device_EjectA Func_RequestDeviceEject;
typedef struct _TEnumDeviceInfo
{
struct _TEnumDeviceInfo *Parent;
DEVINST DevInst;
ULONG Status;
ULONG ProblemNumber;
} TEnumDeviceInfo,* PEnumDeviceInfo;
TDeviceEjectErrorCode EnumDevices(PEnumDeviceInfo ParentEnumDeviceInfo,PDWORD EjectDeviceFound,PCHAR EjectDevSpec,BOOL EjectDevSpecIsName,DEVINST DevInst,int Indent,PDWORD NativeErrorCode);
BOOL GetFriendlyName(PCHAR DeviceId,PCHAR Name,DWORD MaxNameSize);
};
typedef TDeviceEject * PDeviceEject;
TDeviceEject::TDeviceEject(BOOL AVerbose,BOOL ADebug)
{
DeviceEjectErrorCode = deec_Ok;
NativeErrorCode = 0;
Verbose = AVerbose;
Debug = ADebug;
Lib = NULL;
UnloadLib = FALSE;
Func_LocateDevNode = NULL;
Func_GetChild = NULL;
Func_GetSibling = NULL;
Func_GetDevNodeStatus = NULL;
Func_GetDeviceIDSize = NULL;
Func_GetDeviceID = NULL;
Func_RequestDeviceEject = NULL;
BOOL OSOk = FALSE;
DWORD V = GetVersion();
if (!(V & 0x80000000))
{
BYTE MajorVersion = (BYTE)V;
if (MajorVersion >= 5)
OSOk = TRUE;
}
if (!OSOk)
DeviceEjectErrorCode = deec_UnsupportedOS;
else
{
const PCHAR LibFileName = "setupapi.dll";
Lib = GetModuleHandle(LibFileName);
if (!Lib)
{
Lib = LoadLibrary(LibFileName);
if (Lib)
UnloadLib = TRUE;
}
if (!Lib)
{
DeviceEjectErrorCode = deec_ErrorLoadingLibrary;
NativeErrorCode = GetLastError();
}
else
{
Func_LocateDevNode = (TCM_Locate_DevNodeA) GetProcAddress(Lib,"CM_Locate_DevNodeA");
Func_GetChild = (TCM_Get_Child) GetProcAddress(Lib,"CM_Get_Child");
Func_GetSibling = (TCM_Get_Sibling) GetProcAddress(Lib,"CM_Get_Sibling");
Func_GetDevNodeStatus = (TCM_Get_DevNode_Status) GetProcAddress(Lib,"CM_Get_DevNode_Status");
Func_GetDeviceIDSize = (TCM_Get_Device_ID_Size) GetProcAddress(Lib,"CM_Get_Device_ID_Size");
Func_GetDeviceID = (TCM_Get_Device_IDA) GetProcAddress(Lib,"CM_Get_Device_IDA");
Func_RequestDeviceEject = (TCM_Request_Device_EjectA)GetProcAddress(Lib,"CM_Request_Device_EjectA");
}
}
}
TDeviceEject::~TDeviceEject()
{
if (Lib && UnloadLib)
FreeLibrary(Lib);
}
BOOL TDeviceEject::GetDriveDeviceId(PCHAR DriveSpec,PCHAR DeviceId,DWORD MaxDeviceIdSize)
{
BOOL Result = FALSE;
if (DeviceId && MaxDeviceIdSize)
DeviceId[0] = '\0';
if (DriveSpec && DriveSpec[0] && DeviceId && MaxDeviceIdSize)
{
HKEY Key;
LONG L = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\MountedDevices",0,KEY_QUERY_VALUE,&Key);
if (L == ERROR_SUCCESS)
{
DWORD Type;
BYTE Value[1024];
DWORD ValueSize = sizeof Value;
CHAR ValueName[256];
strcpy(ValueName,"\\DosDevices\\");
strncat(ValueName,DriveSpec,sizeof ValueName - 1);
ValueName[sizeof ValueName - 1] = '\0';
L = RegQueryValueEx(Key,ValueName,0,&Type,(BYTE *)Value,&ValueSize);
RegCloseKey(Key);
if ((L == ERROR_SUCCESS) && (Type == REG_BINARY))
{
// Beispielsweise:
// \??\SBP2#API-903-95__&1394_Storage_+_Repeater_&LUN0#0050c564500068e2#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}
// ->
// SBP2\API-903-95__&1394_STORAGE_+_REPEATER_&LUN0\0050C564500068E2
PWSTR p1 = (PWSTR)Value;
ValueSize /= sizeof *p1;
if ((p1[0] == '\\') && (p1[1] == '?') && (p1[2] == '?') && (p1[3] == '\\'))
{
Result = TRUE;
p1 += 4;
ValueSize -= 4;
PCHAR p2 = DeviceId;
for (unsigned int i = 0;i < ValueSize;++i)
{
CHAR c = p1[i];
if ((c == '{') || ((c == '#') && (p1[i + 1] == '{')))
break;
if (c == '#')
c = '\\';
if ((p2 - DeviceId) < (MaxDeviceIdSize - 1))
*p2++ = c;
}
*p2 = '\0';
}
}
}
}
return Result;
}
BOOL TDeviceEject::GetFriendlyName(PCHAR DeviceId,PCHAR Name,DWORD MaxNameSize)
{
BOOL Result = FALSE;
if (Name && MaxNameSize)
Name[0] = '\0';
if (DeviceId && DeviceId[0] && Name && MaxNameSize)
{
HKEY Key;
CHAR KeyName[1024];
strcpy(KeyName,"SYSTEM\\CurrentControlSet\\Enum\\");
strncat(KeyName,DeviceId,sizeof KeyName - 1);
KeyName[sizeof KeyName - 1] = '\0';
LONG L = RegOpenKeyEx(HKEY_LOCAL_MACHINE,KeyName,0,KEY_QUERY_VALUE,&Key);
if (L == ERROR_SUCCESS)
{
DWORD Type;
BYTE Value[1024];
DWORD ValueSize = sizeof Value;
L = RegQueryValueEx(Key,"FriendlyName",0,&Type,(BYTE *)Value,&ValueSize);
if (L != ERROR_SUCCESS)
L = RegQueryValueEx(Key,"DeviceDesc",0,&Type,(BYTE *)Value,&ValueSize);
RegCloseKey(Key);
if ((L == ERROR_SUCCESS) && (Type == REG_SZ))
{
strncpy(Name,(PCHAR)Value,MaxNameSize - 1);
Name[MaxNameSize - 1] = '\0';
Result = TRUE;
}
}
}
return Result;
}
static BOOL CompareWithWildcard(PCHAR s1,PCHAR s2)
{
if (s1 && s2)
for (;;)
{
if (*s2 == '*')
return TRUE;
if (!*s1)
{
if (!*s2)
return TRUE;
break;
}
if (!*s2)
{
if (!*s1)
return TRUE;
break;
}
if (toupper(*s1++) != toupper(*s2++))
break;
}
return FALSE;
}
TDeviceEject::TDeviceEjectErrorCode TDeviceEject::EnumDevices(PEnumDeviceInfo ParentEnumDeviceInfo,PDWORD EjectDeviceFound,PCHAR EjectDevSpec,BOOL EjectDevSpecIsName,DEVINST DevInst,int Indent,PDWORD NativeErrorCode)
{
TDeviceEjectErrorCode Result = deec_Ok;
DEVINST ThisDevInst = DevInst;
while (Result == deec_Ok)
{
ULONG Status; // DN_...
ULONG ProblemNumber;
CONFIGRET r = Func_GetDevNodeStatus(&Status,&ProblemNumber,ThisDevInst,0);
if (r == CR_NO_SUCH_DEVNODE)
{
}
else if (r != CR_SUCCESS)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -