做项目时碰到这个问题,在网上搜了半天,资料很少。不过做了多次试验后总算调出来了,放出来供大家参考。eVC函数原型 int Init_Port(char *mPort); 这个函数需要接收一个Char *参数,指示打开哪个com端口。
private readonly String ComPortName = "COM5:";
我需要把ComPortName的值作为参数进行传递。 一开始,我定义
[DllImport("ComPort.dll", EntryPoint = "Init_Port", CharSet = CharSet.Auto)] private static extern Int32 Init_Port(String PortName); 调用Init_Port(ComPortName)后没有报异常,但是返回值显示端口打开失败。分析后认为,还是参数传值的时候出了问题。然后先后把PortName声明为 StringBuilder---端口打开失败 [Marshal.LPArray] String,报Unsupported异常。 多次试验后。决定用Byte[]试试看。于是有了以下代码 声明部分:
调用部分:[DllImport("ComPort.dll", EntryPoint = "Init_Port", CharSet = CharSet.Auto)] private static extern Int32 Init_Port(Byte[] buf);
Byte[] buf = System.Text.Encoding.ASCII.GetBytes(ComPortName);
try
{
Int32 iRet = Init_Port(buf);
if (iRet == 0)
{
_CurPortState = PortState.Opened;
}
else _CurPortState = PortState.OpenFailed;
}
catch (Exception) { _CurPortState = PortState.OpenFailed; }
一次性调试通过。实际上,这个动态库只能接受ASCII编码的参数。但是在Mobile平台,参数的传递是基于Unicode的。有资料说如果eVC将函数声明为WChar_t *,那么直接传递String就可以了。我自己没办法做实验,进做资料的记录。 顺便记一下如何从处理IntPtr参数值。
/// <summary>
/// 消息循环,在这里处理消息。
/// </summary>
/// <param name="msg"></param>
protected override void WndProc(ref Message msg)
{
switch (msg.Msg)
{
case WM_SCAN:
try
{
Byte[] Ret = new Byte[20];
Marshal.Copy(msg.WParam, Ret, 0, 20);
TMCode = Encoding.ASCII.GetString(Ret, 0, 20).Trim(new Char[] { '/0' });
CurScanState = ScanState.Finished;
}
catch (Exception)
{
CurScanState = ScanState.Finished;
}
break;
}
base.WndProc(ref msg);
}
eVC程序利用SendMessage将一个字符串发送到我窗体的handle。因此我首先要处理这个消息循环,相应消息。我需要取得的值被保存在WParam的指针里面。 首先声明长度为20的Byte[],之后用Marshal.Copy将Msg.WParam指针指向的内存数据复制到这个数组。 然后再利用Encoding.ASCII将Byte[]转换为String。并将结果截断后面的/0。空数据 实际上
Marshal有一个方法,用于将IntPtr转换为String。名字为Marshal.PtrToStringBSTR(ptr) 。 然而我的程序里面,调用这个方法会产生内存溢出异常。可能还是源程序写的不够规范吧。