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

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

  下面请看代码示例

 
 
1 using System;
2   using System.Collections.Generic;
3   using System.Linq;
4   using System.Text;
5   using Microsoft.Win32;
6   using System.Runtime.InteropServices;
7
8   namespace OperateRegistrationTable
9 {
10 class Programe
11 {
12 static void Main( string [] args)
13 {
14 string myParentKeyName = " HKEY_LOCAL_MACHINE " ;
15 string mySubKeyName = @" SOFTWARE\EricSun\MyTestKey " ;
16 string myKeyName = " MyKeyName " ;
17
18 string value = string .Empty;
19 value = Utility.Get64BitRegistryKey(myParentKeyName, mySubKeyName, myKeyName);
20 Console.WriteLine( " The Value is: {0} " , value);
21 }
22 }
23
24 public class Utility
25 {
26 #region 32位程序读写64注册表
27
28 static UIntPtr HKEY_CLASSES_ROOT = (UIntPtr) 0x80000000 ;
29 static UIntPtr HKEY_CURRENT_USER = (UIntPtr) 0x80000001 ;
30 static UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr) 0x80000002 ;
31 static UIntPtr HKEY_USERS = (UIntPtr) 0x80000003 ;
32 static UIntPtr HKEY_CURRENT_CONFIG = (UIntPtr) 0x80000005 ;
33
34 // 关闭64位(文件系统)的操作转向
35   [DllImport( " Kernel32.dll " , CharSet = CharSet.Auto, SetLastError = true )]
36 public static extern bool Wow64DisableWow64FsRedirection( ref IntPtr ptr);
37 // 开启64位(文件系统)的操作转向
38   [DllImport( " Kernel32.dll " , CharSet = CharSet.Auto, SetLastError = true )]
39 public static extern bool Wow64RevertWow64FsRedirection(IntPtr ptr);
40
41 // 获取操作Key值句柄
42   [DllImport( " Advapi32.dll " , CharSet = CharSet.Auto, SetLastError = true )]
43 public static extern uint RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions, 
                                  int samDesired, out IntPtr phkResult);
44 // 关闭注册表转向(禁用特定项的注册表反射)
45 [DllImport( " Advapi32.dll " , CharSet = CharSet.Auto, SetLastError = true )]
46 public static extern long RegDisableReflectionKey(IntPtr hKey);
47 // 使能注册表转向(开启特定项的注册表反射)
48 [DllImport( " Advapi32.dll " , CharSet = CharSet.Auto, SetLastError = true )]
49 public static extern long RegEnableReflectionKey(IntPtr hKey);
50 // 获取Key值(即:Key值句柄所标志的Key对象的值)
51 [DllImport( " Advapi32.dll " , CharSet = CharSet.Auto, SetLastError = true )]
52 private static extern int RegQueryValueEx(IntPtr hKey, string lpValueName, int lpReserved,
53 out uint lpType, System.Text.StringBuilder lpData,
54 ref uint lpcbData);
55
56 private static UIntPtr TransferKeyName( string keyName)
57 {
58 switch (keyName)
59 {
60 case " HKEY_CLASSES_ROOT " :
61 return HKEY_CLASSES_ROOT;
62 case " HKEY_CURRENT_USER " :
63 return HKEY_CURRENT_USER;
64 case " HKEY_LOCAL_MACHINE " :
65 return HKEY_LOCAL_MACHINE;
66 case " HKEY_USERS " :
67 return HKEY_USERS;
68 case " HKEY_CURRENT_CONFIG " :
69 return HKEY_CURRENT_CONFIG;
70 }
71
72 return HKEY_CLASSES_ROOT;
73 }
74
75 public static string Get64BitRegistryKey( string parentKeyName, string subKeyName, string keyName)
76 {
77 int KEY_QUERY_VALUE = ( 0x0001 );
78 int KEY_WOW64_64KEY = ( 0x0100 );
79 int KEY_ALL_WOW64 = (KEY_QUERY_VALUE | KEY_WOW64_64KEY);
80
81 try
82 {
83 // 将Windows注册表主键名转化成为不带正负号的整形句柄(与平台是32或者64位有关)
84 UIntPtr hKey = TransferKeyName(parentKeyName);
85
86 // 声明将要获取Key值的句柄
87 IntPtr pHKey = IntPtr.Zero;
88
89 // 记录读取到的Key值
90 StringBuilder result = new StringBuilder( "" .PadLeft( 1024 ));
91 uint resultSize = 1024 ;
92 uint lpType = 0 ;
93
94 // 关闭文件系统转向
95 IntPtr oldWOW64State = new IntPtr();
96 if (Wow64DisableWow64FsRedirection( ref oldWOW64State))
97 {
98 // 获得操作Key值的句柄
99 RegOpenKeyEx(hKey, subKeyName, 0 , KEY_ALL_WOW64, out pHKey);
100
101 // 关闭注册表转向(禁止特定项的注册表反射)
102 RegDisableReflectionKey(pHKey);
103
104 // 获取访问的Key值
105 RegQueryValueEx(pHKey, keyName, 0 , out lpType, result, ref resultSize);
106
107 // 打开注册表转向(开启特定项的注册表反射)
108 RegEnableReflectionKey(pHKey);
109 }
110
111 // 打开文件系统转向
112 Wow64RevertWow64FsRedirection(oldWOW64State);
113
114 // 返回Key值
115 return result.ToString().Trim();
116 }
117 catch (Exception ex)
118 {
119 return null ;
120 }
121 }
122
123 #endregion
124 }
125 }

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

