求助C转C#调用动态库的问题

chenxd110 2018-04-08 10:51:24
有一个C调用动态库实现的demo需要转成C#,有一个动态库的参数是结构体,遇到了问题,传过去的数据不对,想请各位大神看下是哪里的问题。


C
引用头文件
#define QRCODE_HEX_DATA "02010054323038383130323135303834323333315A2F1CC80A0D0A0D00000000000000000000000003BEDDEA3AAA38BABEA523A6727F066248FCCBEE59CA00165A5748303030303031083030303030303031051234567890463044022063B2600A7327976B326C1E7DC32E675BC8FA8B551117A59D75C371E6A7ACD7440220521D28F6164D7A080F4B4231088C53B119DFACF25651A019C375C051B40098EE0458A680F836303402184CC9C9F567BBA3F8E2B30D7FAF5E03E55FC24CE9AEC8E5B1021806E5F931628C522C378DFBCD99CDEC271432C3D1486DD34F"

参数定义
int qrcode_len = 0;
unsigned char qrcode[512] = {0};

/**
* mock一个用户传入的二维码数据qrcode
*/

typedef struct _verify_request_v2{
const unsigned char* qrcode;
int qrcode_len;
const char* pos_param;
int amount_cent;
}VERIFY_REQUEST_V2;

/**
*/
typedef struct _verify_response_v2{
char* uid;
int uid_len;
char* record;
int record_len;
char* card_no;
int card_no_len;
unsigned char* card_data;
int card_data_len;
char* card_type;
int card_type_len;
}VERIFY_RESPONSE_V2;



mock_qrcode(qrcode, &qrcode_len);



/**
* mock一个用户传入的二维码数据qrcode
* 此处是使用QRCODE_HEX_DATA mock出的用户二维码数据
* 开发者测试时请使用二维码工具生成一个新的QRCODE_HEX_DATA后
* 装入宏定义中QRCODE_HEX_DATA,再执行mock
*/
void mock_qrcode(unsigned char* qrcode, int* qrcode_len){

char qrcode_hex[] = QRCODE_HEX_DATA;
int qrcode_hex_len = strlen(qrcode_hex);
*qrcode_len = strlen(qrcode_hex)/2;
hex_string_to_bytes(qrcode_hex, qrcode_hex_len, qrcode, *qrcode_len);
}

/**
* hex格式字符串转字节数组
* @param hex_string: 十六进制字符串
* @param hex_string_len: 十六进制字符串长度
* @param bytes: 二进制数据存储空间
* @param bytes_len: 目标空间长度
*/
int hex_string_to_bytes(
char* hex_string,
int hex_string_len,
unsigned char* bytes,
int bytes_len) {

int i = 0;

/**
* 校验十六进制字符串长度必须偶数,并且目标存储空间必须足够存放转换后的二进制数据
*/
if((hex_string_len % 2 != 0) || (bytes_len * 2 < hex_string_len)) {
return -1;
}

for(i = 0; i < hex_string_len; i += 2) {
bytes[i/2] = ((hex_of_char(hex_string[i]) << 4) & 0xF0) |
(hex_of_char(hex_string[i + 1]) & 0x0F);
}
return 1;
}
#endif

/**
* hex格式char转二进制
*/
unsigned char hex_of_char(char c) {
unsigned char tmp = 0;
if(c >= '0' && c <= '9') {
tmp = (c - '0');
}
else if(c >= 'A' && c <= 'F') {
tmp = (c - 'A' + 10);
}
else if(c >= 'a' && c <= 'f') {
tmp = (c - 'a' + 10);
}
return tmp;
}



//拼装验证请求
VERIFY_REQUEST_V2 verify_request;
//装入二进制格式的二维码
verify_request.qrcode = qrcode;
//装入二进制二维码长度
verify_request.qrcode_len = qrcode_len;
//装入pos_param
verify_request.pos_param = pos_param;
//装入本次消费金额
verify_request.amount_cent = AMOUNT_CENT;

VERIFY_RESPONSE_V2 verify_response;
verify_response.uid = (char*)malloc(17);
verify_response.uid_len = 17;
verify_response.record = (char*)malloc(2048);
verify_response.record_len = 2048;
verify_response.card_no = (char*)malloc(32);
verify_response.card_no_len = 32;
verify_response.card_data = (unsigned char*)malloc(128);
verify_response.card_data_len = 128;
verify_response.card_type = (char*)malloc(16);
verify_response.card_type_len = 16;
/**
* 调用接口验证二维码的有效性
*/
ret = verify_qrcode_v2(&verify_request, &verify_response);


结果是正确的。




c#

string qrcodeHexData = "02010054323038383130323135303834323333315A2F1CC80A0D0A0D00000000000000000000000003BEDDEA3AAA38BABEA523A6727F066248FCCBEE59CA00165A5748303030303031083030303030303031051234567890463044022063B2600A7327976B326C1E7DC32E675BC8FA8B551117A59D75C371E6A7ACD7440220521D28F6164D7A080F4B4231088C53B119DFACF25651A019C375C051B40098EE0458A680F836303402184CC9C9F567BBA3F8E2B30D7FAF5E03E55FC24CE9AEC8E5B1021806E5F931628C522C378DFBCD99CDEC271432C3D1486DD34F";

int qrcodeLen = 0;
byte[] qrcode = new byte[512];



