please dont rip this site

Language Asm Masmwin Com COM_1.TXT


This article will discuss how to use COM interfaces in your assembly language
programs.  It will not discuss what COM is and how it is used, but rather how 
it can be used when programming in assembler.  It will discuss only how to
use existing interfaces, and not how to actually implement new ones; this will
be shown in a future atricle.

About COM

Here is a brief introduction to the basics behind COM.  

A COM object is one in which access to an object's data is achieved
exclusively through one or more sets of related functions. These function
sets are called interfaces, and the functions of an interface are called
methods. COM requires that the only way to gain access to the methods of an
interface is through a pointer to the interface. 

An interface is actually a contract that consists of a group of related 
function prototypes whose usage is defined but whose implementation 
is not. An interface definition specifies the interface's member functions, 
called methods, their return types, the number and types of their parameters, 
and what they must do. There is no implementation associated with an
interface. An interface implementation is the code a programmer supplies to
carry out the actions specified in an interface definition. 

An instance of an interface implementation is actually a pointer to an array 
of pointers to methods (a function table that refers to an implementation of 
all of the methods specified in the interface). Any code that has a pointer 
through which it can access the array can call the methods in that interface. 

Using a COM object assembly language

Access to a COM object occurs through a pointer.  This pointer points to a
table of function pointers in memory, called a virtual function table, or
vtable in short.  This vtable contains the addresses of each of the objects
methods. To call a method, you indirectly call it through this pointer table.

Here is an example of a C++ interface, and how its methods are called:

	interface IInterface
             HRESULT QueryInterface( REFIID iid, void ** ppvObject );
             ULONG AddRef();
             ULONG Release();
             Function1( INT param1, INT param2);
             Function2( INT param1 );

	// calling the Function1 method
	pObject->Function1( 0, 0);
Now here is how the same functionality can be implemented using assembly

	; defining the interface
        ; each of these values are offsets in the vtable
        QueryInterface          equ             0h
        AddRef                  equ             4h
	Release			equ		8h
	Function1		equ		0Ch
	Function2		equ		10h
	; calling the Function1 method in asm
        ; the method is called by obtaining the address of the objects
        ; vtable and then calling the function addressed by the proper
        ; offset in the table
	push	param2
	push	param1
        mov     eax, pObject
	push	eax
        mov     eax, [eax]
	call	[eax + Function1]
You can see this is somewhat different than calling a function normally.
Here, pObject points to the Interface's vTable.  At the Function1(0Ch) offset
in this table is a pointer to the actual function we wish to call.


The return value of OLE APIs and methods is an HRESULT. This is not a handle 
to anything, but is merely a 32-bit value with several fields encoded in the 
value.  The parts of an HRESULT are shown below.  

HRESULTs are 32 bit values layed out as follows:

 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|S|R|C|N|r|    Facility         |               Code            |

 S - Severity Bit 
     Used to indicate success or failure
     0 - Success
     1 - Fail

     By noting that this bit is actually the sign bit of the 32-bit value, 
     checking success/failure is simply performed by checking its sign:

     call       ComFunction        ; call the function
     test       eax,eax            ; now check its return value
     js         error              ; jump if signed (meaning error returned)
     ; success, so continue
 R - reserved portion of the facility code, corresponds to NT's
     second severity bit.

 C - reserved portion of the facility code, corresponds to NT's
     C field.

 N - reserved portion of the facility code. Used to indicate a
     mapped NT status value.

 r - reserved portion of the facility code. Reserved for internal
     use. Used to indicate HRESULT values that are not status
     values, but are instead message ids for display strings.

 Facility - is the facility code
     FACILITY_RPC        = 1
     FACILITY_WIN32      = 7
     FACILITY_NULL       = 0
     FACILITY_ITF        = 4

     To retreive the Facility, 
     call       ComFunction    ; call the function     
     shr        eax, 16        ; shift the HRESULT to the right by 16 bits
     and        eax, 1FFFh     ; mask the bits, so only the facility remains
     ; eax now contains the HRESULT's Facility code

 Code - is the facility's status code
     To get the Facility's status code,
     call       ComFunction             ; call the function
     and	eax, 0000FFFFh		; mask out the upper 16 bits
     ; eax now contains the HRESULT's Facility's status code

Using COM with MASM
If you use MASM to assemble your programs, you can use some of its
capabilities to make calling COM functions very easy.  Using invoke, you can
make COM calls look almost as clean as regular calls, plus you can add type
checking to each function.

Defining the interface:

     IInterface_Function1Proto     typedef proto :DWORD
     IInterface_Function2Proto     typedef proto :DWORD, :DWORD
     IInterface_Function1          typedef ptr IInterface_Function1Proto
     IInterface_Function2          typedef ptr IInterface_Function2Proto

     IInterface struct DWORD
           QueryInterface          IUnknown_QueryInterface         ?
           AddRef                  IUnknown_AddRef                 ?
           Release                 IUnknown_Release                ?
           Function1               IInterface_Function1            ?
           Function2               Interface_Function2             ?
     IInterface ends

