Discussion:
WinInet API + "POST" request - how to make upload progress bar?
(too old to reply)
chox.nox
2007-08-07 10:31:22 UTC
Permalink
Hi,

I'm using WinInet APIs in async mode to upload files to server using
HTTP protocol and "POST" request. As a matter of fact, I'm trying to
simulate HTML form (multipart data) submit button.

I can successfully send file, but I have problem with making progress
bar while uploading.
Here is code I'm using for sending:

Code:
------------------------------------------------------------------------------------------------------
while (dwReadLength != 0)
{
DWORD dwBytesSent = 0;
dwReadLength = fileLocal.Read(pBuffer, dwChunkLength);
if (dwReadLength != 0)
{
if (!InternetWriteFile(hInternetFile, pBuffer, dwReadLength,
&dwBytesWritten))
{
if (::GetLastError() != ERROR_IO_PENDING)
{

strError.Format("CFileHostingHttpUpload::UploadFile::InternetWriteFile(2)
= %d", ::GetLastError());
return FALSE;
}
WaitForSingleObject(hAsyncOp, INFINITE);
}
dwTotalRead+=dwBytesWritten;
pbUpload->SetPos(((double)dwTotalRead/
dwTotalRequestLength)*100);
}
}
------------------------------------------------------------------------------------------------------

The problem is that my progress bar gets fully "progressed" in about
1-2 seconds, but file uploading is far slower (25kb/s upload speed).
When I track transfer with net sniffer tool I can see that it takes
about 10 seconds to upload 256 kb file, but progress bar gets fill
almost instantly. I've tried about 6-7 different upload "loops" but
all of them are giving almost same result.

InternetStatusCallback gives me this:
------------------------------------------------------------------------------------------------------
11:49:19 - Connected to server.
11:49:19 - Sending request ...
11:49:19 - Request sent: 186 bytes
11:49:19 - Request complete.
11:49:19 - Sending request ...
11:49:19 - Request sent: 86 bytes
11:49:19 - Sending request ...
11:49:19 - Request sent: 4096 bytes
...
... (a lot of same status until the end of upload, no need to paste
them all :))
...
11:49:19 - Sending request ...
11:49:19 - Request sent: 4096 bytes
11:49:19 - Sending request ...
11:49:19 - Request sent: 4096 bytes
11:49:19 - Request complete.
11:49:19 - Sending request ...
11:49:19 - Request sent: 802 bytes
11:49:19 - Sending request ...
11:49:19 - Request sent: 16 bytes
11:49:19 - Receiving response ...
11:49:29 - Response received: 1024 bytes
11:49:29 -
11:49:29 - Request complete.
------------------------------------------------------------------------------------------------------

Does anybody have any kind of solution?

Best Regards and have a nice day!
Paul Baker [MVP, Windows - SDK]
2007-08-07 13:54:53 UTC
Permalink
What's hAsyncOp? It's not declared in this code segment and it's not used
except in a call to WaitForSingleObject.

So, it is not clear that you're waiting for the pending asynchronous
operation before starting another one.

Paul
Post by chox.nox
Hi,
I'm using WinInet APIs in async mode to upload files to server using
HTTP protocol and "POST" request. As a matter of fact, I'm trying to
simulate HTML form (multipart data) submit button.
I can successfully send file, but I have problem with making progress
bar while uploading.
------------------------------------------------------------------------------------------------------
while (dwReadLength != 0)
{
DWORD dwBytesSent = 0;
dwReadLength = fileLocal.Read(pBuffer, dwChunkLength);
if (dwReadLength != 0)
{
if (!InternetWriteFile(hInternetFile, pBuffer, dwReadLength,
&dwBytesWritten))
{
if (::GetLastError() != ERROR_IO_PENDING)
{
strError.Format("CFileHostingHttpUpload::UploadFile::InternetWriteFile(2)
= %d", ::GetLastError());
return FALSE;
}
WaitForSingleObject(hAsyncOp, INFINITE);
}
dwTotalRead+=dwBytesWritten;
pbUpload->SetPos(((double)dwTotalRead/
dwTotalRequestLength)*100);
}
}
------------------------------------------------------------------------------------------------------
The problem is that my progress bar gets fully "progressed" in about
1-2 seconds, but file uploading is far slower (25kb/s upload speed).
When I track transfer with net sniffer tool I can see that it takes
about 10 seconds to upload 256 kb file, but progress bar gets fill
almost instantly. I've tried about 6-7 different upload "loops" but
all of them are giving almost same result.
------------------------------------------------------------------------------------------------------
11:49:19 - Connected to server.
11:49:19 - Sending request ...
11:49:19 - Request sent: 186 bytes
11:49:19 - Request complete.
11:49:19 - Sending request ...
11:49:19 - Request sent: 86 bytes
11:49:19 - Sending request ...
11:49:19 - Request sent: 4096 bytes
...
... (a lot of same status until the end of upload, no need to paste
them all :))
...
11:49:19 - Sending request ...
11:49:19 - Request sent: 4096 bytes
11:49:19 - Sending request ...
11:49:19 - Request sent: 4096 bytes
11:49:19 - Request complete.
11:49:19 - Sending request ...
11:49:19 - Request sent: 802 bytes
11:49:19 - Sending request ...
11:49:19 - Request sent: 16 bytes
11:49:19 - Receiving response ...
11:49:29 - Response received: 1024 bytes
11:49:29 -
11:49:29 - Request complete.
------------------------------------------------------------------------------------------------------
Does anybody have any kind of solution?
Best Regards and have a nice day!
chox.nox
2007-08-11 12:16:02 UTC
Permalink
On Aug 7, 3:54 pm, "Paul Baker [MVP, Windows - SDK]"
Post by Paul Baker [MVP, Windows - SDK]
What's hAsyncOp? It's not declared in this code segment and it's not used
except in a call to WaitForSingleObject.
So, it is not clear that you're waiting for the pending asynchronous
operation before starting another one.
Paul
Hi,

