MFC application and a non-MFC modal dialog - winapi

I'm writing a Win32 plug-in DLL for a third-party MFC app. The DLL needs to display a modal dialog. When I do this using DialogBox() or other plain Win32 API (e.g. I tried to write my own modal loop), the main application's window doesn't redraw all elements: it redraws standard elements, but not the client area. Modeless dialogs display just fine.
I suspect this happens because MFC doesn't really have modal dialogs in Win32 sense. It can only have one message loop and a separate loop in DialogBox() disrupts its delicate machinery. Here's a CodeProject article that explains this. But this CodeProject article is 9 years old, so maybe things have changed since then. Could somebody shed some light on this? The app uses MFC 8 (i.e. mfc80.dll).
Update. Here's a link to the original question; it may contain some additional information.
Update 2. Thanks everyone; I really appreciate all the advice, it certainly helps me to get the big picture of how things fit together. The first path I'm going to explore is to use native MFC 'modal' dialogs. (Since I do all this from Python, I'll use Python bindings for MFC, pywin32). This will take some time; when it's ready, I'll update the post with results.

Every thread can have a message loop. Put your modal dialog into a separate thread and emulate the standard behavior of Windows by disabling the parent window.
Edit: after some discussion (see below) it appears that the parent code behaves incorrectly.
Still, I think there are possible workarounds. One could be a parent window (to the modal dialog, but child to the one that currently behaves incorrectly) that overlays the erroneous window content, but redraws it from a DC in memory to mimic correct behavior. Of course the parent window still would have to be disabled. Another solution may be to subclass the parent window, to correct the behavior. Since the plugin would run within the same process, the implementation should be straightforward.

Related

Is it possible to call a function in a different, but currently executing process?

I have a friend who's working at a company that offers pretty poor support for its developers (scoring a 1/12 on the Joel Test).
Their build process is locked down pretty tight, and depending on the size of project it could take 40+(x2) mouse clicks to deploy. So I thought, "Hey, why not automate it the clicks using the win32api?" (Specifically using Python). I've got him a real nice tool that works just fine except for one issue - the tool that they use has a navigation pane that may or may not be open.
You can open and close it with a button press, but I'm not sure how I could make sure it was either open or closed. It's irrelevant to the build process - the only problem is that it alters where the mouse needs to click on the screen depending on its open status. The application is written in .NET and it exposes a function call that applications are able to use to toggle the panel, so I've been looking around for ideas and so far I've got two of them:
Attach to the process via a debugger and execute the function call somehow.
Take a screenshot at the location of the panels titlebar (which I've got through the win32 API and doesn't appear to change regardless if the panel is hidden or not).
Is there an easier way to figure out the state of this panel? The developers are given an admin account on their machine in addition to their regular account, so I can entertain ideas that require admin access, though I don't think that should be necessary?
UPDATE:
It looks like there's a button that can close the pane. In UIAVerify something shows up as "text" "Navigation" "btnClose". It says its AutomationId is btnClose but it's a ControlType.Text
What technology is this panel built from? Is it standard GDI or WPF? If its GDI, it should have a HWND. You should be able to find this HWND through either a class name or window title. Once you have the HWND, you can get its width.
If its built with WPF, er, I have no idea, but Snoop does this kind of thing, so I know its possible.

Show a popup menu in another application's window

How can a Delphi XE application show a popup menu inside another application's window? The idea is for a helper-type app, running in the background. On a registered hotkey the application needs to display a popup menu near the text caret or mouse cursor.
Applications that do that are common, here's a menu created by AutoHotkey and displayed in a text editor:
I guess what I'm asking is: how can I display a popup menu at an arbitrary screen location, without it being attached to a Delphi control?
Create a TPopupMenu with the appropriate menu items. When you need to show it simply call Popup passing the top left position in screen coordinates.
PopupMenu1.Popup(X, Y);
#DavidHeffernan answered your question, but you might not have asked the right question.
Let's take the example you gave: the user is running some arbirary application, and you want to be able to detect a hotkey, display a menu, and then take some action based on the menu item chosen (and maybe even the user's context, such as the word under the cursor). This is more complicated than simply displaying a menu at arbitrary screen coordinates.
My recommendation is to use AutoHotKey instead of trying to replicate this in some other programming language. In case you're not aware of this, it is possible for your code to run AutoHotKey scripts. IIRC, you can compile AHK scripts, so you wouldn't need to install AHK, just the compiled scripts. AHK may not be the most elegant of solutions, but it has depth and maturity.
If this is not possible, then I suggest you research Windows Hooks and DLL Injection. Unless you can find some preexisting code or framework, this will entail quite a bit of work.
The reason for this complexity? To augment another program smoothly (without running into problems with focus, etc.) you want to have your code run as part of that other program. The mechanics of this can be done via DLL injection. However, that's only the first step. Once your code is running in the right context, then your code has to inter-operate with the "host" program. This can be tricky (it helps if you have deep experience with Windows messaging and the Windows API). If you want this to work smoothly with any arbitrary program, it gets even harder.

