As a C++ beginner I need your help!
I'm currently working on a program that should be able to read a registry key and its value and write it into a vector array for further processing.
But now I have the problem that umlauts are displayed cryptically in the output on the console. I suspect this is due to the fact that a wrong character encoding is used. After some research I found the function "SetConsoleOutputCP(65001)", which is supposed to set the output of the console to UTF8.
Unfortunately, the output now breaks on umlauts if the Unicode compatible functions were used to read the registry. In the second case the console simply hides the umlauts when using the ANSI compatible functions. What am I doing wrong here and how do I get umlauts correctly read from the registry and output to the console?
Also I would like to write the umlauts correctly into a CSV file later. Do I have to pay attention to anything special here as well?
You can find my code below with some comments. Thanks to all helpers!
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
/**
* @brief Function to read an registry key to a vector of strings. Registry function will be called as unicode compatible version e.g. RegQueryValueExW (W at the end). This function is overloaded and exists with a different parameter list as well.
*
* @param rootKey Standard hkey for the root key value
* @param subKey Specific path for a subkey value
* @param value The value name whose value is to be read
* @return std::vector<std::wstring>
*/
std::vector<std::wstring> regMultiSzToVector(HKEY rootKey, LPCWSTR subKey, LPCWSTR value) {
HKEY hkey;
DWORD type, size;
std::vector<std::wstring> target;
// Open registry key and write it to hkey variable
if (RegOpenKeyEx(rootKey, subKey, 0, KEY_READ | KEY_WOW64_64KEY, &hkey) != ERROR_SUCCESS)
exit(1);
// Get type and necessary memory size
if (RegQueryValueExW(hkey, value, NULL, &type, NULL, &size) != ERROR_SUCCESS)
exit(1);
if (type == REG_MULTI_SZ) {
std::vector<wchar_t> temp(size / sizeof(wchar_t));
if (RegQueryValueExW(hkey, value, NULL, NULL, reinterpret_cast<LPBYTE>(&temp[0]), &size) != ERROR_SUCCESS)
exit(1);
// Writing value from registry key to string array
size_t index = 0;
size_t len = wcslen(&temp[0]);
while (len > 0) {
target.push_back(&temp[index]);
index += len + 1;
len = wcslen(&temp[index]);
}
}
// Closing registry key (see API)
RegCloseKey(hkey);
return target;
}
/**
* @brief Function to read an registry key to a vector of strings. Registry function will be called as ansi compatible version e.g. RegQueryValueExA (A at the end). This function is overloaded and exists with a different parameter list as well.
*
* @param rootKey Standard hkey for the root key value
* @param subKey Specific path for a subkey value
* @param value The value name whose value is to be read
* @return std::vector<std::string>
*/
std::vector<std::string> regMultiSzToVector(HKEY rootKey, LPCSTR subKey, LPCSTR value) {
HKEY hkey;
DWORD type, size;
std::vector<std::string> target;
// Open registry key and write it to hkey variable
if (RegOpenKeyExA(rootKey, subKey, 0, KEY_READ | KEY_WOW64_64KEY, &hkey) != ERROR_SUCCESS)
exit(1);
// Get type and necessary memory size
if (RegQueryValueExA(hkey, value, NULL, &type, NULL, &size) != ERROR_SUCCESS)
exit(1);
if (type == REG_MULTI_SZ) {
std::vector<char> temp(size);
if (RegQueryValueExA(hkey, value, NULL, NULL, reinterpret_cast<LPBYTE>(&temp[0]), &size) != ERROR_SUCCESS)
exit(1);
// Writing value from registry key to string array
size_t index = 0;
size_t len = strlen(&temp[0]);
while (len > 0) {
target.push_back(&temp[index]);
index += len + 1;
len = strlen(&temp[index]);
}
}
// Closing registry key (see API)
RegCloseKey(hkey);
return target;
}
int main(int argc, char const* argv[]) {
// Saving function return values to vectors
std::vector<std::wstring> result1 = regMultiSzToVector(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\007", L"Counter");
std::vector<std::string> result2 = regMultiSzToVector(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\007", "Counter");
// Printing String values from first and second vector
printf("Vector 1: \n");
for (auto &e : result1) {
std::wcout << e << std::endl;
}
printf("\n\n\n Vector 2: \n");
for (auto &e : result2) {
std::cout << e << std::endl;
}
return 0;
}
If you want to use CP65001 (UTF-8) then you also need to convert your utf-16 encoded wstring
to a utf-8 encoded string.
Here is a simple way of doing this: https://stackoverflow.com/a/12903901/347508
I've made only small modifications to your code:
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
#include <codecvt>
#pragma comment(lib, "user32")
#pragma comment(lib, "Advapi32")
// utf-8 conversion from https://stackoverflow.com/a/12903901/347508
// convert UTF-8 string to wstring
std::wstring utf8_to_wstring (const std::string& str)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
return myconv.from_bytes(str);
}
// convert wstring to UTF-8 string
std::string wstring_to_utf8 (const std::wstring& str)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
return myconv.to_bytes(str);
}
/**
* @brief Function to read an registry key to a vector of strings. Registry function will be called as unicode compatible version e.g. RegQueryValueExW (W at the end). This function is overloaded and exists with a different parameter list as well.
*
* @param rootKey Standard hkey for the root key value
* @param subKey Specific path for a subkey value
* @param value The value name whose value is to be read
* @return std::vector<std::wstring>
*/
std::vector<std::wstring> regMultiSzToVector(HKEY rootKey, LPCWSTR subKey, LPCWSTR value) {
HKEY hkey;
DWORD type, size;
std::vector<std::wstring> target;
// Open registry key and write it to hkey variable
if (RegOpenKeyExW(rootKey, subKey, 0, KEY_READ | KEY_WOW64_64KEY, &hkey) != ERROR_SUCCESS)
exit(1);
// Get type and necessary memory size
if (RegQueryValueExW(hkey, value, NULL, &type, NULL, &size) != ERROR_SUCCESS)
exit(1);
if (type == REG_MULTI_SZ) {
std::vector<wchar_t> temp(size / sizeof(wchar_t));
if (RegQueryValueExW(hkey, value, NULL, NULL, reinterpret_cast<LPBYTE>(&temp[0]), &size) != ERROR_SUCCESS)
exit(1);
// Writing value from registry key to string array
size_t index = 0;
size_t len = wcslen(&temp[0]);
while (len > 0) {
target.push_back(&temp[index]);
index += len + 1;
len = wcslen(&temp[index]);
}
}
// Closing registry key (see API)
RegCloseKey(hkey);
return target;
}
int main(int argc, char const* argv[]) {
// Saving function return values to vectors
std::vector<std::wstring> res = regMultiSzToVector(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", L"hansi");
// Printing String values from first and second vector
printf("Result: \n");
for (auto &e : res) {
std::wcout << "* utf-16=" << e << std::endl;
std::cout << " utf-8 =" << wstring_to_utf8(e) << std::endl;
}
return 0;
}
Output:
C:\Users\Hansi>chcp 850
Active code page: 850
C:\Users\Hansi>cl /EHsc reg_test.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29910 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
reg_test.cpp
Microsoft (R) Incremental Linker Version 14.28.29910.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:reg_test.exe
reg_test.obj
C:\Users\Hansi>reg_test.exe
Result:
* utf-16=Íl
utf-8 =Öl
* utf-16=H÷ren
utf-8 =H├Âren
* utf-16=T³re
utf-8 =T├╝re
* utf-16=Da▀
utf-8 =Daß
C:\Users\Hansi>chcp 65001
Active code page: 65001
C:\Users\Hansi>reg_test.exe
Result:
* utf-16=l
utf-8 =Öl
* utf-16=Hren
utf-8 =Hören
* utf-16=T utf-8 =Türe
utf-8 =Daß