News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Getting Command Line Arguments

Started by fallenhobbit, February 07, 2005, 11:44:43 AM

Previous topic - Next topic

fallenhobbit

This post is not a question. Its an example for newbies on how to get command line arguments under NT/XP. I need to do this for a new project and whipped this up today. NT and XP use unicode by default and so my first few attempts caused some memory exceptions. But I finally got some good stable code. In c++ you can ignore the fact that NT uses unicode. It gets translated for you. But when manipulating stack data passed to your program by the OS in assmebly, this is not a very good idea (as I learned).

Cheers,
fallenhobbit

[attachment deleted by admin]

Vortex

Hi fallenhobit,

Your DLL is a nice work. If it's possible, could you release the sources?

fallenhobbit

Vortex, the source for the dll is here:

http://students.csci.unt.edu/~jcb0075/fhcrtsrc.zip

It was actually pretty easy to write. I wrote a small c++ app that read in a list of prototypes for the exported c/c++ functions and just wrote out the assembly based on a basic asm proc template. I mention this because this basic technique could be used to wrap virtually any dll you can get an export list for. The basic idea is this: Use the dlltool (or some other tool like it) to get a .lib file for the target dll. The use hutchs lib2inc tool to get a prototype list for it. Then write a small c++ app that does what I did.

Cheers,
Fallenhobbit

Vortex

fallenhobit,

Thanks for the source code. Extracting a lib file from the target DLL is a problem because it's nearly impossible to guess the number of parameters of each exported function. To create an import library, you can use an inc2lib tool, check my website.

Your msvcrt.inc file contains external function declarations with no any calling convention. It's easy to get the function prototypes:

http://www.masmforum.com/simple/index.php?topic=480.msg3109#msg3109

ToutEnMasm

Hello,
Here is a piece of code written with masm32 and that accept win98 and XP.He have been improved more than two years without problems.
It's a proc,call it with two parameters
                     1) the number of the parameter ,the first,the second .....
                     2) the address of the buffer where to write the parameter
   sample:           invoke GetParaLigneCommande,0,addr buffer

                   Hélas, comment are in french


                         code
                 ;################################################################
            comment ?
Fonctionnement similaire a  GetCL de masmlib ,en acceptant les noms longs avec espaces,c'est a dire
en entree le numero de parametre voulu et l'adresse de la chaine ou ecrire la valeur du parametre
si le numero est egal a zero,renvoi le nom de l'executable
en retour ,eax = 0 pas de parametre,eax != 0 longueur de la chaine zero nom compris
            --------------------------
La distinction entre un nom de fichier et un parametre se fait par ":\"
DANS LES commandes de RACCOURCIS,on doit passer LE NOM COMPLET du FICHIER
sinon   le NOM de fichier COMPORTANT DES ESPACES SERA DECOUPE comme un parametre
Suivant le programme , le "  encadrant le nom de l'executable ,peut signifier pas d'autre parametres ou
l'inverse.Il faut visualiser la ligne (messagebox) sans parametres pour savoir dans quel cas on se trouve
Comment determiner par avance quel va etre la reaction du programme,secret microsoft.Vous avez la reponse
m'ecrire
içi les " ne sont pas interprétés comme le signe de présence ou non d'autres paramètres
ce qui permet de porter le sub dans n'importe quel programme
                ?
GetParaLigneCommande PROC   Numero:DWORD,AdrChaine:DWORD
        Local   AdrPara :DWORD   
        Local   Cpt:DWORD   
        Local   Trema:DWORD 
        Local   Pointeur:DWORD
        local    LongCommande:DWORD
        Local    LongPara:DWORD
        Local   Debutpara:DWORD
        Local   FinPara:DWORD
        Local phrase[MAX_PATH]:BYTE
        Local decompte:DWORD
        LOCAL   CHERCHEpara:WIN32_FIND_DATA
   
    invoke GetCommandLine
    mov AdrPara, eax                             ;adresse de la ligne de paramètres
        ;invoke MessageBox,NULL,AdrPara,SADD("Ligne de paramètres"),MB_OK
    mov esi,AdrPara
    xor eax,eax
    mov Cpt,eax
        mov Trema,eax
    invoke  lnstr,AdrPara                       ;la ligne de para se termine par zero(byte)
    mov LongCommande,eax

    ;fin init pointeurs et variables
    ;le premier parametre est le nom complet de l'executable entre deux " si autres para
    ;passer le nom de l'executable encadrer ou non par "
    ;la suite des parametres est empilé convention dos,separé par des espaces,que le nom de
    ;fichier comporte ou non des espaces,ceci pour win 98
        ;windows XP fonctionne différemment de 98
        ;dans XP , tous les parametres sont entre " ce qui empeche la confusion entre noms longs
        ;avec espace et paramametres.les noms passés sont en convention noms longs.
        ;Avec 98 les noms de fichiers sont en convention dos et il faut les traduire en nom longs
        ; nom de fichier long avec espaces peut etre confondu
        ;Le cas ou le parametre est un nom long sans " se présente sous 98 et XP lorsque l'on ajoute
        ;ce parametre a un raccourci au lieu de pointer le fichier et d'utiliser envoyer vers
        ;c'est ce problème que résout l'appel a findfirstfile permettant d'identifier un nom de
        ;fichier long ou un répertoire en tant que parametre.
        ;recherche le debut de para du nom d'executable
        cld
    mov esi,AdrPara
    mov Debutpara,esi
        @@:                          ;passer espaces tab de têtes de ligne , le "
        lodsb
        .if al == 20h || al == 34 || al == 9 ; jusqu'a la fin du nom d'executable
            .if al == 34
                mov Trema,1      ;signale la présence d'un tréma
            .endif
        jmp @B
    .endif
        dec esi
        mov Debutpara,esi            ;esi 1 letrre de l'executable
       
       
    mov al,"."
    cld
    mov edi,Debutpara
    mov ecx,LongCommande
    repnz scasb     ;edi pointe apres le "."         ;la ligne de parametre commence
    mov eax,edi                 ;par nomprog.exe(ppath.exe) qui n'est pas un parametre
    mov esi,eax
    @@:
    lodsb
    .if al == 0 || al == " " || al == 34    ;poursuivre jusqu'a la fin du nom d'executable
        jmp @F
    .else
        jmp @B
    .endif
    @@:
    dec esi
    mov Pointeur,esi            ;Pointeur apres .exe
        mov al,[esi]
        .if al == 34
            inc Pointeur            ;Pointeur apres le trema
        .endif
    mov ecx,esi
    sub ecx,Debutpara           ;nombre de caracteres du chemin executable
    mov LongPara,ecx            ;
    mov eax,Numero          ;
    .if eax == 0
        mov esi,Debutpara       ;si le numero de para demandé est zero renvoyé
        mov ecx,LongPara
        mov edi,AdrChaine
        cld
        rep movsb
        mov al,0
        stosb                    ;asciiz
        mov eax,LongPara
        ret
    .endif
    ;****************************** les parametres normaux ************************
    ;******************************************************************************

    ParametreSuivant:
    xor eax,eax
        mov Trema,eax
    ;avancé jusqu'au parametre suivant
    mov esi,Pointeur                 ;pointe le byte après le dernier parametre
    @@:
    cld
    lodsb
    .if al == 0                             ;fin de ligne de commande
        xor eax,eax
        jmp FindeGetParaLigneCommande
    .elseif al == " " || al == 34
            .if al == 34
                mov Trema,1                  ;signe XP le début du para est "
            .endif
        jmp @B
    .endif
    mov Debutpara,esi
    dec Debutpara                   ;un parametre existe
    mov ecx,LongCommande                ;decompte de caracteres restant a explorés
    add ecx,AdrPara
    sub ecx,Debutpara
    mov decompte,ecx
    ;cela peut etre un mot , un chemin ecrit en convention windows ou dos
    mov esi,Debutpara
        mov edi,Debutpara   
            ; trie les possibilités
                    ;la solution la plus simple XP
        ;-----------------------------------------------
        .if Trema == 1          ;la signature XP
                mov al,34
                cld
                repnz scasb
                mov Pointeur,edi         ;edi est après "
                mov ecx,edi
                dec ecx              ;ecx sur le "
                sub ecx,esi          ; esi début du mot
                push ecx                ;sauvegarde la longueur du mot
                mov esi,Debutpara
                lea edi,phrase
                cld
                mov decompte,ecx
                rep movsb
                mov al,0
                stosb                ;recopie le parametre dans phrase
                pop ecx
                jmp estcelebonnumerodepara
        .endif
        ;-----------------------------------------------           
                    ;WINDOWS 98
                    ;Nom chemin

    mov al,byte ptr [esi+1]
    .if al !=":"        ;le : peut etre un debut de chemin
        jmp Paranom
    .endif
    mov al,byte ptr [esi+2]
    .if al != "\"
        jmp Paranom         ; sequence :    .endif
    ;       ****** on est dans le cas d'un chemin convention dos ou windows *******
    ;dos        : envoyer vers (mettre le racourci dans windows\sendto )
    ;windows    : double clic sur fichier
    ; le but est de parcourir la chaine de droite a gauche en se positionnant sur les espaces
    ; et voir si l'intervalle entre debut de nom de fichier et espace correspond a un nom valide
    ; la longueur entre le debut et l'espace est limité a max-path
    ; ceci elimine les risques de coupures avec les fichiers comportant des espaces
    ;CELA OBLIGE A PASSER LE NOM COMPLET du FICHIER dans LES RACCOURCIS sinon
    ;LE NOM COMPORTANT DES ESPACES SERA DECOUPE
    mov eax,decompte
    .if eax > MAX_PATH
        mov eax,MAX_PATH
        mov decompte,eax
    .endif
    mov esi,Debutpara
    add esi,decompte
    mov ecx,decompte
    parcours:
    std                                 ;ouille?
    lodsb
    dec decompte
    ;il n'y a pas de
    .if al == 0 || al == " "
        mov Pointeur,esi
        mov ecx,esi
        inc ecx
        sub ecx,Debutpara   ;nombre de caracteres du chemin eventuel
        jmp @F
    .else
        mov eax,decompte
        .if eax != 0   
            jmp parcours
        .else
            ;pas de solution trouvée
            xor eax,eax
            jmp FindeGetParaLigneCommande
        .endif
       
    .endif
    @@:
    ;test pour voir si le fichier existe
    cld ;?
    mov esi,Debutpara
    lea edi,phrase
    cld
    rep movsb
    mov al,0
    stosb                   ;recopie le parametre suppose dans phrase
    invoke FindFirstFile,addr phrase,addr CHERCHEpara
    mov edx,eax
    push eax
    invoke  CloseHandle,edx
    mov ecx,decompte
    pop eax
    .if eax == INVALID_HANDLE_VALUE
        ;le parametre chemin est incomplet ou mal ecrit
        .if ecx == 0
            ; erreur de chemin annule le parametre
            xor eax,eax
            jmp FindeGetParaLigneCommande
        .else
            ;pousuivre la recherche le nom comporte un espace
            mov esi,Pointeur
            jmp parcours
        .endif
    .else
        ;le parametre est valide
        inc Cpt
        mov eax,Cpt
        cmp eax,Numero
        jz @F
            ;ce n'est pas le bon numero de para demandé
            .if ecx != 0
                inc Pointeur
                jmp ParametreSuivant   
            .else
                ;il n'y a plus de parametres
                xor eax,eax
                jmp FindeGetParaLigneCommande                   
            .endif
        @@:
        invoke  lstrcpy,AdrChaine,addr phrase
        mov eax,decompte
        jmp FindeGetParaLigneCommande

    .endif
   
    ;Bien que l'on puisse mettre un espace dans l'extension ,windows refuse de le passer en parametre
    ;auto (double clic)
   
                           
    Paranom:                 ;----------------------------para normal DOS ------------------
    mov ecx,LongCommande                ;decompte de caracteres restant a explorés
    add ecx,Debutpara
    sub ecx,AdrPara
    ;arret sur zero ou espace
    @@:
    cld
    lodsb
    .if al == 0 || al == " "
        mov Pointeur,esi                    ;pointeur byte après para
        jmp @F
    .endif
    loop @B
    ;ne devant pas se produire ecx=0 et al non zero
    xor eax,eax
    jmp FindeGetParaLigneCommande
    @@:
        ;le parametre est valide
    push ecx
    mov ecx,Pointeur
    sub ecx,Debutpara
    mov esi,Debutpara
    lea edi,phrase
    cld
    mov decompte,ecx
    rep movsb
    mov al,0
    stosb                   ;recopie le parametre dans phrase
    pop ecx
        estcelebonnumerodepara:
    inc Cpt
    mov eax,Cpt
    cmp eax,Numero
    jz @F
        ;ce n'est pas le bon numero de para demandé
        .if ecx != 0
            jmp ParametreSuivant   
        .else
            ;il n'y a plus de parametres
            xor eax,eax
            jmp FindeGetParaLigneCommande                   
        .endif
    @@:
        invoke  lstrcpy,AdrChaine,addr phrase
        mov eax,decompte

   
FindeGetParaLigneCommande:
         ret
GetParaLigneCommande endp

; #########################################################################




end code

Vortex

Hi fallenhobit,

I coded two different command line parameter parsers for console and GUI applications. They are a part of my tiny C executables project:

http://www.masmforum.com/simple/index.php?topic=166.0