How come some controls don't have a windows handle?

I want to get the window handle of some controls to do some stuff with it (requiring a handle). The controls are in a different application.
Strangely enough; I found out that many controls don't have a windows handle, like the buttons in the toolbar (?) in Windows Explorer. Just try to get a handle to the Folder/Search/(etc) buttons. It just gives me 0.
So.. first question: how come that some controls have no windows handle? Aren't all controls windows, in their hearts? (Just talking about standard controls, like I would expect them in Windows Explorer, nothing customdrawn on a pane or the like.)
Which brings me to my second question: how to work with them (like using EnableWindow) if you cannot get their handle?
Many thanks for any inputs!
EDIT (ADDITIONAL INFORMATION):
Windows Explorer is just an example. I have the problem frequently - and in a different application (the one I am really interested in, a proprietary one). I have "physical" controls (since I can get an AutomationElement of those controls), but they have no windows handle. Also, I am trying to send a message (SendMessage) to get the button state, trying to find out whether it is pushed or not (it is a standard button that seems to exhibit that behaviour only through that message - at least as far as I have seen. Also, the pushed state can last a lot longer on that button than you would expect on a standard button, though the Windows Explorer buttons show a similar behaviour, acting like button-style checkboxes, though they are (push)buttons). SendMessage requires a window handle.
Does a ToolBar in some way change the behaviour of its child elements? Taking away their window handle or something similar? (Using parent handle/control id for identification??) But then how to use functions on those controls that require a windows handle?
If they don't have a handle, they're not real controls, they're just drawn to look like controls.
But of course, the toolbar buttons in Windows Explorer do have window handles, they're part of a toolbar. Use the toolbar manipulation functions to interact with them, not EnableWindow.
Or, better yet, use the documented APIs for things like search. Reverse-engineering Windows Explorer has never ended well for anyone, least of all the poor Windows Shell team, saddled with years of backwards-compatibility hacks for certain developers who thought that APIs are for everyone else. Whatever you do manage to get to work is very likely to break on the next version of Windows.
The controls you are talking about are using the ToolbarWindow32 class. If you want to interact with them then you'll need to use the toolbar control APIs/message. For example for enabling buttons you'd want to use TB_ENABLEBUTTON.
You can implement the controls yourself using GDI, OpenGL or DirectX. Try Window Detective on Mozilla Firefox and you will see that there is only one window. Controls in dialog boxes are not windows known to Windows.

Win32: CreateDialog instead of multiple calls to CreateWindow - any downsides?