//二维码验证请求结构体
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct Verify_Rrequest_V2 {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] qrcode;
public int qrcode_Len;
[MarshalAsAttribute(UnmanagedType.LPStr,SizeConst =2048)]
public string pos_Param;
public int amount_Cent;
}

//验证二维码的响应结构体
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct Verify_Response_V2
{
[MarshalAsAttribute(UnmanagedType.LPStr,SizeConst =17)]
public string uid;
public int uid_Len;
[MarshalAsAttribute(UnmanagedType.LPStr,SizeConst =2048)]
public string record;
public int record_Len;
[MarshalAsAttribute(UnmanagedType.LPStr,SizeConst =32)]
public string card_No;
public int card_No_Len;
[MarshalAs(UnmanagedType.ByValArray,SizeConst =128)]
public byte[] card_Data;
public int card_Data_Len;
[MarshalAsAttribute(UnmanagedType.LPStr,SizeConst =16)]
public string card_Type;
public int card_Type_Len;
}

[DllImport("libposoffline.dll", CallingConvention = CallingConvention.Cdecl)]
public extern static int verify_qrcode_v2(ref Verify_Rrequest_V2 verify_request_v2,ref Verify_Response_V2 verify_resopnse_v2);

//mock一个用户传入的二维码数据qrcode
qrcode = StringToHexByte(qrcodeHexData);//目前提示二维码格式错误,有可能这个函数有问题,还在进一步研究
qrcodeLen = qrcode.Length;


Verify_Rrequest_V2 verify_Request_V2 = new Verify_Rrequest_V2();
verify_Request_V2.qrcode = new byte[512];
qrcode.CopyTo(verify_Request_V2.qrcode, 0);
verify_Request_V2.qrcode_Len = qrcodeLen;
verify_Request_V2.pos_Param = posParam;
verify_Request_V2.amount_Cent = 200;

Verify_Response_V2 verify_Resopnse_V2 = new Verify_Response_V2();
verify_Resopnse_V2.uid = "";
verify_Resopnse_V2.uid_Len = 17;
verify_Resopnse_V2.record = "";
verify_Resopnse_V2.record_Len = 2048;
verify_Resopnse_V2.card_No = "";
verify_Resopnse_V2.card_No_Len = 32;
verify_Resopnse_V2.card_Data = new byte[128];
verify_Resopnse_V2.card_Data_Len = 128;
verify_Resopnse_V2.card_Type = "";
verify_Resopnse_V2.card_Type_Len = 16;


//16进制格式string 转byte[]:
public static byte[] StringToHexByte(string hexString)
{
hexString = hexString.Replace(" ", "");
if ((hexString.Length % 2) != 0)
hexString += " ";
byte[] returnBytes = new byte[hexString.Length / 2];
for (int i = 0; i < returnBytes.Length; i++)
returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
return returnBytes;
}



//验证二维码
verifyResult = verify_qrcode_v2(ref verify_Request_V2,ref verify_Resopnse_V2).ToString();

报错,报二维码格式不对,求大神指点。
...全文
237 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
chenxd110 2018-04-08
  • 打赏
  • 举报
回复
引用 3 楼 xian_wwq 的回复:
1.CallingConvention修改为stdcall试试
2.把API定义贴出来
一般来说,c/c++ dll要被c#调用,都会封装为 extern “C”这种格式的API


换成stdcall

托管调试助手 "PInvokeStackImbalance":“对 PInvoke 函数“OfflinePayDemo!OfflinePayDemo.Form1::verify_qrcode_v2”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配。”


没有DLL的代码,这是C里面的
/**
* 验证二维码信息 版本二
* @param:request 验证请求
* @return: 成功返回 1 失败见错误码
*
* */
int verify_qrcode_v2(VERIFY_REQUEST_V2* request_v2,
VERIFY_RESPONSE_V2* response_v2);

xian_wwq 2018-04-08
  • 打赏
  • 举报
回复
1.CallingConvention修改为stdcall试试 2.把API定义贴出来 一般来说,c/c++ dll要被c#调用,都会封装为 extern “C”这种格式的API
chenxd110 2018-04-08
  • 打赏
  • 举报
回复
引用 1 楼 xian_wwq 的回复:
P/Invoke调用, 结构体对应时,最好显式声明编码格式(CharSet),字节对齐方式(Pack) c#默认是采用Unicode,而c/c++ API 可能会使用Ansi
引用 1 楼 xian_wwq 的回复:
P/Invoke调用, 结构体对应时,最好显式声明编码格式(CharSet),字节对齐方式(Pack) c#默认是采用Unicode,而c/c++ API 可能会使用Ansi
试过了,都不好使 //验证二维码的请求结构体 [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi,Pack =1)] public struct VerifyRrequestV2 { [MarshalAs(UnmanagedType.ByValArray)] public byte[] qrcode; public int qrcodeLen; [MarshalAsAttribute(UnmanagedType.LPStr,SizeConst =2048)] public string posParam; public int amountCent; } //验证二维码函数 [DllImport("libposoffline.dll", CharSet = CharSet.Ansi,CallingConvention = CallingConvention.Cdecl)] public extern static int verify_qrcode_v2(ref VerifyRrequestV2 verifyRequestV2,ref VerifyResponseV2 verifyResopnseV2); 奇怪的很。
xian_wwq 2018-04-08
  • 打赏
  • 举报
回复
P/Invoke调用, 结构体对应时,最好显式声明编码格式(CharSet),字节对齐方式(Pack) c#默认是采用Unicode,而c/c++ API 可能会使用Ansi

110,566

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