707 lines
18 KiB
C
707 lines
18 KiB
C
/****************************************************************************\
|
|
*
|
|
* Module Name : regapi.c
|
|
*
|
|
* Multimedia support library
|
|
*
|
|
* This module contains the code for accessing the registry
|
|
*
|
|
* Copyright (c) 1993 Microsoft Corporation
|
|
*
|
|
\****************************************************************************/
|
|
|
|
#define UNICODE
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include "winmmi.h"
|
|
|
|
HANDLE Drivers32Handle;
|
|
|
|
/*
|
|
** Free everything cached
|
|
*/
|
|
|
|
VOID mmRegFree(VOID)
|
|
{
|
|
if (Drivers32Handle != NULL) {
|
|
NtClose(Drivers32Handle);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Open a subkey
|
|
*/
|
|
HANDLE mmRegOpenSubkey(HANDLE BaseKeyHandle, LPCWSTR lpszSubkeyName)
|
|
{
|
|
UNICODE_STRING unicodeSectionName;
|
|
HANDLE KeyHandle;
|
|
OBJECT_ATTRIBUTES oa;
|
|
|
|
RtlInitUnicodeString(&unicodeSectionName, lpszSubkeyName);
|
|
InitializeObjectAttributes(&oa,
|
|
&unicodeSectionName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
BaseKeyHandle,
|
|
(PSECURITY_DESCRIPTOR)NULL);
|
|
|
|
/*
|
|
** Open the sub section
|
|
*/
|
|
|
|
if (!NT_SUCCESS(NtOpenKey(&KeyHandle, GENERIC_READ, &oa))) {
|
|
return NULL;
|
|
} else {
|
|
return KeyHandle;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
** Open a subkey
|
|
*/
|
|
HANDLE mmRegOpenSubkeyForWrite(HANDLE BaseKeyHandle, LPCWSTR lpszSubkeyName)
|
|
{
|
|
UNICODE_STRING unicodeSectionName;
|
|
HANDLE KeyHandle;
|
|
OBJECT_ATTRIBUTES oa;
|
|
|
|
RtlInitUnicodeString(&unicodeSectionName, lpszSubkeyName);
|
|
InitializeObjectAttributes(&oa,
|
|
&unicodeSectionName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
BaseKeyHandle,
|
|
(PSECURITY_DESCRIPTOR)NULL);
|
|
|
|
/*
|
|
** Open the sub section
|
|
*/
|
|
|
|
if (!NT_SUCCESS(NtOpenKey(&KeyHandle, MAXIMUM_ALLOWED, &oa))) {
|
|
return NULL;
|
|
} else {
|
|
return KeyHandle;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Read (small) registry data entries
|
|
*/
|
|
|
|
BOOL mmRegQueryValue(HANDLE BaseKeyHandle,
|
|
LPCWSTR lpszSubkeyName,
|
|
LPCWSTR lpszValueName,
|
|
ULONG dwLen,
|
|
LPWSTR lpszValue)
|
|
{
|
|
BOOL ReturnCode;
|
|
HANDLE KeyHandle;
|
|
UNICODE_STRING unicodeSectionName;
|
|
UNICODE_STRING unicodeValueName;
|
|
ULONG ResultLength;
|
|
|
|
struct {
|
|
KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
|
|
UCHAR Data[MAX_PATH * sizeof(WCHAR)];
|
|
} OurKeyValueInformation;
|
|
|
|
|
|
if (lpszSubkeyName) {
|
|
KeyHandle = mmRegOpenSubkey(BaseKeyHandle, lpszSubkeyName);
|
|
} else {
|
|
KeyHandle = NULL;
|
|
}
|
|
|
|
/*
|
|
** Read the data
|
|
*/
|
|
|
|
|
|
if (lpszValueName == NULL) {
|
|
RtlInitUnicodeString(&unicodeValueName, TEXT(""));
|
|
} else {
|
|
RtlInitUnicodeString(&unicodeValueName, lpszValueName);
|
|
}
|
|
|
|
ReturnCode = NT_SUCCESS(NtQueryValueKey(KeyHandle == NULL ?
|
|
BaseKeyHandle : KeyHandle,
|
|
&unicodeValueName,
|
|
KeyValuePartialInformation,
|
|
(PVOID)&OurKeyValueInformation,
|
|
sizeof(OurKeyValueInformation),
|
|
&ResultLength));
|
|
|
|
if (ReturnCode) {
|
|
/*
|
|
** Check we got the right type of data and not too much
|
|
*/
|
|
|
|
if (OurKeyValueInformation.KeyInfo.DataLength > dwLen * sizeof(WCHAR) ||
|
|
(OurKeyValueInformation.KeyInfo.Type != REG_SZ &&
|
|
OurKeyValueInformation.KeyInfo.Type != REG_EXPAND_SZ)) {
|
|
|
|
ReturnCode = FALSE;
|
|
} else {
|
|
/*
|
|
** Copy back the data
|
|
*/
|
|
|
|
if (OurKeyValueInformation.KeyInfo.Type == REG_EXPAND_SZ) {
|
|
lpszValue[0] = TEXT('\0');
|
|
ExpandEnvironmentStringsW
|
|
((LPCWSTR)OurKeyValueInformation.KeyInfo.Data,
|
|
(LPWSTR)lpszValue,
|
|
dwLen);
|
|
} else {
|
|
CopyMemory((PVOID)lpszValue,
|
|
(PVOID)OurKeyValueInformation.KeyInfo.Data,
|
|
dwLen * sizeof(WCHAR));
|
|
lpszValue[ min(OurKeyValueInformation.KeyInfo.DataLength,
|
|
dwLen-1) ] = TEXT('\0');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (KeyHandle) {
|
|
NtClose(KeyHandle);
|
|
}
|
|
|
|
return ReturnCode;
|
|
}
|
|
|
|
/*
|
|
** Read a mapped 'user' value in a known section
|
|
*/
|
|
|
|
BOOL mmRegQueryUserValue(LPCWSTR lpszSectionName,
|
|
LPCWSTR lpszValueName,
|
|
ULONG dwLen,
|
|
LPWSTR lpszValue)
|
|
{
|
|
HANDLE UserHandle;
|
|
BOOL ReturnCode;
|
|
|
|
/*
|
|
** Open the user's key. It's important to do this EACH time because
|
|
** on the server it's different for different threads.
|
|
*/
|
|
|
|
if (!NT_SUCCESS(RtlOpenCurrentUser(GENERIC_READ, &UserHandle))) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
ReturnCode = mmRegQueryValue(UserHandle,
|
|
lpszSectionName,
|
|
lpszValueName,
|
|
dwLen,
|
|
lpszValue);
|
|
|
|
NtClose(UserHandle);
|
|
|
|
return ReturnCode;
|
|
}
|
|
|
|
|
|
/*
|
|
** Set a mapped 'user' value in a known section
|
|
*/
|
|
|
|
BOOL mmRegSetUserValue(LPCWSTR lpszSectionName,
|
|
LPCWSTR lpszValueName,
|
|
LPCWSTR lpszValue)
|
|
{
|
|
HANDLE UserHandle;
|
|
BOOL ReturnCode = FALSE;
|
|
|
|
/*
|
|
** Open the user's key. It's important to do this EACH time because
|
|
** on the server it's different for different threads.
|
|
*/
|
|
|
|
if (NT_SUCCESS(RtlOpenCurrentUser(MAXIMUM_ALLOWED, &UserHandle)))
|
|
{
|
|
HANDLE KeyHandle;
|
|
|
|
KeyHandle = mmRegOpenSubkeyForWrite (UserHandle, lpszSectionName);
|
|
if (KeyHandle != NULL)
|
|
{
|
|
UNICODE_STRING ValueName;
|
|
if (lpszValueName == NULL) {
|
|
RtlInitUnicodeString (&ValueName, TEXT(""));
|
|
} else {
|
|
RtlInitUnicodeString (&ValueName, lpszValueName);
|
|
}
|
|
|
|
ReturnCode = NT_SUCCESS( NtSetValueKey (KeyHandle,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
(PVOID)lpszValue,
|
|
(lstrlenW(lpszValue)+1)* sizeof(lpszValue[0])
|
|
) );
|
|
NtClose(KeyHandle);
|
|
}
|
|
|
|
NtClose(UserHandle);
|
|
}
|
|
|
|
return ReturnCode;
|
|
}
|
|
|
|
|
|
BOOL mmRegCreateUserKey (LPCWSTR lpszPath, LPCWSTR lpszNewKey)
|
|
{
|
|
HANDLE UserHandle;
|
|
BOOL ReturnValue = FALSE;
|
|
|
|
/*
|
|
** Open the user's key. It's important to do this EACH time because
|
|
** on the server it's different for different threads.
|
|
*/
|
|
|
|
if (NT_SUCCESS(RtlOpenCurrentUser(MAXIMUM_ALLOWED, &UserHandle)))
|
|
{
|
|
HANDLE PathHandle;
|
|
HANDLE KeyHandle;
|
|
UNICODE_STRING unicodeSectionName;
|
|
OBJECT_ATTRIBUTES oa;
|
|
|
|
if (lpszPath == NULL)
|
|
{
|
|
PathHandle = NULL;
|
|
}
|
|
else
|
|
{
|
|
PathHandle = mmRegOpenSubkeyForWrite (UserHandle, lpszPath);
|
|
if (PathHandle == NULL)
|
|
{
|
|
NtClose(UserHandle);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
RtlInitUnicodeString(&unicodeSectionName, lpszNewKey);
|
|
InitializeObjectAttributes(&oa,
|
|
&unicodeSectionName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
(PathHandle == NULL)
|
|
? UserHandle : PathHandle,
|
|
(PSECURITY_DESCRIPTOR)NULL);
|
|
|
|
/*
|
|
** Create the sub section
|
|
*/
|
|
|
|
if (NT_SUCCESS( NtCreateKey(&KeyHandle,
|
|
KEY_READ | KEY_WRITE,
|
|
&oa,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
) ))
|
|
{
|
|
if (KeyHandle)
|
|
{
|
|
ReturnValue = TRUE;
|
|
NtClose (KeyHandle);
|
|
}
|
|
}
|
|
|
|
if (PathHandle != NULL)
|
|
{
|
|
NtClose(PathHandle);
|
|
}
|
|
|
|
NtClose(UserHandle);
|
|
}
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
|
|
/*
|
|
** Test whether a mapped 'user' key exists
|
|
*/
|
|
|
|
BOOL mmRegQueryUserKey (LPCWSTR lpszKeyName)
|
|
{
|
|
HANDLE UserHandle;
|
|
BOOL ReturnValue = FALSE;
|
|
|
|
if (lpszKeyName == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (NT_SUCCESS(RtlOpenCurrentUser(MAXIMUM_ALLOWED, &UserHandle)))
|
|
{
|
|
HANDLE KeyHandle;
|
|
|
|
KeyHandle = mmRegOpenSubkeyForWrite (UserHandle, lpszKeyName);
|
|
if (KeyHandle != NULL)
|
|
{
|
|
ReturnValue = TRUE;
|
|
NtClose(KeyHandle);
|
|
}
|
|
|
|
NtClose(UserHandle);
|
|
}
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
|
|
/*
|
|
** Delete a mapped 'user' key. Careful--this function deletes recursively!
|
|
*/
|
|
|
|
#define nMaxLevelsToRecurseInDELETEKEY 3 // don't runaway or stack fault
|
|
|
|
BOOL mmRegDeleteUserKeyRecurse (HANDLE UserHandle, LPCWSTR lpszName, int level)
|
|
{
|
|
HANDLE KeyHandle;
|
|
|
|
if (lpszName == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (level > nMaxLevelsToRecurseInDELETEKEY)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ((KeyHandle = mmRegOpenSubkeyForWrite (UserHandle, lpszName)) != NULL)
|
|
{
|
|
struct {
|
|
KEY_BASIC_INFORMATION kbi;
|
|
WCHAR NameBuffer [MAX_PATH];
|
|
} kbi;
|
|
|
|
/*
|
|
** Before NtDeleteKey() will work on this key, we have to ensure
|
|
** there are no subkeys.
|
|
*/
|
|
|
|
while (TRUE)
|
|
{
|
|
ULONG cbReturned = 0L;
|
|
WCHAR szSubKeyName[ MAX_PATH ];
|
|
|
|
ZeroMemory (&kbi, sizeof(kbi));
|
|
|
|
if (!NT_SUCCESS(NtEnumerateKey(KeyHandle,
|
|
0,
|
|
KeyBasicInformation,
|
|
(PVOID)&kbi,
|
|
sizeof(kbi),
|
|
&cbReturned)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
wsprintf (szSubKeyName, L"%ls\\%ls", lpszName, kbi.kbi.Name);
|
|
|
|
if (!mmRegDeleteUserKeyRecurse (UserHandle, szSubKeyName, 1+level))
|
|
{
|
|
NtClose (KeyHandle);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Once there are no subkeys, we should be able to delete this key.
|
|
*/
|
|
|
|
if (NT_SUCCESS(NtDeleteKey(KeyHandle)))
|
|
{
|
|
// no need to close the deleted keyhandle
|
|
return TRUE;
|
|
}
|
|
|
|
NtClose(KeyHandle);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL mmRegDeleteUserKey (LPCWSTR lpszKeyName)
|
|
{
|
|
HANDLE UserHandle;
|
|
BOOL ReturnValue = FALSE;
|
|
|
|
if (lpszKeyName == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (NT_SUCCESS(RtlOpenCurrentUser(MAXIMUM_ALLOWED, &UserHandle)))
|
|
{
|
|
ReturnValue = mmRegDeleteUserKeyRecurse (UserHandle, lpszKeyName, 1);
|
|
|
|
NtClose(UserHandle);
|
|
}
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
|
|
/*
|
|
** Read a mapped 'HKLM' value in a known section
|
|
*/
|
|
|
|
BOOL mmRegQueryMachineValue(LPCWSTR lpszSectionName,
|
|
LPCWSTR lpszValueName,
|
|
ULONG dwLen,
|
|
LPWSTR lpszValue)
|
|
{
|
|
WCHAR FullKeyName[MAX_PATH];
|
|
HANDLE HostHandle;
|
|
BOOL ReturnCode = FALSE;
|
|
|
|
lstrcpyW (FullKeyName, L"\\Registry\\Machine\\");
|
|
lstrcatW (FullKeyName, lpszSectionName);
|
|
|
|
if ((HostHandle = mmRegOpenSubkey (NULL, FullKeyName)) != NULL)
|
|
{
|
|
ReturnCode = mmRegQueryValue (HostHandle,
|
|
lpszSectionName,
|
|
lpszValueName,
|
|
dwLen,
|
|
lpszValue);
|
|
|
|
NtClose (HostHandle);
|
|
}
|
|
|
|
return ReturnCode;
|
|
}
|
|
|
|
|
|
/*
|
|
** Write a mapped 'HKLM' value in a known section
|
|
*/
|
|
|
|
BOOL mmRegSetMachineValue(LPCWSTR lpszSectionName,
|
|
LPCWSTR lpszValueName,
|
|
LPCWSTR lpszValue)
|
|
{
|
|
WCHAR FullKeyName[MAX_PATH];
|
|
HANDLE HostHandle;
|
|
BOOL ReturnCode = FALSE;
|
|
|
|
lstrcpyW (FullKeyName, L"\\Registry\\Machine\\");
|
|
lstrcatW (FullKeyName, lpszSectionName);
|
|
|
|
if ((HostHandle = mmRegOpenSubkeyForWrite (NULL, FullKeyName)) != NULL)
|
|
{
|
|
UNICODE_STRING ValueName;
|
|
if (lpszValueName == NULL) {
|
|
RtlInitUnicodeString (&ValueName, TEXT(""));
|
|
} else {
|
|
RtlInitUnicodeString (&ValueName, lpszValueName);
|
|
}
|
|
|
|
ReturnCode = NT_SUCCESS( NtSetValueKey (HostHandle,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
(PVOID)lpszValue,
|
|
(lstrlenW(lpszValue)+1)* sizeof(lpszValue[0])
|
|
) );
|
|
|
|
NtClose(HostHandle);
|
|
}
|
|
|
|
return ReturnCode;
|
|
}
|
|
|
|
|
|
BOOL mmRegCreateMachineKey (LPCWSTR lpszPath, LPCWSTR lpszNewKey)
|
|
{
|
|
WCHAR FullKeyName[MAX_PATH];
|
|
HANDLE HostHandle;
|
|
BOOL ReturnValue = FALSE;
|
|
|
|
lstrcpyW (FullKeyName, L"\\Registry\\Machine\\");
|
|
lstrcatW (FullKeyName, lpszPath);
|
|
|
|
if ((HostHandle = mmRegOpenSubkeyForWrite (NULL, FullKeyName)) != NULL)
|
|
{
|
|
HANDLE KeyHandle;
|
|
UNICODE_STRING unicodeSectionName;
|
|
OBJECT_ATTRIBUTES oa;
|
|
|
|
RtlInitUnicodeString(&unicodeSectionName, lpszNewKey);
|
|
InitializeObjectAttributes(&oa,
|
|
&unicodeSectionName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
HostHandle,
|
|
(PSECURITY_DESCRIPTOR)NULL);
|
|
|
|
/*
|
|
** Create the sub section
|
|
*/
|
|
|
|
if (NT_SUCCESS( NtCreateKey(&KeyHandle,
|
|
KEY_READ | KEY_WRITE,
|
|
&oa,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
) ))
|
|
{
|
|
if (KeyHandle)
|
|
{
|
|
ReturnValue = TRUE;
|
|
NtClose (KeyHandle);
|
|
}
|
|
}
|
|
|
|
NtClose(HostHandle);
|
|
}
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
** Read stuff from system.ini
|
|
*/
|
|
|
|
BOOL mmRegQuerySystemIni(LPCWSTR lpszSectionName,
|
|
LPCWSTR lpszValueName,
|
|
ULONG dwLen,
|
|
LPWSTR lpszValue)
|
|
{
|
|
WCHAR KeyPathBuffer[MAX_PATH];
|
|
|
|
/*
|
|
** Create the full path
|
|
*/
|
|
|
|
lstrcpy(KeyPathBuffer,
|
|
(LPCTSTR) L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\");
|
|
|
|
lstrcat(KeyPathBuffer, lpszSectionName);
|
|
|
|
if (lstrcmpiW(lpszSectionName, wszDrivers) == 0) {
|
|
if (Drivers32Handle == NULL) {
|
|
Drivers32Handle = mmRegOpenSubkey(NULL, KeyPathBuffer);
|
|
}
|
|
|
|
if (Drivers32Handle != NULL) {
|
|
return mmRegQueryValue(Drivers32Handle,
|
|
NULL,
|
|
lpszValueName,
|
|
dwLen,
|
|
lpszValue);
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return mmRegQueryValue(NULL, KeyPathBuffer, lpszValueName, dwLen, lpszValue);
|
|
}
|
|
|
|
/*
|
|
** Translate name through sounds section
|
|
*/
|
|
|
|
BOOL mmRegQuerySound(LPCWSTR lpszSoundName,
|
|
ULONG dwLen,
|
|
LPWSTR lpszValue)
|
|
{
|
|
WCHAR KeyPathBuffer[MAX_PATH];
|
|
|
|
lstrcpy(KeyPathBuffer, (LPCWSTR)L"Control Panel\\");
|
|
lstrcat(KeyPathBuffer, szSoundSection);
|
|
|
|
return mmRegQueryUserValue(KeyPathBuffer,
|
|
lpszSoundName,
|
|
dwLen,
|
|
lpszValue);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* MyGetPrivateProfileString
|
|
*
|
|
* Attempt to bypass stevewo's private profile stuff.
|
|
*
|
|
* History:
|
|
* dd-mm-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
DWORD
|
|
winmmGetPrivateProfileString(
|
|
LPCWSTR lpSection,
|
|
LPCWSTR lpKeyName,
|
|
LPCWSTR lpDefault,
|
|
LPWSTR lpReturnedString,
|
|
DWORD nSize,
|
|
LPCWSTR lpFileName
|
|
)
|
|
{
|
|
/*
|
|
** for now just look for to the [Drivers32] section of system.ini
|
|
*/
|
|
|
|
if ( (lstrcmpiW( lpFileName, wszSystemIni ) == 0L)
|
|
&& ( ( lstrcmpiW( lpSection, wszDrivers ) == 0L ) ||
|
|
lstrcmpiW( lpSection, (LPCWSTR)MCI_HANDLERS) == 0L ) ) {
|
|
|
|
if (mmRegQuerySystemIni(lpSection, lpKeyName, nSize, lpReturnedString)) {
|
|
return lstrlen(lpReturnedString);
|
|
} else {
|
|
if (lpDefault != NULL) {
|
|
wcsncpy(lpReturnedString, lpDefault, nSize);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
|
|
return GetPrivateProfileStringW( lpSection, lpKeyName, lpDefault,
|
|
lpReturnedString, nSize, lpFileName );
|
|
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
winmmGetProfileString(
|
|
LPCWSTR lpAppName,
|
|
LPCWSTR lpKeyName,
|
|
LPCWSTR lpDefault,
|
|
LPWSTR lpReturnedString,
|
|
DWORD nSize
|
|
)
|
|
{
|
|
|
|
/*
|
|
** See if it's one we know about
|
|
*/
|
|
|
|
if (lstrcmpiW(lpAppName, szSoundSection) == 0) {
|
|
|
|
if (mmRegQuerySound(lpKeyName, nSize, lpReturnedString)) {
|
|
return lstrlen(lpReturnedString);
|
|
} else {
|
|
if (lpDefault != NULL) {
|
|
wcsncpy(lpReturnedString, lpDefault, nSize);
|
|
}
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
return GetProfileString(lpAppName,
|
|
lpKeyName,
|
|
lpDefault,
|
|
lpReturnedString,
|
|
nSize);
|
|
}
|
|
}
|