原文:C# 32位程序访问64位系统注册表

  我的上一篇文章已经阐述了“32位程序和64位程序在64位平台上读\写注册表的区别”,那么接下来将要回答上篇所留下来的一个问题:32位程序如何访问64位系统注册表(即:64位程序所访问的注册表位置)。

  我们已经知道:

    ①:本机模式 64 位程序运行在纯模式下,并且访问键和存储在以下注册表子键中的值:HKEY_LOCAL_MACHINE\Software

    ②:32 位程序运行在 WOW64 模式下,并且访问键和值存储在以下注册表子项中:HKEY_LOCAL_MACHINE\Software\WOW6432nod

  那么要实现32为程序访问64位注册表信息,还要知道如下概念:1:文件系统转向。2:注册表重定向(转向)。3:注册表反射。

    ①:文件系统转向

    32
位进程不能加载64位Dll,64位进程也不可以加载32位Dll。Windows的系统目录包含了所有安装的应用程序和它们的Dll文件,根据我们所述

的规则,

    它应该被分为给64位应用程序的目录和给32位应用程序的目录。如果不这样,我们就无法区分32位和64位的Dll文件。对于64位应用程序,其
文件通常被

    放在%windir%\system32和%programfiles%(比如:c:\program
files)。对于32位应用程序,其文件通常在%windir%\syswow64和

    C:\program files
(x86)下面。如果我们用32位程序去访问%windir%\system32,不管我们用硬编码还是其它的方式,系统都会自动地给我们

    转向到%windir%\syswow64下面。这种转向对于每个32位应用程序默认都是打开的。但是这种转向对于我们来说并不总是需要的。那么我们可以在

    C#里面调用相关的API来关闭和打开这种转向。常用的函数有3个:

        Wow64DisableWow64FsRedirection(关闭系统转
向),

        Wow64RevertWow64FsRedirection(打开系统转向),

        Wow64EnableWow64FsRedirection(打
开系统转向)。

    但是Wow64EnableWow64FsRedirection在嵌套使用的时候不可靠,所以通常用上面的
Wow64RevertWow64FsRedirection来打开文件系统转向

    功能。在C#中,我们可以利用DllImport直接调用这两个函数。

    ②:注册表重定向(转向)

    若要支持的 32 位和 64 位 COM 注册和程序共存状态,WOW64 子系统提供 32 位程序使用的注册表的另一个视图。在 WOW64 子系统使用注册表

    重定向截获位级别的注册表调用。注册表重定向还可以确保注册表调用被定向到在注册表中正确的分支。
    当我们安装新程序或 Windows x64 版的计算机上运行程序时,所做的 64 位程序的注册表调用访问
HKEY_LOCAL_MACHINE\Software 注册表子键

    不重定向。WOW64 截获由 32 位程序的注册表调用到
HKEY_LOCAL_MACHINE\Software,然后将它们重定向到

    HKEY_LOCAL_MACHINE\Software\WOW6432node 子键。 通过重定向仅 32 位程序调用,WOW64
可确保程序始终写入相应的注册表子键。

    注册表重定向不要求程序代码修改,和此过程是对用户透明。

    ③:注册表反射

    反射使两个相同的注册表,以支持同时进行的本机和 WOW64 操作的物理副本的存在,

    打开注册表的 64 位节在所有时间和注册表反射提供了一种容纳 32 位的实时方法。

  简单的了解了这些,下面说一下具体的实现步骤:

    关闭64位(文件系统)的操作转向

      获得操作Key值的句柄

        关闭注册表转向(禁止特定项的注册表反射)

      获取访问的Key值

        打开注册表转向(开启特定项的注册表反射)

    开启64位(文件系统)的操作转向

  【注:由于我们在程序中用了DllImport,所以要引入命名空间:System.Runtime.InteropServices】

  下面请看代码示例

