It's my first try with IDispatch . I call GetIDsOfNames and ALWAYS get HRESULT 80020001
DISP_E_UNKNOWNINTERFACE (http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.vsconstants.disp_e_unknowninterface.aspx) :
QuoteA return value that indicates that the interface identifier passed in riid is not equal to IID_NULL.
include \masm32\include\masm32rt.inc
__UNICODE__ EQU
.data
IID_IDispatch GUID <00020400h,0000h,0000h,<0C0h,0h,0h,0h,0h,0h,0h,46h>>
IID_NULL GUID <00000000h,0000h,0000h,<0h,0h,0h,0h,0h,0h,0h,0h>>
.data?
lpszProgID dd ?
lpszMember dd ?
DISPID dd ?
pclsid dd ?
ppv dd ?
.code
start:
cls
call main
inkey
exit
main proc
mov eax,uc$("Shell.Application")
invoke SysAllocString,eax
mov lpszProgID,eax
invoke CLSIDFromProgID,eax,addr pclsid
.if eax != S_OK
print LastError$(),13,10,0
ret
.endif
print "CLSIDFromProgID : SUCCESS",13,10,0
invoke CoInitialize,NULL
invoke CoCreateInstance,addr pclsid,
NULL,
CLSCTX_INPROC_SERVER,
addr IID_IDispatch,
addr ppv
.if eax != S_OK
fnx MessageBox,0,hex$(eax),"HRESULT: ",MB_OK
print LastError$(),13,10,0
ret
.endif
print "CoCreateInstance: SUCCESS",13,10,0
mov eax,uc$("NameSpace")
invoke SysAllocString,eax
mov lpszMember, eax
; ------------------------------------------------------------------------;
; invoke IDispatch_GetIDsOfNames, riid, rgszNames, cNames, lcid, rgDispId ;
; ------------------------------------------------------------------------;
push 0 ; program terminates abnormally without it :-\
push offset DISPID ; rgDispId
push 800h ; lcid
push 1 ; cNames
push eax ; rgszNames
push offset IID_NULL ; riid
mov edx, dword ptr [ppv]; pointer to IDispatch
mov eax, [edx]
mov edx, dword ptr [eax+20] ; offset of GetIDsOfNames
call edx
.if eax != S_OK
fnx MessageBox,0,hex$(eax),"HRESULT: ",MB_OK
print "GetIDsOfNames : FAILED ",13,10,0
jmp _exit
.endif
print "GetIDsOfNames : SUCCESS",13,10,0
_exit:
invoke SysFreeString , addr lpszProgID
invoke SysFreeString , addr lpszMember
invoke CoUninitialize
ret
main endp
end start
Awaiting the enlightment from COM gurus ;)
push 0 ; program terminates abnormally without it :-\
push offset DISPID ; rgDispId
push 800h ; lcid
push 1 ; cNames
push eax ; rgszNames
push offset IID_NULL ; riid
mov edx, dword ptr [ppv]; pointer to IDispatch
mov eax, [edx]
mov edx, dword ptr [eax+20] ; offset of GetIDsOfNames
call edx
not good :P
give me a few minutes...
something like this should may work
;###############################################################################################
;METHOD macro by qWord
METHOD MACRO name,args:VARARG
LOCAL _type1,_type2
_type1 TYPEDEF PROTO args
_type2 TYPEDEF PTR _type1
EXITM <name _type2 ?>
ENDM
;###############################################################################################
;IDispatch interface
IDispatch STRUCT
METHOD(QueryInterface, _this:LPVOID,riid:LPVOID,ppvObj:LPVOID)
METHOD(AddRef, _this:LPVOID)
METHOD(Release, _this:LPVOID)
METHOD(GetTypeInfoCount, _this:LPVOID,pctinfo:UINT)
METHOD(GetTypeInfo, _this:LPVOID,iTInfo:UINT,lcid:LCID,ppTInfo:LPVOID)
METHOD(GetIDsOfNames, _this:LPVOID,riid:LPVOID,rgszNames:LPOLESTR,cNames:UINT,lcid:LCID,rgDispId:DWORD)
METHOD(Invoke, _this:LPVOID,dispIdMember:DWORD,riid:LPVOID,lcid:LCID,wFlags:DWORD,pDispParams:LPVOID,pVarResult:LPVOID,pExcepInfo:LPVOID,puArgErr:UINT)
IDispatch ENDS
;###############################################################################################
;
;
;
mov edx,ppv
mov ecx,[edx]
INVOKE [ecx].IDispatch.GetIDsOfNames,edx,riid,rgszNames,cNames,lcid,rgDispId
;
;
;
EDIT: updated the INVOKE line
edited again - had ECX and EDX swapped
Thank you , Dave
but still no luck
it crashes
With Dave's/qWord's code on top, this builds fine (provided you comment out/complete the UNICODE line):
; ------------------------------------------------------------------------;
; invoke IDispatch_GetIDsOfNames, riid, rgszNames, cNames, lcid, rgDispId ;
; ------------------------------------------------------------------------;
if 1
rgDispId equ <DISPID>
lcid equ 800h
cNames equ 1
rgszNames equ eax
riid equ <offset IID_NULL>
mov edx,ppv
mov ecx, [edx]
INVOKE [ecx].IDispatch.GetIDsOfNames,edx,riid,rgszNames,cNames,lcid,rgDispId
else
push 0 ; program terminates abnormally without it :-\
push offset DISPID ; rgDispId
push 800h ; lcid
push 1 ; cNames
push eax ; rgszNames
push offset IID_NULL ; riid
mov edx, dword ptr [ppv]; pointer to IDispatch
mov eax, [edx]
mov edx, dword ptr [eax+20] ; offset of GetIDsOfNames
call edx
endif
.if eax != S_OK
; fnx MessageBox,0,hex$(eax),"HRESULT: ",MB_OK
print "GetIDsOfNames : FAILED ",13,10,0
jmp _exit
.endif
print "GetIDsOfNames : SUCCESS",13,10,0
_exit:
i have found a few issues
first, if you are going to define the __UNICODE__ symbol, do so before the include files
next, in the IDispatch interface, the function named "Invoke" must be named something else :P
you have an LCID of 800h - not sure how critical this is, but i replaced it with 409h
the DISPID variable must be an array of DWORDS - if i understand correctly, at least 2 DWORDS
i think we have one more issue
that is that we are passing the pointer to a dynamic string (BSTR)
i seem to recall that dynamic string arrays have the array count in the first element
we should be able to use Hutch's array allocation macro(s)
here is what i have so far
__UNICODE__ EQU 1
include \masm32\include\masm32rt.inc
;###############################################################################################
;METHOD macro by qWord
METHOD MACRO name,args:VARARG
LOCAL _type1,_type2
_type1 TYPEDEF PROTO args
_type2 TYPEDEF PTR _type1
EXITM <name _type2 ?>
ENDM
;###############################################################################################
;IDispatch interface
IDispatch STRUCT
METHOD(QueryInterface, _this:LPVOID,riid:LPVOID,ppvObj:LPVOID)
METHOD(AddRef, _this:LPVOID)
METHOD(Release, _this:LPVOID)
METHOD(GetTypeInfoCount, _this:LPVOID,pctinfo:UINT)
METHOD(GetTypeInfo, _this:LPVOID,iTInfo:UINT,lcid:LCID,ppTInfo:LPVOID)
METHOD(GetIDsOfNames, _this:LPVOID,riid:LPVOID,rgszNames:LPOLESTR,cNames:UINT,lcid:LCID,rgDispId:LPVOID)
METHOD(dInvoke, _this:LPVOID,dispIdMember:DWORD,riid:LPVOID,lcid:LCID,wFlags:DWORD,pDispParams:LPVOID,pVarResult:LPVOID,pExcepInfo:LPVOID,puArgErr:UINT)
IDispatch ENDS
;###############################################################################################
.data
IID_IDispatch GUID <00020400h,0000h,0000h,<0C0h,0h,0h,0h,0h,0h,0h,46h>>
IID_NULL GUID <00000000h,0000h,0000h,<0h,0h,0h,0h,0h,0h,0h,0h>>
.data?
lpszProgID dd ?
lpszMember dd ?
DISPID dd ?,?
pclsid dd ?
ppv dd ?
.code
start:
cls
call main
inkey
exit
main proc
mov eax,uc$("Shell.Application")
invoke SysAllocString,eax
mov lpszProgID,eax
invoke CLSIDFromProgID,eax,addr pclsid
.if eax != S_OK
print LastError$(),13,10,0
ret
.endif
print "CLSIDFromProgID : SUCCESS",13,10,0
invoke CoInitialize,NULL
invoke CoCreateInstance,addr pclsid,
NULL,
1, ;CLSCTX_INPROC_SERVER,
addr IID_IDispatch,
addr ppv
.if eax != S_OK
fnx MessageBox,0,hex$(eax),"HRESULT: ",MB_OK
print LastError$(),13,10,0
ret
.endif
print "CoCreateInstance: SUCCESS",13,10,0
mov eax,uc$("NameSpace")
invoke SysAllocString,eax
mov lpszMember, eax
; ------------------------------------------------------------------------;
; invoke IDispatch_GetIDsOfNames, riid, rgszNames, cNames, lcid, rgDispId ;
; ------------------------------------------------------------------------;
; push 0 ; program terminates abnormally without it :-\
; push offset DISPID ; rgDispId
; push 800h ; lcid
; push 1 ; cNames
; push eax ; rgszNames
; push offset IID_NULL ; riid
; mov edx, dword ptr [ppv]; pointer to IDispatch
; mov eax, [edx]
; mov edx, dword ptr [eax+20] ; offset of GetIDsOfNames
; call edx
mov edx,ppv
mov ecx,[edx]
INVOKE [ecx].IDispatch.GetIDsOfNames,edx,offset IID_NULL,eax,1,409h,offset DISPID
.if eax != S_OK
fnx MessageBox,0,hex$(eax),"HRESULT: ",MB_OK
print "GetIDsOfNames : FAILED ",13,10,0
jmp _exit
.endif
print "GetIDsOfNames : SUCCESS",13,10,0
_exit:
invoke SysFreeString , addr lpszProgID
invoke SysFreeString , addr lpszMember
invoke CoUninitialize
ret
main endp
end start
Even with a proper BSTR, I get "The requested lookup key was not found in any active activation context" aka 80070057h...
Quote from: jj2007 on January 11, 2014, 05:54:45 PM
Even with a proper BSTR, I get "The requested lookup key was not found in any active activation context" aka 80070057h...
The functions called so far don't require BSTRs, just wide strings.
I get error 80020006, which means that name "NameSpace" is unknown ( sounds plausible):
include \masm32\include\masm32rt.inc
includelib msvcrt.lib
printf proto c :vararg
;###############################################################################################
;METHOD macro by qWord
METHOD MACRO name,args:VARARG
LOCAL _type1,_type2
_type1 TYPEDEF PROTO args
_type2 TYPEDEF PTR _type1
EXITM <name _type2 ?>
ENDM
L macro parms:VARARG
local wstr
wstr textequ <>
for parm,<parms>
ifidn <">,@SubStr(parm,1,1)
% forc chr$, <@SubStr(parm,2,@SizeStr(parm)-2)>
ifnb wstr
wstr CatStr wstr,<,>
endif
wstr CatStr wstr,<'&chr$'>
endm
else
ifnb wstr
wstr CatStr wstr,<,>
endif
wstr CatStr wstr,<parm>
endif
endm
exitm <wstr>
endm
CStr macro text:vararg
local xxx
.const
xxx db text,0
.code
exitm <offset xxx>
endm
;###############################################################################################
;IDispatch interface
IDispatch STRUCT
METHOD(QueryInterface, _this:LPVOID,riid:LPVOID,ppvObj:LPVOID)
METHOD(AddRef, _this:LPVOID)
METHOD(Release, _this:LPVOID)
METHOD(GetTypeInfoCount, _this:LPVOID,pctinfo:UINT)
METHOD(GetTypeInfo, _this:LPVOID,iTInfo:UINT,lcid:LCID,ppTInfo:LPVOID)
METHOD(GetIDsOfNames, _this:LPVOID,riid:LPVOID,rgszNames:LPOLESTR,cNames:UINT,lcid:LCID,rgDispId:LPVOID)
METHOD(dInvoke, _this:LPVOID,dispIdMember:DWORD,riid:LPVOID,lcid:LCID,wFlags:DWORD,pDispParams:LPVOID,pVarResult:LPVOID,pExcepInfo:LPVOID,puArgErr:UINT)
IDispatch ENDS
;###############################################################################################
.data
IID_IDispatch GUID <00020400h,0000h,0000h,<0C0h,0h,0h,0h,0h,0h,0h,46h>>
IID_NULL GUID <00000000h,0000h,0000h,<0h,0h,0h,0h,0h,0h,0h,0h>>
wszCls dw L("Shell.Application"),0
wszNS dw L("NameSpace"),0
.data?
; lpszProgID dd ?
; lpszMember dd ?
DISPID dd ?,?
pclsid dd ?
ppv dd ?
.code
start:
cls
call main
inkey
exit
main proc
invoke CLSIDFromProgID,addr wszCls,addr pclsid
.if eax != S_OK
invoke printf, CStr("CLSIDFromProgID FAILED, eax=%X",10), eax
ret
.endif
print "CLSIDFromProgID : SUCCESS",13,10,0
invoke CoInitialize,NULL
invoke CoCreateInstance,addr pclsid,
NULL,
1, ;CLSCTX_INPROC_SERVER,
addr IID_IDispatch,
addr ppv
.if eax != S_OK
invoke printf, CStr("CoCreateInstance FAILED, eax=%X",10), eax
ret
.endif
invoke printf, CStr( "CoCreateInstance: SUCCESS",10 )
; ------------------------------------------------------------------------;
; invoke IDispatch_GetIDsOfNames, riid, rgszNames, cNames, lcid, rgDispId ;
; ------------------------------------------------------------------------;
; push 0 ; program terminates abnormally without it :-\
; push offset DISPID ; rgDispId
; push 800h ; lcid
; push 1 ; cNames
; push eax ; rgszNames
; push offset IID_NULL ; riid
; mov edx, dword ptr [ppv]; pointer to IDispatch
; mov eax, [edx]
; mov edx, dword ptr [eax+20] ; offset of GetIDsOfNames
; call edx
mov edx,ppv
mov ecx,[edx]
INVOKE [ecx].IDispatch.GetIDsOfNames,edx,offset IID_NULL,addr wszNS,1,409h,offset DISPID
.if eax != S_OK
invoke printf, CStr("GetIDsOfNames FAILED, eax=%X",10), eax
jmp _exit
.endif
print "GetIDsOfNames : SUCCESS",13,10,0
_exit:
; invoke SysFreeString , addr lpszProgID
; invoke SysFreeString , addr lpszMember
invoke CoUninitialize
ret
main endp
end start
Quote from: japheth on January 11, 2014, 07:57:16 PM
The functions called so far don't require BSTRs, just wide strings.
I get error 80020006, which means that name "NameSpace" is unknown ( sounds plausible):
...
I removed those unnecessary calls - SysAllocString, SysFreeString
As to "NameSpace" member of Shell.Application object - it does exist.
I've got the following CPP code working on XP SP3:
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <Objbase.h>
#pragma comment (lib,"Ole32.lib")
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
// Get clsid from name
CLSID clsid;
CLSIDFromProgID(L"shell.application",&clsid);
// Create instance
IDispatch *obj=NULL;
CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,__uuidof(IDispatch),(void**)&obj);
HRESULT hresult;
OLECHAR FAR* szMember = (OLECHAR*)L"NameSpace";
DISPID dispid;
hresult = obj->GetIDsOfNames(IID_NULL, &szMember, 1,LOCALE_SYSTEM_DEFAULT, &dispid) ;
return 0;
}
My results for posted fixes:
@dedndave : crash (i.e. I'm seeing WerFault.exe's dialog)
@Japheth : 80020006 (DISP_E_UNKNOWNNAME)
@jj2007 : 80070057 (declared in windows.inc as E_INVALIDARG )
I debugged my code and discovered that shell32 compares its own _GUID_NULL not with IID_NULL but with rgszNames string or even with part of "Press any key to continue ..." string . It makes me think that the problem is in parameters and stack balance .
Having working CPP code makes the task much simpler .
I'll report my results
Thank you all :t
Quote from: vertograd on January 11, 2014, 10:15:19 PM
I've got the following CPP code working on XP SP3:
Ok, your C++ sample reveals what's wrong in the assembly source - an incorrect "level of indirection".
This should work:
include \masm32\include\masm32rt.inc
includelib \wininc\lib\msvcrt.lib
printf proto c :vararg
;###############################################################################################
;METHOD macro by qWord
METHOD MACRO name,args:VARARG
LOCAL _type1,_type2
_type1 TYPEDEF PROTO args
_type2 TYPEDEF PTR _type1
EXITM <name _type2 ?>
ENDM
L macro parms:VARARG
local wstr
wstr textequ <>
for parm,<parms>
ifidn <">,@SubStr(parm,1,1)
% forc chr$, <@SubStr(parm,2,@SizeStr(parm)-2)>
ifnb wstr
wstr CatStr wstr,<,>
endif
wstr CatStr wstr,<'&chr$'>
endm
else
ifnb wstr
wstr CatStr wstr,<,>
endif
wstr CatStr wstr,<parm>
endif
endm
exitm <wstr>
endm
CStr macro text:vararg
local xxx
.const
xxx db text,0
.code
exitm <offset xxx>
endm
;###############################################################################################
;IDispatch interface
IDispatch STRUCT
METHOD(QueryInterface, _this:LPVOID,riid:LPVOID,ppvObj:LPVOID)
METHOD(AddRef, _this:LPVOID)
METHOD(Release, _this:LPVOID)
METHOD(GetTypeInfoCount, _this:LPVOID,pctinfo:UINT)
METHOD(GetTypeInfo, _this:LPVOID,iTInfo:UINT,lcid:LCID,ppTInfo:LPVOID)
METHOD(GetIDsOfNames, _this:LPVOID,riid:LPVOID,rgszNames:LPOLESTR,cNames:UINT,lcid:LCID,rgDispId:LPVOID)
METHOD(dInvoke, _this:LPVOID,dispIdMember:DWORD,riid:LPVOID,lcid:LCID,wFlags:DWORD,pDispParams:LPVOID,pVarResult:LPVOID,pExcepInfo:LPVOID,puArgErr:UINT)
IDispatch ENDS
;###############################################################################################
.data
IID_IDispatch GUID <00020400h,0000h,0000h,<0C0h,0h,0h,0h,0h,0h,0h,46h>>
IID_NULL GUID <00000000h,0000h,0000h,<0h,0h,0h,0h,0h,0h,0h,0h>>
wszCls dw L("Shell.Application"),0
wszNS dw L("NameSpace"),0
itemtab label ptr
dd wszNS
dd 0
.data?
; lpszProgID dd ?
; lpszMember dd ?
DISPID dd ?,?
pclsid dd ?
ppv dd ?
.code
start:
; cls
call main
; inkey
exit
main proc
invoke CLSIDFromProgID,addr wszCls,addr pclsid
.if eax != S_OK
invoke printf, CStr("CLSIDFromProgID FAILED, eax=%X",10), eax
ret
.endif
print "CLSIDFromProgID : SUCCESS",13,10,0
invoke CoInitialize,NULL
invoke CoCreateInstance,addr pclsid,
NULL,
1, ;CLSCTX_INPROC_SERVER,
addr IID_IDispatch,
addr ppv
.if eax != S_OK
invoke printf, CStr("CoCreateInstance FAILED, eax=%X",10), eax
ret
.endif
invoke printf, CStr( "CoCreateInstance: SUCCESS",10 )
; ------------------------------------------------------------------------;
; invoke IDispatch_GetIDsOfNames, riid, rgszNames, cNames, lcid, rgDispId ;
; ------------------------------------------------------------------------;
; push 0 ; program terminates abnormally without it :-\
; push offset DISPID ; rgDispId
; push 800h ; lcid
; push 1 ; cNames
; push eax ; rgszNames
; push offset IID_NULL ; riid
; mov edx, dword ptr [ppv]; pointer to IDispatch
; mov eax, [edx]
; mov edx, dword ptr [eax+20] ; offset of GetIDsOfNames
; call edx
mov edx,ppv
mov ecx,[edx]
INVOKE [ecx].IDispatch.GetIDsOfNames,edx,offset IID_NULL,addr itemtab,1,800h,offset DISPID
.if eax != S_OK
invoke printf, CStr("GetIDsOfNames FAILED, eax=%X",10), eax
jmp _exit
.endif
print "GetIDsOfNames : SUCCESS",13,10,0
_exit:
; invoke SysFreeString , addr lpszProgID
; invoke SysFreeString , addr lpszMember
invoke CoUninitialize
ret
main endp
end start
Quote from: japheth on January 11, 2014, 10:40:17 PM
This should work:
Replace all printf with crt_printf, and comment out the printf PROTO, and it works on Masm32.
Japheth and Jochen !
Thank you both :t
Now it works fine and I'm to do the next step - IDispatch_Invoke :biggrin:
Quote from: vertograd on January 11, 2014, 11:06:03 PM
Japheth and Jochen !
Thank you both :t
Now it works fine and I'm to do the next step - IDispatch_Invoke :biggrin:
so, i'm chopped liver ?
Quote from: dedndave on January 12, 2014, 12:01:06 AM
Quote from: vertograd on January 11, 2014, 11:06:03 PM
Japheth and Jochen !
Thank you both :t
Now it works fine and I'm to do the next step - IDispatch_Invoke :biggrin:
so, i'm chopped liver ?
Dave, certainly not!
Quote from: vertograd on January 11, 2014, 10:15:19 PM
Thank you all :t
I'm greatly appreciate your help
Thank you, Dave :t
:P
Quote from: japheth on January 11, 2014, 10:40:17 PMOk, your C++ sample reveals what's wrong in the assembly source - an incorrect "level of indirection".
More precisely, it is the "NameSpace" string that played foul. This works:
rgDispId equ <DISPID>
lcid equ 800h
cNames equ 1
rgszNames equ <eax>
riid equ <offset IID_NULL>
mov edx, ppv
mov ecx, [edx]
push uc$("NameSpace") ; create a slot on the stack containing the address of "NameSpace"
mov eax, esp ; eax is now pointer to the slot containing the address of the Unicode "NameSpace"
invoke [ecx].IDispatch.GetIDsOfNames, edx, riid, eax, cNames, lcid, addr rgDispId
pop edx
It worked for me , Jochen :t
QuotergDispId equ <offset DISPID>
Finally I've found out what was wrong with my code . Here's my fixed and working 0x0BADC0DE :
Quote
; -----------------------------------------------------------------------------------;
; invoke IDispatch GetIDsOfNames, riid, rgszNames, cNames, lcid, rgDispId ;
; -----------------------------------------------------------------------------------;
push uc$("NameSpace") ; Jochen's idea
mov eax ,esp ;
push offset DISPID
push 409h
push 1
push eax
push offset IID_NULL
mov edx, ppv
mov ecx, [edx]
push edx ; I tried this but didn't insert "pop edx" after the call
call dword ptr [ecx+20] ; offset of GetIDsOfNames
pop edx
.if eax != S_OK
printf("GetIDsOfNames : FAILED 0x%08X\n ",eax)
jmp _exit
.endif
Quote from: vertograd on January 13, 2014, 12:53:13 AM
It worked for me , Jochen :t
Good ;)
Japheth had the idea, though, I just showed it in more detail.
I wonder if one day I'll understand the superior conceptual logic behind that COM "pointer to a pointer to a pointer" stuff ::)
Quote from: jj2007 on January 13, 2014, 04:31:27 AM
I wonder if one day I'll understand the superior conceptual logic behind that COM "pointer to a pointer to a pointer" stuff ::)
In this particular case it's simple, since not a single string but an array of strings (names) is passed to the function. So the pointer points at the first string pointer in the array.
Point taken, thanks Yuri :P