6.10. 调用本地代码时,数据类型有什么限制?What are the limitations on marshalling types via P/Invoke?
返回值
只能是长度小于等于32位的类型
非浮点型not floating point
参数
Only support marshaling blittable types
blittable types -> same representation in memory in both managed and native
non-blittable -> memory transformation required
Since only blittable types, all objects are pinned and never copied
Exception: passing String ByVal in VB.NET
Implies that you can't marshal nested objects since this requires a memory transformation (non-blittable)
只能是长度小于等于32位的类型
值通过堆栈传递
例外:float32
参考(References)
Pass blittable reference types
把参考传递到值类型变量
这就是如何传递float32类型的值
可以传递值类型的数组
在本地代码中,您可以使用指针指向第一个对象,然后一个接一个地访问其他对象
String是特殊的,传递char数组 -> 不变的
StringBuilder是特殊的,传递char数组 -> 易变的 (需要单独传递长度)
注意:C# bool是8个比特位的,并且不等于Win32的BOOL
队列:编译器默认的队列 (4字节)
Marshal.GetLastWin32Error 支持 GetLastError() 语义
未支持的:
MarshalAs: no support for non-blittable types
StructLayout: 不能改变外观
Delegates(委托)
DateTime
Only support default calling convention
6.11. 调用GetLastError时,总是获得不定的代码?
尽量不要尝试调用Windows GetLastError() API,因为CLR调用本地代码时可能会改变last error的代码。取而代之的是,使用调用的返回值标记错误代码,再调用System.Runtime.InteropServices.Marshal.GetLastWin32Error()方法来获得错误代码。
using System.Runtime.InteropServices;
[DllImport("coredll.dll", SetLastError=true)]
int myFoo(...);
Foo(...)
{
int rc = myFoo(...);
if (rc == false)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "Foo failed");
}
}
6.12. 调用本地代码时,有没有参数数量的限制?
有限制。.net精简框架版本1.0的限制为12个。
6.13. 调用本地代码时,为什么得到"NotSupportedException"异常?
通常有三种可能性:
在托管代码中的申明不正确
.net精简框架不支持你想做的操作
dll的名称在暴露过程中损坏了
检查以下项目:
有没有违反.net精简框架 P/Invoke(调用)的限制?
有没有参数需要预先分配内存(如,是不是指针)? 如果是的,您应该传递已经存在的变量的参考。
暴露的函数名是否正确? 可以用DUMPBIN.EXE工具来验证
是不是想尝试太多的参数?
例如,针对上面的第二点,RegOpenKey API的最后一个参数HKEY的指针。您应该这样申明和调用: //C#
[DllImport("coredll.dll", SetLastError=true)]
public static extern long RegOpenKey(
IntPtr hkey,
string lpSubKey,
ref IntPtr hkeyResult
);
public long OpenMySubKey()
{
IntPtr hkey = IntPtr.Zero;
return RegOpenKey(HKEY_CLASSES_ROOT, "MySubKey", ref hkey);
}
'VB
<DllImport("coredll.dll", SetLastError:=True)> _
Public Shared Function RegOpenKey(ByVal hkey As IntPtr, ByVal lpSubKey As String, ByRef hkeyResult As IntPtr) As Long
End Function