2

EDIT: I forgot to mention, I do not have source code for the DLL that creates window, so I can't actually change the function to return HWND.

I am creating a Win32 application, and am using a DLL that creates a window for me through one of its exported function "void X();" I call X() in my WinMain().

It does create a window for me. I want to get the HWND of the window that was created by this exported library function, as X() returns void, so I can use it for other API calls. Can someone tell the easiest to get the HWND?

I have searched and questions answered here, but I cant somehow figure out the exact, appropriate solution. I tried EnumWIndows() and then getting the Process ID, and then comparing with the current thread process ID. But I guess there should be a far better much more efficient and a easy way to get HWND. After all, I am in the WinMain of the process that created this window in the first place.

If I need to explain anything, that I have missed out writing here, please let me know.

I am sure that this is very basic and am missing something blatantly here. Sorry. Thanks & Regards!

aeon
  • 1,029
  • 2
  • 13
  • 23
  • Is there any reason why you can't return the handle from the function that creates the window in the DLL, instead of `void`? – Mr Lister Jan 19 '13 at 07:38
  • Create another exported function in the DLL which returns the `HWND`. – JosephH Jan 19 '13 at 07:38
  • @ Mr Lister: I forgot to mention, I do not have source code for the DLL that creates window, so I can't actually change the function to return HWND. – aeon Jan 19 '13 at 07:39
  • @aeon Ah, I see why it is a problem then. – Mr Lister Jan 19 '13 at 07:40
  • @ Mr Lister: The X() does not return HWND, but I need it for using in some other calls later on in my application. There is no exported function in the DLL that gives me the HWND. So I need to get the HWND in another way. – aeon Jan 19 '13 at 07:42
  • Is it possible to use [GetActiveWindow](http://msdn.microsoft.com/en-us/library/windows/desktop/ms646292%28v=vs.85%29.aspx). – Althaf Hameez Jan 19 '13 at 07:44
  • 1
    Why dont you create the window yourself and take full control? – Juarrow Jan 19 '13 at 08:47
  • @Althaf: `GetActiveWindow()` returns a handle to the active window. You cannot assume that a window that was just created is in fact the active window. For example, the window could be created without the `WS_VISIBLE` style, or with a `WS_EX_NOACTIVATE` style. – IInspectable Jan 19 '13 at 12:21
  • Perhaps the library doesn't want you messing with its private window handle. You didn't explain why you need the window handle. Maybe you can accomplish what you need by simply creating your own window and using that. – Raymond Chen Jan 19 '13 at 13:07
  • @Raymond: I am creating a small game, and I am using this library to create and initialize the main window. I want to use GetClientRect(HWND hWnd, LPRECT lpRect); to get the client area co-ords and use them to restrict the movement of the sprites to be within the client area. Unfortunately I cannot bypass using the library. – aeon Jan 20 '13 at 13:26

2 Answers2

2

The easiest way to do that is to use the function SetWindowsHookEx(WH_CBT, fun, NULL, GetCurrentThreadId()). Then the fun function, a callback defined by you, will be called when a number of events happen. The one you want is the HCBT_CREATEWND.

Somethink like that (totally untested):

HWND hDllHandle = NULL;
LRESULT CALLBACK X_CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HCBT_CREATEWND)
        hDllHandle = (HWND)wParam;
    return CallNextHookEx(NULL, nCode, wParam, lParam); //The first parameter is useless
}

HWND CallXAndGetHWND()
{
    HHOOK hDllHook = SetWindowsHookEx(WH_CBT, X_CBTProc, NULL, GetCurrentThreadId());
    X();
    UnhookWindowsHookEx(hDllHook);
    //hDllHandle is a global variable, so will be now you window!
    return hDllHandle;
}

Note that this function is not thread-aware, but most likely you will call it just once at the beginning of your code, so it shouldn't matter.

And beware! Many functions, even Win32 API functions, create hidden windows. This code will hook all of them and return the last one to be created. Changing it to return any other, or even a list of them, if needed, should be trivial.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • That's a good idea. I had this in my mind, but I thought I didn't have to get into hooking to just get a HWND of the main window that is created by my own application (through a library call, that is). I just can't believe I have to do this just to get a HWND of my own app :-| I will try this and let you know. Meanwhile, if some other solutions comes to your mind, please let me know. Cheers. – aeon Jan 19 '13 at 10:01
  • @aeon: Actually I didn't invent this method: this is how MFC used to do it the last time I looked into it, to get the `HWND` of the `MessageBox()` window, for example. Although in that case you'll want the first window created, not the last one. – rodrigo Jan 19 '13 at 14:47
2

Use a tool like Spy++ or Winspector to see all of the HWNDs created by your app, in particular their class names and window titles. Then you can copy those values into your code and make a single call to FindWindow() after the DLL has created its window, eg:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // ...
    X();
    HWND hWnd = FindWindow("ClassNameHere", "TitleHere");
    // ...
    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    This will do very strange things if two copies of the library are running. – Raymond Chen Jan 20 '13 at 17:50
  • @Raymond: What do you suggest that I do to get the HWND without ambiguity? – aeon Jan 21 '13 at 08:03
  • @aeon: You have two choices: 1) use a combination of EnumWindows(), GetWindowThreadProcessId(), GetClassName() and/or GetWindowText() to locate any HWND(s) of the desired class/title that only belong to the calling process. 2) use SetWindowsHookEx(WH_CBT) to detect every HWND that is created while X() is running, using GetClasssName() to verify if multiple HWNDs are created. – Remy Lebeau Jan 21 '13 at 10:26
  • @Remy: Thanks for that. I will check that. I only wish there was something simpler to do :-) – aeon Mar 11 '13 at 03:20