2016-07-28 62 views
3

我正在創建一個C#DLL,該DLL將用作PLSQL Developer IDE(用C++設計)的插件。如何將C++指針指定給C#函數

我的C#DLL需要接受一個C++指針,然後將該指針分配給函數或方法,稍後再調用。

IDE爲構建這些插件提供了一個規範文檔,但它僅提供了C++和Delphi的示例。規格文檔提供我包含在這個 screenshot.

提供的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#我到目前爲止有:

我要指出,我使用羅伯特Gieseckes 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#的方法呢?

+0

你在c#中嘗試過'void *'類型嗎? –

+0

我可以將Addr參數從intPtr更改爲void *。那麼我該怎麼做才能將void * Addr分配給一個方法?謝謝。 –

+1

你可以試試'Marshal.GetDelegateForFunctionPointer()' –

回答

2

出於實用目的,編譯的方法不能在運行時更改。因此改變IDE_Connected()(來自您的代碼示例)的功能是不可能的。

但是,您可以將方法聲明爲delegates(請參閱here),並創建每個方法的靜態實例。試試這個:

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#中更加有用。

+0

再次感謝您的幫助。 –