Служба Windows, созданная для выключения компьютера, не работает, когда компьютер заблокирован - PullRequest
5 голосов
/ 20 апреля 2011

Я создал службу Windows в C # для выключения компьютера.

Служба отлично работает, когда компьютер не заблокирован (Ctrl + Alt + Del).

Но некоторые какон не выключается, когда мой компьютер заблокирован.

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

ОБНОВЛЕНИЕ:

Основано на помощи Криса Хааса. Я пытаюсьчтобы определить, какой вызов возвращает ошибку, на основе значения 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 

Но ok всегда возвращает true.

Ответы [ 3 ]

2 голосов
/ 21 апреля 2011

Используйте вместо
InitiateSystemShutdownEx .Смотрите комментарии относительно параметров, вы можете принудительно завершить работу, если машина заблокирована.

РЕДАКТИРОВАТЬ: Я помню, что использовал его некоторое время назад.В MSDN есть специальный комментарий:

* Windows Server 2003 и Windows XP: если компьютер заблокирован и параметр bForceAppsClosed имеет значение FALSE, последний код ошибки - ERROR_MACHINE_LOCKED.Если система не готова обработать запрос, последний код ошибки - ERROR_NOT_READY.Приложение должно немного подождать и повторить вызов.Например, система может быть не готова инициировать завершение работы и возвращать ERROR_NOT_READY, если запрос на завершение работы приходит одновременно с попыткой пользователя войти в систему.В этом случае приложение должно немного подождать и повторить вызов. *

2 голосов
/ 21 апреля 2011

Полагаю, это проблема с разрешением, но я точно не знаю.Очень важно то, что вы отбрасываете возможные ошибки.Вы продолжаете устанавливать переменную ok, но никогда не проверяете ее.Это, вероятно, скажет вам, где есть проблема

РЕДАКТИРОВАТЬ

Кроме того, я думаю, вы действительно хотите передать EWX_SHUTDOWN | EWX_POWEROFF

РЕДАКТИРОВАТЬ2

Если вы получили сообщение об ошибке, вы должны позвонить Marshal.GetLastWin32Error()

РЕДАКТИРОВАТЬ 3

Вы не 'не нужно каждый раз вызывать GetLastError, просто если ok равно false:

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 голосов
/ 21 апреля 2011

Служба Windows требует разрешения учетной записи пользователя, в которой она установлена. Вы можете

отредактируйте это разрешение, щелкнув правой кнопкой мыши и выбрав Logon после перехода к

AdministartiveTools-> service-> yourService. Обычно для этого параметра устанавливается значение "LOCAL SERVICE",

попробуйте указать учетные данные учетной записи, в которой работает ваша служба.

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.

Надеюсь, это поможет вам ........

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...