Sending http request repeatedly, more fast (async mode) - c++

I need to send one request to server more quickly and repeatedly.
So I implemented code like this.
BOOL CTestDlg::OnInitDialog()
{
...
m_hInstance = InternetOpen(L"asynchttp", INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,INTERNET_FLAG_ASYNC);
if(m_hInstance == NULL)
{
ErrorLog(L"InternetOpen Failed");
return TRUE;
}
if (InternetSetStatusCallback(m_hInstance,(INTERNET_STATUS_CALLBACK)&Callback) == INTERNET_INVALID_STATUS_CALLBACK)
{
ErrorLog(L"Set Callback Function Failed");
return TRUE;
}
m_hConnect = InternetConnect(m_hInstance, L"192.168.2.116", 8080,NULL,NULL,INTERNET_SERVICE_HTTP,INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_KEEP_CONNECTION,1);
if(m_hConnect == NULL)
{
if(DWORD dwError = GetLastError() != ERROR_IO_PENDING)
{
ErrorLog(L"Fail to Connect Server");
return TRUE;
}
WaitForSingleObject(hConnectedEvent, INFINITE);
}
CreateThread(0 , 0 , (LPTHREAD_START_ROUTINE)SendThread , 0 , 0 , 0);
return TRUE;
}
void __stdcall Callback(HINTERNET hInternet,DWORD dwContext,DWORD dwInternetStatus,LPVOID lpStatusInfo,DWORD dwStatusInfoLen)
{
switch(dwContext)
{
case 1:
{
SetEvent(hConnectedEvent);
}
break;
}
}
DWORD SendThread(LPVOID lpParam)
{
TCHAR *szAceptType[] = {_T("*/*") , NULL};
CString szContentType = _T("Content-Type: application/x-www-form-urlencoded\r\n");
char szPostData[MAX_PATH];
sprintf(szPostData , "num=1234&str=3240");
HINTERNET hRequest = HttpOpenRequest(m_hConnect, L"POST", L"/TestWeb/index.jsp", HTTP_VERSION , NULL , (LPCTSTR*)szAceptType , 0, 2);
while(1)
{
try
{
if (!HttpSendRequest(hRequest, szContentType, (DWORD)szContentType.GetLength(), szPostData,(DWORD)strlen(szPostData)))
{
if (DWORD dwError = GetLastError() != ERROR_IO_PENDING)
ErrorLog(L"SendRequest: Error = %d" , dwError);
}
}
catch (CException* e)
{
UNREFERENCED_PARAMETER(e);
}
Sleep(100);
}
return 0;
}
When execute or debug program, I saw this "SendRequest; Error = 1" log frequently.
And Server does not record anymore to database , after one or two request data recorded
It seems like HttpSendRequest API doesn't work correctly after error occured.
I aim to send one request to server more fast and more correctly, without loss.
Please teach me what is wrong problem.
Or if you got another best way, then please tell me.
Thanks.

Error code 1 is "Invalid Parameter".
You appear to be mixing ASCII (char and sprintf) and Unicode strings in your sample above. Have you tried with all Unicode strings (making szPostData a WCHAR array)? From MSDN: "There two versions of HttpSendRequest —HttpSendRequestA (used with ANSI builds) and HttpSendRequestW (used with Unicode builds)". It goes on to talk about when ERROR_INVALID_PARAMETER is returned. http://msdn.microsoft.com/en-us/library/windows/desktop/aa384247(v=vs.85).aspx
Also, I haven't used MFC in a long time, but I remember that you should call e->Delete() in your exception handler (unless you re-throw). The CException::Delete method will delete any thrown exception created on the heap (and do nothing otherwise).

Related

How Do I Use NotifyServiceStatusChange to Get Notified When a Service Is Deleted?

