我正在考虑为名为 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/