powered by simpleCommunicator - 2.0.56     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Доступ к реестру x64 из приложения x86
3 сообщений из 3, страница 1 из 1
Доступ к реестру x64 из приложения x86
    #38567584
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Доброго времени суток.

.NET 3.5 SP1

Мною ранее была написана некоторая библиотека AcadInfo.dll, скомпилированная как AnyCPU. В ней, помимо прочего, определён метод, считывающий из реестра необходимую информацию обо всех установленных на локальной\удалённой машине версиях программы AutoCAD (нередко их может быть установлено сразу несколько). Поскольку разрядность установленного AutoCAD всегда совпадает с разрядностью операционной системы, то вся необходимая информация размещена в ветке HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD. В ветке HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Autodesk подраздел AutoCAD отсутствует (можно убедиться через regedit).

Если пишется некое приложение, использующее AcadInfo.dll и оно так же компилируется как AnyCPU, то информация об установленных AutoCAD успешно считывается. Недавно обнаружил, что если это приложение компилировать как x86 и запустить его в операционной системе x64, то в коде библиотеки AcadInfo.dll (по прежнему скомпилированной как AnyCPU) значение свойства IntPtr.Size будет равным 4, а не 8 и получить ветки реестра, относящиеся к установленным AutoCAD не удаётся:
Код: c#
1.
2.
3.
// parrentRegistry: HKEY_LOCAL_MACHINE
// ParrentAcadRegistryKey: @"SOFTWARE\Autodesk\AutoCAD"
regAcad = parrentRegistry.OpenSubKey(ParrentAcadRegistryKey, false); // null



Я попробовал воспользоваться методами расширений, приведённых в Example 3 . Наименования этих методов некорректны и сбивают с толку, т. к. на самом деле они возвращают не ветку реестра, а строковое значение параметра, имя которого обозначено в качестве аргумента:
Код: c#
1.
2.
public static string GetRegKey64(this RegistryKey inKey, String inPropertyName)
public static string GetRegKey32(this RegistryKey inKey, String inPropertyName)


т.е. по смыслу правильнее было бы как-то так:
Код: c#
1.
2.
public static string GetPropertyValueAsStringFromRegKey64(this RegistryKey inKey, String inPropertyName)
public static string GetPropertyValueAsStringFromRegKey32(this RegistryKey inKey, String inPropertyName)



Однако код по указанной выше ссылке, использующий DllImport, в данном случае не работает так, как ожидалось:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
Int32 size = IntPtr.Size; // Если код данной библиотеки компилируется как AnyCPU, 
// но использующее её приложение скомпилировано как x64, то размер указателя
// в коде этой библиотеки будет равен 4, даже если разрядность операционной 
// системы x64.

// parrentRegistry: HKEY_LOCAL_MACHINE
// ParrentAcadRegistryKey: @"SOFTWARE\Autodesk\AutoCAD"
regAcad = parrentRegistry.OpenSubKey(ParrentAcadRegistryKey, false); // null
regAcad2 = parrentRegistry.OpenSubKey(@"SOFTWARE\Wow6432Node\Autodesk\AutoCAD", false); // null			
String x64 = parrentRegistry.GetRegKey64(@"SOFTWARE\Autodesk\AutoCAD\R17.2\ACAD-7001:409\Location"); // null
String x86 = parrentRegistry.GetRegKey32(@"SOFTWARE\Autodesk\AutoCAD\R17.2\ACAD-7001:409\Location"); // null
String _x64 = parrentRegistry.GetRegKey64(@"SOFTWARE\Wow6432Node\Autodesk\AutoCAD\R17.2\ACAD-7001:409\Location"); // null
String _x86 = parrentRegistry.GetRegKey32(@"SOFTWARE\Wow6432Node\Autodesk\AutoCAD\R17.2\ACAD-7001:409\Location"); // null



Как в обозначенной ситуации получить доступ к интересующим меня веткам реестра?

