I need to get the index of a Network Interface in Windows.
There is NetworkInterface.getIndex() method to do this, but it's only available starting Java 7.
The requirement from the Boss is that the app needs to run in Java 6.
After some searching, I found JNA lib to call Win API functions.
The function itself is GetIfTable (http://msdn.microsoft.com/en-us/library/windows/desktop/aa365943(v=vs.85).aspx)
However, I've not been able to successfully call this function using JNA.
The return value of GetIfTable is always 122 which means ERROR_INSUFFICIENT_BUFFER. Even if I keep adding buffer it still says insufficient buffer, until when the supplied value reach certain number, then "Invalid memory access" error shows up.
Here's what I already did:
public interface IpHlpAPI extends StdCallLibrary {
IpHlpAPI INSTANCE = (IpHlpAPI) Native.loadLibrary("IpHlpAPI", IpHlpAPI.class);
public static class MIB_IFTABLE extends Structure {
public int dwNumEntries;
public MIB_IFROW table[] = new IpHlpAPI.MIB_IFROW[1];
public MIB_IFTABLE() {}
public MIB_IFTABLE(int size) {
this.allocateMemory(size);
}
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"dwNumEntries", "table"});
}
}
public static class MIB_IFROW extends Structure {
public char wszName[] = new char[256];
public int dwIndex;
public int dwType;
public int dwMtu;
public int dwSpeed;
public int dwPhysAddrLen;
public byte bPhysAddr[] = new byte[8];
public int dwAdminStatus;
public int dwOperStatus;
public int dwLastChange;
public int dwInOctets;
public int dwInUcastPkts;
public int dwInNUcastPkts;
public int dwInDiscards;
public int dwInErrors;
public int dwInUnknownProtos;
public int dwOutOctets;
public int dwOutUcastPkts;
public int dwOutNUcastPkts;
public int dwOutDiscards;
public int dwOutErrors;
public int dwOutQLen;
public int dwDescrLen;
public byte bDescr[] = new byte[256];
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"wszName", "dwIndex", "dwType", "dwMtu",
"dwSpeed", "dwPhysAddrLen", "bPhysAddr", "dwAdminStatus", "dwOperStatus",
"dwLastChange", "dwInOctets", "dwInUcastPkts", "dwInNUcastPkts", "dwInDiscards",
"dwInErrors", "dwInUnknownProtos", "dwOutOctets", "dwOutUcastPkts",
"dwOutNUcastPkts", "dwOutDiscards", "dwOutErrors", "dwOutQLen", "dwDescrLen", "bDescr"});
}
}
int GetIfTable(MIB_IFTABLE pIfTable, IntByReference pdwSize, boolean bOrder);
}
public static void main(String[] args) {
IpHlpAPI ipHlpApi = IpHlpAPI.INSTANCE;
IpHlpAPI.MIB_IFTABLE ifTable = new IpHlpAPI.MIB_IFTABLE();
IntByReference psize = new IntByReference(ifTable.size());
int status = ipHlpApi.GetIfTable(ifTable, psize, false);
if (status == 122) {
// Calculate the required number of elements in the MIB_IFROW array
ifTable = new IpHlpAPI.MIB_IFTABLE((psize.getValue() - 4) / ifTable.table[0].size());
psize.setValue(ifTable.size());
status = ipHlpApi.GetIfTable(ifTable, psize, false);
System.out.println(status);
}
System.exit(0);
}
Any ideas why is this happening?
Your input structure isn't large enough. You need to reallocate the table field to be sufficiently large based on the value returned in the pdwSize parameter.
Add a constructor to MIB_IFTABLE that indicates the size of the table array and initializes it accordingly. That will automatically give you a bigger buffer.
MIB_IFTABLE ifTable = new MIB_IFTABLE();
IntByReference psize = new IntByReference(ifTable.size());
int status = ipHlpApi.GetIfTable(ifTable, psize, false);
if (status == 122) {
// Calculate the required number of elements in the MIB_IFROW array
ifTable = new MIB_IFTABLE((psize.getValue() - 4) / ifTable.table[0].size());
psize.setValue(ifTable.size());
status = ipHlpApi.GetIfTable(ifTable, psize, false);
// If status is still 122, then there's an issue with the MIB_IFROW definition
// ...
}
EDIT
Change your constructor:
public MIB_IFTABLE(int nentries) {
this.dwNumEntries = nentries;
this.table = (MIB_IFROW[])new MIB_IFROW().toArray(nentries);
}
You should probably initialize your other ctor to have a default value for dwNumEntries; as it is you'll be passing in a default value of zero, which will guarantee you get a return value of 122 on the first call. I'm assuming dwNumEntries refers to the size of the array.
Related
I am invoking the win32 API function GetMenuItemInfoW. When I invoke the function I it returns false, and Native.getLastError() returns 87:
ERROR_INVALID_PARAMETER 87 (0x57) The parameter is incorrect.
I think that my error is in my implementation of the structure MenuItemInfoW:
#Structure.FieldOrder({"cbSize", "fMask", "fType", "fState", "wId", "hSubMenu", "hBmpChecked", "hBmpUnchecked", "dwItemData", "dwTypeData", "cch", "hbmpItem"})
public class MENUITEMINFOW extends Structure {
public int cbSize;
public int fMask;
public int fType;
public int fState;
public int wId;
public Pointer hSubMenu;
public Pointer hBmpChecked;
public Pointer hBmpUnchecked;
public WinDef.ULONGByReference dwItemData;
public WString dwTypeData;
public int cch;
public Pointer hbmpItem;
public MENUITEMINFOW() {
super();
}
public MENUITEMINFOW(Pointer pointer) {
super(pointer);
}
}
And this is my code for invoking the function:
MENUITEMINFOW menuiteminfow = new MENUITEMINFOW();
menuiteminfow.fMask = 0x00000040 | 0x00000080 | 0x00000004 | 0x00000002;
menuiteminfow.fType = 0x00000000;
menuiteminfow.cch = 256;
menuiteminfow.dwTypeData = new WString(String.join("", Collections.nCopies(256, " ")));
menuiteminfow.cbSize = Native.getNativeSize(menuiteminfow.getClass());
WinDef.BOOL result = User32Ex.INSTANCE.GetMenuItemInfoW(hMenu.getPointer(), 0, true, menuiteminfow.getPointer());
if (!result.booleanValue()) {
int errorCode = Native.getLastError();
System.out.println("Error Code: " + errorCode);
}
I have edited my editing my code for your tip, but I get the same error 87. This is my new code:
MENUITEMINFOW menuiteminfow = new MENUITEMINFOW();
menuiteminfow.fMask = 0x00000040 | 0x00000080 | 0x00000004 | 0x00000002;
menuiteminfow.fType = 0x00000000;
menuiteminfow.cch = 0;
menuiteminfow.dwTypeData = Pointer.NULL;
menuiteminfow.cbSize = Native.getNativeSize(menuiteminfow.getClass());
WinDef.BOOL result = User32Ex.INSTANCE.GetMenuItemInfoW(hMenu.getPointer(),
new WinDef.UINT(0), new WinDef.BOOL(true), menuiteminfow.getPointer());
if (!result.booleanValue()) {
int errorCode = Native.getLastError();
System.out.println("Error Code: " + errorCode);
}
And this is new version of my structure:
#Structure.FieldOrder({"cbSize", "fMask", "fType", "fState", "wId", "hSubMenu", "hBmpChecked", "hBmpUnchecked", "dwItemData", "dwTypeData", "cch", "hbmpItem"})
public class MENUITEMINFOW extends Structure {
public int cbSize;
public int fMask;
public int fType;
public int fState;
public int wId;
public Pointer hSubMenu;
public Pointer hBmpChecked;
public Pointer hBmpUnchecked;
public BaseTSD.LONG_PTR dwItemData;
public Pointer dwTypeData;
public int cch;
public WinDef.HBITMAP hbmpItem;
public MENUITEMINFOW() {
super();
}
public MENUITEMINFOW(Pointer pointer) {
super(pointer);
this.read();
}
}
Thank you for your response.
Your structure mapping can be improved.
First, a ULONG_PTR is not the same as a WinDef.ULONGByReference. The ULONG_PTR is a pointer-sized value, but it does not actually point to anything.
JNA has a built-in BaseTSD.LONG_PTR type which you could use here.
While a Pointer technically works for hbmpItem and the other bitmap fields, the type WinDef.HBITMAP is already defined in JNA so you should use that mapping.
Finally, and the likely cause of your error, dwTypeData receives a String, but it is a buffer that you need to allocate and fill. From the MENUITEMINFO docs:
To retrieve a menu item of type MFT_STRING, first find the size of the string by setting the dwTypeData member of MENUITEMINFO to NULL and then calling GetMenuItemInfo. The value of cch+1 is the size needed. Then allocate a buffer of this size, place the pointer to the buffer in dwTypeData, increment cch, and call GetMenuItemInfo once again to fill the buffer with the string.
So in this case, you'd want to map a Pointer to dwTypeData, call the function the first time with that pointer set to Pointer.NULL, and then alloating memory for it based on incrementing cch:
menuiteminfow.cch++;
// allocate 2 bytes per widechar
menuiteminfow.dwTypeData = new Memory(cch * 2);
You can fetch the string from there after the function call with menuiteminfow.dwTypeData.getWideString().
I wrote some classes in Java but when I run the program I receive the error "ArrayIndexOutOfBoundsException", the incriminate class is this:
public class Bank {
private String name;
private int maxbankaccount;
private int activebankaccount;
private String radice = "IT8634";
private Conto[] bankaccount = new Conto[maxbankaccount];
public void addconto(String cf) {
bankaccount[activebankaccount] = new Conto(radice + activebankaccount , cf);
activebankaccount++;
}
public Bank(String name, int maxbankaccount) {
this.name = name;
this.maxbankaccount = maxbankaccount;
}
}
I wrote a tester class to test :
public class TestBank {
public static void main (String[] args) {
Bank b1 = new Bank("Fidelity", 10);
b1.addconto("PROVA");
}
}
Since I didn't seem to have made logical errors using the array I debugged, I realized that in the creation of the array of objects the maxbankaccount variable isn't 10 (value passed in Test) but as default value (0),then I tried passing 10 directly and it works good. Why is not the value 10 of maxbankaccount passed but 0?
private Conto[] bankaccount = new Conto[maxbankaccount];
This initialization takes place before the rest of the constructor runs.
Move it into the constructor:
public Bank(String name, int maxbankaccount) {
this.name = name;
this.maxbankaccount = maxbankaccount;
this.bankaccount = new Conto[maxbankaccount];
}
You have indeed made a logical error. The array bankaccount is getting initialized when the class is instantiated and is always 0.
Move it into the constructor and initialize it.
public Bank(String name, int maxbankaccount) {
/* ... */
this.bankaccount = new Conto[maxbankaccount];
}
Further more than the issues that are in the other answers, this
private int activebankaccount;
does not initialize the variable activebankaccount
So in:
public void addconto(String cf) {
bankaccount[activebankaccount] = new Conto(radice + activebankaccount , cf);
activebankaccount++;
}
you are using an uninitialized vale as index of the array bankaccount
I have a java class called Player. The mechanics on how the player file interacts with the server would take a lot to explain and I have no issues with the file, I just want to improve it and better my programming skills. So my question is, how would I take the many variables I have, ints, strings, booleans and make the code faster and more efficient/cleaner. Here is an example so you can see what the file looks like
enter code here
public boolean usingGlory = false;
public int[] woodcut = new int [3];
public int wcTimer = 0;
public int[] mining = new int [3];
public int miningTimer = 0;
public boolean fishing = false;
public int fishtimer = 0;
public int fishXP;
public int fishies = 0;
public int fishreqt = 0;
public int fishitem = 0;
public int fishemote = 0;
public int fishies2 = 0;
public int fishreq2 = 0;
public boolean isfishing = false;
public boolean attemptingfish = false;
public int smeltType; //1 = bronze, 2 = iron, 3 = steel, 4 = gold, 5 = mith, 6 = addy, 7 = rune
public int smeltAmount;
public int smeltTimer = 0;
public boolean smeltInterface;
public boolean patchCleared;
public int[] farm = new int[2];
public boolean antiFirePot = false;
public boolean Lattack = false;
public boolean Lranged = false;
public boolean Lmagic = false;
public boolean Ldefense = false;
public boolean Lstrength = false;
public boolean Lspecial = false;
public boolean inPits = false;
public int pitsStatus = 0;
public boolean inFunPk = false;
public boolean InDung = false;
You can break down the data into several classes, each of which contains information on a specific area.
For example, here, you have a group of variables that are related to fishing - these can be grouped into e.g. a FishingComponent class. There's also a group of information on smelting that could be split into a SmeltingComponent class, and so forth. This may lead to making the code more readable by taking groups of closely related information and functionality into their own classes.
For reusability's sake, you may wish to use an entity component system. These are popular in games programming as they allow the makeup of objects to be customised more than just inheritance. If there is, for example, an NPC that may hold information on fishing but does not have stats, the fishing component may be added to the NPC entity, and all of the code relating to fishing may be re-used.
You also mention making the code faster - unless you have a specific performance problem, you are probably attempting to prematurely optimise. However, you may wish to look into pooling objects if they need to be garbage collected a lot, as in games written in garbage collected languages, garbage collection cycles can be one of the biggest cause of framedrops.
You might want to apply two common OOP techniques: encapsulation and composition. First of all, it's bad practice to have a bunch of public fields in your class. Instead, encapsulate them using getter and setter methods. Here's an example for the first two variables:
private boolean usingGlory = false;
public boolean isUsingGlory() {
return usingGlory;
}
public void setUsingGlory(boolean using) {
usingGlory = using;
}
private int[] woodcut = new int[3];
public int[] getWoodcut() {
return woodcut;
}
public void setWoodcut(int[] woodcut) {
this.woodcut = woodcut;
}
For more info, see Wikipedia.
The second technique is composition. You're right not to like having so many variables in your class. Instead of having all the variables be part of the Player class, group them into classes containing related items. You can even group methods, when appropriate! Here's an example that uses your fishing variables:
public class Player {
//...
private FishingState fishingState = new FishingState();
//Getter and setter
//...
}
public class FishingState {
private boolean fishing = false;
private int timer = 0;
private int XP;
private int fishies = 0;
private int reqt = 0;
private int item = 0;
private int emote = 0;
private int fishies2 = 0;
private int req2 = 0;
//Getters and setters
//A constructor and some methods:
public FishingState(int XP) {
this.XP = XP;
}
public void resetTimer() {
timer = 0;
}
}
Now, player.fishemote = 3 becomes player.getFishingState().setEmote(3). Longer, but clearer.
I am working on a windows device manager which will work with java.
I stick on trying to pass without error SetupDiSetClassInstallParams function. (I am trying disable an device.)
I am running exact same structure(necessary way) in C++ and I do not have any problem.
I am getting ERROR_INVALID_USER_BUFFER error. When I tried get this error in C++ I need to change SP_PROPCHANGE_PARAMS structs values with wrong ones.
My struct declerations:
public static class SP_CLASSINSTALL_HEADER extends Structure {
public static class ByReference extends SP_CLASSINSTALL_HEADER implements Structure.ByReference {
public ByReference() {
}
public ByReference(Pointer memory) {
super(memory);
}
}
public SP_CLASSINSTALL_HEADER() {
cbSize = size();
}
public SP_CLASSINSTALL_HEADER(Pointer memory) {
super(memory);
read();
}
public int cbSize;
public long InstallFunction; **/* <-- this should be int or else buffer size changes, dll cannot place variables on right places. */**
protected List getFieldOrder() {
return Arrays.asList(new String[] { "cbSize", "InstallFunction" });
}
}
public static class SP_PROPCHANGE_PARAMS extends Structure {
public static class ByReference extends SP_PROPCHANGE_PARAMS implements Structure.ByReference {
public ByReference() {
}
public ByReference(Pointer memory) {
super(memory);
}
}
public SP_PROPCHANGE_PARAMS() {
}
public SP_PROPCHANGE_PARAMS(Pointer memory) {
super(memory);
read();
}
public SP_CLASSINSTALL_HEADER ClassInstallHeader = new SP_CLASSINSTALL_HEADER();
public int StateChange;
public int Scope;
public int HwProfile;
protected List getFieldOrder() {
return Arrays.asList(new String[] { "ClassInstallHeader", "StateChange", "Scope", "HwProfile" });
}
}
My function decleration:
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, Pointer deviceInfoData, Pointer classInstallHeader, int size);
How do I calling this function:
SP_PROPCHANGE_PARAMS spPropChangeParams = new SP_PROPCHANGE_PARAMS();
spPropChangeParams.ClassInstallHeader.InstallFunction = DISetupApi.DIF_PROPERTYCHANGE;
spPropChangeParams.Scope = DISetupApi.DICS_FLAG_GLOBAL;
spPropChangeParams.HwProfile = 0;
spPropChangeParams.StateChange = DISetupApi.DICS_DISABLE;
int spPropChangeParamsSize = spPropChangeParams.size();
SP_CLASSINSTALL_HEADER classInstallHeaderReference = new SP_CLASSINSTALL_HEADER(spPropChangeParams.getPointer());
setupApi.SetupDiSetClassInstallParams(hDevInfo, device.getSPDeviceInfoData().getPointer(), classInstallHeaderReference.getPointer(),
spPropChangeParamsSize);
How It works in c++:
SP_PROPCHANGE_PARAMS spPropChangeParams;
spPropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
spPropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
spPropChangeParams.Scope = DICS_FLAG_GLOBAL;
spPropChangeParams.HwProfile = 0;
spPropChangeParams.StateChange = DICS_DISABLE;
SetupDiSetClassInstallParams(hDeviceInfo, &device.getDeviceInfoData(), (SP_CLASSINSTALL_HEADER*)&spPropChangeParams, sizeof(spPropChangeParams));
Actually I mixed and matched too many ways these structs and function I changed variable types of structs and parameter types of function at the end I could not get anything but error. I cannot find what is my mistake. Could you please help me solve this.
Thanks in advance!
When you're passing around a Structure, don't use Structure.getPointer() unless you have to. When you do that, JNA can't automatically synch the native and Java data, and it's error-prone to remember where to do that yourself. In your case, whatever is in the Java fields never gets copied to native memory in your call to setupApi.SetupDiSetClassInstallParams.
Change your function mapping to this:
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, SP_DEVINFO_DATA deviceInfoData, SP_CLASSINSTALL_HEADER classInstallHeader, int size);
and change the invocation to this:
setupApi.SetupDiSetClassInstallParams(hDevInfo, device.getSPDeviceInfoData(), classInstallHeaderReference, spPropChangeParamsSize);
EDIT
If you stick to your original struct definition (where SP_CLASSINSTALL_HEADER is a field), you need to add a function mapping to the interface (extend the interface and create your own instance of the native library):
public interface MySetupApi extends SetupApi {
MySetupApi INSTANCE = (MySetupApi)Native.loadLibrary(MySetupApi.class, W32APIOptions.DEFAULT_OPTIONS);
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, SP_DEVINFO_DATA deviceInfoData, SP_PROPCHANGE_PARAMS propChangeParams, int size);
}
Just trying to run through some code for an assignment I'm doing. It is probably simple but for the life of me I can't figure out why I get the above error at the first line
(public WaterLog.......).
Later I want to pass it this line:
[ log = new WaterLog(8, damCapacity); ]
Any help would be appreciated, I am new to this sorry.
public class WaterLog(Integer windowSize, Integer maxEntry) {
private Integer size = windowSize;
private Integer max = maxEntry;
private ArrayList theLog(int windowSize);
private int counter = 0;
public void addEntry(Integer newEntry) throws SimulationException {
theLog.add(0, newEntry);
counter++;
}
public Integer getEntry(Integer index) throws SimulationException {
If (thelog.isEmpty() || thelog.size() < index) {
return null;
}
return thelog.get(index);
}
public Integer variation() throws SimulationException {
int old, recent = 0;
recent = thelog.get(0);
old = thelog.get(thelog.size-1);
return recent-old;
}
public Integer numEntries() {
return counter;
}
}
Assuming SimulationException is defined correctly:
class WaterLog{
private Integer size;
private Integer max ;
private ArrayList<Integer> theLog; //parameterize your lists
private int counter = 0;
public WaterLog(Integer windowSize, Integer maxEntry) //this is the behavior you were looking for
{
this.size = windowSize;
this.max = maxEntry;
theLog = new ArrayList<Integer>(windowSize);
}
public void addEntry(Integer newEntry) throws SimulationException {
theLog.add(0, newEntry);
counter++;
}
public Integer getEntry(Integer index) throws SimulationException {
if (theLog.isEmpty() || theLog.size() < index) { //Java is case sensitive
return null;
}
return theLog.get(index);
}
public Integer variation() throws SimulationException {
int old, recent = 0;
recent = theLog.get(0);
old = theLog.get(theLog.size()-1); //again, watch case, also size is a method
return recent-old;
}
public Integer numEntries() {
return counter;
}
}
See the comments I added.
EDIT: To explain a bit further what was going on, let's take a look at what you were doing.
public class WaterLog(Integer windowSize, Integer maxEntry) {
private Integer size = windowSize;
private Integer max = maxEntry;
private ArrayList theLog(int windowSize);
private int counter = 0;
You seem to have confused a class with a constructor. The variables you defined were attributes, which was correct. You needed to use the syntax I showed in my answer to create a constructor. For that same reason, you don't have access to variables like windowSize. To remedy this, we allow them to still be defined outside the constructor, but assigned values inside it, where we have access to windowSize and maxEntry.
If you want to pass some parameters to this class you need a constructor. By default Each and EVERY class comes with a default constructor - which is there, you just don't see it ( but can declare it). What you can then do is make an overloaded construcotr ( which takes some arguments ) and this is what you want so..
if you have a class
class WaterLog {
// no constructor
}
the above is really a
class WaterLog {
public WaterLog() {
// this is the constructor - if you do not declare it its still here, you just dont see it. Ofcourse you have option to declare it.
}
}
The overloaded constructor is something like this
class WaterLog {
public WaterLog() {
//default constructor
}
public WaterLog(Integer int, String string, etc...) {
//overloaded constructor
}
}
and the above is what you need in order to pass arguments to this class constructor. I am not briliant at explaining things but if you need more clarification just let me know :)