调用CoCreateInstance后得到了一个DLL(COM)的接口地址.
那然后比如我想调用里面的"speak".
怎么算接口表里函数的偏移? 
下面是用eXeScope打开这个DLL的部分内容
Interface ISpVoice; // ISpVoice Interface
GUID={6C44DF74-72B9-4992-A1EC-EF996E0422D4};
  function SetOutput(pUnkOutput:IUnknown; fAllowFormatChanges:I4): HResult;
  function GetOutputObjectToken(out ppObjectToken:^^ISpObjectToken): HResult;
  function GetOutputStream(out ppStream:^^ISpStreamFormat): HResult;
  function Pause: HResult;
  function Resume: HResult;
  function SetVoice(pToken:^ISpObjectToken): HResult;
  function GetVoice(out ppToken:^^ISpObjectToken): HResult;
  function Speak(pwcs:LPWSTR; dwFlags:UI4; out pulStreamNumber:^UI4): HResult;
  function SpeakStream(pStream:^IStream; dwFlags:UI4; out pulStreamNumber:^UI4): HResult;
  function GetStatus(out pStatus:^SPVOICESTATUS; out ppszLastBook:^LPWSTR): HResult;
  function Skip(pItemType:LPWSTR; lNumItems:I4; out pulNumSkipped:^UI4): HResult;
  function SetPriority(ePriority:SPVPRIORITY): HResult;
  function GetPriority(out pePriority:^SPVPRIORITY): HResult;
  function SetAlertBoundary(eBoundary:SPEVENTENUM): HResult;
  function GetAlertBoundary(out peBoundary:^SPEVENTENUM): HResult;
  function SetRate(RateAdjust:I4): HResult;
  function GetRate(out pRateAdjust:^I4): HResult;
  function SetVolume(usVolume:UI2): HResult;
  function GetVolume(out pusVolume:^UI2): HResult;
  function WaitUntilDone(msTimeout:UI4): HResult;
  function SetSyncSpeakTimeout(msTimeout:UI4): HResult;
  function GetSyncSpeakTimeout(out pmsTimeout:^UI4): HResult;
  function SpeakCompleteEvent: ^void;
  function IsUISupported(pszTypeOfUI:^UI2; pvExtraData:^void; cbExtraData:UI4; out pfSupported:^I4): HResult;
  function DisplayUI(hWndParent:wireHWND; pszTitle:^UI2; pszTypeOfUI:^UI2; pvExtraData:^void; cbExtraData:UI4): HResult; 

解决方案 »

  1.   

    接口都获得了,直接->Speak就可以了
      

  2.   

    那用汇编呢,假如EAX是接口的地址,先把Speak的参数PUSH进栈,再CALL DWORD (EAX + 偏移),好像这个偏移是50H,但我自己算不对,哪位大侠来简单再说一说呀,怎么算的!
      

  3.   

    接口指向的地址才是函数地址开始的地方,也就是[EAX]+偏移 才是函数
      

  4.   

    这是在网上看的别人的例子,编译成功,但不知那个偏移50咋来的!我本愚钝!
    .586
    .model flat,stdcall
    option casemap:none   include windows.inc
       include kernel32.inc
       include ole32.inc
       
       includelib kernel32.lib
       includelib ole32.lib.data
    CLSID_SpVoice GUID <096749377h, 03391h, 011D2h, <09Eh, 0E3h, 000h, 0C0h, 04Fh, 079h, 073h, 096h>>
    IID_ISpVoice  GUID <06C44DF74h, 072B9h, 04992h, <0A1h, 0ECh, 0EFh, 099h, 06Eh, 004h, 022h, 0D4h>>TEXT    db 'I',0,' ',0 ,'L',0 ,'o',0 ,'v',0 ,'e',0 ,' ',0 ,'Y',0 ,'o',0 ,'u',0 ,'!',0,0.data?
    PCOM    dd ?
    .code; ---------------------------------------------------------------------------start:
        invoke CoInitialize,0
        invoke CoCreateInstance,offset CLSID_SpVoice, 0, CLSCTX_INPROC_SERVER, offset IID_ISpVoice,offset PCOM
        .if eax == 0
            push 0
            push 0
            push offset TEXT
            mov eax,PCOM
            push eax
            mov eax,[eax]
            call DWORD PTR[eax+50h] ;PCOM->Speak(L"I LOVE YOU!", 0, 0);
        .endif
        invoke ExitProcess,eaxend start
      

  5.   

    我也不知道50是怎么来的,也问问别人。
    按理说,Speak函数是第7个函数,那么实际函数就是第10个函数(接口最开始的还有3个默认函数)
    也就是说,偏移量应该是10*4=40=28h才是,但是现在是50h=80,难道每个函数使用的是8个字节?
      

  6.   

    和参数没啥关系,是因为此接口不是直接从IUnknown继承的,
    ISpvoice <-- ISpEventSource <-- ISpNotifySource <-- IUnknown
    你数数里头的接口数目,正好是第21个接口,也就是相对偏移50h
      

  7.   

    正如doudouHuY大哥所教!
    谢谢大家帮忙,感激不尽!
      

  8.   

    你去看看COM原理与应用,里面有说的。就是指针首先是指向VTL,每个虚函数的指针占一定空间,顺着下去就可以了。好像是这样,我当时也没看的太认真。