I'm trying to configure a custom window procedure and it works. However, after a while, the window stops reacting to any input. It seems that the more rendering is going on in a scene, the sooner the window gets broken.
This even happens if my custom window procedure simply calls the default window.
Reproducer:
package com.example;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.BaseTSD;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.win32.W32APIOptions;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.stage.Stage;
import static com.sun.jna.platform.win32.WinUser.GWL_WNDPROC;
public class CustomWndProc {
public static void main(String[] args) {
CustomFrameApplication.launch(CustomFrameApplication.class, args);
}
public static class CustomFrameApplication extends Application {
#Override
public void start(Stage primaryStage) {
primaryStage.setScene(new Scene(new ProgressIndicator(ProgressIndicator.INDETERMINATE_PROGRESS)));
primaryStage.show();
HWND hwnd = new HWND();
hwnd.setPointer(User32.INSTANCE.GetActiveWindow().getPointer());
BaseTSD.LONG_PTR defaultWindowProc = User32.INSTANCE.GetWindowLongPtr(hwnd, GWL_WNDPROC);
WinUser.WindowProc windowProc = (hwnd1, uMsg, wParam, lParam) ->
User32Ex.INSTANCE.CallWindowProc(defaultWindowProc, hwnd1, uMsg, wParam, lParam);
User32Ex.INSTANCE.SetWindowLongPtr(hwnd, GWL_WNDPROC, windowProc);
}
}
public interface User32Ex extends User32 {
User32Ex INSTANCE = Native.load("user32", User32Ex.class, W32APIOptions.DEFAULT_OPTIONS);
Pointer SetWindowLongPtr(HWND hWnd, int nIndex, WindowProc wndProc);
LRESULT CallWindowProc(LONG_PTR proc, HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam);
}
}
Give it a few seconds or minutes and you won't be able to move, minimize, maximize or close the window anymore.
If you want guaranteed freeze, use a WebView instead of a ProgressIndicator:
WebView webView = new WebView();
webView.getEngine().load("https://www.google.com");
primaryStage.setScene(new Scene(webView));
I wondered if it has something to do that my code runs in the JavaFX Application thread (leading to some race condition) but I assume so does the default window procedure (how can I verify?).
I'm trying to build a JavaFX application that uses a custom frame.
Using JNA 5.5.0.
I think this is the right way to do it, but maybe I'm wrong..
I got the Information from:
Why my JNA using application doesn't react in a right way?
import com.sun.jna.LastErrorException;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.BaseTSD;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.win32.W32APIOptions;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.stage.Stage;
public class CustomWndProc {
public static void main(String[] args) {
CustomFrameApplication.launch(CustomFrameApplication.class, args);
}
public static class CustomFrameApplication extends Application {
private BaseTSD.LONG_PTR baseWndProc;
public User32Ex.WNDPROC listener = new User32Ex.WNDPROC() {
public WinDef.LRESULT callback(HWND hWnd, int uMsg, WinDef.WPARAM uParam,
WinDef.LPARAM lParam) {
// TODO handle the window message
// calling the base WndProc
return User32Ex.INSTANCE.CallWindowProc(baseWndProc, hWnd, uMsg, uParam, lParam);
}
};
#Override
public void start(Stage primaryStage) {
primaryStage.setScene(new Scene(new ProgressIndicator(ProgressIndicator.INDETERMINATE_PROGRESS)));
primaryStage.show();
HWND hwnd = new HWND();
hwnd.setPointer(User32.INSTANCE.GetActiveWindow().getPointer());
this.baseWndProc = User32Ex.INSTANCE.GetWindowLongPtr(hwnd, User32Ex.GWL_WNDPROC);
User32Ex.INSTANCE.SetWindowLongPtr(hwnd, User32Ex.GWL_WNDPROC, this.listener);
}
}
public interface User32Ex extends User32 {
User32Ex INSTANCE = Native.load("user32", User32Ex.class, W32APIOptions.DEFAULT_OPTIONS);
interface WNDPROC extends StdCallCallback {
LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam);
}
LONG_PTR GetWindowLongPtr(HWND hWnd, int nIndex) throws LastErrorException;
LRESULT CallWindowProc(LONG_PTR proc, HWND hWnd, int uMsg, WPARAM uParam, WinDef.LPARAM lParam) throws LastErrorException;
LONG_PTR SetWindowLongPtr(HWND hWnd, int nIndex, WNDPROC wndProc) throws LastErrorException;
}
}
Related
I need to turn off my monitor in code. I googled and found some code that should do it, but when I run this, nothing at all happens, and I just get a 0 WinAPI result. What am I doing wrong?
class Program
{
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern IntPtr GetDesktopWindow();
const int SC_MONITORPOWER = 0xF170;
const int WM_SYSCOMMAND = 0x0112;
const int MONITOR_OFF = 2;
static void Main(string[] args)
{
Console.WriteLine(
SendMessage(
GetDesktopWindow(),
WM_SYSCOMMAND,
(IntPtr) SC_MONITORPOWER,
(IntPtr) MONITOR_OFF));
Console.WriteLine("Hello World!");
}
}
From Fumbling around in the dark and stumbling across the wrong solution:
the desktop window is a very special window and as a rule should be avoided, since it won't behave like windows created by applications. In particular, the author tried to post a message to the desktop window. This used to work in the historically open world of the window manager, but security and robustness concerns have come to take priority over compatibility.
The real solution is to create your own window and send it the message, anything else is a hack.
If you don't mind hacks, at least try to find a suitable window:
[DllImport("user32.dll", SetLastError = false)]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
const int SC_MONITORPOWER = 0xF170;
const int WM_SYSCOMMAND = 0x0112;
const int MONITOR_OFF = 2;
static void Main(string[] args)
{
IntPtr w;
for (; IntPtr.Zero == (w = GetForegroundWindow());) System.Threading.Thread.Sleep(1000);
PostMessage(w, WM_SYSCOMMAND, (IntPtr) SC_MONITORPOWER, (IntPtr) MONITOR_OFF);
}
And because it is a hack there are where times it might not work. The window you are borrowing might be destroyed before you post the message. You might not have the right to send messages to it (UAC). Or it might decide to not pass this message to DefWindowProc.
Another slightly better hack is to create a temporary window:
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern int DestroyWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError=true)]
public static extern IntPtr CreateWindowEx(uint dwExStyle, string lpClassName, IntPtr cap, uint dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam);
const int SC_MONITORPOWER = 0xF170;
const int WM_SYSCOMMAND = 0x0112;
const int MONITOR_OFF = 2;
static void Main(string[] args)
{
IntPtr w = CreateWindowEx(0, "Button", IntPtr.Zero, 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
if (w != IntPtr.Zero)
{
SendMessage(w, WM_SYSCOMMAND, (IntPtr) SC_MONITORPOWER, (IntPtr) MONITOR_OFF);
DestroyWindow(w);
}
}
This is still somewhat of a hack because it never actually pumps messages.
I'm working on a custom shortcut but I'm facing the problem, that the key events do not fire when outlook 2013 is focused (with 2007 & 2010 it's working fine). So far, I've tried different solutions. This one seems to be the best so far, the following code is a global hook.
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc callback, IntPtr hInstance, uint threadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("user32.dll")]
static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x100;
private LowLevelKeyboardProc _proc = hookProc;
private static IntPtr hhook = IntPtr.Zero;
public void SetHook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, hInstance, 0);
}
public static IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
{
Debug.WriteLine("key event triggered");
//...
return CallNextHookEx(hhook, code, (int)wParam, lParam);
}
Im trying to get this thing to work all day.
Im trying to paste an input text to a textbox in another windows application, (lets say Chrome's URL bar)
I managed to get the main window hwnd, but when I used SendMessage, it just changed the title of the window
SO I am trying to figure out how exactly do I find out, dynamically, the hwnd of my textbox.
I also tried Spy++ but it gave me the same hwnd for all child windows for some reason, must did something wrong.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
private static IntPtr WinGetHandle(string wName)
{
IntPtr hWnd = IntPtr.Zero;
foreach (Process pList in Process.GetProcesses())
{
if (pList.MainWindowTitle.Contains(wName))
{
hWnd = pList.MainWindowHandle;
}
}
return hWnd;
}
static void Main(string[] args)
{
List<IntPtr> myList = GetChildWindows(WinGetHandle("chrome"));
foreach(IntPtr ptr in myList)
{
//No idea which one of those IntPtr is actually my textbox
//SendMessage((IntPtr)788018, 0x000C, 0, "text here");
}
Console.ReadLine();
}
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
return result;
}
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
GCHandle gch = GCHandle.FromIntPtr(pointer);
List<IntPtr> list = gch.Target as List<IntPtr>;
if (list == null)
{
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
}
list.Add(handle);
// You can modify this to check to see if you want to cancel the operation, then return a null here
return true;
}
public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
}
}
I also tried Spy++ but it gave me the same hwnd for all child windows
for some reason, must did something wrong.
Not all applications use old-school "heavy" controls backed by a windows handle. For example, .Net WPF applications will exhibit the same behavior of just one handle for the main window itself. Everything is else drawn directly to the screen as needed via DirectX. Web browsers are "light" as well and don't use controls backed by a handles. Basically if Spy++ doesn't show child windows inside the main window then you won't be able to use the traditional window manipulation APIs or SendMessage().
Sadly I couldnt find a way to make it the way I wanted, but I found a workaround that works pretty well:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
static void Main(string[] args)
{
IntPtr hWnd = FindWindow(null, "Origin");
if (!hWnd.Equals(IntPtr.Zero))
{
// activate Notepad window
if (SetForegroundWindow(hWnd))
{
// send "Hello World!"
SendKeys.SendWait("Hello World!");
// send key "Tab"
SendKeys.SendWait("{TAB}");
// send key "Enter"
SendKeys.SendWait("{ENTER}");
}
}
}
}
}
How can I get all handles of a window via Win32? I found this code but I don't know how is it work!
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
private List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
return result;
}
public interface User32Extra extends User32 {
User32Extra INSTANCE = (User32Extra) Native.loadLibrary("user32", User32Extra.class, W32APIOptions.DEFAULT_OPTIONS);
public HWND FindWindow(String string, String string1);
long SendMessageA(HWND hWnd, int msg, WPARAM wPAram, LPARAM lParam);
}
public class ecbot {
//http://msdn.microsoft.com/en-us/library/windows/desktop/ms645607(v=vs.85).aspx
private static int WM_KEYDOWN = 256;
public static void main(String[] args) {
HWND hWnd = User32.INSTANCE.FindWindow("Notepad", null);
System.out.println(hWnd.toString());
LPARAM lParam1 = new LPARAM(1);
LPARAM lParam0 = new LPARAM(0);
for (int i = 0; i < 1000; i++) {
WinDef.WPARAM wParam = new WinDef.WPARAM(i);
User32Extra.INSTANCE.SendMessageA(hWnd, WM_KEYDOWN, wParam, lParam1);
User32Extra.INSTANCE.SendMessageA(hWnd, WM_KEYDOWN, wParam, lParam0);
User32Extra.INSTANCE.SendMessageA(hWnd, WM_KEYDOWN, wParam, null);
}
}
}
I'm trying to send messages to key presses, looking for the right window handle but that message is not getting .... Why?((