bloc-blog de .NET de www.d-activo.com

<May 2008>
SuMoTuWeThFrSa
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567


Navigation

Subscriptions

Article Categories



Cómo averiguar si un programa de consola tiene ya una ventana abierta en .NET 1

Esta pregunta nos la hemos hecho algunos cuando se trataba de hacer un programa que sólo pudiera tener una ventana abierta a la vez, esto a veces puede ser útil por ejemplo para hacer un aplicación MDI, o porque al ser un programa único sin posibles añadidos ni cambio de pantallas, quisiéramos que no ocurriera nada.
Pues bien, éste es mi truco personal:

                    Process oCurrentProcess = Process.GetCurrentProcess();

                   //get all other process by the same name, atleast one will be returned - the current one.

                  Process[] arrProcesses = Process.GetProcessesByName(oCurrentProcess.ProcessName);

 

                  bool bProcess = false;

                  //go thru all of them

                  foreach(Process oProcess in arrProcesses)

                  {

                        //if the id is different, that means another process by the same name exists

                        if(oProcess.Id != oCurrentProcess.Id) //

                        {

                             MessageBox.Show("Another instance of the application is already running");

                             bProcess = true;

                             break;

                        }

                  }

 

                  if(!bProcess)

                  {

                        //if process not found, start one

                        Application.Run(new actualizaDB());

                  }

                  else

                  {

                        //else exit

                        Application.Exit();

                       }
Hasta aquí yo creo que todo se entiende, y siento no tener mucho tiempo para explicarlo con detenimiento.
Pero el caso es que pensaréis, aquí falta algo, ese algo es que la ventana del programa no se abre en estos casos, se queda minimizada.
Bueno, este truco es más difícil y requiere algo más de programación pero seguro que me agradecéis que os pase este código tan socorrido.
Ah, por cierto, en .NET 2 ha llegado a mis oídos que ya hay métodos para facilitar la tarea.

Primero crear la siguiente clase:
using System;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Runtime.InteropServices;
 
namespace Win32APIs
{
    /// &ltsummary>
    /// WindowsHelper implements managed wrappers for unmanaged Win32 APIs.
    /// </summary>
    public sealed class WindowsHelper
    {
        #region structures needed to call into unmanaged Win32 APIs.
        /// &ltsummary>
        /// Point struct used for GetWindowPlacement API.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
            private class ManagedPt 
        {
            public int x = 0;
            public int y = 0;
            
            public ManagedPt() 
            {
            }
 
            public ManagedPt(int x, int y) 
            {
                this.x = x;
                this.y = y;
            }
        }
 
        /// &ltsummary>
        /// Rect struct used for GetWindowPlacement API.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private class ManagedRect 
        {
            public int x = 0;
            public int y = 0;
            public int right = 0;
            public int bottom = 0;
            
            public ManagedRect() 
            {
            }
 
            public ManagedRect(int x, int y, int right, int bottom) 
            {
                this.x = x;
                this.y = y;
                this.right = right;
                this.bottom = bottom;
            }
        }
 
        /// &ltsummary>
        /// WindowPlacement struct used for GetWindowPlacement API.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private class ManagedWindowPlacement 
        {
            public uint length = 0;
            public uint flags = 0;
            public uint showCmd = 0;
            public ManagedPt minPosition = null;
            public ManagedPt maxPosition = null;
            public ManagedRect normalPosition = null;
            
            public ManagedWindowPlacement() 
            {
                this.length = (uint)Marshal.SizeOf(this);
            }
        }
        #endregion
 
        // External Win32 APIs that we're calling directly.
        [DllImport("USER32.DLL", SetLastError=true)]
        private static extern uint ShowWindow (uint hwnd, int showCommand);
        
        [DllImport("USER32.DLL", SetLastError=true)]
        private static extern uint SetForegroundWindow (uint hwnd);
        
        [DllImport("USER32.DLL", SetLastError=true)]
        private static extern uint GetWindowPlacement (uint hwnd, 
            [In, Out]ManagedWindowPlacement lpwndpl);
        
        [DllImport("USER32.DLL", SetLastError=true)]
        private static extern uint FindWindow (string lpClassName, string lpWindowName);
 
        // Windows defined constants.
        private const int WM_ACTIVATE = 0x0006;
        private const int WA_CLICKACTIVE = 2;
        private const int SW_SHOWNORMAL = 1;
        private const int SW_SHOWMINIMIZED = 2;
        private const int SW_SHOWMAXIMIZED = 3;
        private const int WPF_RESTORETOMAXIMIZED = 2;
 
        /// &ltsummary>
        /// Finds the specified window by its name (or caption). 
        /// </summary>
        /// &ltparam name="windowName">Name of the window to find and activate.</param>
        /// &ltreturns>Window handle or 0 if window not found by that name.</returns>
        static private uint FindWindow(string windowName)
        {
            // first, try to find the window by its window name or caption.
            uint hwndInstance = FindWindow(null, windowName);
            if (hwndInstance <= 0)
            {
                Debug.Assert(false, 
                    "Couldn't find window handle for the specified window name.");
            }
 
            return hwndInstance;
        }
 
        /// &ltsummary>
        /// Finds the specified window by its name (or caption).  Then brings it to
        /// the foreground.
        /// </summary>
        /// &ltparam name="windowName">Name of the window to find and activate.</param>
        static public void ActivateWindow(string windowName)
        {
            // first, try to find the window by its window name or caption.
            uint hwndInstance = FindWindow(windowName);
 
            // Then, get the WindowPlacement, so we can decide the best way to 
            // activate the window correctly.
            ManagedWindowPlacement placement = new ManagedWindowPlacement();
            GetWindowPlacement(hwndInstance, placement);
 
            if (placement.showCmd == SW_SHOWMINIMIZED)
            {
                // if the window is minimized, then we need to restore it to its
                // previous size.  we also take into account whether it was 
                // previously maximized.
                int showCmd = (placement.flags == WPF_RESTORETOMAXIMIZED) ? 
                    SW_SHOWMAXIMIZED : SW_SHOWNORMAL;
                ShowWindow(hwndInstance, showCmd);
            }
            else
            {
                // if it's not minimized, then we just call SetForegroundWindow to 
                // bring it to the front.
                SetForegroundWindow(hwndInstance);
            }
        }
    }
}

Después cread esta otra clase:
using System;
using System.Collections.Specialized;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using Win32APIs;
 
namespace SingleInstanceApp
{
    /// &ltsummary>
    /// SingleInstanceHelper implements functionality to create single instance
    /// WinForms applications.
    /// </summary>
    public sealed class SingleInstanceHelper
    {
        // private member data.
        static private Mutex singleInstance = null;        // holds the mutex for this application.
 
        // private constants.
        private const string formatMutexName = "SingleInstanceMutex-{0}-{1}";
 
        /// &ltsummary>
        /// Generates a unique identifier for this application's mutex based on its
        /// assembly name and version.
        /// </summary>
        static private string UniqueIdentifier
        {
            get
            {
                string appName = "";
                string appVersion = "0.0.0.0";
                Assembly entry = Assembly.GetEntryAssembly();
 
                if (entry != null) 
                {
                    AssemblyName assemblyName = entry.GetName();
                    if (assemblyName != null)
                    {
                        appName = assemblyName.Name;
                        appVersion = assemblyName.Version.ToString();
                    }
            &n