Click here to Skip to main content
15,884,537 members
Articles / Programming Languages / C#
Tip/Trick

How to make a callback to C# from C/C++ code

Rate me:
Please Sign up or sign in to vote.
4.96/5 (46 votes)
26 Jun 2013CPOL1 min read 227.7K   89   41
This post shows how to make a callback to C# from C/C++
Almost everyone knows how to make a call to a function in an unmanaged DLL. However, sometimes we wish that we could call C# code from C/C++ code.
Imagine a scenario wherein we have a C# application which has a native C DLL called Engine.dll. There is a function entry named “DoWork” in this DLL that we need to call. Calling DoWork in the engine is as easy as making the following declaration in the C# code:
C#
[DllImport("Engine.dll")]
public static extern void DoWork(); 
…and then using it like any other static C# method in our C# application.
 
This will work just fine. However, let’s assume DoWork is a long-running task and we want to show a progress or so in the C# app in order to keep our user(s) updated. To make this happen, we need to…
  1. Define an unmanaged delegate in the C# code like –
    C#
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    delegate void ProgressCallback(int value);
  2. Define callback signature in the C code –
    C++
    typedef void (__stdcall * ProgressCallback)(int);
  3. Change DoWork signature in C code to accept ProgressCallback address:
    C++
    DLL void DoWork(ProgressCallback progressCallback)
    Note: DLL is…
    C++
    #define DLL __declspec(dllexport)
  4. Inside the C# code, we need to create a delegate of type of the unmanaged delegate –
    C#
    ProgressCallback callback =
        (value) =>
        {
            Console.WriteLine("Progress = {0}", value);
        };
  5. Then for calling DoWork, we need to do it like this –
    C#
    DoWork(callback);
Here is a sample source code for a simple application. This code snippet includes a second scenario wherein we have a function in C code called ProcessFile that needs to get back to the C# in order to obtain a file path for further processing - in this case, printing its contents to the console.
 
Engine.dll/Main.h
C++
#include "Windows.h"

#ifdef __cplusplus
extern "C"
{
#endif
 
    #define DLL __declspec(dllexport)
    typedef void (__stdcall * ProgressCallback)(int);
    typedef char* (__stdcall * GetFilePathCallback)(char* filter);
 
    DLL void DoWork(ProgressCallback progressCallback);
    DLL void ProcessFile(GetFilePathCallback getPath);
 
#ifdef __cplusplus
}
#endif
 
Engine.dll/Main.c
C++
#include "Main.h"
#include <stdio.h>

DLL void DoWork(ProgressCallback progressCallback)
{
    int counter = 0;
 
    for(; counter<=100; counter++)
    {
        // do the work...

        if (progressCallback)
        {
            // send progress update
            progressCallback(counter);
        }
    }
}
 
DLL void ProcessFile(GetFilePathCallback getPath)
{
 
    if (getPath)
    {
        // get file path...
        char* path = getPath("Text Files|*.txt");
        // open the file for reading
        FILE *file = fopen(path, "r");
        // read buffer
        char line[1024];
 
        // print file info to the screen
        printf("File path: %s\n", path ? path : "N/A");
        printf("File content:\n");
 
        while(fgets(line, 1024, file) != NULL)
        {
            printf("%s", line);
        }
 
        // close the file
        fclose(file);
    }
}
 
TestApp.exe/Program.cs
C#
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
 
class Program
{
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    delegate void ProgressCallback(int value);
 
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    delegate string GetFilePathCallback(string filter);
 
    [DllImport("Engine.dll")]
    public static extern void DoWork([MarshalAs(UnmanagedType.FunctionPtr)] ProgressCallback callbackPointer);
 
    [DllImport("Engine.dll")]
    public static extern void ProcessFile([MarshalAs(UnmanagedType.FunctionPtr)] GetFilePathCallback callbackPointer);
 
    [STAThread]
    static void Main(string[] args)
    {
        // define a progress callback delegate
        ProgressCallback callback =
            (value) =>
            {
                Console.WriteLine("Progress = {0}", value);
            };
 
        Console.WriteLine("Press any key to run DoWork....");
        Console.ReadKey(true);
        // call DoWork in C code
        DoWork(callback);
 
        Console.WriteLine();
        Console.WriteLine("Press any key to run ProcessFile....");
        Console.ReadKey(true);
 
        // define a get file path callback delegate
        GetFilePathCallback getPath =
            (filter) =>
            {
                string path = default(string);
 
                OpenFileDialog ofd =
                    new OpenFileDialog()
                {
                    Filter = filter
                };
 
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    path = ofd.FileName;
                }
 
                return path;
            };
 
