GetWindowRect 在一个应用程序上返回错误值,所有其他应用程序都是正确的

Posted

技术标签:

【中文标题】GetWindowRect 在一个应用程序上返回错误值,所有其他应用程序都是正确的【英文标题】:GetWindowRect returns wrong values on one application, all other applications are correct 【发布时间】:2012-05-10 00:45:26 【问题描述】:

我正在使用 Windows API 中的 GetWindowRect 来获取正在运行的应用程序的边界,然后我使用这些边界来截取应用程序。

我的代码适用于我测试过的大约 10 个程序,notepad.exe 和其他一些程序,但是我想将它与 RocLink800 一起使用的一个应用程序返回不正确的静态值,无论应用程序的位置如何。

代码是 C# .NET

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    
        public int X;
        public int Y;
        public int Width;
        public int Height;
    

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool GetWindowRect(IntPtr hWnd, ref RECT Rect);

    IntPtr error = GetWindowRect(proc.MainWindowHandle, ref rect);

    ... main code
    while (error == (IntPtr)0)
    
        error = GetWindowRect(proc.MainWindowHandle, ref rect);
    

    int width = rect.right - rect.left;
    int height = rect.bottom - rect.top;

现在所有应用程序都返回正确的宽度和高度,使用 roclink800 它返回错误值 1 表示成功,但无论应用程序位置如何,它都会返回以下值:

rect.right = 960 rect.left = 960 rect.bottom = 600 rect.top = 600

我完全不知道为什么会发生这种情况或如何纠正它,roclink800 是从 windows95 天移植的旧程序,所以它可能使用了一些奇怪的 api,如果是这种情况,是否有任何来自 windows API 的替代方案( user32.dll) 来获取它的屏幕坐标?

我想我可以强制应用程序全屏并以这种方式截屏,但它不太优雅。

有什么想法吗?

编辑:我获取句柄的代码

        Process roclink = new Process();
        roclink.StartInfo.FileName = "C:/Program Files (x86)/ROCLINK800/Roclink.exe";
        //roclink.StartInfo.FileName = "notepad.exe";
        roclink.Start();
        IntPtr error = GetWindowRect(roclink.MainWindowHandle, ref rect);

        try
        
            proc = Process.GetProcessesByName("roclink")[0];
        
        catch (IndexOutOfRangeException e)
        
            return null;
        

两个代码块都返回相同的 IntPtr 并且它们都返回 960,960,600,600 但是如果我调用

int error = SetWindowPos(roclink.MainWindowHandle, HWND_TOPMOST, 0, 0, 25,50, SWP_SHOWWINDOW);

然后我得到返回的坐标是 0,0,25,50 但应用程序大小没有改变。

我试过破解程序,关闭 roclink 和 SetWindowPos 和 GetWindowRect 都返回 0 并且不返回 false 值,表明句柄确实是正确的句柄。

所以看来这个应用程序无法设置或通过 windowsAPI 获取它的窗口大小,有人知道为什么会这样吗?

roclink.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;

这也被忽略,应用程序不会全屏打开,只是它上次打开时的大小。

编辑:我能想到的唯一解决方案是复制 roclink.exe 并手动全屏打开它然后关闭它,如果没有其他人打开此文件,它将始终全屏打开,这是狡猾的我不喜欢它,但除非有人知道为什么会这样,否则我可能不得不这样做。 :(

【问题讨论】:

【参考方案1】:

我认为对于您的应用程序,MainWindowHandle 显然不是应用程序启动的实际“主窗口”。

【讨论】:

哇,这真的很简单,由于某种原因,当我通过“roclink”获取句柄时,我得到一个非零值,这让我认为它成功获取了句柄,如果我把乱码放进去返回一个空值,但不是“roclink”,多么奇怪,我通过一个进程启动了应用程序并使用 process.MainWindowHandle 现在它运行成功。谢谢! 好的,现在它随机工作并且随机不交替提供正确的坐标,然后再次提供 960,960,600,600。任何人都知道为什么我的手柄会给出正确的坐标 1/10 次,然后其余时间都是这些垃圾? 更奇怪的是,如果我发送 SetWindowPos(roclink.MainWindowHandle, HWND_TOPMOST, 0, 0, 25,50, SWP_SHOWWINDOW);然后它返回 0,0,25,50 的坐标,但应用程序实际上并没有改变它的坐标。也许这说明它是错误的句柄,也许更好的问题是它为什么返回错误的句柄?我将使用句柄获取代码来更新我的问题。 我的建议是 .MainWindowHandle 属性不是您要获取的实际窗口。使用 SPY++ 将您正在检查的句柄与窗口的实际句柄进行比较。 你是对的,它是表单中某些属性的句柄,我将如何以编程方式获取这个正确的句柄?【参考方案2】:

看这个 RockLink800 应用程序的截图,似乎这是一个 Delphi 应用程序,旧版本的 Delphi 有一个隐藏窗口,即 Application.Handle。

这是一个 SO 回答如何为旧的 Delphi 应用程序获取主窗口句柄:

Retrieving Delphi Window Handles

【讨论】:

谢谢,这解释了为什么我找不到窗口句柄,我使用 Rotems 的建议来找到正确的句柄。

以上是关于GetWindowRect 在一个应用程序上返回错误值,所有其他应用程序都是正确的的主要内容,如果未能解决你的问题,请参考以下文章

C++ MFC - 在 CDialog::OnSize 事件 (GetWindowRect) 上没有引发运行时错误的代码执行失败

从外部窗口的 GetWindowRect 获取 DPI 感知正确的 RECT

为啥他们在 GetWindowRect 函数中使用它

各位高手,小弟请教关于GetWindowRect,GetClientRect以及ClientToScreen,ScreenToClient的使用!先谢谢啦

Linux 的 PInvoke GetWindowRect 等效项

Windows 7 上的 GetWindowRect 太小