Going background with window messages

Nicholas Tsipanov (nicholas@spbteam.com), October 22, 2001.

Summary

It is often needed to run your application in background, invisible to user. This article describes one of possible approaches to the problem solution.

Preface

What could you do on desktop if you were asked to create a background process? You can either create a service application (on NT) or create an appliation that has only one WinMain function. Pocket PC lacks NT services like Windows 9' platform so this solution won't do. But we can create an invisible window that activates its work on system timer clicks or window custom messages.

Getting started

We won't need to have a Dialog based application but we need to have support of MFC classes (CString is the most wanted of them).

Create a standard MFC dialog based application called BackgroundApp, then eliminate all unnecessary stuff: remove CBackgroundAppDlg.* from project (we will create a CWnd-based window instead) and remove #include "BackgroundAppDlg.h" line. Then change the standard CBackgroundAppApp::InitInstance implementation. You will have something like this:

BOOL CBackgroundAppApp::InitInstance() { //We wanted to start message pump so we need to return TRUE return TRUE; }

This will compile but won't run because MFC applications cannot run without MainWindow. That's the task we have to accomplish.

Within windows - without windows

Here we will create a light-weighted window (comparing to CDialog based windows) that will get its own window procedure:

class CBackgroundWnd : public CWnd { public: CBackgroundWnd(); //{{AFX_VIRTUAL(CBackgroundWnd) protected: virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); //}}AFX_VIRTUAL public: void Create(); virtual ~CBackgroundWnd(); protected: BOOL m_bInProcess; //{{AFX_MSG(CBackgroundWnd) afx_msg void OnTimer(UINT nIDEvent); //}}AFX_MSG DECLARE_MESSAGE_MAP() };

We override CWnd::Create to create this window invisible to user :

void CBackgroundWnd::Create() { CString strParentClass = AfxRegisterWndClass(0); CWnd::CreateEx(0, strParentClass, WINDOW_TITLE, 0, -1, -1, 0, 0, 0, 0); SetTimer(ID_BACKGROUND_TIMER, STEP_TIME, NULL); }

Let's do something useful on timer events:

void CBackgroundWnd::OnTimer(UINT nIDEvent) { if (nIDEvent==ID_BACKGROUND_TIMER) { if (!m_bInProcess) { m_bInProcess = TRUE; RunSlice(); m_bInProcess = FALSE; } } CWnd::OnTimer(nIDEvent); } void CBackgroundWnd::RunSlice() { // TODO: do something useful here.. MessageBeep(MB_OK); }

We had declared a custom window message that we will handle if we need this process to handle our commands. To handle this we have to override WindowProc method:

LRESULT CBackgroundWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if (message==m_nMessage) { m_bInProcess = TRUE; m_bInProcess = FALSE; OnMessage(wParam, lParam); } return CWnd::WindowProc(message, wParam, lParam); } void CBackgroundWnd::OnMessage(WPARAM wParam, LPARAM lParam) { ::MessageBox(NULL, TEXT("Message has been received!"), TEXT("Message from background"), MB_OK); }

To test this feature create a simple application that either sends a custom message to your invisible window directly or sends it broadcast:

//Somewhere in control application: int nMessage = RegisterWindowMessage(WINDOW_MESSAGE_KEY); ::SendMessage(HWND_BROADCAST, nMessage, 0 , 0 );

Then we will add a manually created invisible window to the application that receives windows messages. (add BackgroundWnd.* to the project before).

#include "BackgroundWnd.h" ...... BOOL CBackgroundAppApp::InitInstance() { CBackgroundWnd *pBackgroundWnd = new CBackgroundWnd(); pBackgroundWnd->Create(); m_pMainWnd = pBackgroundWnd; return TRUE; //we need to start the application message pump rather than exit }

Sample

You can download a sample project (10Kb) that was used in this article.

Conclusion

Sometimes it is useful to have a background application (e. g. doing some log). One of the approaches is to create an invisible window and spawn it to activate on timer ticks. To make other communications with your window the simplest way is to send it user window messages in the way described in this article. You can develop this application further; for example you can add process dispatcher its processes according to some rules. The other way to communicate is to create use system pipes, semaphores but they are a bit more complicated.

Related resources: