WinHttp编程初步心得

代码都在下面了,目前这个版本实现的功能还非常的少,能实现的有:

1. GET方法。给定一个URL(可以带中文),返回http的响应数据,包括文本和二进制数据
2. 支持代理服务器,需要用户预先设定好proxy server ip, port, username, password.

不支持的有:
1. POST
2. 查询http响应的header。
3. 将返回的文本数据重新编码,变成UTF-16。这需要首先从header取出http server响应的数据是什么编码的,然后就可以使用windows的MultiByteToWideChar来进行转换。

这里总结几点开发过程中的注意点:
1. MSDN上的资料不是非常的全,所以有些参考了google得来的内容。
2. WinHttpOpen的时候,如果用AUTO PROXY,也就是让winhttp从注册表读取proxy设置的话(这个注册表的设置是proxycfg.exe生成的,和IE中的那个proxy设置是两码事)。
3. proxy的用户名和密码需要用WinHttpSetOption来进行设置, timeout设定用WinHttpSetTimeouts
4. 使用WinHttpCrackUrl可以将一个给定的url(必须以http://, https://打头)分解,设置到URL_COMPONENTS这个structure中。在这里其实就可以做url encoding(也就是将url不支持的字符转换成%xxx这样的东西),但是这样做的话需要手动给URL_COMPONENETS中的member分 配内存,比较麻烦,所以没做。
5. 使用WinHttpCreateUrl可以根据URL_COMPONENETS重新生成一个string的URL,但是这里没用到。
6. 使用WinHttpConnect的时候,一定要注意要给出hostname,不是url,所以要手动分解,只取出http server的那个部分,比如http://www.google.com/sfsdfdsf?id=xxx& user=xxxx,hostname就是www.google.com
7. 然后使用WinHttpOpenRequest的时候,就可以给出去掉了http://之后的后面所有内容了,也就是www.google.com /sfsdfdsf?id=xxx&user=xxxx这样的东西。注意最后的flag设 置:WINHTTP_FLAG_ESCAPE_PERCENT | WINHTTP_FLAG_REFRESH,这两个很有用,WINHTTP_FLAG_ESCAPE_PERCENT就是将url中不合法的内容转 成%xxx,WINHTTP_FLAG_REFRESH就是跳过proxy的cache,每次都请求全新的数据。还有需要注意的 是,WinHttpOpenRequest中,要求给出我们能接受的mimetype,这里可以参考代码,如果要文本,就给text/*,如果要二进制数 据,就可以像这里给出application/*, image/*, audio/*......
8. 最后WinHttpSendRequest的时候,也可以设定additional header和optional数据。这里的optional数据一般是用于POST的,也就是将需要post到server的数据填充在这个地方。 WinHttpSendRequest将header都发送出去之后,紧接着就会发送这个optional数据。
9. WinHttpQueryDataAvailable可以check是否还有数据需要接收。WinHttpReadData用来读取数据,注意读出来的数 据就是字节流,像前面所说,如果是文本,那么要根据response header,首先知道是什么编码和字符集,然后再用MultiByteToWideChar来转换。也要注意WinHttpReadData的最后一个 参数,给出了实际读取到的字节数,也可以根据这个信息来判断是否已经接收完了。此外特别需要注意的是,如果用的是一个固定的buffer循环接收,就像这 里一样,那么不要忘记接收完成的时候,要在尾部加上\0,分配buffer的时候也要留出\0的位置。


复制代码
     /*
    * Schedule Download Http utilities, based on winhttp
    * Written by Eric Zhang <nicolas.m.zhang@gmail.com>
    
*/

    #include 
" ..\include\http.h "
    #include 
" ..\include\logger.h "
    #include 
" ..\include\utils.h "
    #include 
" ..\include\defs.h "
    #include 
" ..\include\macros.h "
    #include 
< strsafe.h >

    
//  http server's hostname length
     #define  HTTP_HOST_NAME_MAX      255
    
#define  HTTP_TEXT_MIMETYPE      1
    
#define  HTTP_BIN_MIMETYPE      2

    
//  mimetypes for WinHttpOpenRequest
    LPCWSTR text_mimetype[]  =  { L " text/* " , L " \0 "  };
    LPCWSTR bin_mimetype[] 
=  { L " application/* " , L " audio/* " , L " image/* " , L " video/* " , L " \0 "  };

    
/*
    * This function used internally. It checks the proxy settings and apply
    * to the WinHttp. Return winhttp session handle if succeeded, otherwise
    * return NULL.
    
*/
    
static  HINTERNET open_winhttp()
    {
       HINTERNET session 
=  NULL;
       TCHAR proxy_enabled[REGISTRY_VALUE_SIZE];
       TCHAR proxy_server[REGISTRY_VALUE_SIZE];
       TCHAR proxy_port[REGISTRY_VALUE_SIZE];
       TCHAR proxy_username[REGISTRY_VALUE_SIZE];
       TCHAR proxy_password[REGISTRY_VALUE_SIZE];
       DWORD errcode;
       size_t proxy_username_len 
=   0 ;
       size_t proxy_password_len 
=   0 ;

       
//  Check whether the proxy has enabled
       SecureZeroMemory(proxy_enabled,  sizeof (proxy_enabled));
       utils_get_registry_value(SD_REGISTRY_KEY, HTTP_PROXY_ENABLED_ENTRY, proxy_enabled, 
sizeof (proxy_enabled));
       
if  (utils_is_string_empty(proxy_enabled)  ||  _tcscmp(proxy_enabled, TEXT( " Y " ))  !=   0 ) {
          
//  proxy isn't enabled, direct connect
          session  =  WinHttpOpen(HTTP_AGENT_NAME, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS,  0 );
          
if  (session  ==  NULL) {
             GET_ERROR_CODE(errcode);
             M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_NO_PROXY_OPEN_FAILED, utils_format_error_string(errcode));
          }
       } 
else  {
          
//  proxy enabled, read server/port/user/pass next
          SecureZeroMemory(proxy_server,  sizeof (proxy_server));
          SecureZeroMemory(proxy_port, 
sizeof (proxy_port));
          SecureZeroMemory(proxy_username, 
sizeof (proxy_username));
          SecureZeroMemory(proxy_password, 
sizeof (proxy_password));
          utils_get_registry_value(SD_REGISTRY_KEY, HTTP_PROXY_SERVER_ENTRY, proxy_server, 
sizeof (proxy_server));
          utils_get_registry_value(SD_REGISTRY_KEY, HTTP_PROXY_PORT_ENTRY, proxy_port, 
sizeof (proxy_port));
          utils_get_registry_value(SD_REGISTRY_KEY, HTTP_PROXY_USER_ENTRY, proxy_username, 
sizeof (proxy_username));
          utils_get_registry_value(SD_REGISTRY_KEY, HTTP_PROXY_PASS_ENTRY, proxy_password, 
sizeof (proxy_password));
          M_GTIF_WITH_LOG(
! utils_is_string_empty(proxy_server), failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_PROXY_SERVER_ABSENT);
          M_GTIF_WITH_LOG(
! utils_is_string_empty(proxy_port), failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_PROXY_PORT_ABSENT);
          M_GTIF_WITH_LOG(utils_is_string_int(proxy_port), failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_PROXY_PORT_ILLEGAL);
          
//  add port into server string
          M_GTIF_WITH_LOG(SUCCEEDED(StringCchPrintf(proxy_server, _countof(proxy_server), TEXT( " %s:%s " ), proxy_server, proxy_port)), failed,
             LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_STRING_OPERATION_FAILED);

          
//  open
          session  =  WinHttpOpen(HTTP_AGENT_NAME, WINHTTP_ACCESS_TYPE_NAMED_PROXY, proxy_server, WINHTTP_NO_PROXY_BYPASS,  0 );
          
if  (session  ==  NULL) {
             GET_ERROR_CODE(errcode);
             M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_OPEN_WITH_PROXY_FAILED, utils_format_error_string(errcode));
          }

          
//  set proxy username & password
           if  ( ! utils_is_string_empty(proxy_username)  &&   ! utils_is_string_empty(proxy_password)) {
             M_GTIF_WITH_LOG(SUCCEEDED(StringCchLength(proxy_username, _countof(proxy_username), 
& proxy_username_len)), failed,
                LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_STRING_OPERATION_FAILED);
             M_GTIF_WITH_LOG(SUCCEEDED(StringCchLength(proxy_password, _countof(proxy_password), 
& proxy_password_len)), failed,
                LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_STRING_OPERATION_FAILED);
             
if  ( ! WinHttpSetOption(session, WINHTTP_OPTION_PROXY_USERNAME, proxy_username, proxy_username_len)) {
                GET_ERROR_CODE(errcode);
                M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_SET_PROXY_USER_FAILED, utils_format_error_string(errcode));
             }
             
if  ( ! WinHttpSetOption(session, WINHTTP_OPTION_PROXY_PASSWORD, proxy_password, proxy_password_len)) {
                GET_ERROR_CODE(errcode);
                M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_SET_PROXY_PASS_FAILED, utils_format_error_string(errcode));
             }
          }
       }

       
