I have an application that on a subsequent start detects if there's a process with the same name already running and, if so, activates the running app's window and then exits.
The problem is that the main window could be hidden (only a notification area icon visible), thus leaving me with no window handle.
At startup, previous instance's MainWindowHandle
property is 0, so I can't send ShowWindow
or PostMessage
.
Is there any way I can send a message that can be intercepted by the running app, thus allowing it to display its main window?
The application is written in C#, the code I'm using to achieve this below.
[STAThread]
static void Main()
{
bool createdNew = true;
using (Mutex mutex = new Mutex(true, "MyMutexName", out createdNew))
{
if (createdNew)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
else
{
Process current = Process.GetCurrentProcess();
foreach (Process process in Process.GetProcessesByName(current.ProcessName))
{
if (process.Id != current.Id)
{
Interop.WINDOWINFO pwi = new Interop.WINDOWINFO();
IntPtr handle = process.MainWindowHandle;
var isVisible = Interop.GetWindowInfo(handle, ref pwi);
if (!isVisible)
{
MessageBox.Show(Constants.APP_NAME + " is already running, check the notification area (near the clock).",
Constants.APP_NAME, MessageBoxButtons.OK, MessageBoxIcon.Information);//temporary message, until I find the solution
//Interop.ShowWindow(handle, Interop.WindowShowStyle.ShowNormal);
//Interop.PostMessage(handle, Interop.WM_CUSTOM_ACTIVATEAPP, IntPtr.Zero, IntPtr.Zero);
}
else
Interop.SetForegroundWindow(handle);//this works when the window is visible
break;
}
}
}
}
}
}
Here's how I've done this:
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
public partial class MainForm : Form
{
#region Dll Imports
private const int HWND_BROADCAST = 0xFFFF;
private static readonly int WM_MY_MSG = RegisterWindowMessage( "WM_MY_MSG" );
[DllImport( "user32" )]
private static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport( "user32" )]
private static extern int RegisterWindowMessage(string message);
#endregion Dll Imports
static Mutex _single = new Mutex(true, "{4EABFF23-A35E-F0AB-3189-C81203BCAFF1}");
[STAThread]
static void Main()
{
// See if an instance is already running...
if (_single.WaitOne(TimeSpan.Zero, true)) {
// No...start up normally.
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try {
Application.Run(new MainForm());
} catch (Exception ex) {
// handle exception accordingly
} finally {
_single.ReleaseMutex();
}
} else {
// Yes...Bring existing instance to top and activate it.
PostMessage(
(IntPtr) HWND_BROADCAST,
WM_MY_MSG,
new IntPtr(0xCDCD),
new IntPtr(0xEFEF));
}
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MY_MSG) {
if ((m.WParam.ToInt32() == 0xCDCD) && (m.LParam.ToInt32() == 0xEFEF)) {
if (WindowState == FormWindowState.Minimized) {
WindowState = FormWindowState.Normal;
}
// Bring window to front.
bool temp = TopMost;
TopMost = true;
TopMost = temp;
// Set focus to the window.
Activate();
}
} else {
base.WndProc(ref m);
}
}
}
I hope I've transcribed this correctly. I had to leave out a lot of other stuff, but I think I got what is necessary. What I have works for me without fail. If you have a problem, let me know, and I'll see what I've missed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With