未支持的:
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
Public Function OpenMySubKey() As Long
Dim hkey As IntPtr = IntPtr.Zero
Return RegOpenKey(HKEY_CLASSES_ROOT, "MySubKey", hkey)
End Function 'OpenMySubKey
6.14. 如何把 byte[] 转换成 IntPtr?
有不止一种的方法访问IntPtr。
第一种方法,使用非安全代码,直接用指针指向byte数组。 //C#
unsafe
{
byte[] test = new byte[5];
fixed (byte* p = &test[0])
{
*p = 0xff;
}
}
也可以使用GCHandle指向对象。 //C#
using System.Runtime.InteropServices;
byte[] test = new byte[5];
GCHandle hObject = GCHandle.Alloc(test, GCHandleType.Pinned);
IntPtr pObject = hObject.AddrOfPinnedObject();
if(hObject.IsAllocated)
hObject.Free();
'VB
Imports System.Runtime.InteropServices