Author Topic: COM interface plugin  (Read 2571 times)

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 8889
  • Assembler is fun ;-)
    • MasmBasic
COM interface plugin
« on: June 09, 2017, 10:23:40 PM »
This should work on any machine that has a VC installation - shout foul if it doesn't:

- extract the DLL from attachment to \Masm32\MasmBasic\Plugins\GetComInterface.dll
- launch \Masm32\MasmBasic\RichMasm.exe
- select text such as IFilterGraph, IDispatch, IWebBrowser2, etc...
- go to menu System & Plugins and click on Get COM interface

(background: I needed the IGraphBuilder interface, so I went to MSDN and copied the members by hand. Disgusting experience, and my code crashed. So I checked, and checked, and checked three times, until I vaguely remembered that I had stumbled over this problem before... the reason for my crashes was that MSDN lists the members, but not in the correct order. It's Micros**t... :()

P.S.: Pick version 2 below, called GetComInterfacePlugin.zip - autocorrection for members called "invoke" or "pause".

mabdelouahab

  • Member
  • ***
  • Posts: 397
Re: COM interface plugin
« Reply #1 on: June 10, 2017, 12:34:20 AM »
strmif.h (IGraphBuilder : public IFilterGraph)
Code: [Select]
typedef struct IGraphBuilderVtbl
    {
        BEGIN_INTERFACE
       
        HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
            IGraphBuilder * This,
            /* [in] */ REFIID riid,
            /* [annotation][iid_is][out] */
            __RPC__deref_out  void **ppvObject);
       
        ULONG ( STDMETHODCALLTYPE *AddRef )(
            IGraphBuilder * This);
       
        ULONG ( STDMETHODCALLTYPE *Release )(
            IGraphBuilder * This);
       
        HRESULT ( STDMETHODCALLTYPE *AddFilter )(
            IGraphBuilder * This,
            /* [in] */ IBaseFilter *pFilter,
            /* [string][in] */ LPCWSTR pName);
       
        HRESULT ( STDMETHODCALLTYPE *RemoveFilter )(
            IGraphBuilder * This,
            /* [in] */ IBaseFilter *pFilter);
       
        HRESULT ( STDMETHODCALLTYPE *EnumFilters )(
            IGraphBuilder * This,
            /* [annotation][out] */
            __out  IEnumFilters **ppEnum);
       
        HRESULT ( STDMETHODCALLTYPE *FindFilterByName )(
            IGraphBuilder * This,
            /* [string][in] */ LPCWSTR pName,
            /* [annotation][out] */
            __out  IBaseFilter **ppFilter);
       
        HRESULT ( STDMETHODCALLTYPE *ConnectDirect )(
            IGraphBuilder * This,
            /* [in] */ IPin *ppinOut,
            /* [in] */ IPin *ppinIn,
            /* [annotation][unique][in] */
            __in_opt  const AM_MEDIA_TYPE *pmt);
       
        HRESULT ( STDMETHODCALLTYPE *Reconnect )(
            IGraphBuilder * This,
            /* [in] */ IPin *ppin);
       
        HRESULT ( STDMETHODCALLTYPE *Disconnect )(
            IGraphBuilder * This,
            /* [in] */ IPin *ppin);
       
        HRESULT ( STDMETHODCALLTYPE *SetDefaultSyncSource )(
            IGraphBuilder * This);
       
        HRESULT ( STDMETHODCALLTYPE *Connect )(
            IGraphBuilder * This,
            /* [in] */ IPin *ppinOut,
            /* [in] */ IPin *ppinIn);
       
        HRESULT ( STDMETHODCALLTYPE *Render )(
            IGraphBuilder * This,
            /* [in] */ IPin *ppinOut);
       
        HRESULT ( STDMETHODCALLTYPE *RenderFile )(
            IGraphBuilder * This,
            /* [in] */ LPCWSTR lpcwstrFile,
            /* [annotation][unique][in] */
            __in_opt  LPCWSTR lpcwstrPlayList);
       
        HRESULT ( STDMETHODCALLTYPE *AddSourceFilter )(
            IGraphBuilder * This,
            /* [in] */ LPCWSTR lpcwstrFileName,
            /* [annotation][unique][in] */
            __in_opt  LPCWSTR lpcwstrFilterName,
            /* [annotation][out] */
            __out  IBaseFilter **ppFilter);
       
        HRESULT ( STDMETHODCALLTYPE *SetLogFile )(
            IGraphBuilder * This,
            /* [in] */ DWORD_PTR hFile);
       
        HRESULT ( STDMETHODCALLTYPE *Abort )(
            IGraphBuilder * This);
       
        HRESULT ( STDMETHODCALLTYPE *ShouldOperationContinue )(
            IGraphBuilder * This);
       
        END_INTERFACE
    } IGraphBuilderVtbl;

    interface IGraphBuilder
    {
        CONST_VTBL struct IGraphBuilderVtbl *lpVtbl;
    };


