ActiveX Scripting Engines: Интерпретация внешнего скрипта в С++ Страница 3. Передача объекта
|
Страница 3 из 4
Передача объектаВспомним описанный ранее объект, порожденный от CCmdTarget и служащий, напомню, для позднего связывания: class CCodeObject : public CCmdTarget { \\. . .
| Пришло его время.
Один из методов интерфейса IActiveScriptSite имеет следующий прототип:
HRESULT _stdcall CScriptHost::GetItemInfo(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown** ppunkItem, ITypeInfo** ppTypeInfo);
| Во время исполнения скрипта метод GetItemInfo будет вызван с определенными параметрами, говорящими о том, что в ответ нужно вернуть указатель на интерфейс IUnknown*. Это как раз и есть тот момент, когда для дальнейшего исполнения скрипта понадобился экземпляр объекта CCodeObject – например, чтобы «поискать» там какую-нибудь переменную, имя которой использовано в скрипте. К этому моменту в каком-нибудь модуле трансляции уже существует экземпляр класса CCodeObjecе. Например, обьявленный как глобальный – сейчас стиль программирования не особо важен, главное – проиллюстрировать суть происходящего. Итак, где-то объявлен и находится в зоне видимости:
Теперь в реализации CScriptHost::GetItemInfo() происходит следующее:
HRESULT _stdcall CScriptHost::GetItemInfo(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown** ppunkItem, ITypeInfo** ppTypeInfo) { // . . . *ppunkItem = codeobj.GetIDispatch(TRUE); // . . . }
| Заметим важный ньюанс – следующая строка НЕПРАВИЛЬНАЯ: *ppunkItem = (IUnknown*)&codeobj; // так нельзя!!!
| Компилятор проглотит, но, хотя наш обьект и унаследован от CCmdTarget, сам класс CCmdTarget не унаследован от IUnknown. Ранее мы создавали CScriptHost, унаследованный от IActiveScriptSite, а сам IActiveScriptSite был унаследован от IUnknown. Это действительно допускает преобразование CScriptHost к IUnknown. Но в случае с классом CCodeObject, порожденным от CCmdTarget, преобразование к типу IUnknown невозможно. Класс CCmdTarget может вернуть указатель на интерфейс IUnknown (или интефейс IDispatch, действительно порожденный от IUnknown). Но делается это путем вызова
IUnknown* punk = CCmdTarget::GetInterface(&IID_IUnknown);
| или
IUnknown* punk = CCmdTarget::GetIDispatch(TRUE);
| В основу положен другой механизм. В очень грубом приближении, в классе CCmdTarget объявлен член класса, имеющий тип IDispatch, а метод GetIDispatch возвращает его адрес:
class CCmdTarget: { // . . . IDispatch m_xxIDispatch;
IUnknown* GetIDispatch(BOOL bAddRef) { if ( bAddRef ) m_xxIDispatch.AddRef(); return &m_xxIDispatch; } };
| На самом деле всё несколько сложнее – применена некоторая арифметика указателей и смещений. Проиллюстрируем это на примере:
class IClassA { };
class ClassB { int dummy1, dummy2, dummy3;
IClassA m_xxIClassA;
static int m_offs;
public:
IClassA* GetIClassA() { IClassA* pia = (IClassA*)((BYTE*)this + m_offs); return pia; } };
int ClassB::m_offs = (size_t)&(((ClassB *)0)->m_xxIClassA);
int main(int argc, char* argv[]) {
ClassB b; IClassA* pA = b.GetIClassA();
return 0; }
| Не будем углубляться дальше. Продолжим работу над главной задачей – запуском скрипта. Осталось совсем немного.
|