tags:

views:

560

answers:

1

I'm trying to create a MIME filter to do some custom processing of resources received with web pages before passing them to the web browser control in our Windows application. The application is written in C#, and I'd like to write the MIME filter in managed code as well, if possible. I'm having trouble with it though: my filter object doesn't seem to be getting called at all.

Here's my code. Sorry it's so long, but I think I might be defining something incorrectly in the COM interfaces, so I'm including those also. Any ideas what I'm doing wrong?

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("00000001-0000-0000-C000-000000000046")]
public interface IClassFactory
{
    void CreateInstance([MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, ref Guid riid, out IntPtr ppvObject);
    void LockServer(bool fLock);
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("79EAC9E4-BAF9-11CE-8C82-00AA004BA90B")]
public interface IInternetProtocol : IInternetProtocolRoot
{
    void LockRequest(Int32 dwOptions);
    [PreserveSig]
    Int32 Read(IntPtr pv, UInt32 cb, out UInt32 pcbRead);
    void Seek(Int64 dlibMove, UInt32 dwOrigin, out UInt64 plibNewPosition);
    void UnlockRequest();
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("79EAC9E3-BAF9-11CE-8C82-00AA004BA90B")]
public interface IInternetProtocolRoot
{
    void Abort(Int32 hrReason, Int32 dwOptions);
    void Continue(IntPtr pProtocolData);
    void Resume();
    void Start([MarshalAs(UnmanagedType.LPWStr)] string szUrl, IInternetProtocolSink pOIProtSink,
               IntPtr pOIBindInfo, UInt32 grfPI, IntPtr dwReserved);
    void Suspend();
    void Terminate(Int32 dwOptions);
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("79EAC9E5-BAF9-11CE-8C82-00AA004BA90B")]
public interface IInternetProtocolSink
{
    void Switch(IntPtr pProtocolData);
    void ReportProgress(UInt32 ulStatusCode, [MarshalAs(UnmanagedType.LPWStr)] string szStatusText);
    void ReportData(UInt32 grfBSCF, UInt32 ulProgress, UInt32 ulProgressMax);
    void ReportResult(Int32 hrResult, UInt32 dwError, [MarshalAs(UnmanagedType.LPWStr)] string szResult);
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("79eac9e7-baf9-11ce-8c82-00aa004ba90b")]
public interface IInternetSession
{
    void CreateBinding(); // Not Implemented
    void GetCache(); // Not Implemented
    void GetSessionOption(); // Not Implemented
    void RegisterMimeFilter([MarshalAs(UnmanagedType.Interface)] IClassFactory pCF, ref Guid rclsid, [MarshalAs(UnmanagedType.LPWStr)] string pwzType);
    void RegisterNameSpace([MarshalAs(UnmanagedType.Interface)] IClassFactory pCF, ref Guid rclsid, [MarshalAs(UnmanagedType.LPWStr)] string pwzProtocol,
                           UInt32 cPatterns, [MarshalAs(UnmanagedType.LPWStr)] string ppwzPatterns, UInt32 dwReserved);
    void SetCache(); // Not Implemented
    void SetSessionOption(); // Not Implemented
    void UnregisterMimeFilter(IClassFactory pCF, [MarshalAs(UnmanagedType.LPWStr)] string pwzType);
    void UnregisterNameSpace(IClassFactory pCF, [MarshalAs(UnmanagedType.LPWStr)] string pwzProtocol);
}

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("C3ED53DA-EC0E-4625-AB0C-9837D0D0D59D")]
public interface _MimeFilter : IClassFactory, IInternetProtocol, IInternetProtocolRoot, IInternetProtocolSink
{
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("C3ED53DA-EC0E-4625-AB0C-9837D0D0D59D")]
public class MimeFilter : _MimeFilter
{
    #region [ IClassFactory ]
    public void CreateInstance([MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, ref Guid riid, out IntPtr ppvObject)
    {
        ... // This is never called
    }

    ...
}

internal class FilterUtils
{
    /// <summary>
    /// Registers the MIME filter for the current process
    /// </summary>
    public static void RegisterFilter()
    {
        IInternetSession session = null;
        int status = NativeMethods.CoInternetGetSession(0, ref session, 0);
        MimeFilter mf = new MimeFilter();
        Guid id = new Guid("C3ED53DA-EC0E-4625-AB0C-9837D0D0D59D");
        session.RegisterMimeFilter(mf, ref id, "text/html; charset=UTF-8");
    }

    private static class NativeMethods
    {
        [DllImport("urlmon.dll")]
        public static extern int CoInternetGetSession(UInt32 dwSessionMode /* = 0 */, ref IInternetSession ppIInternetSession, UInt32 dwReserved /* = 0 */);
    }
}

As far as I can tell, the next thing that should happen is that the MimeFilter.CreateInstance() method should be called. It's not getting called, nor are any of the other methods in MimeFilter.

I'd appreciate any help anyone can offer. Thanks.

A: 

Turns out the MSDN documentation and Visual Studio 2008 disagree about default COM visibility. The MSDN documentation says that all .NET types are visible to COM by default, but the Visual Studio 2008 class library project template disables COM visibility in the AssemblyInfo.cs file.

Solution: remove the line

[assembly: ComVisible(false)]

from the AssemblyInfo.cs file.

I may have also had bad COM interface declarations. I've replaced them with the ones from this CodeProject document.

The only readable MIME filter sample code I've found is available here and (briefly) documented here.

Greg
Greg, could you post your updated sample - as you say, samples of MIME filters are pretty hard to come by. Thanks! Or add to http://stackoverflow.com/questions/1052871
Rory