jj2007

  • Moderator
  • Member
  • *****
  • Posts: 8889
  • Assembler is fun ;-)
    • MasmBasic
Re: COM interface plugin
« Reply #2 on: June 10, 2017, 02:47:40 AM »
What is the problem? I get this:
Code: [Select]
IGraphBuilder STRUCT
QueryInterface dd ?
AddRef dd ?
Release dd ?
AddFilter dd ?
RemoveFilter dd ?
EnumFilters dd ?
FindFilterByName dd ?
ConnectDirect dd ?
Reconnect dd ?
Disconnect dd ?
SetDefaultSyncSource dd ?
Connect dd ?
Render dd ?
RenderFile dd ?
AddSourceFilter dd ?
SetLogFile dd ?
Abort dd ?
ShouldOperationContinue dd ?
IGraphBuilder ENDS

Siekmanski

  • Member
  • *****
  • Posts: 1706
Re: COM interface plugin
« Reply #3 on: June 10, 2017, 02:52:49 AM »
Maybe have a look at my directshow webcam example. It uses the IGraphBuilder interface.

Webcam: http://masm32.com/board/index.php?topic=4858.msg52908#msg52908
Creative coders use backward thinking techniques as a strategy.

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 8889
  • Assembler is fun ;-)
    • MasmBasic
Re: COM interface plugin
« Reply #4 on: June 10, 2017, 03:49:41 AM »
You mean this one? How did you generate it?
Code: [Select]
_vtIGraphBuilder MACRO CastName:REQ
    _vtIUnknown CastName
    &CastName&_AddFilter                comethod3 ?
    &CastName&_RemoveFilter             comethod2 ?
    &CastName&_EnumFilters              comethod2 ?
    &CastName&_FindFilterByName         comethod3 ?
    &CastName&_ConnectDirect            comethod4 ?
    &CastName&_Reconnect                comethod2 ?
    &CastName&_Disconnect               comethod2 ?
    &CastName&_SetDefaultSyncSource     comethod1 ?
    &CastName&_Connect                  comethod3 ?
    &CastName&_Render                   comethod2 ?
    &CastName&_RenderFile               comethod3 ?
    &CastName&_AddSourceFilter          comethod4 ?
    &CastName&_SetLogFile               comethod2 ?
    &CastName&_Abort                    comethod1 ?
    &CastName&_ShouldOperationContinue  comethod1 ?
ENDM

Siekmanski

  • Member
  • *****
  • Posts: 1706
Re: COM interface plugin
« Reply #5 on: June 10, 2017, 04:49:12 AM »
I got it from "strmif.h" and converted it by hand to asm so i could use it with the coinvoke macro.
The interface GUIDS are in it as well.

Code: [Select]
    MIDL_INTERFACE("56a868a9-0ad4-11ce-b03a-0020af0ba770")
    IGraphBuilder : public IFilterGraph

#define IGraphBuilder_QueryInterface(This,riid,ppvObject) \
    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )

#define IGraphBuilder_AddRef(This) \
    ( (This)->lpVtbl -> AddRef(This) )

