| [ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )] public String versionString; } |
此例中用到MashalAs特性,它用于描述字段、方法或参数的封送处理格式。用它作为参数前缀并指定目标需要的数据类型。例如,以下代码将两个参数作为数据类型长指针封送给 Windows API 函数的字符串 (LPStr):
| [MarshalAs(UnmanagedType.LPStr)] String existingfile; [MarshalAs(UnmanagedType.LPStr)] String newfile; |
注意结构作为参数时候,一般前面要加上ref修饰符,否则会出现错误:对象的引用没有指定对象的实例。
| [ DllImport( "kernel32", EntryPoint="GetVersionEx" )] public static extern bool GetVersionEx2( ref OSVersionInfo2 osvi ); |
三、如何保证使用托管对象的平台调用成功? 如果在调用平台 invoke 后的任何位置都未引用托管对象,则垃圾回收器可能将完成该托管对象。这将释放资源并使句柄无效,从而导致平台invoke 调用失败。用 HandleRef 包装句柄可保证在平台 invoke 调用完成前,不对托管对象进行垃圾回收。 例如下面:
| FileStream fs = new FileStream( "a.txt", FileMode.Open ); StringBuilder buffer = new StringBuilder( 5 ); int read = 0; ReadFile(fs.Handle, buffer, 5, out read, 0 ); //调用Win API中的ReadFile函数 |
由于fs是托管对象,所以有可能在平台调用还未完成时候被垃圾回收站回收。将文件流的句柄用HandleRef包装后,就能避免被垃圾站回收:
| [ DllImport( "Kernel32.dll" )] public static extern bool ReadFile( HandleRef hndRef, StringBuilder buffer, int numberOfBytesToRead, out int numberOfBytesRead, ref Overlapped flag ); ...... ...... FileStream fs = new FileStream( "HandleRef.txt", FileMode.Open ); HandleRef hr = new HandleRef( fs, fs.Handle ); StringBuilder buffer = new StringBuilder( 5 ); int read = 0; // platform invoke will hold reference to HandleRef until call ends ReadFile( hr, buffer, 5, out read, 0 ); |
|