65.9K
CodeProject 正在变化。 阅读更多。
Home

WinHttpGateway 库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.17/5 (4投票s)

2009 年 4 月 30 日

CDDL

13分钟阅读

viewsIcon

27610

downloadIcon

2230

具有异步调用机制和 HTTPS 协议支持的 WinHttp API 包装器库。

引言

WinHttpGateway 是一个动态库,用于简化 WinHttp API 的工作。它是该 API 的封装代码。WinHttp API 是 WinINet API 的替代品(有关 Microsoft 推荐使用 WinHttp API 的更多信息,请参阅 关于 WinHTTP)。该库的特点是使用异步数据传输模式。该库被用作动态连接模块,并提供了一个简单的接口,使得可以从任何线程独立于其他线程调用 HTTP 协议。

库使用快速概述。

动态模块导出函数

由于该库是作为动态连接的,实际上它只导出一个函数(即 GetInterface)。

extern "C" LPVOID __declspec(dllexport)
GetInterface() 
{
    return static_cast(&g_winhttplauncher);
}
//WinHttpGateway\HttpGateway.cpp 

该函数返回一个接口指针,该接口提供了该库的功能。为了方便在 C++ 中使用,该库的代码封装了 IWinHttpLauncher 接口(CWinHttpLauncherStub 类,它提供了调用动态 WinHttpGateway.dll 模块的机制)。要使用该库,只需包含 WinHttpGateway.h 文件。然后连接到库模块,您应该创建一个 CWinHttpLauncherStub 类。

使用示例可以在 WinHttpGatewayTest 项目中找到。

WinHttpGateway.dll 模块的基本用法。

int _tmain(int _argc, TCHAR* _argv[], TCHAR* _envp[])
{
            // initialize MFC and print and error on failure
            if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
            {
                        // TODO: change error code to suit your needs
                        cerr << _T("Fatal Error: MFC initialization failed") << endl;
                        return 1;
            }
 
            CWinHttpLauncherStub winhttp;
            CString sPath = _T("WinHttpGateway.dll");
            if(!winhttp.load(sPath) || !winhttp)
            {
                        CString mess;
                        mess.Format(_T("Can`t load %s"),(LPCTSTR)sPath);
                        ::AfxMessageBox(mess,MB_OK|MB_ICONERROR);
                        return 1;
            }
 
            CString sProxyURL = _T("");
            CString sBypass = _T("");
            CString sLogin = _T("");
            CString sPassword = _T("");
 
            DWORD dwErrCode = 0;
            LPTSTR szError = NULL;
            if(!winhttp.initilize(IWinHttpLauncher::PAT_NO_PROXY,sProxyURL,sBypass,&dwErrCode,&szError))
            {
                        CString mess;
                        mess.Format(_T("Initialization error code = %d \"%s\""),dwErrCode,szError);
                        ::AfxMessageBox(mess,MB_OK|MB_ICONERROR);
                        winhttp.free_string(szError);
                        return 1;
            }
 
            winhttp.set_options(
                        IWinHttpLauncher::Option_ProxyLogin
                        ,IWinHttpLauncher::OptionScope_Root
                        ,(LPVOID)(LPCTSTR)sLogin
                        );
            winhttp.set_options(
                        IWinHttpLauncher::Option_ProxyPassword
                        ,IWinHttpLauncher::OptionScope_Root
                        ,(LPVOID)(LPCTSTR)sPassword
                        );
 
            CString sUrl = _T("https://codeproject.org.cn/info/about.aspx");
            CString sMethod = _T("GET");
            CString sHeaders = _T("");
            CString sData2Send = _T("");
 
            LPTSTR szHeaders = NULL;
            LPTSTR szContentType = NULL;
            LPTSTR szReadedData = NULL;
 
            if(!winhttp.request(
                                   sUrl,sMethod,sData2Send,sHeaders
                                   ,&szHeaders,&szContentType,&szReadedData
                                   ,&dwErrCode,&szError
                                   )
                        )
            {
                        CString mess;
                        mess.Format(_T("Request error [url=%s] code = %d \"%s\""),(LPCTSTR)sUrl,dwErrCode,szError);
                        ::AfxMessageBox(mess,MB_OK|MB_ICONERROR);
                        winhttp.free_string(szError);
                        return 1;
            }
 
            long i = 0;
            CString sReadedData = szReadedData;
            cout << _T("Data was readed") << endl;
            cout << _T("ContentType = ") << szContentType << endl;
            cout << _T("Data length ") << sReadedData.GetLength() << endl;
            cout << _T("Data:") << endl;
 
            for(i=0;i<sReadedData.GetLength();i+=256) cout << (LPCTSTR)sReadedData.Mid(i,256);
           
            winhttp.free_string(szHeaders);
            winhttp.free_string(szContentType);
            winhttp.free_string(szReadedData);
 
            return 0;
}

