Sử dụng mã C ++ trong dự án C # phần 1
One day, I came up with an idea of combining my familiar OpenCV codes (written in unmanaged C++) with nice UIs (created by C#), rather than involving more open source languages, like OpenQt, in my project. As things related to OpenCV are always troublesome from my experience, I tried importing simple C++ codes into a C# project first.

The solution sounds very simple: just create a DLL file of my C++ codes and use it in C#. But, as I expected, getting it done is not easy. After some survey, I came to a rough conclusion that there are two main types of DLL we can created:

  • Unmanaged DLL (native DLL): this is what you gonna read in the rest of this blog. When codes contain keywords like dllimportdllexport, and extern “c”, that means you are now dealing with an unmanaged DLL. Unfortunately, you cannot use Add Reference to easily import this DLL to C# projects. Otherwise, the error saying
A reference to xxx dll could not be added. Please make sure that the file is accessible and that it is a valid assembly or COM component.

will appear. Instead, you have to use InteropServices (a.k.a., pinvoke), as you will see later in this blog.

  • Managed DLL: managed codes mean that it lets the compiler take care of cleaning the memory space (i.e., do garbage collection). Creating managed C++ classes compatible with C#, involves learning to write a new .NET language called C++/CLI. Therefore, I will skip it now.

Note: whenever you create a Class Library project, you are accidentally telling MVS to make a .net library using CLI (managed) extension of C++. To create an unmanaged DLL, choose File > New > Project > VC++ > Win32 project > Application setting > Application type: DLL instead.

Well, that’s enough for an introduction. Let’s start creating an unmanaged DLL file from C++ and use it in C#.

:::::::: STEP 1: Create unmanaged DLL from C++ (no OpenCV yet) ::::::::

Creating an unmanaged DLL from C++ codes is not difficult. Simply say that you are about to create a C++ project without main() function with some additional export keywords.

Reference: msdn.microsoftstackoverflow

1 ) Create a new DLL project in Visual Studio 2010 by File > New > Project > Visual C++ > Win32 > Win32 Console Application.

2 ) Specify a name for the project (e.g., MathFuncDll) in the Name box. Specify a name for the solution (e.g., testDynamicLibrary) in the Solution Name box.

3 ) In Win32 Application Wizard dialog box, choose Application Settings > Application Type > DLL. Click Finish button.

4 ) Create a header file by choosing Project > Add New Item > Visual C++ > Code > Header File (.h). Specify a name (e.g., MathFuncsDll.h) and click Add button.

5 ) Insert the following codes in MathFuncsDll.h.

#include <stdexcept>
using namespace std;

namespace MathFuncs
{
   extern "C" { __declspec(dllexport) double Add(double a, double b); }
   extern "C" { __declspec(dllexport) double Subtract(double a, double b); }
   extern "C" { __declspec(dllexport) double Multiply(double a, double b); }
   extern "C" { __declspec(dllexport) double Divide(double a, double b); }
}

Note: I tried putting these four functions in a structural C++ class before, as it was suggested by the MSDN document. However, C# kept giving me an error saying

Unable to find an entry point in xxx DLL.

So I went back to conventional C styles (no OOP, no class)  and the error disappeared. My guess is that the corresponding LIB (as a stub of DLL) is missing.

6 ) Create a C++ source file by choosing Project > Add New Item > Visual C++ > Code > Source Files (.cpp). Specify a name (e.g., MathFuncsDll.cpp) and click Add button.

7 ) Insert the following codes in MathFuncsDll.cpp:

#include "MathFuncsDll.h"

namespace MathFuncs
{
    double Add( double a, double b )
    { return a+b; }
    double Subtract( double a, double b )
    { return a-b; }
    double Multiply( double a, double b )
    { return a*b; }
    double Divide( double a, double b )
    {
       if ( b == 0 )
            throw invalid_argument("b cannot be zero!");
       return a/b;
    }
}

8 ) Compile the DLL by choosing Build > Build Solution. Note that this project cannot be run as there is no main() function.

9 ) That’s it. Your DLL should be at either <solution dir>/Debug/MathFuncsDll.dll or <solution dir>/Release/MathFuncsDll.dll, depending on your build mode.

:::::::: STEP 2: Use the created DLL in your C# project ::::::::

Reference: stackoverflow

1 ) Create a new C# project by choosing File > New > Project > Other Languages > Visual C# > Windows Forms Application. Specify values in Name and Solution Name, then click OK button.

2 ) Suppose that you create Form2 containing one click-button named button1 and one text label named label1. Below is an example of how to call Add function from your DLL. (Commands related to DLL calling are written in blue bold characters)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

// Allow managed code to call unmanaged functions that are implemented in a DLL
using System.Runtime.InteropServices; 

namespace testCSharpInterface
{
    public partial class Form2 : Form
    {
       private double c = 10;

       [DllImport("C:\\testCreateDLLcpp\\Debug\\MathFuncsDll.dll", CallingConvention=CallingConvention.Cdecl)]
       public static extern double Add(double a, double b);

       public Form2()
       {
          InitializeComponent();
       }

       private void button1_Click(object sender, EventArgs e)
       {
          c = Add(c, c);
          label1.Text = c.ToString() ;
       }
    }
}

3 ) Build and run your project. See what will happen when you click the button. Your C++ codes can now be called from your C# project.

::::::: Conclusion :::::::

You may recognize that namespace MathFuncs defined in the VC++ project has no use at all in the C# project. Try removing namespace{} from MathFuncsDll.h and MathFuncsDll.cpp; it should not hurt anything in your C++ and C# projects.

An obvious downside of this method is when you use a number of functions (from an unmanaged DLL) in your C# project. Because it means that you also have to repeatedly write a number of public static extern …… somewhere in your C# codes.

Last but not least, check the below video tutorial for another programming technique using dllimport/dllexport.

The above solution consists of two VC++ projects and one VC# project.

  • The first VC++ project is a Win32 Console Application project that contains three files — header.hbody.cpp, and main.cpp. Functions and variables to be called by C# are written as class’s methods and class’s variables inside header.h and body.cpp; this is done in conventional C++ class styles and there is no extern “c” __declspec keyword yet. Finally, main.cpp is used for testing correctness of the created class.
  • The second VC++ project is a Win32 project (Application type: DLL, Additional options: Empty project) that consists of a single file named main.cpp (no main() function). In main.cppheader.h and body.cpp from the first VC++ project are included at the top and a wrapper function (for those function required by C#) is written underneath with extern “c” __declspec(dllexport) keyword.
  • The VC# project is the simplest one. It uses dllimport to call the wrapper function from the second VC++ project. So, C# can indirectly use functions written in the first VC++ project.

  • Nguồn https://drthitirat.wordpress.com/
10/22/2020 10:00:47 PM