C# 3.0 包含向量的C#pinvoke编组结构<;结构>;

C# 3.0 包含向量的C#pinvoke编组结构<;结构>;,c#-3.0,compact-framework,pinvoke,C# 3.0,Compact Framework,Pinvoke,对于windows ce 6.0项目,我需要调用一个函数,该函数返回一个包含int和C#中其他结构向量的结构: 该功能由第三方提供商(pda的中国制造商)提供,他们只向我提供了.h文件、dll和lib 我试图在C#中调用的函数在.h文件中定义为: DLLGSMADAPTER ApnInfoData* GetAvailApnList(); 数据结构如下所示: typedef struct ApnInfoData { int m_iDefIndex; ApnInfoArray m_

对于windows ce 6.0项目,我需要调用一个函数,该函数返回一个包含int和C#中其他结构向量的结构:

该功能由第三方提供商(pda的中国制造商)提供,他们只向我提供了.h文件、dll和lib

我试图在C#中调用的函数在.h文件中定义为:

DLLGSMADAPTER ApnInfoData* GetAvailApnList();
数据结构如下所示:

typedef struct ApnInfoData
{
    int m_iDefIndex;
    ApnInfoArray m_apnList;
}

typedef struct ApnInfo
{
    DWORD m_dwAuthType;
    TCHAR m_szName[64];
    TCHAR m_szTel[32];
    TCHAR m_szUser[32];
    TCHAR m_szPassword[32];
    TCHAR m_szApnName[32];
}*LPAppInfo;

typedef vector<ApnInfo> ApnInfoArray;

我的问题是如何在.net cf中pinvoke这个函数,因为它使用vector类,我不知道如何封送它。

这是不可能的。P/Invoke设计为仅封送C类型。您有几个选择:

  • 使用C++/CLI围绕C库构建托管包装器,然后从C中使用它#
  • 在C++类型周围写一个C包装器,然后调用/调用C包装器< /LI> 在C++类型周围写一个COM包装器,然后生成COM互操作存根。
最基本的C包装应该是这样的:

// creates/loads/whatever your vector<ApnInfo> and casts it to void*, and then returns it through 'handle'
int GetAppInfoHandle(void **handle);

// casts handle back to vector<ApnInfo> and calls .size()
int GetAppInfoLength(void *handle);   

// Load into 'result' the data at ((vector<ApnInfo>*)handle)[idx];
void GetAppInfo(void *handle, int idx, ApnInfo *result);  
//创建/加载/任意向量并将其强制转换为void*,然后通过“handle”返回
int GetAppInfoHandle(无效**句柄);
//将句柄强制转换回vector和calls.size()
int GetAppInfoLength(void*句柄);
//将((向量*)句柄)[idx]处的数据加载到“结果”中;
void GetAppInfo(void*句柄、int idx、apinfo*结果);

在C#中包装一个
std::vector
,只需要常规的p/Invoke互操作就可以了,尽管这很复杂

< C++ > C++ C++语言中的一个例子,它是从.NET世界中实例化C++对象的基本思想是从.NET中分配C++对象的精确大小,然后调用从C++ DLL导出的构造函数来初始化对象,然后如果任何方法涉及其他C++类,那么你就可以调用任何函数来访问C++对象。您还需要将它们封装在C#类中,对于具有基元类型的方法,您可以简单地P/调用它们。如果您只有几个方法可以调用,那么它将很简单,手动编码不会花费很长时间。当你完成C++对象时,你也调用C++对象的析构函数方法,这也是一个导出函数。如果它没有,那么您只需要从.NET中释放内存

这里有一个例子

public class SampleClass : IDisposable
{    
    [DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi,          CallingConvention=CallingConvention.ThisCall)]
    public extern static void SampleClassConstructor(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject, int x);

    IntPtr ptr;

    public SampleClass(int sizeOfYourCppClass)
    {
        this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass);
        SampleClassConstructor(this.ptr);  
    }

    public void DoSomething()
    {
        DoSomething(this.ptr);
    }

    public void DoSomethingElse(int x)
    {
        DoSomethingElse(this.ptr, x);
    }

    public void Dispose()
    {
        Marshal.FreeHGlobal(this.ptr);
    }
}
有关详细信息,请参见以下链接


(我是SDK工具的作者)

因此我必须创建一个c包装器来导出此函数,并为每个元素调用GetAppInfo来检索我需要的信息,当然,在调用GetAppInfo之前,我必须调用其他元素以获得句柄和元素数。谢谢你的快速回答当然,诸如此类。关键是C++没有很好地跨越语言障碍。类型太复杂,C++类型本身不描述向量内的实际布局。P/UnjKE可以处理C类型,并且C++可以假装是C.。你明白了。尽管它被标记为正确答案。在我看来,C++/CLI在Windows CE上不可用。为什么?如果你能提供细节,我将不胜感激。谢谢我做了一个快速的研究,没有发现任何东西阻止开发人员从C#创建std::vector对象,并使用Compact框架通过常规的P/Invoke互操作调用函数。你能进一步解释一下吗?谢谢要实例化一个STD::vector对象并调用C++对象,我们只需要为C++ STD::vector分配内存,然后调用std::vector的构造函数来初始化对象,然后您可以调用导出DLL的std::vector类的任何函数。我读了几本关于compact框架中封送类的书,compact版本中缺少一些静态封送方法,这些缺失的方法都不能阻止使用这个解决方案来包装C++类,所以它不适用于紧凑框架的声明是不正确的。我将改进我们的C#包装器生成器,以支持compact framework。在我使用compact framework版本时,我发现windows CE存在限制,不支持通过compact framework将浮点值类型传递给windows CE DLL,解决方法是添加原始方法的替代方法,该方法通过传递对浮点类型值的引用来传递浮点类型的值。
public class SampleClass : IDisposable
{    
    [DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi,          CallingConvention=CallingConvention.ThisCall)]
    public extern static void SampleClassConstructor(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject, int x);

    IntPtr ptr;

    public SampleClass(int sizeOfYourCppClass)
    {
        this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass);
        SampleClassConstructor(this.ptr);  
    }

    public void DoSomething()
    {
        DoSomething(this.ptr);
    }

    public void DoSomethingElse(int x)
    {
        DoSomethingElse(this.ptr, x);
    }

    public void Dispose()
    {
        Marshal.FreeHGlobal(this.ptr);
    }
}