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.
11,288 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,851 questions
0 comments No comments
{count} votes

Accepted answer
  1. RLWA32 47,031 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.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.