flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Extended headers and extra imports

Author
Thread Post new topic Reply to topic
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 13 Apr 2010, 10:33
In Windows forum mindcooler has raised interesting question: How do I import CommandLineToArgvW from shell32.dll?
While it seems to involve editing of API\SHELL32.INC, some macro voodoo looks like to work:
Code:
;;; This file is named "Win32WX+.Inc"

; These symbolic constants will collect additional libraries/imports
irp lib, kernel32,user32,gdi32,advapi32,comctl32,comdlg32,shell32,wsock32 {
  additional_#lib#_imports equ
}
additional_libs equ

;;;
;;; Support macros (actually strucs ;-)
;;;

struc reequ [value] {
common
  restore .; «value» should not depend on equated symbolic constant, to keep it simple
  . equ value
}

struc append [items] {
; assumes list is initialized (at least empty, not undefined)
common
  match items_value, items \{; got something to append
    match list_value, . \\{; both non-empty, concatenate with comma
      . reequ list_value, items_value
    \\}
    match , . \\{; list was empty, simply equate
      . reequ items
    \\}
  \}
}

struc if_in_list item, [list] {
common
  . equ 0
forward
  match =item, list \{ . reequ 1 \}
}

struc if_odd_in_list item, [first, second] {
common
  . reequ 0
forward
  match =item, first \{ . reequ 1 \}
}

;;;
;;; Some real things
;;;

macro library [lib, name] {
; Instead of generating import directory, collect lib names in additional_libs
common local .done
forward
  .done if_in_list lib, kernel32,user32,gdi32,advapi32,comctl32,comdlg32,shell32,wsock32
  ; just in case somebody forgot that they're imported by default
  match =0, .done \{; not standard lib
    additional_libs append lib, name
    match =additional_#lib#_imports,\; clumsy way to check for undefined equ
           additional_#lib#_imports \\{
      ; «import» before «library»
      additional_#lib#_imports equ
    \\}
  \}
  restore .done
}

macro import lib, [functions] {
; Similar to «library» above, collect imports
common
  local .done
  .done if_in_list lib, kernel32,user32,gdi32,advapi32,comctl32,comdlg32,shell32,wsock32
  match =1, .done \{ additional_#lib#_imports append functions \}
  match =0, .done \{; not standard lib
    match .libs, additional_libs \\{; dereference libraries list
      .done if_odd_in_list lib, .libs
    \\}
    match =0, .done \\{; «import» before «library»
      match =additional_#lib#_imports,\; clumsy way to check for undefined equ
             additional_#lib#_imports \\\{
        additional_#lib#_imports equ
      \\\}
    \\}
    additional_#lib#_imports append functions
  \}
}

macro .end label {
  purge library, import; flush collectors down the drain, real workers on the way

  macro library [args] \{
  \common
    match .libs, additional_libs \\{
      library args, .libs
    \\}
    match , additional_libs \\{
      library args
    \\}
  \}

  macro import lib, [functions] \{
  \common
    local .done
    .done if_in_list lib, kernel32,user32,gdi32,advapi32,comctl32,comdlg32,shell32,wsock32
    match =1, .done \\{; got standard lib
      match .imports, additional_\#lib\#_imports \\\{; got imports to add
        import lib, functions, .imports
      \\\}
      match , additional_\#lib\#_imports \\\{; got nothing
        import lib, functions
      \\\}
    \\}
    match =0,.done \\{; not standard lib
      import lib, functions
    \\}
    restore .done
  \}

  macro additional_libs_imports [lib, name] \{
    match .imports, additional_\#lib\#_imports \\{
      import lib, .imports
      restore additional_\#lib\#_imports
    \\}
  \}

  .end label

  match .libs, additional_libs \{
    additional_libs_imports .libs
  \}
  purge library, import, additional_libs_imports; work is done, so are the workers
}    
Code:
;;; This is test example
        format  PE console
        include "Win32WX.Inc"
        include "Win32WX+.Inc"

        import  shell32, CommandLineToArgvW, "CommandLineToArgvW"; quite unusual?
        import  MSVCRT, _wprintf, "wprintf"; "Curiouser and curiouser!"
        import  MSVCRT, _putws, "_putws"
        library MSVCRT, "MSVCRT"

        .code

test_it:
        invoke  CommandLineToArgvW, <invoke GetCommandLine>, argc
        mov     esi, eax
        cinvoke _wprintf, msg_argc, [argc]
        .repeat
          cinvoke _putws, dword[esi]
          add     esi, 4
          dec     [argc]
        .until  ZERO?
        ret

        .data
msg_argc TCHAR  "argc=%u", 10, 0
        align   4
argc    rd      1

        .end    test_it    
