在 JNA 中创建一个本机 Windows 窗口和一些带有 GWL_WNDPROC 的 GetWindowLong

发布于 2024-09-29 16:33:55 字数 1577 浏览 0 评论 0原文

美好的一天,

我已经使用 JNA 与 Windows API 交互有一段时间了,现在我在创建窗口时陷入困境。据我做了以下事情: 1. 创建了现有窗口的子窗口并为其获取了有效的处理程序。 2. 了解Windows 中的每个窗口都有一个不间断的消息分发循环。 3. 了解将我的窗口包含在消息分发循环中的最佳方法是使用类似以下代码的代码(不是我的,但这也是我会做的):

final LONG_PTR prevWndProc = new LONG_PTR(User32.INSTANCE.GetWindowLong(hwnd, User32.GWL_WNDPROC));       //this is to obtain a pointer to the WNDPROC of the parent window, which we are going to need later
  wndProcCallbackListener = new WndProcCallbackListener()
   {
      public LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam)
      {
         if (uMsg == WTSAPI.WM_POWERBROADCAST)
         {
           System.out.println("WM_POWERBROADCAST Event: hWnd="+hwnd+", uMsg="+uMsg+", uParam="+uParam+", lParam="+lParam);
         }
         else if (uMsg == WTSAPI.WTS_SESSION_CHANGE)
         {
           System.out.println("WTS_SESSION_CHANGE Event: hWnd="+hwnd+", uMsg="+uMsg+", uParam="+uParam+", lParam="+lParam);
         }

        //Call the window's actual WndProc so the events get processed.
        return User32.INSTANCE.CallWindowProc(prevWndProc, hWnd, uMsg, uParam, lParam);
      }
   };
      //Set the WndProc function to use our callback listener instead of the window's one. 
   int result = User32.INSTANCE.SetWindowLong(hwnd, User32.GWL_WNDPROC, wndProcCallbackListener);

但是,我的问题是当我调用 GetWindowLong 时() 对于父窗口(我的第一行代码) 我得到的指针为 0,这表明该函数未成功完成。随后调用 GetLastError() 并快速检查错误代码会出现“访问被拒绝”错误。当然,这是合乎逻辑的,因为我试图从自己的线程访问另一个线程的 WNDPROC 地址,但我想知道是否有任何方法(当然应该有)来规避它。

有什么指点吗? (双关语)

Good day,

I have been using JNA for a while to interact with the Windows API and now I am stuck when creating a window. As far as I have done the following:
1. Have created a child window of an existing window and obtained a valid handler to it.
2. Understood that every window in Windows has a non-stop message-dispatch loop.
3. Understood that the best way to include my window in the message-dispatch loop is to use something like the following code (not mine, but that is what I would do as well):

final LONG_PTR prevWndProc = new LONG_PTR(User32.INSTANCE.GetWindowLong(hwnd, User32.GWL_WNDPROC));       //this is to obtain a pointer to the WNDPROC of the parent window, which we are going to need later
  wndProcCallbackListener = new WndProcCallbackListener()
   {
      public LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam)
      {
         if (uMsg == WTSAPI.WM_POWERBROADCAST)
         {
           System.out.println("WM_POWERBROADCAST Event: hWnd="+hwnd+", uMsg="+uMsg+", uParam="+uParam+", lParam="+lParam);
         }
         else if (uMsg == WTSAPI.WTS_SESSION_CHANGE)
         {
           System.out.println("WTS_SESSION_CHANGE Event: hWnd="+hwnd+", uMsg="+uMsg+", uParam="+uParam+", lParam="+lParam);
         }

        //Call the window's actual WndProc so the events get processed.
        return User32.INSTANCE.CallWindowProc(prevWndProc, hWnd, uMsg, uParam, lParam);
      }
   };
      //Set the WndProc function to use our callback listener instead of the window's one. 
   int result = User32.INSTANCE.SetWindowLong(hwnd, User32.GWL_WNDPROC, wndProcCallbackListener);

However, my problem is when I call the GetWindowLong() for the parent window (my first line of code) I get a 0 for the pointer which indicated the function did not complete successfully. A subsequent call to GetLastError() and a quick check in the error codes give me an 'Access is denied' error. This, of course, is logical, since I am trying from my own thread to access the address of the WNDPROC of another, but I was wondering if there is any way (there should be, of course) to circumvent that.

Any pointers? (pun intended)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

メ斷腸人バ 2024-10-06 16:33:55

JNA 调用后请勿使用 GetLastError()。 JNA& JNI 可能会调用其他可能更改最后一个错误的 API。声明 SetWindowLong 并使用子句抛出 LastErrorException,如下所示:

int SetWindowLongA(int hWnd, int nIndex, WndProcCallbackListener dwNewLong)
    throws LastErrorException;

注意名称后面的“A”。它明确使用 ANSI 版本。您也可以使用 SetWindowLongW。

确保您的回调同时实现 Callback 和 StdCall。我更喜欢尽可能使用原始类型,因为这使得映射对于 JNA 来说变得快速且明显:

public interface WndProcCallbackListener extends Callback, StdCall {

    int callback(int hWnd, int Msg, int wParam, int lParam);

}

Do not use GetLastError() after a JNA call. JNA & JNI may call other APIs that may change the last error. Declare SetWindowLong with the clause throws LastErrorException, like this:

int SetWindowLongA(int hWnd, int nIndex, WndProcCallbackListener dwNewLong)
    throws LastErrorException;

Notice the 'A' after the name. It makes explicit use of ANSI version. You could use SetWindowLongW as well.

Make sure your callback implements both Callback and StdCall. I prefer using primitive types as much as possible, because this makes mapping fast and obvious to JNA:

public interface WndProcCallbackListener extends Callback, StdCall {

    int callback(int hWnd, int Msg, int wParam, int lParam);

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文