FileVersionInfo.GetVersionInfo alternative - c#

I have an application that checks for updates. To check for updates I need to get the version of the file on the user's computer.
I used this code:
if (File.Exists(dataFile))
{
var verLocal = Version.Parse(FileVersionInfo.GetVersionInfo(dataFile).FileVersion);
if (verSite > verLocal)
{
needToAdd = true;
}
}
Today I found out that the method FileVersionInfo.GetVersionInfo(String) may not get the file version! Here is a description from the help:
If the file did not contain version information, the FileVersionInfo
contains only the name of the file requested.
So that there was no error, I did like this:
if (File.Exists(dataFile))
{
if (Version.TryParse(FileVersionInfo.GetVersionInfo(dataFile).FileVersion, out var verLocal))
{
if (verSite > verLocal)
{
needToAdd = true;
}
}
}
But now there is a problem - if the user this method will never return the version of the file, then the user will never receive updates! So I need a way to get the version of the file that always works.
Are there alternatives to this method in c#?

That Version info metadata really only applies the Executeables or DLL's. It is supposed to be set during compilation. I have not seen it apply (be written) to any word document, image or similar non-executeable file.
A pretty dated approach for archiving, would be the old Archive Bit/Atribute. Just throwing it out there for completeness.
Usually for a "did it change?" check, it is sufficient to just check the file Size and LastUpdated dates of the file for changes. If you pick any backup maker, it will not do more advanced checks then this (plus the archive bit thing as a option). That one of those two values does not change can happen. But both of them is to unlikely to bother with.
The only 100%* reliable way to check for changes is to calculate a files hash-value. But that usually is something you only do during stuff like install verifications, not as a basic backup.
*Technically not even that is 100%. Hash Colissions are a thing, but are realistically impossible if you already check size and change date.

Related

OpenFileDialog & SaveFileDialog Pop-up search with filter in C#