源代码可以在“contest”文件夹中找到。如果使用代理服务器,则需要在初始化时使用其他参数,并且有必要设置代理服务器的 URL,以及用户的登录名和密码(如果需要)。

更复杂的库用法示例可以在测试示例(WinHttpGatewayTest 文件夹)中找到。 

我将对 IWinHttpLauncher 接口进行简要说明。

IWinHttpLauncher 接口已在代码中记录(WinHttpGateway.h 文件)。

枚举。

enum ProxyAccessTypeEn – 描述 WinHttp API 的操作模式。

enum OptionsEn – 描述用于自定义 WinHttp API 的选项,这些选项用于 WinHttpGateway 动态模块的自定义。

enum OptionScopeEn – 设置已安装选项的范围(请参阅“设置选项(通过 WinHttpGateway 配置 WinHttp API)”部分)。

函数。

void enable_tracing (BOOL _en) const – 启用或禁用 WinHttp API 的跟踪(有关详细信息,请参阅 WinHttpTraceCfg.exe,跟踪配置工具

BOOL check_platform () const – 如果当前操作系统支持 WinHttp API,则返回 TRUE。

BOOL initilize (
IN ProxyAccessTypeEn _proxyaccess
,IN LPCTSTR _proxyname
,IN LPCTSTR _proxybypass
,OUT DWORD* _dwErrCode
,OUT LPTSTR* _szError
);
– WinHttpGateway 模块初始化函数。可以选择使用或不使用代理服务器,安装代理服务器的 URL,以及要绕过此代理服务器的 URL 列表。之后,所有调用都将使用设置的值进行。

BOOL set_options(
IN OptionsEn _option
,IN OptionScopeEn _scope
,IN LPVOID _lpdata
);
- 设置调用选项。

BOOL request(
IN LPCTSTR _szUrl
,IN LPCTSTR _szMethod
,IN LPCTSTR _szData2Send
,IN LPCTSTR _szHeaders2Send
,OUT LPTSTR* _pszReadedHeaders
,OUT LPTSTR* _pszContentType
,OUT LPTSTR* _pszReadedData
,OUT DWORD* _dwErrCode
, OUT LPTSTR* _pszError
);
– 使用 _szUrl 参数指定的 URL,通过 _szMethod 方法,使用 _szData2Send 发送数据,以及 _szHeaders2Send 发送的头部。但重要的是,从并行线程调用时,独立的调用(请求将同时独立地进行)。

BOOL request(
IN LPCTSTR _szUrl
,IN LPCTSTR _szMethod
,IN LPCTSTR _szData2Send
,IN LPCTSTR _szHeaders2Send
,IN LPCTSTR _szXSLTFName
,OUT LPTSTR* _pszReadedHeaders
,OUT LPTSTR* _pszContentType
,OUT LPTSTR* _pszReadedData
,OUT LPTSTR** _ppszTagNames
,OUT LPTSTR** _ppszTagValues
,OUT DWORD* _dwErrCode
,OUT LPTSTR* _pszError
);
– 与前一个函数类似,但是如果服务器响应的类型为“text/xml”,则将以两个字符串列表的形式返回(第一个列表将返回标签名称,第二个列表将返回这些标签的值)。返回的数据还可以通过 xslt 转换进行处理(参数 _szXSLTFName,指定 xslt 转换的文件名(xstl 文件))。

void enum_certificates(
OUT LPTSTR** _ppszStorage
,OUT LPTSTR** _ppszName
);
– 返回系统中已安装证书的列表。用于通过 set_options() 函数安装用于 HTTPS 调用(通过 set_options() 函数)的证书名称。

上面描述的函数,如果调用成功则返回 TRUE,否则返回 FALSE。发生错误时,错误消息文本会返回到参数 _pszError,错误代码会返回到参数 _dwErrCode。WinHttpGateway 模块定义了一些错误代码(请参阅 WinHttpGateway\messages.mc 文件),其他错误代码属于操作系统 API,包括 WinHttp API。另外,如果函数返回指向字符串或字符串数组的指针,则需要在客户端释放它们。最好使用 free_list() free_string() 函数来释放这些分配的数据。

CWinHttpLauncherStub 类。

它旨在以类的形式向程序员呈现 WinHttpGateway 动态模块。

函数。

bool load(LPCTSTR _szDllName) – 将 WinHttpGateway 模块加载到内存中,获取用于操作此 dll 模块的接口。

void unload() – 卸载 WinHttpGateway(dll 模块)。

operator bool() - 提供 CWinHttpLauncherStub 类的有效性信息。当模块成功加载并且可以调用该模块的 IWinHttpLauncher 接口提供的函数时,该类才有效。该类继承自 IWinHttpLauncher 接口,并在模块加载时将调用重定向到已加载的动态模块(或者仅输出断言而不进行任何调用)。

static void free_list(LPTSTR* _ppsz) – 该函数释放为通过接口调用(WinHttpGateway 模块)接收到的字符串值列表分配的内存。

static long get_listlength(LPTSTR* _ppsz) – 该函数返回通过接口 IWinHttpLauncher 函数(WinHttpGateway 模块)返回的字符串值列表的长度。

static void free_string(LPTSTR _psz) – 该函数释放 WinHttpGateway 模块为字符串值分配的内存,并将该字符串值返回给使用该模块的代码。

有关该库的更多信息。

设置选项(通过 WinHttpGateway 配置 WinHttp API)。

由于 WinHttpGateway 模块的常规创建/使用方式是在一个(通常是主)线程中创建 CWinHttpLauncherStub 类,然后在不同线程(工作流)中使用,因此提供了已安装选项的范围设置器。因此,区分根选项(可以作为所有线程的默认选项使用的选项)和当前线程选项(仅在此线程中使用)。也就是说,如果在任何线程中使用某个选项作为默认选项而不是当前线程选项,那么该选项将从根选项集中获取(默认情况下,它们由默认值初始化(请参阅 WinHttpGateway\WinHttpGateway.h 文件,OptionsEn 枚举的说明以指定这些值))。

库的内部视图。

类的简要说明(按字母顺序)。

class CAutoLock - 实现使用临界区对某些代码片段进行自动锁定的类。

template class CAutoRefPtr - 用于实现数据智能指针的模板类。在代码中,此模板类用于支持按需接收的数据的各个部分。

struct CBuffer – 数据缓冲区。它(目前)用于内部数据存储。它实现数据转换,以便在不同表示中使用这些数据。

class CCertificate – 用于表示证书的类。存储证书存储名称和证书名称,并提供 PCCERT_CONTEXT 以在系统中表示证书。

class CCertificates – 证书列表。该列表由为给定用户或计算机安装的所有证书组成(有关可能集合的数据从注册表中提取)。

struct CHttpVersionInfo – 结构是系统结构 HTTP_VERSION_INFO 的包装器。

class CmpStrNoCase – 一个扩展 CString 类并支持不区分大小写匹配的类。

class CPassword – 用于表示密码的类。

template class CPropertyBase – 用于实现基本数据类型选项类的模板类。

class CPropMassAction – 执行对所有选项的操作。

class CPropMassActionIni – 扩展 CPropMassAction 并实现选项在注册表中的保存/加载。

struct CRefCounter – 引用计数基类。

struct CUrlComponents – 系统结构 URL_COMPONENTSW 的包装器。

class CWinHttp – 异步操作 WinHttp API 的类。

struct CWinHttp::CRequestInfo - 请求信息集。

struct CWinHttpAsyncResult – 系统结构 WINHTTP_ASYNC_RESULT 的包装器。

struct CWinHttpAutoproxyOptions – 系统结构 WINHTTP_AUTOPROXY_OPTIONS 的包装器。

struct CWinHttpCertificateInfo – 系统结构 WINHTTP_CERTIFICATE_INFO 的包装器。

struct CWinHttpCurrentUserIEProxyConfig – 系统结构 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG 的包装器。

class CWinHttpError – WinHttpGateway 模块中使用的异常类。

class CWinHttpGatewayApp - 模块实现类。

class CWinHttpLauncher - 用于在以下模式下读取数据的实现:一个线程一个请求。IWinHttpLauncher 接口的内部实现。

class CWinHttpLauncherStub – (面向程序员 - WinHttpGateway 模块的用户)IWinHttpLauncher 接口的包装器。该类旨在简化客户端代码与 WinHttpGateway 模块的操作。

class CWinHttpLog – WinHttpGateway 模块的日志文件实现。

struct CWinHttpProxyInfo – 系统结构 WINHTTP_PROXY_INFO 的包装器。

struct CWinHttpRequest – 一个请求的实现。

struct CXSLTFile – 用于支持 xslt 文件池以优化转换的类。

class CXSLTProcessor – 数据处理器。实现 xslt 转换。

template class IniAccessorBase – 用于实现用作选项的数据特性的模板类。

template class IniAccessorMassAction – 用于将选项数据保存到 ini 文件中的机制(策略)的模板实现。

interface IWinHttpLauncher – 与 WinHttpGateway 模块进行调用的接口

interface IWinHttpRequest – 操作单个请求的接口。

template class NullAccessorAction – 用于数据(不保存/加载任何内容)的 null 保存机制(策略)的模板实现。

库功能审查

接口类 IWinHttpLauncher

class CWinHttpLauncher – 是 IWinHttpLauncher 接口的内部实现,通过它提供了 WinHttpGateway 库的功能。该类存储了一组选项,用于支持 WinHttp API 的配置。对 CWinHttp 类的引用,该类直接实现 WinHttp API 的操作(实现了异步调用机制)。还存储了证书列表,即 CCertificates 类的变量,该变量用于存储和表示系统中用于支持 WinHttpGateway 模块中证书操作的证书数据。

在初始化阶段,创建了一个 CWinHttp 类的对象,该对象随后用于组织请求。

该类主要工作发生在 request() 函数中。它包含一个 CWinHttpRequest 类的对象,该对象被初始化,传递给 CWinHttp 类,并简单地等待该请求的结束(行:request.waitEOR();)。

选项设置通过 set_options() 函数进行,该函数仅设置存储选项列表的内部变量的值。(错误通过 SetLastError() 返回,可以通过调用 GetLastError() 函数获得,如果 set_options() 返回 FALSE)。

WinHttp API 操作的核心类

class CWinHttp - 是该库功能的基础。它将组织异步请求处理:回调函数的安装、回调支持、数据传输、等待数据传输的可能性、保存/累积通过调用接收到的数据。此外,还支持处理一些错误,这些错误可以由该模块自动处理,并且只有在无法自动处理这些错误时才通知 WinHttpGateway 模块的用户。

由于操作是异步进行的,所以该类几乎所有的工作都包含在回调函数 CWinHttp::WinHttpStatusCallback() 的操作中,该函数调用启动了 WinHttpGateway 模块在处理 HTTP/HTTPS 请求方面的所有操作。我们将考虑来自 WinHttp API 的消息以及处理这些消息的函数。


WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER
WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER
WINHTTP_CALLBACK_STATUS_NAME_RESOLVED
WINHTTP_CALLBACK_STATUS_REDIRECT
WINHTTP_CALLBACK_STATUS_RESOLVING_NAME

CWinHttp::RequestStatus() 函数处理,该函数简单地将状态信息传递给请求类 CWinHttpRequest


WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED
WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE
WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED
WINHTTP_CALLBACK_STATUS_SENDING_REQUEST
WINHTTP_CALLBACK_STATUS_HANDLE_CREATED

– 未处理。


WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE

CWinHttp::RequestDataAvailable() 函数处理。该消息在有数据可接收或通知不再有数据可用时出现。如果所有数据都已传输(大小 == 0),则请求将被关闭并结束处理。如果大小大于零,则会创建一个缓冲区,并调用 WinHttp API 中的函数来查询请求数据。


WINHTTP_CALLBACK_STATUS_HEADERS_AVAILAB

CWinHttp::RequestHeadersAvalable() 函数处理。该函数支持身份验证的可能性:来自网站和来自代理服务器,如果代理服务器或网站请求此类操作。

如果不需要身份验证,则直接请求传入数据的头部。然后请求读取此请求所需的数据大小。

WinHttpGateway 模块可以处理的“错误”(即请求证书和需要重复发送请求 ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDEDERROR_WINHTTP_RESEND_REQUEST)也得到额外处理。


WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE

CWinHttp::RequestIntermediateResponse() 函数处理,该函数不做其他事情。


WINHTTP_CALLBACK_STATUS_READ_COMPLETE

CWinHttp::RequestReadComplete() 函数处理。该函数将缓冲区从“读取数据”状态转到“数据已读取”状态,并查询新的数据块。


WINHTTP_CALLBACK_STATUS_REQUEST_ERROR

CWinHttp::RequestError() 处理。该函数处理 WinHttpGateway 模块可以处理的错误,或形成错误消息并将其传输到表示请求数据的 CWinHttpRequest 类对象。


WINHTTP_CALLBACK_STATUS_SECURE_FAILURE

CWinHttp::RequestSecureFailure() 函数处理。该函数安装忽略某些证书操作错误。


WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE

CWinHttp::RequestSendCompleted() 函数处理。当发送的查询包含多个部分时,此消息出现,并且该函数强制传输连续的数据块。如果所有数据都已发送,则开始数据接收。


WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE

CWinHttp::RequestWriteCompleted() 函数处理,该函数几乎是 CWinHttp::RequestSendCompleted() 函数的精确副本,具有相同的功能。


其他函数。

CWinHttp::create() – 根据 CWinHttpRequest 类对象的指针创建请求,该对象作为该函数的参数传递。在此函数中,对请求的 URL 进行分析,打开请求并发送它。

CWinHttp::Send() – 发送请求。如何分派请求(根据错误信息和/或来自 WinHttp API 的消息),该函数安装指定的身份验证然后分派请求(也包括重复分派)。

CWinHttp::set_Certificate() – 组织为某些请求安装证书的操作。

CWinHttp::add_request()CWinHttp::find_request()CWinHttp::remove_request() – 支持函数:将请求添加到内部请求列表,根据其描述符搜索所需请求,以及删除请求(终止与请求的操作)。

void CWinHttp::free() – 停止 CWinHttp 类对象运行的函数。

注意:可以使用/必须在 CWinHttp::RequestSecureFailure() 中自定义与证书操作相关的安全级别。

请求类

struct CWinHttpRequest – 提供请求的类。该类实现了 IWinHttpRequest 接口,该接口在 CWinHttp 类中用于操作请求。该类用于在将请求传输到 CWinHttp 类之前进行请求配置,以及进一步按需获取数据。

注意:目前未实现此类的任何同步机制。

其他类。

template class CPool – 用于组织池的模板类。池对象的类必须继承自 template struct Construct 类,该类对池数据项施加了特定约定。

 

© . All rights reserved.