Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Added Service_GetStatus immediate CA.
  • Loading branch information
vladaver authored and dblock committed Apr 28, 2014
1 parent d9b4230 commit cd27902
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 2 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
@@ -1,9 +1,10 @@
### 1.5 (Next Release)

* **Features**:
* **Bugs**:
* [#8](https://github.com/dblock/msiext/pull/8) - Added `Service_GetStatus` immediate custom action - [@vladaver](https://github.com/vladaver).
* **Bugs**:
* **Misc**:
* [#5] (https://github.com/dblock/msiext/pull/5) - Fixed WiX UI extension screens: texts, icons, margins, spacing - [@romanws](https://github.com/romanws).
* [#5](https://github.com/dblock/msiext/pull/5) - Fixed WiX UI extension screens: texts, icons, margins, spacing - [@romanws](https://github.com/romanws).

### 1.4.1114.0 (11/14/2013)

Expand Down
23 changes: 23 additions & 0 deletions src/Common/Service/ServiceInstance.cpp
Expand Up @@ -134,6 +134,29 @@ DWORD ServiceInstance::GetServiceState() const
return status.dwCurrentState;
}

std::wstring ServiceInstance::GetServiceStateString()
{
switch (GetServiceState())
{
case SERVICE_STOPPED:
return L"Stopped";
case SERVICE_START_PENDING:
return L"Starting";
case SERVICE_STOP_PENDING:
return L"Stopping";
case SERVICE_RUNNING:
return L"Running";
case SERVICE_CONTINUE_PENDING:
return L"Resuming";
case SERVICE_PAUSE_PENDING:
return L"Pausing";
case SERVICE_PAUSED:
return L"Paused";
default:
return L"Unknown";
}
}

bool ServiceInstance::Wait(DWORD timeout) const
{
DWORD slept = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/Common/Service/ServiceInstance.h
Expand Up @@ -42,6 +42,8 @@ namespace AppSecInc
void Continue();
//! return the service state
DWORD GetServiceState() const;
//! return string presentation of the service state
std::wstring GetServiceStateString();
//! returns true if the service is started
bool IsStarted() const { return (GetServiceState() == SERVICE_RUNNING); }
//! returns true if the service is stopped
Expand Down
10 changes: 10 additions & 0 deletions src/Common/Service/ServiceInstanceUnitTests.cpp
Expand Up @@ -40,6 +40,16 @@ void ServiceInstanceUnitTests::testGetServiceProcessStatus()
CPPUNIT_ASSERT(0 != status.dwProcessId);
}

void ServiceInstanceUnitTests::testGetServiceStateString()
{
ServiceManager scm;
scm.Open();
ServiceInstance instance;
instance.Open(scm, L"Eventlog");
std::wstring state = instance.GetServiceStateString();
CPPUNIT_ASSERT( L"Running" == state );
}

void ServiceInstanceUnitTests::testControl()
{
ServiceManager scm;
Expand Down
2 changes: 2 additions & 0 deletions src/Common/Service/ServiceInstanceUnitTests.h
Expand Up @@ -13,6 +13,7 @@ namespace AppSecInc
CPPUNIT_TEST( testCreateDelete );
CPPUNIT_TEST( testOpenClose );
CPPUNIT_TEST( testGetServiceProcessStatus );
CPPUNIT_TEST( testGetServiceStateString );
CPPUNIT_TEST( testControl );
CPPUNIT_TEST( testGetConfig );
CPPUNIT_TEST( testGetDescription );
Expand All @@ -23,6 +24,7 @@ namespace AppSecInc
void testOpenClose();
void testControl();
void testGetServiceProcessStatus();
void testGetServiceStateString();
void testGetConfig();
void testGetDescription();
};
Expand Down
24 changes: 24 additions & 0 deletions src/CustomActions/SystemTools/ServiceImpl.cpp
Expand Up @@ -171,3 +171,27 @@ CA_API UINT __stdcall Service_Exists(MSIHANDLE hInstall)
MSI_EXCEPTION_HANDLER_EPILOG;
return ERROR_SUCCESS;
}


CA_API UINT __stdcall Service_GetStatus(MSIHANDLE hInstall)
{
MSI_EXCEPTION_HANDLER_PROLOG;
MsiInstall msiInstall(hInstall);

std::wstring service_name = msiInstall.GetProperty(L"SERVICE_STATUS_SERVICE_NAME");
if (service_name.empty()) {
service_name = msiInstall.GetProperty(L"SERVICE_NAME");
}

AppSecInc::Service::ServiceManager scm;
scm.Open(SC_MANAGER_CONNECT|STANDARD_RIGHTS_READ);
AppSecInc::Service::ServiceInstance service;
service.Open( scm, service_name );
std::wstring state = service.GetServiceStateString();

msiInstall.SetProperty(L"SERVICE_STATUS", state);

MSI_EXCEPTION_HANDLER_EPILOG;
return ERROR_SUCCESS;
}

10 changes: 10 additions & 0 deletions src/CustomActions/SystemTools/ServiceImpl.h
Expand Up @@ -100,3 +100,13 @@ CA_API UINT __stdcall Service_GetConfig(MSIHANDLE hInstall);
\return SERVICE_EXISTS set to "1" if service exists, "0" otherwise
*/
CA_API UINT __stdcall Service_Exists(MSIHANDLE hInstall);

/*!
\brief Get status of a service
\param SERVICE_STATUS_SERVICE_NAME service name
\param SERVICE_NAME alternative property for service name, used when SERVICE_STATUS_SERVICE_NAME is not set
\return SERVICE_STATUS set to one of: Stopped, Starting, Stopping, Running, Resuming, Pausing, Paused depending on the current service state. Fails if service does not exist; SERVICE_STATUS is unchanged in this case.
*/
CA_API UINT __stdcall Service_GetStatus(MSIHANDLE hInstall);

35 changes: 35 additions & 0 deletions src/CustomActions/SystemTools/ServiceImplUnitTests.cpp
Expand Up @@ -21,6 +21,7 @@ void ServiceImplUnitTests::Test_EntryPoints()
CPPUNIT_ASSERT(NULL != GetProcAddress(h, "Service_Delete"));
CPPUNIT_ASSERT(NULL != GetProcAddress(h, "Service_GetConfig"));
CPPUNIT_ASSERT(NULL != GetProcAddress(h, "Service_Exists"));
CPPUNIT_ASSERT(NULL != GetProcAddress(h, "Service_GetStatus"));
::FreeLibrary(h);
}

