【发布时间】:2015-02-24 20:55:30
【问题描述】:
我最近一直在开发一个需要与服务器建立 FTP 连接并从中下载/上传文件的应用程序。出于性能原因,我想一次下载多个文件。出于这个原因,我尝试使用InternetOpen 函数和INTERNET_FLAG_ASYNC 标志以及InternetSetStatusCallback 函数在Wininet API 上实现异步操作。这是我的代码示例,我想在其中递归地列出远程服务器主目录中的所有文件:
/*Global variables*/
HANDLE MayContinue=0;
DWORD LatestResult=1;
/*Prototypes*/
void CALLBACK CallbackFunction(HINTERNET,DWORD_PTR,DWORD,LPVOID,DWORD);
//Iteration function called by main()
void FTPIterate()
{
WIN32_FIND_DATAA data;
HINTERNET Internet;
INTERNET_STATUS_CALLBACK call;
HINTERNET h_file;
MayContinue = ::CreateEvent (NULL, FALSE, FALSE, NULL);
iconnect=InternetOpen(NULL,INTERNET_OPEN_TYPE_PROXY,proxy_url,NULL,INTERNET_FLAG_ASYNC);
call=InternetSetStatusCallback(iconnect,(INTERNET_STATUS_CALLBACK)CallbackFunction);
while(f[FLAG_FTP_ITERATE])
{
MayContinue = ::CreateEvent(NULL,FALSE,FALSE,NULL);
InternetConnect(iconnect,ftp_url,INTERNET_DEFAULT_FTP_PORT,ftp_user,ftp_pass,INTERNET_SERVICE_FTP,NULL,LatestResult);
WaitForSingleObject (MayContinue, INFINITE);
server=(HINTERNET)LatestResult;
printf("Server handle: %i\n",(int)server);
printf("Server Error: %i\n",GetLastError());
SetLastError(0);
MayContinue = ::CreateEvent(NULL,FALSE,FALSE,NULL);
FtpFindFirstFile(server,ftp_base,&data,INTERNET_FLAG_NO_CACHE_WRITE,LatestResult);
WaitForSingleObject(MayContinue,INFINITE);
h_file=(HINTERNET)LatestResult;
//do stuff
printf("FindFirstFile handle: %i\n",(int)h_File);
while((MayContinue = ::CreateEvent(NULL,FALSE,FALSE,NULL)) && InternetFindNextFileA(h_file,&data))
{
WaitForSingleObject(MayContinue,INFINITE);
//do stuff
}
printf("FindNextFile Error: %i\n",GetLastError()); //loop is never executed
InternetCloseHandle(server);
}
}
void CALLBACK CallbackFunction(HINTERNET hInternet,DWORD_PTR dwContext,DWORD dwInternetStatus,LPVOID lpvStatusInformation,DWORD dwStatusInformationLength)
{
if (dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE)
{
LatestResult = ((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwResult;
SetEvent (MayContinue);
}
}
我的代码基于来自 Stack Overflow 的 this 帖子。当我运行它时,首先在调用InternetConnect 后出现错误,即ERROR_IO_PENDING。根据 WinAPI 参考,这意味着仍有一些操作正在执行。对WaitForSingleObject 的调用不应该防止这种情况发生吗? (实际上,InternetConnect 返回的HINTERNET 句柄似乎是有效的)。
当我调用FtpFindFirstFile 函数时,它会正确检索第一个文件,但是当我在InternetFindNextFile 函数中使用它返回的HINTERNET 句柄(这似乎是有效的)时,它会失败并出现错误INVALID_HANDLE_VALUE。
编辑:我在使用 Remy 的代码时遇到了这些错误:
Connect Handle 00CC0004
Waiting for server handle
Unable to find first file. OS Error: 6 //aren't those calls to FindFirstFile weird if InternetConnect hasn't returned yet?
Waiting for server handle
Unable to find first file. OS Error: 6
Waiting for server handle
Unable to find first file. OS Error: 6
Waiting for server handle
Unable to find first file. OS Error: 6
Waiting for server handle
Unable to find first file. OS Error: 6
Waiting for server handle
Unable to find first file. OS Error: 6
Waiting for server handle.
Unable to connect to Server. Inet Error: 12015 Waiting for server handle
谁能帮我找出错误? 提前谢谢你。
【问题讨论】:
-
"我首先在调用
InternetConnect后得到一个错误,即ERROR_IO_PENDING" - 你知道这个如何吗?您似乎没有检查InternetConnect的结果以获取成功的 HANDLE 返回值,也没有任何代码在返回句柄为 NULL 的情况下检查GetLastError()的子路径。 -
@WhozCraig 正如我在帖子中所说,为了清楚起见,我省略了错误检查。实际上,在我的源代码中,我检查了
InternetConnect返回的 HANDLE(在调用WaitForSingleObject之后),将其转换为 ìnt`(不为空),然后调用GetLastError(),它返回 @987654343 @。稍后在FtpFindFirstFile和InternetFindNextFile之后执行类似的检查。我正在编辑 sn-p 以显示它。 -
ERROR_IO_PENDING 实际上并不是一个错误。它只是意味着 I/O 操作已成功启动,但尚未完成。由于你请求异步操作,ERROR_IO_PENDING是正常的。
标签: c++ winapi asynchronous ftp wininet