studio - llamar un servicio windows desde c#
¿Cómo puedo ejecutar un programa EXE desde un servicio de Windows usando C#? (7)
Primero, vamos a crear un servicio de Windows que se ejecute bajo la cuenta del sistema. Este servicio será responsable de generar un proceso interactivo dentro de la sesión del usuario actualmente activa. Este proceso recién creado mostrará una IU y se ejecutará con todos los derechos de administrador. Cuando el primer usuario inicia sesión en la computadora, este servicio se iniciará y se ejecutará en Session0; sin embargo, el proceso que genera este servicio se ejecutará en el escritorio del usuario que está actualmente conectado. Nos referiremos a este servicio como el LoaderService.
A continuación, el proceso winlogon.exe es responsable de administrar los procedimientos de inicio de sesión y cierre de sesión del usuario. Sabemos que cada Usuario que inicie sesión en la computadora tendrá una ID de sesión única y un proceso winlogon.exe correspondiente asociado con su Sesión. Ahora, hemos mencionado anteriormente, el LoaderService se ejecuta bajo la cuenta del sistema. También confirmamos que cada proceso de winlogon.exe en la computadora se ejecuta bajo la cuenta del sistema. Como la cuenta del sistema es propietaria de los procesos LoaderService y winlogon.exe, nuestro LoaderService puede copiar el token de acceso (y el ID de sesión) del proceso winlogon.exe y luego llamar a la función Win32 API CreateProcessAsUser para iniciar un proceso en el sesión actualmente activa del Usuario conectado. Dado que el ID de sesión ubicado dentro del token de acceso del proceso winlogon.exe copiado es mayor que 0, podemos iniciar un proceso interactivo usando ese token.
Prueba este. Subvertir Vista UAC en Arquitecturas de 32 y 64 bit
¿Cómo puedo ejecutar un programa EXE
desde un servicio de Windows usando C #?
Este es mi código:
System.Diagnostics.Process.Start(@"E:/PROJECT XL/INI SQLLOADER/ConsoleApplication2/ConsoleApplication2/ConsoleApplication2/bin/Debug/ConsoleApplication2.exe");
Cuando ejecuto este servicio, la aplicación no se inicia.
¿Qué pasa con mi código?
Creo que estás copiando el .exe a una ubicación diferente. Este podría ser el problema, supongo. Cuando copia el exe, no está copiando sus dependencias.
Entonces, lo que puedes hacer es poner todos los dlls dependientes en GAC para que cualquier .NET exe pueda acceder a él
De lo contrario, no copies el exe en una nueva ubicación. Solo crea una variable de entorno y llama al exe en tu c #. Como la ruta está definida en variables de entorno, su programa c # puede acceder al exe.
Actualizar:
anteriormente tenía algún tipo de problema en mi proyecto c # .net 3.5 en el que intentaba ejecutar un archivo .exe desde el código c # .net y ese exe no era más que el otro proyecto exe (donde agregué algunos dlls de soporte para mi funcionalidad) y esos métodos dlls que estaba usando en mi aplicación exe. Finalmente resolví esto creando esa aplicación como un proyecto separado para la misma solución y agregué ese resultado del proyecto a mi proyecto de implementación. De acuerdo con este escenario, respondí: si no es lo que él quiere, entonces lo siento mucho.
He intentado este artículo Code Project , está funcionando bien para mí. También he usado el código. el artículo es excelente en explicación con captura de pantalla.
Estoy agregando la explicación necesaria a este escenario
Acaba de arrancar su computadora y está a punto de iniciar sesión. Cuando inicia sesión, el sistema le asigna una ID de sesión única. En Windows Vista, al primer usuario que inicia sesión en la computadora se le asigna una ID de sesión de 1 por parte del sistema operativo. Al siguiente Usuario que inicie sesión se le asignará una ID de sesión de 2. Y así sucesivamente. Puede ver la ID de sesión asignada a cada Usuario conectado desde la pestaña Usuarios en el Administrador de tareas.
Pero su servicio de Windows tiene una identificación de sesión de 0. Esta sesión está aislada de otras sesiones. En última instancia, esto impide que el servicio de Windows invoque la aplicación que se ejecuta en sesiones de usuario como 1 o 2.
Para invocar la aplicación desde el servicio de Windows, debe copiar el control de winlogon.exe que actúa como usuario registrado presente como se muestra en la captura de pantalla siguiente.
Códigos importantes
// 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
);
Puede ejecutar un .exe desde un servicio de Windows muy bien en Windows XP. Lo he hecho yo mismo en el pasado.
Debe asegurarse de haber marcado la opción "Permitir interactuar con el escritorio" en las propiedades del servicio de Windows. Si eso no se hace, no se ejecutará.
Necesito verificar en Windows 7 o Vista, ya que estas versiones requieren privilegios de seguridad adicionales por lo que puede arrojar un error, pero estoy bastante seguro de que se puede lograr ya sea directa o indirectamente. Para XP, estoy seguro de haberlo hecho yo mismo.
Puede usar el programador de tareas de Windows para este fin, hay muchas bibliotecas como TaskScheduler que lo ayudan.
por ejemplo, consideremos que queremos programar una tarea que se ejecutará una vez cinco segundos después:
using (var ts = new TaskService())
{
var t = ts.Execute("notepad.exe")
.Once()
.Starting(DateTime.Now.AddSeconds(5))
.AsTask("myTask");
}
notepad.exe se ejecutará cinco segundos después.
para más detalles y más información, vaya al wiki
Si sabe qué clase y método necesita, puede invocarlo usted mismo de la siguiente manera:
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;
}
}
}
System.Diagnostics.Process.Start ("Nombre de Exe");
Esto nunca funcionará , al menos no con Windows Vista o posterior. El problema clave es que está intentando ejecutar esto desde un servicio de Windows, en lugar de una aplicación estándar de Windows. El código que ha mostrado funcionará perfectamente en una aplicación Windows Forms, WPF o Console, pero no funcionará en absoluto en un servicio de Windows.
Los Servicios de Windows no pueden iniciar aplicaciones adicionales porque no se están ejecutando en el contexto de ningún usuario en particular. A diferencia de las aplicaciones normales de Windows, los servicios ahora se ejecutan en una sesión aislada y tienen prohibido interactuar con un usuario o el escritorio. Esto no deja lugar para que se ejecute la aplicación.
Hay más información disponible en las respuestas a estas preguntas relacionadas:
- ¿Cómo puede un servicio de Windows iniciar un proceso cuando se produce un evento Timer?
- ¿Qué proceso en Windows es específico del usuario?
- servicio de Windows (permite que el servicio interactúe con el escritorio)
La mejor solución para su problema, como probablemente ya haya descubierto, es crear una aplicación estándar de Windows en lugar de un servicio. Están diseñados para que los ejecute un usuario en particular y estén asociados con el escritorio de ese usuario. De esta forma, puede ejecutar aplicaciones adicionales siempre que lo desee, utilizando el código que ya ha mostrado.
Otra posible solución, suponiendo que su aplicación de consola no requiera una interfaz o salida de ningún tipo, es instruir al proceso para que no cree una ventana. Esto evitará que Windows bloquee la creación de su proceso, porque ya no solicitará que se cree una ventana de Consola. Puede encontrar el código relevante en esta respuesta a una pregunta relacionada.