How to get a registry read function to work properly? (c++) - c++

When I compile and run the following code snippet (in visual studio 2019),
it runs but returns an incorrect value of
Key Value: 000000D1E14FF920 and actual bytes read was: 12
instead of
Key Value: 18363 and actual bytes read was: 6
here is the code
#include <Windows.h>
#include <iostream>
#include <string>
#include <tchar.h>
wchar_t value[255];
DWORD BufferSize = sizeof(value);
RegGetValue(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\"), _T("CurrentBuildNumber"), RRF_RT_ANY, NULL, (PVOID)&value, &BufferSize);
std::cout << "Key Value: " << value << " and actual bytes read was: " << BufferSize << std::endl;
I tried multiple methords of fixing this problem but I couldnt get it to work properly with visual studio (probably because it uses unicode)

You are mixing char and TCHAR APIs. It is clear that RegGetValue() is returning a Unicode wide string, because 12 bytes is correct for a 6-character null-terminated wchar_t string. So TCHAR is mapping to wchar_t in your build, and thus RegGetValue() is calling RegGetValueW(). You are trying to print out that wide string using std::cout, which does not support wchar_t strings, so you are actually calling the void* overload of std::basic_osteam::operator<<. That is why you are seeing a memory address being printed out.
To deal with TCHAR correctly, try this instead:
#include <Windows.h>
#include <iostream>
#include <string>
#include <tchar.h>
#ifdef UNICODE
#define tcout std::wcout
#else
#define tcout std::cout
#endif
TCHAR value[255] = {};
DWORD BufferSize = sizeof(value);
RegGetValue(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\"), _T("CurrentBuildNumber"), RRF_RT_REG_SZ, NULL, &value, &BufferSize);
tcout << _T("Key Value: ") << value << _T(" and actual bytes read was: ") << (BufferSize / sizeof(TCHAR)) << std::endl;
However, you really should forget that TCHAR exists, it has no place in modern coding anymore. Just go full Unicode only:
#include <Windows.h>
#include <iostream>
#include <string>
WCHAR value[255] = {}
DWORD BufferSize = sizeof(value);
RegGetValueW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\", L"CurrentBuildNumber", RRF_RT_REG_SZ, NULL, &value, &BufferSize);
std::wcout << L"Key Value: " << value << L" and actual bytes read was: " << (BufferSize / sizeof(WCHAR)) << std::endl;

Related

Use TCHAR still can't use std::cout ? cout should automatically get converted to wcout right?

I thought using TCHAR, and setting the character set to UNICODE in Visual Studio, maybe now I could get results in wide character ie 16 bits Unicode system, but it is not working.
This is my code:
#include<Windows.h> //to use windows API
#include<iostream>
int main()
{
TCHAR a[] = TEXT("This is not ANSI anymore! Olé!"); //8bits each char
wchar_t b[] = L"This is the Unicode Olé!"; //16 bits each char
std::cout << a << "\n";
std::wcout << b << "\n";
return 0;
}
So I thought, after defining TCHAR, I could make use of:
#ifdef UNICODE
#define std::cout std::wcout
#else
#define std::cout std::cout
#endif
But still, my output is in hex for TCHAR a[], but why? It should use wcout automatically, right?
std::cout does not support wchar_t strings, and std::wcout does not support char strings. So you will have to pick one or the other based on which character type TCHAR is using.
You were right to try to use #define to work around that, but you used the wrong syntax for it.
Try this instead:
#include <Windows.h> //to use windows API
#include <iostream>
#ifdef UNICODE
#define t_cout std::wcout
#else
#define t_cout std::cout
#endif
int main()
{
TCHAR a[] = TEXT("Olé!");
t_cout << a << TEXT("\n");
// or: t_cout << a << std::endl;
return 0;
}
But still, my output is in hex for TCHAR a[], but why?
You'll need to use _setmode with stdout for a correct console output. You'll need to do it to stdin also if you want to read console input.
It should use wcout automatically, right?
The macros are not correct, but if you define them correctly and assuming you enabled unicode, yes, TCHAR should expand t wchar_t, and the used output macro will be the one enabled by your #ifdef condition:
#include <Windows.h> //to use windows API
#include <iostream>
#include <fcntl.h>
#include <io.h>
#ifdef UNICODE
#define tcout std::wcout //unicode enabled
#else
#define tcout std::cout
#endif
int main()
{
_setmode(_fileno(stdout), _O_WTEXT); // enable wide char output
TCHAR a[] = TEXT("This is not ANSI anymore! Olé!");
tcout << a << TEXT("\n");
}
With _setmode:
Without _setmode:
In Windows with UNICODE set, TCHAR comes out to wchar_t.
You can't use std::cout with wide characters. It only ever uses char. windows.h doesn't redefine cout in the way you think.
So it's as if you were outputting an array of (signed or unsigned) short to the stream. The array decays to a pointer and that's probably why you see hex.
However
std::wcout << a << "\n";
should work.
It's only possible for functions that are part of the Windows API, because the windows.h header file defines two functions, one each for ASCII and Unicode forms. TCHAR would change only for those present there.
cout and wcout are not part of the Windows API. Rather, they are part of the standard C++ iostream header, so they do not change based on the definition of TCHAR.

Problem joining char* to filesystem::path.filename() or char[260]

I Know similar questions have been asked before but none of them Helped in my case.
Basically I want dstPath = %AppData% + "CURRENT EXE NAME"
but problem is with different string types and string concantation
SIMPLIFIED CODE :-
#include <stdio.h>
#include <string>
#include <filesystem>
#include <Shlwapi.h>
#include <Windows.h>
using namespace std;
int main()
{
TCHAR selfPath[MAX_PATH];
TCHAR dstPath[MAX_PATH];
if (GetModuleFileName(NULL, selfPath, MAX_PATH) == 0) // Getting exe File Location
printf("Error : %ul\n", GetLastError());
filesystem::path p(selfPath);
dstPath = strcat(getenv("APPDATA"), p.filename().string().c_str()); // Here Comes The Error
printf("Src : %s\n", selfPath);
printf("Dst : %s\n", dstPath);
return 0;
}
COMPILER COMMAND :-
g++ -Os -s -o ./builds/gcc-rat-x64.exe ./source/rat.cpp -std=c++17 -m64 -lshlwapi
COMPILER ERROR :-
error: incompatible types in assignment of 'char*' to 'TCHAR [260]' {aka 'char [260]'}
80 | dstPath = strcat(getenv("APPDATA"), p.filename().string().c_str());
You cannot assign to arrays. You should use strcpy() to copy C-style strings.
strcpy(dstPath, getenv("APPDATA"));
strcat(dstPath, p.filename().string().c_str());
Or the concatination can be done in one line via snprintf():
snprintf(dstPath, sizeof(dstPath), "%s%s", getenv("APPDATA"), p.filename().string().c_str());
Finally, TCHAR and GetModuleFileName can refer to UNICODE version of the API, according to the compilation option. Using ANSI version (char and GetModuleFileNameA) explicitly is safer to work with std::string and other APIs that require strings consists of char.
You are trying to use strcat to concatenate two strings and store the result in another one, but it does not work that way. The call strcat (str1, str2) adds the content of str2 at the end of str1. It also returns a pointer to str1 but I don't normally use it.
What you are trying to do should be done in three steps:
Make sure that dstPath contains an empty string
Concatenate to dstPath the value of the environment variable APPDATA
Concatenate to dstPath the value of filename
Something like this:
dstPath[0] = '\0';
strcat(dstPath, getenv("APPDATA"));
strcat(dstPath, p.filename().string().c_str());
You should also add checks not to overflow dstPath...
First off, you are mixing TCHAR and char APIs in a way you should not be. You really should not be using TCHAR at all in modern code. But, if you are going to use TCHAR, then at least use TCHAR- based functions/macros, like _tprintf() instead of printf(), _tcscat() instead of strcat(), etc.
The compiler error is because you are trying to assign the char* pointer returned by strcat() to your dstPath TCHAR[] array. You can't assign a pointer to an array like that. You should strcpy() the result of getenv() into dstPath first, and then strcat() your filename onto the end of it, eg:
#include <string>
#include <filesystem>
#include <Windows.h>
#include <Shlwapi.h>
#include <stdio.h>
#include <tchar.h>
TCHAR* _tgetenv(const TCHAR *varname)
{
#ifdef _UNICODE
return _wgetenv(varname);
#else
return getenv(varname);
#endif
}
std::basic_string<TCHAR> path2TStr(const std::filesystem::path &p)
{
#ifdef _UNICODE
return p.wstring();
#else
return p.string();
#endif
}
int main()
{
TCHAR selfPath[MAX_PATH];
TCHAR dstPath[MAX_PATH];
if (GetModuleFileName(NULL, selfPath, MAX_PATH) == 0) // Getting exe File Location
{
printf("Error : %ul\n", GetLastError());
return 0;
}
std::filesystem::path p(selfPath);
_tcscpy(dstPath, _tgetenv(_T("APPDATA")));
_tcscat(dstPath, path2TStr(p.filename()).c_str());
_tprintf(_T("Src : %s\n"), selfPath);
_tprintf(_T("Dst : %s\n"), dstPath);
return 0;
}
However, you really should be using SHGetFolderPath(CSIDL_APPDATA) or SHGetKnownFolderPath(FOLDERID_RoamingAppData) instead of using getenv("APPDATA").
And since you are using the <filesystem> library anyway, you really should just use std::filesystem::path for all of your path handling. It has operator/= and operator/ to concatenate path segments, and an operator<< for printing paths to a std::ostream, like std::cout. Don't use strcat() for concatenating path segments, it won't handle directory separators correctly, at least.
Try this instead:
#include <iostream>
#include <string>
#include <filesystem>
#include <stdexcept>
#include <Windows.h>
#include <Shlobj.h>
std::filesystem::path getSelfPath()
{
WCHAR wPath[MAX_PATH] = {};
if (!GetModuleFileNameW(NULL, wPath, MAX_PATH)) // Getting exe File Location
{
DWORD err = GetLastError();
throw std::runtime_error("Error : " << std::to_string(err));
}
return wPath;
}
std::filesystem::path getAppDataPath()
{
WCHAR wPath[MAX_PATH] = {};
HRESULT hRes = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wPath); // Getting APPDATA Folder Location
if (hRes != S_OK)
throw std::runtime_error("Error : " << std::to_string(hRes));
return wPath;
}
int main()
{
try
{
auto selfPath = getSelfPath();
auto dstPath = getAppDataPath() / selfPath.filename();
std::cout << "Src : " << selfPath << "\n";
std::cout << "Dst : " << dstPath << "\n";
}
catch (const std::exception &e)
{
std::cerr << e.what() << "\n";
}
return 0;
}

Trouble printing DIDEVICEINSTANCE tszProductName to Windows Console

I've been following a DirectInput tutorial and am having trouble printing a list of DirectInput device product names to a Windows console.
I'm using VS19's C++ compiler and am compiling with UNICODE defined. Since tszProductName is of type TCHAR which resolves to WCHAR I followed this stack overflow answer to allow the windows console to print unicode while also avoiding mixing wcout with cout in the same program.
Before I made those changes nothing was printed. Now the console prints '쳌' repeatedly for each device name. I tried switching from Unicode to Multibyte and going back to cout to no avail. Here is the code in question.
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#pragma comment (lib,"dinput8.lib")
#pragma comment (lib,"dxguid.lib")
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <locale.h>
#include <clocale>
#include <io.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
IDirectInput8* dev;
std::vector<LPDIRECTINPUTDEVICE8> gameControllers;
BOOL CALLBACK enumGameControllers(LPCDIDEVICEINSTANCE devInst, LPVOID pvRef) {
LPDIRECTINPUTDEVICE8 gameController;
if (FAILED(dev->CreateDevice(devInst->guidInstance, &gameController, NULL)))
return DIENUM_CONTINUE;
else {
gameControllers.push_back(gameController);
return DIENUM_CONTINUE;
}
}
int wmain(int argc, wchar_t* argv[]) {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
char* a = setlocale(LC_ALL, "en-US.UTF8");
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
CONSOLE_FONT_INFOEX fontInfo;
fontInfo.cbSize = sizeof(fontInfo);
fontInfo.FontFamily = 20;
fontInfo.FontWeight = 400;
fontInfo.nFont = 0;
const wchar_t myFont[] = L"Lucida Console";
fontInfo.dwFontSize = { 8, 16 };
std::copy(myFont, myFont + _countof(myFont), fontInfo.FaceName);
SetCurrentConsoleFontEx(hConsole, false, &fontInfo);
if (FAILED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&dev, NULL))) {
std::wcout << L"Critical error: Unable to create the main DirectInput 8 COM object!\n";
return 1;
}
if (FAILED(dev->EnumDevices(DI8DEVCLASS_GAMECTRL, &enumGameControllers, NULL, DIEDFL_ATTACHEDONLY))) {
std::wcout << L"Critical error: Unable to enumerate input devices!\n";
return 1;
}
if (gameControllers.empty()) {
std::wcout << L"No peripherals found\n";
return 1;
}
int count = 1;
std::wcout << L"Number of devices: " << gameControllers.size() << std::endl;
for (LPDIRECTINPUTDEVICE8 i : gameControllers) {
DIDEVICEINSTANCE deviceInfo;
i->GetDeviceInfo(&deviceInfo);
std::wcout << L"Device Number " << count << L": ";
std::wcout << deviceInfo.tszProductName << std::endl;
if (FAILED(i->SetCooperativeLevel(GetConsoleWindow(), DISCL_BACKGROUND | DISCL_EXCLUSIVE))) {
std::wcout << L"Cooperative level could not be set\n";
return 1;
}
++count;
}
return 0;
}
Thanks in advance for any suggestions and/or solutions.
DIDEVICEINSTANCE deviceInfo;
i->GetDeviceInfo(&deviceInfo);
Problems with this code are that:
DIDEVICEINSTANCE::dwSize is not initialized as required, and
the return value of IDirectInputDevice8::GetDeviceInfo is not checked for errors.
Change to the following, instead.
DIDEVICEINSTANCE deviceInfo = { sizeof(DIDEVICEINSTANCE) };
if(i->GetDeviceInfo(&deviceInfo) != DI_OK) { /* call failed, handle error */ }

