Analysis on Calling C ++ DLL in C # (1) -- generate an unmanaged dll

Source: Internet
Author: User


After one night of hard work, I decided to write down some of my experiences to avoid repeated work in the future.


C # compared with C/C ++, the advantage of the former lies in the UI, and the advantage of the latter lies in the algorithm. Although the pointer in C ++ is disgusting, it is quite convenient to use it properly, the most important issue is that many popular development tool libraries on the market almost do not support C ++, but it is rare to fully support C #. As the CPU has grown to today, if the execution efficiency of C # is significantly different from that of C ++, it is not so reliable. If it is not a last resort, I would rather use C # To write code and debug anything conveniently.


If you have to use C ++ functions or classes in C #, the best way is to use dynamic link library dll ), as for what COM is, I haven't figured out its principle yet, maybe it's mainly because it's too troublesome to register something). If you use dll, you can easily break down a project into two parts, collaborative programming can accelerate progress. Of course, it is not impossible to rewrite the Code with C #. But if you have tens of thousands of lines of code that are ready-made, it is really a headache. Please feel at ease using the dynamic link library.


When you open VS2012 and create a project, you may find that there is a "CLR class library" project type, which is not known until today, CLR originally referred to hosting C ++. Hosting C ++ has a certain relationship with unmanaged C ++, however, many prefer to regard them as two different programming languages. Hosting C ++ is a very spoof, its only function is to write C # content with a C ++ vest, and ultimately serves C, the dll generated by CLR can be referenced directly under C #. It is easier to use C # directly than to use CLR ).


This is the most common technique. The materials on the Internet are a large ticket. But to make me forget my head, I 'd better explain it step by step. Based on my overnight achievements, it is finally proved that it is impossible to import classes in native C ++, so the following is only about how to import functions-just as you have seen on the Internet.


1) create a dll Generation Project


I use VS2012, but it seems that there is no big difference with the previous version. Open VS and select "new project"-"VC ++"-"Win32"-"Win32 Project". The project name is "MyNativeDll". The configuration is shown in, because I may use the MFC class, I checked the "MFC" option. Note that if you did not select the "MFC" option when creating the project, however, if you want to use the content of MFC later, you will encounter"MFC apps must not # include <windows. h>"Error, but modification in the project configuration is useless at all, must be done to re-build the project.


650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/161I0F94-0.jpg "title =" 1.jpg"/>


2) dll export Function


After creating a project, you can see the directory as shown in solution Resource Manager of VS. In fact, you do not need to worry about these default files. If you want to use it, you can check MyNativeDll. the description in h is probably understandable.


650) this. width = 650; "src =" http://www.bkjia.com/uploads/allimg/131228/161I03621-1.jpg "title =" 2.jpg"/>


Add several files in the project: Define. h, CFunction. h, CFunction. cpp. The content is as follows:


// Define. h is used to import the macro definition of dll.

//Define.h
///////////////////////////////////////////
//////////////////////////////////////////
#ifndef _DEFINE_H_
#define _DEFINE_H_
#define _EXTERN_C_ extern "C" _declspec (dllexport)
#endif


//CFunction.h function definition, here I specifically define a set of structures, my intention will be described later.

//CFunction.h
////////////////////////////////////////////
///////////////////////////////////////////
#ifndef _C_FUNCTION_H_
#define _C_FUNCTION_H_
#include "Define.h"
#include <string>
#include <istream>
struct SystemTime
{
    int year;
    int month;
    int day;
    int hour;
    int minute;
    int second;
    int millsecond;
    SystemTime & operator = (SystemTime st)
    {
        this-> year = st.year;
        this-> month = st.month;
        this-> day = st.day;
        this-> hour = st.hour;
        this-> minute = st.minute;
        this-> second = st.second;
        this-> millsecond = st.millsecond;
        return * this;
    }
};
_EXTERN_C_ int add (int x, int y);
_EXTERN_C_ int sub (int x, int y);
_EXTERN_C_ int testChar (char * src, char * res, int nCount);
_EXTERN_C_ int testStruct (SystemTime & stSrc, SystemTime & stRes);
#endif // _ C_FUNCTION_H_


// The implementation of CFunction.cpp dll function is just a simple assignment, everyone should understand it.

//CFunction.cpp
////////////////////////////////////////////
////////////////////////////////////////////
#include "stdafx.h"
#include "CFunction.h"
#include <stdio.h>
int add (int x, int y)
{
    return x + y;
}
int sub (int x, int y)
{
    return x-y;
}
int testChar (char * src, char * res, int nCount)
{
    memcpy (res, src, sizeof (char) * nCount);
    return 1;
}
int testStruct (SystemTime & stSrc, SystemTime & stRes)
{
    stRes = stSrc;
    return 1;
}


