Calling unmanaged C + + generated DLL files on VS2010 using C #

Source: Internet
Author: User

Background

During the project, sometimes you need to invoke DLL files that are not written in C #, especially when using some third-party communication components, when developing applications through C #, you need to use the DllImport feature to make method calls. This article will guide you through the process of making this call fast.

Steps

1. Create a csharpinvokecpp solution:

2. Create a C + + Dynamic Library project:

3. In the application settings, select "DLL" and others follow the default options:

Finally click Finish to get the project:

We can see that there are some files here, where dllmain.cpp as the entry point for defining the DLL application, and its function is the same as the EXE file has a main or WinMain entry function, it is a DLL as an entry function, in fact, it is an optional file. It is called when a static link or dynamic link calls LoadLibrary and FreeLibrary. For more information, refer to (http://blog.csdn.net/benkaoya/archive/2008/06/02/2504781.aspx).

4. Now we open the CSharpInvokeCPP.CPPDemo.cpp file:

Now let's add the following:

Csharpinvokecpp_cppdemo.cpp: Defines an export function for a DLL application. #include "stdafx.h" extern "C" __declspec (dllexport) int Add (int x, int y) {return x + y;} extern "C" __declspec (dllexport) int Sub (int x, int y) {return x-y;} extern "C" __declspec (dllexport) int Multiply (int x, int y) {return x * y;} extern "C" __declspec (dllexport) int Divide (int x, int y) {return x/y;}

  

extern "C" contains a double meaning, literally: First, the object it modifies is "extern", and secondly, the target it modifies is "C". The variables and functions modified by extern "C" are compiled and concatenated in the C language way.

The purpose of __declspec (dllexport) is to put the corresponding function into the DLL dynamic library.

The extern "C" __declspec (dllexport) is added in order to invoke DLL files of unmanaged C + + using DllImport. Because using DllImport, you can only invoke DLLs made from C-language functions.

5. Compile the project program and finally generate CSharpInvokeCPP.CPPDemo.dll and CSharpInvokeCPP.CPPDemo.lib in the debug directory

It can be found that these four kinds of "subtraction" methods are included in external public functions.

6. Now to demonstrate how to use a C # project to invoke an unmanaged C + + DLL, first create a C # Console application:

7. Create a new Cppdll class on the Csharpinvokecsharp.csharpdemo project and write the following code:

public class Cppdll    {        [DllImport ("Csharpinvokecpp_cppdemo.dll", CallingConvention = callingconvention.cdecl )] public        static extern int Add (int x, int y);        [DllImport ("Csharpinvokecpp_cppdemo.dll", CallingConvention = callingconvention.cdecl)]        public static extern int Sub (int x, int y);        [DllImport ("Csharpinvokecpp_cppdemo.dll", CallingConvention = callingconvention.cdecl)]        public static extern int Multiply (int x, int y);        [DllImport ("Csharpinvokecpp_cppdemo.dll", CallingConvention = callingconvention.cdecl)]        public static extern int Divide (int x, int y);    }

DllImport is used as the import entry feature for C + + DLL classes in C # and corresponds to extern "C" through static extern. Where CallingConvention is the invocation of the declared function, which is to determine the order in which the function parameters are in the stack.

8. Also, remember to copy the DLL files generated in the Cppdemo to the Csharpdemo bin\debug or bin\release directory. In addition, if you have been copying trouble, you can also set the project properties of the DLL project, the output directory in the general of the configuration properties, project properties, and so on:

In this way, each recompiled DLL file is automatically output to the directory of the C # project that uses it.

9. Then write the test code in the main portal of the Test class in C #:

static void Main (string[] args) {int result = Cppdll.    ADD (10, 20);     Console.WriteLine ("Ten + = {0}", result); result = Cppdll.    Sub (30, 12);     Console.WriteLine ("30-12 = {0}", result); result = Cppdll.    Multiply (5, 4);     Console.WriteLine ("5 * 4 = {0}", result); result = Cppdll.    Divide (30, 5);     Console.WriteLine ("30/5 = {0}", result); Console.ReadLine ();}

Test the result of the code run:

10. The above method can only be called by a static method for a function in C + +. So how do you invoke a method in a class object in C + + with a static method? Now I add a header file to the Cppdemo project userinfo.h:

Class UserInfo {private:char* m_name;        int M_age;public:userinfo (char* name, int age) {m_name = name;    M_age = age;    } virtual ~userinfo () {} int getage () {return m_age;} char* GetName () {return m_name;}};

In CSharpInvokeCPP.CPPDemo.cpp, add some code:

#include <malloc.h> #include "userinfo.h" typedef struct{char NAME[32];INT Age;} User; UserInfo *userinfo;extern "C" __declspec (dllexport) user* Create (char *name, int age) {User *user = (user *) malloc (sizeof (U Ser)); userInfo = new UserInfo (name, age); strcpy (User->name, Userinfo->getname ()); user->age = userinfo-> Getage (); return user;}

  

This declares a structure, including name and age, that is used to map the structure of the C # aspect.

Note: user* in the code is a pointer, and returning is also an object pointer, in order to prevent the release of local variables after the end of the method scope.

strcpy is a function that replicates a char array.

11. Supplement the code in the Cppdll class in the Csharpdemo project:

[DllImport ("CSharpInvokeCPP.CPPDemo.dll")]public static extern IntPtr Create (string name, int age); [StructLayout (layoutkind.sequential)]public struct user{    [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 32)] public    string Name;     public int age;}

