Windows API-Wininet&WinHTTP
July 11, 2020 10:33 PM
WinInet
WinInet(“Windows Internet”)API幫助程序員使用三個常見的Internet協議,這三個協議是用於World Wide Web萬維網的超文本傳輸協議(HTTP:Hypertext Transfer Protocol)、文件傳輸協議(FTP:File Transfer Protocol)和另一個稱為Gopher的文件傳輸協議。WinInet函數的語法與常用的Win32 API函數的語法類似,這使得使用這些協議就像使用本地硬盤上的文件一樣容易。
WinInet 概述
⊙ Hinternet 句柄的層次關系
⊙ HTTP 函數層次關系
⊙ 典型的 HTTP 客戶端程序的處理流程
1、普通 WinInet 處理函數
⊙ InternetOpen 初始化 WinInet.dll
⊙ InternetOpenUrl 打開 Url,讀取數據
⊙ InternetAttemptConnect 嘗試建立到 Internet 的連接
⊙ InternetConnect 建立 Internet 的連接
⊙ InternetCheckConnection 檢查 Internet 的連接是否能夠建立
⊙ InternetSetOption 設置一個 Internet 選項
⊙ InternetSetStausCallback 安裝一個回調函數,供 API 函數調用
⊙ InternetQueryOption 查詢在一個指定句柄上的 Internet 選項
⊙ InternetQueryDataAvailable 查詢可用數據的數量
⊙ InternetReadFile(Ex) 從一個打開的句柄讀取數據
⊙ InternetFindNextFile 繼續文件搜尋
⊙ InetrnetSetFilePointer 為 InternetReadFile 設置一個文件位置
⊙ InternetWriteFile 將數據寫到一個打開的 Internet 文件
⊙ InternetLockRequestFile 允許用戶為正在使用的文件加鎖
⊙ InternetUnlockRequestFile 解鎖被鎖定的文件
⊙ InternetTimeFromSystemTime 根據指定的 RFC 格式格式化日期和時間
⊙ InternetTimeToSystemTime 將一個 HTTP 時間/日期字串格式化為 SystemTime 結構對象
⊙ InternetConfirmZoneCrossing 檢查在安全 URL 和非安全 URL 間的變化
⊙ InternetCloseHandle 關閉一個單一的 Internet 句柄
⊙ InternetErrorDlg 顯示錯誤信息對話框
⊙ InternetGetLastResponesInfo 獲取最近發送的 API函數的錯誤
2、HTTP 處理函數
⊙ HttpOpenRequest 打開一個 HTTP 請求的句柄
⊙ HttpSendRequert(Ex) 向 HTTP 服務器發送指定的請求
⊙ HttpQueryInfo 查詢有關一次 HTTP 請求的信息
⊙ HttpEndRequest 結束一個 HTTP 請求
⊙ HttpAddRequestHeaders 添加一個或多個 HTTP 請求報頭到 HTTP請求句柄
3、FTP 處理函數
⊙ FtpCreateDirectory 在 Ftp 服務器新建一個目錄
⊙ FtpDelectFile 刪除存儲在 Ftp 服務器上的文件
⊙ FtpFindFirstFile 查找給定 Ftp 會話中的指定目錄
⊙ FtpGetCurrentDirectory 為指定 Ftp 會話獲取當前目錄
⊙ FtpGetFile 從 Ftp 服務器下載文件
⊙ FtpOpenFile 訪問一個遠程文件以對其進行讀寫
⊙ FtpPutFile 向 Ftp 服務器上傳文件
⊙ FtpRemoveDirectory 在 Ftp 服務器刪除指定的文件
⊙ FtpRenameFile 為 Ftp 服務器上的指定文件改名
⊙ FtpSetCurrentDirectory 更改在 Ftp 服務器上正在使用的目錄
WinInet 層關系
1、WinInet 是一個網絡編程接口,包含了 Internet 底層協議 HTTP,FTP。
2、借助 WinInet 接口,可不必去了解 Winsock、TCP/IP 和特定 Internet 協議的細節就可以編寫出高水平的 Internet 客戶端程序。
3、WinInet 為 HTTP、FTP 提供了統一的函數集,也就是 Win32 API 接口。
4、WinInet 簡化了 HTTP、FTP 協議的編程,可輕松地將 Internet 集成到應用程序中。
Hinternet 句柄的層次關系
1、首先通過 InternetOpen 函數創建位於根部的 Hinternet 句柄,然后才能通過其進一步建立 HTTP、FTP 的連接。
2、使用 InternetConnect 函數創建一個指定的連接,它將通過傳遞給它的參數為指定的站點初始化 HTTP、FTP 連接並創建一個從根句柄分支出去的 Hinernet 句柄。
3、HttpOpenRequest 和 FtpOpenFile、FtpFindFirstFile等函數將使用 InternetConnect
所創建的句柄以建立到指定站點的連接。
HTTP 函數層次關系
1、對於 WWW 服務器提供的資源可以直接通過 InternetOpenUrl 或是 HTTP 函數對潛在的協議進行處理來訪問。
2、由於 HTTP 協議是在不斷發展的,當這些底層協議被更新后也將影響這些 HTTP 函數行為
3、InternetOpen、InternetConnect、HttpOpenRequest 將返回 Hinternet 句柄,而HttpAddRequestHeaders、HttpQueryInfo、HttpSendRequest、HttpSendRequestEx、InternetErrorDlg 將使用它們所依靠的這些函數創建的 Hinternet句柄。
FTP 函數層次關系
1、FTP 函數需要請求得到特定類型的 Hinternet句柄才能正常工作,這些句柄的創建必須按一定次序來進行:
1、首先使用 InternetOpen 創建根句柄,然后才能通過 InternetConnect 創建一個FTP連接句柄
2、該圖展示了依賴於 InternetConnect 所返回FTP 連接句柄的 FTP函數之間的層次關系。
典型的 HTTP 客戶端程序的處理流程
1、目的:開始 HTTP會話,建立 HTTP 連接
方法:InetrnetOpen、InternetAttemptConnect、InternetConnect
結果:初始化 WinInet.dll 並聯接服務器,返回相應的句柄
2、目的:創建一個 HTTP請求
方法:HttpOpenRequest
結果:
3、目的:發送一個 HTTP請示
方法:HttpAddRequestHeaders
HttpSendRequest(Ex)
結果:
4、目的:讀文件
方法:InternetReadFile(Ex)
結果:使用你提供的緩沖讀指定的字節
5、目的:獲取 HTTP請求信息
方法:HttpQueryInfo
結果:從服務器獲取 HTTP 請求頭信息
6、目的:異常處理
方法:InternetGetLastResponesInfo、InternetErrorDlg
結果:處理所有普通的異常類型
7、目的:結束 HTTP 會話
方法:HttpEndRequest、InternetCloseHandle
結果:自動清除打開的句柄的連接
InetrnetOpen 初始化
InternetOpen(lpszAgent: PChar;
dwAccessType: DWORD;
lpszProxy,
lpszProxyBypass:PChar;
dwFlags: DWORD): HINTERNET; stdcall;
參數:
1、lpszAgent 應用程序名,可以自定義
2、dwAccessType 存取類型,可以是:
①INTERNET_OPEN_TYPE_PRECONFIG =0 使用 IE 中的連接設置
②INTERNET_OPEN_TYPE_DIRECT =1 直接連接到服務器
③INTERNET_OPEN_TYPE_PROXY =3 通過代理服務器進行連接
為 3 時需指定代理服務器地址
3、lpszProxy CERN 代理服務器地址,一般設置為 null;
4、lpszProxyBypass 代理服務器地址;
5、dwFlags 標記,一般設置為 0,可以是:
①INTERNET_FLAG_DONT_CACHE 不在緩存中保存取得的內容
②INTERNET_FLAG_OFFLINE 脫機方式
InternetOpenUrl 打開 Url,讀取數據
InternetOpenUrl(hInet: HINTERNET;
lpszUrl: PChar;
lpszHeaders: PChar;
dwHeadersLength: DWORD;
dwFlags: DWORD;
dwContext: DWORD): HINTERNET; stdcall;
2、參數:
1、hInet 由 InternetOpen返回的句柄
2、lpszUrl 文件 Url 地址,以 http:,ftp:打頭的 Url 地址;
3、lpszHeaders 發送到服務器的數據頭;
4、dwHeadersLength 發送到服務器的數據頭長度
5、dwFlags 標記,可以是:
①INTERNET_FLAG_RELOAD 強制重讀數據
②INTERNET_FLAG_DONT_CACHE 不保存到緩存
③INTERNET_FLAG_TRANSFER_ASCII 使用文本數據
④INTERNET_FLAG_TRANSFER_BINARY 使用二進制數據
6、dwContext 上下文標記,如果使用回調功能時這個值將傳送給回調函數
Internet 的連接
InternetConnect
InternetConnect(hInet: HINTERNET;
lpszServerName: PChar;
nServerPort: INTERNET_PORT;
lpszUsername: PChar;
lpszPassword: PChar;
dwService: DWORD;
dwFlags: DWORD;
dwContext: DWORD): HINTERNET; stdcall;
參數:
1、hInet 由 InternetOpen 返回的句柄
2、lpszServerName 服務器的地址
HTTP 地址必須為服務器名作InternetOpenUrl語法分析
3、nServerPort HTTP協議端口號(缺省80)
4、lpszUsername 用戶名
5、lpszPassword 用戶密碼
6、dwService 決定服務類型 HTTP,FTP,可以是:
①INTERNET_SERVICE_FTP = 1; 連接到一個 FTP 服務器上
②INTERNET_SERVICE_HTTP = 3; 連接到一個 HTTP 服務器上
7、dwFlags
8、dwContext
HttpOpenRequest
HttpOpenRequest(hConnect: HINTERNET;
lpszVerb: PChar;
lpszObjectName: PChar;
lpszVersion: PChar;
lpszReferrer: PChar;
lplpszAcceptTypes: PLPSTR;
dwFlags: DWORD;
dwContext: DWORD): HINTERNET; stdcall;
參數:
1、hConnect InternetConnect句柄
2、lpszVerb 命令字,如果為 NULL,使用缺省值“GET”
3、lpszObjectName 命令對象,通常是一個文件名、可執行文件或是一個搜索列表
4、lpszVersion HTTP版本,如果為空,將使用“HTTP/1.0”
5、lpszReferrer 一個網址,可以為空
6、lplpszAcceptTypes中程序接收的文件類型列表。把空值傳給該函數即通知了服務器只有文本文件可以被接收'application/octet-stream'
7、dwFlags 標志 使用 or 連接標志
①INTERNET_FLAG_NO_CACHE_WRITE 標志不緩沖寫
②INTERNET_FLAG_KEEP_CONNECTION 保持連接
③INTERNET_FLAG_SECURE { use PCT/SSL if applicable (HTTP) }
{ Security Ignore Flags, Allow HttpOpenRequest to overide
Secure Channel (SSL/PCT) failures of the following types. }
④INTERNET_FLAG_IGNORE_CERT_CN_INVALID { bad common name in X509 Cert. }
⑤INTERNET_FLAG_IGNORE_CERT_DATE_INVALID { expired X509 Cert. }
8、dwContext Integer(Self)?
向 HTTP 服務器發送指定的請求
HttpSendRequest
HttpSendRequest(hRequest: HINTERNET;
lpszHeaders: PChar;
dwHeadersLength: DWORD;
lpOptional: Pointer;
dwOptionalLength: DWORD): BOOL; stdcall;
參數:
1、hRequest HttpOpenRequest句柄
2、lpszHeaders 服務請求的數據頭
3、dwHeadersLength 服務請求的數據頭的長度
4、lpOptional 緊跟在標題后任意數據的地址,此參數一般用於 POST 和 PUT 操作
5、dwOptionalLength 數據的長度
InternetSetOption
InternetSetOption 設置一個 Internet 選項
InternetSetOption(hInet: HINTERNET;
dwOption: DWORD;
lpBuffer: Pointer;
dwBufferLength: DWORD): BOOL; stdcall;
參數:
1、hInet 句柄
2、dwOption Internet 選項,可以是:
①INTERNET_OPTION_SEND_TIMEOUT 設置,發送請求和連接時的超時時間
②INTERNET_OPTION_RECEIVE_TIMEOUT 設置,接收請求和連接時的超時間間
3、lpBuffer 值
4、dwBufferLength 值大小
WinHTTP
https://docs.microsoft.com/en-us/windows/desktop/winhttp/porting-wininet-applications-to-winhttp
Code demo
| Header | winhttp.h |
| Library | Winhttp.lib |
| DLL | Winhttp.dll |
DWORD dwSize = 0;
LPVOID lpOutBuffer = NULL;
BOOL bResults = FALSE;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen( L"A WinHTTP Example Program/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
// Specify an HTTP server.
if (hSession)
hConnect = WinHttpConnect( hSession, L"www.microsoft.com",
INTERNET_DEFAULT_HTTP_PORT, 0);
// Create an HTTP request handle.
if (hConnect)
hRequest = WinHttpOpenRequest( hConnect, L"GET", NULL,
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
0);
// Send a request.
if (hRequest)
bResults = WinHttpSendRequest( hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0, WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
// End the request.
if (bResults)
bResults = WinHttpReceiveResponse( hRequest, NULL);
// First, use WinHttpQueryHeaders to obtain the size of the buffer.
if (bResults)
{
WinHttpQueryHeaders( hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF,
WINHTTP_HEADER_NAME_BY_INDEX, NULL,
&dwSize, WINHTTP_NO_HEADER_INDEX);
// Allocate memory for the buffer.
if( GetLastError( ) == ERROR_INSUFFICIENT_BUFFER )
{
lpOutBuffer = new WCHAR[dwSize/sizeof(WCHAR)];
// Now, use WinHttpQueryHeaders to retrieve the header.
bResults = WinHttpQueryHeaders( hRequest,
WINHTTP_QUERY_RAW_HEADERS_CRLF,
WINHTTP_HEADER_NAME_BY_INDEX,
lpOutBuffer, &dwSize,
WINHTTP_NO_HEADER_INDEX);
}
}
// Print the header contents.
if (bResults)
printf("Header contents: \n%S",lpOutBuffer);
// Free the allocated memory.
delete [] lpOutBuffer;
// Report any errors.
if (!bResults)
printf("Error %d has occurred.\n",GetLastError());
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
WinHttpQueryDataAvailable\WinHttpReadData
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
BOOL bResults = FALSE;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen( L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
// Specify an HTTP server.
if (hSession)
hConnect = WinHttpConnect( hSession, L"www.microsoft.com",
INTERNET_DEFAULT_HTTPS_PORT, 0);
// Create an HTTP request handle.
if (hConnect)
hRequest = WinHttpOpenRequest( hConnect, L"GET", NULL,
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE);
// Send a request.
if (hRequest)
bResults = WinHttpSendRequest( hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0, WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
// End the request.
if (bResults)
bResults = WinHttpReceiveResponse( hRequest, NULL);
// Continue to verify data until there is nothing left.
if (bResults)
do
{
// Verify available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable( hRequest, &dwSize))
printf( "Error %u in WinHttpQueryDataAvailable.\n",
GetLastError());
// Allocate space for the buffer.
pszOutBuffer = new char[dwSize+1];
if (!pszOutBuffer)
{
printf("Out of memory\n");
dwSize=0;
}
else
{
// Read the Data.
ZeroMemory(pszOutBuffer, dwSize+1);
if (!WinHttpReadData( hRequest, (LPVOID)pszOutBuffer,
dwSize, &dwDownloaded))
printf( "Error %u in WinHttpReadData.\n", GetLastError());
else
printf( "%s\n", pszOutBuffer);
// Free the memory allocated to the buffer.
delete [] pszOutBuffer;
}
} while (dwSize > 0);
// Report any errors.
if (!bResults)
printf( "Error %d has occurred.\n", GetLastError());
// Close open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);