5

Please note: I have created this GitHub project right here that can be used to perfectly reproduce the problem I'm seeing.


Java 8 here attempting to use Launch4J via the gradle-launch4j Gradle plugin to build a Windows native EXE application. I am doing the development of a Java Swing app on my Mac but the app must run as a Windows EXE on Windows 10. I am also using ShadowJar to build my self-contained "fat jar".

I can build my (Swing) app's fat jar and then run it on my Mac via java -jar build/lib/myapp.jar. It starts and runs no problem.

Here is my Gradle config for Launch4J:

launch4j {
    mainClassName = 'com.example.windows.hello.HelloWindowsApp'
    icon = "${projectDir}/icon.ico"
    jdkPreference = 'jdkOnly'
    initialHeapSize = 128
    jreMinVersion = '1.8.0'
    jreMaxVersion = '1.8.9'
    maxHeapSize = 512
    stayAlive = false
    bundledJre64Bit = true
    bundledJrePath = '../hello-windows/jre8'
}

When I run ./gradle clean build shadowJar createExe createDistro it produces:

hello-windows.zip/
    hello-windows.exe       -->     The Windows EXE built by the 'createExe' task
    lib/*                   -->     The lib/ dir for the EXE that is also built by the `createExe` task 
    jre8/                   -->     OpenJDK JRE8 (copied from the libs/jre8 dir)

So I copy that ZIP file and port it over to a Windows 10 (64-bit) machine. I extract the ZIP and run the EXE by double clicking it inside Windows Explorer (which I can confirm does see the EXE as an Application type). First I see this:

enter image description here

Why is this happening? Are there any Launch4J configurations/settings I can change so that this doesn't happen?

Thanks in advance!

hotmeatballsoup
  • 385
  • 6
  • 58
  • 136
  • Can you start the exe file from the Windows command line with the argument `--l4j-debug` and post the contents of the generated `launch4j.log` here? See https://github.com/TheBoegl/gradle-launch4j#debugging. – Thomas Traude Dec 04 '19 at 06:37
  • 1
    I cloned your GitHub repo and built the project using the Gradle command you posted. I can confirm that the exe file can be started in my Virtual Machine with Windows 10 Enterprise Evaluation 64 bit. There is no confirmation by the defender and no other message. Just the GUI pops up correctly. – Thomas Traude Dec 04 '19 at 06:42

4 Answers4

3

You need to sign the executable created by launch4j as described here to prevent SmartScreen from blocking it to be run. See also the related discussion in the support forum.

sschuberth
  • 28,386
  • 6
  • 101
  • 146
  • Does that mean we need to purchase a commercial certificate for signing purpose? I check price randomly, it seems like $600 per year! – Cheok Yan Cheng Mar 24 '22 at 11:48
  • If you are a commercial vendor, then probably yes. Open Source developers might get free certificates from some providers, also see https://stackoverflow.com/q/1177552/1127485. – sschuberth Mar 24 '22 at 15:08
1

Try setting the bundledJrePath in your build.gradle to just jre8:

launch4j {
  ...
  bundledJrePath = 'jre8'
}

Because that is in your case the relative path where the jre is when extracting the zip.

http://launch4j.sourceforge.net/docs.html

<path>, <minVersion>, <maxVersion>

The <path> property is used to specify the absolute or relative path (to the executable) of a bundled JRE, it does not rely on the current directory or <chdir>. Note that this path is not checked until the actual application execution

Beware that the path must not contain the /bin/javaw.exe.

When running the exe with the debug flag like this

hello-windows.exe --l4j-debug

then it will create a file launch4j.log in the same directory. There you can check that the correct jre is picked up, for example:

...
Bundled JRE:    jre8
Check launcher: C:\Users\IEUser\Downloads\hello-windows\jre8\bin\javaw.exe (OK)
...
Thomas Traude
  • 840
  • 7
  • 17
1

Your first question is more like a Windows question. When you unzip an application from a zip file, Windows will naturally mark it as unsafe, in fact if you check the application properties tab, you will see a checkbox where you can remove that unsafe attribute. It's same as running chmod+x for an executable script in Linux.

For the second part, I assume you are using the gradle plugin for Launch4j, there are two main ways to configure Launch4j assuming your project folder is structured commonly with the jre library in the same folder containing your executable folder.

  1. By specifying the path only like

    ../jre
    
  2. By specifying the full relative path

    ../jre/bin/javaw.exe
    

Your generated xml at the end should look like this in the first case.

<jre>
    <path>../jre</path>
</jre>

The main point is that the path to JRE is relative to the position of the executable not the current directory. In this case, we step back one directory from the executable folder to the folder containing jre.

Chibueze Opata
  • 9,856
  • 7
  • 42
  • 65
  • Thanks @Chibueze (+1) - you're suggestions worked and got it finding the JRE! Just one quick followup question for you, if you don't mind: when you say "_in fact if you check the application properties tab, you will see a checkbox where you can remove that unsafe attribute_", I'm sorry but I'm not understanding 100%. **Which** "application properties" tab are you referring to, and where could I find it? Basically, I just need this "Windows defender" warning to go away and just run my app, how do I fix that? – hotmeatballsoup Dec 06 '19 at 17:07
  • @hotmeatballsoup I'm referring to the window that shows when you right click the executable and click **Properties**. The only solution to this is to sign the file. You can use your own strong key to [sign it](https://stackoverflow.com/a/252245/612717). Since you are using Mac, I believe you can do it via [Mono](https://stackoverflow.com/a/18288049/612717) – Chibueze Opata Dec 07 '19 at 13:04
0

I upvoted the answer above from sschuberth, as that is the best answer to your question. Signing the executable will make SmartScreen happy.

As addition I would rather prevent trying to create an executable, even signing it, best to create a MSI. For example by using Javapackager. See also this question. That guy created his own tool after using Nullsoft.

It is very cumbersome to get an executable accepted by every virus scanner around the world. I have the experience of using WIX Toolset to create an MSI and wrapped it into a bootstrapper executable, signed it using the company signing certificate. However in the end I had to send requests to McAfee, Norton, Avast, AVG, KasperSky and Trend Micro. Gladly all accepted it over time, only Trend Micro never even responded.

rfcdejong
  • 2,219
  • 1
  • 25
  • 51