News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

COM problem

Started by minor28, September 18, 2009, 04:15:51 PM

Previous topic - Next topic

minor28

To get the names of a method's parameters from a type library I have used ITypeInfo.GetNames to retrieve the method name and the parameter names.

I have not succeeded to retrieve the method's return parameter name only the type. Anyone know where to find it? I have the method id, type and other things.

Best regards

minor28

You find the return value name int corresponding interface.

baltoro

As a general overview, read, The Rules of the Component Object Model : http://msdn.microsoft.com/en-us/library/ms810016.aspx   
The return value of a COM member function is supposed to be an HRESULT, which is a 32-bit value.   
Do you have access to the IDL file that MIDL uses to compile the COM Interlace? It would have to be defined there, I think.
Baltoro

minor28

I am writing code to read the type library not to create an instance. With VS tool oleview I can get the idl text. In that way I can read the answer to what my problematical code should give.

BATSoftware

FDESC is a filled in FUNCDESC structure for the function. BSTRARR[0] is the function name, BSTRARR[1..BSTRCNT-1] are the parameters.
   LOCAL   BSTRARR[16]:DWORD,BSTRCNT:DWORD,FDESC:FUNCDESC,PTIPTR:DWORD

;
   LEA   EDI,BSTRARR   ;ZERO OUT
   MOV   ECX,16
   XOR   EAX,EAX
   REP   STOSD
;
   MOV   EBX,FDESC
;
   MOV   EDX,PTIPTR
   MOV   EDX,[EDX]
   INVOKE   ITYPEINFO_GETNAMES PTR [EDX+ITYPEINFOVTBL.GETNAMES],PTIPTR,[EBX+FUNCDESC.memid],ADDR BSTRARR,16,ADDR BSTRCNT
   TEST   EAX,EAX
   JNZ   @@10
;

minor28

Quote
FDESC is a filled in FUNCDESC structure for the function. BSTRARR[0] is the function name, BSTRARR[1..BSTRCNT-1] are the parameters.

Yes and the last parameter is the return parameter but only if you retriev the FUNCDESC struct from INTERFACE type TYPEINFO or ITypeInfo.GetRefTypeInfo.

The only return name I get is "RHS";right hand side? Not the name of the function. I have not found out how to do it.

BATSoftware

Wrong interface, RHS is the default parameter name used in IDispatch. The interface you want is the referneced interface from IDispatch. That interface will return the actual interface parameter names.

Here is a snipit from the Platform SDK:

"For dual interfaces, ITypeLib::GetTypeInfo returns only the TKIND_DISPATCH type information. To get the TKIND_INTERFACE type information, ITypeInfo::GetRefTypeOfImplType can be called on the TKIND_DISPATCH type information, passing an index of –1. Then, the returned type information handle can be passed to ITypeInfo::GetRefTypeInfo."


minor28

That's what I have done.


invoke LoadTypeLib, "name", addr pTypeLib
invoke pTypeLib.GetTypeInfoOfGuid, pCLSID, addr ppTinfo
invoke ppTinfo.GetFuncDesc, index, addr pFuncDesc
invoke ppTinfo.GetDocumentation, pFuncDesc.memid, addr var.bstrVal,0,0,0


var.bstrVal = name of method

pFuncDesc holds most data about the method. Also in my case VT_PTR a pointer type.

To get return return parameter name

movzx edi,[eax].FUNCDESC.elemdescFunc.tdesc.vt
.if edi==VT_PTR || edi==VT_SAFEARRAY || edi==VT_CARRAY || edi==VT_USERDEFINED
invoke ppTinfo.GetRefTypeOfImplType, -1, addr pRefTypehandle
invoke ppTinfo.GetRefTypeInfo, pRefTypehandle, addr ppTinfo2
invoke ppTinfo2.GetNames, pFuncDesc.memid, addr Array, sizeof Array, addr cArray
.endif


The Array holds the name "RHS".

BATSoftware

You sure this is a dual interface?