How can I use NotifyServiceStatusChange properly so I can get notified when the service specified is deleted? My current code successfully stops the service and marks it for deletion. However, I want to be notified when the service is fully deleted.
Here are the main points of my code:
SC_HANDLE SCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE,
SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
HANDLE EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL);
SERVICE_NOTIFY ServiceNotify;
ServiceNotify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
ServiceNotify.pszServiceNames = ServiceName;
ServiceNotify.pContext = &EventHandle;
ServiceNotify.pfnNotifyCallback = (PFN_SC_NOTIFY_CALLBACK)CallbackFunction;
DWORD status = NotifyServiceStatusChangeW(SCManager, SERVICE_NOTIFY_DELETED, &ServiceNotify);
WaitForSingleObject(EventHandle, INFINITE);
CloseServiceHandle(SCManager);
CloseHandle(EventHandle);
(ServiceName is WCHAR*)
CallbackFunction code:
VOID CALLBACK CallbackFunction(IN PVOID pParameter) {
SERVICE_NOTIFY* ServiceNotify = pParameter;
HANDLE EventHandle = *(HANDLE*)ServiceNotify->pContext;
SetEvent(EventHandle);
}
NotifyServiceStatusChange is returning ERROR_SUCCESS (0). However, my callback function is not being called at all. How can I fix this?
Edit:
Here is minimal reproducible code:
void ErrorExit(char* FunctionName, unsigned long ErrorCode) {
char* ErrorMessage;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, ErrorCode, LANG_USER_DEFAULT, (LPTSTR)&ErrorMessage, 0, NULL);
int MessageSize = (strlen(ErrorMessage) + strlen(FunctionName) + 50) * sizeof(char);
char* FullMessage = malloc(MessageSize);
sprintf_s(FullMessage, MessageSize, "%s failed with error %d: %s", FunctionName, ErrorCode, ErrorMessage);
MessageBoxA(NULL, FullMessage, "Error", MB_OK);
ExitProcess(ErrorCode);
}
PFN_SC_NOTIFY_CALLBACK CallbackFunction(PVOID pParameter) {
printf("CallbackFunction has been called.\r\n");
SERVICE_NOTIFY* ServiceNotify = pParameter;
HANDLE EventHandle = ServiceNotify->pContext;
if (!SetEvent(EventHandle)) {
ErrorExit("SetEvent", GetLastError());
}
}
int main()
{
WCHAR* ServiceName = L"SERVICE NAME"; // Input service name here
SC_HANDLE SCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
if (!SCManager) {
ErrorExit("OpenSCManagerW", GetLastError());
}
SC_HANDLE ServiceHandle = OpenServiceW(SCManager, ServiceName,
SERVICE_ENUMERATE_DEPENDENTS | SERVICE_STOP | DELETE);
if (!ServiceHandle) {
ErrorExit("ServiceHandle", GetLastError());
}
if (!DeleteService(ServiceHandle)) {
ErrorExit("DeleteService", GetLastError());
}
if (!CloseServiceHandle(ServiceHandle)) {
ErrorExit("CloseServiceHandle", GetLastError());
}
HANDLE EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL);
if (!EventHandle) {
ErrorExit("CreateEventW", GetLastError());
}
SERVICE_NOTIFY ServiceNotify;
ServiceNotify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
ServiceNotify.pszServiceNames = ServiceName;
ServiceNotify.pContext = EventHandle;
ServiceNotify.pfnNotifyCallback = CallbackFunction;
DWORD status = NotifyServiceStatusChangeW(SCManager, SERVICE_NOTIFY_DELETED, &ServiceNotify);
if (status != ERROR_SUCCESS) {
ErrorExit("NotifyServiceStatusChangeW", GetLastError());
}
status = WaitForSingleObjectEx(EventHandle, INFINITE, TRUE);
if (status == WAIT_FAILED) {
ErrorExit("WaitForSingleObjectEx", GetLastError());
}
printf("WaitForSingleObjectEx Result: %lu\r\n", status);
system("pause");
return 0;
}
When I run this, no other service depends on the service being deleted, and the service being deleted is already stopped. My error handling function "ErrorExit" is never called. Nothing is printed on the screen. My program simply pauses, which I assume is from WaitForSingleObjectEx.
I know the service is being deleted because I have ProcessHacker open, and it is giving me notifications that the service is being deleted.
NotifyServiceStatusChange is returning ERROR_SUCCESS (0). However, my callback function is not being called at all.
The NotifyServiceStatusChangeW documentation says:
When the service status changes, the system invokes the specified callback function as an asynchronous procedure call (APC) queued to the calling thread. The calling thread must enter an alertable wait (for example, by calling the SleepEx function) to receive notification. For more information, see Asynchronous Procedure Calls.
So, make sure you are actually processing APC notifications while you wait. WaitForSingleObject() will not do that for you.
Use WaitForSingleObjectEx() instead. It has a bAlertable parameter you can set to TRUE. You will have to call it in a loop, since it will return when any APC call is processed by the calling thread, which may not be the one you are expecting.
You also need to call NotifyServiceStatusChangeW() in a loop, too. The documentation does not mention this, but the callback will be called only 1 time per use. Once the callback is called, you need to call NotifyServiceStatusChangeW() again to receive another notification if the current one is not the event you are expecting.
With that said, try something more like this:
struct MyCallbackInfo {
HANDLE EventHandle;
LPCWSTR pszServiceName;
bool bDeleted;
};
...
VOID CALLBACK CallbackFunction(PVOID pParameter) {
SERVICE_NOTIFYW* ServiceNotify = (SERVICE_NOTIFYW*) pParameter;
MyCallbackInfo *ci = (MyCallbackInfo*) ServiceNotify->pContext;
if (ServiceNotify->dwNotificationStatus == ERROR_SUCCESS) {
LPWSTR pServiceName = ServiceNotify->pszServiceNames;
while (*pServiceName != L'\0') {
if (lstrcmpW(pServiceName, ci->pszServiceName) == 0) {
ci.bDeleted = true;
break;
}
pServiceName += (lstrlenW(pServiceName) + 1);
}
LocalFree(ServiceNotify->pszServiceNames);
}
SetEvent(ci->EventHandle);
}
...
MyCallbackInfo ci;
ci.EventHandle = CreateEventW(NULL, TRUE, FALSE, NULL);
ci.pszServiceName = ServiceName;
ci.bDeleted = false;
if (!ci.EventHandle) {
// error handling...
}
SC_HANDLE SCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE,
SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
if (!SCManager) {
// error handling...
}
SERVICE_NOTIFYW ServiceNotify = {};
ServiceNotify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
ServiceNotify.pContext = &ci;
ServiceNotify.pfnNotifyCallback = CallbackFunction;
DWORD status;
do {
status = NotifyServiceStatusChangeW(SCManager, SERVICE_NOTIFY_DELETED, &ServiceNotify);
if (status != ERROR_SUCCESS) {
// error handling...
}
while ((status = WaitForSingleObjectEx(ci.EventHandle, INFINITE, TRUE)) == WAIT_IO_COMPLETION);
if (status == WAIT_FAILED) {
// error handling...
}
if (ci.bDeleted) {
// service has been deleted ...
break;
}
ResetEvent(ci.EventHandle);
}
while (true);
CloseServiceHandle(SCManager);
CloseHandle(ci.EventHandle);

