c# 调用Delphi的dll时, 1.如果dll中的函数参数含有var,则c#中要加上ref(引用); 否则,会有提示错误:“尝试读取或写入受保护的内容。这通常指示其他内存已损坏”。 2.如果dll中的参数是THandle类型,在c#中用IntPtr代替。 3.如果dll中的参数是PChar类型,在c#中应该用byte[]代替。 使用网上说的用ref string或StringBuilder代替PChar都有问题。
另外,这里有一些类型对照:
dephi c++ C# PChar 32位字符型指针 unsigned char * String /byte[] THandle 句柄 *int IntPtr
下面是具体例子: ======================================================================================================================= 假设有一个Delphi写的dll名字为“EastRiver.dll”; 它的函数有: (1)OpenCommPort: 打开串行通讯端口 语法: function OpenCommPort(Port: Integer; BaudRate: Integer): Thandle; 参数说明: Port:端口号,允许值1-256。 BaudRate:端口波特率,允许值:通常是9600。。 如果函数调用成功,返回的值就是端口句柄,用于其它函数调用。当返回的值是-1时,端口无效或正在使用;当返回的值是0时,无法打开端口。 (2) CallClock: 显式联机命令 语法: function CallClock(hPort: THandle; Clock_id: Integer): Boolean; 参数说明: hPort: 端口句柄,通过调用OpenCommPort函数得到 clock_id: 机号,允许值: 0-255。 返回变量: 如果返回为True表示联机成功,如果返回为False表示联机失败。 (3)ReadICCard: 读IC卡信息 语法: function ReadICCard(hPort: THandle; CardNo, CardName: PChar; var Money, Times, Ver: Integer): Boolean; 参数说明: hPort: 端口句柄, 调用OpenCommPort函数得到,需要联机 CardNo: 返回卡号,16位, CardName: 返回姓名,长度不小于16位 Money: 返回卡上金额 Times: 返回充值次数 Ver: IC卡格式, 允许值如下: 0830 返回变量: 如果返回False表示失败,如果返回True表示成功
=======================================================================================================================
那么,在c#中可以使用以下方法动态加载dll:
class ReadWriteCard { public struct info { public byte[] CardNo; public byte[] CardName; public int Money ; public int Times ; public int Ver ; } public class readwriteDll { [DllImport("EastRiver.dll", EntryPoint = "OpenCommPort", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr OpenCommPort(int port,int RaudRate);
[DllImport("EastRiver.dll", EntryPoint = "CallClock", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool CallClock(IntPtr hport, int Clock_id);
[DllImport("EastRiver.dll", EntryPoint = "ReadICCard", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool ReadICCard(IntPtr hport, byte[] CardNo, byte[] CardName, ref int Money, ref int Times,ref int ver); }
然后,在另一个方法调用这里的函数:
private void button1_Click(object sender, EventArgs e) { IntPtr portptr = ReadWriteCard.readwriteDll.OpenCommPort(Int32.Parse(comboBox1.Text), Int32.Parse(comboBox2.Text)); int port = Int32.Parse(portptr.ToString()); bool isclock; MessageBox.Show("端口句柄:" + portptr);//+port.ToString()); if (port != -1 && port != 0) { //联机 isclock = ReadWriteCard.readwriteDll.CallClock(portptr, Int32.Parse(comboBox3.Text)); if (isclock) { MessageBox.Show("联机成功!"); //读卡 ReadWriteCard.info temp = new ReadWriteCard.info(); temp.CardNo = new byte[255]; temp.CardName = new byte[255]; temp.Money = 0; temp.Times = 0; temp.Ver = 0000; MessageBox.Show("正在读卡...!"); try { bool suc = ReadWriteCard.readwriteDll.ReadICCard(portptr, temp.CardNo, temp.CardName, ref temp.Money, ref temp.Times, ref temp.Ver); MessageBox.Show(suc.ToString()); if (suc) { MessageBox.Show("读卡成功!"); } else { MessageBox.Show("读卡失败!"); } } catch (Exception ex) { MessageBox.Show(ex.Message, "警告:出错了..."); } MessageBox.Show("正在关闭端口...!"); if (ReadWriteCard.readwriteDll.CloseCommPort(Int32.Parse(comboBox1.Text))) { MessageBox.Show("已经关闭端口!"); } } else { MessageBox.Show("联机失败!"); ReadWriteCard.readwriteDll.CloseCommPort(Int32.Parse(comboBox1.Text)); }
} else if (port == 0) { MessageBox.Show("无法打开端口!"); } else if (port == -1) { MessageBox.Show("端口无效或正在使用!"); } }
|
请发表评论