C++ threading to download - c++

I need help with C++ threading stuff, I have created a dll which has a exported function as downloadfile (to download a file from the internet). This function in turns create a thread to download a file (the function used to download a file is blocking function i.e. URLDownloadToFile that's why I put the download functionality on thread).
I want to achieve following.
my call to downloadfile function should not block the main thread.
I want to download more than one file at a time.
remember that, download functionality is in the dll created in C++ and this dll will be used in Pascal.
following is the code snippet:
struct DOWNLOADPARAM
{
HANDLE hEventStop;
TCHAR *szURL;
TCHAR *szFilePath;
};
DWORD WINAPI Transfer(void *hw)
{
Mutex mutex_;
DOWNLOADPARAM *const pDownloadParam = static_cast<DOWNLOADPARAM *>(hw);
CBSCallbackImpl bsc(NULL, pDownloadParam->hEventStop);
const HRESULT hr = ::URLDownloadToFile(NULL,pDownloadParam->szURL ,pDownloadParam->szFilePath,0,&bsc);
return 0;
}
extern "C" void __declspec(dllexport) downloadfile(TCHAR *url, TCHAR *dest)
{
Mutex mutex_;
DWORD dwThreadId;
DOWNLOADPARAM *obj = new DOWNLOADPARAM();
obj->szURL = url;
obj->szFilePath = dest;
if((hThread = CreateThread(NULL, 0, Transfer, (LPVOID)obj, 0,&dwThreadId)) != NULL)
{
}
// Following code block the thread untill finished
WaitForSingleObject(hThread, INFINITE);
TerminateThread(hThread, 0);
CloseHandle(hThread);
}

It looks like your downloadFile function is waiting for the download thread to finish before it returns, which will cause it to block just like the URLDownloadToFile function does. I would suggest that you break this apart into two operations; downloadFile should return some sort of handle or event that the calling program can use to determine whether the operation has completed, and then when it has, provide a second function that cleans up the thread and handles. That way, the calling program can continue to run and use a WaitForMultipleObjects or some other mechanism to allow it to perform its own processing while still being notified when the download has completed. My Win32 is sketchy at best, so I can't really draft up some example code, but I hope the design idea is helpful.

Calling WaitForSingleObject on thread handle immediately after launching the thread is nothing more than a synchronous/blocking call. You should defer WaitForSingleObject.

Related

Send an http request in a new thread C++

I am new to C ++ and I am designing an application that requires getting information from the internet, my problem is that if there is no internet connection, or this is slow, my application freezes for seconds. My application also has a hook to the keyboard so when my application freezes, Windows also does.
My application is for Windows only.
This is a simulation of my problem:
std::string instruction;
std::string otherValue;
int timerId;
int main(int argc, char* argv[])
{
StartKeysListener(); //Keyboard Hook
timerId = SetTimer(nullptr, 0, 5000, static_cast<TIMERPROC>(TimerCallback));
MSG msg;
while (GetMessageA(&msg, nullptr, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
VOID CALLBACK TimerCallback(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime)
{
DownloadInstructions();
}
std::string DownloadInstructions(std::string url)
{
std::string response = HttpRequest(url); //HttpRequest is a function that uses Windows SOCKET to send an http request
if (!response.empty())
{
instruction = response.substr(0, 5);
otherValue = response.substr(6, 15);
}
}
I have tried calling the "DownloadInstructions" function on a new thread using std::async but I do not know how to return the server response to a callback to update the "instruction" and "otherValue" variables.
How can i solve this problem? I could not find what I'm looking for on Google.
Given you are using a Win32 style message loop, the usual way to pass information back to the main thread from a worker thread is to send a message. (It doesn't look like your sample code would quite work as written as you need at least a dummy HWND though.)
Custom messages (as opposed to predefined system messages) can be defined as an offset from WM_APP, so you can do something like:
#define WM_INSTRUCTIONS_LOADING (WM_APP + 0)
#define WM_INSTRUCTIONS_READY (WM_APP + 1)
/* ... */
Then in DownloadInstructions you can notify the main thread that the download is complete by using the PostMessage API (which sends an asynchronous message) where the HWND parameter is passed in to the thread from your main loop:
PostMessage(WM_INSTRUCTIONS_READY, hwndMain, 0, 0);
Now it doesn't look like DownloadInstructions is actually running in another thread. You're using the SetTimer API which will just send a WM_TIMER message to your event loop at some point in the future. The message will still be processed in your event loop, and thus on the main thread.
You really do need to spawn a separate thread if you want it to be truly asynchronous. The mechanism for using std::async and is quite different to using CreateThread. The std::async call will spawn a thread and return you a std::future which you need to join on to get the result. This is probably not a great match for your current design. If you just spawn DownloadInstructions as a separate thread and pass it some context (at least the HWND to post back to) via the void* argument pointer, that should be sufficient to do what you describe.
Now having said all that, are you sure you want to write a C++ app using the rather old-fashioned and low-level C Win32 API? There are numerous libraries and frameworks for C++ which provide a much higher level API to do all these sorts of things more easily.

unresolved problems with C++ EDITTEXT and DIRECTSHOW PAUSE()

i have a simple winform that writes to an EDITTEXT , as the program goes on the printing process executing perfectly . but once i click the STOP BUTTON which firstly calls the PAUSE()
function my program gets stuck inside the
SetWindowText(m_hWatermarksEditBox, &m_watermarkLog[0]);
all values are initialized and proper data gets in.
my guess is that i have to declare a METHOD WORKER , like in C#.NET but i dont know how.
STDMETHODIMP CNaveFilter::Pause()
{
ATLTRACE(L"(%0.5d)CNaveFilter::Pause() (this:0x%.8x)\r\n", GetCurrentThreadId(), (DWORD)this);
HRESULT hr = S_OK;
CAutoLock __lock(&m_cs);
hr = CBaseFilter::Pause();
return hr;
}
STDMETHODIMP CNaveFilter::Stop()
{
ATLTRACE(L"(%0.5d)CNaveFilter::Stop() (this:0x%.8x)\r\n", GetCurrentThreadId(), (DWORD)this);
HRESULT hr = S_OK;
CAutoLock __lock(&m_cs);
hr = CBaseFilter::Stop();
ATLASSERT(SUCCEEDED(hr));
return hr;
}
You don't show where you are doing SetWindowText but as you have the custom filter the most likely problem is that with this call you block your streaming/worker thread execution and the involved threads lock dead.
SetWindowText is only safe to be called from your UI thread (well, technically not only it, but definitely not a streaming thread). So if you want to update the control text or send any message to it, you have to do it in a different way, so that your caller thread could keep running.
Typically, you would store some relevant information in member variable (don't forget critical section lock) then PostMessage, receive the message on your window/control and handle it there in the right thread, calling SetWindowText there.
See controlling frame/rate and exposure time through sampleCB. It covers a bit different topic, but useful in terms of sending/posting messages in a DirectShow filter.

How to write simple background thread in CWorkerThread

I'm trying to asynchronously run function in my add-on for Internet Explorer (I'm writing BHO in VC++). As suggested here I'm trying to use CWorkerThread.
I've been trying to figure it out for hours but still have no idea how to do it. I don't have much experience in ATL. The lack of a good documentations or tutorials on Internet is killing me.
I'm creating class by Add->Class and choosing ATL Simple Object (that's how you add classed to ATL project right?). But how to implement this IWorkerThreadClient? I thought that choosing Add->Implement Interface in Class View would be good but there is no IWorkerThreadClient on the list.
I think I don't know ATL or COM enaugh but can't find good resource for learning this (esspessialy newest ATL7).
I even tried winapi CreateThread approach but it isn't working. I'm passing this class pointer to run static method but something is corrupting with memory later. Nevertheless if It had worked I still would rather use something else than CreateThread.
Right now I have something like this. In OnDocumentComplete there's RemoveImages(sptmlDoc) and I just want to run it asynchronously.
EDIT: What I did with CreateThread:
I tried running RemoveImages function (from here) asynchronously. I created static function in my class with signature like here. RemoveImages has parameter so I copied it to a member of a class:
if (htmlDoc2 != NULL)
{
m_tmpHtmlDocument2 = htmlDoc2;
m_hThread = CreateThread( NULL, 0, MyThreadFunction, this, 0, &m_threadId);
}
and MyThreadFunction:
static DWORD WINAPI MyThreadFunction( LPVOID lpParam )
{
CHelloWorldBHO* myClass = (CHelloWorldBHO*)lpParam;
myClass->RemoveImages(myClass->m_tmpHtmlDocument2);
return 0;
}
I get "Unhandled exception at 0x60c0da05 in iexplore.exe: 0xC0000005: Access violation reading location 0x000001b8." here in the bold line:
void CHelloWorldBHO::DontDisplayElement(CComPtr htmlElement)
{
CComPtr style;
HRESULT hr = htmlElement->get_style(&style);
if (hr == S_OK && style != NULL)
{
static const CComBSTR strNone(L"none");
style->put_display(strNone);
}
}
Your performing a naughty by trying to use a COM handle allocated in 1 thread in another. BHO environment is STA (Single Threaded Apartment) so you should be marshalling the m_tmpHtmlDocument2 object for use in your thread.
Experiance has shown that in some cases IE may let you get away with passing the Browser com object from 1 thread to another and then getting the document and elements afterwards may work. This is entirely unreliable.
Depending on IE 6/7/8 you will have different target threads to execute your actions on, thinking at the levels of per security level/frame/tab/window. basically any time IE creates a new 'Site'
Also to prevent your app from holding the pages active even after navigation away from the page, in FireFox you would use an nsWeakPointer<> , I've never found the equivelant in IE.
Suggestion: Perhaps instead of marshalling com to another thread because your interaction with the page is slow, trying to improve the way you interact with the page and improve performance in process might be a better aim.
Here is an outline using the CThreadPool which will queue up requests, and then execute them when the pool has space.
I use pvWorkerParam to tie the threads back to the site.
I have different types of ActionRequests, you could of course simplify and just pass null for the request.
Note: This doesn't resolve marshalling issues you already have
class ActionRequest{
DontDisplayElement();// define your do stuff in here
};
class ScriptWorker
{
public:
ScriptWorker(void);
virtual ~ScriptWorker(void);
public:
BOOL Initialize(void* pvWorkerParam);
void Execute(ActionRequest *request, void* pvWorkerParam, OVERLAPPED* pOverlapped){
try{
std::auto_ptr<ActionRequest> cleanupRequest(request);
request.DontDisplayElement();
} catch(...) {}
}
void Terminate(void* pvWorkerParam);
private:
boolean m_bCoUninit;
};
Site{
CThreadPool<ScriptWorker> m_scriptWorkerThread;
Site() {
void *pvWorkerParam = this;// or whatever you want to have passed to every script worker and execute in the pool.
m_scriptWorkerThread.Initialize( pvWorkerParam, 1 );
}
OnDocumentComplete() {
m_scriptWorkerThread.QueueRequest( new ActionRequest() );
}
}
and sptmlDoc - is it an IHTMLDocumet* ?
IWorkerThreadClient - never heard of it
"I even tried winapi CreateThread approach but it isn't working. I'm passing this class pointer to run static method but something is corrupting with memomory later"
Keeping it simple is the best design pattern of them all. So stick with CreateThread unless you have good reasons not to. Now, my guess is that the crash occurs because of sptmlDoc being passed to the thread for later processing. The thing is such pointers are only valid from the BeforeNavigate event until DocumentComplete event. Try to do that processing on the spot (inside your event handler) and see if it stil crashes. Some code posting would help too

Explicit Linking DLL and Program Hangs

I've the following piece of code in my program which dynamically links wtsapi32.dll file for session notifications like WTS_SESSION_LOCK and WTS_SESSION_UNLOCK and runs in background. After the first lock/unlock the program hangs and not responding.
Is this a right way of doing explicit linking ?
void RegisterSession(HWND hwnd)
{
typedef DWORD (WINAPI *tWTSRegisterSessionNotification)( HWND,DWORD );
tWTSRegisterSessionNotification pWTSRegisterSessionNotification=0;
HINSTANCE handle = ::LoadLibrary("wtsapi32.dll");
pWTSRegisterSessionNotification = (tWTSRegisterSessionNotification) :: GetProcAddress(handle,"WTSRegisterSessionNotification");
if (pWTSRegisterSessionNotification)
{
pWTSRegisterSessionNotification(hwnd,NOTIFY_FOR_THIS_SESSION);
}
::FreeLibrary(handle);
handle = NULL;
}
Edited:
I have another method UnRegisterSession() function which calls WTSUnRegisterSessionNotification, I am calling the RegisterSession() in WinMain method ( removed FreeLibrary as suggested by 1800) and calling UnRegisterSession() in WM_DESTROY of CALLBACK WindowProcedure function. But still the application hangs.
I'd say you probably cannot safely call FreeLibrary like that - you will be unloading the code you want to have call you. You should probably ensure not to free the dll until after you are finished getting notifications.
MS documentation suggests that you must call WTSUnRegisterSessionNotification before re-registering the session - as it only happens on your second attempt to lock it perhaps this is your issue?
With 1800 wrt the free library - you must keep this library loaded while you use it.
According to the documentation (http://msdn.microsoft.com/en-us/library/aa383841(VS.85).aspx):
"When a window no longer requires these notifications, it must call WTSUnRegisterSessionNotification before being destroyed."
I would try unregistering the notification during WM___CLOSE instead of WM_DESTROY.

Assertion in VS2008 but not in VS2005

After switching from VS2005 to VS2008 SP1, I found an issue that I can't explain.
A program works fine under VS2005 in both release and debug mode. Under VS2008, when entering the debugger an assert is raised.
If I let the program run (in debug or release mode), no assertion at all.
I spent almost two days on this and I don't understand what I do wrong.
Description of the program:
I have a MFC dialog based program that creates a user thread (CWinThread) that creates the main dialog of the application.
A worker thread loops infinitely and posts each second a message to the dialog. The message is processed in the gui thread.
Some parts of my code:
The InitInstance of the gui thread:
BOOL CGraphicalThread::InitInstance()
{
CGUIThreadDlg* pDlg = new CGUIThreadDlg();
pDlg->Create(CGUIThreadDlg::IDD);
m_pMainWnd = pDlg;
AfxGetApp()->m_pMainWnd = pDlg;
return TRUE;
}
The worker thread:
UINT ThreadProc(LPVOID pVoid)
{
do
{
AfxGetApp()->m_pMainWnd->PostMessage(WM_APP+1, (WPARAM)new CString("Hello"), NULL);
Sleep(1000);
}
while(!bStopThread);
return 0;
}
The dialog message handler is like this:
LRESULT CGUIThreadDlg::OnMsg(WPARAM wp, LPARAM lp)
{
CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST1);
CString* ps = (CString*)wp;
pList->InsertString(-1, *ps);
delete ps;
return 1L;
}
This works perfectly fine with VS2005.
But with VS2008, but as soon as a put a breakpoint and enter the debugging mode, I have an assertion raised ???
wincore.cpp line 906
CObject* p=NULL;
if(pMap)
{
ASSERT( (p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
}
ASSERT((CWnd*)p == this); // must be us
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
If I remove the GUI thread and create the dialog into the CWinApp thread, the problem doesn't occur anymore.
Does anybody have any idea?
Am I doing something wrong?
Thank you
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
#Ismael: I had already tried that the assert is still fired. The only way I found to remove the assert is to create the dialog into the CWinApp thread.
But this doesn't explain what happens since there's still the worker thread that post to the dialog every second.
Anyway , thanks.
#daanish.rumani: I've checked the wincore.cpp and the CWnd::AssertValid() is exactly the same (but there's of lot of differences in the rest of the files).
I would accept that a piece of code works with VS2005 and not VS2008, but
I can't see what I do wrong.
If I do something wrong, what is the correct way to proceed?
Why the assert is only fired when a breakpoint is hit and I step over the Sleep call?
I can run the program fine, even when its compiled in debug mode, as long as I don't enter the debugger.
Could it be a bug in the debugger?