using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using Microsoft.Win32;
 using System.Runtime.InteropServices;

 namespace OperateRegistrationTable
{
class Programe
{
static void Main(string[] args)
{
string myParentKeyName = "HKEY_LOCAL_MACHINE";
string mySubKeyName = @"SOFTWARE\EricSun\MyTestKey";
string myKeyName = "MyKeyName";

string value = string.Empty;
value = Utility.Get64BitRegistryKey(myParentKeyName, mySubKeyName, myKeyName);
Console.WriteLine("The Value is: {0}", value);
}
}

public class Utility
{
#region 32位程序读写64注册表

static UIntPtr HKEY_CLASSES_ROOT = (UIntPtr)0x80000000;
static UIntPtr HKEY_CURRENT_USER = (UIntPtr)0x80000001;
static UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
static UIntPtr HKEY_USERS = (UIntPtr)0x80000003;
static UIntPtr HKEY_CURRENT_CONFIG = (UIntPtr)0x80000005;

// 关闭64位(文件系统)的操作转向
  [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
// 开启64位(文件系统)的操作转向
  [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);

// 获取操作Key值句柄
  [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions, 
                                  int samDesired, out IntPtr phkResult);
//关闭注册表转向(禁用特定项的注册表反射)
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern long RegDisableReflectionKey(IntPtr hKey);
//使能注册表转向(开启特定项的注册表反射)
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern long RegEnableReflectionKey(IntPtr hKey);
//获取Key值(即:Key值句柄所标志的Key对象的值)
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int RegQueryValueEx(IntPtr hKey, string lpValueName, int lpReserved,
out uint lpType, System.Text.StringBuilder lpData,
ref uint lpcbData);

private static UIntPtr TransferKeyName(string keyName)
{
switch (keyName)
{
case "HKEY_CLASSES_ROOT":
return HKEY_CLASSES_ROOT;
case "HKEY_CURRENT_USER":
return HKEY_CURRENT_USER;
case "HKEY_LOCAL_MACHINE":
return HKEY_LOCAL_MACHINE;
case "HKEY_USERS":
return HKEY_USERS;
case "HKEY_CURRENT_CONFIG":
return HKEY_CURRENT_CONFIG;
}

return HKEY_CLASSES_ROOT;
}

public static string Get64BitRegistryKey(string parentKeyName, string subKeyName, string keyName)
{
int KEY_QUERY_VALUE = (0x0001);
int KEY_WOW64_64KEY = (0x0100);
int KEY_ALL_WOW64 = (KEY_QUERY_VALUE | KEY_WOW64_64KEY);

try
{
//将Windows注册表主键名转化成为不带正负号的整形句柄(与平台是32或者64位有关)
UIntPtr hKey = TransferKeyName(parentKeyName);

//声明将要获取Key值的句柄
IntPtr pHKey = IntPtr.Zero;

//记录读取到的Key值
StringBuilder result = new StringBuilder("".PadLeft());
uint resultSize = ;
uint lpType = ;

//关闭文件系统转向
IntPtr oldWOW64State = new IntPtr();
if (Wow64DisableWow64FsRedirection(ref oldWOW64State))
{
//获得操作Key值的句柄
RegOpenKeyEx(hKey, subKeyName, , KEY_ALL_WOW64, out pHKey);

//关闭注册表转向(禁止特定项的注册表反射)
RegDisableReflectionKey(pHKey);

//获取访问的Key值
RegQueryValueEx(pHKey, keyName, , out lpType, result, ref resultSize);

//打开注册表转向(开启特定项的注册表反射)
RegEnableReflectionKey(pHKey);
}

//打开文件系统转向
Wow64RevertWow64FsRedirection(oldWOW64State);

//返回Key值
return result.ToString().Trim();
}
catch (Exception ex)
{
return null;
}
}

#endregion
}
}

Get64BitRegistryKey函数的三个参数分别代表:主键名(如:HKEY_LOCAL_MACHINE等),子键名,Key名,返回的是Key的Value(64位系统注册表的键值),通过上面的方法就完全可以实现用32程序访问64位系统注册表(即:64位程序所访问的注册表位置)。

C# 32位程序访问64位系统注册表的更多相关文章

  1. 使用.netFx4.0提供的方法解决32位程序访问64位系统的64位注册表

    原文:使用.netFx4.0提供的方法解决32位程序访问64位系统的64位注册表 我们知道目标平台是32位的程序运行在64位的系统上,去访问部分注册表的时候系统自动重定向到win32node节点对应的 ...

  2. C# 32位程序访问64位注册表

    接上文:http://www.cnblogs.com/TaiYangXiManYouZhe/p/5086974.html 上代码: RegistryKey localKey; if (Environm ...

  3. 32位程序在64位系统上获取系统安装时间(要使用KEY_WOW64_64KEY标记)

