Click here to Skip to main content
Click here to Skip to main content

Tagged as

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

, 26 Jun 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
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:
[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 –
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    delegate void ProgressCallback(int value);
  2. Define callback signature in the C code –
    typedef void (__stdcall * ProgressCallback)(int);
  3. Change DoWork signature in C code to accept ProgressCallback address:
    DLL void DoWork(ProgressCallback progressCallback)
    Note: DLL is…
    #define DLL __declspec(dllexport)
  4. Inside the C# code, we need to create a delegate of type of the unmanaged delegate –
    ProgressCallback callback =
        (value) =>
        {
            Console.WriteLine("Progress = {0}", value);
        };
  5. Then for calling DoWork, we need to do it like this –
    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
#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
#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
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)

Share

About the Author

Tecfield
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

 
GeneralThanks. Very informative and clear PinmemberIssaharNoam11-Oct-14 9:28 
QuestionExcellent and informative PinmemberMember 1039745231-Dec-13 15:27 
GeneralMy vote of 5 PinmemberRene Pilon24-Jun-13 3:49 
Generalnice Pinmembercuolyut21-Jun-13 20:10 
Questiondeclare parameter as ProgressCallback instead of long? PinmemberMember 64339520-Jun-13 5:24 
AnswerRe: declare parameter as ProgressCallback instead of long? PinmemberTecfield21-Jun-13 4:42 
QuestionThreaded callbacks [modified] PinmemberDaedalusAlpha4-Feb-13 3:34 
AnswerRe: Threaded callbacks PinmemberTecfield18-Jul-13 20:10 
GeneralMy vote of 5 PinmemberTheMahakhef16-Jan-13 2:58 
GeneralMy vote of 5 PinmembermYashodhar19-Jul-12 19:01 
QuestionMoving pointer from C/C++ dll to C# callback Pinmemberkobbi_k4-Jul-12 3:33 
GeneralRe: Moving pointer from C/C++ dll to C# callback PinmemberTecfield6-Jul-12 7:04 
GeneralRe: Moving pointer from C/C++ dll to C# callback PinmemberMember 64339515-May-13 1:27 
GeneralRe: Moving pointer from C/C++ dll to C# callback PinmemberTecfield15-May-13 3:26 
AnswerRe: Moving pointer from C/C++ dll to C# callback PinmemberTecfield6-Jul-12 7:10 
GeneralMy vote of 5 PinmemberShmuel Zang20-Jun-12 11:12 
GeneralMy vote of 5 Pinmemberjuan_tabares00130-May-12 21:23 
QuestionCongratulations, so easy and simple PinmemberMiguel Correia Lima7-May-12 8:34 
GeneralReason for my vote of 5 nice article Pinmembersan123pune26-Feb-12 9:39 
GeneralNice... Pinmemberjaffar Ramnad13-Feb-12 22:00 
GeneralReason for my vote of 5 good explanation, straight forward! ... PinmemberEmiel Duivenvoorden31-Jan-12 6:30 
GeneralReason for my vote of 5 ...Once upon a time I needed such fu... Pinmemberkosmoh24-Jan-12 21:12 
General[UnmanagedFunctionPointer(CallingConvention.StdCall)] de... PinmemberSelvin23-Jan-12 23:49 
GeneralRe: Thanks for the update :) I modified it to reflect your sugge... PinmemberTecfield24-Jan-12 4:04 
QuestionNice ! Pinmemberraananv31-Jan-12 12:27 
AnswerRe: Nice ! PinmemberTecfield31-Jan-12 17:19 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.1411023.1 | Last Updated 26 Jun 2013
Article Copyright 2012 by Tecfield
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid