home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / LordLucifer / win32asm / tutorials / com_1.txt < prev    next >
Text File  |  2000-05-25  |  13KB  |  389 lines

  1. COM in ASM
  2. ------------------------------------------------------------------------------
  3.  
  4. This article will discuss how to use COM interfaces in your assembly language
  5. programs.  It will not discuss what COM is and how it is used, but rather how 
  6. it can be used when programming in assembler.  It will discuss only how to
  7. use existing interfaces, and not how to actually implement new ones; this will
  8. be shown in a future atricle.
  9.  
  10.  
  11. About COM
  12. ------------------------------------------------------------------------------
  13.  
  14. Here is a brief introduction to the basics behind COM.  
  15.  
  16. A COM object is one in which access to an object's data is achieved
  17. exclusively through one or more sets of related functions. These function
  18. sets are called interfaces, and the functions of an interface are called
  19. methods. COM requires that the only way to gain access to the methods of an
  20. interface is through a pointer to the interface. 
  21.  
  22. An interface is actually a contract that consists of a group of related 
  23. function prototypes whose usage is defined but whose implementation 
  24. is not. An interface definition specifies the interface's member functions, 
  25. called methods, their return types, the number and types of their parameters, 
  26. and what they must do. There is no implementation associated with an
  27. interface. An interface implementation is the code a programmer supplies to
  28. carry out the actions specified in an interface definition. 
  29.  
  30. An instance of an interface implementation is actually a pointer to an array 
  31. of pointers to methods (a function table that refers to an implementation of 
  32. all of the methods specified in the interface). Any code that has a pointer 
  33. through which it can access the array can call the methods in that interface. 
  34.  
  35.  
  36.  
  37. Using a COM object assembly language
  38. -------------------------------------------------------------------------------
  39.  
  40. Access to a COM object occurs through a pointer.  This pointer points to a
  41. table of function pointers in memory, called a virtual function table, or
  42. vtable in short.  This vtable contains the addresses of each of the objects
  43. methods. To call a method, you indirectly call it through this pointer table.
  44.  
  45. Here is an example of a C++ interface, and how its methods are called:
  46.  
  47.     interface IInterface
  48.     {
  49.              HRESULT QueryInterface( REFIID iid, void ** ppvObject );
  50.              ULONG AddRef();
  51.              ULONG Release();
  52.              Function1( INT param1, INT param2);
  53.              Function2( INT param1 );
  54.     }
  55.  
  56.     // calling the Function1 method
  57.     pObject->Function1( 0, 0);
  58.     
  59. Now here is how the same functionality can be implemented using assembly
  60. language:
  61.  
  62.     ; defining the interface
  63.         ; each of these values are offsets in the vtable
  64.         QueryInterface          equ             0h
  65.         AddRef                  equ             4h
  66.     Release            equ        8h
  67.     Function1        equ        0Ch
  68.     Function2        equ        10h
  69.             
  70.     ; calling the Function1 method in asm
  71.         ; the method is called by obtaining the address of the objects
  72.         ; vtable and then calling the function addressed by the proper
  73.         ; offset in the table
  74.     push    param2
  75.     push    param1
  76.         mov     eax, pObject
  77.     push    eax
  78.         mov     eax, [eax]
  79.     call    [eax + Function1]
  80.     
  81. You can see this is somewhat different than calling a function normally.
  82. Here, pObject points to the Interface's vTable.  At the Function1(0Ch) offset
  83. in this table is a pointer to the actual function we wish to call.
  84.  
  85.  
  86.  
  87. Using HRESULT's
  88. -------------------------------------------------------------------------------
  89.  
  90. The return value of OLE APIs and methods is an HRESULT. This is not a handle 
  91. to anything, but is merely a 32-bit value with several fields encoded in the 
  92. value.  The parts of an HRESULT are shown below.  
  93.  
  94. HRESULTs are 32 bit values layed out as follows:
  95.  
  96.  3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  97.  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
  98. +-+-+-+-+-+---------------------+-------------------------------+
  99. |S|R|C|N|r|    Facility         |               Code            |
  100. +-+-+-+-+-+---------------------+-------------------------------+
  101.  
  102.  S - Severity Bit 
  103.      Used to indicate success or failure
  104.      0 - Success
  105.      1 - Fail
  106.  
  107.      By noting that this bit is actually the sign bit of the 32-bit value, 
  108.      checking success/failure is simply performed by checking its sign:
  109.  
  110.      call       ComFunction        ; call the function
  111.      test       eax,eax            ; now check its return value
  112.      js         error              ; jump if signed (meaning error returned)
  113.      ; success, so continue
  114.     
  115.  R - reserved portion of the facility code, corresponds to NT's
  116.      second severity bit.
  117.  
  118.  C - reserved portion of the facility code, corresponds to NT's
  119.      C field.
  120.  
  121.  N - reserved portion of the facility code. Used to indicate a
  122.      mapped NT status value.
  123.  
  124.  r - reserved portion of the facility code. Reserved for internal
  125.      use. Used to indicate HRESULT values that are not status
  126.      values, but are instead message ids for display strings.
  127.  
  128.  Facility - is the facility code
  129.      FACILITY_WINDOWS    = 8
  130.      FACILITY_STORAGE    = 3
  131.      FACILITY_RPC        = 1
  132.      FACILITY_WIN32      = 7
  133.      FACILITY_CONTROL    = 10
  134.      FACILITY_NULL       = 0
  135.      FACILITY_ITF        = 4
  136.      FACILITY_DISPATCH   = 2
  137.  
  138.      To retreive the Facility, 
  139.      
  140.      call       ComFunction    ; call the function     
  141.      shr        eax, 16        ; shift the HRESULT to the right by 16 bits
  142.      and        eax, 1FFFh     ; mask the bits, so only the facility remains
  143.      ; eax now contains the HRESULT's Facility code
  144.  
  145.  Code - is the facility's status code
  146.     
  147.      To get the Facility's status code,
  148.      call       ComFunction             ; call the function
  149.      and    eax, 0000FFFFh        ; mask out the upper 16 bits
  150.      ; eax now contains the HRESULT's Facility's status code
  151.     
  152.     
  153.  
  154. Using COM with MASM
  155. ------------------------------------------------------------------------------
  156. If you use MASM to assemble your programs, you can use some of its
  157. capabilities to make calling COM functions very easy.  Using invoke, you can
  158. make COM calls look almost as clean as regular calls, plus you can add type
  159. checking to each function.
  160.  
  161.  
  162. Defining the interface:
  163.  
  164.      IInterface_Function1Proto     typedef proto :DWORD
  165.      IInterface_Function2Proto     typedef proto :DWORD, :DWORD
  166.     
  167.      IInterface_Function1          typedef ptr IInterface_Function1Proto
  168.      IInterface_Function2          typedef ptr IInterface_Function2Proto
  169.  
  170.      IInterface struct DWORD
  171.            QueryInterface          IUnknown_QueryInterface         ?
  172.            AddRef                  IUnknown_AddRef                 ?
  173.            Release                 IUnknown_Release                ?
  174.            Function1               IInterface_Function1            ?
  175.            Function2               Interface_Function2             ?
  176.      IInterface ends
  177.  
  178. Using the interface to call COM functions:
  179.  
  180.      mov     eax, pObject                   
  181.      mov     eax, [eax]
  182.      invoke  (IInterface [eax]).Function1, 0, 0
  183.  
  184. As you can see, the syntax may seem a bit strange, but it allows for a simple
  185. method using the function name itself instead of offsets, as well as type
  186. checking.
  187.  
  188.  
  189.  
  190. A Sample program written using COM
  191. ------------------------------------------------------------------------------
  192.  
  193. Here is some sample source code which uses COM written in straight assembly 
  194. language, so it should be compatable with any assembler you prefer with only 
  195. minor changes necessary.  
  196.  
  197. This program uses the Windows Shell Interfaces to show the contents of the
  198. Desktop folder in a window.  The program is not complete, but shows how the 
  199. COM library is initialized, de-initialized, and used. I also shows how the
  200. shell library is used to get folders and obcets, and how to perform 
  201. actions on them.
  202.  
  203.  
  204. .386
  205. .model flat, stdcall
  206.  
  207. include windows.inc        ; include the standard windows header
  208. include shlobj.inc        ; this include file contains the shell namespace 
  209.                                 ; definitions and constants
  210.  
  211. ;----------------------------------------------------------
  212. .data
  213.         wMsg                    MSG     <?>
  214.         g_hInstance             dd      ?
  215.     g_pShellMalloc        dd    ?
  216.  
  217.         pshf                    dd      ?       ; shell folder object
  218.         peidl                   dd      ?       ; enum id list object
  219.  
  220.         lvi                     LV_ITEM <?>
  221.         iCount                  dd      ?
  222.         strret                  STRRET  <?>
  223.         shfi                    SHFILEINFO <?>
  224.     ...
  225.     
  226. ;----------------------------------------------------------
  227. .code
  228. ; Entry Point
  229. start:                                          
  230.     push    0h
  231.     call    GetModuleHandle
  232.     mov     g_hInstance,eax
  233.            
  234.     call    InitCommonControls       
  235.         
  236. ; initialize the Component Object Model(COM) library
  237. ; this function must be called before any COM functions are called
  238.     push    0
  239.     call    CoInitialize
  240.     test    eax,eax                         ; error when the MSB = 1
  241.                                             ; (MSB = the sign bit) 
  242.     js      exit                            ; js = jump if signed
  243.  
  244. ; Get the Shells IMalloc object pointer, and save it to a global variable
  245.     push    offset g_pShellMalloc
  246.     call    SHGetMalloc
  247.     cmp     eax, E_FAIL
  248.     jz      shutdown
  249.     
  250.  
  251. ; here we would set up the windows, list view, message loop, and so on....
  252. ; we would also call the FillListView procedure...
  253. ; ....
  254.     
  255.  
  256. ; Cleanup
  257. ; Release IMalloc Object pointer
  258.     mov     eax, g_pShellMalloc
  259.     push    eax
  260.     mov     eax, [eax]
  261.     call    [eax + Release]         ; g_pShellMalloc->Release();
  262.     
  263. shutdown:    
  264. ; close the COM library
  265.     call    CoUninitialize 
  266.          
  267. exit:
  268.     push    wMsg.wParam
  269.     call    ExitProcess
  270. ; Program Terminates Here
  271.  
  272.  
  273. ;----------------------------------------------------------
  274. FillListView proc
  275.  
  276. ; get the desktop shell folder, saved to pshf
  277.     push    offset pshf
  278.     call    SHGetDesktopFolder
  279.     
  280. ; get the objects of the desktop folder using the EnumObjects method of
  281. ; the desktop's shell folder object
  282.     push    offset peidl    
  283.     push    SHCONTF_NONFOLDERS
  284.     push    0
  285.     mov     eax, pshf
  286.     push    eax
  287.     mov     eax, [eax]
  288.     call    [eax + EnumObjects]
  289.     
  290.     xor     ebx, ebx ;use ebx for the counter
  291.     
  292. ; now loop through the enum id list
  293. idlist_loop:
  294. ; Get next id list item
  295.     push    0                       
  296.     push    offset pidl             
  297.     push    1                       
  298.     mov     eax, peidl 
  299.     push    eax                     
  300.     mov     eax, [eax]
  301.     call    [eax + Next]
  302.     test    eax,eax
  303.     jnz     idlist_endloop
  304.  
  305.     mov     lvi.imask, LVIF_TEXT or LVIF_IMAGE
  306.     mov     lvi.iItem, ebx
  307.                                     
  308. ; Get the item's name by using the GetDisplayNameOf method
  309.     push    offset strret
  310.     push    SHGDN_NORMAL
  311.     push    offset pidl
  312.     mov     eax, pshf
  313.     push    eax
  314.     mov     eax, [eax]
  315.     call    [eax + GetDisplayNameOf]
  316. ; GetDisplayNameOf returns the name in 1 of 3 forms, so get the correct
  317. ; form and act accordingly
  318.     cmp     strret.uType, STRRET_CSTR
  319.     je      strret_cstr
  320.     cmp     strret.uType, STRRET_OFFSET
  321.     je      strret_offset
  322.     
  323. strret_olestr:
  324.     ; here you could use WideCharToMultiByte to get the string,
  325.     ; I have left it out because I am lazy
  326.     jmp     strret_end
  327.     
  328. strret_cstr:
  329.     lea     eax, strret.cStr
  330.     jmp     strret_end
  331.                         
  332. strret_offset:
  333.     mov     eax, pidl
  334.     add     eax, strret.uOffset
  335.     
  336. strret_end:    
  337.     mov     lvi.pszText, eax
  338.     
  339. ; Get the items icon
  340.     push    SHGFI_PIDL or SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_ICON
  341.     push    sizeof SHFILEINFO
  342.     push    offset shfi
  343.     push    0
  344.     push    pidl
  345.     call    SHGetFileInfo
  346.     mov     eax, shfi.iIcon
  347.     mov     lvi.iImage, eax
  348.  
  349. ; now add item to the list
  350.     push    offset lvi
  351.     push    0
  352.     push    LVM_INSERTITEM
  353.     push    hWndListView
  354.     call    SendMessage 
  355.  
  356. ; increment counter ebx and repeat the loop    
  357.     inc     ebx, ebx
  358.     jmp     idlist_loop
  359.  
  360. idlist_endloop:
  361.  
  362. ; now free the enum id list
  363. ; Remember all allocated objects must be released...
  364.     mov     eax, peidl
  365.     push    eax
  366.     mov     eax,[eax]
  367.     call    [eax + Release]
  368.        
  369. ; free the desktop shell folder object
  370.     mov     eax, pshf
  371.     push    eax
  372.     mov     eax,[eax]
  373.     call    [eax + Release]
  374.     
  375.     ret
  376. FillListView endp
  377.  
  378.  
  379. END start
  380.  
  381.  
  382. Conclusiom
  383. -------------------------------------------------------------------------------
  384.  
  385. Well, that is about it for using COM with assembly language.  Hopefully, my
  386. next article will go into how to define your own interfaces.  As you can
  387. see, using COM is not difficult at all, and with it you can add a very
  388. powerful capability to your assembly language programs.
  389.