Expand Down Expand Up @@ -218,3 +219,37 @@ void ServiceImplUnitTests::Test_Service_Exists()
CPPUNIT_ASSERT(ERROR_SUCCESS == hInstall.ExecuteCA(L"SystemTools.dll", L"Service_Exists"));
CPPUNIT_ASSERT(L"0" == msiInstall.GetProperty(L"SERVICE_EXISTS"));
}

void ServiceImplUnitTests::Test_Service_GetStatus()
{
AppSecInc::Msi::MsiShim hInstall;
MsiInstall msiInstall(hInstall);

msiInstall.SetProperty(L"SERVICE_STATUS_SERVICE_NAME", L"Eventlog");
CPPUNIT_ASSERT(ERROR_SUCCESS == hInstall.ExecuteCA(L"SystemTools.dll", L"Service_GetStatus"));
CPPUNIT_ASSERT(L"Running" == msiInstall.GetProperty(L"SERVICE_STATUS"));

msiInstall.SetProperty(L"SERVICE_STATUS_SERVICE_NAME", L"Wecsvc");
CPPUNIT_ASSERT(ERROR_SUCCESS == hInstall.ExecuteCA(L"SystemTools.dll", L"Service_GetStatus"));
CPPUNIT_ASSERT(L"Stopped" == msiInstall.GetProperty(L"SERVICE_STATUS"));

msiInstall.SetProperty(L"SERVICE_STATUS_SERVICE_NAME", AppSecInc::Com::GenerateGUIDStringW());
CPPUNIT_ASSERT(ERROR_SUCCESS != hInstall.ExecuteCA(L"SystemTools.dll", L"Service_GetStatus"));
// SERVICE_STATUS should remain unchanged
CPPUNIT_ASSERT(L"Stopped" == msiInstall.GetProperty(L"SERVICE_STATUS"));
}

void ServiceImplUnitTests::Test_Service_GetStatus_Accepts_SERVICE_NAME()
{
AppSecInc::Msi::MsiShim hInstall;
MsiInstall msiInstall(hInstall);

msiInstall.SetProperty(L"SERVICE_NAME", L"W32Time");
CPPUNIT_ASSERT(ERROR_SUCCESS == hInstall.ExecuteCA(L"SystemTools.dll", L"Service_GetStatus"));
CPPUNIT_ASSERT(L"Running" == msiInstall.GetProperty(L"SERVICE_STATUS"));

// more specific name should override generic one:
msiInstall.SetProperty(L"SERVICE_STATUS_SERVICE_NAME", L"Wecsvc");
CPPUNIT_ASSERT(ERROR_SUCCESS == hInstall.ExecuteCA(L"SystemTools.dll", L"Service_GetStatus"));
CPPUNIT_ASSERT(L"Stopped" == msiInstall.GetProperty(L"SERVICE_STATUS"));
}
4 changes: 4 additions & 0 deletions src/CustomActions/SystemTools/ServiceImplUnitTests.h
Expand Up @@ -18,6 +18,8 @@ namespace AppSecInc
CPPUNIT_TEST( Test_Service_Delete );
CPPUNIT_TEST( Test_Service_GetConfig );
CPPUNIT_TEST( Test_Service_Exists );
CPPUNIT_TEST( Test_Service_GetStatus );
CPPUNIT_TEST( Test_Service_GetStatus_Accepts_SERVICE_NAME );
CPPUNIT_TEST_SUITE_END();
private:
std::wstring service_name;
Expand All @@ -33,6 +35,8 @@ namespace AppSecInc
void Test_Service_Control();
void Test_Service_GetConfig();
void Test_Service_Exists();
void Test_Service_GetStatus();
void Test_Service_GetStatus_Accepts_SERVICE_NAME();
};
}
}
Expand Down
1 change: 1 addition & 0 deletions src/CustomActions/SystemTools/SystemTools.def
Expand Up @@ -35,6 +35,7 @@ EXPORTS
Service_ChangeDescription
Service_GetConfig
Service_Exists
Service_GetStatus
TemplateFiles_Immediate
TemplateFiles_Deferred
Registry_CopyBranch
Expand Down

0 comments on commit cd27902

Please sign in to comment.