穿梭于丛林之间  
一个热爱设计的孩纸,有着程序猿的情节,干着穿山越岭工作。

C# 调用传统的 API 动态链接库,是.NET开发经常被讨论的问题。

比如有这么一个动态链接库(delphi 语言):

library DelphiDLL;

 1 uses
 2 SysUtils,
 3 Classes,
 4 Windows;
 5 
 6 {$R *.res}
 7 
 8 function TestMyFunction( a: Integer ): Integer; stdcall;
 9 begin
10 Result := a * a;
11 end;
12 
13 exports
14 TestMyFunction;
15 
16 begin
17 end.

在C#中调用这个动态链接库的一般方法是:

1 class DllStatic
2 {
3    [DllImport( "DelphiDLL.dll" )]
4   public static extern int TestMyFunction( int a );
5 }

但这种方法类似传统语言对动态链接库的“静态调用”(如 delphi 中的 external )。这种静态调用,有的时候并不是我们想要的。

在传统语言中,我们可以用 LoadLibrary、GetProcAddress 来替代上面的方法。

1.   Loadlibrary: 装载指定DLL动态库

2.   GetProcAddress:获得函数的入口地址

3.   Freelibrary: 从内存中卸载动态库

经过思考的试验,在C#中,也可以使用这种方法来实现。

 1 class DllDynamic
 2 {
 3 [DllImport( "Kernel32.dll" )]
 4   public static extern int LoadLibrary( string lpFileName );
 5 
 6    [DllImport( "Kernel32.dll" )]
 7   public static extern bool FreeLibrary( int hModule );
 8 
 9 [DllImport( "Kernel32.dll" )]
10   public static extern IntPtr GetProcAddress( int hModule, string lpProcName );
11 }
12 
13 class Program
14 {
15   public delegate int TestMyFunction( int a );
16 
17   static void Main( string[] args )
18    {   
19     int hLib = DllDynamic.LoadLibrary( "DelphiDLL.dll" );
20     try
21     {
22       IntPtr ptr = DllDynamic.GetProcAddress( hLib, "TestMyFunction" );
23       TestMyFunction myfunc = (TestMyFunction) Marshal.GetDelegateForFunctionPointer( ptr, typeof( TestMyFunction ) );
24 
25       for (int i = 0; i < 10; i++ )
26       {
27         Console.WriteLine( myfunc( i ) );
28       }
29     }
30     finally
31     {
32       DllDynamic.FreeLibrary( hLib );
33     }
34 }
35 }

其中,对 GetProcAddress 的结果做何处理,是尝试多次的焦点问题。查找若干资料,终于发现 Marshal 类中的静态方法可以进行内存地址到函数托管的封存转换。

Marshal.GetDelegateForFunctionPointer( ptr, typeof( TestMyFunction ) );这句即是将非托管函数指针转换为委托。

posted on 2014-11-21 09:23  perrychum  阅读(189)  评论(0)    收藏  举报