I am getting the error "The supplied user buffer is not valid for the requested operation" after the call to WriteFile in the code below. I am just trying to read a file, write it to the console and then copy it into another file. All works OK except for the copying bit.
INCLUDE \masm32\include\masm32rt.inc
.DATA
hInputFile DD ?
hOutputFile DD ?
fileSize DD ?
numRead DD ?
numWritten DD ?
inputFile DB "Test.asm", 0
outputFile DB "Copy.asm", 0
hStdOut DD ?
hMemory DD ?
errorNum DD ?
errorBuffer DB MAX_PATH DUP(?)
.CODE
start:
INVOKE GetStdHandle, STD_OUTPUT_HANDLE ; -11
MOV hStdOut, EAX
INVOKE CreateFile, \
OFFSET inputFile, \
GENERIC_READ, \
FILE_SHARE_READ, \
NULL, \
OPEN_EXISTING, \
FILE_ATTRIBUTE_NORMAL, \
NULL
MOV hInputFile, EAX
CMP hInputFile, INVALID_HANDLE_VALUE
JE errorProcess
INVOKE CreateFile, \
OFFSET outputFile, \
GENERIC_WRITE, \
0, \
NULL, \
CREATE_ALWAYS, \
FILE_ATTRIBUTE_NORMAL, \
NULL
MOV hOutputFile, EAX
CMP hOutputFile, INVALID_HANDLE_VALUE
JE errorProcess
INVOKE GetFileSize, hInputFile, NULL
MOV fileSize, EAX
INVOKE GlobalAlloc, GMEM_FIXED, fileSize
MOV hMemory, EAX
CMP hMemory, 0
JE errorProcess
INVOKE ReadFile, \
hInputFile, \
ADDR hMemory, \
fileSize, \
ADDR numRead, \
0
CMP EAX, 0
JE errorProcess
INVOKE WriteConsole, hStdOut, OFFSET hMemory, fileSize, numWritten, 0
INVOKE WriteFile, \
hOutputFile, \
hMemory, \
fileSize, \
ADDR numWritten, \
NULL
CMP EAX, 0
JE errorProcess
JMP finalise
errorProcess:
INVOKE GetLastError
INVOKE FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM, 0, EAX, 0, ADDR errorBuffer, MAX_PATH, 0
INVOKE WriteConsole, hStdOut, OFFSET errorBuffer, MAX_PATH, numWritten, 0
finalise:
INVOKE GlobalFree, hMemory
INVOKE CloseHandle, hInputFile
INVOKE CloseHandle, hOutputFile
INVOKE ExitProcess, 0
END start
addr hMemory and offset hMemory - not the address of the variable, but the variable hMemory itself is needed.
Furthermore, you should not write more than, say, 32k to the console - see WriteFile doc, Community additions (http://msdn.microsoft.com/en-us/library/windows/desktop/ms687401%28v=vs.85%29.aspx):
mov edx, fileSize
.if edx>32768
mov edx, 32768
.endif
INVOKE WriteConsole, hStdOut, hMemory, edx, addr numWritten, 0
JJ is correct here, if you want to write large amounts of text to the console you need to chop it up into smaller bits, 10k seems to work OK and if you use StdOut style output you can redirect it to a file with standard console notation.
Quote from: jj2007 on December 01, 2011, 11:59:38 PM
addr hMemory and offset hMemory - not the address of the variable, but the variable hMemory itself is needed.
jj, strangely enough, I have now managed to make the program work using OFFSET on both the WriteConsole and WriteFile calls.
So, the following works:
INVOKE WriteConsole, hStdOut, OFFSET hMemory, fileSize, numWritten, 0
INVOKE WriteFile, \
hOutputFile, \
OFFSET hMemory, \
fileSize, \
ADDR numWritten, \
NULL
I.e. the program writes on the console and also writes in the copy file.
If I remove the OFFSET only from the WriteFile call:
INVOKE WriteConsole, hStdOut, OFFSET hMemory, fileSize, numWritten, 0
INVOKE WriteFile, \
hOutputFile, \
hMemory, \
fileSize, \
ADDR numWritten, \
NULL
then it writes on the console fine, and creates the copy file but doesn't write any lines.
If I remove the OFFSET from the WriteConsole call, then the program crashes:
INVOKE WriteConsole, hStdOut, hMemory, fileSize, numWritten, 0
INVOKE WriteFile, \
hOutputFile, \
hMemory, \
fileSize, \
ADDR numWritten, \
NULL
I am not quite sure what is happening.
PS. I take your and Hutch's point about size.
Quote from: bf2 on December 02, 2011, 07:15:39 AM
Quote from: jj2007 on December 01, 2011, 11:59:38 PM
addr hMemory and offset hMemory - not the address of the variable, but the variable hMemory itself is needed.
jj, strangely enough, I have now managed to make the program work using OFFSET on both the WriteConsole and WriteFile calls.
Congrats. How big is your test.asm? Have you tried with something a little bit bigger than MAX_PATH?
Hint: Your program works even if you comment out the GlobalAlloc part, like this:
; INVOKE GlobalAlloc, GMEM_FIXED, fileSize
; MOV hMemory, EAX
; CMP hMemory, 0
; JE errorProcess
.data
...
hMemory DD ?
errorNum DD ?
errorBuffer DB MAX_PATH DUP(?)
.CODE
Here is how to stream any sized file to the cxonsole.
IF 0 ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
.data?
var dd ?
.data
winc db "\masm32\include\windows.inc",0
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
LOCAL hFile :DWORD ; file handle
LOCAL bcnt :DWORD ; read block size
LOCAL pMem :DWORD ; memory handle
LOCAL hOut :DWORD
LOCAL bWrt :DWORD
mov bcnt, 8192 ; set your buffer size
; -------------------------
; allocate that much memory
; -------------------------
invoke GlobalAlloc,GMEM_FIXED,bcnt
mov pMem, eax
; --------------------------------
; open the file and get its handle
; --------------------------------
invoke CreateFile,ADDR winc,GENERIC_READ or GENERIC_WRITE,
NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
mov hFile, eax ; get handle to open file
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov hOut, eax
@@:
; ---------------------------------------
; read the bcnt buffer size from the file
; ---------------------------------------
invoke ReadFile,hFile,pMem,bcnt,ADDR var,NULL
; ----------------------------------------------------
; write the actual number of bytes read to the console
; ----------------------------------------------------
fn WriteConsole,hOut,pMem,var,ADDR bWrt,NULL
mov eax, var ; load "var" into EAX
.if eax == bcnt ; if "var" is equal to bcnt
jmp @B ; loop back and read next block
.endif
invoke CloseHandle,hFile
invoke GlobalFree,pMem
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
i was playing with this some time ago
i found the limit to be something in the 55 kb neighbourhood (XP)
if you wrote less than the limit, it worked fine
if you wrote more than the limit, nothing happened - lol
odd size - the 55 kb - i forget the exact number - it probably varies from OS to OS - i don't know
but - 32 kb is reasonably safe
let's face it - if you are dumping that much to the console, you aren't going to see most of it, anyways
Dave,
That may be because of some console restriction, but when copying files using unbuffered I/O, I use 64KB all of the time with no error. You need buffers that are mod sector size and need to do sector sized reads and writes. Use VirualAlloc to get the buffers and you get such buffers. When reading or writing the final piece (if it is not mod sector size), read or write mod sector sized pieces, then close the file and open it as buffered, position the file to the end of the last piece read or written, then read or write the final fractional piece.
Dave.
Quote from: dedndave on December 02, 2011, 04:38:41 PM
i found the limit to be something in the 55 kb neighbourhood (XP)
53216 bytes :bg
Quote mov ebx, fileSize
.if ebx>60000
mov ebx, 60000
.endif
.Repeat
INVOKE WriteConsole, hStdOut, hMemory, ebx, addr numWritten, 0
dec ebx
.Until eax
Print Str$("\n\nFirst good result: %i\n\n\n", ebx)
oh yes - i know you can use larger buffers for things other than console output
i just thought it was an odd boundry, is all - lol
of course - it's just one more bug that the console has
for some time, i have learned to view the console as a "test tool", more or less
it has it's uses - sure
but, it's no place for any kind of application that uses a "dynamic" display
i.e. one where you reposition the cursor, rather that tty scrolling the output text
as we can see, it doesn't even do that right :bg
Quote from: jj2007 on December 02, 2011, 08:23:43 AM
Quote from: bf2 on December 02, 2011, 07:15:39 AM
Quote from: jj2007 on December 01, 2011, 11:59:38 PM
addr hMemory and offset hMemory - not the address of the variable, but the variable hMemory itself is needed.
jj, strangely enough, I have now managed to make the program work using OFFSET on both the WriteConsole and WriteFile calls.
Congrats. How big is your test.asm? Have you tried with something a little bit bigger than MAX_PATH?
Hint: Your program works even if you comment out the GlobalAlloc part, like this:
; INVOKE GlobalAlloc, GMEM_FIXED, fileSize
; MOV hMemory, EAX
; CMP hMemory, 0
; JE errorProcess
.data
...
hMemory DD ?
errorNum DD ?
errorBuffer DB MAX_PATH DUP(?)
.CODE
jj, sorry I am being thick but I am still not clear about this. I appreciate your comment about file size, but I cannot understand why the program works even when you have commented out the GlobalAllock block and why my previous version worked when I used the address of hMem as opposed to hMem itself.
Please help.
Quote from: bf2 on December 02, 2011, 08:59:21 PM
I cannot understand why the program works even when you have commented out the GlobalAllock block and why my previous version worked when I used the address of hMem as opposed to hMem itself.
You pass a pointer to a buffer to ReadFile and WriteFile.
If you pass hMemory, the two functions will use the memory that you got with GlobalAlloc.
If you pass addr hMemory, the two functions will use ... the .data section, i.e. everything that comes after hMemory. And Bang! with files larger than some kBytes...
.DATA
...
hMemory DD ?
errorNum DD ?
errorBuffer DB MAX_PATH DUP(?)
Working correct version attached.
Ah, got it now. Thanks very much.