Вызов TMouse.GetCursorPos иногда завершается с ошибкой «Сбой вызова функции ОС» - PullRequest
5 голосов
/ 12 июня 2009

Иногда мое приложение получает ошибку ниже.

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

TMouse.GetCursorPostion не делает ничего, кроме вызова API-интерфейса Windows для GetCursorPosition. Затем он проверяет возвращаемое значение и вызывает GetLastError, если это не удалось.

«Сбой вызова функции ОС» не очень помогает отследить причину этого. Может ли вызывать эту ошибку экранную заставку или спящий режим? Я мог бы изменить компонент так, чтобы он просто перехватывал и игнорировал ошибку, но, если это возможно, я бы предпочел знать, что / почему это происходит в первую очередь.

Мое приложение использует Delphi 2007, и вызов выполняется из компонента Transfer @ Once (v 1.7) Quasidata.

Вот стек вызовов:

operating system  : Windows XP Service Pack 3 build 2600
exception number  : 1
exception class   : EOSError
exception message : A call to an OS function failed.

main thread ($d34):
0045e208 UaarSales.exe SysUtils       RaiseLastOSError
0045e191 UaarSales.exe SysUtils       RaiseLastOSError
0045e237 UaarSales.exe SysUtils       Win32Check
004c6de9 UaarSales.exe Controls       TMouse.GetCursorPos
00736d8b UaarSales.exe taoCntrr  3999 TtaoHoverTimer.Timer
004a1d27 UaarSales.exe ExtCtrls       TTimer.WndProc
0047a7a0 UaarSales.exe Classes        StdWndProc
7e4196c2 USER32.dll                   DispatchMessageA
004da230 UaarSales.exe Forms          TApplication.ProcessMessage
004da26a UaarSales.exe Forms          TApplication.HandleMessage
004da55f UaarSales.exe Forms          TApplication.Run
00b3ea76 UaarSales.exe UaarSales  117 initialization

Вот процедура таймера


procedure TtaoHoverTimer.Timer;
var
  lPos: TPoint;
begin
  lPos := Mouse.CursorPos;  <b> // this is line 3999 </b>
  if (lPos.X = FMousePos.X) and (lPos.Y = FMousePos.Y) and
    not ((lPos.X = FOutdatedPos.X) and (lPos.Y = FOutdatedPos.Y)) then
  begin
    inherited Timer;
    FOutdatedPos := Point(MaxInt, MaxInt);
  end;
  Enabled := False;
end;

Ответы [ 3 ]

13 голосов
/ 12 июня 2009

CursorPos использует метод Windows GetCursorPos. Замечания по MSDN говорят, что у него есть два требования:

  • "Вызывающий процесс должен иметь доступ WINSTA_READATTRIBUTES к оконной станции."
  • «Рабочий стол ввода должен быть текущим рабочим столом при вызове GetCursorPos. Вызовите OpenInputDesktop, чтобы определить, является ли текущий рабочий стол входным рабочим столом. Если это не так, вызовите SetThreadDesktop с HDESK, возвращаемым OpenInputDesktop, чтобы переключиться на этот рабочий стол».

Таким образом, есть вероятность, что заставка работает на другом рабочем столе. С другой стороны, если вы используете Vista, я почти уверен, что диалоговое окно ввода пароля (для разблокировки компьютера) работает и на другом рабочем столе.

Поскольку у вас есть источник для этого компонента, вы можете написать свою собственную обертку для CursorPos, которая возвращает фиктивное значение в случае возникновения проблемы. (Правка: или комментатор предложил обработать ошибку для получения встроенной позиции вместо написания функции для возврата фиктивного значения.)

Наконец, вы можете вызвать GetLastError, чтобы увидеть, какой была последняя ошибка Windows, после того как было сгенерировано исключение. Это должно точно сказать вам, что является реальной проблемой, с которой он сталкивается. Как и в комментарии (спасибо!), Вы уже столкнулись с сообщением об ошибке в сообщении об исключении.

0 голосов
/ 16 июня 2009

Попробуйте вызвать метод GetCursorPos (cursorPos); в Windows .

Примерно так:

var
   cursorPos       : TPoint;

begin
     GetCursorPos(cursorPos);
     cursorPos := ScreenToClient(cursorPos);

Работает без проблем во всех моих приложениях.

0 голосов
/ 12 июня 2009

Не видя код и какую версию Windows, остается только догадываться. Я бы посмотрел код процедуры TtaoHoverTimer.Timer в модуле taoCntrr.

...