无法获得窗把手? [英] Can't get a window handle?

查看:106
本文介绍了无法获得窗把手?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经四处搜寻,以寻找解决自己困境的答案,但似乎找不到有效的答案.我正尝试用Xlib编写一些等效的user32.dll代码,以便可以支持Linux用户.我当然正在运行Linux,所以我正在使用Mono.当我什至无法从Process类中获取窗口句柄时,问题就来了,因为它从未实现过:

I've searched all over to try and find an answer to my predicament but cannot seem to find a valid answer. I'm trying to write some equivalent user32.dll code with Xlib instead so I can support Linux users. I'm of course running Linux, so I'm using Mono. Problem comes along when I cannot even grab a window handle from the Process class because it was never even implemented:

[MonoTODO]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The handle of the main window of the process.")]
public IntPtr MainWindowHandle {
    get {
        return((IntPtr)0);
    }
}

(来源)

这尤其令人沮丧,因为似乎没有其他选择.我试图像这样抓住窗户把手:

This is especially frustrating because there is seemingly no alternative. I'm trying to grab a window handle like so:

[DllImport("libX11")]
private static extern IntPtr XOpenDisplay(IntPtr display);

[DllImport("libX11")]
private static extern int XRaiseWindow(IntPtr display, IntPtr window);

private IntPtr ApplicationHandle;
private IntPtr Display;

private void TestXlib() {
    Process process = Process.GetProcessById(myPid);

    ApplicationHandle = process.MainWindowHandle;

    Display = XOpenDisplay(IntPtr.Zero);

    XRaiseWindow(Display, ApplicationHandle);
}

注意:代替"myPid"的是正确的进程ID.用有效的进程ID替换"myPid".是的,我确实确保替换的"myPid"是有效的进程ID,并且我的代码没有抛出任何错误,表明我使用的任何无效的进程ID.

NOTE: In place of "myPid" is a proper process ID. Replace "myPid" with a valid process ID. Yes, I did make sure the replaced "myPid" was a valid process ID and my code didn't throw any errors indicating any process IDs I used as invalid.

这不会使我的应用程序崩溃,但是几乎每次我调用XRaiseWindow时,它都会打印:

This doesn't crash my application, but almost every time I call XRaiseWindow it prints:

X11 Error encountered: 
  Error: BadWindow (invalid Window parameter)
  Request:     12 (0)
  Resource ID: 0x0
  Serial:      121
  Hwnd:        <null>
  Control:     <null>

这显然是因为Process.MainWindowHandle返回IntPtr.Zero.有没有其他方法可以获取窗口句柄?预先感谢!

This obviously occurs because Process.MainWindowHandle returns IntPtr.Zero. Is there no other way to get a window handle? Thanks in advance!

推荐答案

是的,我知道这是很久以前我才问过的,但是我现在正在回答,因为我自己找到解决方案后就一直忘记回答.我最初使用@SushiHangover的解决方案,但并不真正喜欢它,因为我觉得依赖外部程序(xwininfo)是一个修补程序,最终只是添加了另一个依赖项.希望这对使用Mono的其他C#开发人员有所帮助.该代码最初是为.NET Framework 2.0编写的.这不是花哨的,并且没有得到很好的记录.我的解决方案是使用Xlib本机枚举窗口,并返回所有窗口,这些窗口的标题与所描述的标题匹配.

Yes, I know this was forever ago that I asked this, but I'm answering it now because I kept forgetting to answer it after I found the solution myself. I originally used @SushiHangover's solution but didn't really like it because I felt relying on an external program(xwininfo) was a hotfix and ultimately just added another dependency. Hopefully this helps other C# developers using Mono. This code was originally written for .NET Framework 2.0. It's not fancy and isn't really documented well. My solution was just to natively enumerate the windows using Xlib myself and return all windows whose title's match the described title.

在X11Wrapper.cs中:

In X11Wrapper.cs:

using System;
using System.Runtime.InteropServices;

namespace Program.PInvoke.Xlib {

    public static class X11Wrapper {

