How do you programatically find Vista's "Saved Games" folder? - c#

I am using XNA and I want to save files to Vista's "Saved Games" folder.
I can get similar special folders like My Documents with Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) but I cannot find an equivalent for the Saved Games folder. How do I get to this folder?

http://msdn.microsoft.com/en-us/library/bb200105.aspx#ID2EWD
Looks like you'll need to use Microsoft.Xna.Framework.Storage and the StorageLocation class to do what you need to.
Currently, the title location on a PC
is the folder where the executable
resides when it is run. Use the
TitleLocation property to access the
path.
User storage is in the My Documents
folder of the user who is currently
logged in, in the SavedGames folder. A
subfolder is created for each game
according to the titleName passed to
the OpenContainer method. When no
PlayerIndex is specified, content is
saved in the AllPlayers folder. When a
PlayerIndex is specified, the content
is saved in the Player1, Player2,
Player3, or Player4 folder, depending
on which PlayerIndex was passed to
BeginShowStorageDeviceSelector.

There is no special folder const for it so just use System Variables. According to this Wikipedia article Special Folders, the saved games folder is just:
Saved Games %USERPROFILE%\saved games Vista
So the code would be:
string sgPath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), "saved games"));
...
EDIT: If, as per the comments, localization is an issue and as per your question you still want access to the Saved Games folder directly rather than using the API, then the following may be helpful.
Using RedGate reflector we can see that GetFolderPath is implemented as follows:
public static string GetFolderPath(SpecialFolder folder)
{
if (!Enum.IsDefined(typeof(SpecialFolder), folder))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, GetResourceString("Arg_EnumIllegalVal"), new object[] { (int) folder }));
}
StringBuilder lpszPath = new StringBuilder(260);
Win32Native.SHGetFolderPath(IntPtr.Zero, (int) folder, IntPtr.Zero, 0, lpszPath);
string path = lpszPath.ToString();
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Demand();
return path;
}
So maybe you think all i need is to create my own version of this method and pass it the folder id for Saved Games. That wont work. Those folder ids pre-Vista were actually CSIDLs. A list of them can be found here. Note the Note: however.
In releasing Vista, Microsoft replaced CLSIDLs with KNOWNFOLDERIDs. A list of KNOWNFOLDERIDs can be found here. And the Saved Games KNOWNFOLDERID is FOLDERID_SavedGames.
But you don't just pass the new const to the old, CLSIDL based, SHGetFolderPath Win32 function. As per this article, Known Folders, and as you might expect, there is a new function called SHGetKnownFolderPath to which you pass the new FOLDERID_SavedGames constant and that will return the path to the Saved Games folder in a localized form.

The easiest way I found to get the Saved Games path was to read the Registry value likes this:
var defaultPath = Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), "Saved Games");
var regKey = "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders";
var regKeyValue = "{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}";
var regValue = (string) Registry.GetValue(regKey, regKeyValue, defaultPath);
I changed the location of my Saved Games via the Shell multiple times and the value of this key changed each time. I use the USERPROFILE/Saved Games as a default because I think that will work for the default circumstance where someone has never changed the location.

Related

I think I am doing this wrong, won't copy to relative path

public void Save_Token(string _Token)
{
var Token_Location = #".\token.txt";
using (StreamWriter sw = new StreamWriter(Token_Location))
{
sw.WriteLine(_Token);
}
}
I tried to get the token from the api (json) and I deserialized and saved it. I would like to write to the file to save for later. But I want this application to be ran on anyone's PC. So I don't want to use the full path.
I also tried
Path.Combine(Environment.CurrentDirectory,Token_Location);
still nothing is written, unless I use the full path.
You can't guarantee that the current user has write access to the folder from where the file is executed. There is a special folder (APP_DATA) that applications are supposed to use when storing user data on a computer:
public void Save_Token(string _Token)
{
var tokenDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "YourCompanyOrOrganizationName");
var tokenFile = Path.Combine(tokenDirectory, "token.txt");
Directory.CreateDirectory(tokenDirectory);
File.WriteAllText(tokenFile, _Token);
}
Your file will then be stored in a path like "C:\Users\yourusername\AppData\Roaming\YourCompanyOrOrganizationName\token.txt"
It is generally a bad idea to use a relative path in software source code because the "current working directory" of the process that the relative path is relative to can change over the runtime of the application.
Activities like showing a file open dialog or using a third-party component can unexpectedly change the current working directory so that it is dangerous to assume a certain current working directory.