Спасибо.
...
Рейтинг: 0 / 0
Доступ к реестру x64 из приложения x86
    #38567832
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пока что удалось получить значение строкового параметра:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
// За основу взят код с сайта http://social.msdn.microsoft.com/Forums/ko-KR/da055767-0f69-4f07-b8e7-f3dce19f7ecb/windows-7-64bit-registry-access-using-x86-assembly?forum=netfx64bit
using System;
using System.Linq;
using System.Text;
 
namespace ConsoleSample {
 
        public static class RegistryTools {
 
                [System.Runtime.InteropServices.DllImport("advapi32.dll",
                        CharSet = System.Runtime.InteropServices.CharSet.Unicode,
                        EntryPoint = "RegQueryValueExW", SetLastError = true)]
                public static extern int RegQueryValueEx(UIntPtr hKey, string lpValueName,
                        int lpReserved, out uint lpType, byte[] lpData, ref int lpcbData);
 
                [System.Runtime.InteropServices.DllImport("advapi32.dll",
                        CharSet = System.Runtime.InteropServices.CharSet.Unicode,
                        EntryPoint = "RegOpenKeyExW", SetLastError = true)]
                public static extern int RegOpenKeyEx(UIntPtr hKey, string subKey,
                        uint options, int sam, out UIntPtr phkResult);
 
                public static UIntPtr HKEY_CURRENT_USER = (UIntPtr)0x80000001;
                public static UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
                public static int KEY_QUERY_VALUE = 0x0001;
                public static int KEY_SET_VALUE = 0x0002;
                public static int KEY_CREATE_SUB_KEY = 0x0004;
                public static int KEY_ENUMERATE_SUB_KEYS = 0x0008;
                public static int KEY_WOW64_64KEY = 0x0100;
                public static int KEY_WOW64_32KEY = 0x0200;
 
                /// <summary>
                /// Прочитать в реестре значение строкового параметра.
                /// </summary>
                /// <param name="rootRegKey">Куст. RegistryTools.HKEY_LOCAL_MACHINE 
                /// или RegistryTools.HKEY_CURRENT_USER.</param>
                /// <param name="regKeyPath">Путь к разделу, в котором находится искомый параметр. 
                /// В пути не указывается куст.</param>
                /// <param name="propName">Наименование искомого строкового параметра.</param>
                /// <returns>Возвращается значение параметра или null, если указанный параметр не найден.</returns>
                public static String GetStringPropertyValue(UIntPtr rootRegKey, String regKeyPath, String propName) {
                        UIntPtr regKeyHandle;
                        if (RegOpenKeyEx(rootRegKey, regKeyPath, 0,
                                KEY_QUERY_VALUE | KEY_WOW64_64KEY, out regKeyHandle) == 0) {
                                UInt32 type;
                                Byte[] buf = new Byte[2048];
                                Int32 cbData = 2048;
                                if (RegQueryValueEx(regKeyHandle, propName, 0, out type, buf, ref cbData) == 0) {
                                        Encoding encoding = Encoding.ASCII;
                                        buf = Encoding.Convert(Encoding.Unicode, encoding, buf);
                                        buf = buf.TakeWhile(n => n != 0).ToArray();
                                        String text = encoding.GetString(buf, 0, buf.Length);
                                        return text;
                                }
                        }
                        return null;
                }
        }
}


Работает так:
Код: c#
1.
2.
String location = RegistryTools.GetStringPropertyValue(RegistryTools.HKEY_LOCAL_MACHINE,
                @"SOFTWARE\Autodesk\AutoCAD\R17.2\ACAD-7001:409", "Location"); // C:\Program Files\Autodesk\AutoCAD 2009


Однако это только капля из того, что требуется...
...
Рейтинг: 0 / 0
Доступ к реестру x64 из приложения x86
    #38570203
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ответ:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
// dev.dll
// RegistryExtensions.cs
// © Андрей Бушман, 2014
// В файле RegistryExtensions.cs определён дополнительный функционал, 
// расширяющий возможности работы с реестром из .NET приложений, написанных на
// .NET 3.5 SP1.
#if !Net_4
using System;
using Microsoft.Win32;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

