Skip to content

Passing Command Line arguments to .exe generated after build #337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
VH97 opened this issue Nov 5, 2019 · 9 comments
Closed

Passing Command Line arguments to .exe generated after build #337

VH97 opened this issue Nov 5, 2019 · 9 comments
Assignees
Milestone

Comments

@VH97
Copy link

VH97 commented Nov 5, 2019

I have a desktop App.exe built using Electron.Net, if I pass parameters along with "electronize start", these arguments get ignored. In command prompt, when I run App.exe with command line arguments it does not accept the parameters being passed to it.

Example: App.exe hello 123
electronize start hello 123

I tried to make little changes in code to try to achieve the same. I have attached my findings below in Changes file.
It would be great if this feature could be supported in the coming days. Thank you.

Changes.docx

@VH97 VH97 added the Feature label Nov 5, 2019
@GregorBiswanger GregorBiswanger self-assigned this Nov 7, 2019
@MrCircuit
Copy link

MrCircuit commented Nov 22, 2019

The implementation sketch given by @VH97 works except for one case:

For the "electronize start [args]" sequence one has to pay attention to the first parameter. If it denotes a valid path, this parameter will be used by the ExecuteAsync method of StartElectronCommand for the "aspCoreProjectPath". A safer solution would be to extend this part like this:

            string aspCoreProjectPath = "";
            if (_args.Length > 0)
            {
                if (Directory.Exists(_args[0]))
                {
                    aspCoreProjectPath = _args[0];
                    _args = _args.Skip(1).ToArray();
                }
            }
            else
            {
                aspCoreProjectPath = Directory.GetCurrentDirectory();
            }

Otherwise, the parameters of "electronize start" must be escaped e.g. using commands like "--path [coreProjectPath]" and "--args [argument list as string]".

MrCircuit added a commit to MrCircuit/Electron.NET that referenced this issue Nov 22, 2019
MrCircuit added a commit to MrCircuit/Electron.NET that referenced this issue Nov 22, 2019
Ensures backward compatibility
@MrCircuit
Copy link

I've implemented the latter because it seemed more reliable to me. I kept the case of exactly one parameter that is interpreted as the aspCoreProjectPath for the sake of backward compatibility.

Shall I create a PR?

@GregorBiswanger GregorBiswanger added this to the 7.30.2 milestone Nov 27, 2019
@GregorBiswanger
Copy link
Member

Implemented! Available in Electron.NET version 7.30.2.

You can start the app with:

electronize start /args --dog=woof --test=true

or

myapp.exe /args --dog=woof --test=true

With the Electron.NET API you can get the value:

if (await Electron.App.CommandLine.HasSwitchAsync("dog"))
{
   string value = await Electron.App.CommandLine.GetSwitchValueAsync("dog");
   await Electron.Dialog.ShowMessageBoxAsync(value);
}      

@VH97
Copy link
Author

VH97 commented Nov 30, 2019

Thank you!

Blind-Striker added a commit to Blind-Striker/Cake.Electron.Net that referenced this issue Jan 26, 2020
* manifest, aspCoreProjectPath parameter support added to Init, Start, Build commands
ElectronNET/Electron.NET#340

Commandline support ElectronNET/Electron.NET#337

* Microsoft.NET.Test.Sdk update
@MrCircuit
Copy link

Just one remark on the feature: The command line arguments are passed in lowercase to the Electron.NET API.

Took me quite some time to find out :-P

@locoruiz
Copy link

Hello, this works very well, however, I need to access a Filepath when a file is dropped on the app.exe to open it.
Or to open it with the protocol from the browser (like Zoom), is this possible?

@danatcofo
Copy link
Contributor

@locoruiz

for url support you need to register a scheme with the os and associate it with the app. This is different for each os in how you do this.

in the code to handle the scheme

In Mac

info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleURLTypes</key>
  <array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>None</string>
        <key>CFBundleUrlIconFile</key>
        <string>Contents/Resouces/MyApp.icns</string>
        <key>CFBundleUrlName</key>
        <string>com.myapp.app</string>
        <key>CFBundleUrlSchemes</key>
        <array>
            <string>myappscheme</string>
        </array>
    </dict>
  </array>
  <key>NSPrincipalClass</key>
  <string>AtomApplication</string>
</dict>
</plist>

electron.manifest.json

{
  "build": {
      "protocols": [
      {
        "name": "myapp",
        "role": "Viewer",
        "schemes": [ "myappscheme"]
      }
    ]
  },
  "mac": {
    "appBundleId": "com.myapp.app",
    "appCategoryType": "app-category-type=public.app-category.developer-tools",
    "extendedInfo": "info.plist"
  }
}

please note that you might have to do some pathing alterations to get the electron.manifest.json embedded paths to resolve correctly

csharp code

app.On("open-url", o => {
  // myappscheme://the/rest/of/the/url
  var url = o.ToString();
  // Do logic here to parse the url for intended results
});

In Windows/Linux

