C++ Win32 - Getting App Name using PID and Executable Path - c++

I'd like to get the name of an application on Windows.
Currently I'm using EnumProcesses() to enumerate all processes and receive a list of PIDs.
Then I'm looping through all PIDs, each iteration looks like this, when aProcess[i] is the current PID:
HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, aProcesses[i]);
std::string processName = get_process_name(proc);
My get_process_name(proc) function uses GetModuleFileNameEx to get the executable path and GetProcessImageFileName in order to retrieve the name of the executable file.
What I want to retrieve is basically the App Name, as it is displayed in the Windows Task Manager.
I've looked throughout Win32 API's documentation and could not find a clue on how to achieve this.
I've tried looking for other ways such as Windows Shell tasklist but it outputs different things, for example- Google Chrome:
Image Name: chrome.exe PID: 84 Session Name: Console
I'd really appreciate any thought on the matter, whether it be the Win32 API or some other way I can implement through C++ code.

You can do this with GetFileVersionInfoA and VerQueryValueA.
You just need to follow the example given in the VerQueryValueA document.
Here is my sample:
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
int main()
{
HANDLE handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION , FALSE, 2140); //Modify pid to the pid of your application
if (!handle) return 0;
wchar_t pszFile[MAX_PATH] = L"";
DWORD len = MAX_PATH;
QueryFullProcessImageName(handle, 0, pszFile, &len);
UINT dwBytes, cbTranslate;
DWORD dwSize = GetFileVersionInfoSize(pszFile, (DWORD*)&dwBytes);
if (dwSize == 0) return 0;
LPVOID lpData = (LPVOID)malloc(dwSize);
ZeroMemory(lpData, dwSize);
if (GetFileVersionInfo(pszFile, 0, dwSize, lpData))
{
VerQueryValue(lpData,
L"\\VarFileInfo\\Translation",
(LPVOID*)&lpTranslate,
&cbTranslate);
wchar_t strSubBlock[MAX_PATH] = { 0 };
wchar_t* lpBuffer;
for (int i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
{
StringCchPrintf(strSubBlock,50,
L"\\StringFileInfo\\%04x%04x\\FileDescription",
lpTranslate[i].wLanguage,
lpTranslate[i].wCodePage);
VerQueryValue(lpData,
strSubBlock,
(void**)&lpBuffer,
&dwBytes);
std::wcout << lpBuffer << std::endl;
}
}
if(lpData) free(lpData);
if (handle) CloseHandle(handle);
return 0;
}
And it works for me:

I think what you want are the "version" resources embedded in the PE file (the executables.)
You seem to be familiar with using Win32 API, so I'm just going to give you some hints.
You have to use LoadLibraryEx to load the EXE file (the Ex suffix is to enable passing the LOAD_LIBRARY_AS_DATAFILE flag,) and then call EnumResourceTypes (also see EnumResourceNames) to enumerate all the resource types/resources in the file, and find what you are looking for and then extract the data with LoadResource. The resource type you want is RT_VERSION.
I'm sure I'm omitting a lot of details (as per usual for Win32 programming,) and there might not be a need for enumeration at all; in which case you may want to call FindResource or FindResourceEx directly (if there is a fixed name for this particular resource.)
As further clarification, this gives you the date you see if you right-click on the EXE file (not the shortcut) in Windows Explorer and select "Properties", then go to the "Details" tab. If that information is indeed what you want (e.g. the "File description" field) then the above method should give you the data.

Related

Read the file version of a dll in C: The system cannot find the file specified

