Thread overview
regarding spawnProcess and parameters in Windows
Dec 15, 2013
Hugo Florentino
Dec 16, 2013
Danny Arends
Dec 16, 2013
Danny Arends
Dec 16, 2013
Hugo Florentino
Dec 16, 2013
Mike Parker
Dec 16, 2013
Hugo Florentino
Dec 16, 2013
Hugo Florentino
Dec 16, 2013
Hugo Florentino
December 15, 2013
Hello,

I am trying to do a small launcher for a Windows application which (in order to be portable) requires a specific parameter, and I am getting this error when I try to run it in Windows 7 SP1:

"std.process.ProcessException@std\process.d(518): Failed to spawn new process (Access denied.)"

This is the code I am trying to use:

import std.stdio, std.file, std.path, std.string, std.process;

static auto appname = "myapp";

int main(string[] args) {
  auto appath = dirName(thisExePath());
  auto appexe = buildPath(appath, appname ~ ".exe");
  auto appini = buildPath(appath, appname ~ ".ini");
  auto applaunchpars = format(`"%s" /ini="%s"`, appexe, appini);
  if (exists(appexe)) {
    auto appPid = spawnProcess(applaunchpars, ["" : ""], Config.suppressConsole);
    scope(failure) return -1;
  }
  return 0;
}

The ugly ["" : ""] hack is because I haven't been able to invoke spawnProcess otherwise, at least withouth specifying stdin and stdout (which I don't really need right now). Actually, I was thinking in making my own wrapper for ShellExecuteA (I don't find spawnProcess particularly intuitive), but I would prefer "the D way".

Anyway, Where could the problem be?

Regards, Hugo

December 16, 2013
On Sunday, 15 December 2013 at 23:14:45 UTC, Hugo Florentino wrote:
> Hello,
>
> I am trying to do a small launcher for a Windows application which (in order to be portable) requires a specific parameter, and I am getting this error when I try to run it in Windows 7 SP1:
>
> "std.process.ProcessException@std\process.d(518): Failed to spawn new process (Access denied.)"
>
> This is the code I am trying to use:
>
> import std.stdio, std.file, std.path, std.string, std.process;
>
> static auto appname = "myapp";
>
> int main(string[] args) {
>   auto appath = dirName(thisExePath());
>   auto appexe = buildPath(appath, appname ~ ".exe");
>   auto appini = buildPath(appath, appname ~ ".ini");
>   auto applaunchpars = format(`"%s" /ini="%s"`, appexe, appini);
>   if (exists(appexe)) {
>     auto appPid = spawnProcess(applaunchpars, ["" : ""], Config.suppressConsole);
>     scope(failure) return -1;
>   }
>   return 0;
> }
>
> The ugly ["" : ""] hack is because I haven't been able to invoke spawnProcess otherwise, at least withouth specifying stdin and stdout (which I don't really need right now). Actually, I was thinking in making my own wrapper for ShellExecuteA (I don't find spawnProcess particularly intuitive), but I would prefer "the D way".
>
> Anyway, Where could the problem be?
>
> Regards, Hugo

You need to pass the INI parameters separately see:

http://dlang.org/phobos/std_process.html#.spawnProcess

spawnProcess([appexe,format("/INI=%s")], ["",""], Config.suppressConsole);

Gr,
Danny Arends
http://www.dannyarends.nl
December 16, 2013
On Monday, 16 December 2013 at 00:59:51 UTC, Danny Arends wrote:
> On Sunday, 15 December 2013 at 23:14:45 UTC, Hugo Florentino wrote:
>> Hello,
>>
>> I am trying to do a small launcher for a Windows application which (in order to be portable) requires a specific parameter, and I am getting this error when I try to run it in Windows 7 SP1:
>>
>> "std.process.ProcessException@std\process.d(518): Failed to spawn new process (Access denied.)"
>>
>> This is the code I am trying to use:
>>
>> import std.stdio, std.file, std.path, std.string, std.process;
>>
>> static auto appname = "myapp";
>>
>> int main(string[] args) {
>>  auto appath = dirName(thisExePath());
>>  auto appexe = buildPath(appath, appname ~ ".exe");
>>  auto appini = buildPath(appath, appname ~ ".ini");
>>  auto applaunchpars = format(`"%s" /ini="%s"`, appexe, appini);
>>  if (exists(appexe)) {
>>    auto appPid = spawnProcess(applaunchpars, ["" : ""], Config.suppressConsole);
>>    scope(failure) return -1;
>>  }
>>  return 0;
>> }
>>
>> The ugly ["" : ""] hack is because I haven't been able to invoke spawnProcess otherwise, at least withouth specifying stdin and stdout (which I don't really need right now). Actually, I was thinking in making my own wrapper for ShellExecuteA (I don't find spawnProcess particularly intuitive), but I would prefer "the D way".
>>
>> Anyway, Where could the problem be?
>>
>> Regards, Hugo
>
> You need to pass the INI parameters separately see:
>
> http://dlang.org/phobos/std_process.html#.spawnProcess
>
> spawnProcess([appexe,format("/INI=%s")], ["",""], Config.suppressConsole);
>
> Gr,
> Danny Arends
> http://www.dannyarends.nl

Pressed send too fast:

1) Separately = As an array

2) And I also forgot the appini variable

So I think this should work:

spawnProcess([appexe,format("/INI=%s",appini)], ["",""],Config.suppressConsole);

