C ++ transmits data to C # Through Callback,

Source: Internet
Author: User

C ++ transmits data to C # Through Callback,

Currently, C # And C ++ are popular in combination: C # Is a GUI with high development efficiency. C ++ is used for computation and high operation efficiency.

However, C ++ and C # must have data interaction. Data Interaction between C # And C ++ dll is always a headache.

There are two scenarios from the call method:

1. C # Call C ++ Functions

In this case, the data flow direction can be C # To C ++, and the data is passed to C ++ through parameters (for example, SetData (double [] data )); it can also be C ++ to C # (for example, GetData (double [] data )).

2. C ++ Callback

In this case, C # code is called through Callback in C ++. It is similar to C ++ that has done some processing and then sent an event to C, events can carry data (such as processed data ). The function pointer defined in C ++ is as follows:

Typedef void (* Render) (double * data, BOOL * color );

 

C # as the delegate, the defined function is called C ++ callback:

Public delegate void RenderCallback ([externalas (UnmanagedType. LPArray, SizeConst = 23)] double [] data, [externalas (UnmanagedType. LPArray, SizeConst = 23)] int [] colors );

Note: The double [] array in delegate must be marked with the passed alas mark, and the number of passed values must be specified. If the number is not marked, only one value is passed at a time, it took me a long time to solve this problem!

Other considerations:

1. How to maintain C ++ function pointers in C #

Another note of the callback function is the issue of passing the callback function pointer to C ++ dll.

Assume that a function transmits a pointer to C ++ dll:

public delegate void EKFRenderCallback(string data, string colors);public class EKFLib{    [DllImport("EKFLib.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]    public static extern void SetRenderCallback(EKFRenderCallback render);

  

In C #, the callback function is passed as follows:

public void RenderCallback(string data, string color){    // rendering}private void Window_Loaded(object sender, RoutedEventArgs e){    EKFLib.SetRenderCallback(RenderCallback);    EKFLib.Init();}

  

Although there is no problem with this, the pointer passed to C ++ through SetRenderCallback () is not managed by the managed code. in C #, the pointer object is not referenced by any code, when GC is used for garbage collection, the local NULL pointer of C # is recycled, leading to the failure of C ++ to execute the callback. The "CallbackOnCollectedDelegate" error occurs:

For "MotionCapture! MotionCapture. EKFRenderCallback: Invoke "type of garbage collection delegate for callback. This may cause application crash, damage, and data loss. When delivering delegates to unmanaged code, managed applications must keep these delegates active until you are sure they will not be called again.

The example on the Microsoft official website is to control the GC collection mechanism. This is a clumsy method. A more natural way is to define a delegate as an attribute and point it to a new callback, then pass the callback to C ++ dll. In this way, the C # End has an object reference, which ensures that GC does not recycle the callback:

public void RenderCallback(string data, string color){    // rendering}private EKFRenderCallback render;private void Window_Loaded(object sender, RoutedEventArgs e){    render = new EKFRenderCallback(RenderCallback);    EKFLib.SetRenderCallback(render);    EKFLib.Init();}

2. _ stdcall and _ cdecl Transfer Data

The latest project uses C ++ dll for high-speed computation, and then calls back the result data to C # (Interface part) through Callback ), the result is always directly suspended after a callback event is received in C # (the program exits without any prompt, without any debugging information or prompts ).

The cause is that, by default, function pointers defined in C ++ are called in the _ cdecl mode:

Typedef void (* Render) (double * data, BOOL * color );

In this case, the parameter stack is maintained by the caller (C ++ side). After C ++ calls this callback function, the parameter pop-up stack is released, this causes an inexplicable error when C # reads data.

The above is the possible situation where the callback function transmits an array, but as shown below, only one parameter is passed, and even the C # side is inexplicably stuck:

typedef void (*CalibrationProgressCallback)(double percent);
Change to _ stdcall to solve the problem. The statement is as follows:

Typedef void (_ stdcall * Render) (double * data, BOOL * color );

The following network sections _ cdecl and _ stdcall must be kept in mind:

1. _ cdecl

That is, the so-called C call rule puts the parameters in the stack in the order from right to left, and the caller pushes the parameters to the stack. Remember: The Memory stack of the transfer parameter is maintained by the caller. The returned value is in EAX. Therefore, this rule must be used for functions that change parameters like printf. When the compiler is hungry for the function generation modifier of this call rule during compilation, it only adds an underline prefix before the output function name in the format of _ functionname.
2. _ stdcall

The parameter is pushed from right to left to the stack. The parameter is pushed to the stack by the caller. _ Stdcall is the default calling method of the Pascal program. It is usually used in Win32 APIs. Remember: The function clears the stack when it exits, and the returned value is in EAX. The _ stdcall call Convention adds an underline prefix before the output function name, followed by the "@" symbol and the number of bytes of the parameter. The format is _ functionname @ number. For example, the modifier of int func (int a, double B) is _ func @ 12.

Therefore, the callback function from C ++ dll transfers data to C #. The C # function must clear the stack after using the data (when exiting the function! The callback function pointer in C ++ should be defined as follows:

typedef void (_stdcall *CalibrationProgressCallback)(double percent);

Summary:

C ++ must pay attention to the following points when passing data to C # Through callback:

1. The callback function in C ++ must be marked with _ stdcall and called back using stdcall;

2. If it is an array, you must mark the parameter with [financialas (UnmanagedType. LPArray, SizeConst = 23)], specify it as an array and mark the length of the array;

3. the C # Party must declare a variable to point to the C ++ callback pointer function to avoid being recycled by C.

From: http://www.roboby.com/

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.