#define IGraphBuilder_Release(This) \
    ( (This)->lpVtbl -> Release(This) )


#define IGraphBuilder_AddFilter(This,pFilter,pName) \
    ( (This)->lpVtbl -> AddFilter(This,pFilter,pName) )

#define IGraphBuilder_RemoveFilter(This,pFilter) \
    ( (This)->lpVtbl -> RemoveFilter(This,pFilter) )

#define IGraphBuilder_EnumFilters(This,ppEnum) \
    ( (This)->lpVtbl -> EnumFilters(This,ppEnum) )

#define IGraphBuilder_FindFilterByName(This,pName,ppFilter) \
    ( (This)->lpVtbl -> FindFilterByName(This,pName,ppFilter) )

#define IGraphBuilder_ConnectDirect(This,ppinOut,ppinIn,pmt) \
    ( (This)->lpVtbl -> ConnectDirect(This,ppinOut,ppinIn,pmt) )

#define IGraphBuilder_Reconnect(This,ppin) \
    ( (This)->lpVtbl -> Reconnect(This,ppin) )

#define IGraphBuilder_Disconnect(This,ppin) \
    ( (This)->lpVtbl -> Disconnect(This,ppin) )

#define IGraphBuilder_SetDefaultSyncSource(This) \
    ( (This)->lpVtbl -> SetDefaultSyncSource(This) )


#define IGraphBuilder_Connect(This,ppinOut,ppinIn) \
    ( (This)->lpVtbl -> Connect(This,ppinOut,ppinIn) )

#define IGraphBuilder_Render(This,ppinOut) \
    ( (This)->lpVtbl -> Render(This,ppinOut) )

#define IGraphBuilder_RenderFile(This,lpcwstrFile,lpcwstrPlayList) \
    ( (This)->lpVtbl -> RenderFile(This,lpcwstrFile,lpcwstrPlayList) )

#define IGraphBuilder_AddSourceFilter(This,lpcwstrFileName,lpcwstrFilterName,ppFilter) \
    ( (This)->lpVtbl -> AddSourceFilter(This,lpcwstrFileName,lpcwstrFilterName,ppFilter) )

#define IGraphBuilder_SetLogFile(This,hFile) \
    ( (This)->lpVtbl -> SetLogFile(This,hFile) )

#define IGraphBuilder_Abort(This) \
    ( (This)->lpVtbl -> Abort(This) )

#define IGraphBuilder_ShouldOperationContinue(This) \
    ( (This)->lpVtbl -> ShouldOperationContinue(This) )


Creative coders use backward thinking techniques as a strategy.

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 8889
  • Assembler is fun ;-)
    • MasmBasic
Re: COM interface plugin
« Reply #6 on: June 10, 2017, 05:31:15 AM »
I got it from "strmif.h" and converted it by hand to asm

That's what I tried, too - but I am lazy, so I coded a plugin. There are over 400 header files that contain OLE interfaces, with over 100,000 members :biggrin:

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 8889
  • Assembler is fun ;-)
    • MasmBasic
Re: COM interface plugin
« Reply #7 on: November 25, 2017, 05:03:45 PM »
Attachment #1 has a new version of the GetComInterface plugin; extract the DLL as \Masm32\MasmBasic\Plugins\GetComInterface.dll, then restart RichMasm with DSound8.asc file from the second attachment.

How does it work?
The IDirectSound8 is not included in the Masm32 SDK (this is one of the rare things that are missing - Hutch has included almost everything relevant :t). So what to do?

- select IDirectSound8 in your source
- click menu System & Plugins/Get COM interface
- when you see the MessageBox, click OK to copy it
- paste it on top of your code
- use with CoInvoke as demonstrated below

include \masm32\MasmBasic\MasmBasic.inc         ; download
include MiscDsound.inc

  SetGlobals pDs8, dscaps:DSCAPS
  Init
  .if !rv(DirectSoundCreate8, 0, addr pDs8, 0)
        m2m dscaps.dwSize, DSCAPS       ; this structure must be initialised
        CoInvoke pDs8, IDirectSound8.GetCaps, addr dscaps
        deb 4, "IDirectSound8.GetCaps", dscaps.dwMinSecondarySampleRate, dscaps.dwMaxSecondarySampleRate
  .endif