How to get FileDescription with VerQueryValue (getting the example to work)?

I am trying to get the various attributes of a file as seen in its "Details" tab with the WinAPI function VerQueryValue. I have successfully used this function to get the non-string version info with VS_FIXEDFILEINFO, but have not been able to get the example shown at the bottom of the functions documentation working.
The example isn't actually complete as it leaves out the use of the other related functions and the constructions of some buffers needed to use the function, so I've filled in the blanks the best I can and changed some of the in-between steps to use C++ SL since that's ultimately the language I need to use this in:
#include <iostream>
#include <iomanip>
#include "sstream"
#include "Windows.h"
#pragma comment(lib, "Version.lib")
int ReadOutFileDescriptions(std::wstring filename)
{
LPBYTE lpBuffer = NULL;
DWORD verHandle, verSize = GetFileVersionInfoSize(filename.c_str(), &verHandle);
if (verSize != NULL)
{
LPSTR verData = new char[verSize];
if (GetFileVersionInfo(filename.c_str(), verHandle, verSize, verData))
{
UINT cbTranslate;
// Structure used to store enumerated languages and code pages.
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
// Read the list of languages and code pages.
VerQueryValue(verData, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate);
// Read the file description for each language and code page.
for (ULONGLONG i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
{
std::wostringstream ss; ss << std::setfill(L'0') << std::hex;
ss << std::setw(4) << lpTranslate[i].wLanguage;
std::wstring langS = ss.str();
ss.str(std::wstring());
ss << std::setw(4) << lpTranslate[i].wCodePage;
std::wstring codeS = ss.str();
std::wstring subBlock = L"\\StringFileInfo\\" + langS + codeS + L"\\FileDescription";
// Retrieve file description for language and code page "i".
WCHAR descBuffer[50];
LPVOID lpBuffer = &descBuffer;
UINT bufferSize;
VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize);
std::cout << bufferSize << '\n' << descBuffer;
}
}
delete[] verData;
}
return 0;
}
int main(int argc, char* argv[])
{
ReadOutFileDescriptions(L"MyFile.exe");
return 0;
}
I only have a little experience with WinAPI and its typedefs and my C is a bit rusty so I'm sure I'm just setting-up/using a buffer incorrectly or the like.
The printed buffer size is correct (the length of MyFile.exe's description + 1 for the null character) so I know the function is getting the right value, but the actually value that gets printed is just a series of hexadecimal character, most likely an address.
What am I doing wrong?
EDIT (Answer):
Thanks to #dxiv I was made aware that I did not fully understand how the "result" argument (lplpBuffer) of VerQueryValue was to be used, both internally and after the function returns.
Changing the end of the loop to the following achieves my desired result:
//WCHAR descBuffer[50] Not required, the function doesn't utilize a user made buffer
LPVOID lpBuffer;
UINT bufferSize;
VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize); // lpBuffer is reassigned here
std::wstring fileDescription((const TCHAR*)lpBuffer); // Create std::string from C style string (char*) that lpBuffer now points to
std::wcout << bufferSize << '\n' << fileDescription;
VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize);
std::cout << bufferSize << '\n' << descBuffer;
Once VerQueryValue returns, lpBuffer no longer points to descBuffer, but to a different buffer assigned inside the call. The returned string is at (const TCHAR *)lpBuffer at that point.