Where the struct user corresponds to the user in C + +.

12. Supplement the code in Program.cs:

IntPtr ptr = cppdll.create ("Stemon", 26); Cppdll.user User = (cppdll.user) System.Runtime.InteropServices.Marshal.PtrToStructure (PTR, typeof (Cppdll.user)); Console.WriteLine ("Name: {0}, Age: {1}", User.Name, User.age);

Here the structure pointer is first converted to a IntPtr handle and then converted to the structure you need by marshal.ptrtostructrue.

Attention:

In unmanaged code, if there is a class, the method used is the one above, the class is converted to the C language structure, because the DLL can only be C language. If the unmanaged class is a functional class, then the struct is not used, and some functions of the C language directly call the member functions of the unmanaged class, that is, the C language function as a DLL external interface, there are C language interface functions to invoke the function of unmanaged code. But to instantiate an object of a class with an init () function before invoking another function. (Of course, if all of the member functions are static, then you do not use the instance object, directly using the class call function.) )

PtrToStructure This function

Marshal.PtrToStructure method (IntPtr, type) PTR type: System.IntPtr    Pointer to an unmanaged block of memory. Structuretype type: System.Type    the type of object to be created. This object must represent a formatted class or struct. Return value type: System.Object    a managed object that contains the data that the PTR parameter points to.

Marshals data from an unmanaged block of memory to a newly assigned managed object of the specified type.

Using system;using system.runtime.interopservices;public struct point{public int x; public int y;}        Class example{static void Main () {//Create a point struct.        Point P;        p.x = 1;        P.Y = 1;        Console.WriteLine ("The value of First point is" + p.x + "and" + P.y + ".");        Initialize unmanged memory to hold the struct.        IntPtr PNT = Marshal.allochglobal (marshal.sizeof (p));            try {//Copy the struct to unmanaged memory.            Marshal.structuretoptr (P, PNT, false);            Create another point.            Point Anotherp;             Set This is the value of the//point in unmanaged memory.            Anotherp = (point) marshal.ptrtostructure (PNT, typeof (Point));        Console.WriteLine ("The value of new point is" + anotherp.x + "and" + Anotherp.y + ".");            finally {//Free the unmanaged memory.       Marshal.freehglobal (PNT); }    }} 

  

Calling unmanaged C + + generated DLL files on VS2010 using C #

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.