【问题标题】:Call a C++ DLL from a C# application从 C# 应用程序调用 C++ DLL
【发布时间】:2013-05-08 16:55:53
【问题描述】:

我目前正在尝试将 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.

我在这里缺少什么? 谢谢

【问题讨论】:

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


    【解决方案1】:

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

    //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 转换创建一个编组缓冲区。如果该函数不被频繁调用或不返回大量数据,则此命中可能可以忽略不计。

    参考:

    【讨论】:

      【解决方案2】:

      在 .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();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多