4

私は文字列の配列を c++ dll から ac# アプリケーションに返す方法を考え出そうとしましたが、これを行う方法や非常に基本的なレベルの記事を見つける方法に行き詰まっています。

以下のコードがあるとします。太字の行を修正するにはどうすればよいですか:

extern "C" {
    __declspec(dllexport) int GetANumber();

//unsure on this line:
    **__declspec(dllexport) ::vector<std::string> ListDevices();**

}

extern::vector<std::string> GetStrings()
{
    vector<string> seqs;
    return seqs;
}

extern int GetANumber()
{
    return 27;
}

ありがとう

マット

4

3 に答える 3

6

.NET は P/Invoke でネイティブにサポートしているため、完全な COM (オブジェクト、クラス、インターフェイス、TLB、レジストリなど) を実行しなくても、COM オートメーションSAFEARRAY型を DLL エクスポートだけで使用できます。このようなもの:

C++:

extern "C" __declspec(dllexport) LPSAFEARRAY ListDevices();

LPSAFEARRAY ListDevices()
{
    std::vector<std::string> v;
    v.push_back("hello world 1");
    v.push_back("hello world 2");
    v.push_back("hello world 3");

    CComSafeArray<BSTR> a(v.size()); // cool ATL helper that requires atlsafe.h

    std::vector<std::string>::const_iterator it;
    int i = 0;
    for (it = v.begin(); it != v.end(); ++it, ++i)
    {
        // note: you could also use std::wstring instead and avoid A2W conversion
        a.SetAt(i, A2BSTR_EX((*it).c_str()), FALSE);
    }
    return a.Detach();
}

C#:

static void Main(string[] args)
{ 
    foreach(string s in ListDevices())
    {
        Console.WriteLine(s);
    }
}


[DllImport("MyUnmanaged.dll")]
[return: MarshalAs(UnmanagedType.SafeArray)] 
private extern static string[] ListDevices();
于 2013-04-04T16:40:10.937 に答える
2

直接行うことはできません。追加レベルの間接化が必要です。C スタイルと互換性のあるインターフェイスの場合、プリミティブ型を返す必要があります。他のコンパイラの C++ DLL を使用することは忘れてください。厳密な C++ ABI はありません。

したがって、割り当てられた文字列ベクトルへの不透明なポインターを返す必要があります。

#define MYAPI __declspec(dllexport)
extern "C" {
    struct StringList;

    MYAPI StringList* CreateStringList();
    MYAPI void DestroyStringList(StringList* sl);
    MYAPI void GetDeviceList(StringList* sl);
    MYAPI size_t StringList_Size(StringList* sl);
    MYAPI char const* StringList_Get(StringList* v, size_t index);
}

そして実装に関しては:

std::vector<std::string>* CastStringList(StringList* sl) {
    return reinterpret_cast<std::vector<std::string> *>(sl);
}

StringList* CreateStringList() {
     return reinterpret_cast<StringList*>(new std::vector<std::string>);
}

void DestroyStringList(StringList* sl) {
     delete CastStringList(sl);
}
void GetDeviceList(StringList* sl) {
     *CastStringList(sl) = GetStrings(); // or whatever
}
size_t StringList_Size(StringList* sl) {
    return CastStringList(sl)->size();
}
char const* StringList_Get(StringList* v, size_t index) {
    return (*CastStringList(sl))[index].c_str();
}

これをすべて実行したら、C# 側でよりクリーンなラッパーを提供できます。もちろん、割り当てられたオブジェクトを DestroyStringList 関数で破棄することを忘れないでください。

于 2013-04-04T11:53:54.693 に答える