summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen D. Huston <shuston@apache.org>2011-02-23 00:48:56 +0000
committerStephen D. Huston <shuston@apache.org>2011-02-23 00:48:56 +0000
commitd07e9a0a24eeab9b16706c8a001864af1f181182 (patch)
tree20b2f989350a538a66c078657056e84758ef4087
parent30996cba9f2588c379adad15b3f2c5c3137c6f55 (diff)
downloadqpid-python-d07e9a0a24eeab9b16706c8a001864af1f181182.tar.gz
Initial commit of patches applied from QPID-2519, formatted mostly for Qpid guidelines. Hasn't been built, will need more changes. Checking in for Kerry's use.
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/QPID-2519@1073566 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--cpp/src/CMakeLists.txt2
-rw-r--r--cpp/src/windows/QpiddBroker.cpp120
-rw-r--r--cpp/src/windows/Service.cpp1050
-rw-r--r--cpp/src/windows/Service.h200
4 files changed, 1371 insertions, 1 deletions
diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt
index 54e9447d7d..9dd81e0e31 100644
--- a/cpp/src/CMakeLists.txt
+++ b/cpp/src/CMakeLists.txt
@@ -660,6 +660,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows)
set (qpidd_platform_SOURCES
windows/QpiddBroker.cpp
+ windows/Service.h
+ windows/Service.cpp
)
set (qpidmessaging_platform_SOURCES
diff --git a/cpp/src/windows/QpiddBroker.cpp b/cpp/src/windows/QpiddBroker.cpp
index e221551575..9432cbc077 100644
--- a/cpp/src/windows/QpiddBroker.cpp
+++ b/cpp/src/windows/QpiddBroker.cpp
@@ -42,6 +42,11 @@ const char *QPIDD_MODULE_DIR = ".";
using namespace qpid::broker;
+// Service support
+#include "Service.h"
+Service s_service( "qpidd" );
+
+
BootstrapOptions::BootstrapOptions(const char* argv0)
: qpid::Options("Options"),
common("", QPIDD_CONF_FILE),
@@ -225,9 +230,39 @@ struct ProcessControlOptions : public qpid::Options {
}
};
+struct DaemonOptions : public qpid::Options {
+ bool install;
+ bool start;
+ bool stop;
+ bool uninstall;
+ bool daemon;
+ string startType;
+ string account;
+ string password;
+ string depends;
+
+ DaemonOptions()
+ : qpid::Options("Service options"), install(false), start(false), stop(false), uninstall(false), daemon(false),
+ startType("demand")
+ {
+ addOptions()
+ ("install", qpid::optValue(install), "Install as service")
+ ("start-type", qpid::optValue(startType,"auto|demand|disabled"), "Service start type\nApplied at install time only.")
+ ("account", qpid::optValue(account,"(LocalService)"), "Account to run as, default is LocalService\nApplied at install time only.")
+ ("password", qpid::optValue(password,"PASSWORD"), "Account password, if needed\nApplied at install time only.")
+ ("depends", qpid::optValue(depends,"(comma delimited list)"), "Names of services that must start before this service\nApplied at install time only.")
+ ("start", qpid::optValue(start), "Start the service.")
+ ("stop", qpid::optValue(stop), "Stop the service.")
+ ("uninstall", qpid::optValue(uninstall), "Uninstall the service.")
+ ("daemon", qpid::optValue(daemon), "Run as a daemon service (internal use only");
+ }
+};
+
struct QpiddWindowsOptions : public QpiddOptionsPrivate {
ProcessControlOptions control;
+ DaemonOptions daemon;
QpiddWindowsOptions(QpiddOptions *parent) : QpiddOptionsPrivate(parent) {
+ parent->add(daemon);
parent->add(control);
}
};
@@ -252,6 +287,19 @@ void QpiddOptions::usage() const {
<< *this << std::endl;
}
+void WINAPI ShutdownProc( void *pContext )
+{
+ if( pContext )
+ reinterpret_cast<Broker*>(pContext)->shutdown();
+}
+
+int __cdecl main(int argc, char* argv[]);
+
+void WINAPI main2( DWORD argc, char* argv[] )
+{
+ (void)main( argc, argv );
+}
+
int QpiddBroker::execute (QpiddOptions *options) {
// Options that affect a running daemon.
QpiddWindowsOptions *myOptions =
@@ -259,6 +307,69 @@ int QpiddBroker::execute (QpiddOptions *options) {
if (myOptions == 0)
throw qpid::Exception("Internal error obtaining platform options");
+ if( myOptions->daemon.install )
+ {
+ size_t p;
+
+ // Handle start type
+ DWORD startType;
+ if( myOptions->daemon.startType.compare( "demand" ) == 0 )
+ startType = SERVICE_DEMAND_START;
+ else if( myOptions->daemon.startType.compare( "auto" ) == 0 )
+ startType = SERVICE_AUTO_START;
+ else if( myOptions->daemon.startType.compare( "disabled" ) == 0 )
+ startType = SERVICE_DISABLED;
+ else if( ! myOptions->daemon.startType.empty() )
+ throw qpid::Exception( "Invalid service start type: " + myOptions->daemon.startType );
+
+ // Get original command line arguments and substitute daemon for install...
+ string args( ::GetCommandLineA() );
+ if( args[0] == '\"' ) // if OS prepended w/ fully qualified path
+ {
+ if( ( p = args.find_first_of( "\"", 1 ) ) != args.npos )
+ args = args.substr( p + 2 ); // trim .exe
+ }
+ else
+ {
+ if( ( p = args.find_first_of( " ", 1 ) ) != args.npos )
+ args = args.substr( p + 1 ); // trim .exe
+ }
+ if( ( p = args.find( "install" ) ) == args.npos )
+ throw qpid::Exception("Internal error relocating install argument for service");
+ string args2 = args.substr( 0, p );
+ args2 += "daemon";
+ args2 += args.substr( p + 7 );
+
+ // Install service and exit
+ WinService::install( "qpidd", args2, startType, myOptions->daemon.account, myOptions->daemon.password, myOptions->daemon.depends );
+ return 0;
+ }
+
+ if( myOptions->daemon.start )
+ {
+ WinService::start( "qpidd" );
+ return 0;
+ }
+
+ else if( myOptions->daemon.stop )
+ {
+ WinService::stop( "qpidd" );
+ return 0;
+ }
+
+ else if( myOptions->daemon.uninstall )
+ {
+ WinService::uninstall( "qpidd" );
+ return 0;
+ }
+
+ // Detect daemon special argument
+ else if( myOptions->daemon.daemon )
+ {
+ WinService::getInstance()->run( main2 );
+ return 1;
+ }
+
if (myOptions->control.check || myOptions->control.quit) {
// Relies on port number being set via --port or QPID_PORT env variable.
NamedSharedMemory<BrokerInfo> info(brokerInfoName(options->broker.port));
@@ -281,6 +392,9 @@ int QpiddBroker::execute (QpiddOptions *options) {
boost::intrusive_ptr<Broker> brokerPtr(new Broker(options->broker));
+ // Enable shutdown
+ s_service.setShutdownProc( ShutdownProc, brokerPtr.get() );
+
// Need the correct port number to use in the pid file name.
if (options->broker.port == 0)
options->broker.port = brokerPtr->getPort(myOptions->control.transport);
@@ -302,7 +416,11 @@ int QpiddBroker::execute (QpiddOptions *options) {
brokerPtr->accept();
std::cout << options->broker.port << std::endl;
brokerPtr->run();
- waitShut.signal(); // In case we shut down some other way
+
+ // Now disable shutdown
+ s_service.setShutdownProc(0,0);
+
+ waitShut.signal(); // In case we shut down some other way
waitThr.join();
// CloseHandle(h);
diff --git a/cpp/src/windows/Service.cpp b/cpp/src/windows/Service.cpp
new file mode 100644
index 0000000000..9ca3fb381b
--- /dev/null
+++ b/cpp/src/windows/Service.cpp
@@ -0,0 +1,1050 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <boost/format.hpp>
+#include <sstream>
+#include <iostream>
+using std::ostringstream;
+#include "qpid/log/Statement.h"
+#include "Service.h"
+
+#pragma comment(lib, "advapi32.lib")
+
+namespace {
+//
+// Purpose:
+// Called by SCM whenever a control code is sent to the service
+// using the ControlService function.
+//
+// Parameters:
+// dwCtrl - control code
+//
+// Return value:
+// None
+//
+VOID WINAPI SvcCtrlHandler(DWORD dwCtrl)
+{
+ qpid::windows::Service * pWinService = qpid::windows::Service::getInstance();
+ if (pWinService)
+ pWinService->svcCtrlHandler(dwCtrl);
+}
+
+/**
+ * Entrypoint from the system to run the service.
+ */
+VOID WINAPI SvcMain(DWORD dwArgc, char *lpszArgv[])
+{
+ qpid::windows::Service* pService = qpid::windows::Service::getInstance();
+ if (pService)
+ pService->svcMain(dwArgc, lpszArgv);
+}
+
+} // namespace
+
+namespace qpid {
+namespace windows {
+
+/**
+ * Ye service instance
+ */
+Service* Service::s_pInstance = 0;
+
+/**
+ * Run the service
+ *
+ * @return false if the service could not be started
+ */
+bool Service::run(tServiceMainProc main)
+{
+ // Register main
+ if (!main)
+ return false;
+ m_main = main;
+
+ // TO_DO: Add any additional services for the process to this table.
+ SERVICE_TABLE_ENTRY DispatchTable[] =
+ {
+ { const_cast<LPSTR>(m_serviceName.c_str()), (LPSERVICE_MAIN_FUNCTION) SvcMain },
+ { NULL, NULL }
+ };
+
+ // This call returns when the service has stopped.
+ // The process should simply terminate when the call returns.
+
+ if (!StartServiceCtrlDispatcher(DispatchTable)) {
+ reportApiErrorEvent("StartServiceCtrlDispatcher");
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Build a command argc/argv set from a string
+ */
+void WinService::commandLineFromString( const string & args, vector<string> & argsv, int * pargc, char ** pargv[] )
+{
+ // Build the substring vector
+ size_t s = 0;
+ while( true )
+ {
+ // Skip leading space
+ size_t p = args.find_first_not_of( " ", s );
+ if( p != args.npos )
+ s = p;
+
+ p = args.find_first_of( " \"", s ); // Look for next quote or space
+
+ if( p == args.npos ) // didn't find it ?
+ {
+ if( s < args.size() - 1 ) // If anything left
+ argsv.push_back( args.substr( s ) ); // substring = rest of string
+ break; // we're done breaking up
+ }
+
+ if( args[p] == '\"' ) // found an open quote ?
+ {
+ size_t p2 = args.find_first_of( "\"", p + 1 ); // search for close quote
+ if( p2 == args.npos ) // didn't find it ?
+ {
+ argsv.push_back( args.substr( p + 1 ) ); // substring = rest of string
+ break; // we're done breaking up
+ }
+ if( p2 - p > 0 ) // If something in between the quotes
+ argsv.push_back( args.substr( p + 1, ( p2 - p ) - 1 ) ); // use it
+ s = p2 + 1; // resume past close quote
+ }
+
+ else // otherwise found a space
+ {
+ argsv.push_back( args.substr( s, p - s ) ); // use it
+ s = p + 1; // resume past space
+ }
+ }
+
+ // Build the argv list
+ if( pargc )
+ * pargc = argsv.size();
+ if( pargv )
+ {
+ char ** ppc = * pargv = new char*[ argsv.size() ];
+ for( size_t i = 0; i < argsv.size(); i++ )
+ ppc[ i ] = const_cast<char*>( argsv[i].c_str());
+ }
+}
+
+/**
+ *
+ */
+Service::Service(const string& serviceName)
+ : ghSvcStopEvent(NULL),
+ m_main(0),
+ m_shutdownProc(0),
+ m_serviceName(serviceName),
+ m_pShutdownContext(0)
+{
+ s_pInstance = this;
+}
+
+/**
+ *
+ */
+SC_HANDLE Service::openSvcManager()
+{
+ SC_HANDLE schSCManager = ::OpenSCManager(NULL, // local computer
+ NULL, // ServicesActive database
+ SC_MANAGER_ALL_ACCESS); // Rights
+ if (NULL == schSCManager) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("OpenSCManager failed: %1%") % GetLastError()).str());
+ //printf("OpenSCManager failed (%d)\n", GetLastError());
+ return 0;
+ }
+
+ return schSCManager;
+}
+
+/**
+ *
+ */
+SC_HANDLE Service::openService(SC_HANDLE hSvcManager,
+ const string& serviceName,
+ DWORD rights)
+{
+ // Get a handle to the service.
+ SC_HANDLE schService = ::OpenService(hSvcManager,
+ serviceName.c_str(),
+ rights);
+ if (schService == NULL) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("OpenService failed: %1%") % GetLastError()).str());
+ //printf("OpenService failed (%d)\n", GetLastError());
+ ::CloseServiceHandle(hSvcManager);
+ return false;
+ }
+
+ return schService;
+}
+
+/**
+ * Install this executable as a service
+ */
+bool Service::install(const string& serviceName,
+ const string& args,
+ DWORD startType,
+ const string& account,
+ const string& password,
+ const string& depends)
+{
+ SC_HANDLE schSCManager;
+ SC_HANDLE schService;
+ char szPath[MAX_PATH];
+
+ // Handle dependent service name list
+ char * pDepends = 0;
+ string depends2 = depends;
+ if (!depends2.empty()) {
+ // CDL to null delimiter w/ trailing double null
+ size_t p = 0;
+ while ((p = depends2.find_first_of( ',', p)) != string::npos)
+ depends2.replace(p, 1, 1, '\0');
+ depends2.push_back('\0');
+ depends2.push_back('\0');
+ pDepends = const_cast<char*>(depends2.c_str()); // win doesn't modify, so can use in this case
+ }
+
+ // Validate account, password
+ HANDLE hToken = NULL;
+ bool logStatus = false;
+ if (!account.empty() && !password.empty() &&
+ !(logStatus = ::LogonUserA(account.c_str(),
+ "",
+ password.c_str(),
+ LOGON32_LOGON_NETWORK,
+ LOGON32_PROVIDER_DEFAULT,
+ &hToken ) != 0))
+ std::cout << "warning: supplied account & password failed with LogonUser." << std::endl;
+ if (logStatus)
+ ::CloseHandle(hToken);
+
+ // Get fully qualified .exe name
+ if (!::GetModuleFileName(NULL, szPath, MAX_PATH)) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("Cannot install service: %1%") % GetLastError()).str());
+ //printf("Cannot install service (%d)\n", GetLastError());
+ return false;
+ }
+
+ string imagePath = szPath;
+ if (!args.empty())
+ imagePath += " " + args;
+
+ // Get a handle to the SCM database.
+ if (!(schSCManager = openSvcManager()))
+ return false;
+
+ // Create the service
+ schService = ::CreateService(schSCManager, // SCM database
+ serviceName.c_str(), // name of service
+ serviceName.c_str(), // name to display
+ SERVICE_ALL_ACCESS, // desired access
+ SERVICE_WIN32_OWN_PROCESS, // service type
+ startType, // start type
+ SERVICE_ERROR_NORMAL, // error cntrl type
+ imagePath.c_str(), // path to service's binary w/ optional arguments
+ NULL, // no load ordering group
+ NULL, // no tag identifier
+ pDepends, // Dependant svc list
+ account.empty() ? NULL : account.c_str(), // account name, or NULL for LocalSystem
+ password.empty() ? NULL : password.c_str()); // password, or NULL for none
+ if (schService == NULL) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("CreateService failed: %1%") % GetLastError()).str());
+ //printf("CreateService failed (%d)\n", GetLastError());
+ ::CloseServiceHandle(schSCManager);
+ return false;
+ }
+ //Note [ds, 27.09.2010]
+ QPID_LOG(info, "Service installed successfully");
+ //printf("Service installed successfully\n");
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+
+ return true;
+}
+
+/**
+ *
+ */
+bool Service::start(const string& serviceName)
+{
+ SC_HANDLE schSCManager;
+ SC_HANDLE schService;
+
+ SERVICE_STATUS_PROCESS ssStatus;
+ DWORD dwOldCheckPoint;
+ DWORD dwStartTickCount;
+ DWORD dwWaitTime;
+ DWORD dwBytesNeeded;
+
+ // Get a handle to the SCM database.
+ if (!(schSCManager = openSvcManager()))
+ return false;
+
+ // Get a handle to the service.
+ if (!(schService = openService(schSCManager, serviceName, SERVICE_ALL_ACCESS)))
+ return false;
+
+ // Check the status in case the service is not stopped.
+ if (!::QueryServiceStatusEx(schService, // handle to service
+ SC_STATUS_PROCESS_INFO, // information level
+ (LPBYTE) &ssStatus, // address of structure
+ sizeof(SERVICE_STATUS_PROCESS), // size of structure
+ &dwBytesNeeded)) { // size needed if buffer is too small
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("QueryServiceStatusEx failed: %1%") % GetLastError()).str());
+ //printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return false;
+ }
+
+ // Check if the service is already running. It would be possible
+ // to stop the service here, but for simplicity this example just returns.
+ if (ssStatus.dwCurrentState != SERVICE_STOPPED &&
+ ssStatus.dwCurrentState != SERVICE_STOP_PENDING) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(warning, "Cannot start the service because it is already running");
+ //printf("Cannot start the service because it is already running\n");
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return false;
+ }
+
+ // Save the tick count and initial checkpoint.
+ dwStartTickCount = ::GetTickCount();
+ dwOldCheckPoint = ssStatus.dwCheckPoint;
+
+ // Wait for the service to stop before attempting to start it.
+ while (ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
+ // Do not wait longer than the wait hint. A good interval is
+ // one-tenth of the wait hint but not less than 1 second
+ // and not more than 10 seconds.
+ dwWaitTime = ssStatus.dwWaitHint / 10;
+ if (dwWaitTime < 1000)
+ dwWaitTime = 1000;
+ else if (dwWaitTime > 10000)
+ dwWaitTime = 10000;
+
+ ::Sleep(dwWaitTime);
+
+ // Check the status until the service is no longer stop pending.
+ if (!::QueryServiceStatusEx(
+ schService, // handle to service
+ SC_STATUS_PROCESS_INFO, // information level
+ (LPBYTE) &ssStatus, // address of structure
+ sizeof(SERVICE_STATUS_PROCESS), // size of structure
+ &dwBytesNeeded)) { // size needed if buffer is too small
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("QueryServiceStatusEx failed: %1%") % GetLastError()).str());
+ //printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return false;
+ }
+
+ if (ssStatus.dwCheckPoint > dwOldCheckPoint) {
+ // Continue to wait and check.
+ dwStartTickCount = GetTickCount();
+ dwOldCheckPoint = ssStatus.dwCheckPoint;
+ } else {
+ if ((::GetTickCount() - dwStartTickCount) > ssStatus.dwWaitHint) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, "Service was in SERVICE_STOP_PENDING state, timeout waiting for service to stop");
+ //printf("Timeout waiting for service to stop\n");
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return false;
+ }
+ }
+ }
+
+ // Attempt to start the service.
+ if (!::StartService(schService, // handle to service
+ 0, // number of arguments
+ NULL)) { // no arguments
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("StartService failed: %1%") % GetLastError()).str());
+ //printf("StartService failed (%d)\n", GetLastError());
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return false;
+ }
+
+ //Note [ds, 27.09.2010]
+ QPID_LOG(info, "Service start pending...");
+ //printf("Service start pending...\n");
+
+ // Check the status until the service is no longer start pending.
+ if (!::QueryServiceStatusEx(
+ schService, // handle to service
+ SC_STATUS_PROCESS_INFO, // info level
+ (LPBYTE) &ssStatus, // address of structure
+ sizeof(SERVICE_STATUS_PROCESS), // size of structure
+ &dwBytesNeeded)) { // if buffer too small
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("QueryServiceStatusEx failed: %1%") % GetLastError()).str());
+ //printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return false;
+ }
+
+ // Save the tick count and initial checkpoint.
+ dwStartTickCount = ::GetTickCount();
+ dwOldCheckPoint = ssStatus.dwCheckPoint;
+
+ while (ssStatus.dwCurrentState == SERVICE_START_PENDING) {
+ // Do not wait longer than the wait hint. A good interval is
+ // one-tenth the wait hint, but no less than 1 second and no
+ // more than 10 seconds.
+
+ dwWaitTime = ssStatus.dwWaitHint / 10;
+
+ if (dwWaitTime < 1000)
+ dwWaitTime = 1000;
+ else if (dwWaitTime > 10000)
+ dwWaitTime = 10000;
+ ::Sleep(dwWaitTime);
+
+ // Check the status again.
+ if (!::QueryServiceStatusEx(schService, // handle to svc
+ SC_STATUS_PROCESS_INFO, // info level
+ (LPBYTE) &ssStatus, // address of structure
+ sizeof(SERVICE_STATUS_PROCESS), // size of structure
+ &dwBytesNeeded)) { // if buff too small
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("QueryServiceStatusEx failed: %1%") % GetLastError()).str());
+ //printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
+ break;
+ }
+
+ if (ssStatus.dwCheckPoint > dwOldCheckPoint) {
+ // Continue to wait and check.
+ dwStartTickCount = GetTickCount();
+ dwOldCheckPoint = ssStatus.dwCheckPoint;
+ }
+ else {
+ if ((::GetTickCount() - dwStartTickCount) > ssStatus.dwWaitHint) {
+ // No progress made within the wait hint.
+ break;
+ }
+ }
+ }
+
+ // Determine whether the service is running.
+ if (ssStatus.dwCurrentState == SERVICE_RUNNING) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(info, "Service started successfully");
+ //printf("Service started successfully.\n");
+
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return true;
+ }
+
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("Service not started: %1% ") % GetLastError()).str());
+ //printf("Service not started. \n");
+ QPID_LOG(error, (boost::format("Current State: %1% ") % ssStatus.dwCurrentState).str());
+ //printf(" Current State: %d\n", ssStatus.dwCurrentState);
+ QPID_LOG(error, (boost::format("Exit Code: %1% ") % ssStatus.dwWin32ExitCode).str());
+ //printf(" Exit Code: %d\n", ssStatus.dwWin32ExitCode);
+ QPID_LOG(error, (boost::format("Check Point: %1% ") % ssStatus.dwCheckPoint).str());
+ //printf(" Check Point: %d\n", ssStatus.dwCheckPoint);
+ QPID_LOG(error, (boost::format("Wait Hint: %1% ") % ssStatus.dwWaitHint).str());
+ //printf(" Wait Hint: %d\n", ssStatus.dwWaitHint);
+
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return false;
+}
+
+/**
+ *
+ */
+bool Service::stop(const string& serviceName)
+{
+ SC_HANDLE schSCManager;
+ SC_HANDLE schService;
+
+ SERVICE_STATUS_PROCESS ssp;
+ DWORD dwStartTime = GetTickCount();
+ DWORD dwBytesNeeded;
+ DWORD dwTimeout = 30000; // 30-second time-out
+ DWORD dwWaitTime;
+
+ // Get a handle to the SCM database.
+ if (!(schSCManager = openSvcManager()))
+ return false;
+
+ // Get a handle to the service.
+ if (!(schService = openService(schSCManager,
+ serviceName,
+ SERVICE_STOP | SERVICE_QUERY_STATUS |
+ SERVICE_ENUMERATE_DEPENDENTS)))
+ return false;
+
+ // Make sure the service is not already stopped.
+ if (!::QueryServiceStatusEx(schService,
+ SC_STATUS_PROCESS_INFO,
+ (LPBYTE)&ssp,
+ sizeof(SERVICE_STATUS_PROCESS),
+ &dwBytesNeeded)) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("QueryServiceStatusEx failed: %1%") % GetLastError()).str());
+ //printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
+ goto stop_cleanup;
+ }
+
+ if (ssp.dwCurrentState == SERVICE_STOPPED) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(info, "Service is already stopped");
+ //printf("Service is already stopped.\n");
+ goto stop_cleanup;
+ }
+
+ // If a stop is pending, wait for it.
+ while (ssp.dwCurrentState == SERVICE_STOP_PENDING) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(info, "Service stop pending...");
+ //printf("Service stop pending...\n");
+
+ // Do not wait longer than the wait hint. A good interval is
+ // one-tenth of the wait hint but not less than 1 second
+ // and not more than 10 seconds.
+ dwWaitTime = ssp.dwWaitHint / 10;
+ if (dwWaitTime < 1000)
+ dwWaitTime = 1000;
+ else if (dwWaitTime > 10000)
+ dwWaitTime = 10000;
+ ::Sleep(dwWaitTime);
+
+ if (!::QueryServiceStatusEx(schService,
+ SC_STATUS_PROCESS_INFO,
+ (LPBYTE)&ssp,
+ sizeof(SERVICE_STATUS_PROCESS),
+ &dwBytesNeeded)) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("QueryServiceStatusEx failed: %1%") % GetLastError()).str());
+ //printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
+ goto stop_cleanup;
+ }
+
+ if (ssp.dwCurrentState == SERVICE_STOPPED) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(info, "Service stopped successfully.");
+ //printf("Service stopped successfully.\n");
+ goto stop_cleanup;
+ }
+
+ if ((::GetTickCount() - dwStartTime) > dwTimeout) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, "Service stop timed out.");
+ //printf("Service stop timed out.\n");
+ goto stop_cleanup;
+ }
+ }
+
+ // If the service is running, dependencies must be stopped first.
+ StopDependentServices(schSCManager, schService);
+
+ // Send a stop code to the service.
+ if (!::ControlService(schService,
+ SERVICE_CONTROL_STOP,
+ (LPSERVICE_STATUS)&ssp)) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("ControlService failed: %1%") % GetLastError()).str());
+ //printf( "ControlService failed (%d)\n", GetLastError() );
+ goto stop_cleanup;
+ }
+
+ // Wait for the service to stop.
+ while (ssp.dwCurrentState != SERVICE_STOPPED) {
+ ::Sleep(ssp.dwWaitHint);
+ if (!::QueryServiceStatusEx(schService,
+ SC_STATUS_PROCESS_INFO,
+ (LPBYTE)&ssp,
+ sizeof(SERVICE_STATUS_PROCESS),
+ &dwBytesNeeded)) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("QueryServiceStatusEx failed: %1%") % GetLastError()).str());
+ //printf( "QueryServiceStatusEx failed (%d)\n", GetLastError() );
+ goto stop_cleanup;
+ }
+
+ if (ssp.dwCurrentState == SERVICE_STOPPED)
+ break;
+
+ if ((::GetTickCount() - dwStartTime) > dwTimeout) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, "Wait timed out.");
+ //printf( "Wait timed out\n" );
+ goto stop_cleanup;
+ }
+ }
+ //Note [ds, 27.09.2010]
+ QPID_LOG(info,"Service stopped successfully.");
+ //printf("Service stopped successfully\n");
+
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return true;
+
+stop_cleanup:
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return false;
+}
+
+/**
+ *
+ */
+BOOL Service::StopDependentServices(SC_HANDLE schSCManager,
+ SC_HANDLE schService)
+{
+ DWORD i;
+ DWORD dwBytesNeeded;
+ DWORD dwCount;
+
+ LPENUM_SERVICE_STATUS lpDependencies = NULL;
+ ENUM_SERVICE_STATUS ess;
+ SC_HANDLE hDepService;
+ SERVICE_STATUS_PROCESS ssp;
+
+ DWORD dwStartTime = ::GetTickCount();
+ DWORD dwTimeout = 30000; // 30-second time-out
+
+ // Pass a zero-length buffer to get the required buffer size.
+ if (::EnumDependentServices(schService,
+ SERVICE_ACTIVE,
+ lpDependencies,
+ 0,
+ &dwBytesNeeded,
+ &dwCount)) {
+ // If the Enum call succeeds, then there are no dependent
+ // services, so do nothing.
+ return TRUE;
+ }
+ else {
+ if (::GetLastError() != ERROR_MORE_DATA)
+ return FALSE; // Unexpected error
+
+ // Allocate a buffer for the dependencies.
+ lpDependencies = (LPENUM_SERVICE_STATUS) HeapAlloc(::GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ dwBytesNeeded);
+ if (!lpDependencies)
+ return FALSE;
+
+ __try {
+ // Enumerate the dependencies.
+ if (!::EnumDependentServices(schService,
+ SERVICE_ACTIVE,
+ lpDependencies,
+ dwBytesNeeded,
+ &dwBytesNeeded,
+ &dwCount))
+ return FALSE;
+
+ for (i = 0; i < dwCount; i++) {
+ ess = *(lpDependencies + i);
+ // Open the service.
+ hDepService = ::OpenService(schSCManager,
+ ess.lpServiceName,
+ SERVICE_STOP | SERVICE_QUERY_STATUS);
+ if (!hDepService)
+ return FALSE;
+
+ __try {
+ // Send a stop code.
+ if (!::ControlService(hDepService,
+ SERVICE_CONTROL_STOP,
+ (LPSERVICE_STATUS) &ssp))
+ return FALSE;
+
+ // Wait for the service to stop.
+ while (ssp.dwCurrentState != SERVICE_STOPPED) {
+ ::Sleep(ssp.dwWaitHint);
+ if (!::QueryServiceStatusEx(hDepService,
+ SC_STATUS_PROCESS_INFO,
+ (LPBYTE)&ssp,
+ sizeof(ssp),
+ &dwBytesNeeded))
+ return FALSE;
+
+ if (ssp.dwCurrentState == SERVICE_STOPPED)
+ break;
+
+ if ((::GetTickCount() - dwStartTime) > dwTimeout)
+ return FALSE;
+ }
+ }
+ __finally {
+ // Always release the service handle.
+ ::CloseServiceHandle(hDepService);
+ }
+ }
+ }
+ __finally {
+ // Always free the enumeration buffer.
+ ::HeapFree(GetProcessHeap(), 0, lpDependencies);
+ }
+ }
+ return TRUE;
+}
+
+/**
+ *
+ */
+bool Service::uninstall(const string& serviceName)
+{
+ SC_HANDLE schSCManager;
+ SC_HANDLE schService;
+
+ // Get a handle to the SCM database.
+ if (!(schSCManager = openSvcManager()))
+ return false;
+
+ // Get a handle to the service.
+ if (!(schService = openService(schSCManager, serviceName, DELETE)))
+ return false;
+
+ // Delete the service.
+ if (!::DeleteService(schService)) {
+ //Note [ds, 27.09.2010]
+ QPID_LOG(error, (boost::format("DeleteService failed: %1%") % GetLastError()).str());
+ //printf("DeleteService failed (%d)\n", GetLastError());
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return false;
+ }
+
+ //Note [ds, 27.09.2010]
+ QPID_LOG(info, "Service deleted successfully.");
+ //printf("Service deleted successfully\n");
+ ::CloseServiceHandle(schService);
+ ::CloseServiceHandle(schSCManager);
+ return true;
+}
+
+/**
+ *
+ */
+bool Service::getServiceImagePathArgs(string& args)
+{
+ // Get service ImagePath string from registry
+ string subkey = "SYSTEM\\CurrentControlSet\\Services\\" + m_serviceName;
+ HKEY hKey;
+ LONG lResult;
+ if ((lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ subkey.c_str(),
+ 0,
+ KEY_READ,
+ &hKey)) != ERROR_SUCCESS) {
+ reportApiErrorEvent("RegOpenKeyEx");
+ return false;
+ }
+
+ DWORD type, len;
+ char buf[1024];
+ len = sizeof(buf) - 1;
+ lResult = ::RegQueryValueEx(hKey,
+ "ImagePath",
+ 0,
+ &type,
+ reinterpret_cast<LPBYTE>(buf),
+ &len);
+ ::RegCloseKey(hKey);
+ if (lResult != ERROR_SUCCESS) {
+ reportApiErrorEvent( "RegQueryValueEx" );
+ return false;
+ }
+ buf[len] = 0; // Guarantee string ends with null pad (required - Windows 'quirk')
+ string ip(buf); // The service ImagePath string
+
+ // Strip service path from start
+ char szPath[MAX_PATH];
+ if (!::GetModuleFileName(NULL, szPath, MAX_PATH)) {
+ reportApiErrorEvent( "GetModuleFileName");
+ return false;
+ }
+ string sp(szPath); // The service path string
+ string ipa;
+ if (sp.length() < ip.length())
+ ipa = ip.substr(sp.length() + 1);
+ args = ipa;
+ return true;
+}
+
+/**
+ *
+ */
+void WINAPI Service::svcMain(DWORD dwArgc, char *lpszArgv[])
+{
+ // Use service name passed in
+ m_serviceName = lpszArgv[0];
+
+ // Register the handler function for the service
+ if (!(gSvcStatusHandle = ::RegisterServiceCtrlHandler(m_serviceName.c_str(),
+ SvcCtrlHandler))) {
+ reportApiErrorEvent( TEXT("RegisterServiceCtrlHandler") );
+ return;
+ }
+
+ // Initialize SERVICE_STATUS members
+ gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ gSvcStatus.dwServiceSpecificExitCode = 0;
+
+ // Report initial status to the SCM
+ ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
+
+ // Only got 1 arg? Try to obtain auto-start arg list
+ // For now, always use it...
+ string ipa;
+ if (!getServiceImagePathArgs(ipa))
+ return;
+ Service::reportInfoEvent("ipa = " + ipa);
+
+ vector<string> argsv;
+ int pargc;
+ char ** pargv = 0;
+ commandLineFromString( ipa, argsv, &pargc, &pargv );
+
+ // Assemble command line
+ string r_args = "rargs:";
+ for( DWORD i=0; i<dwArgc; i++ ) {
+ if (i)
+ r_args += " ";
+ r_args += lpszArgv[i];
+ }
+ Service::reportInfoEvent(r_args);
+ Service::reportInfoEvent(string("Hello world!"));
+
+ // Report running status when initialization is complete.
+ ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
+
+ // Create stop event
+ ghSvcStopEvent = ::CreateEvent(NULL, // default security attributes
+ TRUE, // manual reset event
+ FALSE, // not signaled
+ NULL); // no name
+ if (ghSvcStopEvent == NULL) {
+ ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
+ return;
+ }
+
+ // Pass control to main or init function
+ //if( m_main )
+ // m_main( dwArgc, lpszArgv );
+ //else
+ // svcInit( dwArgc, lpszArgv );
+
+ if (m_main)
+ m_main(pargc, pargv);
+ else
+ svcInit(pargc, pargv);
+
+ if (pargv)
+ delete[] pargv;
+
+ // Report stop as our last action...
+ ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
+}
+
+//
+// Purpose:
+// The service code
+//
+// Parameters:
+// dwArgc - Number of arguments in the lpszArgv array
+// lpszArgv - Array of strings. The first string is the name of
+// the service and subsequent strings are passed by the process
+// that called the StartService function to start the service.
+//
+// Return value:
+// None
+//
+void Service::svcInit(DWORD dwArgc, char *lpszArgv[])
+{
+ // TO_DO: Declare and set any required variables.
+ // Be sure to periodically call ReportSvcStatus() with
+ // SERVICE_START_PENDING. If initialization fails, call
+ // ReportSvcStatus with SERVICE_STOPPED.
+
+ // Create an event. The control handler function, SvcCtrlHandler,
+ // signals this event when it receives the stop control code.
+
+
+
+ // TO_DO: Perform work until service stops.
+
+ while (1) {
+ // Check whether to stop the service.
+ ::WaitForSingleObject(ghSvcStopEvent, INFINITE);
+ ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
+ return;
+ }
+}
+
+//
+// Purpose:
+// Sets the current service status and reports it to the SCM.
+//
+// Parameters:
+// dwCurrentState - The current state (see SERVICE_STATUS)
+// dwWin32ExitCode - The system error code
+// dwWaitHint - Estimated time for pending operation,
+// in milliseconds
+//
+// Return value:
+// None
+//
+void Service::ReportSvcStatus(DWORD dwCurrentState,
+ DWORD dwWin32ExitCode,
+ DWORD dwWaitHint)
+{
+ static DWORD dwCheckPoint = 1;
+
+ // Fill in the SERVICE_STATUS structure.
+ gSvcStatus.dwCurrentState = dwCurrentState;
+ gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
+ gSvcStatus.dwWaitHint = dwWaitHint;
+
+ if (dwCurrentState == SERVICE_START_PENDING)
+ gSvcStatus.dwControlsAccepted = 0;
+ else
+ gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+
+ if ((dwCurrentState == SERVICE_RUNNING) ||
+ (dwCurrentState == SERVICE_STOPPED) )
+ gSvcStatus.dwCheckPoint = 0;
+ else
+ gSvcStatus.dwCheckPoint = dwCheckPoint++;
+
+ // Report the status of the service to the SCM.
+ ::SetServiceStatus(gSvcStatusHandle, &gSvcStatus);
+}
+
+
+void WINAPI Service::svcCtrlHandler(DWORD dwCtrl)
+{
+ // Handle the requested control code.
+ switch(dwCtrl) {
+ case SERVICE_CONTROL_STOP:
+ ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
+ // Signal the service to stop.
+ // SetEvent(ghSvcStopEvent);
+ if (m_shutdownProc)
+ m_shutdownProc(m_pShutdownContext);
+
+ ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
+ break;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ break;
+
+ default:
+ break;
+ }
+}
+
+//
+// Purpose:
+// Logs messages to the event log
+//
+// Parameters:
+// szFunction - name of function that failed
+//
+// Return value:
+// None
+//
+// Remarks:
+// The service must have an entry in the Application event log.
+//
+void Service::reportApiErrorEvent(char * szFunction)
+{
+ HANDLE hEventSource;
+ LPCTSTR lpszStrings[2];
+ // char Buffer[80];
+
+ hEventSource = ::RegisterEventSource(NULL, m_serviceName.c_str());
+ if (NULL != hEventSource) {
+ lpszStrings[0] = m_serviceName.c_str();
+
+ // sprintf( Buffer, "%s failed with %d", szFunction, GetLastError());
+ // lpszStrings[1] = Buffer;
+ ostringstream buf;
+ buf << szFunction << " failed with " << GetLastError();
+ lpszStrings[1] = buf.str().c_str();
+
+#define SVC_ERROR ((DWORD)0xC0020001L)
+
+ ::ReportEvent(hEventSource, // event log handle
+ EVENTLOG_ERROR_TYPE, // event type
+ 0, // event category
+ SVC_ERROR, // event identifier
+ NULL, // no security identifier
+ 2, // size of lpszStrings array
+ 0, // no binary data
+ lpszStrings, // array of strings
+ NULL); // no binary data
+
+ ::DeregisterEventSource(hEventSource);
+ }
+}
+
+/**
+ *
+ */
+void Service::reportInfoEvent(const string & message)
+{
+ HANDLE hEventSource = ::RegisterEventSource(NULL, m_serviceName.c_str());
+ if (hEventSource) {
+// #define SVC_ERROR ((DWORD)0xC0020001L)
+#define SVC_INFO ((DWORD)0x40020001L)
+
+ LPCTSTR lpszStrings[2];
+ lpszStrings[0] = m_serviceName.c_str();
+ lpszStrings[1] = message.c_str();
+
+ ::ReportEvent(hEventSource, // event log handle
+ EVENTLOG_INFORMATION_TYPE, // event type
+ 0, // event category
+ SVC_INFO, // event identifier
+ NULL, // no security identifier
+ 2, // size of lpszStrings array
+ 0, // no binary data
+ lpszStrings, // array of strings
+ NULL); // no binary data
+
+ ::DeregisterEventSource( hEventSource );
+ }
+}
diff --git a/cpp/src/windows/Service.h b/cpp/src/windows/Service.h
new file mode 100644
index 0000000000..df0c4a67a6
--- /dev/null
+++ b/cpp/src/windows/Service.h
@@ -0,0 +1,200 @@
+#ifndef WINDOWS_SERVICE_H
+#define WINDOWS_SERVICE_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include <string>
+#include <vector>
+using std::string;
+using std::vector;
+
+#ifdef UNICODE
+#undef UNICODE
+#endif
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+
+namespace qpid {
+namespace windows {
+
+class Service
+{
+public:
+
+ /**
+ * @param serviceName the name to register the service as
+ */
+ Service(const string& serviceName);
+
+ /**
+ * Install this executable as a service
+ *
+ * @param serviceName The name of the service
+ * @param args The argument list to pass into the service
+ * @param startType The start type: SERVICE_DEMAND_START,
+ * SERVICE_AUTO_START, SERVICE_DISABLED
+ * @param account If not empty, the account name to install this
+ * service under
+ * @param password If not empty, the account password to install this
+ * service with
+ * @param depends If not empty, a comma delimited list of services
+ * that must start before this one
+ * @return false on error, which will be sent to stdout
+ */
+ static bool install(const string& serviceName,
+ const string& args,
+ DWORD startType = SERVICE_DEMAND_START,
+ const string& account = "",
+ const string& password = "",
+ const string& depends = "");
+
+ /**
+ * Uninstall this executable as a service
+ *
+ * @param serviceName the name of the service
+ * @return false on error, which will be sent to stdout
+ */
+ static bool uninstall(const string& serviceName);
+
+ /**
+ * Start the specified service
+ *
+ * @param serviceName the name of the service
+ * @return false on error, which will be sent to stdout
+ */
+ static bool start(const string& serviceName);
+
+ /**
+ * Stop the specified service
+ *
+ * @param serviceName the name of the service
+ * @return false on error, which will be sent to stdout
+ */
+ static bool stop(const string &serviceName);
+
+ typedef VOID (WINAPI *tServiceMainProc)(DWORD dwNumServicesArgs,
+ LPSTR *lpServiceArgVectors);
+
+ /**
+ * Run the service
+ *
+ * @return false if the service could not be started
+ */
+ bool run(tServiceMainProc main);
+
+ typedef void (WINAPI *tShutdownProc)(void* pContext);
+
+ /**
+ * Set the shutdown proc
+ */
+ void setShutdownProc(tShutdownProc shutdownProc,
+ void * pContext)
+ { m_shutdownProc = shutdownProc; m_pShutdownContext = pContext; }
+
+ /**
+ *
+ */
+ void reportApiErrorEvent(char* szFunction);
+
+ /**
+ *
+ */
+ void WINAPI svcMain(DWORD dwArgc, char *lpszArgv[]);
+
+ /**
+ *
+ */
+ void WINAPI svcCtrlHandler(DWORD dwCtrl);
+
+ /**
+ *
+ */
+ void svcInit(DWORD dwArgc, char *lpszArgv[]);
+
+ /**
+ *
+ */
+ static Service* getInstance() { return s_pInstance; }
+
+ void reportInfoEvent(const string& message);
+
+protected:
+
+ static SC_HANDLE openSvcManager();
+
+ static SC_HANDLE openService(SC_HANDLE hSvcManager,
+ const string& serviceName,
+ DWORD rights);
+
+ bool getServiceImagePathArgs(string& args);
+
+ /**
+ * Build a command argc/argv set from a string
+ *
+ * Note that by convention, the argv list does not OWN the actual substring
+ * pointers. To maintain that convention, this function also requires a
+ * temporary array of strings to be maintained, which will own the substring
+ * memory. Note that the substring pointers are only valid while this
+ * temporary array exists. While technically unnecessary (the argv list
+ * COULD own the substrings), it simplifies substring management, as it is
+ * trivial to place the substring vector on the stack and thereby guarantee
+ * it is freed automatically.
+ *
+ * @param args the string to parse
+ * @param argsv the vector to build to hold the substrings
+ * @param pargc pointer to the int to return the number of substrings in
+ * @param pargv pointer to the character pointer array to allocate to hold
+ * substring pointers
+ */
+ // REPLACE THIS WITH boost split_winmain static void commandLineFromString( const string & args, vector<string> & argsv, int * pargc, char ** pargv[] );
+
+ /**
+ *
+ */
+ void ReportSvcStatus(DWORD dwCurrentState,
+ DWORD dwWin32ExitCode,
+ DWORD dwWaitHint);
+
+ /**
+ *
+ */
+ static BOOL StopDependentServices(SC_HANDLE schSCManager,
+ SC_HANDLE schService);
+
+ static Service * s_pInstance; ///< Singleton
+
+ SERVICE_STATUS gSvcStatus; ///<
+ SERVICE_STATUS_HANDLE gSvcStatusHandle; ///<
+ HANDLE ghSvcStopEvent; ///<
+ string m_serviceName; ///< Specified service name
+ tServiceMainProc m_main; ///< Registered app entry point
+ tShutdownProc m_shutdownProc; ///< Registered shutdown function pointer
+ void* m_pShutdownContext; ///< Context pointer supplied to shutdown proc
+};
+
+}} // namespace qpid::windows
+
+#endif /* #ifndef WINDOWS_SERVICE_H */