Вызов TMouse.GetCursorPos иногда завершается с ошибкой "Сбой вызова функции ОС"
Иногда моя заявка получает ошибку ниже.
Обычно это происходит, когда пользователь отходит от своего рабочего стола, оставляя мою программу открытой. Когда они возвращаются, эта ошибка появилась.
TMouse.GetCursorPostion не делает ничего, кроме вызова API-интерфейса Windows для GetCursorPosition. Затем он проверяет возвращаемое значение и вызывает GetLastError, если это не удалось.
"Ошибка вызова функции ОС" не очень помогает выявлять причину этого. Может ли вызывать эту ошибку экранную заставку или спящий режим? Я мог бы изменить компонент так, чтобы он просто перехватывал и игнорировал ошибку, но, если это возможно, я бы предпочел знать, что / почему это происходит в первую очередь.
Мое приложение использует Delphi 2007, и вызов выполняется из компонента Transfer@Once (v 1.7) Quasidata.
Вот стек вызовов:
операционная система: Windows XP с пакетом обновления 3, сборка 2600 номер исключения: 1 класс исключения: EOSError сообщение об исключении: сбой вызова функции ОС. основная тема ($d34): 0045e208 UaarSales.exe SysUtils RaiseLastOSError 0045e191 UaarSales.exe SysUtils RaiseLastOSError 0045e237 UaarSales.exe SysUtils Win32Check 004c6de9 UaarSales.exe контролирует TMouse.GetCursorPos 00736d8b UaarSales.exe taoCntrr 3999 TtaoHoverTimer.Timer 004a1d27 UaarSales.exe ExtCtrls TTimer.WndProc 0047a7a0 UaarSales.exe Классы StdWndProc 7e4196c2 USER32.dll DispatchMessageA 004da230 UaarSales.exe Формы TApplication.ProcessMessage 004da26a UaarSales.exe Формы TApplication.HandleMessage 004da55f UaarSales.exe Формы TApplication.Run 00b3ea76 UaarSales.exe UaarSales 117 инициализация
Вот процедура таймера
procedure TtaoHoverTimer.Timer;
var
lPos: TPoint;
begin
lPos := Mouse.CursorPos; // this is line 3999
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 ответа
CursorPos использует метод Windows GetCursorPos. Замечания в MSDN говорят, что у него есть два требования:
- "Вызывающий процесс должен иметь доступ WINSTA_READATTRIBUTES к оконной станции".
- "Рабочий стол ввода должен быть текущим рабочим столом при вызове GetCursorPos. Вызовите OpenInputDesktop, чтобы определить, является ли текущий рабочий стол входным рабочим столом. Если это не так, вызовите SetThreadDesktop с HDESK, возвращаемым OpenInputDesktop, чтобы переключиться на этот рабочий стол".
Таким образом, есть вероятность, что заставка работает на другом рабочем столе. С другой стороны, если вы используете Vista, я уверен, что диалоговое окно ввода пароля (для разблокировки компьютера) работает и на другом рабочем столе.
Поскольку у вас есть источник для этого компонента, вы можете написать свою собственную обертку для CursorPos, которая возвращает фиктивное значение при возникновении проблемы. (Правка: или комментатор предложил обработать ошибку, чтобы получить позицию в строке, вместо того, чтобы написать функцию для возврата фиктивного значения.)
Наконец, вы можете вызвать GetLastError, чтобы увидеть, какой была последняя ошибка Windows, после того, как было сгенерировано исключение. Это должно сказать вам наверняка, какова реальная проблема, с которой он сталкивается. Как и в комментарии (спасибо!), Вы уже столкнулись с сообщением об ошибке в сообщении об исключении.
Попробуйте вызвать GetCursorPos(cursorPos); метод в модуле Windows.
Что-то вроде этого:
var
cursorPos : TPoint;
begin
GetCursorPos(cursorPos);
cursorPos := ScreenToClient(cursorPos);
Работает без проблем во всех моих приложениях.
Не видя код и какую версию Windows, можно только догадываться. Я бы посмотрел код процедуры TtaoHoverTimer.Timer в модуле taoCntrr.