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

来源:互联网 发布:sql server 2012版本 编辑:程序博客网 时间:2024/06/11 20:35

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

Tecfield26 Jun 2013 CPOL 60.1K 66
Rate:
vote 1vote 2vote 3vote 4vote 5
 
This post shows how to make a callback to C# from C/C++
Is your email address OK? You are signed up for our newsletters but your email address is either unconfirmed, or has not been reconfirmed in a long time. Please click here to have a confirmation email sent so we can confirm your email address and start sending you newsletters again. Alternatively, you can update your subscriptions.
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 __cplusplusextern "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
0 0