I am new in the forum but I have already found a lot of help for my other projects.
I am using Visual Studio 2019 and I have created a .rc file which contains the file version and a few other things. These information are displayed in the Properties window of the my dll correctly.
I have created a function
void PrintVersion(TCHAR* pszFilePath, void (*printFunc)(const char*, ...));
which receives the file path and a pointer to my logger function. Inside that function I want to read the file version and print it to the logger. But my logger returns Error in GetFileVersionInfoSize: The system cannot find the file specified.
My function call does look like this:
TCHAR* filename = L"mydll.dll";
PrintVersion(filename, gPrintFunc);
And the function is implemented as follows:
// Read the version of the dll and write it to the logger
void PrintVersion(TCHAR* pszFilePath, void (*printFunc)(const char*, ...))
{
DWORD dwSize = 0;
DWORD verHandle = 0;
BYTE* pbVersionInfo = NULL;
VS_FIXEDFILEINFO* pFileInfo = NULL;
UINT puLenFileInfo = 0;
// Get the size of the version information. This is done to check if the file is avaialbe
// If the size is zero then a error occured
dwSize = GetFileVersionInfoSize(pszFilePath, &verHandle);
if (dwSize == 0)
{
gPrintFunc("Error in GetFileVersionInfoSize: ");
PrintLastErrorString(gPrintFunc);
return;
}
// Create some memory for the file version info
pbVersionInfo = malloc(dwSize);
// Store the information into pbVersionInfo
#pragma warning(suppress : 6387)
if (!GetFileVersionInfo(pszFilePath, verHandle, dwSize, pbVersionInfo))
{
gPrintFunc("Error in GetFileVersionInfo: ");
PrintLastErrorString(gPrintFunc);
free(pbVersionInfo);
return;
}
// Make the information easier accessable in pFileInfo
#pragma warning(suppress : 6387)
if (!VerQueryValue(pbVersionInfo, TEXT("\\"), (LPVOID*)&pFileInfo, &puLenFileInfo))
{
gPrintFunc("Error in VerQueryValue: ");
PrintLastErrorString(gPrintFunc);
free(pbVersionInfo);
return;
}
// pFileInfo->dwFileVersionMS and pFileInfo->dwFileVersionLS contain the software version
// Major2B.Minor2B.Revision2B.Build2B
gPrintFunc("File Version of %s: %d.%d.%d.%d\n",
pszFilePath,
(pFileInfo->dwFileVersionMS >> 16) & 0xffff,
(pFileInfo->dwFileVersionMS >> 0) & 0xffff,
(pFileInfo->dwFileVersionLS >> 16) & 0xffff,
(pFileInfo->dwFileVersionLS >> 0) & 0xffff
);
// Free up the reserved memory
free(pbVersionInfo);
}
// Used for receiving the last WIN32 error and write it to the logger
void PrintLastErrorString(void (*printFunc)(const char*, ...))
{
// Get the error id of the last error
DWORD iLastError;
iLastError = GetLastError();
//Ask Win32 to give us the string version of that message ID.
//The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
LPSTR messageBuffer = NULL;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, iLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
gPrintFunc("%s\n", messageBuffer);
return;
}
I created that function by combining a few different C++ and C# examples from this forum. I am not familiar with the TCHAR* datatype. I assume that the problem has maybe something to do with the filename string. Further I am not able to print the filename to the logger with the %s format placeholder. In this case only the first letter of the filename is displayed.
One further info. Before I copied that code to the dll. I created a small console application. And in this case it was possible to read the file version of the exe. I also tried to specify the complete path of the dll. The dll and the exe, which uses the dll are in the same directory.
Maybe someone can help me :)
BR
Thank you for your answers.
I changed now the character set to: Use Unicode Character Set and now it works as expected.

How to use OpenPrinter for a network printer?