//  set timeouts
        if  ( ! WinHttpSetTimeouts(session, HTTP_RESOLVE_TO, HTTP_CONNECT_TO, HTTP_SEND_TO, HTTP_RECV_TO)) {
          GET_ERROR_CODE(errcode);
          M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_SET_TIMEOUTS_FAILED, utils_format_error_string(errcode));
       }

       
return  session;
    failed:
       
if  (session  !=  NULL) WinHttpCloseHandle(session);
       
return  NULL;
    }

    
static  BOOL http_get(PCTSTR url, HINTERNET  * sess, HINTERNET  * conn, HINTERNET  * req, DWORD mimetype)
    {
       HINTERNET session 
=  NULL, connect  =  NULL, request  =  NULL;
       BOOL result 
=  FALSE;
       DWORD errcode;
       URL_COMPONENTS url_comp;
       size_t url_len_input;
       TCHAR http_host_name[HTTP_HOST_NAME_MAX];
       
int  hostname_index;

       M_RETURN_VAL_IF_FAIL(url 
!=  NULL, FALSE);
       M_RETURN_VAL_IF_FAIL(sess 
!=  NULL, FALSE);
       M_RETURN_VAL_IF_FAIL(conn 
!=  NULL, FALSE);
       M_RETURN_VAL_IF_FAIL(req 
!=  NULL, FALSE);
       M_RETURN_VAL_IF_FAIL(logger_is_enabled(), FALSE);

       session 
=  open_winhttp();
       M_RETURN_VAL_IF_FAIL(session 
!=  NULL, FALSE);   //  log has been done in open_winhttp function

       
//  crack url input
       
//  Initialize the URL_COMPONENTS structure.
        SecureZeroMemory( & url_comp,  sizeof (url_comp));
        url_comp.dwStructSize 
=   sizeof (url_comp);

        
//  Set required component lengths to non-zero
        
//  so that they are cracked.
        url_comp.dwSchemeLength     =   - 1 ;
        url_comp.dwHostNameLength  
=   - 1 ;
        url_comp.dwUrlPathLength   
=   - 1 ;
        url_comp.dwExtraInfoLength 
=   - 1 ;

       M_GTIF_WITH_LOG(SUCCEEDED(StringCchLength(url, STRSAFE_MAX_CCH, 
& url_len_input)), failed, LOG_LEVEL_ERROR,
          __SDFILE__, __LINE__, HTTP_STRING_OPERATION_FAILED);
       result 
=  WinHttpCrackUrl(url, url_len_input,  0 & url_comp);
       
if  ( ! result) {
          GET_ERROR_CODE(errcode);
          M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_CRACK_URL_FAILED, utils_format_error_string(errcode));
       }

       
