찾던 중 비슷한게 있어서 찾아 수정하였음
기본 로직은 시작표시줄 및 트레이 아이콘 쪽에 프로그램 이름을 검색 후 같은 프로그램 이름이 있으면
작동하게 되어 있으며,
기존 로직은 원래 있던 자리로 띄우는 것이나 내가 수정한 것은 기존 프로그램의 위치가 어디에 있든
새로 띄울 때는 첫번째 모니터의 정중앙에 띄우게 한다.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace MLauncher
{
/// <summary>
/// Check running processes for an already-running instance. Implements a simple and
/// always effective algorithm to find currently running processes with a main window
/// matching a given substring and focus it.
/// Combines code written by Lion Shi (MS) and Sam Allen.
///
/// 사용법:Program.cs파일의 다음 부분에 아래와 같이 소스를 수정한다.
/// "Program Window Text"은 폼의 타이틀 이름이다.
/// (띄어쓰기가 있는
/// [STAThread]
/// static void Main()
/// {
/// if (ProcessChecker.IsOnlyProcess("Program Window Text"))
/// {
/// Application.EnableVisualStyles();
/// Application.SetCompatibleTextRenderingDefault(false);
/// Application.Run(new TextWindow());
/// }
/// }
///
/// 출처:http://dotnetperls.com/single-instance-windows-form
/// </summary>
static class ProcessChecker
{
/// <summary>
/// 찾아야 할 캡션
/// </summary>
static string _requiredString;
/// <summary>
/// Contains signatures for C++ DLLs using interop.
/// </summary>
internal static class NativeMethods
{
/// <summary>
/// 현재 실행중인 윈도우의 상태를 보여준다.
/// </summary>
/// <param name="hWnd"></param>
/// <param name="nCmdShow"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
/// <summary>
/// 선택한 윈도우를 뒤에 숨어있었으면 앞으로, 최소화상태였으면 원래상태로 되돌려놓으며 활성화시킨다.
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
/// <summary>
/// EnumWindows 함수는 모든 최상위 윈도우를 검색해서 그 핸들을 콜백함수로 전달하되
/// 모든 윈도우를 다 찾거나 콜백함수가 FALSE를 리턴할 때까지 검색을 계속한다.
/// 콜백함수는 검색된 윈도우의 핸들을 전달받으므로 모든 윈도우에 대해 모든 작업을 다 할 수 있다.
/// EnumWindows 함수는 차일드 윈도우는 검색에서 제외된다.
/// 단 시스템이 생성한 일부 최상위 윈도우는 WS_CHILD 스타일을 가지고 있더라도 예외적으로 검색에 포함된다.
/// </summary>
/// <param name="lpEnumFunc">EnumWindows의 실행 결과를 받아줄 콜백함수이다. EnumWindows는 이 함수 결과가 false가 될 때까지 계속 윈도우를 검색하게 된다.</param>
/// <param name="lParam"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern bool EnumWindows(EnumWindowsProcDel lpEnumFunc, Int32 lParam);
/// <summary>
/// HWND 값을 이용하여 프로세스 ID를 알려주는 함수이다.
/// </summary>
/// <param name="hWnd"></param>
/// <param name="lpdwProcessId"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern int GetWindowThreadProcessId(IntPtr hWnd, ref Int32 lpdwProcessId);
/// <summary>
/// 윈도우의 캡션을 가져온다.
/// </summary>
/// <param name="hWnd"></param>
/// <param name="lpString"></param>
/// <param name="nMaxCount"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, Int32 nMaxCount);
/// <summary>
/// 윈도우를 이동시킨다
/// </summary>
/// <param name="hWnd"></param>
/// <param name="X"></param>
/// <param name="Y"></param>
/// <param name="nWidth"></param>
/// <param name="nHeight"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern int MoveWindow(IntPtr hWnd, Int32 X, Int32 Y, Int32 nWidth, Int32 nHeight);
/// <summary>
/// 윈도우의 크기 및 좌표를 셋팅하고 상태를 조절한다.
/// uFlags 값에 의해 상태를 조절함
/// </summary>
/// <param name="hWnd"></param>
/// <param name="hWndInsertAfter"></param>
/// <param name="X"></param>
/// <param name="Y"></param>
/// <param name="W"></param>
/// <param name="H"></param>
/// <param name="uFlags"></param>
/// <returns></returns>
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, Int32 hWndInsertAfter, int X, int Y, int W, int H, uint uFlags);
/// <summary>
/// 윈도우의 크기를 알아내는 함수
/// </summary>
/// <param name="hwnd"></param>
/// <param name="lpRect"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
//윈도우의 상태를 normal로 하게 하는 상수
public const int SW_SHOWNORMAL = 1;
public const int HWND_TOPMOST = -1;
public const uint SWP_NOSIZE = 1;
}
/// <summary>
/// EnumWindows의 실행 결과를 받아줄 콜백함수이다.
/// EnumWindows는 이 함수 결과가 false가 될 때까지 계속 윈도우를 검색하게 된다.
/// </summary>
/// <param name="hWnd"></param>
/// <param name="lParam"></param>
/// <returns></returns>
public delegate bool EnumWindowsProcDel(IntPtr hWnd, Int32 lParam);
/// <summary>
/// Perform finding and showing of running window.
/// 모든 실행중인 윈도우를 검색하며 찾고자 하는 캡션의 윈도우를 발견하면 활성화시킨다.
/// </summary>
/// <returns>Bool, which is important and must be kept to match up
/// with system call.</returns>
static private bool EnumWindowsProc(IntPtr hWnd, Int32 lParam)
{
int processId = 0;
NativeMethods.GetWindowThreadProcessId(hWnd, ref processId);
StringBuilder caption = new StringBuilder(1024);
NativeMethods.GetWindowText(hWnd, caption, 1024); //방금 검색한 윈도우의 캡션을 가져온다.
//찾을 윈도우명과 가져온 캡션이 일치한다면,
if (processId == lParam && (caption.ToString().IndexOf(_requiredString, StringComparison.OrdinalIgnoreCase) != -1))
{
//윈도우를 normal 상태로 바꾸고 제일 앞으로 가져온다.
NativeMethods.ShowWindowAsync(hWnd, NativeMethods.SW_SHOWNORMAL);
//NativeMethods.SetWindowPos(hWnd, NativeMethods.HWND_TOPMOST, 123, 123, 0, 0, NativeMethods.SWP_NOSIZE);
CentreWindow(hWnd);
//NativeMethods.MoveWindow(hWnd, 0, 0, 511, 326);
//NativeMethods.SetForegroundWindow(hWnd);
}
return true; //왜 계속 true만 반환해야 할까???
}
/// <summary>
/// 지금 실행하려는 프로그램이 이미 실행중인지 아닌지 찾아보고 결과를 알려준다.
/// </summary>
/// <param name="forceTitle">찾으려는 윈도우의 캡션, 즉 프로그램 타이틀</param>
/// <returns>해당 캡션의 윈도우가 이미 실행중이라면 False,
/// 처음 실행하는 것이라면 True를 반환한다.</returns>
static public bool IsOnlyProcess(string forceTitle)
{
_requiredString = forceTitle;
//먼저 실행파일의 이름으로 이름이 같은 프로세스를 검색해본다.
foreach (Process proc in Process.GetProcessesByName(Application.ProductName))
{
if (proc.Id != Process.GetCurrentProcess().Id)
{
NativeMethods.EnumWindows(new EnumWindowsProcDel(EnumWindowsProc), proc.Id);
return false;
}
}
return true;
}
/// <summary>
/// 윈도우를 첫번째 모니터 가운데에 위치하게 한 후 가장 상위탭으로 끓어올림
/// </summary>
/// <param name="hWnd"></param>
private static void CentreWindow(IntPtr hWnd)
{
NativeMethods.RECT _rect = default(NativeMethods.RECT);
//NativeMethods.GetWindow_rect(new HandleRef(this, hWnd), out _rect);
NativeMethods.GetWindowRect(hWnd, out _rect);
Size monitorDimensions = SystemInformation.PrimaryMonitorSize;
Int32 x1Pos = monitorDimensions.Width / 2 - (_rect.Right - _rect.Left) / 2;
Int32 x2Pos = _rect.Right - _rect.Left;
Int32 y1Pos = monitorDimensions.Height / 2 - (_rect.Bottom - _rect.Top) / 2;
Int32 y2Pos = _rect.Bottom - _rect.Top;
NativeMethods.SetWindowPos(hWnd, NativeMethods.HWND_TOPMOST, x1Pos, y1Pos, 0, 0, NativeMethods.SWP_NOSIZE);
}
}
}