简体   繁体   English

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

[英]Call to TMouse.GetCursorPos sometimes fails with “A call to an OS function failed”

On occasion my application gets the error below. 有时我的应用程序会收到以下错误。

Normally this happens when the user steps away from their desk leaving my program open. 通常,当用户离开办公桌离开我的程序时会发生这种情况。 When they come back this error has appeared. 当他们回来时,出现了这个错误。

TMouse.GetCursorPostion does not do anything except make the Windows API call to GetCursorPosition. 除了对GetCursorPosition进行Windows API调用之外,TMouse.GetCursorPostion不执行任何操作。 Then it checks the return value and calls GetLastError if it failed. 然后它检查返回值并在失败时调用GetLastError。

"A call to an OS function failed" is not very helpful in tracking down the cause of this. “对OS功能的调用失败”对于追踪其原因并不是很有帮助。 Could a screen saver or sleep mode be kicking in causing this error? 屏幕保护程序或睡眠模式是否会导致此错误? I could modify the component to just catch and ignore the error, but if possible I would rather know what/why it is happening in the first place. 我可以修改组件以捕获并忽略错误,但如果可能的话,我宁愿知道它首先发生了什么/为什么。

My application is using Delphi 2007 and the call is being made from Transfer@Once (v 1.7) component by Quasidata. 我的应用程序使用的是Delphi 2007,并且Quasidata正在调用Transfer @ Once(v 1.7)组件。

Here is the call stack: 这是调用堆栈:

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

Here is the Timer procedure 这是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;

CursorPos uses the Windows GetCursorPos method. CursorPos使用Windows GetCursorPos方法。 The remarks on MSDN says it has two requirements: MSDN上的评论说它有两个要求:

  • "The calling process must have WINSTA_READATTRIBUTES access to the window station." “调用进程必须具有WINSTA_READATTRIBUTES访问窗口站的权限。”
  • "The input desktop must be the current desktop when you call GetCursorPos. Call OpenInputDesktop to determine whether the current desktop is the input desktop. If it is not, call SetThreadDesktop with the HDESK returned by OpenInputDesktop to switch to that desktop." “当您调用GetCursorPos时,输入桌面必须是当前桌面。调用OpenInputDesktop以确定当前桌面是否为输入桌面。如果不是,请使用OpenInputDesktop返回的HDESK调用SetThreadDesktop切换到该桌面。”

So, chances are that the screensaver is running on another desktop. 因此,屏幕保护程序可能正在另一个桌面上运行。 Alternately, if you're using Vista I'm pretty sure the password dialog (for unlocking a computer) runs on another desktop as well. 或者,如果您使用的是Vista,我非常确定密码对话框(用于解锁计算机)也可以在另一台桌面上运行。

Since you have the source for this component, you may want to write your own wrapper for CursorPos that returns a dummy value when there's a problem. 由于您拥有此组件的源代码,因此您可能希望为CursorPos编写自己的包装器,以便在出现问题时返回虚拟值。 (Edit: or a commenter suggested handling the failure to get a position inline instead of writing a function to return a dummy value.) (编辑:或评论者建议处理无法获取内联位置而不是编写函数以返回虚拟值。)

Finally, you can call GetLastError to see what the last Windows error was, after it's thrown the exception. 最后,您可以在抛出异常后调用GetLastError以查看上一次Windows错误。 That should tell you for sure what the actual problem it's encountering is. 这应该告诉你它确实遇到的实际问题是什么。 As in a comment (thanks!) you have already encountered the error message in the exception message. 在评论中(谢谢!),您已经在异常消息中遇到了错误消息。

Without seeing the code and which version of Windows, one can only guess. 没有看到代码和Windows的哪个版本,人们只能猜测。 I would look into the code of the TtaoHoverTimer.Timer procedure in unit taoCntrr. 我将在单元taoCntrr中查看TtaoHoverTimer.Timer过程的代码。

Try calling the GetCursorPos(cursorPos); 尝试调用GetCursorPos(cursorPos); method in the Windows unit. Windows单元中的方法。

Something like this: 像这样的东西:

var
   cursorPos       : TPoint;

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

It works with no problem on all my applications. 它在我的所有应用程序上都没有问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM