I am new to C# and I have made a simple Windows Forms Application that basically updates the persons files for a game.
They have to manually move and delete certain folders just to change version every time. I have successfully accomplished this.
However before I start giving it out I really should improve it. I know I need to change the name of the processes and remove my descriptions ETC.
I have stumbled onto an error and instead of me taking a guess I think it is best to get an opinion from a more experienced person about how to do this.
I am going to use Inno Setup to make the installer for my application, this way I can be sure it will go into their program files 32 and 64 bit. So I know this will be in program files.
So now I am wondering if I have done this the correct way or not? I was using this format to find their program files:
string programFilesFolder = Environment.GetEnvironmentVariable("PROGRAMFILES(X86)") ?? Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
However, would this work on all windows systems(XP, Vista, Win7, Win8) and is it completely accurate? I was going to use the above, and then use this:
string PATCHSELECTOR = Path.Combine(programFiles, #"PATCH SELECTOR");
if (Directory.Exists(PATCHSELECTOR))
{
string GamereliteFolder = Path.Combine(programFiles, #"GAMERELITE~1");
if (Directory.Exists(GamereliteFolder))
And then I move the files using the string method. If the file exists it is deleted before I copy the file over from PATCH SELECTOR to GAMERELITE.
Also will windows XP support using the .exe with an assembly resource embedded which is making the program need to be ran as administrator? I previously was making the assembly work through UAC however that wouldnt always work if they have UAC off or if it is XP so I thought I would try the admin assembly instead.
Can anyone possibly give me some insight, ideas or links?
For executables (not sure for websites & web application) this returns the directory where the executable lives (it's actually the base path where the framework will probe for Assemblies to load, 99% of the the that's the same thing).
System.AppDomain.CurrentDomain.BaseDirectory
This method works for any executable located in a folder which is defined in the windows PATH variable:
private string LocateEXE(String fileName)
{
string path = Environment.GetEnvironmentVariable("path");
string[] folders = path.Split(';');
foreach (var folder in folders)
{
if (File.Exists(Path.Combine(folder, fileName)))
{
return Path.Combine(folder, fileName);
}
}
return String.Empty;
}
Usage:
string pathToEXE = LocateEXE("Example.exe");
Reference:
how to find the execution path of a installed software
How can I get another application's installation path programmatically?
Couple things:
Among the already stated answers, Assembly.GetExecutingAssembly().Location will also give you the full file path of the currently "executing" Assembly. (Alternatively, GetCurrentAssembly)
If I'm reading your question correctly, you're trying to find both your own location as well as another application's. I would highly recommend seeing if the other application has a registry key that specifies the exact location - it'll make your copy step WAY more stable.
Related
I'm working on a project that involves the rewriting of legacy Windows applications for a modern .NET environment. The structure of these applications requires that there is one "Master" application running locally on the user's machine that fetches the others from a network share, along with required DLLs, and then runs them locally. This is not a problem per se, but I'm running into issues when I try to use the current user's AppData folder structure for this, whether it's local or roaming.
Thing is though, I can create a subfolder without a problem, I can copy files over (via a call to System.IO.File.Copy) and run them (via creating and starting an instance of System.Diagnostics.Process), but still the applications complain that they can't find the needed DLLs. This probably is related to the fact that the subfolder doesn't show up in the file system at all, which leads me to believe that files are not being copied over there in a fully conventional sense, but rather exist in some sort of limbo that prevents them from being "aware" of each other. When I do the copying and running to a standard filesystem folder, it all works fine. I've been trying to Google this issue as I was sure that this was a known problem, but I'm having a hard time finding anything on this subject. Hence this question.
Any ideas as to what might be going on? Or is my approach of using AppData for this particular purpose perhaps misguided to begin with?
EDIT: Comments asked for a viable code sample that reproduces the problem. I did have some interesting results trying to reproduce the issue as simply as I could. I created a fresh console app and could not reproduce it there. I then tried a fresh WinUI 3 app (which is what I'm trying to work with for my project) and I reproduced it there - the code seems to create the directory and then the file, without complaints (I run without the subfolder being there), but they don't show up in Explorer. For comparison, I then tried a fresh WPF app that does the exact same thing but this behaves the same as the console app, no issue with the subfolder and file showing up after running the app. So my issue seems to be confined to WinUI only.
You should be able to reproduce by placing this code inside the main window of a fresh application (and creating a button called myButton if VS doesn't do that automatically) and comparing WinUI 3 with WPF.
public MainWindow()
{
InitializeComponent();
}
private void myButton_Click(object sender, RoutedEventArgs e)
{
// See https://aka.ms/new-console-template for more information
var destinationPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Subfolder");
string sourceFilename = "C:\\Data\\Textfile.txt";
CopyFileToLocalExecutionPath(sourceFilename, destinationPath);
}
private string CopyFileToLocalExecutionPath(string sourceFilename, string destinationPath)
{
// Make sure that destination path exists before copying file
if (!Directory.Exists(destinationPath))
Directory.CreateDirectory(destinationPath);
// Assign full destination filename - local path + same as source filename
var destinationFilename = System.IO.Path.Combine(destinationPath, System.IO.Path.GetFileName(sourceFilename));
// Do not overwrite file if it's already there
if (!File.Exists(destinationFilename))
File.Copy(sourceFilename, destinationFilename);
return destinationFilename;
}
I want to save my Files in a more generic way than on Desktop.
So i want to create my own Subfolder in Programs Folder, which i can use to save my stuff.
But i get "System.UnauthorizedAccessException" if i try to create a File using File.AppendAllText(#"C:\Program Files\MySubfolder\MyFile.txt,someString);
I even disabled the Protection of the Folders manually.
My App is not yet compiled so i cant run it as administrator, can i?
How does every Program use this Folder but i cant?
Do i need to compile my App everytime i make a small change and want to test it?
I would really apreciate Help since im stuck with that multiple hours now
It is a very bad practice to try to write in Program Files. This folder as well as other sensitive folders are protected by the OS to prevent malicious code hide between your programs or to prevent unsavy users from messing on the installed programs.
If you want to write your private stuff on your disk you can use these folders
string folder = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
string myFolder = Path.Combine(folder, "MyReservedPath");
Directory.CreateDirectory(myFolder); // if exists does nothing
string myFile = Path.Combine(myFolder, "MyPrivateData.txt");
File.WriteAllText(myFile, dataToWriteOnDisk);
The CommonApplicationData resolves to C:\programdata and this place is usually used to store information needed by your program for any user that uses it.
If you want to store some data that your program produces then it is better to use the
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
There are many other places available, just look at the Environment.SpecialFolder enum.
This code will give you a list of everything mapped to the actual folders in your system
foreach (Environment.SpecialFolder x in Enum.GetValues(typeof(Environment.SpecialFolder)))
Console.WriteLine($"{x} = {Environment.GetFolderPath(x)}");
Situation
this is probably a really simple question with a really simple answer, but I can't find the answer anywhere, so I'm going to ask here, I've been working around this because it isn't a huge issue for me, but it will be when I submit my work.
Problem
I have a soundplayer, it works fine on my PC and does exactly what I want it to do on this PC.
SoundPlayer player = new SoundPlayer(#"C:\Users\Font\Desktop\GRADED_UNIT_SOLUTION_PLANNING_UPDATED\HillRacingGraded\HillRacingGraded\Resources\Audio\" + track + ".wav");
The problem is the path.
because of THIS path my program won't work on ANY other System apart from the one it's working on right now. It crashes soon after startup.
And.. as you can probably see from the path, it's going to eventually be graded, so my lecturer will need to use this program without having to switch around a directory.
How can I get the Soundplayer path to start at "HillRacingGraded\ ...\ ..."?
Rather than it starting at the C: drive.
If you're using System.Media.SoundPlayer, it supports reading of sound files from streams and I've seen it successfully used in the past from the UnmanagedResourceStream you get from an embedded resource. So one option would be to embed your sound file as a resource in your application and play it from there.
If embedding the file isn't an option, you can get paths relative to your executable folder using code similar to that shown below. Then you just have to provide your executable and the resource files in a subdirectory (but be careful with GetExecutingAssembly() if there's any chance your code is in a DLL and can be hosted by an arbitrary executable).
var assembly = Assembly.GetExecutingAssembly();
var folder = Path.GetDirectoryName(assembly.Location);
var soundFile = Path.Combine(folder, "MySoundFile.wav");
The special folder path helpers can also reduce the hard-coding but work best when your application will be installed via an installer and you can put files in the appropriate places automatically (which isn't likely to be the case for a school project).
For me (VS 2022, .net 6, C # 10) it worked:
Import the "file.wav" file into the main directory.
Change in: Properties (file.wav) - Copy to Output Directory to: Copy always.
Later it was enough to:
SoundPlayer player = new SoundPlayer("file.wav");
player.Load ();
player.Play ();
I wrote a program need to call an external exe using
Process proc = Process.Start(filepath).
I specify the absolute path of the exe and it works fine. However, I need to use this program in different computers. Each time the exe has a different absolute path and I need to change the code for this part. I would like to know is there a way that I don't need to change the code? Thanks in advance!
You are asking the wrong question. Is not how to modify the API to work with your fixed requirements ("launch process w/o knowing the path", ignoring for a moment what huge security problem that is). The question you should ask is How can I modify my code to match the API I use?
Since starting a process works better if a full path is given (it also works if the executable name is in %PATH%, but that is a different topic), have you app figure out the correct path and then launch the process. There are countless ways to achieve this. Probably the safest option is to use an App.Setting that points to the path. At deployment the app is properly configured with the location of the required program. there are (many) more ways to do this, it will all depend on what you're actually trying to solve, more details would be needed.
If both exe-files are in the same folder, then
winforms:
var filepath = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), otherexename);
Process.Start(filepath);
wpf:
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, otherexename)
Process.Start(filepath);
In a windows service, you can do the following to get the directory of the currently running assembly, then to generate the right path to your exe:
var directory = Path.GetDirectoryName(
new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
var exeLocation = Path.Combine(directory,"myExe.exe");
i made a program that uses a pre-made text file that hold a list of sites.
now in some computer the program works fine but, in my friend computer it doesn't.
i check the program on 2 of my windows 7 computers, and 1 xp and i don't have any errors.
this program was used for some time on XP, now my friend want to install it in his windows 7 computer at home, but the program doesn't find the file after he install the program.
this is the error he get:
System.IO.FileNotFoundException: file not found 'C:\Users\eli\AppData\Roaming\fourmlinks.txt'.
file name: 'C:\Users\eli\AppData\Roaming\fourmlinks.txt'
the thing is that i ship the this file in main program folder (Application Files), and it still cant find it.
this is the code i use to find the file when the program starts:
sring path = "";
path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\fourmlinks.txt";
System.OperatingSystem osInfo = System.Environment.OSVersion;
if (osInfo.Platform == PlatformID.Win32NT)
{
if (osInfo.Version.Major == 5 && osInfo.Version.Minor != 0)
{
//running XP
//path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\fourmlinks.txt";
path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\fourmlinks.txt";
}
}
you can see, that i tried to make sure it will work on windows 7 and, windows xp.
NOTE:
i don't mind changing the way i work with this file, or even loss this way and try completely different way that will work on the OS's (win 7 and XP). if u suggest me new way, i will be glad to give a try out.
my questions:
how is it possible that the program works in some computer and in some not?
will you put the file in a different place other then the program folder?
(sorry for my English)
How is it possible that the program works in some computer and in some not?
Because the program depends on something specific to a computer, and this something is different between the two computers. For example, your error message says:
file not found 'C:\Users\eli\AppData\Roaming\fourmlinks.txt'
The program is looking for a file in the Users folder; that is specific to every user on every machine, different users and different machines will have different files.
will you put the file in a different place other then the program folder
Will I? No, I can't because I'm not that user on that machine. If you mean "can my program put the file in a different place ..." then yes, it can.
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "fourmlinks.txt");
That will get a path to the logged-on user's private application data. If you have the "fourmlinks.txt" file in this folder on your machine but someone else doesn't have this file on their machine, then that will work on your machine but not on someone else's, as you asked.
string path = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
"fourmlinks.txt");
That will get the path to the installed file. If both you and someone else install the program, then both you and someone else will have the file. If either of you change the file, then the other gets the changes.
So should you always use GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)? Well, that depends. GetExecutingAssembly().Location is typically a place standard users cannot write to, only read from. If you want users to only read and never write to your data, then that is a good place to put it. If you don't, then it isn't.
If you want to create a new file for users to write to and to read from, then write to Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData). If you want to install some starting data with your application but allow the user to change it, then you should include the starting data file in your application. It will get installed to System.Reflection.Assembly.GetExecutingAssembly().Location. Then your application should do something like:
string fileName = "fourmlinks.txt";
string target = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), fileName);
if (!File.Exists(target))
{
string source = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), fileName);
File.Copy(source, target);
}
Another important difference between GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) and Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) is that the former is part of your installer packages; if the user uninstalls or updates your application all their runtime changes will be deleted.
If you want each user to have their own private data that does not get deleted when the application is modified, then you want to use Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData).