git-svn-id: svn://10.65.10.50/branches/R_10_00@23067 c028cbd2-c16b-5b4b-a496-9718f37d4682

This commit is contained in:
guy 2015-04-01 08:51:44 +00:00
parent b5c2266041
commit 55412a57c6
21 changed files with 2426 additions and 0 deletions

108
SSAservice/ESignMain.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
};

View 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);
}

View 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
View 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

Binary file not shown.

BIN
SSAservice/cert/Guysoft.pvk Normal file

Binary file not shown.

Binary file not shown.

View 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"

Binary file not shown.

68
SSAservice/esigner.h Normal file
View 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