// testwinInet.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <WINDOWS.H>
#include <WININET.H>
#include <STDLIB.H>
#include <string>
#include <IOSTREAM.H>
#pragma comment(lib,"wininet.lib")
using namespace std;
void CALLBACK InternetStatusCallback(
HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpvStatusInformation,
DWORD dwStatusInformationLength);
HANDLE hEvent[3];
HINTERNET hFile;
HINTERNET hNet;
HINTERNET hSession,hConnect,hRequest;
int WaitExitEvent()
{
//return 1;
DWORD dwRet = ::WaitForMultipleObjects(3, hEvent, FALSE, 30000);//INFINITE);
int x=-1;
switch (dwRet)
{
//句柄被建立事件或者讀資料請求成功完成事件
case WAIT_OBJECT_0:
x=0;
cout<<"WAIT_OBJECT_0"<<endl;
//句柄被關閉事件
break;
case WAIT_OBJECT_0+1:
x=1;
cout<<"WAIT_OBJECT_1"<<endl;
//使用者要求終止子線程事件或者發生錯誤事件
break;
case WAIT_OBJECT_0+2:
x=2;
cout<<"WAIT_OBJECT_2"<<endl;
break;
default:
cout<<"WaitForMultipleObjects time out"<<endl;
return -1;
}
return x;
}
// 支援代理設定, 是否異步設定; 采用事件驅動
void WinINet3(bool setProxy, bool ASYNC)
{
hSession=NULL;
hConnect=NULL;
hRequest=NULL;
int i;
for (i = 0; i < 3; i++)
{
hEvent[i] = CreateEvent(
NULL, // default security attributes
FALSE, // auto-reset event object
FALSE, // initial state is nonsignaled
NULL); // unnamed object
if (hEvent[i] == NULL)
{
printf("CreateEvent error: %d\n", GetLastError() );
ExitProcess(0);
}
}
char *url = "http://down.360safe.com/setup.exe";
char *pip = "down.360safe.com";
char *paim = "/setup.exe";
// step 1
if(ASYNC) cout<<"異步模式"<<endl;
// setProxy =false;
if(setProxy)
{
cout<<"代理模式"<<endl;
if(ASYNC)
hSession = InternetOpen("name",
INTERNET_OPEN_TYPE_DIRECT,//|INTERNET_OPEN_TYPE_PROXY,// INTERNET_OPEN_TYPE_PROXY,
NULL,NULL,INTERNET_FLAG_ASYNC); // 異步
else
hSession = InternetOpen("name",INTERNET_OPEN_TYPE_PROXY,NULL,NULL,0); // 同步
}
else
{
if(ASYNC)
hSession = InternetOpen("name",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,INTERNET_FLAG_ASYNC); // 異步
else
hSession = InternetOpen("name",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0); // 同步
}
if(!hSession)
{
DWORD er = ::GetLastError();
cout<<"InternetOpen error"<<endl;//, "Err", MB_OK);
return;
}
if(ASYNC)
{
//Sleep(500);
INTERNET_STATUS_CALLBACK res = ::InternetSetStatusCallback(hSession,InternetStatusCallback);
if(res == INTERNET_INVALID_STATUS_CALLBACK)
{
cout<<"InternetSetStatusCallback failed, so return "<<endl;
return ;
}
else
{
cout<<"InternetSetStatusCallback succeed, so go on "<<endl;
}
//Sleep(500);
}
char strProxyList[MAX_PATH], strUsername[64], strPassword[64];
strcpy(strProxyList, "SOCKS=58.56.87.2:1080"); // 寫上socks怎麼就無效了呢???SOCKS5=172.18.132.27:1080
strcpy(strUsername, "user01");
strcpy(strPassword, "baidu");
INTERNET_PROXY_INFO proxy;
proxy.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
proxy.lpszProxy = strProxyList;
proxy.lpszProxyBypass = NULL;
if( setProxy &&!InternetSetOption(hSession,INTERNET_OPTION_PROXY ,&proxy,sizeof(INTERNET_PROXY_INFO)))
{
cout<<"InternetSetOption failed"<<endl;
return ;
}
// step 2
//如果明确知道需要認證,第4,5個參數可以輸入使用者名,密碼"administrator","password"
//第2,3個參數為目标主機IP、端口号(不是代理伺服器的參數)
hConnect = InternetConnect(hSession,pip,INTERNET_DEFAULT_HTTP_PORT,NULL,NULL,INTERNET_SERVICE_HTTP,INTERNET_FLAG_RELOAD,0);
if(!ASYNC &&!hConnect){
cout<<"同步,InternetConnect error"<<endl;//, "Err", MB_OK);
return;
}
if( ASYNC&& hConnect== NULL)// 異步需要等待 竟然直接建立好了
{
DWORD dwError = ::GetLastError();
if (dwError != ERROR_IO_PENDING)
{
cout<<"CHttpDownload::OpenInternetConnection| 連接配接失敗" <<endl;
return ;
}
else //
{
cout<<"hConnect == NULL, so run WaitExitEvent"<<endl;
WaitExitEvent(); // 等待成功建立 // 這裡應該等待 這裡應該顯示一次呀
::ResetEvent(hEvent[0]);
::ResetEvent(hEvent[1]);
::ResetEvent(hEvent[2]);
}
}
cout<<"step 2 :InternetConnect succeed"<<endl;
// ::InternetSetStatusCallback(hConnect,InternetStatusCallback);
// step 3!!!
char szHead[] = "Accept: *NULL,0,0"; // no request;
CONST TCHAR *szAcceptType="__HTTP_ACCEPT_TYPE";
hRequest = ::HttpOpenRequest(hConnect,
"GET",
paim,
HTTP_VERSION,
"",
&szAcceptType,
INTERNET_FLAG_RELOAD|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_NO_CACHE_WRITE,
0);
//::HttpAddRequestHeaders( hRequest, __HTTP_ACCEPT, strlen(__HTTP_ACCEPT), HTTP_ADDREQ_FLAG_REPLACE);
if (!ASYNC&& !hRequest)
{
cout<<"同步,HttpOpenRequest error"<<endl;//, "Err", MB_OK);
return;
}
if( ASYNC&& hRequest== NULL)// 異步需要等待
{
int er = GetLastError();
DWORD dwError = ::GetLastError();
if (dwError != ERROR_IO_PENDING)
{
cout<<"CHttpDownload::OpenInternetConnection | 連接配接失敗" <<endl;
return ;
}
else //
{
cout<<"hRequest == NULL, so run WaitExitEvent"<<endl;
WaitExitEvent(); // 等待成功建立
::ResetEvent(hEvent[0]);
::ResetEvent(hEvent[1]);
::ResetEvent(hEvent[2]);
}
}
//Sleep(10000);
cout << "step 3 : HttpOpenRequest success"<<endl;
//::InternetSetStatusCallback(hRequest,InternetStatusCallback);
//
if (setProxy )
{
// InternetSetOption 不要異步等待
if( !InternetSetOption(hRequest,INTERNET_OPTION_PROXY_USERNAME ,strUsername,strlen(strUsername)+1))
{
cout<<"InternetSetOption Username failed"<<endl;
return ;
}
if( !InternetSetOption(hRequest,INTERNET_OPTION_PROXY_PASSWORD ,strPassword,strlen(strPassword)+1))
{
cout<<"InternetSetOption Password failed"<<endl;
return ;
}
}
// step 4
//HttpSendRequest(hRequest,NULL,0,NULL,0);
//Sleep(3000);
::ResetEvent(hEvent[0]);
::ResetEvent(hEvent[1]);
::ResetEvent(hEvent[2]);
if(!::HttpSendRequest(hRequest,NULL,0,NULL,0)) // 為什麼失敗???
{
//Sleep(3000);
if(!ASYNC)// 同步
{
DWORD dwError = ::GetLastError();
cout<<"同步,HttpSendRequest failed, GetLastError=="<<dwError<<endl;
return ;
}
else
{
Sleep(3000);
DWORD dwError = ::GetLastError();
cout<<"dwError =="<<dwError<<endl;
if (dwError != ERROR_IO_PENDING)
{
cout<<"dwError != ERROR_IO_PENDING, so quit,dwError =="<<dwError<<endl;
return ;
}
else //
{
cout<<"HttpSendRequest, so run WaitExitEvent"<<endl;
Sleep(3000);
//if(WaitExitEvent()!=2)//; // 等待成功建立 等待是否不對???
{
cout<<"had not recv complete event, so quit"<<endl;
// return ;
}
}
}
}
Sleep(3000);
cout << "step 4: HttpSendRequest success!"<<endl;
int bufh[1000];
DWORD dwLen,dwIndex;
// 判斷狀态碼;
char m_dwStatusCode[90];
DWORD dwStatusSize = sizeof(m_dwStatusCode);
DWORD dwByteToRead = 0;
DWORD dwSizeOfRq = 4;
DWORD dwBytes = 0;
//這三個值分别存儲檔案的大小,HttpQueryInfo内容的大小和總共讀取的位元組數。
//HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwByteToRead, &dwSizeOfRq, NULL);
//需要說明的是 HttpQueryInfo 并不進行網絡操作,是以它不需要進行異步操作的處理。
if (!HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwByteToRead, &dwSizeOfRq, NULL))
{ // 這裡失敗了???
DWORD dwError = ::GetLastError();
cout<<"HttpQueryInfo failed, so return, GetLastError() =="<<dwError<<endl;
return ;
}
FILE * pFile = fopen("d://baidu01.exe", "wb" );
//ofstream mfile("out.txt");//定義檔案輸出流ouf,并關聯到out.txt
i=0;
DWORD leftB = dwByteToRead;
cout<<"開始下載下傳"<<endl;
if( !ASYNC) // 同步下載下傳
{
while(true)
{
const int MAX_BUFFER_SIZE = 65536;
unsigned long nSize = 0;
char szBuffer[MAX_BUFFER_SIZE+2];
int num = MAX_BUFFER_SIZE;
if( leftB < num)
num = leftB;
BOOL bRet = ::InternetReadFile(hRequest, szBuffer, num, &nSize); // 異步 需要等待
leftB -= nSize;
cout<<i++<<" size: "<<nSize<<endl;
if(!bRet || nSize <= 0)
break;
fwrite(szBuffer, sizeof(char), nSize, pFile);
}
}
else // 異步下載下傳
{
INTERNET_BUFFERS i_buf = {0};
i_buf.dwStructSize = sizeof(INTERNET_BUFFERS);
i_buf.lpvBuffer = new TCHAR[10242];
i_buf.dwBufferLength = 10240;
for( DWORD i=0;i<dwByteToRead;)
{
//重置讀資料事件
::ResetEvent( hEvent[0]);
int num = 10240;
if(dwByteToRead-i<10240)
{
num = dwByteToRead-i;
i_buf.dwBufferLength = dwByteToRead-i;
}
if (FALSE == ::InternetReadFileEx(hRequest,
&i_buf,
IRF_ASYNC,
NULL))
{
if (ERROR_IO_PENDING == ::GetLastError())
{
if ( NULL)//WaitExitEvent()!=2)
{
delete[] i_buf.lpvBuffer;
return ;
}
}
else
{
cout<<"down failed,so return"<<endl;
delete[] i_buf.lpvBuffer;
return ;
}
}
else
{
//在網絡傳輸速度快,步長較小的情況下,
//InternetReadFileEx 經常會直接傳回成功,
//是以要判斷是否發生了使用者要求終止子線程事件。
cout<<"網絡很好,InternetReadFileEx傳回true"<<endl;
// 暫不考慮使用者退出
}
i += i_buf.dwBufferLength; // 最後一次寫多了!!!
fwrite(i_buf.lpvBuffer, sizeof(char), i_buf.dwBufferLength, pFile);
cout<<"i== "<<i<<endl;
//儲存資料
//通知主線程下載下傳進度
}
}
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
cout<<"success download file"<<endl;
return;
}
int main(int argc, char* argv[])
{
printf("Starting .......!\n");
WinINet3(true,true);
return 1;
}
void OnInternetHandleCreated(HINTERNET hInternet, LPINTERNET_ASYNC_RESULT lpInetStatusResult)
{
if(NULL == lpInetStatusResult)
{
//ATLASSERT( 0 );
return;
}
hFile = HINTERNET(lpInetStatusResult->dwResult);
HINTERNET hInet = HINTERNET(lpInetStatusResult->dwResult);
DWORD dwInetHandleType;
DWORD dwTypeLen = sizeof(dwInetHandleType);
InternetQueryOption( hInet, INTERNET_OPTION_HANDLE_TYPE, &dwInetHandleType, &dwTypeLen);
switch(dwInetHandleType)
{
case INTERNET_HANDLE_TYPE_CONNECT_HTTP:
//CloseInternetConnection(); // 這裡是何意???? 通過回調 設定httpConnect
hConnect = hInet; //
break;
case INTERNET_HANDLE_TYPE_HTTP_REQUEST:
//CloseInternetFile(); // 這裡是何意?? 通過回調設定httpFile
hRequest = hInet; //
break;
default:
break;
}
cout<<"OnInternetHandleCreated, so ::SetEvent(hEvent[0])"<<endl;
// HANDLE已建立事件(異步控制)
::SetEvent(hEvent[0]);
}
void OnInternetRequestComplete(HINTERNET hInternet, LPINTERNET_ASYNC_RESULT lpInetStatusResult)
{
if( lpInetStatusResult == NULL )
{
//ATLASSERT( 0 );
return;
}
cout<<"OnInternetRequestComplete, so ::SetEvent(hEvent[2])"<<endl;
// 激發請求完成事件(異步控制)
::SetEvent(hEvent[0]);
}
void CALLBACK InternetStatusCallback(
HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpvStatusInformation,
DWORD dwStatusInformationLength
)
{
cout<<"進入回調"<<endl;
switch (dwInternetStatus)
{
case INTERNET_STATUS_RESOLVING_NAME:
break;
case INTERNET_STATUS_NAME_RESOLVED:
break;
case INTERNET_STATUS_CONNECTING_TO_SERVER:
break;
case INTERNET_STATUS_CONNECTED_TO_SERVER:
break;
case INTERNET_STATUS_SENDING_REQUEST:
break;
case INTERNET_STATUS_REQUEST_SENT:
break;
case INTERNET_STATUS_RECEIVING_RESPONSE:
break;
case INTERNET_STATUS_RESPONSE_RECEIVED:
break;
case INTERNET_STATUS_CLOSING_CONNECTION:
break;
case INTERNET_STATUS_CONNECTION_CLOSED:
break;
case INTERNET_STATUS_HANDLE_CREATED:
cout<<"回調是INTERNET_STATUS_HANDLE_CREATED"<<endl;
OnInternetHandleCreated(hInternet, LPINTERNET_ASYNC_RESULT(lpvStatusInformation));
break;
case INTERNET_STATUS_HANDLE_CLOSING:
break;
case INTERNET_STATUS_REQUEST_COMPLETE:
cout<<"回調是INTERNET_STATUS_REQUEST_COMPLETE"<<endl;
OnInternetRequestComplete(hInternet, LPINTERNET_ASYNC_RESULT(lpvStatusInformation));
break;
case INTERNET_STATUS_REDIRECT:
case INTERNET_STATUS_INTERMEDIATE_RESPONSE:
case INTERNET_STATUS_STATE_CHANGE:
default:
break;
}
}