How to get the parent structure as Spy++ gives it? - windows

In our code, a C++ class that is derived from CMDIChildWnd is instantiated and its Create() function is called, which is actually CMDIChildWnd::Create(). The 5th parameter pParentWnd is being set to a CMDIFrameWnd object. This in turn (within the MFC code) sets up a CREATESTRUCT object, sets it's hwndParent to that parameter and then calls PreCreateWindow() with that object passed as one of the parameters.
However, when going up the parent window list using CWnd::GetParent() (original) GetAncestor(hwnd, GA_PARENT) (just a try, since the original didn't work and this code is 20+ years old) and even GetWindow(hwnd, GW_OWNER) just to see if it was setting the window's owner for some reason. In each case, I do not see the handle which is associated with the CMDIFrameWnd object. Instead, the parent shown is the desktop, and owner is NULL.
Using Spy++, it shows what I was expecting. How would I get the layout given by Spy++ programmatically?

In MDI interface CMDIChildWnd is usually passed to CMultiDocTemplate, then we create a new window through CDocManager::OnFileNew, that in turn calls CFrameWnd::LoadFrame which passes NULL for child window's parent (at least in VS 2017)
We usually don't call mdi_child->Create directly, unless we initialize everything else manually. Perhaps you mean the base class CMDIChildWnd::Create is called, or you are able to override it.
In child window,
::GetAncestor(m_hWnd, GA_ROOT) or ::GetAncestor(m_hWnd, GA_ROOTOWNER)
Should return a reference to the main frame, otherwise use AfxGetMainWnd()

Related

How do I test if my custom callback is set as the current procedure for a given window?

We have a kiosk mode application for Windows Mobile 5 that was going strong for a year at least in production. It uses window subclassing through the SetWindowLong windows API function to override the behavior of the taskbar to prevent users from ever leaving our application or other explicitly allowed applications.
My callback overrides the handling of a few window messages and calls the default handler for other messages. This is done by storing the previous function pointer returned by SetWindowLong, and using it inside of the new function by calling CallWindowProc on it.
Then we had to update the application to be compatible with Windows Mobile 6.5.3, and started having a bunch of problems. I followed this article to disable the bottom menu buttons which are new on 6.5. On a single application, it works fine and the menu respects my callback. As soon as the user opens up another application through ours, that window seems to be recreated, and I had to devise a mechanism to detect foreground window changes and then "resubclass" the window again.
In my code, I don't have control of when exactly this window is recreated, so my first attempt was to use the GetWindowLong function to obtain the current callback address and test it against my own function address. I learned the hard way that I can't just compare the values like that, since it does not always return the function pointer.
Because I'm not able to test if my method is the current handler that way, I end up sometimes setting my method as the handler, and the previous handler is also my own method (in this case, the window was not recreated and thus already had my method set). This results in an infinite loop, since my callback ends up calling itself indefinitely.
How can I know if my custom function is the one being used by a certain window, so that I can avoid this infinite recursion?
Don't use SetWindowLong(GWL_WNDPROC) to subclass a window. Use SetWindowSubClass() instead (like Raymond Chen said):
Subclassing Controls
Safer subclassing
Amongst providing safer subclassing semantics (such as allowing multiple subclasses at a time), it also allows you to associate user-defined data with each subclass. So you could use GetWindowSubclass() to check if you have already subclassed the window or not.
Or, you could simply keep track of whether or not you have already subclassed the window. A simple boolean variable will suffice. Once your subclass is in place, you MUST remove the subclass before the window is fully destroyed. So, for instance, when the subclass receives the WM_NCDESTROY message, you can remove the subclass and clear your boolean at the same time, and then the next time you see the window again your boolean will tell you that you need to subclass the window.
Send the custom message to window. Handle this message in your custom function to return some value that will indicate that it was your custom handler.. and so on.
if(SendMessage(hwnd, mymsg, 0, 0) != myvalue)
;// It's not your handler

Access Windows Controls from another class or window

In an MFC program I am trying to access controls that are in one window (class) from another (sibling or daughter) window with code in a different .cpp file. Typically you access a control with a DDX_Control variable defined in the class .cpp file.
DDX_Control(pDX, IDC_STATUS, m_Status);
The code for the other window is in a different file, so I don’t have access to the control variable (m_Status). What I have done is used FindWindow to find the main window, then GetDlgItem to find the control I am interested in:
CWnd * tmpWnd = CWnd::FindWindow(NULL,"MainWindow"); // find the main dialog box
CStatic * tmpStatus = (CStatic*) tmpWnd->GetDlgItem(IDC_Status);
tmpStatus->SetWindowText(“Status Report);
This works fine in the debugger, but fails when executed outside the debugger. FindWindow gets the window ID correctly, but GetDlgItem returns null.
Ideally I’d like to access the control variable (m_Status) from the other window, but I don’ know how to do so. I understand the GetDlgItem is less than ideal under any circumstance.
One solution would be to send a message to the main window class and tell it what to do, but I’d have to have a routine to handle each control and know how to handle whatever kind of data I am sending.
Is there a “right” way to do this?
Thank you
The ultimate answer is to cast to the original class:
((CspDlg *)AfxGetMainWnd())->m_Status.SetWindowText("Report");
Since you created the "main" window you have an object or pointer for it. Or, you can call AfxGetMainWnd() to get a pointer to it. Then you can use that to access a public member such as m_Status. All of your windows are interconnected and it should not be necessary to use FindWindow to find any window in your own program.
The fact that some variables may be defined in another file is not relevant. That can be handled with suitable use of #include "theotherfile.h" and object pointers/references.

DestroyIcon after SHGetFileInfo?

I'm using SHGetFileInfo to get the icon of specific file type. The MSDN says about the SHFILEINFO:
hIcon
Type: HICON
A handle to the icon that represents the file. You are responsible
for destroying this handle with DestroyIcon when you no longer
need it.
To get the icon from HIcon, I use Icon.FromHandle. Again, MSDN says:
Remarks
When using this method, you must dispose of the original icon
by using the DestroyIcon method in the Win32 API to ensure
that the resources are released.
It is even more confusing as SGHFI_ICON description contains the following information:
SHGFI_ICON (0x000000100)
Retrieve the handle to the icon that represents the file and the
index of the icon within the system image list. The handle is
copied to the hIcon member of the structure specified by psfi,
and the index is copied to the iIcon member.
From this description, it seems like the handle is kept by the OS and I shouldn't actually destroy it.
My question is then: if, and if so, when should I dispose of the icon handle?
Immediately after Icon.FromHandle() ?
When I no longer need the icon created from Icon.FromHandle() ? (in such case I guess that I'd rather copy the icon, release the original and return the copy to avoid handle leaks)
Never (it will be done automatically somehow? Many examples of SHGetFileInfo - even on SO - does not include any code releasing the icon handle)
The system doesn't keep icon handles, it keeps image lists. When you use the SHGFI_ICON flag, SHGetFileInfo creates an icon by calling ImageList_GetIcon against the system image list. You can do this yourself by passing the SHGFI_SYSICONINDEX flag instead to retrieve just the icon index.
The icon should be destroyed when you're done with it.
No, you really do have to call DestroyIcon yourself. The Icon.FromHandle() method is pretty useless to help you with that, it still requires you to call DestroyIcon. You've got to implement your own garbage collector code to know that the icon is no longer in use so it is safe to pinvoke DestroyIcon.
This is cruel and unusual punishment. The Icon class does in fact have a constructor that can create an Icon object from a handle and owns the handle, automatically calling DestroyIcon when the Icon object is disposed or finalized. They however made it inaccessible for unphantomable reasons, major bummer. Reflection to the rescue, you can bypass this silly restriction and still use the constructor, find the code in this answer.

Recreate Window Using GetConsoleScreenBufferInfo Method

I believe that the GetConsoleScreenBufferInfo method gets information about the window passed as a parameter into it into a CONSOLE_SCREEN_BUFFER_INFO structure. Can this information be used to recreate a window? Or is there a method which can create a window taking CONSOLE_SCREEN_BUFFER_INFO as a parameter?
There is no function that I know of that will create a new window given a CONSOLE_SCREEN_BUFFER_INFO structure. There certainly isn't such a thing described in the Console Functions reference.
I'd be interested to know why you want such a thing. Are you trying to create a duplicate console window? If so, you should note that a process can be associated with only one console. And you can't create a console window that's not attached to a process. The console goes away when the last process detaches from it.

Real hwnd from the point

When we use WindowFromPoint winapi function we usually can get the case, when Point specifies to some control within a window. And in such cases WindowFromPoint returns handle to that control, not to the window that handles that control.
For example in my small test application if I point to the "body" of chrome browser I get the control with class = Chrome_RenderWidgetHostHWND and its hwnd.
But what I need is to get the "parent" window for that control (which is obviously should be the chrome window).
Traverse the parents using GetAncestor() passing GA_PARENT. This differs from calling GetParent() which will return the owner if the window is a top-level window.
Can't you just use GetParent? Keep traversing until you find the desktop window.

Resources