C # dynamic calling of DLL functions written in C ++

Source: Internet
Author: User

Dynamic DLL loading requires the use of Windows API functions: LoadLibrary, GetProcAddress, and FreeLibrary. We can use these three functions in C # using DllImport.

[DllImport ("Kernel32")]
Public static extern int GetProcAddress (int handle, String funcname );

[DllImport ("Kernel32")]
Public static extern int LoadLibrary (String funcname );

[DllImport ("Kernel32")]
Public static extern int FreeLibrary (int handle );

When we dynamically call functions in Dll in C ++, the general method is:
Assume that the DLL contains an export function. The function prototype is as follows:
BOOL _ stdcall foo (Object & object, LPVOID lpReserved );

1. First define the corresponding function pointer:
Typedef BOOL (_ stdcall * PFOO) (Object & object, LPVOID lpReserved );

2. Call LoadLibrary to load dll:
HINSTANCE hInst =: LoadLibraryW (dllFileName );

3. Call the GetProcAddress function to obtain the address of the function to be called:
PFOO foo = (PFOO) GetProcAddress (hInst, "foo ");
If (foo = NULL)
{
FreeLibrary (hInst );
Return false;
}

4. Call the foo function:
BOOL bRet = foo (object, (LPVOID) NULL );

5. Release the DLL after use:
FreeLibrary (hInst );

So what should I do in C? The method is basically the same. We use a delegate to replace the function pointer of C ++, and use the new function GetDelegateForFunctionPointer of. NET Framework 2.0 to get an instance of delegation:

The following encapsulates a class, through which we can dynamically call functions in Dll in C:

Public class DLLWrapper
{
/// <Summary>
/// API LoadLibrary
/// </Summary>
[DllImport ("Kernel32")]
Public static extern int LoadLibrary (String funcname );

/// <Summary>
/// API GetProcAddress
/// </Summary>
[DllImport ("Kernel32")]
Public static extern int GetProcAddress (int handle, String funcname );

/// <Summary>
/// API FreeLibrary
/// </Summary>
[DllImport ("Kernel32")]
Public static extern int FreeLibrary (int handle );

/// <Summary>
/// Use an unmanaged function name to convert to the corresponding delegate, by jingzhongrong
/// </Summary>
/// <Param name = "dllModule"> DLL handle obtained through LoadLibrary </param>
/// <Param name = "functionName"> unmanaged function name </param>
/// <Param name = "t"> delegate type </param>
/// <Returns> delegate instance, which can be forcibly converted to an appropriate delegate type </returns>
Public static Delegate GetFunctionAddress (int dllModule, string functionName, Type t)
{
Int address = GetProcAddress (dllModule, functionName );
If (address = 0)
Return null;
Else
Return Marshal. GetDelegateForFunctionPointer (new IntPtr (address), t );
}

/// <Summary>
/// Convert the IntPtr instance indicating the function address to the corresponding delegate, by jingzhongrong
/// </Summary>
Public static Delegate GetDelegateFromIntPtr (IntPtr address, Type t)
{
If (address = IntPtr. Zero)
Return null;
Else
Return Marshal. GetDelegateForFunctionPointer (address, t );
}

/// <Summary>
/// Convert the int representing the function address to the corresponding delegate, by jingzhongrong
/// </Summary>
Public static Delegate GetDelegateFromIntPtr (int address, Type t)
{
If (address = 0)
Return null;
Else
Return Marshal. GetDelegateForFunctionPointer (new IntPtr (address), t );
}
}

Through this class, we call the DLL as follows:

1. Declare the relevant delegate (correct declaration is very important; otherwise, the call cannot be successful, which will be detailed later ).

2. Load DLL:
Int hModule = DLLWrapper. LoadLibrary (dllFilePath );
If (hModule = 0)
Return false;

