News:

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

Create folder list from INI file

Started by otisbee, December 16, 2011, 11:38:48 AM

Previous topic - Next topic

otisbee

Hi,

The following code creates each folder listed in an INI file. I would like to modify it so that it looks for the INI file in the folder where the application is located.

Something like argv[0] and replace extension with .ini

This is my first program and is just some other examples from this forum put together.

Please let me know if there is anything else that looks wrong or how to make the application smaller?

Thanks.


include \masm32\include\masm32rt.inc

.code
start:

; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Main proc

    LOCAL pMem  :DWORD
    LOCAL rpos  :DWORD
    LOCAL buffer[MAX_PATH]:BYTE

    mov pMem, InputFile("%SystemRoot%\system32\profiles.ini")  ; load the INI file into memory
    mov rpos, 0                         ; zero the read position pointer
    test ecx,ecx
    jz next

my_loop:
    mov rpos, linein$(pMem,ADDR buffer,rpos)
    lea esi,buffer
    invoke lstrlen,addr buffer
    .IF eax==0
        jmp next
    .ENDIF
    cmp byte ptr [esi],'['
    jz my_loop
    call ExpandEnvironmentFileSpec
    print "Creating "
    print esi, ": "
    push esi
    call MakeDir
    .if eax==FILE_ATTRIBUTE_DIRECTORY
        print str$(eax), " - success!!", 13, 10
    .else
        print str$(eax), " - failed!!", 13, 10
    .endif

jmp my_loop
next:
    free pMem                           ; free the memory

close:
    invoke ExitProcess,0
    ret

Main endp

; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

align 16
MakeDir proc ; arg is pPath; returns 16 if success, zero for failure
push esi
push edi
push ebx
push ecx
mov ebx, esp ; shortest solution
sub esp, MAX_PATH ; create a buffer for the copy
mov edi, esp ; edi points to buffer
invoke lstrcpy, edi, [ebx+4*4+4] ; src=pPath
xchg ecx, len(edi) ; set counter for scasb
push edi
pop esi
NxtFile: mov al, "\"
repne scasb ; find the next backslash
dec edi
.if byte ptr [edi-1]!=":" && esi!=edi ; drives and leading \ should be ignored
.if !ecx && [edi]!=al ; last element may or may not have backslash
inc edi
.endif
mov byte ptr [edi], 0 ; zero-delimit current path
push ecx
invoke GetFileAttributes, esi
pop ecx
.if eax==INVALID_FILE_ATTRIBUTES ; folder not found
push ecx
invoke CreateDirectory, esi, 0
pop ecx
test eax, eax
je @Err
mov al, FILE_ATTRIBUTE_DIRECTORY ; folder successfully created
.endif
and eax, FILE_ATTRIBUTE_DIRECTORY ; really a folder?
je @Err
mov byte ptr [edi], "\" ; restore full path
.endif
inc edi
test ecx, ecx
ja NxtFile
@Err: mov esp, ebx
pop ecx
pop ebx
pop edi
pop esi
retn 4
MakeDir endp

; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

align 16
ExpandEnvironmentFileSpec proc
    local bFileSpec[MAX_PATH]: byte

    invoke ExpandEnvironmentStrings, esi, addr bFileSpec, sizeof bFileSpec
    invoke lstrcpy, esi, addr bFileSpec

    ret
ExpandEnvironmentFileSpec endp

; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start

fearless

I use the following code (as part of custom lib of mine) to create a .ini file for my programs. It looks for an .ini file with the same name as the .exe (without the .exe part). Ive tried to make it winxp/vista aware - hope that is useful to you or others.

CreateIniFilename           PROTO :DWORD

.486                     
.model flat, stdcall      ; memory model & calling convention
option casemap :none      ; case sensitive
include windows.inc
include kernel32.inc
includelib kernel32.lib
include shell32.inc
includelib shell32.lib
include masm32.inc
includelib masm32.lib



.data
szBackSlash         db "\",0
szIni               db ".ini",0
szExe               db ".exe",0

.code
;-------------------------------------------------------------------------------------
; Creates the ini filename based on the current exe filename
; WinXP/Vista/Win7 Compatible
; Will create a <progname>.ini file in a specific folder depending on your
; operating system, where <progname> is the name of your program's exe:
;
; - Windows 2000/NT/XP: current folder that the <progname>.exe is ran from
; - Vista: C:\Documents & Settings\<Your Username>\Application Data\<progname> folder
; - Windows 7: C:\Users\<Your Username>\AppData\Roaming\<progname> folder
;
;
;-------------------------------------------------------------------------------------
CreateIniFilename PROC szIniFilename:DWORD
    LOCAL VersionInformation:OSVERSIONINFO
    LOCAL ModuleFullPathname[MAX_PATH]:BYTE
    LOCAL ModuleName[MAX_PATH]:BYTE
    LOCAL ppidl:DWORD
    LOCAL hInst:DWORD

    LOCAL PosFullStop:DWORD
    LOCAL PosBackSlash:DWORD
    LOCAL StartPos:DWORD
    LOCAL SubStringLength:DWORD   

    Invoke GetModuleFileName, NULL, Addr ModuleFullPathname, Sizeof ModuleFullPathname

    ;=============================================
    ; Get Module Name from the last \ to the .
    ;=============================================
    xor ecx, ecx ; counter for position
    lea ebx, ModuleFullPathname

again:
    xor eax, eax
    mov al, byte ptr [ebx]
    .IF eax==46
        jmp ok
    .ELSE
        inc ebx
        inc ecx
        jmp again
    .ENDIF
ok:
    mov PosFullStop, ecx
    ; Find backslash postion
    mov ecx, PosFullStop
    lea ebx, ModuleFullPathname
    add ebx, PosFullStop
again2:
    xor eax, eax
    mov al, byte ptr [ebx]
    .IF eax==92
        jmp ok2
    .ELSE
        dec ebx
        dec ecx
        jmp again2
    .ENDIF
ok2:
    mov PosBackSlash, ecx
    inc ecx ; start position within string is backslash + 1
    mov StartPos, ecx

    mov eax, PosFullStop
    mov edx, PosBackSlash
    sub eax, edx ; length
    dec eax
    mov SubStringLength, eax ; Len is (posfullstop - backslash )-1
    lea ebx, ModuleFullPathname
    Invoke szMid, Addr ModuleFullPathname, Addr ModuleName, StartPos, SubStringLength
    ;=============================================


    mov  VersionInformation.dwOSVersionInfoSize, SIZEOF OSVERSIONINFO
    Invoke GetVersionEx, Addr VersionInformation
    mov eax, VersionInformation.dwMajorVersion
   
    .IF eax > 5 ; Vista / Win7
        Invoke GetModuleHandle, NULL
        mov hInst, eax
        Invoke SHGetSpecialFolderLocation, hInst, CSIDL_APPDATA, Addr ppidl
        Invoke SHGetPathFromIDList, ppidl, szIniFilename
        Invoke szCatStr, szIniFilename, Addr szBackSlash
        Invoke szCatStr, szIniFilename, Addr ModuleName
        Invoke GetFileAttributes, szIniFilename
        .IF eax != FILE_ATTRIBUTE_DIRECTORY
            Invoke CreateDirectory, szIniFilename, NULL
        .ENDIF
        Invoke szCatStr, szIniFilename, Addr szBackSlash
        Invoke szCatStr, szIniFilename, Addr ModuleName
        invoke szCatStr, szIniFilename, Addr szIni

    .ELSE ; WinXP
        Invoke szRep, Addr ModuleFullPathname, szIniFilename, Addr szExe, Addr szIni
    .endif

    ret
CreateIniFilename endp

END



Example Usage:

.data
MYPROG_INI_FILENAME          db 512 dup 0 ; long enough for .ini file

.code
Invoke CreateIniFileName, Addr MYPROG_INI_FILENAME
; Now we can read .ini - for instance using GetPrivateProfileString to check starting options for our program
ƒearless

evlncrn8

well, storing in the system32 folder might cause you problems with access rights on vista etc..

fearless

i concur. best place it somewhere you know will have full access, putting it in system folders is just going to cause you more hassle.
ƒearless

otisbee

@fearless, thanks, your code works as expected, the final .exe is about 4k, it would be nice to make it smaller. Would the .exe be smaller if i removed masm32rt.inc and added the individual include files, or maybe use some other compile/link options?

dedndave

the libs won't make a difference
if you don't reference a module, it doesn't get pulled in

however, you can combine sections to make it smaller
an easy way is to use PoLink instead of Link

polink /SUBSYSTEM:WINDOWS MyFile.obj

the same thing can be accomplished using Link...

Link /SUBSYSTEM:WINDOWS /OPT:NOREF /MERGE:.data=.text /ALIGN:4 MyFile.obj