/// В данном пространстве имён собран общий дополнительный функционал, который
/// может быть полезен при разработке любого .NET приложения.
namespace Bushman.Developing {
	/// <summary>
	/// Данный класс предназначен для предоставления 32-битным приложениям 
	/// доступа к 64-битным разделам реестра. Класс так же может использоваться
	/// для предоставления 64-битным приложениям ветке реестра, предназначенной
	/// для 32-битных. За основу взят код, опубликованный в блоге 
	/// http://clck.ru/96A9U
	/// </summary>
	public static class RegistryExtensions {
		/// <summary>
		/// Открытие ключа реестра, с указанием того, какую именно часть 
		/// следует открывать: записи для 32-битных приложений, или же записи 
		/// для 64-битных.
		/// </summary>
		/// <param name="parentKey">Родительский элемент RegistryKey, в котором
		/// следует выполнить открытие подраздера.</param>
		/// <param name="subKeyName">Name of the key to be opened</param>
		/// <param name="writable">true - открывать для чтения и записи; 
		/// false - открывать только для чтения.</param>
		/// <param name="options">Какую именно часть реестра следует открывать:
		/// относящуюся к 32-битным приложениям или же относящуюся к 64-битным.
		/// </param>
		/// <returns>Возвращается RegistryKey или null, если по каким-либо
		/// причинам получить RegistryKey не удалось.</returns>
		public static RegistryKey OpenSubKey(this RegistryKey parentKey,
			String subKeyName, Boolean writable, RegWow64Options options) {
			// Проверка работоспособности
			if (parentKey == null || GetRegistryKeyHandle(parentKey) ==
				IntPtr.Zero) {
				return null;
			}
			// Назначение прав
			Int32 rights = (Int32)(writable ? RegistryRights.WriteKey :
				RegistryRights.ReadKey);

			// Вызов функций неуправляемого кода
			Int32 subKeyHandle, result = RegOpenKeyEx(GetRegistryKeyHandle(
				parentKey), subKeyName, 0, rights | (Int32)options,
				out subKeyHandle);

			// Если мы ошиблись - возвращаем null
			if (result != 0) {
				return null;
			}

			// Получаем ключ, представленный указателем, возвращённым из 
			// RegOpenKeyEx
			RegistryKey subKey = PointerToRegistryKey((IntPtr)subKeyHandle,
				writable, false);
			return subKey;
		}

		/// <summary>
		/// Получить указатель на ключ реестра.
		/// </summary>
		/// <param name="registryKey">Ключ реестра, указатель на который нужно 
		/// получить.
		/// </param>
		/// <returns>Возвращается объект IntPtr. Если не удалось получить 
		/// указатель на обозначенный объект RegistryKey, то возвращается 
		/// IntPtr.Zero.</returns>
		public static IntPtr GetRegistryKeyHandle(this RegistryKey registryKey) {
			if (registryKey == null) return IntPtr.Zero;
			Type registryKeyType = typeof(RegistryKey);
			System.Reflection.FieldInfo fieldInfo =
			registryKeyType.GetField("hkey", BindingFlags.NonPublic |
			BindingFlags.Instance);
			// Получить дескриптор для поля hkey
			SafeHandle handle = (SafeHandle)fieldInfo.GetValue(registryKey);
			// Получить небезопасный дескриптор
			IntPtr dangerousHandle = handle.DangerousGetHandle();
			return dangerousHandle;
		}

