Re: JNA call RegisterDeviceNotification fails with error 1066

454 views
Skip to first unread message

Timothy Wall

unread,
Oct 3, 2012, 6:18:16 PM10/3/12
to Siva Rama Krishna (MT, BLR), jna-...@googlegroups.com
If your structure has array fields they need to be initialized before you try to do anything that requires the size of the structure to be known (like allocating its backing memory).

On Oct 3, 2012, at 7:10 AM, Siva Rama Krishna (MT, BLR) wrote:

> This is what I tried
>
> case MyUser32.DBT_DEVTYP_DEVICEINTERFACE:
> {
> int size = (devHDR.dbch_size - 28) / 2;
> DEV_BROADCAST_DEVICEINTERFACE devInterf = new DEV_BROADCAST_DEVICEINTERFACE(
> new Pointer(lParam.longValue()));
> Arrays.copyOf(devInterf.dbcc_name, size);
> String str = new String(devInterf.dbcc_name, 0,size);
> System.out.println("Device name : " + str);
>
> }
>
> And it is giving the error as follows :
>
> JNA: Callback com.merittrac.apollo.testplayer.maldetect.ExternalDeviceDetector$1@d7b7d9 threw the following exception:
> java.lang.IllegalStateException: Array fields must be initialized
> at com.sun.jna.Structure.deriveLayout(Structure.java:919)
> at com.sun.jna.Structure.calculateSize(Structure.java:827)
> at com.sun.jna.Structure.ensureAllocated(Structure.java:307)
> at com.sun.jna.Structure.ensureAllocated(Structure.java:294)
> at com.sun.jna.Structure.read(Structure.java:467)
> at com.merittrac.apollo.testplayer.maldetect.MyUser32$DEV_BROADCAST_DEVICEINTERFACE1.<init>(MyUser32.java:122)
> at com.merittrac.apollo.testplayer.maldetect.ExternalDeviceDetector$1.callback(ExternalDeviceDetector.java:172)
> at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> at java.lang.reflect.Method.invoke(Method.java:597)
> at com.sun.jna.CallbackReference$DefaultCallbackProxy.invokeCallback(CallbackReference.java:444)
> at com.sun.jna.CallbackReference$DefaultCallbackProxy.callback(CallbackReference.java:474)
> at sun.awt.windows.WToolkit.eventLoop(Native Method)
> at sun.awt.windows.WToolkit.run(WToolkit.java:291)
> at java.lang.Thread.run(Thread.java:619)
>
> can you explain me with some example...
>
> Thanks,
> Siva
>
>
> -----Original Message-----
> From: Timothy Wall [mailto:twal...@java.net]
> Sent: Wednesday, October 03, 2012 4:30 PM
> To: Siva Rama Krishna (MT, BLR)
> Subject: Re: JNA call RegisterDeviceNotification fails with error 1066
>
> You simply need to look up the name (as a String), extract the char[] from the String, and assign it to the structure field dbcc_name and adjust the dbcc_size.
>
> JNA includes utilities for manipulating the registry.
>
> On Oct 3, 2012, at 2:26 AM, Siva Rama Krishna (MT, BLR) wrote:
>
>> My DEV_BROADCAST_DEVICEINTERFACE1 structure in c# is as follows :
>>
>> [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
>> public struct DEV_BROADCAST_DEVICEINTERFACE1
>> {
>> public int dbcc_size;
>> public int dbcc_devicetype;
>> public int dbcc_reserved;
>> public Guid dbcc_classguid;
>> [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
>> public Char[] dbcc_name;
>> }
>> Thanks,
>> Siva.
>>
>> -----Original Message-----
>> From: Timothy Wall [mailto:twal...@java.net]
>> Sent: Monday, October 01, 2012 5:14 PM
>> To: iss...@jna.java.net
>> Cc: Siva Rama Krishna (MT, BLR)
>> Subject: Re: JNA call RegisterDeviceNotification fails with error 1066
>>
>> * Your return type is LONG, which is 32 bits, but should be of type HDEVNOTIFY, which is probably a pointer type.
>> * You might as well declare the second argument to be of type DEV_BROADCAST_DEVICEINTERFACE and pass the arg directly (instead of Structure.getPointer()).
>> * make sure you declare your structure field order (3.5.0 and later requires this; earlier depend on the JVM doing the expected thing if you don't specify it).
>> * dbcc_name might be char[] or byte[] depending on whether you're using ASCII/UNICODE mapping. You should probably initialize the name.
>>
>> On Oct 1, 2012, at 2:51 AM, Shankar Kommineni (MT, BLR) wrote:
>>
>>> Hi,
>>>
>>> We are attempting to register for notifications on USB device arrival
>>> and device remove complete events from a java application using JNA
>>> framework. But we seem to hit a problem with
>>> RegisterDeviceNotification
>>> () method which seems to throw error 1066 all the time. Can some shed some light on this issue?. Below is the sample code that we are using:
>>>
>>> JNA Version :: jna-3.4.1
>>>
>>> Interface File Declaration ::
>>>
>>> LONG RegisterDeviceNotification(HWND hWnd, Pointer pointer,int
>>> deviceNotifyWindowHandle); public static final int
>>> DBT_DEVTYP_DEVICEINTERFACE= 0x00000005; public static GUID[] arrGuid
>>> = new GUID[] {
>>> GUID_DEVINTERFACE_USB_DEVICE,Ole32Util.getGUIDFromString("{4d1e55b2-f
>>> 1
>>> 6f-11cf-88cb-001111000030}"),Ole32Util.getGUIDFromString("{53f56307-b
>>> 6
>>> bf-11d0-94f2-00a0c91efb8b}"),
>>> Ole32Util.getGUIDFromString("{784126bf-4190-11d4-b5c2-00c04f687a67}")
>>> ,
>>> Ole32Util.getGUIDFromString("{4D36E96B-E325-11CE-BFC1-08002BE10318}")
>>> };
>>>
>>> Notification Registration Code :
>>>
>>> HWND hWnd = new HWND();
>>> hWnd.setPointer(Native.getWindowPointer(window));
>>>
>>> DEV_BROADCAST_DEVICEINTERFACE filter = new
>>> DEV_BROADCAST_DEVICEINTERFACE(); filter.dbcc_devicetype = new
>>> DWORD(MyUser32.DBT_DEVTYP_DEVICEINTERFACE);
>>> filter.dbcc_name = new char[1];
>>> filter.dbcc_reserved = new DWORD(0);
>>> filter.dbcc_size = new DWORD(filter.size());
>>>
>>> for(int i=0;i<MyUser32.arrGuid.length;i++)
>>> {
>>> filter.dbcc_classguid = MyUser32.arrGuid[i];
>>> LONG retVal = MyUser32.MYINSTANCE.RegisterDeviceNotification(hWnd, filter.getPointer(), MyUser32.DEVICE_NOTIFY_WINDOW_HANDLE);
>>> if (retVal.longValue() == 0)
>>> {
>>> System.out.println("Error registering for usb: " + Native.getLastError());
>>> }
>>> else
>>> {
>>> System.out.println("Returned value 0 for registerDeviceNotifcation"+retVal.longValue());
>>> }
>>> }
>>>
>>> Let us know if you need any more information.
>>>
>>> Thanks
>>> Shankar
>>> Mailgate Notification
>>> ---------------------------------------------------------------------
>>> The information in this email is confidential and is intended solely for the addressee(s). Access to this email by anyone else is unauthorized. If you are not an intended recipient, you must not use or disseminate the information contained in this email.
>>> ---------------------------------------------------------------------
>>>
>>
>>
>> Mailgate Notification
>> ---------------------------------------------------------------------
>> The information in this email is confidential and is intended solely for the addressee(s). Access to this email by anyone else is unauthorized. If you are not an intended recipient, you must not use or disseminate the information contained in this email.
>> ---------------------------------------------------------------------
>>
>
>
> Mailgate Notification
> ---------------------------------------------------------------------
> The information in this email is confidential and is intended solely for the addressee(s). Access to this email by anyone else is unauthorized. If you are not an intended recipient, you must not use or disseminate the information contained in this email.
> ---------------------------------------------------------------------
>

Timothy Wall

unread,
Oct 3, 2012, 6:25:05 PM10/3/12
to Siva Rama Krishna (MT, BLR), jna-...@googlegroups.com
If the size of an array field is unknown (or may be unknown, as in the case where it is passed to a callback or otherwise initialized from an existing pointer), you need to initialize the field to its smallest value, and then adjust it as necessary, e.g.

> public DEV_BROADCAST_DEVICEINTERFACE(Pointer base) {
> super(base);
this.dbcc_size = (int)readField("dbcc_size");
// figure out how long dbcc_name should be based on the size
int len = this.dbcc_size - size() + 1;
this.dbcc_name = new char[len];
> read();
> }
>
> public DWORD dbcc_size;
> public DWORD dbcc_devicetype;
> public DWORD dbcc_reserved;
> public GUID dbcc_classguid;
> public char[] dbcc_name = new char[1];


On Oct 3, 2012, at 9:18 AM, Siva Rama Krishna (MT, BLR) wrote:

> On the whole we are trying to get the connected USB device name(friendly name from registry) for that we registered the USB device GUID and we are getting the WM_DEVICECHANGE event and now based on the WPARAM value we are able to know whether it is ARRIVAL or REMOVAL after that we are initializing the DEV_BROADCAST_HDR as follows :
>
> DEV_BROADCAST_HDR devHDR = new DEV_BROADCAST_HDR(new Pointer(lParam.longValue()));
>
> Then DEV_BROADCAST_HDR structure is getting initialized and based on the dbch_DeviceType parameter we are writing a switch case as follows :
>
> switch (devHDR.dbch_DeviceType)
> {
> case MyUser32.DBT_DEVTYP_VOLUME:
> {
> DEV_BROADCAST_VOLUME pVol = new DEV_BROADCAST_VOLUME(new Pointer(lParam.longValue()));
>
> char cDriveLetter = GetDriveLetter(pVol.dbcv_unitmask);
> System.out.println("Device has been inserted."+ cDriveLetter);
> popUpFrame = getInitializedPopUPFrame(storage_device);
> popUpFrame.setVisible(true);
> break;
> }
> case MyUser32.DBT_DEVTYP_PORT:
> {
> // TODO
> }
> case MyUser32.DBT_DEVTYP_DEVICEINTERFACE:
> {
> // TODO
> int size = (devHDR.dbch_size - 28) / 2;
> DEV_BROADCAST_DEVICEINTERFACE devInterf = new DEV_BROADCAST_DEVICEINTERFACE(new Pointer(lParam.longValue())); // giving me the error
> Arrays.copyOf(devInterf.dbcc_name, size);
> String str = new String(devInterf.dbcc_name, 0 , size);
> System.out.println("Device name : " + devInterf.dbcc_name);
> }
> }
>
> The code under DBT_DEVTYP_VOLUME is working fine but the code under DBT_DEVTYP_DEVICEINTERFACE is giving the error as follows :
>
> JNA: Callback com.merittrac.apollo.testplayer.maldetect.ExternalDeviceDetector$1@1e4a47e threw the following exception:
> java.lang.IllegalStateException: Array fields must be initialized
> at com.sun.jna.Structure.deriveLayout(Structure.java:919)
> at com.sun.jna.Structure.calculateSize(Structure.java:827)
> at com.sun.jna.Structure.ensureAllocated(Structure.java:307)
> at com.sun.jna.Structure.ensureAllocated(Structure.java:294)
> at com.sun.jna.Structure.read(Structure.java:467)
> at com.merittrac.apollo.testplayer.maldetect.MyUser32$DEV_BROADCAST_DEVICEINTERFACE.<init>(MyUser32.java:107)
> at com.merittrac.apollo.testplayer.maldetect.ExternalDeviceDetector$1.callback(ExternalDeviceDetector.java:175)
> at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> at java.lang.reflect.Method.invoke(Method.java:597)
> at com.sun.jna.CallbackReference$DefaultCallbackProxy.invokeCallback(CallbackReference.java:444)
> at com.sun.jna.CallbackReference$DefaultCallbackProxy.callback(CallbackReference.java:474)
> at sun.awt.windows.WToolkit.eventLoop(Native Method)
> at sun.awt.windows.WToolkit.run(WToolkit.java:291)
> at java.lang.Thread.run(Thread.java:619)
>
>
> Structure definitions in my interface class are :
>
> public static class DEV_BROADCAST_HDR extends Structure
> {
> public DEV_BROADCAST_HDR() {
> super();
> }
>
> public DEV_BROADCAST_HDR(Pointer base) {
> super(base);
> read();
> }
>
> public int dbch_size;
> public int dbch_DeviceType;
> public int dbch_reserved;
> }
>
> public static class DEV_BROADCAST_VOLUME extends Structure {
> public DEV_BROADCAST_VOLUME() {
> super();
> }
>
> public DEV_BROADCAST_VOLUME(Pointer base) {
> super(base);
> read();
> }
>
> public int dbcv_size;
> public int dbcv_devicetype;
> public int dbcv_reserved;
> public int dbcv_unitmask;
> public int dbcv_flags;
> }
>
> public static class DEV_BROADCAST_DEVICEINTERFACE extends Structure {
> public DEV_BROADCAST_DEVICEINTERFACE() {
> super();
> }
>
> public DEV_BROADCAST_DEVICEINTERFACE(Pointer base) {
> //useMemory(base);
> super(base);
> read();
> }
>
> public DWORD dbcc_size;
> public DWORD dbcc_devicetype;
> public DWORD dbcc_reserved;
> public GUID dbcc_classguid;
> public char[] dbcc_name;
> };
>
> I was a bit confused that the statement
> DEV_BROADCAST_VOLUME pVol = new DEV_BROADCAST_VOLUME(new Pointer(lParam.longValue())); is working fine but the statement
> DEV_BROADCAST_DEVICEINTERFACE devInterf = new DEV_BROADCAST_DEVICEINTERFACE(new Pointer(lParam.longValue())); giving me the error.
>
> And finally the callback function is :
>
> interface WNDPROC extends StdCallCallback {
> LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam);
> }
>
> Let us know if you need any more information.
>

Timothy Wall

unread,
Oct 19, 2012, 7:18:25 AM10/19/12
to Siva Rama Krishna (MT, BLR), jna-...@googlegroups.com
The DLL you attempt to load must match the architecture of the JVM you're loading from.

64-bit DLLs only load under 64-bit JVMs, 32-bit DLLs only load under 32-bit JVMs. This has nothing to do with Java, and everything to do with restrictions of the OS. I'm not aware of any common OS that lets you do otherwise.

On Oct 19, 2012, at 3:22 AM, Siva Rama Krishna (MT, BLR) wrote:

> Hi wall,
>
> Need to know one thing :
>
> Does jna is capable of loading native libraries based on the JVM(32-bit or 64-bit)?
>
> I worked on a module which detects the connected usb devices which works fine for me if I run it under 32 bit JVM but fails under 64 bit JVM.

Timothy Wall

unread,
Oct 19, 2012, 9:09:59 AM10/19/12
to jna-...@googlegroups.com, Siva Rama Krishna (MT, BLR)
I believe that's the recommended approach according to MSDN anyway. XLongX deals with 32-bit quantities (on either platform), while XLongPtrX deals with pointer-sized quantities.

On Oct 19, 2012, at 7:55 AM, Siva Rama Krishna (MT, BLR) wrote:

> Ok ,thanks for the reply I'm able to solve my problem for now
>
> The problem is with "GetWindowLongW" and "SetWindowLongW" methods which are executing perfectly in 32 bit JVM but they are not working under 64 bit JVM fails with 1413 error code(Invalid Index).But there are two more methods "GetWindowLongPtrW" and "SetWindowLongPtrW" which are similar to the above methods through which I'm able to run my application under 64 bit JVM.
>
> So, finally I'm switching between these methods based on the JVM architechture.
>
> Regards,
> Siva ram.

Tobias Wolf

unread,
Dec 7, 2012, 8:44:00 AM12/7/12
to jna-...@googlegroups.com, Siva Rama Krishna (MT, BLR)
I`m working currently on a JNA example which will be commited soon. Is the issue still open? Let me know!

Timothy Wall

unread,
Dec 7, 2012, 8:53:54 AM12/7/12
to jna-...@googlegroups.com, Siva Rama Krishna (MT, BLR)
This isn't a JNA issue.

Arrays within a structure must be initialized before the structure layout information is required.

Tobias Wolf

unread,
Dec 7, 2012, 9:10:44 AM12/7/12
to jna-...@googlegroups.com, Siva Rama Krishna (MT, BLR)
I get the following issue, dbcc_name should be an char Array, but it seems to me a pointer? How can I get the value as char array or as string?
 

dbcc_devicetype: 5

dbcc_name: [C@d377df

dbcc_classguid: {10BFDCA5-3065-D211-901F-00C04FB951ED}

public class DEV_BROADCAST_DEVICEINTERFACE extends Structure {

/** The dbcc_size. */

public int dbcc_size;

/** The dbcc_devicetype. */

public int dbcc_devicetype;

/** The dbcc_reserved. */

public int dbcc_reserved;

/** The dbcc_classguid. */

public GUID dbcc_classguid;

/** The dbcc_name. */

public char[] dbcc_name = new char[1];

/**

* Instantiates a new dev broadcast deviceinterface.

*/

public DEV_BROADCAST_DEVICEINTERFACE() {

// TODO Auto-generated constructor stub

}

/**

* Dev broadcast hdr.

*

*

@param pointer

* the pointer

*/

public DEV_BROADCAST_DEVICEINTERFACE(long pointer) {

this(new Pointer(pointer));

}

/**

* Instantiates a new dev broadcast deviceinterface.

*

*

@param memory

* the memory

*/

public DEV_BROADCAST_DEVICEINTERFACE(Pointer memory) {

super(memory);

this.dbcc_size = this.size();

read();

}

/*

* (non-Javadoc)

*

* @see com.sun.jna.Structure#getFieldOrder()

*/

protected List getFieldOrder() {

return Arrays.asList(new String[] { "dbcc_size", "dbcc_devicetype",

"dbcc_reserved", "dbcc_classguid", "dbcc_name" });

}

}

Tobias Wolf

unread,
Dec 7, 2012, 9:48:46 AM12/7/12
to jna-...@googlegroups.com, Siva Rama Krishna (MT, BLR)
Yes you are right, now is working....But do you know how I could cut the char array to the usage chars?
 
currently the result is:
 

this.dbcc_size = (Integer)this.readField("dbcc_size");

// figure out how long dbcc_name should be based on the size

int len = this.dbcc_size - (size() + 1);

this.dbcc_name = new char[len];

read();

Timothy Wall

unread,
Dec 7, 2012, 10:02:11 AM12/7/12
to jna-...@googlegroups.com, Siva Rama Krishna (MT, BLR)

On Dec 7, 2012, at 9:10 AM, Tobias Wolf wrote:

> I get the following issue, dbcc_name should be an char Array, but it seems to me a pointer? How can I get the value as char array or as string?
>
> dbcc_devicetype: 5
>
> dbcc_name: [C@d377df

This is just an array of Java char (make sure you're using the unicode version of your functions)

>
> dbcc_classguid: {10BFDCA5-3065-D211-901F-00C04FB951ED}
>
> public class DEV_BROADCAST_DEVICEINTERFACE extends Structure {
>
> /** The dbcc_size. */
> public int dbcc_size;
>
> /** The dbcc_devicetype. */
> public int dbcc_devicetype;
>
> /** The dbcc_reserved. */
> public int dbcc_reserved;
>
> /** The dbcc_classguid. */
> public GUID dbcc_classguid;
>
> /** The dbcc_name. */
> public char[] dbcc_name = new char[1];
>
> public DEV_BROADCAST_DEVICEINTERFACE(Pointer memory) {
> super(memory);
> this.dbcc_size = this.size();

This is incorrect. Since you're initializing from native, you don't know how big the structure is. Read the actual memory size from memory, then set your character array size accordingly.

this.dbcc_size = memory.getInt(0);
this.dbcc_name = new char[this.dbcc_size - this.size() + 1];
calculateSize();

> read();

Timothy Wall

unread,
Dec 7, 2012, 10:05:56 AM12/7/12
to jna-...@googlegroups.com, Siva Rama Krishna (MT, BLR)
Use Native.toString(char[]) to extract the string and terminate it at the first NUL character.

Timothy Wall

unread,
Dec 7, 2012, 10:08:17 AM12/7/12
to jna-...@googlegroups.com, Siva Rama Krishna (MT, BLR)

On Dec 7, 2012, at 9:48 AM, Tobias Wolf wrote:

> this.dbcc_size = (Integer)this.readField("dbcc_size");
>
> // figure out how long dbcc_name should be based on the size
>
> int len = this.dbcc_size - (size() + 1);

int len = 1 + this.dbcc_size - size();


Reply all
Reply to author
Forward
0 new messages