EndOfCode


Output on my machine:
Code: [Select]
IDirectSound8.GetCaps
dscaps.dwMinSecondarySampleRate 100
dscaps.dwMaxSecondarySampleRate 200000

jj2007

  • Moderator
  • Member
  • *****
  • Posts: 8889
  • Assembler is fun ;-)
    • MasmBasic
The mysteries of COM
« Reply #8 on: April 20, 2018, 03:40:19 AM »
Here is a simple program that opens a Microsoft Internet Explorer window and loads a well-known web page:

include \masm32\MasmBasic\MasmBasic.inc
  Init                          ; ## COM demo: open Internet Explorer ##
  invoke OleInitialize, NULL
  .if eax==S_OK
        push Chr$("http://masm32.com/board/index.php?action=unread")
        call MyBrowser
  .endif
  invoke OleUninitialize
  Exit

CLSID_IExplorer        GuidFromString("0002DF01-0000-0000-C000-000000000046")  ; either use quoted text syntax or...
IID_IWebBrowser2       GuidFromString({D30C1661-CDAF-11D0-8A3E-00C04FC9E26E})  ; ... paste copied registry key name

MyBrowser proc uses esi url
LOCAL vEmpty:VARIANT, hWin
  ClearLocals
  push eax                      ; create a DWORD variable on the stack
  ; now ask the OS gently to create a table with addresses that you can call to configure your Explorer Window (MSDN)
  invoke CoCreateInstance, addr CLSID_IExplorer, NULL, CLSCTX_LOCAL_SERVER, addr IID_IWebBrowser2, esp  ; esp is the address of that variable
  pop esi                               ; CoCreateInstance has filled the variable with the address to the vtable
  pInterface equ esi
  .if eax==S_OK
       CoInvoke pInterface, IWebBrowserVtbl.put_StatusBar, VARIANT_FALSE       ; OK, now configure the browser
       CoInvoke pInterface, IWebBrowserVtbl.put_MenuBar, VARIANT_TRUE          ; false = no menu
       CoInvoke pInterface, IWebBrowserVtbl.put_Visible, VARIANT_TRUE
       ; CoInvoke pInterface, IWebBrowserVtbl.get_HWND, addr hWin              ; optional: get handle of the Explorer window
        lea edx, vEmpty         ; Navigate needs pointers to four empty VARIANTS
       ; Ole$(url): COM wants a BSTR, so the ANSI URL needs to be converted
       CoInvoke pInterface, IWebBrowserVtbl.Navigate, Ole$(url), edx, edx, edx, edx
  .endif
  ret
MyBrowser endp
end start


If you love cryptic jargon, open the MSDN link above; otherwise, continue reading: What does this code do?
- after initialisation, it pushes the URL and calls MyBrowser
- push eax decreases esp and thus creates a DWORD slot for the OS
- CoCreateInstance uses the two GUID identifiers to find out what the user wants, and then fills the DWORD slot with a pointer to a so-called "interface"
- we pop that pointer into esi
- CoInvoke pInterface, IWebBrowserVtbl.put_StatusBar, VARIANT_FALSE does the following:
  - it pushes one argument on the stack (VARIANT_FALSE)
  - it gets the address of a proc called "put_StatusBar" that needs one argument on the stack:
Code: [Select]
push 0                      ; VARIANT_FALSE
push esi                    ; pInterface
mov eax, [esi]              ; get first DWORD from that interface
call near [eax+0AC]         ; call the address in the put_StatusBar offset

That's all, folks. It is that simple.

Now one might ask the developers of COM why CoCreateInstance needs the address of a variable to deliver pInterface, instead of simply returning it in eax. The answer will be "it's by design" or "why do something simple if there is a more complicated way?". Redmond speaking... 8)