		/// <summary>
		/// Получить ключ реестра на основе его указателя.
		/// </summary>
		/// <param name="hKey">Указатель на ключ реестра</param>
		/// <param name="writable">true - открыть для записи; false - для 
		/// чтения.</param>
		/// <param name="ownsHandle">Владеем ли мы дескриптором: true - да, 
		/// false - нет.</param>
		/// <returns>Возвращается объект RegistryKey, соответствующий 
		/// полученному указателю.</returns>
		public static RegistryKey PointerToRegistryKey(IntPtr hKey,
			Boolean writable, Boolean ownsHandle) {
			BindingFlags privateConstructors = BindingFlags.Instance |
				BindingFlags.NonPublic;
			Type safeRegistryHandleType =
				typeof(SafeHandleZeroOrMinusOneIsInvalid).Assembly
				.GetType("Microsoft.Win32.SafeHandles.SafeRegistryHandle");
			// Получаем массив типов, соответствующих аргументом конструктора,
			// который нам нужен
			Type[] safeRegistryHandleCtorTypes = new Type[] { typeof(IntPtr), 
				typeof(Boolean) };
			// Получаем ConstructorInfo для нашего объекта
			System.Reflection.ConstructorInfo safeRegistryHandleCtorInfo =
				safeRegistryHandleType.GetConstructor(privateConstructors,
				null, safeRegistryHandleCtorTypes, null);
			// Вызываем конструктор для SafeRegistryHandle.
			// Класс SafeRegistryHandle появился в .NET 4.0
			Object safeHandle = safeRegistryHandleCtorInfo.Invoke(
				new Object[] { hKey, ownsHandle });

			Type registryKeyType = typeof(RegistryKey);
			// Получаем массив типов, соответствующих аргументом конструктора,
			// который нам нужен
			Type[] registryKeyConstructorTypes = new Type[] { 
				safeRegistryHandleType, typeof(bool) };
			// Получаем ConstructorInfo для нашего объекта
			System.Reflection.ConstructorInfo registryKeyCtorInfo =
				registryKeyType.GetConstructor(privateConstructors, null,
				registryKeyConstructorTypes, null);
			// Вызываем конструктор для RegistryKey
			RegistryKey resultKey = (RegistryKey)registryKeyCtorInfo.Invoke(
				new Object[] { safeHandle, writable });
			// возвращаем полученный ключ реестра
			return resultKey;
		}

		/// <summary>
		/// Получение числового значения указателя на искомый подраздел реестра.
		/// </summary>
		/// <param name="hKey">Указатель на родительский раздел реестра.</param>
		/// <param name="subKey">Имя искомого подраздела.</param>
		/// <param name="ulOptions">Этот параметр зарезервирован и всегда 
		/// должен быть равным 0.</param>
		/// <param name="samDesired">Права доступа (чтение\запись) и указание 
		/// того, как именно следует открывать реестр. Значение этого параметра
		/// формируется путём применения операции логического "И" для объектов
		/// перечислений RegistryRights и RegWow64Options.</param>
		/// <param name="phkResult">Ссылка на переменную, в которую следует 
		/// сохранить полученное числовое значение указателя на искомый 
		/// подраздел.</param>
		/// <returns></returns>
		[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
		public static extern Int32 RegOpenKeyEx(IntPtr hKey, String subKey,
			Int32 ulOptions, Int32 samDesired, out Int32 phkResult);
	}
	/// <summary>
	/// Перечисление указывает, какую именно часть реестра следует открывать:
	/// относящуюся к 32-битным приложениям или же относящуюся к 64-битным.
	/// </summary>
	public enum RegWow64Options {
		/// <summary>
		/// Открывать ту часть реестра, которая хранит информацию приложений,
		/// разрядность которых соответствует разрядности текущего приложения
		/// (x86\x64).
		/// </summary>
		None = 0,
		/// <summary>
		/// Открывать часть реестра, относящуюся к 64-битным приложениям.
		/// </summary>
		KEY_WOW64_64KEY = 0x0100,
		/// <summary>
		/// Открывать часть реестра, относящуюся к 32-битным приложениям.
		/// </summary>
		KEY_WOW64_32KEY = 0x0200
	}
	/// <summary>
	/// Перечисление, указывающее на то, с каким уровнем доступа следует 
	/// открывать ветку реестра: для чтения, или же для чтения\записи.
	/// </summary>
	public enum RegistryRights {
		/// <summary>
		/// Открыть только для чтения.
		/// </summary>
		ReadKey = 131097,
		/// <summary>
		/// Открыть для чтения и записи.
		/// </summary>
		WriteKey = 131078
	}
}
#endif
...
Рейтинг: 0 / 0
3 сообщений из 3, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Доступ к реестру x64 из приложения x86
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]