Java 不能在爪哇/C++中始终设置外部应用程序
我正在寻找解决方案,使外部应用程序而不是像记事本或calc.exe这样的windows应用程序在按下Java GUI中的按钮后始终保持在顶部。 我在C++中使用这个代码,在桌面上打开所有打开的窗口,并将java中的进程ID与从我的应用程序中发送的PID匹配:Java 不能在爪哇/C++中始终设置外部应用程序,java,c++,java-native-interface,jna,always-on-top,Java,C++,Java Native Interface,Jna,Always On Top,我正在寻找解决方案,使外部应用程序而不是像记事本或calc.exe这样的windows应用程序在按下Java GUI中的按钮后始终保持在顶部。 我在C++中使用这个代码,在桌面上打开所有打开的窗口,并将java中的进程ID与从我的应用程序中发送的PID匹配: #include "cjni.h" #include <cstdlib> #include <iostream> #include <windows.h>
#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中,我使用以下代码获取所选进程的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 <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;
}
我的第二个问题是,当我尝试为外部应用程序设置Aways时,该exe文件会生成多个PID进程ID,因为它不工作。有什么不对劲吗?对于软件,它只生成一个正在工作的进程ID,对于另一个生成多个PID的软件exe文件,例如当我打开Adobe Reader时,它为一个未工作的exe文件生成两个PID
我非常感谢您帮助我将功能从C++/JNI代码转移到JNA。
我希望通过JNA解决Java代码中的这些问题。如果为进程找到第一个窗口,JNI/C++实现将在第一个窗口之后停止枚举窗口。如果该窗口是虚拟不可见窗口,则无法处理该进程的其他窗口:在EnumWindowsProc中应始终返回TRUE
另外,不必为不可见的窗口使用SetWindowPos。非常感谢:现在它可以工作了:是否可以将JNI/C++实现的功能移动到JNA?老实说,我不知道如何将这个实现正确地移动到JNA。@JBAS抱歉,我总是使用JNI,而不是JNA,但我认为JNA的全部目的是使事情变得更简单。使用谷歌制作一些文档和教程,自己至少尝试一下,然后在stackowerflow上询问这是否像预期的那样有效,只需要很少的代码就可以重现问题。我的应用程序还有一个问题。现在,我可以为外部应用程序设置“始终在顶部”,这太棒了。不幸的是,当我尝试为外部应用程序设置顶部的Aways时,该exe文件会生成多个PID进程ID,但它不起作用。有什么不对劲吗?对于一个进程ID,它工作,对于多个进程ID,例如,当我打开Adobe Reader时,它为一个exe文件生成两个pid,但它不工作。@JBAS您不能在问题得到回答后更改该问题,也不能发布您自己的问题的答案,该问题与答案相比更像是另一个问题。您应该接受/投票选出真实的答案,然后发布另一个新问题,详细说明您想要什么,您尝试了什么,以及为什么/如何不按预期工作。@JBAS谢谢。如果您想发布另一个问题,有一个提示:您应该更精确地指定您想要实现的目标。
#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;
}
/*
* 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
}
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);
}
}