[펌]Mutex

IT/Dot Net 2009/05/08 13:52
다른 용도로 사용가능할 듯

 

 

원본 위치 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

설정

트랙백

http://blog.kkomzi.net/trackback/170 관련글 쓰기

댓글