0

我需要在 C# 中备份一个注册表项。我一直在尝试 P/Invoke RegSaveKey 无济于事。由于无法关闭组策略设置,我无法使用“Reg.exe”备份注册表。

这是所有代码:

private static UIntPtr GetKey(string registryPath)
{
  UIntPtr hKey = UIntPtr.Zero;

  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, registryPath, 0, KEY_READ, out hKey) != 0)
  {
     throw new Exception("Error getting key!");
  }

  return hKey;
}

private static void ExportRegistry(string registryPath)
{
  UIntPtr key = UIntPtr.Zero;
  try
  {
    key = GetKey(registryPath);
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex.Message);
    return;
  }

  if (key == UIntPtr.Zero)
  {
    Console.WriteLine("Not key to export!");
    return;
  }

  try
  {
    RegSaveKey(key, "c:\\temp\\test.reg", IntPtr.Zero);
  }
  catch (Exception ex)
  {
    Console.WriteLine(ex);
  }

  if (key != UIntPtr.Zero)
  {
    RegCloseKey(key);
  }
}

private static int KEY_READ = 131097;
private static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);

[DllImport("advapi32.dll", SetLastError = true)]
private static extern int RegCloseKey(UIntPtr hKey);

[DllImport("advapi32.dll", SetLastError = true)]
private static extern int RegOpenKeyEx(UIntPtr hKey, string subKey, int ulOptions, int samDesired, out UIntPtr hkResult);

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint RegSaveKey(UIntPtr hKey, string lpFile, IntPtr lpSecurityAttributes);
4

2 回答 2

2

您似乎没有检查 RegOpenKeyEx 或 RegSaveKey 的返回值是否有错误。我怀疑你得到的返回值是 ERROR_PRIVILEGE_NOT_HELD。Registry 函数不使用 SetLastError 他们直接返回它。与几乎每个 Win32 API 调用一样,必须检查返回值。

无论您的 ACL 访问级别如何,RegSaveKey 都需要启用 SE_BACKUP_NAME 权限。因此,您需要在调用 RegSaveKey 之前添加代码以启用此权限,然后在调用完成后禁用它。

这是另一个包含更多信息的问题,我相信还有其他问题。

于 2013-02-01T18:26:43.107 回答
1

首先,我想评论一下,您的问题遗漏了一些非常重要的细节。也就是说,您实际上并没有提供有关代码如何失败的任何信息。你只说:

我一直在尝试 P/Invoke RegSaveKey 无济于事。

像这样的问题都是关于细节的。我们需要看到精确而详细的错误诊断。请记住,我们看不到您的屏幕。

您需要更加注意 API 调用的返回值。您正在检查RegOpenKeyEx0 的返回值,但仅此而已。您需要捕获并检查RegOpenKeyEx. 那是一个错误代码。Win32Exception如果错误代码不等于零,您可以抛出 a 。

int err = RegOpenKeyEx(...);
if (err != 0)
    throw new Win32Exception(err);

将代码更改为 throw Win32Exception,当错误发生时,您至少会得到一些信息性文本。所以,如果RegOpenKeyEx失败了,你至少会找出原因。

而且您根本没有检查其他 API 调用。给予他们同样的待遇。

您调用的失败模式确实很少RegOpenKeyEx。我可以编造的唯一合理的解释是注册表项不存在。我希望你已经检查过了。但请注意注册表重定向器。如果您的进程是在 64 位操作系统上运行的 32 位进程,那么重定向器会将您带到WOW6432Node注册表部分,即 32 位视图。也许您所说的“无济于事”是指将信息保存到文件中,但这是错误的信息。这与使您感到困惑的注册表重定向器一致。

如果那是什么在咬你,那么KEY_WOW64_64KEY在调用RegOpenKeyEx. 或以 x64 为目标。

RegistryKey使用它来打开钥匙会容易得多。我知道你不能轻易打电话RegSaveKey,所以你仍然需要 p/invoke 。但是RegistryKey暴露了一个Handle你可以传递给RegSaveKey. 有一个附带条件。如果您确实需要使用该KEY_WOW64_64KEY标志,则需要 .net 4 和RegistryView.

至于RegSaveKey,我听从斯蒂芬在回答中给出的信息。

于 2013-02-01T19:08:55.263 回答