【问题标题】:Passing a string from a DLL to C#将字符串从 DLL 传递到 C#
【发布时间】:2014-02-24 18:55:41
【问题描述】:

我有一个 C# 应用程序,它使用 CLI DLL 从非托管 C++ 库访问函数。我的问题是我无法从 C++ 库中获取文本以正确传递给 C# 应用程序。我到目前为止的代码如下:

C#

[DllImport("Wrapper.dll", EntryPoint = "GetNameLength", CallingConvention = CallingConvention = CallingConvention.Cdecl)]
public static extern bool _GetNameLength( int index, out int size);
[DllImport("Wrapper.dll", CharSet = CharSet.Ansi, EntryPoint = "GetName", CallingConvention = CallingConvention.Cdecl)]
public static extern bool _GetName( out Stringbuilder name, int size, int index);

private void TestFunction()
{
    int size = 0;
    _GetNameLength(2, out size);
    StringBuilder str = new StringBuilder(size + 1);

    _GetName(out str, str.Capacity, 2);

    btnName.Text = str.ToString();
}

命令行界面

// In the header.
#define DllExport __declspec( dllexport)

extern "C" {
    DllExport bool __cdecl GetNameLength( int index, int& size);
    DllExport bool __cdecl GetName( char* name, int size, int index);
};


// In the '.cpp'.
bool __cdecl GetNameLength( int index, int& size) {
    if( gp_app == nullptr)
        return false;

    gp_app->GetNameLength( index, size);

    return true;
}

bool __cdecl GetName( char* name, int index, int size) {
    if( gp_app == nullptr)
        return false;

    const char* n = "";
    n = gp_app->GetName( index);

    name = new char[size];
    strcpy( name, n);

    return true;
}

C++

// In the header.
class App {
    void GetNameLength( int index, int& size);
    const char* GetName( int index);
};

// In the '.cpp'.
void App::GetNameLength( int index, int& size) {
    if( index >= 0 && index < gs_namesCount)
        size = strlen( gs_names[index]);
}

const char* App::GetName( int index) {
    if( index >= 0 && index < gs_namesCount)
        return gs_names[index];

    return nullptr;
}

我能够调试到 DLL 并且我已经看到它确实可以正确复制名称,即使我只使用 name = const_cast&lt;char*&gt;( n)(并且当我使用字符串而不是 StringBuilder 时),但出于某种原因该值不会从 DLL 返回到 C#。

我读到一个可能的原因是因为 C++ 可能使用 ASCII 字符,而 C# 使用 16 位字符,并且解决方法是包含 CharSet = CharSet.Ansi 以便在返回到 C# 时正确编组,但这显然没有帮助。

谁能告诉我我做错了什么?


解决方案
使用public ref class 而不是命名空间,并使用void Foo( [Out] String^ %name) 声明函数,确保包含using namespace System::Runtime::InteropServices;

【问题讨论】:

  • 在我看来,您的 C++ 部分中的标头与 GetName 的实现不匹配(一个需要一个 arg,另外两个)。
  • 如果您使用的是 C++/CLI,为什么还要麻烦 dll 导出?使用ref class,您可以像使用 C# 一样使用它。
  • @500-InternalServerError 啊,对不起,这是在复制代码时打错了。
  • @crashmstr 因为我之前没有使用过ref class,而且我有大量使用这种方法实现的代码。 ref class 可以使用指向非托管 C++ 类的指针吗?

标签: c# c++ dll c++-cli parameter-passing


【解决方案1】:

这告诉我你实际上有一个托管的 c++ dll。

if( gp_app == nullptr)
    return false;

如果是这样,您可以导出托管类并使用 String 作为方法的参数。

检查这个:http://msdn.microsoft.com/library/windows/apps/hh699870.aspx

【讨论】:

  • 我尝试在我的包装器中使用StringStringBuilder 作为参数,但这意味着我不能用__cdecl 分配它(我必须使用__clrdecl,我相信它是)这意味着它不能被导出以在我的 C# 代码中使用。
  • @Edward 使用 ref 类并从那里调用这些函数。然后使用 String 构造函数创建托管字符串。
  • 我只是尝试更改为 ref 类并使用name = %String( n) 并对其进行编译,我对其进行调试,name 已正确更新为正确的值,但该值仍未被传回离开函数后进入我的 C# 代码。
  • 你应该将name参数声明为out String^ name
  • 如果我尝试这样做,它会显示'out' : undeclared indentifier。与ref 相同(但可以将类声明为public ref class)。
猜你喜欢
  • 2012-02-12
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多