1

I have some code to run java.exe with command line to launch a game. Since I don't players launch more than one game program instance at same time, so I need to check whether the game has been running or not.

For normal exe file, I can get exe path from process information. But for java game, the execute file path is always the java.exe or javaw.exe's path. So I have thought to get the command line information to get the jar file running. But there is the reason why I can't get the command line:

Remember that from Win32's point of view, the command line is just a string that is copied into the address space of the new process. How the launching process and the new process interpret this string is governed not by rules but by convention.

So, I need another way to do such thing, but I can't thought out any method to distinguish two java process. Anyone could give me some tips?

zzy
  • 1,771
  • 1
  • 13
  • 48
  • Set up a [named Mutex](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686927.aspx) from your Java code. If the call to [CreateMutex](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682411.aspx) succeeds, this is the first instance. If it fails with error code `ERROR_ALREADY_EXISTS`, it's not the first instance. – IInspectable Sep 09 '15 at 10:21
  • @IInspectable That's a good point, but I can't change the Java code for some reason. Is there another way? – zzy Sep 09 '15 at 10:39
  • Move that to your launcher application then, and keep the launcher process around, until java.exe returns (presumably when the game terminates). This won't keep an attacker from launching the game multiple times, though. It'll only keep people launching the game through the launcher from running that multiple times concurrently. – IInspectable Sep 09 '15 at 11:31
  • @IInspectable The difficult aspect is how to keep launcher process alive? People can kill it simply by taskmgr. – zzy Sep 09 '15 at 11:38
  • *"So I have thought to get the command line information to get the jar file running."* process explorer shows that information, so it should be available through some API – the8472 Sep 09 '15 at 11:48
  • @the8472 I think so before I found the quoted sentences. It shows me that even you can get it, it would not be the one you first pass it into. In other words, is there some articles shows that the command line passed to java.exe would be changed? – zzy Sep 09 '15 at 12:01
  • If you insist on not changing anything, don't be surprised that you won't get the perfect solution. Your expectations are not realistic. – David Heffernan Sep 09 '15 at 12:04
  • @DavidHeffernan I have never said everything can not be changed, I only said the java game's code can not be changed. I use win32 program to run java.exe. All of other things are changeable. – zzy Sep 09 '15 at 12:19
  • So put the java processes in a job with your launcher, and if the launcher is killed, the java processes go down too. Or something along those lines. – David Heffernan Sep 09 '15 at 12:23
  • 1
    If you cannot change the Java code, why do you presume, that gathering the command line that launched said Java code would be of any help? Also, the user doesn't have to kill your launcher process, to start a new game instance from the command line. After all, the user can inspect the command line you passed to java.exe to launch the game, using tools like Process Explorer. Unless you modify the actual game code, you will have to live with a half-assed solution. – IInspectable Sep 09 '15 at 12:28
  • 1
    possible duplicate of [How to implement a single instance Java application?](http://stackoverflow.com/questions/177189/how-to-implement-a-single-instance-java-application) – theB Sep 09 '15 at 12:30
  • @IInspectable You're right, I will reconsider my aim. – zzy Sep 09 '15 at 12:41
  • @the8472 - The problem is programs are free to change their command lines as soon as they start, therefore the value is non-authoritative. See Raymond Chen's [excellent article](http://blogs.msdn.com/b/oldnewthing/archive/2009/11/25/9928372.aspx) on the subject. – theB Sep 09 '15 at 14:10
  • @theB just because it *can* happen doesn't mean it will be a problem in your case. – the8472 Sep 09 '15 at 15:15
  • @the8472: If it can happen, it **will** happen. It's not a matter of whether this is a bug, but rather, when it turns into a problem. – IInspectable Sep 09 '15 at 15:49
  • @IInspectable, huge asteroids also strike the earth often, stars go dim and bismuth does undergo radioactive decay. – the8472 Sep 09 '15 at 16:30
  • @the8472: One difference: Applications change the command line **very** frequently. Pretty much every application parses the command line, inserting NUL characters to delimit parameters. You are right about one thing, though: It's a matter of time, until an asteroid hits planet earth. – IInspectable Sep 09 '15 at 16:43

2 Answers2

4

You don't have to run java.exe from your launcher. Instead your launcher may create an in-process JVM by using the Invocation API. This way you can check executable path, examine the command line, create named mutex or do whatever you want without relying on an external Java launcher.

The other solution is to find the main class, the arguments and the VM options of other Java processes in the system using Jvmstat Performance Counters, just like jps and jcmd utitities do. The idea is that every Java process (unless run with -XX:+PerfDisableSharedMem) exports certain run-time information as a memory-mapped file in user's Temp\hsperfdata_user folder. So you can examine these files to see if they belong to the game.

apangin
  • 92,924
  • 10
  • 193
  • 247
  • For hsperfdata, it says "This file must not be on a FAT filesystem.". It would cause some problem for someone. – zzy Sep 10 '15 at 01:42
  • pretty sure that a temp dir on FAT would cause problems for many applications in any modern operating system, that's not really specific to java. – the8472 Sep 13 '15 at 16:38
0

I guess You can pass JVM arguments as "-Dservice.name". Then from the launch file (.bat or .sh file) and before get it launched again, you can check whether a process is running already with service.name or not. And take the decision accordingly.

Ankit_ceo2
  • 317
  • 1
  • 6
  • 14