/*  No need to create url because No winhttp functions accept a whole escaped url
       // get new url length, allocate it
       WinHttpCreateUrl(&url_comp, 0, NULL, &url_len_cracked);
       M_GTIF_WITH_LOG(url_len_cracked > 0, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_CREATE_URL_GET_LEN_FAILED);
       // the length WinHttpCreateUrl generated is wide character numbers
       url_cracked = (TCHAR *)HeapAlloc(sdc_heap, HEAP_ZERO_MEMORY, url_len_cracked * sizeof(WCHAR));
       M_GTIF_WITH_LOG(url_cracked != NULL, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_HEAP_ALLOC_FAILED);
       // call create url again, this time get result url
       result = WinHttpCreateUrl(&url_comp, 0, url_cracked, &url_len_cracked);
       if (!result) {
          GET_ERROR_CODE(errcode);
          M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_CREATE_URL_FAILED, utils_format_error_string(errcode));
       } 
*/

       
//  url OK, connect. Notice here WinHttpConnect needs Host/Server name, not the whole URL
       
//  Request file and parameters should be set in WinHttpOpenRequest function
       
//  get hostname
       hostname_index  =  utils_find_char(url_comp.lpszHostName, (TCHAR) ' / ' );
       
if  (hostname_index  <   0 ) {
          
//  not found or error occurs, use the original hostname
          connect  =  WinHttpConnect(session, url_comp.lpszHostName, INTERNET_DEFAULT_HTTP_PORT,  0 );
       } 
