无法获得 window 句柄?

Can't get a window handle?

我到处搜索试图找到解决我的困境的答案,但似乎找不到有效的答案。我正在尝试使用 Xlib 编写一些等效的 user32.dll 代码,以便我可以支持 Linux 用户。我当然是 运行 Linux,所以我使用的是 Mono。当我什至无法从进程 class 中获取 window 句柄时,问题就出现了,因为它甚至从未实现过:

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

(Source)

这尤其令人沮丧,因为似乎别无选择。我正在尝试像这样获取 window 句柄:

[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。将 "myPid" 替换为有效的进程 ID。是的,我确实确保替换的 "myPid" 是一个有效的进程 ID,并且我的代码没有抛出任何错误,表明我使用的任何进程 ID 都是无效的。

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

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

这显然是因为 Process.MainWindowHandle returns IntPtr.Zero。没有其他方法可以获得 window 句柄吗?提前致谢!

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

在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中:

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)所以我对自己使用互操作实现功能犹豫不决。如果你最终像我一样更多地使用 Xlib,那么考虑使用 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