I'm currently working on a Win32 program which requires a main window containing many child window controls - buttons, listviews and so on. I believe the standard way to build such a window is to first call CreateWindow for the main window, then again for each of the controls.
As an easier option, I'm considering designing the main window using the resource editor's dialog box designer, then using CreateDialog to build the main window in one go.
By using a CLASS statement in the dialog box template, I should be able to get the main window to use a custom window class (and hence a custom window procedure) and thus avoid the window having any dialog-like behaviour. An example of this technique can be found in Charles Petzold's "Programming Windows": the HEXCALC program in chapter 11.
Are there any downsides to creating my main window in this way? If so, what are they? If not, why is this approach rarely used?
You don't get control of your main window message loop - the dialog manager handles it for you. On the other hand, the dialog manager handles keyboard accelerators, tab ordering and a number of other effects.
You'd be surprised what you can do with a standard dialog box - the windows volume control is implemented with about four different dialog boxes - it has a frame dialog box which in turn host hosts a tray window which in turn holds volume control dialog boxes, one for each app volume.
The only downside of CreateDialog I know of (as compared to repeated CreateWindow, not talking about some heavyweight framework, just Win32 vs Win32) is that dialog resources position child windows using dialog units. So the layout is dependent not only on DPI, but also on the user's theme settings (choice and size of font).
If any of your controls need to have fixed sizes in terms of pixels, you won't be happy with the dialog-provided positioning and will need to go through and move all the child windows after the fact.
So yes, you can use CreateDialog as a shortcut for creating a bunch of windows with specified classes and styles. But no, you can't do your layout in the dialog editor.
OTOH, you could store the DLU <-> pixel conversion used on your design machine, and then learn enough about parsing the DIALOG resource internal format to pull out the positioning information, then convert to pixels and correct the positioning in more automated fashion.
You will be able to have the full control over your window, even if it was created with CreateDialog.
Normally, when you create your own window (of your class), the window procedure used is the one that you registered with the class. OTOH windows created via CreateDialog will have the dialog standard window procedure (DefDlgProc), which will mostly invoke your supplied "dialog handler".
If you want to have full control of all the messages you may replace the window proc of the newly created window right after its creation. Just call SetWindowLongPtr with GWLP_WNDPROC parameter. Still, you may do the auto processing of some dialog-specific things by calling IsDialogMessage within your procedure.
There is no downside whatsoever.
Why is it rarely used? Because:
People normally use DialogBox instead, since that is easier for simpler cases.
For more complex cases, people use things like MFC or ATL (or some external library like GTk or Qt), and don't bother with native Win32 graphics.
There are no downsides using the Windows SDK, internally libraries like MFC use the Windows SDK .
People tend to use libraries like MFC over Windows SDK, as libaries have the readymade stuff. However Windows SDK calls are faster than library calls, so in some situations developers call Windows SDK directly .
CButton btnOk ;
btnOK.Create(_T("Press Me"), WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(100,100,300,300), pParentWnd, 1);
is similar to the following code ,
HWND hWnd = CreateWindow("BUTTON","Press Me",WS_CHILD|WS_POPUP|BS_DEFPUSHBUTTON,100,100,300,300,NULL,NULL,GetModuleHandle(NULL),NULL);
ShowWindow(hWnd,SW_SHOW);

Why might IsDialogMessage() never return?

I am debugging an application which, in its message loop, calls IsDialogMessage(). Occasionally, IsDialogMessage() never returns (where never is an interval greater than 1 hour). Based on the symbols for user32.dll available from Microsoft's symbol server, it appears to be stuck in GetNextDlgGroupItem() (or an internal variant of the same), iterating over some set of windows.
The application is multithreaded and frequently receives notification of external events, which arrive as DCOM calls. I suspect that such a call is handled incorrectly in a way that corrupts some window state. If I can learn what sort of state corruption might cause an infinite loop in IsDialogMessage(), I think I will be more easily able to identify the source of the corruption.
I know this is old, but answering for posterity since no one here mentioned it.
More than likely what is going on is trouble with the windows manager determining where to forward a message. If you have a hierarchy of windows, as you probably do, then you need to ensure that non-top-level windows that contain controls themselves must have the WS_EX_CONTROLPARENT style set. If it is a dialog, you use the DS_CONTROL style. The presence of these flags modify the behavior of IsDialogMessage; they identify a window as having its own controls which can receive focus and handle tab order, etc, rather than just being a control itself.
For example, if you have a main frame window, which has a child window with WS_EX_CONTROLPARENT, which has a child window without WS_EX_CONTROLPARENT, which has a child window that has focus, and you hit TAB, you will likely encounter an infinite loop at the same place you mention.
Setting the second child's extended style to include WS_EX_CONTROLPARENT will resolve the issue.
Are you maybe disabling controls (using ::EnableWindow()) without checking first whether that control has the focus? If yes, then the focus gets lost and GetNextDlgGroupItem() gets confused.
Another reason this can happen is if you reparent a modeless dialog. At least this can happen with wxWidgets...
I've made some investigation, trying to answer this question. But only in situation, when parent window is in native MFC project and child is a managed C# Windows Forms. If you have such situation, then you may try 3 resolutions:
Run MFC dialog message loop on Windows Forms side. Here is more info: Integrate Windows Forms Into Your MFC Applications Through C++ Interop
Create 2 threads: one for Windows Forms dialog and one for native dialog. Here you can create dialog in Windows Forms, then with SetParent() set it's parent to native dialog. But be ware: if you add TabControl to Windows Forms, than hang with "IsDialogMessage() never return" will occur.
Make a wrapper for Windows Forms dialog to use in native project. For ex., wrapper may be WPF, see here: Windows Form as child window of an unmanaged app
I've taken information mostly from: http://msdn.microsoft.com/en-us/library/ms229600.aspx
And the temporary cure can be to change focus behavior. For example, disable them, or SetFocus() to parent or child windows only. But I strongly recommend to investigate the real reason, why IsDialogMessage() never return in your case.

Resources