无法在Java / C ++中为外部应用程序设置always-on-top [英] Can't set always-on-top for external applications in Java / C++

查看:176
本文介绍了无法在Java / C ++中为外部应用程序设置always-on-top的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找使外部应用程序(不是像notepad或calc.exe这样的Windows应用程序)的解决方案,以便在按下Java GUI中的按钮后始终保持在顶部。
我在C ++中使用这段代码来获取桌面上所有打开的窗口,并将它们的进程ID(PID)与发送的PID(来自我的Java应用程序)相匹配:

I'm looking for solution to make external application (not windows application like notepad or calc.exe) to stay always-on-top after pressing the button in Java GUI. I'm using this code in C++ for taking all opened windows on desktop and matching their Process ID (PID) with sent PID (from my app in Java) :

     #include "cjni.h"
     #include <cstdlib>
     #include <iostream>
     #include <windows.h>

     using namespace std;

     BOOL CALLBACK EnumWindowsProc(HWND windowHandle, LPARAM lParam){

 DWORD searchedProcessId = (DWORD)lParam;
 DWORD windowProcessId = 0;
 GetWindowThreadProcessId(windowHandle, &windowProcessId);
 printf("process id=%d\n", windowProcessId);


 if(searchedProcessId == windowProcessId) {
    HWND hwnd = windowHandle;
    SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
    printf("Process ID found !");
    return FALSE;
}
return TRUE;
      }




       JNIEXPORT void JNICALL Java_gui_CJNI_AlwaysOnTop
      (JNIEnv *env, jclass jobj, jint processId) {

     //(*env)->EnumWindows(&EnumWindowsProc, (LPARAM)processId);  
     EnumWindows(&EnumWindowsProc, (LPARAM)processId);   

         }






实施在Java JNI中:


Implementation in Java JNI:

    package gui;

    public class CJNI {

    static {
    System.loadLibrary("cjni");
    }

    static native void AlwaysOnTop(int processId);



    public void metoda(final int processId) {

        //AlwaysOnTop(processId);

    }






In Java我正在使用此代码获取所选进程的PID:


In Java I'm using this code for getting PID of selected process:

    public int getPID(Process p) {

    try {
        Field f = p.getClass().getDeclaredField("handle");
        f.setAccessible(true);
        long handl = f.getLong(p);

        Kernel32 kernel = Kernel32.INSTANCE;
        WinNT.HANDLE handle = new WinNT.HANDLE();
        handle.setPointer(Pointer.createConstant(handl));

        return kernel.GetProcessId(handle);

    } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e) {
        return -1;
    }

}






我的程序适用于MS Windows应用程序,使它们始终处于最佳状态。不幸的是,外部应用程序并不总是在顶部。我正在使用SetWindowPos();来自C ++的方法。当我通过GetForegroundWindow()选择外部程序窗口并将此窗口句柄(HWND)作为SetWindowPos()的参数时,它可以工作;
这里的代码使用外部应用程序,总是在顶部(但我必须自己选择应用程序窗口 - 通过鼠标选择):


My program works fine with MS windows applications, makes them always on top. Unfortunately, external applications didn't take always on top. I'm using SetWindowPos(); method from C++. It works when I select external program window by GetForegroundWindow() and put this window Handle (HWND) as an argument on SetWindowPos(); Here's code working with external applications with always on top (but I must select application window by my own - selecting by mouse):

    #include <windows.h>
    #include <iostream>

     using namespace std;


    int main(){

    cout << "Select window within 2 seconds\n";
        Sleep(2000);
        HWND hWnd = GetForegroundWindow();

    //HWND hWnd = (HWND)0x8036c;

     SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);

         cout <<"Number hwnd: " << hWnd << endl;
         cout << "Always on top set on window.\n";
         return 0;
       }






是否可以获取从JNI实现C ++中的方法,并使用JNA,使用Java GUI打开外部设备并始终设置应用程序?


