Managed/Unmanaged Code Interoperability

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 ................................................................................................................................................... 1
1. 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:

  1. extern "C"
  2. {
  3.     __declspec(dllexportint test(int a,int b);
  4. }

And then write the function body in the .cpp file like:

  1. int test(int a,int b)
  2. {
  3.        return a+b;
  4. }

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:

  1. [DllImport("MyDll.dll", EntryPoint = "test",PreserveSig=true)]
  2. public static extern int test1(int a,int b);
The parameter *EntryPoint* is exactly the function name you declare in C++ header file. You can self define the extern method name in C#.

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:

  1. [DllImport("kernel32.dll")]
  2. public static extern IntPtr LoadLibrary(string lpFileName);
  3. [DllImport("kernel32.dll")]
  4. public static extern IntPtr FreeLibrary(IntPtr library);

Declaration of your functions from C++ DLL:

  1. [DllImport("MyDll.dll", EntryPoint = "test",PreserveSig=true)]
  2. public static extern int test1(int a,int b);

Loading DLL:

  1. string dllpath = Configuration.AacTagDll;
  2. IntPtr aaclib = LoadLibrary(dllpath);
  3. if (aaclib == IntPtr.Zero)
  4. {
  5.     throw new CustomException("Local My.dll failed, path=" + dllpath);
  6. }

Now you can call it:

And after you did what you wanted, don't forget to free it:

  1. if (handle != IntPtr.Zero)
  2. {
  3.            FreeLibrary(handle);
  4.            FreeLibrary(handle);
  5. }

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.

  1. VOID EXEFunc() {
  2.    PVOID pv = DLLFunc();
  3.    // Access the storage pointed to by pv...
  4.    // Makes no assumptions about C/C++ run-time heap
  5.    DLLFreeFunc(pv);
  6. }
  7. PVOID DLLFunc() {
  8.    // Allocate block from DLL's C/C++ run-time heap
  9.    PVOID pv = malloc(100);
  10.    return(pv);
  11. }
  12. BOOL DLLFreeFunc(PVOID pv) {
  13.    // Free block from DLL's C/C++ run-time heap
  14.    return(free(pv));
  15. }

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

 


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值