C++/CLI marshaling .NET delegate to native delegate

北战南征 提交于 2019-12-13 05:13:35

问题


I am trying to pass a delegate with managed parameters to native code to be invoked. My code below runs ok, but the string output is garbage.

Native Class

Header

#pragma once
typedef void (* SegmentCreatedDelegate)(char** arg);
public class SampleClass
{
public:
    SampleClass(void);
    ~SampleClass(void);
    void DoWork(SegmentCreatedDelegate callback);
};

Code

SampleClass::SampleClass(void)
{
}

SampleClass::~SampleClass(void)
{

}

void SampleClass::DoWork(SegmentCreatedDelegate callback)
{
    for(int x = 0; x< 10; x++)
    {
        char* myStr2 = "newsegment!";
        callback(&myStr2);
    }
}

Managed Class

Header

#pragma once
public ref class SampleClassNet
{
public:
    delegate void SegmentCreatedDelegateNet(System::String^ arg);
    SampleClassNet(void);
    void DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback);
};

Code

SampleClassNet::SampleClassNet(void)
{
}

void SampleClassNet::DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback)
{
    SampleClass* nativeClass = new SampleClass();
    System::IntPtr pointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(segmentCreatedCallback);
    nativeClass->DoWork((SegmentCreatedDelegate)(void*)pointer);
    System::GC::KeepAlive(segmentCreatedCallback);
}

This code runs fine with the follow c#.

var sampleClass = new SampleClassNet();
sampleClass.DoWork((Console.WriteLine));

Except I get the following output, instead of the expected 10 entries of "newsegment!".

(ÇÆX
(ÇÆX☺
(ÇÆX☻
(ÇÆX♥
(ÇÆX♦
(ÇÆX♣
(ÇÆX♠
(ÇÆX
(ÇÆX
(ÇÆX

Not exactly "newsegment!", but I am not sure why the marshaling is not working. Maybe I need I need some kind of "MarshalAs" attribute so that the System::String knows that I have 8-bit chars?


回答1:


As mentioned in the comments, you should convert the char** to a String^. (Btw, why pass char**, not char*? String has a constructer taking char*, which might simplify things a lot.)

I haven't tried the following, but you might give it a try:

public ref class SampleClassNet {
private:
    delegate void SegmentCreatedDelegateNative(char** str);
    SegmentCreatedDelegateNet^ managedCallback;
    SegmentCreatedDelegateNative^ nativeCallback;
    void printString(char** string);
public:
    delegate void SegmentCreatedDelegateNet(System::String^ arg);
    SampleClassNet();
    void DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback);
};

SampleClassNet::SampleClassNet() {
    nativeCallback = printString;
}

void SampleClassNet::DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback) {
    SampleClass* nativeClass = new SampleClass();
    managedCallback = segmentCreatedCallback;
    System::IntPtr pointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(nativeCallback);
    nativeClass->DoWork((SegmentCreatedDelegate)(void*)pointer);
}

void SampleClassNet::printString(char** string) {
    if (this->managedCallback != nullptr) {
        String^ str = gcnew String(*string);
        managedCallback(str);
    }
}

The basic idea is to use another delegate, SegmentCreatedDelegateNative, handed to the native class, and to call the actual managed delegate from the function associated with the wrapper.



来源:https://stackoverflow.com/questions/21054847/c-cli-marshaling-net-delegate-to-native-delegate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!