RegSetValueEx returns 998 (ERROR_NOACCESS) 如果在没有引用的情况下调用

RegSetValueEx returns 998 (ERROR_NOACCESS) if called without ref

我正在尝试使用 C# 将 DWORD 写入注册表。 由于注册表重定向,使用 p/invoke。

我搜索了这个问题,终于可以解决了,但我不明白。

[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);

如果我将 outref 放在 lpData 参数上,这将起作用,如果我不这样做,则会出现 returns 错误 998 (ERROR_NOACCESS),这是为什么呢?如果我将 IntPtr 更改为 int,并传递实际值,也会发生同样的事情,但这次我在代码中遇到第一个异常 AccessViolation。

它的 winapi 声明是 *lpData,我认为这是传递 IntPtr 的意思。

  _In_       const BYTE    *lpData,  

api需要一个指向数据的指针加上数据的大小。您不能传递 intcharbool。您需要传递一个指向数据的指针。如果您传递其他内容,API 会将其解释为指向数据的指针,并且会发生随机结果。

使用 P/Invoke,指向某物的 ref 被转换为指向该某物的指针。

现在,您可以

[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);

然后在 cbData 中传递 sizeof(uint) 这个 将起作用,因为 P/Invoke 的 refref.

只有一件事,我建议删除

[MarshalAs(UnmanagedType.LPStr)]

因为没有它 P/Invoke 将使用该方法的 Unicode 版本,这更正确。