This article will deal with a call to a managed C # code (.Net) from unmanaged C code.
Once at work they gave a project, or rather not even the project itself, but only a part of it. The project itself consisted of two parts: a functional written in C (unmanaged code) and an interface part written in C # (managed code). My task was to write the interface and connect it with the functionality.
Further in this article the managed code will be called the top level, unmanaged - the bottom level.
As is known, the P / Invoke (Platform Invoke) mechanism is used to access the lower level from the top in C #. To do this, the bottom level is wrapped in a Dll (that is, all functions of the bottom level are made exported) and called from above using the DllImport attribute. For those unfamiliar with this mechanism -
msdn.microsoft.com/en-us/library/aa288468 (v = vs.71) .aspx
During the assignment, I faced a problem - at the lower level there was a callback function, which was supposed to notify the upper level about the success or failure of the function. To solve the problem, it was necessary either to call the upper level from the lower level or to come up with some mechanism to find out when the top-level function was called (for example, using an event). Searching the Internet for the topic of calling managed code from unmanaged did not bring proper fruits. Nevertheless, it was decided to try to do a little blood and not reinvent the wheel.
')
To simplify understanding, a new solution was created, including two projects: a low-level project (CallC) and a high-level project (SharpForCall).
So, we have an empty C # project (Console Application) and someone wrote a C project (I initially only had h-file, of course, we take the project right away for simplicity). Type of project in C - Dll, which naturally should lie next to our executable obtained in C #. There is a * .cpp file in the project as follows:
typedef VOID (__stdcall * pResultCallBack)( int nStatus ); __declspec(dllexport) int FuncC(pResultCallBack pfResult, PVOID pContext) {
Once again I will explain the meaning of what needs to be done. The exported function here (FuncC) will be imported on the C # side, which, suppose, is called when the user clicks a button (let's not forget that the main task is to connect the interface with the functionality). This function (imported on the C # side) will naturally call the FuncC function in this * .cpp file (see above), which, after execution, must report the result of execution back to C # by calling the pResultCallBack function. On the top-level side, the pResultCallBack function (in our case, FuncCSharp, see below) will analyze the result of the execution of the FuncC function and, depending on the value transferred to it, perform certain actions (for example, when returning a status code reporting a failed call, etc.). d.) In general, this idea can be used to control one machine (host) with another machine.
Let's start the implementation.
First, go to the settings of the S-project in the Configuration Properties-> General-> Output Directory and write the path to the folder with the C # project.

Secondly, do not forget to go to the Project Dependencies of the C # project and put a tick there next to the C-project.

Next, create the Import.cs class, in which we describe the imported function using the P / Invoke mechanism.
using System; using System.Runtime.InteropServices;// namespace SharpForCall { class Import { [DllImport("CallC.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int FuncC( [MarshalAs(UnmanagedType.FunctionPtr)] ResultCallBack pfResult, IntPtr pContext); } }
Replace the PVOID with IntPtr, and the pointer to the pResultCallBack function to the ResultCallBack delegate, which is described in the Program.cs file as follows:
using System; namespace SharpForCall { public delegate void ResultCallBack(Int32 nStatus); class Program { static void Main(string[] args) { ResultCallBack result = new ResultCallBack(FuncCSharp); IntPtr pContext = IntPtr.Zero; int nRes = Import.FuncC(result, pContext); } public static void FuncCSharp(Int32 nStatus) { if ( 1 == nStatus ) {
Now, running the program and walking along it in steps (in order to enter unmanaged code you need to set the checkbox in the project properties -> Debug-> Enable unmanaged code debugging), we will see that first the upper level calls the lower level, passing it to ) delegate, and the bottom one - after the end of the execution of the FuncC function, calls the top one (FuncCSharp function) by that “delegate” and sends it the result of the function execution (in this case “1”). Next, the function analyzes the received status code and returns control to the lower level, from there control is transferred to the upper level. If at execution the program issues an action of the following content:

then we add on side C in the definition of the __stdcall callback.
If this did not help, then on the C # side in the Import class, you need to add CallingConvention = CallingConvention.Cdecl when calling the DllImport attribute. All this is necessary in order to return the stack to its original state.
Now everything works. We have just accomplished what many consider impossible - called the managed code from unmanaged.
PS: I think someone will come in handy. Waiting for your comments ...