After adding the code, select the "Generate" option, because the Debug file in the project directory already exists the MyNativeDll.dll file we need, along with the static library file of lib to be used later), and others Related debugging files, so far, we have successfully generated the native C ++ dynamic link library, I can only say that this is a fairly simple first step.



3) Use the generated dll under C # project



I personally hate the console program for creating a new C # window project. The project is named "DllTest", so I won't teach it.



Add a CFunction.cs class in the newly created form project. This class is mainly used to export the functions in the above dll. Without further ado, just paste the code directly:



//CFunction.cs dll function interface

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace DllTest
{
    [StructLayout (LayoutKind.Sequential)]
    public struct SystemTime
    {
        public int year;
        public int month;
        public int day;
        public int hour;
        public int minute;
        public int second;
        public int millsecond;
        public SystemTime (DateTime dt)
        {
            this.year = dt.Year;
            this.month = dt.Month;
            this.day = dt.Day;
            this.hour = dt.Hour;
            this.minute = dt.Minute;
            this.second = dt.Second;
            this.millsecond = dt.Millisecond;
        }
        public override string ToString ()
        {
            return this.year.ToString () + "-" + this.month.ToString () + "-" + this.day.ToString () + ""
                + this.hour.ToString () + ":" + this.minute.ToString () + "-" + this.second.ToString () + "-"
                + this.millsecond.ToString ();
        }
    };
    public class CFunction
    {
        [DllImport ("MyNativeDll.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public extern static int add (int x, int y);
        [DllImport ("MyNativeDll.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public extern static int sub (int x, int y);
        [DllImport ("MyNativeDll.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public extern static int testChar (ref byte src, ref byte res, int nCount);
        [DllImport ("MyNativeDll.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public extern static int testStruct (ref SystemTime stSrc, ref SystemTime stRes);
    }
}
The format of the code above does not look good. Everyone is optimistic about the file in the attachment. The above method is quite a static CFunction class. Then write the test code directly in the Form1.cs form, I wrote directly in the initialization function of Form1, lazy, no way.



//Form1.cs add test code in C # form initialization function

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DllTest
{
    public partial class Form1: Form
    {
        public Form1 ()
        {
            InitializeComponent ();
            int a = CFunction.add (100, 50);
            int b = CFunction.sub (100, 50);
            Debug.WriteLine ("add =" + a.ToString () + "b =" + b.ToString ());
            Debug.WriteLine ("\ r \ n");
            string src = "123456";
            byte [] srcBytes = System.Text.Encoding.ASCII.GetBytes (src);
            byte [] resBytes = new byte [100];
            a = CFunction.testChar (ref srcBytes [0], ref resBytes [0], src.Length);
            string res = (System.Text.Encoding.ASCII.GetString (resBytes, 0, resBytes.Length)). TrimEnd ();
            Debug.WriteLine (res.ToString ());
            Debug.WriteLine ("\ r \ n");
            SystemTime stSrc = new SystemTime (DateTime.Now);
            SystemTime stRes = new SystemTime ();
a = CFunction.testStruct (ref stSrc, ref stRes);
            Debug.WriteLine (stRes.ToString ());
            Debug.WriteLine ("\ r \ n");
        }
    }
}


Before you debug, be sure to copy the MyNativeDll.dll generated in the second step to the bin \ Debug \ directory of the C # project, and then click "Debug" to see the output window, there should be something output, I It will not be posted.



4) Summary



1) In general, it is not very difficult to generate a native C ++ dll, the focus is on the dll export function under C #;



2) According to personal experience, using native C ++ can import functions. As for exporting C ++ classes, it is not impossible to use pointers, but the method is too complicated, it is recommended not to do so;



3) When writing dll export functions, the transfer of variables is the key. It is recommended to use the basic types of C ++, such as int, float, double, etc., because the concept of pointers under C # is very tangled. C # uses the ref logo. One thing to keep in mind is that the types of C # and C ++ are not completely general structure alignment issues), pay attention to making changes. Like the testChar function above, the original string (C #) corresponds to char * (C ++), but due to various Unicode or multi-byte relationships, I ca n’t return the correct value, so I used the byte input Types of. Regarding the type of C # and C ++ mixed, you can check the following articles: C ++ and C # type conversion, article 2, article 3, it is not easy to find good articles on the Internet.



4) Observe the structure I wrote. The structure used in C ++ must be redefined in C #. Use the [StructLayout (LayoutKind.Sequential)] logo for the alignment of the structure. If you use string like this in your variable Type, you also need to use the method of MarshalAs to define its length-it can correspond to char *;



5) Don't use any string for the return value of the function. I found the method to get the correct return value. It is best to use the ref method to return it.



6) The transfer of pointer parameters uses the IntPtr type for conversion under C #. I will not elaborate first. There are still many related articles on the Internet.



5) Download of sample files



This article is from the blog "A few wisps of rain and lock clearing autumn", please be sure to keep this source http://joeyliu.blog.51cto.com/3647812/1289614

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.