Author Topic: COM Question -- Class Moniker  (Read 6005 times)

Zen

  • Member
  • ****
  • Posts: 962
  • slightly red-shifted
COM Question -- Class Moniker
« on: July 28, 2015, 04:56:08 AM »
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).
Anyway, I'm attempting to instantiate the COM object from the CLSID, and I tried two methods:
  • Creating a Class Moniker, with CreateClassMoniker, and then calling IMoniker::BindToObject to get a pointer to the COM Class (supplying IID IUnknown as the interface reference).
  • Calling CoCreateInstance 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,...
 
Code: [Select]
;      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,...

Code: [Select]
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
Zen

dedndave

  • Member
  • *****
  • Posts: 8828
  • Still using Abacus 2.0
    • DednDave
Re: COM Question -- Class Moniker
« Reply #1 on: July 28, 2015, 06:01:32 AM »
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...

Code: [Select]
mov     esi,PtrCLSIDMoniker
mov     ecx,[esi]
invoke  Struct.Member[ecx],esi,.......

another thing that looks suspicious....
Quote
pmkToLeft [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

and, finally, the IID - i think it's actually a pointer to an IID
not sure about that one

mabdelouahab

  • Member
  • ****
  • Posts: 511
Re: COM Question -- Class Moniker
« Reply #2 on: July 28, 2015, 06:03:33 AM »
Maybe you should replace: ADDR PtrBindContx by PtrBindContx in BindToObject

dedndave

  • Member
  • *****
  • Posts: 8828
  • Still using Abacus 2.0
    • DednDave
Re: COM Question -- Class Moniker
« Reply #3 on: July 28, 2015, 06:11:13 AM »
here is an example that i know works, showing the THIS pointer
Code: [Select]
            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

Code: [Select]
;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

Zen

  • Member
  • ****
  • Posts: 962
  • slightly red-shifted
Re: COM Question -- Class Moniker
« Reply #4 on: July 28, 2015, 06:15:34 AM »
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 interface into a MASM compatible structure, I used this interface definition from an old Japheth example (the include file, OBJIDL.INC):
Code: [Select]
;-----------------------------------------------------------------------------
; 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:
Code: [Select]
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:
Quote
A 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:
Quote
COM is hard - lol
...I would amend that to read: COM is HELL. War is HARD.
Zen

Zen

  • Member
  • ****
  • Posts: 962
  • slightly red-shifted
Re: COM Question -- Class Moniker
« Reply #5 on: July 28, 2015, 07:21:56 AM »
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:

Code: [Select]
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.
Zen

TouEnMasm

  • Member
  • *****
  • Posts: 1762
    • EditMasm
Re: COM Question -- Class Moniker
« Reply #6 on: July 28, 2015, 07:52:02 PM »
Hello,
This one is part of the full sdk translated.Look how they are translated can avoid all those troubles.


Fa is a musical note to play with CL

rrr314159

  • Member
  • *****
  • Posts: 1378
Re: COM Question -- Class Moniker
« Reply #7 on: July 29, 2015, 12:45:17 AM »
Quote from: dedndave
COM 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"
I am NaN ;)

Zen

  • Member
  • ****
  • Posts: 962
  • slightly red-shifted
Re: COM Question -- Class Moniker
« Reply #8 on: July 29, 2015, 06:13:04 AM »
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,...
Zen

TouEnMasm

  • Member
  • *****
  • Posts: 1762
    • EditMasm
Re: COM Question -- Class Moniker
« Reply #9 on: July 31, 2015, 08:14:01 PM »
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
Fa is a musical note to play with CL