Convert and use C++ callback function in a C# libary

bioan 41 Reputation points
2021-10-08T07:35:08.327+00:00

Hi everybody!

I'm trying to wrap a C++ dll using C#.
I have the following C++ function signature:

/** 
  @param documen - the current document
  @param progress Callback for progress and abort support. May be nullptr.
  @param context Progress context.
*/
unsigned int Longtime_function(IUnknown* document, Longtime_function_Progress progress, void* context);

where the prototype for the callback function is defined like below:

/** Callback function for progress. Must return 0 or task will be aborted. */
typedef unsigned int (Longtime_function_Progress)(IUnknown* document, void* context, double progress);

which I want to use inside a C# .dll library project using P/Invoke mechanism.

The first problem is how to express in C# both, the function and callback function.
The second problem is how to use it in my C# library, because I need to wait the result from the function in order to use it in a foreach loop
but in the same time I do not want to block my main window app interface.

Thanks for any feedback!

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,606 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,625 questions
0 comments No comments
{count} votes

Accepted answer
  1. RLWA32 43,041 Reputation points
    2021-10-08T11:33:11.353+00:00

    The following example code from a console application shows how to use pass a C# function to be used as a callback to an unmanaged C++ function called using P/Invoke -

    C# Callback -

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    delegate uint CSCALLBACK([MarshalAs(UnmanagedType.IUnknown)] object document, IntPtr context, double progress);
    
    [DllImport("ArrayMarshal.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    static extern int Longtime_function([MarshalAs(UnmanagedType.IUnknown)] object document, CSCALLBACK cbFunc, IntPtr context);
    

    The C# Callback function -

    static uint MyCallback(object document, IntPtr context, double progress)
    {
    //Your code here
    }
    

    Call the C++ function (example allocates unmanaged memory for the context pointer and stores an int value) -

    IntPtr ptContext = Marshal.AllocHGlobal(sizeof(int));
    Marshal.WriteInt32(ptContext, 42);
    
    int iret = Longtime_function(aObjects[0], MyCallback, ptContext);
    
    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. bioan 41 Reputation points
    2021-10-08T13:46:29.2+00:00

    Excellent excellent!!

    Thank you very much!!!
    It works perfectly!!

    Now I have to understand how to deal with this callback inside my C# library, because I want to wait the result from Longtime_function() to use immediately when is available but in the same time I do not want this Longtime_function() waiting to block my current app interface.
    Longtime_function() reads some data in a for loop, and after the parsing is finished it must writes a temporary file on my disk which will be converted into another final file, like below:

    void ConversionUtility()
    {
        string myTempFile = "D:\\Temp";
        for (int i = 0; i < 20; i++)
        {
            Longtime_function(i);//here a temporary file (tempFile) is created on disk at each iteration of the for cycle
            // OtherLongtime_function must wait for Longtime_function() to finish parsing internal data and write the file (tempFile) to the disk
            string ConvertedFilePath = myTempFile + i.ToString();
            OtherLongtime_function(tempFile, ConvertedFilePath);
        }
    }
    

    How can I use in this scenario the callback function provided by the C++ library?
    There are some other API like async which can be used in this case?
    I have never use asynchronous technology before, but as I read, something like Task class is very popular.
    Ideally ConversionUtility() must run on a different thread than the main app thread.