的ERROR_IO_PENDING
误差从InternetOpen()
本身到来。由于WaitForSingleObject()
成功,因此它不会覆盖GetLastError()
(因为大多数API都会出错,所以错误会从InternetOpen()
的结果继续进行)。这是不是正确的使用方法GetLastError()
。假设所有的API覆盖GetLastError()
(如果记录使用GetLastError()
在所有),并确保你怎么称呼它立即只有当API失败(除非记录为在成功的条件下使用)。
什么你的代码做的是不异步!您正在发出异步API调用,但是您正在等待其结果,这打破了目的。您的代码是同步作用,一样的,如果你省略INTERNAL_FLAG_ASYNC
标志和WaitForSingleObject()
电话(别说你是通过调用CreateEvent()
不必要的泄漏事件资源),例如:
void LogError(const char *Op)
{
DWORD err = GetLastError();
if (err == ERROR_INTERNET_EXTENDED_ERROR)
{
LPSTR szBuffer;
DWORD dwLength = 0;
InternetGetLastResponseInfoA(&err, NULL, &dwLength);
if (GetLastError() != INSUFFICIENT_BUFFER)
{
printf("%s. Unknown Inet Error. OS Error: %u", Op, GetLastError());
return;
}
szBuffer = new char[dwLength+1];
InternetGetLastResponseInfoA(&err, szBuffer, &dwLength);
szBuffer[dwLength] = 0;
printf("%s. Inet Error: %u %s", Op, err, szBuffer);
delete[] szBuffer;
}
else
{
LPSTR lpBuffer = NULL;
DWORD dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, (LPSTR)&lpBuffer, 0, NULL);
if (lpBuffer)
{
printf("%s. OS Error: %u %s", Op, err, lpBuffer);
LocalFree(lpBuffer);
}
else
printf("%s. OS Error: %u", Op, err);
}
printf("\n");
}
void FTPIterate()
{
WIN32_FIND_DATAA data;
HINTERNET hConnect;
HINTERNET hServer;
HINTERNET hFile;
hConnect = InternetOpen(NULL, INTERNET_OPEN_TYPE_PROXY, proxy_url, NULL, 0);
if (hConnect == NULL)
{
LogError("Unable to Open Internet");
return;
}
printf("Connect handle: %p\n", hConnect);
while (f[FLAG_FTP_ITERATE])
{
printf("Connecting to Server\n");
hServer = InternetConnect(hConnect, ftp_url, INTERNET_DEFAULT_FTP_PORT, ftp_user, ftp_pass, INTERNET_SERVICE_FTP, NULL, 0);
if (hServer == NULL)
{
LogError("Unable to connect to Server");
continue;
}
printf("Connected to Server. Server handle: %p\n", hServer);
printf("Finding first file\n");
hFile = FtpFindFirstFileA(hServer, ftp_base, &data, INTERNET_FLAG_NO_CACHE_WRITE, 0);
if (hFile == NULL)
{
if (GetLastError() == ERROR_NO_MORE_FILES)
printf("No files were found\n");
else
LogError("Unable to find first file");
}
else
{
printf("Find handle: %p\n", hFile);
do
{
//do stuff
printf("Finding next file\n");
if (!InternetFindNextFileA(hFile, &data))
{
if (GetLastError() == ERROR_NO_MORE_FILES)
printf("No more files were found\n");
else
LogError("Unable to find next file")
break;
}
}
while (true);
InternetCloseHandle(hFile);
}
InternetCloseHandle(hServer);
}
InternetCloseHandle(hConnect);
}
为了使该代码运行异步,摆脱所有的关闭等待和实施需要回调的进步状态机,如:
enum FTPState {ftpConnect, ftpWaitingForConnect, ftpFindFirstFile, ftpWaitingForFirstFind, ftpFindNextFile, ftpWaitingForNextFind, ftpProcessFile, ftpDisconnect};
struct REQ_CONTEXT
{
FTPState State;
WIN32_FIND_DATAA data;
HINTERNET hConnect;
HINTERNET hServer;
HINTERNET hFile;
HANDLE hDoneEvent;
};
void LogError(const char *Op, DWORD err)
{
if (err == ERROR_INTERNET_EXTENDED_ERROR)
{
LPSTR szBuffer;
DWORD dwLength = 0;
InternetGetLastResponseInfoA(&err, NULL, &dwLength);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
printf("%s. Unknown Inet Error. OS Error: %u", Op, GetLastError());
return;
}
szBuffer = new char[dwLength+1];
InternetGetLastResponseInfoA(&err, szBuffer, &dwLength);
szBuffer[dwLength] = 0;
printf("%s. Inet Error: %u %s", Op, err, szBuffer);
delete[] szBuffer;
}
else
{
LPSTR lpBuffer = NULL;
DWORD dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, (LPSTR)&lpBuffer, 0, NULL);
if (lpBuffer)
{
printf("%s. OS Error: %u %s", Op, err, lpBuffer);
LocalFree(lpBuffer);
}
else
printf("%s. OS Error: %u", Op, err);
}
printf("\n");
}
void LogError(const char *Op)
{
LogError(Op, GetLastError());
}
void DoNextStep(REQ_CONTEXT *ctx)
{
do
{
if ((ctx->State == ftpConnect) && (!f[FLAG_FTP_ITERATE]))
{
printf("Done!\n");
SetEvent(ctx->hDoneEvent);
return;
}
switch (ctx->State)
{
case ftpConnect:
{
printf("Connecting to Server\n");
HINTERNET hServer = InternetConnect(ctx->hConnect, ftp_url, INTERNET_DEFAULT_FTP_PORT, ftp_user, ftp_pass, INTERNET_SERVICE_FTP, NULL, (DWORD_PTR)ctx);
if (hServer != NULL)
{
if (ctx->hServer == NULL)
{
ctx->hServer = hServer;
printf("Server handle: %p\n", ctx->hServer);
}
printf("Connected to Server\n");
ctx->State = ftpFindFirstFile;
}
else if (GetLastError() == ERROR_IO_PENDING)
{
if (ctx->hServer == NULL)
printf("Waiting for Server handle\n");
printf("Waiting for Server connect to complete\n");
ctx->State = ftpWaitingForConnect;
}
else
LogError("Unable to connect to Server");
break;
}
case ftpWaitingForConnect:
return;
case ftpFindFirstFile:
{
printf("Finding first file\n");
HINTERNET hFile = FtpFindFirstFileA(ctx->hServer, ftp_base, &ctx->data, INTERNET_FLAG_NO_CACHE_WRITE, (DWORD_PTR)ctx);
if (hFile != NULL)
{
if (ctx->hFile == NULL)
{
ctx->hFile = hFile;
printf("Find handle: %p\n", ctx->hFile);
}
ctx->State = ftpProcessFile;
}
else if (GetLastError() == ERROR_IO_PENDING)
{
if (ctx->hFile == NULL)
printf("Waiting for Find handle\n");
printf("Waiting for Find to complete\n");
ctx->State = ftpWaitingForFirstFind;
}
else
{
if (GetLastError() == ERROR_NO_MORE_FILES)
printf("No files were found\n");
else
LogError("Unable to find first file");
ctx->State = ftpDisconnect;
}
break;
}
case ftpWaitingForFirstFind:
case ftpWaitingForNextFind:
return;
case ftpProcessFile:
{
//do stuff
printf("Finding next file\n");
if (!InternetFindNextFileA(ctx->hFile, &ctx->data))
{
if (GetLastError() == ERROR_IO_PENDING)
{
printf("Waiting for next file to complete\n");
ctx->State = ftpWaitingForNextFind;
}
else
{
if (GetLastError() == ERROR_NO_MORE_FILES)
printf("No more files were found\n");
else
LogError("Unable to find next file");
ctx->State = ftpDisconnect;
}
}
break;
}
case ftpDisconnect:
{
printf("Disconnecting\n");
if (ctx->hFile != NULL)
{
InternetCloseHandle(ctx->hFile);
ctx->hFile = NULL;
}
if (ctx->hServer != NULL)
{
InternetCloseHandle(ctx->hServer);
ctx->hServer = NULL;
}
ctx->State = ftpConnect;
break;
}
}
}
while (true);
}
void CALLBACK CallbackFunction(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)
{
REQ_CONTEXT *ctx = (REQ_CONTEXT*) dwContext;
switch (dwInternetStatus)
{
case INTERNET_STATUS_HANDLE_CREATED:
{
LPINTERNET_ASYNC_RESULT Result = (LPINTERNET_ASYNC_RESULT) lpvStatusInformation;
switch (ctx->State)
{
case ftpConnect:
case ftpWaitingForConnect:
ctx->hServer = (HINTERNET) Result->dwResult;
printf("Server handle: %p\n", ctx->hServer);
break;
case ftpFindFirstFile:
case ftpWaitingForFirstFind:
ctx->hFile = (HINTERNET) Result->dwResult;
printf("Find handle: %p\n", ctx->hFile);
break;
}
break;
}
case INTERNET_STATUS_REQUEST_COMPLETE:
{
LPINTERNET_ASYNC_RESULT Result = (LPINTERNET_ASYNC_RESULT) lpvStatusInformation;
switch (ctx->State)
{
case ftpWaitingForConnect:
{
if (!Result->dwResult)
{
LogError("Unable to connect to Server", Result->dwError);
ctx->State = ftpDisconnect;
}
else
{
printf("Connected to Server\n");
ctx->State = ftpFindFirstFile;
}
break;
}
case ftpWaitingForFirstFind:
case ftpWaitingForNextFind:
{
if (!Result->dwResult)
{
if (Result->dwError == ERROR_NO_MORE_FILES)
printf("No %sfiles were found\n", (ctx->State == ftpWaitingForNextFind) ? "more " : "");
else if (ctx->State == ftpWaitingForFirstFind)
LogError("Unable to find first file", Result->dwError);
else
LogError("Unable to find next file", Result->dwError);
ctx->State = ftpDisconnect;
}
else
ctx->State = ftpProcessFile;
break;
}
}
DoNextStep(ctx);
break;
}
}
}
void FTPIterate()
{
REQ_CONTEXT ctx = {0};
ctx.State = ftpConnect;
ctx.hDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (ctx.hDoneEvent == NULL)
{
LogError("Unable to Create Done Event");
return;
}
ctx.hConnect = InternetOpen(NULL, INTERNET_OPEN_TYPE_PROXY, proxy_url, NULL, INTERNET_FLAG_ASYNC);
if (ctx.hConnect == NULL)
{
LogError("Unable to Open Internet");
CloseHandle(ctx.hDoneEvent);
return;
}
printf("Connect handle: %p\n", ctx.hConnect);
InternetSetStatusCallback(ctx.hConnect, &CallbackFunction);
DoNextStep(&ctx);
WaitForSingleObject(ctx.hDoneEvent, INFINITE);
InternetCloseHandle(ctx.hConnect);
CloseHandle(ctx.hDoneEvent);
}
“我调用'InternetConnect',这是'ERROR_IO_PENDING'后,首先是得到一个错误” - 你知道这* *如何*?你似乎没有检查'InternetConnect'的结果是否有成功的HANDLE返回值,也没有任何代码在NULL返回句柄的情况下检查子路径到'GetLastError()'。 – WhozCraig 2015-02-24 21:11:26
@WhozCraig正如我在帖子中所说,错误我已经省略错误检查的清晰度。事实上,在我的源代码中,我检查了由'InternetConnect'返回的HANDLE(在调用WaitForSingleObject之后),将其转换为一个“not”(非空),然后调用GetLastError(),它返回'997'。在'FtpFindFirstFile'和'InternetFindNextFile'之后执行类似的检查。我正在编辑该片段以显示它。 – JuanGM 2015-02-24 21:17:10
ERROR_IO_PENDING实际上并不是一个错误。这仅表示I/O操作已成功启动,但尚未完成。由于您请求异步操作,因此ERROR_IO_PENDING是正常的。 – 2015-02-24 23:02:02