minor28

Yes.

I am testing with excel type library. This is what the ms viewer show.


[
odl,
uuid(000208D5-0000-0000-C000-000000000046),
helpcontext(0x00020001),
dual,
oleautomation
]
interface _Application : IDispatch {
[id(0x00000094), propget, helpcontext(0x00010094)]
HRESULT Application([out, retval] Application** RHS);
[id(0x00000095), propget, helpcontext(0x00010095)]
HRESULT Creator([out, retval] XlCreator* RHS);
.....


and this is what my code read.


_Application
IID = {000208D5-0000-0000-C000-000000000046}
Number of functions = 378
Types = 1040h [Dual] [Dispatchable]

Application
Method offset = 28
Function memer id = 94h
Calling convention = CC_STDCALL
Invokation kind = INVOKE_PROPERTYGET
Number of parameters (optional) = 1 (0):
RHS [retval,out] VT_PTR
Return parameter type = VT_HRESULT

.....



BATSoftware

"GetNames" is passed in the size(# of elements not memory size) and address of array of DWORDs. Each DWORD in the array will be filled with the address of a BSTR correspoinding to the name of the parameter. The first DWORD will be the function name.

As for the code section displayed, you are looking at the IDispatch interface. See the ": IDispatch" inheritance? If you are using OLE View, the IDispatch interfaces have the red triangle icon. The base interfaces have the the cirle/stick icon. If you open the IDispatch interface and open the "Inhereted Interface" item, you will see the base interface.

What I think is happening is that you are no recursively processing the ITYPEINFO interfaces. The interface you want is the base enterface. Once you get the IDispatch TYPEINFO, keep processing the IMPTYPES, retrieving the referenced TYPEINFO until there are no more referenced interfaces. Think of the interfaces as a nested tree - the same tree you see when you select the IDispatch interface for a control in OLEview:

IDispatch    <--this is the interface you are processing
    Methods 
       IDispatch exposed methods  <---these are the methods you are processing
    Intereted Interfaces
        Base Interface       <--this is the interface you want
            Base methods    <---these are the methods you want to be processing
            Inhereted Interfaces
                IDispatch
...
To retriece all the methods of a dual interface ,keep processing TYPEINFOs for each cImplTypes




minor28

Quote
"GetNames" is passed in the size(# of elements not memory size) and address of array of DWORDs. Each DWORD in the array will be filled with the address of a BSTR correspoinding to the name of the parameter. The first DWORD will be the function name.

OK, I change from sizeof to number of dword in the array.

This is what I have done.


;Get number of interface functions
mov eax,pTypeAttr2 ;pTypeAttr2 is descended from GetRefTypeOfImplType
movzx eax,[eax].TYPEATTR.cFuncs
push eax

;Get number of dispinterface functions
mov eax,pTypeAttr
movzx eax,[eax].TYPEATTR.cFuncs
push eax

;Get number of IDispatch and IUnknown functions
mov eax,pTypeAttr
movzx eax,[eax].TYPEATTR.cbSizeVft
shr eax,2
push eax


                                        ;   Adjustment  IFont   _Application
pop edi ;number of IDispatch functions          (7)     (38)        (7)     
pop ecx ;number of dispinterface functions      (13)    (31)        (378)   
pop eax ;number of interface functions          (4)     (31)        (371)   
sub ecx,edi ;                                   =6      = -7        =371   
sub ecx,eax ;other than IDispatch and IUnknown  = 2     = 0         =0     


Adjustment ecx=2 are the functions (Application and Creator) of inherited _MsoDispObj. But how do I get the name of the inherited interface or even the office typelibrary I can't understand. That is one of my two present problems.

The other is the name of interface to which the retvalue pointer points.

Quote
What I think is happening is that you are no recursively processing the ITYPEINFO interfaces. ....

If I understand you right I get this result


;Dispinterface
invoke pTypeLib.GetTypeInfoOfGuid,pCLSID,addr ppTinfo ;this is "Adjustment"

invoke ppTinfo.GetDocumentation,-1,addr var.bstrVal,0,0,0 ;=> "Adjustment"
invoke ppTinfo.GetFuncDesc,0,addr pFuncDesc
invoke ppTinfo.GetNames,pFuncDesc.memid,addr pArray,35,addr pcFound ;first element => "QueryInterface" found 3

;Implemented interface
invoke ppTinfo.GetRefTypeOfImplType,-1,addr pRefTypehandle
invoke ppTinfo.GetRefTypeInfo,pRefTypehandle,addr ppTinfo2
invoke ppTinfo2.GetDocumentation,-1,addr var.bstrVal,0,0,0 ;=> "Adjustment"
invoke ppTinfo2.GetFuncDesc,0,addr pFuncDesc
invoke ppTinfo2.GetNames,pFuncDesc.memid,addr pArray,35,addr pcFound ;first element => "Parent" found 2

;Again implemented interface
invoke ppTinfo2.GetRefTypeOfImplType,-1,addr pRefTypehandle2
invoke ppTinfo2.GetRefTypeInfo,pRefTypehandle,addr ppTinfo3
invoke ppTinfo3.GetDocumentation,-1,addr var.bstrVal,0,0,0 ;=> "Adjustment"
invoke ppTinfo3.GetFuncDesc,0,addr pFuncDesc
invoke ppTinfo3.GetNames,pFuncDesc.memid,addr pArray,35,addr pcFound ;first element => "QueryInterface" found 3

;and again implemented interface
invoke ppTinfo3.GetRefTypeOfImplType,-1,addr pRefTypehandle3
invoke ppTinfo3.GetRefTypeInfo,pRefTypehandle,addr ppTinfo4
invoke ppTinfo4.GetDocumentation,-1,addr var.bstrVal,0,0,0 ;=> "Adjustment"
invoke ppTinfo4.GetFuncDesc,0,addr pFuncDesc
invoke ppTinfo4.GetNames,pFuncDesc.memid,addr pArray,35,addr pcFound ;first element => "Parent" found 2

;and again implemented interface
invoke ppTinfo4.GetRefTypeOfImplType,-1,addr pRefTypehandle4
invoke ppTinfo4.GetRefTypeInfo,pRefTypehandle,addr ppTinfo5
invoke ppTinfo5.GetDocumentation,-1,addr var.bstrVal,0,0,0 ;=> "Adjustment"
invoke ppTinfo5.GetFuncDesc,0,addr pFuncDesc
invoke ppTinfo5.GetNames,pFuncDesc.memid,addr pArray,35,addr pcFound ;first element => "QueryInterface" found 3


I appreciate your efforts to help me. I feel I have not come much closer and soon I give up and have to use the tlbinf32.dll


BATSoftware


BATSoftware

Here is the main processing loop for my OLEHDR program:

OLEHDR_SCAN_INTERFACE PROC PRIVATE USES EBX,PTI:DWORD,IDX:DWORD
   LOCAL   HREFTYP:DWORD,TYPATTR:DWORD,PTI1:DWORD,FUNCCNT:DWORD,HRESULT:DWORD
;
   MOV   EDX,PTI
   MOV   EDX,[EDX]
   INVOKE   ITYPEINFO_GETREFTYPEOFIMPLTYPE PTR [EDX+ITYPEINFOVTBL.GETREFTYPEOFIMPLTYPE],PTI,IDX,ADDR HREFTYP
   MOV   HRESULT,EAX
   TEST   EAX,EAX
   JNZ   @@9
;
   MINTERFACE ITYPEINFO,GETREFTYPEINFO,PTI,<,HREFTYP,ADDR PTI1>
   MOV   HRESULT,EAX
   TEST   EAX,EAX
   JNZ   @@9
;
   MINTERFACE ITYPEINFO,GETTYPEATTR,PTI1,<,ADDR TYPATTR>
   MOV   HRESULT,EAX
   TEST   EAX,EAX
   JNZ   @@8
;
   MOV   EBX,TYPATTR
   MOVZX   EAX,[EBX+TYPEATTR.cFuncs]
   MOV   FUNCCNT,EAX
   MOVZX   EAX,[EBX+TYPEATTR.cImplTypes]
   TEST   EAX,EAX
   JZ   @F
;
   INVOKE   OLEHDR_SCAN_INTERFACE,PTI1,0
;
@@:   INVOKE   DECODE_FUNCS,PTI1,FUNCCNT
   MOV   HRESULT,EAX
;
@@9:   MINTERFACE ITYPEINFO,RELEASETYPEATTR,PTI1,<,TYPATTR>
@@8:   MINTERFACE IUNKNOWN,RELEASE,PTI1
   MOV   EAX,HRESULT
   RET
OLEHDR_SCAN_INTERFACE ENDP
;
; Start the recursive decent here after getting the ITYPEINFO using the IPROVIDECLASSINFO interface
   MINTERFACE IPROVIDECLASSINFO,GETCLASSINFO,PCI,<,ADDR PTI>
   MOV   HRESULT,EAX
   TEST   EAX,EAX
   JNZ   @@9
;
; Get TYPEATTR for the COCLASS
   MINTERFACE ITYPEINFO,GETTYPEATTR,PTI,<,ADDR TYPATTR>
   MOV   HRESULT,EAX
   TEST   EAX,EAX
   JNZ   @@9
;
   MOV   EBX,TYPATTR
   MOVZX   EAX,[EBX+TYPEATTR.cImplTypes]
   MOV   CNT1,EAX
   MOV   IDX1,0
; Process each interface exposed by the  COCLASS
@@1:   MINTERFACE ITYPEINFO,GETIMPLTYPEFLAGS,PTI,<,IDX1,ADDR IFLAGS>
   MOV   HRESULT,EAX
   TEST   EAX,EAX
   JNZ   @@9
;
   MOV   EAX,IFLAGS
   MOV   [EBX+INTER_REC.IFLAGS],EAX   
;
   MINTERFACE ITYPEINFO,GETREFTYPEOFIMPLTYPE,PTI,<,IDX1,ADDR HREFTYP>
   MOV   HRESULT,EAX
   TEST   EAX,EAX
   JNZ   @@9
;
   MINTERFACE ITYPEINFO,GETREFTYPEINFO,PTI,<,HREFTYP,ADDR PTI2>
   MOV   HRESULT,EAX
   TEST   EAX,EAX
   JNZ   @@9
;
   MINTERFACE ITYPEINFO,GETTYPEATTR,PTI2,<,ADDR TYPATTR2>
   MOV   HRESULT,EAX
   TEST   EAX,EAX
   JNZ   @@9
;
   MOV   EAX,TYPATTR2
   MOVZX   EAX,[EAX+TYPEATTR.wTypeFlags]
   XOR   EDX,EDX
   TEST   EAX,TYPEFLAG_FDUAL
   JZ   @F
;
   INC   EDX
@@:   MOV         DUALFLAG,,EDX
;
   XOR   EAX,EAX
   CMP   DUALFLAG,TRUE
   JNE   @F
;
   DEC   EAX   
@@:   INVOKE   OLEHDR_SCAN_INTERFACE,PTI2,EAX
;
              INC           IDX1
              DEC          CNT1
              JNZ          @@1
;
That will property traverse an interface ITYPELIB. If you store the inteformation at the right spots, you will have the VTBL, and all the methods.

minor28

I cannot quite follow your code. I don't understand "MINTERFACE", "INVOKE   DECODE_FUNCS" etc. But as I can see your code is very alike mine. The only difference is the use of IPROVIDECLASSINFO. Is that essebtial for the result.

Quote
That will property traverse an interface ITYPELIB. If you store the inteformation at the right spots, you will have the VTBL, and all the methods.

Are we talking about the same thing. I have got all data but the name of the method to which the result value points. See the image