November 23, 2014
Hot Topics:

Understanding Mobile Data Synchronization: Creating Custom File Filters

  • September 1, 2005
  • By Alex Gusev
  • Send Email »
  • More Articles »

This code sample follows the standard procedure:

  • Create source and destination streams via an ICeFileFilterSite instance passed in the pci->pffs parameter.
  • Subsequently read and write data.
  • Perform the desired conversion.
  • Report about operation's progress.
  • Close all streams.
  • Return ERROR_NO_MORE_ITEMS to indicate that conversion is completed.

Your filter may support one other interface, ICeFileFilterOptions. In this case, MS ActiveSync will be able to inform your filter whether or not to show the options dialog during file conversion. All this will cost you one additional simple method, SetFilterOptions, and HasOptions in the Registry:

HRESULT __stdcall CDat2LogFileFilter::SetFilterOptions
                  (CFF_CONVERTOPTIONS* pco)
{
   m_bShowOptions = pco->bNoModalUI;
   return S_OK;
}

After doing all this, your filter will be able to behave properly. I leave all additional details behind the scene, so you can take a closer look at the accompanying sample for all other details. For those of you who are mad about C#, let me drop a schematic C# class wrapping its C++ buddy (don't curse me for possible errors); I just like to illustrate the possibility) here:

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.ComponentModel;
namespace CSHFilter
{
   [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
                 GuidAttribute("6C5C05E1-97A2-11cf-8011-00A0C90A8F78")]
   public interface ICeFileFilterSite
   {
      uint OpenSourceFile(int nHowToOpenFile, ref UCOMIStream ppObj);
      uint OpenDestinationFile(int nHowToOpenFile, byte[] pszFullpath,
                               ref UCOMIStream ppObj);
      uint CloseSourceFile(ref UCOMIStream pObj);
      uint CloseDestinationFile(bool bKeepFile,ref UCOMIStream pObj);
      uint ReportProgress(uint nPercent);
      uint ReportLoss(uint dw, StringBuilder psz, System.ArgIterator args);
   };
   [StructLayout(LayoutKind.Sequential)]
   public struct csCFF_CONVERTINFO
   {
      public bool bImport;
      public uint hwndParent;
      public uint bYesToAll;
      public ICeFileFilterSite pffs;
   };
   [StructLayout(LayoutKind.Sequential)]
   public struct csCFF_DESTINATIONFILE
   {
      public byte[] szFullpath;
      public byte[] szPath;
      public byte[] szFilename;
      public byte[] szExtension;
   };
   [StructLayout(LayoutKind.Sequential)]
   public struct csCFF_SOURCEFILE
   {
      public byte[] szFullpath;
      public byte[] szPath;
      public byte[] szFilename;
      public byte[] szExtension;
      public uint cbSize;
      public double ftCreated;
      public double ftModified;
   };
   /// <summary>
   /// Summary description for Class1.
   /// </summary>
   [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
                 GuidAttribute("418C5FF2-DD1B-45d1-A160-A1A954832713")]
   public interface ICeFilter
   {
      [PreserveSig()]
      uint NextConvertFile(int nConversion,
                           ref csCFF_CONVERTINFO pci,
                           ref csCFF_SOURCEFILE psf,
                           ref csCFF_DESTINATIONFILE pdf,
                           ref int pbCancel,
                           ref long perr);
      [PreserveSig()]
      uint FilterOptions(uint hwndParent);
      [PreserveSig()]
      uint FormatMessage(uint  dwFlags,
                         uint  dwMessageId,
                         uint  dwLanguageId,
                         [MarshalAs(UnmanagedType.LPStr)]
                         String  lpBuffer,
                         uint  nSize,
                         System.ArgIterator Arguments,
                         ref uint  pcb);
   }
   // Class ComClass1
   [Guid("418C5FF2-DD1B-45d1-A160-A1A954832713"),
   ClassInterface(ClassInterfaceType.None),
   ComVisible(true)]
   public unsafe class CCeFilter : ICeFilter
   {
      public const int ERROR_NO_MORE_ITEMS = 259;
      public const int PF_OPENFLAT = 0;
      public const int PF_OPENCOMPOUND = 1;
      public const uint E_FAIL = 2417500037;
      public const uint ERROR_ACCESS_DENIED = 5;
      public const uint ERROR_CANCELLED = 1223;
      public uint HRESULT_FROM_WIN32(uint x)
      {
         if ( x <= 0 )
         {
            return x;
         }
         else
         {
            uint y = (x & 0x0000FFFF) | (7 << 16) | 0x80000000;
            return y;
         }
      }
      uint HRESULT_TO_CFERROR(uint hr, uint def)
      {
         if ( hr == 0 )
            return 0;
         else
         {
            if ( (((hr) >> 16) & 0x1fff) == 7 )
               return ((hr) & 0xFFFF);
            else
               return def;
         }
      }
      [DllImport("kernel32.dll", EntryPoint = "FormatMessageA",
                 CharSet=CharSet.Ansi,SetLastError=true)]
      static extern uint FormatMessageA(
            uint dwFlags, uint lpSource,
            uint dwMessageId, uint dwLanguageId,
            [MarshalAs(UnmanagedType.LPStr)] String lpBuffer,
            uint nSize,
            System.ArgIterator Arguments);
      public uint NextConvertFile(int nConversion,
         ref csCFF_CONVERTINFO pci,
         ref csCFF_SOURCEFILE psf,
         ref csCFF_DESTINATIONFILE pdf,
         ref int pbCancel,
         ref long perr)
      {
         UCOMIStream pstreamSrc = null;
         UCOMIStream  pstreamDest = null;
         ICeFileFilterSite pffs;
         uint cBytesRemaining = 0, cBytesRead = 0, cBytesWritten = 0;
         uint hr = 0;
         int nToRead = 0;
         uint ulTotalMoved = 0;
         byte [] pBuff = new byte[4096];
         ushort usUnicodeSig = 0xFEFF;
         // return if we're called not the very first time
         if (nConversion > 0)
            return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
         //if ( m_bShowOptions )
         FilterOptions(pci.hwndParent);
         pBuff.Initialize();
         // Get pointer to FileFilterSite interface.
         pffs = pci.pffs;
         // Open source file.
         hr = pffs.OpenSourceFile(PF_OPENFLAT, ref pstreamSrc);
         if ( 0 != hr )
         {
            perr = HRESULT_TO_CFERROR (hr, ERROR_ACCESS_DENIED);
            return E_FAIL;
         }
         // Open destination file.
         hr = pffs.OpenDestinationFile(PF_OPENFLAT, pdf.szFullpath,
                                       ref pstreamDest);
         if ( 0 != hr )
         {
            pffs.CloseSourceFile (ref pstreamSrc);
            perr = HRESULT_TO_CFERROR (hr, ERROR_ACCESS_DENIED);
            return E_FAIL;
         }
         cBytesRemaining = psf.cbSize;
         if ( pci.bImport )
         {
            pstreamDest.Write(BitConverter.GetBytes(usUnicodeSig),
                              2, (IntPtr)cBytesWritten);
            if ( cBytesWritten != 2 )
            {
               pffs.CloseSourceFile (ref pstreamSrc);
               pffs.CloseDestinationFile (true,  ref pstreamDest);
               perr = HRESULT_TO_CFERROR (hr, ERROR_ACCESS_DENIED);
               return E_FAIL;
            }
         }

         // Convert & Copy data.
         for (; cBytesRemaining > 0; )
         {
            if ( cBytesRemaining > 4096 )
               nToRead = 4096;
            else
               nToRead = (int)cBytesRemaining;

            pstreamSrc.Read (pBuff, nToRead, (IntPtr)(cBytesRead));
            if (cBytesRead == 0)
               break;
            if (pbCancel == 1)
            {
               hr = ERROR_CANCELLED;
               break;
            }
            // Create two different encodings.
            Encoding ascii = Encoding.ASCII;
            Encoding unicode = Encoding.Unicode;
            // Convert the string into a byte[].
            char[] chars = new char[cBytesRead];
            pBuff.CopyTo(chars,0);
            byte[] asciiBytes = ascii.GetBytes(chars,0,(int)cBytesRead);
            // Perform the conversion from one encoding to the other.
            byte[] unicodeBytes = Encoding.Convert(ascii, unicode,
                                                   asciiBytes);
            pstreamDest.Write (unicodeBytes, unicodeBytes.Length,
                               (IntPtr)cBytesWritten);
            if ( cBytesWritten == 0 )
               break;
            ulTotalMoved += cBytesRead;
            cBytesRemaining -= cBytesRead;
            pffs.ReportProgress (ulTotalMoved/psf.cbSize * 100);
         }
         // Perform some cleanup
         pffs.CloseSourceFile (ref pstreamSrc);
         pffs.CloseDestinationFile (true, ref pstreamDest);
         if (hr == ERROR_CANCELLED)
            return HRESULT_FROM_WIN32 (ERROR_CANCELLED);
         if ( 0 != hr)
         {
            perr = hr;
            return E_FAIL;
         }
         return 0;
      }
      public uint FilterOptions(uint hwndParent)
      {
         return 0;
      }
      public uint FormatMessage(uint  dwFlags,
                                uint  dwMessageId,
                                uint  dwLanguageId,
                                [MarshalAs(UnmanagedType.LPStr)]
                                String  lpBuffer,
                                uint  nSize,
                                System.ArgIterator Arguments,
                                ref uint  pcb)
      {
         pcb = FormatMessageA (
               dwFlags,
               0, dwMessageId, dwLanguageId,
               lpBuffer, nSize, Arguments);
               if (pcb == 0)
            return 0x80004005;
         return 0;
      }
   }
}




Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel