I'm implementing a C# Windows console application to manage files in Windows Explorer. At this point of my work I need to create file custom properties and both set and get their values. I've read many web articles, and I understand that I can't do this for each file, it depends on the type/nature of the selected file... and this is ok for me, this is a limit that I took into account and accepted before starting my work.
Please consider that I want to manage these properties without using the file related application (for example, in case of a .docx file I don't want to open the Word application and then work with Microsoft.Office.Interop.Word.Application and Microsoft.Office.Interop.Word.Document classes). Cases do in fact exist where it is possible to right-click on a file in Win Explorer, select 'Properties' and then find a tab named as 'Custom' where you can search, read and set custom properties.
What I want to do is manage (Read & Write) this file Custom information programmatically.
Any hint? Thanks!
EDIT #1:
I tried to follow the Simon Mourier's hint but unfortunately it does not work, I was not able to SET the property value. I tried also the Rod Howarth's hint but it fails when you try to set the value of an existing custom property... moreover, using the DSOFile library there are problems related to the persistence of the saved custom property.
See this. It is about office file custom properties, but there is one answer describing the method how to get custom properties of any file (as far as I anderstood, even txt file can have some)
This solution seems working fine if you need to set the value of an existing custom property; if you need to create a new born custom property, then you must use the Add(string sPropName, ref object Value) method of the CustomProperties collection.
Related
I have an application that I am developing that is made with Window Forms. For localizing all my Labels, ToolStripMenuItems, Buttons, etc I use resx resource files. Specifically to localize my application for German, I open my Main.en-CA.resx file in winres. I then go through all the terms found in the form and change them to their German translation. I then save the file to Main.de-DE.resx. I now have a Main.en-CA.resx file and a Main.de-DE.resx file. In my code I then only have to change the current culture to whatever language I want and apply the change to all my Labels, Controls, Buttons, etc. For example something like this:
System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language);
// Must re-apply resources after changing the culture
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Main));
resources.ApplyResources(this, "$this");
foreach (Control c in this.Controls)
{
resources.ApplyResources(c, c.Name);
}
This seems to work great for all Labels etc that do not change. I do however have entries that are changed. For example I might have a dropdown ComboBox that is filled with the entries: "Apple", "Banana", "Orange". Or I might have some error messages: "Missing Input", "Cannot find xml file" that are only sometimes displayed. Now I suppose maybe for the error messages I could just have Labels and selectively change their visibility depending on whether they need to be shown, however for the dropdown ComboBox these entries might change depending on say which file the user loads.
I am wondering then, is there a way to store these entries in the resx files and then access them from my code. I tried opening the resx files and adding them manually (i.e. without using winres) but attempting to do this resulted in the warning:
You are trying to edit a resource file that is a part of another project item (such as a form or control). Editing this item could corrupt the project item, and you will have to recover it by hand. In addition, changes made to this resource file may be lost if further changes are made to the project item.
Do you really want to edit this file?
This sounded like a bad idea so I didn't try that any further. Additionally I am not sure on how I would access the terms in the file manually. I am very new to windows forms and resource files (this is my first time using them) so I realize this might be a simple question but I have had trouble finding information on how exactly to do this.
Ok as it turns out I have uncovered how I can achieve what I am looking for. Ok from the SO post I can access any strings stored in the files Resource.resx by the code:
myLabel.Text = Properties.Resources.MissingController;
where MissingController is a key (i.e. Name) in the file Resources.resx.
Therefore all I need to do is add additional resource files such as Resource.de-DE.resx in the case of German and fill in the translations (i.e. the values in the resource file) corresponding to the same keys (i.e. the names in the resource file).
The Resources.resx file looks like:
and the Resources.de-DE.resx looks like:
As mentioned in the question I had already created some resource files for translating my forms but I had used winres. Whereas they had been located under my Main.cs [Design] file, the Resources.resx and Resources.de-de.resx are located under Properties. Because I had used winres to make my resx files I think that meant I was not supposed to manually edit them hence the warning it gave?? I'm still not 100% sure about this.
Regardless I can now just manually add terms to my Resource.resx file as well as create different versions of this file for different languages and the localization will work. When right clicking on Properties and going Add->New Item and then selecting Resource, if you do not see the Resource file type as an option (as happened to me) then that might mean you need to add the development tools that did not get installed with your version of visual studio. You can achieve this by just running the visual studio installer again and clicking modify and adding the .NET development tools.
I'm using Settings.Settings to store settings at run-time. It was very helpful for my earlier application to store data. But in my current project its not saving the settings data. My application have some tab and each tab contains some TextBox. Im using textBox Text to store string values.
Properties.Settings.Default.Setting1 = textBox2.Text;
Properties.Settings.Default.Save();
It is a working method for my all previous application.But I can't understand why its not working in my current project.
Since your question does not include many details, I've tried to answer as much as possible:
Try to perform a Properties.Settings.Default.Upgrade() and then saved settings get loaded.
You have to call the Upgrade method of ApplicationSettingsBase derived class (that is normally called Settings and is created for you by Visual Studio)
Properties.Settings.Default.Upgrade();
When/where to call the Upgrade method? There is a simple trick you can apply: define a user setting called UpgradeRequired (example) as bool (the easiest way is through IDE). Make sure its default value is true.
Insert this code snipped at the start of the application:
if (Properties.Settings.Default.UpgradeRequired)
{
Properties.Settings.Default.Upgrade();
Properties.Settings.Default.UpgradeRequired = false;
Properties.Settings.Default.Save();
}
So the Upgrade method will be called only after the version changes and only one time (since you disable further upgrades by setting UpgradeRequired = false until a version change - when the property regains default value of true).
Check the scope of your settings [USER/APPLICATION]
Try this out, and if it doesn't work check the below conditions.
Also, a more detailed question next time would be much appreciated.
Permission (NTFS permission)
Or Active directory permission
Or capacity of windows drive is full.
Or there exist two or more user folders and you checked another.
For example: There are two or three folders, user.domain, user.workgroupname, user.
Despite all this, I suggest you to learn about System.Reflection and develop your personalized method to save settings, the option provided by the Visual Studio isn't very dependable.
Hope this was helpful.
I'm trying to run this code:
this.storage =
Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts)
.GetStorage("ws_up_storage", Outlook.OlStorageIdentifierType.olIdentifyByMessageClass);
It runs perfectly well on some machines, but on others it throws this exception:
I also tried other folder names, like olFolderInbox, olFolderCalendar. I've looked at Microsoft docs for this, and it says this error is to be expected if the folder is one of the following:
The folder is a Microsoft Exchange public folder, an Internet Message Access Protocol (IMAP), MSN Hotmail, or a Microsoft SharePoint Foundation folder.
The user permission for the folder is read-only.
The store provider does not support hidden items.
The sad fact is, I do not know how to check which one of these is true and if it's at all possible.
How would I go about determining the cause of the problem and addressing it?
The easiest way to handle all these cases is to try to get a storage. You will need much efforts to implement all cases. The PR_MDB_PROVIDER property allows to identify the store provider, but not all cases such as user permissions for the folder and etc. You can use the try/catch block where you may check the error code - 0x80040102 (MAPI_E_NO_SUPPORT).
However, you may use any low-level property viewers (for example, a free open source tool - MFCMAPI) for exploring Extended MAPI property values. Thus, you may find all the required info about not supported scenarious.
The error 0x80040102 is MAPI_E_NO_SUPPORT, which means the store does not support hidden (associated) items.
Read the PR_MDB_PROVIDER property (DASL name http://schemas.microsoft.com/mapi/proptag/0x34140102) using PropertyAccessor.GetProperty. The returned 16 byte array will be specific for each store kind. E.g. for an Exchange store, it will be pbExchangeProviderPrimaryUserGuid (5494A1C0297F101BA58708002B2A2517). Take a look at any object in the store in question using OutlookSpy (I am its author - click IMessage, IMAPIFolder, or IMsgStore) to see the PR_MDB_PROVIDER property.
Good day, is there any option how to create a box, which cannot be seen from Windows? I would like to insert some files into this box. These files should be accessible only through my application, not from Windows. Thank you in advance.
How many files and how do you need to access them? If they are only for reading and you don't have too many, you always have the option to store them as a resource in your project. Have a look at this link on MSDN on how to store various file types directly inside your assembly.
NOTE: If you are planning on storing passwords or security-sensitive data, you shouldn't use this approach.
Another alternative would be to store you files inside a database. If you were to use something such as SQLite (here is the .Net data provider), Windows would have access to the database file, but not to the files contained within the database (which could be encrypted). Depending on your data, you'd have to store the file information as a binary large object (blob). See here for an example of how to do this.
It depends on the layer of abstraction you want. All files created by an application are at some level accessible by windows, however, you can mask the content of these files (i.e. encrypt them).
Generally speaking, you could still store the files in a folder, and apply encryption. Here's the msdn article on the point. The other issue is where do you store the key used for encryption.
A simple solution is to hard-code the key in some variable. However, if the assembly is decompiled, the key will become apparent. On the other hand, if you want the user that created the files to begin with, to be the only one to access the files, then you can use the Data Protection API.
If your question is how to the hide the box then you can set the "Visible" attribute to false no matter what control you are using for this "box".
if your box does not include a lot of files or not large file, you can try save it in a compress file like .zip and add a password for it. also add the hidden attribute on that box.
I need to set the Company field value for some Word/PDF documents. I am talking about the extended file properties (summary/author/title, etc.) you see under File Properties.
I know how to get them (by using shell32.dll class library). I assumed that I could also set them with the same class library, but it seems like writing extended properties is a little bit more difficult and shell32.dll doesn't allow that.
I found something about taglib-sharp, which seems to have an option to set extended properties, but I don't really understand how it works.
Add following NuGet packages to your project:
Microsoft.WindowsAPICodePack-Shell by Microsoft
Microsoft.WindowsAPICodePack-Core by Microsoft
Read and Write Properties
using Microsoft.WindowsAPICodePack.Shell;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;
string filePath = #"C:\temp\example.docx";
var file = ShellFile.FromFilePath(filePath);
// Read and Write:
string[] oldAuthors = file.Properties.System.Author.Value;
string oldTitle = file.Properties.System.Title.Value;
file.Properties.System.Author.Value = new string[] { "Author #1", "Author #2" };
file.Properties.System.Title.Value = "Example Title";
// Alternate way to Write:
ShellPropertyWriter propertyWriter = file.Properties.GetPropertyWriter();
propertyWriter.WriteProperty(SystemProperties.System.Author, new string[] { "Author" });
propertyWriter.Close();
Important:
The file must be a valid one, created by the specific assigned software. Every file type has specific extended file properties and not all of them are writable.
If you right-click a file on desktop and cannot edit a property, you wont be able to edit it in code too.
Example:
Create txt file on desktop, rename its extension to docx. You can't
edit its Author or Title property.
Open it with Word, edit and save
it. Now you can.
So just make sure to use some try catch
Further Topic:
MS Docs: Implementing Property Handlers
Ok here is answer to my own question, since I wasn't really able to find my answer in this forum, it could be useful for others.
Solution is to use dsofile.dll and OleDocumentPropertiesClass.
Here is MS article about dsofile.dll - Link
In this link, you can download dsofile.dll with some other files. But most probably, just like I did, you will face some weird problems that are hard to find a solution for.
1) After intalling dsofile.dll, you will need to register the class: oped cmd and navigate to c:\dsofile of to directory, where you have extracted your downloaded dsofile.dll. After that - write line regsvr32 dsofile.dll. You should get a messagebox saying that registeration was succesful. If not, most propably you don't have admin rights. You are going to need admin rights in case you want this to work.
2) After trying to use this class in your program, if you are using .NET 4.0 it is possible, that you will see error saying something like "class cannot be embedded ..."
Well, for that, right click on dsofile in references list, properties -> embed interop files -> set to FALSE.
3) How to use:
//creates new class of oledocumentproperties
var doc = new OleDocumentPropertiesClass();
//open your selected file
doc.Open(pathToFile, false, dsoFileOpenOptions.dsoOptionDefault);
//you can set properties with summaryproperties.nameOfProperty = value; for example
doc.SummaryProperties.Company = "lol";
doc.SummaryProperties.Author = "me";
//after making changes, you need to use this line to save them
doc.Save();
Windows Explorer (using shell32.dll) is able to display the extended properties because it understands a lot of different file formats and can parse these. However, to set an extended property you probably need a file format specific library. E.g. to set the author of an MP3 file file is very different compared to setting the author of an Office document. (Actually Windows Explorer allows you to set some extended properties on Office documents.)
The taglib-sharp only works with media files and is most likely not able to set extended properties of any other type of file.
What you need is a library or a tool you can automate to modify PDF files. You can try to google pdf sdk. If you also need to work with Word files you can use COM automation to automate Word. Depending on the Word file format used you may also be able to work directly with the file without having Word installed (XML being much easier than the old binary "streams" format).
To set properties, you could utilize Windows' Property System. It provides an interface for accessing the "Property Store Cache" (IPropertyStore) where you can read/set any file's properties (regardless of the format), and add your own custom properties (the c library propkey.h has a comprehensive list of all available properties; you can also find these using prop.exe). This is essentially creating a Property Handler that must be later registered to your file extension. It is officially unsupported in managed code, so you might either want to write your own wrapper or use c++ (since this is a c# tagged question).
If you're specifically asking for media properties, check out metadata handlers, which are essentially codecs that extract your properties from the file and also called by explorer by default if you register them correctly.