I am currently working on implementing Drag & Drop from Outlook to Swing (on Windows) using a Swing DropTarget. Because Outlook Drag and Drop does no automatically work with Swing, I debugged it and found out it used the FileNameW native for the event. To support this I use this code:
private static final String nativeFileNameW = "FileNameW";
private static final DataFlavor fileNameWFlavor = new DataFlavor(InputStream.class, nativeFileNameW);
public void installFileNameWFlavorIfWindows(DropTarget dt) {
FlavorMap fm = dt.getFlavorMap();
if (!(fm instanceof SystemFlavorMap)) {
fm = SystemFlavorMap.getDefaultFlavorMap();
}
if (fm instanceof SystemFlavorMap) {
SystemFlavorMap sysFM = (SystemFlavorMap) fm;
sysFM.addFlavorForUnencodedNative(nativeFileNameW, fileNameWFlavor);
sysFM.addUnencodedNativeForFlavor(fileNameWFlavor, nativeFileNameW);
dt.setFlavorMap(sysFM);
}
}
It seems to work fine, but I am not sure if this is the correct approach, since I couldn't find any resources on this problem.
In the drop event I can now get an InputStream when an Outlook Email is dropped on the Swing Component. I use the following code in my drop method (the real method is more complex, because it also handles other DataFlavors, but this example here can reproduce the error):
public void drop(DropTargetDropEvent dtde) {
Transferable transfer = dtde.getTransferable();
boolean accepted = false;
if (transfer.isDataFlavorSupported(fileNameWFlavor)) {
accepted = true;
dtde.acceptDrop(DnDConstants.ACTION_COPY);
try (InputStream is = (InputStream) transfer.getTransferData(fileNameWFlavor)) {
//Do something with InputStream
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
dtde.dropComplete(accepted);
}
I use a try with resource statement to ensure the stream is closed after the drop event. I want to close the stream to make sure there are no open File Handles or similar native resources, that could be limited, after the drop is completed.
The InputStream for a Drop from Outlook is an Instance of WDropTargetContextPeerFileStream and when the close method is called, it crashes in the native Method freeStgMedium, which should free the native windows data structure.
I do not get any error output on the command line.
The Program terminates with error code -1073740940 which seems to indicate a heap corruption error.
Is there anything I am missing? Is this InputStream not supposed to be closed or is there a Bug earlier on.
I am using the JDK from Azul, Zulu 8.48.0.53 (Java 8u265).
I have also tried it with Zulu 11, Oracle Java 8 and a Redhat build of Openjdk 8, all fail the same way.
Update:
I think I tracked the bug down to JDK native code, that gets the data.
The JDK Code creates a STGMEDIUM object on the stack and passes a Pointer to that to the Windows Method IDataObject::GetData(). This method writes its data back into the STGMEDIUM* parameter.
This should not be a problem, since all examples of this Windows function did it the same way. But it seems, that Outlook does not initialize the member variable IUnknown *STGMEDIUM::pUnkForRelease, but instead relies on the caller to zero-fill the data structure (or Outlook has a Bug).
When the native resources are released by Java, it calls ReleaseStgMedium, which tries to call Release on the pUnkForRelease pointer, if it isn't NULL, which causes the error.
For now, I simply don't close the input stream and let a FileHandle leak, which is not optimal, but I don't see any other solution.
If I find a real solution to this Bug, I will write an Update/Answer here.
Related
I need to prevent users from starting my Java application (WebStart Swing app) multiple times. So if the application is already running it shouldn't be possible to start it again or show a warning / be closed again.
Is there some convenient way to achieve this? I thought about blocking a port or write sth to a file. But hopefully you can access some system properties or the JVM?
btw. target platform is Windows XP with Java 1.5
I think your suggestion of opening a port to listen when you start your application is the best idea.
It's very easy to do and you don't need to worry about cleaning it up when you close your application. For example, if you write to a file but someone then kills the processes using Task Manager the file won't get deleted.
Also, if I remember correctly there is no easy way of getting the PID of a Java process from inside the JVM so don't try and formulate a solution using PIDs.
Something like this should do the trick:
private static final int PORT = 9999;
private static ServerSocket socket;
private static void checkIfRunning() {
try {
//Bind to localhost adapter with a zero connection queue
socket = new ServerSocket(PORT,0,InetAddress.getByAddress(new byte[] {127,0,0,1}));
}
catch (BindException e) {
System.err.println("Already running.");
System.exit(1);
}
catch (IOException e) {
System.err.println("Unexpected error.");
e.printStackTrace();
System.exit(2);
}
}
This sample code explicitly binds to 127.0.0.1 which should avoid any firewall warnings, as any traffic on this address must be from the local system.
When picking a port try to avoid one mentioned in the list of Well Known Ports. You should ideally make the port used configurable in a file or via a command line switch in case of conflicts.
As the question states that WebStart is being used, the obvious solution is to use javax.jnlp.SingleInstanceService.
This service is available in 1.5. Note that 1.5 is currently most of the way through its End Of Service Life period. Get with Java SE 6!
I think that the better idea would be to use file lock (quite an old idea :) ). Since Java 1.4 a new I/O library was introduced, that allows file locking.
Once the application starts it tries to acquire lock on a file (or create it if does not exist), when the application exits the lock is relased. If application cannot acquire a lock, it quits.
The example how to do file locking is for example in Java Developers Almanac.
If you want to use file locking in Java Web Start application or an applet you need to sing the application or the applet.
You can use JUnique library. It provides support for running single-instance java application and is open-source.
http://www.sauronsoftware.it/projects/junique/
See also my full answer at How to implement a single instance Java application?
We do the same in C++ by creating a kernal mutex object and looking for it at start up. The advantages are the same as using a socket, ie when the process dies/crashes/exits/is killed, the mutex object is cleaned up by the kernel.
I'm not a Java programmer, so I am not sure whether you can do the same kind of thing in Java?
I've create the cross platform AppLock class.
http://mixeddev.info/articles/2015/02/01/run-single-jvm-app-instance.html
It is using file lock technique.
Update. At 2016-10-14 I've created package compatible with maven/gradle https://github.com/jneat/jneat and explained it here http://mixeddev.info/articles/2015/06/01/synchronize-different-jvm-instances.html
You could use the registry, although this halfheartedly defeats the purpose of using a high-level language like java. At least your target platform is windows =D
Try JUnique:
String appId = "com.example.win.run.main";
boolean alreadyRunning;
try {
JUnique.acquireLock(appId);
alreadyRunning = false;
} catch (AlreadyLockedException e) {
alreadyRunning = true;
}
if (alreadyRunning) {
Sysout("An Instance of this app is already running");
System.exit(1);
}
I've seen so many of this questions and I was looking to solve the same problem in a platform independent way that doesn't take the chance to collide with firewalls or get into socket stuff.
So, here's what I did:
import java.io.File;
import java.io.IOException;
/**
* This static class is in charge of file-locking the program
* so no more than one instance can be run at the same time.
* #author nirei
*/
public class SingleInstanceLock {
private static final String LOCK_FILEPATH = System.getProperty("java.io.tmpdir") + File.separator + "lector.lock";
private static final File lock = new File(LOCK_FILEPATH);
private static boolean locked = false;
private SingleInstanceLock() {}
/**
* Creates the lock file if it's not present and requests its deletion on
* program termination or informs that the program is already running if
* that's the case.
* #return true - if the operation was succesful or if the program already has the lock.<br>
* false - if the program is already running
* #throws IOException if the lock file cannot be created.
*/
public static boolean lock() throws IOException {
if(locked) return true;
if(lock.exists()) return false;
lock.createNewFile();
lock.deleteOnExit();
locked = true;
return true;
}
}
Using System.getProperty("java.io.tmpdir") for the lockfile path makes sure that you will always create your lock on the same place.
Then, from your program you just call something like:
blah blah main(blah blah blah) {
try() {
if(!SingleInstanceLock.lock()) {
System.out.println("The program is already running");
System.exit(0);
}
} catch (IOException e) {
System.err.println("Couldn't create lock file or w/e");
System.exit(1);
}
}
And that does it for me. Now, if you kill the program it won't delete the lock file but you can solve this by writing the program's PID into the lockfile and making the lock() method check if that process is already running. This is left as an assingment for anyone interested. :)
I am trying to create an app which I use it for remote control an android device(TV). Actually I did it however when I click a button on the controller device(mobile), it takes apprx. 1 sec to do the work in the device(TV) that I want to control.
When I checked all logs in the code and I see that method spends that much time...
String commandStr;
commandStr = String.format("%s"," input keyevent "+keyCode);
try {
process = runTimeExec(commandStr);
runTimeExec(commandStr);
} catch (IOException e) {
}
And the runTimeExec defined as;
public static Process runTimeExec(String commandStr) throws IOException {
Runtime.getRuntime().exec(commandString);
}
I just wanna learn if there is any other solution to run command immediately on the TV device itself? Or how can I make faster this code here?
I've used the getevent/sendevent code for this purpose. Its very fast and works immediately on the TV device. Just try it. You can find detailed documentations in https://source.android.com
I want to check if a Windows Workstation is logged on or off. I've found a solution in C#:
public class CheckForWorkstationLocking : IDisposable
{
private SessionSwitchEventHandler sseh;
void SysEventsCheck(object sender, SessionSwitchEventArgs e)
{
switch (e.Reason)
{
case SessionSwitchReason.SessionLock: Console.WriteLine("Lock Encountered"); break;
case SessionSwitchReason.SessionUnlock: Console.WriteLine("UnLock Encountered"); break;
}
}
public void Run()
{
sseh = new SessionSwitchEventHandler(SysEventsCheck);
SystemEvents.SessionSwitch += sseh;
}
#region IDisposable Members
public void Dispose()
{
SystemEvents.SessionSwitch -= sseh;
}
#endregion
}
but at the end I'm going to need this boolean in my Java Program.
I already tried the following:
I started both programs and C# writes into a file from where I can check all few seconds if the data has changed or not from java (don't need to say that this solution is just slow and insufficient)
Another solution would be :
Java starts the C# .exe which waits until Java connects to it through sockets and they share the data over the open connection.
Is there a better way to solve this with less effort than with this socket interface solution?
You don't have to go to any complicated lengths to get this done. It can be quite simple.
Save the boolean into a file in C#, then have a file watcher watching the directory in Java. If there is a change it can read the file in Java and find the value of the boolean. Such a solution would not be expensive and eat up a lot of CPU cycles, like a solution where you had a while loop that checked the file would be.
The beginnings of the Java code can be as simple as
import static java.nio.file.StandardWatchEventKinds.*;
Path dir = ...;
try {
WatchKey key = dir.register(watcher,
ENTRY_CREATE,
ENTRY_DELETE,
ENTRY_MODIFY);
} catch (IOException x) {
System.err.println(x);
}
There are lots of possible solutions to this issue. My personal preference would be to use a message queue to post messages between the applications. (http://zeromq.org/ is light and would be my recommendation)
The advantage of this approach is the two applications are decoupled and and its not relying on the filesystem which is notoriously prone to errors.
To call a function that is written in C# (or any .NET library function) from Java, you can use JNI.
However, all JNI will do is get you to C/C++. You will need to write a simple managed C++ object that can forward request from the unmanaged side to the .NET library.
Example Here
I am using java jinput library to read data from joypad, and I have trouble reloading Controllers, I use this to load them:
public Controller[] findStickControllers() {
ControllerEnvironment ce =
ControllerEnvironment.getDefaultEnvironment();
Controller[] cs = ce.getControllers();
System.out.println(cs.length); //test
ArrayList<Controller> sel = new ArrayList<>();
for (Controller c: cs) {
if(c.getType() == Type.STICK) {
sel.add(c);
}
}
return sel.toArray(new Controller[]{});
}
This works fine, but if I disconnect my controller, calling this will find it again, and vice versa (connecting it after the first check will not find it at all).
I have tried to put sleep before the fist lookup, with these results:
Controllers are acctually scanned when this method is called first time (not at start of the program)
When called again, this always returns same controllers as it returned for the first time.
First call will also write warning bellow
Even when controller is connected (and works), then disconnected (it will still find it though) and reconnected, it will not work
Warning from point 3: (didn't format well in the list)
WARNING: Found unknown Windows version: Windows 8
Attempting to use default windows plug-in.
Loading: net.java.games.input.DirectAndRawInputEnvironmentPlugin
I am using Win 8, and had same problem on Win 7. I had also tried this with mouse, same results.
How can I acctually reload controllers for the 2nd, 3rd, and so on time?
I encountered the same problem. The reason is that the actual hardware scan happens only once for each DefaultControllerEnvironment object. Since the only accessible instantiation is a singleton, it never does another scan.
A simple way to force a hardware scan is to create a new object, but neither the class nor the constructor are public. You can however work around this limitation by calling the constructor via reflection.
Rescan
private static ControllerEnvironment createDefaultEnvironment() throws ReflectiveOperationException {
// Find constructor (class is package private, so we can't access it directly)
Constructor<ControllerEnvironment> constructor = (Constructor<ControllerEnvironment>)
Class.forName("net.java.games.input.DefaultControllerEnvironment").getDeclaredConstructors()[0];
// Constructor is package private, so we have to deactivate access control checks
constructor.setAccessible(true);
// Create object with default constructor
return constructor.newInstance();
}
Usage
// Be aware that creating a new environment is fairly expensive
Controller[] controllers = createDefaultEnvironment().getControllers();
Remove Windows 8 Warnings
/**
* Fix windows 8 warnings by defining a working plugin
*/
static {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
String os = System.getProperty("os.name", "").trim();
if (os.startsWith("Windows 8")) { // 8, 8.1 etc.
// disable default plugin lookup
System.setProperty("jinput.useDefaultPlugin", "false");
// set to same as windows 7 (tested for windows 8 and 8.1)
System.setProperty("net.java.games.input.plugins", "net.java.games.input.DirectAndRawInputEnvironmentPlugin");
}
return null;
}
});
}
If you use the accepted answer, you might want to consider killing the thread that was spawned by the previous environment before setting a new one because it won't be cleaned up otherwise. You can do so by calling something like:
final Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (final Thread thread : threadSet) {
final String name = thread.getClass().getName();
if (name.equals("net.java.games.input.RawInputEventQueue$QueueThread")) {
thread.interrupt();
try {
thread.join();
} catch (final InterruptedException e) {
thread.interrupt();
}
}
}
The warning is because the last time I updated that code windows 7 wasn't even out IIRC, I'll update it.
The controller reload is a feature that has been requested a number of times, but no-one deems it important enough to spend any time implementing it. If you submit a patch I'll take a look and see about committing it. Until someone finds it important enough to spend the time to write it, it's just a missing feature.
I had the same problem before.
I add the rescanning feature (for Windows back-end only) and post the patch on Java gaming forum but no ones seem interested in to integrate it.
So if you need it, apply my patch from here: http://www.java-gaming.org/topics/rescan-controllers/24782/msg/224604/view.html#msg224604
As it was made clear in my recent question, Swing applications need to explicitly call System.exit() when they are ran using the Sun Webstart launcher (at least as of Java SE 6).
I want to restrict this hack as much as possible and I am looking for a reliable way to detect whether the application is running under Webstart. Right now I am checking that the value of the system property "webstart.version" is not null, but I couldn't find any guarantees in the documentation that this property should be set by future versions/alternative implementations.
Are there any better ways (preferably ones that do not ceate a dependency on the the webstart API?)
When your code is launched via javaws, javaws.jar is loaded and the JNLP API classes that you don't want to depend on are available. Instead of testing for a system property that is not guaranteed to exist, you could instead see if a JNLP API class exists:
private boolean isRunningJavaWebStart() {
boolean hasJNLP = false;
try {
Class.forName("javax.jnlp.ServiceManager");
hasJNLP = true;
} catch (ClassNotFoundException ex) {
hasJNLP = false;
}
return hasJNLP;
}
This also avoids needing to include javaws.jar on your class path when compiling.
Alternatively you could switch to compiling with javaws.jar and catching NoClassDefFoundError instead:
private boolean isRunningJavaWebStart() {
try {
ServiceManager.getServiceNames();
return ds != null;
} catch (NoClassDefFoundError e) {
return false;
}
}
Using ServiceManager.lookup(String) and UnavailableServiceException is trouble because both are part of the JNLP API. The ServiceManager.getServiceNames() is not documented to throw. We are specifically calling this code to check for a NoClassDefFoundError.
Use the javax.jnlp.ServiceManager to retrieve a webstart service.
If it is availabe, you are running under Webstart.
See http://download.java.net/jdk7/docs/jre/api/javaws/jnlp/index.html
As you mentioned, checking the System property as follows is probably the cleanest way:
private boolean isRunningJavaWebStart() {
return System.getProperty("javawebstart.version", null) != null;
}
In a production system I have used the above technique for years.
You can also try to check to see if there are any properties that start with "jnlpx." but none of those are really "guaranteed" to be there either as far as I know.
An alternative could be to attempt to instantiate the DownloadService us suggested by Tom:
private boolean isRunningJavaWebStart() {
try {
DownloadService ds = (DownloadService) ServiceManager.lookup("javax.jnlp.DownloadService");
return ds != null;
} catch (UnavailableServiceException e) {
return false;
}
}
Of course that does have the downside of coupling your code to that API.
I have no real experience with Java web start other than looking at it a few years back.
How about start your application with a parameter that you define than you set when the app is started via Java web start.
If you want to pass in arguments to your app, you have to add them to the start-up file (aka JNLP descriptor) using or elements.
Then check to see if these properties are set.
Again this is a suggestion I have not coded for JWS and it may not be this easy.
You can check whether the current classloader is an instance of com.sun.jnlp.JNLPClassLoader (Java plugin 1) or sun.plugin2.applet.JNLP2ClassLoader (Java plugin 2). Despite the "applet" package, an applet using JNLP with the Java plugin 2 uses another classloader, sun.plugin2.applet.Applet2ClassLoader. It works with OpenJDK too.