A new version of WinRun4J is available. …

A new version of WinRun4J is available. It contains the following fixes and new features:

  • Major new feature is the dynamic native binding. This provides the ability to use native Windows API functions without having to write any JNI/native code. See native binding examples for more information.
  • Fixed a race condition in the service implementation for quick starting applications.
  • The launcher java library now requires java 1.5 minimum (due to use of annotations). The launcher executable is compatible with java 1.4 and above.
  • Fixed lowercased key issue with INI file
  • Fixed max heap size issue on 64-bit VM
  • Added option to set console title via INI file
  • Added option to suppress error popups
  • DDE activate message sends command line

The following shows a simple example of the native binding:

package org.boris.winrun4j.test;

import org.boris.winrun4j.PInvoke;
import org.boris.winrun4j.PInvoke.DllImport;
import org.boris.winrun4j.PInvoke.UIntPtr;

public class BindingExample1
{
    @DllImport("kernel32")
    public static native boolean GetComputerName(StringBuilder lpBuffer, UIntPtr lpnSize);
    
    public static void main(String[] args) throws Exception {
        StringBuilder name = new StringBuilder();
        UIntPtr size = new UIntPtr(100);
        if (GetComputerName(name, size)) {
            System.out.println(name);
        }
    }

    static {
        PInvoke.bind(BindingExample1.class);
    }
}

You can download the new version from the WinRun4J Sourceforge Site.

Thanks to everyone who found bugs and gave suggestions.

Advertisements

