C++/CLI 调用 C DLL ,错误:此Bug常见来源包括用户对 COM-interope 或 Pinvoke的封送处理,这些错误可能会损坏堆栈
背景介绍:现有 C 和 C ++ 的混合代码,我要用 C++/CLI 去调用它,考虑到语言的差异,所以要将前者封装成 DLL。
C 函数原型:
int fb_data_send_Me(omap_usb_handle *usb, const void *data, unsigned size, unsigned count);
该函数的作用是往指定的 usb 对象中写入 data ,data 的长度是 size,count 是写的次数;
其中:fb_data_send_Me 第一句代码是这样的:
unsigned char* ptr = (unsigned char*) data; // 可见传递的是 unsigned char 类型数组; c++/cli pinvoke C dll 封送处理 --------------------编程问答-------------------- 我的处理方法:
我尝试了三种方法在 C++/CLI 中对 fb_data_send_Me进行声明:
声明式样一:
int fb_data_send_Me( UsbDriver^ usb, System::IntPtr data, unsigned int size, unsigned int count);
声明样式二:
int fb_data_send_Me( UsbDriver^ usb,
[MarshalAs(UnmanagedType::LPArray,SizeParamIndex = 1)]
array< byte >^ data,
unsigned int s ize,
unsigned int count ); 声明式样三: int fb_data_send_Me( UsbDriver^ usb, array<byte>^ data, unsigned int size, unsigned int count); --------------------编程问答-------------------- 对于声明一的调用方式:
int total = 1;
int size = 0;
int writeTotal = 0; // 存储实际写入的数据量;
array< System::IntPtr >^ ptBuffer = gcnew array< System::IntPtr >( total );
size = System::Runtime::InteropServices::Marshal::SizeOf( buffer[0] ) * buffer->Length;
// 获取数组大小,buffer 为已经被填充的,即将传递下去的字节数组;
ptBuffer[0] = System::Runtime::InteropServices::Marshal::AllocHGlobal( size ); // 分配非托管内存,到时候要手动释放;
System::Runtime::InteropServices::Marshal::Copy( buffer,0,(System::IntPtr)ptBuffer[0],buffer->Length ); // 复制托管数组到非托管内存;
//
// 使用复制内存的方法,并且使用 drv_usb 对象,NG;
//
writeTotal = fb_data_send_Me( drv_usb, ( System::IntPtr )ptBuffer[0], (unsigned int)buffer->Length, (unsigned int)0 ); --------------------编程问答-------------------- 程序报告错误,截图如下:
--------------------编程问答-------------------- 第一个参数可能就错了
omap_usb_handle 类型是托管的还是非托管的,如果是非托管的不能用^ --------------------编程问答-------------------- 对于方式二的引用:
writeTotal = fb_data_send_Me( drv_usb,buffer, (unsigned int)buffer->Length, (unsigned int)0 ));
其中:buffer 为已经填充 Ok 的unsigned char 星字节数组。
编译还是报告相同的错误。 --------------------编程问答-------------------- 第一个参数是个抽象类,其源代码是这样子的:
class ComDriver
{
public:
virtual ~ComDriver() { };
virtual S8 open(U8 port, U32 baudRate, U8 parity, U8 stopBits, U8 data) = 0;
virtual S8 close(void) = 0;
virtual S8 reset(void) = 0;
virtual S8 configure(U32 baudRate, U8 parity, U8 stopBits, U8 data) = 0;
virtual S32 write(U8 *buffer, U32 size) = 0;
virtual S32 read(U8 *buffer, U32 size, U32 timeout) = 0;
virtual void registerCallback(T_COM_DRV_CALL_BACK callback) = 0;
virtual void unregisterCallback() = 0;
virtual void registerConnectionLostCallback(T_COM_DRV_CONNECTION_LOST_CALL_BACK callback) = 0;
virtual U16 sid() = 0;
virtual int getDrvErr() = 0;
protected:
U8 debugLevel;
virtual U8 initDebugLevel();
virtual void debugPrint(U8 level, const char *format, ...);
}; --------------------编程问答-------------------- 之后有一个类 usbdriver 继承了该类,其具体如下:
class API UsbDriver : public ComDriver
{
public:
UsbDriver(U16 sid = 0);
~UsbDriver();
S8 open(U8 port, U32 baudRate, U8 parity, U8 stopBits, U8 data);
S8 close(void);
S8 reset(void);
S8 configure(U32 baudRate, U8 parity, U8 stopBits, U8 data);
S32 write(U8 *buffer, U32 size);
S32 read(U8 *buffer, U32 size, U32 timeout);
void registerCallback(T_COM_DRV_CALL_BACK callback);
void unregisterCallback();
void registerConnectionLostCallback(T_COM_DRV_CONNECTION_LOST_CALL_BACK callback);
U16 sid() { return sessionId; }
int getDrvErr() { return driverErr; }
//
// 手动添加测试;
//
int add( int x,int y );
private:
U8 portNum;
U16 sessionId, threadId;
bool isOpen;
bool isClosing;
bool rxComplete;
U8 *readFifo;
U32 readFifoPtr;
U32 readFifoBytesAvailable;
HANDLE usbDevice;
HANDLE listener;
HANDLE readyEvent;
HANDLE shutdownEvent;
char driverName[50];
int driverErr;
unsigned char bulkInPipe;
unsigned char bulkOutPipe;
WINUSB_INTERFACE_HANDLE winUsbHandle;
T_COM_DRV_CALL_BACK rxCallback;
T_COM_DRV_CONNECTION_LOST_CALL_BACK connectionLostCallback;
HANDLE getDeviceHandle(U8 port);
void getDriverName(char deviceKeyName[]);
void getDeviceKeyName(char usbPath[], char deviceKeyName[]);
S32 readHw(U8 *buffer, U32 size, U32 timeout);
// to use for WinUSB
bool initializeDevice();
friend unsigned int __stdcall usbListener(void *drvObj);
};
我在进行封送的时候,在C++/CLI 中重构了 usbdriver 的所有变量,在程序跟踪时发现所有的变量都被赋值了,这个可能没错吧。
还是感谢以上的回答。
我明天尝试一下奉送 comdriver 这个抽象类试试 --------------------编程问答-------------------- 没仔细看,你使用c++/cli啊,他可以直接调用非托管dll,而不要像C#那样还要自己再封装一下 --------------------编程问答-------------------- 你好 问下这个问题解决了么 我也是报的同样的错误,在C#中调用了C++的代码,导致堆栈出错。但是对封装、封送知识还不大了解,嫩那个不能赐教下。多谢多谢
补充:.NET技术 , 其他语言