我正在尝试为特定的 USB 设备构建 DLL。该 DLL 使用抽象接口导出类。我正在使用 setupapi.dll 进行 USB 设备识别、接收和发送数据包到设备。我收到导入函数的运行时检查错误 0。顺便说一句,正在使用多字节字符集。这是相关代码(它有点长,所以很抱歉):
//Bikedll.h
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> //Definitions for various common and not so common types like DWORD, PCHAR, HANDLE, etc.
#include <Dbt.h> //Need this for definitions of WM_DEVICECHANGE messages
#include <setupapi.h>
#include <string>
#include "AbstrClass.h"
using namespace std;
#define Cihaz_ID "Vid_a0a1&Pid_4147"
#define __YAZI__ "Esetron USB Kart V1.0"
typedef GUID* LPGUID;
typedef HDEVINFO ( *SetupDiGetClassDevsUMPTR)(LPGUID, PCTSTR, HWND, DWORD);
typedef WINSETUPAPI BOOL ( *SetupDiEnumDeviceInterfacesUMPTR)(HDEVINFO, PSP_DEVINFO_DATA, LPGUID, DWORD, PSP_DEVICE_INTERFACE_DATA);
typedef WINSETUPAPI BOOL ( *SetupDiDestroyDeviceInfoListUMPTR)(HDEVINFO);
typedef WINSETUPAPI BOOL ( *SetupDiEnumDeviceInfoUMPTR)(HDEVINFO, DWORD, PSP_DEVINFO_DATA);
typedef WINSETUPAPI BOOL ( *SetupDiGetDeviceRegistryPropertyUMPTR)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD);
typedef WINSETUPAPI BOOL ( *SetupDiSetDeviceRegistryPropertyUMPTR)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, const BYTE*, DWORD);
typedef BOOL ( *SetupDiGetDeviceInterfaceDetailUMPTR)(HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA, DWORD, PDWORD, PSP_DEVINFO_DATA);
typedef HDEVNOTIFY ( *RegisterDeviceNotificationUMPTR)(HANDLE, LPVOID, DWORD);
//Globally Unique Identifier (GUID) for HID class devices. Windows uses GUIDs to identify things.
GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30};
//USB variables
BOOL AttachedState = false;
BOOL AttachedButBroken = false;
PSP_DEVICE_INTERFACE_DETAIL_DATA DetailedInterfaceDataStructure = new SP_DEVICE_INTERFACE_DETAIL_DATA;
HANDLE WriteHandleToUSBDevice = INVALID_HANDLE_VALUE;
HANDLE ReadHandleToUSBDevice = INVALID_HANDLE_VALUE;
unsigned char LED_durum = 0;
HANDLE EP1INHandle = INVALID_HANDLE_VALUE;
HANDLE EP1OUTHandle = INVALID_HANDLE_VALUE;
bool durum = false;
unsigned char gond_paket[65]; //Number of elements, including '/0'
unsigned char gelen_paket[65];
DWORD Gond_say;
DWORD Gelen_say;
class Bikedll : public AbstrClass
{
public:
SetupDiGetClassDevsUMPTR _SetupDiGetClassDevsUMPTR;
SetupDiEnumDeviceInterfacesUMPTR _SetupDiEnumDeviceInterfacesUMPTR;
SetupDiDestroyDeviceInfoListUMPTR _SetupDiDestroyDeviceInfoListUMPTR;
SetupDiEnumDeviceInfoUMPTR _SetupDiEnumDeviceInfoUMPTR;
SetupDiGetDeviceRegistryPropertyUMPTR _SetupDiGetDeviceRegistryPropertyUMPTR;
SetupDiSetDeviceRegistryPropertyUMPTR _SetupDiSetDeviceRegistryPropertyUMPTR;
SetupDiGetDeviceInterfaceDetailUMPTR _SetupDiGetDeviceInterfaceDetailUMPTR;
RegisterDeviceNotificationUMPTR _RegisterDeviceNotificationUMPTR;
DWORD ErrorStatusWrite;
DWORD ErrorStatusRead;
//Explicit Linking
HINSTANCE hSetUpApi;
HINSTANCE hUser32;
string get_POT();
string get_RPM();
Bikedll();
BOOL CheckIfPresentAndGetUSBDevicePath(void)
{
HDEVINFO DeviceInfoTable = INVALID_HANDLE_VALUE;
PSP_DEVICE_INTERFACE_DATA InterfaceDataStructure = new SP_DEVICE_INTERFACE_DATA;
SP_DEVINFO_DATA DevInfoData;
DWORD InterfaceIndex = 0;
DWORD StatusLastError = 0;
DWORD dwRegType;
DWORD dwRegSize;
DWORD StructureSize = 0;
PBYTE PropertyValueBuffer;
bool MatchFound = false;
DWORD ErrorStatus;
BOOL BoolStatus = FALSE;
DWORD LoopCounter = 0;
string DeviceIDToFind = Cihaz_ID;
//First populate a list of plugged in devices (by specifying "DIGCF_PRESENT"), which are of the specified class GUID.
DeviceInfoTable = _SetupDiGetClassDevsUMPTR(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); // Run Time Check Error 0 (AKA RTCE 0) type of errors start here
//Now look through the list we just populated. We are trying to see if any of them match our device.
while(true)
{
InterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if(_SetupDiEnumDeviceInterfacesUMPTR(DeviceInfoTable, NULL, &InterfaceClassGuid, InterfaceIndex, InterfaceDataStructure)) //RTCE 0
{
ErrorStatus = GetLastError();
if(ERROR_NO_MORE_ITEMS == GetLastError()) //Did we reach the end of the list of matching devices in the DeviceInfoTable?
{ //Cound not find the device. Must not have been attached.
_SetupDiDestroyDeviceInfoListUMPTR(DeviceInfoTable); //Clean up the old structure we no longer need. Still RTCE 0
return FALSE;
}
}
else //Else some other kind of unknown error ocurred...
{
ErrorStatus = GetLastError();
_SetupDiDestroyDeviceInfoListUMPTR(DeviceInfoTable); //Clean up the old structure we no longer need. RTCE 0
return FALSE;
}
//Now retrieve the hardware ID from the registry. The hardware ID contains the VID and PID, which we will then
//check to see if it is the correct device or not.
//Initialize an appropriate SP_DEVINFO_DATA structure. We need this structure for SetupDiGetDeviceRegistryProperty().
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
_SetupDiEnumDeviceInfoUMPTR(DeviceInfoTable, InterfaceIndex, &DevInfoData); //RTCE 0
//First query for the size of the hardware ID, so we can know how big a buffer to allocate for the data.
_SetupDiGetDeviceRegistryPropertyUMPTR(DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &dwRegType, NULL, 0, &dwRegSize); //RTCE 0
//Allocate a buffer for the hardware ID.
PropertyValueBuffer = (BYTE *) malloc (dwRegSize);
if(PropertyValueBuffer == NULL) //if null, error, couldn't allocate enough memory
{ //Can't really recover from this situation, just exit instead.
_SetupDiDestroyDeviceInfoListUMPTR(DeviceInfoTable); //Clean up the old structure we no longer need. RTCE 0
return FALSE;
}
//Retrieve the hardware IDs for the current device we are looking at. PropertyValueBuffer gets filled with a
//REG_MULTI_SZ (array of null terminated strings). To find a device, we only care about the very first string in the
//buffer, which will be the "device ID". The device ID is a string which contains the VID and PID, in the example
//format "Vid_04d8&Pid_003f".
_SetupDiGetDeviceRegistryPropertyUMPTR(DeviceInfoTable, &DevInfoData, SPDRP_HARDWAREID, &dwRegType, PropertyValueBuffer, dwRegSize, NULL); // RTCE 0
//Now check if the first string in the hardware ID matches the device ID of my USB device.
string* DeviceIDFromRegistry = new string((char *)PropertyValueBuffer);
free(PropertyValueBuffer); //No longer need the PropertyValueBuffer, free the memory to prevent potential memory leaks
//Now check if the hardware ID we are looking at contains the correct VID/PID
if (std::string::npos != DeviceIDFromRegistry->find(DeviceIDToFind))
{
MatchFound = true;
}
if(MatchFound == true)
{
//Device must have been found. Open WinUSB interface handle now. In order to do this, we will need the actual device path first.
//We can get the path by calling SetupDiGetDeviceInterfaceDetail(), however, we have to call this function twice: The first
//time to get the size of the required structure/buffer to hold the detailed interface data, then a second time to actually
//get the structure (after we have allocated enough memory for the structure.)
DetailedInterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
//First call populates "StructureSize" with the correct value
_SetupDiGetDeviceInterfaceDetailUMPTR(DeviceInfoTable, InterfaceDataStructure, NULL, NULL, &StructureSize, NULL);
DetailedInterfaceDataStructure = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(malloc(StructureSize)); //Allocate enough memory
if(DetailedInterfaceDataStructure == NULL) //if null, error, couldn't allocate enough memory
{ //Can't really recover from this situation, just exit instead.
_SetupDiDestroyDeviceInfoListUMPTR(DeviceInfoTable); //Clean up the old structure we no longer need.
return FALSE;
}
DetailedInterfaceDataStructure->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
//Now call SetupDiGetDeviceInterfaceDetail() a second time to receive the goods.
_SetupDiGetDeviceInterfaceDetailUMPTR(DeviceInfoTable, InterfaceDataStructure, DetailedInterfaceDataStructure, StructureSize, NULL, NULL);
// Set Device Name
BYTE *pbuf = new BYTE[sizeof(TEXT(__YAZI__))];
pbuf = (BYTE*)TEXT(__YAZI__);
_SetupDiSetDeviceRegistryPropertyUMPTR(DeviceInfoTable, &DevInfoData, SPDRP_FRIENDLYNAME , pbuf, sizeof(TEXT(__YAZI__)));
//We now have the proper device path, and we can finally open a device handle to the device.
//WinUSB requires the device handle to be opened with the FILE_FLAG_OVERLAPPED attribute.
_SetupDiDestroyDeviceInfoListUMPTR(DeviceInfoTable); //Clean up the old structure we no longer need.
return TRUE;
}
InterfaceIndex++;
//Keep looping until we either find a device with matching VID and PID, or until we run out of devices to check.
//However, just in case some unexpected error occurs, keep track of the number of loops executed.
//If the number of loops exceeds a very large number, exit anyway, to prevent inadvertent infinite looping.
LoopCounter++;
if(LoopCounter == 10000000) //Surely there aren't more than 10 million devices attached to any forseeable PC...
{
return FALSE;
}
}
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~Bikedll()
{
//Close the read/write handles, if they are currently open.
if(AttachedState == TRUE)
{
CloseHandle(WriteHandleToUSBDevice);
CloseHandle(ReadHandleToUSBDevice);
}
}
};
string Bikedll::get_RPM(){
gond_paket[0] = 0;
gond_paket[1] = 160;
gond_paket[2] = 0;
gond_paket[3] = 0;
string str;
for(unsigned char i = 4; i <65; i++)
gond_paket[i] = 0xFF;
WriteFile(WriteHandleToUSBDevice, &gond_paket, 65, &Gond_say, 0);
if (ReadFile(ReadHandleToUSBDevice,&gelen_paket,65,&Gelen_say,0))
{
if (gelen_paket[1] == 0xBA)
{
return str = gelen_paket[3];
}
}
}
string Bikedll::get_POT(){
gond_paket[0] = 0;
gond_paket[1] = 160;
gond_paket[2] = 0;
gond_paket[3] = 0;
string str;
for(unsigned char i = 4; i <65; i++)
gond_paket[i] = 0xFF;
WriteFile(WriteHandleToUSBDevice, &gond_paket, 65, &Gond_say, 0);
if (ReadFile(ReadHandleToUSBDevice,&gelen_paket,65,&Gelen_say,0))
{
if (gelen_paket[1] == 0xBA)
{
return str = gelen_paket[5];
}
}
}
Bikedll::Bikedll(){
hSetUpApi = LoadLibrary("setupapi.dll");
hUser32 = LoadLibrary("user32.dll");
_SetupDiGetClassDevsUMPTR = (SetupDiGetClassDevsUMPTR)GetProcAddress(hSetUpApi, "SetupDiGetClassDevsA");
_SetupDiEnumDeviceInterfacesUMPTR = (SetupDiEnumDeviceInterfacesUMPTR)GetProcAddress(hSetUpApi, "SetupDiEnumDeviceInterfaces");
_SetupDiDestroyDeviceInfoListUMPTR = (SetupDiDestroyDeviceInfoListUMPTR)GetProcAddress(hSetUpApi, "SetupDiDestroyDeviceInfoList");
_SetupDiEnumDeviceInfoUMPTR = (SetupDiEnumDeviceInfoUMPTR)GetProcAddress(hSetUpApi, "SetupDiEnumDeviceInfo");
_SetupDiGetDeviceRegistryPropertyUMPTR = (SetupDiGetDeviceRegistryPropertyUMPTR)GetProcAddress(hSetUpApi, "SetupDiGetDeviceRegistryPropertyA");
_SetupDiSetDeviceRegistryPropertyUMPTR = (SetupDiSetDeviceRegistryPropertyUMPTR)GetProcAddress(hSetUpApi, "SetupDiSetDeviceRegistryPropertyA");
_SetupDiGetDeviceInterfaceDetailUMPTR = (SetupDiGetDeviceInterfaceDetailUMPTR)GetProcAddress(hSetUpApi, "SetupDiGetDeviceInterfaceDetailA");
DEV_BROADCAST_DEVICEINTERFACE MyDeviceBroadcastHeader;// = new DEV_BROADCAST_HDR;
MyDeviceBroadcastHeader.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
MyDeviceBroadcastHeader.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
MyDeviceBroadcastHeader.dbcc_reserved = 0; //Reserved says not to use...
MyDeviceBroadcastHeader.dbcc_classguid = InterfaceClassGuid;
if(CheckIfPresentAndGetUSBDevicePath()) //Look for the device
{
DWORD ErrorStatusWrite;
DWORD ErrorStatusRead;
WriteHandleToUSBDevice = CreateFile(DetailedInterfaceDataStructure->DevicePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
ErrorStatusWrite = GetLastError();
ReadHandleToUSBDevice = CreateFile(DetailedInterfaceDataStructure->DevicePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
ErrorStatusRead = GetLastError();
if((ErrorStatusWrite == ERROR_SUCCESS) && (ErrorStatusRead == ERROR_SUCCESS))
{
AttachedState = TRUE;
AttachedButBroken = FALSE;
//okay
}
else //reading or writing operations failed
{
AttachedState = FALSE;
AttachedButBroken = TRUE;
if(ErrorStatusWrite == ERROR_SUCCESS)//Açık bağlantıları kapat
CloseHandle(WriteHandleToUSBDevice);
if(ErrorStatusRead == ERROR_SUCCESS)
CloseHandle(ReadHandleToUSBDevice);
//err1();
}
}
else
{
AttachedState = FALSE;
AttachedButBroken = FALSE;
//err2();
}
}
//Interface to be exported with usable virtual functions
#include <string>
class AbstrClass{
public:
virtual std::string get_POT() = 0;
virtual std::string get_RPM() = 0;
};
// Bikedll.cpp : Defines the exported functions for the DLL application.
#include "stdafx.h"
#include "Bikedll.h"
extern "C" __declspec(dllexport) AbstrClass* __cdecl create_AbstrClass()
{
return new Bikedll;
}
// TestdllBike.cpp : Program to test Bikedll
#include "stdafx.h"
#include "AbstrClass.h"
#include <Windows.h>
#include <iostream>
using namespace std;
typedef AbstrClass* (__cdecl *abstrClass_factory)();
int main()
{
HINSTANCE dll_handle = ::LoadLibrary(TEXT("Bikedll.dll"));
if(!dll_handle){
cerr << "Installation failed!";
return 1;
}
abstrClass_factory factory_func = reinterpret_cast<abstrClass_factory>(::GetProcAddress(dll_handle, "create_AbstrClass"));
if (!factory_func) {
cerr << "function was not imported from dll!\n";
::FreeLibrary(dll_handle);
return 1;
}
AbstrClass* instance = factory_func();
string t = instance->get_POT();
cout << "POT : " << t << endl;
string v = instance->get_RPM();
cout << "RPM : " << v << endl;
return 0;
}