0

I'm trying to make an app that will run something only if in the moment that the dll is called, the window that is focused in that moment has the same path as a values that is given. That being said, the following code will be added in a dll which will have a function with the path value as it parameter that returns true if the condition is met, or false otherwise. The problem I have is that I can't seem to find a way to get the path of the focused window, the following code always returns an empty string. And I can't simply use the title of the windows because there are apps that yes, the title is static like Task Manager, but there are others that the title is changed, like Windows Explorer changes it's title depending where the user is in. What do I have to change?

The following code is used only as a test, because later on that is the base for what I need, and I will only have to add a comparison on path variable, and based on that to return true or false:

#include "Windows.h";
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;

int main() {
    // 2 seconds delay to have time to switch windows
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));

    HWND hWnd = GetForegroundWindow(); 
    int length = GetWindowTextLength(hWnd);
    wchar_t* title = new wchar_t[length];
    GetWindowTextW(hWnd, title, length);

    DWORD id;
    GetWindowThreadProcessId(hWnd, &id); 

    wchar_t* path = new wchar_t[MAX_PATH];
    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
    GetModuleFileNameW((HMODULE)hProc, path, MAX_PATH);
    CloseHandle(hProc);

    wcout << "ID: " << id << " | Title: " << title << " | Path: " << path << endl << endl;
    return 1;
} 

Output example: ID: 2536 | Title: Task Manage | Path:

Jabberwocky
  • 45,262
  • 17
  • 54
  • 100
sValentin
  • 81
  • 7
  • 1
    You are using GetModuleFilename incorrectly. It returns the filename of a module in the current process, it takes a HMODULE, not a HPROCESS. It's not for getting information about another process. – CherryDT Oct 05 '21 at 11:44
  • Does this answer your question? [How do I GetModuleFileName() if I only have a window handle (hWnd)?](https://stackoverflow.com/questions/277085/how-do-i-getmodulefilename-if-i-only-have-a-window-handle-hwnd) – CherryDT Oct 05 '21 at 11:45
  • 1
    You probably want `GetModuleFileNameEx`. You may also find `GetProcessImageFileName` or `QueryFullProcessImageName` interesting. (right now MSDN docs return a 404 for some reason but it's still in Google Cache) – CherryDT Oct 05 '21 at 11:48
  • Unfortunately what you suggested in that other thread is for C#, and neither that nor C++ are what I usually use, C++ is only for when I actually need something that can't be done in Java, and I need a native function. Now as for `GetModuleFileNameEx`, it doesn't let me use it and it gets marked as `undefined`. – sValentin Oct 05 '21 at 12:30
  • `QueryFullProcessImageNameA` does work, and it is giving me what I want (it does need to be run as `Admin` for some, ex `Task Manager`), but I noticed a problem when it comes to browsers, it fails there. But I suspect that is the problem because they are creating a lot of instances and not just a single say `firefox.exe` or `edge.exe`. `GetWindowTextW` and `GetWindowThreadProcessId` still works with browsers too, but not `QueryFullProcessImageNameA`. – sValentin Oct 05 '21 at 13:14
  • C#/C++ - yes but it shows the correct API calls to use and what parameters to pass, so you can apply it independently of the language. Also some answers show C++ actually. If you are looking for Java and not C++ then maybe you should update your question's tags! (About `GetModuleFileNameEx`: Note the info in the remarks section in MSDN, you probably didn't include the right header and/or didn't import the right library and/or didn't set the `PSAPI_VERSION` define accordingly.) – CherryDT Oct 05 '21 at 13:56

1 Answers1

1

To get the result I wanted, I switched to QueryFullProcessImageName (like CherryDT suggested to take a look at), but you have to be careful, you need to run it with Admin rights to get the path for some apps like I encountered with Task Manager, maybe because it is an Windows app, not sure and you'll have to do some research on that if you need more details. Here is a little example:

#include "Windows.h";
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;

int main() {
    // 2 seconds delay to have time to switch windows
    std::this_thread::sleep_for(std::chrono::milliseconds(2000));

    HWND hWnd = GetForegroundWindow(); 
    int lgth = GetWindowTextLength(hWnd) + 1;
    wchar_t* title = new wchar_t[lgth];
    GetWindowTextW(hWnd, title, lgth);

    DWORD id;
    GetWindowThreadProcessId(hWnd, &id); 

    wchar_t* path = new wchar_t[MAX_PATH];
    DWORD size = MAX_PATH;
    HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, id);
    QueryFullProcessImageNameW(hProc, 0, path, &size);
    CloseHandle(hProc);

    wcout << "ID: " << id << " | Title: " << title << " | Path: " << path << endl << endl;
    return 1;
} 

Output example: ID: 12580 | Title: Task Manage | Path: C:\Windows\System32\Taskmgr.exe

sValentin
  • 81
  • 7
  • I think you can also use the `W` version instead of the `A` version, and use `wchar_t` instead of `char`, like you did for the title. (In fact you should get the `W` version if you just don't use any suffix in your case.) This way, paths with Unicode characters will still work properly. – CherryDT Oct 05 '21 at 14:03