Comment puis-je exécuter un programme EXE à partir D'un service Windows en utilisant C#?

Comment puis-je exécuter un programme EXE à partir d'un Service Windows en utilisant C#?

C'est mon code:

System.Diagnostics.Process.Start(@"E:PROJECT XLINI SQLLOADERConsoleApplication2ConsoleApplication2ConsoleApplication2binDebugConsoleApplication2.exe");

Lorsque j'exécute ce service, l'application ne démarre pas.

Qu'est-ce qui ne va pas avec mon code?

36
demandé sur Vikrant 2011-03-15 08:47:24

7 réponses

cela ne fonctionnera jamais , du moins pas sous Windows Vista ou plus tard. Le problème principal est que vous essayez d'exécuter cela à partir d'un Service Windows, plutôt que D'une application Windows standard. Le code que vous avez montré fonctionnera parfaitement dans une application Windows, WPF, ou Console, mais il ne fonctionnera pas du tout dans un service Windows.

les Services Windows ne peuvent pas démarrer d'applications supplémentaires parce qu'ils ne sont pas en cours d'exécution dans le contexte d'un utilisateur particulier. À la différence des applications Windows habituelles, les services sont maintenant exécutés dans une session isolée et sont interdits d'interagir avec un utilisateur ou le bureau. Cela ne laisse aucune place pour l'application à exécuter.

vous trouverez de plus amples informations dans les réponses à ces questions connexes:

la meilleure solution à votre problème, comme vous l'avez probablement compris maintenant, est de créer une application Windows standard au lieu d'un service. Ceux-ci sont conçus pour être exécutés par un utilisateur particulier et sont associés au bureau de cet utilisateur. De cette façon, vous pouvez exécuter des applications supplémentaires quand vous voulez, en utilisant le code que vous avez déjà montré.

une autre solution possible, en supposant que votre application Console ne nécessite pas d'interface ou de sortie, consiste à donner des instructions au processus pour qu'il ne crée pas de fenêtre. Cela empêchera Windows de bloquer la création de votre processus, car il ne demandera plus qu'une fenêtre Console soit créée. Vous pouvez trouver le code correspondant dans cette réponse à une question connexe.

57
répondu Cody Gray 2017-05-23 12:34:15

j'ai essayé cet article Code Project , il fonctionne très bien pour moi. J'ai utilisé le code aussi. article est excellent dans l'explication avec screenshot.

j'ajoute l'explication nécessaire à ce scénario

Vous venez de démarrer votre ordinateur et ouvrez une session. Lorsque vous ouvrez une session, le système vous attribue un identifiant de Session unique. Dans Windows Vista, le premier utilisateur à se connecter à l'ordinateur se voit attribuer une Session ID de 1 par L'OS. L'utilisateur suivant pour se connecter se verra attribuer un ID de Session de 2. Et ainsi de suite et ainsi de suite. Vous pouvez voir L'ID de Session assigné à chaque utilisateur connecté à partir de L'onglet Utilisateurs dans le Gestionnaire des tâches. enter image description here

mais votre service windows est placé sous le numéro de session 0. Cette session est isolée des autres. Cela empêche en fin de compte le service windows d'invoquer l'application tournant sous les sessions utilisateur comme 1 ou 2.

afin d'invoquer l'application à partir du service windows, vous devez copier la commande à partir de winlogon.exe qui agit en tant qu'utilisateur présent a enregistré comme montré dans screenshot ci-dessous. enter image description here

Codes importants

// obtain the process id of the winlogon process that 
// is running within the currently active session
Process[] processes = Process.GetProcessesByName("winlogon");
foreach (Process p in processes)
{
    if ((uint)p.SessionId == dwSessionId)
    {
        winlogonPid = (uint)p.Id;
    }
}

// obtain a handle to the winlogon process
hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);

// obtain a handle to the access token of the winlogon process
if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken))
{
    CloseHandle(hProcess);
    return false;
}

// Security attibute structure used in DuplicateTokenEx and   CreateProcessAsUser
// I would prefer to not have to use a security attribute variable and to just 
// simply pass null and inherit (by default) the security attributes
// of the existing token. However, in C# structures are value types and   therefore
// cannot be assigned the null value.
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);

// copy the access token of the winlogon process; 
// the newly created token will be a primary token
if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, 
    (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, 
    (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
    {
      CloseHandle(hProcess);
      CloseHandle(hPToken);
      return false;
    }

 STARTUPINFO si = new STARTUPINFO();
 si.cb = (int)Marshal.SizeOf(si);

// interactive window station parameter; basically this indicates 
// that the process created can display a GUI on the desktop
si.lpDesktop = @"winsta0\default";

// flags that specify the priority and creation method of the process
int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;

// create a new process in the current User's logon session
 bool result = CreateProcessAsUser(hUserTokenDup,  // client's access token
                            null,             // file to execute
                            applicationName,  // command line
                            ref sa,           // pointer to process    SECURITY_ATTRIBUTES
                            ref sa,           // pointer to thread SECURITY_ATTRIBUTES
                            false,            // handles are not inheritable
                            dwCreationFlags,  // creation flags
                            IntPtr.Zero,      // pointer to new environment block 
                            null,             // name of current directory 
                            ref si,           // pointer to STARTUPINFO structure
                            out procInfo      // receives information about new process
                            );
4
répondu Pranesh Janarthanan 2016-11-28 08:13:21

tout d'abord, nous allons créer un service Windows qui fonctionne sous la Système de compte. Ce service sera responsable de la processus interactif au sein de la Session de l'Utilisateur. Ce le processus nouvellement créé affichera un UI et s'exécutera avec administrateur complet droit. Lorsque le premier Utilisateur se connecte à l'ordinateur, ce service sera le processus qui sera lancé en Session0; toutefois, ce service s'exécute sur le bureau de la actuellement de l'Utilisateur connecté. Nous appellerons ce service le LoaderService.

ensuite, le winlogon.exe processus est responsable de la gestion de la connexion de l'Utilisateur et les procédures de déconnexion. Nous savons que chaque utilisateur qui se connecte l'ordinateur aura un ID de Session unique et un correspondant winlogon.processus exe associé à leur Session. Maintenant, nous avons mentionné ci-dessus, le LoaderService fonctionne sous le compte système. Nous avons également confirmé que chaque winlogon.processus exe sur l'ordinateur fonctionne sous le compte Système. Parce que le compte système est le propriétaire des deux le LoaderService et le winlogon.processus exe, notre service de chargement peut copier le token d'accès (et L'ID de Session) du winlogon.processus exe et ensuite appeler la fonction API Win32 CreateProcessAsUser pour lancer un processus de la Session de l'Utilisateur connecté. Depuis L'ID de Session situé dans le token d'accès du copié winlogon.processus exe est supérieur à 0, nous pouvons lancement interactif processus à l'aide de ce jeton.

essayez celui-ci. Subversion UAC de Vista en 32 et 64 bits Architectures

2
répondu Elshan 2015-11-24 09:43:34

vous pouvez exécuter an .exe d'un service Windows très bien dans Windows XP. Je l'ai fait moi-même dans le passé.

vous devez vous assurer que vous avez coché l'option" Permettre d'interagir avec le bureau " dans les propriétés du service Windows. Si cela n'est pas fait, il ne s'exécutera pas.

je dois vérifier dans Windows 7 ou Vista que ces versions nécessitent des privilèges de sécurité supplémentaires afin qu'il peut jeter une erreur, mais je suis tout à fait sûr qu'il peut être atteint directement ou indirectement. Pour XP je suis certain que je l'avais fait moi-même.

1
répondu Depinder Bharti 2012-10-26 06:39:04

je pense que Vous copiez le .exe vers un autre emplacement. Ce pourrait être le problème, je suppose. Lorsque vous copiez l'exe, vous ne copiez pas ses dépendances.

donc, ce que vous pouvez faire, c'est de mettre tous les dlls dépendants dans GAC afin que n'importe quel. exe. net puisse y accéder

sinon, ne copiez pas l'exe à un autre endroit. Il suffit de créer une variable d'environnement et d'appeler l'exe dans votre c#. Puisque le chemin est défini dans les variables d'environnement, l'exe est accessible par votre programme c#.

mise à jour:

auparavant, j'avais une sorte de problème dans mon c#.net 3.5 projet dans lequel j'étais en train d'exécuter une .fichier exe à partir de c#.net code et que exe n'était rien d'autre que l'autre projet exe(où j'ai ajouté peu de DLLs de soutien pour ma fonctionnalité) et les méthodes dlls que j'utilisais dans mon application exe. Enfin j'ai résolu ceci en créant cette application comme un projet séparé à la même solution et j'ai ajouté que la sortie du projet pour mon projet de déploiement. Selon ce scénario, j'ai répondu, Si ce n'est pas ce qu'il veut, puis je suis extrêmement désolé.

0
répondu SharpUrBrain 2011-03-15 06:36:04

vous pouvez utiliser windows task scheduler à cet effet, il existe de nombreuses bibliothèques comme TaskScheduler qui vous aident.

par exemple considérer que nous voulons programmer une tâche qui exécutera une fois cinq secondes plus tard:

using (var ts = new TaskService())
        {

            var t = ts.Execute("notepad.exe")
                .Once()
                .Starting(DateTime.Now.AddSeconds(5))
                .AsTask("myTask");

        }

bloc-notes.exe sera exécuté cinq secondes plus tard.

pour plus de détails et de plus amples informations, veuillez aller à wiki

si vous savez quelle classe et quelle méthode dans cette assemblée vous avez besoin, vous pouvez l'invoquer vous-même comme ceci:

        Assembly assembly = Assembly.LoadFrom("yourApp.exe");
        Type[] types = assembly.GetTypes();
        foreach (Type t in types)
        {
            if (t.Name == "YourClass")
            {
                MethodInfo method = t.GetMethod("YourMethod",
                BindingFlags.Public | BindingFlags.Instance);
                if (method != null)
                {
                    ParameterInfo[] parameters = method.GetParameters();
                    object classInstance = Activator.CreateInstance(t, null);

                    var result = method.Invoke(classInstance, parameters.Length == 0 ? null : parameters);

                    break;
                }
            }

        }
0
répondu Rahmat Anjirabi 2018-07-23 10:43:58
Système

.Diagnostic.Processus.Début("Nom De Fichier Exe");

-11
répondu Abhishek 2012-01-09 13:03:47