[英]'ShowSUM': __declspec(dllexport) cannot be applied to a function with the __clrcall calling convention
[英]__declspec(dllexport) ::vector<std::string>
我一直在努力研究如何將一個字符串數組從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;
}
謝謝
馬特
您可以使用COM自動化SAFEARRAY類型,即使沒有完整的COM(沒有對象,沒有類,沒有接口,沒有TLB,沒有注冊表等),只是使用DLL導出,因為.NET本身支持P / Invoke,這樣的事情:
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();
你不能直接做 - 你需要一個額外的間接水平。 對於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函數銷毀已分配的對象。
您有兩種“標准”方法可以從C ++到C#。
第一個是C ++ / CLI。 在這種情況下,您將構建一個C ++ / CLI庫,它接受std::vector<std::string>
並將其轉換為System::vector<System::string>
。 然后你可以在C#中自由地使用它作為System.String[]
。
另一個是COM。 在那里,您創建一個COM接口,返回包含BSTR
字符串的SAFEARRAY
。 然后通過C#中的System.Runtime.InteropServices實例化此COM接口。 然后SAFEARRAY
是一個Object [],可以裝入單個字符串對象。
將C接口加載到C#的工具基本上限於C.任何C ++都將失敗,Pete提供“非標准”方法。 (效果很好,不是MS想要你做的。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.