MFC Application: Adding Service Mode Support | CodeGuru

MFC Application: Adding Service Mode Support

Introduction Quite often an application has an opportunity to extend its existence on the market but must first meet new requirements, such as being able to run service mode. Imagine that you have developed a huge MFC based server application for years. You’ve already put a great deal of effort into teaching it various tricks […]

Written By
CodeGuru Staff
CodeGuru Staff
Feb 27, 2012
2 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Introduction

Quite often an application has an opportunity to extend its existence on the market but must first meet new requirements, such as being able to run service mode. Imagine that you have developed a huge MFC based server application for years. You’ve already put a great deal of effort into teaching it various tricks and features with a lot of useful functionality but missed one point during all the years of your product’s life; your app is able to run in interactive user session only. Now, your customers are no longer allowed to have endless interactive sessions, therefore they want 24/7, they want remote system reboots with your server to start automatically, without any administrator intervention.

What options do you have now? First, you can fully rewrite your server using some framework or programming language, like C#, that provides the ability to run the required mode. Full rewrite; you think–disaster.

Second, you can split your server into a number of elementary libraries, and reuse those in your new service project. A little better, you think, but not good enough.

Third, you can make your current app to be launched in service session, with tools like the well-known SRVANY, which never makes your app to be a real service…

I have to confess here. Some time ago I was in a situation exactly like this. None of the above appeared to be a viable alternative, as I wanted to make my server become a dual mode app able to run both interactive and service modes. I’m going to give you an idea of the enhancement.

The Server as it Now is

To start this tutorial with something material, let’s see how a simple MFC server might perform a simple function running interactive mode. The function will be logging timestamps to a file with 1 second intervals. This means no rich GUI at all, to let us focus on the server part only.

The server starts, spawns a worker thread that performs iterative logging to the file. Closing the main server window results in stopping the worker thread with further application closure.

#include <afxwin.h>
#include <atltime.h>
#include <share.h>
#include <process.h>

CRITICAL_SECTION g_csLog;
CString g_log;

struct LogInit
{
    LogInit() { InitializeCriticalSection(&g_csLog); }
    ~LogInit() { DeleteCriticalSection(&g_csLog); }
} logInit;

void PutLog(LPCTSTR entry)
{
    EnterCriticalSection(&g_csLog);
    FILE* f = _tfsopen(g_log, TEXT("at+"), _SH_DENYWR);
    if (f)
        _ftprintf(f, TEXT("%sn"), entry);
    fclose(f);
    LeaveCriticalSection(&g_csLog);
}

class CMainFrame: public CFrameWnd
{
    HANDLE  m_hStop;
    HANDLE  m_hWorker;

    DECLARE_MESSAGE_MAP()

public:
    CMainFrame():
        m_hStop(NULL),
        m_hWorker(NULL)
    {}

private:
    static UINT WINAPI WorkerThread(LPVOID pVoid)
    {
        CMainFrame* pThis = (CMainFrame*)pVoid;
        if (pThis)
            _endthreadex(pThis->Worker());
        return 0;
    }

    DWORD Worker()
    {
        HANDLE hStop = m_hStop;
        PutLog(TEXT("n++ Worker started ++"));
        BOOL loop = TRUE;
        while (loop)
        {
            DWORD waitRes = WaitForSingleObject(hStop, 1000);
            switch (waitRes)
            {
            case WAIT_OBJECT_0:
                PutLog(TEXT("Worker stop requested"));
                loop = FALSE;
                break;

            case WAIT_TIMEOUT:
                PutLog(CTime::GetCurrentTime().Format(TEXT("%#c")));
                break;
            }
        }
        PutLog(TEXT("-- Worker finished --n"));
        return 0;
    }

    BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pcx)
    {
        TCHAR path[MAX_PATH] = {0};
        if (GetModuleFileName(NULL, path, MAX_PATH))
        {
            g_log = path;
            g_log += TEXT(".log");
        }

        m_hStop = CreateEvent(NULL, TRUE, FALSE, NULL);

        UINT threadId;
        m_hWorker = (HANDLE)_beginthreadex(NULL, 0, WorkerThread, this, 0, &threadId);

        return TRUE;
    }

    void CloseWorker()
    {
        SetEvent(m_hStop);
        WaitForSingleObject(m_hWorker, INFINITE);
    }

    void OnClose()
    {
        PutLog(TEXT("Closing..."));
        CloseWorker();
        CWnd::OnClose();
    }

};

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    ON_WM_CLOSE()
END_MESSAGE_MAP()

class CMyApp: public CWinApp
{
    BOOL InitInstance()
    {
        CMainFrame* pFr = new CMainFrame;
        if (!pFr->Create(NULL, TEXT("EasyStart")))
        {
            return FALSE;
        }

        m_pMainWnd = pFr;
        pFr->ShowWindow(SW_SHOW);
        pFr->UpdateWindow();
        return TRUE;
    }
};

CMyApp theApp;

The log produced by the server: (to be compared with the service version later).

++ Worker started ++
Sunday, January 22, 2012 18:28:27
Sunday, January 22, 2012 18:28:28
Sunday, January 22, 2012 18:28:29
Closing...
Worker stop requested
-- Worker finished --

The code above seems pretty simple. The application class creates the frame instance. The frame class creates the worker thread and signals it to stop when it gets the WM_CLOSE message. The worker thread waits 1 second to put another log entry. Trivial. But great for our purpose nevertheless. Now it’s time to turn it into a service.

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.