Hi all,
i'm trying to figure out an easy way to get the filename given to my program. eg:
in C you could do:
int main(int argc,char *argv[])
{
printf("%s is the name of our file.",argv[0]);
return 0;
}
now if i would try to use an API for this i would get the complete path including name. then i would have to remove the path at first to extract the filename.
here are the API's i have used:
GetCommandLine
GetModuleFileName
GetShortPathName
i have even tried:
include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
invoke GetCL,0,addr buffer
but this returns also the complete path :(
any ideas?
Thanks in advance!
If the function is returning the complete path then strip the filename out of it, it is fairly easy as it will always begin with the last \
invoke lstrlen, offset FileName
mov ecx,eax
mov edi, offset FileName
add edi, ecx
mov eax,"\"
std
repne scasb
cld
; The filename portion will begin at EDI+2
Use invoke GetCommandLine. Eax is the pointer to the path null terminated string.
I used:
invoke GetFullPathName
invoke GetModuleFileName, hInst, addr file, sizeof file
invoke lstrlen, addr path
add eax, offset file
-> addr of filename in eax
or something similar.
But I found no direct way to obtain the filename without path.
If you need a direct way, just make your own proc with the code to get the filename and put it in the masm32 library. Then you can just call it to get the filename.
Another, perhaps more familiar, method. But unless I needed only the filename without the extension, I would use donkey's method because this method requires more memory and more code.
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\kernel32.inc
include \masm32\include\msvcrt.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib
include \masm32\macros\macros.asm
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
modpath db MAX_PATH dup(0)
moddrive db 0,0,0
moddir db MAX_PATH dup(0)
modfname db MAX_PATH dup(0)
modext db MAX_PATH dup(0)
.code
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke GetModuleFileName,0,ADDR modpath,MAX_PATH
print ADDR modpath
print chr$(13,10)
invoke _splitpath,ADDR modpath,
ADDR moddrive,
ADDR moddir,
ADDR modfname,
ADDR modext
print ADDR moddrive
print chr$(13,10)
print ADDR moddir
print chr$(13,10)
invoke szCatStr,ADDR modfname,ADDR modext
print ADDR modfname
mov eax,input(13,10,13,10,"Press enter to exit...")
exit
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
void _splitpath(
const char *path,
char *drive,
char *dir,
char *fname,
char *ext
);
i was afraid of that. i kindof hoped i could use a function which already exists since i'm working on several different machines and then i wouldn't have to make my own functions everytime i needed it.
but ok, i will do it with my own function then. Thanks for all responses :)
Well, unless you are changing architectures you can just put the function in a library and use it from that. I have a function that does this available in my files.lib library available from my website, it is both MASM and GoAsm compatible.
well i've already written a PROC:
;***********************************************************
;Get FileName procedure, returns eax as offset
;***********************************************************
GetFileName PROC
LOCAL FileName[2048] :BYTE
invoke GetModuleFileName,NULL,addr FileName,sizeof FileName
invoke lstrlen,addr FileName
mov ecx,eax
lea eax,FileName
add eax,ecx
next:
cmp byte ptr [eax],5Ch ;first '\' from the back
jz contin
dec eax
jmp next
contin:
inc eax
ret
GetFileName ENDP
;***********************************************************
what do you think of it?
white scorpion,
There is a procedure in the masm32 library called NameFromPath:
This is what it does:
; #########################################################################
.386
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
.code
; ########################################################################
NameFromPath proc lpPath:DWORD,lpBuffer:DWORD
push edi
mov ecx, lpPath
; -------------------------------------------------------
; Scan path buffer for "\" and put each offset + 1 from
; ecx into edx. Offset of last occurrence of "\" + 1 will
; be in edx when loop exits on zero.
; -------------------------------------------------------
@@:
mov al, [ecx]
inc ecx
cmp al, 0 ; exit condition for 1st loop
je @F
cmp al, "\" ; test for "\"
jne @B
mov edx, ecx ; if "\" put ecx+1 offset in edx
jmp @B
@@:
sub ecx, lpPath ; length in ecx
add ecx, edx ; create exit condition
; ---------------------------
; copy file name to lpBuffer
; ---------------------------
mov edi, lpBuffer
@@:
mov al, [edx]
inc edx
mov [edi], al
inc edi
cmp edx, ecx
jne @B
pop edi
ret
NameFromPath endp
; #########################################################################
end
Why not use what already exists?
Paul
I've used this method of getting just a file's name:
.data
ofn OPENFILENAME<> ; ofn = openfilename struct
buffer db 256 dup(0) ; path & filename buffer
pFileName db 64 dup(0) ; filename buffer
.code
Invoke GetOpenFileName, Addr ofn ; select a file
.If Eax != 0 ; if valid file is chosen
Movzx EAX, WORD PTR ofn.nFileOffset ; pointer to where filename begins
Mov ECX, OFFSET buffer ; load the path into ecx
Add ECX, EAX ; move to where the filename begins
Mov DWORD PTR pFileName, ECX ; save original filename pointer
QuoteWhy not use what already exists?
Paul
since i didn't knew of its existance... but to be honest i like mine better, since it is shorter and exactly what i need.
Quotenow if i would try to use an API for this i would get the complete path including name. then i would have to remove the path at first to extract the filename.
Hi white scorpion,
There is a simple solution with API :-)
invoke GetModuleFileName,NULL,addr FileName,sizeof FileName
fn wsprintf, addr FileName, "%s", FUNC (PathFindFileName, addr FileName)
or eventualy:
invoke GetModuleFileName,NULL,addr FileName,sizeof FileName
fn wsprintf, addr FileName, "%s", FUNC (PathStripPath, addr FileName)
Include:
include shlwapi.inc
includelib shlwapi.lib
Regards,
faiseur
Faiseur,
Yep, using the Shell API calls makes things like getting the filename, extension or other information pretty easy. ;-)
Relvinian
Thanks Faiseur, i will check it out, it sounds great!
QuoteYep, using the Shell API calls makes things like getting the filename, extension or other information pretty easy. ;-)
Yep ;-)
Faiseur,
I really like the simplicity of that code!
White Scorpion,
I don't blame you for liking your own code more. Always take pidein your work. Way to go!
Paul