Gr,
Danny Arends
http://www.dannyarends.nl
December 16, 2013
On Mon, 16 Dec 2013 02:04:10 +0100, Danny Arends wrote:
> ...
> So I think this should work:
>
> spawnProcess([appexe,format("/INI=%s",appini)],
> ["",""],Config.suppressConsole);
>

Hmm... that did not work either, it complained that the parameter was not correct. Actually, the syntax I was using should have worked (according to documentation, second overload of spawnProcess), and I also (unsuccessfully) tried with function execute.

Anyway, since my launcher will only be run from Windows, finally I decided to call ShellExecuteA directly (I find it less cumbersome to use and actually more elegant).

However, something is bothering me: when running the launcher, it opens a console temporarily before launching the other process (even when I am not using std.stdio) and I cannot get rid of this behavior.

This is the code I am now using:

import std.file: exists, getcwd;
import std.path: buildPath, dirName;
import std.string: format, toStringz;
import core.sys.windows.windows;

immutable static auto appname = "myapp";

extern(Windows) HANDLE ShellExecuteA(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, int);

int main(string[] args) {
  auto appath = getcwd();
  auto appexe = buildPath(appath, appname ~ ".exe");
  if (exists(appexe)) {
    auto param = format(`/ini="%s"`, buildPath(appath, appname ~ ".ini"));
    ShellExecuteA(null, "", toStringz(appexe), toStringz(param), "", SW_SHOWMAXIMIZED);
    scope(failure) return -1;
  }
  return 0;
}

Why does the console window appear and how can I prevent this?

Regards, Hugo
December 16, 2013
On 12/16/2013 6:33 PM, Hugo Florentino wrote:
> On Mon, 16 Dec 2013 02:04:10 +0100, Danny Arends wrote:

>
> However, something is bothering me: when running the launcher, it opens
> a console temporarily before launching the other process (even when I am
> not using std.stdio) and I cannot get rid of this behavior.
>
> This is the code I am now using:
>
> import std.file: exists, getcwd;
> import std.path: buildPath, dirName;
> import std.string: format, toStringz;
> import core.sys.windows.windows;
>
> immutable static auto appname = "myapp";
>
> extern(Windows) HANDLE ShellExecuteA(HWND, LPCSTR, LPCSTR, LPCSTR,
> LPCSTR, int);
>
> int main(string[] args) {
>    auto appath = getcwd();
>    auto appexe = buildPath(appath, appname ~ ".exe");
>    if (exists(appexe)) {
>      auto param = format(`/ini="%s"`, buildPath(appath, appname ~ ".ini"));
>      ShellExecuteA(null, "", toStringz(appexe), toStringz(param), "",
> SW_SHOWMAXIMIZED);
>      scope(failure) return -1;
>    }
>    return 0;
> }
>
> Why does the console window appear and how can I prevent this?

This is how Windows works. There are a couple of ways to eliminate the console. One is to use WinMain instead of main. That requires some boilerplate, though, as it bypasses the main function in DRuntime, so you have to initialize the runtime manually. It has the benefit of being portable across compilers. Another way, which is what I always do, is to add this to the command line (assuming DMD with OPTLINK):

-L/SUBSYSTEM:WINDOWS:5.01

Every linker on Windows has some form of this flag. It may even be the same when using the VC toolchain. Also, you can drop the version number at the end. It depends on the minimum version of Windows you target and the target architecture (32-bit vs. 64-bit). Google it if you want to be sure of the details.

December 16, 2013
On Mon, 16 Dec 2013 04:33:53 -0500, Hugo Florentino wrote:
> ...
> Why does the console window appear and how can I prevent this?
>

I forgot to mention that I tried using "int main ()" and even "void main()" and removing returns, but the console window keeps appearing, which is rather annoying for a Windows launcher.
December 16, 2013
On Mon, 16 Dec 2013 18:59:52 +0900, Mike Parker wrote:
> On 12/16/2013 6:33 PM, Hugo Florentino wrote:
>> ...
>> Why does the console window appear and how can I prevent this?
>
> This is how Windows works. There are a couple of ways to eliminate
> the console. One is to use WinMain instead of main. That requires some
> boilerplate, though, as it bypasses the main function in DRuntime, so
> you have to initialize the runtime manually. It has the benefit of
> being portable across compilers. Another way, which is what I always
> do, is to add this to the command line (assuming DMD with OPTLINK):
>
> -L/SUBSYSTEM:WINDOWS:5.01
>
> Every linker on Windows has some form of this flag. It may even be
> the same when using the VC toolchain. Also, you can drop the version
> number at the end. It depends on the minimum version of Windows you
> target and the target architecture (32-bit vs. 64-bit). Google it if
> you want to be sure of the details.

That did the trick, thanks.

Now, suppose I have two versions of the application (myapp32.exe and myapp64.exe), and I want my launcher to launch either, based on the architecture it detected from the OS being run on. What could I do in this case, which is actually what I need to do? (I just started with the simpler variant)
December 16, 2013
On Mon, 16 Dec 2013 05:15:24 -0500, Hugo Florentino wrote:
>
> Now, suppose I have two versions of the application (myapp32.exe and
> myapp64.exe), and I want my launcher to launch either, based on the
> architecture it detected from the OS being run on. What could I do in
> this case, which is actually what I need to do? (I just started with
> the simpler variant)

Disregard that (since Windows 64-bit can run 32-bit applications just fine), I made a new thread regarding the OS architecture detection.