        public const string SOName = "libX11.so";

        [DllImport(SOName)]
        // See: https://tronche.com/gui/x/xlib/display/display-macros.html#DefaultRootWindow
        public static extern IntPtr XDefaultRootWindow(IntPtr display);

        [DllImport(SOName)]
        // See: https://tronche.com/gui/x/xlib/window-information/XQueryTree.html
        public static extern int XQueryTree(IntPtr display, IntPtr w,
                                            out IntPtr root_return, out IntPtr parent_return,
                                            out IntPtr[] children_return, out int nchildren_return);

        [DllImport(SOName)]
        // See: https://tronche.com/gui/x/xlib/ICC/client-to-window-manager/XFetchName.html
        public static extern int XFetchName(IntPtr display, IntPtr w,
                                            out string window_name_return);
    }
}

在Linux.Utilities.cs中:

In Linux.Utilities.cs:

using Program.PInvoke.Xlib;

namespace Program {

    public static partial class Utilities {

        public static bool IsUnix {
            get {
                return Environment.OSVersion.
                       Platform == PlatformID.Unix;
            }
        }

        private static IntPtr[] FindChildWindows(IntPtr display, IntPtr window,
                                                 string title, ref List<IntPtr> windows) {
            IntPtr rootWindow;
            IntPtr parentWindow;

            IntPtr[] childWindows = new IntPtr[0];

            int childWindowsLength;

            X11Wrapper.XQueryTree(display, window,
                                  out rootWindow, out parentWindow,
                                  out childWindows, out childWindowsLength);

            childWindows = new IntPtr[childWindowsLength];

            X11Wrapper.XQueryTree(display, window,
                                  out rootWindow, out parentWindow,
                                  out childWindows, out childWindowsLength);

            string windowFetchedTitle;

            X11Wrapper.XFetchName(display, window, out windowFetchedTitle);

            if(title == windowFetchedTitle &&
               !windows.Contains(window)) {
                windows.Add(window);
            }

            for(int childWindowsIndexer = 0;
                childWindowsIndexer < childWindows.Length;
                childWindowsIndexer++) {
                IntPtr childWindow = childWindows[childWindowsIndexer];

                string childWindowFetchedTitle;

                X11Wrapper.XFetchName(display, childWindow,
                                      out childWindowFetchedTitle);

                if(title == childWindowFetchedTitle &&
                   !windows.Contains(childWindow)) {
                    windows.Add(childWindow);
                }

                FindChildWindows(display, childWindow, title, ref windows);
            }

            windows.TrimExcess();

            return windows.ToArray();
        }

        public static IntPtr[] FindWindows(IntPtr display, string title) {
            List<IntPtr> windows = new List<IntPtr>();

            return FindChildWindows(display,
                                    X11Wrapper.XDefaultRootWindow(display),
                                    title,
                                    ref windows);
        }
    }
}

脚注:我最初说自己不是C开发人员(此后情况发生了变化,并且我已经学习了C),所以我很犹豫自己使用interop来实现该功能.如果您确实像我一样使用Xlib,那么可以考虑使用 tronche 作为Xlib API参考.它在C语言中,但我发现在C#中将其转换为PInvokable函数和可沼泽结构非常容易.也有一些注意事项也要考虑在内.另一个有助于翻译的好资源是直接使用源代码来查找低级类型的定义,以帮助查找C#等效项.这样的事情将极大地帮助您:

Footnote: I initially stated I wasn't a C developer(Things have changed since then and I've learned C) so I was hesitant to implement the functionality myself using interop. If you do end up using Xlib a lot more like I did then consider using tronche as an Xlib API reference. It is in C but I found it was pretty easy to translate to PInvokable functions and marshable structs in C#. Has some good notes to take into account too. Another good resource to help translation is directly using the source to find the definitions of the low level types to help find C# equivalents. Something like this should greatly aid you: http://refspecs.linuxbase.org/LSB_4.0.0/LSB-Desktop-generic/LSB-Desktop-generic/libx11-ddefs.html

这篇关于无法获得窗把手?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