JNA call PostMessage ~ passing String "Environment" - jna

http://www.codeguru.com/cpp/w-p/win32/tutorials/article.php/c10849/Setting-a-System-Environment-Variable.htm
SendMessage( HWND_BROADCAST , WM_SETTINGCHANGE , 0 , (LPARAM) "Environment" );
JNA and windows xp: call to notify that Environment has been changed
see link: twall.github.com/jna/3.5.1/javadoc/
see link: twall.github.com/jna/3.5.1/javadoc/com/sun/jna/platform/win32/User32.html
PostMessage(WinDef.HWND hWnd, int msg, WinDef.WPARAM wParam, WinDef.LPARAM lParam)
This function places a message in the message queue associated with the thread that created the specified window and then returns without waiting for the thread to process the message.
import com.sun.jna.*;
import com.sun.jna.win32.*;
import com.sun.jna.platform.win32.*;
import com.sun.jna.ptr.*;
public class MainJNA {
public static void main (String [] args){
String myString = "Environment";
Pointer myPointer = new Memory(myString.length()+1);
myPointer.setString(0,myString);
Pointer HWND_BROADCAST = new Pointer(0xFFFF);
int msg = 0x001A; // WM_SETTINGCHANGE = WM_WININICHANGE = 0x001A
WinDef.HWND hWnd = new WinDef.HWND( HWND_BROADCAST );
WinDef.WPARAM wParam = new WinDef.WPARAM(0);
WinDef.LPARAM lParam = new WinDef.LPARAM( myPointer.getLong(0) );
// Exception in thread "main" java.lang.IllegalArgumentException:
// Argument value 0x6d6e6f7269766e45 exceeds native capacity (4 bytes)
// mask=0xffffffff00000000
User32 user32 = (User32) Native.loadLibrary(
"user32" , User32.class , W32APIOptions.DEFAULT_OPTIONS );
user32.PostMessage( hWnd , msg , wParam , lParam );
}
} // end of class MainJNA
How to pass String parameter "Environment" to user32.PostMessage ???
And not to get Exception in thread "main" java.lang.IllegalArgumentException: Argument value 0x6d6e6f7269766e45 exceeds native capacity (4 bytes) mask=0xffffffff00000000
Thx

You're getting that error because you're trying to write a 64-bit value (myPointer.getLong(0)) into a 32-bit container (LPARAM).
You already have the pointer value you need for the LPARAM in myPointer; the recommended way to "cast" the pointer to LPARAM is to simply declare a version of PostMessage which takes an appropriately-typed fourth argument, e.g.
void PostMessage(WinDef.HWND hWnd, int msg, WinDef.WPARAM wParam, Pointer lParam);
void PostMessage(WinDef.HWND hWnd, int msg, WinDef.WPARAM wParam, String lParam);
This is preferable and more type-safe than manually converting between disparate types (i.e. from String or Pointer to an integer type).

Related

Cast LPARAM to a Java-Pojo

I have a c application and a java application. I communicate with jna to get results from the c program.
I Have a jna-Callback function:
public LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WinUserConstants.WM_GRAB_BASE:
System.out.println("WM_GRAB_BASE");
return new LRESULT(1);
case WinUserConstants.WM_GRAB_TRANSFER_FINISHED:
System.out.println("WM_GRAB_TRANSFER_FINISHED");
return new LRESULT(1);
case WinUserConstants.WM_GRAB_IMAGE_SAVED:
System.out.println("WM_GRAB_IMAGE_SAVED");
return new LRESULT(1);
default:
return User32.INSTANCE.DefWindowProc(hWnd, uMsg, wParam, lParam);
}
I need the WPARAM variable. I cant change the WPARAM to String. If i do that my window shows no controls.
WPARAM is defined as "HGLOBAL on memory containing (wchar_t *)filename". I need that filename and cant access the c code.
You can use WPARAM.toPointer().getWideString(0) to extract the string.
toPointer() effectively "casts" the WPARAM to a pointer value, from which you can then extract the (wide) native C string.

Parameters to use in a Vapi definition for passing arrays by reference

I have the following C code that uses libmodbus to read a single device register using ModbusTCP:
modbus_t *ctx;
uint16_t tab_reg[16];
ctx = modbus_new_tcp("10.0.1.77", 502);
modbus_read_registers(ctx, 0x20, 2, tab_reg);
printf("reg = %d (0x%X)\n", tab_reg[0], tab_reg[0]);
printf("reg = %d (0x%X)\n", tab_reg[1], tab_reg[1]);
now trying to switch this over to Vala using a Vapi that I've generated, the contents of that for new and read are:
[CCode (cheader_filename = "modbus.h", cname = "modbus_new_tcp")]
public static unowned Modbus.modbus_t create_tcp (string ip_address, int port);
public static int read_registers (Modbus.modbus_t ctx, int addr, int nb, uint16 dest);
[CCode (cheader_filename = "modbus.h")]
and the translated Vala program is:
class ModbusReadTest : GLib.Object {
unowned Modbus.modbus_t ctx;
public void run () {
uint16 reg = 0x00;
ctx = create_tcp ("10.0.1.77", 502);
Modbus.read_registers (ctx, 0x20, 2, reg);
message ("reg = %d (0x%X)", reg, reg);
Modbus.close(ctx);
}
}
Coincidentally, when I compile this into C code and then into a binary using gcc I get the error:
read-registers-test.c:71:2: warning: passing argument 4 of ‘modbus_read_registers’ makes pointer from integer without a cast [enabled by default]
which is not surprising. But I'm not sure how I should go about modifying the Vapi contents to closer match the prototype in the libmodbus header:
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
I've tried a mix of array options and using 'out', but haven't been able to get more than a single double byte register at a time.
read_registers should probably be an instance method (on Modbus.modbus_t) instead of a static method, and Modbus.modbus_t should probably be renamed to something like Modbus.Context, create_tcp should probably be a constructor, and Modbus.close should be a free function on the Modbus.Context compact class, but that's beside the point of this question (if you stop by #vala on irc.gnome.org you can get help with that stuff).
You probably want to make it an array:
public static int read_registers (Modbus.modbus_t ctx, int addr, [CCode (array_length_pos = 2.5)] uint16[] dest);
Then you would do something like this in Vala:
public void run () {
uint16 reg[2];
ctx = create_tcp ("10.0.1.77", 502);
Modbus.read_registers (ctx, 0x20, reg);
message ("reg = %d (0x%X)", reg, reg);
Modbus.close(ctx);
}
For a port more faithful to the original C (where tab_reg has 16 elements instead of 2), you could use array slicing:
public void run () {
uint16 reg[16];
ctx = create_tcp ("10.0.1.77", 502);
Modbus.read_registers (ctx, 0x20, reg[0:2]);
stdout.printf ("reg = %d (0x%X)\n", reg, reg);
Modbus.close(ctx);
}
Note that if you make it an instance method you'll need to change the array_length_pos to 1.5.

