0

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("-", "");
        }

    }
}
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
liquidair
  • 177
  • 2
  • 11
  • Does this answer your question? [How do I get the path of the assembly the code is in?](https://stackoverflow.com/questions/52797/how-do-i-get-the-path-of-the-assembly-the-code-is-in) – jjxtra Apr 12 '21 at 22:35
  • you've made an assumption, asked a question about it, and it might not even be your problem, but we have no idea what your code does, what version of .net you are targeting, what platform, etc etc. It's likely the solution is really simple. Also, from the sounds of it, your program would be better off taking command line parameters rather than hardcoded filenames – Keith Nicholas Apr 12 '21 at 22:40
  • @liquidair: [illegitimi non carborundum](https://en.wikipedia.org/wiki/Illegitimi_non_carborundum). FYI, in the future, please specify 1) language (C#, which you did), 2) Target platform (.Net/ASP.Net MVC, ASP.Net Core, .Net 5, etc) and, most importantly, 3) specify exactly "what's going wrong". Copy/paste the exact error text (if any), – FoggyDay Apr 12 '21 at 22:54
  • @FoggyDay: For 3, that's part of the problem is I don't know how to debug what is happening in the new location. I run it with a post-build event in Atmel Studio and all I can see is `call VersionAppend.exe exited with code -2147450726`. I was getting a similar exit code when the path's were wrong while writing the app. Is there a way to debug in VS2019 as if the app was running firmware project folder, that would help. – liquidair Apr 12 '21 at 23:01
  • @KeithNicholas: Well I don't hardcode the file names either, just search for a .bin file with 'firmware' as a part of it's name. That way it shouldn't matter what I call things in future projects. – liquidair Apr 12 '21 at 23:04
  • when it is in the folder you want, is the subdirectory "firmware" the path you want? – Keith Nicholas Apr 13 '21 at 00:08
  • oh, in the same directory with ```*firmware.bin``` – Keith Nicholas Apr 13 '21 at 00:10

1 Answers1

4

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”

paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • Just tried all of these so it appears this isn't actually the problem. Do I have to switch the build to "release" or is there anything like that that needs to be done? Great answer btw! – liquidair Apr 12 '21 at 23:17
  • Q: I don't know how to debug what is happening in the new location. A: 1) Does your target environment have some kind of "dir" command or "File explorer"? Use it - tell us the results. 2) How do you view "printf" stmts (e.g. `Trace.WriteLine()`) from your target environment. Add lots of stmts - tell us the results. 3) Be aware that files in your MSVS project *WON'T* be copied to the target unless you explicitly set "Properties > Copy > Copy if Newer" (or equivalent) for that file. – paulsm4 Apr 12 '21 at 23:29
  • No, you don't need to set the build to "release". We *DO* need to know more about "what's going wrong". Specifically: 1) Is the file ever getting to your target environment? 2) What *IS* the target environment, and what tools are you using to a) trace your program (eg. "printf" stmts), and b) list files in the environment? – paulsm4 Apr 12 '21 at 23:34
  • 1. I'm not sure I understand. I'm on Windows 10 so I have a File Explorer, what do you mean by tell us the results? I can verify that VersionAppend, in it's VS project folder, is both getting the path to it's folder and finding the "version" file, and is looking in it's `path\Debug` folder for the firmware file. I can tell this by `Trace.WriteLine(path)` and by setting a breakpoint and stepping through, looking at the variable's contents (paths are double slashed though ...\\path\\Debug\\...). – liquidair Apr 13 '21 at 00:55
  • From here, what I'm doing is navigating to `VersionAppend\bin\Debug\netcoreapp3.1` and copying the VersionAppend.exe to the firmware's folder manually, so I know that is in the right spot too. All I know to do at this point is to set the "Build Event" to "call VersionAppend.exe" to run it and that fails but AFAIK, there's no way to see why it fails in that location and not the project's original location. – liquidair Apr 13 '21 at 01:02
  • I wasn't sure if you were in some weird embedded environment. Never mind - you're good :) 2) Q: So how exactly did you decide to query the path? 3) Q: What exactly is the value of `versionFileName` in your debugger? 4) Q: Does the filepath `versionFileName` actually exist? Double-check? 5) Q: Can you step past `File.ReadAllText(versionFileName);` in your debugger? Q: What is the value of `versionString`? 6) Finally, what is the value of `ver` after you step through `Version.Parse()`? – paulsm4 Apr 13 '21 at 03:10
  • 2. I went with `AppContext.BaseDirectory`. 3. `versionFileName` is a long path that ends in VersionAppend project's `Debug\netcoreapp3.1\` folder. version file is extensionless, created by a bash script. 4, 5. Yup, and I can step through the entire app and it works correctly. `versionString` is "0.0.8\n". 6 `ver` is "0.0.8" after Version.parse. – liquidair Apr 13 '21 at 04:18
  • I think what is actually going on is that I don't actually know how to build a working standalone .exe like I'm trying to do. Perhaps it's the wrong version of .net, or it doesn't have the required files and dependencies when copied to the new location. I forgot how, but I was able to get an error running the .exe in the firmware project folder that said either the `VersionAppend.exe` or `.dll` or something didn't exist. I also tried debugging the VersionAppend.exe itself in VS2019 and again it wasn't happy, saying it was missing a `.dll` and symbol files. – liquidair Apr 13 '21 at 04:30
  • Sigh... I thought your *app* was "VersionAppend.exe". I thought it read a binary array from a file called "version". And that the whole problem was you weren't able to find "version" in the directory you expected. Feel free to open a new question. Be sure to 1) Describe the goal/expected behavior of your app, 2) provide a complete C# example, 3) give the EXACT problem your encountering; 4) copy/paste the EXACT error message(s) if any. – paulsm4 Apr 13 '21 at 05:07
  • Well, no that's all right. This will be my first app outside of VS ever, and that seemed to be the most logical problem to a noob as it's the obvious change. Thank you for your help and because your answer is better than all of the answers about this problem, I've marked it so it could help others! – liquidair Apr 13 '21 at 15:14