C # Call the DLL compiled by C ++

Source: Internet
Author: User
Tags button attributes emit

The methods for calling DLL in each programming language are different. Here we will only introduce the methods for calling DLL with C. First, you need to know what is managed and what is not managed. It is generally considered that the unmanaged code is mainly developed based on the DLL and ActiveX Components developed on the Win 32 platform, and the managed code is developed based on the. NET platform. If you want to learn more about the relationship and differences between hosting and non-hosting, and their operating mechanism, please search for information on your own. This document will not be discussed here.
(1) General method for calling unmanaged functions in DLL

First, the external method should be declared in the C # language source program. The basic form is:

[Dllimport ("DLL file")]

Modifier extern return variable type method name (parameter list)

Where:

DLL file: contains the library file that defines external methods.
Modifier: access modifier, which can be used in addition to abstract when declaring a method.
Return variable type: In the DLL file, you need to call the return variable type of the method.
Method Name: name of the method to be called in the DLL file.
Parameter List: list of methods to be called in the DLL file.

Note: The system. runtime. interopservices namespace must be used in the program declaration.

Dllimport can only be placed on method declaration.

The DLL file must be located in the current program directory or the system-defined query path (that is, the path set by path in the system environment variable ).
The returned variable type, method name, and parameter list must be consistent with the definition in the DLL file.
To use other function names, you can use the entrypoint attribute settings, such:

[Dllimport ("user32.dll", entrypoint = "messageboxa")]
Static extern int msgbox (INT hwnd, string MSG, string caption, int type );

Other optional dllimportattribute attributes:

Charset indicates the character set used in the entry point, for example, charset = charset. ANSI;

Setlasterror indicates whether the method retains Win32 "previous error", for example, setlasterror = true;

Exactspelling indicates whether entrypoint must exactly match the spelling of the indicated entry point, for example, exactspelling = false;

Preservesig indicates whether the method signature should be retained or converted, for example, preservesig = true;

Callingconvention indicates the call convention of the entry point, for example: callingconvention = callingconvention. winapi;

For more information about "data sending and writing" and "sending numbers and logical scalar", see [2].

C # example:

1. Start vs. NET and create a new project named "TZB". The template is "Windows application ".

2. Double-click the "button" item in the "Windows Forms" item in the "toolbox" to add a button to the "form1" form.

3. Change the button attributes: name is "B1", text is "use dllimport To Call DLL to bring up a prompt box", and adjust the button B1 to the appropriate size and move it to the appropriate position.

4. double-click "form1" in the Class View, open the "form1.cs" Code view, and enter "using system" on "namespace TZB. runtime. interopservices; "to import the namespace.

5. in the "form1.cs [design]" view, double-click the button B1, use the keyword static and extern to declare the method "msgbox" on the "b1_click" method, and append the dllimport attribute to this method, here we will use the "messageboxa" function in "user32.dll". The specific code is as follows:

[Dllimport ("user32.dll", entrypoint = "messageboxa")]
Static extern int msgbox (INT hwnd, string MSG, string caption, int type );

Then add the following code in the "b1_click" method to call the method "msgbox ":

Msgbox (0, "this is the prompt box for calling DLL with dllimport! "," Mug ", 0x30 );

6. Press F5 to run the program and click B1. The following prompt box is displayed:

(2) Dynamic Loading and calling of unmanaged functions in DLL

The preceding figure shows how to use dllimport to call the unmanaged function in DLL, but this is a global function. If the unmanaged function in dll has a static variable S, each time you call this function, the static variable s automatically adds 1. Results: When a new count is required, the expected results cannot be obtained. The following is an example:

1. Create DLL

1) Start visual c ++ 6.0;

2) create a "Win32 dynamic-Link Library" project named "count ";

3) on the "DLL kind" selection page, select "A simple DLL project ";

4) Open count. cpp and add the following code:

