I have the following code:
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
int main(int argc, wchar_t*argv[])
{
std::locale::global(std::locale("spanish"));
/*Declaración de variables*/
HKEY hKey = HKEY_CURRENT_USER;
LPCTSTR lpSubKey = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU");
DWORD ulOptions = 0;
REGSAM samDesired = KEY_READ | KEY_WRITE;
HKEY phkResult;
DWORD dwIndex = 0;
TCHAR lpValueName[16383];
DWORD lpcchValueName = 16383;
LPTSTR lpData="";
long OpenK = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &phkResult);
if (OpenK == ERROR_SUCCESS)
{
long R = RegEnumValue(phkResult, dwIndex, lpValueName, &lpcchValueName, NULL, NULL,(LPBYTE)lpData, NULL);
if (R == ERROR_SUCCESS)
{
cout << "The value and data is: \n" << lpValueName << ": " << lpData << endl;
//printf(TEXT("(%d) %s\n"), lpValueName);
}
else
cout << "Error: " << R << endl;
}
else if (OpenK == ERROR_FILE_NOT_FOUND)
{
cout << "La sub-clave RunMRU no existe." << endl;
}
else if (OpenK == ERROR_ACCESS_DENIED)
{
cout << "Acceso denegado al abrir la sub-clave RunMRU." << endl;
}
else
{
cout << "Error al abrir la clave de registro. Código: " << OpenK << endl;
}
system("Pause");
}
I am trying to show both, the Value name, and its Data using the RegEnumValue in the first if (The value and data is:) but I can only show the Value name.
Is there any way to do that? I'm trying to figure out how to use the lpData, but I can't because I only receive error 87 (Incorrect parameters) or nothing (If I set NULL instead).
You're not providing a suitable buffer for RegEnumValue() to store the data.
LPTSTR lpData="";
This is just a string literal, of at most 2 bytes in size, and is almost certainly not writable anyway. You need to allocate an area of memory and pass that to RegEnumValue() to read the data back for each value.
Your first step should be to use RegQueryInfoKey() to find out how big the largest data value is. I showed you how to use this function in a previous answer to query the size of the largest value name - the process is the same. See the docs for RegQueryInfoKey() to find out which parameter provides the data size.
Once you know how big your largest item of data is, allocate a buffer for it:
void* pData = malloc(dwLargestValueSize);
// remember this buffer needs to be freed at the end with free()
You then pass that buffer, plus a value indicating its size, to RegEnumValue().
Something else you need to be aware of is that registry values can be different types - REG_DWORD, REG_SZ, etc, and the data you get back from RegEnumValue() is the raw data. RegEnumValue() can also return a value indicating the type of data and if you're to properly interpret it, you absolutely need to check this as well.
Changes to your code to get a string value into lpData:
#define MAX_DATA_LENGTH 16383
char* lpData = new char[MAX_DATA_LENGTH];
DWORD lpDataLength = MAX_DATA_LENGTH;
RegEnumValue(phkResult, dwIndex, lpValueName, &lpcchValueName, NULL, NULL, (unsigned char*)lpData, &lpDataLength);
Related
The below code can correctly read Registry values from various different keys, however whenever I try to read a value from a key under Winlogon it will either come up as "not found" or it will return a completely wrong value. The code is ran as admin, and compiled with Visual Studio 2017.
HKEY registryHandle = NULL;
int registryResult = NULL;
DWORD dataType;
TCHAR dataBuffer[1024] = {};
DWORD bufferSize = sizeof(dataBuffer);
registryResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_QUERY_VALUE, ®istryHandle);
if (registryResult != ERROR_SUCCESS) {
std::cout << "Error: " << registryResult << std::endl;
return false;
}
registryResult = RegQueryValueEx(registryHandle, L"LastUsedUsername", NULL, NULL, (LPBYTE)dataBuffer, &bufferSize);
if (registryResult != ERROR_SUCCESS) {
std::cout << "Error2: " << registryResult << std::endl;
return false;
}
std::cout << "Data Size: " << bufferSize << std::endl;
for (int i = 0; i < 256; i++) {
if (dataBuffer[i] == NULL) { break; }
std::cout << (char)dataBuffer[i];
}
std::cin.get();
RegCloseKey(registryHandle);
Registry value that I'm trying to read:
Below refers to Remy's suggested solution.
RegQueryValueEx Returns a buffer size of 4 with an output of 18754 17236 0 52428
You are clearly calling the Unicode version of the Registry functions, so you should be using WCHAR instead of TCHAR for your data buffer.
And you should not be truncating the characters to char at all. Use std::wcout instead of std::cout for printing out Unicode strings. And use the returned bufferSize to know how many WCHARs were actually output. Your printing loop is ignoring the bufferSize completely, so it is possible that you are actually printing out random garbage that RegQueryValueEx() did not actually intend for you to use (hence why lpcbData parameter is an in/out parameter, so you know how many bytes are actually valid).
You are also leaking the opened HKEY handle if RegQueryValueEx() fails.
Try something more like this instead:
HKEY registryHandle;
int registryResult;
registryResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_QUERY_VALUE, ®istryHandle);
if (registryResult != ERROR_SUCCESS) {
std::cout << "Error: " << registryResult << std::endl;
return false;
}
WCHAR dataBuffer[1024];
DWORD bufferSize = sizeof(dataBuffer);
// TODO: consider using RegGetValueW() instead, which is safer
// when it comes to reading string values from the Registry...
registryResult = RegQueryValueExW(registryHandle, L"LastUsedUsername", NULL, NULL, (LPBYTE)dataBuffer, &bufferSize);
RegCloseKey(registryHandle);
if (registryResult != ERROR_SUCCESS) {
std::cout << "Error2: " << registryResult << std::endl;
return false;
}
DWORD len = bufferSize / sizeof(WCHAR);
if ((len > 0) && (dataBuffer[len-1] == L'\0')) {
--len;
}
std::cout << "Data Byte Size: " << bufferSize << std::endl;
std::cout << "Data Character Length: " << len << std::endl;
std::wcout.write(dataBuffer, len);
std::cin.get();
return true;
That being said, on my machine, there is no LastUsedUsername value in the Winlogon key you are accessing, so getting a "not found" error is a very likely possibility. But you definately need to handle
Background:
I'm trying to write a C++ application that can scan for and attempt to restore deleted files from a WinPE environment, mostly as a learning exercise. This app utilizes the FMAPI library (fmapi.dll), which is a scarcely-documented library that only works in a WinPE environment (does not work in a full Windows OS). I've been using the ScanRestorableFiles example released by MS (available here) as a starting point.
Now, I've done a LOT of digging and have found next to nothing when it comes to FMAPI documentation - just the sample noted above and some basic MSDN docs here. The MSDN pages provide the definitions for the API functions and a few extra notes on a couple of the functions that provide a hint or two, but that's it. So I thought I'd come here in hopes of finding some assistance.
Also please note, as far as development languages go, C++ is not my strong point - I would consider myself novice at best.
Now to the issue at hand:
My app is able to successfully load the library, create the file restore context and scan for restorable files. However, once I try to call the RestoreFile() function on one of the restorable items that was returned by the ScanRestorableFiles() call, I get an Invalid Handle error. The "restored file" ends up being a 0-byte file (it does get created successfully in the proper place) with no data in it.
Interestingly, even after returning the Invalid Handle error code, my app holds a handle open on the file until the file restore context is closed (I know this because if I try to read the restored file immediately after attempting to restore it, I get a "file is in use by another process" error).
Posted below is the entire code for my app (its just a single source file, not counting headers and such) - since this seems to be a rarely-used API, I feel like I should post the whole thing to add context to each function call (and also because I'm not quite sure exactly what may or may not be relevant to the issue I'm having).
Code:
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>
#include <stdlib.h>
#define SCAN_PATH L"\\"
//
//Define the needed FMAPI structures as documented in FMAPI
//
#define FILE_RESTORE_MAJOR_VERSION_2 0x0002
#define FILE_RESTORE_MINOR_VERSION_2 0x0000
#define FILE_RESTORE_VERSION_2 ((FILE_RESTORE_MAJOR_VERSION_2 << 16) | FILE_RESTORE_MINOR_VERSION_2)
using namespace std;
//External API function declarations
//We don't have an import library or
//header for the FMAPI functions, so
//we must dynamically link to them at
//runtime.
typedef PVOID PFILE_RESTORE_CONTEXT;
typedef enum {
ContextFlagVolume = 0x00000001,
ContextFlagDisk = 0x00000002,
FlagScanRemovedFiles = 0x00000004,
FlagScanRegularFiles = 0x00000008,
FlagScanIncludeRemovedDirectories = 0x00000010
} RESTORE_CONTEXT_FLAGS;
typedef enum {
FileRestoreProgressInfo = 100,
FileRestoreFinished = 101
} FILE_RESTORE_PACKET_TYPE, *PFILE_RESTORE_PACKET_TYPE;
typedef BOOL (WINAPI *FuncCreateFileRestoreContext) (
_In_ PCWSTR Volume,
_In_ RESTORE_CONTEXT_FLAGS Flags,
_In_ LONGLONG StartSector,
_In_ LONGLONG BootSector,
_In_ DWORD Version,
_Out_ PFILE_RESTORE_CONTEXT* Context
);
typedef BOOL (WINAPI *FuncCloseFileRestoreContext) (
_In_ PFILE_RESTORE_CONTEXT Context
);
typedef struct _RESTORABLE_FILE_INFO
{
ULONG Size;
DWORD Version;
ULONGLONG FileSize;
FILETIME CreationTime;
FILETIME LastAccessTime;
FILETIME LastWriteTime;
DWORD Attributes;
BOOL IsRemoved;
LONGLONG ClustersUsedByFile;
LONGLONG ClustersCurrentlyInUse;
ULONG RestoreDataOffset;
WCHAR FileName[1]; // Single-element array indicates a variable-length structure
} RESTORABLE_FILE_INFO, *PRESTORABLE_FILE_INFO;
typedef struct _FILE_RESTORE_PROGRESS_INFORMATION {
LONGLONG TotalFileSize;
LONGLONG TotalBytesCompleted;
LONGLONG StreamSize;
LONGLONG StreamBytesCompleted;
PVOID ClbkArg;
} FILE_RESTORE_PROGRESS_INFORMATION, *PFILE_RESTORE_PROGRESS_INFORMATION;
typedef struct _FILE_RESTORE_FINISHED_INFORMATION {
BOOL Success;
ULONG FinalResult;
PVOID ClbkArg;
} FILE_RESTORE_FINISHED_INFORMATION, *PFILE_RESTORE_FINISHED_INFORMATION;
typedef BOOL (WINAPI *FuncScanRestorableFiles) (
_In_ PFILE_RESTORE_CONTEXT Context,
_In_ PCWSTR Path,
_In_ ULONG FileInfoSize,
_Out_bytecap_(FileInfoSize) PRESTORABLE_FILE_INFO FileInfo,
_Out_ PULONG FileInfoUsed
);
typedef BOOLEAN (*FILE_RESTORE_CALLBACK) (
_In_ FILE_RESTORE_PACKET_TYPE PacketType,
_In_ ULONG PacketLength,
_In_ PVOID PacketData
);
typedef BOOL (WINAPI *FuncRestoreFile) (
_In_ PFILE_RESTORE_CONTEXT Context,
_In_ PRESTORABLE_FILE_INFO RestorableFile,
_In_ PCWSTR DstFile,
_In_opt_ FILE_RESTORE_CALLBACK Callback,
_In_opt_ PVOID ClbkArg
);
HMODULE hLib;
wchar_t VOLUME[255];
BOOLEAN FuncRestoreCallback(_In_ FILE_RESTORE_PACKET_TYPE pType, _In_ ULONG pLength, _In_ PVOID pData)
{
// This is the callback that is passed to RestoreFile(), which
// returns data about the status of an attempted restoration.
if (pType == FileRestoreProgressInfo)
{
wcout << L"FILE RESTORE PROGRESS INFO:" << L"\n";
wprintf(L"Length of status data: %lu\n", pLength);
wcout << L"Location of data: " << pData << L"\n";
PFILE_RESTORE_PROGRESS_INFORMATION restoreProgressInfo = static_cast<PFILE_RESTORE_PROGRESS_INFORMATION>(pData);
wprintf(L"Total file size: %lld\n", restoreProgressInfo->TotalFileSize);
wprintf(L"Total bytes completed: %lld\n", restoreProgressInfo->TotalBytesCompleted);
wprintf(L"Stream size: %lld\n", restoreProgressInfo->StreamSize);
wprintf(L"Stream bytes completed: %lld\n", restoreProgressInfo->StreamBytesCompleted);
//wcout << L"Callback arg data: " << restoreProgressInfo->ClbkArg << L"\n";
wprintf(L"Callback arg: %p\n", restoreProgressInfo->ClbkArg);
}
else if (pType == FileRestoreFinished)
{
wcout << L"FILE RESTORE FINISHED INFO:" << L"\n";
wprintf(L"Length of status data: %lu\n", pLength);
wcout << L"Location of data: " << pData << L"\n";
// Obtain the struct
PFILE_RESTORE_FINISHED_INFORMATION restoreFinishedInfo = static_cast<PFILE_RESTORE_FINISHED_INFORMATION>(pData);
// Try to read some data from it
wprintf(L"Success data: %d\n", restoreFinishedInfo->Success);
wprintf(L"Final result data: %lu\n", restoreFinishedInfo->FinalResult);
wprintf(L"Callback arg: %p\n", restoreFinishedInfo->ClbkArg);
}
return TRUE;
}
void Scan(_In_ PFILE_RESTORE_CONTEXT context, _In_ LPCWSTR path)
{
// This is the main function that scans the files
// Dynamically link to the needed FMAPI functions
FuncScanRestorableFiles ScanRestorableFiles;
ScanRestorableFiles = reinterpret_cast<FuncScanRestorableFiles>( GetProcAddress( hLib, "ScanRestorableFiles" ) );
ULONG neededBufferSize = 0;
BOOL success = TRUE;
RESTORABLE_FILE_INFO tempFileInfo;
// Call ScanRestorableFiles the first time with a size of 0 to get the required buffer size
if ( ! ScanRestorableFiles(context, path, 0, &tempFileInfo, &neededBufferSize) )
{
wprintf(L"Failed to retrieve required buffer size, Error: #%u\n", GetLastError());
return;
}
// Create the buffer needed to hold restoration information
BYTE *buffer = new BYTE[neededBufferSize];
wcout << L"Initial buffer size is: " << neededBufferSize << L"\n";
// Loops until an error occurs or no more files found
while (success)
{
// Cast the byte buffer pointer into a structure pointer
PRESTORABLE_FILE_INFO fileInfo = reinterpret_cast<PRESTORABLE_FILE_INFO>(buffer);
#pragma warning( push )
#pragma warning( disable : 6386 ) /* warning is ignored since fileInfo grows in size by design */
success = ScanRestorableFiles(context, path, neededBufferSize, fileInfo, &neededBufferSize);
#pragma warning( pop )
wcout << L"Current buffer size is: " << neededBufferSize << L"\n";
if (success)
{
wcout << L"Call returned success! Required buffer size from latest call is " << neededBufferSize <<
L" bytes." L"\n";
if (fileInfo->IsRemoved)
{
// Found restorable file
wprintf(L"Restorable file found: %s\n", fileInfo->FileName);
// Echo size of char array containing file name
wcout << L"Restorable file name size: " <<
(sizeof(fileInfo->FileName) / sizeof(fileInfo->FileName[0])) << L"\n";
// Echo RESTORABLE_FILE_INFO structure info to console
wcout << L"Restorable file info structure memory address: " << fileInfo << L"\n";
wcout << L"Restorable file info structure size (returned via RESTORABLE_FILE_INFO): " << fileInfo->Size << L"\n";
wcout << L"Restorable file info structure size (returned via sizeof()): " << sizeof(*fileInfo) << L"\n";
// Echo restorable file (FMAPI) version to console
wcout << L"Restorable file version: " << fileInfo->Version << L"\n";
// Retrieve creation, write and access times for the file
// Define temp FILETIME, SYSTEMTIME and TIME_ZONE_INFORMATION
// structure vars
// All of these types and functions are defined in windows.h
FILETIME tmpFT;
SYSTEMTIME tmpST;
TIME_ZONE_INFORMATION tmpTZI;
// Initialize empty char arrays
wchar_t szLocalDate[255] = {0}, szLocalTime[255] = {0};
// Get local time zone info
SetTimeZoneInformation(&tmpTZI);
// Get file creation time
FileTimeToLocalFileTime(&(fileInfo->CreationTime), &tmpFT);
FileTimeToSystemTime(&tmpFT, &tmpST);
// Format to readable output and store in char arrays
GetDateFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, DATE_LONGDATE, &tmpST, NULL, szLocalDate, 255, NULL);
GetTimeFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, 0, &tmpST, NULL, szLocalTime, 255);
wcout << L"Restorable file created: " << szLocalDate << " " << szLocalTime << L"\n";
// Clear array for re-use
fill(begin(szLocalDate), end(szLocalDate), 0);
// Get last write time
FileTimeToLocalFileTime(&(fileInfo->LastWriteTime), &tmpFT);
FileTimeToSystemTime(&tmpFT, &tmpST);
// Format to readable output and store in char arrays
GetDateFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, DATE_LONGDATE, &tmpST, NULL, szLocalDate, 255, NULL);
GetTimeFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, 0, &tmpST, NULL, szLocalTime, 255);
wcout << L"Restorable file last written: " << szLocalDate << " " << szLocalTime << L"\n";
// Clear array for re-use
fill(begin(szLocalDate), end(szLocalDate), 0);
// Get last access time
FileTimeToLocalFileTime(&(fileInfo->LastAccessTime), &tmpFT);
FileTimeToSystemTime(&tmpFT, &tmpST);
// Format to readable output and store in char arrays
GetDateFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, DATE_LONGDATE, &tmpST, NULL, szLocalDate, 255, NULL);
GetTimeFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, 0, &tmpST, NULL, szLocalTime, 255);
wcout << L"Restorable file last accessed: " << szLocalDate << " " << szLocalTime << L"\n";
// Output the rest of the file info
wcout << L"Restorable file attributes: " << fileInfo->Attributes << L"\n";
wcout << L"Restorable file size: " << fileInfo->FileSize << L"\n";
wcout << L"Restorable file ClustersUsedByFile: " << fileInfo->ClustersUsedByFile << L"\n";
wcout << L"Restorable file ClustersCurrentlyInUse: " << fileInfo->ClustersCurrentlyInUse << L"\n";
wcout << L"Restorable file RestoreDataOffset: " << fileInfo->RestoreDataOffset << L"\n";
// Attempt to restore the file
wstring tmpStr;
getline(wcin, tmpStr);
// Convert input to uppercase
for (wstring::size_type i = 0; i < tmpStr.size(); i++)
{
towupper(tmpStr[i]);
}
wcout << L"tmpStr is: " << tmpStr << L"\n";
if (tmpStr == L"RESTORE")
{
// Attempt to restore the file
wcout << L"Attempting to restore file " << fileInfo->FileName << L"..." << L"\n";
FuncRestoreFile RestoreFile;
//RestoreFile = (FuncRestoreFile)GetProcAddress( hLib, "RestoreFile" );
RestoreFile = reinterpret_cast<FuncRestoreFile>(GetProcAddress(hLib, "RestoreFile"));
wcout << L"RestoreFile address: " << RestoreFile << L"\n";
BOOL tmpRetVal = false;
PCWSTR restoredFileName = L"X:\\testfile.txt";
wcout << L"New file name: " << restoredFileName << L"\n";
PVOID cbArg = NULL;
tmpRetVal = RestoreFile(context, fileInfo, restoredFileName, &FuncRestoreCallback, cbArg);
wcout << L"Return value: " << tmpRetVal << L" ; cbArg: " << cbArg << L"\n";
if (tmpRetVal == 0)
{
wcout << L"Error was: " << GetLastError() << L"\n";
}
}
else if (tmpStr == L"CLOSE")
{
// Abort the scanning process and close the file restore context
wcout << L"Aborting scan and closing file restore context..." << L"\n";
success = false;
}
}
}
else
{
DWORD err = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == err)
{
wcout << L"Insufficient buffer size! Current size is " << sizeof(buffer) << L" bytes; " <<
L" required size is " << neededBufferSize << L" bytes. Resizing..." << L"\n";
delete [] buffer;
buffer = new BYTE[neededBufferSize];
success = true;
}
else if (ERROR_NO_MORE_FILES == err)
{
wprintf(L"Scanning Complete.\n");
success = false;
}
else
{
wprintf(L"ScanRestorableFiles, Error #%u.\n", err);
}
}
}
delete [] buffer;
buffer = NULL;
}
//
// Program entry point
//
void __cdecl wmain(int argc, wchar_t *argv[])
{
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
// Load the FMAPI DLL
hLib = ::LoadLibraryEx(L"fmapi.dll", NULL, NULL);
if ( !hLib )
{
wprintf(L"Could not load fmapi.dll. Error #%u.\n", GetLastError());
return;
}
// Dynamically link to the needed FMAPI functions
FuncCreateFileRestoreContext CreateFileRestoreContext;
CreateFileRestoreContext = reinterpret_cast<FuncCreateFileRestoreContext>( GetProcAddress( hLib, "CreateFileRestoreContext" ) );
FuncCloseFileRestoreContext CloseFileRestoreContext;
CloseFileRestoreContext = reinterpret_cast<FuncCloseFileRestoreContext>( GetProcAddress( hLib, "CloseFileRestoreContext" ) );
// Set the flags value for which kind of items we want to scan for
RESTORE_CONTEXT_FLAGS flags;
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
switch (argc)
{
case 2:
{
if (wcslen(argv[1]) < (sizeof(VOLUME) / sizeof(VOLUME[0]))) // ensure that argv[1] is not >255 chars long
{
wcscpy_s(VOLUME, argv[1]);
}
else
{
wcscpy_s(VOLUME, 255, argv[1]);
}
wcout << L"Volume set to: " << VOLUME << L"\n";
wcout << L"Defaulting to VOLUME search type; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
break;
}
case 3:
{
if (wcslen(argv[1]) < (sizeof(VOLUME) / sizeof(VOLUME[0]))) // ensure that argv[1] is not >255 chars long
{
wcscpy_s(VOLUME, argv[1]);
}
else // if it is, only copy the first 255 chars
{
wcscpy_s(VOLUME, 255, argv[1]);
}
int len;
// Get length of second argument passed by the user
len = wcslen(argv[2]);
// Allocate new wchar_t array big enough to hold it
wchar_t *tmpArg = new (nothrow) wchar_t[len + 1];
// Ensure that the memory was allocated successfully
if (tmpArg == nullptr)
{
// Error allocating memory - bail out
wcout << L"Error allocating memory! Bailing out..." << L"\n";
return;
}
// Copy the argument string from argv to tmpArg
wcscpy_s(tmpArg, len + 1, argv[2]);
// Convert to uppercase
_wcsupr_s(tmpArg, len + 1);
// Check whether VOLUME or DISK search type was specified and set flags accordingly
if (wcscmp(tmpArg, L"VOLUME") == 0)
{
wcout << L"Volume set to: " << VOLUME << L"\n";
if (wcschr(VOLUME, L':') != NULL)
{
wcout << L"VOLUME search type specified; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
}
else
{
wcout << L"VOLUME search type specified, but the volume identifier given doesn't appear " <<
L"to be a valid mounted volume! Please check your arguments and try again." << L"\n";
delete [] tmpArg;
return;
}
}
else if (wcscmp(tmpArg, L"DISK") == 0)
{
wcout << L"Disk set to: " << VOLUME << L"\n";
if (wcschr(VOLUME, L':') == NULL)
{
wcout << L"DISK search type specified; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagDisk | FlagScanRemovedFiles);
}
else
{
wcout << L"DISK search type specified, but the disk identifier given doesn't appear " <<
L"to be a valid physical disk! Please check your arguments and try again." << L"\n";
delete [] tmpArg;
return;
}
}
else
{
wcout << L"UNKNOWN search type specified! Defaulting to VOLUME; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
}
delete [] tmpArg;
break;
}
default:
{
// Set the default volume to scan here
wcscpy_s(VOLUME, L"\\\\.\\D:");
wcout << L"No arguments specified! Defaulting to VOLUME search of \\\\.\\D:" << L"\n";
break;
}
}
// Create the FileRestoreContext
PFILE_RESTORE_CONTEXT context = NULL;
if ( ! CreateFileRestoreContext(VOLUME, flags, 0, 0, FILE_RESTORE_VERSION_2, &context) )
{
DWORD err = GetLastError();
wprintf(L"Failed to Create FileRestoreContext, Error #%u.\n", err);
return;
}
else
{
wcout << L"Success! File restore context created! Value of context is: " << context << L"\n";
}
// Find restorable files starting at the given directory
Scan(context, SCAN_PATH);
// Close the context
if (context)
{
CloseFileRestoreContext(context);
context = NULL;
}
}
Please note this is still a very rudimentary app in its beginning stages. It basically begins a scan, defaulting (if no args are given) to scanning the D:\ drive and attempting to restore a deleted file to X:\testfile.txt. For those that may not be familiar with WinPE, X: is the system drive in a WinPE environment, and D: is usually the letter assigned to the OS drive of the machine that is booted to PE while in the PE environment, depending on the setup, with C: being the system reserved partition.
For each restorable file found, it pauses, and if the user enters the text "RESTORE" and hits ENTER, it will attempt to restore the file (this takes place around line 247). The callback function that indicates status for the restoration returns error code 6 (via FinalResult), as does GetLastError().
Any help on this is very much appreciated!
Following is the code:
#include <windows.h>
#include <iostream>
using namespace std;
#define WIN_32_LEAN_AND_MEAN
void readValueFromRegistry(void)
{
HKEY hKey;
DWORD lRv;
LPCWSTR subKey = L"SYSTEM\\CurrentControlSet\\Services\\HRM";
lRv = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
subKey,
0,
KEY_READ ,
&hKey
);
if (lRv == ERROR_SUCCESS)
{
DWORD BufferSize = sizeof(DWORD);
DWORD dwRet;
DWORD cbData = 10;
DWORD lpType;
wchar_t cbVal[10];
cout<<"Value before calling RegQueryValueEx is " << cbVal << endl;
dwRet = RegQueryValueEx(
hKey,
L"DataBaseIn",
NULL,
&lpType,
reinterpret_cast<LPBYTE>(cbVal),
&cbData
);
if( lpType == REG_SZ )
cout << "Reg_SZ" <<endl;
if( dwRet == ERROR_SUCCESS )
cout<<"Value is " << cbVal << endl;
else cout<<"RegQueryValueEx failed " << dwRet << endl;
}
}
int main()
{
readValueFromRegistry();
cin.get();
return 0;
}
The output is :
Value before calling RegQueryValueEx is 0030F810
Reg_SZ
Value is 0030F810
So RegQueryValueEx returns ERROR_SUCCESS, and returns the type of the value also correctly in the lpType(the Reg_SZ). But I dont get the value in the buffer.
It always seems to hold the garbage values.
What could be the issue and how to solve?
FYI: The key I am trying to access is created by a windows service developed by me. And DataBaseIn is the value I am trying to access:
The char buffer should be initialized not only declared.
wchar_t cbVal[10] = L"";
Should use wcout to print unicode strings:
wcout << cbVal ;
I have trouble making this code I found work for me.
Now: It adds 2 DWORD values the the Interface folder (registry key) in registry.
Desired: I would want it to add those 2 DWORD values to ALL the subkeys (subfolders) of the Interface registry key (folder).
I have got this pseudo code:
Open the parent key with RegOpenKey or RegOpenKeyEx
Enumerate all of the child keys of the parent using RegEnumKey or RegEnumKeyEx in a loop
For each child key, set the desired value with RegSetValueEx
Close the parent key with RegCloseKey
I'll keep trying to get this sorted, but maybe someone can help?
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <iostream>
using std::cout;
using std::endl;
HKEY OpenKey(HKEY hRootKey, wchar_t* strKey)
{
HKEY hKey;
LONG nError = RegOpenKeyEx(hRootKey, strKey, NULL, KEY_ALL_ACCESS, &hKey);
if(nError==ERROR_FILE_NOT_FOUND)
{
cout << "Creating registry key: " << strKey << endl;
nError = RegCreateKeyEx(hRootKey, strKey, NULL, NULL, REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL, &hKey, NULL);
}
if(nError)
{
cout << "Error: " << nError << " Could not find or create " << strKey << endl;
}
return hKey;
}
void SetVal(HKEY hKey, LPCTSTR lpValue, DWORD data)
{
LONG nError = RegSetValueEx(hKey, lpValue, NULL, REG_DWORD, (LPBYTE)&data, sizeof(DWORD));
if(nError)
{
cout << "Error: " << nError << " Could not set registry value: " << (char*)lpValue << endl;
}
}
DWORD GetVal(HKEY hKey, LPCTSTR lpValue)
{
DWORD data;
DWORD size = sizeof(data);
DWORD type = REG_DWORD;
LONG nError = RegQueryValueEx(hKey, lpValue, NULL, &type, (LPBYTE)&data, &size);
if(nError==ERROR_FILE_NOT_FOUND)
{
data = 0; // The value will be created and set to data next time SetVal() is called.
}
else if(nError)
{
cout << "Error: " << nError << " Could not get registry value " << (char*)lpValue << endl;
}
return data;
}
int main()
{
static DWORD v1, v2;
HKEY hKey = OpenKey(HKEY_LOCAL_MACHINE,L"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces\\");
v1 = GetVal(hKey, L"Registry Value1");
v2 = GetVal(hKey, L"Registry Value2");
v1 += 5;
v2 += 2;
SetVal(hKey, L"Registry Value1", v1);
SetVal(hKey, L"Registry Value2", v2);
RegCloseKey(hKey);
return 0;
}
Here's a bare minimum example without any extras:
// open desired key whose subkeys shall be enumerated
HKEY hKey={0};
LPCTSTR path=TEXT("SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces");
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,path,0,KEY_ENUMERATE_SUB_KEYS,&hKey) != ERROR_SUCCESS)
return; // failed to open
DWORD index=0; // enumeration index
TCHAR keyName[256]={0}; // buffer to store enumerated subkey name
DWORD keyLen=256; // buffer length / number of TCHARs copied to keyName
// enumerate subkey names of hKey, result stored in keyName, keyLen set to strlen(keyName)
while(RegEnumKeyEx(hKey,index++,keyName,&keyLen,0,0,0,0) == ERROR_SUCCESS) {
keyLen=256; // reset buffer length (RegEnumKeyEx changes this value)
// open the subkey and set the desired value(s)
HKEY hSubKey={0};
if(RegOpenKeyEx(hKey,keyName,0,KEY_SET_VALUE,&hSubKey) == ERROR_SUCCESS) {
// set desired value(s):
DWORD myValue = 0xCAFEBABE;
//RegSetValueEx(hSubKey,TEXT("MyValueName"),0,REG_DWORD,(LPBYTE)&myValue,sizeof(DWORD));
RegCloseKey(hSubKey); // close sub key
}
// else: failed to open subkey
}
// RegEnumKeyEx either returns ERROR_SUCCESS, ERROR_NO_MORE_ITEMS, or a system error code
RegCloseKey(hKey); // close key
Please note, this example does not evaluate error codes. It simply demonstrates the process of enumerating sub keys and setting a value. The RegOpenKeyEx access rights are set to the minimum required to perform this task (set them to whatever you wish to do with the opened keys). The while loop does not distinct from ERROR_NO_MORE_ITEMS (once there are no more subkeys to enumerate) or an actual error. RegSetValueEx is commented out for safety and its return value is ignored.
What code add to this function to work good? (ERROR_SUCCESS)
I have code, that check value in registry.
In function RegQueryValueEx is bug.
When oldValue is few letters longer than newValue, function shows ERROR_MORE_DATA, but I want want ERROR_SUCCESS
What code add to this function to do this?
void function(string newValue, string key, string name)
{
// string key - key in registry, ie Myapp\\Options
// string name - name in registry
// string newValue - data in REG_SZ
string oldValue;
DWORD keytype = REG_SZ;
HKEY keyHandle;
DWORD size = sizeof(string);
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, key.c_str(),0L,KEY_ALL_ACCESS,&keyHandle) == ERROR_SUCCESS)
{
LONG isgood = RegQueryValueEx(keyHandle, name.c_str(), 0, &keytype, (LPBYTE)&oldValue, &size);
if(isgood == ERROR_MORE_DATA)
{
cout << "Error more data\n";
}
if(isgood == ERROR_SUCCESS)
{
cout << "Old data is " << oldValue.c_str() << endl;
cout << "New data is " << newValue.c_str() << endl;
if(strcmp(newValue.c_str(), oldValue.c_str()) != 0) // compare 2 strings, if
{
cout << "String 1 and string 2 are different";
}
else
{
cout << "String 1 and string 2 are the same";
}
}
if(isgood == ERROR_FILE_NOT_FOUND)
{
cout << "Name in registry not found!";
}
}
}
ERROR_MORE_DATA means that you need to pass in a larger string buffer. The typical pattern you'll need to use is to call once to get the size, then allocate a properly-sized buffer, then call again. Or, alternatively, you can guess at a size, pass in that-sized buffer, and increase size if you get ERROR_MORE_DATA back.
BTW, you are also computing size incorrectly. And you're not closing the registry key. And you're not prepared to support being compiled under unicode or non-unicode modes.
Here's some revised code which addresses these issues.
#include <string>
#include <vector>
#include <iostream>
#include <windows.h>
using namespace std;
namespace std
{
#ifdef _UNICODE
#define tcout wcout
#define tcin wcin
typedef wstring tstring;
#else
#define tcout cout
#define tcin cin
typedef string tstring;
#endif
};
void function(tstring newValue, tstring key, tstring name)
{
// string key - key in registry, ie Myapp\\Options
// string name - name in registry
// string newValue - data in REG_SZ
HKEY keyHandle;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, key.c_str(),0L,KEY_ALL_ACCESS,&keyHandle) == ERROR_SUCCESS)
{
DWORD size = 500; // initial size
vector<TCHAR> buf(size);
tstring oldValue;
DWORD keytype = REG_SZ;
LONG isgood = RegQueryValueEx(keyHandle, name.c_str(), 0, &keytype, (LPBYTE) &buf[0], &size);
if(isgood == ERROR_SUCCESS)
{
oldValue.assign (&buf[0], size);
}
else if(isgood == ERROR_MORE_DATA)
{
buf.reserve (size); // expand to however large we need
isgood = RegQueryValueEx(keyHandle, name.c_str(), 0, &keytype, (LPBYTE)&buf[0], &size);
if(isgood == ERROR_SUCCESS)
oldValue.assign (&buf[0], size);
}
RegCloseKey (keyHandle); // remember to close this!
if(isgood == ERROR_SUCCESS)
{
tcout << _T("Old data is ") << oldValue << endl;
tcout << _T("New data is ") << newValue << endl;
if(newValue.compare(oldValue) != 0) // compare 2 strings, if
{
tcout << _T("String 1 and string 2 are different");
}
else
{
tcout << _T("String 1 and string 2 are the same");
}
}
if(isgood == ERROR_FILE_NOT_FOUND)
{
tcout << _T("Name in registry not found!");
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
tstring val;
function (val, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"), _T("CommonFilesDir"));
return 0;
}
ERROR_MORE_DATA means the buffer you supplied to hold the data is not big enough.
Your problems are multiple:
When you say sizeof(string) you're getting the size of the string data type, not the length of the string. You should call string::size() to get the length of the string.
You can't just cast a string to an LPBYTE. That is going to FAIL miserably. The Registry APIs are not designed to work with strings, they are designed to work with char* and WCHAR* types. You need to declare a local character array (e.g. char *foo = new char[256]) and then pass that. If you get ERROR_MORE_DATA, declare a bigger one.