使用DllImport从C#调用Win API的访问冲突

时间:2011-12-24 09:31:33

标签: c# .net interop pinvoke

任务是确定注册表项的上次写入时间。由于标准RegistryKey类不提供此功能,我必须使用WinAPI函数“RegQueryInfoKey”。要获得密钥句柄,我可以通过“RegOpenKeyEx”打开它。

这是该函数的WinAPI原型(取自MSDN):

LONG WINAPI RegOpenKeyEx(
  __in          HKEY hKey,
  __in          LPCTSTR lpSubKey,
                DWORD ulOptions,
  __in          REGSAM samDesired,
  __out         PHKEY phkResult
);

我使用以下声明:

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int RegOpenKeyEx(UIntPtr hkey, string lpSubKey, uint samDesired, ref UIntPtr phkResult);

然后我用以下方式调用它:

UIntPtr hKey = UIntPtr.Zero;
string myKeyName = "blablabla";
UIntPtr HKEY_USERS = (UIntPtr)0x80000003; 
uint KEY_READ = 0x20019;
RegOpenKeyEx(HKEY_USERS, myKeyName, KEY_READ, ref hKey);

此时我收到“访问冲突”异常。我究竟做错了什么? 我认为参数传递有问题,但如何做到对不对?

谢谢。

2 个答案:

答案 0 :(得分:4)

您的P / Invoke签名中错过了ulOptions

答案 1 :(得分:4)

原生函数原型中有5个参数,P / Invoke签名中只有4个参数。

特别是,你错过了DWORD ulOptions。根据MSDN文档,此参数为“保留且必须为零”,但仍必须在函数调用中传递。

此外,您无需设置SetLastError field,因为RegOpenKeyEx函数返回其错误代码;您无需通过调用GetLastError来检索它。因此,您不需要编组程序自动为您保存该值。只需检查错误代码的返回值。

将您的P / Invoke签名更改为:

[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenKeyEx(UIntPtr hkey, string lpSubKey,
                                      uint ulOptions, uint samDesired,
                                      out UIntPtr phkResult);

错误的P / Invoke签名几乎总是“访问冲突”错误的原因。当你看到其中一个时,请务必仔细检查两次!