从C#应用程序调用C ++ DLL

时间:2013-05-08 16:55:54

标签: c# c++ .net dll interop

我目前正在尝试将C ++ DLL集成到我们的C#应用​​程序中,但我无法确定调用其中一种方法的正确方法。在文档的两个不同位置,方法定义不相等:

ImageAndScanError GetMicrInfo(unsigned char *ptrCodeline,int* iLength) 

ImageAndScanError WINAPI GetMicrInfo(char* cMicrInfo,int* iInfoLength);

/*
ImageAndScanError GetMicrInfo(unsigned char *ptrCodeline,int* iLength) 

Parameters: 

ptrCodeline: a pointer to the output buffer that will receive the code line read by the MICR algorithm. The ptrCodeline should allocate room for 96 characters. 

iLength: the number of characters contained in the code line 

Function: Read MICR line on the check. This function must be called after StartScan . 

Returns: ErrorNone is returned upon success. Otherwise, an enum ImageAndScanError value that indicates the reason for failure is returned. 
*/

这就是我包含dll方法的方法

[DllImport("ScanDll.dll", CallingConvention = CallingConvention.Winapi)]

这就是我到目前为止所做的所有组合

public static extern ImageAndScanError GetMicrInfo(out IntPtr cMicrInfo, out int iInfoLength);
public static extern ImageAndScanError GetMicrInfo(out byte[] cMicrInfo, out int iInfoLength);
public static extern ImageAndScanError GetMicrInfo(out string cMicrInfo, out int iInfoLength);
public static extern ImageAndScanError GetMicrInfo(out StringBuilder cMicrInfo, out int iInfoLength);

IntPtr cMicrInfoTMP;
byte[] cMicrInfoTMP= new byte[96];
string cMicrInfoTMP;
StringBuilder cMicrInfoTMP;

GetMicrInfo(out cMicrInfoTMP, out iInfoLengthTMP);

当我使用IntPtr时,调试在VS2010中给出的值是859256727,大小为4,当我这样做时

string myString = Marshal.PtrToStringAnsi(cMicrInfoTMP);

我总是得到一个空字符串。

当我尝试其他任何一个(byte [],string,StringBuilder)时,我得到了

The runtime has encountered a fatal error. The address of the error was at
0x53e6716a, on thread 0x1084. The error code is 0xc0000005. This error may
be a bug in the CLR or in the unsafe or non-verifiable portions of user
code. Common sources of this bug include user marshaling errors for COM-interop
or PInvoke, which may corrupt the stack.

我在这里缺少什么? 感谢

2 个答案:

答案 0 :(得分:0)

在.NET中,当被调用者创建对象时使用out个参数。您需要为函数提供现有缓冲区,因此您应首先初始化StringBuilder。然后,编组器将指向对象的内部字符缓冲区的指针传递给函数。

您必须确定哪个字符集和编码用于MICR字符串。它可以是UTF-16,在这种情况下,将声明更改为CharSet.Unicode

试试这个:

[DllImport("ScanDll.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Ansi)]
private static extern ImageAndScanError GetMicrInfo(StringBuilder cMicrInfo, out int iInfoLength);

public String GetMicrInfo()
{
    StringBuilder info = new StringBuilder(96);
    int length;
    ImageAndScanError error = GetMicrInfo(info, out length);
    if (error != ImageAndScanError.ErrorNone) throw new Exception(String.Format("GetMicrInfo error: {0}", error));
    return info.ToString();
}

答案 1 :(得分:0)

您可以分配缓冲区,然后传递给本机函数。

//error handling omitted
[DllImport("your.dll", CharSet = CharSet.Ansi)]
ImageAndScanError GetMicrInfo(IntPtr ptrCodeline,ref int bytesCopied);

IntPtr ip = Marshal.AllocCoTaskMem(bufferLen);
Win32API.ZeroMemory(ip, (uint)(bufferLen));
int bytesCopied=0;
GetMicrInfo(ip, ref bytesCopied);
string info= Marshal.PtrToStringAnsi(bytesCopied);
Marshal.FreeCoTaskMem(ip);

如果在多次调用GetMicrInfo期间不需要重用缓冲区,则可以使用StringBuilder的默认封送器:

[DllImport("your.dll", CharSet = CharSet.Ansi)]
ImageAndScanError GetMicrInfo(StringBuilder ptrCodeline,ref int bytesCopied);
StringBuilder ptrCodeline(bufferLen);
int bytesCopied=0;
GetMicrInfo(ptrCodeline, ref bytesCopied);

如果多次调用GetMicrInfo,它会带来性能损失,因为在每次调用时,默认的CLR编组器都会为固定和unicode-ANSI转换创建编组缓冲区。如果不经常调用该函数或者不返回大量数据,则此命中可以忽略不计。

参考: