MS Asynchronous Internet Request Example converted to PB

Share your advanced PureBasic knowledge/code with the community.
nalor
Enthusiast
Enthusiast
Posts: 115
Joined: Thu Apr 02, 2009 9:48 pm

MS Asynchronous Internet Request Example converted to PB

Post by nalor »

Just want to share a converted code - it's not fully tested, but the basic functions are working for me.

Here's the source from microsoft:

https://msdn.microsoft.com/en-us/librar ... s.85).aspx

And here's my PB Code:

Update 20180630:
# didn't work properly in thread-safe mode: GetLastError_() has to be called directly after the previous windows-api function in order to return the correct error (that is required to work correctly)
# fixed a memory problem in SendRequestWithBody: it's necessary to allocate *BuffersIn with AllocateStructure because it's used async

Code: Select all

; https://msdn.microsoft.com/en-us/library/windows/desktop/cc185684(v=vs.85).aspx

EnableExplicit


#BUFFER_LEN=4096
#ERR_MSG_LEN=512

#METHOD_NONE=0
#METHOD_GET =1
#METHOD_POST=2

#REQ_STATE_SEND_REQ             =0
#REQ_STATE_SEND_REQ_WITH_BODY   =1
#REQ_STATE_POST_GET_DATA        =2
#REQ_STATE_POST_SEND_DATA       =3
#REQ_STATE_POST_COMPLETE        =4
#REQ_STATE_RESPONSE_RECV_DATA   =5
#REQ_STATE_RESPONSE_WRITE_DATA  =6
#REQ_STATE_COMPLETE             =7

#DEFAULT_TIMEOUT =2 * 60 * 1000 ; Two minutes

#DEFAULT_HOSTNAME ="www.microsoft.com"
#DEFAULT_RESOURCE ="/"

#DEFAULT_OUTPUT_FILE_NAME ="response.htm"
#SPIN_COUNT =4000

#INTERNET_STATUS_COOKIE_SENT=320
#INTERNET_STATUS_COOKIE_RECEIVED=321
#INTERNET_STATUS_COOKIE_HISTORY=327
#INTERNET_STATUS_CLOSING_CONNECTION=50
#INTERNET_STATUS_CONNECTED_TO_SERVER=21
#INTERNET_STATUS_CONNECTING_TO_SERVER=20
#INTERNET_STATUS_CONNECTION_CLOSED=51
#INTERNET_STATUS_HANDLE_CLOSING=70
#INTERNET_STATUS_HANDLE_CREATED=60
#INTERNET_STATUS_INTERMEDIATE_RESPONSE=120
#INTERNET_STATUS_RECEIVING_RESPONSE=40
#INTERNET_STATUS_RESPONSE_RECEIVED=41
#INTERNET_STATUS_REDIRECT=110
#INTERNET_STATUS_REQUEST_COMPLETE=100
#INTERNET_STATUS_REQUEST_SENT=31
#INTERNET_STATUS_DETECTING_PROXY=80
#INTERNET_STATUS_RESOLVING_NAME=10
#INTERNET_STATUS_NAME_RESOLVED=11
#INTERNET_STATUS_SENDING_REQUEST=30
#INTERNET_STATUS_STATE_CHANGE=200
#INTERNET_STATUS_P3P_HEADER=325

Import ""
    InitializeCriticalSectionAndSpinCount(*lpCriticalSection.CRITICAL_SECTION, dwSpincount.i)
    
;     BOOL WINAPI InitializeCriticalSectionAndSpinCount(
;   _Out_ LPCRITICAL_SECTION lpCriticalSection,
;   _In_  DWORD              dwSpinCount
; );
    
EndImport

; Structure To store configuration in that was gathered from passed in arguments

Structure CONFIGURATION
    Method.i                     ; DWORD                // Method, GET or POST
    HostName.s                   ; LPWSTR             // Host to connect to
    ResourceOnServer.s           ; LPWSTR     // Resource to get from the server
    InputFileName.s              ; LPWSTR        // File containing data to post
    OutputFileName.s             ; LPWSTR       // File to write the data received from the server
    UseProxy.i                   ; BOOL               // Flag to indicate the use of a proxy
    ProxyName.s                  ; LPWSTR            // Name of the proxy to use
    IsSecureConnection.i         ; BOOL     // Flag to indicate the use of SSL
    UserTimeout.i                ; DWORD           // Timeout for the async operations
EndStructure

; Structure used For storing the context For the asynchronous calls

Structure REQUEST_CONTEXT
    RequestHandle.i              ; HINTERNET
    ConnectHandle.i              ; HINTERNET
    CompletionEvent.i            ; HANDLE
    CleanUpEvent.i               ; HANDLE
    *OutputBuffer                ; LPSTR
    DownloadedBytes.i            ; DWORD
    WrittenBytes.i               ; DWORD
    ReadBytes.i                  ; DWORD
    UploadFile.i                 ; HANDLE
    FileSize.i                   ; DWORD
    DownloadFile.i               ; HANDLE
    Method.i                     ; DWORD
    State.i                      ; DWORD
    
    CriticalSection.CRITICAL_SECTION   ; CRITICAL_SECTION
    CritSecInitialized.i         ; BOOL

    ; Synchronized by CriticalSection

    HandleUsageCount.i           ; DWORD // Request object is in use(not safe to close handle)
    Closing.i                    ; BOOL  // Request is closing(don't use handle)

EndStructure


Structure InternetCookieHistory
	fAccepted.i ; BOOL
	fLeashed.i	; BOOL
	fDowngraded.i  ; BOOL
	fRejected.i		; BOOL
EndStructure

Structure INTERNET_ASYNC_RESULT
	*dwResult ; DWORD_PTR
	dwError.i	 ; DWORD
EndStructure


;- DECLARE

Declare CallBack(hInternet.i, dwContext.i, dwInternetStatus.i, lpvStatusInformation.i, dwStatusInformationLength.i)
Declare.i AllocateAndInitializeRequestContext(SessionHandle.i, *Configuration.CONFIGURATION, *ReqContext.REQUEST_CONTEXT)
Declare.i ProcessRequest(*ReqContext.REQUEST_CONTEXT, Error.i)
Declare WaitForRequestCompletion(*ReqContext.REQUEST_CONTEXT, Timeout.i)
Declare CleanUpRequestContext(*ReqContext.REQUEST_CONTEXT)
Declare CleanUpSessionHandle(SessionHandle.i)
Declare.i SendRequest(*ReqContext.REQUEST_CONTEXT)
Declare.i SendRequestWithBody(*ReqContext.REQUEST_CONTEXT)
Declare.i GetDataToPost(*ReqContext.REQUEST_CONTEXT)
Declare.i PostDataToServer(*ReqContext.REQUEST_CONTEXT, *Eof.INTEGER)
Declare.i CompleteRequest(*ReqContext.REQUEST_CONTEXT)
Declare.i RecvResponseData(*ReqContext.REQUEST_CONTEXT)
Declare.i WriteResponseData(*ReqContext.REQUEST_CONTEXT, *Eof.INTEGER)
Declare.i OpenFiles(*ReqContext.REQUEST_CONTEXT, Method.i, InputFilename.s, OutputFilename.s)
Declare.i CreateWininetHandles(*ReqContext.REQUEST_CONTEXT, SessionHandle.i, HostName.s, Resource.s, IsSecureConnection.i)
Declare.i CloseRequestHandle(*ReqContext.REQUEST_CONTEXT)
Declare.i AcquireRequestHandle(*ReqContext.REQUEST_CONTEXT)
Declare.i ReleaseRequestHandle(*ReqContext.REQUEST_CONTEXT)
Declare ShowUsage()

#INTERNET_INVALID_STATUS_CALLBACK=-1


Procedure ParseArguments(*Configuration.CONFIGURATION)
;     __in int argc,
;     __in_ecount(argc) LPWSTR *argv,
;     __inout PCONFIGURATION Configuration

