Get the path to the bundle in Mono C# CLI application - c#

I need to retrieve the full path (up to directory) of the application's executable file made using mkbundle --static. It is a CLI application that I test on OSX, suppose the executable resides at /usr/local/bin/.
The matters might be further complicated (but I don't really know) since I want to run the utility from any directory, so I add the above path to $PATH environment variable (in this case, it is already there).
Now, suppose the application is launched while being at ~/dir1/dir2/, and suppose it prints the Application.StartupPath. That yields the path ~/dir1/dir2/. In contrast, I want to always retrieve the real directory from which the application is launched, i.e. /usr/local/bin/.
Is there any way to achieve this (preferably in a platform-independent way)?
I use Xamarin Studio configured with Mono/.NET 4.5 and C# 6.0.
UPDATE: Getting typeof(Program).Assembly.Location also doesn't help much.
I mean, it works well when I just run the normal application executable (produced during the build process).
However, if I run a bundle made with mkbundle --static, the Location just gives the executable name App.exe without any prior path.
Probably it just displays the relative path inside the bundle. Is there any way I can get the path to the bundle itself?..

The only thing I've found reliable (probably not the fastest way though) is through Process:
Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)

With a type defined in an assembly that is part of your application you can find its location by doing:
string location = typeof(Foo).Assembly.Location;
This gives you the full path to the .dll or .exe, depending on where the type Foo is defined. Then you can use Path.GetDirectoryName if you only want the directory.
string directory = System.IO.Path.GetDirectoryName(location);
The above should work with Mono and also on Windows.

Related

How to get actual path to executable when using .netcore 3.0 and using the /p:PublishSingleFile=true flag?

I recently upgraded an application to dotnet core 3 and started using the PublishSingleFile flag during the build process. With these two changes the way the executable path is found has changed. Now instead of getting the path where the executable file is, I get redirected to a random directory in /var/tmp/.net/ where as I used to get /opt/appdir/.
Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
Edit: So it seems like the random dir it is spitting out actually points to an unpacked version of my application which does not contain vital resources that are in the other directory.
The following seems to give the path you're after, to the original executable:
System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName
You were getting the actual executable path. You just didn't understand what was going on.
Using the PublishSingleFile is not generating a single file that when executes does exactly what the software is programmed to do. What is actually happening is that a publish with this flag generates a file that contains a packaged version of all your files, which when executed unpacks them into the a subdirectory of /var/tmp/.net and then executes it. So if you are moving configs into the publish dir after the publish process, they will not automatically make it to the executable location when you deploy and try to run it.

FileNotFoundException is occur while running Wpf application on 32bit machine

I created setup file using Inno setup.I have exe,dll and one xml file in my setup.
When I install on 64 bit machine it works fine means it take xml file from directory where exe is present.
But When I install same setup on 32 bit machine it take dll path but while accessing xml file it takes path of desktop where shortcut of exe is present and showing FileNotFoundException.
Thanks
Your application is most likely not specifying pathnames on the files it is trying to open, so it is expecting to find them in the current directory. Inno Setup by default does not set the "Start In" field on shortcuts its creates; this causes Windows to pick a directory itself, which usually won't be the directory containing your application.
In virtually all cases, this is something that should be corrected at the application level. Properly designed GUI applications should not expect to be started from a particular directory; they should always specify full pathnames on files they open. In Delphi or C++Builder, for example, it's possible to get the full pathname of the directory containing the application EXE by calling: ExtractFilePath(ParamStr(0)). To get the full path of a file named "File.txt" in the application directory, use: ExtractFilePath(ParamStr(0)) + 'File.txt'.
To get path of working directory of application while loading xml file in code.
string WorkingDir=System.AppDomain.CurrentDomain.BaseDirectory
XDocument temp_xdocument= XDocument.Load(WorkingDir+"file.xml");
It works for me.

Application will not launch from command line full path, but will after CDing to directory

I am attempting to get a .Net C# application to run from a Registry Run key (at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run, where other string values live and launch things just fine). But for some inexplicable reason, the path to my app doesn't launch my app. So I decided to run the command manually from a command prompt, just to see if that was the problem. It was. So now I'm really perplexed:
This is a .Net 4.0 C# application which I've compiled in Release mode. The application lives at:
C:\Program Files (x86)\MyCompany\MyProduct\MyProduct.exe
I can double-click on the application and it runs properly. I can also open a CMD window and do the following:
cd "C:\Program Files (x86)\MyCompany\MyProduct\"
MyProduct.exe
And the application launches just fine. HOWEVER, if I try this:
"C:\Program Files (x86)\MyCompany\MyProduct\MyProduct.exe"
The application does not launch. (!) SO obviously the Registry key isn't going to work either.
Is there some kind of additional step which must be taken to run a .Net application from its full path?
Apparently your app depends on the "Current Directory". For opening some sort of file.
The best thing to do is to find that dependency and fix it with an absolute path.
When that's not possible the second-best option would be to change the Current folder to that of the running .EXE as soon as possible. That mean you should execute this line as soon as possible:
Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
But that will only work if you manage to execute that before the faulty code. Could be hard when it's for instance in a static constructor.
Sounds like you've got a relative file reference to something in the working directory. Is there a file that you're trying to load in your app? Make sure you're using the right file paths.

