如何将C++指针分配给C#函数

3
我正在创建一个C# DLL,将用作PLSQL Developer IDE的插件,该IDE是用C++设计的。
我的C# DLL需要接受一个C++指针,然后将该指针分配给一个函数或方法,在以后调用时使用。
这个IDE为构建这些插件提供了规范文档,但它只提供了C++和Delphi的示例。规范文档提供了更多信息,我在这个截图中包含了它。
提供的C++示例:
void (*IDE_MenuState)(int ID, int Index, BOOL Enabled);
BOOL (*IDE_Connected)();
void (*IDE_GetConnectionInfo)(char **Username, char **Password, char **Database);
void (*IDE_GetBrowserInfo)(char **ObjectType, char **ObjectOwner, char **ObjectName);

void RegisterCallback(int Index, void *Addr)
{
    switch (Index)
    {
        case 10 :
        (void *)IDE_MenuState = Addr;
        break;
        case 11 :
        (void *)IDE_Connected = Addr;
        break;
        case 12 :
        (void *)IDE_GetConnectionInfo = Addr;
        break;
        case 13 :
        (void *)IDE_GetBrowserInfo = Addr;
        break;
    }
}

C# 我目前掌握的:

我应该注意到,我正在使用 Robert Giesecke 的Unmanaged Exports NuGet 包来导出函数。如果需要,我可以更改此设置。

public bool IDE_Connected()
{
    return false;
}

public void IDE_MenuState(int ID, int Index, bool Enabled)
{

}

[DllExport("add", CallingConvention = CallingConvention.Cdecl, ExportName= "RegisterCallback")]
public static void RegisterCallback(int Index, IntPtr Addr)
{
    if (Index == 10)
    {
       // Assign IntPtr Addr to IDE_MenuState()
       // Please help :)
    }
    if (Index == 11)
    {
       // Assign IntPtr Addr to IDE_Connected()
       // Please help :)
    }

}

我该如何将C++指针参数赋值给我的C#方法?


你尝试过在C#中使用void*类型吗? - Mr Anderson
我可以将Addr参数从intPtr更改为void。那么,我该如何将void Addr分配给一个方法呢?谢谢。 - Josh
1
你可以尝试使用 Marshal.GetDelegateForFunctionPointer() - Mr Anderson
我会尝试这个并很快回复您。感谢您在此方面的帮助。 - Josh
1个回答

2

为实际目的,编译方法无法在运行时更改。因此,更改IDE_Connected()的功能(来自您的代码示例)是不可能的。

但是,您可以将方法声明为委托(请参见此处),并创建每个方法的静态实例。尝试这样做:

public unsafe class MyClass
{
    delegate void IDE_MenuState(int ID, int Index, bool Enabled);
    delegate bool IDE_Connected();
    delegate void IDE_GetConnectionInfo(char** Username, char** Password, char** Database);
    delegate void IDE_GetBrowserInfo(char** ObjectType, char** ObjectOwner, char** ObjectName);

    static IDE_MenuState method_IDE_MenuState;
    static IDE_Connected method_IDE_Connected;
    static IDE_GetConnectionInfo method_IDE_GetConnectionInfo;
    static IDE_GetBrowserInfo method_IDE_GetBrowserInfo;

    public static void RegisterCallback(int Index, IntPtr Addr)
    {
        switch (Index)
        {
            case 10:
                method_IDE_MenuState = (IDE_MenuState)Marshal.GetDelegateForFunctionPointer(Addr, typeof(IDE_MenuState));
                break;
            case 11:
                method_IDE_Connected = (IDE_Connected)Marshal.GetDelegateForFunctionPointer(Addr, typeof(IDE_Connected));
                break;
            case 12:
                method_IDE_GetConnectionInfo = (IDE_GetConnectionInfo)Marshal.GetDelegateForFunctionPointer(Addr, typeof(IDE_GetConnectionInfo));
                break;
            case 13:
                method_IDE_GetBrowserInfo = (IDE_GetBrowserInfo)Marshal.GetDelegateForFunctionPointer(Addr, typeof(IDE_GetBrowserInfo));
                break;
        }
    }

    public static void IDE_MenuState(int ID, int Index, bool Enabled)
    {
        if (method_IDE_MenuState == null)
        {
            throw new MissingMethodException("IDE_MenuState has not been assigned pointer yet.");
        }
        method_IDE_MenuState(ID, Index, Enabled);
    }

    public static bool IDE_Connected()
    {
        if (method_IDE_Connected == null)
        {
            throw new MissingMethodException("IDE_Connected has not been assigned pointer yet.");
        }
        return method_IDE_Connected();
    }

    public static void IDE_GetConnectionInfo(char** Username, char** Password, char** Database)
    {
        if (method_IDE_GetConnectionInfo == null)
        {
            throw new MissingMethodException("IDE_GetConnectionInfo has not been assigned pointer yet.");
        }
        method_IDE_GetConnectionInfo(Username, Password, Database);
    }

    public static void IDE_GetBrowserInfo(char** ObjectType, char** ObjectOwner, char** ObjectName)
    {
        if (method_IDE_GetBrowserInfo == null)
        {
            throw new MissingMethodException("IDE_GetBrowserInfo has not been assigned pointer yet.");
        }
        method_IDE_GetBrowserInfo(ObjectType, ObjectOwner, ObjectName);
    }
}

注意:我没有测试过这个方法,但是尝试将IDE_GetConnectionInfoIDE_GetBrowserInfo的方法签名改为使用out char[]或者更好的out string,而不是char**。这将使您的API在C#中更有用。


再次感谢您的帮助。 - Josh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接