Show Form with PInvoke
I have below scenario: WinForms app which allow only one instance of this app to be run (Mutex is in use here to check). App on start with some paramatere is runnig but hidden. When somebody will click on app again then Mutex will detect that app is already running and "unhide" the main form by call of native method (see method BringWindowToFront below).
Here is a code to find and show form window:
public static class NativeMethods
{
public enum ShowWindowOptions
{
FORCEMINIMIZE = 11,
HIDE = 0,
MAXIMIZE = 3,
MINIMIZE = 6,
RESTORE = 9,
SHOW = 5,
SHOWDEFAULT = 10,
SHOWMAXIMIZED = 3,
SHOWMINIMIZED = 2,
SHOWMINNOACTIVE = 7,
SHOWNA = 8,
SHOWNOACTIVATE = 4,
SHOWNORMAL = 1开发者_JS百科
}
[DllImport("user32.dll")]
public static extern int ShowWindow(int hwnd, int cmdShow);
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public static void BringWindowToFront(string windowTitle)
{
// Get a handle to the application.
IntPtr handle = FindWindow(null, windowTitle);
// Verify that app is a running process.
if (handle == IntPtr.Zero)
{
return;
}
// With this line you have changed window status from example, minimized to normal
ShowWindow((int)handle, (int)ShowWindowOptions.SHOWDEFAULT);
// Make app the foreground application
SetForegroundWindow(handle);
}
}
Everything is fine BUT I need one functionality yet. I would like to show another additional form when Main Form will unhide at 1st time. Normally I do it by form _Shown event. But when I use PInvoke methods to show window then this event is not fired up.
So basically I would like to show additional form when main form is shown (using ShowWindow PInvoke method)
Is this possible? Any other idea how to achieve it?
Writing single-instance apps is tricky. You don't have to, the .NET framework already supports them really well. Project + Add Reference, select Microsoft.VisualBasic. Open your project's Program.cs file and make it look like this:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.VisualBasic.ApplicationServices;
namespace WindowsFormsApplication1 {
class Program : WindowsFormsApplicationBase {
[STAThread]
static void Main(string[] args) {
var prg = new Program();
prg.EnableVisualStyles = true;
prg.IsSingleInstance = true;
prg.MainForm = new Form1();
prg.Run(args);
}
protected override void OnStartupNextInstance(StartupNextInstanceEventArgs e) {
var main = this.MainForm as Form1;
main.WindowState = FormWindowState.Normal;
main.BringToFront();
// You could do something interesting with the command line arguments:
//foreach (var arg in e.CommandLine) {
// main.OpenFile(arg);
//}
}
}
}
The Form.Shown
event is only fired the first time the form is shown (i.e. after loading), doing any other action later on (for example, hiding and then re-showing) will not trigger the event. For more information see: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.shown.aspx
There are a couple of other events that may be useful in your case:
- Form.Activated
- Control.Enter
- Control.GotFocus
- Control.VisibleChanged
If none of these work, and you must use P/Invoke then I would go with SetActiveWindow which will send a WM_ACTIVATE message, which should force a Form.Activated.
Note that if that doesn't work (since SetActiveWindow
sends a WM_ACTIVATE
with a low order bit of 1, indicating that the window wasn't activated by a mouse, then you could work around this by sending a message directly to the window with your own WM_ACTIVATE message.
精彩评论