Search code examples
c#.net-coreatmelstudio

Getting the path of the executable file's current location


I have a very simple app that will automatically get the version number of a firmware file from Git Tags and will both write the firmware version to the end of the binary file and append the version to the name each time I build the firmware file. For every project I work on, I want to copy this executable in the firmware's project folder, so the app only has to look in the same directory it's in for the files it needs, regardless of the actual location it is in (thus I don't have to reprogram it each time).

This works perfectly in the VS project folder (I copied in the files needed), but when I move the .exe file into the firmware project folder it no longer works. I assume the issue is the code to get the path of the .exe's location is still it's own project folder and not the new location. What's the correct way to get this to work?

I've tried:

Environment.CurrentDirectory;
Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
System.Reflection.Assembly.GetExecutingAssembly().Location;

and a few others. I don't see why this has to be such a hard thing to do.

Edit: .Net Core3.1

Edit: Full code:

using System;
using System.IO;
using System.Diagnostics;

namespace VersionAppend
{ 
    class Program
    {
        const int INSERT_OFFSET = 0x1EFF9;
        const byte VER_NUMS = 3;
        const byte VER_SIZE = VER_NUMS * sizeof(ushort);

        static void Main(string[] args)
        {
            byte[] version = new byte[VER_SIZE];
            string versionFileName = AppContext.BaseDirectory + @"\version";

            if (!File.Exists(versionFileName))
            {
                Trace.WriteLine("Error");
                return;
            }

            // Get Firmware version as string
            string versionString = File.ReadAllText(versionFileName);

            // Break version into parts
            Version ver = Version.Parse(versionString);

            convertVersionToBytes(ver, version);

            // Search for Firmware File
            string directory = AppContext.BaseDirectory + @"\Debug";
            string firmwareKeyword = "firmware";

            var files = Directory.EnumerateFiles(directory, "*" + firmwareKeyword + ".bin");

            foreach (string item in files)
            {
                // Open firmware file
                BinaryWriter firmware = new BinaryWriter(new FileStream(item, FileMode.Open));

                firmware.Seek(INSERT_OFFSET, SeekOrigin.Begin);
                // Write version to end
                firmware.Write(version, 0, (int)VER_SIZE);

                // Close firmware file
                firmware.Close();

                string extension = Path.GetExtension(item);

                string file = Path.GetFileNameWithoutExtension(item);

                // Rename file with version
                string verString = convertVersionToString(version);
                File.Move(item, @item.Substring(0, item.Length -extension.Length) + "_" + verString + ".bin");
            }
               
        }

        private static void convertVersionToBytes (Version ver, byte [] version)
        {
            // Major.MSB, Major LSB, Minor...
            version[0] = (byte)((ushort)(ver.Major >> 8) & 0xFF);
            version[1] = (byte)((ushort)ver.Major & 0xFF);
            version[2] = (byte)((ushort)(ver.Minor >> 8) & 0xFF);
            version[3] = (byte)((ushort)ver.Minor & 0xFF);
            version[4] = (byte)((ushort)(ver.Build >> 8) & 0xFF);
            version[5] = (byte)((ushort)ver.Build & 0xFF);
        }

        private static string convertVersionToString(byte [] version)
        {
            return BitConverter.ToString(version).Replace("-", "");
        }

    }
}

Solution

  • It isn't hard.

    But it MIGHT depend on your target platform (which you haven't specified).

    For .Net Core 1.x and .Net 5 or higher, I would use AppContext.BaseDirectory

    Here are some other alternatives for various environments over the years:

    6 ways to get the current directory in C#, August 17, 2010

    • AppDomain.CurrentDomain.BaseDirectory This is the best option all round. It will give you the base directory for class libraries, including those in ASP.NET applications.

    • Directory.GetCurrentDirectory() Note: in .NET Core this is the current best practice. The details below relate to the .NET Framework 4.5 and below.

      This does an interop call using the winapi GetCurrentDirectory call inside kernel32.dll, which means the launching process’ folder will often be returned. Also as the MSDN documents say, it’s not guaranteed to work on mobile devices.

    • Environment.CurrentDirectory
      This simply calls Directory.GetCurrentDirectory()

    • Assembly.Location
      This would be called using

      this.GetType().Assembly.Location

      This returns the full path to the calling assembly, including the assembly name itself. If you are calling a separate class library, then its base directory will be returned, such “C:\myassembly.dll” - depending obviously on which Assembly instance is being used.

    • Application.StartupPath
      This is inside the System.Windows.Forms namespace, so is typically used in window forms application only.

    • Application.ExecutablePath The same as Application.StartupPath, however this also includes the application name, such as “myapp.exe”