Prevent Application from running inside the wrong folder - c#

I have a (rather huge) application which is depending on some resources residing in the same folder as the application (e.g. settings files, unmanaged libraries etc.).
I also have registered a URI-protocol for this application, so that every URI-call starting with xyz://... will launch my application with the respective parameters.
The problem is, that if you use the URI-call, the application will run from the %windir%/system32-folder, or the ../ProgramFiles/Chrome/...-folder (when the URI is called from my webbrowser). It will not run my application from the folder, which it resides in.
(you can probably see my problem already...)
If my app runs from the sys32-folder it will (naturally) not have access to the local libraries, which some of my P/Invoke functions need.
My question is: how can I run my application from the correct folder or prevent it being run from a folder like sys32?
And no - I do not like following idea:
if (Directory.GetCurrentDirectory().ToLower() != "/my/home/dir") {
MessageBox.Show("You have no power over here!");
Exit(1);
}

OK - this comment written by #MutantNinjaCodeMonkey helped me out in the end:
Directory.SetCurrentDirectory(#"c:\path\to\app");
"resets" the working directory to the desired path. In my specific case I used:
FileInfo nfo = new FileInfo(Assembly.GetExecutingAssembly().Location);
Directory.SetCurrentDirectory(nfo.Directory.FullName);

Related

Does File.Exists not work inside a UWP project?

File.Exists(filePath); works perfectly inside a console application, but when I do the same thing inside uwp it doesn't detect a file.
I have tried to put breakpoints on various methods and stepped into anything that could give me some information about the issue, but I'm getting no information at all no matter what i try.
Code from UWP app:
string path = #"C:\Users\Name\Desktop\image.jpg";
if (File.Exists(path))
{
ProcessFile(path);
}
else if (Directory.Exists(path))
{
ProcessDirectory(path);
}
UWP:
When it hits File.Exists i get a return value of false, and yes i know for a fact the image is where it is.
Console:
When it hits File.Exists i get a return value of true, then goes onto the called method without any issues.
I'm expecting my code to find a File and pass the filePath into my method called "processFile".
Does UWP applications not have access to files outside of its LocalStorage or is it another issue that I'm not seeing?
UWP does not have direct access to files outside of the application folder and application data folder. That are the only two locations accessible via the System.IO APIs.
You can use StorageFile APIs to access more locations if you enable appropriate capabilities - like access to libraries or broadFileSystemAccess or use file/folder pickers. In particular, broadFileSystemAccess allows you to access the whole file system, but your app should have a good reason to do so (otherwise it will not pass the Microsoft Store certification process).
For more info see the Docs.
This is correct. UWP apps are sandboxed and cannot access files outside of LocalStorage in this way.
If you want to open a file on the users file system you have to use FileOpenPicker.PickSingleFileAsync or similar to prompt the user to pick a file, which you'll then be able to work with.
Further reading: Working with Files in UWP applications

C# - Relative path of class

Trying to get relative path of config file, which is next to a class in core project, and also trying to avoid hardcoded relative paths (i.e. "../../../seleniumconfig.json")
This is my project structure,
Awesome.Core (library project)
Selenium (folder)
ZSelenium.cs
seleniumconfig.json (want it here so only powerusers can reach to this file)
Awesome.OtherProject1 (calling project, references Awesome.Core)
Program.cs
Awesome.OtherProject2 (another calling project, references Awesome.Core)
Program.cs
Program.cs (in Awesome.OtherProject1)
using (var scope = Container.BeginLifetimeScope())
{
var selenium = scope.Resolve<ZSelenium>();
...
}
ZSelenium.cs
var rootDir = new DirectoryInfo(Environment.CurrentDirectory);
// "/users/myuser/Documents/MyProject/AwesomeProject.OtherProject"
I can construct my relative path from rootDir variable, but there will be a lot of hardcoded ../../.. stuff which I would like to avoid. Also, if I call ZSelenium.cs from another project, the relative path might change.
Does anyone know a better way to get the path of ZSelenium.cs within the core project?
Configurations files do not belong into the Programm folder, ever. We did kind of do it anyway in the Windows 98 times, but it was frowned upon back then. Since XP is it not reliably possible anymore to write such a configuration file. The Programm folders is protected. Most users can only read them, not write them for security reasons. And that includes any programms started by that user too.
If you want to store user or system specific settings, that is what the special folders are there for. Their one defining purpose is that whatever user runs your programm, should have read (and likely write) access to his own and all shared folders.
You may be able to add a "default configuration" to the Programm directory to use as pattern for new users. But even for that there is a existing structure (the default user folder) so you can leave placing the template to the Setup.

How do I write to a non-standard config file?

I have a file called middle.config that is deployed in the same directory as an exe, but I need to update values in this file. That means that I have to go to C:\Program Files (x86)\ directory to access the file. Although it is named as a .config file it does not follow the usual schema of a .config file. It looks like this:
<configuationSettings>
<middleSettings
groupName="XYZ"
forkName="SomeDbName"
dbServerName="123.123.123.123"
cnnTimeoutSeconds="30"
cmdDefaultTimeoutSeconds="30"
cmdMediumTimeoutSeconds="60"
cmdLongTimeoutSeconds="480"
/>
<userKeys>
<Assemblies value="C:\assemblies\" />
</userKeys>
<friendlyDbName value="NiceData"/>
</configuationSettings>
I'm able to read and manipulate the content with Xml, but when I try to save the file back, a "No Permissions" error is thrown. I cannot relocate the file. I'm stuck with this legacy schema so I'm not able to treat it like a normal .config file using ConfigurationManager.OpenExeConfiguration. I cannot define sections or groups on this schema (I've not been able to anyway). All my users are Administrators on their local machines.
How do I overwrite or delete and replace this file while it is in a protected directory(my assumption about the permissions error)? Failing that, is there a way to access this schema somehow with ConfigurationManager.OpenExeConfiguration.
{edit starts here}
There are three applications in this scenario, A, B, and mine C. Application A does not know about any other applications. It can connect to many, many databases, and it drops a single file 'middle.config' that contains pointer info to the last database location that was used by the last Application A session. Application B, let's call it an import/export application, only operates on the last Application A database location. Application B reads the 'middle.config' file for database pointer info and then executes console commands against that database. It performs bulk dumps or bulk imports for selected portions of the database.
This was the situation when I come along to build application C that uses the import/export application B to fetch, blocks of data and return them to the database. So, in order for application C to use Application B
against any database, application C must modify the 'middle.config' file so that application B will find the correct database. Application C is new and the other two are legacy. I either find a way to make this work, or I force the user to start Application A and point to the database of interest, then close Application A. This is VERY unhandy.
{edit ends here}
It is not advisable to write data files to the program files directory, as this requires elevated permissions. Giving a program elevated permissions just to update a config file clashes with the Principal of Least Privilege, which states that
a particular abstraction layer of a computing environment, every
module (such as a process, a user or a program depending on the
subject) must be able to access only the information and resources
that are necessary for its legitimate purpose
It's not a "legitimate purpose" to give the process elevated permissions (that can allow it to do many harmful things) just to update a config file. MS recommended practice is to write that type of data elsewhere.
Instead, consider storing the config file in a subfolder of the ApplicationData folder.
Suggested that your app is creating its own location under the AppData location folder for the current user instead of writing to files under location where the the app is installed (especially if under Program Files which is very strict.) Not suggested to force the user to run as Administrator for your application either.
Your assumption about protected directories is correct. Program Files has an Access Control List which prevents modification by processes running as standard users and, on Vista upwards, even by administrator processes which are not running elevated. Accessing the file using the standard configuration classes would not get around this.
If you absolutely can't move the file (Eric J. is right when says that writing to Program Files after installation is a bad idea), then you could embed a manifest in your config file-editing program which will try to force elevation with a UAC prompt at launch. Of course, the best solution would involve a) using standard config schema and b) keeping user data in user-writeable locations, but sometimes that isn't possible for legacy reasons.
I'm not aware of any way to persuade ConfigurationManager to read a non-standard schema, unfortunately.
Move the logic to a separate process and launch it with admin privileges from your current application.
From a different angle, look at this: Writing custom sections into app.config
I found the linked article to be very useful. Not sure it is going to answer all your questions though.

