Nous avons une application de console que nous avons lancé à partir d'une invite de commande pour le débogage, mais nous le lancons également comme un service NT pour la production.
En ce moment, le code a cette logique: p>
if (__argc <= 1) {
assumeService();
} else {
assumeForgound();
}
5 Réponses :
Vous pouvez vérifier si les processus parents sont des services.exe ou svchoste.exe. Ou vous pouvez interroger le gestionnaire de contrôle de service à l'aide de WinapI si votre service est démarré et que l'ID de processus actuel est égal à celui du service démarré.
en C # Le code suivant le ferait (puisqu'il s'agit de Winapi, cela devrait fonctionner de manière similaire en C ++, exemple de code ICI ): P>
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <aclapi.h>
#include <stdio.h>
bool IsRunningAsService(const TCHAR* szSvcName)
{
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwBytesNeeded;
SC_HANDLE schSCManager = OpenSCManager(
NULL, // local computer
NULL, // servicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (NULL == schSCManager)
{
printf("OpenSCManager failed (%d)\n", GetLastError());
return false;
}
// Get a handle to the service.
SC_HANDLE schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_ALL_ACCESS); // full access
if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return false;
}
// Check the status in case the service is not stopped.
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // information level
(LPBYTE) &ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded ) ) // size needed if buffer is too small
{
printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return false;
}
return GetCurrentProcessId() == ssStatus.dwProcessId;
}
Ah désolé. Nous n'utilisons pas c # - mais votre réponse s'applique de toute façon je pense.
Veuillez noter que cette approche nécessite des autorisations, le processus actuel doit pouvoir interroger le gestionnaire de services de service.
Vérifierait qu'un compte d'utilisateur vous aidait? IIRC Un service serait exécuté sous le nom System em> ou quelque chose de très similaire et je suppose que vous exécutez votre application en mode de débogage sous votre compte d'utilisateur normal. Je pense que openprocessToken code> et getTokenInformation code> avec Tokenuser code> fonctionnerait ici. P>
Les services peuvent être exécutés sous des comptes d'utilisateurs
Voici un certain code que j'ai créé (semble fonctionner bien). Toutes mes excuses pour les en-têtes manquants, #defines, etc. Si vous voulez voir la version complète, Regardez ici .
bool
CArchMiscWindows::wasLaunchedAsService()
{
CString name;
if (!getParentProcessName(name)) {
LOG((CLOG_ERR "cannot determine if process was launched as service"));
return false;
}
return (name == SERVICE_LAUNCHER);
}
bool
CArchMiscWindows::getParentProcessName(CString &name)
{
PROCESSENTRY32 parentEntry;
if (!getParentProcessEntry(parentEntry)){
LOG((CLOG_ERR "could not get entry for parent process"));
return false;
}
name = parentEntry.szExeFile;
return true;
}
BOOL WINAPI
CArchMiscWindows::getSelfProcessEntry(PROCESSENTRY32& entry)
{
// get entry from current PID
return getProcessEntry(entry, GetCurrentProcessId());
}
BOOL WINAPI
CArchMiscWindows::getParentProcessEntry(PROCESSENTRY32& entry)
{
// get the current process, so we can get parent PID
PROCESSENTRY32 selfEntry;
if (!getSelfProcessEntry(selfEntry)) {
return FALSE;
}
// get entry from parent PID
return getProcessEntry(entry, selfEntry.th32ParentProcessID);
}
BOOL WINAPI
CArchMiscWindows::getProcessEntry(PROCESSENTRY32& entry, DWORD processID)
{
// first we need to take a snapshot of the running processes
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE) {
LOG((CLOG_ERR "could not get process snapshot (error: %i)",
GetLastError()));
return FALSE;
}
entry.dwSize = sizeof(PROCESSENTRY32);
// get the first process, and if we can't do that then it's
// unlikely we can go any further
BOOL gotEntry = Process32First(snapshot, &entry);
if (!gotEntry) {
LOG((CLOG_ERR "could not get first process entry (error: %i)",
GetLastError()));
return FALSE;
}
while(gotEntry) {
if (entry.th32ProcessID == processID) {
// found current process
return TRUE;
}
// now move on to the next entry (when we reach end, loop will stop)
gotEntry = Process32Next(snapshot, &entry);
}
return FALSE;
Si le programme fonctionne sans paramètres, vous supposez que c'est un service. Changer que em> et le reste de vos problèmes de démarrage de service disparaissent. nécessite un paramètre pour que le programme agisse comme un service. strong> Lorsque vous installez le service, incluez simplement ce paramètre dans la ligne de commande que vous vous enregistrez avec Windows. P>
Sans paramètres, créez le programme Imprimer sa documentation d'utilisation et quitter. Là, il peut expliquer, par exemple, que les utilisateurs doivent utiliser -f code> pour le débogage de ligne de commande, -i code> pour installer le service, et -u code > Pour désinstaller, et qu'ils ne doivent pas utiliser -s code> car cela permettrait d'essayer de fonctionner comme un service de la ligne de commande, qui n'est pas un cas d'utilisation pris en charge. (Ils doivent utiliser net Démarrage code> ou SC Démarrer code> pour démarrer le service à la place.) P>
Rob, comment puis-je commencer un service avec argways? Nous utilisons CreateService, que je crois ne vous donne pas l'option ... msdn.microsoft.com/en-us/library/ms682450 (vs.85) .aspx
Lisez ce lien plus attentivement. En particulier, lisez tout le texte décrivant le paramètre LPBinairePathName. Cela démontre spécifiquement des arguments de passage au programme.
Ah, "Le chemin peut également inclure des arguments pour un service de démarrage automatique". J'ai été induisée par une mauvaise documentation dans notre projet qui a déclaré que "les services de Windows ne prennent pas arguments" que j'aurais dû ignorer au lieu de la lire Verbatim. L'ancien code va même dans l'ampleur de la création d'une clé Reg spécifiquement pour les arguments, ha!
Si votre application est en cours d'exécution d'une application de console (lorsqu'elle n'est pas utilisée comme service), une solution simple consiste à vérifier si une console a été allouée:
if(GetConsoleWindow())
{
//Running as console Application
}
else
{
//Running as Service
}
Quelle langue de développement utilisez-vous?
C ++ (le titre est maintenant fixé).