Hi all,
I'm completely at a loss here. I'm calling "GetModuleFileName" to get the full path + filename for my program. Now I want to use "GetFullPathName" to weed out the directory part only.
invoke GetModuleFileName, hInst, addr szExebuffer, MAX_PATH
this gives me the full path + filename in szExebuffer.
Now I want to find out only the directory part using GetFullPathName. Any help on how I go about it?
Any help is greatly appreciated.
start at the end of the string and work toward the beginning
the first "\" or ":" you find tells you where the filename starts
of course, that function never returns a ":" without a "\", so you can just look for "\"
but, to make a more universal function, you might search either
i would suggest you use the UNICODE version,
noting that UNICODE pathnames must be prepended with "\\?\" for many functions
GetModuleFileNameW
Dave is ambitious, as usual :biggrin:
Here is a very simple example with no error checking (there won't be errors):
include \masm32\include\masm32rt.inc
.data?
buffer db 1000 dup(?)
.code
start: mov esi, offset buffer
invoke GetModuleFileName, rv(GetModuleHandle, 0), esi, MAX_PATH
print esi, 13, 10
lea edx, [esi+len(esi)] ; add the length of the full path
.Repeat
dec edx
.Until byte ptr [edx]=="\"
mov byte ptr [edx], 0 ; insert a zero to delimite the string
inkey esi, 13, 10
exit
end start
Welcome to the Forum. How did you find us, and why do you want to learn assembler? It's a rare art nowadays ;-)
Here is a routine i commonly use, where i create an .ini filename based on the current module name, checking for . and \ and determining where to store the file based on the current OS version. Should give you an idea on what to do hopefully.
.486
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
include shell32.inc
includelib shell32.lib
.data
szBackslash db "\",0 ; backslash char
szExtEXE db ".exe",0 ; exe file extension
szExtINI db ".ini",0 ; ini file extension
;szIniFilename db MAX_PATH dup (0) ; buffer to hold our ini filename
.code
;--------------------------------------------------------------------------------------
; Create an .ini filename based on the executables name.
;
; Example Usage:
;
; Invoke CreateIniFilename, Addr szIniFilename
;
; 22/01/2014 - Added lpszBaseModuleName param (optional) if not NULL will copy
; the base module name to this buffer.
;--------------------------------------------------------------------------------------
CreateIniFilename PROC lpszIniFile:DWORD, lpszBaseModuleName:DWORD
LOCAL VersionInformation:OSVERSIONINFO
LOCAL ModuleFullPathname[MAX_PATH]:BYTE
LOCAL ModuleName[MAX_PATH]:BYTE
LOCAL hInst:DWORD
LOCAL ppidl:DWORD
LOCAL LenFilePathName:DWORD
LOCAL PosFullStop:DWORD
LOCAL PosBackSlash:DWORD
Invoke GetModuleFileName, NULL, Addr ModuleFullPathname, Sizeof ModuleFullPathname
Invoke lstrlen, Addr ModuleFullPathname ; length of module path
mov LenFilePathName, eax ; save var for later
;----------------------------------------------------------------------
; Find the fullstop position in the module full pathname
;----------------------------------------------------------------------
mov PosFullStop, 0
lea esi, ModuleFullPathname
add esi, LenFilePathName
mov ecx, LenFilePathName
.WHILE ecx >= 0
movzx eax, byte ptr [esi]
.IF al == 46d ; 46d = 2Eh is full stop .
mov PosFullStop, ecx ; save fullstop position
.BREAK
.ELSE
dec esi ; move down string by 1
dec ecx ; decrease ecx counter
.ENDIF
.ENDW
.IF PosFullStop == 0 ; if for some reason we dont have the position
mov eax, FALSE ; we should probably exit with an error
ret
.ENDIF
;----------------------------------------------------------------------
; Determine what OS we are running on
mov VersionInformation.dwOSVersionInfoSize, SIZEOF OSVERSIONINFO
Invoke GetVersionEx, Addr VersionInformation
mov eax, VersionInformation.dwMajorVersion
;----------------------------------------------------------------------
; Find the backslash position in the module full pathname
;----------------------------------------------------------------------
mov PosBackSlash, 0
lea esi, ModuleFullPathname
add esi, PosFullStop
mov ecx, PosFullStop
.WHILE ecx >= 0
movzx eax, byte ptr [esi]
.IF al == 92 ; 92d = 5Ch is backslash \
mov PosBackSlash, ecx ; save backslash position
.BREAK
.ELSE
dec esi ; move down string by 1
dec ecx ; decrease ecx counter
.ENDIF
.ENDW
.IF PosBackSlash == 0 ; if for some reason we dont have the position
mov eax, FALSE ; we should probably exit with an error
ret
.ENDIF
; Fetch just the module name based on last backslash position
; and the fullstop positions that we found above.
lea edi, ModuleName
lea esi, ModuleFullPathname
add esi, PosBackSlash
inc esi ; skip over the \
mov ecx, PosBackSlash
inc ecx ; skip over the \
.WHILE ecx < PosFullStop
movzx eax, byte ptr [esi]
mov byte ptr [edi], al
inc esi
inc edi
inc ecx
.ENDW
mov byte ptr [edi], 0 ; zero last byte to terminate string.
;----------------------------------------------------------------------
.IF eax > 5 ; Vista / Win7
;----------------------------------------------------------------------
; Glue all the bits together to make the new ini file location
;
; include shell32.inc & includelib shell32.lib required for the
; SHGetSpecialFolderLocation & SHGetPathFromIDList functions
;----------------------------------------------------------------------
Invoke GetModuleHandle, NULL
mov hInst, eax
Invoke SHGetSpecialFolderLocation, hInst, CSIDL_APPDATA, Addr ppidl
Invoke SHGetPathFromIDList, ppidl, lpszIniFile
Invoke lstrcat, lpszIniFile, Addr szBackslash ; add a backslash to this path
Invoke lstrcat, lpszIniFile, Addr ModuleName ; and add our app exe name
Invoke GetFileAttributes, lpszIniFile
.IF eax != FILE_ATTRIBUTE_DIRECTORY
Invoke CreateDirectory, lpszIniFile, NULL ; create directory if needed
.ENDIF
Invoke lstrcat, lpszIniFile, Addr szBackslash ; add a backslash to this as well
Invoke lstrcat, lpszIniFile, Addr ModuleName ; add module name to our folder path
invoke lstrcat, lpszIniFile, Addr szExtINI
;----------------------------------------------------------------------
.ELSE ; WinXP
Invoke lstrcpyn, lpszIniFile, Addr ModuleFullPathname, PosFullStop
Invoke lstrcat, lpszIniFile, Addr szExtINI
.ENDIF
.IF lpszBaseModuleName != NULL ; save the result to address specified by user
Invoke lstrcpy, lpszBaseModuleName, Addr ModuleName ; (2nd parameter)
.ENDIF
mov eax, TRUE
ret
CreateIniFilename ENDP
END
You have this procedure in the MASM32 library.
GetPathOnly proc src:DWORD, dst:DWORD
Feed a GetModuleFileName result to it and get the bare path back.
Even simpler, use PathRemoveFileSpec
Quote from: sinsi on September 30, 2014, 04:33:39 PM
Even simpler, use PathRemoveFileSpec
Never thought of that one :t
include \masm32\include\masm32rt.inc
uselib Shlwapi
.data?
buffer db MAX_PATH dup(?)
.code
start:
mov esi, offset buffer
invoke GetModuleFileName, rv(GetModuleHandle, 0), esi, sizeof buffer
invoke PathRemoveFileSpec, esi
inkey esi
exit
end start
How about using SearchPath() with 0 to path and "." to filename ?
Here is the other MASM32 library module to get this result. It should be tweaked up to a 256 character path but it works fine.
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.486 ; set processor model
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include \masm32\include\kernel32.inc
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
align 4
GetAppPath proc lpPathBuffer:DWORD
invoke GetModuleFileName,0,lpPathBuffer,128 ; return length in eax
add eax, lpPathBuffer
; ---------------------------------------
; scan backwards for first "\" character
; ---------------------------------------
@@:
dec eax ; dec ECX
cmp BYTE PTR [eax],'\' ; compare if "\"
jne @B ; jump back to @@: if not "\"
mov BYTE PTR [eax+1],0 ; write zero terminator after "\"
mov eax, lpPathBuffer
ret
GetAppPath endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end
Here is a quick update on the old algo.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
comment * -----------------------------------------------------
Build this template with
"CONSOLE ASSEMBLE AND LINK"
----------------------------------------------------- *
AppPath PROTO
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
print rv(AppPath),13,10
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
AppPath proc
.data?
appath db 260 dup (?)
.data
ppth dd appath
.code
mov eax, rv(GetModuleFileName,0,ppth,260)
add eax, ppth
@@:
sub eax, 1
cmp BYTE PTR [eax], "\"
jne @B
mov BYTE PTR [eax+1], 0
mov eax, ppth
ret
AppPath endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
Quote from: TWell on September 30, 2014, 06:11:33 PM
How about using SearchPath() with 0 to path and "." to filename ?
Do you have a working example? Mine returns always the full path...
MbExeFolder$: D:\masm32\MasmBasic\Res\
GmFileName: D:\masm32\MasmBasic\Res\SkelMbEmpty.exe
SearchPath: D:\masm32\MasmBasic\Res\SkelMbEmpty.exe#include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
Init
PrintLine "MbExeFolder$:", Tb$, MbExeFolder$ ; far too simple ;-)
sub esp, MAX_PATH*2 ; create two buffers
mov esi, esp
invoke GetModuleFileName, 0, esi, MAX_PATH
PrintLine "GmFileName:", Tb$, esi
invoke SetLastError, 0 ; test for errors
lea edi, [esi+MAX_PATH] ; destination buffer
invoke SearchPath, esi, Chr$("."), 0, MAX_PATH, edi, 0
; deb (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1019) 4, "sp", eax, $Err$() ; no errors!
mov dword ptr [edi+eax], "#" ; set a marker
PrintLine "SearchPath:", Tb$, edi
Exit
end start
Wow! Thanks for all the nice input! PathRemoveFileSpec sounds like the way to go. Will check it out as soon as I can.
jj2007>> I've been dabbling with x86 assembler on and off for the last 10-15 years. Mainly I return to it because it's fun. :) I used to code 6502/6510 assembler back in the days of the C64, and I really enjoy the low level aspect of it. I used to be a member on the old forum, but forgot my username. :/
Thanks for all the help lads!
Quote from: Landsfiskalen on September 30, 2014, 10:58:07 PMI used to be a member on the old forum, but forgot my username. :/
Shouldn't be a problem to find it, if you remember what you typically posted (http://www.masmforum.com/board/index.php?action=search;advanced) ;)
Quote from: jj2007 on September 30, 2014, 08:25:11 PM
Quote from: TWell on September 30, 2014, 06:11:33 PM
How about using SearchPath() with 0 to path and "." to filename ?
Do you have a working example? Mine returns always the full path...
Sure
.686
.MODEL FLAT, STDCALL
OPTION CASEMAP :NONE
ExitProcess PROTO STDCALL :DWORD
SearchPathA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
INCLUDELIB kernel32.lib
MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD
INCLUDELIB user32.lib
InitCommonControls PROTO
INCLUDELIB comctl32.lib
.data
dd InitCommonControls ; for manifest only
msg1 db "SearchPath",0
msg2 db ".",0
buf db 260 dup(?)
.code
start PROC
INVOKE SearchPathA,0,ADDR msg2,0,260,ADDR buf,0
INVOKE MessageBoxA,0,ADDR buf,ADDR msg1,0
INVOKE ExitProcess,eax
;mov eax, InitCommonControls
start ENDP
END start
Hi Landsfiskalen,
welcome to the forum and have a lot of fun.
Gunther
Quote from: TWell on October 01, 2014, 12:33:16 AM
Quote from: jj2007 on September 30, 2014, 08:25:11 PM
Do you have a working example? Mine returns always the full path...
Sure
That works indeed: SearchPathA, 0, ...
But I wonder why it doesn't work if I use GetModuleFileNameA instead of NULL ::)