sikuli-driver team mailing list archive
-
sikuli-driver team
-
Mailing list archive
-
Message #28617
[Question #255504]: sikulixapi-1.1.0 Java only, JNA 4 sample code.
New question #255504 on Sikuli:
https://answers.launchpad.net/sikuli/+question/255504
I downloaded sikulixapi-1.1.0.jar a month ago, and I am using it for regression test of a Windows application. I must tell you that I am really, really happy with it. I've tried several other automation tools (AutoIT, QTP, SWTBot) but I think Sikuli is the most reliable. That's important because I hate debugging test cases.
Some functionality is missing in Sikuli. I cannot get the title of the App window. I cannot resize the App (except perhaps with dragdrop). I can't search all system top level windows, or all children windows of an App. I cannot get the App border width and title bar height.
However I can do all these things using JNA 4.0. Below is a class I wrote as a convenience to use JNA 4.0, enjoy.
import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Shell32;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinBase.PROCESS_INFORMATION;
import com.sun.jna.platform.win32.WinBase.STARTUPINFO;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.INT_PTR;
import com.sun.jna.platform.win32.WinDef.RECT;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.ptr.IntByReference;
/**
* This is a wrapper for the HWND type that is in JNA 4.0.
* PUBLIC DOMAIN
* @author John Henckel, Oct 2014
*/
public class Window
{
public HWND hWnd;
public Window(HWND hwnd)
{
this.hWnd = hwnd;
}
public boolean isNull()
{
return hWnd == null || hWnd.hashCode() == 0;
}
public static Window getForegroundWindow()
{
return new Window(User32.INSTANCE.GetForegroundWindow());
}
public void setForeground()
{
User32.INSTANCE.SetForegroundWindow(hWnd);
minimize();
restore();
}
/**
* Flash the window three times
*/
public void flash()
{
WinUser.FLASHWINFO pfwi = new WinUser.FLASHWINFO();
pfwi.cbSize = 20;
pfwi.hWnd = hWnd;
pfwi.dwFlags = 3; // 3 = FLASHW_ALL
pfwi.uCount = 3;
pfwi.dwTimeout = 250;
User32.INSTANCE.FlashWindowEx(pfwi);
sleep(1000);
}
/**
* Returns the class of the window, such as "SWT_Window0" for any SWT application. See AutoIt Window Info Tool
*/
public String getClassName()
{
char[] buffer = new char[2048];
User32.INSTANCE.GetClassName(hWnd, buffer, 1024);
return Native.toString(buffer);
}
public boolean isVisible()
{
return User32.INSTANCE.IsWindowVisible(hWnd);
}
/**
* 3=SW_MAXIMIZE, etc
*/
private void showWindow(int nCmdShow)
{
User32.INSTANCE.ShowWindow(hWnd, nCmdShow);
}
public void minimize()
{
showWindow(6);
}
public void maximize()
{
showWindow(3);
}
/**
* Activate and displays the window in normal mode (not minimized or maximized)
*/
public void restore()
{
showWindow(9);
}
/**
* Return true if the window message queue is idle, false if timeout
*/
public boolean waitForInputIdle(int timeout_ms)
{
IntByReference lpdwProcessId = new IntByReference();
User32.INSTANCE.GetWindowThreadProcessId(hWnd, lpdwProcessId);
return User32.INSTANCE.WaitForInputIdle(new HANDLE(lpdwProcessId.getPointer()), new DWORD(timeout_ms)).intValue() == 0;
}
public void setRectangle(Rectangle rect)
{
User32.INSTANCE.MoveWindow(hWnd, rect.x, rect.y, rect.width, rect.height, true);
}
public String getTitle()
{
char[] buffer = new char[2048];
User32.INSTANCE.GetWindowText(hWnd, buffer, 1024);
return Native.toString(buffer);
}
public int getProcessID()
{
IntByReference processID = new IntByReference();
User32.INSTANCE.GetWindowThreadProcessId(hWnd, processID);
return processID.getValue();
}
public Rectangle getRectangle()
{
RECT rect = new RECT();
User32.INSTANCE.GetWindowRect(hWnd, rect);
return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
}
/**
* In windows the user can customize the border and title bar size.
* @return x = border thickness in pixels, y = x + titlebar height
*/
public static Point getClientOffset()
{
return new Point(getBorderSize(), getTitleHeight());
}
/**
* In windows the user can customize the border and title bar size.
* @return titlebar height
*/
public static int getTitleHeight()
{
int f = User32.INSTANCE.GetSystemMetrics(33); // 33 = SM_CYSIZEFRAME
return User32.INSTANCE.GetSystemMetrics(4) + f; // 4 = SM_CYCAPTION
}
/**
* In windows the user can customize the border and title bar size.
* @return border thickness in pixels
*/
public static int getBorderSize()
{
int f = User32.INSTANCE.GetSystemMetrics(32); // 32 = SM_CXSIZEFRAME
return User32.INSTANCE.GetSystemMetrics(5) + f; // 5 = SM_CXBORDER
}
/**
* Find the FIRST top level window with specified class and title.
* @param className such as "SWT_Window0" or null
* @param title such as "QREADS" or null
* @return first window found, or null if not found.
*/
public static Window findWindow(String className, String title)
{
return new Window(User32.INSTANCE.FindWindow(className, title));
}
/**
* Get the next top-level window in Z-order, (from foreground to background).
*
* To iterate all windows, use
*
* for (Window w = getForegroundWindow(); !w.isNull(); w = w.next()) ...
*
* @return
*/
public Window next()
{
return new Window(User32.INSTANCE.GetWindow(hWnd, new DWORD(2))); // 2 = GW_HWNDNEXT
}
/**
* This is used to gather results of EnumWindows
*/
private static class WindowList implements WinUser.WNDENUMPROC
{
ArrayList<Window> list = new ArrayList<Window>();
Pattern titlePattern = null;
int processID;
@Override
public boolean callback(HWND hWnd, Pointer data)
{
Window w = new Window(hWnd);
if (titlePattern == null || titlePattern.matcher(w.getTitle()).matches())
{
if (processID == 0 || processID == w.getProcessID())
{
list.add(new Window(hWnd));
if (processID > 0)
{
return false; // if matching processID, only need one result
}
}
}
return true; // keep going
}
// Convert the list into an ordinary array
Window[] toArray()
{
return list.toArray(new Window[list.size()]);
}
}
public static Window[] getTopLevelWindows()
{
WindowList result = new WindowList();
User32.INSTANCE.EnumWindows(result, null);
return result.toArray();
}
public static Window[] getTopLevelWindows(String titleRegex)
{
WindowList result = new WindowList();
result.titlePattern = Pattern.compile(titleRegex);
User32.INSTANCE.EnumWindows(result, null);
return result.toArray();
}
public Window[] getChildren()
{
WindowList result = new WindowList();
User32.INSTANCE.EnumChildWindows(hWnd, result, null);
return result.toArray();
}
public static Window getProcessWindow(int processID)
{
WindowList result = new WindowList();
result.processID = processID;
User32.INSTANCE.EnumWindows(result, null);
return result.list.size() > 0 ? result.list.get(0) : null;
}
/**
* Sleep for milliseconds.
*/
public static void sleep(int milliseconds)
{
try
{
Thread.sleep(milliseconds);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
private static long getProcessHandle(Process process)
{
String n = process.getClass().getName();
if (n.equals("java.lang.ProcessImpl") || n.equals("java.lang.Win32Process"))
{
try
{
Field field = process.getClass().getDeclaredField("handle");
field.setAccessible(true);
return field.getLong(process);
}
catch (Exception e)
{
e.printStackTrace();
}
}
return 0;
}
public static int getProcessID(Process process)
{
long id = getProcessHandle(process);
if (id != 0)
{
HANDLE handle = new HANDLE();
handle.setPointer(Pointer.createConstant(id));
return Kernel32.INSTANCE.GetProcessId(handle);
}
return 0;
}
/**
* Runs a program and returns the process
*/
public static Process runCommand(List<String> cmdline) throws IOException
{
ProcessBuilder builder = new ProcessBuilder();
builder.command(cmdline).redirectErrorStream(true);
return builder.start();
}
/**
* Runs a program and returns the process
*/
public static Process runCommand(String... cmdline) throws IOException
{
return runCommand(Arrays.asList(cmdline));
}
/**
* Runs a program and returns the process id. Note: use runCommand instead of this.
*/
public static int createProcess(String program, String args, String currentDirectory)
{
STARTUPINFO startupInfo = new STARTUPINFO(); // input
PROCESS_INFORMATION processInformation = new PROCESS_INFORMATION(); // output
String cmdline = (args == null || args.length() == 0) ? null : program + " " + args;
boolean ok = Kernel32.INSTANCE.CreateProcess(program, cmdline, null, null, false, new DWORD(0), null, currentDirectory, startupInfo, processInformation);
if (!ok) System.out.println("CreateProcess failed err="+Kernel32.INSTANCE.GetLastError());
return processInformation.dwProcessId.intValue();
}
/**
* Note: use runCommand instead of this, if possible.
* Use this to open a program or any kind of file, like pdf, jpeg, html, etc.
* @return true on success.
*/
public static boolean shellExecute(String filename, String args, String currentDirectory)
{
String verb = null; // possible values 'open' (or null), 'edit', 'print', etc.
INT_PTR intPtr = Shell32.INSTANCE.ShellExecute(null, verb, filename, args, currentDirectory, 1); // 1=SW_SHOWNORMAL
int rc = intPtr.intValue();
if (rc <= 32) System.out.println("ShellExecute failed err="+rc+" for filename="+filename);
return rc > 32;
}
}
--
You received this question notification because you are a member of
Sikuli Drivers, which is an answer contact for Sikuli.