2012-01-13 3 views
4

Как я могу обеспечить один экземпляр моего приложения и установить фокус на него при попытке открыть второй экземпляр?Как я могу применить один экземпляр моего приложения?

Я пробовал:

public partial class Form1 : Form { 

    [DllImport("USER32.DLL", CharSet = CharSet.Unicode)] 
    public static extern 
    IntPtr FindWindow(String lpClassName, String lpWindowName); 

    [DllImport("USER32.DLL")] 
    public static extern 
    Boolean SetForegroundWindow(IntPtr hWnd); 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     bool isRunning = Process.GetProcesses() 
           .Where(p => p.MainWindowTitle.Contains(Text)) 
           .Count() > 1; 

     if (isRunning) 
     { 
      FocusWindow(Text); 
      Application.Exit(); 
     } 
    } 

    public static void FocusWindow(string title) 
    { 
     SetForegroundWindow(FindWindow(null, title)); 
    } 
} 

Это не фокусирование приложения. Как я могу это исправить?

+0

Вы уверены, что FindWindow возвращает действительный HWND? – Tigran

+0

Не было бы более целесообразным проверить в Program.cs перед запуском формы? Проверьте экземпляр имени процесса с помощью 'count> 0'. –

+1

См. [Приложения с одним экземпляром в C#] (http://blogs.msdn.com/b/tyler_whitney/archive/2005/11/28/497604.aspx) – LarsTech

ответ

6

Вместо этого вы можете использовать Mutex, что позволяет избежать незначительного ненадежного поиска окон (представьте, что вы переименовываете свою основную форму или открываете другую форму).

bool createdNew; 
Mutex m = new Mutex(true, "SomeNameHere", out createdNew); 

if (!createdNew) 
{ 
    // Application already running. Call it and ask to show it's form. 
    IpcClientChannel clientChannel = new IpcClientChannel(); 
    ChannelServices.RegisterChannel(clientChannel, true); 

    RemotingConfiguration.RegisterWellKnownClientType(typeof(ExchangeBase), "ipc://SomeNameHere/YourAppBase"); 

    ExchangeBase Exchange = new ExchangeBase(); 
    Exchange.ShowForm(); 
} 
else 
{ 
    IpcServerChannel serverChannel = new IpcServerChannel("SomeNameHere"); 
    ChannelServices.RegisterChannel(serverChannel, true); 
    RemotingConfiguration.RegisterWellKnownServiceType(typeof(ExchangeBase), "YourAppBase", WellKnownObjectMode.SingleCall); 

    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 

    MainForm = new FormMain(); 
    if (!MainForm.StopLoading) 
    { 
     Application.Run(MainForm); 

     // Keep the mutex reference alive until the termination of the program. 
     GC.KeepAlive(m); 
    } 
} 
2

Похоже, вы передаете Text в качестве параметра в свой метод FocusWindow, но при выполнении проверки Contains. Готов поспорить, что текст является лишь частичным заголовком окна и, таким образом, вызывает ошибку FindWindow. Попробуйте передавая полный текст оконной ручки вместо как:

var proc = Process.GetProcesses() 
        .Where(p => p.MainWindowTitle.Contains(Text)) 
        .FirstOrDefault(); 

     if (proc != null) 
     { 
      FocusWindow(p.MainWindowTitle); 
      Application.Exit(); 
     } 
1

Это, вероятно, вызвано тем же названием окон, поэтому FindWindow получить фактические окна ручки, попробуйте использовать EnumWindows функцию вместо FindWindow.

1

Выполнение этой проверки загрузки формы неверен. Вы должны использовать Mutex, чтобы убедиться, что работает только один экземпляр приложения. См. this article для примера о том, как это сделать, а также настройки фокуса на существующий экземпляр.

0

Поместите этот код в файле App.xaml.cs:

using System.Runtime.InteropServices; 

#region SetWindowPos Definitions 
[DllImport("user32.dll")] 
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, 
    int X, int Y, int cx, int cy, uint uFlags); 

static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); 
static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); 
static readonly IntPtr HWND_TOP = new IntPtr(0); 
static readonly IntPtr HWND_BOTTOM = new IntPtr(1); 

const UInt32 SWP_NOSIZE = 0x0001; 
const UInt32 SWP_NOMOVE = 0x0002; 
const UInt32 SWP_NOZORDER = 0x0004; 
const UInt32 SWP_NOREDRAW = 0x0008; 
const UInt32 SWP_NOACTIVATE = 0x0010; 
const UInt32 SWP_FRAMECHANGED = 0x0020; 
const UInt32 SWP_SHOWWINDOW = 0x0040; 
const UInt32 SWP_HIDEWINDOW = 0x0080; 
const UInt32 SWP_NOCOPYBITS = 0x0100; 
const UInt32 SWP_NOOWNERZORDER = 0x0200; 
const UInt32 SWP_NOSENDCHANGING = 0x0400; 
#endregion 
#region OnStartup 
protected override void OnStartup(StartupEventArgs e) 
{ 
    // Only allow one instance of the application 
    Process thisProc = Process.GetCurrentProcess(); 
    Process[] processes = Process.GetProcessesByName(thisProc.ProcessName); 
    if (processes.Length > 1) 
    { 
     Application.Current.Shutdown(); 

     SetWindowPos(processes[1].MainWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, 
      SWP_NOSIZE | SWP_NOMOVE); 
     SetWindowPos(processes[1].MainWindowHandle, HWND_NOTOPMOST, 0, 0, 0, 0, 
      SWP_NOSIZE | SWP_NOMOVE); 
    } 
    else 
    { 
     base.OnStartup(e); 
    } 
} 
#endregion 
Смежные вопросы