Is it possible to takie the implementation of method in C++ from JNI, and use JNA, to open external and set applications ALWAYS ON TOP, using Java GUI ?

         /*
          * To change this license header, choose License Headers in Project Properties.
          * To change this template file, choose Tools | Templates
          * and open the template in the editor.
          */
          package gui;

          import com.sun.jna.Pointer;
          import com.sun.jna.platform.win32.Kernel32;
          //import com.sun.jna.platform.win32.User32;
          //import com.sun.jna.platform.win32.WinDef;
          import com.sun.jna.platform.win32.WinNT;
          //import com.sun.jna.platform.win32.WinUser;

          //import com.sun.jna.win32.StdCallLibrary;


         import java.io.IOException;
         import java.lang.reflect.Field;
         import java.util.logging.Level;
         import java.util.logging.Logger;


        //import com.sun.jna.platform.win32.WinDef.DWORD;
        //import com.sun.jna.platform.win32.WinNT.HANDLE;

        /**
          *
          * @author adrians
          */
 public class Test extends javax.swing.JFrame /*implements WndEnumProc*/ {


   long startTime;
   long stopTime;

/**
 * Creates new form Test
 */
public Test() {

    initComponents();
}



/**
 * This method is called from within the constructor to initialize the form.
 * WARNING: Do NOT modify this code. The content of this method is always
 * regenerated by the Form Editor.
 */
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">                          
private void initComponents() {

    jButton1 = new javax.swing.JButton();
    jButton2 = new javax.swing.JButton();
    jButton3 = new javax.swing.JButton();
    jButton4 = new javax.swing.JButton();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

    jButton1.setText("Kalkulator");
    jButton1.setMaximumSize(new java.awt.Dimension(87, 23));
    jButton1.setMinimumSize(new java.awt.Dimension(87, 23));
    jButton1.setPreferredSize(new java.awt.Dimension(83, 23));
    jButton1.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jButton1ActionPerformed(evt);
        }
    });

    jButton2.setText("Notatnik");
    jButton2.setMaximumSize(new java.awt.Dimension(87, 23));
    jButton2.setMinimumSize(new java.awt.Dimension(87, 23));
    jButton2.setPreferredSize(new java.awt.Dimension(83, 23));
    jButton2.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jButton2ActionPerformed(evt);
        }
    });

    jButton3.setText("SeaNet Pro");
    jButton3.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jButton3ActionPerformed(evt);
        }
    });

    jButton4.setText("Paint");
    jButton4.setMaximumSize(new java.awt.Dimension(87, 23));
    jButton4.setMinimumSize(new java.awt.Dimension(87, 23));
    jButton4.setPreferredSize(new java.awt.Dimension(87, 23));
    jButton4.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jButton4ActionPerformed(evt);
        }
    });

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addGap(50, 50, 50)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(jButton4, javax.swing.GroupLayout.DEFAULT_SIZE, 127, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(jButton3, javax.swing.GroupLayout.DEFAULT_SIZE, 125, Short.MAX_VALUE)
                    .addComponent(jButton2, javax.swing.GroupLayout.DEFAULT_SIZE, 125, Short.MAX_VALUE)
                    .addComponent(jButton1, javax.swing.GroupLayout.DEFAULT_SIZE, 125, Short.MAX_VALUE)))
            .addContainerGap(53, Short.MAX_VALUE))
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addGap(30, 30, 30)
            .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addGap(25, 25, 25)
            .addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addGap(25, 25, 25)
            .addComponent(jButton3, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addGap(25, 25, 25)
            .addComponent(jButton4, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addContainerGap(30, Short.MAX_VALUE))
    );

    pack();
}// </editor-fold>                        

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    run("calc.exe");
}                                        

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    run("notepad.exe");
}                                        

private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    run("\"C:\\Program Files\\vlc-2.1.1\\vlc.exe\"");
}                                        

private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    run("mspaint.exe");
}                                        

public void run(String name) {

    try {
        Process process = Runtime.getRuntime().exec(name);
        final int pid = getPID(process);

        System.out.println("Program name: " + name + ", PID=" + pid);

        new Thread(new Runnable() {
            public void run() {
                try {

                    startTime = System.currentTimeMillis();

                    Thread.sleep(150);
                    CJNI.AlwaysOnTop(pid);

                    stopTime = System.currentTimeMillis() - startTime;
                    System.out.println("Time: "+stopTime);

                } catch (InterruptedException ex) {
                    Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }).start();
    } catch (IOException ex) {
        Logger.getLogger(Okno.class.getName()).log(Level.SEVERE, null, ex);
    }
}

public int getPID(Process p) {

    try {
        Field f = p.getClass().getDeclaredField("handle");
        f.setAccessible(true);
        long handl = f.getLong(p);

        Kernel32 kernel = Kernel32.INSTANCE;
        WinNT.HANDLE handle = new WinNT.HANDLE();
        handle.setPointer(Pointer.createConstant(handl));

        //final User32 user32 = User32.INSTANCE;

        return kernel.GetProcessId(handle);

    } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e) {
        return -1;
    }

}


/**
 * @param args the command line arguments
 */
public static void main(String args[]) {
    /* Set the Nimbus look and feel */
    //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
    /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
     * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
     */
    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException ex) {
        java.util.logging.Logger.getLogger(Test.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        java.util.logging.Logger.getLogger(Test.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        java.util.logging.Logger.getLogger(Test.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(Test.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }
    //</editor-fold>

    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            new Test().setVisible(true);
        }
    });
}

// Variables declaration - do not modify                     
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JButton jButton3;
private javax.swing.JButton jButton4;
// End of variables declaration                   


}



< hr>

请帮忙。
我不能总是为外部应用程序设置(非MS Windows软件)。
我正在使用JNA 3.0.0版本。


