C#:Cdecl DllExport,参数中带有指向类实例的指针

标签 c# c++ interop

我正在考虑为名为 SmartDVB 的软件编写插件。它需要我导出以下函数(这是一个 C++ 示例):

BOOL RegisterAddOn(UINT iAddOnId, IAddOnInterfaces *pInt, AddOnSettings &settings) {
    /* ... */ 
    return TRUE;
}

其中IAddonInterfaces是一个抽象类(接口(interface)):

class IAddOnInterfaces {
public:
    virtual HRESULT AddSectionFilter(UINT uiAddOnId, UINT pid, BYTE *filter, BYTE *mask, BYTE length, DeviceSettings *pDev) = 0;
    virtual HRESULT RemoveSectionFilter(UINT uiAddOnId, UINT pid, DeviceSettings *pDev) = 0;
    virtual HRESULT AddFilter(UINT uiAddOnId, UINT pid, DeviceSettings *pDev=NULL) = 0;
    virtual HRESULT RemoveFilter(UINT uiAddOnId, UINT pid, DeviceSettings *pDev=NULL) = 0;
    virtual HRESULT GetChannel(UINT uiAddOnId, CHANNEL *chn, DeviceSettings *pDev=NULL) = 0;
    virtual HRESULT GetTransponder(UINT uiAddOnId, SATELLITE *sat, TRANSPONDER *t, DeviceSettings *pDev=NULL) = 0;
    virtual HRESULT SetTransponder(UINT uiAddOnId, SATELLITE sat, TRANSPONDER t, DeviceSettings *pDev=NULL) = 0;
    virtual HRESULT CreateOSDElement(UINT uiAddOnId,  OSDWindowType type, ULONG &ulId, OSDWindowInfo &info) = 0;
    virtual HRESULT ChangeChannel(UINT uiAddOnId,  CHANNEL &chn, DeviceSettings *pDev=NULL) = 0;
    virtual HRESULT RegisterOSDEvents(UINT iAddOnId, IAddOnOSDEvents *pEvents) = 0;
    virtual HRESULT RegisterMenuEvents(UINT iAddOnId, IAddOnMenuEvents *pEvents) = 0;
    virtual HRESULT RegisterChnEvents(UINT iAddOnId, IAddOnChnEvents *pEvents) = 0;
    virtual HRESULT DoDVBCmd(UINT iAddOnId, BYTE pCmd, UINT uiLen, DeviceSettings *pDev=NULL) = 0;
    virtual HRESULT DoDiseqc(UINT iAddOnId, CHANNEL &chn, DeviceSettings *pDev=NULL) = 0;
    virtual HRESULT RecordBusy(UINT iAddOnId, BOOL *bBusy, DeviceSettings *pDev=NULL) = 0;
    virtual HRESULT GetDeviceSettings(UINT iAddOnId, DeviceSettings &Dev) = 0;
    virtual HRESULT GetSignalStrength(UINT iAddOnId, LONG *lStrength, DeviceSettings *Dev) = 0;
    virtual HRESULT GetSignalQuality(UINT iAddOnId, LONG *lQuality, DeviceSettings *Dev) = 0;
};

AddOnSettings 是一个结构体:

typedef struct _AddOnSettings{
    HINSTANCE hInst; // SmartDVB application instance
    HWND hwnd;
    TCHAR name[256]; // addon name
    HMENU menu;      // addon popup menu
    WORD idmenustart;
} AddOnSettings;

在c#中,我将结构定义为

using HINSTANCE = System.IntPtr;
using HWND = System.IntPtr;
using HMENU = System.IntPtr;

/* ... */

public unsafe struct AddOnSettings{
    HINSTANCE hInst; // SmartDVB application instance
    HWND hwnd;
    [MarshalAs(UnmanagedType.LPArray, SizeConst = 256)]
    char[] name; // addon name
    HMENU menu;      // addon popup menu
    ushort idmenustart;
};

/* ... */

但是,我仍然需要以某种方式定义类,以便可以将其导出。

最后,我想要这样的东西:

    [DllExport("RegisterAddOn", CallingConvention = CallingConvention.Cdecl)]
    public static bool RegisterAddOn(uint iAddOnId, IAddOnInterfaces* pInt, ref AddOnSettings settings)
    {
        /* ... */
        return true;
    }

问题是,当我这样做时,出现以下错误:

Error   1   Cannot take the address of, get the size of, or declare a pointer to a managed type ('ChannelSwitchCS.IAddOnInterfaces')    D:\Work\coding\projects\buster\smartdvb\ChannelSwitchCS\ChannelSwitchCS\Class1.cs   102 28  ChannelSwitchCS

附言我不要求完整的解决方案,我只需要了解这种特殊情况,即如何(以及是否可能)在导出函数中拥有指向类实例的指针。因此,我确实意识到我将不得不转换在 IAddOnInterfaces 的方法中使用的所有其他结构和类。

最佳答案

当我不得不使用 PInvoke 并且需要将类的实例作为指针传递时,我为我将在 C++ 中使用的非托管代码编写了一个简单的包装器,它只接受原始类型并将它们排列成任何类型需要。

在将指针传递给类的实例时,我使用了 IntPtr,一切都按照我的预期进行。

关于C#:Cdecl DllExport,参数中带有指向类实例的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28805100/

相关文章:

c# - 加入两个模型以将数据放入 View

c# - 带有单元测试的 C# IDE(如 Eclipse for Java 和 assertEquals( ... ) 等)

c++ - 什么是 Unresolved external 因素?

c# - C#中 bool 值的大小是多少?它真的需要 4 个字节吗?

c# - 互操作和 CRL 事件

c# - WinDbg 从符号中获取所有函数的地址

c# - 在Visual Studio中运行.net应用程序时,我们可以直接登录Cloudwatch吗

c++ - 计算 Base64 编码消息的大小

c++ - 基类,继承类sizeof()

ios - 有什么方法可以在 Objective C 文件中使用普通的 Swift 类?