简体   繁体   English

无法获得窗口句柄?

[英]Can't get a window handle?

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. 我正在尝试用Xlib编写一些等效的user32.dll代码,以便我可以支持Linux用户。 I'm of course running Linux, so I'm using Mono. 我当然在运行Linux,所以我使用的是Mono。 Problem comes along when I cannot even grab a window handle from the Process class because it was never even implemented: 当我甚至无法从Process类中获取窗口句柄时出现问题,因为它甚至从未实现过:

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

( Source ) 来源

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);
}

NOTE: In place of "myPid" is a proper process ID. 注意:代替“myPid”是一个正确的进程ID。 Replace "myPid" with a valid process ID. 将“myPid”替换为有效的进程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. 是的,我确实确保替换的“myPid”是一个有效的进程ID,我的代码没有抛出任何错误,表明我使用的任何进程ID都是无效的。

This doesn't crash my application, but almost every time I call XRaiseWindow it prints: 这不会导致我的应用程序崩溃,但几乎每次我调用XRaiseWindow它都会打印:

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

This obviously occurs because Process.MainWindowHandle returns IntPtr.Zero. 这显然是因为Process.MainWindowHandle返回IntPtr.Zero。 Is there no other way to get a window handle? 没有其他方法可以获得窗口句柄吗? Thanks in advance! 提前致谢!

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. 我最初使用@SushiHangover的解决方案,但并不喜欢它,因为我觉得依赖外部程序( xwininfo )是一个修补程序,最终只添加了另一个依赖项。 Hopefully this helps other C# developers using Mono. 希望这有助于其他使用Mono的C#开发人员。 This code was originally written for .NET Framework 2.0. 此代码最初是为.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. 我的解决方案只是本身使用Xlib枚举窗口并返回标题与所描述标题匹配的所有窗口。

In X11Wrapper.cs: 在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);
    }
}

In Linux.Utilities.cs: 在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);
        }
    }
}

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. 脚注:我最初声明我不是C开发人员(事情发生了变化,我学习了C)所以我对使用互操作自己实现功能犹豫不决。 If you do end up using Xlib a lot more like I did then consider using tronche as an Xlib API reference. 如果您最终使用Xlib,那么就像我一样,考虑使用tronche作为Xlib API参考。 It is in C but I found it was pretty easy to translate to PInvokable functions and marshable structs in C#. 它在C中,但我发现在C#中转换为PInvokable函数和marshable结构非常容易。 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. 另一个帮助翻译的好资源是直接使用源来查找低级类型的定义,以帮助找到C#等价物。 Something like this should greatly aid you: http://refspecs.linuxbase.org/LSB_4.0.0/LSB-Desktop-generic/LSB-Desktop-generic/libx11-ddefs.html 这样的事情应该对你有很大帮助: http//refspecs.linuxbase.org/LSB_4.0.0/LSB-Desktop-generic/LSB-Desktop-generic/libx11-ddefs.html

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

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