Access user data associated with event provided using TraceLoggingWrite

I am able to generate tracelogging events from my application(able to view them in Windows Performance Analyzer) using this method.
The event emitted is as follows
HRESULT CTracelogger::PublishEvent(void *pData)
{
if (pData)
{
EVENT_H sHEvent = *(static_cast<EVENT_H *>(pData));
TraceLoggingWrite(g_hEventProvider,
"HEvent",
TraceLoggingStruct(5, "HEventData"),
TraceLoggingUInt32(sHEvent.m_eEventType, "eEventType"),
TraceLoggingUInt32(sHEvent.m_uiVersion, "Version"),
TraceLoggingUInt32(sHEvent.m_uiPid, "Pid"),
TraceLoggingUInt32(sHEvent.m_uiSize, "Size"),
TraceLoggingWideString(sHEvent.m_wszHName, "HName")
);
}
return S_OK;
}
I am trying to consume the same events in a different application by writing a custom consumer, the consumer is receiving the events(as the corresponding provider GUID events are being received). I am trying to access the user data associated with the event using TdhGetProperty() as shown in documentation here but the function TdhGetEventInformation() is failing with ERROR_NOT_FOUND if the variable buffersize is initialized to 0 and fails with error ERROR_INVALID_PARAMETER if buffersize is initialized to a non-zero value.
Is the above approach taken correct to retrieve the data associated with the tracelogging event?
If yes, then why TdhGetEventInformation() is failing?
VOID WINAPI CEventLogger::EventRecordCallback(PEVENT_RECORD pEvent)
{
DWORD status = ERROR_SUCCESS;
PTRACE_EVENT_INFO pInfo = NULL;
char msgbuf[4096];
DWORD BufferSize = 0;
status = TdhGetEventInformation(pEvent, 0, nullptr, pInfo, &BufferSize);
if (ERROR_INSUFFICIENT_BUFFER == status)
{
pInfo = (TRACE_EVENT_INFO*)malloc(BufferSize);
if (pInfo == NULL)
{
OutputDebugString("Failed to allocate memory for event info");
status = ERROR_OUTOFMEMORY;
return;
}
else
{
OutputDebugString("successful memory allocation");
}
// Retrieve the event metadata.
status = TdhGetEventInformation(pEvent, 0, nullptr, pInfo, &BufferSize);
}
if (ERROR_SUCCESS != status)
{
sprintf_s(msgbuf, "TdhGetEventInformation failed status[%d], buffersize[%d]", status, BufferSize);
OutputDebugString(msgbuf);
}
else
{
sprintf_s(msgbuf, "TdhGetEventInformation successful, buffersize[%d]", BufferSize);
OutputDebugString(msgbuf);
}
}
The code above looks reasonable. My guess is that the problem is with your call to OpenTrace. By default (for backwards-compatibility with very old code), OpenTrace assumes that your callback wants to receive an EVENT_TRACE structure. However, your callback wants to receive an EVENT_RECORD. To tell OpenTrace to use the newer EVENT_RECORD format, you have to set ProcessTraceMode to PROCESS_TRACE_MODE_EVENT_RECORD.