app.On("second-instance", o => {
  var args = ((JToken)o).ToObject(typeof(List<string>)) as List<string>;
  var url = args.FirstOrDefault(i => i.StartsWith("myappscheme://");
  if (string.IsNullOrWhitespace(url) == false) {
    // Do logic here to parse the url for intended results
  }
});

Likewise handling files is similar, you must first register the app as a handler for the file type and that is os dependent.

In Windows with NSIS

Nsis install script adddition

; Register the extension with your app, look up RegisterExtension in NSIS documentation
${RegisterExtension} "$INSTDIR\MyApplication.exe" ".ext" "NAME_FOR_EXTENSION"

Don't ask me how to integrate that off the shelf with electron-builder, I have a very customized nsis build script that using the unpacked outputs.
In Windows/Linux

csharp code

app.On("second-instance", o => {
   var args = ((JToken)o).ToObject(typeof(List<string>)) as List<string>;
   var path = args
      .SkipWhile(a => !a.Equals("--allow-file-access-from-files"))
      .Skip(1).FirstOrDefault();
   if (string.IsNullOrWhiteSpace(path) == false) {
      // do something with the path
   }
});

Notice this is the same event listener in windows/linux as the scheme (url) handler

In Mac

csharp

  app.On("open-file", async o =>
  {
      var path = o.ToString();
      // Do something with the path
  });

Note that the file handlers described here also work as the handlers for any Recent Documents that are attached to the program in the OS

Now I'm sure I've definitely missed something here in this long winded explanation as there are too many intricacies that I figured out, got set up and working and promptly forgot about but this should get you started.

@locoruiz
Copy link

@locoruiz

for url support you need to register a scheme with the os and associate it with the app. This is different for each os in how you do this.

in the code to handle the scheme

In Mac

info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleURLTypes</key>
  <array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>None</string>
        <key>CFBundleUrlIconFile</key>
        <string>Contents/Resouces/MyApp.icns</string>
        <key>CFBundleUrlName</key>
        <string>com.myapp.app</string>
        <key>CFBundleUrlSchemes</key>
        <array>
            <string>myappscheme</string>
        </array>
    </dict>
  </array>
  <key>NSPrincipalClass</key>
  <string>AtomApplication</string>
</dict>
</plist>

electron.manifest.json

{
  "build": {
      "protocols": [
      {
        "name": "myapp",
        "role": "Viewer",
        "schemes": [ "myappscheme"]
      }
    ]
  },
  "mac": {
    "appBundleId": "com.myapp.app",
    "appCategoryType": "app-category-type=public.app-category.developer-tools",
    "extendedInfo": "info.plist"
  }
}

please note that you might have to do some pathing alterations to get the electron.manifest.json embedded paths to resolve correctly

csharp code

app.On("open-url", o => {
  // myappscheme://the/rest/of/the/url
  var url = o.ToString();
  // Do logic here to parse the url for intended results
});

In Windows/Linux

app.On("second-instance", o => {
  var args = ((JToken)o).ToObject(typeof(List<string>)) as List<string>;
  var url = args.FirstOrDefault(i => i.StartsWith("myappscheme://");
  if (string.IsNullOrWhitespace(url) == false) {
    // Do logic here to parse the url for intended results
  }
});

Likewise handling files is similar, you must first register the app as a handler for the file type and that is os dependent.

In Windows with NSIS

Nsis install script adddition

; Register the extension with your app, look up RegisterExtension in NSIS documentation
${RegisterExtension} "$INSTDIR\MyApplication.exe" ".ext" "NAME_FOR_EXTENSION"

Don't ask me how to integrate that off the shelf with electron-builder, I have a very customized nsis build script that using the unpacked outputs.
In Windows/Linux

csharp code

app.On("second-instance", o => {
   var args = ((JToken)o).ToObject(typeof(List<string>)) as List<string>;
   var path = args
      .SkipWhile(a => !a.Equals("--allow-file-access-from-files"))
      .Skip(1).FirstOrDefault();
   if (string.IsNullOrWhiteSpace(path) == false) {
      // do something with the path
   }
});

Notice this is the same event listener in windows/linux as the scheme (url) handler

In Mac

csharp

  app.On("open-file", async o =>
  {
      var path = o.ToString();
      // Do something with the path
  });

Note that the file handlers described here also work as the handlers for any Recent Documents that are attached to the program in the OS

Now I'm sure I've definitely missed something here in this long winded explanation as there are too many intricacies that I figured out, got set up and working and promptly forgot about but this should get you started.

Thank you very much!

@Atmosferrum
Copy link

Atmosferrum commented Nov 1, 2022

Implemented! Available in Electron.NET version 7.30.2.

You can start the app with:

electronize start /args --dog=woof --test=true

or

myapp.exe /args --dog=woof --test=true

With the Electron.NET API you can get the value:

if (await Electron.App.CommandLine.HasSwitchAsync("dog"))
{
   string value = await Electron.App.CommandLine.GetSwitchValueAsync("dog");
   await Electron.Dialog.ShowMessageBoxAsync(value);
}      

The " myapp.exe /args --dog=woof --test=true" desn't work for me. I'm getting:
A positional parameter cannot be found that accepts argument '--dog=woof'.
It doesn't matter even if I use my own arguments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants