How can I open an *modal* file dialog with IFileOpenDialog? - c++

I've been trying to implement a file dialog into my C++ application for a while now, and I achieved good success with the code described in this article (It is german, but the code should be understandable):
https://msdn.microsoft.com/de-de/library/windows/desktop/ff485843(v=vs.85).aspx
However, using this code in my window class, which is a CDialogImpl, I just can't find out how to make this file picker modal. If I use this code, I can just spawn multiple file picker.
Of course, I could just keep track of the state by adding a member variable representing the state, but it would still not solve the problem of being able to click around in the main window while the dialog is opened.
Is there any way which would allow me to make this window modal? I've been trying to scan through all available methods, but I couldn't find anything. I didn't find any flags which could be passed in the creation, neither any options which I could set after creation.
Any help is appreciated!

The example you link to is very simple and has no UI other than the file dialog. Your program is more complex, having a window from which the file dialog is invoked.
You need to provide an owner for the file dialog. When you do that the owner is disabled, part of what makes the dialog modal. Failing to pass an owner means that the other windows are not disabled and so still respond to user input.
The example code provides no owner, but since there are no other windows in that program, that is benign. Modality is only meaningful when there are multiple windows.
So, to solve the problem, pass the owner, the handle of your window, to the Show method of the file dialog.
Disabling owner windows is one of the key parts of a modal dialog. You will find that any API for modal dialogs expects you to specify an owner. Get into the habit of expecting to provide that ownwr window, and looking for the means to do so.

Related

Display and use the same MFC CList control in multiple dialogs

I am coding a test application for a windows CE device. This is the first time I am programming for a handheld device. I use MFC VC++ on Visual Studio 2008. I have found that there are many restrictions in the controls and what I could do with them when running the program on a handy versus when I run a similar program on a desktop computer.
Now, the device I am currently deploying my test program to, does not have a touchscreen and has few extra keys other that the numberpad 0-9 keys. So, I have to do with a simple GUI that uses keydowns to call specific functions like add, edit, delete etc... It also forces me to use separate dialogs for each of these functions so as to avoid unnecessary mouse cursor usage.
This leads me to my current problem: The 'ADD' dialog of my test app adds some user data to a CListCtrl that is on the 'MAIN' dialog. The 'EDIT/DELETE' dialog is to allow the user to select the desired data from its own CListCtrl and press the "ENTER" key, which thereby deletes the selected data from the 'MAIN' dialog's CListCtrl. Thus, both the main dialog and the 'EDIT/DELETE' dialog have CListCtrl with the exact same data. So, instead of having to use 2 separate list controls and using loops to copy the data to and fro among them, is there a way in which i could use the exact same CListCtrl (one and only one instance of the CListCtrl exists), but display it on 2 separate dialogs? This would remove all the copying code, as well as halve the amount of data in memory.
I tried passing a pointer to the MAIN dialog's CListCtrl to the 'EDIT/DELETE' dialog in hopes that I could redraw the control there, but in vain. I could call the RedrawWindow, RedrawItems commands, but they seem to have no effect in the 'EDIT/DELETE' dialog (I think it is because the control itself is not present on the edit/delete dialog). Any other suggestions?
You could temporarily change the parent of the ListCtrl using CWnd::SetParent to the EDIT/DELETE dialog, and set the position with CWnd::SetWindowPos to where you want to have it. When the dialog gets closed, set the parent back to the MAIN dialog.

Win32 multiple dialogs command handler [duplicate]

