Results 1 to 13 of 13

Thread: wininet asynchronous download

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    678

    Question wininet asynchronous download

    Because of Dragokas the thread, I checked my hard disk and found asynchronous code downloads about wininet. I feel that there is too little information here and I hope someone can improve. At the same time the search forum found this thread, the lesson can help

    http://www.vbforums.com/showthread.p...eaded-Callback


    NOW ,i fixed,may work ok?



    Code:
    'Constants - InternetOpen.dwFlags
    Private Const INTERNET_FLAG_ASYNC = &H10000000
    ? or INTERNET_FLAG_ASYNC =1


    Code:
    hInternet = InternetOpenUrl(hSession, sURL, vbNullString, 0, INTERNET_FLAG_RELOAD Or INTERNET_FLAG_PRAGMA_NOCACHE Or INTERNET_FLAG_NO_CACHE_WRITE, ByVal VarPtr(lngContext(0)))
    change into

    Code:
    hInternet = InternetOpenUrl(hSession, sURL, vbNullString, 0, INTERNET_FLAG_RELOAD Or INTERNET_FLAG_PRAGMA_NOCACHE Or INTERNET_FLAG_NO_CACHE_WRITE, VarPtr(lngContext(0)))
    now ide work ok,but is exe crash also..
    Attached Files Attached Files
    Last edited by xxdoc123; Apr 4th, 2019 at 07:55 PM.

  2. #2
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: wininet asynchronous download

    I don't have an answer, but just a brief check of that other thread, shows that at the time Lavolpe didn't quite understand that any other callback thread initiated by another method/api call (in this case wininet) needs the runtime initiated on the thread before it can use any runtime functions, or error checking, or even declared APIs (not in a typelib).
    You can't even use (shared) variables or data outside the local (stack based) ones within the function, unless you use synchronization or marshalling/serializing or IPC.

    Things to keep in mind if you are servicing a callback on a thread not created by yourself.

    The first order in servicing a callback from on another thread should be getting the VB6 runtime initiated.
    Either that or you can keep the actual callback functionality very minimal, and use typelib APIs to either post messages back to the main thread (this is what i do) or use synchronization to access global variables.
    Last edited by DEXWERX; Jun 12th, 2018 at 07:19 AM.

  3. #3
    Frenzied Member
    Join Date
    Jun 2015
    Posts
    1,068

    Re: wininet asynchronous download

    [...]
    Last edited by dz32; Apr 26th, 2019 at 11:17 AM.

  4. #4
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: wininet asynchronous download

    Quote Originally Posted by dz32 View Post
    The C thread has access to some VB variable addresses which it writes to directly (no sync) and seems to work.
    I guess technically that wouldn't cause an automatic crash... assuming you only read the data from VB, and write from C.

    You just have no guarantee when the data is updated. But you can try coordinate with a PostMessage back to the main thread.
    Trying to figure out, how to make that work is making my head hurt... I think when it comes to threading, I'll just go by the book and use proper sync.
    Last edited by DEXWERX; Jun 12th, 2018 at 03:46 PM.

  5. #5
    Frenzied Member
    Join Date
    Jun 2015
    Posts
    1,068

    Re: wininet asynchronous download

    [...]
    Last edited by dz32; Apr 26th, 2019 at 11:17 AM.

  6. #6
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: wininet asynchronous download

    as far as VB6 on x86 is concerned, Integer writes are atomic. I would just never do it

    As for subclassing, I made a crashproof subclasing dll, so it's as convenient as checking off a reference.
    I get people don't like 3rd party dependencies (myself included),
    But since know what's in it, I'm happy to use it myself.
    Last edited by DEXWERX; Jun 12th, 2018 at 05:23 PM.

  7. #7
    Frenzied Member
    Join Date
    Jun 2015
    Posts
    1,068

    Re: wininet asynchronous download

    [...]
    Last edited by dz32; Apr 26th, 2019 at 11:17 AM.

  8. #8

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    678

    Re: wininet asynchronous download

    Code:
    class CHttpClient
    {
    public:
    	CHttpClient(void);
    	~CHttpClient(void);
    public:
    	BOOL Open(LPCTSTR lpUrl,int timeout = INFINITE);
    	int Read(unsigned char* buffer,int size,int timeout = INFINITE);
    	void Close();
    };
    Code:
    int main(int argc, char *argv[])
    {
    	CHttpClient httpClient;
    	BOOL bRet = httpClient.Open("http://192.168.169.200/stream.php?cam=c0a86b8500",5000);
    	if(!bRet)
    	{
    		return 0;
    	}
    	unsigned char buffer[4096] = {0};
    	while(1)
    	{
    		int len = httpClient.Read(buffer,sizeof(buffer));
    		if(len <= 0)
    		{
    			break;
    		}
    	}
    	httpClient.Close();
    	return 1;
    }
    Code:
    /********************************************************************  
    filename:   HttpClient.h
    created:    2016-04-08
    author:     firehood  
    purpose:    A Asynchronous Http Client By Using WinInet HTTP functions
    *********************************************************************/
    #pragma once
    #include <windows.h>
    #include <wininet.h>
    
    class CHttpClient
    {
    public:
    	CHttpClient(void);
    	~CHttpClient(void);
    public:
    	BOOL Open(LPCTSTR lpUrl,int timeout = INFINITE);
    	int Read(unsigned char* buffer,int size,int timeout = INFINITE);
    	void Close();
    private:
    	static void CALLBACK HttpStatusCallback(
    		HINTERNET hInternet,
    		DWORD dwContext,
    		DWORD dwInternetStatus,
    		LPVOID lpStatusInfo,
    		DWORD dwStatusInfoLen);
    private:
    	HINTERNET  m_hInternet;
    	HINTERNET  m_hSession;
    	HANDLE  m_hRequestOpenedEvent;
    	HANDLE  m_hRequestCompleteEvent;
    	DWORD   m_dwCompleteResult;
    };
    
    CHttpClient.cpp
    
    /********************************************************************  
    filename:   HttpClient.cpp
    created:    2016-04-08
    author:     firehood  
    purpose:    A Asynchronous Http Client By Using WinInet HTTP functions
    *********************************************************************/
    #include "HttpClient.h"
    #include <tchar.h>
    #pragma comment(lib,"wininet.lib")
    
    CHttpClient::CHttpClient(void)
    : m_hInternet(NULL)
    , m_hSession(NULL)
    , m_dwCompleteResult(0)
    {
    	m_hRequestOpenedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    	m_hRequestCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    }
    
    CHttpClient::~CHttpClient(void)
    {
    	Close();
    	if(m_hRequestOpenedEvent)
    	{
    		CloseHandle(m_hRequestOpenedEvent);
    		m_hRequestOpenedEvent = NULL;
    	}
    	if(m_hRequestCompleteEvent)
    	{
    		CloseHandle(m_hRequestCompleteEvent);
    		m_hRequestCompleteEvent = NULL;
    	}
    }
    
    BOOL CHttpClient::Open(LPCTSTR lpUrl,int timeout)
    {
    	if(lpUrl == NULL)
    	{
    		return FALSE;
    	}
    
    	if(m_hInternet)
    	{
    		Close();
    	}
    	BOOL bRet = FALSE;
    	do
    	{
    		m_hInternet = InternetOpen(NULL,INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,INTERNET_FLAG_ASYNC);
    
    		if (m_hInternet == NULL)
    		{
    			break;
    		}
    
    		// Setup callback function
    		if (InternetSetStatusCallback(m_hInternet,HttpStatusCallback) == INTERNET_INVALID_STATUS_CALLBACK)
    		{
    			break;
    		}
    
    		m_hSession = InternetOpenUrl(m_hInternet,lpUrl,NULL,NULL,INTERNET_FLAG_NO_CACHE_WRITE,(DWORD_PTR)this);
    		if(NULL == m_hSession)
    		{
    			if (GetLastError() != ERROR_IO_PENDING)
    			{
    				break;
    			}
    			// Wait until we get the connection handle
    			if(WaitForSingleObject(m_hRequestOpenedEvent,timeout) == WAIT_TIMEOUT)
    			{
    				break;
    			}
    		}
    
    		if(WaitForSingleObject(m_hRequestCompleteEvent,timeout) == WAIT_TIMEOUT)
    		{
    			break;
    		}
    
    		if(m_dwCompleteResult == 0)
    		{
    			break;
    		}
    
    		DWORD dwStatusCode;
    		TCHAR responseText[256] = {0};
    		DWORD responseTextSize = sizeof(responseText);
    		if(!HttpQueryInfo(m_hSession,HTTP_QUERY_STATUS_CODE,&responseText,&responseTextSize,NULL))
    		{
    			break;
    		}
    		dwStatusCode = _ttoi(responseText);
    		if(dwStatusCode != HTTP_STATUS_OK )
    		{
    			break;
    		}
    		bRet = TRUE;
    	}while(0);
    
    	if(!bRet)
    	{
    		if(m_hSession)
    		{
    			InternetCloseHandle(m_hSession);
    			m_hSession = NULL;
    		}
    		if(m_hInternet)
    		{
    			InternetSetStatusCallback(m_hInternet, NULL);
    			InternetCloseHandle(m_hInternet);
    			m_hInternet = NULL;
    		}
    	}
    	return bRet;
    }
    
    int CHttpClient::Read(unsigned char* buffer,int size,int timeout)
    {
    	if(buffer == NULL || size <= 0)
    	{
    		return -1;
    	}
    	INTERNET_BUFFERS InetBuff;
    	memset(&InetBuff, 0, sizeof(InetBuff));
    	InetBuff.dwStructSize = sizeof(InetBuff);
    	InetBuff.lpvBuffer = buffer;
    	InetBuff.dwBufferLength = size;
    
    	if(!InternetReadFileEx(m_hSession,&InetBuff,0,(DWORD_PTR)this))
    	{
    		if (GetLastError() == ERROR_IO_PENDING)
    		{
    			if(WaitForSingleObject(m_hRequestCompleteEvent,timeout) == WAIT_TIMEOUT)
    			{
    				return -1;
    			}
    		}
    		else
    		{
    			return -1;
    		}
    	}
    	return InetBuff.dwBufferLength;
    }
    
    void CHttpClient::Close()
    {
    	SetEvent(m_hRequestOpenedEvent);
    	SetEvent(m_hRequestCompleteEvent);
    	if(m_hSession)
    	{
    		InternetCloseHandle(m_hSession);
    		m_hSession = NULL;
    	}
    	if(m_hInternet)
    	{
    		InternetSetStatusCallback(m_hInternet, NULL);
    		InternetCloseHandle(m_hInternet);
    		m_hInternet = NULL;
    	}
    	ResetEvent(m_hRequestOpenedEvent);
    	ResetEvent(m_hRequestCompleteEvent);
    }
    
    void CALLBACK CHttpClient::HttpStatusCallback(
    						HINTERNET hInternet,
    						DWORD dwContext,
    						DWORD dwInternetStatus,
    						LPVOID lpStatusInfo,
    						DWORD dwStatusInfoLen)
    {
    	CHttpClient *p = (CHttpClient*)dwContext;
    
    	switch(dwInternetStatus)
    	{
    	case INTERNET_STATUS_HANDLE_CREATED:
    		{
    			INTERNET_ASYNC_RESULT *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
    			p->m_hSession = (HINTERNET)pRes->dwResult;
    			SetEvent(p->m_hRequestOpenedEvent);
    		}
    		break;
    	case INTERNET_STATUS_REQUEST_COMPLETE:
    		{
    			INTERNET_ASYNC_RESULT *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
    			p->m_dwCompleteResult = pRes->dwResult;
    			SetEvent(p->m_hRequestCompleteEvent);
    		}
    		break;
    	case INTERNET_STATUS_HANDLE_CLOSING:
    		break;
    	case INTERNET_STATUS_RESPONSE_RECEIVED:
    		break;
    	default:
    		break;
    	}
    }
    I found this code on the Internet, it looks nothing special, why can not be translated into vb

  9. #9
    Frenzied Member
    Join Date
    Jun 2015
    Posts
    1,068

    Re: wininet asynchronous download

    [...]
    Last edited by dz32; Apr 26th, 2019 at 11:16 AM.

  10. #10

  11. #11
    Frenzied Member
    Join Date
    Jun 2015
    Posts
    1,068

    Re: wininet asynchronous download

    [...]
    Last edited by dz32; Apr 26th, 2019 at 11:16 AM.

  12. #12

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2016
    Posts
    678

    Re: wininet asynchronous download

    Quote Originally Posted by dz32 View Post
    just to test the direct memory access code a little deeper I modified the c example dll i gave earlier so that
    it now can handle multiple async background downloads each in their own thread.

    The var writes are to private class variables and the class has a check on terminate to
    auto abort and wait until the downloader thread exits to prevent any crashs.

    the main form occasionally polls the class for current download status on a timer
    still seems ok in testing
    Name:  error1.jpg
Views: 639
Size:  22.1 KB

    i used Dev-Cpp compilation have a error.

    cfg->hOpen = InternetOpen("WininetDl", INTERNET_OPEN_TYPE_PRECONFIG, NULL,NULL, 0 );

    C:\Users\xxdoc\Desktop\C_VB_Background_Download\collect2.exe [Error] ld returned 1 exit status

  13. #13
    Frenzied Member
    Join Date
    Jun 2015
    Posts
    1,068

    Re: wininet asynchronous download

    [...]
    Last edited by dz32; Apr 26th, 2019 at 11:16 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width