Using Windows API call in Java using "native" - java

I've tried to solve this issue by referring possible duplicates but none of them seem to be helpful.
Here's a code that I'm using to call Win API methods in Java to get current Windows User Name, and a native Windows MessageBox, but I'm getting UnsatisfiedLinkError that says that my code is unable to locate the native method I'm trying to call.
public class TestNative
{
public static void main(String[] args)
{
long[] buffer= { 128 };
StringBuffer username = new StringBuffer((int)buffer[0]);
GetUserNameA(username,buffer);
System.out.println("Current User : "+username);
MessageBoxA(0,"UserName : "+username,"Box from Java",0);
}
/** #dll.import("ADVAPI32") */
static native void GetUserNameA(StringBuffer username,long[] buffer);
/** #dll.import("USER32") */
private static native int MessageBoxA(int h,String txt,String title,int style);
}
What can be my possible (relatively simple) solution to call native Windows methods in Java. I realize that it will kill the very reason of Java being a cross-platform language, but I need to work on a project for Windows, to be developed in Java.
Thanks.
Update
As David Heffernan suggested, I've tried changing the method signature of MessageBox to MessageBoxA, but still it's not working.

I would guess it's related to the signatures not matching completely.
The GetUserName function takes two parameters: a LPTSTR and a LPDWORD. Java will likely not handle the StringBuffer acting as a TCHAR array for you.
Also, why bother using the Windows API for this? Java can probably get the user's logon name (quick google says: System.getProperty("user.name")), and Swing can make a message box (even one that looks like a Windows one).

Have you tried https://github.com/twall/jna. I have heard good things and its supposed to make jni that bit easier with many conveniences and simplifications.

Do you have a -Djava.library.path VM arg set with the path to your DLL's? Alternatively, you can have it in your system PATH.

The error is because there is no MessageBox. You presumably mean MessageBoxA.

Related

How is obfuscation done in Java?