Probably this can be of interest for someone.
Post 13 Apr 2010, 10:33
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 14 Apr 2010, 21:35
I was toying with above macros and contrived another trick: why should I insert those library and import things? Let invoke do it!
Code:
;;; This file is named "Win32W+.Inc", because it really doesn't depend on A/W

; These symbolic constants will collect additional libraries/imports
irp lib, kernel32,user32,gdi32,advapi32,comctl32,comdlg32,shell32,wsock32 {
  additional_#lib#_imports equ
}
additional_libs equ

;;;
;;; Support macros (actually strucs ;-)
;;;

struc reequ [value] {
common
  restore .; «value» should not depend on equated symbolic constant, to keep it simple
  . equ value
}

struc append [items] {
; assumes list is initialized (at least empty, not undefined)
common
  match items_value, items \{; got something to append
    match list_value, . \\{; both non-empty, concatenate with comma
      . reequ list_value, items_value
    \\}
    match , . \\{; list was empty, simply equate
      . reequ items
    \\}
  \}
}

struc if_in_list item, [list] {
common
  . equ 0
forward
  match =item, list \{ . reequ 1 \}
}

struc if_odd_in_list item, [first, second] {
common
  . equ 0
forward
  match =item, first \{ . reequ 1 \}
}

;;;
;;; Some real things
;;;

macro library [lib, name] {
; Instead of generating import directory, collect lib names in additional_libs
common local .done
forward
  .done if_in_list lib, kernel32,user32,gdi32,advapi32,comctl32,comdlg32,shell32,wsock32
  ; just in case somebody forgot that they're imported by default
  match =0, .done \{; not standard lib
;;;---
;;; That was original line, unconditionally append libname
;;;
;;; additional_libs append lib, name
;;;+++
;;; This code is added: now we can have several <library> invocations for the same library,
;;; so check for duplicate should be done.
;;;
    match .libs, additional_libs \\{; dereference libraries list
      .done if_odd_in_list lib, .libs
    \\}
    match =0, .done \\{
      additional_libs append lib, name
    \\}
;;;===
    match =additional_#lib#_imports,\; clumsy way to check for undefined equ
        additional_#lib#_imports \\{
      ; «import» before «library»
      additional_#lib#_imports equ
    \\}
  \}
  restore .done
}

macro import lib, [function] {
; Similar to «library» above, collect imports
common
  local .done
  .done if_in_list lib, kernel32,user32,gdi32,advapi32,comctl32,comdlg32,shell32,wsock32
  match =1, .done \{ additional_#lib#_imports append function \}
  match =0, .done \{; not standard lib
    match .libs, additional_libs \\{; dereference libraries list
      restore .done
      .done if_odd_in_list lib, .libs
    \\}
    match =0, .done \\{; «import» before «library»
      match =additional_#lib#_imports,\; clumsy way to check for undefined equ
         additional_#lib#_imports \\\{
  additional_#lib#_imports equ
      \\\}
    \\}
    match .imports, additional_#lib#_imports \\{
forward
      restore .done
      .done if_in_list function, .imports
      match =0, .done \\\{
        additional_#lib#_imports append function
      \\\}
common
    \\}
    match , additional_#lib#_imports \\{
      additional_#lib#_imports append function
    \\}
  \}
  restore .done
}

macro .end label {
  purge library, import; flush collectors down the drain, real workers on the way

  macro library [args] \{
  \common
    match .libs, additional_libs \\{
      library args, .libs
    \\}
    match , additional_libs \\{
      library args
    \\}
  \}

  macro import lib, [functions] \{
  \common
    local .done
    .done if_in_list lib, kernel32,user32,gdi32,advapi32,comctl32,comdlg32,shell32,wsock32
    match =1, .done \\{; got standard lib
      match .imports, additional_\#lib\#_imports \\\{; got imports to add
       import lib, functions, .imports
      \\\}
      match , additional_\#lib\#_imports \\\{; got nothing
       import lib, functions
      \\\}
    \\}
    match =0,.done \\{; not standard lib
      import lib, functions
    \\}
    restore .done
  \}

  macro additional_libs_imports [lib, name] \{
    match .imports, additional_\#lib\#_imports \\{
      import lib, .imports
      restore additional_\#lib\#_imports
    \\}
  \}

  .end label

  match .libs, additional_libs \{
    additional_libs_imports .libs
  \}
  purge library, import, additional_libs_imports; work is done, so are the workers
}