I have openFileDialog and saveFileDialog with filter (only .dvbcfg extention):
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "DVB Configuration File (*.dvbcfg)|*.dvbcfg";
saveFileDialog.DefaultExt = "dvbcfg";
saveFileDialog.AddExtension = true;
It works properly, but when I'm trying to type filename manually it shows files with any extentions w/o filtering and opens/saves them (first - open file, second - save file):
ScreenShot
How to show only files that matches saveFileDialog.Filter?
P.S. I have overwrite function in saveFileDialog.
UPD I have another option - throw an exception when user selected wrong filetype, but I have no idea how to get only file extention from saveFileDialog.FileName string.
At a certain point, you have to "trust" your users. You can steer them towards good ways of working with your program, but at a certain point, you have to recognise that you've put enough simple barriers in their way to prevent accidental misuse1 but you're unlikely to be able to create enough barriers (in these dialogs) to prevent malicious misuse.
The problem is that using wrong file may cause damage to expensive equipment (DVB-3030 Digital Modulator in this case) even if I'm using try/catch to get variables from files (they need to be integers, in try segment I have Convert.ToInteger32) and variable ranges in if/else checks (for example Frequency range should be 10MHz - 90 MHz with 100Hz step). Since program will be used by students, they can purposely try to break it.
And nothing in your current question (or sought answer) would prevent someone from renaming any arbitrary file to have a .dvbcfg extension.
At this point, you "trust" that the user has given you the filename they wish to use. What you need to do next is to validate the contents of the file. If it has a .dvbcfg extension but isn't actually a valid DVB config file, you need to reject it. If it doesn't have a .dvbcfg extension (hey, maybe they're working with an old file system that only allows 8.3 file names :-)) but turns out to have valid content, why be churlish and reject that file?
I would recommend more than just wrapping ToInteger32 calls in try/catch. Go through the file. Ensure it contains exactly what it should and nothing else. Read each parameter value and probably use TryParse on those. Because your code now "expects" to receive invalid inputs. Then validate ranges, etc.
1Which I'd say you've already got.

C# results FALSE at `File.Exists` even if the file EXISTS

As title says I don't know what's wrong with my code but if (File.Exists) give negative result even if the file is there.
Below is my code
if (File.Exists(ZFileConfig.FileName.Replace(".xml", "_abc.xml")))
Here, ZFileConfig.FileName is E:\\Application\\Application\\bin\\Debug\\resources\\FirstFile.xml
And amazingly ZFileConfig.FileName.Replace(".xml", "_abc.xml") gives me E:\\Application\\Application\\bin\\Debug\\resources\\FirstFile_abc.xml that is what is needed. EVENTHOUGH IF falied to return TRUE.
It looks like your file is actually named abc_RotateFlip.xml.xml.
I can't imagine why any programmer would ever allow hidden file extensions, but your Excel file shows that they are indeed hidden. Turn that off! Choose to know what's going on inside your computer!
You can also use this registry script to change that setting;
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
"HideFileExt"=dword:00000000
Please check with FileInfo :
FileInfo fi = new FileInfo(#"_abc.xml");
bool isExists = fi.Exists;
Generally if you are performing a single operation on a file, use the File class. If you are performing multiple operations on the same file, use FileInfo.
The reason to do it this way is because of the security checking done when accessing a file. When you create an instance of FileInfo, the check is only performed once. However, each time you use a static File method the check is performed.

Having trouble saving multiple items to Isolated Storage

I have a noteapp, two pages:
MainPage.xaml — the creation of notes;
NoteList.xaml — a list of notes.
Notes are saved by means of IsolatedStorage, and appear in NoteList.xaml (listbox), but notes with the same name is not stored, how to fix it?
I need to be able to add notes with the same name (but with different content).
Thanks!
Are you using the note name as the file name? If so... don't do that. Save each file with a unique name. There are myriad ways of doing this. You could use a GUID or a timestamp, or you could append a timestamp to the end of the file name. If you were so inclined you could store all of the notes in a single formatted file-- perhaps XML.
What you need is a way to uniquely identify each note without using:
a. The note's name
b. The note's contents
While using a timestamp might make sense for your application right now (since a user probably cannot create two disparate notes simultaneously), using a timestamp to identify each note could lead to problems down the line if you wanted to implement say... a server side component to your application. What happens if in version 23 of your application (which obviously sells millions in the first months), you decide to allow users to collaborate on notes, and a Note is shared between two instances of your app where they happened to be created at the EXACT same time? You'd have problems.
A reasonable solution to finding a unique identifier for each Note in your application is through the use of the Guid.NewGuid method. You should do this when the user decides to "save" the note (or if your app saves the note the moment it's created, or at some set interval to allow for instant "drafts".
Now that we've sufficiently determined a method of uniquely identifying each Note that your application will allow a user to create, we need to think about how that data should be stored.
A great way to do this is through the use of XmlSerializer, or better yet using the third party library Json.Net. But for the sake of simplicity, I recommend doing something a bit easier.
A simpler method (using good ole' plain text) would be the following:
1: {Note.Name}
2: {Guid.ToString()}
3: {Note.Contents}
4: {Some delimiter}
When you are reading the file from IsolatedStorage, you would read through the file line by line, considering each "chunk" of lines between the start of the file and each {Some delimiter} and the end of the file to be the data for one "Note".
Keep in mind there are some restrictions with this format. Mainly, you have to keep the user from having the last part of their note's contents be equal to the {Some delimiter} (which you are free to arbitrarily define btw). To this end, it may be helpful to use a string of characters the user is not likely to enter, such as "##&&ENDOFNOTE&&##" Regardless of how unlikely it is the user will type that in, you need to check to make sure before you save to IsolatedStorage that the end of the Note does not contain this string, because it will break your file format.
If you want a simple solution that works, use the above method. If you want a good solution that's scalable, use JSON or XML and figure out a file format that makes sense to you. I highly encourage you to look into JSON, it's value reaches so much further than this isolated scenario.
I've had a need to write notes to IsolatedStorage. What I did was to them them to a file.IsolatedStorageFile I write date on which the note was written and then note. From the list box i store them to two arrays. Then before exiting the app, write them to a file.
try
{
using (IsolatedStorageFile storagefile = IsolatedStorageFile.GetUserStoreForApplication())
{
if (storagefile.FileExists("NotesFile"))
{
using (IsolatedStorageFileStream fileStream = storagefile.OpenFile("NotesFile", FileMode.Open, FileAccess.ReadWrite))
{
StreamWriter writer = new StreamWriter(fileStream);
for (int i = 0; i < m_noteCount; i++)
{
//writer.Write(m_arrNoteDate[i].ToShortDateString());
writer.Write(m_arrNoteDate[i].ToString("d", CultureInfo.InvariantCulture));
writer.Write(" ");
writer.Write(m_arrNoteString[i]);
writer.WriteLine("~`");
}
writer.Close();
}
}

Implementing a save function in a C# image manipulation app

I started thinking about how to handle the save functionality of my app, and thought about 2 options:
The application has nodes like:
Blur
Contrast
Sharpen
Invert
...
1. Interpreting the saved file, like:
Blur name:"Blur01" Amount:5
...
2. Having the saved file in a self executable format, like:
Blur blur = new Blur ();
blur.Name = "Blur01"
blur.Amount = 5
...
Which one should I go for? Is there a better way to handle this?
I want the saved file to be backwards and forwards compatible.
EDIT: Thanks for all the replies. Anyone can please explain why #2 would not be future proof? Is it because one can change the load/open code for #1, but not for #2?
You could probably use XML Serialization, since it's widely accepted and human readable.
Here's a tutorial on that: XML Serialization
I would go with something more like the first option.
Although, in general, I think XML would be a better approach to this than making your own syntax. This is much better from a compatibility/future-proofing standpoint than trying to make your own syntax parsers for your file.
What about something like:
<Filters>
<Blur Name="Blur01" />
<Sharpen Name="Sharpen01" Amount=5 />
</Filters>
I too would go with an XML file as this will allow you to ensure compatibility both forwards and backwards.
This is because you look for properties rather than parsing the file line by line.
For example, if blur changes from:
<Blur>
<name>Blur01</name>
<amount>5</amount>
</Blur>
to:
<Blur>
<name>Blur01</name>
<amount>5</amount>
<feather>true</feather>
</Blur>
Older versions of the app will still be able to read the file as they won't look for the feather property. All you need to do is ensure that you set default values when you create your objects so that the older files can be read without leaving unset data.
In response to the update - there's no reason why you couldn't make #2 future proof. You'd just have to do the versioning yourself.
The reason having a self-executing "save format" is generally bad is that today your "Blur" function might look like:
public class Blur
{
int Amount = 5;
}
but in the future, you might improve your blur "system" to instead have something like:
public class Blur
{
int HorizontalAmount = 5;
int VerticalAmount = 10;
}
and now when you execute that saved file, it will no longer compile because there is no longer an 'Amount' property. Then to get backwards compatibility you will need to 'interpret' the Amount value to now mean HorizontalAmount = 5 AND VerticalAmount = 5 (or whatever).
So really, in the long run, you will be better off by having an interpreted file format from the start.
Are you saving it in a text file?
If that is so wouldn't it be better to save it as XML?
<Blur>
<name>Blur01</name>
<amount>5</amount>
</Blur>
Otherwise I am not sure I understand the question :)

How to get max allowed filesize in .Net?

Does anyone know how to (natively) get the max allowed file size for a given drive/folder/directory? As in for Fat16 it is ~2gb, Fat32 it was 4gb as far as I remember and for the newer NTFS versions it is something way beyond that.. let alone Mono and the underlying OSes.
Is there anything I can read out / retrieve that might give me a hint on that? Basically I -know- may app will produce bigger, single files than 2gb and I want to check for that when the user sets the corresponding output path(s)...
Cheers & thanks,
-J
This may not be the ideal solution, but I will suggest the following anyway:
// Returns the maximum file size in bytes on the filesystem type of the specified drive.
long GetMaximumFileSize(string drive)
{
var driveInfo = new System.IO.DriveInfo(drive)
switch(driveInfo.DriveFormat)
{
case "FAT16":
return 1000; // replace with actual limit
case "FAT32":
return 1000; // replace with actual limit
case "NTFS":
return 1000; // replace with actual limit
}
}
// Examples:
var maxFileSize1 = GetMaximumFileSize("C"); // for the C drive
var maxFileSize2 = GetMaximumFileSize(absolutePath.Substring(0, 1)); // for whichever drive the given absolute path refers to
This page on Wikipedia contains a pretty comprehensive list of the maximum file sizes for various filesystems. Depending on the number of filesystems for which you want to check in the GetMaximumFileSize function, you may want to use a Dictionary object or even a simple data file rather than a switch statement.
Now, you may be retrieve the maximum file size directly using WMI or perhaps even the Windows API, but these solutions will of course only be compatible with Windows (i.e. no luck with Mono/Linux). However, I would consider this a reasonably nice purely managed solution, despite the use of a lookup table, and has the bonus of working reliably on all OSs.
Hope that helps.
How about using System.Info.DriveInfo.DriveFormat to retrieve the drive's file system (NTFS, FAT, ect.)? That ought to give you at least some idea of the supported file sizes.

Categories