Xamarin media plugin get android image path

I am using the media plugin for xamarin forms (by james montemagno) and the actual taking of the picture and storing it works fine, I have debugged the creation of the image on the emulator and it is stored in
/storage/emulated/0/Android/data/{APPNAME}.Android/files/Pictures/{DIRECTORYNAME}/{IMAGENAME}
however in my app it will get a list of file names from an API I want to check if the image exists in that folder.
The following works fine on IOS
var documentsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string jpgFilename = System.IO.Path.Combine(documentsDirectory, App.IMAGE_FOLDER_NAME);
jpgFilename = System.IO.Path.Combine(jpgFilename, name);
I have tried the 2 following methods for getting it on android but both are incorrect
var documentsDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
string jpgFilename = System.IO.Path.Combine(documentsDirectory, App.IMAGE_FOLDER_NAME);
jpgFilename = System.IO.Path.Combine(jpgFilename, name);
Java.IO.File dir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DataDirectory + "/" + App.IMAGE_FOLDER_NAME + "/" + name);
dir ends up as
/storage/emulated/0/data/{DIRECTORY}/{IMAGENAME}
jpgFileName ends up as /data/data/{APPNAME}.Android/files/{DIRECTORYNAME}/{IMAGENAME}
I dont want to hardcode anything in the paths but neither of these are right. I could not find anything in the GIT documentation for getting the file path except by looking at the path of the file created when taking a picture
The problem
I had the same kind of issue with Xamarin Media Plugin. For me, the problem is:
we don't really know where the plugin save the picture on android.
After reading all documentation I found, I just noted this:
... When your user takes a photo it will still store temporary data, but also if needed make a copy to the public gallery (based on platform). In the MediaFile you will now see a AlbumPath that you can query as well.
(from: Github plugin page)
so you can save your photo to your phone gallery (it will be public) but the path is known.
and we don't know what means "store the temporary data".
Solution
After investigating on how/where an app can store data, I found where the plugin stores photos on Android >> so I can generate back the full file names
In your Android app, the base path you are looking for is:
var basePath = Android.App.Application.Context.GetExternalFilesDir(null).AbsolutePath
It references your app's external private folder. It looks like that:
/storage/emulated/0/Android/data/com.mycompany.myapp/files
So finally to get your full file's path:
var fullPath = basePath + {DIRECTORYNAME} + {FILENAME};
I suggest you to make a dependency service, for instance 'ILocalFileService', that will expose this 'base path' property.
Please let me know if it works for you !
I resolved a similar problem. I wanted to collect all files for my app in a folder visible to all users.
var documentsDirectory = Android.OS.Environment.GetExternalStoragePublicDirectory(
Android.OS.Environment.DirectoryDocuments);
If you want to create Directory, add to your class using System.IO; and you have the same functions in a normal .NET application.
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
If you want to create files or directory, you can use PCLStorage.
public async Task<bool> CreateFileAsync(string name, string context)
{
// get hold of the file system
IFolder folder = FileSystem.Current.LocalStorage;
// create a file, overwriting any existing file
IFile file = await folder.CreateFileAsync(name,
CreationCollisionOption.ReplaceExisting);
// populate the file with some text
await file.WriteAllTextAsync(context);
return true;
}
to get the private path
var privatePath = file.Path;
to get the public Album path
var publicAlbumPath = file.AlbumPath;
se the documentation here https://github.com/jamesmontemagno/MediaPlugin

