I wrote a batch program which opens and changes MS Word and Excel files. However, if an input file is password...
protected, the password dialog comes up and my program is stuck. Can you tell me how to either find if a file is password protected without opening it, or how to open it so that it will just fail, without bringing the dialog?
This looked easy. Really it did. I figured ten minutes to figure it out, ten to test the solution then ten to write it up. I'd have plenty of time to read /. and eetimes tonight before calling it quits. Starting with the obvious, you'd figure that there'd be some help from the Word/Excel automation objects here. But as you already know you've got a chicken and egg problem with password protection. If you need to open the doc with an application to inspect whether you can open the doc, then you have a problem.
It'd be possible to brute-force this thing and just handle smashing the dialog pop and ignoring those, but in general this is not what you want to do. I don't know the word automation landscape completely so I don't know if there is a good way to silence the dialog. It wasn't clear to me how to do it and, anyway, there is a right way to do this so we should consider that.
Office documents are special types of compound files. They contain lots of stuff, including the document but also things like macros, checksums and other file properties. Microsoft invented a special format for this purpose, essentially implementing a file system within a file called OLE Structured Storage. This format was a key piece of the Object Linking and Embedding (OLE) system and it was adopted across the whole Office product line to support heterogeneous file content.
Your problem is how to manipulate structured storage from a .Net application. Surprisingly, when you go look for .Net support, you don't find any (we'll come back to this). Without .Net native support, the next best thing would be a COM utility object that helped manipulate these documents. Well, there is an unsupported object from Microsoft but it is incomplete and cannot retrieve all the properties. Of course, as Murphy predicts, one of the missing properties from the utility object is the document security property (the one that tells you if the file is password protected). Stepping down a level, you'll find that there are OLE32 interfaces that are well documented and for which there is plenty of sample C++ sample code. If you build the samples you find out pretty quickly that you're looking for the Document Security property of your document and that it's easily retrievable in good-ole unmanaged C++ land.
So now we're back to .Net support for structured storage. Unfortunately, we're faced with the not-so-pleasant task of wrapping the OLE32 calls so that you can conveniently use them in your VB.Net code. Fortunately, you get a break here! There are no less than three implementations that I found on the web that wrap the structured storage interfaces for use in .Net applications. Two are OSS and one is commercial software. I came across software at the following site that implements a set of useful wrappers (http://www.domaindlx.com/e_morcillo/scripts/cod/net.asp). As with anything you drag in from the Web, use at your own risk. I don't know these people nor do I recommend them, vouch for them, yadda, yadda, yadda. They provide source for your perusal and there's really no magic here just a bunch of (much appreciated!!) grunt work to make the interfaces useful in .Net applications. If it's interesting to people, we can investigate how to implement your own wrappers for native APIs in more detail in another article but for now, let's just get your problem solved.
If you use the library referenced in the URL above, the snippet of code below performs the query that you want. Note that this is a VB.Net console application and all error handling has been removed so you can see what's going on.
Click here to view part two of this answer.