2010-07-09 26 views
8

A menudo escribo aplicaciones .net que solo admiten una instancia. Anteriormente utilizaba .net-remoting y ahora WCF para detectar si ya se está ejecutando una instancia de mi aplicación y darle el foco a esta instancia..NET 4 instancia de aplicación única

Mi pregunta es, si hay .NET4 una mejor solución disponible para lograr aplicaciones de instancia única (o existe en general una mejor solución disponible, porque la carga del ensamblaje WCF o remoto al inicio de la aplicación tiene una mala influencia de rendimiento)

actualización

Gracias por todo el mensaje. La respuesta a mi pregunta inicial parece ser "no, no hay nada nuevo para lograr aplicaciones de instancia única en .net 4".

Gracias a toda la información adicional, cambiaré mis proyectos actuales para usar un Mutex para proporcionar la funcionalidad deseada. Acepté la respuesta de Bob Moore porque tiene la mayor cantidad de información adjunta, pero gracias a todos los que publicaron información útil.

+1

nada especial para. net 4. wcf y remoto suenan como una gran sobrecarga para una tarea tan simple – Andrey

+0

posible duplicado de [¿Cuál es la forma correcta de crear una aplicación de instancia única?] (http: // stackoverflow.com/questions/19147/what-is-the-correct-way-to-create-one-instance-application-application) – ChrisF

+0

@Andrey: Sí, es su sobrecarga, pero debo decir que en la mayoría de estas aplicaciones I use WCF/Remoting de todos modos, esto justifica el uso de ellos. Pero el momento en que se carga el ensamblaje es malo porque extiende el tiempo que tarda la aplicación en cargarse/inicializarse. – HCL

Respuesta

11

La forma tradicional de hacerlo es con un mutex, p. Ej.

bool bNew = true; 
using (Mutex mutex = new Mutex(true, "MYAPP_0D36E4C9-399D-4b05-BDA3-EE059FB77E8D", out bNew)) 
{ 
    if (bNew) 
    { 
     // blah, blah, 
     Application.Run(new MainForm()); 
    } 
} 

Editar:

me encontré con este código para invocar SetForegroundWindow en línea, para que pueda encontrar la otra instancia de la aplicación y llevarlo hacia adelante:

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool SetForegroundWindow(IntPtr hWnd); 


Process me = Process.GetCurrentProcess(); 
foreach (Process process in Process.GetProcessesByName (me.ProcessName)) 
{ 
    if (process.Id != me.Id) 
    { 
     SetForegroundWindow (process.MainWindowHandle); 
     break; 
    } 
} 

Tenga en cuenta que en las modernas implementaciones de Windows solo puedes dar el primer plano.

+0

¿Funciona esto también en entornos de Terminal Server? – HCL

+1

Un Mutex puede ser por sesión o por toda la máquina. – GvS

+0

Y cómo activar la aplicación existente (Give Focus)? PInvoke? – HCL

2

Uso un Mutex y FindWindow para hacer esto.

En cuanto a su comentario en otra respuesta:
Para obtener información sobre los mutex locales y globales en Terminal Services, follow this link.

cliente de Terminal Services procesa puede utilizar nombres de objeto con un "Global \" o "local \" prefijo de forma explícita crear un objeto en el espacio global o nombre de la sesión.

Este es el código que utilizo para activar la ventana:

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool IsIconic(IntPtr hWnd); 

[DllImport("user32.dll")] 
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 
private const int SH_SHOW = 5; 
private const int SH_RESTORE = 9; 

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool SetForegroundWindow(IntPtr hWnd); 

public void Activate(IntPtr hwnd) 
{ 
    if (IsIconic(hwnd)) 
     ShowWindow(hwnd, SH_RESTORE); 
    else 
     ShowWindow(hwnd, SH_SHOW); 

    SetForegroundWindow(hwnd); 
} 
2

Hay una manera más simple - con la ayuda de la clase WindowsFormsApplicationBase de Microsoft.VisualBasic.ApplicationServices: (ejemplo para VB.net!)

using System; 
using System.Collections.Generic; 

public class SingleInstanceApplicationWrapper : 
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase 
{ 
    public SingleInstanceApplicationWrapper() 
    { 
    IsSingleInstance = true; 
    } 

    private MyApp m_app; 
    protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e) 
    { 
    // here we create our WPF application 
    m_app = new MyApp(); 
    m_app.Run(); 
    return false; 
    } 

    protected override void OnStartupNextInstance(Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e) 
    { 
    m_app.DispatchCommandLineParams(e.CommandLine); 
    } 
} 

public class MyApp : System.Windows.Application 
{ 
    protected override void OnStartup(System.Windows.StartupEventArgs e) 
    { 
    base.OnStartup(e); 
    DispatchCommandLineParams(e.Args); 
    } 
    public void DispatchCommandLineParams(IEnumerable<string> cmdParams) 
    { 
    // process command line parameters 
    Console.WriteLine(this.GetHashCode() + " - dispatched"); 
    } 
} 
public class Program 
{ 
    [STAThread] 
    public static void Main(string[] args) 
    { 
    var wrapper = new SingleInstanceApplicationWrapper(); 
    wrapper.Run(args); 
    } 
} 
Cuestiones relacionadas