Background
I have been working on a project which reads and displays HXS and CHM help files on a Pocket PC with .NET Compact Framework installed. An old version of this program (CHM Reader) was posted here at Code Project. On my web site, I have a more up to date version of the CHM Reader program. While working on the new version, I had an idea. Once a help file has been opened and decoded, why not save that data to a file so that all that processing does not have to be done each time the file is opened. Then, I thought it would be even better if this pre-processing takes place on the PC instead of Pocket PC because of the extra processing power of the PC. I thought it would be a good idea if pre-processing takes place while the user copies the help files from the PC to the Pocket PC � and so the search to find out how to write an Active-Sync File Filter in C# began.
Notes
- I will not explain the working of active-sync file filter as this is documented in MSDN. (Search for Active-Sync File Filter.)
- The code for the
HelpFileFilter
is only intended as a guide and will not compile as I have not included all the libraries that I use to make my file filter.
- This code has been tested only on Active-Sync 3.7.1.
The projects
The solution files included with this project include a basic test program to test the C# code and the file filter code.
The Active-Sync File Filter project builds a DLL class library which performs all the processing on the file as it copies. This DLL basically creates a COM object that the Active-Sync manager will load and call when the defined file types are to be copied to/from the Pocket PC. Because of this, the DLL needs to be installed into the GAC when you install your application.
The interface
At the very core, the Active-Sync File Filter is the COM interface which makes it all work, it is here where I had the most trouble getting the C# interop code to match the COM definitions. The interfaces are all defined in Interfaces.cs (what a surprise!) I am not totally convinced that I have all the bugs out if it, but what I do have seems to work without any errors.
IceFileFilter
is the main interface. It has three methods and the most important one is the 'NextConvertFile
'.
int NextConvertFile(int nConversion, ref CFF_CONVERTINFO pci,
ref CFF_SOURCEFILE psf, ref CFF_DESTINATIONFILE pdf,
ref bool pbCancel, ref Int32 perr)
nConversion
� This is an index value which determines the number of times this function is called for current file copy. (You can copy multiple files and class it as a single operation.)
pci
� This is a structure which contains information about file copy. (Pocket PC to PC or PC to Pocket PC, a hWnd to the parent app, a flag bYesToAll, and pointer to IceFileFilterSite
object. This object allows you to open and close files on source and target files and report progress.)
psf
� This is a structure which contains the source file name.
pdf
� This is a structure which contains the target file name.
When a file is to be copied, this method is called with nConvertsion =0
. You can then detect this and perform any operation that you like to init your code. When I pre-process the help files it is when nConversion =0
where the help files are loaded and processed, and some extra files get created. I also create a list of files which need to be copied. I then return RESULT.NOERROR
. This tells Active-Sync to continue copying the file, and the function is called again with nConversion=1
. It is here I copy the files in my list from the source location to the target location.
Note: These file locations are not on the Pocket PC, but virtual locations. The file transfer gets performed from within Active-Sync code.
If all the files have been copied, I return HRESULT.E_ERROR_NO_MORE_ITEMS
.
Other notes
Here are some notes on the other methods that are included in the interfaces. These methods do not get called, or if they do, they do not have any effect on the conversion process.
IceFileFilterOptions.SetFilterOptions
- Set options for conversion but options ignored.
IceFileFilter.FilterOptions
- Never called.
IceFileFilter.FormatMessage
- Never called.
The final bits
There are a few bits left over:
- You need to declare your DLL as strongly named DLL, so you need to specify:
[assembly:
AssemblyKeyFile(@"..\..\HelpFileFilter.snk")]
- You need to make your class COM visible:
[ ProgId("MSHelReader.CHMPreProcessor"),
Guid("B424CF38-10C0-46ec-A29C-8F78A5990B5F")]
Class CMyFileFilter : ICeFileFilter, ICeFileFilterOptions
{....
}
- You need to specify COM Register and COM UnRegister functions so that you can add/remove the registry information which maps your file filter to Active-Sync.
- The ActiveSync test project is a small C++ project which allows you to create and play with the file filter COM objects when they are called, and to test your code.
Details of the new version of PPCHelpReader which can read both HXS and CHM help files can be found here.