Write to a File in Monotouch

How would I create and write to a file in a Monotouch iPhone app?
The file should persist between application launches, so I guess it has to be placed somewhere in the App bundle ( documents or resources?).
[Note: My response is pretty thorough because I don't know your level of understanding regarding app bundles or the structure of your iPhone app's sandboxed little world - apologies if I cover things you already know - I prefer to write a little too much than too little, and to add a bit of the why when discussing the how...]
You have a few options (of course). I'm assuming you're already familiar with .Net to some extent and that your question is more about how to do this the iPhone Way.
Every iPhone app (and you'll see the same thing for apps on OS X) is a "bundle" which isn't an executable in the traditional sense, but actually a folder hierarchy inside of which your app binary lives (along with resources, settings, etc.).
Because of how uber-sandboxed iPhone apps are, you don't have access to the shared folders you'd usually be able to use when doing desktop development (having, for example, a common Documents folder that lives under a user's home folder to which applications have access).
Instead, your app has its own folder hierarchy that's like its own personal set of the folders that would typically be shared across apps.
The easiest way to see what your app's folder structure looks like on the phone is to look at the folder the iPhone simulator uses for app installs, settings, blah blah blah. On my machine (I don't recall if this is configurable, but it's probably the same on your system), you can get to the folder by this path:
~/Library/Application Support/iPhone Simulator
Inside of that, there's a User/Applications folder that contains the apps you've installed to the simulator. Drill down into any one of those folders, and you can see the folder structure your app will have access to on the phone.
For storing files that you'd like persisted across app sessions, your app's Documents folder is the spot. It's not your only choice for creating files, but it's the right choice for this job. In addition to your files being properly stored, keeping them in the Documents folder will also get them backed up by iTunes when the user syncs.
With MonoTouch, you can get your app's Documents folder path with Environment.GetFolderPath(Environment.SpecialFolder.Personal);
If you'd like to test it out, this is some extremely simple code that'll write a file called "out.txt" to your app's Documents folder. This code also reads the contents of the file to show it was created - for further verification, go to the simulator's Applications folder, sort the app folders by the date they were modified, drill down into the most recently modified, and look inside its Documents folder - you'll find "out.txt" (you can't find your app's folder by name because, when your app is installed, it gets stuffed inside a folder with a name like "2B3CA854-FADB-4DDC-9732-0E61B3DD8D8C" - sorting the folders by the date they were modified will point you to the most recently modified app, which, in this case, is whatever app contains the following code):
// For this to function, don't forget "using System.IO;"
// If you're just playing around with this to see it work, place it inside
// your AppDelegate's "FinishedLaunching" method in main.cs
string path = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
string filePath = Path.Combine(path, "out.txt");
// File.WriteAllText will create a file and then write text to it. If the
// file already exists, File.WriteAllText will overwrite it.
File.WriteAllText(filePath, "Howdy, world.");
// Now we prove it worked by reading the contents of the file and then
// printing them to the console...
string text = File.ReadAllText(filePath);
Console.WriteLine(text);
So, the only thing here that's really iPhone-specific is knowing that "Environment.SpecialFolder.Personal" maps to your app's Documents folder. Beyond that, it's .Net as usual.
And, again, this was probably overkill, but I wanted to answer sufficiently thoroughly for everybody who sees it.
The following How To from the Xamarin.iOS guide site has a few pointers to where to store your files:
http://docs.xamarin.com/guides/ios/application_fundamentals/working_with_the_file_system/
You can do something like this at runtime:
using (StreamWriter writer = new StreamWriter (Path.Combine (Environment.SpecialFolders.Documents, "yourfilename.ext"))) { }
and that will create the file. To open it for reading, use the same Path.Combine() but with StreamReader.

How can I launch a program from memory in C#?

I have some UI application that lives in the user's task bar that is written in C#. The EXE for the tool is checked in to our source control system on a number of projects that use it so we are able to update the version they run with by checking in updated EXE.
The problem is that when the users get the latest revision of the exe, the program is often running, and the sync fails on their machine. I want to fix it so the program doesn't lock the exe and any dependent DLL's when it runs so they can sync without having to shut down the program.
Currently, I have a program that takes an executable as a parameter and will launch it from memory by reading the assembly contents into memory ahead of time. Unfortunetly, this totally fails when it comes to the DLL's that the program requires.
The code I have right now looks something like this:
public class ExecuteFromMemory
{
public static void Main(string[] args)
{
//Figure out the name of the EXE to launch and the arguments to forward to it
string fileName = args[0];
string[] realArgs = new string[args.Length - 1];
Array.Copy(args, 1, realArgs, 0, args.Length - 1);
//Read the assembly from the disk
byte[] binary = File.ReadAllBytes(fileName);
//Execute the loaded assembly using reflection
Assembly memoryAssembly = null;
try
{
memoryAssembly = Assembly.Load(binary);
}
catch (Exception ex)
{
//Print error message and exit
}
MethodInfo method = memoryAssembly.EntryPoint;
if (method != null && method.IsStatic)
{
try
{
method.Invoke(null, new object[] { realArgs });
}
catch(Exception ex)
{
//Print error message and exit
}
}
else
{
//Print error message and exit
}
}
}
My question is, am I doing something totally stupid? Is there a better way to handle this? If not, what should I do to support handling external dependencies?
For example, the above code fails to load any dependent files if you try to run 'Foo.exe' that uses functions from 'Bar.dll', the 'Foo.exe' will be overwriteable, but 'Bar.dll' is still locked and can't be overwritten.
I tried getting the list of referenced assemblies from the 'GetReferencedAssemblies()' method on the loaded assmebly, but that doesn't seem to give any indication where the assemblies should be loaded from... Do I need to search for them myself? If so, what's the best way to do this?
It seems like other people might have come across this before, and I don't want to re-invent the wheel.
-
Update:
The EXE is checked in because thats how we distribute our in-house tools to the teams that use them. Its not optimal for this use-case, but I don't have the opportunity to change that policy.
Disclaimer: I don't use Windows, though I am familiar with its strange way of locking things.
In order to update your application while it is running, you'll likely need to have two processes: The executable itself, and an update “helper” application that will finish the update process. Let's say that your application is ProcessA.exe and your update helper is Updater.exe. Your main program will download a new copy of the executable, saving it with a random name. Then you run your updater program, which watches for the termination of your current process. When your process terminates, it displays a quick window showing the status of the update, moving the new executable into the place of the old one, and then restarting that program.
It'd be more elegant to be able to emulate POSIX filesystem semantics and be able to delete the currently-running process disk image and replace it with a new file, but I don't know if that is even possible on Windows. On a POSIX system, you can delete an in-use file and it won't actually be deleted until any remaining file handles are closed, though you can then reuse the filename.
You might want to check out an article written at CodeProject that talks about this. It also has a follow-up article.
Good luck!
Does the program need to keep running while updating?
Typically to update a program which is running you would copy over any of the files that are to be replaced to a temporary folder. Then shut down the old instance, delete it and move the new files over to the correct locations then re-launch it.
This allows for minimal down time of the application since the longest part is usually the copy and the file move is very fast if the temporary folder is on the same logical drive.
Although Michael's answer is one way of doing this, there are tools out there that are explicitly for managing what's installed on the desktop.
What you are doing with the exe being checked into source control is not normal. If you have a windows domain controller, you can use Group Policy to push programs down to the client. Alternatively, you could use something like Altiris to handle it.
If you must continue the way you are going then you have two options. One, using a helper / loader app which does a version check on launch. This is similar to how firefox works.
The second way is to build a helper service that sits in memory and polls every so often for updates. This is how Google Chrome, Adobe, etc work.

Categories

Resources