Mario M.

Hi,

I have an WPF application that starts as "hidden" window and only shows an icon in the system tray. Double clicking the icon makes the window visible.

Now I need something that ensures, that there is only one active instance of my application. If someone tries to start a second instance the already existing one should change its window state from "hidden" to "visible" (if currently hidden").

I tried following attempt:

Code Snippet

//... win32.dll import stuff

//...

Process current_proc = Process.GetCurrentProcess();

Process[] processes = Process.GetProcessesByName( current_proc.ProcessName );

foreach ( Process p in processes )

{

if ( p.Id != current_proc.Id ) //if there is already an instance running

{

System.Windows.MessageBox.Show( "Another App is already running" );

if ( IsWindowVisible( p.MainWindowHandle ) == true )

{

System.Windows.MessageBox.Show( "App is already visible" );

ShowWindow( p.MainWindowHandle, 0 ); //hide

}

else

{

System.Windows.MessageBox.Show( "App is hidden" );

ShowWindow(p.MainWindowHandle , 1 ); //show

}

//...terminate app

}

}

The "//hide part" works fine, but the "//show part" seems to do nothing... (it only displays the "App is hidden" message)

Does anyone have an idea what is wrong

And if I fixed that issue, will it also work with Windows XP

Thanks,

Mario M.



Re: UI Development for Windows Vista How do I make a hidden app visible if another instance of the same app gets started?

mommi

Use something like this.

(I have a class called NativeMethods that contain all P/Invoke methods I use...)

[STAThread]

static void Main()

{

//***Single instance check***

using (Mutex mut = new Mutex(false, "Global\\" + Application.ProductName + Application.CompanyName))//using a global mutex

{

if (!mut.WaitOne(0, false))//if current thread can't own the mutex, then another instance must be running

{

IntPtr hWnd;

Process[] processes = Process.GetProcessesByName(Application.ProductName);

if (processes.Length >= 1)

{

if (processes[0] == Process.GetCurrentProcess()) hWnd = processes[1].MainWindowHandle;

else hWnd = processes[0].MainWindowHandle;

if (!NativeMethods.IsIconic(hWnd)) NativeMethods.ShowWindowAsync(hWnd, 9);//restore the window

NativeMethods.SetForegroundWindow(hWnd);//bring it to the foreground

}

processes = null;

return;//exit current process

}

Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);

Application.Run(new FormMain());

mut.ReleaseMutex();//just in case, hopefully this keeps a reference to stop it from beeing GC-d...

}//using

}//Main





Re: UI Development for Windows Vista How do I make a hidden app visible if another instance of the same app gets started?

Mario M.

Thanks, but it didn't solve my problem. The hidden window is still not visible.

Microsoft Spy++ tells me that the first instance receives the "hide" message from

ShowWindow( p.MainWindowHandle, 0 ); // hide part

and its window gets "hidden".

Fine, but when it's already hidden, the "show" message from

ShowWindow( p.MainWindowHandle, 1 ); //show part

never gets received, although the function gets executed.

If you are creating a new WPF project you only have to replace the Window1.xaml.cs file with following code snipped to see what I mean:

Code Snippet

using System;

using System.Collections.Generic;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

using System.Diagnostics;

using System.Runtime.InteropServices;

namespace WindowHide

{

/// <summary>

/// Interaction logic for Window1.xaml

/// </summary>

public partial class Window1 : System.Windows.Window

{

[DllImport( "user32.dll" )]

private static extern bool IsWindowVisible( IntPtr hWnd );

[DllImport( "user32.dll" )]

private static extern bool ShowWindowAsync( IntPtr hWnd, int nCmdShow );

public Window1()

{

Process proc = Process.GetCurrentProcess();

IntPtr mh = proc.MainWindowHandle;

Process[] processes = Process.GetProcessesByName( proc.ProcessName );

foreach ( Process p in processes )

{

if ( p.Id != proc.Id )

{

System.Windows.MessageBox.Show( "Another App is already running",

processes.Length.ToString() );

if ( IsWindowVisible( p.MainWindowHandle ) == true )

{

System.Windows.MessageBox.Show( "Another App is already visible" );

ShowWindowAsync( p.MainWindowHandle, 0 );

}

else

{

System.Windows.MessageBox.Show( "Another App is hidden" );

ShowWindowAsync( p.MainWindowHandle, 1 ); //make visible

}

this.Close();

}

}

InitializeComponent();

}

}

}

Thanks,

Mario M.





Re: UI Development for Windows Vista How do I make a hidden app visible if another instance of the same app gets started?

Mario M.

Oh, I think I know why it doesn't work:

when I say "hide" I use the MainWindowHandle... this works fine, but when I say "unhide" I try to use the MainWindowHandle again and this won't work because now this MainWindowHandle is set to '0'.

Any idea how I can get the original MainWindowHandle

Thanks,

Mario M.





Re: UI Development for Windows Vista How do I make a hidden app visible if another instance of the same app gets started?


Re: UI Development for Windows Vista How do I make a hidden app visible if another instance of the same app gets started?

clez

I'm not used to cs, so sorry for not providing a code example. Some time ago, I had the same problem and solved it using a mutex and messages.

Here's my example code in VC++, there shouldn't be a big difference (except of yours propably being better):

My applications runs in system tray and should stay unique.

Initialization

gMainMutex = CreateMutex (
(LPSECURITY_ATTRIBUTES)NULL,

(BOOL)TRUE,

(LPCTSTR)APPNAME_APP_MUTEX_NAME);
dwLastErr = GetLastError ();
if (gMainMutex == NULL) {
bRet = FALSE;
/* exit condition */
}
if(dwLastErr == ERROR_ALREADY_EXISTS) {
CloseHandle (gMainMutex);
gMainMutex = NULL;
bReturn = FALSE;
HWND existingWindow;
WPARAM wParam = 0 | IDM_CONTEXT_SETUP;
if(strcmp(lpCmdLine,"") == 0) {
wParam = 0 | IDM_CONTEXT_OPEN;
}
existingWindow = FindWindow(APPNAME_MAIN_WINDOW_CLASS, NULL);
SendMessage(existingWindow,WM_COMMAND,wParam,NULL);
}


And here's where I get the message back:

Code Block

switch(msg) {

[..]

/**
* get commands from tray context menu and (tried) instances
*/
case WM_COMMAND: {
WORD wNotifyCode = HIWORD(wParam);
WORD wID = LOWORD(wParam);
HWND hwndCtl = (HWND)lParam;

if(wID == IDM_CONTEXT_OPEN) {

lRet = 0;

OpenMainDialog (hwnd);

}

[..]

break;
}

[..]

}


OpenMainDialog then uses DialogBox() to show it. Maybe it's not the most beautiful way Wink

HTH & good luck Smile