小弟要用C#调用C++写的dll,现在调用报错,说是参数不对,请众位大虾指点!!谢谢!!!只剩58分了可用了,别嫌分少
--------------------编程问答-------------------- 我自己顶起!大虾们帮帮忙!!!谢谢了 --------------------编程问答-------------------- 记得以前不是这样做的首先得定义结构体长度
其次应该把结构体转化成byte数组 --------------------编程问答-------------------- 我自己顶起!大虾们帮帮忙!!!谢谢了 --------------------编程问答-------------------- bobui您好,能把您以前的代码给我参考一下吗? --------------------编程问答-------------------- 我自己顶起!大虾们帮帮忙!!!谢谢了 --------------------编程问答-------------------- 你的代码太多,自己看看这篇文章吧http://msdn.microsoft.com/zh-cn/library/aa288468%28VS.71%29.aspx --------------------编程问答-------------------- http://msdn.microsoft.com/zh-cn/library/aa288468%28VS.71%29.aspx
此文章已看过,对我有一些帮助(比如:[MarshalAs(UnmanagedType.ByValTStr, SizeConst=LF_FACESIZE)]
),但我这里的C++定义的数据结构是struct内包含struct的,比较复杂。
我正在调整、测试中,但还是想请大虾们出手帮帮忙!!
--------------------编程问答-------------------- 楼主,你第一个结构体最后那个数组有问题吧:
pPosItems ItemsInfo[XXX]; // Vendors need to decide
XXX是什么意思? --------------------编程问答-------------------- 楼主,你那样转换错的太多了,我暂且把第一个结构体的最后一句当成这样:PosItems ItemsInfo[2];
完整解决:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Pos
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)]
public String POSID;
public char TransactionType;TransactionType
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public String TransactionNumber;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public String TransactionDate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 7)]
public String TransactionTime;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 31)]
public String CashierName;
public Int32 SiteID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]
public String SiteName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public String NozzleNum;
public Int32 ItemCount;
public Single TotalAmount;
public Single InvoiceAmount;
public Single DiscountAmount;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]
public String Extra1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]
public String Extra2;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]
public String Extra3;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public PosItems[] ItemsInfo;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct PosItems
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public String ItemCode;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]
public String ItemName;
public Single ItemQuantity;
public Single UnitPrice;
public Single ItemAmount;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
public String Extra1;
}
函数映射:
[DllImport("invoice.dll", EntryPoint="Tax_Invoice",CharSet = CharSet.Ansi)]
public static extern int Tax_Invoice(ref Pos val);//不知你为何突然变成PosInvoice ,让人不可思议! --------------------编程问答--------------------
不错应该试试 --------------------编程问答--------------------
不错应该试试 --------------------编程问答-------------------- 根据LZ的问题感觉是
字节大小不一致 --------------------编程问答-------------------- 非常感谢sdl2005lyx !!!!!
正在测试中 --------------------编程问答-------------------- 各位大虾现在的问题是这样的
C#结构定义已经改为:
public struct Pos
{
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=3)]
public string POSID;//2+1 POS机编号
public char TransactionType;// 交易类型 S Sale R Return
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=11)]
public string TransactionNumber;//10+1 交易流水号
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=9)]
public string TransactionDate;//8+1 打印日期CCYYMMDD
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=7)]
public string TransactionTime;//6+1 打印时间HHMMSS
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=31)]
public string CashierName;//30+1 收银员
public Int32 SiteID;// 加油站编码
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=41)]
public string SiteName;//40+1 加油站名称
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=5)]
public string NozzleNum;//4+1 油枪号
public Int32 ItemCount;// 商品项目数量
public Single TotalAmount;// 应收金额
public Single InvoiceAmount;// 实收金额
public Single DiscountAmount;// 优惠金额
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=41)]
public string Extra1;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=41)]
public string Extra2;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=41)]
public string Extra3;
[MarshalAs(UnmanagedType.ByValArray,SizeConst=1)]
public PosItems[] ItemsInfo;//明细数据
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct PosItems
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string ItemCode;//15+1 商品编码
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]
public string ItemName;//40+1 商品名称
public Single ItemQuantity;// 商品数量
public Single UnitPrice;// 商品单价
public Single ItemAmount;// 商品小计金额
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
public string Extra1;//20+1 备用1
}
现在的问题是如何为Pos及PosItems赋值?如何调用C++中定义的Tax_Invoice (Pos *pPos)??
我现在是如下操作的:
public Pos makeval()
{
Pos reval = new Pos();
reval.POSID = "12";// = POSID// POS机编号
reval.TransactionType = 'S';// 交易类型
reval.TransactionNumber = "12345678";// 交易流水号
reval.TransactionDate = "20090603";// 打印日期
reval.TransactionTime = "130721";//打印时间
reval.CashierName = "收银";//收银员
reval.SiteID = 100;
reval.SiteName = "站点名称";
reval.NozzleNum = "1234";
reval.ItemCount = 1;// 商品项目数量
reval.TotalAmount = 150.00f;// 应收金额
reval.InvoiceAmount = 120.00f;// 实收金额
reval.DiscountAmount = 30.00f;// 优惠金额
reval.Extra1 = "备注1";
reval.Extra2 = "";
reval.Extra3 = "";
#region 商品明细_开始
PosItems[] item = new PosItems[1];//明细数据
item[0].ItemCode = "12345";//vItemCode;
item[0].ItemName = "商品名称";//vItemName;
item[0].ItemQuantity = 30.0f;
item[0].UnitPrice = 50.0f;
item[0].ItemAmount = 150.0f;
item[0].Extra1 = "备注1明细";
#endregion 商品明细_结束
reval.ItemsInfo = new PosInvoiceItemsA[1];//为Pos中的PosItems初始化并赋值
reval.ItemsInfo[0] = item[0];
return reval;
}
调用方法改为:
[DllImport("auto_invoice.dll", EntryPoint="Tax_Invoice",CharSet = CharSet.Ansi)]
static extern int Tax_Invoice(ref Pos val);
void Button1Click(object sender, System.EventArgs e)
{
Pos pPos = new Pos();
pPos = this.makeval();
i = MainForm.Tax_Invoice(ref pPos);
}
调用时报错 --------------------编程问答-------------------- 我自己顶起来 --------------------编程问答--------------------
报什么错?你编码有问题吗? --------------------编程问答-------------------- 代码太长!!! 错误说参数有问题?!!?
那就只能是数量和类型有冲突。。 好好看看!!! --------------------编程问答-------------------- 我自己顶起来
我自己有两个疑问:
1、
typedef struct
{
char POSID[POSID_LEN+1]; //POSID
char TransactionType; //transaction type
char TransactionNumber[TRS_NO_LEN+1];//transaction serial number
char TransactionDate[TRS_DATE _LEN + 1];//transaction date
char TransactionTime[TRS_TIME _LEN + 1];//transaction time
char CashierName[CASHIER_NAME_LEN +1];//cashier name
int SiteID; //site ID
char SiteName[SITENAME_NAME_LEN +1]; //site name
char NozzleNum[NOZZLE_NO_LEN +1]; //nozzle number
int ItemCount; //item count
float TotalAmount; //total amount
float InvoiceAmount; //actual received amount
float DiscountAmount; //discount amount
char Extra1[BACK_UP_LEN + 1]; //backup field
char Extra2[BACK_UP_LEN + 1]; // backup field
char Extra3[BACK_UP_LEN + 1]; // backup field
pPosItems ItemsInfo[XXX]; // Vendors need to decide
} Pos, *pPos;
与
typedef struct
{
char POSID[POSID_LEN+1]; //POSID
char TransactionType; //transaction type
char TransactionNumber[TRS_NO_LEN+1];//transaction serial number
char TransactionDate[TRS_DATE _LEN + 1];//transaction date
char TransactionTime[TRS_TIME _LEN + 1];//transaction time
char CashierName[CASHIER_NAME_LEN +1];//cashier name
int SiteID; //site ID
char SiteName[SITENAME_NAME_LEN +1]; //site name
char NozzleNum[NOZZLE_NO_LEN +1]; //nozzle number
int ItemCount; //item count
float TotalAmount; //total amount
float InvoiceAmount; //actual received amount
float DiscountAmount; //discount amount
char Extra1[BACK_UP_LEN + 1]; //backup field
char Extra2[BACK_UP_LEN + 1]; // backup field
char Extra3[BACK_UP_LEN + 1]; // backup field
pPosItems ItemsInfo[XXX]; // Vendors need to decide
} Pos;//去掉了 *pPos
有什么区别??
2、我看见有的例子中是用IntPtr在C#中给c++定义的方法中的参数赋值的。是不是我这个也要用IntPtr这种方法给参数赋值?
特别是我这个参数自身是个结构,但结构中的某个参数又是一个结构数组。调用及赋值方法是不是有些特殊? --------------------编程问答-------------------- 我自己顶起来 --------------------编程问答-------------------- 我给你一个建议,要求编写c++ dlld的人提供一套经过严格测试的c#类库。否则谁主张用c++谁去实现它。 --------------------编程问答-------------------- 楼主,回答你几个问题:
1、“去掉了 *pPos”,这个没有任何关系和影响,判断调用只关心两边的结构体大小和顺序是否一致,别名无关紧要!
2、用IntPtr当然可以,只是增加解析复杂度,要用到Marshal类进行转换!对应有明确类型定义的数据结构,参数封送直接用具体类型为好!除非碰到void*这种类型,必须使用IntPtr。
3、“ [MarshalAs(UnmanagedType.ByValArray,SizeConst=1)]
public PosItems[] ItemsInfo;//明细数据”
如果你这里只用到1个成员,就不要定义为数组,直接用成员变量即可!
但是你的C++代码:pPosItems ItemsInfo[XXX]; // Vendors need to decide
让人无法判断!
4、其实这个结构体并不怎么复杂,只有成员很多而已!这样容易是开发人员犯简单错误。经常会出现调用错误:试图读写受保护的内存!大多由两边结构不一致导致!对付这种问题,一个最直接的方法:
在C++那边用sizeof()看看大小为多少!
在C#这部用Marshal.Sizof(Type)看看大小为多少!
发现两边大小不一致,楼主你就仔细检查,一项一项来!别人有时无法代替!
--------------------编程问答-------------------- 谢谢众位!上楼这位大虾的话让我收益非浅!! --------------------编程问答-------------------- 正在测试中
还请其它大虾继续给予指点!! --------------------编程问答-------------------- 现在报错信息为:
调试器抛出异常 System.AccessViolationException:
尝试读取或写入受保护的内存。这通常指示其他内存已损坏。 --------------------编程问答-------------------- c#调用c++的? --------------------编程问答--------------------
楼主,这是参数封送常见错误,由于你的结构体太长,别人一下不好帮你定位!
不知你用我给你的方法没有:
1、比较两边结构体的大小,看是否一致!
2、先在两边屏蔽一些结构体成员测试,当然逐步放开。 --------------------编程问答-------------------- 十分的混乱。而且你数据结构中的最后一项没有指定大小,如果你不指定大小,那么你应该定义为指针,而不是数组。
C# code
[MarshalAs(UnmanagedType.ByValArray,SizeConst=1)]
public PosItems[] ItemsInfo;//明细数据
--------------------编程问答-------------------- 我自己顶起来 --------------------编程问答-------------------- 谢谢大家!!!
一、C++中结构定义为
#define POSID_LEN 2 //POSID length
#define TRS_NO_LEN 10 //transaction serial number length
#define CASHIER_NAME_LEN 30 //cashier name length
#define SITENAME_NAME_LEN 40 //site name length
#define NOZZLE_NO_LEN 4 //nozzle number length
#define BACK_UP_LEN 40 //backup field length
#define ITEM_CODE_LEN 15 //item code length
#define ITEM_NAME_LEN 40 //item name length
#define TRS_DATE _LEN 8 //Transaction date length
#define TRS_TIME _LEN 6 //Transaction date length
#define ITEM_BACK_UP_LEN 20 //Item backup field length
typedef struct
{
char POSID[POSID_LEN+1]; //POSID
char TransactionType; //transaction type
char TransactionNumber[TRS_NO_LEN+1];//transaction serial number
char TransactionDate[TRS_DATE _LEN + 1];//transaction date
char TransactionTime[TRS_TIME _LEN + 1];//transaction time
char CashierName[CASHIER_NAME_LEN +1];//cashier name
int SiteID; //site ID
char SiteName[SITENAME_NAME_LEN +1]; //site name
char NozzleNum[NOZZLE_NO_LEN +1]; //nozzle number
int ItemCount; //item count
float TotalAmount; //total amount
float InvoiceAmount; //actual received amount
float DiscountAmount; //discount amount
char Extra1[BACK_UP_LEN + 1]; //backup field
char Extra2[BACK_UP_LEN + 1]; // backup field
char Extra3[BACK_UP_LEN + 1]; // backup field
pPosInvoiceItems ItemsInfo[255]; // Vendors need to decide
} PosInvoice, *pPos;
typedef struct
{
char ItemCode[ITEM_CODE_LEN+1]; //item code
char ItemName[ITEM_NAME_LEN+1]; //item name
float ItemQuantity; //item quantity
float UnitPrice; //unit price
float ItemAmount; //item amount
char Extra1[ITEM_BACK_UP_LEN+1]; //backup field
} PosInvoiceItems, *pPosInvoiceItems;
命令函数:int Tax_Invoice (Pos *pPos)
C#中结构定义为
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct PosInvoice
{
[MarshalAs(UnmanagedType.ByValArray,SizeConst=3)]
public byte[] POSID;//2+1 POS机编号
public char TransactionType;// 交易类型 S Sale R Return
[MarshalAs(UnmanagedType.ByValArray,SizeConst=11)]
public byte[] TransactionNumber;//10+1 交易流水号
[MarshalAs(UnmanagedType.ByValArray,SizeConst=9)]
public byte[] TransactionDate;//8+1 打印日期CCYYMMDD
[MarshalAs(UnmanagedType.ByValArray,SizeConst=7)]
public byte[] TransactionTime;//6+1 打印时间HHMMSS
[MarshalAs(UnmanagedType.ByValArray,SizeConst=31)]
public byte[] CashierName;//30+1 收银员
public Int32 SiteID;// 加油站编码
[MarshalAs(UnmanagedType.ByValArray,SizeConst=41)]
public byte[] SiteName;//40+1 加油站名称
[MarshalAs(UnmanagedType.ByValArray,SizeConst=5)]
public byte[] NozzleNum;//4+1 油枪号
public Int32 ItemCount;// 商品项目数量
public Single TotalAmount;// 应收金额
public Single InvoiceAmount;// 实收金额
public Single DiscountAmount;// 优惠金额
[MarshalAs(UnmanagedType.ByValArray,SizeConst=41)]
public byte[] Extra1;
[MarshalAs(UnmanagedType.ByValArray,SizeConst=41)]
public byte[] Extra2;
[MarshalAs(UnmanagedType.ByValArray,SizeConst=41)]
public byte[] Extra3;
[MarshalAs(UnmanagedType.ByValArray,SizeConst=255)]
public PosInvoiceItems[] ItemsInfo;//明细数据
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct PosInvoiceItems
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] ItemCode;//15+1 商品编码
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 41)]
public byte[] ItemName;//40+1 商品名称
public Single ItemQuantity;// 商品数量
public Single UnitPrice;// 商品单价
public Single ItemAmount;// 商品小计金额
// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 21)]
public byte[] Extra1;//20+1 备用1
}
C#中对结构赋值为
public PosInvoiceA makevalA()
{
PosInvoiceA reval = new PosInvoiceA();
reval.POSID = new byte[3];
Array.Copy(this.String2Bytes("29"),reval.POSID,this.String2Bytes("29").Length);
reval.TransactionType = 'S';
reval.TransactionNumber = new byte[11];
Array.Copy(this.String2Bytes("20000009"),reval.TransactionNumber,this.String2Bytes("20000009").Length);
reval.TransactionDate = new byte[9];
Array.Copy(this.String2Bytes("20110711"),reval.TransactionDate,this.String2Bytes("20110711").Length);
reval.TransactionTime = new byte[7];
Array.Copy(this.String2Bytes("161718"),reval.TransactionTime,this.String2Bytes("161718").Length);
reval.CashierName = new byte[31];
Array.Copy(this.String2Bytes("按擦剂威武"),reval.CashierName,this.String2Bytes("按擦剂威武").Length);
reval.SiteID = 100;// 加油站编码
reval.SiteName = new byte[41];
Array.Copy(this.String2Bytes("加油站名称:刘某人的油站"),reval.SiteName,this.String2Bytes("加油站名称:刘某人的油站").Length);
reval.NozzleNum = new byte[5];
Array.Copy(this.String2Bytes("9118"),reval.NozzleNum,this.String2Bytes("9118").Length);
reval.ItemCount = 1;// 商品项目数量
reval.TotalAmount = 123.45f;// 应收金额
reval.InvoiceAmount = 100.12f;// 实收金额
reval.DiscountAmount = 23.33f;// 优惠金额
reval.Extra1 = new byte[41];
Array.Copy(this.String2Bytes("备用1"),reval.Extra1,this.String2Bytes("备用1").Length);
reval.Extra2 = new byte[41];
reval.Extra3 = new byte[41];
#region 商品明细_开始
PosInvoiceItemsA[] item = new PosInvoiceItemsA[1];//明细数据
item[0].ItemCode = new byte[16];
Array.Copy(this.String2Bytes("16898"),item[0].ItemCode,this.String2Bytes("16898").Length);
item[0].ItemName = new byte[41];
Array.Copy(this.String2Bytes("商品名称"),item[0].ItemName,this.String2Bytes("商品名称").Length);
item[0].ItemQuantity = 30.0f;
item[0].UnitPrice = 50.0f;
item[0].ItemAmount = Convert.ToSingle(150.0f);
item[0].Extra1 = new byte[21];
Array.Copy(this.String2Bytes("商品备注"),item[0].Extra1,this.String2Bytes("商品备注").Length);
#endregion 商品明细_结束
reval.ItemsInfo = new PosInvoiceItemsA[255];
reval.ItemsInfo[0] = item[0];
return reval;
}
C#调用代码为
--------------------编程问答-------------------- 测试时还用另一种方式定义为C#中的结构:
[DllImport("auto_invoice.dll", EntryPoint="Tax_Invoice",CharSet = CharSet.Ansi)]
static extern int Tax_Invoice(ref PosInvoice val);
void Button1Click(object sender, System.EventArgs e)
{
int i = MainForm.Tax_Connection();
if (i==0)
{
i=255;
PosInvoice pPos = new PosInvoice();
pPos = this.makeval();
int k = Marshal.SizeOf(pPos);//24736
i = MainForm.Tax_Invoice(ref pPos);
MessageBox.Show(i.ToString());
}
else
MessageBox.Show("连接失败"+i.ToString());
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct PosInvoice
{
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=3)]
public string POSID;//2+1 POS机编号
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=1)]
public string TransactionType;// 交易类型 S Sale R Return
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=11)]
public string TransactionNumber;//10+1 交易流水号
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=9)]
public string TransactionDate;//8+1 打印日期CCYYMMDD
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=7)]
public string TransactionTime;//6+1 打印时间HHMMSS
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=31)]
public string CashierName;//30+1 收银员
public Int32 SiteID;// 加油站编码
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=41)]
public string SiteName;//40+1 加油站名称
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=5)]
public string NozzleNum;//4+1 油枪号
public Int32 ItemCount;// 商品项目数量
public Single TotalAmount;// 应收金额
public Single InvoiceAmount;// 实收金额
public Single DiscountAmount;// 优惠金额
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=41)]
public string Extra1;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=41)]
public string Extra2;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=41)]
public string Extra3;
[MarshalAs(UnmanagedType.ByValArray,SizeConst=255)]
public PosInvoiceItems[] ItemsInfo;//明细数据
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct PosInvoiceItems
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string ItemCode;//15+1 商品编码
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 41)]
public string ItemName;//40+1 商品名称
public Single ItemQuantity;// 商品数量
public Single UnitPrice;// 商品单价
public Single ItemAmount;// 商品小计金额
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
public string Extra1;//20+1 备用1
}
补充:.NET技术 , C#