Author: shuston
Date: Wed Feb 23 00:48:56 2011
New Revision: 1073566

URL: http://svn.apache.org/viewvc?rev=1073566&view=rev
Log:
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.

Added:
    qpid/branches/QPID-2519/cpp/src/windows/Service.cpp   (with props)
    qpid/branches/QPID-2519/cpp/src/windows/Service.h   (with props)
Modified:
    qpid/branches/QPID-2519/cpp/src/CMakeLists.txt
    qpid/branches/QPID-2519/cpp/src/windows/QpiddBroker.cpp

Modified: qpid/branches/QPID-2519/cpp/src/CMakeLists.txt
URL: 
http://svn.apache.org/viewvc/qpid/branches/QPID-2519/cpp/src/CMakeLists.txt?rev=1073566&r1=1073565&r2=1073566&view=diff
==============================================================================
--- qpid/branches/QPID-2519/cpp/src/CMakeLists.txt (original)
+++ qpid/branches/QPID-2519/cpp/src/CMakeLists.txt Wed Feb 23 00:48:56 2011
@@ -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

Modified: qpid/branches/QPID-2519/cpp/src/windows/QpiddBroker.cpp
URL: 
http://svn.apache.org/viewvc/qpid/branches/QPID-2519/cpp/src/windows/QpiddBroker.cpp?rev=1073566&r1=1073565&r2=1073566&view=diff
==============================================================================
--- qpid/branches/QPID-2519/cpp/src/windows/QpiddBroker.cpp (original)
+++ qpid/branches/QPID-2519/cpp/src/windows/QpiddBroker.cpp Wed Feb 23 00:48:56 
2011
@@ -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 qp
     }
 };
 
+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 *
     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 *
 
     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 *
     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);

Added: qpid/branches/QPID-2519/cpp/src/windows/Service.cpp
URL: 
http://svn.apache.org/viewvc/qpid/branches/QPID-2519/cpp/src/windows/Service.cpp?rev=1073566&view=auto
==============================================================================
--- qpid/branches/QPID-2519/cpp/src/windows/Service.cpp (added)
+++ qpid/branches/QPID-2519/cpp/src/windows/Service.cpp Wed Feb 23 00:48:56 2011
@@ -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 );
+    }
+}

Propchange: qpid/branches/QPID-2519/cpp/src/windows/Service.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: qpid/branches/QPID-2519/cpp/src/windows/Service.cpp
------------------------------------------------------------------------------
    svn:keywords = Author Date Rev Id

Added: qpid/branches/QPID-2519/cpp/src/windows/Service.h
URL: 
http://svn.apache.org/viewvc/qpid/branches/QPID-2519/cpp/src/windows/Service.h?rev=1073566&view=auto
==============================================================================
--- qpid/branches/QPID-2519/cpp/src/windows/Service.h (added)
+++ qpid/branches/QPID-2519/cpp/src/windows/Service.h Wed Feb 23 00:48:56 2011
@@ -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 */

Propchange: qpid/branches/QPID-2519/cpp/src/windows/Service.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: qpid/branches/QPID-2519/cpp/src/windows/Service.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Rev Id



---------------------------------------------------------------------
Apache Qpid - AMQP Messaging Implementation
Project:      http://qpid.apache.org
Use/Interact: mailto:commits-subscr...@qpid.apache.org

Reply via email to