I'm trying to establish a connection between a Windows 10 machine and a network printer via OpenPrinter API.
At the moment, OpenPrinter does not return with a valid handle and GetLastError() returns with Error 1801: "The printer name is invalid".
If I use a local printer connected to the machine, it does not occur and it works fine.
I've tried several versions of the name: The printer name used by Windows Control Panel, device name, IP, etc.,... but no success.
Within the registry only the local device is available. I use the network printer in several programs and I can ping it. So, from the network side it is ok.
But, the more I read about the Windows printer API, the more I get confused:
My basic understanding of this API is that I use an UNC name and post it to OpenPrinter(). Then OpenPrinter gives me a valid handle for the printer.
From my point of view anything else, like a socket connection, would be done by the API. Maybe I'm completely wrong and somebody can enlighten me.
Basically, the posted code snipped is an example provided by MSDN.
The variable LPWSTR printer = L"\\\\gisrv44.wekal.de\\wkkp04"; is given to LPTSTR szPrinterName.
BOOL RawDataToPrinter(LPTSTR szPrinterName, LPBYTE lpData, DWORD dwCount)
{
BOOL bStatus = FALSE;
HANDLE hPrinter = NULL;
DOC_INFO_1 DocInfo;
DWORD dwJob = 0L;
DWORD dwBytesWritten = 0L;
DWORD dwError = 0;
PRINTER_DEFAULTSA *pDefault = new PRINTER_DEFAULTSA();
pDefault->DesiredAccess = PRINTER_ACCESS_ADMINISTER;
PRINTER_OPTIONSA *pOptions = new PRINTER_OPTIONSA();
pOptions->dwFlags = PRINTER_OPTION_NO_CACHE;
// Open a handle to the printer.
bStatus = OpenPrinter(szPrinterName, &hPrinter, pDefault);
if (!bStatus)
{
dwError = GetLastError();
cout << dwError << endl;
}
.....etc
}
I think this is your problem:
The variable LPWSTR printer = L"\\gisrv44.wekal.de\wkkp04"; is given
to LPTSTR szPrinterName.
In C/C++ the character \ has a special purpose in string literals and can be used to express string that otherwise can't be expressed, such as \0, \n, \x48 and so on. This means that if you want to include a \ in your code, you will need to enter it twice, so you'll need to enter:
LPWSTR printer = L"\\\\gisrv44.wekal.de\\wkkp04";
If you want the string literal to become \\gisrv44.wekal.de\wkkp04
Alternatively, you can use the C++11 raw string literal syntax like:
LPWSTR printer = LR"(\\gisrv44.wekal.de\wkkp04)";
See here for more on C string literals
Furthermore, the usage of LPWSTR printer = ... for your printer url would suggest you are using the Unicode version of OpenPrinter (so OpenPrinterW) while PRINTER_DEFAULTSA would suggest you are using the ASCII version. Both should either use the ASCII (LPCSTR and PRINTER_DEFAULTSA) or the Unicode (LPWSTR and PRINTER_DEFAULTSW) variant, depending on the actual OpenPrinter define.
I would recommend to use OpenPrinterA or OpenPrinterW to make all WINAPI types and functions explicitly use ASCII or Unicode.
For example:
LPCSTR printer = R"(\\gisrv44.wekal.de\wkkp04)";
PRINTER_DEFAULTSA pDefault;
pDefault.DesiredAccess = PRINTER_ACCESS_ADMINISTER;
// Open a handle to the printer.
bStatus = OpenPrinterA(szPrinterName, &hPrinter, &pDefault);

How to get Machine id using c++

