Introduction & Background
For the last two weeks, I was searching the whole web looking for something that will let me easily determine the width/height and version of Flash SWF files. Needless to say, there wasn't any!! At least I didn't find any... Then I said - "OK, then I'll make one!" So, I decided I wanted to develop something that will add the required information to the 'Summary' tab when looking at the properties of an SWF file. But I searched and searched, and did not find any idea of how to do what I wanted.
Just two hours ago, I found this amazing article on CodeProject: The Complete Idiot's Guide to Writing Shell Extensions - Part V. I started immediately to combine Michael Dunn's code with my SWF code (included in my project). The result is exactly what I wanted. (Well, I made it, so why wouldn't it?) I hope you guys/gals enjoy it as I do!
Note 1: My SWF Header Reader code is something I wrote ages ago, and it works on Flash SWF version 1-10... It supports decompressed SWFs too!
Note 2: Because my SWF reader uses ZLIB (only a compacted version), it may be necessary to include some license agreement regarding ZLIB to the project. Right now, I don't know anything about ZLIB licensing.
Note 3: If you are interested in understanding the SWF specs - go to http://www.adobe.com/devnet/swf/pdf/swf_file_format_spec_v10.pdf.
Using the Code
Actually, I do not have the time to sit and explain the whole code. So, I'll assume that you are either an expert developer or someone who is not interested in the sources. If you want to understand how the Shell Extension mechanism works, take a look at Michael Dun's article here.
Attached to the article are two files:
- A zipped installation, which includes an INF with the DLL. Just right click the INF -> Install, and it will be ready!
- A zip file with the whole sources, including a compiled DLL and the installation INF.
The INF file adds a line to your Add/Remove Programs in Control Panel, so you could easily remove it (why would you want to do that?). It copies the DLL to the ShellExt folder in System32, where it should be. For those who like RegSvr32 - it works with it too, so you don't really need the INF, but it's nice
OK, so how did I do that?
The first thing is to use Visual Studio's wizard to create a new ATL application with COM support, because all Shell extensions are based on the COM technology. Now, you Add->Class->ATL COM Component, and name it... You now have the COM component that your DLL needs to call on the DLL entry point. (See the
OBJECT_ENTRY macros in my code.)
According to MSDN (http://msdn.microsoft.com/en-us/library/cc144106(VS.85).aspx), you have to make that COM component implement two additional interfaces:
IShellExtInit has one important function:
Initialize. That is when the shell passes the names of the file(s) in question.
IShellPropSheetExt has two important functions to implement:
ReplacePages is not being called, so we just return
AddPages is the important one: that is where you add the Property Page(s).
Basically, what I do in my code is this: iterate over all the filenames, and keep only those with an SWF extension. If there is only one, add a property page for it with an "SWF Summary" caption. If there's more than one, add a page for each one with the name of the file.
If you want more details about the code - you should either dive into the code (the best option), or read Michael Dunn's article (great too!). My code (the part relating to the Shell extension) is largely based on Michael Dunn's code, and most of his comments are still in there!
Now to the Registry part(!):
In the Registry, most of the connections between files/programs/handlers are stored in
Basically, each extension has its key (like a folder) in the
HKEY_CLASSES_ROOT. And each extension's key points to another key which contains information about what context menu items it will have, and what default program to associate with it, and of course, Property Sheet Handlers.
If you will open REGEDIT.EXE and go into
HKEY_CLASSES_ROOT, you'll find the .swf key there, and the main value in it is the "Default Value", which most of the time has the value of "
ShockwaveFlash.ShockwaveFlash" is actually the name of another key, which contains information about the Flash Player application, so .swf will be run with the Flash Player.
Now, go look at
HKEY_CLASSES_ROOT\ShockwaveFlash.ShockwaveFlash. You will find that there is a key inside name "
shell", which contains most of the context menu items (e.g., Open, Edit...). What we want in there is actually the "
shellex" key, which is not there by default.
shellex key contains two keys: "
PropertySheetHandlers" and "
ContextMenuHandlers" is the key that manages the Context Menu Handlers which are DLLs and not direct .EXE associations.
PropertySheetHandlers" is the key responsible for the property pages inside the File Properties dialog.
To add a COM handler inside "
PropertySheetHandlers", you just create a key named with the CLSID of that COM handler, or a CLSID with another name of your choice, but with the default value containing the CLSID.
There are two other special keys inside
HKEY_CLASSES_ROOT: "*" and "Folder" - Folder is a global key which is responsible for the handlers for all the folders. * is a global key relating to all of the files (not folders)!
So, if we want to handle .bmp and .gif, we don't have to add our handler inside .bmp's key and .gif's key, but only in * (and filter the extensions in our DLL's code).
Actually, there is another problem with using the individual extensions' keys anyway: when you want to install an extension, you have to lookup the .extension key's default value, and follow it to the real key where the work is done. If someone then installs another program which points the .SWF to another key, then our handler is registered in the wrong place and will not be used...
So, the solution is to just use the */Folder keys. And this is what I did, because this way, you can make sure that the handler is always being called.
By the way - Imagine that there are 20 handlers in the * key, which are called all the time, and check file extensions or formats in order to determine if they should display information or not. This situation can be a giant bottleneck for Windows... Actually, most of Windows' bottlenecks are such cases where too many DLLs are being loaded with no real reason. So, what I want to say here is this:
- If you think you could be satisfied with registering the handler within an individual extension's key instead of the global "*" key, then go for it!
- If you like cleaning up your Windows Registry, check out the * and Folder keys to make sure you don't have too many handlers that you don't really need. It can be very annoying if you right-click a file or folder and it takes ages to show the context-menu... But be careful not to remove the important ones... (like the default 'Summary' property sheet for files, or the default 'OpenWith' ContextMenuHandler for files...).
OK, have fun!
Points of Interest
It is interesting that Macromedia and Adobe did not come up with this one until today!!!
Well, this is the first version, and hopefully, there are no bugs, and therefore this is the last version too
Update: I have added a x64 version too, and I have updated the sources package, and there's also a package ready to install for both x86 and x64.