;;;+++
;;; Redefine macros to accept lib::function name syntax and add import
;;;
irps invoke_macro, invoke cinvoke {
  macro invoke_macro name,[args] \{
  \common
    \local .done
    .done equ 0
    match lib=:=:function, name \\{
      library lib,\\`lib
      import  lib,function,\\`function
      invoke_macro function,args
      .done reequ 1
    \\}
    match =0, .done \\{ invoke_macro name,args \\}
    restore .done
  \}
}
;;;===
;;; That's all, folks!    
Now test example looks as follows:
Code:
        format  PE console
        include "Win32WX.Inc"
        include "Win32X+.Inc"

        .code

test_it:
        invoke  shell32::CommandLineToArgvW, <invoke GetCommandLine>, argc
        mov     esi, eax
        cinvoke MSVCRT::wprintf, msg_argc, [argc]
        .repeat
          cinvoke MSVCRT::_putws, dword[esi]
          add     esi, 4
          dec     [argc]
        .until  ZERO?
        ret

        .data
msg_argc TCHAR  "argc=%u", 10, 0
        align   4
argc    rd      1

        .end    test_it    
EDIT: handled case of duplicate «library»::«function» usage (though «library»::«function» can be passed to invoke/cinvoke only once anywhere in the program and used simply as «function» elsewhere).
Post 14 Apr 2010, 21:35
View user's profile Send private message Reply with quote
mindcooler



Joined: 01 Dec 2009
Posts: 423
Location: Västerås, Sweden
mindcooler 07 May 2010, 00:39
I really think fasmw needs complete win32/64 headers, or a really easy way of appending to the import lists not to lose its conciseness.

_________________
This is a block of text that can be added to posts you make.
Post 07 May 2010, 00:39
View user's profile Send private message Visit poster's website MSN Messenger ICQ Number Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 07 May 2010, 13:39
mindcooler,

What do you mean, "complete"? Platform SDK contains ~1.8 million lines of .h, even if only 5% of them is relevant for FASM, that's almost ten-fold increase of API include files length. Would you take the burden of conversion?

However, public repository of community-made include files (not only for Win32/64) can be helpful. It's maintenance that frightens me.
Quote:
…a really easy way of appending to the import lists not to lose its conciseness.
How easy should it be? Easier than one include and «library::» prefix in invoke/cinvoke once for each imported function?
Post 07 May 2010, 13:39
View user's profile Send private message Reply with quote
mindcooler



Joined: 01 Dec 2009
Posts: 423
Location: Västerås, Sweden
mindcooler 07 May 2010, 14:43
baldr wrote:

What do you mean, "complete"? Platform SDK contains ~1.8 million lines of .h, even if only 5% of them is relevant for FASM, that's almost ten-fold increase of API include files length. Would you take the burden of conversion?


Perhaps not an all-encompassing win32, but complete entries (w2k+) for the DLLs already headered in fasm.

Wasn't there a header conversion tool project somewhere?

baldr wrote:

However, public repository of community-made include files (not only for Win32/64) can be helpful. It's maintenance that frightens me.
How easy should it be? Easier than one include and «library::» prefix in invoke/cinvoke once for each imported function?


Not to depreciate your solution, personally I would prefer something like this:
Code:
include 'win32wxp.inc'  
import shell32,CommandLineToArgvW,'CommandLineToArgvW',2
import "someobscure.dll",SomeObscureFunction,'SomeObscureFunction'[,PCOUNT]
    

_________________
This is a block of text that can be added to posts you make.
Post 07 May 2010, 14:43
View user's profile Send private message Visit poster's website MSN Messenger ICQ Number Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 07 May 2010, 17:54
mindcooler,

Those macros do almost as you wish. I'd rather not modify standard import arguments' signature, probably this will do?
Code:
import  rtl60="rtl60.bpl",\
        Move(3), "@System@Move$qqrpxvpvi",\
        UnicodeNToUtf8(4), "@System@UnicodeToUtf8$qqrpcuipbui"
;...
import  rtl60,\
        UnicodeToUtf8(3), "@System@UnicodeToUtf8$qqrpcpbi"    
First «name»="«string»" (="«string»" is optional if already used in import macro) gives pair for old library macro, following «label»(«count»), "«string»" gives pairs for old import macro and value for «label»% constant.

These functions use Borland fastcall calling conventions, another macro (bfinvoke)? Or better, calling convention can be declared right in import statement, saved in some constant and recognized by invoke macro.

System::UnicodeToUtf8() is polymorphic, thus different labels.
Post 07 May 2010, 17:54
View user's profile Send private message Reply with quote
mindcooler



Joined: 01 Dec 2009
Posts: 423
Location: Västerås, Sweden
mindcooler 07 May 2010, 19:44
Yeah, something like that would be great.

I will probably not be using borland libraries, but there doesn't seem to be a fastcall macro, direct or indirect, in proc32.inc. I take that it isn't that common.
Post 07 May 2010, 19:44
View user's profile Send private message Visit poster's website MSN Messenger ICQ Number Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.