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 ) );这句即是将非托管函数指针转换为委托。

浙公网安备 33010602011771号