Retrieving item text with JNA and SendMessage()

I am attempting to retrieve the item text from a Win32 ListView-like control. I am using JNA and SendMessageW() to send LVM_GETITEMTEXTW to the control. I have been successful at retrieving the item count (via LVM_GETITEMCOUNT) but am stumped at this point. My User32 class is setup like so:
public interface MyUser32 extends User32 {
MyUser32 INSTANCE = (MyUser32)Native.loadLibrary("user32", MyUser32.class);
LRESULT SendMessageW(HWND hWnd, int msg, WPARAM wParam, LVITEM lParam);
}
My LVITEM class is setup like so:
public class LVITEM extends Structure{
public LVITEM() {
pszText = new Memory(MEMSIZE);
cchTextMax = MEMSIZE;
}
private static final int MEMSIZE = 256;
public UINT mask;
public int iItem;
public int iSubItem;
public UINT state;
public UINT stateMask;
public Pointer pszText;
public int cchTextMax;
public int iImage;
public LPARAM lParam;
public int iIndent;
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "mask", "iItem", "iSubItem", "state", "stateMask", "pszText", "cchTextMax", "iImage", "lParam", "iIndent"});
}
}
And the code that calls it all is like so:
MyUser32 u32 = MyUser32.INSTANCE;
LVITEM lvItem = new LVITEM();
WPARAM wPar = new WPARAM(1);
...
lvItem.iSubItem = 0;
res = u32.SendMessageW(handle, LVM_GETITEMTEXTW, wPar, lvItem);
System.out.println(res.intValue());
s = lvItem.pszText.getString(0);
System.out.println(s);
I've left out a bit of the code but I believe those are the important parts. My issue is that when I print out res.intValue() it is always 0 (meaning no text was returned) and when I print out the string value of pszText it is always some garbage characters. I'm completely stumped at this point so any suggestions are greatly appreciated. Thanks.

JNA - How to convert LPARAM pointer to a Class object?

I am novice jn JNA and am getting a bit confused with mixture of java and C++. In the WNDPROC callback method, the LPARAM is sent to the callback has to be used to retrive the DEV_BROADCAST_DEVICEINTERFACE class object. This is my code:
public static User32.WNDPROC WndProc = new User32.WNDPROC() {
#Override
public LRESULT callback(HWND hWnd, int uMSG, WPARAM uParam, LPARAM lParam)
{
User32.DEV_BROADCAST_DEVICEINTERFACE b = (User32.DEV_BROADCAST_DEVICEINTERFACE) lParam;
if(b != null){
System.out.println("Device Name: " + b.dbcc_name.toString ()); System.out.println("New Volume GUID:" + b.dbcc_classguid.toString());
}
}
The compiler begins to complain when I try to convert the lParam to class object, for obvious reasons. How do I achieve this?
You don't have to use LPARAM; if you're being passed a structure (or other specific type) by the native code, you can define the appropriate method signature and JNA will do the right thing, converting the native value into something useful in Java.
public LRESULT callback(HWND hWnd, int uMSG, WPARAM uParam, User32.DEV_BROADCAST_DEVICEINTERFACE lParam);

Pinvoke stack imbalance detected

I have the following function:
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, SPoint lParam);
It keeps complaining about Pinvoke stack imbalance when the following code executes:
SendMessage(EventRichTextBox.Handle, EM_GETSCROLLPOS, 0, OldScrollPoint);
What can cause that issue?
this is my SPoint
private struct SPoint
{
public Int32 x;
public Int32 y;
}
and
SPoint OldScrollPoint = default(SPoint);
Can't say for sure, but one obvious possibility is that you are on a 64 bit machine and int is the wrong type for wParam. It needs to be a 64 bit value in a 64 bit process.
We also have no idea how you have declared SPoint. You are meant to pass a pointer to a POINT struct. It doesn't look as though you have done that.
The correct signature is:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(
IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
Your edit clarifies that SPoint is a struct. This then is clearly wrong. You could simply pass the SPoint as an out parameter. That would be the simplest solution.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(
IntPtr hWnd, int Msg, IntPtr wParam, out SPoint lParam);
If you wanted a more general SendMessage signature then you should use IntPtr as I stated above and use Marshal.StructureToPtr.
The wParam argument should be IntPtr. But that's not what triggers the MDA, lying about the argument type is fine but you do have to do it correctly. Structures are passed by reference in the Windows api, declare the lParam argument as ref SPoint. Or out if the structure is returned, the case for EM_GETSCROLLPOS.

Resources