Summary
This article is based on Paragallo's DownloadService Project. Invoking C++ Dynamic-link library from C# is used in it. The C++ dll runs on win32 platform which is unmanaged code. C# runs on .NET3.5 platform of IIS6.0(Actually it is .net 2.0, I think). This article will talk about how to invoke C++ dll from C#? how the memory will be managed of the dll? And how to release the unmanaged resource?
Table of Contents
Summary ................................................................................................................................................... 11. Invoke C++ Dynamic-link library from C# ........................................................................................... 1
1.1 Prepare Dll ...................................................................................................................................... 1
1.2 Invoke from C# ............................................................................................................................... 1
2. Memory Management of the DLL ......................................................................................................... 2
2.1 How the memory allocated ........................................................................................................... 2
2.2 Memory Operate in DLL ................................................................................................................. 3
Reference .................................................................................................................................................. 3
1. Invoke C++ Dynamic-link library from C#
1.1 Prepare Dll
This is easy. Declare the function in C++ header file like this:
- extern "C"
- {
- __declspec(dllexport) int test(int a,int b);
- }
And then write the function body in the .cpp file like:
- int test(int a,int b)
- {
- return a+b;
- }
It's ok now. You can bulid the C++ project and generate the dll. Remember to choose win2 platform if you are using Visual Studio 2008.
1.2 Invoke from C#
The needs using Namespace System.Runtime.InteropServices.
First we should import the method in Dll. Note the method must be declare by dllexport in the C++ header file.
Example code:
- [DllImport("MyDll.dll", EntryPoint = "test",PreserveSig=true)]
- public static extern int test1(int a,int b);
Second we should configure the path of dll. If you don't special the dll file path, you need to put it in the same folder with you program. But it's very flexible, you can special the dll path and load and free it dynamically in the code. We simply load DLL ahead using LoadLibrary. Once it's in memory, the system will not look around on disk and will simply use it. We free the DLL using FreeLibrary.
Example code:
Declaration of LoadLibrary:
- [DllImport("kernel32.dll")]
- public static extern IntPtr LoadLibrary(string lpFileName);
- [DllImport("kernel32.dll")]
- public static extern IntPtr FreeLibrary(IntPtr library);
Declaration of your functions from C++ DLL:
- [DllImport("MyDll.dll", EntryPoint = "test",PreserveSig=true)]
- public static extern int test1(int a,int b);
Loading DLL:
- string dllpath = Configuration.AacTagDll;
- IntPtr aaclib = LoadLibrary(dllpath);
- if (aaclib == IntPtr.Zero)
- {
- throw new CustomException("Local My.dll failed, path=" + dllpath);
- }
Now you can call it:
And after you did what you wanted, don't forget to free it:
- if (handle != IntPtr.Zero)
- {
- FreeLibrary(handle);
- FreeLibrary(handle);
- }
Note: DLLImport seems to increase refcount on the library just like LoadLibrary() does. Hence, it looks like you will need to call FreeLibrary() twice.
2. Memory Management of the DLL
2.1 How the memory allocated
The DLL don't have its own address space. It uses the application's address space. Before an application (or another DLL) can call functions in a DLL, the DLL's file image must be mapped into the calling process' address space. Once a DLL's file image is mapped into the calling process' address space, the DLL's functions are available to all the threads running within the process.
Once a DLL's file image is mapped into the calling process' address space, the DLL's functions are available to all the threads running within the process. In fact, the DLL loses almost all of its identity as a DLL: To the threads in the process, the DLL's code and data simply look like additional code and data that happen to be in the process' address space. When a thread calls a DLL function, the DLL function looks at the thread's stack to retrieve its passed parameters and uses the thread's stack for any local variables that it needs. In addition, any objects created by code in the DLL's functions are owned by the calling thread or process—a DLL never owns anything.
As you know, the global and static variables of an executable file are not shared between multiple running instances of the same executable. Global and static variables in a DLL are handled in exactly the same way. When one process maps a DLL image file into its address space, the system creates instances of the global and static data variables as well. But all thread in this process can read and write the global and static data.
If we new a thread and then load library inside this thread, although the dll is in memory, but another thread in same process can't access this thread's global and static data. Because the dll is loaded in thread's stack not process's address space.
2.2 Memory Operate in DLL
Allocate and free memory in dll.
- VOID EXEFunc() {
- PVOID pv = DLLFunc();
- // Access the storage pointed to by pv...
- // Makes no assumptions about C/C++ run-time heap
- DLLFreeFunc(pv);
- }
- PVOID DLLFunc() {
- // Allocate block from DLL's C/C++ run-time heap
- PVOID pv = malloc(100);
- return(pv);
- }
- BOOL DLLFreeFunc(PVOID pv) {
- // Free block from DLL's C/C++ run-time heap
- return(free(pv));
- }
This code is correct and will always work. When you write a module, don't forget that functions in other modules might not even be written in C/C++ and therefore might not use malloc and free for memory allocations. Be careful not to make these assumptions in your code. By the way, this same argument holds true for the C++ new and delete operators while calling malloc and free internally.
OK finished:)
Reference
1. Calling a DLL with C# (C Sharp) http://www.adp-gmbh.ch/csharp/call_dll.html
2. How to call C++ DLL from ASP.NET (C#) code? http://blogs.msdn.com/eldar/archive/2006/09/22/how-to-call-c-dll-from-asp-net-c-code.aspx
3. Dynamic-link library http://en.wikipedia.org/wiki/Dynamic-link_library#Memory_management
4. An Overview of Managed/Unmanaged Code Interoperability http://msdn.microsoft.com/en-us/library/ms973872.aspx
5. DLLs http://msdn.microsoft.com/en-us/library/1ez7dh12(VS.80).aspx
6. Windows via C/C++, Fifth Edition , Jeffrey Richter