상세 컨텐츠

본문 제목

오직 한 번만 실행되는 프로그램 - 이미 실행중인 프로그램에 데이터 전달하기

C#

by 탑~! 2013. 5. 13. 10:20

본문


  1. [STAThread]  
  2. static void Main()  
  3. {  
  4.     // 이미 프로그램 인스턴스가 존재하는 경우 프로그램 종료  
  5.     if (IsExistAnotherInstance())  
  6.         return;    // 프로그램 종료  
  7.   
  8.     Application.EnableVisualStyles();  
  9.     Application.SetCompatibleTextRenderingDefault(false);  
  10.     Application.Run(new Form1());  
  11. }  
  12.   
  13. private static bool IsExistAnotherInstance()  
  14. {  
  15.     bool createdNew;  
  16.     Mutex mutex = new Mutex(true, Application.ProductName, out createdNew);  
  17.     if (createdNew)  
  18.     {  
  19.         // 이번 실행이 처음 실행이다.  
  20.         return false;  
  21.     }  
  22.   
  23.     // 이미 실행되고 있는 인스턴스를 활성화시킨다.  
  24.     Process[] viewProcesses = Process.GetProcessesByName(Application.ProductName);  
  25.     if (null != viewProcesses && 2 == viewProcesses.Length)  
  26.     {  
  27.         Process view = (viewProcesses[0].Id == Process.GetCurrentProcess().Id) ?   
  28.             viewProcesses[1] : viewProcesses[0];  
  29.   
  30.         IntPtr hWndOfPrevInstance = view.MainWindowHandle;  
  31.         if (Win32.IsIconic(hWndOfPrevInstance))  
  32.             Win32.ShowWindowAsync(hWndOfPrevInstance, Win32.SW_RESTORE);  
  33.         Win32.SetForegroundWindow(hWndOfPrevInstance);  
  34.   
  35.         return true;  
  36.     }  
  37.     return false;  
  38. }  

위 코드에서 사용하고 있는 Win32 클래스의 내용(일부 발췌)
  1. public class Win32  
  2. {  
  3.     /// <summary>  
  4.     /// The SetForegroundWindow function puts the thread that created the specified window  
  5.     /// into the foreground and activates the window. Keyboard input is directed to the window,  
  6.     /// and various visual cues are changed for the user. The system assigns a slightly higher  
  7.     /// priority to the thread that created the foreground window than it does to other threads.  
  8.     /// </summary>  
  9.     [DllImport("user32.dll")]  
  10.     public static extern bool SetForegroundWindow(IntPtr hWnd);  
  11.   
  12.     /// <summary>  
  13.     /// The ShowWindowAsync function sets the show state of a window created by a different thread.  
  14.     /// </summary>  
  15.     [DllImport("user32.dll")]  
  16.     public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);  
  17.   
  18.     /// <summary>  
  19.     /// The IsIconic function determines whether the specified window is minimized (iconic).  
  20.     /// </summary>  
  21.     [DllImport("user32.dll")]  
  22.     public static extern bool IsIconic(IntPtr hWnd);  
  23.   
  24.     // Activates and displays the window. If the window is minimized or maximized, the system  
  25.     // restores it to its original size and position. An application should specify this flag  
  26.     // when restoring a minimized window.  
  27.     public static int SW_RESTORE = 9;  
  28. }  

[이미 실행중인 프로그램에 데이터 전달하기]
WM_COPYDATA 메시지를 사용하는 원리
프로그램은 ClickOnce 로 배포되고 있고, 웹페이지에서 파라미터를 사용하여 프로그램을 실행시키는 경우라고 가정함.
프로그램 실행시 전달된 파라미터 수집 : GetQueryStringParameters()
  1. [STAThread]  
  2. static void Main()  
  3. {  
  4.     // 프로그램 실행시 전달된 파라미터 수집  
  5.     Dictionary<stringstring> dicParams = GetQueryStringParameters();  
  6.   
  7.     // 이미 존재하는 인스턴스가 있을 수 있으므로 프로그램 실행시 전달받은 파라미터 딕셔너리를 전달함  
  8.     if (IsExistAnotherInstance(ref dicParams))  
  9.         return;  
  10.   
  11.     Application.EnableVisualStyles();  
  12.     Application.SetCompatibleTextRenderingDefault(false);  
  13.     Application.Run(new Form1());  
  14. }  
  15.   
  16. private static Dictionary<stringstring> GetQueryStringParameters()  
  17. {  
  18.     Dictionary<stringstring> nameValueTable = new Dictionary<stringstring>();  
  19.   
  20.     try  
  21.     {  
  22.         if (ApplicationDeployment.IsNetworkDeployed)  
  23.         {  
  24.             string url = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[0];  
  25.             string queryString = ApplicationDeployment.CurrentDeployment.ActivationUri.Query;  
  26.             if (string.Empty == queryString) return (nameValueTable);  
  27.   
  28.             int nIndex = queryString.IndexOf("?");  
  29.   
  30.             if (nIndex > -1) queryString = queryString.Remove(nIndex, 1);  
  31.             queryString = HttpUtility.UrlDecode(queryString);  
  32.             string[] nameValuePairs = queryString.Split('&');  
  33.             if (nameValuePairs != null && nameValuePairs.Length > 0)  
  34.             {  
  35.                 foreach (string pair in nameValuePairs)  
  36.                 {  
  37.                     string[] vars = pair.Split('=');  
  38.                     if (!nameValueTable.ContainsKey(vars[0]))  
  39.                     {  
  40.                         nameValueTable.Add(vars[0], vars[1]);  
  41.                     }  
  42.                 }  
  43.             }  
  44.         }  
  45.     }  
  46.     catch (Exception)  
  47.     {  
  48.     }  
  49.   
  50.     return (nameValueTable);  
  51. }  
프로그램의 인스턴스가 이미 존재하는지 확인하고 이미 존재하면 해당 인스턴스에게 프로그램 실행시 전달받은 파라미터 문자열을 전달함.
  1. private static bool IsExistAnotherInstance(ref Dictionary<stringstring> dicParams)  
  2. {  
  3.     bool createdNew;  
  4.     Mutex mutex = new Mutex(true, Application.ProductName, out createdNew);  
  5.     if (createdNew)  
  6.     {  
  7.         // 이번 실행이 처음 실행이다.  
  8.         return false;  
  9.     }  
  10.   
  11.     Process[] viewProcesses = Process.GetProcessesByName(Application.ProductName);  
  12.     if (null != viewProcesses && 2 == viewProcesses.Length)  
  13.     {  
  14.         Process view = (viewProcesses[0].Id == Process.GetCurrentProcess().Id) ?   
  15.             viewProcesses[1] : viewProcesses[0];  
  16.   
  17.         IntPtr hWndOfPrevInstance = view.MainWindowHandle;  
  18.         if (Win32.IsIconic(hWndOfPrevInstance))  
  19.             Win32.ShowWindowAsync(hWndOfPrevInstance, Win32.SW_RESTORE);  
  20.         Win32.SetForegroundWindow(hWndOfPrevInstance);  
  21.   
  22.         // 이미 실행중인 인스턴스에 이 인스턴스가 전달받은 파라미터 문자열을 전달함  
  23.         SendParams(hWndOfPrevInstance, ref dicParams);  
  24.   
  25.         return true;  
  26.     }  
  27.     return false;  
  28. }  
  29.   
  30. private static void SendParams(IntPtr hWndTarget, ref Dictionary<stringstring> dicParams)  
  31. {  
  32.     // 파라미터 딕셔너리를 파라미터 문자열로 만든다.  
  33.     StringBuilder sb = new StringBuilder();  
  34.     foreach (string key in dicParams.Keys)  
  35.     {  
  36.         if (sb.Length > 0)  
  37.             sb.Append("&");  
  38.         sb.AppendFormat("{0}={1}", key, dicParams[key]);  
  39.     }  
  40.   
  41.     if (sb.Length > 0)  
  42.         SendArgs(hWndTarget, sb.ToString());  
  43. }  
  44.   
  45. private static void SendArgs(IntPtr hWndTarget, string text)  
  46. {  
  47.     Win32.CopyDataStruct cds = new Win32.CopyDataStruct();  
  48.     try  
  49.     {  
  50.         cds.cbData = (text.Length + 1) * 2;  
  51.         cds.lpData = Win32.LocalAlloc(0x40, cds.cbData);  
  52.         Marshal.Copy(text.ToCharArray(), 0, cds.lpData, text.Length);  
  53.         cds.dwData = (IntPtr)1;  
  54.         Win32.SendMessage(hWndTarget, Win32.WM_COPYDATA, IntPtr.Zero, ref cds);  
  55.     }  
  56.     finally  
  57.     {  
  58.         cds.Dispose();  
  59.     }  
  60. }  
위 코드에서 사용된 Win32 클래스의 내용(전체)
  1. public class Win32  
  2. {  
  3.     /// <summary>  
  4.     /// The SetForegroundWindow function puts the thread that created the specified window  
  5.     /// into the foreground and activates the window. Keyboard input is directed to the window,  
  6.     /// and various visual cues are changed for the user. The system assigns a slightly higher  
  7.     /// priority to the thread that created the foreground window than it does to other threads.  
  8.     /// </summary>  
  9.     [DllImport("user32.dll")]  
  10.     public static extern bool SetForegroundWindow(IntPtr hWnd);  
  11.   
  12.     /// <summary>  
  13.     /// The ShowWindowAsync function sets the show state of a window created by a different thread.  
  14.     /// </summary>  
  15.     [DllImport("user32.dll")]  
  16.     public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);  
  17.   
  18.     /// <summary>  
  19.     /// The IsIconic function determines whether the specified window is minimized (iconic).  
  20.     /// </summary>  
  21.     [DllImport("user32.dll")]  
  22.     public static extern bool IsIconic(IntPtr hWnd);  
  23.   
  24.     // Activates and displays the window. If the window is minimized or maximized, the system  
  25.     // restores it to its original size and position. An application should specify this flag  
  26.     // when restoring a minimized window.  
  27.     public static int SW_RESTORE = 9;  
  28.   
  29.     /// <summary>  
  30.     /// The SendMessage API  
  31.     /// </summary>  
  32.     /// <param name="hWnd">handle to the required window</param>  
  33.     /// <param name="Msg">the system/Custom message to send</param>  
  34.     /// <param name="wParam">first message parameter</param>  
  35.     /// <param name="lParam">second message parameter</param>  
  36.     /// <returns></returns>  
  37.     [DllImport("user32.dll")]  
  38.     public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref CopyDataStruct lParam);  
  39.   
  40.     [DllImport("kernel32.dll", SetLastError = true)]  
  41.     public static extern IntPtr LocalAlloc(int flag, int size);  
  42.   
  43.     [DllImport("kernel32.dll", SetLastError = true)]  
  44.     public static extern IntPtr LocalFree(IntPtr p);  
  45.   
  46.     public const int WM_COPYDATA = 0x004A;  
  47.   
  48.     public struct CopyDataStruct : IDisposable  
  49.     {  
  50.         public IntPtr dwData;  
  51.         public int cbData;  
  52.         public IntPtr lpData;  
  53.   
  54.         public void Dispose()  
  55.         {  
  56.             if (this.lpData != IntPtr.Zero)  
  57.             {  
  58.                 LocalFree(this.lpData);  
  59.                 this.lpData = IntPtr.Zero;  
  60.             }  
  61.         }  
  62.     }  
  63. }  

프로그램의 메인폼에서는 WM_COPYDATA 메시지를 처리함.
  1. public partial class Form1 : Form  
  2. {  
  3.     public Form1()  
  4.     {  
  5.         InitializeComponent();  
  6.     }  
  7.   
  8.     protected override void WndProc(ref Message m)  
  9.     {  
  10.         switch (m.Msg)  
  11.         {  
  12.             case Win32.WM_COPYDATA:  
  13.                 Win32.CopyDataStruct st = (Win32.CopyDataStruct)Marshal.PtrToStructure(m.LParam, typeof(Win32.CopyDataStruct));  
  14.                 string strData = Marshal.PtrToStringUni(st.lpData);  
  15.                 textBox1.Text = strData;  
  16.                 break;  
  17.             default:  
  18.                 // let the base class deal with it  
  19.                 base.WndProc(ref m);  
  20.                 break;  
  21.         }  
  22.     }  
  23. }  




OneInstanceAndParameterExecute.zip


출처 : http://iwoohaha.tistory.com/90

'C#' 카테고리의 다른 글

C# 에서 Crystal Report 사용하기  (0) 2013.05.20
PrintDocument 사용 Sample  (0) 2013.05.20
C# OutLook AttachFile Drop&Drop  (0) 2013.04.22
Keyboard Hooking  (0) 2013.04.17
Mouse Hooking  (0) 2013.04.17

관련글 더보기