WinHttp Delphi 包装器
Posted
技术标签:
【中文标题】WinHttp Delphi 包装器【英文标题】:WinHttp Delphi wrapper 【发布时间】:2011-10-07 05:01:23 【问题描述】:请告知 Delphi XE 中是否有 WinHTTP 包装器
按优先顺序:
-
开箱即用的 Delphi 单元
带有移植入口例程的第三方开源 pas 文件
xxx_TLB.pas 包装器
解决方案:
由于 cmets 不允许格式化代码,我将解决方案粘贴到问题中:
const
winhttpdll = 'winhttp.dll';
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY = 0;
WINHTTP_FLAG_REFRESH = $00000100;
WINHTTP_FLAG_SECURE = $00800000;
WINHTTP_ADDREQ_FLAG_COALESCE = $40000000;
WINHTTP_QUERY_FLAG_NUMBER = $20000000;
function WinHttpOpen(pwszUserAgent: PWideChar; dwAccessType: DWORD;
pwszProxyName, pwszProxyBypass: PWideChar; dwFlags: DWORD): HINTERNET; stdcall; external winhttpdll;
function WinHttpConnect(hSession: HINTERNET; pswzServerName: PWideChar;
nServerPort: INTERNET_PORT; dwReserved: DWORD): HINTERNET; stdcall; external winhttpdll;
function WinHttpOpenRequest(hConnect: HINTERNET; pwszVerb: PWideChar;
pwszObjectName: PWideChar; pwszVersion: PWideChar; pwszReferer: PWideChar;
ppwszAcceptTypes: PLPWSTR; dwFlags: DWORD): HINTERNET; stdcall; external winhttpdll;
function WinHttpCloseHandle(hInternet: HINTERNET): BOOL; stdcall; external winhttpdll;
function WinHttpAddRequestHeaders(hRequest: HINTERNET; pwszHeaders: PWideChar; dwHeadersLength: DWORD;
dwModifiers: DWORD): BOOL; stdcall; external winhttpdll;
function WinHttpSendRequest(hRequest: HINTERNET; pwszHeaders: PWideChar;
dwHeadersLength: DWORD; lpOptional: Pointer; dwOptionalLength: DWORD; dwTotalLength: DWORD;
dwContext: DWORD): BOOL; stdcall; external winhttpdll;
function WinHttpReceiveResponse(hRequest: HINTERNET;
lpReserved: Pointer): BOOL; stdcall; external winhttpdll;
function WinHttpQueryHeaders(hRequest: HINTERNET; dwInfoLevel: DWORD; pwszName: PWideChar;
lpBuffer: Pointer; var lpdwBufferLength, lpdwIndex: DWORD): BOOL; stdcall; external winhttpdll;
function WinHttpReadData(hRequest: HINTERNET; lpBuffer: Pointer;
dwNumberOfBytesToRead: DWORD; var lpdwNumberOfBytesRead: DWORD): BOOL; stdcall; external winhttpdll;
function WinHttpQueryDataAvailable(hRequest: HINTERNET; var lpdwNumberOfBytesAvailable: DWORD): BOOL;
stdcall; external winhttpdll;
function WinHttpSetOption(hInternet: HINTERNET; dwOption: DWORD; lpBuffer: Pointer; dwBufferLength: DWORD): BOOL;
stdcall; external winhttpdll;
function WinHttpQueryOption(hInternet: HINTERNET; dwOption: DWORD; var lpBuffer: Pointer; var lpdwBufferLength: DWORD): BOOL;
stdcall; external winhttpdll;
function WinHttpWriteData(hRequest: HINTERNET; lpBuffer: Pointer; dwNumberOfBytesToWrite: DWORD;
var lpdwNumberOfBytesWritten: DWORD): BOOL; stdcall; external winhttpdll;
function WinHttpCheckPlatform(): BOOL; stdcall; external winhttpdll;
还有几个缺失的:
WinHttpCrackUrl
WinHttpCreateUrl
WinHttpSetStatusCallback
WinHttpTimeFromSystemTime
WinHttpTimeToSystemTime
【问题讨论】:
第三个不是Delphi会在你导入类型库的时候自动为你创建的吗? 我还发现了有用的tek-tips.com/faqs.cfm?fid=7493 请在answer部分发布解决方案,而不是问题。 你对缺失的函数做了什么?是不是不能导入? 【参考方案1】: 项目 导入类型库 Microsoft WinHTTP 服务,版本 5.1(版本 5.1)C:\Windows\system32\winhttp.dll
然后使用它:
var
http: IWinHttpRequest;
szUrl: WideString;
begin
szUrl := 'http://***.com/questions/6725348/winhttp-delphi-wrapper';
http := CoWinHttpRequest.Create;
http.open('GET', szUrl, False);
http.send(EmptyParam);
if (http.status = 200) then
ShowMessage(http.responseText);
所以:
它是开箱即用的 - 使用开箱即用的工具 它是开源的 - 您可以随意修改源代码 这是 TLB【讨论】:
... 并且使用 COM Wrapper 而不是 C WinHTTP 库会产生一些不必要的开销。 COM 可能是多线程服务中的噩梦。我宁愿在 Delphi 软件中调用 C API。 COM 接口已经改变(例如 5.0 已被弃用),所以您将来可能会遇到问题... 5.0 在 10 多年前被取代;这是5.1,一直很稳定。进程内 COM 对象的调用方法没有开销——它与在 Delphi 中调用对象的方法一样快。如果您不喜欢通过虚拟方法表调用函数的性能损失,那么您也不会使用 Delphi。 开销当然不在 asmcall
本身,而是在 COM 实例创建和完成(例如处理 Vista/Seven 中增强的安全性)和参数转换(OleStr/WideString 做有成本)。而且您必须在每个线程中调用 CoInitialize,这在多线程服务中可能会很棘手。如果您有一个直接的类 C 包装器,它将比 COM 版本更快,后者旨在用于 Visual Basic 和脚本。
旋转 100,000 个线程我以 2.89µs 的速度对 CoInitialize
和 CoWinHttpRequest.Create
进行基准测试(0.092µs 初始化单元,2.79µs 构建 WinHttp
对象)。 Delphi 中的字符串已经是 Wide(至少是作者正在谈论的 Delphi 版本)。但是,如果您将 AnsiString
到 WideString
的 100,000 次转换相加,那么每个字符串又需要 0.246µs。我不确定你从哪里得到 3.5µs 是一个巨大的负担的想法;足以证明不使用已经存在了十多年的标准、经过充分测试、支持、强化的辅助对象。
Delphi 2009+ 中的字符串是 Unicode 编码的,但仍然存在从 UnicodeString
到 WideString
的转换。重要的不是 Unicode 转换,而是 WideString
分配:BSTR 不使用 FastMM4,但要慢得多 SysAllocStringLen
WinAPI 调用。在 Vista/7 下它比在 XP 下快,但它仍然比 Delphi string
慢。当然,在检索 HTTP 内容时并不重要!所以我同意你的观点,COM 在这里不是速度瓶颈,即使当我有一个普通的 C API 可用时我总是不喜欢使用 COM 接口。【参考方案2】:
如果您想在您的应用程序中实现 HTTP 客户端访问,您可以考虑以下几种选择:
使用提供的 Indy 组件; 使用第三方组件,例如 Synapse、ICS 或您自己的基于 WinSock 的包装器; 使用 WinINet; 使用 WinHTTP。对于our ORM,对于它的 HTTP/1.1 连接层,我们尽量避免外部依赖,并且不需要所有 Indy 的特性和开销。
我们首先编写了自己的 WinSock 包装器,然后试用了 WinInet。在我们的测试基准中使用时,我们发现 WinINet 非常缓慢。
然后我们尝试了微软提供的新 API WinHTTP,我们发现它的速度非常快。与直接 WinSock 访问一样快,无需编写所有包装代码。
这是我们的 OpenSource WinHTTP 包装器,位于 unit named SynCrtSock 中。测试从 Delphi 5 到 XE。
您会看到我们为 WinINet 和 WinHTTP 使用了相同的泛型类。事实上,这两个库非常接近。
见this article for details。有一个关于自动代理检索的说明。
编辑: 使用即将推出的 Delphi XE2,您将能够交叉编译到 Mac OS X。在这种情况下,使用“抽象”类非常有意义,例如 @ 987654325@。在 Windows 下,它将使用 WinHTTP,但在 Mac OS X 下,它将调用套接字 API。要使您的代码编译,您只需调整类类型,而不是您的代码。
【讨论】:
正是您的博文让我想到了迁移到 WinHttp。我在您的 SynCrtSock 单元中找到了我需要的东西: 而且某些版本的 WinInet 有一个可怕的超时错误!不能信任 WinInet 可以在您的所有客户端 PC 上运行,除非您希望有 30-60 秒的冻结,否则请不要使用它,这只能通过让您的用户升级他们安装的 Internet Explorer 版本来解决。 @Warren P. Microsoft 确实建议人们使用IServerWinHttpRequest
。这是一个更稳定、更安全的重写版本,具有更多用于控制代理设置和超时的功能。 (这就是为什么它被称为 server - 它更稳定,这是您在服务器上运行时想要的)
@Ian 这是什么IServerWinHttpRequest
?没有关于它的谷歌资源......从“服务器”这个词来看,这可能是因为 WinHTTP 可以在服务或服务器端使用,而 WinINet 是为客户端设计的。
@Arnaud Bouchez:对不起,我的意思是IServerXMLHTTPRequest
(msdn.microsoft.com/en-us/library/ms762278(v=VS.85).aspx)(而不是IXMLHTTPRequest
)。您可以使用 IXMLHttpRequest
获取常规 html 内容。 IXMLHttpRequest
建立在 WinInet API 之上。 “然而,与XMLHTTP
不同,ServerXMLHTTP
对象不依赖 WinInet 控件来对远程 XML 文档进行 HTTP 访问。ServerXMLHTTP
使用新的 HTTP 客户端堆栈。设计用于服务器应用程序,WinInet 的这个服务器安全子集提供以下优点: ..."以上是关于WinHttp Delphi 包装器的主要内容,如果未能解决你的问题,请参考以下文章
wininet 或 winhttp,这是 POST 请求的首选