How do I find out the current directory of my EXE ...
# compose-desktop
s
How do I find out the current directory of my EXE on Windows?
File(".").absolutePath
returns the working directory which I could change in a symlink.
Copy code
Server.class.getProtectionDomain().getCodeSource().getLocation().getPath()
results in NullPointer if started from the EXE. Is there something compose specific to find that out?
1
t
Not sure why you're looking for something "compose specific". Maybe natvie specific. And if you want to support it for JVM, than do you mean to find java.exe path?
s
I was thinking that maybe Jetbrains has made a nice API for that I'm not aware of. The pure Java ways are somewhat hacky and some of them don't work from that EXE. I meant "Compose for Desktop specific"
Think of the very nice way they implemented to detect if the dark mode is active... You can do this on yourself, but sometimes Compose for Desktop already has a nice util for stuff like that ready to use. 😉
Copy code
val path = Thread.currentThread().contextClassLoader.getResource("icon.ico")

val jarPath = path.path.substring(6, path.path.length - 10)

val pathToDir = File(jarPath)
  .parentFile
  .parentFile
  .canonicalPath
  .replace("%20", " ")
Not nice, but seems to work.
e
a more reliable way to get the JAR file from a resource URL would be
Copy code
File((path.openConnection() as JarURLConnection).jarFileURL.toURI())
👍 1
and a more reliable way to get the JAR file containing a class in general would be
Copy code
java.io.File(this::class.java.protectionDomain.codeSource.location.toURI())
s
No, that does not work. "codesource" is NULL executed in the EXE
e
which class are you using for that? it will be null if it's a system class, but if it's one of your own I would expect it to work… unless something unusual is going on with the packaging
🙈 1
s
I improved my solution a bit.
Copy code
val url = Thread.currentThread().contextClassLoader.getResource("icon.ico")

val jarPath = url.path.substring(0, url.path.length - 10)

val pathToExe = Paths.get(URI(jarPath))
  .resolve("../../MyApp.exe")
  .toFile()
  .canonicalPath
Oh, well... Yes, I used a system class. I wasn't aware that this will make a difference 😅
e
it makes a huge difference; it comes from the parent classloader, after all. in any case I would consider
File(.toURI())
to be far more reliable than
.replace("%20", " ")
s
Yes, you are right. Even URLDecoder.decode() is better than that.
I ended up with this and tested it even for UNC paths:
Copy code
val url = Thread.currentThread().contextClassLoader.getResource("icon.ico")

val jarPath = url.path.substring(0, url.path.length - 10)

val pathToExe = Paths.get(URI(jarPath))
    .resolve("../../MyApp.exe")
    .toFile()
    .canonicalPath

<http://Log.info|Log.info>("App location: $pathToExe")
Other solutions may work well, too, but I think this is good enough. I can change the working dir in a link and it still finds the correct place of the EXE file. Is there any case where this code could break? 🤔
I would really love JetBrains to provide a variable with the path to the EXE and I think based on the Gradle native distribution configuration they could provide it. All they need is the name of the EXE which is configured and unless the user actively changes it I see no reason why this can fail.
But if the user starts to rename files in my distribution a lot of other things should fail as well 😄
225 Views