5

I have a java class file with a main method. In Windows, I would like to be able to drag files onto a desktop icon/short/etc that would call supply the filenames to my main method. Basically, I want to allow users to drag-and-drop files at program execution instead of having type them on the command line.

Any thoughts?

PhiLho
  • 40,535
  • 6
  • 96
  • 134
  • Any equivalent for Mac OS X? I too have a file I would like to drag onto a Java class, in order to provide the dragged file as an argument. – Michael Innes Sep 16 '16 at 23:27

5 Answers5

4

To build on daub815's answer, in Windows, you can use a batch file to pass arguments to another command. In this case, we'll use the java launcher to launch your class with the main method.

I did a quick Google search on how to do write a batch file to take multiple arguments, and found a page with a batch file to pass arguments to another command. Adapting from the example, here is what you can do:

@ECHO OFF
:Loop
IF "%1" == "" GOTO Done
java YourClass %1
SHIFT
GOTO Loop
:Done

Save the above file as a batch file (with a ".bat" extension), and then you can drag-and-drop files onto it, and it will be passed as arguments.

Also, you can call the batch file from the command line and pass arguments as well.

Edit: It appears that the batch file will not work with quoted arguments which contain spaces. Using a workaround presented in the site I've linked to will split the spaces contained in the quoted full path of the file into separate arguments, so that won't work either. If anyone has a good idea how to fix this, please either edit this entry, or post another answer. I will make this a community wiki.

coobird
  • 159,216
  • 35
  • 211
  • 226
  • Are you sure it wouldn't run. I guess it will run, but with a few arguments. Then we can merge/concatenate all arguments back to one in our Java program. What you say? – Adeel Ansari Dec 20 '08 at 14:28
3

PhiLho's answer works perfectly if you pack the classes in an executable JAR file (it's how you're meant to do it anyway) and make a .reg file that looks like the one below. Then just double-click that .reg file to merge it into the registry and you're good to go. This lets you both double-click a JAR file to run it, and starting it by Drag & Drop.

Do remember to change the path to where your Java executable is installed.

Windows Registry Editor Version 5.00 

[HKEY_CLASSES_ROOT\.jar] 
@="jarfile" 

[HKEY_CLASSES_ROOT\jarfile\DefaultIcon] 
@="C:\\Java\\jdk1.7.0\\bin\\java.exe,1" 

[HKEY_CLASSES_ROOT\jarfile\shell\open] 
@="Run Java Program" 

[HKEY_CLASSES_ROOT\jarfile\shell\open\command] 
@="\"C:\\Java\\jdk1.7.0\\bin\\java.exe\" -jar \"%1\" %*" 

[HKEY_CLASSES_ROOT\jarfile\shellex\DropHandler] 
@="{86C86720-42A0-1069-A2E8-08002B30309D}" 
  • The drophandler key was all that needed to be added to make it work perfectly (the others existed already). I was however confused about the weird key value: {86C867...} So, I did some digging and this is the windows id key for the .exe drop target protocol handler. It's essentially a way of plugging the default drag'n'drop behaviour of 'argument passing' into the jarfile open command. To verify that the number is the same for you, open regedit and do a search for the value ".exe drop target", it should bring you to a key with this ID under HKEY_LOCAL_MACHINE/SOFTWARE/Classes/ Fyi :) – Andrew Nov 03 '14 at 07:27
  • The key value "{60254CA5-953B-11CF-8C96-00AA00B8708C}" is better for this - it's the WSH drop handler that handles long filenames better. (obtained from here: https://stackoverflow.com/a/142854/638544) – Brilliand Sep 14 '18 at 05:45
2

OK, I made it work... The base knowledge is to use DropHandler UUID in the registry. I made a base setting, as follow:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\.class]
@="JavaClass"

[HKEY_CLASSES_ROOT\JavaClass\DefaultIcon]
@="C:\\Java\\jdk1.6.0_05\\bin\\java.exe,1"

[HKEY_CLASSES_ROOT\JavaClass\shell\open]
@="Run Java class"

[HKEY_CLASSES_ROOT\JavaClass\shell\open\command]
@="\"C:\\Java\\jdk1.6.0_05\\bin\\java.exe\" \"%1\" %*"

[HKEY_CLASSES_ROOT\JavaClass\shellex\DropHandler]
@="{86C86720-42A0-1069-A2E8-08002B30309D}"

and... it didn't work!
I just forgot that java.exe wants a class name, not a file name! But I see no way to do that in the registry.

Fortunately, there is a workaround, which still need a script file if we want to be generic, to work on any/all class files (with static main function, of course!). Not batch, I avoid them when I can. I chose to use WSH, as it should be available on any modern Windows system. I also chose to make a JS script, it could have been a VB script as well.

So I made the following script (LaunchJavaClass.js):

if (WScript.Arguments.count() == 0)
{
  WScript.StdOut.Write("No parameters");
  WScript.Quit(1);
}
var className = WScript.Arguments.Item(0);
//~ WScript.StdOut.Write(className + "\n");
var m = className.match(/^(.*)\\(.+?)\.class$/);
if (m == null)
{
  WScript.StdOut.Write("Not a class file");
  WScript.Quit(1);
}
var classPath = m[1];
className = m[2];
//~ WScript.StdOut.Write(classPath + " >>> " + className + "\n");
var params = new Array();
for (i = 1; i < WScript.Arguments.count(); i++)
{
  params[params.length] = WScript.Arguments.Item(i);
}
var cmd = "cmd /c cd /D " + classPath + 
    " & C:/Java/jdk1.6.0_05/bin/java.exe " + 
    className + " " + params.join(" ");
//~ WScript.StdOut.Write(cmd + "\n");
var shell = WScript.CreateObject("WScript.Shell");
//~ var exec = shell.Exec(cmd); // Can be used to get stdout
shell.Run(cmd, 0);

I left some output, not useful in this context, but usable for debugging (run with cscript).
Of course, the path to the JRE must be adjusted.

And I changed the command in the registry, as follow:

[HKEY_CLASSES_ROOT\JavaClass\shell\open\command]
@="\wscript -b "D:\\_PhiLhoSoft\\WSH\\LaunchJavaClass.js\" %1 %*"

Of course, adjust path, and keep the above other lines.

Now, if I drag'n'drop some files to a .class file, it gets the short file paths as arguments of the main() function.

import java.io.*;

class TestDnD
{
 public static void main(String[] args)
 {
  Writer output = null;
  try
  {
   output = new BufferedWriter(new FileWriter(new File("LogFile.txt")));
   for (String arg : args)
   {
    output.write(arg + "\n");
   }
  }
  catch (IOException ioe)
  {
   ioe.printStackTrace();
   return;
  }
  finally
  {
    try { output.close(); } catch (IOException e) {}
  }
 }
}

I think the first version of the .reg file can be used for something else, eg. to drag'n'drop on .jar files (adapting it, of course).

This technique has limited use: we rarely make one-class programs in Java! But it looked like a good and interesting challenge, so I didn't resist to solve it. Note: you can add stuff like -Djava.ext.dirs="some path;another path" if you ever need to use external libraries (in jar files).

PhiLho
  • 40,535
  • 6
  • 96
  • 134
0

Adding onto Adiel A. If you create a batch file, which launches your a Java window using Swing. You would have the user drop the files onto that window. You could then be able to root through those dropped files.

kevindaub
  • 3,293
  • 6
  • 35
  • 46
  • I deleted my post, to clean up things. That was a misunderstanding becuase I haven't read the question well. Stupid me. – Adeel Ansari Dec 20 '08 at 14:29
0

So there's no way to have windows itself pass the args into main() via drag and drop?