; Routine Description:
;      This routine is used To Parse command line arguments. Flags are
;      Case sensitive.
; 
; Arguments:
;      argc - Number of arguments
;      argv - Pointer To the argument vector
;      Configuration - pointer To configuration struct To write configuration
; 
; Return Value:
;     Error Code For the operation.


	Protected Error.i = #ERROR_SUCCESS
	Protected i.i
	
	For i=0 To CountProgramParameters()-1
		
		If (Left(ProgramParameter(i), 1)<>"-")
			PrintN("Invalid switch >"+ProgramParameter(i)+"<")
			Continue
			
		Else
			Select Mid(ProgramParameter(i), 2, 1)
					
				Case "p"
					
					*Configuration\UseProxy=1
					
					If (i < (CountProgramParameters()-1))
						i+1
						*Configuration\ProxyName = ProgramParameter(i)
					EndIf
					
				Case "h"
					If (i < (CountProgramParameters()-1))
						i+1
						*Configuration\HostName = ProgramParameter(i)
					EndIf
					
				Case "o"
					
					If (i < (CountProgramParameters()-1))
						i+1
						*Configuration\ResourceOnServer = ProgramParameter(i)
					EndIf
					
				Case "r"
					
					If (i < (CountProgramParameters()-1))
						i+1
						*Configuration\InputFileName = ProgramParameter(i)
					EndIf
					
				Case "w"
					
					If (i < (CountProgramParameters()-1))
						i+1
						*Configuration\OutputFileName = ProgramParameter(i)
					EndIf
					
				Case "m"
					
					If (i < (CountProgramParameters()-1))
						
						If LCase(ProgramParameter(i+1))="get"
							*Configuration\Method = #METHOD_GET
						ElseIf LCase(ProgramParameter(i+1))="post"
							*Configuration\Method = #METHOD_POST
						EndIf
						
					EndIf
					i+1
					
				Case "s"
					
					*Configuration\IsSecureConnection = #True
					
					
				Case "t"
					
					If (i < (CountProgramParameters()-1))
						i+1
						*Configuration\UserTimeout = Val( ProgramParameter(i)  )
					EndIf
					
				Default
					Error = #ERROR_INVALID_PARAMETER
					
			EndSelect
			
		EndIf
		
	Next
	
	If (Error = #ERROR_SUCCESS)
		
		If (*Configuration\UseProxy And *Configuration\ProxyName = "")
			
			Print(~"No proxy server name provided!\n\n")
			Error = #ERROR_INVALID_PARAMETER
			Goto Exit
		EndIf
		
		If (*Configuration\HostName = "")
			
			PrintN("Defaulting hostname to: "+#DEFAULT_HOSTNAME)
			*Configuration\HostName = #DEFAULT_HOSTNAME
			
		EndIf
		
		If (*Configuration\Method = #METHOD_NONE)
			PrintN("Defaulting method to: GET")
			*Configuration\Method = #METHOD_GET
		EndIf
		
		If (*Configuration\ResourceOnServer = "")
			PrintN("Defaulting resource to: "+#DEFAULT_RESOURCE)
			*Configuration\ResourceOnServer = #DEFAULT_RESOURCE
		EndIf
		
		If (*Configuration\UserTimeout = 0)
			PrintN("Defaulting timeout to: "+#DEFAULT_TIMEOUT)
			*Configuration\UserTimeout = #DEFAULT_TIMEOUT
		EndIf
		
		If (*Configuration\InputFileName = "" And *Configuration\Method = #METHOD_POST)
			
			PrintN("Error: File to post not specified")
			Error = #ERROR_INVALID_PARAMETER
			Goto Exit
		EndIf
		
		If (*Configuration\OutputFileName = "")
			PrintN("Defaulting output file to: "+#DEFAULT_OUTPUT_FILE_NAME)
			*Configuration\OutputFileName = #DEFAULT_OUTPUT_FILE_NAME
		EndIf
		
	EndIf
	
	Exit:
	
	ProcedureReturn Error
	
EndProcedure


Procedure wmain()

	Protected Error.i
	Protected OpenType.i = #INTERNET_OPEN_TYPE_PRECONFIG  ; Use pre-configured options as default
	
	Protected Configuration.CONFIGURATION
	
	Protected ReqContext.REQUEST_CONTEXT
	Protected SessionHandle.i
	
	; Callback function
	Protected CallbackPointer.i    ; INTERNET_STATUS_CALLBACK
	
	;     // Parse the command line arguments
	;     Error = ParseArguments(argc, argv, &Configuration);
	
	
	Error=ParseArguments(@Configuration)
	If (Error <> #ERROR_SUCCESS)
		ShowUsage()
		Goto Exit
	EndIf
	
	If (Configuration\UseProxy)
		OpenType = #INTERNET_OPEN_TYPE_PROXY
	EndIf
	
	; Create Session handle And specify async Mode
	SessionHandle = InternetOpen_("WinInet HTTP Async Sample",  ; User Agent
	                              OpenType,							; Preconfig Or Proxy
	                              Configuration\ProxyName,		; Proxy name
	                              #Null,								; Proxy bypass, do Not bypass any address
	                              #INTERNET_FLAG_ASYNC)			; 0 for Synchronous
	
	If (SessionHandle = #Null)
		PrintN("ERROR! InternetOpen >"+GetLastError_()+"<")
		Goto Exit
	EndIf
	
	; Set the status callback For the handle To the Callback function
	CallbackPointer = InternetSetStatusCallback_(SessionHandle, @CallBack())
	
	If (CallbackPointer = #INTERNET_INVALID_STATUS_CALLBACK)
		PrintN("ERROR! InternetSetStatusCallback failed With INTERNET_INVALID_STATUS_CALLBACK")
		Goto Exit
	EndIf
	
	;  Initialize the ReqContext To be used in the asynchronous calls
	Error = AllocateAndInitializeRequestContext(SessionHandle,
	                                            @Configuration,
	                                            @ReqContext)
	
	If (Error <> #ERROR_SUCCESS)
		Goto Exit
	EndIf
	
	; Send out request And receive response
	
	ProcessRequest(@ReqContext, #ERROR_SUCCESS)
	
	; Wait For request completion Or timeout
	
	WaitForRequestCompletion(@ReqContext, Configuration\UserTimeout);
	
Exit:
	
	; Clean up the allocated resources
	CleanUpRequestContext(@ReqContext)
	
	CleanUpSessionHandle(SessionHandle)
	
	If (Error <> #ERROR_SUCCESS)
		ProcedureReturn #True
	Else
		ProcedureReturn #False
	EndIf
    
 EndProcedure

Procedure CallBack(hInternet.i, *dwContext, dwInternetStatus.i, *lpvStatusInformation, dwStatusInformationLength.i)
	
;     __in HINTERNET hInternet,
;     __in DWORD_PTR dwContext,
;     __in DWORD dwInternetStatus,
;     __in_bcount(dwStatusInformationLength) LPVOID lpvStatusInformation,
;     __in DWORD dwStatusInformationLength
	
	
; Routine Description:
;     Callback routine For asynchronous WinInet operations
; 
; Arguments:
;      hInternet - The handle For which the callback function is called.
;      dwContext - Pointer To the application defined context.
;      dwInternetStatus - Status code indicating why the callback is called.
;      lpvStatusInformation - Pointer To a buffer holding callback specific Data.
;      dwStatusInformationLength - Specifies size of lpvStatusInformation buffer.
; 
; Return Value:
;     None.

	Protected *cookieHistory.InternetCookieHistory
	Protected *ReqContext.REQUEST_CONTEXT
	Protected *StatusInformation.INTERNET_ASYNC_RESULT
	
	*ReqContext=*dwContext
 
;     UNREFERENCED_PARAMETER(dwStatusInformationLength);

	Select dwInternetStatus
			
		Case #INTERNET_STATUS_COOKIE_SENT
			PrintN("Status: Cookie found And will be sent With request")
			
		Case #INTERNET_STATUS_COOKIE_RECEIVED
			PrintN("Status: Cookie Received")
			
		Case #INTERNET_STATUS_COOKIE_HISTORY
			PrintN("Status: Cookie History")
			
; 			ASYNC_ASSERT(lpvStatusInformation)
; 			ASYNC_ASSERT(dwStatusInformationLength == SizeOf(InternetCookieHistory))
			
			*cookieHistory = *lpvStatusInformation
			
			If (*cookieHistory\fAccepted)
				PrintN("Cookie Accepted")
			EndIf
			
			If (*cookieHistory\fLeashed)
				PrintN("Cookie Leashed")
			EndIf
			
			If (*cookieHistory\fDowngraded)
				PrintN("Cookie Downgraded")
			EndIf
			
			If (*cookieHistory\fRejected)
				PrintN("Cookie Rejected")
			EndIf
			
		Case #INTERNET_STATUS_CLOSING_CONNECTION
			PrintN("Status: Closing Connection")
			
		Case #INTERNET_STATUS_CONNECTED_TO_SERVER
			PrintN("Status: Connected to Server")
			
		Case #INTERNET_STATUS_CONNECTING_TO_SERVER
			PrintN("Status: Connecting to Server")
			
		Case #INTERNET_STATUS_CONNECTION_CLOSED
			PrintN("Status: Connection Closed")
			
		Case #INTERNET_STATUS_HANDLE_CLOSING
			PrintN("Status: Handle Closing")

;             // Signal the cleanup routine that it is
;             // safe To cleanup the request context

;             ASYNC_ASSERT(ReqContext);
					
			SetEvent_(*ReqContext\CleanUpEvent)

		Case #INTERNET_STATUS_HANDLE_CREATED
			
; 			ASYNC_ASSERT(lpvStatusInformation)
			
			*StatusInformation=*lpvStatusInformation
			
			PrintN("Handle "+*StatusInformation\dwResult+" created") ; ((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwResult)
			
		Case #INTERNET_STATUS_INTERMEDIATE_RESPONSE
			PrintN("Status: Intermediate response")

		Case #INTERNET_STATUS_RECEIVING_RESPONSE
			PrintN("Status: Receiving Response")

		Case #INTERNET_STATUS_RESPONSE_RECEIVED
;          	ASYNC_ASSERT(lpvStatusInformation)
;          	ASYNC_ASSERT(dwStatusInformationLength == SizeOf(DWORD))

			PrintN("Status: Response Received ("+PeekI(*lpvStatusInformation)+" Bytes)")

		Case #INTERNET_STATUS_REDIRECT
			PrintN("Status: Redirect")

		Case #INTERNET_STATUS_REQUEST_COMPLETE
			PrintN("Status: Request complete")

; 			ASYNC_ASSERT(lpvStatusInformation)
			
			*StatusInformation=*lpvStatusInformation

 			ProcessRequest(*ReqContext, *StatusInformation\dwError)

		Case #INTERNET_STATUS_REQUEST_SENT
;          	ASYNC_ASSERT(lpvStatusInformation)
;          	ASYNC_ASSERT(dwStatusInformationLength == SizeOf(DWORD))

			PrintN("Status: Request sent ("+PeekI(*lpvStatusInformation)+" Bytes)") ;, *((LPDWORD)lpvStatusInformation));
			
	
		Case #INTERNET_STATUS_DETECTING_PROXY
			PrintN("Status: Detecting Proxy")
		
		Case #INTERNET_STATUS_RESOLVING_NAME
			PrintN("Status: Resolving Name")
		
		Case #INTERNET_STATUS_NAME_RESOLVED
			PrintN("Status: Name Resolved")
		
		Case #INTERNET_STATUS_SENDING_REQUEST
			PrintN("Status: Sending request")
		
		Case #INTERNET_STATUS_STATE_CHANGE
			PrintN("Status: State Change")
		
		Case #INTERNET_STATUS_P3P_HEADER
			PrintN("Status: Received P3P header")
		
		Default
			PrintN("Status: Unknown >"+dwInternetStatus+"<")
	
	EndSelect

EndProcedure

Procedure.i ProcessRequest(*ReqContext.REQUEST_CONTEXT, Error.i)
;     __inout PREQUEST_CONTEXT ReqContext,
;     __in DWORD Error
	
	
; Routine Description:
;     Process the request context - Sending the request And
;     receiving the response
; 
; Arguments:
;     ReqContext - Pointer To request context Structure
;     Error - error returned from last asynchronous call
; 
; Return Value:
;     None.

	
	Protected Eof.i=#False

    While (Error=#ERROR_SUCCESS And *ReqContext\State <> #REQ_STATE_COMPLETE)
        Select *ReqContext\State
            Case #REQ_STATE_SEND_REQ
; 					Debug "#REQ_STATE_SEND_REQ"
                *ReqContext\State = #REQ_STATE_RESPONSE_RECV_DATA
                Error = SendRequest(*ReqContext)
                
            Case #REQ_STATE_SEND_REQ_WITH_BODY
;                 Debug "#REQ_STATE_SEND_REQ_WITH_BODY"
                *ReqContext\State = #REQ_STATE_POST_GET_DATA
                Error = SendRequestWithBody(*ReqContext)             

            Case #REQ_STATE_POST_GET_DATA
;                 Debug "#REQ_STATE_POST_GET_DATA"
                *ReqContext\State = #REQ_STATE_POST_SEND_DATA
                Error = GetDataToPost(*ReqContext)
                
            Case #REQ_STATE_POST_SEND_DATA
;                 Debug "#REQ_STATE_POST_SEND_DATA"
                *ReqContext\State = #REQ_STATE_POST_GET_DATA
                Error = PostDataToServer(*ReqContext, @Eof)
                
                If(Eof)
;                     ASYNC_ASSERT(Error == ERROR_SUCCESS)
                    *ReqContext\State = #REQ_STATE_POST_COMPLETE
                EndIf
                
            Case #REQ_STATE_POST_COMPLETE
;                 Debug "#REQ_STATE_POST_COMPLETE"
                *ReqContext\State = #REQ_STATE_RESPONSE_RECV_DATA
                Error = CompleteRequest(*ReqContext)
                
            Case #REQ_STATE_RESPONSE_RECV_DATA
;                 Debug "#REQ_STATE_RESPONSE_RECV_DATA"
                *ReqContext\State = #REQ_STATE_RESPONSE_WRITE_DATA
                Error = RecvResponseData(*ReqContext)
                
            Case #REQ_STATE_RESPONSE_WRITE_DATA
; 					Debug "#REQ_STATE_RESPONSE_WRITE_DATA"
                *ReqContext\State = #REQ_STATE_RESPONSE_RECV_DATA;
                Error = WriteResponseData(*ReqContext, @Eof)

                If(Eof)
;                     ASYNC_ASSERT(Error == ERROR_SUCCESS);
                    *ReqContext\State = #REQ_STATE_COMPLETE
                EndIf
                
            Default
;                 Debug #PB_Compiler_Procedure+" - Default >"+*ReqContext\State+"< >"+*ReqContext\DownloadedBytes+"<"
;                 ASYNC_ASSERT(FALSE);
                
        EndSelect
    Wend
    
    If (Error <> #ERROR_IO_PENDING)
;         // Everything has been procesed Or has failed. 
;         // In either Case, the signal processing has
;         // completed

        SetEvent_(*ReqContext\CompletionEvent)
    EndIf

EndProcedure

Procedure.i AllocateAndInitializeRequestContext(SessionHandle.i, *Configuration.CONFIGURATION, *ReqContext.REQUEST_CONTEXT)

; Routine Description:
;     Allocate the request context And initialize it values
; 
; Arguments:
;     ReqContext - Pointer To Request context Structure
;     Configuration - Pointer To configuration Structure
;     SessionHandle - Wininet session handle To use when creating
;                     connect handle
;     
; Return Value:
;     Error Code For the operation.


	Protected Error.i = #ERROR_SUCCESS
	Protected Success.i
    
	*ReqContext\RequestHandle = #Null
	*ReqContext\ConnectHandle = #Null
	*ReqContext\DownloadedBytes = 0
	*ReqContext\WrittenBytes = 0
	*ReqContext\ReadBytes = 0
	*ReqContext\UploadFile = #INVALID_HANDLE_VALUE
	*ReqContext\DownloadFile = #INVALID_HANDLE_VALUE
	*ReqContext\FileSize = 0
	*ReqContext\HandleUsageCount = 0
	*ReqContext\Closing = #False
	*ReqContext\Method = *Configuration\Method
	*ReqContext\CompletionEvent = #Null    
	*ReqContext\CleanUpEvent = #Null
	*ReqContext\OutputBuffer = #Null
	If (*ReqContext\Method=#METHOD_GET)
		*ReqContext\State = #REQ_STATE_SEND_REQ
	Else
		*ReqContext\State = #REQ_STATE_SEND_REQ_WITH_BODY
	EndIf
	
	*ReqContext\CritSecInitialized = #False   
	   
	; initialize critical section
	
	Success = InitializeCriticalSectionAndSpinCount(@*ReqContext\CriticalSection, #SPIN_COUNT)
	
	If (Not Success)
		Error = GetLastError_()
		PrintN("ERROR InitializeCriticalSectionAndSpinCount >"+Error+"<")
		Goto Exit
	EndIf
	
	*ReqContext\CritSecInitialized = #True
	
	*ReqContext\OutputBuffer = AllocateMemory(#BUFFER_LEN)
	
	If (Not *ReqContext\OutputBuffer)
		
		Error = #ERROR_NOT_ENOUGH_MEMORY
		Goto Exit
	EndIf
	
	; 	// create events
	
	*ReqContext\CompletionEvent = CreateEvent_(#Null,  ;// Sec attrib
	                                               #False, ;// Auto reset
	                                               #False, ;// Initial state unsignalled
	                                               #Null)	 ; // Name
	
	If (*ReqContext\CompletionEvent = #Null)
		Error = GetLastError_()
		PrintN("ERROR CreateEvent CompletionEvent >"+Error+"<")
		Goto Exit
	EndIf
	
	; 	// create events
	
	*ReqContext\CleanUpEvent = CreateEvent_(#Null,  ;// Sec attrib
	                                            #False, ;// Auto reset
	                                            #False, ;// Initial state unsignalled
	                                            #Null)	 ; // Name
	
	If (*ReqContext\CleanUpEvent = #Null)
		Error = GetLastError_()
		PrintN("ERROR CreateEvent CleanUpEvent >"+Error+"<")
		Goto Exit
	EndIf
	
; 	// Open the file To dump the response entity body And
; 	// If required the file With the Data To post
	
	Error = OpenFiles(*ReqContext,
	                   *Configuration\Method, 
	                   *Configuration\InputFileName, 
	                   *Configuration\OutputFileName)
	
	If (Error <> #ERROR_SUCCESS)
		PrintN("ERROR OpenFiles failed With >"+Error+"<")
		Goto Exit
	EndIf
	
	; 	// Verify If we've opened a file to post and get its size
	
	If (*ReqContext\UploadFile <> #INVALID_HANDLE_VALUE)
		*ReqContext\FileSize = GetFileSize_(*ReqContext\UploadFile, #Null)
		
		If(*ReqContext\FileSize = #INVALID_FILE_SIZE)
			Error = GetLastError_()
			PrintN("ERROR GetFileSize >"+Error+"<")
			Goto Exit
		EndIf
		
	EndIf

	Error = CreateWininetHandles(*ReqContext, 
	                              SessionHandle,
	                              *Configuration\HostName,
	                              *Configuration\ResourceOnServer,
	                              *Configuration\IsSecureConnection)
	
	If (Error <> #ERROR_SUCCESS)
		PrintN("ERROR CreateWininetHandles failed With >"+Error+"<")
		Goto Exit
	EndIf
	

Exit:
	
	If (Error <> #ERROR_SUCCESS)
		CleanUpRequestContext(*ReqContext)
	EndIf
		
	ProcedureReturn Error
	
EndProcedure




Procedure WaitForRequestCompletion(*ReqContext.REQUEST_CONTEXT, Timeout.i)
	;     __in PREQUEST_CONTEXT ReqContext,
	;     __in DWORD Timeout
	
	; Routine Description:
	;     Wait For the request To complete Or timeout To occur
	; 
	; Arguments:
	;     ReqContext - Pointer To request context Structure
	; 
	; Return Value:
	;     None.
	
	Protected SyncResult.i ;     DWORD SyncResult;
	Protected iError.i
	
	;     // The preferred method of doing timeouts is To
	;     // use the timeout options through InternetSetOption,
	;     // but this overall timeout is being used To show 
	;     // the correct way To abort And close a request.
	
	SyncResult = WaitForSingleObject_(*ReqContext\CompletionEvent, Timeout)    ; Wait until we receive the completion
	
	Select (SyncResult)
		Case #WAIT_OBJECT_0
			PrintN("Done!")
		
		Case #WAIT_TIMEOUT
			PrintN("Timeout while waiting for completion event (request will be cancelled)")
			
		
		Case #WAIT_FAILED:
			iError=GetLastError_()
			PrintN("Wait failed with Error "+iError+" While waiting For completion Event (request will be cancelled)")
			
		
		Default        ; Not expecting any other error codes
			
	
	EndSelect

EndProcedure
   




Procedure CleanUpRequestContext(*ReqContext.REQUEST_CONTEXT)
;     __inout_opt PREQUEST_CONTEXT ReqContext

; Routine Description:
;     Used To cleanup the request context before exiting.
; 
; Arguments:
;     ReqContext - Pointer To request context Structure
; 
; Return Value:
;     None.


	If (*ReqContext\RequestHandle) 
		CloseRequestHandle(*ReqContext)

;         // Wait For the closing of the handle To complete
;         // (waiting For all async operations To complete)
;         //
;         // This is the only safe way To get rid of the context
		
		WaitForSingleObject_(*ReqContext\CleanUpEvent, #INFINITE)
	EndIf
    
	If (*ReqContext\ConnectHandle)
;         // Remove the callback from the ConnectHandle since
;         // we don't want the closing notification
;         // The callback was inherited from the session handle

		InternetSetStatusCallback_(*ReqContext\ConnectHandle, #Null)
	
		InternetCloseHandle_(*ReqContext\ConnectHandle)
	EndIf  

	If (*ReqContext\UploadFile <> #INVALID_HANDLE_VALUE) 
		CloseHandle_(*ReqContext\UploadFile)
	EndIf
	
	If (*ReqContext\DownloadFile <> #INVALID_HANDLE_VALUE) 
		CloseHandle_(*ReqContext\DownloadFile)
	EndIf
	
	If (*ReqContext\CompletionEvent) 
		CloseHandle_(*ReqContext\CompletionEvent)
	EndIf
	
	If (*ReqContext\CleanUpEvent) 
		CloseHandle_(*ReqContext\CleanUpEvent)
	EndIf
	
	If(*ReqContext\CritSecInitialized)
		DeleteCriticalSection_(*ReqContext\CriticalSection)
	EndIf

EndProcedure
 
 
Procedure CleanUpSessionHandle(SessionHandle.i)
;     __in HINTERNET SessionHandle

; Routine Description:
;     Used To cleanup session before exiting.
; 
; Arguments:
;     SessionHandle - Wininet session handle
; 
; Return Value:
;     None.

    If (SessionHandle) 

;         // Remove the callback from the SessionHandle since
;         // we don't want the closing notification
		InternetSetStatusCallback_(SessionHandle, #Null)

;         // Call InternetCloseHandle And do Not wait For the closing notification 
;         // in the callback function
		
		InternetCloseHandle_(SessionHandle)
	EndIf
	
EndProcedure

Procedure.i SendRequest(*ReqContext.REQUEST_CONTEXT)
;     __in PREQUEST_CONTEXT ReqContext


; Routine Description:
;     Send the request using HttpSendRequest
; 
; Arguments:
;     ReqContext - Pointer To request context Structure
; 
; Return Value:
;     Error code For the operation.

	Protected Success.i
	Protected Error.i=#ERROR_SUCCESS
	
	Success = AcquireRequestHandle(*ReqContext)
	If Not Success
		Error = #ERROR_OPERATION_ABORTED
		Goto Exit
	EndIf
	
	
	Success = HttpSendRequest_(*ReqContext\RequestHandle,
										#Null,                   ;do Not provide additional Headers
										0,                      ;dwHeadersLength 
										#Null,                   ;Do Not send any Data 
										0)                     ;dwOptionalLength 
	
	ReleaseRequestHandle(*ReqContext)
	
	If Not Success
		Error = GetLastError_()

		If(Error <>#ERROR_IO_PENDING)
			PrintN("ERROR HttpSendRequest >"+Error+"<")
		EndIf
	EndIf
		
	
Exit:
	
	ProcedureReturn Error
	     
EndProcedure


Structure INTERNET_BUFFERS
	dwStructSize.l ;   DWORD             ;
	*Next ;   _INTERNET_BUFFERS ;
	lpcszHeader.l ;   LPCTSTR           ;
	dwHeadersLength.l  ;   DWORD             ;
	dwHeadersTotal.l   ;   DWORD             ;
	lpvBuffer.l  ;   LPVOID            ;
	dwBufferLength.l    ;   DWORD             ;
	dwBufferTotal.l    ;   DWORD             ;
	dwOffsetLow.l   ;   DWORD             ;
	dwOffsetHigh.l   ;   DWORD             ;
EndStructure


Procedure.i SendRequestWithBody(*ReqContext.REQUEST_CONTEXT)
;     __in PREQUEST_CONTEXT ReqContext

; Routine Description:
;     Send the request With entity-body using HttpSendRequestEx
; 
; Arguments:
;     ReqContext - Pointer To request context Structure
; 
; Return Value:
;     Error code For the operation.
	
	Protected Success.i
	Protected *BuffersIn.INTERNET_BUFFERS
	Protected Error.i=#ERROR_SUCCESS
    

;     // HttpSendRequest can also be used also To post Data To a server, 
;     // To do so, the Data should be provided using the lpOptional
;     // parameter And it's size on dwOptionalLength.
;     // Here we decided To depict the use of HttpSendRequestEx function.

    
;     //Prepare the Buffers To be passed To HttpSendRequestEx
	*BuffersIn=AllocateStructure(INTERNET_BUFFERS)
	
	*BuffersIn\dwStructSize = SizeOf(INTERNET_BUFFERS)
	*BuffersIn\lpvBuffer = #Null
	*BuffersIn\dwBufferLength = 0
	*BuffersIn\dwBufferTotal = *ReqContext\FileSize; // content-length of data to post

	Success = AcquireRequestHandle(*ReqContext)
	If (Not Success)
		Error = #ERROR_OPERATION_ABORTED
		Goto Exit
	EndIf
   
	Success = HttpSendRequestEx_(*ReqContext\RequestHandle,
	                             *BuffersIn,
	                             #Null,      ;           // Do Not use output buffers
	                             0,			  ;         // dwFlags reserved
	                             *ReqContext)
	
	Error = GetLastError_()
	
	ReleaseRequestHandle(*ReqContext)
		
	If (Not Success)
		
		Error = GetLastError_()

		If (Error <> #ERROR_IO_PENDING)
			
			PrintN("ERROR HttpSendRequestEx >"+Error+"<")
			
		EndIf
		
		Goto Exit
		
	EndIf

Exit:
	
	ProcedureReturn Error
	
EndProcedure

Procedure.i GetDataToPost(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext
	
; Routine Description:
;     Reads Data from a file
; 
; Arguments:
;     ReqContext - Pointer To request context Structure
; 
; Return Value:
;     Error code For the operation.

	Protected Error = #ERROR_SUCCESS
	Protected Success.i
	
; 	// ReadFile is done inline here assuming that it will Return quickly
; 	// I.E. the file is on disk
; 	//
; 	// If you plan To do blocking/intensive operations they should be
; 	// queued To another thread And Not block the callback thread
	
	Success = ReadFile_(*ReqContext\UploadFile,
	                    *ReqContext\OutputBuffer,
	                    #BUFFER_LEN,
	                    @*ReqContext\ReadBytes,
	                    #Null)
	If (Not Success)
		Error = GetLastError_()
		
		PrintN("ERROR ReadFile >"+Error+"<")
		
	EndIf
	
	ProcedureReturn Error
	
EndProcedure

Procedure.i PostDataToServer(*ReqContext.REQUEST_CONTEXT, *Eof.INTEGER)
;     __inout PREQUEST_CONTEXT ReqContext,
;     __out PBOOL Eof

; Routine Description:
;     Post Data in the http request
; 
; Arguments:
;     ReqContext - Pointer To request context Structure
;     Eof - Done posting Data To server
; 
; Return Value:
;     Error code For the operation.

	
	Protected Error.i = #ERROR_SUCCESS
	Protected Success.i
	
	
	*Eof\i = #False
	
	If (*ReqContext\ReadBytes = 0)
		*Eof\i = #True
		Goto Exit
	EndIf
		
	Success = AcquireRequestHandle(*ReqContext)
	If (Not Success)
		Error = #ERROR_OPERATION_ABORTED
		Goto Exit
	EndIf
		
; 	// The lpdwNumberOfBytesWritten parameter will be
; 	// populated on async completion, so it must exist
; 	// Until INTERNET_STATUS_REQUEST_COMPLETE.
; 	// The same is true of lpBuffer parameter.

	Success = InternetWriteFile_(*ReqContext\RequestHandle,
	                             *ReqContext\OutputBuffer,
	                             *ReqContext\ReadBytes,
	                             @*ReqContext\WrittenBytes)
	
	ReleaseRequestHandle(*ReqContext)
	
	If (Not Success)
		Error = GetLastError_()
		
		If (Error = #ERROR_IO_PENDING)
			
			PrintN("Waiting For InternetWriteFile To complete")
			
		Else
			PrintN("ERROR InternetWriteFile >"+Error+"<")
		EndIf
		
		Goto Exit
	EndIf
	
Exit:
	
	ProcedureReturn Error
	
EndProcedure


Procedure.i CompleteRequest(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext

; Routine Description:
;     Perform completion of asynchronous post.
; 
; Arguments:
;     ReqContext - Pointer To request context Structure
; 
; Return Value:
;     Error Code For the operation.

	Protected Error.i = #ERROR_SUCCESS
	Protected Success.i
	
	Success = AcquireRequestHandle(*ReqContext)
	
	If (Not Success)
		Error = #ERROR_OPERATION_ABORTED
		Goto Exit
	EndIf
	
	Success = HttpEndRequest_(*ReqContext\RequestHandle, #Null, 0, 0)
	
	ReleaseRequestHandle(*ReqContext)
	
	If (Not Success)
		Error = GetLastError_()
		If (Error = #ERROR_IO_PENDING)
			
			PrintN("Waiting for HttpEndRequest to complete")
			
		Else			
			PrintN("ERROR HttpEndRequest >"+Error+"<")
			Goto Exit
		EndIf
	EndIf
	
Exit:
	ProcedureReturn Error
	
EndProcedure


Procedure.i RecvResponseData(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext

; Routine Description:
;      Receive response
; 
; Arguments:
;      ReqContext - Pointer To request context Structure
; 
; Return Value:
;      Error Code For the operation.

	Protected Error.i = #ERROR_SUCCESS
	Protected Success.i
	
	Success = AcquireRequestHandle(*ReqContext)
	
	If (Not Success)
		Error = #ERROR_OPERATION_ABORTED
		Goto Exit
	EndIf
	
; 	// The lpdwNumberOfBytesRead parameter will be
; 	// populated on async completion, so it must exist
; 	// Until INTERNET_STATUS_REQUEST_COMPLETE.
; 	// The same is true of lpBuffer parameter.
; 	//
; 	// InternetReadFile will block Until the buffer
; 	// is completely filled Or the response is exhausted.
	
	Success = InternetReadFile_(*ReqContext\RequestHandle,
	                            *ReqContext\OutputBuffer,
	                            #BUFFER_LEN,
	                            @*ReqContext\DownloadedBytes)
	
	ReleaseRequestHandle(*ReqContext)
	
	If (Not Success)
		Error = GetLastError_()
		If(Error = #ERROR_IO_PENDING)
			PrintN("Waiting for InternetReadFile to complete")
		Else
			PrintN("ERROR InternetReadFile >"+Error+"<")
		EndIf
		
		Goto Exit
	EndIf
	
Exit:
	
	ProcedureReturn Error
	
EndProcedure



Procedure.i WriteResponseData(*ReqContext.REQUEST_CONTEXT, *Eof.INTEGER)
;     __in PREQUEST_CONTEXT ReqContext,
;     __out PBOOL Eof
	
; Routine Description:
;      Write response To a file
; 
; Arguments:
;      ReqContext - Pointer To request context Structure
;      Eof - Done With response
; 
; Return Value:
;      Error Code For the operation.

	
	Protected Error.i = #ERROR_SUCCESS
	Protected BytesWritten.i = 0
	Protected Success.i
	
	*Eof\i = #False
	
	; 	// Finished receiving response
	
	If (*ReqContext\DownloadedBytes = 0)
		*Eof\i = #True
		Goto Exit
	EndIf
	
; 	// WriteFile is done inline here assuming that it will Return quickly
; 	// I.E. the file is on disk
; 	//
; 	// If you plan To do blocking/intensive operations they should be
; 	// queued To another thread And Not block the callback thread
	
	Success = WriteFile_(*ReqContext\DownloadFile,
	                     *ReqContext\OutputBuffer,
	                     *ReqContext\DownloadedBytes,
	                     @BytesWritten,
	                     #Null)
	
	If (Not Success)
		Error = GetLastError_()
		PrintN("ERROR WriteFile >"+Error+"<")
		Goto Exit
	EndIf
	
Exit:
	
	ProcedureReturn Error
	
EndProcedure




Procedure.i OpenFiles(*ReqContext.REQUEST_CONTEXT, Method.i, InputFilename.s, OutputFilename.s)
;     __inout PREQUEST_CONTEXT ReqContext,
;     __in DWORD Method,
;     __in LPWSTR InputFileName,
;     __in LPWSTR OutputFileName    


; Routine Description:
;     This routine opens files, one To post Data from, And
;     one To write response into
; 
; Arguments:
;     ReqContext - Pointer To request context Structure
;     Method - GET Or POST - do we need To open the input file
;     InputFileName - Input file name
;     OutputFileName - output file name
; 
; Return Value:
;     Error Code For the operation.

	Protected Error.i=#ERROR_SUCCESS
	
	If (Method = #METHOD_POST)
;         // Open input file
		*ReqContext\UploadFile = CreateFile_(InputFileName,
		                                     #GENERIC_READ,
		                                     #FILE_SHARE_READ, 
		                                     #Null,                   ;// handle cannot be inherited
		                                     #OPEN_ALWAYS,				  ;// If file exists, open it
		                                     #FILE_ATTRIBUTE_NORMAL,
		                                     #Null)	;                  // No template file
		
		If (*ReqContext\UploadFile = #INVALID_HANDLE_VALUE)
			Error = GetLastError_()
			PrintN("ERROR CreateFile for input file >"+InputFilename+"< Error >"+Error+"<")
			Goto Exit
		EndIf
	EndIf
	
	;// Open output file
	
	*ReqContext\DownloadFile = CreateFile_(OutputFileName,
	                                       #GENERIC_WRITE,
	                                       0,                        ;// Open exclusively
	                                       #Null,						  ;// handle cannot be inherited
	                                       #CREATE_ALWAYS,			  ;// If file exists, delete it
	                                       #FILE_ATTRIBUTE_NORMAL,
	                                       #Null);                    // No template file
	
	If (*ReqContext\DownloadFile = #INVALID_HANDLE_VALUE)
		Error = GetLastError_()
		PrintN("ERROR CreateFile for output file >"+OutputFilename+"< Error >"+Error+"<")
		Goto Exit
	EndIf
	
Exit:
	ProcedureReturn Error
	
EndProcedure




Procedure.i CreateWininetHandles(*ReqContext.REQUEST_CONTEXT, SessionHandle.i, HostName.s, Resource.s, IsSecureConnection.i)
;     __inout PREQUEST_CONTEXT ReqContext,
;     __in HINTERNET SessionHandle,
;     __in LPWSTR HostName,
;     __in LPWSTR Resource,
;     __in BOOL IsSecureConnection

; Routine Description:
;     Create connect And request handles
; 
; Arguments:
;     ReqContext - Pointer To Request context Structure
;     SessionHandle - Wininet session handle used To create
;                     connect handle
;     HostName - Hostname To connect
;     Resource - Resource To get/post
;     IsSecureConnection - SSL?
; 
; Return Value:
;     Error Code For the operation.
	
	Protected Error.i = #ERROR_SUCCESS
	Protected ServerPort = #INTERNET_DEFAULT_HTTP_PORT
	Protected RequestFlags = 0
	Protected Verb.s
	
; 	 // Set the correct server port If using SSL
;   // Also set the flag For HttpOpenRequest 
	
	If (IsSecureConnection)
		ServerPort = #INTERNET_DEFAULT_HTTPS_PORT
		RequestFlags = #INTERNET_FLAG_SECURE
	EndIf
	
; 	// Create Connection handle And provide context For async operations
	*ReqContext\ConnectHandle = InternetConnect_(SessionHandle,
	                                             HostName,                  ;// Name of the server To connect To
	                                             ServerPort,						;// HTTP (80) Or HTTPS (443)
	                                             #Null,							;// Do Not provide a user name For the server
	                                             #Null,							;// Do Not provide a password For the server
	                                             #INTERNET_SERVICE_HTTP,
	                                             0,                         ;// Do Not provide any special flag
	                                             *ReqContext)					;    // Provide the context to be used during the callbacks
	
;     // For HTTP InternetConnect returns synchronously because it does Not
;     // actually make the connection.
;     //
;     // For FTP InternetConnect connects the control channel, And therefore
;     // can be completed asynchronously.  This sample would have To be
;     // changed, so that the InternetConnect's asynchronous completion
;     // is handled correctly To support FTP.
	
	If (*ReqContext\ConnectHandle = #Null)
		Error = GetLastError_()
		PrintN("ERROR InternetConnect >"+Error+"<")
		Goto Exit
	EndIf
	
;     // Set the Verb depending on the operation To perform
	If (*ReqContext\Method = #METHOD_GET)
		Verb = "GET"
	Else
; 		ASYNC_ASSERT(ReqContext->Method == METHOD_POST);
		Verb = "POST"
	EndIf
	
;     // We're overriding WinInet's Default behavior.
;     // Setting these flags, we make sure we get the response from the server And Not the cache.
;     // Also ask WinInet Not To store the response in the cache.
;     //
;     // These flags are Not performant And are only used To show Case WinInet's Async I/O.
;     // A real WinInet application would Not want To use this flags.
    
	RequestFlags = RequestFlags | #INTERNET_FLAG_RELOAD | #INTERNET_FLAG_NO_CACHE_WRITE
	
;     // Create a Request handle
	*ReqContext\RequestHandle = HttpOpenRequest_(*ReqContext\ConnectHandle,
	                                             Verb,                     ;// GET Or POST
	                                             Resource,					  ;// root "/" by Default
	                                             #Null,						  ;// Use Default HTTP/1.1 As the version
	                                             #Null,						  ;// Do Not provide any referrer
	                                             #Null,						  ;// Do Not provide Accept types
	                                             RequestFlags,
	                                             *ReqContext)
	
	If (*ReqContext\RequestHandle = #Null)
		Error = GetLastError_()
		PrintN("ERROR HttpOpenRequest >"+Error+"<")
		Goto Exit
	EndIf
	
Exit:
	
	ProcedureReturn Error
EndProcedure

Procedure.i CloseRequestHandle(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext

; Routine Description:
;     Safely  close the request handle by synchronizing
;     With all threads using the handle.
; 
;     When this function returns no more calls can be made With the
;     handle.
;     
; Arguments:
;     ReqContext - Pointer To Request context Structure
; Return Value:
;     None.

	
	Protected Close = #False
	
	EnterCriticalSection_(*ReqContext\CriticalSection)
	
;     // Current implementation only supports the main thread
;     // kicking off the request handle close
;     //
;     // To support multiple threads the lifetime 
;     // of the request context must be carefully controlled
;     // (most likely guarded by refcount/critsec)
;     // so that they are Not trying To abort a request
;     // where the context has already been freed.
    
;     ASYNC_ASSERT(ReqContext->Closing == FALSE);
	*ReqContext\Closing = #True
	
	If (*ReqContext\HandleUsageCount = 0)
		Close = #True
	EndIf
	
	LeaveCriticalSection_(*ReqContext\CriticalSection)
	
	If (Close)
;         // At this point there must be the guarantee that all calls
;         // To wininet With this handle have returned With some value
;         // including ERROR_IO_PENDING, And none will be made after
;         // InternetCloseHandle.
		
		InternetCloseHandle_(*ReqContext\RequestHandle)
	EndIf
	
EndProcedure


Procedure.i AcquireRequestHandle(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext
	
; Routine Description:
;     Acquire use of the request handle To make a wininet call
; Arguments:
;     ReqContext - Pointer To Request context Structure
; Return Value:
;     TRUE - Success
;     FALSE - Failure
	
	
	Protected Success.i = #True
	
	EnterCriticalSection_(@*ReqContext\CriticalSection)
	
	If(*ReqContext\Closing = #True)
		Success = #False
	Else
		*ReqContext\HandleUsageCount+1
	EndIf
	
	LeaveCriticalSection_(@*ReqContext\CriticalSection)
	
	ProcedureReturn Success
	
EndProcedure


Procedure.i ReleaseRequestHandle(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext

; Routine Description:
;     release use of the request handle
; Arguments:
;     ReqContext - Pointer To Request context Structure
; Return Value:
;     None.
	
	Protected Close.i = #False
	
	EnterCriticalSection_(*ReqContext\CriticalSection)
	
	; 	ASYNC_ASSERT(ReqContext->HandleUsageCount > 0)
	
	*ReqContext\HandleUsageCount-1
	
	If (*ReqContext\Closing = #True And *ReqContext\HandleUsageCount = 0)
		
		Close = #True
		
	EndIf
	
	LeaveCriticalSection_(*ReqContext\CriticalSection)
	
	If (Close)
		
;         // At this point there must be the guarantee that all calls
;         // To wininet With this handle have returned With some value
;         // including ERROR_IO_PENDING, And none will be made after
;         // InternetCloseHandle.
		
		InternetCloseHandle_(*ReqContext\RequestHandle)
		
	EndIf
	
EndProcedure


Procedure ShowUsage()

; Routine Description:
;       Shows the usage of the application.
; 
; Arguments:
;       None.
; 
; Return Value:
;       None.
	
	
	PrintN("Usage: async [-m {GET|POST}] [-h <hostname>] [-o <resourcename>] [-s] [-p <proxyname>] [-w <output filename>] [-r <file to post>] [-t <userTimeout>]\n")
	PrintN("Option Semantics:")
	PrintN(~"-m : Specify method (Default: \"GET\")")
	PrintN(~"-h : Specify hostname (Default: \""+#DEFAULT_HOSTNAME+~"\"")
	PrintN(~"-o : Specify resource name on the server (Default: \""+#DEFAULT_RESOURCE+~"\")")
	PrintN("-s : Use secure connection - https");
	PrintN("-p : Specify proxy");
	PrintN(~"-w : Specify file to write output to (Default: \""+#DEFAULT_OUTPUT_FILE_NAME+~"\")")
	PrintN("-r : Specify file to post data from")
	PrintN("-t : Specify time to wait in ms for operation completion (Default: "+#DEFAULT_TIMEOUT+")")
    
EndProcedure



If OpenConsole("MS Async Example")
	
	wmain()

	PrintN("Press return to close console")
	Input()
	CloseConsole()
	
EndIf
Last edited by nalor on Sat Jun 30, 2018 8:57 pm, edited 2 times in total.
User avatar
Sicro
Enthusiast
Enthusiast
Posts: 538
Joined: Wed Jun 25, 2014 5:25 pm
Location: Germany
Contact:

Re: MS Asynchronous Internet Request Example converted to PB

Post by Sicro »

; Copyright (C) Microsoft. All Rights Reserved.
You should remove this, because the code is so different from the original code that you are the new copyright holder of the code and thus have the sole copyright to the entire code.
If this wouldn't the case, you may not modify the code and publish it here, unless Microsoft has put the original code under a license that allows you to do that.
Image
Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version
nalor
Enthusiast
Enthusiast
Posts: 115
Joined: Thu Apr 02, 2009 9:48 pm

Re: MS Asynchronous Internet Request Example converted to PB

Post by nalor »

Sicro wrote:
; Copyright (C) Microsoft. All Rights Reserved.
You should remove this, because the code is so different from the original code that you are the new copyright holder of the code and thus have the sole copyright to the entire code.
If this wasn't the case, you may not modify the code and publish it here, unless Microsoft has put the original code under a license that allows you to do that.
You are right, removed this line.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: MS Asynchronous Internet Request Example converted to PB

Post by Kwai chang caine »

Hello NALOR
I have tested your splendid code in my enterprise, and it works like a charm :D
It's nearly the first time since several years an internet code works perfectly and the first time with the PROXY i have :shock:

I have not really all understand how use it :oops:
But apparently that works, see yourself :wink:
Defaulting hostname to: http://www.microsoft.com
Defaulting method to: GET
Defaulting resource to: /
Defaulting timeout to: 120000
Defaulting output file to: response.htm
Handle 13369352 created
Handle 13369356 created
Status: Detecting Proxy
Status: Cookie found And will be sent With request
Status: Resolving Name
Status: Name Resolved
Status: Connecting to Server
Status: Connected to Server
Status: Sending request
Status: Request sent (297 Bytes)
Status: Receiving Response
Status: Response Received (204 Bytes)
Status: Redirect
Status: Detecting Proxy
Status: Cookie found And will be sent With request
Status: Sending request
Status: Request sent (405 Bytes)
Status: Receiving Response
Status: Response Received (1024 Bytes)
Status: Received P3P header
Status: Request complete
Status: Receiving Response
Status: Response Received (3990 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (3178 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (647 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (3601 Bytes)
Status: Receiving Response
Waiting for InternetReadFile to complete
Status: Response Received (4096 Bytes)
Status: Request complete
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (24 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (24 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4040 Bytes)
Done!
Status: Handle Closing
Press return to close console
Thanks a lot for sharing 8)
ImageThe happiness is a road...
Not a destination
nalor
Enthusiast
Enthusiast
Posts: 115
Joined: Thu Apr 02, 2009 9:48 pm

Re: MS Asynchronous Internet Request Example converted to PB

Post by nalor »

The only problem is that sometimes I get an 'Invalid memory access' at random locations ... if someone has an idea please tell me.

Basically I'd like to create a module from it with more or less the same syntax as the purebasic native command ReceiveHttpFile - but just to post files instead of receiving them.
nalor
Enthusiast
Enthusiast
Posts: 115
Joined: Thu Apr 02, 2009 9:48 pm

Re: MS Asynchronous Internet Request Example converted to PB

Post by nalor »

nalor wrote:The only problem is that sometimes I get an 'Invalid memory access' at random locations ... if someone has an idea please tell me.
I think I've found the error myself - corrected the source in the first post and included a small note about my 2 corrections compared to the original post.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: MS Asynchronous Internet Request Example converted to PB

Post by Kwai chang caine »

Works with W10 X64 / v5.61(x86)
Thanks NALOR 8)
Defaulting hostname to: www.microsoft.com
Defaulting method to: GET
Defaulting resource to: /
Defaulting timeout to: 120000
Defaulting output file to: response.htm
Handle 13369352 created
Handle 13369356 created
Status: Detecting Proxy
Status: Cookie found And will be sent With request
Status: Resolving Name
Status: Name Resolved
Status: Connecting to Server
Status: Connected to Server
Status: Sending request
Status: Request sent (494 Bytes)
Status: Receiving Response
Status: Response Received (174 Bytes)
Status: Redirect
Status: Detecting Proxy
Status: Cookie found And will be sent With request
Status: Connecting to Server
Status: Connected to Server
Status: Sending request
Status: Request sent (593 Bytes)
Status: Receiving Response
Status: Response Received (1024 Bytes)
Status: Receiving Response
Status: Response Received (1024 Bytes)
Status: Received P3P header
Status: Cookie Received
Status: Request complete
Status: Receiving Response
Status: Response Received (3371 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (2773 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (1325 Bytes)
Status: Receiving Response
Waiting for InternetReadFile to complete
Status: Response Received (4096 Bytes)
Status: Request complete
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (2752 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (3756 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (24 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (12 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (4096 Bytes)
Status: Receiving Response
Status: Response Received (12 Bytes)
Status: Receiving Response
Waiting for InternetReadFile to complete
Status: Response Received (4096 Bytes)
Status: Request complete
Status: Receiving Response
Status: Response Received (2156 Bytes)
Status: Receiving Response
Status: Response Received (12 Bytes)
Done!
Status: Handle Closing
Press return to close console
ImageThe happiness is a road...
Not a destination
jassing
Addict
Addict
Posts: 1745
Joined: Wed Feb 17, 2010 12:00 am

Re: MS Asynchronous Internet Request Example converted to PB

Post by jassing »

Windows 10 x64 (pb 5.62 x64)

Code: Select all

Defaulting hostname to: www.microsoft.com
Defaulting method to: GET
Defaulting resource to: /
Defaulting timeout to: 120000
Defaulting output file to: response.htm
Handle 13369352 created
Handle 13369356 created
ERROR HttpSendRequest >0<
Done!
Status: Detecting Proxy
Status: Request complete
Status: Handle Closing
Press return to close console
User avatar
Zapman
User
User
Posts: 13
Joined: Tue Jan 07, 2020 7:27 pm

Re: MS Asynchronous Internet Request Example converted to PB

Post by Zapman »

Hi Nalor,

Thanks a lot for this beautiful work. It's very helpfull.
I adapted the code to make it thread safe and to correct a bug when downloading big files.
I added the mention "ADDED BY ZAPMAN" on the modified lines.

[Edit] Modified on 3 march 2020: there was a bug with POST method

Code: Select all

; FROM https://msdn.microsoft.com/en-us/library/windows/desktop/cc185684(v=vs.85).aspx
;
; The conversion to PureBasic has been made by nalor - https://www.purebasic.fr/english/viewtopic.php?f=12&t=70916
;
; Adapted by Zapman to become thread-safe and to correct some weird bugs.
; Also adapted to receive data in memory instead of create a file, if wished.
;
;
; For Purebasic 5.xx - Windows version.
;

;EnableExplicit

;- CONSTANTS AND STRUCTURES
;{
#BUFFER_LEN=20000
#ERR_MSG_LEN=512

#METHOD_NONE=0
#METHOD_GET =1
#METHOD_POST=2

#RWDataFile = 1
#RWDataMemory = 2

#REQ_STATE_SEND_REQ             =0
#REQ_STATE_SEND_REQ_WITH_BODY   =1
#REQ_STATE_POST_GET_DATA        =2
#REQ_STATE_POST_SEND_DATA       =3
#REQ_STATE_POST_COMPLETE        =4
#REQ_STATE_RESPONSE_RECV_DATA   =5
#REQ_STATE_RESPONSE_WRITE_DATA  =6
#REQ_STATE_COMPLETE             =7

#DEFAULT_TIMEOUT = 30000 ; 30 sec.

#SPIN_COUNT =4000

#INTERNET_STATUS_COOKIE_SENT=320
#INTERNET_STATUS_COOKIE_RECEIVED=321
#INTERNET_STATUS_COOKIE_HISTORY=327
#INTERNET_STATUS_CLOSING_CONNECTION=50
#INTERNET_STATUS_CONNECTED_TO_SERVER=21
#INTERNET_STATUS_CONNECTING_TO_SERVER=20
#INTERNET_STATUS_CONNECTION_CLOSED=51
#INTERNET_STATUS_HANDLE_CLOSING=70
#INTERNET_STATUS_HANDLE_CREATED=60
#INTERNET_STATUS_INTERMEDIATE_RESPONSE=120
#INTERNET_STATUS_RECEIVING_RESPONSE=40
#INTERNET_STATUS_RESPONSE_RECEIVED=41
#INTERNET_STATUS_REDIRECT=110
#INTERNET_STATUS_REQUEST_COMPLETE=100
#INTERNET_STATUS_REQUEST_SENT=31
#INTERNET_STATUS_DETECTING_PROXY=80
#INTERNET_STATUS_RESOLVING_NAME=10
#INTERNET_STATUS_NAME_RESOLVED=11
#INTERNET_STATUS_SENDING_REQUEST=30
#INTERNET_STATUS_STATE_CHANGE=200
#INTERNET_STATUS_P3P_HEADER=325

#INTERNET_INVALID_STATUS_CALLBACK=-1

Import ""
  
    InitializeCriticalSectionAndSpinCount(*lpCriticalSection.CRITICAL_SECTION, dwSpincount.i)
   
EndImport

; Structure To store configuration in that was gathered from passed in arguments

Structure CONFIGURATION
    Method.i                     ; DWORD      Method, GET or POST
    HostName.s                   ; LPWSTR     Host to connect to
    URIPath.s                    ; LPWSTR     Resource to get from the server
    InputFileName.s              ; LPWSTR     File containing data to post
    OutputFileName.s             ; LPWSTR     File to write the data received from the server
    UseProxy.i                   ; BOOL       Flag to indicate the use of a proxy
    ProxyName.s                  ; LPWSTR     Name of the proxy to use
    IsSecureConnection.i         ; BOOL       Flag to indicate the use of SSL
    UserTimeout.i                ; DWORD      Timeout for the async operations
EndStructure

; Structure used For storing the context For the asynchronous calls

Structure REQUEST_CONTEXT
    RequestHandle.i              ; HINTERNET
    ConnectHandle.i              ; HINTERNET
    CompletionEvent.i            ; HANDLE
    CleanUpEvent.i               ; HANDLE
    *TemporaryBuffer             ; LPSTR
    *PermanentBuffer             ;        - ADDED BY ZAPMAN TO RECEIVE DATA IN MEMORY INSTEAD OF CREATE A FILE
                                 ;          OR TO SEND DATA FROM MEMORY INSTEAD OF READ A FILE
    FileOrMemory.l               ;        - ADDED BY ZAPMAN TO RECEIVE DATA IN MEMORY INSTEAD OF CREATE A FILE
                                 ;          OR TO SEND DATA FROM MEMORY INSTEAD OF READ A FILE
                                 ;          Fill this field with #RWDataFile = 1 or #RWDataMemory = 2
    Down_Up_loadedBytes.i        ; DWORD
    WrittenBytes.i               ; DWORD
    ReadBytes.i                  ; DWORD
    UploadFile.i                 ; HANDLE
    Memory_File_Size.i           ; DWORD
    DownloadFile.i               ; HANDLE
    Method.i                     ; DWORD
    State.i                      ; DWORD
   
    CriticalSection.CRITICAL_SECTION   ; CRITICAL_SECTION
    CritSecInitialized.i         ; BOOL

    ; Synchronized by CriticalSection

    HandleUsageCount.i           ; DWORD // Request object is in use(not safe to close handle)
    Closing.i                    ; BOOL  // Request is closing(don't use handle)
    MustWait.l                   ; BOOL - ADDED BY ZAPMAN TO AVOID CONNECTION TO CLOSE WHILE DATA IS STILL COMING/SENDING FROM/TO THE SERVER

EndStructure


Structure InternetCookieHistory
   fAccepted.i    ; BOOL
   fLeashed.i     ; BOOL
   fDowngraded.i  ; BOOL
   fRejected.i    ; BOOL
EndStructure

Structure INTERNET_ASYNC_RESULT
   *dwResult    ; DWORD_PTR
   dwError.i    ; DWORD
EndStructure

Structure INTERNET_BUFFERS
   dwStructSize.l    ;   DWORD
   *Next             ;   _INTERNET_BUFFERS
   lpcszHeader.l     ;   LPCTSTR
   dwHeadersLength.l ;   DWORD
   dwHeadersTotal.l  ;   DWORD
   lpvBuffer.l       ;   LPVOID
   dwBufferLength.l  ;   DWORD
   dwBufferTotal.l   ;   DWORD
   dwOffsetLow.l     ;   DWORD
   dwOffsetHigh.l    ;   DWORD
EndStructure

;- DECLARE

Declare ReceiveHTTPData(Uri$,SendTo.l = #RWDataMemory,FileName.s="")
Declare CallBack(hInternet.i, dwContext.i, dwInternetStatus.i, lpvStatusInformation.i, dwStatusInformationLength.i)
Declare.i AllocateAndInitializeRequestContext(SessionHandle.i, *Configuration.CONFIGURATION, *ReqContext.REQUEST_CONTEXT)
Declare.i ProcessRequest(*ReqContext.REQUEST_CONTEXT, Error.i)
Declare WaitForRequestCompletion(*ReqContext.REQUEST_CONTEXT, Timeout.i)
Declare CleanUpRequestContext(*ReqContext.REQUEST_CONTEXT)
Declare CleanUpSessionHandle(SessionHandle.i)
Declare.i SendRequest(*ReqContext.REQUEST_CONTEXT)
Declare.i SendRequestWithBody(*ReqContext.REQUEST_CONTEXT)
Declare.i GetDataToPost(*ReqContext.REQUEST_CONTEXT)
Declare.i PostDataToServer(*ReqContext.REQUEST_CONTEXT, *Eof.INTEGER)
Declare.i CompleteRequest(*ReqContext.REQUEST_CONTEXT)
Declare.i RecvResponseData(*ReqContext.REQUEST_CONTEXT)
Declare.i WriteResponseData(*ReqContext.REQUEST_CONTEXT, *Eof.INTEGER)
Declare.i OpenFiles(*ReqContext.REQUEST_CONTEXT, Method.i, InputFilename.s, OutputFilename.s)
Declare.i CreateWininetHandles(*ReqContext.REQUEST_CONTEXT, SessionHandle.i, HostName.s, Resource.s, IsSecureConnection.i)
Declare.i CloseRequestHandle(*ReqContext.REQUEST_CONTEXT)
Declare.i AcquireRequestHandle(*ReqContext.REQUEST_CONTEXT)
Declare.i ReleaseRequestHandle(*ReqContext.REQUEST_CONTEXT)
;}

; __________________________________________________________________________
;-                                   DEMO
; __________________________________________________________________________

;{

Demo = 1

If Demo
  Define Uri$ = "http://www.boursorama.com/bourse/action/graph/ws/download?length=5&period=1&symbol=1rPCAC"
  
  If Demo = 1
    *Buffer = ReceiveHTTPData(Uri$,#RWDataMemory)
    If Not *Buffer
      Debug "ERROR : Nothing has been received !!"
    Else
      Debug PeekS(*Buffer,-1,#PB_UTF8)
      FreeMemory(*Buffer)
    EndIf
    
  Else
  
    ReceiveHTTPData(Uri$,#RWDataFile,"test.txt")
    
  EndIf
  
EndIf


; __________________________________________________________________________
;                                END OF DEMO
; __________________________________________________________________________
;
;}


Procedure PrintErrorMessage(Value)  ; By Fr34k
  Protected Message$
  If Value
    Message$ = Space(3000) 
    FormatMessage_(#FORMAT_MESSAGE_IGNORE_INSERTS|#FORMAT_MESSAGE_FROM_SYSTEM, 0, Value, 0, @Message$, 3000, 0) 
    MessageRequester("Error","Error #"+Str(Value)+":"+Chr(13)+Message$, #MB_ICONERROR)
  EndIf
EndProcedure 


Procedure ReceiveHTTPData(Uri$,SendTo.l = #RWDataMemory,FileName.s="")

   Protected Error.i, TD, UriParameters$
   Protected OpenType.i = #INTERNET_OPEN_TYPE_PRECONFIG  ; Use pre-configured options as default
   
   Protected Configuration.CONFIGURATION
   
   Protected ReqContext.REQUEST_CONTEXT
   Protected SessionHandle.i
   
   ; Callback function
   Protected CallbackPointer.i    ; INTERNET_STATUS_CALLBACK
   
   TD = ElapsedMilliseconds()
   
   Configuration\HostName = GetURLPart(Uri$,#PB_URL_Site)
   Configuration\URIPath = GetURLPart(Uri$,#PB_URL_Path)
   UriParameters$ = GetURLPart(Uri$,#PB_URL_Parameters)
   If UriParameters$
     Configuration\URIPath + "?" + UriParameters$
   EndIf
   If Configuration\URIPath
     Configuration\URIPath = "/"+Configuration\URIPath
   EndIf

   Configuration\UserTimeout = #DEFAULT_TIMEOUT
   Configuration\OutputFileName = FileName ; set this field to "test.txt" to record the HTTP page in a file of that name
   Configuration\Method = #METHOD_GET
   ReqContext\FileOrMemory = SendTo ; set this to #RWDataFile to get the HTTP recorded in a file
   
   ; Create Session handle And specify async Mode
   SessionHandle = InternetOpen_("WinInet HTTP Async Sample",  ; User Agent
                                 OpenType,                     ; Preconfig Or Proxy
                                 Configuration\ProxyName,      ; Proxy name
                                 #Null,                        ; Proxy bypass, do Not bypass any address
                                 #INTERNET_FLAG_ASYNC)         ; 0 for Synchronous
   If (SessionHandle = #Null)
      ;debug("ERROR! InternetOpen >"+GetLastError_()+"<")
      Goto Exit
   EndIf
   ; Set the status callback For the handle To the Callback function
   CallbackPointer = InternetSetStatusCallback_(SessionHandle, @CallBack())
   
   If (CallbackPointer = #INTERNET_INVALID_STATUS_CALLBACK)
      ;debug("ERROR! InternetSetStatusCallback failed With INTERNET_INVALID_STATUS_CALLBACK")
      Goto Exit
   EndIf
   
   ;  Initialize the ReqContext To be used in the asynchronous calls
   Error = AllocateAndInitializeRequestContext(SessionHandle,
                                               @Configuration,
                                               @ReqContext)
   
   If (Error <> #ERROR_SUCCESS)
      Goto Exit
   EndIf
    
    
   Repeat ; ADDED BY ZAPMAN TO AVOID CONNECTION TO CLOSE WHILE DATA IS STILL COMING/SENDING FROM/TO THE SERVER
   
     ; Send out request And receive response
     
     ProcessRequest(@ReqContext, #ERROR_SUCCESS)
     
     ; Wait For request completion Or timeout
     
     WaitForRequestCompletion(@ReqContext, Configuration\UserTimeout);
     
     Delay(1)

   Until ReqContext\MustWait = 0 ; ADDED BY ZAPMAN TO AVOID CONNECTION TO CLOSE WHILE DATA IS STILL COMING/SENDING FROM/TO THE SERVER

Exit:
   
   ; Clean up the allocated resources

   CleanUpRequestContext(@ReqContext)
   
   CleanUpSessionHandle(SessionHandle)
   
   ;Debug "Page read in "+StrF((ElapsedMilliseconds()-TD)/1000,2)+" sec."
   
   ProcedureReturn ReqContext\PermanentBuffer

EndProcedure


Procedure CallBack(hInternet.i, *dwContext, dwInternetStatus.i, *lpvStatusInformation, dwStatusInformationLength.i)
   
;     __in HINTERNET hInternet,
;     __in DWORD_PTR dwContext,
;     __in DWORD dwInternetStatus,
;     __in_bcount(dwStatusInformationLength) LPVOID lpvStatusInformation,
;     __in DWORD dwStatusInformationLength
   
   
; Routine Description:
;     Callback routine For asynchronous WinInet operations
;
; Arguments:
;      hInternet - The handle For which the callback function is called.
;      dwContext - Pointer To the application defined context.
;      dwInternetStatus - Status code indicating why the callback is called.
;      lpvStatusInformation - Pointer To a buffer holding callback specific Data.
;      dwStatusInformationLength - Specifies size of lpvStatusInformation buffer.
;
; Return Value:
;     None.

   Protected *cookieHistory.InternetCookieHistory
   Protected *ReqContext.REQUEST_CONTEXT
   Protected *StatusInformation.INTERNET_ASYNC_RESULT
   
   *ReqContext=*dwContext
 
;     UNREFERENCED_PARAMETER(dwStatusInformationLength);

   Select dwInternetStatus
         
      Case #INTERNET_STATUS_COOKIE_SENT
         ;debug("Status: Cookie found And will be sent With request")
         
      Case #INTERNET_STATUS_COOKIE_RECEIVED
         ;debug("Status: Cookie Received")
         
      Case #INTERNET_STATUS_COOKIE_HISTORY
         ;debug("Status: Cookie History")
         
;          ASYNC_ASSERT(lpvStatusInformation)
;          ASYNC_ASSERT(dwStatusInformationLength == SizeOf(InternetCookieHistory))
         
         *cookieHistory = *lpvStatusInformation
         
         If (*cookieHistory\fAccepted)
            ;debug("Cookie Accepted")
         EndIf
         
         If (*cookieHistory\fLeashed)
            ;debug("Cookie Leashed")
         EndIf
         
         If (*cookieHistory\fDowngraded)
            ;debug("Cookie Downgraded")
         EndIf
         
         If (*cookieHistory\fRejected)
            ;debug("Cookie Rejected")
         EndIf
         
      Case #INTERNET_STATUS_CLOSING_CONNECTION
         ;debug("Status: Closing Connection")
         
      Case #INTERNET_STATUS_CONNECTED_TO_SERVER
         ;debug("Status: Connected to Server")
         
      Case #INTERNET_STATUS_CONNECTING_TO_SERVER
         ;debug("Status: Connecting to Server")
         
      Case #INTERNET_STATUS_CONNECTION_CLOSED
         ;debug("Status: Connection Closed")
         
      Case #INTERNET_STATUS_HANDLE_CLOSING
         ;debug("Status: Handle Closing")

;             // Signal the cleanup routine that it is
;             // safe To cleanup the request context

;             ASYNC_ASSERT(ReqContext);
               
         SetEvent_(*ReqContext\CleanUpEvent)

      Case #INTERNET_STATUS_HANDLE_CREATED
         
;          ASYNC_ASSERT(lpvStatusInformation)
         
         *StatusInformation=*lpvStatusInformation
         
         ;debug("Handle "+*StatusInformation\dwResult+" created") ; ((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwResult)
         
      Case #INTERNET_STATUS_INTERMEDIATE_RESPONSE
         ;debug("Status: Intermediate response")

      Case #INTERNET_STATUS_RECEIVING_RESPONSE
         ;debug("Status: Receiving Response")

      Case #INTERNET_STATUS_RESPONSE_RECEIVED
;             ASYNC_ASSERT(lpvStatusInformation)
;             ASYNC_ASSERT(dwStatusInformationLength == SizeOf(DWORD))

         ;debug("Status: Response Received ("+PeekI(*lpvStatusInformation)+" Bytes)")

      Case #INTERNET_STATUS_REDIRECT
         ;debug("Status: Redirect")

      Case #INTERNET_STATUS_REQUEST_COMPLETE
         ;debug("Status: Request complete")

         ;          ASYNC_ASSERT(lpvStatusInformation)
            
        
         *StatusInformation=*lpvStatusInformation

         ProcessRequest(*ReqContext, *StatusInformation\dwError)
         

      Case #INTERNET_STATUS_REQUEST_SENT
;             ASYNC_ASSERT(lpvStatusInformation)
;             ASYNC_ASSERT(dwStatusInformationLength == SizeOf(DWORD))

         ;debug("Status: Request sent ("+PeekI(*lpvStatusInformation)+" Bytes)") ;, *((LPDWORD)lpvStatusInformation));
         
   
      Case #INTERNET_STATUS_DETECTING_PROXY
         ;debug("Status: Detecting Proxy")
      
      Case #INTERNET_STATUS_RESOLVING_NAME
         ;debug("Status: Resolving Name")
      
      Case #INTERNET_STATUS_NAME_RESOLVED
         ;debug("Status: Name Resolved")
      
      Case #INTERNET_STATUS_SENDING_REQUEST
         ;debug("Status: Sending request")
      
      Case #INTERNET_STATUS_STATE_CHANGE
         ;debug("Status: State Change")
      
      Case #INTERNET_STATUS_P3P_HEADER
         ;debug("Status: Received P3P header")
      
      Default
         ;debug("Status: Unknown >"+dwInternetStatus+"<")
   
   EndSelect

EndProcedure


Procedure.i ProcessRequest(*ReqContext.REQUEST_CONTEXT, Error.i)
;     __inout PREQUEST_CONTEXT ReqContext,
;     __in DWORD Error
   
   
; Routine Description:
;     Process the request context - Sending the request And
;     receiving the response
;
; Arguments:
;     ReqContext - Pointer To request context Structure
;     Error - error returned from last asynchronous call
;
; Return Value:
;     None.

   
   Protected Eof.i=#False

    While (Error=#ERROR_SUCCESS And *ReqContext\State <> #REQ_STATE_COMPLETE)
        Select *ReqContext\State
            Case #REQ_STATE_SEND_REQ
                 ;debug "#REQ_STATE_SEND_REQ"
                 *ReqContext\State = #REQ_STATE_RESPONSE_RECV_DATA
                 Error = SendRequest(*ReqContext)
                 *ReqContext\MustWait = 1 ; ADDED BY ZAPMAN TO AVOID CONNECTION TO CLOSE WHILE DATA IS STILL COMING FROM THE SERVER

            Case #REQ_STATE_SEND_REQ_WITH_BODY
                 ;debug "#REQ_STATE_SEND_REQ_WITH_BODY"
                *ReqContext\State = #REQ_STATE_POST_GET_DATA
                Error = SendRequestWithBody(*ReqContext)
                *ReqContext\MustWait = 1 ; ADDED BY ZAPMAN TO AVOID CONNECTION TO CLOSE WHILE DATA IS STILL SENDING TO THE SERVER

            Case #REQ_STATE_POST_GET_DATA
                 ;debug "#REQ_STATE_POST_GET_DATA"
                *ReqContext\State = #REQ_STATE_POST_SEND_DATA
                Error = GetDataToPost(*ReqContext)
               
            Case #REQ_STATE_POST_SEND_DATA
                 ;debug "#REQ_STATE_POST_SEND_DATA"
                *ReqContext\State = #REQ_STATE_POST_GET_DATA
                Error = PostDataToServer(*ReqContext, @Eof)
               
                If(Eof)
                   *ReqContext\State = #REQ_STATE_POST_COMPLETE
                EndIf
               
            Case #REQ_STATE_POST_COMPLETE
                 ;debug "#REQ_STATE_POST_COMPLETE"
                *ReqContext\State = #REQ_STATE_RESPONSE_RECV_DATA
                Error = CompleteRequest(*ReqContext)
               
            Case #REQ_STATE_RESPONSE_RECV_DATA
                 ;debug "#REQ_STATE_RESPONSE_RECV_DATA"
                *ReqContext\State = #REQ_STATE_RESPONSE_WRITE_DATA
                Error = RecvResponseData(*ReqContext)
               
            Case #REQ_STATE_RESPONSE_WRITE_DATA
                ;debug "#REQ_STATE_RESPONSE_WRITE_DATA"
                *ReqContext\State = #REQ_STATE_RESPONSE_RECV_DATA;
                Error = WriteResponseData(*ReqContext, @Eof)
                
                If(Eof)
                    *ReqContext\State = #REQ_STATE_COMPLETE
                EndIf
               
            Default
                 ;debug #PB_Compiler_Procedure+" - Default >"+*ReqContext\State+"< >"+*ReqContext\Down_Up_loadedBytes+"<"
;                 ASYNC_ASSERT(FALSE);
               
        EndSelect
    Wend
   
    If (Error <> #ERROR_IO_PENDING)
;         // Everything has been processed Or has failed.
;         // In either Case, the signal processing has
;         // completed
      SetEvent_(*ReqContext\CompletionEvent)
    Else
      *ReqContext\MustWait = 1  ; ADDED BY ZAPMAN TO AVOID CONNECTION TO CLOSE WHILE DATA IS STILL COMING/SENDING FROM/TO THE SERVER
    EndIf
      

EndProcedure


Procedure.i AllocateAndInitializeRequestContext(SessionHandle.i, *Configuration.CONFIGURATION, *ReqContext.REQUEST_CONTEXT)

; Routine Description:
;     Allocate the request context And initialize it values
;
; Arguments:
;     ReqContext - Pointer To Request context Structure
;     Configuration - Pointer To configuration Structure
;     SessionHandle - Wininet session handle To use when creating
;                     connect handle
;     
; Return Value:
;     Error Code For the operation.


   Protected Error.i = #ERROR_SUCCESS
   Protected Success.i
   
   *ReqContext\RequestHandle = #Null
   *ReqContext\ConnectHandle = #Null
   *ReqContext\Down_Up_loadedBytes = 0
   *ReqContext\WrittenBytes = 0
   *ReqContext\ReadBytes = 0
   *ReqContext\UploadFile = #INVALID_HANDLE_VALUE
   *ReqContext\DownloadFile = #INVALID_HANDLE_VALUE
   *ReqContext\Memory_File_Size = 0
   *ReqContext\HandleUsageCount = 0
   *ReqContext\Closing = #False
   *ReqContext\Method = *Configuration\Method
   *ReqContext\CompletionEvent = #Null   
   *ReqContext\CleanUpEvent = #Null
   *ReqContext\TemporaryBuffer = #Null
   If (*ReqContext\Method=#METHOD_GET)
      *ReqContext\State = #REQ_STATE_SEND_REQ
   Else
      *ReqContext\State = #REQ_STATE_SEND_REQ_WITH_BODY
   EndIf
   
   *ReqContext\CritSecInitialized = #False   
      
   ; initialize critical section
   
   If Not InitializeCriticalSectionAndSpinCount(@*ReqContext\CriticalSection, #SPIN_COUNT)
      Error = GetLastError_()
      ;debug("ERROR InitializeCriticalSectionAndSpinCount >"+Error+"<")
      Goto Exit
   EndIf
   
   *ReqContext\CritSecInitialized = #True
   
   *ReqContext\TemporaryBuffer = AllocateMemory(#BUFFER_LEN)
   
   If Not *ReqContext\TemporaryBuffer
      
      Error = #ERROR_NOT_ENOUGH_MEMORY
      Goto Exit
   EndIf
   
   ;    // create events
   
   *ReqContext\CompletionEvent = CreateEvent_(#Null,  ;// Sec attrib
                                                  #False, ;// Auto reset
                                                  #False, ;// Initial state unsignalled
                                                  #Null)    ; // Name
   
   If (*ReqContext\CompletionEvent = #Null)
      Error = GetLastError_()
      ;debug("ERROR CreateEvent CompletionEvent >"+Error+"<")
      Goto Exit
   EndIf
   
   ;    // create events
   
   *ReqContext\CleanUpEvent = CreateEvent_(#Null,  ;// Sec attrib
                                               #False, ;// Auto reset
                                               #False, ;// Initial state unsignalled
                                               #Null)    ; // Name
   
   If (*ReqContext\CleanUpEvent = #Null)
      Error = GetLastError_()
      ;debug("ERROR CreateEvent CleanUpEvent >"+Error+"<")
      Goto Exit
   EndIf
   
;    // Open the file To dump the response entity body And
;    // If required the file With the Data To post
   
   If *ReqContext\FileOrMemory <> #RWDataMemory
     
     Error = OpenFiles(*ReqContext,
                        *Configuration\Method,
                        *Configuration\InputFileName,
                        *Configuration\OutputFileName)
     
     If (Error <> #ERROR_SUCCESS)
        ;debug("ERROR OpenFiles failed With >"+Error+"<")
        Goto Exit
     EndIf
     
     ;    // Verify If we've opened a file to post and get its size
     
     If (*ReqContext\UploadFile <> #INVALID_HANDLE_VALUE)
        *ReqContext\Memory_File_Size = GetFileSize_(*ReqContext\UploadFile, #Null)
        
        If(*ReqContext\Memory_File_Size = #INVALID_FILE_SIZE)
           Error = GetLastError_()
           ;debug("ERROR GetMemory_File_Size >"+Error+"<")
           Goto Exit
        EndIf
        
     EndIf
     
   Else
     
     ;    // Verify If there's a memory buffer to post and get its size
     ;
     If *ReqContext\PermanentBuffer
       *ReqContext\Memory_File_Size = MemorySize(*ReqContext\PermanentBuffer)
     EndIf
     
   EndIf

   Error = CreateWininetHandles(*ReqContext,
                                 SessionHandle,
                                 *Configuration\HostName,
                                 *Configuration\URIPath,
                                 *Configuration\IsSecureConnection)
   
   If (Error <> #ERROR_SUCCESS)
      ;debug("ERROR CreateWininetHandles failed With >"+Error+"<")
      Goto Exit
   EndIf
   

Exit:
   
   If (Error <> #ERROR_SUCCESS)
      CleanUpRequestContext(*ReqContext)
   EndIf
      
   ProcedureReturn Error
   
EndProcedure


Procedure WaitForRequestCompletion(*ReqContext.REQUEST_CONTEXT, Timeout.i)
   ;     __in PREQUEST_CONTEXT ReqContext,
   ;     __in DWORD Timeout
   
   ; Routine Description:
   ;     Wait For the request To complete Or timeout To occur
   ;
   ; Arguments:
   ;     ReqContext - Pointer To request context Structure
   ;
   ; Return Value:
   ;     None.
   
   Protected SyncResult.i ;     DWORD SyncResult;
   Protected iError.i
   
   ;     // The preferred method of doing timeouts is To
   ;     // use the timeout options through InternetSetOption,
   ;     // but this overall timeout is being used To show
   ;     // the correct way To abort And close a request.
   
   SyncResult = WaitForSingleObject_(*ReqContext\CompletionEvent, Timeout)    ; Wait until we receive the completion
   
   Select (SyncResult)
      Case #WAIT_OBJECT_0
         ;debug("Done!")
      
      Case #WAIT_TIMEOUT
         ;debug("Timeout while waiting for completion event (request will be cancelled)")
         
      
      Case #WAIT_FAILED:
         iError=GetLastError_()
         ;debug("Wait failed with Error "+iError+" While waiting For completion Event (request will be cancelled)")
         
      
      Default        ; Not expecting any other error codes
         
   
   EndSelect

 EndProcedure
 
 
Procedure CleanUpRequestContext(*ReqContext.REQUEST_CONTEXT)
;     __inout_opt PREQUEST_CONTEXT ReqContext

; Routine Description:
;     Used To cleanup the request context before exiting.
;
; Arguments:
;     ReqContext - Pointer To request context Structure
;
; Return Value:
;     None.


   If (*ReqContext\RequestHandle)
      CloseRequestHandle(*ReqContext)

;         // Wait For the closing of the handle To complete
;         // (waiting For all async operations To complete)
;         //
;         // This is the only safe way To get rid of the context
      
      WaitForSingleObject_(*ReqContext\CleanUpEvent, #INFINITE)
   EndIf
   
   If (*ReqContext\ConnectHandle)
;         // Remove the callback from the ConnectHandle since
;         // we don't want the closing notification
;         // The callback was inherited from the session handle

      InternetSetStatusCallback_(*ReqContext\ConnectHandle, #Null)
   
      InternetCloseHandle_(*ReqContext\ConnectHandle)
   EndIf 

   If (*ReqContext\UploadFile <> #INVALID_HANDLE_VALUE)
      CloseHandle_(*ReqContext\UploadFile)
   EndIf
   
   If (*ReqContext\DownloadFile <> #INVALID_HANDLE_VALUE)
      CloseHandle_(*ReqContext\DownloadFile)
   EndIf
   
   If (*ReqContext\CompletionEvent)
      CloseHandle_(*ReqContext\CompletionEvent)
   EndIf
   
   If (*ReqContext\CleanUpEvent)
      CloseHandle_(*ReqContext\CleanUpEvent)
   EndIf
   
   If(*ReqContext\CritSecInitialized)
      DeleteCriticalSection_(*ReqContext\CriticalSection)
   EndIf

EndProcedure
 
 
Procedure CleanUpSessionHandle(SessionHandle.i)
;     __in HINTERNET SessionHandle

; Routine Description:
;     Used To cleanup session before exiting.
;
; Arguments:
;     SessionHandle - Wininet session handle
;
; Return Value:
;     None.

    If (SessionHandle)

;         // Remove the callback from the SessionHandle since
;         // we don't want the closing notification
      InternetSetStatusCallback_(SessionHandle, #Null)

;         // Call InternetCloseHandle And do Not wait For the closing notification
;         // in the callback function
      
      InternetCloseHandle_(SessionHandle)
   EndIf
   
EndProcedure


Procedure.i SendRequest(*ReqContext.REQUEST_CONTEXT)
;     __in PREQUEST_CONTEXT ReqContext


; Routine Description:
;     Send the request using HttpSendRequest
;
; Arguments:
;     ReqContext - Pointer To request context Structure
;
; Return Value:
;     Error code For the operation.

   Protected Success.i
   Protected Error.i=#ERROR_SUCCESS
   
   Success = AcquireRequestHandle(*ReqContext)
   If Not Success
      Error = #ERROR_OPERATION_ABORTED
      Goto Exit
   EndIf
   
   
   If Not HttpSendRequest_(*ReqContext\RequestHandle,
                              #Null,                   ;do Not provide additional Headers
                              0,                       ;dwHeadersLength
                              #Null,                   ;Do Not send any Data
                              0)                       ;dwOptionalLength
   
      Error = GetLastError_()

      If(Error <>#ERROR_IO_PENDING)
         ;debug("ERROR HttpSendRequest >"+Error+"<   Handle = "+Str(*ReqContext\RequestHandle))
      EndIf
       
   EndIf
   
   ReleaseRequestHandle(*ReqContext)
   
Exit:
   
   ProcedureReturn Error
        
EndProcedure


Procedure.i SendRequestWithBody(*ReqContext.REQUEST_CONTEXT)
;     __in PREQUEST_CONTEXT ReqContext

; Routine Description:
;     Send the request With entity-body using HttpSendRequestEx
;
; Arguments:
;     ReqContext - Pointer To request context Structure
;
; Return Value:
;     Error code For the operation.
   
   Protected Success.i
   Protected *BuffersIn.INTERNET_BUFFERS
   Protected Error.i=#ERROR_SUCCESS
   

;     // HttpSendRequest can also be used also To post Data To a server,
;     // To do so, the Data should be provided using the lpOptional
;     // parameter And it's size on dwOptionalLength.
;     // Here we decided To depict the use of HttpSendRequestEx function.

   
;     //Prepare the Buffers To be passed To HttpSendRequestEx
   *BuffersIn=AllocateStructure(INTERNET_BUFFERS)
   
   *BuffersIn\dwStructSize = SizeOf(INTERNET_BUFFERS)
   *BuffersIn\lpvBuffer = #Null
   *BuffersIn\dwBufferLength = 0
   *BuffersIn\dwBufferTotal = *ReqContext\Memory_File_Size; // content-length of data to post

   If Not AcquireRequestHandle(*ReqContext)
      Error = #ERROR_OPERATION_ABORTED
      Goto Exit
   EndIf
   
   If Not HttpSendRequestEx_(*ReqContext\RequestHandle,
                                *BuffersIn,
                                #Null,      ;           // Do Not use output buffers
                                0,          ;           // dwFlags reserved
                                *ReqContext)
   
      Error = GetLastError_()

      If (Error <> #ERROR_IO_PENDING)
         ;debug("ERROR HttpSendRequestEx >"+Error+"<")
      EndIf
       
    EndIf
    
    ReleaseRequestHandle(*ReqContext)

Exit:
   
   ProcedureReturn Error
   
EndProcedure


Procedure.i GetDataToPost(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext
   
; Routine Description:
;     Reads Data from a file or Memory
;
; Arguments:
;     ReqContext - Pointer To request context Structure
;
; Return Value:
;     Error code For the operation.

   Protected Error = #ERROR_SUCCESS
   Protected Success.i
   
;    // ReadFile is done inline here assuming that it will Return quickly
;    // I.E. the file is on disk
;    //
;    // If you plan To do blocking/intensive operations they should be
;    // queued To another thread And Not block the callback thread
   
   If *ReqContext\FileOrMemory = #RWDataMemory
      If *ReqContext\PermanentBuffer
        MemLim.l = MemorySize(*ReqContext\PermanentBuffer)
        If (*ReqContext\PermanentBuffer+*ReqContext\Down_Up_loadedBytes+#BUFFER_LEN) > MemLim
          *ReqContext\ReadBytes = MemLim-*ReqContext\Down_Up_loadedBytes ; It remains less than #BUFFER_LEN to transfert.
        Else
          *ReqContext\ReadBytes = #BUFFER_LEN
        EndIf
          
        CopyMemory(*ReqContext\PermanentBuffer+*ReqContext\Down_Up_loadedBytes,*ReqContext\TemporaryBuffer,*ReqContext\ReadBytes)
        *ReqContext\Down_Up_loadedBytes + *ReqContext\ReadBytes
      Else
        ;debug("ERROR ReadMemory >"+Data missing in Buffer+"<")
        Error = #ERROR_NOACCESS
        *ReqContext\MustWait = 0 ; ADDED BY ZAPMAN TO AVOID CONNECTION TO CLOSE WHILE DATA IS STILL SENDING TO THE SERVER
      EndIf
      
   Else ; By default, data will be read from a file
   
     If Not ReadFile_(*ReqContext\UploadFile,
                         *ReqContext\TemporaryBuffer,
                         #BUFFER_LEN,
                         @*ReqContext\ReadBytes,
                         #Null)
       
        Error = GetLastError_()
        
        ;debug("ERROR ReadFile >"+Error+"<")
        *ReqContext\MustWait = 0 ; ADDED BY ZAPMAN TO AVOID CONNECTION TO CLOSE WHILE DATA IS STILL COMING FROM THE SERVER
        
      EndIf
      
   EndIf
   
   ProcedureReturn Error
   
EndProcedure


Procedure.i PostDataToServer(*ReqContext.REQUEST_CONTEXT, *Eof.INTEGER)
;     __inout PREQUEST_CONTEXT ReqContext,
;     __out PBOOL Eof

; Routine Description:
;     Post Data in the http request
;
; Arguments:
;     ReqContext - Pointer To request context Structure
;     Eof - Done posting Data To server
;
; Return Value:
;     Error code For the operation.

   
   Protected Error.i = #ERROR_SUCCESS
   Protected Success.i
   
   
   *Eof\i = #False
   
   If (*ReqContext\ReadBytes = 0)
      *Eof\i = #True
      Goto Exit
   EndIf
      
   If Not AcquireRequestHandle(*ReqContext)
      Error = #ERROR_OPERATION_ABORTED
      Goto Exit
   EndIf
      
;    // The lpdwNumberOfBytesWritten parameter will be
;    // populated on async completion, so it must exist
;    // Until INTERNET_STATUS_REQUEST_COMPLETE.
;    // The same is true of lpBuffer parameter.

   If Not InternetWriteFile_(*ReqContext\RequestHandle,
                             *ReqContext\TemporaryBuffer,
                             *ReqContext\ReadBytes,
                             @*ReqContext\WrittenBytes)

      Error = GetLastError_()
      
      If (Error = #ERROR_IO_PENDING)
         ;debug("Waiting For InternetWriteFile To complete")
      Else
         ;debug("ERROR InternetWriteFile >"+Error+"<")
      EndIf
      
   EndIf
    
   ReleaseRequestHandle(*ReqContext)
   
Exit:

   *ReqContext\MustWait = 0 ; ADDED BY ZAPMAN TO AVOID CONNECTION TO CLOSE WHILE DATA IS STILL COMING FROM THE SERVER
   ProcedureReturn Error
   
EndProcedure


Procedure.i CompleteRequest(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext

; Routine Description:
;     Perform completion of asynchronous post.
;
; Arguments:
;     ReqContext - Pointer To request context Structure
;
; Return Value:
;     Error Code For the operation.

   Protected Error.i = #ERROR_SUCCESS
   Protected Success.i
   
   If Not AcquireRequestHandle(*ReqContext)
      Error = #ERROR_OPERATION_ABORTED
      Goto Exit
   EndIf
   
   If Not HttpEndRequest_(*ReqContext\RequestHandle, #Null, 0, 0)

      Error = GetLastError_()
      If (Error = #ERROR_IO_PENDING)
         ;debug("Waiting for HttpEndRequest to complete")
      Else         
         ;debug("ERROR HttpEndRequest >"+Error+"<")
      EndIf
   EndIf
    
   ReleaseRequestHandle(*ReqContext) 
   
Exit:
   ProcedureReturn Error
   
EndProcedure


Procedure.i RecvResponseData(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext

; Routine Description:
;      Receive response
;
; Arguments:
;      ReqContext - Pointer To request context Structure
;
; Return Value:
;      Error Code For the operation.

   Protected Error.i = #ERROR_SUCCESS
   Protected Success.i
   
   If Not AcquireRequestHandle(*ReqContext)
   
      Error = #ERROR_OPERATION_ABORTED
      Goto Exit
   EndIf
   
;    // The lpdwNumberOfBytesRead parameter will be
;    // populated on async completion, so it must exist
;    // Until INTERNET_STATUS_REQUEST_COMPLETE.
;    // The same is true of lpBuffer parameter.
;    //
;    // InternetReadFile will block Until the buffer
;    // is completely filled Or the response is exhausted.
   
   If Not InternetReadFile_(*ReqContext\RequestHandle,
                               *ReqContext\TemporaryBuffer,
                               #BUFFER_LEN,
                               @*ReqContext\Down_Up_loadedBytes)

      Error = GetLastError_()
      If (Error = #ERROR_IO_PENDING)
         ;debug("Waiting for InternetReadFile to complete")
      Else
        ;debug("ERROR InternetReadFile >"+Error+"<")
        *ReqContext\MustWait = 0 ; ADDED BY ZAPMAN TO AVOID CONNECTION TO CLOSE WHILE DATA IS STILL COMING FROM THE SERVER
      EndIf

   EndIf
   
   ReleaseRequestHandle(*ReqContext)
   
Exit:
   
   ProcedureReturn Error
   
EndProcedure


Procedure.i WriteResponseData(*ReqContext.REQUEST_CONTEXT, *Eof.INTEGER)
;     __in PREQUEST_CONTEXT ReqContext,
;     __out PBOOL Eof
   
; Routine Description:
;      Write response To a file
;
; Arguments:
;      ReqContext - Pointer To request context Structure
;      Eof - Done With response
;
; Return Value:
;      Error Code For the operation.

   
   Protected Error.i = #ERROR_SUCCESS
   Protected BytesWritten.i = 0
   Protected Success.i
   Protected OldSize.l
   
   *Eof\i = #False
   
   ;    // Finished receiving response
   
   If (*ReqContext\Down_Up_loadedBytes = 0)
      *Eof\i = #True
      Goto Exit
   EndIf
   
;    // WriteFile is done inline here assuming that it will Return quickly
;    // I.E. the file is on disk
;    //
;    // If you plan To do blocking/intensive operations they should be
;    // queued To another thread And Not block the callback thread
;
   If *ReqContext\FileOrMemory = #RWDataMemory
     ;debug "memory"
     If *ReqContext\PermanentBuffer
       OldSize = MemorySize(*ReqContext\PermanentBuffer)
     Else
       OldSize = 0
     EndIf
     *ReqContext\PermanentBuffer = ReAllocateMemory(*ReqContext\PermanentBuffer,OldSize+*ReqContext\Down_Up_loadedBytes)
     
     If Not *ReqContext\PermanentBuffer
       Error = GetLastError_()
       ;debug("ERROR Memory >"+Error+"<")
        Goto Exit
     EndIf
     ;
     CopyMemory(*ReqContext\TemporaryBuffer,*ReqContext\PermanentBuffer+OldSize,*ReqContext\Down_Up_loadedBytes)
     BytesWritten = *ReqContext\Down_Up_loadedBytes
     
   Else ; By default, data will be saved in a file
     
     
     If Not WriteFile_(*ReqContext\DownloadFile,
                       *ReqContext\TemporaryBuffer,
                       *ReqContext\Down_Up_loadedBytes,
                       @BytesWritten,
                       #Null)
       Error = GetLastError_()
       ;debug("ERROR WriteFile >"+Error+"<")
     EndIf
     
   EndIf
   
Exit:
   *ReqContext\MustWait = 0  ; ADDED BY ZAPMAN TO AVOID CONNECTION TO CLOSE WHILE DATA IS STILL COMING FROM THE SERVER
   ProcedureReturn Error
   
EndProcedure


Procedure.i OpenFiles(*ReqContext.REQUEST_CONTEXT, Method.i, InputFilename.s, OutputFilename.s)
;     __inout PREQUEST_CONTEXT ReqContext,
;     __in DWORD Method,
;     __in LPWSTR InputFileName,
;     __in LPWSTR OutputFileName   


; Routine Description:
;     This routine opens files, one To post Data from, And
;     one To write response into
;
; Arguments:
;     ReqContext - Pointer To request context Structure
;     Method - GET Or POST - do we need To open the input file
;     InputFileName - Input file name
;     OutputFileName - output file name
;
; Return Value:
;     Error Code For the operation.

   Protected Error.i=#ERROR_SUCCESS
   
   If (Method = #METHOD_POST)
;         // Open input file
      *ReqContext\UploadFile = CreateFile_(InputFileName,
                                           #GENERIC_READ,
                                           #FILE_SHARE_READ,
                                           #Null,                   ;// handle cannot be inherited
                                           #OPEN_ALWAYS,              ;// If file exists, open it
                                           #FILE_ATTRIBUTE_NORMAL,
                                           #Null)   ;                  // No template file
      
      If (*ReqContext\UploadFile = #INVALID_HANDLE_VALUE)
         Error = GetLastError_()
         ;debug("ERROR CreateFile for input file >"+InputFilename+"< Error >"+Error+"<")
         Goto Exit
      EndIf
   EndIf
   
   ;// Open output file
   
   
   *ReqContext\DownloadFile = CreateFile_(OutputFileName,
                                          #GENERIC_WRITE,
                                          0,                        ;// Open exclusively
                                          #Null,                    ;// handle cannot be inherited
                                          #CREATE_ALWAYS,           ;// If file exists, delete it
                                          #FILE_ATTRIBUTE_NORMAL,
                                          #Null);                    // No template file
   
   If (*ReqContext\DownloadFile = #INVALID_HANDLE_VALUE)
      Error = GetLastError_()
      ;debug("ERROR CreateFile for output file >"+OutputFilename+"< Error >"+Error+"<")
      Goto Exit
   EndIf
   
Exit:
   ProcedureReturn Error
   
EndProcedure


Procedure.i CreateWininetHandles(*ReqContext.REQUEST_CONTEXT, SessionHandle.i, HostName.s, Resource.s, IsSecureConnection.i)
;     __inout PREQUEST_CONTEXT ReqContext,
;     __in HINTERNET SessionHandle,
;     __in LPWSTR HostName,
;     __in LPWSTR Resource,
;     __in BOOL IsSecureConnection

; Routine Description:
;     Create connect And request handles
;
; Arguments:
;     ReqContext - Pointer To Request context Structure
;     SessionHandle - Wininet session handle used To create
;                     connect handle
;     HostName - Hostname To connect
;     Resource - Resource To get/post
;     IsSecureConnection - SSL?
;
; Return Value:
;     Error Code For the operation.
   
   Protected Error.i = #ERROR_SUCCESS
   Protected ServerPort = #INTERNET_DEFAULT_HTTP_PORT
   Protected RequestFlags = 0
   Protected Verb.s
   
;     // Set the correct server port If using SSL
;   // Also set the flag For HttpOpenRequest
   
   If (IsSecureConnection)
      ServerPort = #INTERNET_DEFAULT_HTTPS_PORT
      RequestFlags = #INTERNET_FLAG_SECURE
   EndIf
   
;    // Create Connection handle And provide context For async operations
   *ReqContext\ConnectHandle = InternetConnect_(SessionHandle,
                                                HostName,                  ;// Name of the server To connect To
                                                ServerPort,                  ;// HTTP (80) Or HTTPS (443)
                                                #Null,                     ;// Do Not provide a user name For the server
                                                #Null,                     ;// Do Not provide a password For the server
                                                #INTERNET_SERVICE_HTTP,
                                                0,                         ;// Do Not provide any special flag
                                                *ReqContext)               ;    // Provide the context to be used during the callbacks
   
;     // For HTTP InternetConnect returns synchronously because it does Not
;     // actually make the connection.
;     //
;     // For FTP InternetConnect connects the control channel, And therefore
;     // can be completed asynchronously.  This sample would have To be
;     // changed, so that the InternetConnect's asynchronous completion
;     // is handled correctly To support FTP.
   
   If (*ReqContext\ConnectHandle = #Null)
      Error = GetLastError_()
      ;debug("ERROR InternetConnect >"+Error+"<")
      Goto Exit
   EndIf
   
;     // Set the Verb depending on the operation To perform
   If (*ReqContext\Method = #METHOD_GET)
      Verb = "GET"
   Else
;       ASYNC_ASSERT(ReqContext->Method == METHOD_POST);
      Verb = "POST"
   EndIf
   
;     // We're overriding WinInet's Default behavior.
;     // Setting these flags, we make sure we get the response from the server And Not the cache.
;     // Also ask WinInet Not To store the response in the cache.
;     //
;     // These flags are Not performant And are only used To show Case WinInet's Async I/O.
;     // A real WinInet application would Not want To use this flags.
   
   RequestFlags = RequestFlags | #INTERNET_FLAG_RELOAD | #INTERNET_FLAG_NO_CACHE_WRITE
   
;     // Create a Request handle
   *ReqContext\RequestHandle = HttpOpenRequest_(*ReqContext\ConnectHandle,
                                                Verb,                     ;// GET Or POST
                                                Resource,                 ;// root "/" by Default
                                                #Null,                    ;// Use Default HTTP/1.1 As the version
                                                #Null,                    ;// Do Not provide any referrer
                                                #Null,                    ;// Do Not provide Accept types
                                                RequestFlags,
                                                *ReqContext)
   
   If (*ReqContext\RequestHandle = #Null)
      Error = GetLastError_()
      ;debug("ERROR HttpOpenRequest >"+Error+"<")
      Goto Exit
   EndIf
   
Exit:
   
   ProcedureReturn Error
EndProcedure


Procedure.i CloseRequestHandle(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext

; Routine Description:
;     Safely  close the request handle by synchronizing
;     With all threads using the handle.
;
;     When this function returns no more calls can be made With the
;     handle.
;     
; Arguments:
;     ReqContext - Pointer To Request context Structure
; Return Value:
;     None.

   
   Protected Close = #False
   
   EnterCriticalSection_(*ReqContext\CriticalSection)
   
;     // Current implementation only supports the main thread
;     // kicking off the request handle close
;     //
;     // To support multiple threads the lifetime
;     // of the request context must be carefully controlled
;     // (most likely guarded by refcount/critsec)
;     // so that they are Not trying To abort a request
;     // where the context has already been freed.
   
;     ASYNC_ASSERT(ReqContext->Closing == FALSE);
   *ReqContext\Closing = #True
   
   If (*ReqContext\HandleUsageCount = 0)
      Close = #True
   EndIf
   
   LeaveCriticalSection_(*ReqContext\CriticalSection)
   
   If (Close)
;         // At this point there must be the guarantee that all calls
;         // To wininet With this handle have returned With some value
;         // including ERROR_IO_PENDING, And none will be made after
;         // InternetCloseHandle.
      
      InternetCloseHandle_(*ReqContext\RequestHandle)
   EndIf
   
EndProcedure


Procedure.i AcquireRequestHandle(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext
   
; Routine Description:
;     Acquire use of the request handle To make a wininet call
; Arguments:
;     ReqContext - Pointer To Request context Structure
; Return Value:
;     TRUE - Success
;     FALSE - Failure
   
   
   Protected Success.i = #True
   
   EnterCriticalSection_(@*ReqContext\CriticalSection)
   
   If(*ReqContext\Closing = #True)
      Success = #False
   Else
      *ReqContext\HandleUsageCount+1
   EndIf
   
   LeaveCriticalSection_(@*ReqContext\CriticalSection)
   
   ProcedureReturn Success
   
EndProcedure


Procedure.i ReleaseRequestHandle(*ReqContext.REQUEST_CONTEXT)
;     __inout PREQUEST_CONTEXT ReqContext

; Routine Description:
;     release use of the request handle
; Arguments:
;     ReqContext - Pointer To Request context Structure
; Return Value:
;     None.
   
   Protected Close.i = #False
   
   EnterCriticalSection_(*ReqContext\CriticalSection)
   
   ;    ASYNC_ASSERT(ReqContext->HandleUsageCount > 0)
   
   *ReqContext\HandleUsageCount-1
   
   If (*ReqContext\Closing = #True And *ReqContext\HandleUsageCount = 0)
      
      Close = #True
      
   EndIf
   
   LeaveCriticalSection_(*ReqContext\CriticalSection)
   
   If (Close)
      
;         // At this point there must be the guarantee that all calls
;         // To wininet With this handle have returned With some value
;         // including ERROR_IO_PENDING, And none will be made after
;         // InternetCloseHandle.
      
      InternetCloseHandle_(*ReqContext\RequestHandle)
      
   EndIf
   
EndProcedure


Last edited by Zapman on Sun Mar 08, 2020 12:03 pm, edited 1 time in total.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: MS Asynchronous Internet Request Example converted to PB

Post by Kwai chang caine »

Hello ZAPMAN :D

It's funny, when i try in my browser the url that download a CAC40...txt file
And with the code i have this answer :oops:

Code: Select all

<html>
  <head>
    <title>401 V Not Authorized</title>
  </head>
  <body>
    <h1>Msg : 401 V Not Authorized</h1>
  </body>
</html>
ImageThe happiness is a road...
Not a destination
User avatar
Zapman
User
User
Posts: 13
Joined: Tue Jan 07, 2020 7:27 pm

Re: MS Asynchronous Internet Request Example converted to PB

Post by Zapman »

Hi KCC,

Many thanks for testing :)

The answer you got is perhaps due to access restrictions from Boursorama, not to the program. Probably a question of cookie. I'm registered as "member" on Boursorama and, perhaps, that's why I can access to data without problem and not you.
Could you try again? Did you try to access to a different URL?
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: MS Asynchronous Internet Request Example converted to PB

Post by Kwai chang caine »

You have right, i'm not enough rich for to be in Boursorama :lol:
I have try "www.google.com" and i have that 8)
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="fr"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title><script nonce="PVYo6UqjGqm3/ZR6BrJhnA==">(function(){window.google={kEI:'g9JoXpbIDIjqaOLereAC',kEXPI:'0,1353747,5662,731,223,5104,207,3204,10,1051,175,364,1435,4,60,742,43,32,383,139,107,5,625,142,247,65,24,251,82,423,15,139,153,1126954,1197761,263,125,41,329077,1294,12383,4855,32691,15248,867,28684,364,8824,8384,4859,1361,4323,4968,3023,4744,3118,7915,1808,4020,978,7931,5297,2054,920,873,1217,2975,6430,11306,2883,21,317,1981,2537,2777,520,399,2277,8,2796,889,704,1279,2212,202,330,147,1103,840,519,1464,8,48,820,3438,108,204,1137,2,2063,606,1839,184,1777,520,1947,747,429,1053,93,328,1284,16,2927,2246,474,1339,748,1039,3228,772,2072,7,817,503,6313,6515,2661,641,599,33,1817,2459,1226,1462,280,3654,1275,108,2854,72,481,908,2,941,972,1642,694,1189,249,265,808,578,1510,328,2195,226,657,338,830,840,188,2,2057,188,3,127,419,30,156,814,183,388,40,134,120,8,365,95,728,473,218,1586,445,706,149,1896,1605,908,1581,476,381,2,174,888,36,22,272,122,38,49,391,96,500,603,608,50,142,924,421,46,114,206,773,259,1732,478,35,13,302,7,298,640,723,154,663,104,586,288,20,51,515,795,5837295,1873,1404,1802617,4194968,2801054,549,333,444,1,2,80,1,900,896,1,8,1,2,2551,1,748,141,59,736,563,1,4265,1,1,1,1,137,1,879,9,305,641,5,76,20,3,1,235,13,2,23963408,23',kBL:'WX7B'};google.sn='webhp';google.kHL='fr';})();(function(){google.lc=[];google.li=0;google.getEI=function(a){for(var b;a&&(!a.getAttribute||!(b=a.getAttribute("eid")));)a=a.parentNode;return b||google.kEI};google.getLEI=function(a){for(var b=null;a&&(!a.getAttribute||!(b=a.getAttribute("leid")));)a=a.parentNode;return b};google.ml=function(){return null};google.time=function(){return Date.now()};google.log=function(a,b,e,c,g){if(a=google.logUrl(a,b,e,c,g)){b=new Image;var d=google.lc,f=google.li;d[f]=b;b.onerror=b.onload=b.onabort=function(){delete d[f]};google.vel&&google.vel.lu&&google.vel.lu(a);b.src=a;google.li=f+1}};google.logUrl=function(a,b,e,c,g){var d="",f=google.ls||"";e||-1!=b.search("&ei=")||(d="&ei="+google.getEI(c),-1==b.search("&lei=")&&(c=google.getLEI(c))&&(d+="&lei="+c));c="";!e&&google.cshid&&-1==b.search("&cshid=")&&"slh"!=a&&(c="&cshid="+google.cshid);a=e||"/"+(g||"gen_204")+"?atyp=i&ct="+a+"&cad="+b+d+f+"&zx="+google.time()+c;/^http:/i.test(a)&&"https:"==window.location.protocol&&(google.ml(Error("a"),!1,{src:a,glmm:1}),a="");return a};}).call(this);(function(){google.y={};google.x=function(a,b){if(a)var c=a.id;else{do c=Math.random();while(google.y[c])}google.y[c]=[a,b];return!1};google.lm=[];google.plm=function(a){google.lm.push.apply(google.lm,a)};google.lq=[];google.load=function(a,b,c){google.lq.push([[a],b,c])};google.loadAll=function(a,b){google.lq.push([a,b])};}).call(this);google.f={};(function(){
document.documentElement.addEventListener("submit",function(b){var a;if(a=b.target){var c=a.getAttribute("data-submitfalse");a="1"==c||"q"==c&&!a.elements.q.value?!0:!1}else a=!1;a&&(b.preventDefault(),b.stopPropagation())},!0);document.documentElement.addEventListener("click",function(b){var a;a:{for(a=b.target;a&&a!=document.documentElement;a=a.parentElement)if("A"==a.tagName){a="1"==a.getAttribute("data-nohref");break a}a=!1}a&&b.preventDefault()},!0);}).call(this);
var a=window.location,b=a.href.indexOf("#");if(0<=b){var c=a.href.substring(b+1);/(^|&)q=/.test(c)&&-1==c.indexOf("#")&&a.replace("/search?"+c.replace(/(^|&)fp=[^&]*/g,"")+"&cad=h")};</script><style>#gbar,#guser{font-size:13px;padding-top:1px !important;}#gbar{height:22px}#guser{padding-bottom:7px !important;text-align:right}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}@media all{.gb1{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb4{text-decoration:underline !important}a.gb1,a.gb4{color:#00c !important}.gbi .gb4{color:#dd8e27 !important}.gbf .gb4{color:#900 !important}
</style><style>body,td,a,p,.h{font-family:arial,sans-serif}body{margin:0;overflow-y:scroll}#gog{padding:3px 8px 0}td{line-height:.8em}.gac_m td{line-height:17px}form{margin-bottom:20px}.h{color:#36c}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}em{font-weight:bold;font-style:normal}.lst{height:25px;width:496px}.gsfi,.lst{font:18px arial,sans-serif}.gsfs{font:17px arial,sans-serif}.ds{display:inline-box;display:inline-block;margin:3px 0 4px;margin-left:4px}input{font-family:inherit}body{background:#fff;color:#000}a{color:#11c;text-decoration:none}a:hover,a:active{text-decoration:underline}.fl a{color:#36c}a:visited{color:#551a8b}.sblc{padding-top:5px}.sblc a{display:block;margin:2px 0;margin-left:13px;font-size:11px}.lsbb{background:#eee;border:solid 1px;border-color:#ccc #999 #999 #ccc;height:30px}.lsbb{display:block}.ftl,#fll a{display:inline-block;margin:0 12px}.lsb{background:url(/images/nav_logo229.png) 0 -261px repeat-x;border:none;color:#000;cursor:pointer;height:30px;margin:0;outline:0;font:15px arial,sans-serif;vertical-align:top}.lsb:active{background:#ccc}.lst:focus{outline:none}</style><script nonce="PVYo6UqjGqm3/ZR6BrJhnA=="></script></head><body bgcolor="#fff"><script nonce="PVYo6UqjGqm3/ZR6BrJhnA==">(function(){var src='/images/nav_logo229.png';var iesg=false;document.body.onload = function(){window.n && window.n();if (document.images){new Image().src=src;}
if (!iesg){document.f&&document.f.q.focus();document.gbqf&&document.gbqf.q.focus();}
}
})();</script><div id="mngb"> <div id=gbar><nobr><b class=gb1>Recherche</b> <a class=gb1 href="http://www.google.fr/imghp?hl=fr&tab=wi">Images</a> <a class=gb1 href="http://maps.google.fr/maps?hl=fr&tab=wl">Maps</a> <a class=gb1 href="https://play.google.com/?hl=fr&tab=w8">Play</a> <a class=gb1 href="http://www.youtube.com/?gl=FR&tab=w1">YouTube</a> <a class=gb1 href="http://news.google.fr/nwshp?hl=fr&tab=wn">Actualit�s</a> <a class=gb1 href="https://mail.google.com/mail/?tab=wm">Gmail</a> <a class=gb1 href="https://drive.google.com/?tab=wo">Drive</a> <a class=gb1 style="text-decoration:none" href="https://www.google.fr/intl/fr/about/pro ... <u>Plus</u> &raquo;</a></nobr></div><div id=guser width=100%><nobr><span id=gbn class=gbi></span><span id=gbf class=gbf></span><span id=gbe></span><a href="http://www.google.fr/history/optout?hl=fr" class=gb4>Historique Web</a> | <a href="/preferences?hl=fr" class=gb4>Param�tres</a> | <a target=_top id=gb_70 href="https://accounts.google.com/ServiceLogi ... oogle.com/" class=gb4>Connexion</a></nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div> </div><center><br clear="all" id="lgpd"><div id="lga"><img alt="Google" height="92" src="/images/branding/googlelogo/1x/googlelogo_white_background_color_272x92dp.png" style="padding:28px 0 14px" width="272" id="hplogo"><br><br></div><form action="/search" name="f"><table cellpadding="0" cellspacing="0"><tr valign="top"><td width="25%">&nbsp;</td><td align="center" nowrap=""><input name="ie" value="ISO-8859-1" type="hidden"><input value="fr" name="hl" type="hidden"><input name="source" type="hidden" value="hp"><input name="biw" type="hidden"><input name="bih" type="hidden"><div class="ds" style="height:32px;margin:4px 0"><input class="lst" style="margin:0;padding:5px 8px 0 6px;vertical-align:top;color:#000" autocomplete="off" value="" title="Recherche Google" maxlength="2048" name="q" size="57"></div><br style="line-height:0"><span class="ds"><span class="lsbb"><input class="lsb" value="Recherche Google" name="btnG" type="submit"></span></span><span class="ds"><span class="lsbb"><input class="lsb" id="tsuid1" value="J'ai de la chance" name="btnI" type="submit"><script nonce="PVYo6UqjGqm3/ZR6BrJhnA==">(function(){var id='tsuid1';document.getElementById(id).onclick = function(){if (this.form.q.value){this.checked = 1;if (this.form.iflsig)this.form.iflsig.disabled = false;}
else top.location='/doodles/';};})();</script><input value="AINFCbYAAAAAXmjgk5yi82QZQCfro6Ee3jOtet3LCPJ_" name="iflsig" type="hidden"></span></span></td><td class="fl sblc" align="left" nowrap="" width="25%"><a href="/advanced_search?hl=fr&authuser=0">Recherche avanc�e</a></td></tr></table><input id="gbv" name="gbv" type="hidden" value="1"><script nonce="PVYo6UqjGqm3/ZR6BrJhnA==">(function(){var a,b="1";if(document&&document.getElementById)if("undefined"!=typeof XMLHttpRequest)b="2";else if("undefined"!=typeof ActiveXObject){var c,d,e=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"];for(c=0;d=e[c++];)try{new ActiveXObject(d),b="2"}catch(h){}}a=b;if("2"==a&&-1==location.search.indexOf("&gbv=2")){var f=google.gbvu,g=document.getElementById("gbv");g&&(g.value=a);f&&window.setTimeout(function(){location.href=f},0)};}).call(this);</script></form><div id="gac_scont"></div><div style="font-size:83%;min-height:3.5em"><br></div><span id="footer"><div style="font-size:10pt"><div style="margin:19px auto;text-align:center" id="fll"><a href="/intl/fr/ads/">Solutions publicitaires</a><a href="/services/">Solutions d'entreprise</a><a href="/intl/fr/about.html">� propos de Google</a><a href="http://www.google.com/setprefdomain?pre ... v></div><p style="font-size:8pt;color:#767676">&copy; 2020 - <a href="//support.google.com/websearch?p=fr_tos">Publication judiciaire</a> - <a href="/intl/fr/policies/privacy/">Confidentialit�</a> - <a href="/intl/fr/policies/terms/">Conditions</a></p></span></center><script nonce="PVYo6UqjGqm3/ZR6BrJhnA==">(function(){window.google.cdo={height:0,width:0};(function(){var a=window.innerWidth,b=window.innerHeight;if(!a||!b){var c=window.document,d="CSS1Compat"==c.compatMode?c.documentElement:c.body;a=d.clientWidth;b=d.clientHeight}a&&b&&(a!=google.cdo.width||b!=google.cdo.height)&&google.log("","","/client_204?&atyp=i&biw="+a+"&bih="+b+"&ei="+google.kEI);}).call(this);})();(function(){var u='/xjs/_/js/k\x3dxjs.hp.en.hIuC4rON5-I.O/m\x3dsb_he,d/am\x3dgAEBNgI/d\x3d1/rs\x3dACT90oF2RviG9Lv3ruHWli8ZOXFPERdGRA';
setTimeout(function(){var b=document;var a="SCRIPT";"application/xhtml+xml"===b.contentType&&(a=a.toLowerCase());a=b.createElement(a);a.src=u;google.timers&&google.timers.load&&google.tick&&google.tick("load","xjsls");document.body.appendChild(a)},0);})();(function(){window.google.xjsu='/xjs/_/js/k\x3dxjs.hp.en.hIuC4rON5-I.O/m\x3dsb_he,d/am\x3dgAEBNgI/d\x3d1/rs\x3dACT90oF2RviG9Lv3ruHWli8ZOXFPERdGRA';})();function _DumpException(e){throw e;}
function _F_installCss(c){}
(function(){google.spjs=false;google.snet=true;google.em=[];google.emw=false;google.pdt=0;})();(function(){var pmc='{\x22d\x22:{},\x22sb_he\x22:{\x22agen\x22:true,\x22cgen\x22:true,\x22client\x22:\x22heirloom-hp\x22,\x22dh\x22:true,\x22dhqt\x22:true,\x22ds\x22:\x22\x22,\x22ffql\x22:\x22fr\x22,\x22fl\x22:true,\x22host\x22:\x22google.com\x22,\x22isbh\x22:28,\x22jsonp\x22:true,\x22lm\x22:true,\x22msgs\x22:{\x22cibl\x22:\x22Effacer la recherche\x22,\x22dym\x22:\x22Essayez avec cette orthographe :\x22,\x22lcky\x22:\x22J\\u0026#39;ai de la chance\x22,\x22lml\x22:\x22En savoir plus\x22,\x22oskt\x22:\x22Outils de saisie\x22,\x22psrc\x22:\x22Cette suggestion a bien �t� supprim�e de votre \\u003Ca href\x3d\\\x22/history\\\x22\\u003Ehistorique Web\\u003C/a\\u003E.\x22,\x22psrl\x22:\x22Supprimer\x22,\x22sbit\x22:\x22Recherche par image\x22,\x22srch\x22:\x22Recherche Google\x22},\x22ovr\x22:{},\x22pq\x22:\x22\x22,\x22refpd\x22:true,\x22rfs\x22:[],\x22sbpl\x22:16,\x22sbpr\x22:16,\x22scd\x22:10,\x22stok\x22:\x22z1SqD7OAwRtOL84gPTgOXkMZDQk\x22,\x22uhde\x22:false}}';google.pmc=JSON.parse(pmc);})();</script> </body></html>
ImageThe happiness is a road...
Not a destination
User avatar
Zapman
User
User
Posts: 13
Joined: Tue Jan 07, 2020 7:27 pm

Re: MS Asynchronous Internet Request Example converted to PB

Post by Zapman »

It looks great, KCC :)
Thank you again.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: MS Asynchronous Internet Request Example converted to PB

Post by Kwai chang caine »

Thanks to you, you want to say :wink:
Have a good day 8)
ImageThe happiness is a road...
Not a destination
Post Reply