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.
Related
I need to write a program in C++ that queries the OS for running Windows, find a Window with a specific window title, and return the Native Window Handle value as a String.
So far, I've figured out everything but the last part. I'm not too familiar with C++, as I'm writing this for a JS project as a NodeJS C++ addon, so I'd appreciate any help.
Here's the program so far:
static BOOL CALLBACK enumWindowCallback(HWND hWnd, LPARAM lparam) {
int length = GetWindowTextLength(hWnd);
char* buffer = new char[length + 1];
GetWindowText(hWnd, buffer, length + 1);
std::string windowTitle(buffer);
if (IsWindowVisible(hWnd) && length != 0) {
std::cout << hWnd << ": " << windowTitle << std::endl;
if (windowTitle.compare("Find This Window") == 0) {
// Here is the confusion. I've found the right HWND, but I don't know how to cast the HWND to a String
return FALSE;
}
}
return TRUE;
}
int::main() {
EnumWindows(enumWindowCallback, NULL);
}
On this line: std::cout << hWnd << ": " << windowTitle << std::endl;, the hWnd returns the hexadecimal value that I want. For example, it prints out: 0000000000100566: Find this App
The value preceding the : is the value I want to return as a String, but I can't figure out how. I've tried casting it, but it doesn't work.
Again, this is probably a simple solution, but I can't find it on the internet and my limited knowledge of C++ is hindering me.
Actually, the question is how to convert number to string.
At the beginning, as #KenWhite said, HWND is an opaque value.
#include <Windows.h>
#include <sstream>
void main()
{
HWND i = FindWindow(NULL,NULL);
char buffer[sizeof(HWND) * 2 + 1]{};
_itoa_s((int)i, buffer, 16);
std::ostringstream Convert;
Convert << std::hex << i;
}
I am new to winsock and I wish to use bluetooth for my project.
I wrote a simple code taking help from online resources to find remote devices
It should print the name of the remote devices but instead it prints some hex value I think...I dont know what that is
The code is
#include "stdafx.h"
#include<iostream>
#include<winsock2.h>
#include<ws2bth.h>
#include<bluetoothapis.h>
#include<stdlib.h>
using namespace std;
#define SUCCESS 0
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "irprops.lib")
int main()
{
WSADATA data;
int result;
result = WSAStartup(MAKEWORD(2, 2), &data);
if (result != SUCCESS)
{
cout << "error occured while initialising winsock...";
exit(result);
}
cout << "winsock initialisation successful\n";
WSAQUERYSET queryset;
memset(&queryset, 0, sizeof(WSAQUERYSET));
queryset.dwSize = sizeof(WSAQUERYSET);
queryset.dwNameSpace = NS_BTH;
HANDLE hLookup;
result = WSALookupServiceBegin(&queryset, LUP_CONTAINERS, &hLookup);
if (result != SUCCESS)
{
cout << "error in initialising look up service\n";
exit(result);
}
cout << "initialising lookup service successful\n";
BYTE buffer[4096];
memset(buffer, 0, sizeof(buffer));
DWORD bufferLength = sizeof(buffer);
WSAQUERYSET *pResults = (WSAQUERYSET*)&buffer;
while (result == SUCCESS)
{
result = WSALookupServiceNext(hLookup, LUP_RETURN_NAME | LUP_CONTAINERS | LUP_RETURN_ADDR | LUP_FLUSHCACHE | LUP_RETURN_TYPE | LUP_RETURN_BLOB | LUP_RES_SERVICE, &bufferLength, pResults);
if (result == SUCCESS)
{
//DEVICE FOUND
LPTSTR s = pResults->lpszServiceInstanceName;
cout << s << endl;
Sleep(1000);
}
}
WSALookupServiceEnd(hLookup);
return 0;
}
I require help in solving this issue
Thanks in advance for any help
You have a (potential) mismatch of character encodings. The line
LPTSTR s = pResults->lpszServiceInstanceName;
expands to
LPWSTR s = pResults->lpszServiceInstanceName;
if you have your project's character encoding set to Unicode (default setting). To output a Unicode string, you have to use std::wcout instead of std::cout:
LPCWSTR s = pResults->lpszServiceInstanceName;
wcout << s << endl;
To reduce the odds of inadvertently using an unexpected character encoding, code should explicitly specify the character encoding it uses. The code in the question should use WSAQUERYSETW, and call WSALookupServiceBeginW and WSALookupServiceNextW instead.
Explanation of the observed behavior:
std::cout interprets a const char* as a C-style string, and displays the characters until it finds a NUL character (see operator<<(std::basic_ostream)).
A const wchar_t*, on the other hand, is not interpreted to mean anything special. std::cout treats it like any other pointer, and prints its value using the hexadecimal numeral system by default (see std::basic_ostream::operator<<).
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!
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);
Can someone please tell me the problems with this piece of code?
I'm bulding a windows app, not a console. Am I using the functions
correctly. What types should I used? Okay I fixed semicolon err and
else err? Still not working properly.
#include <windows.h>
int WINAPI WinMain(HINSTANCE thisin,HINSTANCE previn,LPSTR lpstr,INT int_)
{
LPTSTR buffer;
DWORD size;
SetConsoleTitle("Console Title");
if(!GetConsoleTitle(buffer,size))
cout << "error" << endl;
else cout << *buffer << endl;
system("Pause");
return 0;
}
It have 2 problems, first a ';' at end of if that is a C++ mistyping error and every body say it, but second is: for every API that get a buffer to return something, you should provide a valid buffer. Assume GetConsoleTitle implemented as:
BOOL GetConsoleTitle(LPTSTR p, DWORD dwSize)
{
LPTSTR actualTitle = /* Get actual title from somewhere */;
while (dwSize--)
{
*p++ = *actualTitle++;
if (!*p++) return TRUE;
}
// Not enough buffer
return FALSE;
}
Now look at your program, you pass an uninitialized LPTSTR to the function and as soon as API call *p++ = *actualTitle++, it will cause a segmentation fault or Access violation.
so in order to solve it, you must pass a valid buffer as first argument and since LPTSTR is a typedef of TCHAR* you should have:
const DWORD dwSize = 128;
TCHAR buffer[dwSize];
if (GetConsoleTitle(buffer, dwSize)) std::cout << "OK!" << std::endl;
First thing is first. Your statement prints whether there is an error or not. Use an else there:
if(!GetConsoleTitle(buffer,size))
cout << "error" << endl;
else
cout << *buffer << endl;
and the ; after your if was a typo, I corrected it above.
You are using API's for Console App. Create a console app, copy this code to console project c or cpp source file and replace
int WINAPI WinMain(HINSTANCE thisin,HINSTANCE previn,LPSTR lpstr,INT int_)
with
int _tmain(int argc, char *argv[])
also remove ';' (semicolon) from 'if' statement.