If I want to use Windows Functions through Java, can I?
For example, when you right click on a File you get Open With..
If I want to add something to it can I do so.
If I want to play with Windows Taskbar can I do so.
Is there a Java library available for doing such tasks.
Thanks!
You can always do these thing from JNI. I have wrote a brief guide on
how to do this using ping as an example. These same concepts can be
applied to the same COM calls required to "register file extensions",
minimize, maximize, etc tasks on the taskbar (assuming this is what
you want). You may first want to define your requirements so you know
exactly what you are looking for:
(1) Introduction to JNI by example using Ping by Richard Sandoz
Ping is the defacto standard for testing point to point network
connectivity. It uses what is called an icmp packet. Java does not
include a "ping" command. Native code must be written to implement
ping.
(2) The signature:
int ping(String host) {
...
return timeInMilliSeconds;
}
This provides two simple cases for input and output for native
functionality.
(3) Common Java
First create a directory structure. I will start the initial
development in the Windows environment. I will start with the C drive
as a point of reference. Create a directory called ICMPLibrary:
C:\ICMPLibrary
Then create a subdirectory called src.
C:\ICMPLibrary\src
Then create a subdirectory called icmp. This will serve as the
package.
C:\ICMPLibrary\src\icmp
Now (inside the icmp subdirectory) create a file called
ICMPInterface.java and enter in the following code:
/*
* @(#) ICMPInterface.java
*/
package icmp;
public class ICMPInterface {
final static String LIBRARY_NAME = "pinglib";
static {
try {
System.out.println("Loading (" +
System.mapLibraryName(LIBRARY_NAME) + ")");
System.loadLibrary(LIBRARY_NAME);
} catch(UnsatisfiedLinkError e) {
System.err.println("library path=" +
System.getProperty("java.library.path"));
System.err.println(e + ":cannot load (" +
System.mapLibraryName(LIBRARY_NAME) + ")");
}
}
static public native boolean ping(String host);
}
This is the native interface portion of the project. It includes the
java native signature for the ping function.
Next create a file called ICMPTest.java and enter in the following
code:
/*
* @(#) ICMPTest.java
*/
package icmp;
public class ICMPTest {
public static void main(String[] args) {
String host = args[0];
for (int i =0; i < 5;i++)
System.out.println(host + "=" +
(ICMPInterface.ping(host)?"ALIVE":"NO RESPONSE"));
}
}
This is simple test code that will allow us to test our native
interface.
Now drop to a DOS prompt and change to the directory:
C:\ICMPLibrary\src
Next compile the two java files you created from above.
javac -classpath . icmp/ICMPTest.java
This will produce the files ICMPInterface.class and ICMPTest.class in
the icmp subdirectory.
(4) Platform specific code:
(A) Windows - Visual C++
Start Microsoft Visual Studio. I will be using Visual Studio 97 for
this example.
Create a new project, specifically a "Win32 Dynamic-Link Library".
In the location field, specify:
C:\ICMPLibrary\
In the project name field, specify:
pinglib
This will also append pinglib to the previous field. Click OK.
Switch to the file view, then create a new file and add the
following code:
typedef unsigned long IPAddr;
typedef struct ip_option_information {
UCHAR Ttl;
UCHAR Tos;
UCHAR Flags;
UCHAR OptionsSize;
PUCHAR OptionsData;
} IP_OPTION_INFORMATION, *PIP_OPTION_INFORMATION;
typedef struct icmp_echo_reply {
IPAddr Address;
ULONG Status;
ULONG RoundTripTime;
USHORT DataSize;
USHORT Reserved;
PVOID Data;
IP_OPTION_INFORMATION Options;
} ICMP_ECHO_REPLY, *PICMP_ECHO_REPLY;
typedef HANDLE (CALLBACK* fnIcmpCreateFile)();
typedef DWORD (CALLBACK* fnIcmpSendEcho)(HANDLE IcmpHandle,IPAddr
DestinationAddress,
LPVOID RequestData,WORD RequestSize,PIP_OPTION_INFORMATION
RequestOptions,
LPVOID ReplyBuffer,DWORD ReplySize, DWORD Timeout);
typedef BOOL (CALLBACK* fnIcmpCloseHandle)(HANDLE IcmpHandle);
BOOL ping(HANDLE hDll, const char* hostname);
Save this as a file called pinglib.h and add it to the project.
Next, create a new file and add the following code:
#include <windows.h>
#include <jni.h>
#include "pinglib.h"
extern "C" {
JNIEXPORT jboolean JNICALL Java_icmp_ICMPInterface_ping(
JNIEnv* env,
jobject thisObj,
jstring jhost)
{
char* strDll = "icmp.dll";
HINSTANCE hDll = LoadLibrary(strDll);
if (hDll) {
const char* host = env->GetStringUTFChars(jhost, FALSE);
jboolean retVal = ping(hDll, host);
env->ReleaseStringUTFChars(jhost, host);
FreeLibrary(hDll);
return retVal;
} else {
printf("Error loading library %s\n", strDll);
exit(0);
}
return 0;
}
}
BOOL ping(HANDLE hDll, const char* hostname) {
fnIcmpCreateFile IcmpCreateFile =
(fnIcmpCreateFile)GetProcAddress(hDll, "IcmpCreateFile");
fnIcmpSendEcho IcmpSendEcho =
(fnIcmpSendEcho)GetProcAddress(hDll, "IcmpSendEcho");
fnIcmpCloseHandle IcmpCloseHandle =
(fnIcmpCloseHandle)GetProcAddress(hDll, "IcmpCloseHandle");
// load winsock
WSADATA WSAData;
if (WSAStartup(MAKEWORD(1,1), &WSAData) != 0) {
fprintf (stderr, "Can't start up winsock.\n");
return FALSE;
}
HANDLE icmpHandle = IcmpCreateFile();
if (icmpHandle == NULL) {
fprintf (stderr, "Can't open the icmp handle.\n");
return FALSE;
}
IPAddr addr = inet_addr(hostname);
if (addr == INADDR_NONE) {
printf("Attempting to resolve %s\n", hostname);
PHOSTENT host = gethostbyname (hostname);
if (host == NULL) {
fprintf (stderr, "Can't figure out host name/ID %s.\n",
hostname);
return FALSE;
}
addr = *(long*)(*host->h_addr_list);
}
BYTE* rdata = (BYTE*)malloc(100);
WORD rdatasize = 100;
BYTE* rbuf = (BYTE*)malloc(3000);
long rbufsize = 3000;
// = new char[(sizeof(ICMP_ECHO_REPLY)+__max(8,rdatasize))];
DWORD dwv = IcmpSendEcho( // return value is N responses
icmpHandle, // Handle of ICMP "file"
addr, // IP address of host
rdata, // ICMP request data
rdatasize, // sizeof above
NULL, // IP request options TBS
rbuf, // reply buffer
rbufsize, // size of above
50); // timeout, millisecondsp
ICMP_ECHO_REPLY* rp = (ICMP_ECHO_REPLY*)rbuf;
// optionally utilize the rp structure to get metrics about the
ping
free(rbuf);
free(rdata);
// close icmp handle
IcmpCloseHandle(icmpHandle);
// unload winsock
WSACleanup();
return dwv!=0;
}
Save this as a file called pinglib.cpp and add it to the project.
Next, create one last file and add the following code:
EXPORTS
Java_icmp_ICMPInterface_ping
Save this as a file called pinglib.def and add it to the project.
Now, access the project setting (from menu, project//settings).
Select the "All configurations" as the settings for field.
Switch to the "Link" tab and append "ws2_32.lib" to the
Object/library modules field
and add "..\src\pinglib.dll" to the "Output file name" field
Next, switch to the C/C++ tab, select Preprocessor from the dropdown
and add:
c:\j2sdk1.4.1_01\include,c:\j2sdk1.4.1_01\include\win32
to this field. Assuming you installed your Java SDK in this
location.
Click OK, then build the project, by selecting build//rebuild all
from the menu.
(5) Run the program:
Now drop to a DOS prompt and change to the source directory:
C:\ICMPLibrary\src
Next run the java test program created.
java -cp . icmp/ICMPTest 127.0.0.1
Loading (pinglib.dll)
127.0.0.1=ALIVE
127.0.0.1=ALIVE
127.0.0.1=ALIVE
127.0.0.1=ALIVE
127.0.0.1=ALIVE
java -cp . icmp/ICMPTest 128.0.0.1
Loading (pinglib.dll)
128.0.0.1=NO RESPONSE
128.0.0.1=NO RESPONSE
128.0.0.1=NO RESPONSE
128.0.0.1=NO RESPONSE
128.0.0.1=NO RESPONSE