Using new created folder with timestamps

I am new to c#, I have made a function which creates a new folder with a time stamp everytime the console is run.
string newfolder = #"d:\Denby_Screenshots" + DateTime.Now.ToString(" yyyy-MM-dd-HH-mm-ss-fff");
if (!Directory.Exists(newfolder))
{
Directory.CreateDirectory(newfolder);
Console.WriteLine("Screenshot folder has been created");
}
I then would like this to be down to allow the screenshots to be saved into this newly created file.
static private Test_Criteria Block_Two(IWebDriver driver, Screenshot screenshot, string newfolder)
{
{
screenshot = ((ITakesScreenshot)driver).GetScreenshot();
screenshot.SaveAsFile("d:\\ScreenShot.png",System.Drawing.Imaging.ImageFormat.Png);
But for the life of me I am not sure how to do this would anyone be able to advise or have any good screenshots for me to be able to work from.
Thanks
If you are doing these two steps in one console context. Then simply, return newly created folder name to the calling function. And use that folder name (as string) to save files into.
Something like this:
SaveAsFile(Path.Combine(returnedFolderName, suggestedFileName).....
Like so:
screenshot.SaveAsFile(Path.Combine(newFolder,"screenshot.png", ImageFormat.Png);
And reconsider your folder structure, it would be extremely annoying to have a zillion folders in your root folder with just one file in each.
A better approach would be
newFolder = Path.Combine(Environment.SpecialFolder.MyPictures, "Screenshots",DateTime.Now.ToString("yyyyMMdd"));
And the target file name:
Path.Combine(newFolder, "Screenshot "+DateTime.Now.ToString("HH-mm-ss-fff")+".png");

Simply get files from internal project folder [duplicate]

This question already exists:
Closed 10 years ago.
Possible Duplicate:
how to populate a listbox with files in the project of my windows phone 7 application
I'm a newbie on C# and this is annoying me a lot.
My application load a set of images from a folder that I simply created on the Solution Explorer called Images. I can see these images if I use it hardcoded with URIs and stuff, but what I want to do is to take these images names dinamycally and then load it. I have seen some questions like it but couldnt solve my problem. I'm trying like this:
DirectoryInfo directoryInfo = new DirectoryInfo(#"/Images");
foreach (FileInfo file in directoryInfo.GetFiles()) {
photos.Add(new Photo() { FileName = file.FullName, PhotoSource = GetImageSource("Images/" + file.FullName) });
}
The directoryInfo is always set as null. My project hierarchy as shown in Solution Explorer is like:
Project
Main.xaml
Maim.xaml.cs
Images
1.jpg
2.jpg
...
Thanks in any help.
From MSDN:
For a Windows Phone application, all I/O operations are restricted to
isolated storage and do not have direct access to the underlying
operating system file system or to the isolated storage of other
applications.
So you can't access your Images folder in the manner you'd like.
Since you can't add images dynamically to your XAP anyway, the images available will be constant. It appears you will just have to add the URIs manually:
BitmapImage myImage = new BitmapImage(new Uri("Images/myImage.png", UriKind.Relative));
If you've got different images for different locales, you could include the image name/path in a resources file and then create them from there.
Alternatively if you have a set of default images and will then have some user-added ones, and you'd like to iterate over all of those, you could write your defaults from your Images folder into IsolatedStorage at first start-up. See here for details on using IsolatedStorage. You can iterate over directories and files within the apps IsolatedStorageFile (see the methods available).
Maybe you want to use
string path = Path.Combine(Environment.CurrentDirectory, "Images");
foreach (string file in Directory.GetFiles(path)
{
photos.Add(new Photo {FileName = file, PhotoSource = GetImageSource(Path.Combine(path, Path.GetFileNameWithoutExtension(file))});
}
which returns a List of the Contents of the Folder.
Path.Combine combines single strings to a full Path (So you don't need to worry about the Backslahes.
The Path Namespace is pretty underrated, i'd suggest you to take a close look to it since it will save you much time.

Converting absolute path to relative path C# [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Getting path relative to the current working directory?
I have code in C# that includes some images from an absolute path to a relative so the image can be found no matter where the application fold is located.
For example the path in my code (and in my laptop for the image) is
C:/something/res/images/image1.jpeg
and I want the path in my code to be
..../images/image1.jpeg
So it can run wherever the folder is put, whatever the name of the C: partition is etc.
I want to have a path in my code which is independant of the application folder location or if it is in another partition, as long as it is in the same folder as the the rest of the solution.
I have this code:
try
{
File.Delete("C:/JPD/SCRAT/Desktop/Project/Resources/images/image1.jpeg");
}
catch (Exception)
{
MessageBox.Show("File not found:C:/Users/JPD/Desktop/Project/images/image1.jpeg");
}
This code only runs if the file and folder are in that certain path, (which is also the location of the code) I wish for that path to be relative so wherever I put the whole folder (code, files etc) the program will still work as long as the code (which is under project folder) is at the same location with the folder images... what should I do?
Relative paths are based from the binary file from which your application is running. By default, your binary files will be outputted in the [directory of your .csproj]/bin/debug. So let's say you wanted to create your images folder at the same level as your .csproj. Then you could access your images using the relative path "../../images/someImage.jpg".
To get a better feel for this, try out the following as a test:
1) create a new visual studio sample project,
2) create an images folder at the same level as the .csproj
3) put some files in the images folder
4) put this sample code in your main method -
static void Main(string[] args)
{
Console.WriteLine(Directory.GetCurrentDirectory());
foreach (string s in Directory.EnumerateFiles("../../images/"))
{
Console.WriteLine(s);
}
Console.ReadLine(); // Just to keep the console from disappearing.
}
You should see the relative paths of all the files you placed in step (3).
see: Getting path relative to the current working directory?
Uri uri1 = new Uri(#"c:\foo\bar\blop\blap");
Uri uri2 = new Uri(#"c:\foo\bar\");
string relativePath = uri2.MakeRelativeUri(uri1).ToString();
Depending on the set up of your program, you might be able to simply use a relative path by skipping a part of the full path string. It's not braggable, so J. Skit might be up my shiny for it but I'm getting the impression that you simply want to make it work. Beauty being a later concern.
String absolutePath = #"c:\beep\boop\HereWeStart\hopp.gif";
String relativePath = absolutePath.Substring(13);
You could then, if you need/wish, exchange the number 13 (which is an ugly and undesirable approach, still working, though) for a dynamically computed one. For instance (assuming that the directory "HereWeStart", where your relative path is starting, is the first occurrence of that string in absolutePath) you could go as follows.
String absolutePath = #"c:\beep\boop\HereWeStart\hopp.gif";
int relativePathStartIndex = absolutePath.IndexOf("HereWeStart");
String relativePath = absolutePath.Substring(relativePathStartIndex);
Also, your question begs an other question. I'd like to know how you're obtaining the absolute path. Perhaps there's an even more clever way to avoid the hustle all together?
EDIT
You could also try the following approach. Forget the Directory class giving you an absolute path. Go for the relative path straight off. I'm assuming that all the files you're attempting to remove are in the same directory. If not, you'll need to add some more lines but we'll cross that bridge when we get there.
Don't forget to mark an answer as green-checked (or explain what's missing or improvable still).
String
deletableTarget = #"\images\image1.jpeg",
hereWeAre = Environment.CurrentDirectory;
MessageBox.Show("The taget path is:\n" + hereWeAre + deletableTarget);
try
{ File.Delete(hereWeAre + deletableTarget); }
catch (Exception exception)
{ MessageBox.Show(exception.Message); }
Also, please note that I took the liberty of changing your exception handling. While yours is working, it's a better style to rely on the built-in messaging system. That way you'll get more professionally looking error messages. Not that we ever get any errors at run-time, right? ;)

Categories