I try to get the name of executable name of all of my launched windows and my problem is that:
I use the method
UINT GetWindowModuleFileName(
HWND hwnd,
LPTSTR lpszFileName,
UINT cchFileNameMax);
And I don't understand why it doesn't work.
Data which I have about a window are: -HWND AND PROCESSID
The error is:
e.g:
HWND: 00170628
ProcessId: 2336
WindowTitle: C:\test.cpp - Notepad++
GetWindowModuleFileName(): C:\test.exe
HWND: 00172138
ProcessId: 2543
WindowTitle: Firefox
GetWindowModuleFileName(): C:\test.exe
HWND: 00120358
ProcessId: 2436
WindowTitle: Mozilla Thunderbird
GetWindowModuleFileName(): C:\test.exe
Note: test.exe is the name of my executable file, but it is not the fullpath of Notepad++... and it make this for Mozilla Thunderbird too... I don't understand why
I use the function like this:
char filenameBuffer[4000];
if (GetWindowModuleFileName(hWnd, filenameBuffer, 4000) > 0)
{
std::cout << "GetWindowModuleFileName(): " << filenameBuffer << std::endl;
}
Thank you for your response.
The GetWindowModuleFileName function works for windows in the current process only.
You have to do the following:
Retrieve the window's process with GetWindowThreadProcessId.
Open the process with PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access rights using OpenProcess.
Use GetModuleFileNameEx on the process handle.
If you really want to obtain the name of the module with which the window is registered (as opposed to the process executable), you can obtain the module handle with GetWindowLongPtr with GWLP_HINSTANCE. The module handle can then be passed to the aforementioned GetModuleFileNameEx.
Example:
TCHAR buffer[MAX_PATH] = {0};
DWORD dwProcId = 0;
GetWindowThreadProcessId(hWnd, &dwProcId);
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ , FALSE, dwProcId);
GetModuleFileName((HMODULE)hProc, buffer, MAX_PATH);
CloseHandle(hProc);
Aaah. I read the MSDN page at the bottom.
From http://support.microsoft.com/?id=228469 (archive.org link):
GetWindowModuleFileName and GetModuleFileName correctly retrieve information about windows and modules in the calling process. In Windows 95 and 98, they return information about windows and modules in other processes. However, in Windows NT 4.0 and Windows 2000, since module handles are no longer shared by all processes as they were on Windows 95 and 98, these APIs do not return information about windows and modules in other processes.
To get more information on Windows 2000, use the Process Status Helper set of APIs (known as PSAPI, see Psapi.h include file), available since Windows NT 4.0. APIs such as GetModuleFileNameEx and GetModuleBaseName offer equivalent functionality.
Try using GetModuleFileNameEx instead.
http://support.microsoft.com/?id=228469 (archive.org link)
The executive summary is, GetWindowModuleFileName() doesn't work for windows in other processes in NT-based Windows.
Instead, you can use QueryFullProcessImageName() once you have a handle to the process. You can get a handle to the process with OpenProcess(), which you can use once you have a process id. You can get the process id from the HWND by using GetWindowThreadProcessId()
This is an example of how get the name of executable that creates window, hope it can give you some ideas about:
while(true)
{
Sleep(250);//reduce cpu usage
CHAR __name[MAX_PATH];//name buffer
HWND hwnd;//window handle
DWORD pid;//process pid
hwnd=FindWindow(NULL,NULL);//find any window
PROCESSENTRY32 entry;//process structure containing info about processes
entry.dwSize=sizeof(PROCESSENTRY32);
HANDLE snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//get processes
if(hwnd!=0)
{
GetWindowThreadProcessId(hwnd,&pid);//get found window pid
}
if (Process32First(snapshot,&entry)==TRUE)//start listing processes
{
while (Process32Next(snapshot,&entry)==TRUE)
{
if (stricmp(entry.szExeFile,"explorer.exe")==0)
{
if(pid!=entry.th32ProcessID)//if found window pid is explorers one, skip it
{
HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);//open processusing PROCESS_ALL_ACCESS to get handle
if(hProcess!=NULL)
{
GetModuleFileNameEx(hProcess,NULL,__name,MAX_PATH);//get executable path
cout<<"Found: "<<__name<<endl;
}
}
}
}
}
To use GetModuleFileNameEx() you probably will need to set linker settings to link library psapi. Also include psapi.h.
Related
I have a problem with DuplicateHandle (Win32). I try to duplicate a named pipe handle and I always get the Error 183 "file already exists". I do not understand this error message, because I try to create a copy of a file handle and the new file handle does not exist before. (Is there a start value required to overwrite?) This is my call:
return DuplicateHandle (MeshellProcessHandle, sourcehandle, HelperProcess, targethandle, 0, TRUE, DUPLICATE_SAME_ACCESS) != 0;
To understand what I am doing, I have to explain more extensively: I am working on a convenient editor frontend for the command line program cmd.exe. This project already works fine on the OS/2 Operating System which is very familiar with Win32, because from a historical point of view, the two OS were developed together until one year before finishing, where Microsoft and IBM went different ways.
The implementation of this program was quite tricky: There's a windowed front end editor program. This program creates named pipes for stderr, stdout and stderr, but from the reverse point of view (output from cmd.exe is input for the editor). Because of limited communication between different sessions, I had to program a "cmd helper program" which is a tiny commandline program holding several API calls and running in the same session as the cmd.exe program. The helper gets the editor process ID via commandline parameter and opens the existing pipes created by the windowed editor program and then redirects stdin/stdout/stderr to the pipes. The helper gets the process handle of the editor from the editor process ID via "OpenProcess" API call. Then the helper executes cmd.exe which automatically inherits the stdin/stdout/stderr handles and now cmd.exe writes to and reads from the pipe.
Another option would be to parse the full pipe names to cmd.exe without using DuplicateHandle, but I would prefer to be as close as to my solution which already works fine on the OS/2 Operating System.
I am still not sure why I have no access rights to duplicate the pipe handles. But I have found another solution: My helper console program starts the child process (cmd.exe) and within this child process, I want to use the named pipes instead of stdin/stdout/stderr - this is the reason why I want to use DuplicateHandle. Windows offers a convenient solution when starting the child process by using
CreateProcess (...)
With CreateProcess, you have always to hold parameters in the STARTUPINFO structure. And there are three handle variables you can set to redirect stdin/stdout/stderr to the three named pipes cmd_std*:
STARTUPINFO StartupInfo;
HFILE cmd_stdout, cmd_stdin, cmd_stderr;
//Open the existing pipes with CreateFile
//Start child process program
StartupInfo.hStdOutput = &cmd_stdout;
StartupInfo.hStdInput = &cmd_stdin;
StartupInfo.hStdError = &cmd_stderr;
CreateProcess (..., &StartupInfo, ...);
This solution has much less code than the variant with DuplicateHandle, because I also have to save and to restore the original file handles, so this way replaces 9 DuplicateHandle calls.
I did program the changes now but my new code described above does not work. If I set the "handle inheritance flag" in CreateProcess to TRUE, cmd.exe does not get executed, but CreateProcess returns TRUE (=OK). Here's my detailed code:
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInformation;
HFILE cmd_stdout, cmd_stdin, cmd_stderr;
char *pprogstr, *pargstr;
//Open the existing pipes with CreateFile
//Start child process program cmd.exe
StartupInfo.hStdOutput = &cmd_stdout;
StartupInfo.hStdInput = &cmd_stdin;
StartupInfo.hStdError = &cmd_stderr;
StartupInfo.dwFlags = STARTF_USESTDHANDLES;
pprogstr = "C:\\WINDOWS\\system32\\cmd.exe";
pargstr = "/K";
CreateProcess (
pprogstr, // pointer to name of executable module
pargstr, // pointer to command line string
NULL, // pointer to process security attributes
NULL, // pointer to thread security attributes
TRUE, // handle inheritance flag
0, // creation flags
NULL, // pointer to new environment block
NULL, // pointer to current directory name
&StartupInfo, // pointer to STARTUPINFO
&ProcessInformation) // pointer to PROCESS_INFORMATION
Any idea?
Win32 programs have an entry parameter HINSTANCE for the Win32 entry function WinMain(). When you create your own window, the CreateWindow() API call needs this parameter.
My first idea in my mind is that this HINSTANCE should be some unique identify to distinguish different windows belong to different processes. Until recently, in some occasions, I use this HINSTANCE. Wow! If you open the same Win32 program (EXE) twice, each process has the same HINSTANCE value.
Later I figured out, it was some resource identifier (memory address) in the process. It's a virtual address for the process which is related to its PE structure in memory.
Now, if I have the two windows' HWND handles, and I want to check whether the two windows are from the same process, what is the best choice?
You can use the GetWindowThreadProcessId function to retrieve the ID of the process that created a window, given that window's HWND.
Below is a brief C code snippet showing how. We check that the return value of each GetWindowThreadProcessId() call is not zero (see this answer or this blog by Raymond Chen), to ensure that we have passed valid HWND handles.
// win1 and win2 are both HWND handles to check...
DWORD proc1, proc2;
if (!GetWindowThreadProcessId(win1, &proc1)) { // Error (invalid HWND?)
//.. error handling
}
if (!GetWindowThreadProcessId(win2, &proc2)) {
//..
}
if (proc1 == proc2) {
// Windows created by same process
}
else {
// Windows created by different processes
}
GetWindowThreadProcessId can do the work. Record here.
An interactive way to do this would be to use Microsoft's Spy++, which lets you find the Process ID, Thread ID, and parents/children of a window by point-and-clicking its GUI.
You can also find window handles (and plenty of other window-specific data) in this way.
It was possible to register the Win+V hotkey on versions of Windows prior to Windows 8. An example application using this combination is PureText.
With the Windows 8 Release Preview I've noticed that Windows 8 has taken control of a lot of hotkeys involving Windows key, but Win+V doesn't appear to be used. The following code will allow me to register a hotkey for Win+CTRL+V:
#include <Windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
if (RegisterHotKey(
NULL,
1,
MOD_WIN | MOD_NOREPEAT | MOD_CONTROL,
0x56)) // 0x56 is 'v'
{
_tprintf(_T("Hotkey 'CTRL+WIN+V' registered, using MOD_NOREPEAT flag\n"));
}
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0) != 0)
{
if (msg.message == WM_HOTKEY)
{
_tprintf(_T("WM_HOTKEY received\n"));
}
}
return 0;
}
If I modify it to register just Win+V then it'll fail to register:
if (RegisterHotKey(
NULL,
1,
MOD_WIN | MOD_NOREPEAT,
0x56)) // 0x56 is 'v'
{
_tprintf(_T("Hotkey 'WIN+V' registered, using MOD_NOREPEAT flag\n"));
}
Is there a way to force registration of the Windows+V hotkey? I assume that there might be a way to do this with Win32 API hooking but it has been a while since I've looked at that. More easily supported options for achieving this would be appreciated.
The RegisterHotKey function has always reserved the Windows key for the system. The documentation even indicates such:
MOD_WIN 0x0008
Either WINDOWS key was held down. These keys are labeled with the Windows logo. Keyboard shortcuts that involve the WINDOWS key are reserved for use by the operating system.
You should choose a different [set of] modifier key[s] when registering your own non-system hotkey.
Besides, as others have mentioned, the +V keyboard shortcut is already in use. And RegisterHotKey fails when you try to register a hot key that is already registered.
Lots of Win32 functions set an error code that indicates what exactly went wrong when they don't work. If the documentation indicates as much, you can call the GetLastError function to determine what that error code was. That will give you a lot more information to help in debugging the problem.
Here is the full list of Windows 8 keyboard shortcuts in pdf or xps. Win+V is already in use; it cycles through notifications. Sticking with Win+CTRL+V is probably your best option.
Use PlainTexter... it uses a global keyboard hook. {Works on my machine}
http://www.elijahg.com/plaintexter
Is it possible to somehow change standart I/O functions handle on Windows? Language preffered is C++. If I understand it right, by selecting console project, compiler just pre-allocate console for you, and operates all standart I/O functions to work with its handle. So, what I want to do is to let one Console app actually write into another app Console buffer. I though that I could get first´s Console handle, than pass it to second app by a file (I don´t know much about interprocess comunication, and this seems easy) and than somehow use for example prinf with the first app handle. Can this be done? I know how to get console handle, but I have no idea how to redirect printf to that handle. Its just study-purpose project to more understand of OS work behind this. I am interested in how printf knows what Console it is assiciated with.
If I understand you correctly, it sounds like you want the Windows API function AttachConsole(pid), which attaches the current process to the console owned by the process whose PID is pid.
If I understand you correct you can find the source code of application which you want to write in http://msdn.microsoft.com/en-us/library/ms682499%28VS.85%29.aspx. This example show how to write in stdin of another application and read it's stdout.
For general understanding. Compiler don't "pre-allocate console for you". Compiler use standard C/C++ libraries which write in the output. So if you use for example printf() the following code will be executed at the end will look like:
void Output (PCWSTR pszwText, UINT uTextLenght) // uTextLenght is Lenght in charakters
{
DWORD n;
UINT uCodePage = GetOEMCP(); // CP_OEMCP, CP_THREAD_ACP, CP_ACP
PSTR pszText = _alloca (uTextLenght);
// in the console are typically not used UNICODE, so
if (WideCharToMultiByte (uCodePage, 0, pszwText, uTextLenght,
pszText, uTextLenght, NULL, NULL) != (int)uTextLenght)
return;
WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), pszText, uTextLenght, &n, NULL);
//_tprintf (TEXT("%.*ls"), uTextLenght, pszText);
//_puttchar();
//fwrite (pszText, sizeof(TCHAR), uTextLenght, stdout);
//_write (
}
So if one changes the value of STD_OUTPUT_HANDLE all output will be go to a file/pipe and so on. If instead of WriteFile the program use WriteConsole function such redirection will not works, but standard C/C++ library don't do this.
If you want redirect of stdout not from the child process but from the current process you can call SetStdHandle() directly (see http://msdn.microsoft.com/en-us/library/ms686244%28VS.85%29.aspx).
The "allocating of console" do a loader of operation system. It looks the word of binary EXE file (in the Subsystem part of IMAGE_OPTIONAL_HEADER see http://msdn.microsoft.com/en-us/library/ms680339%28VS.85%29.aspx) and if the EXE has 3 on this place (IMAGE_SUBSYSTEM_WINDOWS_CUI), than it use console of the parent process or create a new one. One can change a little this behavior in parameters of CreateProcess call (but only if you start child process in your code). This Subsystem flag of the EXE you define with respect of linker switch /subsystem (see http://msdn.microsoft.com/en-us/library/fcc1zstk%28VS.80%29.aspx).
If you want to redirect printf to a handle (FILE*), just do
fprintf(handle, "...");
For example replicating printf with fprintf
fprintf(stdout, "...");
Or error reporting
fprintf(stderr, "FATAL: %s fails", "smurf");
This is also how you write to files. fprintf(file, "Blah.");
Does anyone know a method to programmatically close the CD tray on Windows 2000 or higher?
Open CD tray exists, but I can't seem to make it close especially under W2k.
I am especially looking for a method to do this from a batch file, if possible, but API calls would be OK.
I kind of like to use DeviceIOControl as it gives me the possibility to eject any kind of removable drive (such as USB and flash-disks as well as CD trays). Da codez to properly eject a disk using DeviceIOControl is (just add proper error-handling):
bool ejectDisk(TCHAR driveLetter)
{
TCHAR tmp[10];
_stprintf(tmp, _T("\\\\.\\%c:"), driveLetter);
HANDLE handle = CreateFile(tmp, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
DWORD bytes = 0;
DeviceIoControl(handle, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, &bytes, 0);
DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0, &bytes, 0);
DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, 0, 0, 0, 0, &bytes, 0);
CloseHandle(handle);
return true;
}
Here is an easy way using the Win32 API:
[DllImport("winmm.dll", EntryPoint = "mciSendStringA", CharSet = CharSet.Ansi)]
protected static extern int mciSendString(string lpstrCommand,StringBuilder lpstrReturnString,int uReturnLength,IntPtr hwndCallback);
public void OpenCloseCD(bool Open)
{
if (Open)
{
mciSendString("set cdaudio door open", null, 0, IntPtr.Zero);
}
else
{
mciSendString("set cdaudio door closed", null, 0, IntPtr.Zero);
}
}
I noticed that Andreas Magnusson's answer didn't quite work exactly the same as Explorer's 'Eject' button did. Specifically, the drive wasn't grayed out in Explorer using Andreas' code, but was if you used the Eject command. So I did some investigating.
I ran API Monitor while running the Eject command from Explorer (Windows 7 SP1 64-bit). I also found a good (now-defunct) MSKB article 165721 titled How To Ejecting Removable Media in Windows NT/Windows 2000/Windows XP. The most interesting part of the article is quoted below:
Call CreateFile with GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, and OPEN_EXISTING. The lpFileName parameter should be \\.\X: (where X is the real drive letter). All other parameters can be zero.
Lock the volume by issuing the FSCTL_LOCK_VOLUME IOCTL via DeviceIoControl. If any other application or the system is using the volume, this IOCTL fails. Once this function returns successfully, the application is guaranteed that the volume is not used by anything else in the system.
Dismount the volume by issuing the FSCTL_DISMOUNT_VOLUME IOCTL. This causes the file system to remove all knowledge of the volume and to discard any internal information that it keeps regarding the volume.
Make sure the media can be removed by issuing the IOCTL_STORAGE_MEDIA_REMOVAL IOCTL. Set the PreventMediaRemoval member of the PREVENT_MEDIA_REMOVAL structure to FALSE before calling this IOCTL. This stops the device from preventing the removal of the media.
Eject the media with the IOCTL_STORAGE_EJECT_MEDIA IOCTL. If the device doesn't allow automatic ejection, then IOCTL_STORAGE_EJECT_MEDIA can be skipped and the user can be instructed to remove the media.
Close the volume handle obtained in the first step or issue the FSCTL_UNLOCK_VOLUME IOCTL. This allows the drive to be used by other
processes.
Andreas's answer, the MSKB article, and my API sniffing of Explorer can be summarized as follows:
CreateFile called to open the volume. (All methods).
DeviceIoControl called with FSCTL_LOCK_VOLUME. (All methods).
DeviceIoControl called with FSCTL_DISMOUNT_VOLUME. (Andreas's and MSKB methods only. Explorer does not call this for some reason. This IOCTL seems to be what affects whether the drive is grayed out in Explorer or not. I am not sure why Explorer doesn't call this).
DeviceIoControl called with IOCTL_STORAGE_MEDIA_REMOVAL and PREVENT_MEDIA_REMOVAL member set to FALSE (MSKB and Explorer methods. This step is missing from Andreas's answer).
DeviceIoControl called with IOCTL_STORAGE_EJECT_MEDIA (Andreas and MSKB article) or IOCTL_DISK_EJECT_MEDIA (Explorer; note this IOCTL was obsoleted and replaced with the STORAGE IOCTL. Not sure why Explorer still uses the old one).
To conclude, I decided to follow the procedure outlined in the MSKB article, as it seemed to be the most thorough and complete procedure, backed up with an MSKB article.
Nircmd is a very handy freeware command line utility with various options, including opening and closing the CD tray.
To close the drive tray do as described here but instead of using DeviceIoControl with IOCTL_STORAGE_EJECT_MEDIA you need to call DeviceIoControl with IOCTL_STORAGE_LOAD_MEDIA.