The MASM Forum

General => The Campus => Topic started by: garyhess on March 13, 2013, 09:41:52 PM

Title: Win32 madness (WinINet problem)
Post by: garyhess on March 13, 2013, 09:41:52 PM
I've been learning assembler with GoAsm and Easy Code since last summer. Things have progressed pretty well, but in the past month I've run into a very frustrating problem with Win32. I'm going to try to describe the problem here for my own edification, and if anyone has any thoughts/recommendations, I would really appreciate that too. This has got to be the most difficult debugging problem I've encountered in my whole life (been writing code off and on since the early 1980s).

I'm working on a little utility program for my own use and I want to upload files to a remote server. I have a Linux server available so I started very simply by getting some PHP scripts there running correctly by testing them manually. Then I started writing GET requests, then POST requests, then POST with a file, all using WinINet. The HTTP protocol is a bit tricky and I have never coded this stuff before on the client side, but I managed to get each of these stages working correctly one by one with WinINet. Here is a chunk of that code to upload a file with fixed content.


; ************************************
;
; testing internet access, 5th attempt
;
; FILE UPLOAD !!!
; writing returned data directly to (temp) file
; ************************************

Invoke InternetOpen, Addr userAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0

Cmp Eax, NULL
Jne >.OK_31
Invoke GetLastError
Invoke String, Eax, Addr myStringVar, ecDecimal
Invoke MessageBoxA, [hWnd], Addr myStringVar, 'InternetOpen failed, error code from GetLastError', MB_ICONINFORMATION
Return (TRUE)

.OK_31

Mov [hInternet_1], Eax

Invoke InternetConnect, [hInternet_1], Addr url_5, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1
; perhaps last value could be NULL instead of 1?

Cmp Eax, NULL
Jne >.OK_32
Invoke GetLastError
Invoke String, Eax, Addr myStringVar, ecDecimal
Invoke MessageBoxA, [hWnd], Addr myStringVar, 'InternetConnect failed, error code from GetLastError', MB_ICONINFORMATION
Invoke InternetCloseHandle, [hInternet_1]
Return (TRUE)

.OK_32

Mov [hInternet_2], Eax

Invoke HttpOpenRequest, [hInternet_2], "POST", Addr objectName_2, NULL, NULL, Addr acceptTypes, 0, 1

Cmp Eax, NULL
Jne >.OK_33
Invoke GetLastError
Invoke String, Eax, Addr myStringVar, ecDecimal
Invoke MessageBoxA, [hWnd], Addr myStringVar, 'HttpOpenRequest failed, error code from GetLastError', MB_ICONINFORMATION
Invoke InternetCloseHandle, [hInternet_1]
Invoke InternetCloseHandle, [hInternet_2]
Return (TRUE)

.OK_33

Mov [hInternet_3], Eax

Invoke HttpSendRequest, [hInternet_3], Addr hdrs_2, SizeOf hdrs_2 - 1, Addr frmdata_2, SizeOf frmdata_2 - 1

Cmp Eax, TRUE ; different return codes here!
Je >.OK_34
Invoke GetLastError
Invoke String, Eax, Addr myStringVar, ecDecimal
Invoke MessageBoxA, [hWnd], Addr myStringVar, 'HttpSendRequest failed, error code from GetLastError', MB_ICONINFORMATION
Invoke InternetCloseHandle, [hInternet_1]
Invoke InternetCloseHandle, [hInternet_2]
Invoke InternetCloseHandle, [hInternet_3]
Return (TRUE)

.OK_34

; open a temporary file to save the data
; could use FILE_FLAG_DELETE_ON_CLOSE so file is automatically deleted
; but then need to have a way to also read the same temp file

Invoke CreateFile, 'c:/test6.txt', GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL

Cmp Eax, INVALID_HANDLE_VALUE
Jne >.OK_35
Invoke GetLastError
Invoke String, Eax, Addr myStringVar, ecDecimal
Invoke MessageBoxA, [hWnd], Addr myStringVar, 'CreateFile failed, error code from GetLastError', MB_ICONINFORMATION
Invoke InternetCloseHandle, [hInternet_1]
Invoke InternetCloseHandle, [hInternet_2]
Invoke InternetCloseHandle, [hInternet_3]
Return (TRUE)

.OK_35

Mov [hOut], Eax

.loop_readfile_4

Invoke InternetReadFile, [hInternet_3], Addr internetBuffer, SizeOf internetBuffer, Addr nIn

Cmp Eax, NULL
Jne >.OK_36
Invoke GetLastError
Invoke String, Eax, Addr myStringVar, ecDecimal
Invoke MessageBoxA, [hWnd], Addr myStringVar, 'InternetReadFile failed, error code from GetLastError', MB_ICONINFORMATION
Invoke InternetCloseHandle, [hInternet_1]
Invoke InternetCloseHandle, [hInternet_2]
Invoke InternetCloseHandle, [hInternet_3]
Invoke CloseHandle, [hOut]
Return (TRUE)

.OK_36

; if no bytes were returned this time, jump to final processing
Mov Eax, [nIn]
Cmp Eax, 0
Je >>.done_readfile_4

