2009-06-03 12 views
12

Potrzebuję skompilować trochę kodu używając kompilatora gcc zawartego w narzędziach R (R program statystyczny dla Windows), problemem jest to, że muszę użyć IDispatch w moim kodzie, aby uzyskać dostęp do metod obiektu COM, a kompilator gcc nie obsługuje dużej części kodu, którego używam, aby to zrobić, czyli w zasadzie kodu C++.Jak używać IDispatch w zwykłym C do wywoływania obiektu COM

Moje pytanie brzmi: jak używać IDispatch w C do tworzenia obiektu COM bez konieczności polegania na MFC, .NET, C#, WTL lub ATL. Wierzę, że jeśli to zrobię, będę w stanie skompilować mój kod bez żadnego problemu.

Odpowiedz

15

Istnieje świetny artykuł na CodeProject pod tytułem "COM in plain C".

Oto the link to Part 1.

Istnieje wiele bardzo dobrych informacji na temat pracy z COM w C w tym artykule i kolejnych obserwacjach autora (myślę, że są 3 lub 4 w serii).

Edytuj:
Myliłem się, jest 8 części!

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

+0

to naprawdę bardzo dobry tutorial, patrzyłem na niego, a pierwsza część wyjaśnia, jak utworzyć obiekt COM, który już mam, problem polega na tym, że mój obiekt COM jest napisany w C#, widziałem w tutorialu, że musisz utworzyć plik włączający (.h), w którym musisz określić VTable, GUID i struktury w twoim obiekcie COM, teraz, czy mogę to zrobić, nawet jeśli mój obiekt COM to C#? – Vic

+0

Hmm - wyobrażam sobie, że jest to możliwe, czy rejestrujesz swój obiekt C# COM w Rejestrze? Myślę, że to wszystko, co konieczne. COM jest standardem binarnym, więc VTable powinien być taki sam niezależnie od tego, czy jest zaimplementowany w C#, C++, VB itd. –

3

Zasadniczo interfejs IDispatch C++ jest po prostu tabelą wskaźników funkcji. W C, to będzie wyglądać mniej więcej tak:

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; 

Należy pamiętać, że każda metoda ma tego wskaźnika jako pierwszy parametr, i że będzie trzeba zdefiniować więcej typów, takich jak ITypeInfo, REFIID, DISPID, etc, itp.

To duże zadanie. Ale możliwe jest tworzenie interfejsów C++ w czystym C.

+2

Pamiętaj, że musisz się upewnić, że konwencje wywoływania są zgodne, w przeciwnym razie porządek przekazywania parametrów i czyszczenie stosu nie będzie działać poprawnie. Upewnij się, że te metody są zadeklarowane jako używające konwencji wywoływania "stdcall". –

+0

to nie dość wyjaśnia, że ​​IDispatch w C++ używa tej komórki, więc przekazuje to przez ecx, a nie na stos; natomiast w C przechodzi to przez stos, a nie ekx; mając na uwadze, że CoCreateInstance nie obchodzi, czy używasz C lub C++. Nie ma sensu, dlaczego jedna z wersji nie zawodzi z powodu niewłaściwej konwencji telefonicznej. Również, jak wspomniano powyżej, twój przykład przyjmuje domyślną wartość cdecl, podczas gdy com oczekuje stdcall, więc kończysz na czyszczeniu stosu dwukrotnie skutecznie go uszkadzając. – Dmitry