Click here to Skip to main content
11,432,427 members (69,227 online)
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

 
QuestionInconsistent accessibility Pin
Member 1144213210-Feb-15 6:48
memberMember 1144213210-Feb-15 6:48 
AnswerRe: Inconsistent accessibility Pin
Tecfield6-Mar-15 3:48
memberTecfield6-Mar-15 3:48 
QuestionWorks Great! Pin
Tamok16-Dec-14 8:17
memberTamok16-Dec-14 8:17 
GeneralThanks. Very informative and clear Pin
IssaharNoam11-Oct-14 9:28
memberIssaharNoam11-Oct-14 9:28 
QuestionExcellent and informative Pin
Member 1039745231-Dec-13 15:27
memberMember 1039745231-Dec-13 15:27 
GeneralMy vote of 5 Pin
Rene Pilon24-Jun-13 3:49
memberRene Pilon24-Jun-13 3:49 
Generalnice Pin
cuolyut21-Jun-13 20:10
membercuolyut21-Jun-13 20:10 
Questiondeclare parameter as ProgressCallback instead of long? Pin
Member 64339520-Jun-13 5:24
memberMember 64339520-Jun-13 5:24 
AnswerRe: declare parameter as ProgressCallback instead of long? Pin
Tecfield21-Jun-13 4:42
memberTecfield21-Jun-13 4:42 
QuestionThreaded callbacks [modified] Pin
DaedalusAlpha4-Feb-13 3:34
memberDaedalusAlpha4-Feb-13 3:34 
AnswerRe: Threaded callbacks Pin
Tecfield18-Jul-13 20:10
memberTecfield18-Jul-13 20:10 
GeneralMy vote of 5 Pin
TheMahakhef16-Jan-13 2:58
memberTheMahakhef16-Jan-13 2:58 
GeneralMy vote of 5 Pin
mYashodhar19-Jul-12 19:01
membermYashodhar19-Jul-12 19:01 
QuestionMoving pointer from C/C++ dll to C# callback Pin
kobbi_k4-Jul-12 3:33
memberkobbi_k4-Jul-12 3:33 
GeneralRe: Moving pointer from C/C++ dll to C# callback Pin
Tecfield6-Jul-12 7:04
memberTecfield6-Jul-12 7:04 
GeneralRe: Moving pointer from C/C++ dll to C# callback Pin
Member 64339515-May-13 1:27
memberMember 64339515-May-13 1:27 
GeneralRe: Moving pointer from C/C++ dll to C# callback Pin
Tecfield15-May-13 3:26
memberTecfield15-May-13 3:26 
AnswerRe: Moving pointer from C/C++ dll to C# callback Pin
Tecfield6-Jul-12 7:10
memberTecfield6-Jul-12 7:10 
GeneralMy vote of 5 Pin
Shmuel Zang20-Jun-12 11:12
memberShmuel Zang20-Jun-12 11:12 
GeneralMy vote of 5 Pin
juan_tabares00130-May-12 21:23
memberjuan_tabares00130-May-12 21:23 
QuestionCongratulations, so easy and simple Pin
Miguel Correia Lima7-May-12 8:34
memberMiguel Correia Lima7-May-12 8:34 
GeneralReason for my vote of 5 nice article Pin
san123pune26-Feb-12 9:39
membersan123pune26-Feb-12 9:39 
GeneralNice... Pin
jaffar Ramnad13-Feb-12 22:00
memberjaffar Ramnad13-Feb-12 22:00 
GeneralReason for my vote of 5 good explanation, straight forward! ... Pin
Emiel Duivenvoorden31-Jan-12 6:30
memberEmiel Duivenvoorden31-Jan-12 6:30 
GeneralReason for my vote of 5 ...Once upon a time I needed such fu... Pin
kosmoh24-Jan-12 21:12
memberkosmoh24-Jan-12 21:12 
General[UnmanagedFunctionPointer(CallingConvention.StdCall)] de... Pin
Selvin23-Jan-12 23:49
memberSelvin23-Jan-12 23:49 
GeneralRe: Thanks for the update :) I modified it to reflect your sugge... Pin
Tecfield24-Jan-12 4:04
memberTecfield24-Jan-12 4:04 
QuestionNice ! Pin
raananv31-Jan-12 12:27
memberraananv31-Jan-12 12:27 
AnswerRe: Nice ! Pin
Tecfield31-Jan-12 17:19
memberTecfield31-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
Web01 | 2.8.150428.2 | Last Updated 26 Jun 2013
Article Copyright 2012 by Tecfield
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid