【问题标题】:Calling C++ function with LPStr return value from C#从 C# 调用具有 LPStr 返回值的 C++ 函数
【发布时间】:2018-11-07 21:37:59
【问题描述】:

我有一个 64 位的 C++ dll,其中包含一个返回 LPStr 的函数。我想在 C# 中调用这个函数。函数声明如下所示:

__declspec(dllexport) LPSTR __stdcall function(int16_t error_code);

在我的 C# 代码中,我尝试了以下方法:

 [DllImport(@"<PathToInterface.dll>", EntryPoint = "function")]
 [return: MarshalAs(UnmanagedType.LPStr)]
 public static extern string function(Int16 error_code);

然后在程序中:

string ErrorMessage = "";
ErrorMessage = function(-10210);

我知道函数本身很好,因为我可以从另一个程序(用 LabVIEW FWIW 编写)调用它。但是当我执行 C# 程序时,它只是以错误代码0x80000003 退出,我什至无法尝试,捕获异常。

如何正确调用这个函数?

作为一个侧节点:我在这个 dll 中确实有其他函数,它们使用 LPStr 作为参数,我可以毫无问题地调用它们。只有两个函数返回 LPStr 会产生问题

【问题讨论】:

  • function是如何实现的?最重要的是如何分配返回值
  • 我读到您需要使用 extern "C" 块定义导出,如下所示: extern "C" __declspec(dllexport) int captureCamera(int& captureId) { ... }
  • 0x80000003 是 E_INVALIDARG。现在,我显然不知道哪个 DLL 函数执行的本机代码导致了错误;但首先要验证您调用的函数是否真正“理解”值-10210(即,该特定值是否存在相应的错误消息/文本字符串?)

标签: c# c++ dll lpstr


【解决方案1】:

如何正确调用这个函数?

作为互操作?你不能……在纯 C++ 中也容易出错

你应该这样做

extern "C" __declspec(dllexport)  int __stdcall function(int16_t error_code, 
             LPSTR buffer, size_t size)
{
    LPCSTR format = "error: %i";
    size_t req = _scprintf(format, error_code); // check for require size
    if (req > size) //buffer size is too small
    {
        return req; //return required size
    }
    sprintf_s(buffer, size, format, error_code); //fill buffer 
    return 0;
}

及用法

class Program
{
    static void Main(string[] args)
    {
        short error_code = -10210;
        var ret = function(error_code, null, 0); // check for required size of the buffer
        var sb = new StringBuilder(ret); // create large enough buffer
        ret = function(error_code, sb, (uint)sb.Capacity + 1); //call again 
        var error_desc = sb.ToString(); //get results
        Console.WriteLine(error_desc);
        Console.ReadKey();
    }

    [DllImport("TestDll.dll", EntryPoint = "function", CharSet = CharSet.Ansi)]
    public static extern int function(short error_code, StringBuilder sb, int size);
}

在 C++ 中的用法

typedef int (__stdcall *function)(int16_t error_code, LPSTR buffer, size_t size);
int main()
{
    auto handle = LoadLibrary(L"TestDll.dll");
    auto proc = (function)GetProcAddress(handle, "_function@12"); 
    // of course it can be done via linking

    int16_t error_code = 333;
    const int ret = proc(error_code, NULL, 0); // check for size
    CHAR* buffer = new CHAR[ret + 1];
    //CHAR buffer[200]; //eventually allocate on stack 
    //but size have to be constant value and may be too small
    proc(error_code, buffer, ret+1); // call again 
    MessageBoxA(0, buffer, "Return", 0); //show result
    delete[] buffer; //free buffer!

    FreeLibrary(handle);
    return 0;
}

【讨论】:

  • 感谢您的回答。很遗憾,这不能以不同的方式处理,因为不是每个人都可以控制他们的 Dll。 (它可能是第三方 dll,在这种情况下就是这样)。我们按照您的指示进行了操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-29
相关资源
最近更新 更多