Full path of executable file in Windows, c++ [duplicate]

This question already has answers here:
Wide character output result [closed]
(2 answers)
Closed 8 years ago.
I just want to get full path of my executable file written on console, but the variable path just stores numbers how can i convert it to string (I know this code only outputs memory location of path)?
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
int main() {
WCHAR path[MAX_PATH];
GetModuleFileName(NULL, path, 500);
cout << "File path is: " << path << endl;
}
There are a couple of problems with your code:
You're passing the wrong size parameter to GetModuleFilename - the buffer size is supposed to be the size in TCHARs, which would be MAX_PATH in your case, not 500. That's a buffer overflow waiting to happen as 500 > MAX_PATH
You're using the narrow stream for your output, that can't print a wide string so you're seeing the address instead. To print wide characters, you need to use std::wcout instead.
As already noted in the comments, you may want to use wcout to print a WCHAR string.
You may want to consider a function like this to wrap the GetModuleFileName() call in a convenient C++ way:
#include <stdexcept> // For std::runtime_error
#include <string> // For std::wstring
#include <Windows.h> // For Win32 API
// Represents an error in a call to a Win32 API.
class win32_error : public std::runtime_error
{
public:
win32_error(const char * msg, DWORD error)
: std::runtime_error(msg)
, _error(error)
{ }
DWORD error() const
{
return _error;
}
private:
DWORD _error;
};
// Returns the full path of current EXE
std::wstring GetPathOfExe()
{
// Get filename with full path for current process EXE
wchar_t filename[MAX_PATH];
DWORD result = ::GetModuleFileName(
nullptr, // retrieve path of current process .EXE
filename,
_countof(filename)
);
if (result == 0)
{
// Error
const DWORD error = ::GetLastError();
throw win32_error("Error in getting module filename.",
error);
}
return filename;
}
Note that if you want the size in WCHARs of a raw string buffer, you may want to use _countof().
wchar are 16bit and you are using cout and that output stream expect 8bit char that's why you get weird number on the output
when you have to use wchar use wcout and take care of the kind of string you use!
#include <iostream>
#include <string>
#include <windows.h>
std::wstring app_path() {
std::wstring path;
path.resize(MAX_PATH, 0);
auto path_size(GetModuleFileName(nullptr, &path.front(), MAX_PATH));
path.resize(path_size);
return path;
}
int main() {
auto path(app_path());
std::wcout << L"File path is: " << path << std::endl;
}
Try this one!