调用TMouse.GetCursorPos有时会因“调用OS函数失败”而失败

时间:2009-06-11 21:15:45

标签: delphi winapi mouse

有时我的应用程序会收到以下错误。

通常,当用户离开办公桌离开我的程序时会发生这种情况。当他们回来时,出现了这个错误。

除了对GetCursorPosition进行Windows API调用之外,TMouse.GetCursorPostion不执行任何操作。然后它检查返回值并在失败时调用GetLastError。

“对OS功能的调用失败”对于追踪其原因并不是很有帮助。屏幕保护程序或睡眠模式是否会导致此错误?我可以修改组件以捕获并忽略错误,但如果可能的话,我宁愿知道它首先发生了什么/为什么。

我的应用程序正在使用Delphi 2007,而Quasidata正在调用Transfer @ Once(v 1.7)组件。

这是调用堆栈:

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

这是Timer程序


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 个答案:

答案 0 :(得分:13)

CursorPos使用Windows GetCursorPos方法。关于MSDN的评论说它有两个要求:

  • “调用进程必须具有WINSTA_READATTRIBUTES访问窗口站的权限。”
  • “当您调用GetCursorPos时,输入桌面必须是当前桌面。调用OpenInputDesktop以确定当前桌面是否为输入桌面。如果不是,请使用OpenInputDesktop返回的HDESK调用SetThreadDesktop切换到该桌面。”

因此,屏幕保护程序可能正在另一个桌面上运行。或者,如果您使用的是Vista,我很确定密码对话框(用于解锁计算机)也可以在另一台桌面上运行。

由于您拥有此组件的源代码,因此您可能希望为CursorPos编写自己的包装器,以便在出现问题时返回虚拟值。 (编辑:或评论者建议处理无法获取内联位置而不是编写函数以返回虚拟值。)

最后,在抛出异常后,可以调用GetLastError来查看上一次Windows错误是什么。这应该告诉你它确实遇到的实际问题是什么。在评论中(谢谢!)你已经在异常消息中遇到了错误消息。

答案 1 :(得分:-1)

没有看到代码和哪个版本的Windows,人们只能猜测。 我将在单元taoCntrr中查看TtaoHoverTimer.Timer过程的代码。

答案 2 :(得分:-1)

尝试在 Windows 单元中调用 GetCursorPos(cursorPos); 方法。

这样的事情:

var
   cursorPos       : TPoint;

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

它对我的所有应用程序都没有问题。