else  {
          
//  found "/"
          memcpy_s(http_host_name,  sizeof (http_host_name), url_comp.lpszHostName, hostname_index  *   sizeof (TCHAR));
          http_host_name[hostname_index] 
=  (TCHAR) ' \0 ' ;
          connect 
=  WinHttpConnect(session, http_host_name, INTERNET_DEFAULT_HTTP_PORT,  0 );
       }
       
if  (connect  ==  NULL) {
          GET_ERROR_CODE(errcode);
          M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_CONNECT_FAILED, utils_format_error_string(errcode));
       }

       
if  (mimetype  ==  HTTP_TEXT_MIMETYPE) {
          request 
=  WinHttpOpenRequest(connect, TEXT( " GET " ), url_comp.lpszUrlPath, NULL, WINHTTP_NO_REFERER,
                      text_mimetype, WINHTTP_FLAG_ESCAPE_PERCENT 
|  WINHTTP_FLAG_REFRESH);
       } 
else  {
          request 
=  WinHttpOpenRequest(connect, TEXT( " GET " ), url_comp.lpszUrlPath, NULL, WINHTTP_NO_REFERER,
                      bin_mimetype, WINHTTP_FLAG_ESCAPE_PERCENT 
|  WINHTTP_FLAG_REFRESH);
       }
       
if  (request  ==  NULL) {
          GET_ERROR_CODE(errcode);
          M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_OPEN_REQUEST_FAILED, utils_format_error_string(errcode));
       }

        
//  Send the request
        result  =  WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS,  0 , WINHTTP_NO_REQUEST_DATA,  0 0 0  );
       
if  ( ! result) {
          GET_ERROR_CODE(errcode);
          M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_SEND_REQUEST_FAILED, utils_format_error_string(errcode));
       }

       
//  Start receiving
       result  =  WinHttpReceiveResponse(request, NULL);
       
if  ( ! result) {
          GET_ERROR_CODE(errcode);
          M_GTIF_WITH_LOG(FALSE, failed, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_RECV_RESPONSE_FAILED, utils_format_error_string(errcode));
       }

       
//  OK, return
        * sess  =  session;
       
* conn  =  connect;
       
* req  =  request;
       
return  TRUE;

    failed:
        
//  Close any open handles
         if  (request) WinHttpCloseHandle(request);
        
if  (connect) WinHttpCloseHandle(connect);
        
if  (session) WinHttpCloseHandle(session);
       