Using the interface to call COM functions:

     mov     eax, pObject                   
     mov     eax, [eax]
     invoke  (IInterface [eax]).Function1, 0, 0

As you can see, the syntax may seem a bit strange, but it allows for a simple
method using the function name itself instead of offsets, as well as type

A Sample program written using COM

Here is some sample source code which uses COM written in straight assembly 
language, so it should be compatable with any assembler you prefer with only 
minor changes necessary.  

This program uses the Windows Shell Interfaces to show the contents of the
Desktop folder in a window.  The program is not complete, but shows how the 
COM library is initialized, de-initialized, and used. I also shows how the
shell library is used to get folders and obcets, and how to perform 
actions on them.

.model flat, stdcall

include		; include the standard windows header
include		; this include file contains the shell namespace 
                                ; definitions and constants

        wMsg                    MSG     <?>
        g_hInstance             dd      ?
	g_pShellMalloc		dd	?

        pshf                    dd      ?       ; shell folder object
        peidl                   dd      ?       ; enum id list object

        lvi                     LV_ITEM <?>
        iCount                  dd      ?
        strret                  STRRET  <?>
        shfi                    SHFILEINFO <?>
; Entry Point
    push    0h
    call    GetModuleHandle
    mov     g_hInstance,eax
    call    InitCommonControls       
; initialize the Component Object Model(COM) library
; this function must be called before any COM functions are called
    push    0
    call    CoInitialize
    test    eax,eax                         ; error when the MSB = 1
                                            ; (MSB = the sign bit) 
    js      exit                            ; js = jump if signed

; Get the Shells IMalloc object pointer, and save it to a global variable
    push    offset g_pShellMalloc
    call    SHGetMalloc
    cmp     eax, E_FAIL
    jz      shutdown

; here we would set up the windows, list view, message loop, and so on....
; we would also call the FillListView procedure...
; ....

; Cleanup
; Release IMalloc Object pointer
    mov     eax, g_pShellMalloc
    push    eax
    mov     eax, [eax]
    call    [eax + Release]         ; g_pShellMalloc->Release();
; close the COM library
    call    CoUninitialize 
    push    wMsg.wParam
    call    ExitProcess
; Program Terminates Here

FillListView proc

; get the desktop shell folder, saved to pshf
    push    offset pshf
    call    SHGetDesktopFolder
; get the objects of the desktop folder using the EnumObjects method of
; the desktop's shell folder object
    push    offset peidl    
    push    0
    mov     eax, pshf
    push    eax
    mov     eax, [eax]
    call    [eax + EnumObjects]
    xor     ebx, ebx ;use ebx for the counter
; now loop through the enum id list
; Get next id list item
    push    0                       
    push    offset pidl             
    push    1                       
    mov     eax, peidl 
    push    eax                     
    mov     eax, [eax]
    call    [eax + Next]
    test    eax,eax
    jnz     idlist_endloop

    mov     lvi.imask, LVIF_TEXT or LVIF_IMAGE
    mov     lvi.iItem, ebx
; Get the item's name by using the GetDisplayNameOf method
    push    offset strret
    push    SHGDN_NORMAL
    push    offset pidl
    mov     eax, pshf
    push    eax
    mov     eax, [eax]
    call    [eax + GetDisplayNameOf]
; GetDisplayNameOf returns the name in 1 of 3 forms, so get the correct
; form and act accordingly
    cmp     strret.uType, STRRET_CSTR
    je      strret_cstr
    cmp     strret.uType, STRRET_OFFSET
    je      strret_offset
    ; here you could use WideCharToMultiByte to get the string,
    ; I have left it out because I am lazy
    jmp     strret_end
    lea     eax, strret.cStr
    jmp     strret_end
    mov     eax, pidl
    add     eax, strret.uOffset
    mov     lvi.pszText, eax
; Get the items icon
    push    sizeof SHFILEINFO
    push    offset shfi
    push    0
    push    pidl
    call    SHGetFileInfo
    mov     eax, shfi.iIcon
    mov     lvi.iImage, eax

; now add item to the list
    push    offset lvi
    push    0
    push    LVM_INSERTITEM
    push    hWndListView
    call    SendMessage 

; increment counter ebx and repeat the loop	
    inc     ebx, ebx
    jmp     idlist_loop


; now free the enum id list
; Remember all allocated objects must be released...
    mov     eax, peidl
    push    eax
    mov     eax,[eax]
    call    [eax + Release]
; free the desktop shell folder object
    mov     eax, pshf
    push    eax
    mov     eax,[eax]
    call    [eax + Release]
FillListView endp

END start


Well, that is about it for using COM with assembly language.  Hopefully, my
next article will go into how to define your own interfaces.  As you can
see, using COM is not difficult at all, and with it you can add a very
powerful capability to your assembly language programs.

file: /Techref/language/asm/masmwin/com/com_1.txt, 12KB, , updated: 1999/10/8 16:01, local time: 2024/7/17 22:18,

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF=""> language asm masmwin com com_1</A>

Did you find what you needed?


Welcome to!


Welcome to!