I have a basic C++ program. Its goal is to display the file names contained in a specific folder. The C++ code is the following :
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
int _tmain(int ac, TCHAR **av)
{
HANDLE hFile;
WIN32_FIND_DATA findFileData;
BOOL retFindNextFile;
TCHAR FilePathPattern[] = TEXT("C:\\Users\\Bloodsucker94\\Desktop\\TestASM\\*.txt");
if ((hFile = FindFirstFile(FilePathPattern, &findFileData)) == INVALID_HANDLE_VALUE)
_tprintf(TEXT("FindFirstFile() failed with code %d\n"), GetLastError());
else {
_tprintf(TEXT("hFile=%d, addr=0x%08X\n"), hFile, &findFileData);
do {
TCHAR beginPath[] = TEXT("C:\\Users\\Bloodsucker94\\Desktop\\TestASM\\");
lstrcat(beginPath, findFileData.cFileName);
_tprintf(TEXT("%s\n"), beginPath);
//printf("%s\n", beginPath);
retFindNextFile = FindNextFile(hFile, &findFileData);
} while (retFindNextFile == TRUE);
}
getchar();
return (EXIT_SUCCESS);
}
I want to produce the same program using MASM :
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
include \masm32\include\masm32rt.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
include \masm32\include\msvcrt.inc
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\crtdll.lib
_tprintf PROTO C :VARARG
.data
FolderPath TCHAR "C:\Users\Bloodsucker94\Desktop\TestASM\*.txt", 0
BeginFolderPath TCHAR "C:\Users\Bloodsucker94\Desktop\TestASM\", 0
FileName TCHAR "ta_mere.txt", 0
LstrcatFailed BYTE "lstrcat failed", 0
FormatPrintString BYTE "%s\n", 0
FindFirstFileError BYTE "FindFirstFile() failed with code %d", 0
FindFirstFileSuccess BYTE "First file found with success - hfile=%d", 0
PrintStructAddr BYTE "addr=Ox%08X", 0
PrintFileName BYTE "%s", 0
.data?
hFile HANDLE ?
findFileData WIN32_FIND_DATA <>
retFindNextFile BOOL ?
ErrorCode DWORD ?
FinalFilePath LPTSTR ?
.code
start:
;--------------------------------------------------------
invoke FindFirstFile, ADDR FolderPath, \
ADDR findFileData
mov hFile, eax
.IF hFile == INVALID_HANDLE_VALUE
invoke GetLastError
mov ErrorCode, eax
printf("%d\n", ErrorCode)
jmp _quit
.ENDIF
;--------------------------------------------------------
_loop:
invoke lstrcat, ADDR BeginFolderPath,
ADDR findFileData.cFileName
mov FinalFilePath, eax
.IF FinalFilePath == NULL
invoke MessageBox, NULL, \
ADDR LstrcatFailed, \
ADDR LstrcatFailed, \
MB_OK
.endif
;invoke crt_printf, ADDR FormatPrintString, \
; findFileData.cFileName
invoke MessageBox, NULL, \
ADDR FinalFilePath, \
ADDR FinalFilePath, \
MB_OK
;--------------------------------------------------------
invoke FindNextFile, hFile, \
ADDR findFileData
.IF eax == NULL
jmp _quit
.ELSE
jmp _loop
.ENDIF
;--------------------------------------------------------
_quit:
invoke ExitProcess, 0
end start
The compilation works perfectly. The lstrcat function does not fail too. But at the execution the message boxes display the string "-O@". I noticed the same behaviour in the c++ program when I want to print with printf and not _tprintf (because print a TCHAR Windows type does not work with printf). Maybe the problem comes from MessageBox function or maybe TCHAR type is not the good one. Only the c++ program works. I'm lost.
Does anyone can help me, please ?
Thanks in advance for your help.
First thing, your call to lstrcat
is going to overwrite memory that comes after BeginFolderPath
. So the value you have for FileName
is going to be overwritten for sure, and if the file name is really long there's no telling what parts of your data segment will be trashed by that call. Buffer overrun is not the only possible problem with lstrcat
. See the documentation at http://msdn.microsoft.com/en-us/library/windows/desktop/ms647487(v=vs.85).aspx
You might consider running this in a debugger and taking a look at memory after the call to lstrcat
returns.
Also, you're mixing TCHAR
and BYTE
for your strings, which is somewhat confusing. It's unclear to me whether you're wanting this program to use Unicode or ANSI strings. As it's currently written, it's impossible to tell. Is TCHAR
a byte in this program, or a word? If it's a word, then you need to be calling MessageBoxW
.
It would be instructive for you to set the compiler switch that outputs an assembly listing file, and compile your C++ program. Take a look at the generated assembly code.