Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

403 lines
13 KiB

  1. /******************************************************************************
  2. *
  3. * $RCSfile: DrvReg.cpp $
  4. * $Source: u:/si/VXP/Wdm/Classes/DrvReg.cpp $
  5. * $Author: Max $
  6. * $Date: 1998/09/28 23:22:38 $
  7. * $Revision: 1.5 $
  8. *
  9. * Written by: Max Paklin
  10. * Purpose: Implementation of registry class
  11. *
  12. *******************************************************************************
  13. *
  14. * Copyright 1996-98, AuraVision Corporation. All rights reserved.
  15. *
  16. * AuraVision Corporation makes no warranty of any kind, express or implied,
  17. * with regard to this software. In no event shall AuraVision Corporation
  18. * be liable for incidental or consequential damages in connection with or
  19. * arising from the furnishing, performance, or use of this software.
  20. *
  21. * Tab step is to be set to 4 to achive the best readability for this code.
  22. *
  23. *******************************************************************************/
  24. #include "Comwdm.h"
  25. #pragma hdrstop
  26. // Convert GUID to WCHAR (or WCHAR to GUID) string MAX_GUIDLENGTH characters
  27. void CKsRegKey::GuidToWChar( const GUID guid, LPWSTR pwszString )
  28. {
  29. UNICODE_STRING usString;
  30. usString.Length = 0;
  31. usString.MaximumLength = MAX_GUIDLENGTH*sizeof( WCHAR );
  32. usString.Buffer = pwszString;
  33. RtlStringFromGUID( guid, &usString );
  34. }
  35. NTSTATUS CKsRegKey::WCharToGuid( LPCWSTR pwszString, GUID guid )
  36. {
  37. UNICODE_STRING usString;
  38. usString.Length = (wcslen( pwszString )+1)*sizeof( WCHAR );
  39. usString.MaximumLength = MAX_GUIDLENGTH*sizeof( WCHAR );
  40. usString.Buffer = (PWSTR)pwszString;
  41. return RtlGUIDFromString( &usString, &guid );
  42. }
  43. // Constructor helper function
  44. void CKsRegKey::Create( LPCWSTR pwszKey, LPCWSTR pwszSubKey,
  45. PVOID hHandle, PDEVICE_OBJECT pDeviceObject )
  46. {
  47. int nLength;
  48. // Calculating the length of key
  49. if( pwszKey )
  50. nLength = wcslen( pwszKey )+1;
  51. else
  52. nLength = 0;
  53. if( pwszSubKey )
  54. nLength += wcslen( pwszSubKey )+1;
  55. if( nLength > 0 )
  56. {
  57. // Allocating memory for key
  58. m_pwszKey = (PWCHAR)ExAllocatePool( PagedPool, nLength*sizeof( WCHAR ) );
  59. if( m_pwszKey == NULL )
  60. {
  61. DebugPrint(( DebugLevelFatal, "%s: out of memory\n", __FILE__ ));
  62. DEBUG_BREAKPOINT();
  63. }
  64. else
  65. {
  66. if( pwszKey )
  67. wcscpy( m_pwszKey, pwszKey );
  68. else
  69. wcscpy( m_pwszKey, L"" );
  70. if( pwszSubKey )
  71. wcscat( m_pwszKey, pwszSubKey );
  72. }
  73. }
  74. else
  75. m_pwszKey = NULL;
  76. m_hHandle = hHandle;
  77. m_pDeviceObject = pDeviceObject;
  78. }
  79. // Helper function that is used to get currently used registry path to get/set values.
  80. // Returned values are used as a parameters to RtlQueryRegistryValues/RtlWriteRegistryValues.
  81. // The first parameter is flag (first parameter) to abovementioned Windows' registry
  82. // functions. It can be or RTL_REGISTRY_HANDLE or RTL_REGISTRY_ABSOLUTE. The first one means
  83. // that return value of this function is actually handle of registry key, while the second
  84. // tells caller that return value is absolute registry key string. The last parameter is
  85. // used to store registry key to close if it was temporary opened
  86. PWSTR CKsRegKey::GetInputData( PULONG puRelativeTo, PHANDLE phHandleToDelete,
  87. ACCESS_MASK amDesiredAccess, BOOL bCreateHandle )
  88. {
  89. *phHandleToDelete = NULL;
  90. PWSTR pKey = NULL;
  91. NTSTATUS ntStatus;
  92. if( m_hHandle || bCreateHandle )
  93. {
  94. // We have handle to key to work with. Open specified subkey and return it telling
  95. // that it is handle and that subkey should be closed when it is not needed
  96. *puRelativeTo = RTL_REGISTRY_HANDLE;
  97. if( m_pwszKey && wcslen( m_pwszKey ) > 0 )
  98. {
  99. HANDLE hHandle;
  100. OBJECT_ATTRIBUTES objAttr;
  101. UNICODE_STRING usValue;
  102. RtlInitUnicodeString( &usValue, m_pwszKey );
  103. InitializeObjectAttributes( &objAttr, &usValue, OBJ_CASE_INSENSITIVE, m_hHandle, NULL );
  104. if( (ntStatus = ZwOpenKey( &hHandle, amDesiredAccess, &objAttr )) == STATUS_SUCCESS )
  105. {
  106. // Subkey was successfully opened, so mark it as "to be released when
  107. // it is not needed anymore"
  108. *phHandleToDelete = hHandle;
  109. pKey = (PWSTR)hHandle;
  110. }
  111. else
  112. DebugPrint(( DebugLevelWarning, "ZwOpenKey() failed: 0x%X\n", ntStatus ));
  113. }
  114. else
  115. pKey = (PWSTR)m_hHandle;
  116. }
  117. else if( m_pDeviceObject )
  118. {
  119. // We have handle to driver key and we are going to work with data store under it.
  120. // Open specified subkey and return it telling that it is handle and that subkey
  121. // should be closed when it is not needed
  122. *puRelativeTo = RTL_REGISTRY_HANDLE;
  123. // First open key for our device object
  124. ntStatus = IoOpenDeviceRegistryKey( (PDEVICE_OBJECT)m_pDeviceObject, PLUGPLAY_REGKEY_DRIVER,
  125. amDesiredAccess, phHandleToDelete );
  126. if( ntStatus == STATUS_SUCCESS )
  127. {
  128. if( m_pwszKey && wcslen( m_pwszKey ) > 0 )
  129. {
  130. // Subkey specified. So open it and mark it as "to be released when
  131. // it is not needed anymore"
  132. HANDLE hHandle = NULL;
  133. OBJECT_ATTRIBUTES objAttr;
  134. UNICODE_STRING usValue;
  135. RtlInitUnicodeString( &usValue, m_pwszKey );
  136. InitializeObjectAttributes( &objAttr, &usValue, OBJ_CASE_INSENSITIVE,
  137. *phHandleToDelete, NULL );
  138. if( ZwOpenKey( &hHandle, amDesiredAccess, &objAttr ) == STATUS_SUCCESS )
  139. pKey = (PWSTR)hHandle;
  140. ZwClose( *phHandleToDelete );
  141. *phHandleToDelete = hHandle;
  142. }
  143. else
  144. pKey = (PWSTR)(*phHandleToDelete);
  145. }
  146. else
  147. DebugPrint(( DebugLevelWarning, "IoOpenDeviceRegistryKey() failed: 0x%X\n", ntStatus ));
  148. }
  149. else if( m_pwszKey )
  150. {
  151. // We have registry key object created as an absolute path to registry key
  152. *puRelativeTo = RTL_REGISTRY_ABSOLUTE;
  153. pKey = m_pwszKey;
  154. }
  155. return pKey;
  156. }
  157. // Set textual and integer values to registry key
  158. BOOL CKsRegKey::SetValue( LPCWSTR pwszValue, LPCWSTR pwszSetTo )
  159. {
  160. if( IsKey() )
  161. {
  162. ULONG uRelativeTo;
  163. HANDLE hHandleToDelete;
  164. PWSTR pKey = GetInputData( &uRelativeTo, &hHandleToDelete, KEY_WRITE );
  165. if( pKey )
  166. {
  167. NTSTATUS ntStatus = RtlWriteRegistryValue( uRelativeTo, pKey, pwszValue, REG_SZ,
  168. (PVOID)pwszSetTo, (wcslen( pwszSetTo )+1)*sizeof( WCHAR ) );
  169. // Close key after the information is read and the key is not needed anymore
  170. if( hHandleToDelete )
  171. {
  172. ZwClose( hHandleToDelete );
  173. }
  174. #ifdef DEBUG
  175. if( ntStatus != STATUS_SUCCESS )
  176. {
  177. DebugPrint(( DebugLevelWarning, "RtlWriteRegistryValue() failed: 0x%X\n", ntStatus ));
  178. }
  179. #endif // DEBUG
  180. return (BOOL)(ntStatus == STATUS_SUCCESS);
  181. }
  182. }
  183. return FALSE;
  184. }
  185. BOOL CKsRegKey::SetValue( LPCWSTR pwszValue, int nSetTo )
  186. {
  187. if( IsKey() )
  188. {
  189. ULONG uRelativeTo;
  190. HANDLE hHandleToDelete;
  191. PWSTR pKey = GetInputData( &uRelativeTo, &hHandleToDelete, KEY_WRITE );
  192. if( pKey )
  193. {
  194. DWORD dwSetTo = (DWORD)nSetTo;
  195. NTSTATUS ntStatus = RtlWriteRegistryValue( uRelativeTo, pKey, pwszValue,
  196. REG_DWORD, &dwSetTo, sizeof( dwSetTo ) );
  197. // Close key after the information is read and the key is not needed anymore
  198. if( hHandleToDelete )
  199. {
  200. ZwClose( hHandleToDelete );
  201. }
  202. #ifdef DEBUG
  203. if( ntStatus != STATUS_SUCCESS )
  204. {
  205. DebugPrint(( DebugLevelWarning, "RtlWriteRegistryValue() failed: 0x%X\n", ntStatus ));
  206. }
  207. #endif // DEBUG
  208. return (BOOL)(ntStatus == STATUS_SUCCESS);
  209. }
  210. }
  211. return FALSE;
  212. }
  213. // Get string and integer value from key. We use this a little bit ugly technique because
  214. // it is the easiest way to do what we want to do. The optimal way would be to put all the
  215. // nessessary data to a number of RTL_QUERY_REGISTRY_TABLE tables and read all of them
  216. // at once but it would be inconvinient for user of this class
  217. BOOL CKsRegKey::GetValue( LPCWSTR pwszGetFrom, LPWSTR pwszValue,
  218. USHORT ushSize, LPCWSTR pwszDefault )
  219. {
  220. BOOL bResult = FALSE;
  221. if( IsKey() )
  222. {
  223. ULONG uRelativeTo;
  224. HANDLE hHandleToDelete;
  225. PWSTR pKey = GetInputData( &uRelativeTo, &hHandleToDelete, KEY_READ );
  226. if( pKey )
  227. {
  228. RTL_QUERY_REGISTRY_TABLE qTable[2];
  229. UNICODE_STRING usValue, usDefault;
  230. NTSTATUS ntStatus;
  231. // Prepare UNICODE strings for buffer to put data into and for default value
  232. usValue.Length = 0;
  233. usValue.MaximumLength = ushSize;
  234. usValue.Buffer = pwszValue;
  235. RtlInitUnicodeString( &usDefault, pwszDefault );
  236. RtlZeroMemory( qTable, sizeof( qTable ) );
  237. qTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  238. qTable[0].Name = (PWSTR)pwszGetFrom;
  239. qTable[0].EntryContext = &usValue;
  240. qTable[0].DefaultType = REG_SZ;
  241. qTable[0].DefaultData = &usDefault;
  242. qTable[0].DefaultLength = 0;
  243. ntStatus = RtlQueryRegistryValues( uRelativeTo, pKey, qTable, NULL, NULL );
  244. if( ntStatus == STATUS_SUCCESS )
  245. bResult = TRUE;
  246. else
  247. DebugPrint(( DebugLevelWarning, "RtlQueryRegistryValues() failed: 0x%X\n", ntStatus ));
  248. // Close key after the information is read and the key is not needed anymore
  249. if( hHandleToDelete )
  250. ZwClose( hHandleToDelete );
  251. }
  252. }
  253. return bResult;
  254. }
  255. BOOL CKsRegKey::GetValue( LPCWSTR pwszGetFrom, PDWORD pdwValue, ULONG ulSize )
  256. {
  257. BOOL bResult = FALSE;
  258. if( IsKey() )
  259. {
  260. ULONG uRelativeTo;
  261. HANDLE hHandleToDelete;
  262. PWSTR pKey = GetInputData( &uRelativeTo, &hHandleToDelete, KEY_READ, TRUE );
  263. if( pKey )
  264. {
  265. ULONG ulReadSize;
  266. UNICODE_STRING usName;
  267. // Here we will be using the nasty trick. Use user's buffer not only for data that
  268. // user requested but also for storing KEY_VALUE_PARTIAL_INFORMATION structure.
  269. // ZwQueryValueKey() will fill out KEY_VALUE_PARTIAL_INFORMATION structure that
  270. // will contain real data at the end of it. All that we have to do is to move the
  271. // tail with data to the beginning of the user's buffer. Of course, it introduces
  272. // potential danger when, for example, user provides buffer of size of 20 bytes for
  273. // reading the data that is 15 bytes long. In this example only a few bytes of
  274. // registry data will be read. However it is not as ugly as it could seem at a first
  275. // glance because in this case we will return FALSE to the user to signal that the
  276. // buffer size is probably not enough for storing the data ('ulSize > ulReadSize'
  277. // check will do it). Therefore the size of buffer should be greater or equal to
  278. // RealSizeOfRegistryData+sizeof( KEY_VALUE_PARTIAL_INFORMATION )-
  279. // sizeof( KEY_VALUE_PARTIAL_INFORMATION.Data )+1
  280. ASSERT( ulSize > sizeof( KEY_VALUE_PARTIAL_INFORMATION ) );
  281. PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)pdwValue;
  282. ASSERT( hHandleToDelete );
  283. RtlInitUnicodeString( &usName, pwszGetFrom );
  284. NTSTATUS ntStatus = ZwQueryValueKey( (HANDLE)pKey, &usName, KeyValuePartialInformation,
  285. pKeyInfo, ulSize, &ulReadSize );
  286. if( ntStatus != STATUS_SUCCESS )
  287. DebugPrint(( DebugLevelWarning, "ZwQueryValueKey() failed: 0x%X\n", ntStatus ));
  288. else if( ulSize > ulReadSize )
  289. {
  290. // We succeeded only if the read size is less than the size of our buffer.
  291. // Otherwise the size of data in registry could be bigger than supplied buffer
  292. bResult = TRUE;
  293. // Move the actual data at the beginning of user's buffer
  294. ASSERT( pKeyInfo->Type == REG_BINARY );
  295. ULONG ulDataLength = pKeyInfo->DataLength;
  296. PBYTE pbData = (PBYTE)&pKeyInfo->Data, pbValue = (PBYTE)pdwValue;
  297. for( ULONG i = 0; i < ulDataLength; i++, pbData++, pbValue++ )
  298. *pbValue = *pbData;
  299. #ifdef _DEBUG
  300. for( ; i < ulSize; i++, pbValue++ )
  301. *pbValue = 0;
  302. #endif
  303. }
  304. // Close key after the information is read and the key is not needed anymore
  305. if( hHandleToDelete )
  306. ZwClose( hHandleToDelete );
  307. }
  308. }
  309. return bResult;
  310. }
  311. BOOL CKsRegKey::GetValue( LPCWSTR pwszGetFrom, long& lValue, long lDefault )
  312. {
  313. BOOL bResult = FALSE;
  314. if( IsKey() )
  315. {
  316. ULONG uRelativeTo;
  317. HANDLE hHandleToDelete;
  318. PWSTR pKey = GetInputData( &uRelativeTo, &hHandleToDelete, KEY_READ );
  319. if( pKey )
  320. {
  321. RTL_QUERY_REGISTRY_TABLE qTable[2];
  322. DWORD dwData = 0;
  323. NTSTATUS ntStatus;
  324. RtlZeroMemory( qTable, sizeof( qTable ) );
  325. qTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  326. qTable[0].Name = (PWSTR)pwszGetFrom;
  327. qTable[0].EntryContext = &dwData;
  328. qTable[0].DefaultType = REG_DWORD;
  329. qTable[0].DefaultData = &lDefault;
  330. qTable[0].DefaultLength = sizeof( lDefault );
  331. ntStatus = RtlQueryRegistryValues( uRelativeTo, pKey, qTable, NULL, NULL );
  332. if( ntStatus == STATUS_SUCCESS )
  333. {
  334. lValue = (int)dwData;
  335. bResult = TRUE;
  336. }
  337. else
  338. DebugPrint(( DebugLevelWarning, "RtlQueryRegistryValues() failed: 0x%X\n", ntStatus ));
  339. // Close key after the information is read and the key is not needed anymore
  340. if( hHandleToDelete )
  341. ZwClose( hHandleToDelete );
  342. }
  343. }
  344. return bResult;
  345. }
  346. // Delete registry subkey
  347. void DeleteSubKey( LPWSTR pwszKey, LPCWSTR pwszSubKey )
  348. {
  349. if( pwszKey )
  350. {
  351. HANDLE hHandle;
  352. OBJECT_ATTRIBUTES objAttr;
  353. UNICODE_STRING usKey;
  354. RtlInitUnicodeString( &usKey, pwszKey );
  355. RtlZeroMemory( &objAttr, sizeof( objAttr ) );
  356. objAttr.Length = sizeof( objAttr );
  357. objAttr.ObjectName = &usKey;
  358. NTSTATUS ntStatus = ZwOpenKey( &hHandle, KEY_SET_VALUE | KEY_CREATE_SUB_KEY, &objAttr );
  359. if( ntStatus == STATUS_SUCCESS )
  360. {
  361. ntStatus = ZwDeleteKey( hHandle );
  362. ASSERT( ntStatus == STATUS_SUCCESS );
  363. }
  364. else
  365. DebugPrint(( DebugLevelWarning, "ZwOpenKey() failed: 0x%X\n", ntStatus ));
  366. }
  367. }