2010-06-01 2 views
5

Sto cercando di capire quale sia il motivo corretto per implementare le interfacce COM dal codice C#. È semplice quando l'interfaccia non eredita da un'altra interfaccia di base. Come questo:Come dichiarare e implementare un'interfaccia COM su C# che eredita da un'altra interfaccia COM?

[ComImport, Guid("2047E320-F2A9-11CE-AE65-08002B2E1262"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IShellFolderViewCB 
{ 
    long MessageSFVCB(uint uMsg, int wParam, int lParam); 
} 

Tuttavia le cose cominciano a diventare weired quando ho bisogno di implementare un'interfaccia che eredita da altre interfacce COM. Ad esempio, se io implementare l'interfaccia IPersistFolder2 che eredita da IPersistFolder che eredita da IPersist come faccio di solito in codice C#:

[ComImport, Guid("0000010c-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IPersist 
{ 
    void GetClassID([Out] out Guid classID); 
} 

[ComImport, Guid("000214EA-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IPersistFolder : IPersist 
{ 
    void Initialize([In] IntPtr pidl); 
} 

[ComImport, Guid("1AC3D9F0-175C-11d1-95BE-00609797EA4F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IPersistFolder2 : IPersistFolder 
{ 
    void GetCurFolder([Out] out IntPtr ppidl); 
} 

Il sistema operativo non è in grado di chiamare i metodi su mia implementazione oggetto. Quando eseguo il debug, posso vedere che il costruttore della mia implementazione IPersistFolder2 viene chiamato più volte, tuttavia i metodi di interfaccia che ho implementato non vengono chiamati. Sto attuazione del IPersistFolder2 come segue:

[Guid("A4603CDB-EC86-4E40-80FE-25D5F5FA467D")] 
public class PersistFolder: IPersistFolder2 
{ 
    void IPersistFolder2.GetClassID(ref Guid classID) { ... } 
    void IPersistFolder2.Initialize(IntPtr pidl) { ... } 
    void IPersistFolder2.GetCurFolder(out IntPtr ppidl) { ... } 
} 

Ciò che sembra strano è quando dichiaro le importazioni di interfaccia COM come segue, funziona:

[ComImport, Guid("0000010c-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
internal interface IPersist 
{ 
    void GetClassID([Out] out Guid classID); 
} 

[ComImport, Guid("000214EA-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
internal interface IPersistFolder : IPersist 
{ 
    new void GetClassID([Out] out Guid classID); 
    void Initialize([In] IntPtr pidl); 
} 

[ComImport, Guid("1AC3D9F0-175C-11d1-95BE-00609797EA4F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
internal interface IPersistFolder2 : IPersistFolder 
{ 
    new void GetClassID([Out] out Guid classID); 
    new void Initialize([In] IntPtr pidl); 
    void GetCurFolder([Out] out IntPtr ppidl); 
} 

Non so perché funziona quando ho dichiarare le interfacce COM in questo modo (nascondendo i metodi dell'interfaccia di base usando new). Forse è legato al modo in cui IUnknown funziona. Qualcuno sa qual è il modo corretto di implementare le interfacce COM in C# che eredita da altre interfacce COM e perché?

+0

Votare l'utente per avermi mostrato come "importare" IPersist. http://stackoverflow.com/questions/1253368/c-get-progid-from-com-object lo utilizza ma non menziona come aggiungere un riferimento ad esso. –

+0

Mi sono imbattuto nello stesso problema e sono riuscito a risolverlo utilizzando la parola chiave "nuova". Grazie anche a @Hans Passant :) –

risposta

3

Trucchi accurati con la nuova parola chiave, che risolverebbero il problema. Il problema qui è che COM non supporta l'ereditarietà. È semplicemente la convenienza notazionale in IDL per farla sembrare come fa. In realtà, un'interfaccia v-table deve aggregare tutte le interfacce di base "ereditate". In altre parole, per l'interfaccia IPersistFolder è necessario replicare gli slot v-table per i 3 metodi IUnknown e il metodo IPersist :: GetClassID. Il CLR si prende cura di IUnknown btw.

La tabella v che .NET build non è compatibile con questo layout, non replica gli slot dei metodi della classe base.