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.
Related
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.
I've working on a project where I'm using ResourceManager extensively and this question just crossed my mind.
Can we read from .resx files without using ResourceManager? I mean, is there another way?
ResourceManager is a convenience class, it works very well with the way the build system supports .resx files. No, it is not a strict necessity.
A .NET assembly has the generic capability of embedding arbitrary data into the manifest of the assembly. Just a blob of bytes, it can be anything you want. Directly supported by the build system as well, just add a file to your project and set its Build Action to "Embedded Resource". At runtime, you retrieve the data in that file with Assembly.GetManifestResourceStream().
You can stop right there, but that's just a single file, it doesn't scale very well if you have many small resources you want to embed. Which is where a .resx file starts, it is an XML file that contains resources in a friendly format. One that gives you a fighting chance to recover the source again when the original got lost.
But an XML format is not a very good format for resource data, it is bulky and it is expensive to find data back. So .NET has resgen.exe, a build tool that turns the XML file into a binary file, a .resources file. Compact and easy to find stuff back. And fit to be embedded directly as a single manifest resource.
What you don't want to do is having to read the .resources data yourself. You'll want to use a helper class that can find specific resources back from the blob of bytes. You want use the ResourceReader class, its GetResourceData() lets you specify the resource name and it will spit the resource type and data back out.
You can stop right there, but an app often has a need for different sets of resources. A very common localization need. Which is what satellite assemblies are all about, different assemblies that contain nothing but resources, each for a specific culture. They are separate so you don't pay for the virtual memory that's required to store all the localized resources when you need only one set of them. What's needed here is a helper class that automatically locates and loads the correct satellite assembly and retrieves the resource for you, based on the current culture.
That helper class is ResourceManager.
If you choose to skip the use of the ResourceManager you can let Visual Studio handle code generation for you. Ultimately the generated code uses a ResourceManager, but you're no longer writing that code manually. Additionally, you get compile-time checking since you're referencing a generated static class.
If you add a resource file to your project and double click it from the Solution Explorer, Visual Studio presents you with a dialog where you can enter a name for a resource, and its value. The dialog presents you with options to add resources as strings, images, audio, etc. (look at the dropdowns at the top of the dialog). Next, to get the code generation bit, you need to set the Access Modifier to either "Public" or "Internal". The third option is "No code generation."
For example, add a resource file called "MyResources", then add a string resource with the name Greeting and a value of Hello! With one of the former two options selected for code generation (start off with public to test it, restrict the access as needed), you should now be able to reference the resources from your code via MyResources.Greeting. If you don't see it right away, make sure you've saved the file and try compiling.
string greeting = MyResources.Greeting; // "Hello!"
If you add other resource types (image, audio, etc.) then the return types will differ, of course.
At this point you could inspect the generated .cs file and see that the generated code is using a ResourceManager. The other use for resource files is localization. Let's say you wanted a Spanish version of MyResources. You would add a new file called MyResources.es.resx, where es corresponds to the language code desired (Spanish in this case). Now add the same resource name of Greeting with a Spanish value of Hola!.
If you change the thread culture to Spanish, referencing the resource will now return the Spanish version:
string defaultGreeting = MyResources.Greeting; // "Hello!"
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("es");
string spanishGreeting = MyResources.Greeting; // "Hola!"
Note that you only really need to set the access modifier to one of the code generation options for your default resource file (i.e., MyResources.resx), not for all the other localized versions you add. There's no harm in doing so, but in my opinion it's cleaner to have the main file generated while the others just have the resource values desired without code generation.
Well, Resources are compiled into the assembly. You could try to read the assembly by reading the bytes (or the IL), and extract the resources from there.
ResourceManager does this all for you, so I could not think of any reason you want to do this... Maybe one, if you don't want to load the assembly in memory, you could do it without ResourceManager.
Ref Microsoft: Represents a resource manager that provides convenient access to culture-specific resources at run time.
I expect, I'd you use multi Lang, you will get a more consistent result and better compatibility.
IMHO
I want my program to be associated with a custom file type so that clicking on a file of that type will open it with my program.
I've seen I can do that by: Properties->Publish->Options->File associations. But I don't know what I should enter as ProgID.
From Wikipedia it seems it's some long number (is there a specific way of choosing it?). From an answer here it seems it's just anything I want.
Just fire up regedit.exe and see how other programs do it. The progids are listed in the HKEY_CLASSES_ROOT. The (Default) value of a filename extension key in the list you see there is the progid associated with the extension. Some common samples:
.dll = "dllfile"
.exe = "exefile"
.ico = "icofile"
.txt = "txtfile"
You see the pattern. It isn't required that it looks like this, just a convention. "YourCompany.YourFileType" is fine as well with the advantages of it being more descriptive and avoiding name collisions.
Is there a standard way in .Net to access and modify the windows services file? Right now I'm just accessing the file via a stream and writing to the file like I would for any other file. The file is located in c:\windows\system32\drivers\etc\, but I'm worried that this may change in 64 bit versions of Windows or may vary in different versions of Windows (I could be wrong and admittedly, I haven't looked into this very much yet). Aside from that, I'm just wondering if there is a standard way, say via WMI and/or the System.Management namespace, to find and modify the services file.
The actual specifics of what I need to do is to check if certain database aliases used for our software are specified for the expected ports. If not, add them.
An open source project called System.Peppers has a class doing this.
There is a registry key that contains the full path to the files you are editing.
Here is a link to the exact class: HostFile class
Use the System.Management.Instrumentation namespace
Sample code here
http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=114
you can use System.Environment.SystemDirectory to get to the sys32 folder
I need to extract some bitmaps from an .msstyles file (the Windows XP visual style files) and I'm not sure where to start. I can't seem to find any documentation on how to do it, and the file format seems to be binary and not easily parsed. I have been able to extract the bitmap by itself using:
IntPtr p = LoadLibrary(UxTheme.ThemeName);
Bitmap bmp = Bitmap.FromResource(p, "BITMAP_NAME");
FreeLibrary(p);
However, I also need the information related to the bitmap, like the margin sizes, spacing and number of "images" per bitmap. Does anyone have any experience with this or any links to documentation that I can use?
This site claims the file format is documented though not by Microsoft.
Also found this in the Wine Crossreference.
Hope that helps!
If you want to get files out of a dll directly (remember, msstyles are dlls with another extension), you could have a look at the Anolis Project.
As for actually parsing that stuff you should look at the various tutorials on creating msstyles for information on how the various text resources in that file work.
This codeproject article seems to have exactly what you want, with a little interop involved. A managed wrapper exists and it seems rather good. The .Net WindowsForms also has the functionality built in, you might want to look at the System.Windows.Forms.VisualStyles namespace if you want simplified read only access.
You can open the msstyles using 7-zip, install it, then right click the msstyles > 7-zip, ther's 2 open inside, one as a normal button and the other with a arrow, choose the second one, then select "#"
You're now inside the msstyles, now right click to 1..mst > Open inside
You're inside the actual theme now, now just extract it's resources
Image of the msstyles open (is in spanish tho)