简体   繁体   中英

Open C# Winforms app through associated file clicking

I am developing a small app that accepts two different types of files (*.miz and *.5js). There are two functions that do parse those files, and they already work properly when triggered from button click events (see below). Also, the solution contains this project and a setup project, to create the installer of the app.

public void button1_Click(object sender, EventArgs e)
    {
        button1.BackColor = Color.Red;

        openFileDialog1.InitialDirectory = "";
        openFileDialog1.Title = "Load mission file";
        openFileDialog1.ShowDialog();
        textBox4.Text = openFileDialog1.FileName;

        processMizFile(openFileDialog1.FileName);

        button1.BackColor = SystemColors.Control;
    }

and

        private void button6_Click(object sender, EventArgs e)
    {
        button6.BackColor = Color.Red;

        openFileDialog2.InitialDirectory = "";
        openFileDialog2.Title = "Load standalone Datacards";
        openFileDialog2.ShowDialog();

        loadDatacard(openFileDialog2.FileName);

        button6.BackColor = SystemColors.Control;
    }

I am now trying to call those functions when I start the app by double clicking in one of those file types (associated to my app through Windows properties dialog). For that, I am running the following code:

public Form1()
    {
        LoadFont();
        InitializeComponent();


        string version = Assembly.GetExecutingAssembly().GetName().Version.ToString();//to display program version in the form
        label29.Text += version;

        string[] cmdl = Environment.GetCommandLineArgs();

        using (StreamWriter sw = File.CreateText(Application.UserAppDataPath + @"\log.txt"))
        {
            if (cmdl.Length > 1)
            {
                sw.WriteLine("Argument 0 - Exe path: " + cmdl[0]);
                sw.WriteLine("Argument 1: " + cmdl[1]);
                sw.WriteLine("File type: " + Path.GetExtension(cmdl[1]).ToUpper());
            }
            else
            {
                sw.WriteLine("Argument 0 - Exe path: " + cmdl[0]);
                sw.WriteLine("No further arguments provided");
            }
        }

        if (cmdl.Length > 1)
        {
            if (Path.GetExtension(cmdl[1]).ToUpper() == ".MIZ")
            {
                processMizFile(cmdl[1]);
                using (StreamWriter sw2 = File.CreateText(Application.UserAppDataPath + @"\log2.txt"))
                {
                    sw2.WriteLine("MIZ file loaded!");
                }
            }
            else if (Path.GetExtension(cmdl[1]).ToUpper() == ".5JS")
            {
                loadDatacard(cmdl[1]);
                using (StreamWriter sw2 = File.CreateText(Application.UserAppDataPath + @"\log2.txt"))
                {
                    sw2.WriteLine("5Js file loaded!");
                }
            }
        }
    }

The streamwriter parts are in place to have some traces, as I am not sure how can I debug this, otherwise.

Now, the problem is that it all works properly on the same laptop where I have Visual Studio installed. But, it does not work on a different computer:

  1. Release Build

    • If I just double click one of the associated files(on the Desktop), the splash screen flashes quickly, and goes away. No log file is written

    • If I double click an associated file in the same path as the installed executable, it works fine

    • If I launch the app from command line, passing a path as argument, I get:

    log.txt: Argument 0 - Exe path: DatacardGenerator.exe Argument 1: C:\Users\Username\OneDrive\Desktop\Datacards.5js File type: .5JS

log3.txt: writes up to "Created path to extract dir: " and the right Appdata folder to temporary extract


using (StreamWriter sw3 = File.AppendText(Application.UserAppDataPath + @"\log3.txt"))
        {
            sw3.WriteLine("Created path to extract dir: " + extract5Js);
        }

        if (Directory.Exists(extract5Js))
        {
            System.IO.Directory.Delete(extract5Js, true);
        }
        using (StreamWriter sw3 = File.AppendText(Application.UserAppDataPath + @"\log3.txt"))
        {
            sw3.WriteLine("Proceeding to unzip...");
        }
        
        ZipFile.ExtractToDirectory(path5jscard, extract5Js);

So, how could I know what happens during the startup of my app when launched by an external file? I`ve set command line arguments in debug mode to test, but I am not sure if they come with full path or not, given the different results on the target machine (works if files in same directory as exe, does not work otherwise)

Thanks for the support:! :)

PS: I do not process the command line arguments directly in Main() because I am using 2 different forms: Form2 is a splash screen, and Form1 is the main program. For that I am using an example I found time ago, in this way:

namespace WindowsFormsApp2{    
static class Program{
    static private List<PrivateFontCollection> _fontCollections;
    

    [STAThread]
    static void Main(string[] args)
    {

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(true);

        CultureInfo culture;
        culture = CultureInfo.CreateSpecificCulture("en-US");
        Thread.CurrentThread.CurrentCulture = culture;
        Thread.CurrentThread.CurrentUICulture = culture;


        //Dispose all used PrivateFontCollections when exiting
        Application.ApplicationExit += delegate {
            if (_fontCollections != null)
            {
                foreach (var fc in _fontCollections) if (fc != null) fc.Dispose();
                _fontCollections = null;
            }
            string appPath = Application.UserAppDataPath;
            string parentPath = System.IO.Directory.GetParent(appPath).ToString();
            
            System.IO.Directory.Delete(parentPath, true);
        };

        //Application.Run(new Form1());
        new MyApp().Run(args);
    }

}
public class MyApp : WindowsFormsApplicationBase
{
    
    protected override void OnCreateSplashScreen()
    {
        this.SplashScreen = new Form2();
    }
    protected override void OnCreateMainForm()
    {
        // Do your initialization here
        //...
        // Then create the main form, the splash screen will automatically close
        this.MainForm = new Form1();
    }
}

}

Solved!

I just had to declare a global var in Main to be accessed from my form, like:

public static string[] cmdlArgs;
    

    [STAThread]
    static void Main(string[] args)
    {

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(true);

        CultureInfo culture;
        culture = CultureInfo.CreateSpecificCulture("en-US");
        Thread.CurrentThread.CurrentCulture = culture;
        Thread.CurrentThread.CurrentUICulture = culture;

        cmdlArgs = Environment.GetCommandLineArgs();

And then it can be accessed using the namespace:

Program.cmdlArgs

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM