· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.WIN32 —› COM

Посл.отвђт Сообщенiе


Дата: Авг 21, 2004 17:27:06

Создаю окно для com-объекта. При помощи ATL.DLL получаю сам объект и вставляю в это онко. Объект отображается, но вот никак не могу добраться до его функций. IUnknown получил, а как определить смещения ф-ций - не знаю. Попробовал таким путём:
При помощи утилиты COM Browser получил описание интерфейса объекта (на примере mediaplayer'a). Примерно такого содержания:
Interface Dispatch DirectFrameMediaPlayer
    Member Get CurrentPosition<&H403>() As Double
    Member Let CurrentPosition<&H403>()   'Parameter Type As Double
    Member Get Duration<&H3EB>() As Double
    Member Get ImageSourceWidth<&H3E9>() As Long
    Member Get ImageSourceHeight<&H3EA>() As Long

Значения <&H3E9>,<&H3EA>,<&H3EB> смещениями относительно IUnknown адресов вызываемых функций не должны быть, т.к. разница меж ними менее дворда. Наугад попробовал вызывать ф-ции по этим смещениям - программа вылетает.
Может кто знает, как получить адреса функций и методов объекта?


Дата: Авг 21, 2004 19:46:41

Может кто знает, как получить адреса функций и методов объекта?

Все зависит от того, используется ли раннее связывание или позднее связывание. Подробнее тут:

http://www.wasm.ru/article.php?article=msi


Дата: Авг 22, 2004 21:48:47

Если ты имеешь _именно_ IUnknown, то сделай ему QueryInterface с REFIID'ом того интерфейса, который ты хочешь. Он тебе на это, если все хорошо, отдаст указатель на область памяти, где в свою очередь первым двордом будет лежать указатель на его vtbl.
Далее, vtbl - это массив указателей на методы класса. Там стандартно идет так:
QueryInterface()
AddRef()
Release()
а вот дальше пошли методы, специфичные для конкретного класса. Для стандартных интерфейсов в *.h от визуал студии есть эти таблицы. Например вот для IDispatch:
    typedef struct IDispatchVtbl
    {
        BEGIN_INTERFACE

        HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
            IDispatch * This,
            /* [in] */ REFIID riid,
            /* [iid_is][out] */ void **ppvObject);

        ULONG ( STDMETHODCALLTYPE *AddRef )(
            IDispatch * This);

        ULONG ( STDMETHODCALLTYPE *Release )(
            IDispatch * This);

        HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )(
            IDispatch * This,
            /* [out] */ UINT *pctinfo);

        HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )(
            IDispatch * This,
            /* [in] */ UINT iTInfo,
            /* [in] */ LCID lcid,
            /* [out] */ ITypeInfo **ppTInfo);

        HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )(
            IDispatch * This,
            /* [in] */ REFIID riid,
            /* [size_is][in] */ LPOLESTR *rgszNames,
            /* [in] */ UINT cNames,
            /* [in] */ LCID lcid,
            /* [size_is][out] */ DISPID *rgDispId);

        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )(
            IDispatch * This,
            /* [in] */ DISPID dispIdMember,
            /* [in] */ REFIID riid,
            /* [in] */ LCID lcid,
            /* [in] */ WORD wFlags,
            /* [out][in] */ DISPPARAMS *pDispParams,
            /* [out] */ VARIANT *pVarResult,
            /* [out] */ EXCEPINFO *pExcepInfo,
            /* [out] */ UINT *puArgErr);

        END_INTERFACE
    } IDispatchVtbl;
(файл OAIdl.h).
Для нестандартных интерфейсов можно попробовать их ИДой расковырять, к ней палгин есть для КОМ-объектов специальный..


Дата: Авг 23, 2004 17:03:26

zed_0xff

Так QueryInterface получается обязательно нужно вызывать? Сразу после получения IUnknown. Либо не сразу, но перед первым вызовом метода. ОК, попробую.


Дата: Авг 23, 2004 17:24:43 · Поправил: cresta

Ещё уточню: значит, я запрашиваю QueryInterface с REFIID'ом (это для всего com-объекта в целом), получаю указатель на указатель на таблицу. После этого ещё раз запрашиваю QueryInterface по первому адресу этой таблицы, но теперь уже для конкретного интерфейса. Если до сих пор я правильно понял, то второй запрос нужно делать уже с ID конкретного интерфейса, т.к. их может быть несколько. И обязательно ли делать Release после каждого вызова функции\метода? Может только при окончании работы с интерфейсом?
О том чтобы расковырять интерфейс: я тут нарыл утилиту COMView, она делает 4 стандартных инклюда + два для конкретного объекта. На асме. Правда, там такое количество макросов :-\ Если вдруг кому надо, она лежит на http://www.japheth.de


Дата: Авг 23, 2004 20:57:47

cresta
допустим мы имеем IUnknown* pUnk
mov ebx, pUnk ; ebx = адрес IUnknown
mov ebx, [ebx]; ebx = адрес vtbl для IUnknown
mov ebx, [ebx]; ebx = адрес QueryInterface() для IUnknown
push offset pWantedInterface
push offset IID_WantedInterface
push pUnk
call ebx
mov ebx, [pWantedInterface]
or ebx,ebx
jnz all_ok

push 1
call ExitProcess

all_ok:
; ebx = указатель на экземпляр искомого объекта
mov ebx, [ebx] ; теперь на его vtbl
add ebx,4*4 ; если мы хотим вызвать 4-ю по порядку функцию
mov ebx,[ebx] ; получаем ее адрес
push arg2 ; аргументы, опять же по вкусу
push arg1
push [pWantedInterface]
call ebx

...............

 ; сюда придет указатель на искомый ифейс:
pWantedInterface: dd 0

 ; а это IID нужного интерфейса, цифры подставить по вкусу :)
IID_WantedInterface: 
  dd 12345678h
  dw 1234h, 1234h
  db 12h, 12h, 12h, 12h, 12h, 12h, 12h, 12h


вроде все.


Дата: Авг 23, 2004 21:41:51

Ага, теперь всё видно :)
Спасибо.


Дата: Авг 23, 2004 22:21:27

Угу. пжалста. Просто как раз совсем недавно проект один сделал, там всяко на голом си с ком-объектами извращался... :)


Дата: Авг 24, 2004 00:51:47

Да я в Си ни в зуб ногой, а все примеры обычно на ём написаны. А ассемблерный как-то всё просто и понятно. Потому сразу и не допёр :((


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.044