Переопределяя PreMessageLoop, когда мне следует вызвать CAtlServiceModuleT :: PreMessageLoop - PullRequest
0 голосов
/ 25 октября 2011

У меня есть сервисный проект в Visual Studio 2005, который был преобразован в проект Visual Studio 2010. И я заметил проблему с функцией PreMessageLoop, которая выглядит следующим образом:

HRESULT CMyModule::PreMessageLoop (int nShowCmd)
{
    HRESULT result = CAtlServiceModuleT<CMyModule,100>::PreMessageLoop(nShowCmd);
    if (ERROR_SUCCESS == result)
    {
        ComplicatedInitialization();
        _AtlModule.SetServiceStatus (SERVICE_START_PENDING);
        MoreComplicatedInitialization();
        _AtlModule.SetServiceStatus (SERVICE_START_PENDING);
        StillMoreComplicatedInitialization();
        _AtlModule.SetServiceStatus (SERVICE_START_PENDING);
        EvenMoreComplicatedInitialization();
    }
    return result;
}

Это прекрасно работает в Visual C ++ 2005: функция Run вызывает мой PreMessageLoop, который вызывает базовый класс PreMessageLoop. Сложная инициализация происходит, когда служба находится в SERVICE_START_PENDING. Когда мой PreMessageLoop возвращается, Run вызывает SetServiceStatus (SERVICE_RUNNING).

Visual C ++ 2010 отличается: базовый класс PreMessageLoop вызывает SetServiceStatus (SERVICE_RUNNING). Сложная инициализация происходит, когда служба находится в состоянии SERVICE_RUNNING, что не очень хорошо (поскольку служба выглядит так, как будто она работает, хотя на самом деле она все еще инициализируется).

Могу ли я просто переместить вызов PreMessageLoop базового класса в конец моего вызова PreMessageLoop? Или это сложнее, чем простой ход?

Followup

Похоже, что служба может перейти из состояния SERVICE_RUNNING обратно в состояние SERVICE_START_PENDING. Это мудро?

Ответы [ 2 ]

1 голос
/ 25 октября 2011

Прежде всего, «if (ERROR_SUCCESS == result)» является чем-то не совсем корректным, так как вы должны проверять результат по значениям HRESULT, то есть по S_OK, S_FALSE или с использованием SUCCEEDED своего рода макросы.

Base PreMessageLoop регистрирует объекты класса COM, если ваша сложная инициализация не использует создание экземпляра COM, вы можете переместить ваши вещи выше __super::PreMessageLoop call.

0 голосов
/ 03 декабря 2012

Коды инициализации COM в PreMessageLoop вызывают ошибку 1053.

Решение 1. Отключите поддержку COM.

#define _ATL_NO_COM_SUPPORT

в "stdafx.h" перед включением всех связанных ATL.

Решение 2. Переопределите «PreMessageLoop» и уберите его из кодов инициализации COM.

HRESULT PreMessageLoop(_In_ int nShowCmd) throw()
{
    if (m_bService)
    {
        // Make sure that service was not stoped during initialization
        if (::InterlockedCompareExchange(&m_status.dwCurrentState, SERVICE_RUNNING, SERVICE_START_PENDING) == SERVICE_START_PENDING)
        {
            LogEvent(_T("Service started/resumed"));
            ::SetServiceStatus(m_hServiceStatus, &m_status);
        }
    }

    // Start the tread(s)
    _worker = new CWorkerThread();

    return S_OK;
}
...