Considering that your question is tagged c#, you have the entire .NET Framework at your disposal, which provides built-in functionality for displaying windows (forms) as modal dialogs. There's no reason you should have to call functions from the Windows API to do this.
In general, the only reason to P/Invoke functions from the Windows API is to use features that were not already exposed through managed code. The average application will have to do this only rarely, and basic use cases like showing a modal dialog certainly does not require it.
The way to do this in C# (or any .NET language) is to change the way you show the form in question. Instead of calling the Form.Show
method, you should use the Form.ShowDialog
method.
There are two overloads available. The first accepts no parameters and sets the owner of the dialog box to the currently active window. The second accepts a single parameter that specifies the window that will own this dialog.
The Form.Modal
property provides a quick way of checking to see whether or not the form is displayed modally. As the documentation notes, however, it is read-only. The only way to display a form modally is to call the ShowDialog
method, as discussed above.
As far as a Windows API solution, there isn't any such function that you can call. A window cannot be transformed into a modal dialog after it has been created. You have to display it that way initially. In a Win32 application, you do that by calling the DialogBox
function (as opposed to CreateDialog
).
MFC shows a modal dialog using the CDialog::DoModal
function, but it doesn't truly show a modal dialog. Instead, it uses a hack to create a pseudo (or simulated) modal dialog that involves disabling the owner window, running its own message loop inside the DoModal
method, and waiting for a pre-defined series of events that causes the modal loop to exit gracefully. I do not recommend doing this in your own application. It's simply not necessary, and it's too easy to get wrong. There are/were enough bugs in the MFC approach, and that team had the full knowledge of the Win32 internals at its disposal.
The ShowDialog
method in WinForms works on a model very similar to that of MFC. Hans's answer here provides additional information. Do note that if you're going to implement your own modal dialog loop, you need to remember to re-enable the
owner window first, and then destroy the modal dialog. If you don't do this in the correct order, you'll end up with the wrong window having the focus. Microsoft's Raymond Chen posted a blog entry about this: The correct order for disabling and enabling windows.
EDIT: Added more information, based on comments from asker.
I'm not sure why you need the wrapper you've created to customize the save dialog to be a UserControl
. It's not a control, the user isn't going to interact with it on your form. You're only going to show it from your code. Thus, I think the better option would be to create a new class, call it something like SaveDialogHelper
, and expose a static method called ShowSaveDialog
or something like that. For example:
public static class SaveDialogHelper
{
public string ShowSaveDialog(IWin32Window owner)
{
// Fill the OPENFILENAME struct, and do any necessary customizations
// ...
// Show the save dialog
// ...
// Return the path that was selected by the user
// ...
}
}
Notice that the ShowSaveDialog
function accepts a single parameter (owner
) of type IWin32Window
, just like the ShowDialog
method(s) in the .NET Framework. When you call that function, just specify the form that you want to own the dialog:
SaveDialogHelper.ShowSaveDialog(this);
And inside the function, you can extract the window handle (hwnd
in Win32 terminology) using the Handle
property, and set the hwndOwner
member of the OPENFILENAME
structure accordingly:
hwndOwner = owner.Handle;