I am trying to make a windows GUI application.
I declared some static variables in my window procedure function and initialized it in the WM_CREATE whose lParam is a pointer to the CREATESTRUCT. However, since these values are static, I can only make one instance of my window; if I make more the previous instances' data will be changed to the new datas.
Is there a way to access the CREATESTRUCT of a window after the WM_CREATE message so that I can solve this problem?
Save a pointer to a user-defined structure in WM_CREATE using either SetWindowLongPtr or SetProp, and retrieve it with the matching functions.
e.g.
case WM_CREATE:
SetWindowLongPtr(hWnd, GWLP_USERDATA, ((LPCREATESTRUCT)lParam)->lpCreateParams);
break;
case <other messages>:
MyData* pData = (MyData*)GetWindowLongPtr(hWnd, GWLP_USERDATA).
Some will argue that you shouldn't use GWLP_USERDATA and instead should reserve storage space in your window class; this is up to you. Using SetProp/GetProp is also a valid alternative.
Related
Within a modeless DialogBoxProcedure(), I implemented two main functions:
Constant movement along the X and Y axis using SetWindowPos(), each movement activated by a timer. (Essentially making the Dialog Box bounce around the screen). I did this by using static int to set the variables, and adjust them accordingly upon receiving a new timer message.
Recursively Creating a new DialogBox by calling CreateDialog() whenever the original Dialog Box receives the appropriate message to do so.
I wanted the new recursively created dialog box to call on its own DialogBoxProcedure with its own set of static variables so it could move independently, but what ended up happening was the new DialogBox was stacked exactly on top of the previous dialog box,probably because of the usage of static variables in the DialogProcedure. Is there a way to fix this?
You can't create multiple instances of the same dialog procedure. You can use the same dialog procedure more than once and make sure it knows which dialog it's talking about.
Store the variables in some kind of structure and make two instances of that, for example using malloc or just two different global or static variables.
Then:
Instead of CreateDialog use CreateDialogParam and give it a pointer:
// instead of
hWndDialog = CreateDialog( hInstance, IDD_MY_DIALOG, hWndParent, MyDialogProc);
// use:
hWndDialog = CreateDialogParam(hInstance, IDD_MY_DIALOG, hWndParent, MyDialogProc, pMyDialogStruct1);
// ^^^^^ ^^^^^^^^^^^^^^^^
When your dialog proc gets a WM_INITDIALOG message, that pointer is in lParam. You can then transfer it to the HWND by using SetWindowLongPtr(DWLP_USER):
SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)lParam);
Now the struct pointer is stored in the HWND and you can get it back at any time:
MyDialogStruct* dlgStruct = (MyDialogStruct*)GetWindowLongPtr(hWnd, DWLP_USER);
I am trying to automate an external Windows application. The goal is to make this application start minimized without showing any active window/splash screens and without stealing focus from other applications.
I wrote a little program on C that calls EnumWindows() in a loop and uses ShowWindow() to minimize the required window. It is quite fast and works in 80% of cases. Unfortunately, sometimes the application window is still showing and stealing the focus for a short period of time.
What would be a better (sure) way to intercept the window?
Is using SetWindowsHookEx hooks the only alternative?
Have you tried using the wShowWindow member of the STARTUPINFO structure you pass to CreateProcess() when starting the application? That was designed to do exactly things like this.
If dwFlags specifies STARTF_USESHOWWINDOW, this member can be any of the values that can be specified in the nCmdShow parameter for the ShowWindow function, except for SW_SHOWDEFAULT. Otherwise, this member is ignored.
For GUI processes, the first time ShowWindow is called, its nCmdShow parameter is ignored wShowWindow specifies the default value. In subsequent calls to ShowWindow, the wShowWindow member is used if the nCmdShow parameter of ShowWindow is set to SW_SHOWDEFAULT.
For example:
STARTUPINFO si = { sizeof(si) }
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_MINIMIZE;
CreateProcess(..., &si, ...);
I had a small debate with a fellow programmer. He uses the following idiom in his code:
HWND hWnd = SomeFunctionWhichReturnsAWindow();
if(hWnd != NULL && hWnd != INVALID_HANDLE_VALUE)
{
// All good
}
else
{
// Error
}
I told him that in my opinion this is a wrong approach, as the HWND type has nothing to do with the INVALID_HANDLE_VALUE definition, but he's sure that this is good code, as a valid handle can never be equal to INVALID_HANDLE_VALUE, and it's in the mood of "better safe than sorry".
So, is it an acceptable and correct idiom?
It is a mistake to compare an HWND against INVALID_HANDLE_VALUE. Although, in practise this is not a mistake that will hurt you.
The only HWND value reserved by CreateWindowEx as being invalid is NULL. Now, it happens to be an implementation detail that INVALID_HANDLE_VALUE cannot ever be a valid HWND, but that is just implementation detail. The function that yields window handles, CreateWindowEx, uses NULL to indicate failure. That's all you need to know.
If you wish to win your argument with your colleague, I suggest you look inside SomeFunctionWhichReturnsAWindow and find out which Win32 API is called to produce the HWND. Then consult the documentation. That will show you that NULL is the reserved invalid value.
For the sake of clarity you absolutely should change the code to test against NULL alone.
INVALID_HANDLE_VALUE is defined as -1. An invalid HWND is defined as 0. No API will ever return HWND(-1) on failure, so checking for INVALID_HANDLE_VALUE is meaningless, it will never happen.
However, there are some APIs that accept reserved non-zero HWND values as input, and thus cannot be used as valid HWND return values, either:
PeekMessage() and GetMessage():
If hWnd is NULL, (Peek/Get)Message retrieves messages for any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL (see the MSG structure). Therefore if hWnd is NULL, both window messages and thread messages are processed.
If hWnd is -1, (Peek/Get)Message retrieves only messages on the current thread's message queue whose hwnd value is NULL, that is, thread messages as posted by PostMessage (when the hWnd parameter is NULL) or PostThreadMessage.
So there is a logical difference between HWND(0) and HWND(-1). And in fact, because of that difference, a valid HWND will never be -1 because a message loop would never be able to retrieve messages for it.
Also SetWindowPos() has some reserved values as well:
hWndInsertAfter [in, optional]
Type: HWND
A handle to the window to precede the positioned window in the Z order. This parameter must be a window handle or one of the following values.
HWND_BOTTOM
(HWND)1
Places the window at the bottom of the Z order. If the hWnd parameter identifies a topmost window, the window loses its topmost status and is placed at the bottom of all other windows.
HWND_NOTOPMOST
(HWND)-2
Places the window above all non-topmost windows (that is, behind all topmost windows). This flag has no effect if the window is already a non-topmost window.
HWND_TOP
(HWND)0
Places the window at the top of the Z order.
HWND_TOPMOST
(HWND)-1
Places the window above all non-topmost windows. The window maintains its topmost position even when it is deactivated.
CreateWindowEx and the similar functions that return a HWND clearly state that an invalid HWND is 0. Anything other might be valid.
Therefore, checking for INVALID_HANDLE_VALUE is 100% wrong, no matter what you might assume.
Making assumptions such as "this will probably never hurt" are very much dangerous and, although at this time valid, in the future you may be used to assume similar features that are not that innocent.
HWND can't be used in comparison to INVALID_HANDLE_VALUE as this two are two different things. Most resources, such as a file, etc return HANDLE and must be compared to INVALID_HANDLE_VALUE to ensure the resource is okay for use by any function which depends on it. However, HWND refers to handle for windows GUI objects. So is save to compare HWND values to 0 for invalid return handles rather than using INVALID_HANDLE_VALUE which is also -1.
Furthermore, to more information on the HANDLE type, you can check this StackOverflow previous answers to learn more.
A HANDLE is a context-specific unique identifier. By context-specific,
I mean that a handle obtained from one context cannot necessarily be
used in any other aribtrary context that also works on HANDLEs.
For example, GetModuleHandle returns a unique identifier to a
currently loaded module. The returned handle can be used in other
functions that accept module handles. It cannot be given to functions
that require other types of handles. For example, you couldn't give a
handle returned from GetModuleHandle to HeapDestroy and expect it to
do something sensible.
The HANDLE itself is just an integral type. Usually, but not
necessarily, it is a pointer to some underlying type or memory
location. For example, the HANDLE returned by GetModuleHandle is
actually a pointer to the base virtual memory address of the module.
But there is no rule stating that handles must be pointers. A handle
could also just be a simple integer (which could possibly be used by
some Win32 API as an index into an array).
The question is the windows handle is valid or not, Why not just use IsWindow()?
I have seen RocketDock redirect the minimize animation in Vista so windows minimize to the dock, and am just curious how this was done. Is the actual minimize animation redirected to the dock, or is something like a hook to stop Windows from minimizing the window and RocketDock has a custom animation when the window is minimized?
I am working on an open source multi-monitor taskbar project called "OpenMMT." I've recently discovered (through many headaches) how to accomplish this.
The following explanation assumes that you know how to go about using RegisterShellHookWindow.
On the window procedure that will receive the shell hooks, look for HSHELL_GETMINRECT.
Now, from here on out is where I had problems. According to MSDN, the lparam member passed contains a pointer to a "SHELLHOOK" object. Which is true, however, I could not get it to work for the simple fact that the "rc" member of that structure, is a RECT that differs from the actual RECT structure in the Windows header files. The RECT in the header files uses LONG for its members, were as on here, we want SHORT.
Anyways, here's a snippet on how I accomplished this.
Structures to define:
typedef struct {
SHORT left;
SHORT top;
SHORT right;
SHORT bottom;
} REALRECT, *LPREALRECT;
typedef struct {
HWND hWnd;
REALRECT rc;
} DOCUMENT_ME_RIGHT_MICROSOFT, *LPDOCUMENT_ME_RIGHT_MICROSOFT;
Then on the Window Procedure:
case HSHELL_GETMINRECT:
{
LPDOCUMENT_ME_RIGHT_MICROSOFT lpShellHook = (LPDOCUMENT_ME_RIGHT_MICROSOFT)lParam;
// lpShellHook now contains all the info. If you want to change the location
// of the animation, simply change the lpShellHook->rc members to point
// to the right coordinates and then return TRUE;
return TRUE;
}
When minimizing programs from my application I encountered some instances where the animation would default back to the original one. I resolved this by minimizing them like so:
void MinimizeApp(HWND hWnd) {
SetForegroundWindow(hWnd);
ShowWindowAsync(hWnd, SW_MINIMIZE);
}
If you want more info regarding my project or you just want to peek at the source, feel free to do so at https://github.com/Fafson/OpenMMT
The ptMinPosition member of the WINDOWPLACEMENT structure specifies the coordinates of the window when it is minimized, so SetWindowPlacement function can be used to that effect. But some testing shows the window should not have a task bar button for that to work (i.e. no WS_EX_APPWINDOW).
I don't know how RocketDock works, but I guess this could be achieved by installing a global WH_CBT hook, and acting upon (setting the ex_style and then setting minimized coordinates) HCBT_MINMAX notification.
You can use the AnimateWindow API function, and pass it e.g. AW_HOR_POSITIVE | AW_VER_POSITIVE to get a diagonal animation.
I'd start with a global hook catching WM_SYSCOMMAND/SC_MINIMIZE, and use AnimateWindow to target the top right corner.
If this doesn't provide the desired effect, the next step would be to use WM_PRINT/WM_PRINTCLIENT to get a copy of the window into a bitmap (I believe this is what AnimateWindow does internally), then hiding the window and doing my own animation.
since I couldn't find an answer to this question I researched a bit further into the MSDN and I found isChild(). It might give me the answer to that other question.
Now, in order to use isChild() I need to pass the HWND of the parent application that I want to check, in this case my own application.
How do I get the HWND of my own application?
I don't know the title since it changes constantly so I can't use FindWindow().
Thanks
Edit:
Since it's not clear, I'll add more information:
I am not creating a window. I don't have access to the creation of a window. My code is a piece of code that gets compiled together with whatever application the other programmer is coding and I have no access to how the window is created, the title or any other information.
So, how do I get the HWND to the "WINDOW" of the application I am running?
Your application doesn't have a HWND. The window does. An application may have no windows or it may have many, so there is no general function to "Get the application's HWND".
The obvious solution is just to hold on to the handle when you get it. When you create the window, a HWND is returned. Store that.
Use GetTopWindow() and GetNextWindow() to walk through windows z-order.
However, don't think it is necessary, but you can use GetCurrentProcessId() and
GetWindowThreadProcessId(), may be something like following will help you:
HWND FindMyTopMostWindow()
{
DWORD dwProcID = GetCurrentProcessId();
HWND hWnd = GetTopWindow(GetDesktopWindow());
while(hWnd)
{
DWORD dwWndProcID = 0;
GetWindowThreadProcessId(hWnd, &dwWndProcID);
if(dwWndProcID == dwProcID)
return hWnd;
hWnd = GetNextWindow(hWnd, GW_HWNDNEXT);
}
return NULL;
}
Can't you just hold onto the handle returned from CreateWindow? If not, why not?
Presumably your code gets called by main application code, otherwise what use is it? In which case I acnnot see why your code's API cannot include some way of informing you of the handle of the application's main window.
As others have already pointed out
In general, an application can have zero or multiple top-level windows.
If you're creating the window yourself you can just remember the HWND somewhere.
But maybe your code is in a DLL, so you didn't actually create the top-level window yourself. So what to do?
I would suggest the following:
Use EnumWindows to enumerate all top-level windows.
Use GetWindowLongPtr to get the HINSTANCE for each top-level window. Compare this against the HINSTANCE of the application, which you can get using GetModuleHandle(NULL). If they're identical, you've found your main window.
Edit: Here is some code. Turns out you also have to use IsWindowVisible because there seem to be quite a few invisible "helper" windows.
HWND hwndMain;
BOOL CALLBACK EnumWindowProc(HWND hwnd, LPARAM lParam)
{
HINSTANCE hinst=(HINSTANCE)GetModuleHandle(NULL);
if((HINSTANCE)GetWindowLongPtr(hwnd, GWL_HINSTANCE)==hinst &&
IsWindowVisible(hwnd))
{
hwndMain=hwnd;
return FALSE;
}
else
return TRUE;
}
Then in the place you want to find the window:
hwndMain=NULL;
EnumWindows(EnumWindowProc, 0);
And after this, hwndMain should contain the handle of the window, or NULL if none exists.
Using EnumWindows is a bit burdensome but is recommended over calling GetWindow in a loop because, as MSDN notes: "An application that calls GetWindow to perform this task risks being caught in an infinite loop or referencing a handle to a window that has been destroyed."
You can inject a DLL in a thread who appeal user32.dll
http://msdn.microsoft.com/en-us/library/ms821625.aspx
This is old for me, but IIRC you should receive the HWND as a parameter in the window proc. You can save it in a global variable somewhere in the beginning.
What about your windows class name?
Is it always different on window creation?
If not you could still you FindWindow().