从C#应用程序调用C++ DLL
问题描述:
我正在尝试将C++ DLL集成到我们的C#应用程序中,但我无法确定调用其方法之一的正确方法。在文件的两个不同地方的方法定义不相等:从C#应用程序调用C++ DLL
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);
我总是得到一个空字符串。
当我尝试任何其他人(字节[],字符串,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.
缺少什么我在这里? 谢谢
答
您可以分配一个缓冲区,然后传递到本地功能。
//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转换。如果该函数没有被频繁调用或者不返回大量数据,则该命中可能可以忽略不计。
参考:
答
在.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();
}