return  FALSE;
    }

    BOOL http_get_text(PCTSTR url, HINTERNET 
* sess, HINTERNET  * conn, HINTERNET  * req)
    {
       
return  http_get(url, sess, conn, req, HTTP_TEXT_MIMETYPE);
    }

    BOOL http_get_bin(PCTSTR url, HINTERNET 
* sess, HINTERNET  * conn, HINTERNET  * req)
    {
       
return  http_get(url, sess, conn, req, HTTP_BIN_MIMETYPE);
    }

    BOOL http_check_data_len(HINTERNET request, DWORD 
* len)
    {
       DWORD data_size 
=   0 ;
       BOOL result 
=  FALSE;
       DWORD errcode;

       M_RETURN_VAL_IF_FAIL(request 
!=  NULL, FALSE);
       M_RETURN_VAL_IF_FAIL(len 
!=  NULL, FALSE);
       M_RETURN_VAL_IF_FAIL(logger_is_enabled(), FALSE);

       
//  Check the data length
       result  =  WinHttpQueryDataAvailable(request,  & data_size);
       
if  ( ! result) {
          GET_ERROR_CODE(errcode);
          M_RVIF_WITH_LOG(FALSE, FALSE, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_QUERY_DATA_FAILED, utils_format_error_string(errcode));
       }

       M_RVIF_WITH_LOG(data_size 
>   0 , FALSE, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_DATA_LENGTH_ILLEGAL, data_size);

       
* len  =  data_size;
       
return  TRUE;
    }

    BOOL http_recv(HINTERNET request, LPVOID buffer, DWORD buffer_len, DWORD 
* bytes_read)
    {
       BOOL result 
=  FALSE;
       DWORD errcode;

       M_RETURN_VAL_IF_FAIL(request 
!=  NULL, FALSE);
       M_RETURN_VAL_IF_FAIL(buffer 
!=  NULL, FALSE);
       M_RETURN_VAL_IF_FAIL(buffer_len 
>   0 , FALSE);
       M_RETURN_VAL_IF_FAIL(bytes_read 
!=  NULL, FALSE);
       M_RETURN_VAL_IF_FAIL(logger_is_enabled(), FALSE);

       
//  Read the Data.
        SecureZeroMemory(buffer, buffer_len);
        result 
=  WinHttpReadData(request, buffer, buffer_len, bytes_read);
       
if  ( ! result) {
          GET_ERROR_CODE(errcode);
          M_RVIF_WITH_LOG(FALSE, FALSE, LOG_LEVEL_ERROR, __SDFILE__, __LINE__, HTTP_READ_DATA_FAILED, utils_format_error_string(errcode));
       }

       
return  TRUE;
    }

    
void  http_close(HINTERNET  * session, HINTERNET  * connect, HINTERNET  * request)
    {
       
if  ( * request) WinHttpCloseHandle( * request);
       
if  ( * connect) WinHttpCloseHandle( * connect);
       
if  ( * session) WinHttpCloseHandle( * session);

       
* session  =  NULL;
       
* connect  =  NULL;
       
* request  =  NULL;

       
return ;
    }

    BOOL http_check_internet(PCTSTR url)
    {
       HINTERNET session 
=  NULL, connect  =  NULL, request  =  NULL;
       BOOL result 
=  FALSE;
       DWORD data_len 
=   0 ;

       M_RETURN_VAL_IF_FAIL(url 
!=  NULL, FALSE);
       M_RETURN_VAL_IF_FAIL(logger_is_enabled(), FALSE);

       result 
=  http_get_text(url,  & session,  & connect,  & request);
       M_RETURN_VAL_IF_FAIL(result, FALSE); 
//  logger has been done in http_send

       result 
=  http_check_data_len(request,  & data_len);
       M_RETURN_VAL_IF_FAIL(result, FALSE);

       
//  internet is OK, no need to receive actual data
       http_close( & session,  & connect,  & request);

       
return  TRUE;

    }


原帖链接: http://www.cnblogs.com/super119/archive/2011/04/10/2011350.html

ps: 这个帖子帮了我大忙, 感谢原作者!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值