am facing two problems one big problem and one small problem :)
problem # 1 : am unable to read Machine ID from below path ... i get my processor name like intel i7 #2.2ghz like that , i do not know why , i should get machine id , long integer string but i not get it , so please help
reg_path="SOFTWARE\\Microsoft\\Cryptography";
rvalue="MachineGuid"; // data value
my registery reading function
string read_reg_sz(char rpath[],char rdata[]) // read registery Loaction
{
REGSAM flag = KEY_WOW64_32KEY or KEY_WOW64_64KEY;
char buffer[MAX];
char Buffer[MAX];
DWORD BufSize = _MAX_PATH;
char dwMHz[MAX];
DWORD dataType = REG_SZ;
HKEY hKey;
long lError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,rpath,NULL, KEY_READ | KEY_WRITE | flag,&hKey);
if(lError != ERROR_SUCCESS)
{// if the key is not found, tell the user why:
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
lError,
0,
Buffer,
_MAX_PATH,
0);
cout<<"\n reg erro : "<<Buffer;
return "N/A";
}
// query the key:
RegQueryValueEx(hKey,rdata,NULL,&dataType,(LPBYTE) &dwMHz,&BufSize);
RegCloseKey(hKey); // close open handle ....
cout<<"\n reg data read: "<<dwMHz;
return dwMHz;
}
second problem :
currently i have function which can totally clean recycle bin :)
SHEmptyRecycleBin(NULL, NULL, SHERB_NOCONFIRMATION | SHERB_NOPROGRESSUI | SHERB_NOSOUND);
but i want to delete single file from recycle bin like passing filename
You should really post it as two different questions, but I'll try to answer both.
1. Get MachineGuid
I think your issue is in this line:
// query the key:
RegQueryValueEx(hKey,rdata,NULL,&dataType,(LPBYTE) &dwMHz,&BufSize);
You should change it to:
// query the key:
RegQueryValueEx(hKey,rvalue,NULL,&dataType,(LPBYTE) &dwMHz,&BufSize);
By the way, dhMHz does not sound like right variable name - change it to reflect reality.
Also, you should have this:
DWORD BufSize = sizeof(Buffer) - 1;
And, it would be nice to NOT have both buffer and Buffer variables.
2. Delete one file from recycle bin
According to Microsoft documentation on SHFileOperation, you should just use DeleteFile on filename like C:\$Recycle.Bin\file.txt:
When used to delete a file, SHFileOperation permanently deletes the file unless you set the FOF_ALLOWUNDO flag in the fFlags member of the SHFILEOPSTRUCT structure pointed to by lpFileOp. Setting that flag sends the file to the Recycle Bin. If you want to simply delete a file and guarantee that it is not placed in the Recycle Bin, use DeleteFile.
To delete a single file from the Recycle Bin, use SHGetSpecialFolderLocation(CSIDL_BITBUCKET) or SHGetKnownFolderIDList(FOLDERID_RecycleBinFolder) to get the absolute PIDL of the Recycle Bin, then use SHBindToObject() to get the IShellFolder interface for it and call its ParseDisplayName() method to convert the desired filename into a relative PIDL, then use SHBindToObject() to get the IContextMenu interface for the file and call its InvokeCommand() method to execute the file's "delete" verb.

FindResource() fails to find data even though data is in exe