目录
相关文章
|
3月前
|
缓存 C# Windows
C#程序如何编译成Native代码
【10月更文挑战第15天】在C#中,可以通过.NET Native和第三方工具(如Ngen.exe)将程序编译成Native代码,以提升性能和启动速度。.NET Native适用于UWP应用,而Ngen.exe则通过预编译托管程序集为本地机器代码来加速启动。不过,这些方法也可能增加编译时间和部署复杂度。
211 2
|
22天前
|
存储 监控 算法
企业内网监控系统中基于哈希表的 C# 算法解析
在企业内网监控系统中,哈希表作为一种高效的数据结构,能够快速处理大量网络连接和用户操作记录,确保网络安全与效率。通过C#代码示例展示了如何使用哈希表存储和管理用户的登录时间、访问IP及操作行为等信息,实现快速的查找、插入和删除操作。哈希表的应用显著提升了系统的实时性和准确性,尽管存在哈希冲突等问题,但通过合理设计哈希函数和冲突解决策略,可以确保系统稳定运行,为企业提供有力的安全保障。
|
1月前
|
算法 Java 测试技术
Benchmark.NET:让 C# 测试程序性能变得既酷又简单
Benchmark.NET是一款专为 .NET 平台设计的性能基准测试框架,它可以帮助你测量代码的执行时间、内存使用情况等性能指标。它就像是你代码的 "健身教练",帮助你找到瓶颈,优化性能,让你的应用跑得更快、更稳!希望这个小教程能让你在追求高性能的路上越走越远,享受编程带来的无限乐趣!
116 13
|
3月前
|
存储 开发框架 .NET
C#语言如何搭建分布式文件存储系统
C#语言如何搭建分布式文件存储系统
97 2
|
3月前
|
设计模式 程序员 C#
C# 使用 WinForm MDI 模式管理多个子窗体程序的详细步骤
WinForm MDI 模式就像是有超能力一般,让多个子窗体井然有序地排列在一个主窗体之下,既美观又实用。不过,也要小心管理好子窗体们的生命周期哦,否则一不小心就会出现一些意想不到的小bug
303 0
|
3月前
|
XML 存储 安全
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
170 0
|
3月前
|
存储 分布式计算 监控
C# 创建一个分布式文件存储系统需要怎么设计??
C# 创建一个分布式文件存储系统需要怎么设计??
56 0
|
4月前
|
C# 容器
C#中的命名空间与程序集管理
在C#编程中,`命名空间`和`程序集`是组织代码的关键概念,有助于提高代码的可维护性和复用性。本文从基础入手,详细解释了命名空间的逻辑组织方式及其基本语法,展示了如何使用`using`指令访问其他命名空间中的类型,并提供了常见问题的解决方案。接着介绍了程序集这一.NET框架的基本单位,包括其创建、引用及高级特性如强名称和延迟加载等。通过具体示例,展示了如何创建和使用自定义程序集,并提出了针对版本不匹配和性能问题的有效策略。理解并善用这些概念,能显著提升开发效率和代码质量。
177 4
|
3月前
|
安全 API C#
C# 如何让程序后台进程不被Windows任务管理器强制结束
C# 如何让程序后台进程不被Windows任务管理器强制结束
89 0
|
3月前
|
API C#
C#实现Winform程序右下角弹窗消息提示
C#实现Winform程序右下角弹窗消息提示
191 0