Hi,...this one's got me baffled (but, then almost everything on this planet does). :dazzled:
I'm writing a COM client app in which the user can select a COM Class from the Registry's CLSID key enumeration (this is an extension of the app I wrote in this thread, COM View, Revisited (http://masm32.com/board/index.php?topic=4394.0)).
Anyway, I'm attempting to instantiate the COM object from the CLSID, and I tried two methods:
- Creating a Class Moniker, with CreateClassMoniker (https://msdn.microsoft.com/en-us/library/windows/desktop/ms688698(v=vs.85).aspx), and then calling IMoniker::BindToObject (https://msdn.microsoft.com/en-us/library/windows/desktop/ms691433(v=vs.85).aspx) to get a pointer to the COM Class (supplying IID IUnknown as the interface reference).
- Calling CoCreateInstance (https://msdn.microsoft.com/en-us/library/windows/desktop/ms686615(v=vs.85).aspx) supplying the COM Class CLSID and the IID for IUnknown as the interface reference.
Weirdly and unexpectedly,...the first Class Moniker technique crashes my app with an
Access Denied exception,...
...and, the second technique (CoCreateInterface works perfectly),...
This doesn't make any sense to me,...:dazzled:
Here is the code that crashes my app (this is the classic QWORD technique):
The BindContext (PtrBindContx) was created with CreateBindCtx (no error returned). I even prototyped the IBindCtx interface,...
; mov esi, PtrCLSIDMoniker ; The interface pointer to the new class moniker (IMoniker pointer), returned from CreateClassMoniker.
; mov esi, [esi] ; ptr IMoniker vtbl
; invoke [esi].IMoniker.BindToObject, PtrCLSIDMoniker, ADDR PtrBindContx, NULL, ADDR IID_IUnknown, ADDR PtrIUnknown
; mov dwRetBindObj, eax
; .IF dwRetBindObj==S_OK
; invoke LogEntry, ADDR szSUCSMnkrBndObj
; .ELSE
; invoke LogEntry, ADDR szFAILMnkBndObj
; JMP ReleaseMoniker
; .ENDIF
...And, yes,...I prototyped the IMoniker interface as a MASM structure,...
IMoniker STRUCT
METHOD(QueryInterface, _this:PVOID, riid:ptr GUID, ppvObj:ptr LPVOID)
METHOD(AddRef, _this:PVOID)
METHOD(Release, _this:PVOID)
METHOD(BindToObject, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, riidResult:REFIID, ppvResult:DWORD) ; ppvResult is an interface pointer
METHOD(BindToStorage, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, riid:REFIID, ppvObj:DWORD) ; ppvObj is an interface pointer
METHOD(Reduce, _this:PVOID, IBindCtx:DWORD, dwReduceHowFar:DWORD, ppmkToLeft:DWORD, ppmkReduced:DWORD) ; ppmkReduced is a pointer to an IMoniker pointer
METHOD(ComposeWith, _this:PVOID, pmkRight:DWORD, fOnlyIfNotGeneric:BOOL, ppmkComposite:DWORD) ; ppmkComposite is A pointer to an IMoniker pointer.
METHOD(Enum, _this:PVOID, fForward:BOOL, ppenumMoniker:DWORD) ; ppenumMoniker is a pointer to an IEnumMoniker pointer.
METHOD(IsEqual, _this:PVOID, pmkOtherMoniker:DWORD) ; pmkOtherMoniker is a pointer to an IMoniker interface.
METHOD(Hash, _this:PVOID, pdwHash:DWORD) ; pdwHash is a pointer to a variable that receives the hash value.
METHOD(IsRunning, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, pmkNewlyRunning:DWORD) ; Both pmkToLeft and pmkNewlyRunning are pointers to the IMoniker interface.
METHOD(GetTimeOfLastChange, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, pFileTime:DWORD) ; pmkToLeft is pointer to the moniker to the left of this moniker.
METHOD(Inverse, _this:PVOID, ppmk:DWORD) ; ppmk is The address of an IMoniker pointer.
METHOD(CommonPrefixWith, _this:PVOID, pmkOther:DWORD, ppmkPrefix:DWORD) ; Both are pointers to an IMoniker interface.
METHOD(RelativePathTo, _this:PVOID, pmkOther:DWORD, ppmkRelPath:DWORD) ; Both are pointers to an IMoniker interface.
METHOD(GetDisplayName, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, pszDisplayName:LPOLESTR) ; pszDisplayName is the address of a pointer variable that receives a pointer to the display name string for the moniker.
METHOD(ParseDisplayName, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, pszDisplayName:LPOLESTR, pchEaten:ULONG, ppmkOut:DWORD) ; ppmkOut is A pointer to an IMoniker pointer.
METHOD(IsSystemMoniker, _this:PVOID, pdwMksys:DWORD) ; pdwMksys is a pointer to a variables that receives one of the values from the MKSYS enumeration and refers to one of the COM moniker classes.
IMoniker ENDS
COM is hard - lol
let's see if any of this helps
one thing i see is the way you invoke
you need a THIS pointer - as i recall, it goes something like this...
mov esi,PtrCLSIDMoniker
mov ecx,[esi]
invoke Struct.Member[ecx],esi,.......
another thing that looks suspicious....
QuotepmkToLeft [in]
If the moniker is part of a composite moniker, pointer to the moniker to the left of this moniker. This parameter is primarily used by moniker implementers to enable cooperation between the various components of a composite moniker. Moniker clients should use NULL.
shouldn't you use NULL ?
https://msdn.microsoft.com/en-us/library/windows/desktop/ms691433%28v=vs.85%29.aspx (https://msdn.microsoft.com/en-us/library/windows/desktop/ms691433%28v=vs.85%29.aspx)
and, finally, the IID - i think it's actually a pointer to an IID
not sure about that one
Maybe you should replace: ADDR PtrBindContx by PtrBindContx in BindToObject
here is an example that i know works, showing the THIS pointer
mov edx,pvShell
mov ecx,[edx]
INVOKE IDispatch.GetIDsOfNames[ecx],edx,offset IID_NULL,offset adwObjSource,1,409h,offset adwDispIdSource
and the interface structures, using qWord's METHOD macro
;IUnknown Interface vTable (structure)
IUnknown STRUCT
METHOD(QueryInterface, _this:LPVOID,riid:LPVOID,ppvObj:LPVOID)
METHOD(AddRef, _this:LPVOID)
METHOD(Release, _this:LPVOID)
IUnknown ENDS
;IDispatch Interface vTable (structure)
IDispatch STRUCT
IUnknown <>
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
notice that i have riid typed as LPVOID - a pointer
i use LPVOID a lot, rather than defining all those types - lol
MABDELOUAHAB,
You're right,...I noticed that (I've done that on a number of occasions, using a pointer where I should just be supplying the variable). I changed the code, and I still got the same error.
But,...you know what I think the
REAL PROBLEM is ???
As my template for prototyping the IMoniker (https://msdn.microsoft.com/en-us/library/windows/desktop/ms679705(v=vs.85).aspx) interface into a MASM compatible structure, I used this interface definition from an old Japheth example (the include file, OBJIDL.INC):
;-----------------------------------------------------------------------------
; IMoniker interface
BEGIN_INTERFACE IMoniker, IPersistStream
STDMETHOD BindToObject, pbc:ptr IBindCtx, pmkToLeft:ptr IMoniker,riidResult:REFIID,ppvResult:ptr ptr
STDMETHOD BindToStorage, pbc:ptr IBindCtx, pmkToLeft:ptr IMoniker,riid:REFIID,ppvObj:ptr ptr
STDMETHOD Reduce, pbc:ptr IBindCtx, dwReduceHowFar:DWORD, ppmkToLeft:ptr ptr IMoniker, ppmkReduced:ptr ptr IMoniker
STDMETHOD ComposeWith, pmkRight:ptr IMoniker, fOnlyIfNotGeneric:BOOL, ppmkComposite:ptr ptr IMoniker
STDMETHOD Enum, fForward:BOOL, ppenumMoniker:ptr ptr IEnumMoniker
STDMETHOD IsEqual, pmkOtherMoniker:ptr IMoniker
STDMETHOD Hash, pdwHash:ptr DWORD
STDMETHOD IsRunning, pbc:ptr IBindCtx, pmkToLeft:ptr IMoniker, pmkNewlyRunning:ptr IMoniker
STDMETHOD GetTimeOfLastChange, pbc:ptr IBindCtx, pmkToLeft:ptr IMoniker, pFileTime:ptr FILETIME
STDMETHOD Inverse, ppmk:ptr ptr IMoniker
STDMETHOD CommonPrefixWith, pmkOther:ptr IMoniker, ppmkPrefix:ptr ptr IMoniker
STDMETHOD RelativePathTo, pmkOther:ptr IMoniker, ppmkRelPath:ptr ptr IMoniker
STDMETHOD GetDisplayName, pbc:ptr IBindCtx, pmkToLeft:ptr IMoniker, ppszDisplayName:ptr ptr WORD
STDMETHOD ParseDisplayName, pbc:ptr IBindCtx, pmkToLeft:ptr IMoniker, pszDisplayName:ptr WORD, pchEaten:ptr DWORD, ppmkOut:ptr ptr IMoniker
STDMETHOD IsSystemMoniker, pdwMksys:ptr DWORD
END_INTERFACE
But,...what I neglected was the critical fact that the IMoniker interface
inherits not only from the
IUnknown interface, but, also from the
IPersistStream interface, which Japheth defines like this:
BEGIN_INTERFACE IPersistStream, IUnknown
; IPersist methods
STDMETHOD GetClassID , pClsID:ptr GUID
; IPersistStream methods
STDMETHOD IsDirty
STDMETHOD Load , pStm:LPSTREAM
STDMETHOD Save , pStm:LPSTREAM, fClearDirty:BOOL
STDMETHOD GetSizeMax , pcbSize:ptr ULARGE_INTEGER
END_INTERFACE
From MSDN documentation:
QuoteA moniker object supports the IMoniker interface, which is derived from the IPersistStream interface and uniquely identifies a single object in the system.
...So,...DAVE,...was right:
QuoteCOM is hard - lol
...I would amend that to read: COM is HELL. War is HARD.
OK,...for you Hardcore COMsters,...that was actually the problem,...the IMoniker interface was not defined correctly.
I re-wrote it, and, it now looks like this:
IMoniker STRUCT
METHOD(QueryInterface, _this:PVOID, riid:ptr GUID, ppvObj:ptr LPVOID)
METHOD(AddRef, _this:PVOID)
METHOD(Release, _this:PVOID)
; Added methods from IPersist and IPersistStream.
METHOD(GetClassID, _this:PVOID, pClassID:CLSID)
METHOD(IsDirty, _this:PVOID)
METHOD(Load, _this:PVOID, pStm:DWORD) ; pStm is an IStream pointer.
METHOD(Save, _this:PVOID, pStm:DWORD, fClearDirty:BOOL) ; pStm is an IStream pointer.
METHOD(GetSizeMax, _this:PVOID, pcbSize:DWORD) ; pcbSize is pointer to ULARGE_INTEGER (The size in bytes of the stream needed to save this object).
METHOD(BindToObject, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, riidResult:REFIID, ppvResult:DWORD) ; ppvResult is an interface pointer
METHOD(BindToStorage, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, riid:REFIID, ppvObj:DWORD) ; ppvObj is an interface pointer
METHOD(Reduce, _this:PVOID, IBindCtx:DWORD, dwReduceHowFar:DWORD, ppmkToLeft:DWORD, ppmkReduced:DWORD) ; ppmkReduced is a pointer to an IMoniker pointer
METHOD(ComposeWith, _this:PVOID, pmkRight:DWORD, fOnlyIfNotGeneric:BOOL, ppmkComposite:DWORD) ; ppmkComposite is A pointer to an IMoniker pointer.
METHOD(Enum, _this:PVOID, fForward:BOOL, ppenumMoniker:DWORD) ; ppenumMoniker is a pointer to an IEnumMoniker pointer.
METHOD(IsEqual, _this:PVOID, pmkOtherMoniker:DWORD) ; pmkOtherMoniker is a pointer to an IMoniker interface.
METHOD(Hash, _this:PVOID, pdwHash:DWORD) ; pdwHash is a pointer to a variable that receives the hash value.
METHOD(IsRunning, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, pmkNewlyRunning:DWORD) ; Both pmkToLeft and pmkNewlyRunning are pointers to the IMoniker interface.
METHOD(GetTimeOfLastChange, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, pFileTime:DWORD) ; pmkToLeft is pointer to the moniker to the left of this moniker.
METHOD(Inverse, _this:PVOID, ppmk:DWORD) ; ppmk is The address of an IMoniker pointer.
METHOD(CommonPrefixWith, _this:PVOID, pmkOther:DWORD, ppmkPrefix:DWORD) ; Both are pointers to an IMoniker interface.
METHOD(RelativePathTo, _this:PVOID, pmkOther:DWORD, ppmkRelPath:DWORD) ; Both are pointers to an IMoniker interface.
METHOD(GetDisplayName, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, pszDisplayName:LPOLESTR) ; pszDisplayName is the address of a pointer variable that receives a pointer to the display name string for the moniker.
METHOD(ParseDisplayName, _this:PVOID, IBindCtx:DWORD, pmkToLeft:DWORD, pszDisplayName:LPOLESTR, pchEaten:ULONG, ppmkOut:DWORD) ; ppmkOut is A pointer to an IMoniker pointer.
METHOD(IsSystemMoniker, _this:PVOID, pdwMksys:DWORD) ; pdwMksys is a pointer to a variables that receives one of the values from the MKSYS enumeration and refers to one of the COM moniker classes.
IMoniker ENDS
And, this works as expected.
Hello,
This one is part of the full sdk translated.Look how they are translated can avoid all those troubles.
Quote from: dedndaveCOM is hard - lol
Quote from: Zen...I would amend that to read: COM is HELL. War is HARD.
- Ideas for bumper stickers:
"COM programmers get into heaven, because they've already served their time in hell"
"COM programmers do it the long, hard way"
Hi,...TOUTENMASM,
I completely forgot about the SDK Translator (and the huge number of translated files),...and, I have it saved to a folder on my computer,...:dazzled:
...And,...RRR314159,...COM programming in assembly is difficult because (as you know), there are no convenient include files included with everything pre-conceived for the programmer,...
No convenient way ?
With the translated SDK you have to:
Include objidl.sdk in your source
Get the pointer on the interface and put it in ppvImoniker and it's finish.
Now you can use the Imoniker Interface calling it by it's Name
Quote
Imoniker Release ;sample source code valuable for 64 or 32 bits