Passing startup arguments to a web-app installed as a windows service

I have a standalone web-app that accepts arguments in the App.Open event (which includes the built-in ability to set the port at start-up through --port=xxxx). When I run the app from the administrator command line, and include arguments like --port=9900 --token=zbdjfvqrhgfv, the web app takes the arguments and processes them correctly. The web-app has default values built-in so that if arguments are not included then it defaults gracefully.

The web-app takes headers and a json string passed to it through the HandleSpecialURL

If I then take the web-app and create a windows service with the sc.exe command from an administrator command line, the service runs correctly if I don’t provide any arguments as it runs with the defaults. I have tried several ways to be able pass the arguments to a service upon start:

  1. Using the built-in Services application and setting the Startup type as Manual (Auto start ignores Start Parameters) and providing the Start parameters as:
    a) --port=9900 --token= zbdjfvqrhgfv
    b) --port=9900, --token= zbdjfvqrhgfv
    c) --port=9900; --token= zbdjfvqrhgfv
    d) “–port=9900” “–token= zbdjfvqrhgfv”
    e) “–port=9900”, “–token= zbdjfvqrhgfv”
    f) “–port=9900”; “–token= zbdjfvqrhgfv”
    plus all the above configurations without the double dash preceding the arguments.

  2. Appending the same variety of start parameters to the Registry Entry ImagePath key (in an attempt to be able to have the service start automatically and still have control over these start up arguments):
    key: ImagePath
    type: REG_EXPAND_SZ
    data: arg1 arg2

None of these variations seem to work. The service seemingly starts and then when queried, immediately returns:

Error 504 “The server did not return a complete response for this request. Server returned 0 bytes.”

and the service dies. A 504 error indicates a gateway timeout error and is usually a network error between servers on the Internet or an issue with an actual server… in this case the web-app standalone I’m presuming.

From the administrator command line: works with or without arguments
As a service: No arguments, it works… with arguments it fails.

What am I missing here?

sc create ServiceName binpath= "“PathWithSpacesToEXE” --port=PortNumber --token=TokenWithoutSpaces” start= auto

Just replace the bold placeholders. The backslash followed by a double quote is an escaped double quote so an executable path with spaces (e.g. C:\Program Files (x86)\App Name\App.exe) can be used.

Thank you Frederick for that response. In this regard you are advocating including the two args within the outer quotes when you create the service with a separate set of inner quotes (escaped) around the PathWithSpacesToEXE. When the service is created this way and then started, I get an error that the application (the one with the inner quotes around it) could not be found because (of course) the path does not include quotes. In other words, the path is C:\Program Files(x86)\App Name\App.exe and not “C:\Program Files(x86)\App Name\App.exe”

When you create the service the way you’ve described, the Registry entry actually has the quotes around the path which isn’t correct. Somehow internally, windows knows how to deal with paths with spaces in them, at least where it regards the Registry. Looking at other entries in the registry that have spaces in the path, they have no double quotes around that path.

Still missing something…

The syntax provided works for all of our commercial web apps on 32-bit and 64-bit versions of Windows 7, Windows 8, Windows 8.1 and Windows 10.

Quotes are not the problem. Perhaps it is a typing error like the one in your path. Program Files (x86) should have a space between Files and b[/b]. Your path is missing that space.

Yes, you are correct that in the example I typed above, there should be a space between Files and (x86), but that is not the problem as I am not hand-typing it when creating the service. Above I was merely pointing out what happened when I followed your instructions by escaping the inner quotes.

Based on the error you’re getting, if it’s not a path problem then it may be a permissions problem. What version of Windows are you using? What’s the exact syntax used to successfully launch the app from a command line? What’s the exact syntax used to create the service that fails to find the executable?

Just a quick note… All of the examples given (a-f) I. The original post have a space between the = and the token value. Is that what you’re really passing to your app?

Have you looked at OptionsParser on Github? it is designed to take command line arguments and parse them out for you.

You shouldn’t need that on a console app.

Greg, the space on the original post is not what is actually being passed. In my haste to detail the problem I inadvertently introduced that space and for that I apologize. When I wrote the post I was attempting to get the concept across that no matter how the arguments were presented, they weren’t being recognized when comparing how the app ran from the command line to how it ran as a service. It almost seems that the app isn’t really running when I start the service even though it says its running… i think…

After sprinkling some “system.DebugLog” entries throughout my code, including several in the App.Open event, I am not seeing any of those messages in DebugView output… which tells me that the app isn’t really running?

Sounds like it.

Okay… the problem has been solved with a bit of offline help from Frederick Roller. Part of my problem has been an inability to understand how to see what is actually going on when running a windows service and just assuming that it’s doing certain things when it’s not (we all know what assuming gets us right? right?) While developing in the IDE you can set breakpoints to determine whats going on within your app.

Once you build a web-app you can still use things like msgbox to give you clues about whats happening because if you launch the app by dbl-clicking on the app icon it opens a command line window and any of the msgbox outputs go to that window. Same with launching the app via command line.

Once you install the app as a service that all goes away. Now, in order to see whats happening you need to look at the system.debuglog. But the debuglog is a different call in your program than msgbox so you either replace the msgbox calls with system.debuglog calls or you duplicate them. I am watching the windows debuglog by using DebugView (a free MS utility). Some stuff is coming through, but not anything from my app. A few tweaks later and I realize that in order to see the WIN32 messages I have to start the DebugView as Administrator… did that… now I’m cookin with crisco. Im still not seeing anything coming through from my app, and I should be because there are several system.debuglog calls in the App.Open event. When you start the service it should fire the App.Open event right?

Frederick warns me that it might be the connection to MSSQL server thats killing the app. I had told him what the general purpose of the app was and part of it relies on a connection to a local MSSQL server. Of course that method isn’t called until well after the app has completed starting up, and I’m not even seeing it start up (according to the system.debuglog). I wasted hours fiddling with launch permissions and installing the service and deleting the service and installing the service again and again in various configurations. Somehow I go back to twiddling with DebugView and see that there is a menu option to “Capture Global Win32” in addition to the already selected “Capture Win32”. So I turn that on and VOILA!!! all of a sudden my system.debuglog messages from the App.Open event start showing up. At this point I realize that I have been wasting my time in all sorts of other directions because of an inability to understand what I needed to do in order to see what was going on under the hood.

Frederick suggests that I look at the Event Viewer to see what the error message is when the app crashes. I’m thinking to myself “Wait… you mean that in addition to a DEBUG LOG I have to go somewhere else to see what the error was when it crashed?” So I open the Event Viewer and am presented with a plethora of event logs to look at; oh goodie! where to start? There it is under the first one I come to; Windows Logs>Application and voila the error is define for me… Login failed for user. Reason: Failed to open the explicitly specified database… Frederick was right.

In the properties for the Service I set the Log on as: to the account which accesses the MSSQL db, started the service and Voila! It worked. I sent data to the service and Voila! it processed it. Stopped the service. Went to the Registry entry for the service and added the args I had been trying to add way back at the beginning. Started the service and Voila! it worked. I sent data to the service on the new port and with a new token and Voila! it processed properly!

As a lot of people have mentioned before, so I will mention now… this is an awesome forum all the way from the presence of Xojo personnel who watch and contribute, down to slugs like myself and all the greatness in-between. Thanks specifically to Frederick Roller for taking the time to coach me through my silly questions on this one… now if I can commit to keeping that information in my head I’ll be fine.

somewhere you have to parse the args from the command line. OptionsParser does a nice job for you so you don’t have to spend the time doing it yourself.

I parse the args from within the app