首页 > 解决方案 > 无法在 C#/.NET 中导出 HKLM 注册表项

问题描述

我需要将 HKLM 配置单元中的注册表项导出到文件中。这是一个键,我在同一个程序中成功创建了几行。我正在使用 Process 对象让我的 C# 程序执行 shell 命令:

cmd.exe /c regedit.exe /e C:\temp\CDPRegExport.txt HKEY_LOCAL_MACHINE\SOFTWARE\NPTMigration

如果我执行我的程序,则不会创建文件C:\temp\CDPRegExport.txt 。但是,如果我直接运行上面的命令(在同一个管理控制台窗口中)它工作正常!

我尝试添加应用程序清单以确保我的 .NET 程序以管理员身份运行。

我尝试调用 reg.exe export 而不是 regedit.exe /e 但结果是一样的(我猜这两个程序最终使用的是同一个 DLL)。

这是主要的注册表导出方法:

static bool RegistryExport(string regKey, string destFile)
{
    Cmd cmd = new Cmd()
    {
        CreateNoWindow = true
    };
    cmd.Exec(@"regedit.exe", @"/e", destFile, regKey);
    Console.WriteLine("Standard Out:\r\n" + cmd.StandardOut);
    Console.WriteLine("Standard Error:\r\n" + cmd.StandardErr);

    if (!File.Exists(destFile))
    {
        AppContext.log.Critical(@"Registry export file ({0}) not found!", destFile);
        return false;
    }

    return true;
 }

...这里是 Cmd.Exe():

public void Exec(string command, params string[] Parameters)
{

    string fullyQualifiedCommand = @"/c " + command + GetParameters(Parameters);
    Console.WriteLine(fullyQualifiedCommand);

    try
    {
        psi = new ProcessStartInfo(@"cmd", fullyQualifiedCommand)
        {
            RedirectStandardOutput = true,
            RedirectStandardError = true,
        };
        psi.UseShellExecute = false;
        psi.CreateNoWindow = true;

        using (Process process = new Process())
        {
            process.StartInfo = psi;
            process.Start();

            if (RedirectIOStreams)
            {
                StandardOut = process.StandardOutput.ReadToEnd();
                StandardErr = process.StandardError.ReadToEnd();
            }
            process.WaitForExit();
         }

        NormalExit = true;
     }
     catch (Exception ex)
     {
        StandardOut = string.Empty;
        StandardErr = ex.ToString();
    }
}

private static string GetParameters(string[] Parameters)
{
    string expression = string.Empty;

    if (Parameters.Length == 0)
        return string.Empty;

    for (int index=0; index<Parameters.Length; index++)
    {
        if (Parameters[index].Contains(" "))
            expression += " \"" + Parameters[index] + "\"";
        else
            expression += " " + Parameters[index];
    }

    return expression;
}

当程序使用 regedit.exe 时,标准输出和标准错误都是空白的。

但是,当它使用reg.exe导出时,标准错误显示:“错误:系统无法找到指定的注册表项或值。”

同样,这很奇怪,因为如果我直接通过命令窗口调用完全相同的reg.exe 或 regedit.exe 语法,它就可以正常工作!

标签: c#.netregistry

解决方案


如果 64 位操作系统上的 32 位进程,则必须禁用 WOW64 文件系统重定向

这个测试对我有用(Windows 10,VS 2015)=>

bool bWow64 = false;
IsWow64Process(Process.GetCurrentProcess().Handle, out bWow64);
if (bWow64)
{
    IntPtr OldValue = IntPtr.Zero;
    bool bRet = Wow64DisableWow64FsRedirection(out OldValue);
}
string sKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\NPTMigration";
string sFile = @"C:\temp\CDPRegExport.txt";
using (Process process = new Process())
{
    ProcessStartInfo psi = new ProcessStartInfo();
    psi.WindowStyle = ProcessWindowStyle.Hidden;
    psi.FileName = "reg";
    psi.Arguments = "export " + "" + sKey + "" + " " + "" + sFile + "";
    psi.RedirectStandardOutput = true;
    psi.UseShellExecute = false;
    process.StartInfo = psi;
    process.Start();
    using (StreamReader reader = process.StandardOutput)
    {
        string sResult = reader.ReadToEnd();
        Console.Write(sResult);
    }
}

声明:

    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern bool IsWow64Process(IntPtr hProcess, out bool Wow64Process);

    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern bool Wow64DisableWow64FsRedirection(out IntPtr OldValue);

推荐阅读