1

I have a case where I want to call a C# Console program built with .Net Framework 4.5 from R. In R I use system2 to launch the program. In this simple demonstration case, the console program (C:\Temp\SettingsApp.exe) just reads some settings from an according .exe.config and prints these to stdout.

My problem is that the config file is not actually read, because somehow the path gets mangled. Here is the program, the config, and the output

using System;
using System.Configuration;

namespace SettingsApp {
  class Program {
    static void Main(string[] args) {
      var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
      Console.WriteLine(config.FilePath);
      Console.WriteLine("Application: " + Properties.Settings.Default.MyAppSetting);
      Console.WriteLine("User: " + Properties.Settings.Default.MyUserSetting);
    }
  }
}

This app defines two settings, an application setting and a user setting and outputs them. In addition it outputs the path of the config file. The config file (C:\Temp\SettingsApp.exe.config) looks as follows.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="SettingsApp.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
        </sectionGroup>
        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="SettingsApp.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <userSettings>
        <SettingsApp.Properties.Settings>
            <setting name="MyUserSetting" serializeAs="String">
                <value>It's a user setting</value>
            </setting>
        </SettingsApp.Properties.Settings>
    </userSettings>
    <applicationSettings>
        <SettingsApp.Properties.Settings>
            <setting name="MyAppSetting" serializeAs="String">
                <value>It's an app setting</value>
            </setting>
        </SettingsApp.Properties.Settings>
    </applicationSettings>
</configuration>

The config file used for building the SettingsApp (App.config in the project) differs in that it uses other values ("This is a user setting" for MyUserSetting and "This is an application setting" for MyAppSetting). In R I then call

system2("C:\\Temp\\SettingsApp.exe")

The expected output would be

C:\Temp\SettingsApp.exe.config
Application: It's an app setting
User: It's a user setting

But the actual output I get on the R console is

C:\Temp\SETTIN~1.EXE.config
Application: This is an application setting
User: This is a user setting

These are the default values for the settings as defined in the project's App.config. Notice that in the first line the path is a strange combination of an 8.3 character DOS filename with the added ".config" at the end. Clearly, this file doesn't exist. My assumption is thus that the configuration file is not actually read:

>type C:\Temp\SETTIN~1.EXE.config
The system cannot find the file specified.

I have thus the following questions:

  1. Why is the config name mangled in such a way?
  2. How can I read the actual config file?

EDIT:

I've tested a workaround as indicated here where I rewrite the config name. This seems to work, but isn't really a solution.

I also noted that e.g. Environment.GetCommandLineArgs()[0] also shows an 8.3 filename for the exe. I see that the rest of the path is not in 8.3, but uses the full name for all folders.

I also tested with system (same error) and shell (which works):

> shell(shQuote("C:\\Temp\\SettingsApp.exe"))
C:\Temp\SettingsApp.exe.Config
Application: It's an app setting
User: It's a user setting

I also tested with putting the executable under a path that is longer and contains spaces. One can see that only the filename is converted to 8.3, but not the full path

> exe <- "C:\\Temp\\Longer More Complex Path\\SettingsApp.exe"
> system(shQuote(exe))
C:\Temp\Longer More Complex Path\SETTIN~1.EXE.config
Application: This is an application setting
User: This is a user setting
> system2(exe)
C:\Temp\Longer More Complex Path\SETTIN~1.EXE.config
Application: This is an application setting
User: This is a user setting
> shell(shQuote(exe))
C:\Temp\Longer More Complex Path\SettingsApp.exe.Config
Application: It's an app setting
User: It's a user setting
Andreas
  • 6,447
  • 2
  • 34
  • 46

1 Answers1

0

Try

system2(shQuote("C:\\Temp\\SettingsApp.exe"))

instead. That may stop R from mangling your filename.


This appears to be a bug/limitation in both system and system2. As a workaround, you can use shell which will indirectly run your program via cmd.exe.

shell(shQuote("C:\\Temp\\SettingsApp.exe"))
Hong Ooi
  • 56,353
  • 13
  • 134
  • 187
  • Not true, unfortunately. According to the doc of system2: "Unlike system, command is always quoted by shQuote, so it must be a single command without arguments." Thus, you'd quote it twice and this doesn't even lead to a call to the program. – Andreas Apr 29 '18 at 20:50
  • I've emailed r-devel about this. – Hong Ooi Apr 30 '18 at 10:04