글
[펌]Mutex
원본 위치 http://iwoohaha.tistory.com/90
이미 실행중 체크하고 종료하는게 아니라
해당 프로그램을 Foreground 로 띄워줌
뮤텍스를 사용하는 원리
프로그램의 메인 폼을 실행시키기 전에 이미 실행되고 있는 프로그램의 인스턴스가 존재하는지를 확인해야 함.
Program Class의 Main 함수에서 확인.
[STAThread]
static void Main()
{
// 이미 프로그램 인스턴스가 존재하는 경우 프로그램 종료
if (IsExistAnotherInstance())
return; // 프로그램 종료
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private static bool IsExistAnotherInstance()
{
bool createdNew;
Mutex mutex = new Mutex(true, Application.ProductName, out createdNew);
if (createdNew)
{
// 이번 실행이 처음 실행이다.
return false;
}
// 이미 실행되고 있는 인스턴스를 활성화시킨다.
Process[] viewProcesses = Process.GetProcessesByName(Application.ProductName);
if (null != viewProcesses && 2 == viewProcesses.Length)
{
Process view = (viewProcesses[0].Id == Process.GetCurrentProcess().Id) ?
viewProcesses[1] : viewProcesses[0];
IntPtr hWndOfPrevInstance = view.MainWindowHandle;
if (Win32.IsIconic(hWndOfPrevInstance))
Win32.ShowWindowAsync(hWndOfPrevInstance, Win32.SW_RESTORE);
Win32.SetForegroundWindow(hWndOfPrevInstance);
return true;
}
return false;
}
위 코드에서 사용하고 있는 Win32 클래스의 내용(일부 발췌)
public class Win32
{
/// <summary>
/// The SetForegroundWindow function puts the thread that created the specified window
/// into the foreground and activates the window. Keyboard input is directed to the window,
/// and various visual cues are changed for the user. The system assigns a slightly higher
/// priority to the thread that created the foreground window than it does to other threads.
/// </summary>
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
/// <summary>
/// The ShowWindowAsync function sets the show state of a window created by a different thread.
/// </summary>
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
/// <summary>
/// The IsIconic function determines whether the specified window is minimized (iconic).
/// </summary>
[DllImport("user32.dll")]
public static extern bool IsIconic(IntPtr hWnd);
// Activates and displays the window. If the window is minimized or maximized, the system
// restores it to its original size and position. An application should specify this flag
// when restoring a minimized window.
public static int SW_RESTORE = 9;
}
[이미 실행중인 프로그램에 데이터 전달하기]
WM_COPYDATA 메시지를 사용하는 원리
프로그램은 ClickOnce 로 배포되고 있고, 웹페이지에서 파라미터를 사용하여 프로그램을 실행시키는 경우라고 가정함.
프로그램 실행시 전달된 파라미터 수집 : GetQueryStringParameters()
[STAThread]
static void Main()
{
// 프로그램 실행시 전달된 파라미터 수집
Dictionary<string, string> dicParams = GetQueryStringParameters();
// 이미 존재하는 인스턴스가 있을 수 있으므로 프로그램 실행시 전달받은 파라미터 딕셔너리를 전달함
if (IsExistAnotherInstance(ref dicParams))
return;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private static Dictionary<string, string> GetQueryStringParameters()
{
Dictionary<string, string> nameValueTable = new Dictionary<string, string>();
try
{
if (ApplicationDeployment.IsNetworkDeployed)
{
string url = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData[0];
string queryString = ApplicationDeployment.CurrentDeployment.ActivationUri.Query;
if (string.Empty == queryString) return (nameValueTable);
int nIndex = queryString.IndexOf("?");
if (nIndex > -1) queryString = queryString.Remove(nIndex, 1);
queryString = HttpUtility.UrlDecode(queryString);
string[] nameValuePairs = queryString.Split('&');
if (nameValuePairs != null && nameValuePairs.Length > 0)
{
foreach (string pair in nameValuePairs)
{
string[] vars = pair.Split('=');
if (!nameValueTable.ContainsKey(vars[0]))
{
nameValueTable.Add(vars[0], vars[1]);
}
}
}
}
}
catch (Exception)
{
}
return (nameValueTable);
}
프로그램의 인스턴스가 이미 존재하는지 확인하고 이미 존재하면 해당 인스턴스에게 프로그램 실행시 전달받은 파라미터 문자열을 전달함.
private static bool IsExistAnotherInstance(ref Dictionary<string, string> dicParams)
{
bool createdNew;
Mutex mutex = new Mutex(true, Application.ProductName, out createdNew);
if (createdNew)
{
// 이번 실행이 처음 실행이다.
return false;
}
Process[] viewProcesses = Process.GetProcessesByName(Application.ProductName);
if (null != viewProcesses && 2 == viewProcesses.Length)
{
Process view = (viewProcesses[0].Id == Process.GetCurrentProcess().Id) ?
viewProcesses[1] : viewProcesses[0];
IntPtr hWndOfPrevInstance = view.MainWindowHandle;
if (Win32.IsIconic(hWndOfPrevInstance))
Win32.ShowWindowAsync(hWndOfPrevInstance, Win32.SW_RESTORE);
Win32.SetForegroundWindow(hWndOfPrevInstance);
// 이미 실행중인 인스턴스에 이 인스턴스가 전달받은 파라미터 문자열을 전달함
SendParams(hWndOfPrevInstance, ref dicParams);
return true;
}
return false;
}
private static void SendParams(IntPtr hWndTarget, ref Dictionary<string, string> dicParams)
{
// 파라미터 딕셔너리를 파라미터 문자열로 만든다.
StringBuilder sb = new StringBuilder();
foreach (string key in dicParams.Keys)
{
if (sb.Length > 0)
sb.Append("&");
sb.AppendFormat("{0}={1}", key, dicParams[key]);
}
if (sb.Length > 0)
SendArgs(hWndTarget, sb.ToString());
}
private static void SendArgs(IntPtr hWndTarget, string text)
{
Win32.CopyDataStruct cds = new Win32.CopyDataStruct();
try
{
cds.cbData = (text.Length + 1) * 2;
cds.lpData = Win32.LocalAlloc(0x40, cds.cbData);
Marshal.Copy(text.ToCharArray(), 0, cds.lpData, text.Length);
cds.dwData = (IntPtr)1;
Win32.SendMessage(hWndTarget, Win32.WM_COPYDATA, IntPtr.Zero, ref cds);
}
finally
{
cds.Dispose();
}
}
위 코드에서 사용된 Win32 클래스의 내용(전체)
public class Win32
{
/// <summary>
/// The SetForegroundWindow function puts the thread that created the specified window
/// into the foreground and activates the window. Keyboard input is directed to the window,
/// and various visual cues are changed for the user. The system assigns a slightly higher
/// priority to the thread that created the foreground window than it does to other threads.
/// </summary>
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
/// <summary>
/// The ShowWindowAsync function sets the show state of a window created by a different thread.
/// </summary>
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
/// <summary>
/// The IsIconic function determines whether the specified window is minimized (iconic).
/// </summary>
[DllImport("user32.dll")]
public static extern bool IsIconic(IntPtr hWnd);
// Activates and displays the window. If the window is minimized or maximized, the system
// restores it to its original size and position. An application should specify this flag
// when restoring a minimized window.
public static int SW_RESTORE = 9;
/// <summary>
/// The SendMessage API
/// </summary>
/// <param name="hWnd">handle to the required window</param>
/// <param name="Msg">the system/Custom message to send</param>
/// <param name="wParam">first message parameter</param>
/// <param name="lParam">second message parameter</param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref CopyDataStruct lParam);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LocalAlloc(int flag, int size);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LocalFree(IntPtr p);
public const int WM_COPYDATA = 0x004A;
public struct CopyDataStruct : IDisposable
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
public void Dispose()
{
if (this.lpData != IntPtr.Zero)
{
LocalFree(this.lpData);
this.lpData = IntPtr.Zero;
}
}
}
}
프로그램의 메인폼에서는 WM_COPYDATA 메시지를 처리함.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case Win32.WM_COPYDATA:
Win32.CopyDataStruct st = (Win32.CopyDataStruct)Marshal.PtrToStructure(m.LParam, typeof(Win32.CopyDataStruct));
string strData = Marshal.PtrToStringUni(st.lpData);
textBox1.Text = strData;
break;
default:
// let the base class deal with it
base.WndProc(ref m);
break;
}
}
}
'IT > Dot Net' 카테고리의 다른 글
| 주석 태그 정리 (0) | 2009/06/16 |
|---|---|
| [펌]Image Codec (0) | 2009/05/27 |
| [펌]Mutex (0) | 2009/05/08 |
| .Net 3.5 관련 IIS MIME 셋팅 (0) | 2009/02/02 |
| User control in toolbox (0) | 2008/12/09 |
| Win32 Data Type Conversion Table (0) | 2008/12/03 |
