2017-09-26 8 views
0

VS 2017 définit cette interface dans Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime.dll:Lors de la définition d'une interface COM Visual Studio en C#, quels attributs de classe/méthode/paramètre dois-je utiliser?

[Guid("A459C228-5617-4136-BCBE-C282DF6D9A62")] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IVsSolutionEvents7 
{ 
    void OnAfterCloseFolder(string folderPath); 
    void OnAfterLoadAllDeferredProjects(); 
    void OnAfterOpenFolder(string folderPath); 
    void OnBeforeCloseFolder(string folderPath); 
    void OnQueryCloseFolder(string folderPath, ref int pfCancel); 
} 

Je veux mettre en œuvre cette interface dans mon extension afin que je puisse répondre à ces événements, mais je veux le même assembly d'extension pour être compatible avec Visual Studio 2015, donc je ne veux pas de dépendance sur cette DLL VS 2017. Par conséquent, je copier-coller cette définition dans mon code.

Je peux obtenir cette définition à partir de la documentation, ou à partir de Visual Studio lui-même via F12 lorsque j'ajoute une référence à cette DLL, ou à partir de JustDecompile. Ils donnent tous à peu près la même définition de l'interface.

Mais cette définition de l'interface ne fonctionne pas:

  • Les méthodes sont dans le mauvais ordre, de sorte que des résultats erronés s'appellent.
  • Les chaînes ne sont pas transmises correctement - je suppose qu'elles sont supposées être des BStr mais ce sont des LPWStrs.
  • Je reçois souvent une violation d'accès après un appel - ma conjecture est une convention d'appel incorrecte.

Si je demande un tas d'attributs à l'interface, il devient ceci:

[ComVisible(true)] 
[ComImport] 
[Guid("A459C228-5617-4136-BCBE-C282DF6D9A62")] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IVsSolutionEvents7 
{ 
    [PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 
    int OnAfterOpenFolder([In, MarshalAs(UnmanagedType.LPWStr)] string folderPath); 
    ... 

et mettre les méthodes dans l'ordre, il fonctionne.

Comment êtes-vous censé savoir lequel de ces attributs utiliser ou dans quel ordre placer les méthodes? La documentation n'est pas nécessairement utile - le documentation for that interface, par exemple, n'ajoute rien à la définition brisée simple ci-dessus.

Même lorsque j'ai accès à un assembly qui définit l'interface (Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime.dll dans ce cas), où vont ces attributs? Quand je regarde la définition dans cette DLL dans Visual Studio ou JustDecompile, je vois seulement cette définition simple, et pourtant si j'utilise l'interface via une référence à cette DLL, cela fonctionne. Les attributs sont en quelque sorte là, mais invisibles, ou sont définis différemment de quand je définis moi-même l'interface. J'ai bricolé ensemble les attributs que j'utilise de la copie culte de la cargaison, en examinant l'IDL, et en essayant aveugle et erreur, et en tant que tel, je ne leur fais pas vraiment confiance. Comment aurais-je dû le faire?

Répondre

2

Il est juste que JustDecompile fait un mauvais travail ici. D'autres outils tels que DotPeek, DnSpy et Reflector (commercial) semblent tous fonctionner correctement. Visual Studio F12 n'est utile que parce qu'il est intégré, mais inutile pour interop.

Une autre option consiste à utiliser les fichiers C/C++/H/IDL lorsqu'ils sont disponibles. L'IDL est disponible ici <programfiles>Microsoft Visual Studio\2017\<sku>\VSSDK\VisualStudioIntegration\Common\IDL\vsshell150.idl et le fichier d'en-tête résultant .h ici <programfiles>Microsoft Visual Studio\2017\<sku>\VSSDK\VisualStudioIntegration\Common\inc\vsshell150.h

Ils sont la loi. En cas de doute, référez-vous à l'un d'eux (je préfère le.h, le niveau binaire le plus bas).

C'est ainsi IVsSolutionEvents7 est défini dans le fichier .h:

MIDL_INTERFACE("A459C228-5617-4136-BCBE-C282DF6D9A62") 
IVsSolutionEvents7 : public IUnknown 
{ 
public: 
    virtual HRESULT STDMETHODCALLTYPE OnAfterOpenFolder( 
     /* [in] */ __RPC__in LPCOLESTR folderPath) = 0; 

    virtual HRESULT STDMETHODCALLTYPE OnBeforeCloseFolder( 
     /* [in] */ __RPC__in LPCOLESTR folderPath) = 0; 

    virtual HRESULT STDMETHODCALLTYPE OnQueryCloseFolder( 
     /* [in] */ __RPC__in LPCOLESTR folderPath, 
     /* [out][in] */ __RPC__inout BOOL *pfCancel) = 0; 

    virtual HRESULT STDMETHODCALLTYPE OnAfterCloseFolder( 
     /* [in] */ __RPC__in LPCOLESTR folderPath) = 0; 

    virtual HRESULT STDMETHODCALLTYPE OnAfterLoadAllDeferredProjects(void) = 0; 

}; 
+0

Merci, oui, j'ai utilisé l'IDL comme une de mes sources. Mais qu'est-ce que, par exemple, MethodImplOptions.InternalCall se rapportent dans l'IDL? (Si ce n'est pas dans l'IDL, mais présent dans le .h comme STDMETHODCALLTYPE, la même question s'applique - comment reliez-vous l'un à l'autre?) – RichieHindle

+0

Et merci pour le pointeur vers dotPeek - qui a immédiatement remplacé JustDecompile dans ma boîte à outils! Je n'avais aucune idée que JustDecompile abandonnerait discrètement des attributs comme ça. – RichieHindle

+0

STDMETHODCALLTYPE est une macro Windows C qui applique fondamentalement la convention d'appel '__stdcall' sur une méthode. Il est implicite du côté .NET pour les méthodes Platform Invoke, vous n'avez donc pas besoin de l'ajouter. InternalCall n'est pas la même chose, c'est lié à la façon dont le CLR va implémenter tout cela, mais vous pouvez oublier cet attribut. –

1

Il suffit d'utiliser Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll, toutes les version plus récente VS ont réoriente liaison

+0

Mais quand j'ajoute une référence à Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll plutôt que .15, je peux. Ne voyez pas IVsSolutionEvents7 ("Le nom du type ou de l'espace de nom n'a pas pu être trouvé"). – RichieHindle

+0

Ces événements prennent en charge une fonctionnalité disponible uniquement dans VS 2017! https://docs.microsoft.com/en-us/visualstudio/extensibility/lightweight-solution-load-extension-impact – ErikEJ

+0

"Je souhaite implémenter cette interface dans mon extension pour pouvoir répondre à ces événements, mais je veux le même assembly d'extension pour être compatible avec Visual Studio 2015 " – RichieHindle