1

I m using c# and I want to make a window a modal one and I want to use methods from Windows API for that. The SetWindowPos function can make a window a top most one, but I couldn t find a way to make it modal...

Is there a way to do so with SetWindowPos or if not, is there any other windows function to do so?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Dulini Atapattu
  • 2,735
  • 8
  • 33
  • 47

2 Answers2

3

Considering that your question is tagged , 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;
Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Actually as I have customized my savefiledialog, I have implemented the ShowDialog method on my own, and inside that, I m calling GetSaveFileName to createt the savefiledialog. So I want to add that modal feature in my ShowDialog method.. any answer??? – Dulini Atapattu Apr 07 '11 at 08:21
  • @dia: I don't understand why you have re-implemented the `ShowDialog` method on your own. Do you mean that you've created a separate form you call *instead* of `SaveFileDialog`, and that *that* form is instead responsible for calling/displaying the save dialog? The Windows API function `GetSaveFileName` takes an `OPENFILENAME` structure as a parameter, one of the members of which is `hwndOwner`. If you specify the correct window handle here, it will automatically display the dialog modally with that window as its owner. – Cody Gray - on strike Apr 07 '11 at 08:45
  • @dia: Use that to specify the handle to your *main* window, not the one that wraps the call to `GetSaveFileName`. I suspect you're *currently* passing that window's handle, so the function is doing the right thing and disabling that window. Except that, you don't care if that window is disabled. – Cody Gray - on strike Apr 07 '11 at 08:46
  • Yeah, you are correct!!! Thanks a lot for that! I had to customize the savefile dialog in order to add some checkboxes for it... So this I m implementing a new user control. But can you pls explain me a way of identifying that form??? One way I thought is to send the handle of the mainform when the object to the user control is created... – Dulini Atapattu Apr 07 '11 at 09:02
  • Thank you so much for your answer!!! It works well!!! I also followed this too: http://stackoverflow.com/questions/1163435/c-method-caller . Both methods work well... Thank you very much again... – Dulini Atapattu Apr 07 '11 at 09:25
  • @dia: You certainly could do that, but remember that there is a (potentially) significant cost associated with using Reflection. Since the caller should always know which form they want to disable, it's faster and simpler to specify it as a parameter. It also makes it clearer what the function does, which window will be disabled, and prevents any potential problems where the wrong window is disabled if you call the function from a background thread or a different form (like when you implement auto-save functionality in your app!). Anyway, you're welcome. Glad you were able to get this to work. – Cody Gray - on strike Apr 07 '11 at 09:31
  • Yeah, that s true, so I feel it s better to use the parameter... Thank you loads for great advices – Dulini Atapattu Apr 07 '11 at 09:37
1

You can't make it modal if it was not upon creation. But you can achieve similar effect by disabling its parent owner.

Serge Wautier
  • 21,494
  • 13
  • 69
  • 110
  • More accurately, you would be disabling its *owner*. The difference between parent windows and owner windows is not always very clear in the documentation, although it's an important one. Raymond Chen provides more information [here](http://blogs.msdn.com/b/oldnewthing/archive/2010/03/15/9978691.aspx). – Cody Gray - on strike Apr 07 '11 at 07:32
  • Oops. I stand corrected. Owner is what I actually meant: A modal window obviously doesn't have a parent. – Serge Wautier Apr 07 '11 at 13:04