FtpGetFile WinINEt never returns

I'm experiencing a curious problem (very strange, let me say hehe). During a FTP download of an EXE file (24 MB), if the connection is ever interrupted, it appears that the function FtpGetFile of the WinINEt library has a bug and it never returns. This causes that future file transfers fail (the connection is already opened).
Apparently, I found a workaround by increasing the timeout of the server transfers but I do not like it. I didn't found a similar problem by googling (maybe I introduced the wrong keywords).
I read some forums on the internet and it seems that everyone does not recommend using the FtpGetFile because it is buggy.
This appears in a network scenario that has a big lag (and not always) but in good conditions it disappears (downloads take place correctly and FtpGetFile returns always).
Here is how I use the function:
if( FtpGetFile(m_hFtpSession, strSourcePath.c_str(), strTargetPath.c_str(), 0, 0, FTP_TRANSFER_TYPE_BINARY, 0)==TRUE)
Can anyone confirm that? Should I refactor my code and look for an update?
Thank you
I found a way to download files without using FtpGetFile. I hope this code can help someone:
bool RetrieveFile(const string& strSource, const string& strTarget) {
/* The handle for the transfer */
HINTERNET hTransfer = NULL;
/*
* Set default error
*/
DWORD error = ERROR_SUCCESS;
if( !isConnected ) {
debug("%s(): ERROR not connected\n", __FUNCTION__);
return false;
}
/* Initiate access to a remote FTP connection */
hTransfer = FtpOpenFile(hFtpSession, strSource.c_str(), GENERIC_READ,
FTP_TRANSFER_TYPE_BINARY, 0);
if(hTransfer) {
std::ofstream myostream(strTarget.c_str(), std::ios::binary);
if ( myostream.is_open() ) {
static const DWORD SIZE = 1024;
BYTE data[SIZE];
DWORD size = 0;
do {
BOOL result = InternetReadFile(hTransfer, data, SIZE, &size);
if ( result == FALSE ) {
error = GetLastError();
Debug("InternetReadFile(): %lu\n", error);
}
myostream.write((const char*)data, size);
}
while ((error == ERROR_SUCCESS) && (size > 0));
// Close the stream
myostream.close();
}
else {
Debug("Could not open '%s'.\n", strTarget.c_str());
error = ERROR_FILE_NOT_FOUND; // Not necessarily not found, but it is to describe a file error which is different from ERROR_SUCCESS
}
// Close
const BOOL result = InternetCloseHandle(hTransfer);
if ( result == FALSE ) {
const DWORD error = GetLastError();
debug("InternetClose(): %lu\n", error);
}
/* Check error status of the process */
return (error == ERROR_SUCCESS);
}
DWORD dwInetError;
DWORD dwExtLength = 1000;
TCHAR *szExtErrMsg = NULL;
TCHAR errmsg[1000];
szExtErrMsg = errmsg;
int returned = InternetGetLastResponseInfo( &dwInetError, szExtErrMsg, &dwExtLength );
debug("dwInetError: %d Returned: %d\n", dwInetError, returned);
debug("Buffer: %s\n", szExtErrMsg);
debug("%s() : ERROR to get '%s' file (errorCode=%d)\n", __FUNCTION__, strSource.c_str(), GetLastError());
return false;
}

ReadDirectoryChangesW issues

