2011-04-20 19 views
5

He creado un servicio de Windows en C# para apagar la computadora.El servicio de Windows creado para apagar la computadora no funciona cuando la computadora está bloqueada

El servicio funciona bien cuando la computadora no está bloqueada (Ctrl + Alt + Supr).

Pero de alguna manera no se apaga cuando mi computadora está bloqueada.

// call 
DoExitWin(EWX_SHUTDOWN); 

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
internal struct TokPriv1Luid 
{ 
    public int Count; 
    public long Luid; 
    public int Attr; 
} 

[DllImport("kernel32.dll", ExactSpelling = true)] 
internal static extern IntPtr GetCurrentProcess(); 

[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] 
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok); 

[DllImport("advapi32.dll", SetLastError = true)] 
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid); 

[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] 
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, 
    ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen); 

[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] 
internal static extern bool ExitWindowsEx(int flg, int rea); 

internal const int SE_PRIVILEGE_ENABLED = 0x00000002; 
internal const int TOKEN_QUERY = 0x00000008; 
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; 
internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege"; 
internal const int EWX_LOGOFF = 0x00000000; 
internal const int EWX_SHUTDOWN = 0x00000001; 
internal const int EWX_REBOOT = 0x00000002; 
internal const int EWX_FORCE = 0x00000004; 
internal const int EWX_POWEROFF = 0x00000008; 
internal const int EWX_FORCEIFHUNG = 0x00000010; 

private static void DoExitWin(int flg) 
{ 
    bool ok; 
    TokPriv1Luid tp; 
    IntPtr hproc = GetCurrentProcess(); 
    IntPtr htok = IntPtr.Zero; 
    ok = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); 
    tp.Count = 1; 
    tp.Luid = 0; 
    tp.Attr = SE_PRIVILEGE_ENABLED; 
    ok = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid); 
    ok = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero,IntPtr.Zero); 
    ok = ExitWindowsEx(flg, 0); 
} 

ACTUALIZACIÓN:

Sobre la base de la ayuda de Chris Haas Estoy tratando de encontrar qué llamada devuelve un error basado en el valor de ok:

ok = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); 
int error = Marshal.GetLastWin32Error(); //error 87 ok return true 
ok = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid); 
error = Marshal.GetLastWin32Error(); //error 997 ok return true rest of ok true with zero error code 

ok = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero,IntPtr.Zero); 
ok = ExitWindowsEx(flg, 0); //This mean error in ok 

Pero ok retornos cierto todo el tiempo.

+0

¿Se está ejecutando el servicio con la cuenta de usuario? – manojlds

+0

No. Servicio local – Rohit

Respuesta

2

Supongo que es un problema de permiso, pero definitivamente no lo sé. Una cosa muy importante es que estás descartando posibles errores. Sigue estableciendo la variable ok pero nunca la verifica. Esto probablemente le diría donde hay un problema

EDITAR

Además, creo que en realidad se quiere pasar EWX_SHUTDOWN | EWX_POWEROFF

EDIT 2

Si se produce un error debe llamar Marshal.GetLastWin32Error()

EDIT 3

Usted no tiene que llamar a GetLastError cada vez, solo si ok es falso:

int error; 
ok = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); 
if(!ok){ 
    error = Marshal.GetLastWin32Error(); 
    throw new ApplicationException('Error : ' + error); 
} 
tp.Count = 1; 
tp.Luid = 0; 
tp.Attr = SE_PRIVILEGE_ENABLED; 
ok = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid); 
if(!ok){ 
    error = Marshal.GetLastWin32Error(); 
    throw new ApplicationException('Error : ' + error); 
} 
ok = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero,IntPtr.Zero); 
if(!ok){ 
    error = Marshal.GetLastWin32Error(); 
    throw new ApplicationException('Error : ' + error); 
} 
ok = ExitWindowsEx(flg, 0); 
if(!ok){ 
    error = Marshal.GetLastWin32Error(); 
    throw new ApplicationException('Error : ' + error); 
} 
+0

No arrojando ningún error. El servicio de Windows funciona bien cuando la computadora no está bloqueada. incluso lo intenté en la aplicación de Windows para la depuración. – Rohit

+0

@Rohit, no conozco su nivel de habilidad, así que me disculpo si ya ha verificado esto. Las funciones de Win32 no arrojan errores, sino que devuelven valores distintos de cero. A continuación, llama a 'GetLastError()' para determinar cuál es realmente el error. Entonces, solo porque no obtenga una excepción no significa que no haya errores. Comprueba el valor de 'ok' en cada paso y si es falsa llama a Marshal.GetLastWin32Error(). –

+0

ok = OpenProcessToken (hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); int error = Marshal.GetLastWin32Error(); // error 87 ok return true ok = LookupPrivilegeValue (null, SE_SHUTDOWN_NAME, ref tp.Luid); error = Marshal.GetLastWin32Error(); // error 997 ok return true resto de bien verdadero con cero código de error – Rohit

0

servicio de Windows requiere el permiso de la cuenta de usuario en el que está instalado. que pueda

editar este permiso haciendo clic derecho y seleccionando inicio de sesión después de navegar a

AdministartiveTools-> servicio-> YourService. Normalmente esto se establecerá en "SERVICIO LOCAL",

intente dar las credenciales de la cuenta en la que se está ejecutando su servicio.

Please cross check whether you have done the following steps during windows service creation: 

1.After creating the windows service project go to the service class's design view(just double click the service1.cs class). 

2.In the design view right click and select Add Installer. This will create an Installer class named ProjectInstaller.cs. With out ProjectInstaller.cs or any error in configuring ProjectInstaller.cs may result in non-showing of the service in service console. 

3.Go to the design view of ProjectInstaller.cs you will find two installers there-> 

a.**ServiceInstaller1** 

    b.**ServiceProcessInstaller1** 
4.Right click ServiceInstaller1 and go to the properties tab 

    a.Edit the ServiceName with the name you want to 
     see your service in the service console. 

    b.Change the **StartType** to **Automatic**. 
5.Right click ServiceProcessInstaller1 and go to the properties tab 

    a.Change the account to **LocalService** 

    6. Save and try it. 

Hope esto le ayudará a ........

2

Uso lugar
InitiateSystemShutdownEx. Consulte los comentarios sobre los parámetros, puede forzar el apagado si la máquina está bloqueada.

EDIT: Recuerdo que lo usé hace algún tiempo.Hay un comentario específico en MSDN:

* Windows Server 2003 y Windows XP: si la computadora está bloqueada y el parámetro bForceAppsClosed es FALSE, el último código de error es ERROR_MACHINE_LOCKED. Si el sistema no está listo para manejar la solicitud, el último código de error es ERROR_NOT_READY. La aplicación debe esperar un momento y volver a intentar la llamada. Por ejemplo, el sistema puede no estar listo para iniciar un apagado, y devolver ERROR_NOT_READY, si la solicitud de cierre se produce al mismo tiempo que un usuario intenta iniciar sesión en el sistema. En este caso, la aplicación debe esperar un momento y volver a intentar la llamada. *

Cuestiones relacionadas