Today I came across an obfuscated class (well a lot of obfuscated classes in a jar) and I do not have a clue on how this kind of obfuscation is done.
An example:
protected void a(ChannelHandlerContext ☃, ByteBuf ☃, ByteBuf ☃)
throws Exception
{
int ☃ = ☃.readableBytes();
if (☃ < this.c)
{
☃.b(0);
☃.writeBytes(☃);
}
else
{
byte[] ☃ = new byte[☃];
☃.readBytes(☃);
☃.b(☃.length);
this.b.setInput(☃, 0, ☃);
this.b.finish();
while (!this.b.finished())
{
int ☃ = this.b.deflate(this.a);
☃.writeBytes(this.a, 0, ☃);
}
this.b.reset();
}
}
}
As you see above, all the parameter variables are a snow-man. How can this be undone? Also how is it done in the first place; how is the JVM able to "process" those and execute the code without any problem?
To clarify, I am not going to use this code, it is just for educational purposes. I am taking the Computer Science course at school so since we are learning Java and talking of limitations such as decompilations. I am interested in learning more, so I decided to have a look into bigger projects especially servers. This piece of code is pulled out of the Spigot server for Minecraft (A game) that is a fork of Bukkit server for Minecraft that was supposed to be open source.
First of all, you should note that it is the parameters which have this unicode and not the methods. Why is this important?
Parameters do not need to have names specified, as they are mostly indexed by a number reference. However it can be specified and I assume that most java runtimes do in fact not check this name as it is not needed for execution.
In the opposite, class names, method names, and field names are however needed.
About you mentioning Spigot, Spigot is indeed open source. However you most likely decompiled a class which is originally from the original Mojang Minecraft server, which is not open source and is indeed obfuscated.
Edit: In the case you want to investigate these classes, I recently found a tool called Bytecode Viewer, which is available at https://github.com/Konloch/bytecode-viewer
This tool has multiple decompilers as well as some options to view a more bytecode like version of the class file.
An example of a function I found contains the following bytecode data:
<localVar:index=1 , name=☃ , desc=D, sig=null, start=L1, end=L2>
<localVar:index=3 , name=☃ , desc=D, sig=null, start=L1, end=L2>
<localVar:index=5 , name=☃ , desc=D, sig=null, start=L1, end=L2>
Indeed as is visible, the unicode name has been set the same, but it does not matter as in the end the indexes (1,3,5) are used to reference these variables.
protected void a(ChannelHandlerContext ☃, ByteBuf ☃, ByteBuf ☃)
This isn't valid. You cannot have multiple parameters with the same name. It could be that you are not reading the unicode text with the right text format.
Your Text editor is showing the value of the unicode character.
I just tested on eclipse and names with unicode characters are acceptable.
public String publicationXmlUrl(int \u9090currentPage) {
But writing with values are not:
public String publicationXmlUrl(int ♥currentPage) {

It's possible to unit test modifications in windows environment variable?

My process simply add some content to the system variable PATH. Actually I'm doing this with a Process that use the setx.exe:
public void changePath(String newPath ) {
String path = System.getenv("PATH") + ";";
String[] cmd = new String[]{"C:\\Windows\\System32\\setx.exe", "PATH",
path+newPath, "-m"};
ProcessBuilder builder = new ProcessBuilder(cmd);
...
}
So I tried to write a test case to it.
Class UpdatePathTest {
#Test
public void testUpdatePath() {
//call the method that update the path
changePath("C:\\somebin");
assertTrue(System.getenv("PATH").contains("C:\\somebin")); //fails
// ProcessBuilder with command String[]{"cmd", "/C", "echo", "%PATH%"}; will fail too.
//and the above in a new Thread will fail too.
}
}
So, is there any way to get the new PATH value? Writing the new path is the only option, because I'm developing a jar that will install a desktop application.
I'm not sure changing the path is a good idea in a unit test. What if the test fails? You will have to make sure you do all the relevant tidy up.
Consider inverting your dependencies and use dependency injection.
This article explains it quite well I think.
So instead of having a method that does:
public void method() {
String path = System.getenv("PATH") + ";";
//do stuff on path
}
consider doing:
public void method(String path) {
//do stuff on path
}
which allows you to stub the path. If you cannot change the signature of the method then consider using the factory pattern and using a test factory to get the path.
EDIT: after update to question
What you have to think about here is what you are testing. When you call C:\Windows\System32\setx.exe you have read the API docs and are calling it with the correct parameters. This is much like calling another method on a java API. For example if you are manipulating a list you "know" it is zero based. You do not need to test this you just read the API and the community backs you up on this. For testing changePath I think you probably what to test what is going into ProcessBuilder. Again you have read the API docs and you have to assume that you are passing in the correct variables. (See //1 at bottom) And again you have to assume that ProcessBuilder works properly and that the Oracle (or most likely Sun) guys have implemented it to the API documents.
So what you want to do is check that you are passing variables to ProcessBuilder that match the specification as you understand it. For this you can mock ProcessBuilder and then verify that you are passing the correct parameters and calling the correct method on this class.
In general it is a hard one to test because you don't want to test the windows functions but want to test java's interaction with them.
//1 The main problem I have had with calling this external commands is understanding the API documents correctly or setting up the command. Usually you have to get the command line out and check that you are using methods correctly (esp cmd functions). This can mean that you work out how to use the cmd function, code it into ProcessBuilder and then write a test (or vice versa on the ProcessBuilder/test) Not the ideal way but sometimes documents are hard to understand.

Can I get handle of the process by executable name?

I am using JNA to use user32.dll and kernel32.dll . I have the sample code which can give me the handle if i specify the title of the process.
hWnd = User32.FindWindowA(null, "Call of Duty®: Modern Warfare® 3 Multiplayer");
I really don't want to search for the process handle by the Title . Is there any method which takes the exe name? Like this:
hWnd = User32.FindWindowByExecutable ( "iw5mp.exe" );
So that, it will return 0 if this process is not running otherwise the handle.
Also, the thing is when using JNA, eclipse obviously can't auto suggest the methods present in User32 or Kernel32 dll. So, what do you do in such cases. Just google the probable method ?
With Java 9, thanks to JEP 102, it will be possible to obtain a handle of the process given an executable name, with the new ProcessHandle interface:
Optional<ProcessHandle> findByExactCommand(String command) {
return ProcessHandle.allProcesses().filter(process -> {
Optional<String> cmd = process.info().command();
return cmd.isPresent() && cmd.get().equals(command);
}).findFirst();
}
Literally answering question in title, ignoring JNA aspects, but reading comments it seems that was OP was after:
I don't think there is anything like Process.GetProcesses in java
Well, now there is ;)
String passed to FindWindow() as a second parameter is NOT title of the process. It is title of some window instead. And value returned by FindWindow() is (surprise!) handle of the window, not process handle.
If title of window you want to find may change i suggest you search window by their class name (first argument of FindWindow) leaving second argument null.
Class of windows application window may be determined by Microsoft Spy++ or similar software.

How can I call a Java object/function from Oracle Forms 6i?

I am working on a legacy project that is using Oracle Forms 6i (yes, I know its old) to call C++ functions from a PLL library.
Now we need to use Java instead of C++, therefore we need to call Java (Object/Class/Method) from Oracle Forms.
I know its a challenging subject, but I would be really happy if someone could provide a simple example that does the following:
Invoking a method from the Java class, passing a int variable (within PL/SQL)
Printing the returned value in the Canvas that executed the Function.
A basic example, perhaps a Hello World would be ideal.
I know some PL/SQL, but I am not a Oracle Forms developer; please bear with me.
If this is not possible, could you point me to some other alternatives?
Well, after an intensive lookup through the internet I came across a very good resource (in Spanish though): Elias blog about Oracle Forms and Java
I use:
Oracle Forms 6i
JDK 1.6
With this I managed to create the hello world example:
Configure PATH environment variables:
C:\PATH_TO_JAVA\Java\jdk1.6.0\bin;
C:\PATH_TO_JAVA\Java\jdk1.6.0\jre\bin;
C:\PATH_TO_JAVA\Java\jdk1.6.0\jre\bin\client;
Ex: PATH_TO_JAVA = C:\Program Files
Add to CLASSPATH
FORMS_HOME\TOOLS\common60\JAVA\IMPORTER.JAR (In my case FORMS_HOME was C:\orant)
PATH_TO_YOUR_JAR\NAME_OF_JAR.jar
Create Java Program
Create with your IDE a simple java program, following is mine:
public class HiWorld{
private String hi="Hello World!";
public String getHi(){
return this.hi;
}
public String getMultiply(int a, int b){
return ""+a*b;
}
public static void main(String args[]){
HiWorld hm = new HiWorld();
System.out.println(hm.getHi());
System.out.println(hm.getMultiply(5,10));
}
}
Export it to Jar file (Path has to be the one you put in CLASSPATH environment variable.
Import the classes to Forms
Create a new project in Oracle Forms and also create a Canvas, in the canvas use a Text and a Button. The name of the button: TEXT_HI_WORLD.
Following click on the Menu: Program > Import Java Classes
If everything went Ok then there will be a new window that will show you the package where the Class is, you extend it until there is the HiWorld class. Import it.
In Program Unit now there will be two files:
HIWORLD (Specification)
HIWORLD (Body)
This are files generated automatically and needed to use the class.
Then go back to the canvas, right click on the Button and select the Thrigger WHEN-BUTTON-PRESSED, the programming of this will be:
DECLARE
v_wb ORA_JAVA.JOBJECT;
v_hi VARCHAR2(20);
BEGIN
v_wb := hiworld.new();
v_hi:= hiworld.getHi(v_wb);
:TEXT_HI_WORLD := v_hi
END;
Now execute the program and click on the button! :)
Hope this helps Java programmers with no much of knowledge on Forms to integrate with legacy systems! :D
I've done this before, and with a simple class this should work, but when you try to develop something more complicated, I recommend extend from the VBean class, you can find the library within oracle's forms installation folders (frmall.jar).
// el programa corregido.
public class HolaMundo {
private String hi= "Hey World!!!";
public String GetHi(){
return this.hi;
}
public static void main(String args[]){
HolaMundo hm = new HolaMundo();
System.out.println(hm.GetHi());
}
}

Accessing Windows Registry [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
read/write to Windows Registry using Java
I need to access Windows registry from Java.. Also I need to copy some registry entries and may have to enter new registry variables using Java..
some one help me please...
I'd recommend the Java Native Access (JNA) library. It's a pretty nice wrapper around JNI. According to this mailing list post, they've already got a contributed wrapper around the native Windows registry function calls.
If you add the JNA libraries to your project, the relevant source you'll want is the Registry.java class. From there, just call methods on that class to investigate the Windows registry.
As a side note, make sure when you use JNA that you use Platform.isXxx() to make sure your code can actually query the registry on the particular platform.
An example will be like this:
import com.ice.jni.registry.*;
public class DeleteEnvironmentVar{
public DeleteEnvironmentVar(String variable, String value) throws Exception {
RegistryKey machine = Registry.getTopLevelKey("HKEY_LOCAL_MACHINE");
RegistryKey environment = machine.openSubKey("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", RegistryKey.ACCESS_WRITE);
try {
if ( value == null ) { //Delete the variable in case value is empty
environment.deleteValue(variable);
}
}
catch( NoSuchValueException nsve ) {}
catch( NoSuchKeyException nske ) {}
}
}
The Preferences class is the Java preferred way of writing to the registry. However, I haven't actually used it, so I don't know if it allows access to the entire registry or just a section specific to the JVM or your application. If it doesn't, then it sounds like for your purpose you'll be needing to look at the JNI solutions posited by others here. If it does work, then you have a platform-independent method of storing off your settings if you ever port it.

Categories

Resources