I'am using ReadDirectoryChangesW to watch a directory changes asynchronously, based on this question I implement a function that watch a given directory, but I still get the error message GetQueuedCompletionStatus(): Timeout
void Filewatcher::OpenWatchDir(QString PathToOpen)
{
QString path=QDir::fromNativeSeparators(PathToOpen);
LPCTSTR Dirname=(LPCTSTR)path.utf16();//.toStdWString().c_str();
dirinfo_t* d =(dirinfo_t*) malloc(1*sizeof(dirinfo_t));
d->CompletionKey = (ULONG_PTR)&somekey;
dirinfo_init(d);
/* set up */
runthread = TRUE;
d->hDirFH = CreateFile(Dirname,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
d->hDirOPPort = CreateIoCompletionPort(d->hDirFH, NULL,
(ULONG_PTR)d->CompletionKey, 1);
DWORD errorcode = 0; // an error code
BOOL bResultQ = FALSE; // obvios=us
BOOL bResultR = FALSE;
DWORD NumBytes = 0;
FILE_NOTIFY_INFORMATION* pInfo = NULL; // the data incoming is a pointer
// to this struct.
int i = 0;
while ( runthread )
{
bResultR = ReadDirectoryChangesW(d->hDirFH, (void*)d->buffer,
16777216, TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION ,
NULL,
&d->o->overlapped,
NULL );
bResultQ = GetQueuedCompletionStatus(d->hDirOPPort,
&NumBytes, &(d->CompletionKey),
(LPOVERLAPPED*)(d->o), 1000);
if ( bResultQ && bResultR )
{
wprintf(L"\n");
pInfo = (FILE_NOTIFY_INFORMATION*) d->buffer;
wprintf(L"File %s", pInfo->FileName);
wprintf(L" changes %d\n", pInfo->Action);
qDebug()<<"file "<<pInfo->FileName<<" was"<<pInfo->Action;
memset(d->buffer, 0, 16777216);
}
else
{
errorcode = GetLastError();
if ( errorcode == WAIT_TIMEOUT )
{
qDebug()<<"GetQueuedCompletionStatus(): Timeout\n";
}
else
{
qDebug()<<"GetQueuedCompletionStatus(): Failed\n";
qDebug()<<"Error Code "<<errorcode;
}
Sleep(500);
}
}
}
I need to know how use ReadDirectoryChangesW asynchronously with IoCompletionPort.
Any help please.
There's no reason to use a completion port here, simple overlapped I/O with an event will work fabulously.
The key is to wait for this operation (whether event or completion port) at the same time as all other events (possibly including GUI messages), and only check the status when the event becomes signaled. For that, use (Msg)WaitForMultipleObjects(Ex).
In Qt, you can add Win32 events (used by OVERLAPPED structure for async I/O) using QWinEventNotifier as described here:
http://www.downtowndougbrown.com/2010/07/adding-windows-event-objects-to-a-qt-event-loop/
thank you guys for your answers, after a deep research and retesting code I solve my problem based on this , I really appreciate your help.

how to detect when kinect is disconnected / unplugged while program is running?

I'm working with one of the official Kinect SDK 1.5 examples, and I'm trying to figure out how to add a check to detect when the Kinect is being disconnected. Currently the app will just freeze, so there must be a way to prevent this from happening.
This is the main message loop from the SDK example:
// Main message loop
while (WM_QUIT != msg.message)
{
hEvents[0] = m_hNextDepthFrameEvent;
// Check to see if we have either a message (by passing in QS_ALLINPUT)
// Or a Kinect event (hEvents)
// Update() will check for Kinect events individually, in case more than one are signalled
DWORD dwEvent = MsgWaitForMultipleObjects(eventCount, hEvents, FALSE, INFINITE, QS_ALLINPUT);
// Check if this is an event we're waiting on and not a timeout or message
if (WAIT_OBJECT_0 == dwEvent)
{
Update();
}
// does not work.
bool bla = m_pNuiSensor->NuiStatus();
if (NULL == m_pNuiSensor)
{
cout << 1 << endl;
}
if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{
// If a dialog message will be taken care of by the dialog proc
if ((hWndApp != NULL) && IsDialogMessageW(hWndApp, &msg))
{
continue;
}
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return static_cast<int>(msg.wParam);
I've added the following bit:
// does not work, bla will always be the same value.
bool bla = m_pNuiSensor->NuiStatus();
if (NULL == m_pNuiSensor)
{
cout << 1 << endl;
}
since I was assuming that maybe NuiStatus would be a way to detect the disconnect. Unfortunately it won't work. The same is true for checking whether m_pNuiSensor is NULL.
So what's the way to detect a disconnect in the running app?
EDIT1: should I be using NuiSetDeviceStatusCallback?
In the documentation it says that NuiStatus returns HRESULT and not bool, so shouldn't it be
HRESULT bla = m_pNuiSensor->NuiStatus();
if (bla == E_NUI_NOTCONNECTED)
{
cout << 1 << endl;
}
instead?
the following solution works.
// check if m_pNuiSensor is initialized.
if (NULL != m_pNuiSensor)
{
// get current status & check if not ok.
HRESULT current_status = m_pNuiSensor->NuiStatus();
if (current_status != S_OK )
{
SetStatusMessage(L"Lost connection to Kinect!");
}
}