Как мне получить экземпляр System.Windows.Form из его дескриптора Win32? - PullRequest
5 голосов
/ 24 февраля 2009

Следующий код реализует простой синглтон, который обеспечивает запуск только 1 экземпляра моего приложения. Однако, если запущен другой экземпляр, мне нужно иметь возможность получить аргументы командной строки этого экземпляра, передать их начальному экземпляру, а затем завершить второй экземпляр.

Проблема возникает, когда я пытаюсь заполучить первый экземпляр приложения. Как только я нашел дескриптор главной формы этого экземпляра, я передаю его методу Control.FromHandle(), ожидая получить MainForm. Вместо этого возвращаемое значение всегда null. (Control.FromChildHandle() дает тот же результат.)

Поэтому мой вопрос прост: что я делаю не так? И возможно ли это даже в .NET?

public class MainForm : Form
{
[DllImport("user32")]
extern static int ShowWindowAsync(IntPtr hWnd, int nCmdShow);

[DllImport("user32")]
extern static bool SetForegroundWindow(IntPtr hWnd);

private Mutex singletonMutex;

private void MainForm_Load(object sender, EventArgs e)
{
  bool wasCreated;
  singletonMutex = new Mutex(false, Application.ProductName + "Mutex", out wasCreated);

  // returns false for every instance except the first
  if (!wasCreated)
  {
    Process thisProcess = Process.GetCurrentProcess();
    Process[] peerProcesses = Process.GetProcessesByName(thisProcess.ProcessName.Replace(".vshost", string.Empty));

    foreach (Process currentProcess in peerProcesses)
    {
      if (currentProcess.Handle != thisProcess.Handle)
      {
        ShowWindowAsync(currentProcess.MainWindowHandle, 1); // SW_NORMAL
        SetForegroundWindow(currentProcess.MainWindowHandle);

        // always returns null !!!
        MainForm runningForm = (MainForm) Control.FromHandle(currentProcess.MainWindowHandle);

        if (runningForm != null)
        {
          runningForm.Arguments = this.Arguments;
          runningForm.ProcessArguments();
        }

        break;
      }
    }

    Application.Exit();

    return;
  }
}

Ответы [ 6 ]

4 голосов
/ 24 февраля 2009

Приложения с одним экземпляром хорошо поддерживаются .NET Framework. Проверьте этот поток на пример, который делает именно то, что вам нужно.

3 голосов
/ 24 февраля 2009

Control.FromHandle не будет работать, потому что искомый элемент управления находится в другом процессе (и, следовательно, в другом домене приложения).

У вас уже есть WindowHandle, но его использование ограничено Win32 API. Ничто из WinForms не будет работать.

Вы можете отправлять (WM_) сообщения, но трудно передать данные.

Опции

  1. использовать что-то низкоуровневое с Темп-файл.

  2. использовать удаленное взаимодействие (WCF)

2 голосов
/ 24 февраля 2009

Вы действительно пытаетесь реализовать одноэлементное приложение. В Интернете есть несколько примеров (извините, я на самом деле не пробовал), например

http://www.codeproject.com/KB/cs/SingletonApplication.aspx

http://www.nathanm.com/csharp-wpf-singleton-application/

2 голосов
/ 24 февраля 2009

Попробуйте следующее

var form = (Form)(Control.FromHandle(myHandle));

EDIT

Перечитал ваш вопрос и понял, что вы смотрите на ручку в другом процессе. Невозможно преобразовать дескриптор в другом процессе в экземпляр Form в текущем процессе. Мое решение будет работать только для ручек в том же процессе.

Единственный способ получить доступ к экземпляру Form - использовать Remoting. Но это потребует сотрудничества со стороны обоих процессов, который, кажется, не является тем, что вы ищете.

0 голосов
/ 25 февраля 2009

Я использую библиотеку Microsoft.VisualBasic.dll, описанную в теме, на которую указал nobugz. Да, вы можете использовать его в C #. Вы просто переопределяете OnStartupNextInstance и передаете командную строку в программу любым удобным для вас способом.

Это намного проще, чем возиться с потоками вручную.

0 голосов
/ 24 февраля 2009

Вы не можете напрямую вызывать код в другом процессе, вам нужно использовать какую-то форму межпроцессного взаимодействия

Если вы общаетесь только между процессами, запущенными одним и тем же пользователем на одном компьютере, вы можете использовать оконные сообщения (используя WinAPI PostMessage и переопределяя WndProc), в противном случае я думаю, что удаленное взаимодействие проще всего использовать в .net

...