Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access violation calling Win API from C# using DllImport

The task is to determine the last write time for the registry key. As standard RegistryKey class doesn't provide this feature, I have to use WinAPI function "RegQueryInfoKey". To get the key handle I open it by "RegOpenKeyEx".

This is the WinAPI prototype of the function (taken from MSDN):

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

I use the following declaration:

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

Then I call it in the following way:

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

At this point I get "Access violation" exception. What am I doing wrong? I think something is wrong with parameters passing, but how to do it right?

Thank you.

like image 217
C-F Avatar asked Feb 23 '23 00:02

C-F


2 Answers

There are 5 parameters in the native function's prototype, and only 4 in your P/Invoke signature.

In particular, you're missing DWORD ulOptions. This parameter is "reserved and must be zero" according to the MSDN documentation, but it must still be passed in the function call.

Also, you don't need to set the SetLastError field because the RegOpenKeyEx function returns its error code; you don't have to retrieve it by calling GetLastError. Consequently, you don't need the marshaler to save that value for you automatically. Just check the return value for the error code.

Change your P/Invoke signature to look like this:

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

The wrong P/Invoke signature is almost always the cause of "access violation" errors. When you see one of those, make sure you double-check it twice!

like image 61
Cody Gray Avatar answered Feb 24 '23 23:02

Cody Gray


You've missed ulOptions from your P/Invoke signature.

like image 35
Roger Lipscombe Avatar answered Feb 25 '23 00:02

Roger Lipscombe