        // call ProcessFile in C code
        ProcessFile(getPath);
    }
}
 
Enjoy it Smile

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
I got my BS in Software Engineering from Iran, worked there for 4.5 years mainly in industrial automation field. Then I moved to Australia. In Australia, I had a great chance to work at some big companies. Since 2009 I have been living in the States. I received my MS in Information Systems from Illinois State University. Currently, I am a Senior Software Development Engineer.

Comments and Discussions

 
QuestionIF the c++ project is a vc++ clr library how would it work Pin
Member 1616904823-Dec-23 6:48
Member 1616904823-Dec-23 6:48 
QuestionError in MS VS 2019 debug mode Pin
Jerry_Mouse6-May-21 4:17
Jerry_Mouse6-May-21 4:17 
Questionwaiting for delegate for returning the values from c++ Pin
Kerito Nation3-Mar-21 1:39
Kerito Nation3-Mar-21 1:39 
QuestionCan we call delegates from c++ whenever needed? Pin
Member 1468675226-Jul-20 18:59
Member 1468675226-Jul-20 18:59 
Questionhow to make DoWork call a non blocking. Pin
Member 1474271015-Feb-20 4:16
Member 1474271015-Feb-20 4:16 
QuestionCan this be done in reverse? Pin
Andrew Truckle7-May-19 21:18
professionalAndrew Truckle7-May-19 21:18 
QuestionOne simplification Pin
Michael Geary13-Feb-17 17:49
Michael Geary13-Feb-17 17:49 
QuestionArrays in Callbacks Pin
Ben99317-Jul-16 7:55
Ben99317-Jul-16 7:55 
QuestionCallback invoked in a separate thread Pin
Radu Tomy17-Feb-16 23:44
Radu Tomy17-Feb-16 23:44 
AnswerRe: Callback invoked in a separate thread Pin
Tecfield18-Feb-16 0:55
Tecfield18-Feb-16 0:55 
GeneralRe: Callback invoked in a separate thread Pin
Radu Tomy18-Feb-16 1:17
Radu Tomy18-Feb-16 1:17 
GeneralRe: Callback invoked in a separate thread Pin
Tecfield18-Feb-16 6:58
Tecfield18-Feb-16 6:58 
QuestionInconsistent accessibility Pin
Member 1144213210-Feb-15 5:48
Member 1144213210-Feb-15 5:48 
AnswerRe: Inconsistent accessibility Pin
Tecfield6-Mar-15 2:48
Tecfield6-Mar-15 2:48 
QuestionWorks Great! Pin
Tamok16-Dec-14 7:17
Tamok16-Dec-14 7:17 
GeneralThanks. Very informative and clear Pin
IssaharNoam11-Oct-14 8:28
IssaharNoam11-Oct-14 8:28 
QuestionExcellent and informative Pin
Master_Clinician31-Dec-13 14:27
Master_Clinician31-Dec-13 14:27 
GeneralMy vote of 5 Pin
2374124-Jun-13 2:49
2374124-Jun-13 2:49 
Generalnice Pin
colttme21-Jun-13 19:10
colttme21-Jun-13 19:10 
Questiondeclare parameter as ProgressCallback instead of long? Pin
Oleg Vazhnev20-Jun-13 4:24
Oleg Vazhnev20-Jun-13 4:24 
AnswerRe: declare parameter as ProgressCallback instead of long? Pin
Tecfield21-Jun-13 3:42
Tecfield21-Jun-13 3:42 
QuestionThreaded callbacks Pin
DaedalusAlpha4-Feb-13 2:34
DaedalusAlpha4-Feb-13 2:34 
AnswerRe: Threaded callbacks Pin
Tecfield18-Jul-13 19:10
Tecfield18-Jul-13 19:10 
GeneralMy vote of 5 Pin
TheMahakhef16-Jan-13 1:58
TheMahakhef16-Jan-13 1:58 
GeneralMy vote of 5 Pin
mYashodhar19-Jul-12 18:01
mYashodhar19-Jul-12 18:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.