2009-06-03 11 views
12

J'ai besoin de compiler du code en utilisant le compilateur gcc inclus dans les outils R (R le programme statistique pour Windows), le problème est que j'ai besoin d'utiliser IDispatch dans mon code pour créer un accès aux méthodes d'un objet COM, et le compilateur gcc ne supporte pas une grande partie du code que j'utilise pour le faire, qui est essentiellement du code C++. Donc, ma question est comment puis-je utiliser IDispatch en C pour créer l'objet COM sans avoir à dépendre de MFC, .NET, C#, WTL ou ATL. Je crois que si je le fais, je serai capable de compiler mon code sans aucun problème.Comment utiliser IDispatch en langage C pour appeler un objet COM

Répondre

15

Il existe un excellent article sur CodeProject intitulé "COM in plain C".

Voici the link to Part 1.

Il y a beaucoup de très bonnes informations sur l'utilisation de COM en C dans cet article et les suivis ultérieurs de l'auteur (je pense qu'il y en a 3 ou 4 dans la série).

Edit:
J'ai eu tort, il y a 8 parties!

Part 2
Part 3
Part 4
Part 5
Part 6
Part 7
Part 8

+0

c'est un très bon tutoriel en effet, je le regardais, et la première partie explique comment créer un objet COM, ce que j'ai déjà, le problème est que mon objet COM est écrit en C#, j'ai vu dans le tutoriel vous devez créer un fichier include (.h) dans lequel vous devez spécifier les VTable, les GUID et les structures dans votre objet COM. Maintenant, puis-je le faire même si mon objet COM est C#? – Vic

+0

Hmm - J'imagine que c'est possible, est-ce que vous enregistrez votre objet C# COM dans le Registre? Je pense que c'est tout ce qui est nécessaire. COM est une norme binaire, donc la VTable devrait être la même, qu'elle soit implémentée en C#, C++, VB, etc. –

3

En général, une interface C++ IDispatch est juste une table de pointeurs de fonction. En C, il ressemblerait à quelque chose comme:

typedef struct { 
    HRESULT(*pQueryInterface)(void* this, REFIID riid, void **ppvObject); 
    ULONG(*pAddRef)(void* this); 
    ULONG(*pRelease)(void* this); 
    HRESULT(*pGetTypeInfoCount)(void* this, unsigned int* pctInfo); 
    HRESULT(*pGetTypeInfo)(void* this, unsigned int iTInfo,LCID lcid, ITypeInfo** ppTInfo); 
    HRESULT(*pGetIDsOfNames)(void* this, REFIID riid, OLECHAR** rgszNames, unsigned int cNames, LCID lcid, DISPID* rgDispId); 
HRESULT(*pInvoke)(void* this, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, unsigned int* puArgErr); 
} IDispatch_in_C; 

Notez que chaque méthode a ce pointeur comme premier paramètre, et que vous aurez besoin de définir plusieurs types, tels que ITypeInfo, REFIID, DISPID, etc, etc.

Ainsi, c'est une grande tâche. Mais il est possible de créer des interfaces C++ en C. pur

+2

Notez que vous devez vous assurer que vos conventions d'appel correspondent, sinon votre ordre de passage des paramètres et le nettoyage de la pile ne fonctionneront pas correctement. Assurez-vous que ces méthodes sont déclarées comme utilisant la convention d'appel 'stdcall'. –

+0

cela n'explique pas tout à fait le fait que IDispatch en C++ utilise thiscall, donc il le transmet via ecx et non sur la pile; alors que dans C il passe ceci via la pile et non ecx; alors que CoCreateInstance ne se soucie pas si vous utilisez C ou C++. Cela n'a aucun sens que l'une des versions n'échoue pas en raison d'une mauvaise convention d'appel. De plus, comme indiqué ci-dessus, votre exemple utilise par défaut cdecl alors que com attend stdcall, donc vous finissez par nettoyer deux fois la pile pour la corrompre. – Dmitry