// Export the function, which is called using the _ stdcall standard.
Extern "C" _ declspec (dllexport) int _ stdcall count (INT init );
Int _ stdcall count (INT init)
{
// Count function, uses the init parameter to initialize the static integer variable S, and returns this value after s Auto-increment 1.
Static int S = Init;
S ++;
Return S;
}

5) Press "F7" to compile and get count. dll (in the debug folder under the project directory ).

2. Use dllimport to call the count function in DLL

1) Open the project "TZB" and add a button to the "form1" form.

2) Change the button attributes: name is "B2", text is "use dllimport to call the count function in DLL", and adjust the button B1 to the appropriate size and move it to the appropriate position.

3) Open the "form1.cs" Code view, use the static and extern keywords to declare the method "count", and enable it to implement the export function count from Count. dll. The Code is as follows:

[Dllimport ("count. dll")]
Static extern int count (INT init );

4) double-click the button B2 in the "form1.cs [design]" view and add the following code in the "b2_click" method:
MessageBox. show ("use dllimport to call the count function in DLL. The input value of N is 0, and the result is:" + count (0 ). tostring (), "Challenge Cup ");

MessageBox. show ("use dllimport to call the count function in DLL. The input value of N is 10. The result is:" + count (10 ). tostring () + "N is not the expected 11 !!! "," Challenge Cup ");

MessageBox. Show ("The result shows that nuse dllimport to call the unmanaged n function in DLL is a global and static function !!! "," Challenge Cup ");

5) copy count. DLL to the bindebug folder of the project "TZB", Press "F5" to run the program, and click "B2" to bring up the following three prompt boxes:

The 1st prompt boxes show the results of calling "count (0)", and the 2nd prompt boxes show the results of calling "count (10, the results show that "using dllimport to call the unmanaged functions in DLL is a global and static function ". Therefore, sometimes it cannot achieve our goal, so we need to use the method described below: C # dynamic call of functions in DLL.

3. C # dynamically call functions in DLL

Because the use of dllimport in C # is not like dynamic load/unload assembly, so you can only use API functions. In kernel32.dll, functions related to dynamic library calling include [3]:

① Loadlibrary (or afxloadlibrary of MFC) to load dynamic libraries.

② Getprocaddress: Get the function to be introduced and convert the symbol name or ID number to the internal DLL address.

③ Freelibrary (or afxfreelibrary of MFC) to release the dynamic link library.

Their prototypes are:

Hmodule loadlibrary (lpctstr lpfilename );
Farproc getprocaddress (hmodule, lpcwstr lpprocname );
Bool freelibrary (hmodule );

Now, we can use intptr hmodule = loadlibrary ("count. DLL); to obtain the DLL handle, use intptr farproc = getprocaddress (hmodule, "_ count @ 4"); to obtain the function entry address.

But how can I call this function after knowing the function entry address? Because there is no function pointer in C # and there is no function pointer call method like C ++ to call the function, we have to use other methods. After research, we found that we can achieve our goal by combining the classes and functions in system. reflection. emit and system. reflection. assembly. For future convenience and code reuse, we can write a class.

1) write the DLD class:

1. open the project "TZB", open the Class View, right-click "TZB", select "add" --> "class", and set the class name to "DLD ", that is, the start letter of each word in dynamic loading DLL.

2. Add the required namespace and declare the parameter transfer method enumeration:

Using system. runtime. interopservices; // This namespace is required for using dllimport
Using system. reflection; // This namespace is required for using the Assembly class
Using system. reflection. emit; // This namespace is required to use ilgenerator
// Add the following code declaration parameter transfer method enumeration on "Public class DlD:
/// <Summary>
/// Parameter transfer mode enumeration, byvalue indicates value transfer, byref indicates Address Transfer
/// </Summary>
Public Enum modepass
{
Byvalue = 0x0001,
Byref = 0x0002
}

3. Declare loadlibrary, getprocaddress, freelibrary, and private variables hmodule and farproc:

