无法在Java / C ++中为外部应用程序设置always-on-top

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

#include "cjni.h" #include  #include  #include  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中的实现:

  package gui; public class CJNI { static { System.loadLibrary("cjni"); } static native void AlwaysOnTop(int processId); public void metoda(final int processId) { //AlwaysOnTop(processId); } 

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

  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()的参数时,它可以工作; 这里的代码使用外部应用程序,总是在顶部(但我必须自己选择应用程序窗口 – 通过鼠标选择):

  #include  #include  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打开外部并始终设置应用程序?

  /* * 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") //  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(); }//  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 */ // /* 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); } // /* 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 } 

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

———————————————–

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

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

这是我的代码:

 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 Top时,哪个exe文件生成多个PID(进程ID),因为它不起作用。 可能有什么不对? 对于软件,它只生成一个正在工作的进程ID,对于生成多个PID的另一个软件(exe文件)(例如,当我打开Adobe Reader,它为一个exe文件生成两个pid时)它不起作用。

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

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

此外,不要将SetWindowPos用于隐形Windows。