Please help. I can't set always on top for external applications (non MS windows software). I'm using JNA 3.0.0 version.

我正在尝试使用C ++ Win Api方法(从我上面的第一个问题) - EnumWindowsProc,EnumWindows GetWindowThreadProcessId和SetWindowPos - 到Java代码实现,以简化我的应用程序的代码。
我试图将C ++ / JNI代码的功能移到JNA。不幸的是,我只能打印所有桌面窗口的句柄(HWND)和窗口标题,没有PID。

I'm trying to take C++ Win Api methods (from my first question above) - EnumWindowsProc, EnumWindows GetWindowThreadProcessId and SetWindowPos - to the Java code implementation, to simplify code of my application. I tried to move functionality of C++/JNI code to the JNA. Unfortunately, I am able to print only the handles (HWND) of all desktop windows with the window titles, without the PID.

我想用Java发送oppened program(exe文件)的进程ID,在Java JNA中实现EnumWindows,并在每个打开的窗口中搜索这个进程ID在Java JNA中的桌面上(在EnumWindowsProc方法中)。然后我想用windowHandle在桌面上打开的窗口来调试windowHandle的发送进程ID。在找到发送进程ID的windowHandle后,我想调用方法SetWindowPos,它允许我在Always on Top(Top Most)上设置打开的窗口。
换句话说,我想通过JNA将函数从C ++ / JNI复制到Java代码。

I would like to send process ID of oppened program (exe file) in Java, to implementation of EnumWindows in Java JNA, and to search this Process ID by every opened window on desktop (in EnumWindowsProc method) in Java JNA. Then I would like to compair windowHandle of send process ID with windowHandle`s of opened windows on the desktop. After finding the windowHandle of send process ID i would like to call method SetWindowPos which allows me to set opened window on Always on Top (Top Most). In other words, I would like to copy functions from C++/JNI to the Java code by JNA.

这是我的代码:

import com.sun.jna.Pointer;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.win32.StdCallLibrary;

   public class n {
     // Equivalent JNA mappings
      public interface User32 extends StdCallLibrary {
        User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);

        interface WNDENUMPROC extends StdCallCallback {
        boolean callback(Pointer hWnd, Pointer arg);
        }

        boolean EnumWindows(WNDENUMPROC lpEnumFunc, Pointer arg);

       int GetWindowTextA(Pointer hWnd, byte[] lpString, int nMaxCount);

       //int GetWindowThread(Pointer hWnd, int windowProcessId);
   }

  public static void main(String[] args) {
    final User32 user32 = User32.INSTANCE;

    user32.EnumWindows(new User32.WNDENUMPROC() {

        int count;

        public boolean callback(Pointer hWnd, Pointer userData) {

            /*
            Pointer searchedProcessId = userData;
            int windowProcessId = 0;

            user32.GetWindowThread(searchedProcessId, windowProcessId);

            System.out.println("Process id = "+user32.GetWindowThread(searchedProcessId, windowProcessId));
            */


            byte[] windowText = new byte[512];
            user32.GetWindowTextA(hWnd, windowText, 512);
            String wText = Native.toString(windowText);
            wText = (wText.isEmpty()) ? "" : "; text: " + wText;
            System.out.println("Found window " + hWnd + ", total " + ++count + wText);


            return true;
        }
    }, null);
  }
 }

我的第二个问题是当我尝试设置Aways On时外部应用程序的顶部,哪个exe文件生成多个PID(进程ID),因为它不起作用。可能有什么不对?对于软件,它只生成一个正在工作的进程ID,对于生成多个PID的另一个软件(exe文件)(例如,当我打开Adobe Reader,它为一个exe文件生成两个pid时)它不起作用。

My second problem is when I try to set Aways On Top for external app, which exe file generates more then one PID (process ID), because it's not working. What could be wrong? For software, that generates only one Process ID it's working, for another software (exe file) which generates more then one PID (for example when I open Adobe Reader, which generates two pid for one exe file) it's not working.

我非常感谢帮助将我的C ++ / JNI代码中的功能转移到JNA。
我想通过JNA解决Java代码中的这些问题。

I would be very grateful for help in moving functionalities from my code in C++/JNI to the JNA. I would like to resolves those problems in Java code by JNA.

推荐答案

您的JNI / C ++实现停止枚举窗口在第一个之后,如果找到一个过程。如果该窗口是虚拟的不可见窗口,则无法处理该过程的其他窗口:您应始终在 EnumWindowsProc TRUE $ c>。

Your JNI/C++ implementation stops enumerating windows after the first one if found for a process. If that window is a dummy invisible window, you can't process the others for that process: you should always return TRUE in EnumWindowsProc.

另外,不要为了看不见的Windows而使用 SetWindowPos

Also, don't bother to use SetWindowPos for invisible Windows.

这篇关于无法在Java / C ++中为外部应用程序设置always-on-top的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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