/// <Summary>
/// The prototype is hmodule loadlibrary (lpctstr lpfilename );
/// </Summary>
/// <Param name = "lpfilename"> DLL file name </param>
/// <Returns> handle of the function library module </returns>
[Dllimport ("kernel32.dll")]
Static extern intptr loadlibrary (string lpfilename );
/// <Summary>
/// The prototype is farproc getprocaddress (hmodule, lpcwstr lpprocname );
/// </Summary>
/// <Param name = "hmodule"> handle of the function library module to be called </param>
/// <Param name = "lpprocname"> name of the called function </param>
/// <Returns> function pointer </returns>
[Dllimport ("kernel32.dll")]
Static extern intptr getprocaddress (intptr hmodule, string lpprocname );
/// <Summary>
/// Prototype: bool freelibrary (hmodule );
/// </Summary>
/// <Param name = "hmodule"> handle of the function library module to be released </param>
/// <Returns> whether the specified dll has been released </returns>
[Dllimport ("Kernel32", entrypoint = "freelibrary", setlasterror = true)]
Static extern bool freelibrary (intptr hmodule );
/// <Summary>
/// Handle of the function library module returned by loadlibrary
/// </Summary>
Private intptr hmodule = intptr. zero;
/// <Summary>
/// Function pointer returned by getprocaddress
/// </Summary>
Private intptr farproc = intptr. zero;

4. added the loaddll method and reloaded this method for convenience during the call:

/// <Summary>
/// Load the DLL
/// </Summary>
/// <Param name = "lpfilename"> DLL file name </param>
Public void loaddll (string lpfilename)
{
Hmodule = loadlibrary (lpfilename );
If (hmodule = intptr. Zero)
Throw (new exception ("not found:" + lpfilename + "."));
}
// If you already have a DLL handle loaded, you can use the second version of the loaddll method:
Public void loaddll (intptr hmodule)
{
If (hmodule = intptr. Zero)
Throw (new exception ("the handle hmodule of the passed function library module is empty ."));
Hmodule = hmodule;
}

5. Add the loadfun method and reload this method for the convenience of calling. The code and comments of the method are as follows:

/// <Summary>
/// Obtain the function pointer
/// </Summary>
/// <Param name = "lpprocname"> name of the called function </param>
Public void loadfun (string lpprocname)
{
// If the handle of the function library module is empty, an exception is thrown.
If (hmodule = intptr. Zero)
Throw (new exception ("the handle of the function library module is empty. Make sure that the loaddll operation has been performed! "));
// Obtain the function pointer
Farproc = getprocaddress (hmodule, lpprocname );
// If the function pointer is used, an exception is thrown.
If (farproc = intptr. Zero)
Throw (new exception ("not found:" + lpprocname + "entry point of this function "));
}
/// <Summary>
/// Obtain the function pointer
/// </Summary>
/// <Param name = "lpfilename"> contains the DLL file name for the function to be called. </param>
/// <Param name = "lpprocname"> name of the called function </param>
Public void loadfun (string lpfilename, string lpprocname)
{
// Obtain the handle of the function library module
Hmodule = loadlibrary (lpfilename );
// If the handle of the function library module is empty, an exception is thrown.
If (hmodule = intptr. Zero)
Throw (new exception ("not found:" + lpfilename + "."));
// Obtain the function pointer
Farproc = getprocaddress (hmodule, lpprocname );
// If the function pointer is used, an exception is thrown.
If (farproc = intptr. Zero)
Throw (new exception ("not found:" + lpprocname + "entry point of this function "));
}

6. added the unloaddll and invoke methods, and the invoke method was also overloaded:

/// <Summary>
/// Uninstall the DLL
/// </Summary>
Public void unloaddll ()
{
Freelibrary (hmodule );
Hmodule = intptr. zero;
Farproc = intptr. zero;

}

Turn: http://hi.baidu.com/mweb/blog/item/da7dba641baecdfaf636541f.html

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.