I get all needed information for x86 programms (in C:\Program Files (x86)) without any problems with below statement. But for x64 empty result for activ window process name. Is it possible detect active window process name (.exe path) for x64 processor with jna?
Eclipse Luna for x64
Windows 8 pro x64
JRE8 x64
jna 4.1.0
import static your.pack.name.EnumerateWindows.Kernel32.OpenProcess;
import static your.pack.name.EnumerateWindows.Kernel32.PROCESS_QUERY_INFORMATION;
import static your.pack.name.EnumerateWindows.Kernel32.PROCESS_VM_READ;
import static your.pack.name.EnumerateWindows.Psapi.GetModuleBaseNameW;
import static your.pack.name.EnumerateWindows.User32DLL.GetForegroundWindow;
import static your.pack.name.EnumerateWindows.User32DLL.GetWindowTextW;
import static your.pack.name.EnumerateWindows.User32DLL.GetWindowThreadProcessId;
import java.lang.management.ManagementFactory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.ptr.PointerByReference;
public class EnumerateWindows {
private static final int MAX_TITLE_LENGTH = 1024;
public static void main(String[] args) throws Exception {
char[] buffer = new char[MAX_TITLE_LENGTH * 2];
GetWindowTextW(GetForegroundWindow(), buffer, MAX_TITLE_LENGTH);
System.out.println("Active window title: " + Native.toString(buffer));
PointerByReference pointer = new PointerByReference();
GetWindowThreadProcessId(GetForegroundWindow(), pointer);
Pointer process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pointer.getValue());
GetModuleBaseNameW(process, null, buffer, MAX_TITLE_LENGTH);
System.out.println("Active window process: " + Native.toString(buffer));
System.out.println(ManagementFactory.getRuntimeMXBean().getName());
}
static class Psapi {
static {
Native.register("psapi");
}
public static native int GetModuleBaseNameW(Pointer hProcess, Pointer hmodule, char[] lpBaseName, int size);
}
static class Kernel32 {
static {
Native.register("kernel32");
}
public static int PROCESS_QUERY_INFORMATION = 0x0400;
public static int PROCESS_VM_READ = 0x0010;
public static native int GetLastError();
public static native Pointer OpenProcess(int dwDesiredAccess, boolean bInheritHandle, Pointer pointer);
}
static class User32DLL {
static {
Native.register("user32");
}
public static native int GetWindowThreadProcessId(HWND hWnd, PointerByReference pref);
public static native HWND GetForegroundWindow();
public static native int GetWindowTextW(HWND hWnd, char[] lpString, int nMaxCount);
}
}
i get all information for x86 and x64 software without any problem, if i export my project to runnable jar.
Above problem affect only on, if i run the project from Eclipse
Related
I am struggling with very annoying error in my code. I have this error appearing over and over again:
No implementation found for long com.oculus.gles3jni.GLES3JNILib.onCreate(android.app.Activity)
(tried Java_com_oculus_gles3jni_GLES3JNILib_onCreate and
Java_com_oculus_gles3jni_GLES3JNILib_onCreate__Landroid_app_Activity_2)
But in my file GLES3JNILib.java I have this:
package com.oculus.gles3jni;
import android.app.Activity;
import android.view.Surface;
// Wrapper for native library
public class GLES3JNILib
{
// Activity lifecycle
public static native long onCreate( Activity obj );
public static native void onStart( long handle );
public static native void onResume( long handle );
public static native void onPause( long handle );
public static native void onStop( long handle );
public static native void onDestroy( long handle );
// Surface lifecycle
public static native void onSurfaceCreated( long handle, Surface s );
public static native void onSurfaceChanged( long handle, Surface s );
public static native void onSurfaceDestroyed( long handle );
// Input
public static native void onKeyEvent( long handle, int keyCode, int action );
public static native void onTouchEvent( long handle, int action, float x, float y );
}
So I am not sure what is wrong. It is there but still I can't start my app. In my cpp code the implementation is:
jlong Java_com_oculus_gles3jni_GLES3JNILib_onCreate( JNIEnv * env, jobject obj, jobject activity )
{
...
}
Does someone see what I am missing, or doing wrong? Is it possible that this is because I don't have h file for my cpp?
You must have generated the C code and then changed the Java native method declaration to static without re-running javah.
Or you didn't run it at all and tried to wing it. Don't do that.
The correct signature has jclass for the second parameter, but don't take my word for it: rerun javah and adjust your .c file accordingly.
NB your .c file should #include your .h file.
Did you forget to load the library?
public class GLES3JNILib
{
static {
try {
System.loadLibrary("libGLES3JNILib");
} catch (UnsatisfiedLinkError e) {
// do something helpful here
}
}
...
}
I am trying to run a ShellExecute function from java with JNA.
I dont have any problems running ShellExecuteA on non-unicode folders
import com.sun.jna.*;
import com.sun.jna.platform.win32.ShellAPI;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.win32.*;
public class Main {
public interface Shell32 extends ShellAPI, StdCallLibrary {
Shell32 INSTANCE = (Shell32)Native.loadLibrary("shell32", Shell32.class);
WinDef.HINSTANCE ShellExecuteA(WinDef.HWND hwnd,
String lpOperation,
String lpFile,
String lpParameters,
String lpDirectory,
int nShowCmd);
}
public static void main(String[] args) {
WinDef.HWND h = null;
WString st = new WString("D:");
Shell32.INSTANCE.ShellExecuteA(h, "open", st.toString(), null, null, 1);
}
}
But since I want to be able to use it on unicode folders I actually want to run ShellExecuteW instead of A version, but cant figure how. Every time I run the following code it just finishes executing without doing anything or showing any errors.
import com.sun.jna.*;
import com.sun.jna.platform.win32.ShellAPI;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.win32.*;
public class Main {
public interface Shell32 extends ShellAPI, StdCallLibrary {
Shell32 INSTANCE = (Shell32)Native.loadLibrary("shell32", Shell32.class);
WinDef.HINSTANCE ShellExecuteW(WinDef.HWND hwnd,
String lpOperation,
WString lpFile,
String lpParameters,
String lpDirectory,
int nShowCmd);
}
public static void main(String[] args) {
WinDef.HWND h = null;
WString st = new WString("D:\\日本語");
Shell32.INSTANCE.ShellExecuteW(h, "open", st, null, null, 1);
}
}
I guess the problem lies withing the third parameter lpFile - I tried using String, WString all the same.
Any help will be appreciated.
Thanks.
Because this is the answer I repeat #technomage's comment to the question here:
If you're going to explicitly use wide strings, you typically need to use them for all function parameters. w32 API will typically have LPTCSTR for all C strings, which means String for ascii and WString for unicode.
The working code is therefore:
import com.sun.jna.*;
import com.sun.jna.platform.win32.ShellAPI;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.win32.*;
public class Main {
public interface Shell32 extends ShellAPI, StdCallLibrary {
Shell32 INSTANCE = (Shell32)Native.loadLibrary("shell32", Shell32.class);
WinDef.HINSTANCE ShellExecuteW(WinDef.HWND hwnd,
WString lpOperation,
WString lpFile,
WString lpParameters,
WString lpDirectory,
int nShowCmd);
}
public static void main(String[] args) {
WinDef.HWND h = null;
WString file = new WString("D:\\日本語");
Shell32.INSTANCE.ShellExecuteW(h, new WString("open"), file, null, null, 1);
}
}
I wrote some java code.
how to run chrome using JNA in windows(32bit).
then I like to get the hwnd of it.
As you know, FindWindow is simple solution but if chrome doesn't running, it doesn't work.
FindWindow example
below like code is possible?
HWND hwnd = User32.CreateProcess(...);
below code open chrome.
but sizing, maxmizing doesn't work.
public interface Kernel32 extends StdCallLibrary {
Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
boolean CreateProcessA(
String lpApplicationName
, String lpCommandLine
, Structure lpProcessAttributes
, Structure lpThreadAttributes
, boolean bInheritHandles
, int dwCreationFlags
, Structure lpEnvironment
, String lpCurrentDirectory
, Structure lpStartupInfo
, Structure lpProcessInformation);
}
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
public class ProcessInformation extends Structure {
public Pointer hProcess;
public Pointer hThread;
public int dwProcessId;
public int dwThreadId;
}
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.WString;
public class StartupInfoA extends Structure {
public int cb;
public WString lpReserved;
public WString lpDesktop;
public WString lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public Pointer lpReserved2;
public Pointer hStdInput;
public Pointer hStdOutput;
public Pointer hStdError;
}
public class Test {
public static void main(String[] args) {
int STARTF_USEPOSITION = 0x00000004;
int STARTF_USESIZE = 0x00000002;
int STARTF_USESHOWWINDOW = 0x00000001;
ProcessInformation processInformation = new ProcessInformation();
StartupInfoA startupInfo = new StartupInfoA();
startupInfo.dwX = 100;
startupInfo.dwY = 100;
startupInfo.dwXSize = 100;
startupInfo.dwYSize = 100;
startupInfo.wShowWindow = (short) SW_MAXIMIZE;
startupInfo.dwFlags = STARTF_USEPOSITION | STARTF_USESIZE;
Kernel32.INSTANCE.CreateProcessA(new String("C:\\Users.....\\Google\\Chrome\\Application\\chrome.exe")
, null
, null
, null
, true
, 0
, null
, null
, startupInfo
, processInformation);
}
}
If Chrome is not running, you can't get a handle of its window, of course, because such a window does not exist. You might want to run Chrome, using something like ProcessBuilder, then call something like this:
user32.EnumWindows( new WndEnumProc()
{
#SuppressWarnings ( "AssignmentToMethodParameter" )
public boolean callback ( int hWnd, int lParam )
{
if ( user32.IsWindow( hWnd ) )
{
if ( user32.IsWindowVisible( hWnd ) )
{
RECT r = new RECT();
user32.GetWindowRect( hWnd, r );
// if (r.left > -32000) // is not minimized
//{
String windowTitle = getWindowParentName( hWnd );
String windowClass = getWindowParentClassName( hWnd );
hWnd = user32.GetAncestor( hWnd, 3 );
if ( !windowTitle.toLowerCase().equals( "program manager" ) && !windowClass.toLowerCase().equals( "progman" ) && !windowTitle.equals( "" ) && !windowClass.toLowerCase().equals( "shell_traywnd" ) )
{
listOfWindows.put( hWnd, getWindowParentRectangle( hWnd ) );
}
// }
}
return true;
}
else
{
return false;
}
}
}, 0 );
Of course, this is already working code that has some conditions specific to my app. But the main idea is to
call EnumWindows with a WndEnumProc() that will put all windows it finds to a collection ( in my case an HashMap ). Then after the EnumWindows returns, you will have a collection of windows in your listOfWindows variable and you will be able to get the hwnd of Chrome if it was running during the time EnumWindows was called.
You should define EnumWindows in your user32 instance like this:
/**
* Enumerates all top-level windows on the screen by passing the handle to each window, in turn, to an application-defined callback function.
* #param wndenumproc A pointer to an application-defined callback function.
* #param lParam An application-defined value to be passed to the callback function.
* #return if the function succeeded.
* <b>Microsoft Reference</b><br>
*/
public boolean EnumWindows ( WndEnumProc wndenumproc, int lParam );
You should also define your WndEnumProc structure in a class (mine was named Structures) something like this:
public static interface WndEnumProc extends StdCallLibrary.StdCallCallback
{
boolean callback ( int hWnd, int lParam );
}
Hope that helps. Please note that Chrome must be running while you are doing all that magic. Running it, as I noted in the beginning, should be relatively straightforward using a ProcessBuilder or if you don't want to bother much and Chrome is in your path, you can use
System.getRuntime().exec("chrome.exe")
to start Chrome.
I want to grab the all global key events on linux using JNA same as window hooks. following is the code:
package pack.tracker.services;
//import sun.awt.X11.XEvent;
//import com.jscape.inet.ssh.transport.KeyCreator;
import com.sun.jna.examples.unix.X11;
import com.sun.jna.examples.unix.X11.Display;
import com.sun.jna.examples.unix.X11.Window;
import com.sun.jna.examples.unix.X11.XEvent;
public class JNATest {
X11 x = X11.INSTANCE;
Window window;
Display display = x.XOpenDisplay("0");
XEvent ev = new XEvent();
public JNATest() {
System.out.println("hi");
// TODO Auto-generated constructor stub
String keyString = "F3" ;
Display display = x.XOpenDisplay(null);
XEvent ev = new XEvent();
window = x.XDefaultRootWindow(display);
for(;;){
x.XNextEvent(display, ev);
if(ev.type == X11.KeyPress){
System.out.println("KeyPressed");
}
else{
System.out.println("ok");
}
}
}
public static void main(String s[]){
new JNATest();
}
}
I donot know whats going wrong. I am unable to use XGrabKeyboard. Please help me out.
Thanks and regards,
Vivek Birdi
The XGrabKeys method has not been implemented in JNA. You will need to extend the X11 library and define the method like so:
import com.sun.jna.*;
import com.sun.jna.platform.unix.X11;
import com.sun.jna.platform.unix.X11.*;
public interface Xlib extends X11 {
int XGrabKey(Display display, int keycode, NativeLong modifiers, Window grab_window, boolean owner_events, int pointer_mode, int keyboard_mode);
/*
Display *display;
int keycode;
unsigned int modifiers;
Window grab_window;
Bool owner_events;
int pointer_mode, keyboard_mode;
*/
}
Have a look at this site for Xlib structures and methods.
If you are still unable to implement in JNA then have a look at JXGrabkey at(http://sourceforge.net/projects/jxgrabkey/).
Is there a way I can use Java (or Groovy) to change my desktop wallpaper in Windows XP? I have a program that creates a new image every day (or whenever) and I would like a way to automatically update my desktop.
I've seem some questions on this site about C++ or .NET, but I did not see anything specific to Java.
Sorry I'm a bit behind #ataylor's answer because I was preparing a snippet to do it. Yes, JNA is a correct approach. Here you go:
import java.util.HashMap;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.UINT_PTR;
import com.sun.jna.win32.*;
public class WallpaperChanger {
public static void main(String[] args) {
//supply your own path instead of using this one
String path = "C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg";
SPI.INSTANCE.SystemParametersInfo(
new UINT_PTR(SPI.SPI_SETDESKWALLPAPER),
new UINT_PTR(0),
path,
new UINT_PTR(SPI.SPIF_UPDATEINIFILE | SPI.SPIF_SENDWININICHANGE));
}
public interface SPI extends StdCallLibrary {
//from MSDN article
long SPI_SETDESKWALLPAPER = 20;
long SPIF_UPDATEINIFILE = 0x01;
long SPIF_SENDWININICHANGE = 0x02;
SPI INSTANCE = (SPI) Native.loadLibrary("user32", SPI.class, new HashMap<Object, Object>() {
{
put(OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
}
});
boolean SystemParametersInfo(
UINT_PTR uiAction,
UINT_PTR uiParam,
String pvParam,
UINT_PTR fWinIni
);
}
}
You need to have the JNA libraries on the classpath for this to work. This was tested in Windows 7, there might be some nuances in XP but I think it should work. That API is presumably stable.
References
Setting Wallpaper - Coding4Fun
How to determine if a screensaver is running in Java?
W32API.java
Edit (2010/01/20):
I had previously omitted the options SPIF_UPDATEINIFILE and SPIF_SENDWININICHANGE. These are now being used as they were suggested in the Coding4Fun MSDN article.
You can do it easier:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.PVOID;
import com.sun.jna.win32.W32APIOptions;
public class Wallpaper {
public static interface User32 extends Library {
User32 INSTANCE = (User32) Native.loadLibrary("user32",User32.class,W32APIOptions.DEFAULT_OPTIONS);
boolean SystemParametersInfo (int one, int two, String s ,int three);
}
public static void main(String[] args) {
User32.INSTANCE.SystemParametersInfo(0x0014, 0, "C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg" , 1);
}
}
You can write a batch file to change the wall-paper, and execute that batch file using,
Runtime.getRuntime.exec()
The JNA java library allows you to easily call Win32 API calls. In particular, to change the desktop background, you need to call the SystemParametersInfo function.
Take a look at this article for an introduction to JNA: http://today.java.net/article/2009/11/11/simplify-native-code-access-jna
Here is a Pure Java implementation which uses Project Panama to make the native callbacks into Windows USER32.DLL. Note that the API is incubating so has changed between JDK16, 17 and later builds. These samples use the versions of Panama that are in the current JDK16/17 release, some changes may be required if you switch to the latest Panama Early Access builds.
import java.lang.invoke.*;
import java.nio.file.Path;
import jdk.incubator.foreign.*;
/**
%JDK16%\bin\java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign SetWallpaper.java A.JPG
*/
public class SetWallpaper {
static final int SPI_SETDESKWALLPAPER = 0x0014;
static final int SPIF_UPDATEINIFILE = 0x01;
static final int SPIF_SENDCHANGE = 0x02;
public static void main(String[] args) throws Throwable {
LibraryLookup user32 = LibraryLookup.ofLibrary("user32");
MethodHandle spi = CLinker.getInstance().downcallHandle(user32.lookup("SystemParametersInfoA").get()
// BOOL SystemParametersInfoA (UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
, MethodType.methodType(int.class, int.class, int.class, MemoryAddress.class, int.class)
, FunctionDescriptor.of(CLinker.C_LONG,CLinker.C_LONG, CLinker.C_LONG, CLinker.C_POINTER, CLinker.C_LONG));
Path path = Path.of(args[0]).toRealPath();
try (NativeScope scope = NativeScope.unboundedScope()) {
MemorySegment img = CLinker.toCString(path.toString(), scope);
int status = (int)spi.invokeExact(SPI_SETDESKWALLPAPER, 0, img.address(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
System.out.println("Changed wallpaper to "+path+" rc="+status+(status == 0 ? " *** ERROR ***": " OK"));
}
}
}
Small changes needed for JDK17:
/**
%JAVA_HOME%\bin\java --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.foreign SetWallpaper.java A.JPG
*/
public static void main(String[] args) throws Throwable {
System.loadLibrary("user32");
// BOOL SystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
MemoryAddress symbol = SymbolLookup.loaderLookup().lookup("SystemParametersInfoW").get();
MethodHandle SystemParametersInfoW = CLinker.getInstance().downcallHandle(symbol
, MethodType.methodType(int.class, int.class, int.class, MemoryAddress.class, int.class)
, FunctionDescriptor.of(CLinker.C_LONG,CLinker.C_LONG, CLinker.C_LONG, CLinker.C_POINTER, CLinker.C_LONG));
Path path = Path.of(args[0]).toRealPath();
try(ResourceScope scope = ResourceScope.newConfinedScope()) {
SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope);
// toCString as WIDE string
Addressable wide = allocator.allocateArray(CLinker.C_CHAR, (path+"\0").getBytes(StandardCharsets.UTF_16LE));
int status = (int)SystemParametersInfoW.invokeExact(SPI_SETDESKWALLPAPER, 0, wide.address(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
System.out.println("Changed wallpaper to "+path+" rc="+status+(status == 0 ? " *** ERROR ***": " OK"));
}
}
Expanding on the answer from #DuncG, here's an updated solution which uses Project Panama from JDK 18.
import jdk.incubator.foreign.*;
import java.lang.invoke.MethodHandle;
import java.nio.file.Path;
import static jdk.incubator.foreign.ValueLayout.*;
public class WindowsOperatingSystem {
private static final int SPI_SETDESKWALLPAPER = 0x0014;
private static final int SPIF_UPDATEINIFILE = 0x01;
private static final int SPIF_SENDCHANGE = 0x02;
private static final MethodHandle systemParametersInfoAFunction;
static {
System.loadLibrary("user32");
// BOOL SystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
systemParametersInfoAFunction = CLinker.systemCLinker().downcallHandle(
SymbolLookup.loaderLookup().lookup("SystemParametersInfoA").get(),
FunctionDescriptor.of(JAVA_BOOLEAN, JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT)
);
}
public static void setWallpaper(Path file) {
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
SegmentAllocator allocator = SegmentAllocator.nativeAllocator(scope);
Addressable nativeFilePath = allocator.allocateUtf8String(file.toString());
var result = (boolean)systemParametersInfoAFunction.invokeExact(
SPI_SETDESKWALLPAPER,
0,
nativeFilePath,
SPIF_UPDATEINIFILE | SPIF_SENDCHANGE
);
if (!result) {
throw new IllegalStateException();
}
} catch (Error | RuntimeException t) {
throw t;
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
}