2015-06-24 5 views
5

Я создаю переключатель kill в своем приложении, так что только один экземпляр может запускаться одновременно на одном компьютере. Я выполнение этого пути размещения сообщений между процессом запущенного приложения и процессом нового экземпляра приложения:PInvoke PostMessage не работает через учетные записи пользователей

[DllImport("user32.dll", EntryPoint = "PostMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] 
private static extern int PostMessage(int hwnd, int wMsg, int wParam, int lParam); 

Я не могу использовать process.kill, потому что если другой пользователь запускает приложение и у текущего пользователя нет достаточных привилегий, я получаю проблемы.

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

Вот моя логика для подписки на сообщения окна:

var wih = new WindowInteropHelper(this); 
var hwndSource = HwndSource.FromHwnd(wih.Handle); 
var hwndSourceHook = new HwndSourceHook(HookHandler); 

if (hwndSource != null) 
    hwndSource.AddHook(hwndSourceHook); 

А вот мой крючок обработчик:

private IntPtr HookHandler(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 
    { 
     handled = false; 

     switch (msg) 
     { 
      case 0x400: // interprocess message received 
       App.InterprocessManager.BuildString(lParam); 
       break; 
     } 
     return IntPtr.Zero; 
    } 

Вот логика, чтобы отправить сообщение:

private void SendString() 
    { 
     //create byte array 
     byte[] ba = null; 
     //encode string to byte array 
     if (object.ReferenceEquals(enc, Encoding.UTF8)) 
     { 
      ba = Encoding.UTF8.GetBytes(lParam); 
     } 
     else if (object.ReferenceEquals(enc, Encoding.Unicode)) 
     { 
      ba = Encoding.Unicode.GetBytes(lParam); 
     } 
     else if (object.ReferenceEquals(enc, Encoding.ASCII)) 
     { 
      ba = Encoding.ASCII.GetBytes(lParam); 
     } 
     else 
     { 
      ba = Encoding.Default.GetBytes(lParam); 
     } 
     int i = 0; 
     for (i = 0; i <= ba.Length - 1; i++) 
     { 
      //start post message 
      PostMessage(hwnd, wMsg, wParam, ba[i]); 
     } 
     //post a terminator message to destination window 
     PostMessage(hwnd, wMsg, wParam, 0); 
    } 

Нет Win32 ошибки устанавливаются функцией PostMessage. Я не могу найти какую-либо документацию, связанную с отправкой сообщений между процессами через учетные записи пользователей. Это то, что на самом деле нельзя сделать?

+4

Другой пользователь запускает программу на своем собственном сеансе с собственной кучей рабочего стола. Шансы, что вы используете правильный дескриптор окна, довольно низки, учитывая, что вы не можете найти его на своем сеансе. Продвигайтесь общим путем, используя именованный мьютекс.Префикс его имени 'Global \ ', чтобы он отображался в разных сеансах. И имейте в виду, что пользователь будет совершенно непонятен, почему он не может запустить программу и не знает, как это исправить. Учитывая, насколько это враждебно, безусловно, лучше вообще не делать этого. –

+0

Я извлекаю дескриптор с Process.MainWindowHandle, поэтому я не уверен, почему мы не получим правильный дескриптор, если система просто не установит произвольный дескриптор в этой точке. Я уже использую мьютекс, чтобы определить, работает ли другой экземпляр, однако сценарий, с которым мы работаем, - это программа запуска User A, система блокировки пользователя A, пользовательский знак B, пытается запустить программу. В этом сценарии мы хотим, чтобы User B мог работать, поэтому нам нужно завершить программу в сеансе User A. Убийство программы не является идеальным, однако мы используем протоколы связи, которые могут использоваться только по одному. – flamebaud

+2

Этот дескриптор можно использовать в сеансе, который его создал, ваше сообщение PostMessage() никуда не отправляется. –

ответ

1

Вы не можете отправлять сообщения окна процессу в другой сеанс. Вы должны использовать механизм IPC, основанный на ядре, а не на объектах пользователя.

В вашем сценарии один из названных мьютексов и один семафор, вероятно, все, что вам нужно. Обратите внимание, что имена должны иметь префикс Global\, чтобы позволить нескольким сеансам совместно использовать один объект.

При запуске процесса сначала создайте или откройте семафор. Установите начальное значение в ноль.

Затем создайте именованный мьютекс с bInitialOwner, установленным на TRUE, и проверьте последний код ошибки, чтобы узнать, существует ли уже мьютекс.

Если мьютекс еще не существует, вы являетесь первым экземпляром, поэтому создайте поток для ожидания на семафоре. Если семафор сигнализирован, выйдите из процесса. Убедитесь, что вы не отпустите мьютекс, пока он не станет безопасным для запуска другого процесса; если вы сомневаетесь, не выпускайте его вообще. Windows выведет ее как покинутую после выхода процесса.

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

Если вам нужен более сложный канал связи между процессами, например, если вам нужно передать текущее состояние канала связи, то лучшим выбором является, вероятно, named pipes.

Смежные вопросы