无法获得窗口句柄?

时间:2017-02-24 22:03:13

标签: c# linux mono xlib

我已经搜遍了所有人,试图找到我的困境的答案,但似乎无法找到有效的答案。我试图用Xlib编写一些等效的user32.dll代码,以便我可以支持Linux用户。我当然在运行Linux,所以我使用的是Mono。当我甚至无法从Process类中获取窗口句柄时出现问题,因为它甚至从未实现过:

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

Source

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

[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。是的,我确实确保更换了#34; 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返回IntPtr.Zero。没有其他方法可以获得窗口句柄吗?提前谢谢!

1 个答案:

答案 0 :(得分:1)

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

在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),所以我很犹豫自己使用interop来实现该功能。如果您确实像我一样使用Xlib,那么可以考虑使用tronche作为Xlib API参考。它在C语言中,但我发现在C#中将其转换为PInvokable函数和可沼泽结构非常容易。也有一些注意事项需要考虑。另一个有助于翻译的好资源是直接使用源代码来查找低级类型的定义,以帮助查找C#等效项。诸如此类的东西应该会对您有很大帮助:http://refspecs.linuxbase.org/LSB_4.0.0/LSB-Desktop-generic/LSB-Desktop-generic/libx11-ddefs.html