; write the current bytes to the temp file
Invoke WriteFile, [hOut], Addr internetBuffer, [nIn], Addr nOut, NULL

Mov Ebx, [nIn] ; nIn, nOut are more traditional
Cmp Ebx, [nOut]
Je .loop_readfile_4 ; if write operation was OK, do it again
; error processing
Invoke GetLastError
Invoke String, Eax, Addr myStringVar, ecDecimal
Invoke MessageBoxA, [hWnd], Addr myStringVar, 'WriteFile failed, error code from GetLastError', MB_ICONINFORMATION
Invoke InternetCloseHandle, [hInternet_1]
Invoke InternetCloseHandle, [hInternet_2]
Invoke InternetCloseHandle, [hInternet_3]
Invoke CloseHandle, [hOut]
Return (TRUE)

; END OF LOOP

.done_readfile_4

; file is on disk, internet operation complete
Invoke InternetCloseHandle, [hInternet_1]
Invoke InternetCloseHandle, [hInternet_2]
Invoke InternetCloseHandle, [hInternet_3]
Invoke CloseHandle, [hOut]

Return (TRUE)
; END of 5TH VERSION!!!
;
;
;



That was working OK, so the next step was to allow the user of my program to select a file. That didn't seem complex since I already had all of the pieces available.

However, I put it together and ran it and suddenly the existing code (above) started producing an error. Specifically, HttpOpenRequest generated error 87 (ERROR_INVALID_PARAMETER). I looked at this in the debugger and it all looked OK, i.e. the parameters in the call to HttpOpenRequest weren't any different than before.

I have experienced a weird problem with Win32 in the past when strings were not properly aligned on a quad word boundary so I set all of the strings to be aligned (ALIGN 4). But that didn't make any difference.

I left this problem a few times and came back to it over the past few weeks. Each time I would test the old code and it would work, but the new code would still generate the same error. But yesterday I tried again and even the old code suddenly generated the same error 87. I have been doing my testing on a Windows XP Pro machine, so I decided to transfer the program to another machine (Windows 7 64-bit). Lo and behold, it ran with no problems! (Note that the XP machine definitely has working Internet because I'm accessing it only via Logmein.)

So what I am wondering is whether anyone else has had a similar experience with Win32 or WinINet and what to do? Is it possible that WinINet is unreliable? I did a lot of Google searches about this error and did find a few unsolved cases where someone had described a similar problem.

I also used the debugger to follow the program code a ways into the operating system. I came across an error function that suggested something had never heard of: a deadlock. (But maybe that is only a debugger issue?)

In general, I wonder if there any other conventions that Win32 programmers automatically follow (like the ALIGN 4 issue) that could be my problem here? For example, I managed to debug an awful problem with the function InternetReadFile: It will overwrite past the end of the buffer that is passed to it, which can cause a bizarre error, if the buffer is not properly aligned (ALIGN 4) and there is another string immediately after it.

I also tried another test yesterday. Since this code is part of a large, messy test program I've been writing since last summer with many unrelated pieces (EXE file = about 1.5 MB), I thought there could be some unexplained interaction (although note that this code is reached directly via a button and none of my other code is executing beforehand). So I created a new, empty project and copied just this code over there: no error has occurred so far. I did notice while copying the variables that not all of them had "ALIGN 4", so I corrected that. Maybe it's as simple as that?

Finally, I wonder how real browsers like Firefox are written? I assume that WININET is not used and the browsers operates at a lower level with sockets, etc.

Thanks in advance for any thoughts. If I can't figure this out, there is always VISUAL BASIC ;-_

Gary
Title: Re: Win32 madness (WinINet problem)
Post by: dedndave on March 13, 2013, 10:14:19 PM
hi Gary
the InternetConnect dwContext parameter appears to be a pointer to a dword variable, even though the hungarian name does not imply it

maybe these links will help

http://etutorials.org/Programming/Pocket+pc+network+programming/Chapter+2.+WinInet/Using+WinInet/ (http://etutorials.org/Programming/Pocket+pc+network+programming/Chapter+2.+WinInet/Using+WinInet/)

http://www.jose.it-berater.org/smfforum/index.php?topic=2881.0 (http://www.jose.it-berater.org/smfforum/index.php?topic=2881.0)
Title: Re: Win32 madness (WinINet problem)
Post by: TouEnMasm on March 14, 2013, 03:49:26 AM
and here a sample in masm,translation of a sdk sample
Title: Re: Win32 madness (WinINet problem)
Post by: dedndave on March 14, 2013, 06:21:40 AM
thanks, Yves   :t
Title: Re: Win32 madness (WinINet problem)
Post by: Magnum on March 14, 2013, 12:17:02 PM
Where can the .sdk files be acquired ?

Thanks.
Title: Re: Win32 madness (WinINet problem)
Post by: dedndave on March 14, 2013, 12:22:40 PM
http://masm32.com/board/index.php?topic=563.msg5617#msg5617 (http://masm32.com/board/index.php?topic=563.msg5617#msg5617)

they are a set of windows include files with extension .sdk put together by Yves
they sometimes have things that are not defined in the masm32 package includes