git-svn-id: svn://10.65.10.50/branches/R_10_00@23067 c028cbd2-c16b-5b4b-a496-9718f37d4682
This commit is contained in:
parent
b5c2266041
commit
55412a57c6
Binary file not shown.
108
SSAservice/ESignMain.cpp
Normal file
108
SSAservice/ESignMain.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/****************************** Module Header ******************************\
|
||||
* Module Name: CppWindowsService.cpp
|
||||
* Project: CppWindowsService
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* The file defines the entry point of the application. According to the
|
||||
* arguments in the command line, the function installs or uninstalls or
|
||||
* starts the service by calling into different routines.
|
||||
*
|
||||
* This source is subject to the Microsoft Public License.
|
||||
* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
|
||||
* All other rights reserved.
|
||||
*
|
||||
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
#pragma region Includes
|
||||
#include "EsignService.h"
|
||||
#include "ServiceInstaller.h"
|
||||
#pragma endregion
|
||||
|
||||
//
|
||||
// Settings of the service
|
||||
//
|
||||
|
||||
// Internal name of the service
|
||||
#define SERVICE_NAME TEXT("ESignService")
|
||||
|
||||
// Displayed name of the service
|
||||
#define SERVICE_DISPLAY_NAME TEXT("Sirio Digital signature service")
|
||||
|
||||
// Service start options.
|
||||
#define SERVICE_START_TYPE SERVICE_AUTO_START
|
||||
|
||||
// List of service dependencies - "dep1\0dep2\0\0"
|
||||
#define SERVICE_DEPENDENCIES TEXT("")
|
||||
|
||||
// The name of the account under which the service should run
|
||||
#define SERVICE_ACCOUNT TEXT("NT AUTHORITY\\LocalService")
|
||||
|
||||
// The password to the service account name
|
||||
#define SERVICE_PASSWORD NULL
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: wmain(int, wchar_t *[])
|
||||
//
|
||||
// PURPOSE: entrypoint for the application.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// argc - number of command line arguments
|
||||
// argv - array of command line arguments
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
// wmain() either performs the command line task, or run the service.
|
||||
//
|
||||
int wmain(int argc, wchar_t *argv[])
|
||||
{
|
||||
if ((argc > 1) && ((*argv[1] == L'-' || (*argv[1] == L'/'))))
|
||||
{
|
||||
if (_wcsicmp(L"install", argv[1] + 1) == 0)
|
||||
{
|
||||
InstallService(
|
||||
SERVICE_NAME, // Name of service
|
||||
SERVICE_DISPLAY_NAME, // Name to display
|
||||
SERVICE_START_TYPE, // Service start type
|
||||
SERVICE_DEPENDENCIES, // Dependencies
|
||||
SERVICE_ACCOUNT, // Service running account
|
||||
SERVICE_PASSWORD // Password of the account
|
||||
);
|
||||
}
|
||||
else if (_wcsicmp(L"remove", argv[1] + 1) == 0)
|
||||
{
|
||||
UninstallService(SERVICE_NAME);
|
||||
}
|
||||
else if (_wcsicmp(L"start", argv[1] + 1) == 0)
|
||||
{
|
||||
StartService(SERVICE_NAME);
|
||||
}
|
||||
else if (_wcsicmp(L"stop", argv[1] + 1) == 0)
|
||||
{
|
||||
StopService(SERVICE_NAME);
|
||||
}
|
||||
else if (_wcsicmp(L"restart", argv[1] + 1) == 0)
|
||||
{
|
||||
StopService(SERVICE_NAME);
|
||||
::Sleep(1000);
|
||||
StartService(SERVICE_NAME);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CESignService service(SERVICE_NAME);
|
||||
if (!CServiceBase::Run(service))
|
||||
{
|
||||
wprintf(L"Parameters: -install -start -stop -restart -remove\n");
|
||||
wprintf(L"Running as standard process from command line\n");
|
||||
service.ServiceLoop();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
543
SSAservice/ESignService.cpp
Normal file
543
SSAservice/ESignService.cpp
Normal file
@ -0,0 +1,543 @@
|
||||
#pragma region Includes
|
||||
#include "ESignService.h"
|
||||
#include "ThreadPool.h"
|
||||
|
||||
#include "esigner.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
#include <zmq.h>
|
||||
|
||||
#pragma endregion
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Utility
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
static std::string GetIniString(const char* key)
|
||||
{
|
||||
char val[_MAX_PATH];
|
||||
::GetPrivateProfileStringA("Default", key, "", val, sizeof(val), "./esigner.ini");
|
||||
return val;
|
||||
}
|
||||
|
||||
static int GetIniInteger(const char* key)
|
||||
{
|
||||
char val[_MAX_PATH];
|
||||
::GetPrivateProfileStringA("Default", key, "", val, sizeof(val), "./esigner.ini");
|
||||
return atoi(val);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// CEsigner
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
class CEsigner
|
||||
{
|
||||
HMODULE _hESigner;
|
||||
ESignerSignProto _SignPDF;
|
||||
ESignerVerifyProto _VerifyPDF;
|
||||
bool m_bMark;
|
||||
int m_nNum;
|
||||
std::string m_strDLL, m_strPFX, m_strPEM, m_strCER, m_strEXT;
|
||||
std::string m_strTSAurl, m_strTSAuser, m_strTSApwd, m_strTSApolicy, m_strTSAcoding;
|
||||
std::string* _socket;
|
||||
|
||||
protected:
|
||||
void Log(const char* fmt, ...) const;
|
||||
bool EsitoZero(const CPathName& strResult) const;
|
||||
|
||||
public:
|
||||
bool IsOk() const { return _hESigner != NULL; }
|
||||
|
||||
void SetOutputString(std::string& s) { _socket = &s; }
|
||||
bool Sign(const CPathName& strInput, CPathName& strOutput, const CPathName& strBackup,
|
||||
const std::string& strPin, const std::string& strExt) const;
|
||||
|
||||
CEsigner();
|
||||
virtual ~CEsigner();
|
||||
};
|
||||
|
||||
void CEsigner::Log(const char* fmt, ...) const
|
||||
{
|
||||
char buffer[512];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsprintf_s(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (_socket != NULL)
|
||||
{
|
||||
*_socket += buffer;
|
||||
*_socket += "\r\n";
|
||||
}
|
||||
else
|
||||
printf("%s\n", buffer);
|
||||
}
|
||||
|
||||
CEsigner::CEsigner() : m_bMark(false), m_nNum(0), _socket(NULL)
|
||||
{
|
||||
char full[_MAX_PATH]; ::GetModuleFileNameA(NULL, full, sizeof(full));
|
||||
CPathName pn = full;
|
||||
::SetCurrentDirectoryA(pn.Path().c_str());
|
||||
|
||||
_hESigner = ::LoadLibrary(TEXT("esigner.dll"));
|
||||
if (_hESigner)
|
||||
{
|
||||
_SignPDF = (ESignerSignProto)::GetProcAddress(_hESigner, "Sign");
|
||||
_VerifyPDF = (ESignerVerifyProto)::GetProcAddress(_hESigner, "Verify");
|
||||
m_strCER = GetIniString("CER");
|
||||
m_strDLL = GetIniString("DLL");
|
||||
m_strPEM = GetIniString("PEM");
|
||||
m_strPFX = GetIniString("PFX");
|
||||
m_strEXT = GetIniString("EXT"); // PDF or P7M
|
||||
if (m_strEXT.empty())
|
||||
m_strEXT = "p7m";
|
||||
|
||||
const int nIdx = GetIniInteger("IDX");
|
||||
if (nIdx > 0)
|
||||
m_nNum = nIdx;
|
||||
}
|
||||
}
|
||||
|
||||
CEsigner::~CEsigner()
|
||||
{
|
||||
if (_hESigner)
|
||||
::FreeLibrary(_hESigner);
|
||||
}
|
||||
|
||||
bool CEsigner::EsitoZero(const CPathName& strResult) const
|
||||
{
|
||||
bool positive = false;
|
||||
FILE* f = NULL;
|
||||
if (fopen_s(&f, strResult.c_str(), "r") == 0)
|
||||
{
|
||||
char buffer[512];
|
||||
while (!feof(f))
|
||||
{
|
||||
fgets(buffer, sizeof(buffer), f);
|
||||
if (strstr(buffer, "ESITO=\"000\"") != NULL)
|
||||
{
|
||||
positive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return positive;
|
||||
}
|
||||
|
||||
|
||||
bool CEsigner::Sign(const CPathName& strInput, CPathName& strOutput, const CPathName& strBackup,
|
||||
const std::string& strPin, const std::string& strExt) const
|
||||
{
|
||||
if (_hESigner == NULL)
|
||||
{
|
||||
Log("Impossibile caricare esigner.dll");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string strMethod;
|
||||
if (!m_strDLL.empty()) // Token
|
||||
{
|
||||
strMethod = "T";
|
||||
Log("Firma tramite token");
|
||||
} else
|
||||
if (!m_strPFX.empty())
|
||||
{
|
||||
strMethod = "P";
|
||||
Log("Firma tramite file PFX");
|
||||
} else
|
||||
if (!m_strCER.empty())
|
||||
{
|
||||
strMethod = "F";
|
||||
Log("Firma tramite i file CER e PEM");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Impossibile trovare certificati o token.\nVerificare i parametri in esigner.ini");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string strOperation = "S";
|
||||
|
||||
const bool bIsTSA = m_bMark && !m_strTSAurl.empty();
|
||||
if (bIsTSA) // Firma con marcatura temporale
|
||||
strOperation += "+T";
|
||||
|
||||
const bool bIsDir = strInput.IsDirectory();
|
||||
if (bIsDir)
|
||||
strOperation += "+D";
|
||||
|
||||
std::string strIndex;
|
||||
strIndex << m_nNum;
|
||||
|
||||
char* operation = (char*)strOperation.c_str();
|
||||
char* method = (char*)strMethod.c_str();
|
||||
char* ext = (char*)(strExt.empty() ? m_strEXT.c_str() : strExt.c_str());
|
||||
char* input = (char*)strInput.c_str();
|
||||
char* output = (char*)strOutput.c_str();
|
||||
|
||||
char* cer = strMethod == "F" ? (char*)m_strCER.c_str() : NULL;
|
||||
char* pem = strMethod == "F" ? (char*)m_strPEM.c_str() : NULL;
|
||||
char* pfx = strMethod == "P" ? (char*)m_strPFX.c_str() : NULL;
|
||||
char* idx = (char*)strIndex.c_str();
|
||||
char* pin = (char*)strPin.c_str();
|
||||
char* dll = strMethod == "T" ? (char*)m_strDLL.c_str() : NULL;
|
||||
|
||||
char* TSA_output = NULL;
|
||||
char* TSA_url = NULL;
|
||||
char* TSA_user = NULL;
|
||||
char* TSA_pwd = NULL;
|
||||
char* TSA_policy = NULL;
|
||||
char* TSA_coding = NULL;
|
||||
char* TSA_rootCA = NULL;
|
||||
|
||||
if (bIsTSA) // Firma con marcatura temporale
|
||||
{
|
||||
TSA_url = (char*)m_strTSAurl.c_str();
|
||||
TSA_user = (char*)m_strTSAuser.c_str();
|
||||
TSA_pwd = (char*)m_strTSApwd.c_str();
|
||||
TSA_policy = (char*)m_strTSApolicy.c_str();
|
||||
TSA_coding = (char*)m_strTSAcoding.c_str();
|
||||
}
|
||||
|
||||
if (bIsDir)
|
||||
{
|
||||
if (strOutput.empty())
|
||||
output = input;
|
||||
}
|
||||
else
|
||||
{
|
||||
//ext = strInput.Lower().EndsWith(".pdf") ? ".pdf.p7m" : ".p7m";
|
||||
if (strOutput.empty())
|
||||
{
|
||||
strOutput = strInput;
|
||||
if (strExt == "p7m")
|
||||
strOutput += ".p7m";
|
||||
}
|
||||
::DeleteFileA(strOutput.c_str()); // Altrimenti la fantastica dll s'incazza come una biscia
|
||||
|
||||
while (!strOutput.Ext().empty())
|
||||
strOutput.SetExt("");
|
||||
output = (char*)strOutput.c_str();
|
||||
}
|
||||
|
||||
int res = _SignPDF(operation, method,
|
||||
input, output, NULL, ext,
|
||||
cer, pem, pfx, dll, pin, NULL, idx,
|
||||
TSA_url, TSA_user, TSA_pwd, TSA_policy, TSA_coding, NULL);
|
||||
|
||||
int nSigned = 0;
|
||||
if (bIsDir) // +D only
|
||||
{
|
||||
std::vector<CPathName> infiles;
|
||||
CPathName pnInput; pnInput.Set(strInput.c_str(), "*", "pdf");
|
||||
const size_t n = pnInput.List(infiles);
|
||||
if (n > 0)
|
||||
{
|
||||
Log("Trovati %d documenti da firmare in %s", n, strInput.c_str());
|
||||
|
||||
res = 0;
|
||||
CPathName pnResult;
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
const CPathName& fi = infiles[i];
|
||||
pnResult.Set(strOutput.c_str(), fi.FullName().c_str(), "result");
|
||||
if (pnResult.IsFile() && EsitoZero(pnResult))
|
||||
{
|
||||
::DeleteFileA(pnResult.c_str());
|
||||
nSigned++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Impossibile firmare il file %s", fi.c_str());
|
||||
res = -99;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mode = 0; // 0=nulla; 1=cancella; 2=backup
|
||||
if (strBackup == "Cestino" || strBackup == "NULL" || strBackup == "Delete" ||
|
||||
strBackup == "Basket" || strBackup == "Trash")
|
||||
mode = 1; else
|
||||
if (strBackup.IsDirectory())
|
||||
mode = 2;
|
||||
|
||||
if (res == 0 && mode != 0 && n > 0)
|
||||
{
|
||||
std::string msg;
|
||||
if (mode == 1)
|
||||
{
|
||||
msg = "Eliminazione file originali in ";
|
||||
msg += strInput;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = "Spostamento file originali da ";
|
||||
msg += strInput;
|
||||
msg += " a ";
|
||||
msg += strBackup;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
const CPathName& fsrc = infiles[i];
|
||||
CPathName fout = fsrc;
|
||||
fout.SetPath(strBackup.c_str());
|
||||
if (mode == 2)
|
||||
::MoveFileA(fsrc.c_str(), fout.c_str());
|
||||
else
|
||||
::DeleteFileA(fsrc.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Un documento da firmare in %s", strInput.c_str());
|
||||
nSigned == res ? 0 : 1;
|
||||
}
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
if (nSigned > 0)
|
||||
Log("Sono stati firmati %d documenti in %s", nSigned, output);
|
||||
else
|
||||
Log("Non è stato firmato alcun documento");
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* msg = NULL;
|
||||
switch (res)
|
||||
{
|
||||
case -2: msg = "Errore di lettura del certificato"; break;
|
||||
case -3: msg = "Errore di lettura della chiave privata"; break;
|
||||
case -4: msg = "Errore di lettura file PFX"; break;
|
||||
case -5: msg = "Errore recupero certificato da Token"; break;
|
||||
case -6: msg = "Errore apertura file"; break;
|
||||
case -7:
|
||||
case -8:
|
||||
case -9: msg = "Errore conatatto TSA"; break;
|
||||
case -10: msg = "Accesso al token fallito"; break;
|
||||
case -11: msg = "Impossibile trovare dll driver del token"; break;
|
||||
case -14: msg = "Il file di output esiste già"; break;
|
||||
case -15:
|
||||
case -16: msg = "Errore di marcatura temporale"; break;
|
||||
case -99: msg = "Impossibile trovare .result per tutti i file della cartella"; break;
|
||||
default : msg = "Errore di accesso alle operazioni di firma"; break;
|
||||
}
|
||||
|
||||
Log(msg);
|
||||
}
|
||||
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// CESignService
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
CESignService::CESignService(LPCTSTR pszServiceName, BOOL fCanStop, BOOL fCanShutdown, BOOL fCanPauseContinue)
|
||||
: CServiceBase(pszServiceName, fCanStop, fCanShutdown, fCanPauseContinue)
|
||||
{
|
||||
m_fStopping = FALSE;
|
||||
|
||||
// Create a manual-reset event that is not signaled at first to indicate
|
||||
// the stopped signal of the service.
|
||||
m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (m_hStoppedEvent == NULL)
|
||||
throw GetLastError();
|
||||
}
|
||||
|
||||
|
||||
CESignService::~CESignService(void)
|
||||
{
|
||||
if (m_hStoppedEvent)
|
||||
{
|
||||
CloseHandle(m_hStoppedEvent);
|
||||
m_hStoppedEvent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CESignService::OnStart(DWORD, LPWSTR *)
|
||||
//
|
||||
// PURPOSE: The function is executed when a Start command is sent to the
|
||||
// service by the SCM or when the operating system starts (for a service
|
||||
// that starts automatically). It specifies actions to take when the
|
||||
// service starts. In this code sample, OnStart logs a service-start
|
||||
// message to the Application log, and queues the main service function for
|
||||
// execution in a thread pool worker thread.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * dwArgc - number of command line arguments
|
||||
// * lpszArgv - array of command line arguments
|
||||
//
|
||||
// NOTE: A service application is designed to be long running. Therefore,
|
||||
// it usually polls or monitors something in the system. The monitoring is
|
||||
// set up in the OnStart method. However, OnStart does not actually do the
|
||||
// monitoring. The OnStart method must return to the operating system after
|
||||
// the service's operation has begun. It must not loop forever or block. To
|
||||
// set up a simple monitoring mechanism, one general solution is to create
|
||||
// a timer in OnStart. The timer would then raise events in your code
|
||||
// periodically, at which time your service could do its monitoring. The
|
||||
// other solution is to spawn a new thread to perform the main service
|
||||
// functions, which is demonstrated in this code sample.
|
||||
//
|
||||
void CESignService::OnStart(DWORD dwArgc, LPWSTR *lpszArgv)
|
||||
{
|
||||
// Log a service start message to the Application log.
|
||||
WriteEventLogEntry(TEXT("ESignService Starting"));
|
||||
|
||||
// Queue the main service function for execution in a worker thread.
|
||||
CThreadPool::QueueUserWorkItem(&CESignService::ServiceLoop, this);
|
||||
}
|
||||
|
||||
char CESignService::ParseHex(const char* hex) const
|
||||
{
|
||||
int n = 0;
|
||||
sscanf_s(hex, "%2X", &n);
|
||||
return char(n);
|
||||
}
|
||||
|
||||
const char* CESignService::ParseString(const char* equal, std::string& str) const
|
||||
{
|
||||
str = "";
|
||||
const char* s = equal;
|
||||
for (; *s != '&' && *s > ' '; s++)
|
||||
{
|
||||
if (*s == '%')
|
||||
{
|
||||
const char h = ParseHex(s+1);
|
||||
str += h;
|
||||
s += 2;
|
||||
}
|
||||
else
|
||||
str += *s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
bool CESignService::ParseGET(const char* get, CPathName& src, CPathName& dst, CPathName& bck,
|
||||
std::string& pin, std::string& ext) const
|
||||
{
|
||||
src = dst = bck = "";
|
||||
pin = "";
|
||||
ext = "";
|
||||
while (get != NULL)
|
||||
{
|
||||
const char* equal = strchr(get, '=');
|
||||
if (equal != NULL)
|
||||
{
|
||||
switch (*(equal-3))
|
||||
{
|
||||
case 'B': get = ParseString(equal+1, bck); break; // BCK
|
||||
case 'D': get = ParseString(equal+1, dst); break; // DST
|
||||
case 'E': get = ParseString(equal+1, ext); break; // EXT
|
||||
case 'P': get = ParseString(equal+1, pin); break; // PIN
|
||||
case 'S': get = ParseString(equal+1, src); break; // SRC
|
||||
default : break;
|
||||
}
|
||||
}
|
||||
else
|
||||
get = equal;
|
||||
}
|
||||
return !src.empty();
|
||||
}
|
||||
|
||||
//
|
||||
// FUNCTION: CESignService::ServiceLoop(void)
|
||||
//
|
||||
// PURPOSE: The method performs the main function of the service. It runs
|
||||
// on a thread pool worker thread.
|
||||
//
|
||||
void CESignService::ServiceLoop(void)
|
||||
{
|
||||
void *ctx = zmq_ctx_new ();
|
||||
assert (ctx);
|
||||
/* Create ZMQ_STREAM socket */
|
||||
void *socket = zmq_socket (ctx, ZMQ_STREAM);
|
||||
assert (socket);
|
||||
|
||||
int nPort = GetIniInteger("PORT");
|
||||
if (nPort < 1000)
|
||||
nPort = 8083;
|
||||
char port[32]; sprintf_s(port, sizeof(port), "tcp://*:%d", nPort);
|
||||
int rc = zmq_bind (socket, port);
|
||||
assert (rc == 0);
|
||||
const int timeout = 5000; // 5 secondi di timeout per verificare anche m_fStopping
|
||||
zmq_setsockopt (socket, ZMQ_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
|
||||
/* Data structure to hold the ZMQ_STREAM ID */
|
||||
uint8_t id [256];
|
||||
/* Data structure to hold the ZMQ_STREAM received data */
|
||||
const size_t raw_max = 512;
|
||||
char* raw = new char[raw_max];
|
||||
while (!m_fStopping)
|
||||
{
|
||||
/* Get HTTP request; ID frame and then request */
|
||||
memset(id, 0, sizeof(id));
|
||||
const int id_size = zmq_recv (socket, id, sizeof(id), 0);
|
||||
if (id_size <= 0)
|
||||
continue;
|
||||
|
||||
memset(raw, 0, raw_max);
|
||||
const size_t raw_size = zmq_recv (socket, raw, raw_max, 0);
|
||||
|
||||
CPathName src, dst, bck;
|
||||
std::string pin, ext;
|
||||
ParseGET(raw, src, dst, bck, pin, ext);
|
||||
|
||||
/* Sends the ID frame followed by the response */
|
||||
zmq_send (socket, id, id_size, ZMQ_SNDMORE);
|
||||
|
||||
/* Prepares the response */
|
||||
std::string log = "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n";
|
||||
CEsigner esigner;
|
||||
esigner.SetOutputString(log);
|
||||
esigner.Sign(src, dst, bck, pin, ext);
|
||||
zmq_send (socket, log.c_str(),log.length(), ZMQ_SNDMORE);
|
||||
|
||||
/* Closes the connection by sending the ID frame followed by a zero response */
|
||||
zmq_send (socket, id, id_size, ZMQ_SNDMORE);
|
||||
zmq_send (socket, 0, 0, ZMQ_SNDMORE);
|
||||
/* NOTE: If we don't use ZMQ_SNDMORE, then we won't be able to send more */
|
||||
/* message to any client */
|
||||
}
|
||||
delete [] raw;
|
||||
zmq_close (socket);
|
||||
zmq_ctx_destroy (ctx);
|
||||
|
||||
// Signal the stopped event.
|
||||
SetEvent(m_hStoppedEvent);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CESignService::OnStop(void)
|
||||
//
|
||||
// PURPOSE: The function is executed when a Stop command is sent to the
|
||||
// service by SCM. It specifies actions to take when a service stops
|
||||
// running. In this code sample, OnStop logs a service-stop message to the
|
||||
// Application log, and waits for the finish of the main service function.
|
||||
//
|
||||
// COMMENTS:
|
||||
// Be sure to periodically call ReportServiceStatus() with
|
||||
// SERVICE_STOP_PENDING if the procedure is going to take long time.
|
||||
//
|
||||
void CESignService::OnStop()
|
||||
{
|
||||
// Log a service stop message to the Application log.
|
||||
WriteEventLogEntry(L"ESignService Stopping");
|
||||
|
||||
// Indicate that the service is stopping and wait for the finish of the
|
||||
// main service function (ServiceWorkerThread).
|
||||
m_fStopping = TRUE;
|
||||
if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
|
||||
throw GetLastError();
|
||||
}
|
46
SSAservice/ESignService.h
Normal file
46
SSAservice/ESignService.h
Normal file
@ -0,0 +1,46 @@
|
||||
/****************************** Module Header ******************************\
|
||||
* Module Name: SampleService.h
|
||||
* Project: CppWindowsService
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Provides a sample service class that derives from the service base class -
|
||||
* CServiceBase. The sample service logs the service start and stop
|
||||
* information to the Application event log, and shows how to run the main
|
||||
* function of the service in a thread pool worker thread.
|
||||
*
|
||||
* This source is subject to the Microsoft Public License.
|
||||
* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
|
||||
* All other rights reserved.
|
||||
*
|
||||
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ServiceBase.h"
|
||||
#include "PathName.h"
|
||||
|
||||
class CESignService : public CServiceBase
|
||||
{
|
||||
private:
|
||||
BOOL m_fStopping;
|
||||
HANDLE m_hStoppedEvent;
|
||||
|
||||
protected:
|
||||
virtual void OnStart(DWORD dwArgc, PWSTR *pszArgv);
|
||||
virtual void OnStop();
|
||||
|
||||
char ParseHex(const char* hex) const;
|
||||
const char* ParseString(const char* s, std::string& str) const;
|
||||
bool ParseGET(const char* get, CPathName& src, CPathName& dst,
|
||||
CPathName& bck, std::string& pin, std::string& ext) const;
|
||||
|
||||
public:
|
||||
CESignService(LPCTSTR pszServiceName, BOOL fCanStop = TRUE,
|
||||
BOOL fCanShutdown = TRUE, BOOL fCanPauseContinue = FALSE);
|
||||
void ServiceLoop(void);
|
||||
virtual ~CESignService();
|
||||
|
||||
};
|
39
SSAservice/EsignTest.html
Normal file
39
SSAservice/EsignTest.html
Normal file
@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" >
|
||||
<head>
|
||||
<title>Firma Digitale Esigner</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="http://127.0.0.1:8083/esign" method="get" target="Result" >
|
||||
<table bgcolor="LightBlue ">
|
||||
<caption style="background:LightCyan">Firma digitale documenti PDF</caption>
|
||||
<tr>
|
||||
<td>Cartella o documento da firmare:</td>
|
||||
<td><input type="text" name="SRC" size="80" maxlenght="256"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cartella di destinazione dei documenti firmati:</td>
|
||||
<td><input type="text" name="DST" size="80" maxlenght="256"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cartella di backup dei documenti originali:</td>
|
||||
<td><input type="text" name="BCK" size="80" maxlenght="256"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><hr/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PIN o password:</td>
|
||||
<td><input type="password" name="PIN" size="8" maxlenght="8" />
|
||||
<input type="submit" value="Firma documenti" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<iframe width="100%%" height="480" style="background:LightCyan" name="Result" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
130
SSAservice/PathName.cpp
Normal file
130
SSAservice/PathName.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
#pragma region Includes
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define STRICT
|
||||
#include <windows.h>
|
||||
|
||||
#include "PathName.h"
|
||||
#include <strstream>
|
||||
#pragma endregion
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// utility
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
std::string& operator<<(std::string& str, int n)
|
||||
{
|
||||
std::strstream convert;
|
||||
convert << n << '\0';
|
||||
str += convert.str();
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string& operator<<(std::string& str, char c)
|
||||
{
|
||||
const char s[2] = { c, '\0' };
|
||||
str += s;
|
||||
return str;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// CPathName
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
std::string CPathName::Path() const
|
||||
{
|
||||
char drive[_MAX_DRIVE], dir[_MAX_DIR];
|
||||
_splitpath_s(c_str(), drive, sizeof(drive), dir, sizeof(dir), NULL, 0, NULL, 0);
|
||||
std::string s = drive; s += dir;
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string CPathName::FullName() const
|
||||
{
|
||||
char name[_MAX_FNAME], ext[_MAX_EXT];
|
||||
_splitpath_s(c_str(), NULL, 0, NULL, 0, name, sizeof(name), ext, sizeof(ext));
|
||||
std::string s = name; s += ext;
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string CPathName::Name() const
|
||||
{
|
||||
char name[_MAX_FNAME];
|
||||
_splitpath_s(c_str(), NULL, 0, NULL, 0, name, sizeof(name), NULL, 0);
|
||||
return name;
|
||||
}
|
||||
std::string CPathName::Ext() const
|
||||
{
|
||||
char ext[_MAX_EXT];
|
||||
_splitpath_s(c_str(), NULL, 0, NULL, 0, NULL, 0, ext, sizeof(ext));
|
||||
return ext;
|
||||
}
|
||||
|
||||
CPathName& CPathName::Set(const char* p, const char* n, const char* e)
|
||||
{
|
||||
char path[_MAX_PATH];
|
||||
_makepath_s(path, sizeof(path), NULL, p, n, e);
|
||||
return operator=(path);
|
||||
}
|
||||
|
||||
CPathName& CPathName::SetPath(const char* p)
|
||||
{
|
||||
char name[_MAX_FNAME], ext[_MAX_EXT], path[_MAX_PATH];
|
||||
_splitpath_s(c_str(), NULL, NULL, NULL, NULL, name, sizeof(name), ext, sizeof(ext));
|
||||
_makepath_s(path, sizeof(path), NULL, p, name, ext);
|
||||
return operator=(path);
|
||||
}
|
||||
|
||||
CPathName& CPathName::SetName(const char* n)
|
||||
{
|
||||
char drive[_MAX_DRIVE], dir[_MAX_DIR], ext[_MAX_EXT], path[_MAX_PATH];
|
||||
_splitpath_s(c_str(), drive, sizeof(drive), dir, sizeof(dir), NULL, 0, ext, sizeof(ext));
|
||||
_makepath_s(path, sizeof(path), drive, dir, n, ext);
|
||||
return operator=(path);
|
||||
}
|
||||
|
||||
CPathName& CPathName::SetExt(const char* e)
|
||||
{
|
||||
char drive[_MAX_DRIVE], dir[_MAX_DIR], name[_MAX_FNAME];
|
||||
_splitpath_s(c_str(), drive, sizeof(drive), dir, sizeof(dir), name, sizeof(name), NULL, 0);
|
||||
char path[_MAX_PATH];
|
||||
_makepath_s(path, sizeof(path), drive, dir, name, e);
|
||||
return operator=(path);
|
||||
}
|
||||
|
||||
bool CPathName::IsFile() const
|
||||
{
|
||||
if (empty())
|
||||
return false;
|
||||
DWORD dwAttrib = ::GetFileAttributesA(c_str());
|
||||
return (dwAttrib != INVALID_FILE_ATTRIBUTES) && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
bool CPathName::IsDirectory() const
|
||||
{
|
||||
if (empty())
|
||||
return false;
|
||||
DWORD dwAttrib = ::GetFileAttributesA(c_str());
|
||||
return (dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
size_t CPathName::List(std::vector<CPathName>& files) const
|
||||
{
|
||||
WIN32_FIND_DATAA ffd;
|
||||
HANDLE hFind = ::FindFirstFileA(c_str(), &ffd);
|
||||
while (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CPathName pn(ffd.cFileName);
|
||||
pn.SetPath(Path().c_str());
|
||||
files.push_back(pn);
|
||||
|
||||
if (!::FindNextFileA(hFind, &ffd))
|
||||
{
|
||||
::FindClose(hFind);
|
||||
hFind = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
return files.size();
|
||||
}
|
||||
|
||||
|
42
SSAservice/PathName.h
Normal file
42
SSAservice/PathName.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#ifndef __PATHNAME_H__
|
||||
#define __PATHNAME_H__
|
||||
|
||||
#ifndef _STRING_
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#ifndef _VECTOR_
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// CPathName
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
class CPathName : public std::string
|
||||
{
|
||||
protected:
|
||||
|
||||
public:
|
||||
std::string Path() const;
|
||||
std::string FullName() const;
|
||||
std::string Name() const;
|
||||
std::string Ext() const;
|
||||
|
||||
CPathName& Set(const char* p, const char* n, const char* e);
|
||||
CPathName& SetPath(const char* p);
|
||||
CPathName& SetName(const char* n);
|
||||
CPathName& SetExt(const char* e);
|
||||
bool IsFile() const;
|
||||
bool IsDirectory() const;
|
||||
size_t List(std::vector<CPathName>& files) const;
|
||||
|
||||
CPathName() {}
|
||||
CPathName(const char* pathname) : std::string(pathname) {}
|
||||
};
|
||||
|
||||
std::string& operator<<(std::string& str, int n);
|
||||
std::string& operator<<(std::string& str, char c);
|
||||
|
||||
#endif
|
108
SSAservice/SSAmain.cpp
Normal file
108
SSAservice/SSAmain.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/****************************** Module Header ******************************\
|
||||
* Module Name: CppWindowsService.cpp
|
||||
* Project: CppWindowsService
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* The file defines the entry point of the application. According to the
|
||||
* arguments in the command line, the function installs or uninstalls or
|
||||
* starts the service by calling into different routines.
|
||||
*
|
||||
* This source is subject to the Microsoft Public License.
|
||||
* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
|
||||
* All other rights reserved.
|
||||
*
|
||||
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
#pragma region Includes
|
||||
#include "SSAservice.h"
|
||||
#include "ServiceInstaller.h"
|
||||
#pragma endregion
|
||||
|
||||
//
|
||||
// Settings of the service
|
||||
//
|
||||
|
||||
// Internal name of the service
|
||||
#define SERVICE_NAME TEXT("SSAservice")
|
||||
|
||||
// Displayed name of the service
|
||||
#define SERVICE_DISPLAY_NAME TEXT("SSA Sirio Software Autentication")
|
||||
|
||||
// Service start options.
|
||||
#define SERVICE_START_TYPE SERVICE_AUTO_START
|
||||
|
||||
// List of service dependencies - "dep1\0dep2\0\0"
|
||||
#define SERVICE_DEPENDENCIES TEXT("")
|
||||
|
||||
// The name of the account under which the service should run
|
||||
#define SERVICE_ACCOUNT TEXT("NT AUTHORITY\\LocalService")
|
||||
|
||||
// The password to the service account name
|
||||
#define SERVICE_PASSWORD NULL
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: wmain(int, wchar_t *[])
|
||||
//
|
||||
// PURPOSE: entrypoint for the application.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// argc - number of command line arguments
|
||||
// argv - array of command line arguments
|
||||
//
|
||||
// RETURN VALUE:
|
||||
// none
|
||||
//
|
||||
// COMMENTS:
|
||||
// wmain() either performs the command line task, or run the service.
|
||||
//
|
||||
int wmain(int argc, wchar_t *argv[])
|
||||
{
|
||||
if ((argc > 1) && ((*argv[1] == L'-' || (*argv[1] == L'/'))))
|
||||
{
|
||||
if (_wcsicmp(L"install", argv[1] + 1) == 0)
|
||||
{
|
||||
InstallService(
|
||||
SERVICE_NAME, // Name of service
|
||||
SERVICE_DISPLAY_NAME, // Name to display
|
||||
SERVICE_START_TYPE, // Service start type
|
||||
SERVICE_DEPENDENCIES, // Dependencies
|
||||
SERVICE_ACCOUNT, // Service running account
|
||||
SERVICE_PASSWORD // Password of the account
|
||||
);
|
||||
}
|
||||
else if (_wcsicmp(L"remove", argv[1] + 1) == 0)
|
||||
{
|
||||
UninstallService(SERVICE_NAME);
|
||||
}
|
||||
else if (_wcsicmp(L"start", argv[1] + 1) == 0)
|
||||
{
|
||||
StartService(SERVICE_NAME);
|
||||
}
|
||||
else if (_wcsicmp(L"stop", argv[1] + 1) == 0)
|
||||
{
|
||||
StopService(SERVICE_NAME);
|
||||
}
|
||||
else if (_wcsicmp(L"restart", argv[1] + 1) == 0)
|
||||
{
|
||||
StopService(SERVICE_NAME);
|
||||
::Sleep(1000);
|
||||
StartService(SERVICE_NAME);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CSSAservice service(SERVICE_NAME);
|
||||
if (!CServiceBase::Run(service))
|
||||
{
|
||||
wprintf(L"Parameters: -install -start -stop -restart -remove\n");
|
||||
wprintf(L"Running as standard process from command line\n");
|
||||
service.ServiceLoop();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
249
SSAservice/SSAservice.cpp
Normal file
249
SSAservice/SSAservice.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
#pragma region Includes
|
||||
#include "SSAservice.h"
|
||||
#include "ThreadPool.h"
|
||||
#include "PathName.h"
|
||||
|
||||
#include <psapi.h>
|
||||
#pragma comment(lib, "Psapi.lib")
|
||||
|
||||
#pragma endregion
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// CSSAservice
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
BOOL CSSAservice::FindAgent(HANDLE& hFound, DWORD& pid) const
|
||||
{
|
||||
DWORD* aProcesses = NULL;
|
||||
DWORD nItems = 0, nFound = 0, i = 0;
|
||||
|
||||
hFound = 0;
|
||||
pid = 0;
|
||||
|
||||
for (nItems = 256; ; nItems *= 2)
|
||||
{
|
||||
DWORD cbNeeded = 0;
|
||||
free(aProcesses);
|
||||
aProcesses = (DWORD*)calloc(nItems, sizeof(DWORD));
|
||||
if (!EnumProcesses(aProcesses, nItems*sizeof(DWORD), &cbNeeded))
|
||||
{
|
||||
free(aProcesses);
|
||||
return FALSE;
|
||||
}
|
||||
nFound = cbNeeded / sizeof(DWORD);
|
||||
if (nFound < nItems)
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < nFound && hFound == NULL; i++) if (aProcesses[i])
|
||||
{
|
||||
HANDLE hProcess = ::OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i] );
|
||||
if (hProcess != NULL)
|
||||
{
|
||||
HMODULE hMod;
|
||||
DWORD cbNeeded;
|
||||
if (::EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) )
|
||||
{
|
||||
TCHAR szProcessName[MAX_PATH] = { 0 };
|
||||
::GetModuleBaseName( hProcess, hMod, szProcessName, sizeof(szProcessName)/sizeof(TCHAR) );
|
||||
if (wcsstr(szProcessName, _agent) != NULL)
|
||||
{
|
||||
hFound = ::OpenProcess( SYNCHRONIZE, FALSE, aProcesses[i] ); // Waitable process handle
|
||||
pid = aProcesses[i];
|
||||
}
|
||||
}
|
||||
// Release the handle to the process.
|
||||
CloseHandle( hProcess );
|
||||
}
|
||||
}
|
||||
|
||||
free(aProcesses);
|
||||
return hFound != NULL;
|
||||
}
|
||||
|
||||
BOOL CSSAservice::FindOrCreateAgent(HANDLE& hProcess, DWORD& pid) const
|
||||
{
|
||||
if (!FindAgent(hProcess, pid))
|
||||
{
|
||||
STARTUPINFO si = { 0 };
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
si.cb = sizeof(si); // si.wShowWindow = SW_HIDE;
|
||||
|
||||
std::wstring str;
|
||||
str = L"Creating instance of "; str += _agent;
|
||||
WriteEventLogEntry(str.c_str());
|
||||
if (CreateProcess(_agent,
|
||||
NULL, // lpCommandLine
|
||||
NULL, // lpProcessAttributes
|
||||
NULL, // lpThreadAttributes
|
||||
FALSE, // no Handle inheritance
|
||||
CREATE_NO_WINDOW | IDLE_PRIORITY_CLASS, // creation flags
|
||||
NULL, // Use parent's environment block
|
||||
NULL, // Use parent's starting directory
|
||||
&si,
|
||||
&pi))
|
||||
{
|
||||
hProcess = pi.hProcess;
|
||||
pid = pi.dwProcessId;
|
||||
}
|
||||
else
|
||||
WriteErrorLogEntry(TEXT("CreateProcess"));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wstring str;
|
||||
str = L"Attaching to instance of "; str += _agent;
|
||||
WriteEventLogEntry(str.c_str());
|
||||
}
|
||||
return hProcess != 0;
|
||||
}
|
||||
|
||||
void CSSAservice::CheckDirectory() const
|
||||
{
|
||||
char full[_MAX_PATH];
|
||||
::GetModuleFileNameA(NULL, full, sizeof(full));
|
||||
CPathName pn = full;
|
||||
::SetCurrentDirectoryA(pn.Path().c_str());
|
||||
}
|
||||
|
||||
CSSAservice::CSSAservice(LPCTSTR pszServiceName,
|
||||
BOOL fCanStop, BOOL fCanShutdown, BOOL fCanPauseContinue)
|
||||
: CServiceBase(pszServiceName, fCanStop, fCanShutdown, fCanPauseContinue), _agent(NULL)
|
||||
{
|
||||
m_fStopping = FALSE;
|
||||
|
||||
// Create a manual-reset event that is not signaled at first to indicate
|
||||
// the stopped signal of the service.
|
||||
m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (m_hStoppedEvent == NULL)
|
||||
throw GetLastError();
|
||||
}
|
||||
|
||||
|
||||
CSSAservice::~CSSAservice(void)
|
||||
{
|
||||
if (m_hStoppedEvent)
|
||||
{
|
||||
CloseHandle(m_hStoppedEvent);
|
||||
m_hStoppedEvent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CSSAservice::OnStart(DWORD, LPWSTR *)
|
||||
//
|
||||
// PURPOSE: The function is executed when a Start command is sent to the
|
||||
// service by the SCM or when the operating system starts (for a service
|
||||
// that starts automatically). It specifies actions to take when the
|
||||
// service starts. In this code sample, OnStart logs a service-start
|
||||
// message to the Application log, and queues the main service function for
|
||||
// execution in a thread pool worker thread.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * dwArgc - number of command line arguments
|
||||
// * lpszArgv - array of command line arguments
|
||||
//
|
||||
// NOTE: A service application is designed to be long running. Therefore,
|
||||
// it usually polls or monitors something in the system. The monitoring is
|
||||
// set up in the OnStart method. However, OnStart does not actually do the
|
||||
// monitoring. The OnStart method must return to the operating system after
|
||||
// the service's operation has begun. It must not loop forever or block. To
|
||||
// set up a simple monitoring mechanism, one general solution is to create
|
||||
// a timer in OnStart. The timer would then raise events in your code
|
||||
// periodically, at which time your service could do its monitoring. The
|
||||
// other solution is to spawn a new thread to perform the main service
|
||||
// functions, which is demonstrated in this code sample.
|
||||
//
|
||||
void CSSAservice::OnStart(DWORD dwArgc, LPWSTR *lpszArgv)
|
||||
{
|
||||
// Log a service start message to the Application log.
|
||||
WriteEventLogEntry(TEXT("SSAservice Starting"));
|
||||
|
||||
// Queue the main service function for execution in a worker thread.
|
||||
CThreadPool::QueueUserWorkItem(&CSSAservice::ServiceLoop, this);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CSSAservice::ServiceLoop(void)
|
||||
//
|
||||
// PURPOSE: The method performs the main function of the service. It runs
|
||||
// on a thread pool worker thread.
|
||||
//
|
||||
void CSSAservice::ServiceLoop(void)
|
||||
{
|
||||
const int nSeconds = 5;
|
||||
CheckDirectory();
|
||||
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE hf = ::FindFirstFile(TEXT("*.ssa"), &fd);
|
||||
if (hf)
|
||||
{
|
||||
_agent = TEXT("SSAagent.exe");
|
||||
::FindClose(hf);
|
||||
}
|
||||
else
|
||||
_agent = TEXT("Authoriz.exe");
|
||||
|
||||
|
||||
HANDLE hProcess = 0;
|
||||
DWORD pid = 0;
|
||||
FindOrCreateAgent(hProcess, pid);
|
||||
|
||||
// Periodically check if the service is stopping.
|
||||
while (hProcess && !m_fStopping)
|
||||
{
|
||||
DWORD ret = ::WaitForSingleObject(hProcess, nSeconds * 1000);
|
||||
if (ret != WAIT_TIMEOUT)
|
||||
{
|
||||
WriteEventLogEntry(TEXT("Unexpected agent termination"), EVENTLOG_WARNING_TYPE);
|
||||
::CloseHandle(hProcess);
|
||||
FindOrCreateAgent(hProcess, pid);
|
||||
}
|
||||
}
|
||||
|
||||
if (hProcess)
|
||||
{
|
||||
::CloseHandle(hProcess);
|
||||
HANDLE hAgent = ::OpenProcess(PROCESS_TERMINATE, FALSE, pid);
|
||||
if (hAgent)
|
||||
{
|
||||
if (::TerminateProcess(hAgent, 0))
|
||||
_agent = NULL;
|
||||
else
|
||||
WriteErrorLogEntry(TEXT("TerminateProcess"));
|
||||
::CloseHandle(hAgent);
|
||||
}
|
||||
else
|
||||
WriteErrorLogEntry(TEXT("OpenProcess(PROCESS_TERMINATE)"));
|
||||
}
|
||||
|
||||
// Signal the stopped event.
|
||||
SetEvent(m_hStoppedEvent);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CSSAservice::OnStop(void)
|
||||
//
|
||||
// PURPOSE: The function is executed when a Stop command is sent to the
|
||||
// service by SCM. It specifies actions to take when a service stops
|
||||
// running. In this code sample, OnStop logs a service-stop message to the
|
||||
// Application log, and waits for the finish of the main service function.
|
||||
//
|
||||
// COMMENTS:
|
||||
// Be sure to periodically call ReportServiceStatus() with
|
||||
// SERVICE_STOP_PENDING if the procedure is going to take long time.
|
||||
//
|
||||
void CSSAservice::OnStop()
|
||||
{
|
||||
// Log a service stop message to the Application log.
|
||||
WriteEventLogEntry(L"SSAservice Stopping");
|
||||
|
||||
// Indicate that the service is stopping and wait for the finish of the
|
||||
// main service function (ServiceWorkerThread).
|
||||
m_fStopping = TRUE;
|
||||
if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
|
||||
throw GetLastError();
|
||||
}
|
47
SSAservice/SSAservice.h
Normal file
47
SSAservice/SSAservice.h
Normal file
@ -0,0 +1,47 @@
|
||||
/****************************** Module Header ******************************\
|
||||
* Module Name: SampleService.h
|
||||
* Project: CppWindowsService
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Provides a sample service class that derives from the service base class -
|
||||
* CServiceBase. The sample service logs the service start and stop
|
||||
* information to the Application event log, and shows how to run the main
|
||||
* function of the service in a thread pool worker thread.
|
||||
*
|
||||
* This source is subject to the Microsoft Public License.
|
||||
* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
|
||||
* All other rights reserved.
|
||||
*
|
||||
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ServiceBase.h"
|
||||
|
||||
class CSSAservice : public CServiceBase
|
||||
{
|
||||
LPCTSTR _agent;
|
||||
|
||||
public:
|
||||
CSSAservice(LPCTSTR pszServiceName,
|
||||
BOOL fCanStop = TRUE,
|
||||
BOOL fCanShutdown = TRUE,
|
||||
BOOL fCanPauseContinue = FALSE);
|
||||
void ServiceLoop(void);
|
||||
virtual ~CSSAservice();
|
||||
|
||||
protected:
|
||||
virtual void OnStart(DWORD dwArgc, PWSTR *pszArgv);
|
||||
virtual void OnStop();
|
||||
|
||||
BOOL FindAgent(HANDLE& hProcess, DWORD& pid) const;
|
||||
BOOL FindOrCreateAgent(HANDLE& hProcess, DWORD& pid) const;
|
||||
void CheckDirectory() const;
|
||||
|
||||
private:
|
||||
BOOL m_fStopping;
|
||||
HANDLE m_hStoppedEvent;
|
||||
};
|
560
SSAservice/ServiceBase.cpp
Normal file
560
SSAservice/ServiceBase.cpp
Normal file
@ -0,0 +1,560 @@
|
||||
/****************************** Module Header ******************************\
|
||||
* Module Name: ServiceBase.cpp
|
||||
* Project: CppWindowsService
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Provides a base class for a service that will exist as part of a service
|
||||
* application. CServiceBase must be derived from when creating a new service
|
||||
* class.
|
||||
*
|
||||
* This source is subject to the Microsoft Public License.
|
||||
* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
|
||||
* All other rights reserved.
|
||||
*
|
||||
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
#pragma region Includes
|
||||
#include "ServiceBase.h"
|
||||
#include <assert.h>
|
||||
#include <strsafe.h>
|
||||
#pragma endregion
|
||||
|
||||
|
||||
#pragma region Static Members
|
||||
|
||||
// Initialize the singleton service instance.
|
||||
CServiceBase *CServiceBase::s_service = NULL;
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::Run(CServiceBase &)
|
||||
//
|
||||
// PURPOSE: Register the executable for a service with the Service Control
|
||||
// Manager (SCM). After you call Run(ServiceBase), the SCM issues a Start
|
||||
// command, which results in a call to the OnStart method in the service.
|
||||
// This method blocks until the service has stopped.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * service - the reference to a CServiceBase object. It will become the
|
||||
// singleton service instance of this service application.
|
||||
//
|
||||
// RETURN VALUE: If the function succeeds, the return value is TRUE. If the
|
||||
// function fails, the return value is FALSE. To get extended error
|
||||
// information, call GetLastError.
|
||||
//
|
||||
BOOL CServiceBase::Run(CServiceBase &service)
|
||||
{
|
||||
s_service = &service;
|
||||
|
||||
SERVICE_TABLE_ENTRY serviceTable[] =
|
||||
{
|
||||
{ service.m_name, ServiceMain },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
// Connects the main thread of a service process to the service control
|
||||
// manager, which causes the thread to be the service control dispatcher
|
||||
// thread for the calling process. This call returns when the service has
|
||||
// stopped. The process should simply terminate when the call returns.
|
||||
return StartServiceCtrlDispatcher(serviceTable);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::ServiceMain(DWORD, PWSTR *)
|
||||
//
|
||||
// PURPOSE: Entry point for the service. It registers the handler function
|
||||
// for the service and starts the service.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * dwArgc - number of command line arguments
|
||||
// * lpszArgv - array of command line arguments
|
||||
//
|
||||
void WINAPI CServiceBase::ServiceMain(DWORD dwArgc, PWSTR *pszArgv)
|
||||
{
|
||||
assert(s_service != NULL);
|
||||
|
||||
// Register the handler function for the service
|
||||
s_service->m_statusHandle = RegisterServiceCtrlHandler(
|
||||
s_service->m_name, ServiceCtrlHandler);
|
||||
if (s_service->m_statusHandle == NULL)
|
||||
{
|
||||
throw GetLastError();
|
||||
}
|
||||
|
||||
// Start the service.
|
||||
s_service->Start(dwArgc, pszArgv);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::ServiceCtrlHandler(DWORD)
|
||||
//
|
||||
// PURPOSE: The function is called by the SCM whenever a control code is
|
||||
// sent to the service.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * dwCtrlCode - the control code. This parameter can be one of the
|
||||
// following values:
|
||||
//
|
||||
// SERVICE_CONTROL_CONTINUE
|
||||
// SERVICE_CONTROL_INTERROGATE
|
||||
// SERVICE_CONTROL_NETBINDADD
|
||||
// SERVICE_CONTROL_NETBINDDISABLE
|
||||
// SERVICE_CONTROL_NETBINDREMOVE
|
||||
// SERVICE_CONTROL_PARAMCHANGE
|
||||
// SERVICE_CONTROL_PAUSE
|
||||
// SERVICE_CONTROL_SHUTDOWN
|
||||
// SERVICE_CONTROL_STOP
|
||||
//
|
||||
// This parameter can also be a user-defined control code ranges from 128
|
||||
// to 255.
|
||||
//
|
||||
void WINAPI CServiceBase::ServiceCtrlHandler(DWORD dwCtrl)
|
||||
{
|
||||
switch (dwCtrl)
|
||||
{
|
||||
case SERVICE_CONTROL_STOP: s_service->Stop(); break;
|
||||
case SERVICE_CONTROL_PAUSE: s_service->Pause(); break;
|
||||
case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break;
|
||||
case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break;
|
||||
case SERVICE_CONTROL_INTERROGATE: break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
#pragma region Service Constructor and Destructor
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::CServiceBase(PWSTR, BOOL, BOOL, BOOL)
|
||||
//
|
||||
// PURPOSE: The constructor of CServiceBase. It initializes a new instance
|
||||
// of the CServiceBase class. The optional parameters (fCanStop,
|
||||
/// fCanShutdown and fCanPauseContinue) allow you to specify whether the
|
||||
// service can be stopped, paused and continued, or be notified when system
|
||||
// shutdown occurs.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * pszServiceName - the name of the service
|
||||
// * fCanStop - the service can be stopped
|
||||
// * fCanShutdown - the service is notified when system shutdown occurs
|
||||
// * fCanPauseContinue - the service can be paused and continued
|
||||
//
|
||||
CServiceBase::CServiceBase(LPCTSTR pszServiceName,
|
||||
BOOL fCanStop,
|
||||
BOOL fCanShutdown,
|
||||
BOOL fCanPauseContinue)
|
||||
{
|
||||
// Service name must be a valid string and cannot be NULL.
|
||||
m_name = (pszServiceName == NULL) ? L"" : pszServiceName;
|
||||
|
||||
m_statusHandle = NULL;
|
||||
|
||||
// The service runs in its own process.
|
||||
m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
|
||||
// The service is starting.
|
||||
m_status.dwCurrentState = SERVICE_START_PENDING;
|
||||
|
||||
// The accepted commands of the service.
|
||||
DWORD dwControlsAccepted = 0;
|
||||
if (fCanStop)
|
||||
dwControlsAccepted |= SERVICE_ACCEPT_STOP;
|
||||
if (fCanShutdown)
|
||||
dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN;
|
||||
if (fCanPauseContinue)
|
||||
dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;
|
||||
m_status.dwControlsAccepted = dwControlsAccepted;
|
||||
|
||||
m_status.dwWin32ExitCode = NO_ERROR;
|
||||
m_status.dwServiceSpecificExitCode = 0;
|
||||
m_status.dwCheckPoint = 0;
|
||||
m_status.dwWaitHint = 0;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::~CServiceBase()
|
||||
//
|
||||
// PURPOSE: The virtual destructor of CServiceBase.
|
||||
//
|
||||
CServiceBase::~CServiceBase(void)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
#pragma region Service Start, Stop, Pause, Continue, and Shutdown
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::Start(DWORD, PWSTR *)
|
||||
//
|
||||
// PURPOSE: The function starts the service. It calls the OnStart virtual
|
||||
// function in which you can specify the actions to take when the service
|
||||
// starts. If an error occurs during the startup, the error will be logged
|
||||
// in the Application event log, and the service will be stopped.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * dwArgc - number of command line arguments
|
||||
// * lpszArgv - array of command line arguments
|
||||
//
|
||||
void CServiceBase::Start(DWORD dwArgc, PWSTR *pszArgv)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Tell SCM that the service is starting.
|
||||
SetServiceStatus(SERVICE_START_PENDING);
|
||||
|
||||
// Perform service-specific initialization.
|
||||
OnStart(dwArgc, pszArgv);
|
||||
|
||||
// Tell SCM that the service is started.
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
// Log the error.
|
||||
WriteErrorLogEntry(L"Service Start", dwError);
|
||||
|
||||
// Set the service status to be stopped.
|
||||
SetServiceStatus(SERVICE_STOPPED, dwError);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Log the error.
|
||||
WriteEventLogEntry(L"Service failed to start.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
// Set the service status to be stopped.
|
||||
SetServiceStatus(SERVICE_STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::OnStart(DWORD, PWSTR *)
|
||||
//
|
||||
// PURPOSE: When implemented in a derived class, executes when a Start
|
||||
// command is sent to the service by the SCM or when the operating system
|
||||
// starts (for a service that starts automatically). Specifies actions to
|
||||
// take when the service starts. Be sure to periodically call
|
||||
// CServiceBase::SetServiceStatus() with SERVICE_START_PENDING if the
|
||||
// procedure is going to take long time. You may also consider spawning a
|
||||
// new thread in OnStart to perform time-consuming initialization tasks.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * dwArgc - number of command line arguments
|
||||
// * lpszArgv - array of command line arguments
|
||||
//
|
||||
void CServiceBase::OnStart(DWORD dwArgc, PWSTR *pszArgv)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::Stop()
|
||||
//
|
||||
// PURPOSE: The function stops the service. It calls the OnStop virtual
|
||||
// function in which you can specify the actions to take when the service
|
||||
// stops. If an error occurs, the error will be logged in the Application
|
||||
// event log, and the service will be restored to the original state.
|
||||
//
|
||||
void CServiceBase::Stop()
|
||||
{
|
||||
DWORD dwOriginalState = m_status.dwCurrentState;
|
||||
try
|
||||
{
|
||||
// Tell SCM that the service is stopping.
|
||||
SetServiceStatus(SERVICE_STOP_PENDING);
|
||||
|
||||
// Perform service-specific stop operations.
|
||||
OnStop();
|
||||
|
||||
// Tell SCM that the service is stopped.
|
||||
SetServiceStatus(SERVICE_STOPPED);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
// Log the error.
|
||||
WriteErrorLogEntry(L"Service Stop", dwError);
|
||||
|
||||
// Set the orginal service status.
|
||||
SetServiceStatus(dwOriginalState);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Log the error.
|
||||
WriteEventLogEntry(L"Service failed to stop.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
// Set the orginal service status.
|
||||
SetServiceStatus(dwOriginalState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::OnStop()
|
||||
//
|
||||
// PURPOSE: When implemented in a derived class, executes when a Stop
|
||||
// command is sent to the service by the SCM. Specifies actions to take
|
||||
// when a service stops running. Be sure to periodically call
|
||||
// CServiceBase::SetServiceStatus() with SERVICE_STOP_PENDING if the
|
||||
// procedure is going to take long time.
|
||||
//
|
||||
void CServiceBase::OnStop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::Pause()
|
||||
//
|
||||
// PURPOSE: The function pauses the service if the service supports pause
|
||||
// and continue. It calls the OnPause virtual function in which you can
|
||||
// specify the actions to take when the service pauses. If an error occurs,
|
||||
// the error will be logged in the Application event log, and the service
|
||||
// will become running.
|
||||
//
|
||||
void CServiceBase::Pause()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Tell SCM that the service is pausing.
|
||||
SetServiceStatus(SERVICE_PAUSE_PENDING);
|
||||
|
||||
// Perform service-specific pause operations.
|
||||
OnPause();
|
||||
|
||||
// Tell SCM that the service is paused.
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
// Log the error.
|
||||
WriteErrorLogEntry(L"Service Pause", dwError);
|
||||
|
||||
// Tell SCM that the service is still running.
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Log the error.
|
||||
WriteEventLogEntry(L"Service failed to pause.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
// Tell SCM that the service is still running.
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::OnPause()
|
||||
//
|
||||
// PURPOSE: When implemented in a derived class, executes when a Pause
|
||||
// command is sent to the service by the SCM. Specifies actions to take
|
||||
// when a service pauses.
|
||||
//
|
||||
void CServiceBase::OnPause()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::Continue()
|
||||
//
|
||||
// PURPOSE: The function resumes normal functioning after being paused if
|
||||
// the service supports pause and continue. It calls the OnContinue virtual
|
||||
// function in which you can specify the actions to take when the service
|
||||
// continues. If an error occurs, the error will be logged in the
|
||||
// Application event log, and the service will still be paused.
|
||||
//
|
||||
void CServiceBase::Continue()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Tell SCM that the service is resuming.
|
||||
SetServiceStatus(SERVICE_CONTINUE_PENDING);
|
||||
|
||||
// Perform service-specific continue operations.
|
||||
OnContinue();
|
||||
|
||||
// Tell SCM that the service is running.
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
// Log the error.
|
||||
WriteErrorLogEntry(L"Service Continue", dwError);
|
||||
|
||||
// Tell SCM that the service is still paused.
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Log the error.
|
||||
WriteEventLogEntry(L"Service failed to resume.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
// Tell SCM that the service is still paused.
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::OnContinue()
|
||||
//
|
||||
// PURPOSE: When implemented in a derived class, OnContinue runs when a
|
||||
// Continue command is sent to the service by the SCM. Specifies actions to
|
||||
// take when a service resumes normal functioning after being paused.
|
||||
//
|
||||
void CServiceBase::OnContinue()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::Shutdown()
|
||||
//
|
||||
// PURPOSE: The function executes when the system is shutting down. It
|
||||
// calls the OnShutdown virtual function in which you can specify what
|
||||
// should occur immediately prior to the system shutting down. If an error
|
||||
// occurs, the error will be logged in the Application event log.
|
||||
//
|
||||
void CServiceBase::Shutdown()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Perform service-specific shutdown operations.
|
||||
OnShutdown();
|
||||
|
||||
// Tell SCM that the service is stopped.
|
||||
SetServiceStatus(SERVICE_STOPPED);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
// Log the error.
|
||||
WriteErrorLogEntry(L"Service Shutdown", dwError);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Log the error.
|
||||
WriteEventLogEntry(L"Service failed to shut down.", EVENTLOG_ERROR_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::OnShutdown()
|
||||
//
|
||||
// PURPOSE: When implemented in a derived class, executes when the system
|
||||
// is shutting down. Specifies what should occur immediately prior to the
|
||||
// system shutting down.
|
||||
//
|
||||
void CServiceBase::OnShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
#pragma region Helper Functions
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::SetServiceStatus(DWORD, DWORD, DWORD)
|
||||
//
|
||||
// PURPOSE: The function sets the service status and reports the status to
|
||||
// the SCM.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * dwCurrentState - the state of the service
|
||||
// * dwWin32ExitCode - error code to report
|
||||
// * dwWaitHint - estimated time for pending operation, in milliseconds
|
||||
//
|
||||
void CServiceBase::SetServiceStatus(DWORD dwCurrentState,
|
||||
DWORD dwWin32ExitCode,
|
||||
DWORD dwWaitHint)
|
||||
{
|
||||
static DWORD dwCheckPoint = 1;
|
||||
|
||||
// Fill in the SERVICE_STATUS structure of the service.
|
||||
|
||||
m_status.dwCurrentState = dwCurrentState;
|
||||
m_status.dwWin32ExitCode = dwWin32ExitCode;
|
||||
m_status.dwWaitHint = dwWaitHint;
|
||||
|
||||
m_status.dwCheckPoint =
|
||||
((dwCurrentState == SERVICE_RUNNING) ||
|
||||
(dwCurrentState == SERVICE_STOPPED)) ?
|
||||
0 : dwCheckPoint++;
|
||||
|
||||
// Report the status of the service to the SCM.
|
||||
::SetServiceStatus(m_statusHandle, &m_status);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::WriteEventLogEntry(PWSTR, WORD)
|
||||
//
|
||||
// PURPOSE: Log a message to the Application event log.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * pszMessage - string message to be logged.
|
||||
// * wType - the type of event to be logged. The parameter can be one of
|
||||
// the following values.
|
||||
//
|
||||
// EVENTLOG_SUCCESS
|
||||
// EVENTLOG_AUDIT_FAILURE
|
||||
// EVENTLOG_AUDIT_SUCCESS
|
||||
// EVENTLOG_ERROR_TYPE
|
||||
// EVENTLOG_INFORMATION_TYPE
|
||||
// EVENTLOG_WARNING_TYPE
|
||||
//
|
||||
void CServiceBase::WriteEventLogEntry(LPCTSTR pszMessage, WORD wType, DWORD id) const
|
||||
{
|
||||
HANDLE hEventSource = ::RegisterEventSource(NULL, m_name);
|
||||
if (hEventSource)
|
||||
{
|
||||
LPCTSTR lpszStrings[2] = { NULL, NULL };
|
||||
lpszStrings[0] = m_name;
|
||||
lpszStrings[1] = pszMessage;
|
||||
|
||||
::ReportEvent(hEventSource, // Event log handle
|
||||
wType, // Event type
|
||||
0, // Event category
|
||||
id, // 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: CServiceBase::WriteErrorLogEntry(PWSTR, DWORD)
|
||||
//
|
||||
// PURPOSE: Log an error message to the Application event log.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * pszFunction - the function that gives the error
|
||||
// * dwError - the error code
|
||||
//
|
||||
void CServiceBase::WriteErrorLogEntry(LPCTSTR pszFunction, DWORD dwError) const
|
||||
{
|
||||
wchar_t szMessage[260];
|
||||
StringCchPrintf(szMessage, ARRAYSIZE(szMessage),
|
||||
L"%s failed: error 0x%08lx", pszFunction, dwError);
|
||||
WriteEventLogEntry(szMessage, EVENTLOG_ERROR_TYPE, dwError);
|
||||
}
|
||||
|
||||
#pragma endregion
|
126
SSAservice/ServiceBase.h
Normal file
126
SSAservice/ServiceBase.h
Normal file
@ -0,0 +1,126 @@
|
||||
/****************************** Module Header ******************************\
|
||||
* Module Name: ServiceBase.h
|
||||
* Project: CppWindowsService
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Provides a base class for a service that will exist as part of a service
|
||||
* application. CServiceBase must be derived from when creating a new service
|
||||
* class.
|
||||
*
|
||||
* This source is subject to the Microsoft Public License.
|
||||
* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
|
||||
* All other rights reserved.
|
||||
*
|
||||
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma region Includes
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define STRICT
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#pragma endregion
|
||||
|
||||
|
||||
class CServiceBase
|
||||
{
|
||||
public:
|
||||
|
||||
// Register the executable for a service with the Service Control Manager
|
||||
// (SCM). After you call Run(ServiceBase), the SCM issues a Start command,
|
||||
// which results in a call to the OnStart method in the service. This
|
||||
// method blocks until the service has stopped.
|
||||
static BOOL Run(CServiceBase &service);
|
||||
|
||||
// Service object constructor. The optional parameters (fCanStop,
|
||||
// fCanShutdown and fCanPauseContinue) allow you to specify whether the
|
||||
// service can be stopped, paused and continued, or be notified when
|
||||
// system shutdown occurs.
|
||||
CServiceBase(LPCTSTR pszServiceName,
|
||||
BOOL fCanStop = TRUE,
|
||||
BOOL fCanShutdown = TRUE,
|
||||
BOOL fCanPauseContinue = FALSE);
|
||||
|
||||
// Service object destructor.
|
||||
virtual ~CServiceBase(void);
|
||||
|
||||
// Stop the service.
|
||||
void Stop();
|
||||
|
||||
protected:
|
||||
|
||||
// When implemented in a derived class, executes when a Start command is
|
||||
// sent to the service by the SCM or when the operating system starts
|
||||
// (for a service that starts automatically). Specifies actions to take
|
||||
// when the service starts.
|
||||
virtual void OnStart(DWORD dwArgc, PWSTR *pszArgv);
|
||||
|
||||
// When implemented in a derived class, executes when a Stop command is
|
||||
// sent to the service by the SCM. Specifies actions to take when a
|
||||
// service stops running.
|
||||
virtual void OnStop();
|
||||
|
||||
// When implemented in a derived class, executes when a Pause command is
|
||||
// sent to the service by the SCM. Specifies actions to take when a
|
||||
// service pauses.
|
||||
virtual void OnPause();
|
||||
|
||||
// When implemented in a derived class, OnContinue runs when a Continue
|
||||
// command is sent to the service by the SCM. Specifies actions to take
|
||||
// when a service resumes normal functioning after being paused.
|
||||
virtual void OnContinue();
|
||||
|
||||
// When implemented in a derived class, executes when the system is
|
||||
// shutting down. Specifies what should occur immediately prior to the
|
||||
// system shutting down.
|
||||
virtual void OnShutdown();
|
||||
|
||||
// Set the service status and report the status to the SCM.
|
||||
void SetServiceStatus(DWORD dwCurrentState,
|
||||
DWORD dwWin32ExitCode = NO_ERROR,
|
||||
DWORD dwWaitHint = 0);
|
||||
|
||||
// Log a message to the Application event log.
|
||||
void WriteEventLogEntry(LPCTSTR pszMessage, WORD wType = EVENTLOG_INFORMATION_TYPE, DWORD id = 0) const;
|
||||
|
||||
// Log an error message to the Application event log.
|
||||
void WriteErrorLogEntry(LPCTSTR pszFunction, DWORD dwError = GetLastError()) const;
|
||||
|
||||
private:
|
||||
|
||||
// Entry point for the service. It registers the handler function for the
|
||||
// service and starts the service.
|
||||
static void WINAPI ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv);
|
||||
|
||||
// The function is called by the SCM whenever a control code is sent to
|
||||
// the service.
|
||||
static void WINAPI ServiceCtrlHandler(DWORD dwCtrl);
|
||||
|
||||
// Start the service.
|
||||
void Start(DWORD dwArgc, PWSTR *pszArgv);
|
||||
|
||||
// Pause the service.
|
||||
void Pause();
|
||||
|
||||
// Resume the service after being paused.
|
||||
void Continue();
|
||||
|
||||
// Execute when the system is shutting down.
|
||||
void Shutdown();
|
||||
|
||||
// The singleton service instance.
|
||||
static CServiceBase *s_service;
|
||||
|
||||
// The name of the service
|
||||
PWSTR m_name;
|
||||
|
||||
// The status of the service
|
||||
SERVICE_STATUS m_status;
|
||||
|
||||
// The service status handle
|
||||
SERVICE_STATUS_HANDLE m_statusHandle;
|
||||
};
|
248
SSAservice/ServiceInstaller.cpp
Normal file
248
SSAservice/ServiceInstaller.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
/****************************** Module Header ******************************\
|
||||
* Module Name: ServiceInstaller.cpp
|
||||
* Project: CppWindowsService
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* The file implements functions that install and uninstall the service.
|
||||
*
|
||||
* This source is subject to the Microsoft Public License.
|
||||
* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
|
||||
* All other rights reserved.
|
||||
*
|
||||
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
#pragma region "Includes"
|
||||
#include "ServiceBase.h"
|
||||
#include "ServiceInstaller.h"
|
||||
#pragma endregion
|
||||
|
||||
static bool LogError(const char* funcname)
|
||||
{
|
||||
fprintf(stderr, "%s failed with error 0x%08lx\n", funcname, GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
class SCManager
|
||||
{
|
||||
SC_HANDLE _handle;
|
||||
|
||||
public:
|
||||
bool IsOk() const { return _handle != NULL; }
|
||||
operator SC_HANDLE() const { return _handle; }
|
||||
|
||||
bool Start(LPCTSTR pszServiceName);
|
||||
bool Stop(LPCTSTR pszServiceName);
|
||||
bool Delete(LPCTSTR pszServiceName);
|
||||
|
||||
SCManager(DWORD mode)
|
||||
{
|
||||
_handle = ::OpenSCManager(NULL, NULL, mode);
|
||||
if (_handle == NULL)
|
||||
LogError("OpenSCManager");
|
||||
}
|
||||
~SCManager()
|
||||
{
|
||||
if (_handle != NULL)
|
||||
CloseServiceHandle(_handle);
|
||||
}
|
||||
};
|
||||
|
||||
bool SCManager::Stop(LPCTSTR pszServiceName)
|
||||
{
|
||||
bool bDone = false;
|
||||
|
||||
if (IsOk())
|
||||
{
|
||||
// Open the service with delete, stop, and query status permissions
|
||||
SC_HANDLE schService = ::OpenService(_handle, pszServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS);
|
||||
if (schService == NULL)
|
||||
{
|
||||
LogError("OpenService");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to stop the service
|
||||
SERVICE_STATUS ssSvcStatus = {};
|
||||
if (::ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus))
|
||||
{
|
||||
wprintf(L"Stopping %s.", pszServiceName);
|
||||
while (::QueryServiceStatus(schService, &ssSvcStatus))
|
||||
{
|
||||
if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING)
|
||||
{
|
||||
wprintf(L".");
|
||||
Sleep(1000);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
bDone = ssSvcStatus.dwCurrentState == SERVICE_STOPPED;
|
||||
wprintf(L"\n");
|
||||
}
|
||||
|
||||
::CloseServiceHandle(schService);
|
||||
|
||||
if (bDone)
|
||||
wprintf(L"\n%s is stopped.\n", pszServiceName);
|
||||
else
|
||||
wprintf(L"\n%s failed to stop.\n", pszServiceName);
|
||||
}
|
||||
return bDone;
|
||||
}
|
||||
|
||||
bool SCManager::Start(LPCTSTR pszServiceName)
|
||||
{
|
||||
bool bDone = false;
|
||||
if (IsOk())
|
||||
{
|
||||
SC_HANDLE schService = OpenService(_handle, pszServiceName, SERVICE_START);
|
||||
if (schService)
|
||||
{
|
||||
bDone = ::StartService(schService, 0, NULL) != 0;
|
||||
if (bDone)
|
||||
wprintf(L"%s started.\n", pszServiceName);
|
||||
else
|
||||
LogError("StartService");
|
||||
}
|
||||
else
|
||||
LogError("OpenService");
|
||||
}
|
||||
return bDone;
|
||||
}
|
||||
|
||||
|
||||
bool SCManager::Delete(LPCTSTR pszServiceName)
|
||||
{
|
||||
bool bDone = false;
|
||||
if (IsOk())
|
||||
{
|
||||
// Open the service with delete, stop, and query status permissions
|
||||
SC_HANDLE schService = ::OpenService(_handle, pszServiceName, DELETE);
|
||||
if (schService)
|
||||
{
|
||||
// Now remove the service by calling DeleteService.
|
||||
bDone = ::DeleteService(schService) != 0;
|
||||
if (bDone)
|
||||
wprintf(L"%s has been removed.\n", pszServiceName);
|
||||
else
|
||||
LogError("DeleteService");
|
||||
|
||||
// Centralized cleanup for all allocated resources.
|
||||
if (schService)
|
||||
{
|
||||
CloseServiceHandle(schService);
|
||||
schService = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
LogError("OpenService");
|
||||
}
|
||||
return bDone;
|
||||
}
|
||||
|
||||
//
|
||||
// FUNCTION: InstallService
|
||||
//
|
||||
// PURPOSE: Install the current application as a service to the local
|
||||
// service control manager database.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * pszServiceName - the name of the service to be installed
|
||||
// * pszDisplayName - the display name of the service
|
||||
// * dwStartType - the service start option. This parameter can be one of
|
||||
// the following values: SERVICE_AUTO_START, SERVICE_BOOT_START,
|
||||
// SERVICE_DEMAND_START, SERVICE_DISABLED, SERVICE_SYSTEM_START.
|
||||
// * pszDependencies - a pointer to a double null-terminated array of null-
|
||||
// separated names of services or load ordering groups that the system
|
||||
// must start before this service.
|
||||
// * pszAccount - the name of the account under which the service runs.
|
||||
// * pszPassword - the password to the account name.
|
||||
//
|
||||
// NOTE: If the function fails to install the service, it prints the error
|
||||
// in the standard output stream for users to diagnose the problem.
|
||||
//
|
||||
void InstallService(LPCTSTR pszServiceName,
|
||||
LPCTSTR pszDisplayName,
|
||||
DWORD dwStartType,
|
||||
LPCTSTR pszDependencies,
|
||||
LPCTSTR pszAccount,
|
||||
LPCTSTR pszPassword)
|
||||
{
|
||||
TCHAR szPath[MAX_PATH];
|
||||
if (::GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0)
|
||||
{
|
||||
LogError("GetModuleFileName");
|
||||
return;
|
||||
}
|
||||
|
||||
// Open the local default service control manager database
|
||||
SCManager schSCManager(SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
|
||||
if (schSCManager.IsOk())
|
||||
{
|
||||
// Install the service into SCM by calling CreateService
|
||||
SC_HANDLE schService = ::CreateService(
|
||||
schSCManager, // SCManager database
|
||||
pszServiceName, // Name of service
|
||||
pszDisplayName, // Name to display
|
||||
SERVICE_QUERY_STATUS, // Desired access
|
||||
SERVICE_WIN32_OWN_PROCESS, // Service type
|
||||
dwStartType, // Service start type
|
||||
SERVICE_ERROR_NORMAL, // Error control type
|
||||
szPath, // Service's binary
|
||||
NULL, // No load ordering group
|
||||
NULL, // No tag identifier
|
||||
pszDependencies, // Dependencies
|
||||
pszAccount, // Service running account
|
||||
pszPassword // Password of the account
|
||||
);
|
||||
if (schService != NULL)
|
||||
{
|
||||
wprintf(L"%s has been installed.\n", pszServiceName);
|
||||
CloseServiceHandle(schService);
|
||||
}
|
||||
else
|
||||
LogError("CreateService");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: UninstallService
|
||||
//
|
||||
// PURPOSE: Stop and remove the service from the local service control
|
||||
// manager database.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * pszServiceName - the name of the service to be removed.
|
||||
//
|
||||
// NOTE: If the function fails to uninstall the service, it prints the
|
||||
// error in the standard output stream for users to diagnose the problem.
|
||||
//
|
||||
void UninstallService(PWSTR pszServiceName)
|
||||
{
|
||||
// Open the local default service control manager database
|
||||
SCManager schSCManager(SC_MANAGER_CONNECT);
|
||||
if (schSCManager.IsOk())
|
||||
{
|
||||
schSCManager.Stop(pszServiceName);
|
||||
schSCManager.Delete(pszServiceName);
|
||||
}
|
||||
}
|
||||
|
||||
void StartService(PWSTR pszServiceName)
|
||||
{
|
||||
SCManager schSCManager(SC_MANAGER_CONNECT);
|
||||
if (schSCManager.IsOk())
|
||||
schSCManager.Start(pszServiceName);
|
||||
}
|
||||
|
||||
void StopService(PWSTR pszServiceName)
|
||||
{
|
||||
SCManager schSCManager(SC_MANAGER_CONNECT);
|
||||
if (schSCManager.IsOk())
|
||||
schSCManager.Stop(pszServiceName);
|
||||
}
|
77
SSAservice/ServiceInstaller.h
Normal file
77
SSAservice/ServiceInstaller.h
Normal file
@ -0,0 +1,77 @@
|
||||
/****************************** Module Header ******************************\
|
||||
* Module Name: ServiceInstaller.h
|
||||
* Project: CppWindowsService
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* The file declares functions that install and uninstall the service.
|
||||
*
|
||||
* This source is subject to the Microsoft Public License.
|
||||
* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
|
||||
* All other rights reserved.
|
||||
*
|
||||
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
\***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: InstallService
|
||||
//
|
||||
// PURPOSE: Install the current application as a service to the local
|
||||
// service control manager database.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * pszServiceName - the name of the service to be installed
|
||||
// * pszDisplayName - the display name of the service
|
||||
// * dwStartType - the service start option. This parameter can be one of
|
||||
// the following values: SERVICE_AUTO_START, SERVICE_BOOT_START,
|
||||
// SERVICE_DEMAND_START, SERVICE_DISABLED, SERVICE_SYSTEM_START.
|
||||
// * pszDependencies - a pointer to a double null-terminated array of null-
|
||||
// separated names of services or load ordering groups that the system
|
||||
// must start before this service.
|
||||
// * pszAccount - the name of the account under which the service runs.
|
||||
// * pszPassword - the password to the account name.
|
||||
//
|
||||
// NOTE: If the function fails to install the service, it prints the error
|
||||
// in the standard output stream for users to diagnose the problem.
|
||||
//
|
||||
void InstallService(LPCTSTR pszServiceName,
|
||||
LPCTSTR pszDisplayName,
|
||||
DWORD dwStartType,
|
||||
LPCTSTR pszDependencies,
|
||||
LPCTSTR pszAccount,
|
||||
LPCTSTR pszPassword);
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: UninstallService
|
||||
//
|
||||
// PURPOSE: Stop and remove the service from the local service control
|
||||
// manager database.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * pszServiceName - the name of the service to be removed.
|
||||
//
|
||||
// NOTE: If the function fails to uninstall the service, it prints the
|
||||
// error in the standard output stream for users to diagnose the problem.
|
||||
//
|
||||
void UninstallService(PWSTR pszServiceName);
|
||||
|
||||
|
||||
//
|
||||
// FUNCTION: StartStopService
|
||||
//
|
||||
// PURPOSE: Starts or Stops the service
|
||||
//
|
||||
// PARAMETERS:
|
||||
// * pszServiceName - the name of the service to be started or stopped.
|
||||
// bStart - TRUE to start or FALSE to stop
|
||||
//
|
||||
// NOTE: If the function fails to uninstall the service, it prints the
|
||||
// error in the standard output stream for users to diagnose the problem.
|
||||
//
|
||||
void StartService(PWSTR pszServiceName);
|
||||
void StopService(PWSTR pszServiceName);
|
31
SSAservice/ThreadPool.h
Normal file
31
SSAservice/ThreadPool.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
class CThreadPool
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename T>
|
||||
static void QueueUserWorkItem(void (T::*function)(void), T *object, ULONG flags = WT_EXECUTELONGFUNCTION)
|
||||
{
|
||||
typedef std::pair<void (T::*)(), T *> CallbackType;
|
||||
std::auto_ptr<CallbackType> p(new CallbackType(function, object));
|
||||
if (::QueueUserWorkItem(ThreadProc<T>, p.get(), flags))
|
||||
p.release();
|
||||
else
|
||||
throw GetLastError();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static DWORD WINAPI ThreadProc(PVOID context)
|
||||
{
|
||||
typedef std::pair<void (T::*)(), T *> CallbackType;
|
||||
|
||||
std::auto_ptr<CallbackType> p(static_cast<CallbackType *>(context));
|
||||
|
||||
(p->second->*p->first)();
|
||||
return 0;
|
||||
}
|
||||
};
|
BIN
SSAservice/cert/Guysoft.cer
Normal file
BIN
SSAservice/cert/Guysoft.cer
Normal file
Binary file not shown.
BIN
SSAservice/cert/Guysoft.pvk
Normal file
BIN
SSAservice/cert/Guysoft.pvk
Normal file
Binary file not shown.
BIN
SSAservice/cert/VisualGala.cer
Normal file
BIN
SSAservice/cert/VisualGala.cer
Normal file
Binary file not shown.
4
SSAservice/cert/buildcer.bat
Normal file
4
SSAservice/cert/buildcer.bat
Normal file
@ -0,0 +1,4 @@
|
||||
set path=C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin
|
||||
del *.cer
|
||||
makecert -n "CN=Guysoft Certificate Authority" -cy authority -a sha1 -sv "Guysoft.pvk" -r "Guysoft.cer"
|
||||
makecert -n "CN=VisualGala.com" -ic "Guysoft.cer" -iv "Guysoft.pvk" -a sha1 -sky exchange -pe -sr localmachine -ss my "VisualGala.cer"
|
BIN
SSAservice/cert/visualgala.pfx
Normal file
BIN
SSAservice/cert/visualgala.pfx
Normal file
Binary file not shown.
68
SSAservice/esigner.h
Normal file
68
SSAservice/esigner.h
Normal file
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
#ifndef _ESIGNER_DLL
|
||||
#define _ESIGNER_DLL
|
||||
|
||||
#define ESIGNER_USE_SHA1_DIGEST 0
|
||||
#define ESIGNER_USE_SHA256_DIGEST 1
|
||||
|
||||
#define ESIGNER_NO_ERROR 0
|
||||
#define ESIGNER_TOKEN_OPERATION_ERROR -1
|
||||
#define ESIGNER_CERT_READ_FAILURE -2
|
||||
#define ESIGNER_PKEY_READ_FAILURE -3
|
||||
#define ESIGNER_PFX_PARSE_FAILURE -4
|
||||
#define ESIGNER_CERT_RETRIEVE_TOKEN_FAILURE -5
|
||||
#define ESIGNER_FILE_OPENING_ERROR -6
|
||||
#define ESIGNER_TSA_URI_CONTACT_ERROR -7
|
||||
#define ESIGNER_TSA_RESPONSE_ERROR -8
|
||||
#define ESIGNER_TSA_RESPONSE_UNPARSABLE -9
|
||||
#define ESIGNER_TOKEN_LOGIN_FAILED -10
|
||||
#define ESIGNER_PKCS11_DLL_NOT_FOUND -11
|
||||
#define ESIGNER_TOKEN_SLOT_NOT_FOUND -12
|
||||
#define ESIGNER_OUTPUT_FILE_OPENING_ERROR -13
|
||||
#define ESIGNER_OUTPUT_FILE_ALREADY_EXISTS_ERROR -14
|
||||
#define ESIGNER_ERROR_TIMESTAMP_FILE -15
|
||||
#define ESIGNER_TIMESTAMPING_FILE_OPENING_ERROR -16
|
||||
#define ESIGNER_FILE_NOT_SIGNED -20
|
||||
#define ESIGNER_FAKE_P7M -21
|
||||
#define ESIGNER_SIGNATURE_INVALID -22
|
||||
#define ESIGNER_CERTIFICATE_REVOKED -23
|
||||
#define ESIGNER_SIGNED_BUT_TIME_STAMP_ERROR -25
|
||||
#define ESIGNER_ROOT_CA_CERT_NOT_FOUND -30
|
||||
#define ESIGNER_CRL_NOT_RETRIEVED -31
|
||||
#define ESIGNER_CERTIFICATE_REVOKED_BUT_SIGNATURE_VALID -32
|
||||
#define ESIGNER_CERTIFICATE_SELFSIGNED -33
|
||||
#define ESIGNER_SIGNER_CERTIFICATE_EXPIRED -34
|
||||
#define ESIGNER_SIGNER_CERTIFICATE_OUT_OF_TIME_VALIDITY -35
|
||||
|
||||
typedef int (PASCAL * ESignerSignProto) (
|
||||
char *operation,
|
||||
char *method,
|
||||
char *inputFile,
|
||||
char *outputFile,
|
||||
char *timestampOutputFile,
|
||||
char *extension,
|
||||
char *certificateFile,
|
||||
char *kprivFile,
|
||||
char *pfxFile,
|
||||
char *pkcs11Dll,
|
||||
char *pin_passphrase,
|
||||
char *directoryTokenCache,
|
||||
char *indexCertificateOnToken,
|
||||
char *tsaURI,
|
||||
char *tsaUsername,
|
||||
char *tsaPassword,
|
||||
char *tsaPolicy,
|
||||
char *tsaCoding,
|
||||
char *rootCADir
|
||||
);
|
||||
|
||||
typedef int (PASCAL * ESignerVerifyProto) (
|
||||
char *operation,
|
||||
char *inputFileName,
|
||||
char *responseFileName,
|
||||
char *rootCADir,
|
||||
char *rootTSADir,
|
||||
char *resultDescription
|
||||
);
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user