Using Windows functions to make a window modal - c#

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?

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;

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

Related

Keep a reference to MessageBox?

I am trying to hide all the windows of my app when a users session time's out. That works great; however, when a MessageBox is left open when the app times out the message box still is there. I want to be able to close the message box or at least hide it. I've looked up hwnds and hinstances and I don't quite know if thats what I am looking for to accomplish this. I thought this would be fairly easy as I thought MessageBox inherited from Window and of course it doesn't. And a top of that you cannot create an instance of message box to keep track of it. At this point I am not sure what to actually do or what to actually search for.
I am in the process of trying to figure some stuff out using reflection. I can create an instance of MessageBox using reflection but don't think I can call Show() using an instance.
Short answer: just create your own window that looks like a message box
Long answer:
Message boxes are normal WinAPI windows (they have an HWND and can be manipulated by the native API windowing functions) however they are not WPF windows and don't have an associated Window object.
Since they are normal windows you can get their HWND (using FindWindow/ FindWindowEx/ EnumWindows) and trick them into closing (for example, by simulating a Cancel button click)
However, because message boxes are not designed to be manipulated like that this trick has some nasty pitfalls you have to take care of.
And, because message boxes are so simple and you can easily create a message box clone it's just easier to create the close and not take care of all the message boxes corner cases.

Create form not affected by ShowDialog()

I'm currently doing a security assessment of an extremely large C# application. I have wrote a tool to help me do the assessment that also runs in C#. The entire application uses ShowDialog aka modal forms. I'm trying to come up with a way where I can still use my tool (click on it for example) while modal dialog boxes are popped up. I figure, this may require another thread or something else. If anyone has any easy tips on a way to make it so that my form doesn't get blocked by ShowDialog, that would be great.
The entire purpose in using a modal dialog is for it to block it's parent until it is dismissed.

Intercepting click event for all controls in an app in C# (WinForms)

I want to make an application to intercept all UI events in all the forms of my application and to write them to a log. This data can than be used to see which controls are the most used, in what order, etc. The problem is that I want this to happen automatically, without modifying the existing classes.
I made a prototype that attaches a method to a click event for all controls in a form, but how can this be done for all forms? Reflection needs a target object when manipulating events, but only the startup form can be easily accessed.
Is there a way to hook the constructor of an object? Then I could "inject" my method in all the events of the new form. Or maybe there is another way to do this.
Thanks in advance!
You can install a message filter.
A message filter is an object that implements IMessageFilter. WinForms calls your PreFilterMessage method for every message that passes through your thread's message loop. This is enough to monitor user input across the application (and gives you the option of manipulating it).
In Windows API this is done using local hooks (you can set local mouse hook using SetWindowsHookEx function). This is the proper way to do your task. In C# you need to use P/Invoke in order to get access to SetWindowsHookEx.
One more task would be to match the HWND (windows handle) to corresponding WinForms control.
Read this article for how to do this (via WM_GETCONTROLNAME message).
Also see this question which is a duplicate of yours.
You will have to work with the Win32's API Messages, I guess.
Here's a little example under the form of tutorial.
You should be able to achieve what you want with message filters - no direct P/Invoke to Win32-APIs required!
See the help on the IMessageFilter interface for more info.

Get component type of custom .NET class from window handle

I need to see the component type, meaning the name of the class that was programmed, of a clicked control in another process. I need the type so I can react to the clicked control and then do some Automation tasks.
Right now I am doing the following:
1. I FindWindow() from Win32 to find the main window handle of the process.
2. Then, I get call EnumChildWindows(), also from Win32, and get the window handles of all the children of the main window handle.
3. Now it gets tricky. When I call GetClassName(), it returns WindowsForms10.STATIC.app [...] since the controls I am trying to read are custom.
How can I get the type of the clicked control using the window handles from EnumChildWindows() ? Is what I am trying to do even possible?
I have been looking into using SendMessage() from Win32 to the process but it seems that there is no system defined message that could help.
I'm afraid that it's not possible. A handle just refers to internal data of the window that Windows needs. There is no information beyond that available.
You can get the class name, but it is neither standardized nor unique. Most controls that are not basic-functionality controls like buttons, lists, etc. are derived from a very primitive one, namely "Static". But again, there's no information about the high-level WinForms control available.
This leads to the fact that, even if you knew the type, you cannot just cast the pointer/handle, because there no data behind it.
Can you somehow restate your problem? Maybe use Remote Procedure Calls? Does it work without the high-level WinForms objects? Things like clicking, moving or renaming work with plain Win32 API.

Get newly created window using Win32 API hooks

This may be a long short or not even possible but no harm in asking.
What I am trying to do is monitor an application for any new windows it creates in its MDI control. I have implemented hooking in C# and can capture the MDICREATE window message but because I need to get information about the window after is has been created the MDICREATE message isn't much help because at that stage the window hasn't been created in the other application yet.
Without going into to much detail I just need to be able to see when a new window has been created.
Is this possible?
Thanks
I'm not aware of another message that gets the info that you are looking for off hand. But if that message works for you, you could hook that message and then do another scan of the windows to find the one you are missing. You can enumerate the child windows of the parent window. Use Spy++ to see the exact window hierarchy.
If you can watch for a particular function call, I would use some kind of hooking library to grab that (EasyHook comes to mind).
You can hook the MDI create function (assuming there is one), watch for that, then inn your code, call the original and do any lookups using the returned value. You'll have access to the returned value and any parameters, so you should be able to get some info out of those.
Two options off the top of my head.
Hook the WM_MDIACTIVATE event, the first time the window is being activated, use a flag to determine the first time the window is being activated.
If you need to run your code after the WM_MDICREATE or WM_MDIACTIVATE, you can post a new custom message from one of these messages, which is then handled after these messages have completed. You then write your code to handle the custom message.

Categories