2010-01-06 8 views
3

En utilisant this comme référence, j'essaye de créer un protocole enfichable asynchrone qui est seulement temporairement disponible à mon application (et non enregistré à l'échelle du système). J'utilise CoInternetGetSession, puis en appelant le RegisterNameSpace pour le faire. Cependant, lorsque je fais l'appel à RegisterNameSpace, j'obtiens une exception AccessViolation: Attempting to read or write protected memory.Protocoles enfichables asynchrones

Une idée de ce qui se passe?

Mon code ressemble à ceci:

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

/* Custom class to act as a class factory that create's an instance of the protocol */ 
[Guid("0b9c4422-2b6e-4c2d-91b0-9016053ab1b1")] 
[ComVisible(true),ClassInterface(ClassInterfaceType.AutoDispatch)] 
public class PluggableProtocolFactory : IClassFactory 
{ 
    public Type AppType; 
    public PluggableProtocolFactory(Type t) 
    { 
     this.AppType = t; 
    } 
    public void CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject) 
    { 
     riid = ProtocolSupport.GetGuid(this.AppType); 
     IInternetProtocol p = Activator.CreateInstance(this.AppType) as IInternetProtocol; 
     ppvObject = Marshal.GetComInterfaceForObject(p, typeof(IInternetProtocol)); 
    } 

    public void LockServer(bool fLock) 
    { 
     var b = fLock; 
    } 

} 

[ComVisible(true)] 
[ComImport] 
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
[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.LPArray,ArraySubType=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(false)] public interface IComRegister 
{ 
    void Register(Type t); 
    void Unregister(Type t); 
} 

[ComVisible(false), AttributeUsage(AttributeTargets.Class, AllowMultiple=true) ] 
public class AsyncProtocolAttribute : Attribute, IComRegister 
{ 
    public string Name; 
    public string Description; 

    [DllImport("urlmon.dll",PreserveSig=false)] 
    public static extern int CoInternetGetSession(UInt32 dwSessionMode /* = 0 */, ref IInternetSession ppIInternetSession, UInt32 dwReserved /* = 0 */); 

    public void Register(Type t) 
    { 
     IInternetSession session = null; 
     CoInternetGetSession(0, ref session, 0); 
     Guid g = new Guid("79EAC9E4-BAF9-11CE-8C82-00AA004BA90B"); 
     session.RegisterNameSpace(new PluggableProtocolFactory(t), ref g, this.Name, 0, null, 0); 

    } 

La méthode CreateInstance dans PluggableProtocolFactory ne sera jamais appelé. (Un point d'arrêt ne sera jamais atteint), donc quelque chose d'autre se passe dans la méthode RegisterNameSpace.

J'ai essayé d'exécuter à la fois en tant qu'administrateur et un utilisateur normal. Même erreur dans les deux cas.

+0

Serait-il possible de coller une mise à jour comprend des échantillons de vous en utilisant votre attribut 'AsyncProtocolAttribute' sur une classe? J'ai essayé de mettre en œuvre le même paradigme de «gestionnaire de protocole temporaire» mais j'ai vu votre travail et je suis intrigué par votre méthode d'attribut. – Codesleuth

+0

J'ai basé mon code sur ceci: http://www.codeproject.com/kb/aspnet/AspxProtocol.aspx Qui a un plein échantillon fonctionnant. –

+0

@HS Merci pour la réponse, j'ai utilisé la même ressource pour construire un exemple de projet de base pour mon plus grand projet. Je reçois une erreur cependant, et puisque vous avez le vôtre fonctionnant je me demandais si vous pourriez éclairer ceci: http://stackoverflow.com/questions/3062642/feeding-pdf-through-iinternetsession-to-webbrowser -control-error – Codesleuth

Répondre

0

OK, figured it out: La déclaration de l'interface IInternetSession était faux:

est ici un meilleur je pris de monoblog:

[ComVisible(true), Guid("79eac9e7-baf9-11ce-8c82-00aa004ba90b"),InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IInternetSession 
{ 
    [PreserveSig] 
    int RegisterNameSpace(
     [In] IClassFactory classFactory, 
     [In] ref Guid rclsid, 
     [In, MarshalAs(UnmanagedType.LPWStr)] string pwzProtocol, 
     [In] 
      int cPatterns, 
     [In, MarshalAs(UnmanagedType.LPWStr)] 
      string ppwzPatterns, 
     [In] int dwReserved); 

    [PreserveSig] 
    int UnregisterNameSpace(
     [In] IClassFactory classFactory, 
     [In, MarshalAs(UnmanagedType.LPWStr)] string pszProtocol); 

    int Bogus1(); 

    int Bogus2(); 

    int Bogus3(); 

    int Bogus4(); 

    int Bogus5(); 
} 
0

Vous appelez le constructeur de votre PluggableProtocolFactory dans votre méthode RegisterNameSpace, mais pas la méthode CreateInstance. Je pense que c'est là où réside votre problème, il n'y a jamais une instance de IInternetProtocol en cours de création pour être passée à votre méthode.

+0

La méthode RegisterNameSpace prend un IClassFactory comme premier paramètre. Je suppose que la méthode RegisterNameSpace appelle CreateInstance lui-même lorsqu'il est prêt à le faire? N'est-ce pas le but d'une interface ClassFactory? –

+0

Non, il ne l'appellera pas par lui-même, vous devez l'appeler dans le constructeur de PluggableProtocolFactory ou l'appeler dans votre méthode Register. Vous devriez revoir ce qu'est une interface et ce qu'elle fait. –

+0

L'intérêt d'avoir une interface est que la méthode consommatrice puisse l'utiliser. Si la méthode consommatrice ne va pas l'utiliser, pourquoi serait-il nécessaire de le déclarer dans l'interface? Désolé, cela n'a aucun sens. Voici une expérience de réflexion: Disons que j'appelle CreateInstance manuellement. Quels paramètres devrais-je lui transmettre? Que ferais-je avec la valeur qu'elle renvoie? Comment RegisterNameSpace en ferait-il usage? Et si RegisterNameSpace ne s'en sert pas, alors en quoi cela serait-il important si je l'appelais ou pas? –