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.
591 lines
18 KiB
591 lines
18 KiB
//
|
|
// REGSVAL.C
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995
|
|
//
|
|
// Implementation of RegSetValue, RegSetValueEx and supporting functions.
|
|
//
|
|
|
|
#include "pch.h"
|
|
|
|
//
|
|
// RgReAllocKeyRecord
|
|
//
|
|
|
|
int
|
|
INTERNAL
|
|
RgReAllocKeyRecord(
|
|
HKEY hKey,
|
|
DWORD Length,
|
|
LPKEY_RECORD FAR* lplpKeyRecord
|
|
)
|
|
{
|
|
|
|
int ErrorCode;
|
|
LPKEY_RECORD lpOldKeyRecord;
|
|
UINT BlockIndex;
|
|
UINT KeyRecordIndex;
|
|
LPDATABLOCK_INFO lpOldDatablockInfo;
|
|
LPKEYNODE lpKeynode;
|
|
|
|
if (Length > MAXIMUM_KEY_RECORD_SIZE) {
|
|
return ERROR_BIGKEY_NEEDED; // A big key is required
|
|
}
|
|
|
|
lpOldKeyRecord = *lplpKeyRecord;
|
|
|
|
BlockIndex = HIWORD(lpOldKeyRecord-> DatablockAddress);
|
|
KeyRecordIndex = LOWORD(lpOldKeyRecord-> DatablockAddress);
|
|
|
|
//
|
|
// Check if we can simply extend this key record by taking space from an
|
|
// adjacent free record.
|
|
//
|
|
|
|
if (RgExtendKeyRecord(hKey-> lpFileInfo, BlockIndex, (UINT) Length,
|
|
lpOldKeyRecord) == ERROR_SUCCESS)
|
|
return ERROR_SUCCESS;
|
|
|
|
//
|
|
// Check if there's enough space in the datablock lpCurrKeyRecord is in to
|
|
// contain a key record of the specified size. If so, then we don't have
|
|
// to dirty the keynode.
|
|
//
|
|
|
|
if (RgAllocKeyRecordFromDatablock(hKey-> lpFileInfo, BlockIndex,
|
|
(UINT) Length, lplpKeyRecord) == ERROR_SUCCESS) {
|
|
|
|
// After an alloc, we must refetch these pointers because they may be
|
|
// invalid.
|
|
lpOldDatablockInfo = RgIndexDatablockInfoPtr(hKey-> lpFileInfo,
|
|
BlockIndex);
|
|
lpOldKeyRecord = RgIndexKeyRecordPtr(lpOldDatablockInfo,
|
|
KeyRecordIndex);
|
|
|
|
// Transfer all the data to the new record, except for the allocated
|
|
// size which is already correctly set.
|
|
MoveMemory(&(*lplpKeyRecord)-> DatablockAddress, &lpOldKeyRecord->
|
|
DatablockAddress, SmallDword(lpOldKeyRecord-> RecordSize) -
|
|
sizeof(DWORD));
|
|
|
|
RgFreeKeyRecord(lpOldDatablockInfo, lpOldKeyRecord);
|
|
|
|
// Update the key record table to point to the new key record.
|
|
lpOldDatablockInfo-> lpKeyRecordTable[KeyRecordIndex] =
|
|
(KEY_RECORD_TABLE_ENTRY) ((LPBYTE) (*lplpKeyRecord) -
|
|
(LPBYTE) lpOldDatablockInfo-> lpDatablockHeader);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// Check if we can allocate a key record from another datablock. If so,
|
|
// then copy the key to the other datablock and update the keynode.
|
|
//
|
|
|
|
if (RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
|
|
&lpKeynode) == ERROR_SUCCESS) {
|
|
|
|
if ((ErrorCode = RgAllocKeyRecord(hKey-> lpFileInfo, (UINT) Length,
|
|
lplpKeyRecord)) == ERROR_SUCCESS) {
|
|
|
|
// After an alloc, we must refetch these pointers because they may
|
|
// be invalid.
|
|
lpOldDatablockInfo = RgIndexDatablockInfoPtr(hKey-> lpFileInfo,
|
|
BlockIndex);
|
|
lpOldKeyRecord = RgIndexKeyRecordPtr(lpOldDatablockInfo,
|
|
KeyRecordIndex);
|
|
|
|
// Transfer all the data to the new record, except for the
|
|
// allocated size which is already correctly set.
|
|
MoveMemory(&(*lplpKeyRecord)-> RecordSize, &lpOldKeyRecord->
|
|
RecordSize, SmallDword(lpOldKeyRecord-> RecordSize) -
|
|
(sizeof(DWORD) * 2));
|
|
|
|
RgFreeKeyRecord(lpOldDatablockInfo, lpOldKeyRecord);
|
|
RgFreeKeyRecordIndex(lpOldDatablockInfo, KeyRecordIndex);
|
|
|
|
// Unlock the old datablock.
|
|
RgUnlockDatablock(hKey-> lpFileInfo, BlockIndex, TRUE);
|
|
|
|
// Update the open key and keynode to point to the key record in
|
|
// the new datablock.
|
|
hKey-> BlockIndex = (*lplpKeyRecord)-> BlockIndex;
|
|
hKey-> BigKeyLockedBlockIndex = hKey-> BlockIndex;
|
|
lpKeynode-> BlockIndex = hKey-> BlockIndex;
|
|
hKey-> KeyRecordIndex = (BYTE) (*lplpKeyRecord)-> KeyRecordIndex;
|
|
lpKeynode-> KeyRecordIndex = hKey-> KeyRecordIndex;
|
|
|
|
}
|
|
|
|
RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, TRUE);
|
|
|
|
return ErrorCode;
|
|
|
|
}
|
|
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// RgSetValue
|
|
// (BIGKEY aware)
|
|
//
|
|
|
|
int
|
|
INTERNAL
|
|
RgSetValue(
|
|
HKEY hKey,
|
|
LPCSTR lpValueName,
|
|
DWORD Type,
|
|
LPBYTE lpData,
|
|
UINT cbData
|
|
)
|
|
{
|
|
int ErrorCode;
|
|
HKEY hKeyExtent;
|
|
UINT Index;
|
|
LPSTR ExtentKeyName;
|
|
DWORD cbExtentKeyName;
|
|
WORD NameID = 1;
|
|
WORD MaxNameID = 0;
|
|
LPKEY_RECORD lpKeyRecord;
|
|
LPVALUE_RECORD lpValueRecord;
|
|
LPKEYNODE lpKeynode;
|
|
BOOL fTryRoot = FALSE;
|
|
|
|
|
|
ErrorCode = RgSetValueStd(hKey, lpValueName, Type, lpData, cbData, FALSE);
|
|
|
|
if (ErrorCode == ERROR_BIGKEY_NEEDED)
|
|
{
|
|
//
|
|
// Couldn't fit the value in the key, make it a big key
|
|
// (if it isn't one already)
|
|
//
|
|
|
|
|
|
// First delete its old value if it exists
|
|
ErrorCode = RgLookupValueByName(hKey, lpValueName, &lpKeyRecord,
|
|
&lpValueRecord);
|
|
|
|
if (ErrorCode == ERROR_SUCCESS)
|
|
{
|
|
// If a value record already existed, and it was not in the root of the big key
|
|
// then we should try inserting the new value record into the root, after deleting
|
|
// it from its old location.
|
|
if (hKey-> BigKeyLockedBlockIndex != hKey-> BlockIndex)
|
|
fTryRoot = TRUE;
|
|
|
|
RgDeleteValueRecord(lpKeyRecord, lpValueRecord);
|
|
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex, TRUE);
|
|
}
|
|
else if (ErrorCode != ERROR_CANTREAD16_FILENOTFOUND32) {
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
if (IsNullPtr(ExtentKeyName = RgSmAllocMemory(MAXIMUM_SUB_KEY_LENGTH)))
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
// Second, search for room in each of the big key's extents
|
|
// (we should never mark the root with an LK_BIGKEYEXT, otherwise it won't be found
|
|
// by RgLookupKey and RgLookupKeyByIndex)
|
|
if ((hKey-> Flags & KEYF_BIGKEYROOT)) {
|
|
if (fTryRoot) {
|
|
// This happens if the value record previously existed in a big key extension,
|
|
// but the new value record doesn't fit in the same extension, so we want to try
|
|
// the root of the big key.
|
|
if ((ErrorCode = RgSetValueStd(hKey, lpValueName, Type, lpData, cbData, TRUE)) ==
|
|
ERROR_SUCCESS) {
|
|
goto lFreeKeyName;
|
|
}
|
|
}
|
|
|
|
Index = 0;
|
|
|
|
do {
|
|
cbExtentKeyName = MAXIMUM_SUB_KEY_LENGTH;
|
|
if (RgLookupKeyByIndex(hKey, Index++, ExtentKeyName, &cbExtentKeyName, LK_BIGKEYEXT) !=
|
|
ERROR_SUCCESS) {
|
|
goto lGrowKey;
|
|
}
|
|
|
|
NameID = RgAtoW(ExtentKeyName);
|
|
|
|
if (NameID > MaxNameID)
|
|
MaxNameID = NameID;
|
|
|
|
if (RgLookupKey(hKey, ExtentKeyName, &hKeyExtent, LK_OPEN | LK_BIGKEYEXT) != ERROR_SUCCESS) {
|
|
goto lGrowKey;
|
|
}
|
|
|
|
ErrorCode = RgSetValueStd(hKeyExtent, lpValueName, Type, lpData, cbData, TRUE);
|
|
|
|
RgDestroyKeyHandle(hKeyExtent);
|
|
|
|
} while (ErrorCode == ERROR_BIGKEY_NEEDED);
|
|
|
|
goto lFreeKeyName;
|
|
}
|
|
|
|
// Third, make it a big key, or if it is a big key, then grow it
|
|
lGrowKey:
|
|
// Create a unique name for the big key extent
|
|
if (MaxNameID)
|
|
NameID = MaxNameID + 1;
|
|
|
|
RgWtoA(NameID, ExtentKeyName);
|
|
|
|
if ((ErrorCode = RgLookupKey(hKey, ExtentKeyName, &hKeyExtent, LK_CREATE)) ==
|
|
ERROR_SUCCESS) {
|
|
|
|
// Mark the parent as the big key root, if it isn't already
|
|
if (!(hKey-> Flags & KEYF_BIGKEYROOT))
|
|
{
|
|
if ((ErrorCode = RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
|
|
&lpKeynode)) != ERROR_SUCCESS)
|
|
goto lFreeKeyName;
|
|
|
|
lpKeynode-> Flags |= KNF_BIGKEYROOT;
|
|
hKey-> Flags |= KEYF_BIGKEYROOT;
|
|
|
|
RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, TRUE);
|
|
}
|
|
|
|
// Mark the new key as a big key extent
|
|
if ((ErrorCode = RgLockInUseKeynode(hKeyExtent-> lpFileInfo, hKeyExtent-> KeynodeIndex,
|
|
&lpKeynode)) != ERROR_SUCCESS)
|
|
goto lFreeKeyName;
|
|
|
|
lpKeynode-> Flags |= KNF_BIGKEYEXT;
|
|
|
|
RgUnlockKeynode(hKeyExtent-> lpFileInfo, hKeyExtent-> KeynodeIndex, TRUE);
|
|
|
|
// Now add the value record to the new key
|
|
ErrorCode = RgSetValueStd(hKeyExtent, lpValueName, Type, lpData, cbData, TRUE);
|
|
|
|
ASSERT(ErrorCode != ERROR_BIGKEY_NEEDED);
|
|
RgDestroyKeyHandle(hKeyExtent);
|
|
}
|
|
|
|
lFreeKeyName:
|
|
RgSmFreeMemory(ExtentKeyName);
|
|
|
|
if (ErrorCode == ERROR_BIGKEY_NEEDED)
|
|
ErrorCode = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
return ErrorCode;
|
|
}
|
|
|
|
|
|
//
|
|
// RgSetValueStd
|
|
//
|
|
|
|
int
|
|
INTERNAL
|
|
RgSetValueStd(
|
|
HKEY hKey,
|
|
LPCSTR lpValueName,
|
|
DWORD Type,
|
|
LPBYTE lpData,
|
|
UINT cbData,
|
|
BOOL fBigKeyExtent
|
|
)
|
|
{
|
|
|
|
int ErrorCode;
|
|
UINT ValueNameLength;
|
|
UINT NewValueRecordLength;
|
|
LPKEY_RECORD lpKeyRecord;
|
|
LPVALUE_RECORD lpValueRecord;
|
|
UINT CurrentValueRecordLength;
|
|
LPBYTE lpDestination;
|
|
UINT BytesToExtend;
|
|
UINT TempCount;
|
|
LPKEYNODE lpKeynode;
|
|
|
|
ValueNameLength = (IsNullPtr(lpValueName) ? 0 : (UINT) StrLen(lpValueName));
|
|
|
|
if (ValueNameLength > MAXIMUM_VALUE_NAME_LENGTH - 1)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
NewValueRecordLength = sizeof(VALUE_RECORD) + ValueNameLength + cbData - 1;
|
|
|
|
if (!fBigKeyExtent) {
|
|
ErrorCode = RgLookupValueByName(hKey, lpValueName, &lpKeyRecord,
|
|
&lpValueRecord);
|
|
}
|
|
else {
|
|
// If we didn't find it searching from the root of a bigkey, then we won't
|
|
// find it beginning from an extent.
|
|
ErrorCode = ERROR_CANTREAD16_FILENOTFOUND32;
|
|
}
|
|
|
|
//
|
|
// A value with this name already exists, so update the existing
|
|
// VALUE_RECORD with the new information.
|
|
//
|
|
|
|
if (ErrorCode == ERROR_SUCCESS) {
|
|
|
|
CurrentValueRecordLength = sizeof(VALUE_RECORD) + lpValueRecord->
|
|
NameLength + lpValueRecord-> DataLength - 1;
|
|
|
|
// Is the value record staying the same?
|
|
if (NewValueRecordLength == CurrentValueRecordLength) {
|
|
if (lpValueRecord-> DataLength == cbData && lpValueRecord->
|
|
DataType == Type && CompareMemory((LPBYTE) lpValueRecord->
|
|
Name + ValueNameLength, lpData, cbData) == 0) {
|
|
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex, FALSE);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
// Is the value record shrinking?
|
|
if (NewValueRecordLength < CurrentValueRecordLength) {
|
|
lpKeyRecord-> RecordSize -= (CurrentValueRecordLength -
|
|
NewValueRecordLength);
|
|
}
|
|
|
|
// Is the value record growing?
|
|
else if (NewValueRecordLength > CurrentValueRecordLength) {
|
|
|
|
BytesToExtend = NewValueRecordLength - CurrentValueRecordLength;
|
|
|
|
// Does the value record fit in the allocated key size?
|
|
if (BytesToExtend > SmallDword(lpKeyRecord-> AllocatedSize) -
|
|
SmallDword(lpKeyRecord-> RecordSize)) {
|
|
|
|
TempCount = (LPBYTE) lpValueRecord - (LPBYTE) lpKeyRecord;
|
|
|
|
// Grow the key record
|
|
if ((ErrorCode = RgReAllocKeyRecord(hKey, lpKeyRecord->
|
|
RecordSize + BytesToExtend, &lpKeyRecord)) !=
|
|
ERROR_SUCCESS) {
|
|
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex,
|
|
FALSE);
|
|
return ErrorCode;
|
|
}
|
|
|
|
lpValueRecord = (LPVALUE_RECORD) ((LPBYTE) lpKeyRecord +
|
|
TempCount);
|
|
|
|
}
|
|
|
|
lpKeyRecord-> RecordSize += BytesToExtend;
|
|
|
|
}
|
|
|
|
lpDestination = (LPBYTE) lpValueRecord + NewValueRecordLength;
|
|
TempCount = (UINT) ((LPBYTE) lpKeyRecord + SmallDword(lpKeyRecord->
|
|
RecordSize) - lpDestination);
|
|
|
|
if (TempCount > 0) {
|
|
MoveMemory(lpDestination, (LPBYTE) lpValueRecord +
|
|
CurrentValueRecordLength, TempCount);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// No value exists with this name. Place a new VALUE_RECORD at the end of
|
|
// the KEY_RECORD.
|
|
//
|
|
|
|
else if (ErrorCode == ERROR_CANTREAD16_FILENOTFOUND32) {
|
|
|
|
// Handle Win95 registries that don't have a key record for the root
|
|
// key. We don't check if this is really the root key, but it doesn't
|
|
// matter much.
|
|
if (IsNullBlockIndex(hKey-> BlockIndex)) {
|
|
|
|
if (RgLockInUseKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex,
|
|
&lpKeynode) != ERROR_SUCCESS)
|
|
goto LockKeynodeFailed;
|
|
|
|
if (RgAllocKeyRecord(hKey-> lpFileInfo, sizeof(KEY_RECORD) +
|
|
NewValueRecordLength, &lpKeyRecord) != ERROR_SUCCESS) {
|
|
RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, FALSE);
|
|
LockKeynodeFailed:
|
|
TRAP();
|
|
return ERROR_CANTOPEN; // Win95 compatibility
|
|
}
|
|
|
|
lpKeyRecord-> RecordSize = sizeof(KEY_RECORD);
|
|
lpKeyRecord-> NameLength = 1; // Win95 compatibility
|
|
lpKeyRecord-> Name[0] = '\0'; // Win95 compatibility
|
|
lpKeyRecord-> ValueCount = 0;
|
|
lpKeyRecord-> ClassLength = 0;
|
|
lpKeyRecord-> Reserved = 0;
|
|
|
|
lpKeynode-> BlockIndex = lpKeyRecord-> BlockIndex;
|
|
lpKeynode-> KeyRecordIndex = lpKeyRecord-> KeyRecordIndex;
|
|
|
|
hKey-> BlockIndex = (WORD) lpKeynode-> BlockIndex;
|
|
hKey-> KeyRecordIndex = (BYTE) lpKeynode-> KeyRecordIndex;
|
|
|
|
RgUnlockKeynode(hKey-> lpFileInfo, hKey-> KeynodeIndex, TRUE);
|
|
|
|
ErrorCode = ERROR_SUCCESS;
|
|
goto AddValueRecord;
|
|
|
|
}
|
|
|
|
if ((ErrorCode = RgLockKeyRecord(hKey-> lpFileInfo, hKey-> BlockIndex,
|
|
hKey-> KeyRecordIndex, &lpKeyRecord)) == ERROR_SUCCESS) {
|
|
|
|
if (NewValueRecordLength > SmallDword(lpKeyRecord-> AllocatedSize) -
|
|
SmallDword(lpKeyRecord-> RecordSize)) {
|
|
|
|
if ((ErrorCode = RgReAllocKeyRecord(hKey, lpKeyRecord->
|
|
RecordSize + NewValueRecordLength, &lpKeyRecord)) !=
|
|
ERROR_SUCCESS) {
|
|
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex,
|
|
FALSE);
|
|
return ErrorCode;
|
|
}
|
|
|
|
}
|
|
|
|
AddValueRecord:
|
|
hKey-> BigKeyLockedBlockIndex = hKey-> BlockIndex;
|
|
lpValueRecord = (LPVALUE_RECORD) ((LPBYTE) lpKeyRecord +
|
|
SmallDword(lpKeyRecord-> RecordSize));
|
|
lpKeyRecord-> RecordSize += NewValueRecordLength;
|
|
lpKeyRecord-> ValueCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If we're successful at this point, then lpValueRecord is valid and we
|
|
// should copy the data into this record.
|
|
//
|
|
|
|
if (ErrorCode == ERROR_SUCCESS) {
|
|
|
|
lpValueRecord-> DataType = Type;
|
|
|
|
lpValueRecord-> NameLength = (WORD) ValueNameLength;
|
|
MoveMemory(lpValueRecord-> Name, lpValueName, ValueNameLength);
|
|
|
|
lpValueRecord-> DataLength = (WORD) cbData;
|
|
MoveMemory((LPBYTE) lpValueRecord-> Name + ValueNameLength, lpData,
|
|
cbData);
|
|
|
|
RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex, TRUE);
|
|
|
|
}
|
|
|
|
return ErrorCode;
|
|
|
|
}
|
|
|
|
//
|
|
// VMMRegSetValueEx
|
|
//
|
|
// See Win32 documentation of RegSetValueEx.
|
|
//
|
|
|
|
LONG
|
|
REGAPI
|
|
VMMRegSetValueEx(
|
|
HKEY hKey,
|
|
LPCSTR lpValueName,
|
|
DWORD Reserved,
|
|
DWORD Type,
|
|
LPBYTE lpData,
|
|
DWORD cbData
|
|
)
|
|
{
|
|
|
|
int ErrorCode;
|
|
|
|
if (IsBadOptionalStringPtr(lpValueName, (UINT) -1))
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
//
|
|
// bad Windows 95 compatibility problem. If the type is REG_SZ,
|
|
// then override cbData with the length of the string pointed to by lpData.
|
|
// This should have only been done in RegSetValue, but we're stuck with it
|
|
// now...
|
|
//
|
|
|
|
if (Type == REG_SZ) {
|
|
if (IsBadStringPtr(lpData, (UINT) -1))
|
|
return ERROR_INVALID_PARAMETER;
|
|
cbData = StrLen(lpData);
|
|
|
|
// Must leave room for the null terminator
|
|
if (cbData >= MAXIMUM_DATA_LENGTH)
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
else {
|
|
if (cbData > 0 && IsBadHugeReadPtr(lpData, cbData))
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (cbData > MAXIMUM_DATA_LENGTH)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
if (!RgLockRegistry())
|
|
return ERROR_LOCK_FAILED;
|
|
|
|
if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) == ERROR_SUCCESS) {
|
|
if (IsDynDataKey(hKey) || (hKey-> lpFileInfo-> Flags & FI_READONLY))
|
|
ErrorCode = ERROR_ACCESS_DENIED;
|
|
else {
|
|
if ((ErrorCode = RgSetValue(hKey, lpValueName, Type, lpData,
|
|
(UINT) cbData)) == ERROR_SUCCESS) {
|
|
RgSignalWaitingNotifies(hKey-> lpFileInfo, hKey-> KeynodeIndex,
|
|
REG_NOTIFY_CHANGE_LAST_SET);
|
|
}
|
|
}
|
|
}
|
|
|
|
RgUnlockRegistry();
|
|
|
|
return ErrorCode;
|
|
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
}
|
|
|
|
//
|
|
// VMMRegSetValue
|
|
//
|
|
// See Win32 documentation of RegSetValue.
|
|
//
|
|
|
|
LONG
|
|
REGAPI
|
|
VMMRegSetValue(
|
|
HKEY hKey,
|
|
LPCSTR lpSubKey,
|
|
DWORD Type,
|
|
LPBYTE lpData,
|
|
DWORD cbData
|
|
)
|
|
{
|
|
|
|
LONG ErrorCode;
|
|
HKEY hSubKey;
|
|
|
|
if ((ErrorCode = RgCreateOrOpenKey(hKey, lpSubKey, &hSubKey, LK_CREATE)) ==
|
|
ERROR_SUCCESS) {
|
|
ErrorCode = VMMRegSetValueEx(hSubKey, NULL, 0, REG_SZ, lpData, 0);
|
|
VMMRegCloseKey(hSubKey);
|
|
}
|
|
|
|
return ErrorCode;
|
|
|
|
UNREFERENCED_PARAMETER(Type);
|
|
UNREFERENCED_PARAMETER(cbData);
|
|
|
|
}
|