hAsyncOp is type of HANDLE and is used for waiting on async operation
which get signalled in InternetStatusCallback proc. Here it goes:

HANDLE hAsyncOp;
HINTERNET hTempHandle;
CProgressCtrl *pbProgressBar;
double dblTotalRead, dblTotalFileSize;

(pbProgressBar is progress bar control for percent of file sent to
server, hTempHandle is used for newly created HINTERNET handle,
hAsyncOp for signalling, dblTotalFileSize is used to determine total
bytes to send to server and dblTotalRead is used for determining total
bytes sent to server)

.......

VOID CALLBACK CTestUpload::InternetStatusCallback(IN HINTERNET
hInternet, IN DWORD dwContext, IN DWORD dwInternetStatus,
IN LPVOID lpvStatusInformation, IN DWORD
dwStatusInformationLength)
{
CString sStatus;
DWORD nBytes = -1;

AFX_MANAGE_STATE(AfxGetStaticModuleState( ));

if (dwInternetStatus == INTERNET_STATUS_REQUEST_SENT ||
dwInternetStatus == INTERNET_STATUS_RESPONSE_RECEIVED)
nBytes = *(DWORD*)lpvStatusInformation;

switch (dwInternetStatus)
{
case INTERNET_STATUS_RESOLVING_NAME: sStatus.Format("Resolving
name ... %s", lpvStatusInformation); break;
case INTERNET_STATUS_NAME_RESOLVED: sStatus.Format("Name
resolved: %s", lpvStatusInformation);
case INTERNET_STATUS_CONNECTING_TO_SERVER:
sStatus.Format("Connecting to server ..."); break;
case INTERNET_STATUS_CONNECTED_TO_SERVER: sStatus.Format("Connected
to server."); break;
case INTERNET_STATUS_SENDING_REQUEST: sStatus.Format("Sending
request ..."); break;
case INTERNET_STATUS_REQUEST_SENT: sStatus.Format("Request
sent: %d bytes", nBytes); break;
case INTERNET_STATUS_RECEIVING_RESPONSE: sStatus.Format("Receiving
response ..."); break;
case INTERNET_STATUS_RESPONSE_RECEIVED: sStatus.Format("Response
received: %d bytes", nBytes); break;
case INTERNET_STATUS_CLOSING_CONNECTION: sStatus.Format("Closing
connection ..."); break;
case INTERNET_STATUS_CONNECTION_CLOSED:
sStatus.Format("Connection closed."); break;
case INTERNET_STATUS_HANDLE_CREATED: sStatus.Format("Handle
created."); break;
case INTERNET_STATUS_HANDLE_CLOSING: sStatus.Format("Handle
closing ..."); break;
case INTERNET_STATUS_REQUEST_COMPLETE: sStatus.Format("Request
complete."); break;
}

if (dwInternetStatus == INTERNET_STATUS_HANDLE_CREATED)
{
INTERNET_ASYNC_RESULT *w =
(INTERNET_ASYNC_RESULT*)lpvStatusInformation;

hTempHandle = (HINTERNET)w->dwResult;
}
if (dwInternetStatus == INTERNET_STATUS_REQUEST_SENT)
{
dblTotalRead+=nBytes;

if (pbProgressBar != NULL)
{
int iPercent = (dblTotalRead / dblTotalFileSize) * 100;

pbProgressBar->SetPos(iPercent);
}
}
if (dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE)
{
INTERNET_ASYNC_RESULT *w =
(INTERNET_ASYNC_RESULT*)lpvStatusInformation;

SetEvent(hAsyncOp);
}
}


Hope this helps.

Best Regards!
Paul Baker [MVP, Windows - SDK]
2007-08-13 13:39:39 UTC
Permalink
Hi,

Again, it is not clear as you have not posted all your code. It would seem
that there is a lot of code involved here. I would suggest that you come up
with a simple stand-alone test case.

Are you sure that:
- The event is created in a nonsignaled state?
- That the callback is being called?
- That the event is being reset with each call?

Paul
Post by chox.nox
On Aug 7, 3:54 pm, "Paul Baker [MVP, Windows - SDK]"
Post by Paul Baker [MVP, Windows - SDK]
What's hAsyncOp? It's not declared in this code segment and it's not used
except in a call to WaitForSingleObject.
So, it is not clear that you're waiting for the pending asynchronous
operation before starting another one.
Paul
Hi,
hAsyncOp is type of HANDLE and is used for waiting on async operation
HANDLE hAsyncOp;
HINTERNET hTempHandle;
CProgressCtrl *pbProgressBar;
double dblTotalRead, dblTotalFileSize;
(pbProgressBar is progress bar control for percent of file sent to
server, hTempHandle is used for newly created HINTERNET handle,
hAsyncOp for signalling, dblTotalFileSize is used to determine total
bytes to send to server and dblTotalRead is used for determining total
bytes sent to server)
.......
VOID CALLBACK CTestUpload::InternetStatusCallback(IN HINTERNET
hInternet, IN DWORD dwContext, IN DWORD dwInternetStatus,
IN LPVOID lpvStatusInformation, IN DWORD
dwStatusInformationLength)
{
CString sStatus;
DWORD nBytes = -1;
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
if (dwInternetStatus == INTERNET_STATUS_REQUEST_SENT ||
dwInternetStatus == INTERNET_STATUS_RESPONSE_RECEIVED)
nBytes = *(DWORD*)lpvStatusInformation;
switch (dwInternetStatus)
{
case INTERNET_STATUS_RESOLVING_NAME: sStatus.Format("Resolving
name ... %s", lpvStatusInformation); break;
case INTERNET_STATUS_NAME_RESOLVED: sStatus.Format("Name
resolved: %s", lpvStatusInformation);
sStatus.Format("Connecting to server ..."); break;
case INTERNET_STATUS_CONNECTED_TO_SERVER: sStatus.Format("Connected
to server."); break;
case INTERNET_STATUS_SENDING_REQUEST: sStatus.Format("Sending
request ..."); break;
case INTERNET_STATUS_REQUEST_SENT: sStatus.Format("Request
sent: %d bytes", nBytes); break;
case INTERNET_STATUS_RECEIVING_RESPONSE: sStatus.Format("Receiving
response ..."); break;
case INTERNET_STATUS_RESPONSE_RECEIVED: sStatus.Format("Response
received: %d bytes", nBytes); break;
case INTERNET_STATUS_CLOSING_CONNECTION: sStatus.Format("Closing
connection ..."); break;
sStatus.Format("Connection closed."); break;
case INTERNET_STATUS_HANDLE_CREATED: sStatus.Format("Handle
created."); break;
case INTERNET_STATUS_HANDLE_CLOSING: sStatus.Format("Handle
closing ..."); break;
case INTERNET_STATUS_REQUEST_COMPLETE: sStatus.Format("Request
complete."); break;
}
if (dwInternetStatus == INTERNET_STATUS_HANDLE_CREATED)
{
INTERNET_ASYNC_RESULT *w =
(INTERNET_ASYNC_RESULT*)lpvStatusInformation;
hTempHandle = (HINTERNET)w->dwResult;
}
if (dwInternetStatus == INTERNET_STATUS_REQUEST_SENT)
{
dblTotalRead+=nBytes;
if (pbProgressBar != NULL)
{
int iPercent = (dblTotalRead / dblTotalFileSize) * 100;
pbProgressBar->SetPos(iPercent);
}
}
if (dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE)
{
INTERNET_ASYNC_RESULT *w =
(INTERNET_ASYNC_RESULT*)lpvStatusInformation;
SetEvent(hAsyncOp);
}
}
Hope this helps.
Best Regards!
Loading...