Updater.exe built into app.exe

Currently I have 2 exe files. app.exe and updater.exe. When app.exe finds out that there is new version available it runs updater.exe, which downloads and replaces it.
I'm wondering if it's possible to build updater.exe into app.exe. On app start it should check if there is updater.exe in the directory and if it's not than extract it. Any help appreciated.
You can integrate updater.exe as a resource into app.exe. The following SO post shows how to extract it at run-time:
Embedding an external executable inside a C# program
Note that, if your application is located in the default application directory (C:\Program Files, or, more generally, %ProgramFiles%), you will not have permissions to create a file in the same directory (which is a good thing). Thus, you might need to extract updater.exe into a temporary directory that the current user has write permissions to (such as Path.GetTempPath).
When I'm understanding you correctly you need to pack you updater.exe into you app.exe as ressource. Extract it, when App.exe starts.
But I can tell you, this idea with replace is bad. You should choose a MSI package to deploy your application.
For traversing and listing directory contents, see http://msdn.microsoft.com/en-us/library/system.io.directory.aspx
For accessing your embedded resources, see http://msdn.microsoft.com/en-us/library/xc4235zt.aspx
For writing binary data to disk, see http://msdn.microsoft.com/en-us/library/system.io.binarywriter.aspx
For running an exe from disk, see http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx

How does default/relative path resolution work in .NET?

So... I used to think that when you accessed a file but specified the name without a path (CAISLog.csv in my case) that .NET would expect the file to reside at the same path as the running .exe.
This works when I'm stepping through a solution (C# .NET2.* VS2K5) but when I run the app in normal mode (Started by a Websphere MQ Trigger monitor & running in the background as a network service) instead of accessing the file at the path where the .exe is it's being looked for at C:\WINDOWS\system32. If it matters The parent task's .exe is in almost the same folder structure/path as my app
I get a matching error: "System.UnauthorizedAccessException: Access to the path 'C:\WINDOWS\system32\CAISLog.csv' is denied."
My workaround is to just fully qualify the location of my file. What I want to understand, however is "What is the .NET rule that governs how a path is resolved when only the file name is specified during IO?" I feel I'm missing some basic concept and it's bugging me bad.
edit - I'm not sure it's a.NET rule per se but Schmuli seems to be explaining the concept a little clearer. I will definitely try Rob Prouse's suggestions in the future so +1 on that too.
If anyone has some re-wording suggestions that emphasize I don't really care about finding the path to my .exe - rather just didn't understand what was going on with relative path resolution (and I may still have my terminlogy screwed up)...
When an application (WinForms) starts up, the Environment.CurrentDirectory contains the path to the application folder (i.e. the folder that contains the .exe assembly). Using any of the File Dialogs, ex. OpenFileDialog, SaveFileDialog, etc. will cause the current directory to change (if a different folder was selected).
When running a Windows Service, its containing folder is C:\Windows\System32, as that is the System folder and it is the System (i.e. the Operation System) that is actually running your Windows Service.
Note that specifying a relative path in most of the System.IO objects, will fall back to using the Environment.CurrentDirectory property.
As mentioned, there are several ways to obtain the path of the service executable, using Assembly.GetEntryAssembly() or Assembly.GetExecutingAssembly() and then using either the Location property or the CodeBase property (be aware that this is the file path, not directory, of the executable).
Another option is to use:
`System.IO.Directory.SetCurrentDirectory( System.AppDomain.CurrentDomain.BaseDirectory );`
Make the call in the Service's OnStart method, applying it to the whole application.
It is based on the current working directory which may or may not be the same as where your application resides, especially if started from a different program or a shortcut with a different working directory.
Rather than hard code the path, get the path to your program and use it. You can do this with something like this
Assembly ass = Assembly.GetEntryAssembly();
string dir = Path.GetDirectoryName(ass.Location);
string filename = Path.Combine( dir, "CAISLog.csv" );
This assumes that the entry assembly is where your file is. If not, you can change up getting the assembly for something like;
Assembly ass = Assembly.GetAssembly( typeof( AClassInYourAssembly ) );
Relative Path resolution never works against the path of the launching executable. It always works against the process' Current Directory, and you can't really expect that to always be set to the directory the .exe lives in.
If you need that behavior, then take care to find out the right path on your own and provide a fully qualified path to the file operations.
You can use this to specify a path that resides at the same path of your exe #"..\CAISLog.csv". Please note that the double dots refer to the parent directory of where ever your .exe lies.
RWendi

Categories