HttpOpenRequest() 中的 WinInet 访问冲突
Posted
技术标签:
【中文标题】HttpOpenRequest() 中的 WinInet 访问冲突【英文标题】:WinInet Access Violation in HttpOpenRequest() 【发布时间】:2021-12-25 18:09:12 【问题描述】:我正在尝试使用 WinInet 将文件上传到 php 页面。我在其中一个功能上遇到访问冲突,但不明白为什么。我已经从示例页面构建了代码。
代码如下:
HINTERNET aInternet=InternetOpen("My-Custom-Agent/1.0",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
HINTERNET aConnect=InternetConnect(aInternet,"www.myserver.com",INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
if (aConnect)
HINTERNET aRequest=HttpOpenRequest(aConnect, (const char*)"POST","myphppage.php", NULL, NULL, (const char**)"*/*\0",0,1);
// ^^
// Exception happens on this line
// Exception thrown at 0x70C85B7C (ininet.dll) in TestApp.exe:
// 0xC00000005: Access violation reading location 0x002A2F2A
//
当我使用InternetOpenURL()
从服务器下载时,一切似乎都很好。它只是不喜欢我在这里某处所做的事情。任何线索我做错了什么?
【问题讨论】:
与您的问题无关,但在 C++ 中,所有文字字符串实际上都是常量字符数组,它衰减为指向常量字符的指针(即const char*
)。换句话说,不需要(const char*)"POST"
中的演员表。事实上,每当你觉得需要进行这样的 C 风格转换时,你应该把它当作你做错了什么的标志。
回到错误的 C 样式转换,字符串 "*/*\0"
将衰减为 const char*
类型的指针。绝对不可能将其用作指向指针的指针(您尝试使用强制转换为const char**
)。而且很可能是坠机的原因。如果您删除演员表,编译器应该(正确地)抱怨。抛开这些抱怨不是一个好主意。
某个程序员老兄,这就是答案。但雷米(下)也给出了一个可行的答案,但没有具体说明。既然你先回答了,如果你想在下面给出答案,我会给你功劳。
@KiraHoneybee 我的回答怎么没有提供细节?
读取位置 0x002A2F2A - 这是"*/*"
的二进制值。字符串数据解释为指针。错误已经给你强烈的提示
【参考方案1】:
根据HttpOpenRequest()
documentation:
[in] lplpszAcceptTypes
指向以空结尾的字符串数组的指针,指示客户端接受的媒体类型。这是一个例子。
PCTSTR rgpszAcceptTypes[] = _T("text/*"), NULL;
未能正确终止使用 NULL 指针的数组将导致崩溃。
您正在传递一个指向单个以 null 结尾的字符串的指针,错误地类型转换为 const char**
:
lplpszAcceptTypes -> "*/*"
但该函数需要一个指向 数组 的指针,该数组包含指向以 null 结尾的字符串的指针,其中数组中的最后一个元素必须为 NULL 才能终止数组(因为没有指定函数参数数组中的元素个数):
-----
lplpszAcceptTypes -> | 0 | -> "*/*"
|---|
| 1 | -> NULL
-----
看到区别了吗?
该函数将您的字符串文字的 content 误解为好像它是一个指针,但事实并非如此,因此导致 AV 崩溃。发生 AV 的地址 0x002A2F2A
与字符串文字内容的字节数完全相同 ("*/*“
= 0x2A 0x2F 0x2A 0x00
)。
你需要改用这个:
LPCSTR rgpszAcceptTypes[] = "*/*", NULL;
HINTERNET aRequest = HttpOpenRequest(aConnect, "POST", "myphppage.php", NULL, NULL, rgpszAcceptTypes, 0, 1);
【讨论】:
嗨,我的字符串中的“\0”扩展为空(通过检查字节确认)。这是另一个问题 - 如果不使用调试器,它可以正常工作。 @KiraHoneybee 字符串文字具有由编译器添加的隐式'\0'
,因此您无需添加自己的。字符串文字"*/*"
是数组'*', '/', '*', '\0'
。通过手动添加'\0'
,您只是将数组扩展到'*', '/', '*', '\0', '\0'
,这对函数处理数据的方式没有任何影响。影响它的是内存中字符串数据的布局,而你最初传入的是完全错误的布局,因此崩溃以上是关于HttpOpenRequest() 中的 WinInet 访问冲突的主要内容,如果未能解决你的问题,请参考以下文章
您可以传递给 Wininet 函数 HttpOpenRequest 的最大 URL 长度是多少?
HttpOpenRequest () Wininet c++ e PHP