Не удается установить всегда поверх внешних приложений в Java / переполнение стека

Я ищу решение сделать так, чтобы внешнее приложение (а не приложение для Windows, такое как notepad или calc.exe) оставалось всегда на вершине после нажатия кнопки в Java GUI.
Я использую этот код в C ++, чтобы взять все открытые окна на рабочем столе и сопоставить их идентификатор процесса (PID) с отправленным PID (из моего приложения на 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:

    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 () и помещаю это окно Handle (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;
}

Можно ли взять реализацию метода в C ++ из JNI и использовать 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")
// <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}

Пожалуйста помоги.
Я не могу установить всегда на первое место для внешних приложений (не MS Windows программного обеспечения).
Я использую версию JNA 3.0.0.

————————————————

Я пытаюсь использовать методы C ++ Win Api (из моего первого вопроса выше) — EnumWindowsProc, EnumWindows GetWindowThreadProcessId и SetWindowPos — для реализации кода Java, чтобы упростить код моего приложения.
Я пытался перенести функциональность кода C ++ / JNI в JNA. К сожалению, я могу печатать только дескрипторы (HWND) всех окон рабочего стола с заголовками окон без PID.

Я хотел бы отправить идентификатор процесса противоположной программы (exe-файл) в Java, для реализации EnumWindows в Java JNA, и искать этот идентификатор процесса по каждому открытому окну на рабочем столе (в методе EnumWindowsProc) в Java JNA. Затем я хотел бы сравнить windowHandle ID процесса отправки с windowHandle`s открытых окон на рабочем столе. После нахождения windowHandle идентификатора процесса отправки я хотел бы вызвать метод SetWindowPos, который позволяет мне устанавливать открытое окно всегда сверху (сверху большинства).
Другими словами, я хотел бы скопировать функции из C ++ / JNI в код Java с помощью 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 Top для внешнего приложения, в котором исполняемый файл генерирует более одного PID (ID процесса), потому что он не работает. Что может быть не так? Для программного обеспечения, которое генерирует только один идентификатор процесса, с которым оно работает, для другого программного обеспечения (exe-файл), который генерирует более одного PID (например, когда я открываю Adobe Reader, который генерирует два pid для одного exe-файла), это не работает.

Я был бы очень признателен за помощь в переносе функциональности из моего кода на C ++ / JNI на JNA.
Я хотел бы решить эти проблемы в коде Java с помощью JNA.

3

Решение

Ваша реализация JNI / C ++ перестает перечислять окна после первого, если найдено для процесса. Если это окно является фиктивным невидимым окном, вы не можете обработать другие для этого процесса: вы всегда должны возвращать TRUE в EnumWindowsProc,

Кроме того, не потрудитесь использовать SetWindowPos для невидимых окон.

0

Другие решения

Других решений пока нет …