I don't really understand this. I have written a small helperfunction which gets a pathname and a pointer with size to save it to a file. I used this function in the maincode and it worked. Now I moved it to a separate function and suddenly CreateFile returns INVALID_HANDLE_VALUE and GetLastError() returns ERROR_NOACCESS (3E6h).
The only thing I changed was that now I put the filename on the stack (because I didn't want to bother with malloc/free). So I thought, maybe the adress must be aligned, or it doesn't accept filenames on the stack, so I copied the filename for testing into a variable in .data? but this also doesn't help.
Any ideas whats wrong?
This is the version with the pointer in a stackvariable
_writeFile proc pFilename: PTR byte, pData: PTR byte, nDataLen: DWORD
LOCAL BytesWritten:DWORD
invoke CreateFile, pFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
And this is where I added code to make the pointer aligned and not on the stack:
_writeFile proc pFilename: PTR byte, pData: PTR byte, nDataLen: DWORD
LOCAL BytesWritten:DWORD
mov eax, pFilename
lea edx, BufferMem
call strcpy
lea eax, BufferMem
invoke CreateFile, eax, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
The filepath is correct. I copied it directly from the variable in a shell and when I create the file from the shell, the file is created.
echo > c:\mypath.txt
what you are not showing us is the code that worked :(
but - that's ok
it's possible that some other program has the file opened
for example - a previous instance of your program did not terminate or close the handle
because you are using FILE_SHARE_READ, the only mode it may then be opened is read
make sure you close the handle when you are done
when i create a file for write-only operations, i generally use
INVOKE CreateFile,lpFileName,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
which appears to be what you have
so - that means that the OS has a lock on the file for some reason
or - you aren't getting a valid name to it
lea eax, BufferMem
this line may be a problem
i take it that BufferMem is a variable with a pointer to the buffer
in that case, use it directly...
...CreateFile,BufferMem,GENERIC_WRITE....
the way it looks, you are passing the address of the BufferMem variable - not the string address
the CreateFile function does not care what kind of buffer you have
it does want a valid path/file name string - with a null terminator
i don't think it has to be aligned
except the UNICODE version - some UNICODE functions require 16-aligned string buffers
to test the file name pointer, just temporarily replace the CreateFile call with MessageBox
use the same pointer you are passing to CreateFile
if it doesn't display the path/file string - you have found the problem
INVOKE MessageBox,0,BufferMem,0,MB_OK
Thanks for oyur reply. The OS doesn't have a lock. I also though of this, and even rebooted, to make sure that this is not happening. As I said, when I create the file in a shell, it works.
But looking at this in the meantime, I found out what the problem is, though I still don't understand it.
If the filename is not exactly 12 characters long, then it works. If the filename is longer or shorter it fails????
So this works:
FileName db '123456789012', 0
But this not:
FileName db '12345678901', 0
or
FileName db '1234567890123', 0
BufferMem is a byte array, just like in the above example. I also traced throug hthe create file function. The first thing it does is to call a function that converst my path to UNICODE and this path is definitely correct, as well as the pointer.
you have something odd going on there - lol
i have never heard of anything like that
but - we need more complete code to be much help
post a complete source, and i will have a look
I see if I can create a small sample that demonstrates it. Maybe this wil help me to find the problem, and if not then I can post it. I sure don't understand this either, as I have never seen such a strange problem. :)
The Messagebox is a good idea, I'll test this.
are you using __UNICODE__ ???
this seems to work ok...
push 0
push 'eliF'
push 'tseT'
mov edx,esp
INVOKE CreateFile,edx,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
add esp,12
INVOKE CloseHandle,eax
an empty file named "TestFile" is created
and - the second time - the file is overwritten with a new one
I'm not using UNICODE, but CreateFileA converts the path to a UNICODE string and forwards the parameters to CreateFileW. Most of the ANSI functions in Windows simply convert to UNICODE and then call the W version.
The messagebox shows exactly what it should, so that works fine, as expected. I also checked the stack for corruption and this also looks good.
then you aren't doing it right :biggrin:
post some code
I finally found the problem. The funny thing is that it was a problem I already anticipated but fixed in the wrong position. :)
I figured that the stack should be aligned on an even address, so I added a check for the pathname to make the stack aligned. However, I did it in the wrong position, so it was NOT aligned when calling CreateFile(). That was the reason why it worked with 12 character filenames, because in this case it happend to be aligned correct.
Now I moved the alignment check after constructing the full path (where it belongs), and now it works. :)
Thanks for your help!
To make it more understandable:
The function takes a directory and a file as two arguments. It calulates the total length of the path and checks if the directory has a `\` so it will yield a valid path when concatenating. My alignment check aligned only the directory path, instead of the full path, so the stackpointer became uneven when the filename was of a different size.
SaveToFile proc pBasepath: PTR byte, pFilename: PTR byte, pData: PTR byte, nMemSize:DWORD
LOCAL pPath: PTR byte
LOCAL StackPathlen:DWORD
LOCAL Path:byte
; Calculate the stringlength of the path plus the filename, plus a missing backslash
; and 0-Byte. We copy the path on the stack, so we wont have to malloc
mov eax, pBasepath
mov esi, eax
call strlen
mov edx, eax
inc eax ; Room for the 0-Byte
inc eax ; If the '\' is missing we need another character
mov edi, eax
; alignment check was here so it could become missaligned.
mov ebx, eax
mov eax, pFilename
call strlen
add ebx, eax
; Check if the stack will be aligned
test ebx, 1
je @@Aligned
inc ebx
@@Aligned:
sub esp, ebx
mov StackPathlen, ebx
mov ebx, eax
; Copy the basepath
mov ecx, edx
mov eax, esi
mov edx, esp
call memcpy
; Append the filename to the path.
; If the path is given without a '\' at the end, we have to append it.
lea edx, [esp+edx-1]
cmp byte ptr [edx], '\'
je @@AppendFile
inc edx
mov byte ptr [edx], '\'
@@AppendFile:
inc ebx ; include the 0-Byte
inc edx
mov ecx, ebx
mov eax, pFilename
call memcpy
mov eax, esp
invoke writeFile, eax, pData, nMemSize
add esp, StackPathlen
ret
SaveToFile endp
:t