I have been all over this one, and I am just plumb stuck. I have been building a project and I want to embed a text file as a resource into the executable. I understand all the basics of how this "should" work, but for some reason it is not. So, let me start from what I have so far and maybe the problem can be pinned down.
There are two functions here, the first, EnumResNameProc was an attempt to debug the problem my self, the second, LoadFileInResource is the function I am trying to get working.
It is a little messy because I was in the middle of building it when I starting having problems.
The exact issue is, FindResourceExA is returning NULL, and I am lost as to the exact reason. I know it is an error, and the return code is 1813, "Resource Not Found".
I have other resources in this project, I have a version node, a mainifest node, (of which, I am not directly reading) I have an icon node (that I am applying to my window system menu icon) and a bitmap (that I am loading as a texture.). These all have defined types, for example, the type for the Bitmap is 12. Now, I am attempting to load a text file, with is a 'user defined' type of 10. I know the data is INSIDE the executable, because if I open it in a text editor... (yes, I tried that) it is present, so, it is being included.
the first function was an attempt to walk through all the file resources in an attempt to locate the data. It found types 2, 3, 14, 16 and 24., but not 10. I have ruled out these other types as being the above mentioned resources. (bitmap=2), (icon=3), (RT_ICON(3)+RT_ICON_GROUP(11)=14) (version=16), (manifest=24). User defined should be type 10, and it didn't find it.
My Resources.rc file includes the following:
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDR_textfile1 textfile ".\\Data\\World.txt"
This defines the file to be loaded, (again, I know this works, I can see the text of the code IN the executable.)
My resources.h file defines the following:
#define IDR_textfile1 102
So, it is being defined, included, built, and all the other resources work, and yet, FindResourceExA returns NULL on this. All the include files are lined up, (i'd get warnings and errors if it was not.)
So, the question is, am I calling FindResourceExA correctly? it is defined as:
WINBASEAPI HRSRC WINAPI FindResourceExA(HINSTANCE,LPCSTR,LPCSTR,WORD);
well, I have tried for HINSTANCE, null, hInstance passed to be my Windows in WinMain, even GetModuleHandleA's results, no dice.
For LPCSTR, which is the resource ID, I have tried what you see, MAKEINTRESOURCE(IDR_textfile1), and I have tried hard coding the ID number as well, in this case, 102. No dice.
For the type, I have tired other variations, the correct value according to Microsoft should be 10. That's why I crated the EnumResNameProc, trying to see what other IDs exist, from 0 to 500, and all I got back was the ones listed above, on the off chance something was defined funny. No Dice.
I have tried both FindResourceExA FindResourceA (with and without the 'Ex')
No Dice.
I know it is there, I have learned more then I care to about this function, but it won't find it, and I am at a loss at what else to try.
As for development environment, I am using MinGW+Eclipse+CDT, and using winres from the GCC tools to build the resource object file. I have looked for bugs in winres to see if it is doing something funny on binary types. (that's what undefined are considered, even though I am loading a text file.) oh, I also tried re-saving the file as ANSI, UTF-8, and UNICODE in case the binary format of the text mattered.
I am at a loss, I don't know what else to try. I know the data is there, I just don't why it won't access it. The Windows API call can't either see the data, or the data is encoded in a screwey way and so it doesn't access it.
What else can I try?
BOOL CALLBACK EnumResNameProc (
HMODULE hModule,
LPCTSTR lpszType,
LPTSTR lpszName,
LONG_PTR lParam)
{
std::cerr << "WTF INFO BEGIN here! \n";
// std::string info = lpszName;
int a = lParam;
std::cerr << "We found something: " << a << std::endl;
MessageBoxA ( NULL, lpszName, (LPCSTR) "Found: ", MB_OK);
std::cerr << "WTF INFO END here! \n";
return true;
}
void LoadFileInResource( HINSTANCE hInstance,
int name,
int type,
DWORD size,
const char* data)
{
// HMODULE handle = GetModuleHandleA(NULL);
for (int a = 0;a<500;a++) {
EnumResourceNamesA(hInstance, MAKEINTRESOURCE(a),
(ENUMRESNAMEPROCA) & EnumResNameProc, (LONG_PTR) a);
}
HRSRC rc = FindResourceExA(hInstance,
MAKEINTRESOURCE(IDR_textfile1),
MAKEINTRESOURCE(10),
MAKELANGID(LANG_NEUTRAL,
SUBLANG_NEUTRAL));
if (rc == NULL) {
DWORD fup = GetLastError();
MessageBoxA ( NULL, (LPCSTR) "Crap not loaded.", (LPCSTR) "Error", MB_OK);
std::cerr << "Crap not loaded, ERR: " << fup << std::endl;
}
// MessageBoxA ( NULL, (LPCSTR) " Test ", (LPCSTR) "Found: ", MB_OK);
HGLOBAL rcData = LoadResource(hInstance, rc);
// data = static_cast<const char*>(LockResource(rcData));
data = (const char*) LockResource(rcData);
size = SizeofResource(hInstance, rc);
std::cout << "Res size = " << (long) size << std::endl;
std::cout << "data =" << data << :: std::endl;
// wsprintf(szMsg,"Values loaded : %d, %d, %d\nSize = %d",
// pmem->Value1,pmem->Value2,pmem->Value3);
// MessageBox(hWnd, szMsg,lpszAppName,MB_OK);
}
IDR_textfile1 textfile ".\\Data\\World.txt"
You declared the resource type as "textfile". Which is fine but that's a string, not a number. So using MAKEINTRESOURCE() for the resource type isn't going to help you find it, that's why EnumResourceNames doesn't find it back. Fix:
IDR_textfile1 RC_DATA ".\\Data\\World.txt"
And
HRSRC rc = FindResourceEx(hInstance,
MAKEINTRESOURCE(RC_DATA),
MAKEINTRESOURCE(IDR_textfile1),
MAKELANGID(LANG_NEUTRAL,
SUBLANG_NEUTRAL));
or if you want to use your original approach:
HRSRC rc = FindResourceEx(hInstance,
L"textfile",
MAKEINTRESOURCE(IDR_textfile1),
MAKELANGID(LANG_NEUTRAL,
SUBLANG_NEUTRAL));
The call to FindResourceExA is wrong, resource type is passed in the second parameter and id in the third.
FindResourceEx at MSDN

How to get Version of the software?

I am working on getting the version of the Software which is installed on the Computer. I have implemented the logic for reading the Uninstall hive of registry, but i have observed that some of the software are not having version entries in the Uninstall hive of the registry. But i want to show the version of those softwares also.
Can some one help me out in this regard?
Supplying a software version to the registry of Windows is voluntary. If the developer of the software you're looking at chose to not display the version there or was simply unaware of such possibility, I am unable to point you to any other location he would choose to use or be aware of. In fact, the software might not even have a version number/name.
Ask yourself this: Where else is the Version detail of the software available if not in the registry? If it is available somewhere else other than registry, ask us if you could get that detail using C++. I guess this would be a better approach to solve your issue.
Added the information below since OP is looking for file version
See if the below code could help you.
CString GetFileVersionInfo(CString strFile, CString strProperty)
{
int rc;
UINT nLen;
DWORD nSize;
DWORD dwHandle = 0;
CString strBuffer;
CString strValue;
CString strBlock;
void *lpPropertyBuffer;
struct LANGANDCODEPAGE
{
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
nSize = GetFileVersionInfoSize(strFile.GetBuffer(strFile.GetLength()), &dwHandle);
::GetFileVersionInfo(strFile.GetBuffer(strFile.GetLength()), 0, nSize, strBuffer.GetBuffer(nSize));
// Read the list of languages and code pages.
if (VerQueryValue(strBuffer.GetBuffer(strBuffer.GetLength()), "\\VarFileInfo\\Translation", (LPVOID *) &lpTranslate, &nLen))
{
strBlock.Format("\\StringFileInfo\\%04x%04x\\%s",
lpTranslate->wLanguage,
lpTranslate->wCodePage,
strProperty);
rc = VerQueryValue(strBuffer.GetBuffer(strBuffer.GetLength()), strBlock.GetBuffer(nSize), &lpPropertyBuffer, &nLen);
if (rc != 0 && nLen > 0)
{
strncpy(strValue.GetBuffer(nLen + 1), (char *) lpPropertyBuffer, nLen);
strValue.ReleaseBuffer(nLen);
}
}
return strValue;
}
user version.lib while linking and you might need winver.h for compilation. You can call the function like this
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
AfxMessageBox(GetFileVersionInfo("shell32.dll", "ProductVersion"));
}
return nRetCode;
}
I'd say look at the file version information. And you might find this article useful on how the Add/Remove Programs dialog gets its information.
If the software developers chose not to add version information into Uninstall information, then there's no reliable way to get it.
You can try to find where application is installed. But even if you have the path, the application can consist of several .exe files which can have different versions and product names. If you add DLLs into the candidate list for getting version information, your results become even less predictable.