Проблема Sendkeys из программы .NET

Код ниже я скопировал из MSDN с небольшой модификацией:

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
DllImport("User32")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
int cnt = 0;
private void button1_Click(object sender, EventArgs e)
{
     IntPtr calculatorHandle = FindWindow("Notepad", "Untitled - Notepad");
      if (calculatorHandle == IntPtr.Zero)
      {
          MessageBox.Show("Calculator is not running.");
          return;
      }
      SetForegroundWindow(calculatorHandle);
      SendKeys.SendWait(cnt.ToString());
      SendKeys.SendWait("{ENTER}");
      cnt++;
      SendKeys.Flush();
      System.Threading.Thread.Sleep(1000);
}

Проблема в том, что последовательность чисел в Блокноте не является непрерывной. Первый щелчок всегда приводит к 0 (как и ожидалось). но со второго клика результат непредсказуем (но последовательность все равно в порядке, например 3, 4, 5, 10, 14, 15, ....)

Если я нажму кнопку достаточно быстро, я смогу получить результат в непрерывном порядке (0,1,2,3,4,....), но иногда он выдает более двух одинаковых чисел (например, 0,1,2 ,3,3,3,4,5,6,6,6,7,8,9,...)


person user397232    schedule 09.04.2010    source источник
comment
Удалите вызов Sleep(), я не могу сделать так, чтобы он не исчез.   -  person Hans Passant    schedule 09.04.2010


Ответы (2)


SetForegroundWindow не будет ждать, пока указанное окно действительно окажется на переднем плане. Он просто «запускает» процесс. Так что вполне возможно, что ваш SendKeys.SendWait не отправляет ключ в окно, которое вы ожидаете.

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

person Dean Harding    schedule 09.04.2010
comment
Вы и SLaks правы с SetForegroundWindow(). Если я перемещу Sleep() сразу после SetForegroundWindow(), все будет хорошо. Что касается Sleep() и пользовательского интерфейса, если я удалю sleep() после SetForegroundWindow(), как это сделать правильно? - person user397232; 09.04.2010
comment
Лучший способ сделать это, я думаю, будет в фоновом потоке. Поставьте операцию в очередь на BackgroundWorker, который выполняет обработку в другом потоке. Таким образом, вы можете выполнять все Sleep() и все, что вам нужно, и это никогда не связывает поток пользовательского интерфейса. Вам просто нужно немного дополнительной логики в обработчике кликов, чтобы он не пытался запустить новый запрос, пока предыдущий не завершится. - person Dean Harding; 09.04.2010

Первая проблема возникает из-за того, что SetForegroundWindow может вернуться до переключения фокуса, поэтому Sendkeys может работать, когда блокнот не активен.

person SLaks    schedule 09.04.2010