美文网首页
C# 调用 C/C++ dll Callback回调函数使用

C# 调用 C/C++ dll Callback回调函数使用

作者: XBruce | 来源:发表于2020-12-11 14:39 被阅读0次

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

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 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);
  1. Define callback signature in the C code –
typedef void (__stdcall * ProgressCallback)(int);
  1. Change DoWork signature in C code to accept ProgressCallback address:
DLL void DoWork(ProgressCallback progressCallback)
Note: DLL is…
#define DLL __declspec(dllexport)
  1. Inside the C# code, we need to create a delegate of type of the unmanaged delegate –
  ProgressCallback callback =
        (value) =>
        {
            Console.WriteLine("Progress = {0}", value);
        };
  1. 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);
    }
}

相关文章

网友评论

      本文标题:C# 调用 C/C++ dll Callback回调函数使用

      本文链接:https://www.haomeiwen.com/subject/oyujgktx.html