Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# __declspec(dllexport):向量<;标准::字符串>; 我一直在尝试如何将一组字符串从C++ DLL返回到C语言应用程序,但是我一直坚持如何在一个非常基本的层次上找到一个文章。_C#_C++_Vector_Pinvoke_Declspec - Fatal编程技术网

C# __declspec(dllexport):向量<;标准::字符串>; 我一直在尝试如何将一组字符串从C++ DLL返回到C语言应用程序,但是我一直坚持如何在一个非常基本的层次上找到一个文章。

C# __declspec(dllexport):向量<;标准::字符串>; 我一直在尝试如何将一组字符串从C++ DLL返回到C语言应用程序,但是我一直坚持如何在一个非常基本的层次上找到一个文章。,c#,c++,vector,pinvoke,declspec,C#,C++,Vector,Pinvoke,Declspec,假设我有下面的代码。如何修复粗体行: extern "C" { __declspec(dllexport) int GetANumber(); //unsure on this line: **__declspec(dllexport) ::vector<std::string> ListDevices();** } extern::vector<std::string> GetStrings() { vector<string>

假设我有下面的代码。如何修复粗体行:

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;
}
extern“C”{
__declspec(dllexport)int GetANumber();
//在这一行:
**__declspec(dllexport)::向量ListDevices()**
}
extern::vector GetStrings()
{
矢量序列;
返回序列;
}
extern int GetANumber()
{
返回27;
}
谢谢


马特

你不能直接这么做——你需要一个额外的间接层次。对于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();
}
std::vector*CastStringList(StringList*sl){
返回重新解释(sl);
}
StringList*CreateStringList(){
返回reinterpret_cast(新标准::向量);
}
作废销毁StringList(StringList*sl){
删除列表(sl);
}
void GetDeviceList(StringList*sl){
*CastStringList(sl)=GetStrings();//或其他
}
大小\u t字符串列表\u大小(字符串列表*sl){
返回CastStringList(sl)->size();
}
char const*StringList\u Get(StringList*v,size\u t索引){
return(*CastStringList(sl))[index].c_str();
}
完成所有这些之后,您可以在C#端提供一个更干净的包装。当然,不要忘记通过Debug StistListScript函数来破坏分配的对象。

< P>你有两种“标准”方法从C++到C语言。p> 第一种是C++/CLI。在本例中,您将构建一个C++/CLI库,该库采用
std::vector
,并将其转换为
System::vector
。然后,您可以在C#中将其作为
System.String[]
自由使用

另一个是COM。在这里,您创建了一个COM接口,该接口返回一个包含
BSTR
字符串的
SAFEARRAY
。然后通过C#中的System.Runtime.InteropServices实例化此COM接口。然后,
SAFEARRAY
是一个对象[],可以将其大小写为单个字符串对象


<>将C接口加载到C中的设备基本上限制在C。任何C++都会失败,Pete提供了“非标准”方法。(它工作得很好,只是不是MS希望您做的。)

您可以使用COM自动化类型,即使不进行完整的COM(没有对象、没有类、没有接口、没有TLB、没有注册表等),也可以使用DLL导出,因为.NET本机通过p/Invoke支持它,如下所示:

C++:


不确定从非托管到托管的向量有多容易。可能需要将函数包装在另一个函数下,该函数返回一个简单的struct数组并公开该数组。参数必须从本机封送到.net运行时(PInvoke)。因此,我们需要在c#端定义具有适当填充(布局)的等效结构。这两种方法都是很好的。但我不认为我的方法是“非标准的”——它非常常见,并且具有很高的可移植性。这是一种非标准的方式,MS training和docs总是展示这两种方法。由于与我交谈的每一位MS人员都不知道的原因,强烈建议我们使用
DllImport
。引用最多的版本是,这是“不安全的”,不管这意味着什么。当我把项目切换到完全的本地C++环境时,我很高兴。我喜欢我不安全的语言。另外,你得到了我的一张赞成票…你也得到了我的一张赞成票。我不知道;不是很使用.net,但不是“不安全”.net术语是指任何不是CLR管理的东西吗?调用COM接口或C++/CLI不会导致执行“不安全”代码,那么区别在哪里呢?不要问我。我认为它指的是这样一个事实:如果你在签名中犯了错误,它将使核心.net框架崩溃。在你的代码中崩溃是可以的,然后你会受到责备;但是在.net代码中崩溃。。。邪恶…谢谢皮特,这正是我想要的。试图定位有点像泥潭:)
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();
}
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();