3. obtain the corresponding delegated instance:
FOO foo = (FOO) DLLWrapper. GetFunctionAddress (hModule, "foo", typeof (FOO ));
If (foo = null)
{
DLLWrapper. FreeLibrary (hModule );
Return false;
}

4. Call a function:
Foo (...);

5... NET does not automatically release the Dynamically Loaded DLL. Therefore, we should release the DLL after using it:
DLLWrapper. FreeLibrary (hModule );

Next, we will discuss how the delegation should be declared. in the actual operation process, I found that the declaration of the function prototype in DLL in C # by using the DllImport method and the dynamic call method is somewhat different. Next I will introduce the declaration of delegation in the dynamic call:

1. The first thing to note is the correspondence between types in C ++ and types in C #. For example, long in C ++ should correspond to Int32 in C # Instead of long, otherwise, an error occurs in the call result.

2. The structure Declaration uses StructLayout to set the corresponding layout of the structure. For details, see MSDN:

Use LayoutKind to specify the layout sequence of members in the structure. Generally, you can use Sequential:
[StructLayout (LayoutKind. Sequential)]
Struct StructVersionInfo
{
Public int MajorVersion;
Public int MinorVersion;
}
In addition, if the internal type is used separately without strings, structures, and classes, you can declare the structure in C # As class:
[StructLayout (LayoutKind. Sequential)]
Class StructVersionInfo
{
Public int MajorVersion;
Public int MinorVersion;
}

Corresponds to the statement in C ++:
Typedef struct _ VERSION_INFO
{
Int MajorVersion;
Int MinorVersion;
} VERSION_INFO, * PVERSION_INFO;

If strings are used in the structure, it is best to specify the corresponding character set:
[StructLayout (LayoutKind. Sequential, CharSet = CharSet. Unicode)]

Some commonly used declarative mappings (in the structure ):
C ++: String Array
Wchar_t Comments [1, 120];
C #:
[Financialas (UnmanagedType. ByValTStr, SizeConst = 120)]
Public string Comments;

C ++: structure member
VERSION_INFO ver;
C #
PublicStructVersionInfo ver;

C ++: function pointer Declaration
PFOO pFoo; // For more information, see the previous section.
C #:
PublicIntPtr pFoo; // It can also be public int pFoo;
// You can use the corresponding functions of the preceding DLLWrapper class to obtain the corresponding delegate instance for different declaration methods.

If union is used in the structure, FieldOffset can be used to specify the specific position.

3. Delegate statement:

When a DLL function written in C ++ needs to pass out a structure through the pointer: See the following statement:
Void getVersionInfo (VERSION_INFO * ver );
For the structure declared as class in C # (when VERSION_INFO is declared as class)
Delegate voidgetVersionInfo (VERSION_INFO ver );
If the structure declaration is struct, use the following statement:
Delegate voidgetVersionInfo (refVERSION_INFO ver );
Note: The ref keyword should be used.


If the DLL function needs to input a string, for example:
BOOL _ stdcall jingzhongrong1 (const wchar_t * lpFileName, int * FileNum );
When using delegation to call a function, you should declare the delegate in C # as follows:
Delegate bool jingzhongrong1 (
[Financialas (UnmanagedType. LPWStr)] String FileName,
Ref int FileNum );
Note: You should use [financialas (UnmanagedType. LPWStr)] and String for declaration.


If you want to output a string in the DLL function, for example:
Void _ stdcall jingzhongrong2 (
Wchar_t * lpFileName, // string to be passed out
Int * Length );
We hereby declare the Commission as follows:
// Use the string that is passed out from the parameter of the unmanaged function by Delegate,
// Declare it like this and prepare enough space for StringBuilder before calling it
Delegate void jingzhongrong2 (
[Financialas (UnmanagedType. LPWStr)] StringBuilder lpFileName,
Ref int Length,
);
Before using a function, declare sufficient space for StringBuilder to store strings:
StringBuilder fileName = new StringBuilder (FileNameLength );

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.