    众所周知,取系统的安装时间可取注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion的子项InstallDate,此值是个 ...

  4. C# 32位程序在64位系统下注册表操作

    在64位的Windows操作系统中,为了兼容32位程序的运行,64位的Windows操作系统采用重定向机制.目的是为了能让32位程序在64位的操作系统不仅能操作关键文件文夹和关键的注册表并且又要避免与 ...

  5. C# 32位程序在64位系统下运行中解决重定向问题

    在64位的Windows操作系统中,为了兼容32位程序的运行,64位的Windows操作系统采用重定向机制.目的是为了能让32位程序在64位的操作系统不仅能操作关键文件文夹和关键的注册表并且又要避免与 ...

  6. iOS上应用如何兼容32位系统和64位系统

    在苹果推出iPhone5S时,64位的应用就走到了眼前.当时就看见苹果官方资料宣布iOS7.x的SDK支持了64位的应用,而且内置的应用都已经是64位. 我记得自己刚刚接触电脑时还有16位的系统,指针 ...

  7. X86(32位)与X64(64位)有什么区别,如何选择对应的操作系统和应用程序?

    X86就是我们一般用的32位的系统,指针长度为32位(386起):X64就是64位的系统,指针长度为64位. 选择硬件对应的软件,建议通过以下三条考虑:1.64位操作系统相对32位操作系统理论上性能会 ...

  8. 【电脑常识】如何查看电脑是32位(X86)还是64位(X64),如何知道硬件是否支持64位系统

    开始->运行->输入cmd确定->输入systeminfo 回车 待加载完成,就会看到如下信息(不同版本略有差异): 一.如何查看电脑是32位(X86)还是64位(X64) 方法2: ...

  9. 关于Qt 5-MSVC 2015 64位在 win7 64位系统debug程序崩溃的问题

     关于Qt 5-MSVC 2015 64位在 win7 64位系统debug程序崩溃的问题 在win7 64位系统安装VC2015的编译器,并安装了 Qt 5.6 -5.7 VC2015 64位版本测 ...

随机推荐

  1. Mina2 研究总结

    一.Mina框架. Mina的框架大概是这么个样子: 底层由Java 的NIO 1.0实现 核心架构应该是这样: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZX ...

  2. 读一读Scktsrvr.exe的源程序

    读一读Scktsrvr.exe的源程序 使用DELPHI做多层开发的朋友们都应该对Scktsrvr.exe这个程序不陌生的,Borland公司在DELPHI中给出了它的源代码.这是一个900来行的程序 ...

  3. 在VC++中启用内存泄露检测

    检测内存泄漏的主要工具是调试器和 CRT 调试堆函数.若要启用调试堆函数,请在程序中包括以下语句: #define CRTDBG_MAP_ALLOC#include <stdlib.h># ...

  4. COCOS2D中对精灵的操作、对图片的各种操作

    内容简要: 1.初始化 2.创建无图的精灵 3.设置精灵贴图大小  4.添加入层中 5.对精灵进行缩放  6.对精灵宽或高进行缩放  7.旋转精灵 8.设置精灵透明度  9.精灵的镜像反转  10.设 ...

  5. cocos2dx之lua项目开发中MVC框架的简单应用

    **************************************************************************** 时间:2015-03-31 作者:Sharin ...

  6. CodeForces 13E. Holes 分块处理

    正解是动态树,太难了,仅仅好分块处理水之.看了看status大概慢了一倍之多..     分块算法大体就是在找一个折衷点,使得查询和改动的时间复杂度都不算太高,均为o(sqrt(n)),所以总的时间复 ...

  7. Qt中无处不在的d指针为何方神圣

    在研究QCoreApplication类的代码时,无意间弄明白了“d_func()”和“d指针”的来源: class Q_CORE_EXPORT QCoreApplication#ifndef QT_ ...

  8. TestComplete实测Flex

    1.TestComplete提供了已经编译好的Flex界面,可以直接使用: http://support.smartbear.com/samples/testcomplete9/flex/orders ...

  9. MQ、JMS以及ActiveMQ

    MQ简介: MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过写和检索出入列队的针对应用程序的数据(消息)来通信,而无需专用连接来链接它们.消息传 ...

  10. shortcut switch in terminal start pos & end pos

    ctrl a ctrl e switch in terminal start pos & end pos