In ResourceHacker, when you open an executable (windows), you can see identifiers associated with dialogs. Does anyone have an idea from where they come? I mean, how can I do the same in my C++ program to get the ID from a HWND?
BTW, GetWindowLong(hwnd, GWL_ID) returns 0.
Thanks
The GetWindowLong(hwnd, GWL_ID) returns the identifier of a control in a dialog, but it cannot be used for the dialog itself, because dialogs simply don't have identifiers.
The identifiers associated with dialogs are actually used to refer to the resource blob itself, not to the window. They are used to create the dialog (see CreateDialog().
Once the dialog is created there is no connection to the original template or to that identifier. Actually there is no use for that ID, the dialog is simply identified by its HWND. Note that you can create several different dialog using the same dialog resource.
These identifiers are assigned (usually) sequentially by the resource editor, or manually if you create the resources by hand.
For more insight on the topic you can read about the CreateDialogIndirect() function, that creates a dialog without using a resouce.
Here you find a good answer:
http://blogs.msdn.com/b/oldnewthing/archive/2005/07/08/436815.aspx
It's like asking, "Given a plate of food, how do I recover the
original cookbook and page number for the recipe?" By doing a chemical
analysis of the food, you might be able to recover "a" recipe, but
there is nothing in the food itself that says, "I came from The Joy of
Cooking, page 253."
So the answer is that there is no way provided by Microsoft to obtain the dialog ID. They could have easily stored it anywhere to make it available, but they did not.
But there would still be a way to do it, although it is not bulletproof. You could:
1.) Get the creator file of the dialog via GetWindowModuleFileName()
2.) Load this Exe or Dll via LoadLibraryEx(..., LOAD_LIBRARY_AS_IMAGE_RESOURCE)
3.) Enumerate all RT_DIALOG resources in the Exe or Dll via EnumResourceNames() where the dialog ID is in the name: ResourceName = MAKEINTRESOURCE(IDD_DIALOG_ID)
4.) Create each enumerated dialog invisibly via LoadResource(), LockResource(), CreateDialogIndirect() but without showing the dialog with ShowWindow().
5.) Enumerate the child controls in each dialog via EnumChildWindows() and compare them to your dialog.
6.) Release all handles and destroy the dialogs.
It is not very probable that there are two identical dialogs in a Exe/Dll file. But the problem is that in WM_INITDIALOG the programmer may eliminate (destroy) or add or modify child controls. So your search algorithm would have to be fault tolerant. This would be possible by counting the congruency between each dialog from the resources and your dialog. You could count for how many child controls the ID (GetDlgCtrlID())and class name (GetClassName()) match. (e.g. Class="BUTTON" and ID = 311") While a programmer can easily change the text of a control or move it around, changing the ID is not very probable and does not make much sense and changing the class of a child control is even impossible.
As I said: It is not bullet proof, but you will find the ID of the resource that has most probably been used to create the dialog.
Be aware that not all dialogs come from a Microsoft resource.
They can be created by a GUI framework that uses its own type of templates. In this case you will never find the Dialog ID because it simply does not exist.

Get the (resource) ID from hWnd

In ResourceHacker, when you open an executable (windows), you can see identifiers associated with dialogs. Does anyone have an idea from where they come? I mean, how can I do the same in my C++ program to get the ID from a HWND?
BTW, GetWindowLong(hwnd, GWL_ID) returns 0.
Thanks
The GetWindowLong(hwnd, GWL_ID) returns the identifier of a control in a dialog, but it cannot be used for the dialog itself, because dialogs simply don't have identifiers.
The identifiers associated with dialogs are actually used to refer to the resource blob itself, not to the window. They are used to create the dialog (see CreateDialog().
Once the dialog is created there is no connection to the original template or to that identifier. Actually there is no use for that ID, the dialog is simply identified by its HWND. Note that you can create several different dialog using the same dialog resource.
These identifiers are assigned (usually) sequentially by the resource editor, or manually if you create the resources by hand.
For more insight on the topic you can read about the CreateDialogIndirect() function, that creates a dialog without using a resouce.
Here you find a good answer:
http://blogs.msdn.com/b/oldnewthing/archive/2005/07/08/436815.aspx
It's like asking, "Given a plate of food, how do I recover the
original cookbook and page number for the recipe?" By doing a chemical
analysis of the food, you might be able to recover "a" recipe, but
there is nothing in the food itself that says, "I came from The Joy of
Cooking, page 253."
So the answer is that there is no way provided by Microsoft to obtain the dialog ID. They could have easily stored it anywhere to make it available, but they did not.
But there would still be a way to do it, although it is not bulletproof. You could:
1.) Get the creator file of the dialog via GetWindowModuleFileName()
2.) Load this Exe or Dll via LoadLibraryEx(..., LOAD_LIBRARY_AS_IMAGE_RESOURCE)
3.) Enumerate all RT_DIALOG resources in the Exe or Dll via EnumResourceNames() where the dialog ID is in the name: ResourceName = MAKEINTRESOURCE(IDD_DIALOG_ID)
4.) Create each enumerated dialog invisibly via LoadResource(), LockResource(), CreateDialogIndirect() but without showing the dialog with ShowWindow().
5.) Enumerate the child controls in each dialog via EnumChildWindows() and compare them to your dialog.
6.) Release all handles and destroy the dialogs.
It is not very probable that there are two identical dialogs in a Exe/Dll file. But the problem is that in WM_INITDIALOG the programmer may eliminate (destroy) or add or modify child controls. So your search algorithm would have to be fault tolerant. This would be possible by counting the congruency between each dialog from the resources and your dialog. You could count for how many child controls the ID (GetDlgCtrlID())and class name (GetClassName()) match. (e.g. Class="BUTTON" and ID = 311") While a programmer can easily change the text of a control or move it around, changing the ID is not very probable and does not make much sense and changing the class of a child control is even impossible.
As I said: It is not bullet proof, but you will find the ID of the resource that has most probably been used to create the dialog.
Be aware that not all dialogs come from a Microsoft resource.
They can be created by a GUI framework that uses its own type of templates. In this case you will never find the Dialog ID because it simply does not exist.

IFileOperation and the progress dialog

so, I am working on this shell namespace extension that handles a kind of ZIP file (let's call it ZOP) like a folder.
Everything is in place, and file operations are processed through IFileOperation and IStream.
The thing is, when copying a file into my virtual ZOP folder, calling IStream::Commit is not trivial, and can take significant time, so I'd like to provide additional feedback to the user (and allow her to cancel the operation).
I already have a progress callback mechanism that kicks in when the stream is committed. What I've done for now is a custom dialog, including a progress bar, that pops up whenever IStream::Commit is called.
However, I can't seem to find the hWnd of the standard progress dialog so that mine can be modal (which means that my dialog can be hidden by the progress dialog itself, which defeats the purpose of my dialog).
I could go the IFileOperation::SetProgressDialog way, creating a bridge to IOperationsProgressDialog, but I'd still have to do some dirty code to find the progress bar from a stream I've not created - all I can think of to pass data around is the TLS, and boy do I hate this solution, akin to using a global variable.
Thoughts about retrieving the window handle or subclassing the standard dialog ?
Note: I've observed that sometimes, for relatively short operations, the standard dialog appears after the stream is flushed. Which is uncool too, as my custom dialog appears and goes away even before the operations seems to start.
Update: I've found the progress window using EnumWindows/FindWindowEx as the window has the Dialog class with a DirectUIHWND child. The funny thing is, when instantiating my dialog using DialogBoxParam() (in a distinct thread from IStream::Commit()), the call hangs even before my dialog is displayed, as it is getting stuck in NtUserCallHwndParamLock.
Sounds like a job for spy++, get the class name of the window who's hwnd your looking for and call FindWinow or FindWindowEx.

DLL plugin that creates a parented window doesn't handle messages correctly

I'm creating a plugin framework, where my application loads a series of plugin DLL's, then creates a new window and pass this new window's handle to the plugin. The plugin can, then, use this handle to create their own GUI.
Everything seems to be working very well. The only problem is that when I press TAB on a plugin widget (An editbox, for example), it doen't jump to another widget. I figured out that some Windows messages are passed, and some others aren't. The WM_KEYDOWN is passed for other keys, because I can type on the editbox, but this message doesn't handle TAB key.
Hope somebody has a hint.
I'm using Borland VCL with CBuilder, but I think I could use any framework under WIN32 to create these plugins, since they never know how their parent windows were created.
It's very complex matter indeed.
When you hit TAB focus jumps to another control only when these controls belong to a Modal Dialog Box. In fact there are some buttons like ESC, LEFT, RIGHT, DOWN, UP, TAB which modal dialog message function treats in a special way. If you want these keys to behave in similar way with modeless dialog box or any other window you should change you message processing function and use IsDialogMessage inside. You'll find more information about IsDialogMessage function in MSDN also to better understand this stuff you may check as well Dialog Boxes section.
And, as was mentioned before, you should set WS_TABSTOP and WS_GROUP styles when needed.
Good luck!
I believe you'll have to take the following steps:
Subclass your edit controls (and other controls as needed).
Capture the WM_KEYDOWN message in your edit control's WndProc.
Check to see if the shift key is currently held down (using GetKeyState or similar).
Call GetWindow, passing in a handle to your edit control and either GW_HWNDPREV or GW_HWNDNEXT depending on whether shift is held down. This will give you the handle to the window that should receive focus.
Call SetFocus and pass in the window handle you got in step 4.
Make sure you handle the case where your edit controls are multiline, as you might want to have a real tab character appear instead of moving to the next control.
Hope that helps!
I believe you suffer from having a different instance of the VCL in each of your dlls and exes. Classes from the dll are not the same as the ones from your exe, even if they are called the same. Also global variables (Application, Screen) are not shared between them. Neither is the memory since they both have their own memory manager.
The solution is to have the dlls and the exe share the VCL library and the memory manager. I am not a BCB developer, but a Delphi developer. In Delphi we would just use the rtl and the vcl as runtime packages. Maybe you could do the BCB equivalent.
A DLL has its own TApplication object.
to provide uniform key handling. when the DLL Loads.
assign the DLL::TApplication to the EXE::TApplication
Be sure to do the reverse on exit.
--
Michael