簡體   English   中英

從C#調用C ++函數,並且param是接口指針

[英]Call a C++ function from C# and the param is a interface pointer

我有一個C ++ DLL。 它包含以下功能:

struct Message {
    int id;
    unsigned short messageLength;
    unsigned char* message;
};

class Listener {
public:
    virtual void OnMessage(Message* message);
};

void init(Listener* listener);

有沒有辦法從C#調用函數“ init”? 我知道您可以在C#中使用[DllImport]來調用C ++函數,但是指針給我帶來了麻煩。

任何幫助,將不勝感激!

我的解決方案

C ++代碼

typedef void (*MessageHander)(Message* message);

class MessageDelegate : public Listener {
public:
    MessageHander* messageCallback; // hold the callback funtion

    virtual void OnMessage(Message* message) {
        if (messageCallback) {
            (*messageCallback)(message);
        }   
    }
}

static MessageDelegate messageDelegate;

void initEx(MessageHander* handler) {
    messageDelegate.messageCallback = handler;
    init(messageDelegate);
}

C#代碼

[Serializable]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Message {
    public int id;
    public ushort messageShort;
    public IntPtr message;
}

class Program {
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void MessageHandler(ref Message message);

    [DllImport("MyCPlusPlusDLLName", CallingConvention = CallingConvention.Cdecl)]
    public static extern void initEx(ref MessageHandler callback);

    public void OnMessage(ref Message message) {
        byte[] rawMessage = new byte[message.messageLength];
        Marshal.Copy(message.message, rawMessage, 0, message.messageLength);
        // some other logic
    }

    public void Run() {
        MessageHandler handler = new MessageHandler(this.OnMessage);
        initEx(ref handler);
    }
}

您的代碼中有幾個問題。

在C ++中,您的MessageHander已經是一個指向函數的指針。 無需指向指針的指針。 修正:

MessageHander messageCallback; // hold the callback function
messageCallback( message );
void initEx( MessageHander handler )

在C#中,應該告訴運行時您將委托作為C函數指針傳遞。 默認值很復雜,有時它會將這些委托作為一些COM對象傳遞:

[DllImport("MyCPlusPlusDLLName", CallingConvention = CallingConvention.Cdecl)]
public static extern void initEx(
    [In, MarshalAs( UnmanagedType.FunctionPtr )] MessageHandler callback);

最后,C#運行時不知道您的C ++代碼保留了該函數指針。 C函數指針非常簡單,無法對其進行引用計數。 您的C#委托將在initEx調用后不久被垃圾回收。 發生這種情況時,您的代碼將使下一個OnMessage調用崩潰,從而調用一個已取消分配的對象。 您需要將handler存儲在某個地方,例如,在一個靜態變量中,因此GC將不理會它。

PS:如果僅以一種方式傳遞該消息,則最好在C ++中指定const Message*在C#中指定[In] ref Message 這將稍微提高性能,封送拆收器將停止將結構從C#編送回C ++。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM