I'm trying to write a DWORD to registry using c#. Using p/invoke because of registry reddirection.
I've searched for this issue and finally could get it working but i don't understand.
[DllImport("advapi32.dll", SetLastError = true)]
static extern uint RegSetValueEx(
IntPtr hKey,
[MarshalAs(UnmanagedType.LPStr)]
string lpValueName,
int Reserved,
RegistryValueKind dwType,
ref IntPtr lpData,
int cbData);
int checkreturn = RegOpenKeyEx(HKeyLocalMachine, @"SOFTWARE\Test", 0, (int) RegistrySecurity.KEY_WOW64_64KEY | (int) RegistrySecurity.KEY_SET_VALUE, ref keyHandle);
const int dataStored = 0;
IntPtr p = new IntPtr(dataStored);
int size = Marshal.SizeOf(dataStored);
uint checkreturn2 = RegSetValueEx(keyHandle, "valueName", 0, RegistryValueKind.DWord, ref p, size);
This works if i put out
or ref
on lpData parameter, if i don't it returns error 998 (ERROR_NOACCESS), why is that? The same thing happens if i change the IntPtr to int, and pass the actual value, but this time i get an first exception AccessViolation on my code.
the winapi declaration for that it's *lpData
, which i assume is what passing a IntPtr
is.
_In_ const BYTE *lpData,
The api requires a pointer to the data plus the size of the data. You can't pass an int
, or a char
, or a bool
. You need to pass a pointer to the data. If you pass something else, the API will interpret it as a pointer to the data, and random results will happen.
With P/Invoke, a ref
to something is translated to a pointer to that something.
Now, you can
[DllImport("advapi32.dll", SetLastError = true)]
static extern uint RegSetValueEx(
IntPtr hKey,
[MarshalAs(UnmanagedType.LPStr)]
string lpValueName,
int Reserved,
RegistryValueKind dwType,
ref uint lpData,
int cbData);
and then in cbData
pass sizeof(uint)
and this will work, because a ref
for P/Invoke is a ref
.
Only thing, I would suggest removing the
[MarshalAs(UnmanagedType.LPStr)]
because without it the P/Invoke will use the Unicode version of the method, that is more correct.