44 Responses to A new version of WinRun4J is available. …

  1. Abdullah says:

    Thanks for the great tool

    RCEDIT.exe /I [YourApp].exe [YourApp].ico

    is working in case *.ico contains 256×256 icon but with /A option is not. is it a bug?

    • poidasmith says:

      Hi,

      Thanks for the feedback. I will double check it could be an issue with RCEDIT or just Microsoft’s resoruce API (which is flaky to say the least).

      Thanks,
      Peter

  2. Matt says:

    Hi Boris,

    Firstly, thanks for this tool, it’s great 🙂

    I was wondering if you could help me with a specific issue I am seeing … when using as a windows service, if you enable either local or remote jmx, you cannot connect to the process using jconsole. Is this a known issue? Do you know of any workarounds?

    Thanks for your time,

    Matt

    • Matt says:

      BTW, the jconsole error is:

      This virtual machine “” does not support dynamic attach.

      I will let you know if I can dig up an answer.

      Thanks

      • poidasmith says:

        I haven’t had a chance to test yet, but could it be related to the fact that the service is running as a different user? ie. a security/permission issue. Also wondering if there are firewall settings for the service user. Do you get the same issue if you set the run user for your service as your own user/pass?

      • Matt says:

        Unfortunately, even with the service and jconsole running under the same user you still get the same error.

      • Matt says:

        However, it works fine when running under winrun4j as a standard executable 🙂

      • poidasmith says:

        Could you try the latest version 0.4.2?

      • Matt says:

        Thanks for the reply 🙂 Have done, and we get a new error, which is progress!

        “The management agent is not enabled on this process.”

        Thanks again for taking the time to look at this 🙂

      • Matt says:

        Seems to be a windows problem, not a Winrun4j problem [http://stackoverflow.com/questions/4669203/jconsole-cannot-connect-to-java-processes-running-as-windows-7-services]. The new version lets me connect remotely 🙂 WIN! Thanks 🙂

    • Adam says:

      I got insecure remote jmx working with these in my service .ini file
      ; if you have -Xrs, remove it
      ;vmarg.1=-Xrs
      vmarg.1=-Dcom.sun.management.jmxremote
      vmarg.2=-Dcom.sun.management.jmxremote.port=8790
      vmarg.3=-Dcom.sun.management.jmxremote.authenticate=false
      vmarg.4=-Dcom.sun.management.jmxremote.ssl=false

      You should be able to do local or secure remote too – this is just how I set it up.

  3. Stefano says:

    Hi,
    I find your tool extremely useful. Thanks!

    But I have a problem: I try the service example, but Windows raise the 1053 error. I found some post about it, but didn’t understand how to fix it.

    Would you be so kind to give me some suggestion?

    Thanks a lot
    Stefano

  4. Adam says:

    The EventLog class puts the message in Windows Events as raw data rather than in the description. It also registers the event source each time and doesn’t deregister it. I tried solving these issues with a bit of a rewrite, but the ReportEvent call fails – I presume because I’m not getting the pointer an array of strings parameter right. I don’t see how to do that.

    /**
    * A mechanism for adding events.
    */
    public class EventLog
    {
    public static final int SUCCESS = 0x0000; //Information Event
    public static final int ERROR = 0x0001; // Error event
    public static final int WARNING = 0x0002; //Warning Event
    public static final int INFORMATION = 0x0004; //Information Event
    public static final int AUDIT_SUCCESS = 0x0008; //Success Audit Event
    public static final int AUDIT_FAILURE = 0x0010; //Failure Audit Event

    private static long library = Native.loadLibrary(“advapi32”);

    /** Windows handle to event source */
    private long hSource = 0;

    /**
    * Initialize EventLog
    *
    * @param source Name of the reporting application or service
    */
    public EventLog(String source)
    {
    long buf = NativeHelper.toNativeString(source, true);
    hSource = NativeHelper.call(library, “RegisterEventSourceW”, 0, buf);
    NativeHelper.free(buf);
    }

    /**
    * Garbage collect instance
    */
    @Override
    protected void finalize() throws Throwable
    {
    if (hSource != 0)
    NativeHelper.call(library, “DeregisterEventSourceW”, 0, hSource);
    }

    /**
    * Is the event log properly initialized?
    */
    public boolean isGood() { return hSource != 0; }

    /**
    * Report an event.
    *
    * @param type The event type. Use one of the EventLog constants
    * @param msg String to log. Must not contain %n, where n is a digit.
    *
    * @return boolean.
    */
    public boolean report(int type, String msg)
    {
    if (hSource == 0)
    return false;

    // Construct pointer to pointer to null-terminated wide string?
    String[] msgs = new String[1];
    msgs[0] = msg;
    long m = NativeHelper.toMultiString(msgs, true);

    long res = NativeHelper.call(library, “ReportEventW”,
    new long[] { hSource, type, /*category*/0,
    /*GENERIC_MESSAGE*/0x20000001L,
    /*userSID*/0, /*numStrings*/1,
    /*dataSize*/0, /*strings*/m, /*rawData*/0 });
    NativeHelper.free(m);
    return (res != 0);
    }
    }

    • poidasmith says:

      Hi,
      Thanks for the feedback. I will take a look and try to get a new version of soon.
      Cheers,
      Peter

      • Omyl says:

        I think, the problem is in NativeHelper.toMultiString implementation – it must return ‘pointer’ to ‘array of pointers to string data’, no ‘pointer to buffer with serialized strings data’

        when I reimplement NativeHelper.toMultiString, everything works OK:

        public static long toMultiString(String[] strs, boolean wideChar) {
        if (strs == null || strs.length == 0)
        return 0;

        int size = strs.length*NativeHelper.PTR_SIZE;
        long ptr = Native.malloc(size);
        ByteBuffer bb = NativeHelper.getBuffer(ptr, size); // pointer array
        for (String actStr:strs) {
        long strPtr = NativeHelper.toNativeString(actStr, wideChar); // pointer to buffer for each string
        //add pointer to pointer array
        if (Native.IS_64) {
        bb.putLong(strPtr);
        }else{
        bb.putInt((int)strPtr);
        }
        }
        return ptr;
        }

  5. Adam says:

    WinRun4J works great so long as Windows Service Control tells the process to shut down. If my process chooses to exit on its own though, it doesn’t actually exit. The flow will return 0 from serviceMain(), but the process remains resident and Windows Service thinks it’s still running.

    How can I exit programmatically? Ideally it should be able to exit success (just stop and be happy about it), or exit with failure, in which case the service’s recovery settings kick in.

    • poidasmith says:

      Hi,

      Yes, good point. I didn’t think of this use case. I suspect the launcher should always report a status update when the java process completes. Thanks, I will take a look and try to get a new version out soon.

      Cheers,
      Peter

    • poidasmith says:

      Actually, looking at the code it does update the service status:

      g_returnCode = env->CallIntMethod(g_serviceInstance, g_mainMethod, args);
      Log::Info("Service method completed.");

      // When the service main completes we assume the service wants to stop
      // so wait for the VM is tidy up (all non-daemon threads complete etc..)
      VM::CleanupVM();
      g_serviceStatus.dwCurrentState = SERVICE_STOPPED;
      SetServiceStatus(g_serviceStatusHandle, &g_serviceStatus);

      return g_returnCode;

      It could be that you are using System.exit? Instead you should just return the exit code from the serviceMain method.

      • Adam says:

        It isn’t working that way for me. Might a daemon thread, or anything else, prevent VM::CleanupVM() from returning?

      • Adam says:

        I checked my application with jconsole. After my program exits serviceMain, all of my threads are indeed gone. The only threads are the usual JVM overhead, the thread that called serviceMain() with and empty stack, and a thread called main, also with an empty stack.

      • Adam says:

        Now I see it hanging sometimes even when using services.msc to stop the service. Again, I can attach with jconsole afterwords and all of my threads have exited.
        I used to exit with System.exit(0). Any chance of that working?

      • Adam says:

        (Wish I could edit or delete my old replies…)
        I think I found it… seems some coincidence was misleading me on the cause/effect.
        It works so long as I don’t make a DB connection. Once I do, stop hangs. If I connect with jconsole and run garbage collection, it immediately exits. I’ll probably be able to handle it from here, but you may want to add a garbage collection before (after?) VM::CleanupVM() to prevent this from being an issue for others.

      • Adam says:

        Hi again. The source code packaged with the library looks different than your paste above. I tried compiling it with Visual C++ 2008 Express Edition, but it fails. (I think I’m lacking an assembler.)

        I can usually exit cleanly now. The reason I was trying to compile the C++ was to add a garbage collection and an option for my program to exit with a request to be immediately restarted. (Do to configuration change.) Need JVM to completely exit and reload so that static instances reinitialize. Any chance you can add that? Basically I want to stop and start the service, but need to trigger that from within the program.

  6. nick says:

    Hi, I’ve been setting up a number of windows services for a large ECM deployment and have decided to use WinRun4J due to it’s simplicity (and cost :). As I have quite a few services to set up I was looking for a way to do this without creating new copies of the service executable and I have failed.
    Is there a hack like the one for windows launch configuration noted previously that can be applied to a service configuration on registration?
    I’ll continue to figure it out myself, and post back if I get anywhere.

    Thanks,
    Nick

    • poidasmith says:

      Hi,

      I haven’t checked but you might be able to use service args and specify:

      –WinRun4J:ExecuteINI [path to ini]

      You do this by modifying the ImagePath key in the registry for the service. Eg look at:

      HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Dhcp

      Hope that helps. Let me know how you get on!

      Regards,
      Peter

  7. gagle says:

    Hi,

    How do I have to write the main service class?

    The .ini file is:
    main.class=test.TestService
    service.class=test.TestService
    service.id=StreamServer
    service.name=StreamServer
    service.description=Servidor que proporciona una comunicación con streams.
    service.controls=stop
    classpath.1=*.jar

    And the class that I must modify is:
    package test;

    public class TestService{
    private static TestServer server;

    public static void main (String[] args){
    if (args.length == 1){
    if (args[0].equals (“start”)){
    if (server == null){
    server = new TestServer (5000);
    server.start ();
    }
    }else if (args[0].equals (“stop”)){
    if (server != null){
    server.stop ();
    server = null;
    }
    }
    }
    }
    }

    The documentation is poor in this aspect.

    Thanks.

  8. scot says:

    First off, great tool! as a newbie….Can you point me to examples of creating a functions that take excel ranges and then loop over the the ranges in excel? not sure of how a excel ranges and variant fields map into java. thanks. -Scot

  9. Neil says:

    Just a quicky – thanks for a great tool. Sourceforge however is offering the 0.4.1 build as the latest to download instead of the 0.4.2. Took me a while to realise I didn’t have the latest build while I was experimenting.

  10. Eyal says:

    Hi Boris
    Great too indeed!

    I have a question – it seems I can’t run a WinRun4J executable from a java application (or any process I suspect).
    When running a WinRun4J executable from my java app, the exe hangs until the parent process (i.e. the calling java app) terminates.

    I think it’s go to do something with defining the executable’s log propety in the ini file, but I gave up at some point and went for a very-not-ideal workaround – Creating a little exe which runs the WinRun4J’s exe.

    Any thoughts?

    Thanks

    Eyal

  11. Eyal says:

    Wrap the following class in app.jar
    ================================

    package test;

    import javax.swing.*;

    public class MyExeMain {
    public static void main(String[] args) {
    JFrame fr = new JFrame(“Hello ” + System.currentTimeMillis());
    fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    fr.setSize(300, 300);
    fr.setLocationByPlatform(true);
    fr.setVisible(true);
    }
    }

    Define this INI file, under C:\test\SomeTest\MyApp.ini:
    ==========================================

    main.class=test.MyExeMain

    classpath.1=*.jar

    And then run this java code:
    =================================

    package test;

    public class ExeRunner {
    public static void main(String[] args) throws Exception {
    go();
    }

    private static void go() throws Exception {
    java.io.File exe = new java.io.File(“C:\\test\\SomeTest\\MyApp.exe”);

    ProcessBuilder x = new ProcessBuilder(exe.getAbsolutePath());
    x.directory(exe.getParentFile());
    x.start();

    for (int i = 3; i >= 1; i–) {
    System.out.println(“Exe’s window will be visible in ” + i + ” second(s)”);
    Thread.sleep(1000);
    }
    }
    }

    If you add a ‘log’ property to the INI, the EXE will indeed run from the ‘go’ method, but if you try calling ‘go’ again, it won’t – until the java app will terminate and then hanging EXE will run

  12. Eyal says:

    Hi

    When is a new version (one which support java 7) will be availale?

    I’m depending on this (great) tool and can’t really use the 64 bit version

    Thanks a lot

    eyal

  13. MIO says:

    Hey poidasmith,

    can you explain me why i’m unable to run two of your WinRun4J as services. When i tried to start the second service it comes with the error 1053. the services works perfect if i run them stand-allone. How can i fix this.

    thanx MIO

    • poidasmith says:

      This is the usual problem where the service has an error on startup. We need to see what the actual error was. Can you enable logging in your service INI and log to a file?

  14. Frank Seidinger says:

    Hi all,

    I’ve tried to use winrun4j as a service with a project that uses spring with annotations, the java persistence api (JPA) with hibernate as SPI provider of JPA and an embedded HSQLDB server instance. If I start my main class using the normal launcher my application starts up just fine. But using the service launcher fails.

    I already left a comment for the version 0.4.3 but this time spend some more time to investigate and found a possible bug (also in 0.4.4) and have a working bug fix that can be applied to the serviceMain method.

    First the results of my investigation. Inspecting the logs of my application lead to a NullPointerExcpetion as the root cause in the hibernate JPA implementation:

    Caused by: java.lang.NullPointerException
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:316)

    Thanks to be open source the affected line of source code can be analyzed and reads as follows:

    Enumeration xmls = Thread.currentThread()
    .getContextClassLoader()
    .getResources( “META-INF/persistence.xml” );

    From analyzing the javadoc descriptions of the affected methods calls only the method getContextClassLoader can return a null value if the primordial thread didn’t supply a context class loader.

    Therefore the following workaround is needed in the serviceMain method before starting the application code:

    // get thread running this method
    Thread currentThread = Thread.currentThread();

    // assure that a context class loader is set
    if (currentThread.getContextClassLoader() == null) {
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    currentThread.setContextClassLoader(systemClassLoader);
    }

    From my point of view the context class loader of the thread running the service main method should be set to a non null value by WinRun4J.

    • poidasmith says:

      Hi Frank,
      Thanks for the bug report and details. It sounds like this problem might be the cause of some issues that other people have reported also. I will do some testing and report back.
      Cheers,
      Peter

%d bloggers like this: