Сделал для тестов обработку пользовательского когда 128.
В HandlerEx собственно вызываю эту функцию RunProcessInSession.
В ней делаю пот шагам:
1. OpenProcessToken(GetCurrentProcess,MAXIMUM_ALLOWED,hProcessToken);
2. DuplicateTokenEx(hProcessToken,TOKEN_ALL_ACCESS or TOKEN_READ or TOKEN_WRITE or TOKEN_EXECUTE,nil,SecurityDelegation,TokenPrimary,hNewToken);
3. SetTokenInformation(hNewToken,TokenSessionId,@SessionID,sizeof(SessionID));
и на этом шаге, даже не дав обработать GetLastError в консоли вываливается:
D:\>sc control test_service 128
[SC] ControlService FAILED 1064:
Здравствуйте, Maclaud, Вы писали:
M>Сделал для тестов обработку пользовательского когда 128. M>В HandlerEx собственно вызываю эту функцию RunProcessInSession. M>В ней делаю пот шагам: M>1. OpenProcessToken(GetCurrentProcess,MAXIMUM_ALLOWED,hProcessToken); M>2. DuplicateTokenEx(hProcessToken,TOKEN_ALL_ACCESS or TOKEN_READ or TOKEN_WRITE or TOKEN_EXECUTE,nil,SecurityDelegation,TokenPrimary,hNewToken); M>3. SetTokenInformation(hNewToken,TokenSessionId,@SessionID,sizeof(SessionID)); M>и на этом шаге, даже не дав обработать GetLastError в консоли вываливается: M>D:\>sc control test_service 128 M>[SC] ControlService FAILED 1064:
M>В чем может быть проблема? Где копать?
Покажите сам код. Скорее всего, неверный параметр (нужно сверяться с сигнатурами
функций очень внимательно).
SERVICE_CONTROL_SESSIONCHANGE: // Windows 2000: This value is not supported.
begin
{$IFDEF dm}_log('SERVICE_CONTROL_SESSIONCHANGE');{$ENDIF}
case dwEventType of
WTS_SESSION_LOGON:
begin
{$IFDEF dm}_log('WTS_SESSION_LOGON: start guard '+sa_inttostr(PWTSSESSION_NOTIFICATION(lpEventData)^.dwSessionID));{$ENDIF}
RunProcessInSession(PWTSSESSION_NOTIFICATION(lpEventData)^.dwSessionID,'c:\windows\system32\cmd.exe','');
exit;
end;
end;
end;
Потестил, захожу черех FUS за другого пользователя, там cmd.exe висит как и положено в его 4(на тот момент) сессии. Как и все другие приложения того пользователя. Но окна не видно.
O>Это ведь код на Delphi, так ? O>Вот тут не может быть ошибки: O>
O>lpDesktop := PChar('winsta0\default');
O>
O>В том смысле, что не может ли обратный слэш восприниматься как escape-последовательность ? O>P.S. Я в Delphi не смыслю ничего...
Нет, в делфи нет экранирования.
Вот такое создание из из сервиса, нормально создает видимый процесс, но только на консоли.
function RunProcess(AExeName,AParamStr:string):boolean;
var
StartUpInfo: TStartUpInfo;
ProcessInfo: TProcessInformation;
begin{$IFDEF dm}_log('RunProcess start '+AExeName+' '+AParamStr,false,1);{$ENDIF}
FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);
FillChar(StartUpInfo, SizeOf(TStartUpInfo), 0);
with StartUpInfo do
begin
cb := SizeOf(TStartUpInfo);
dwFlags := STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK;
wShowWindow := SW_SHOWNORMAL;
lpDesktop := PChar('winsta0\default');
end;
result := func_CreateProcessA(PChar(AExeName), PChar(AExeName+' '+AParamStr), nil, nil, false, NORMAL_PRIORITY_CLASS, nil, nil, StartUpInfo, ProcessInfo);
if not WindowsError(result) then
begin//func_WaitForInputIdle(ProcessInfo.hProcess, 60000);
func_CloseHandle(ProcessInfo.hThread);
func_CloseHandle(ProcessInfo.hProcess);
end;
{$IFDEF dm}_log('RunProcess end',false,-1);{$ENDIF}end;
Здравствуйте, Maclaud, Вы писали:
M>Так идет запуск:
M>SERVICE_CONTROL_SESSIONCHANGE: // Windows 2000: This value is not supported. M> begin M> {$IFDEF dm}_log('SERVICE_CONTROL_SESSIONCHANGE');{$ENDIF} M> case dwEventType of M> WTS_SESSION_LOGON: M> begin M> {$IFDEF dm}_log('WTS_SESSION_LOGON: start guard '+sa_inttostr(PWTSSESSION_NOTIFICATION(lpEventData)^.dwSessionID));{$ENDIF} M> RunProcessInSession(PWTSSESSION_NOTIFICATION(lpEventData)^.dwSessionID,'c:\windows\system32\cmd.exe',''); M> exit; M> end; M> end; M> end;
M>Потестил, захожу черех FUS за другого пользователя, там cmd.exe висит как и положено в его 4(на тот момент) сессии. Как и все другие приложения того пользователя. Но окна не видно.
Дабы развеять сомнения провел следующий эксперимент.
Накатал сервис, который при старте запускает командное окно (cmd.exe) и
калькулятор (calc.exe), обе программы в сессиях 1 и 2.
Запустил Windows Vista, залогинился админом (сессия 1), затем гостем (сессия 2),
затем снова переключился на админа и запустил сервис командой net start.
Номера сессий подсмотрел в диспетчере задач.
При запуске появилось окно калькулятора и командной оболочки.
Переключился на гостя — там то же самое, свои экземпляры cmd.exe и calc.exe.
O>Кстати, Shell_NotifyIcon иногда возвращает ошибку, если пользователь уже вошел в систему, а O>его интерактивное окружение (рабочий стол) еще не до конца загрузилось. O>Надо просто организовать цикл и в нем вызывать Shell_NotifyIcon до тех пор, пока она O>не вернет код успеха. Скажем, раз в секунду. Проверено.
Не надо цикла, надо реагировать на сообщение с кодом, полученным от RegisterWindowMessage("TaskbarCreated").
Но это все равно не поможет топикстартеру.
Как много веселых ребят, и все делают велосипед...
Здравствуйте, Maclaud, Вы писали: M>Выложи плиз исходники, я си нормально знаю, постараюсь сравнить найти косяк.
здесь
Код проверен на XP SP2, Server 2003 R2, Vista SP2 (x86), Windows 7 (amd64) и Server 2008 R2.
#include"Common.h"// "targetver.h", <Windows.h>, и др.#include <boost/smart_ptr.hpp>
#include"Procedures.h"namespace {
BOOL
_stdcall
RunInteractiveProcess(
__in wchar_t const * pCmdLine,
__in DWORD IdSession
)
{
// Получаем маркер безопасности текущего процесса.
HANDLE hProcessToken;
if (FALSE == OpenProcessToken(GetCurrentProcess(),
TOKEN_ALL_ACCESS,
&hProcessToken))
{
return FALSE;
}
// Создаем производный маркер.
HANDLE hNewToken;
if (FALSE == DuplicateTokenEx(hProcessToken,
MAXIMUM_ALLOWED,
NULL,
SecurityDelegation,
TokenPrimary,
&hNewToken))
{
CloseHandle(hProcessToken);
return FALSE;
}
CloseHandle(hProcessToken);
// Устанавливаем в маркере id сессии пользователя, в
// которой будет создан новый процесс.if (FALSE == SetTokenInformation(hNewToken,
TokenSessionId,
&IdSession,
sizeof (IdSession)))
{
CloseHandle(hNewToken);
return FALSE;
}
// Выделяем временный буфер для командной строки.
// Зачем это надо - смотрите в описании третьего параметра
// функции CreateProcessAsUser (MSDN).int LengthOfCmdLine = lstrlenW(pCmdLine);
boost::scoped_array<wchar_t> CmdLineBuffer(new wchar_t[LengthOfCmdLine + 1]);
lstrcpyW(CmdLineBuffer.get(), pCmdLine);
// Заполняем структуру STARTUPINFO.
STARTUPINFOW si;
GetStartupInfoW(&si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
si.lpDesktop = L"WinSta0\\Default";
// Запускаем процесс с новым маркером безопасности.
PROCESS_INFORMATION pi;
if (FALSE == CreateProcessAsUserW(hNewToken,
NULL,
CmdLineBuffer.get(),
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&si,
&pi))
{
CloseHandle(hNewToken);
return FALSE;
}
// Очистка ресурсов и выход.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hNewToken);
return TRUE;
}
} // namespace (anonymous)
VOID
_stdcall
ServiceMain(
__in DWORD /* nArgs */,
__in wchar_t ** /* pArgs */
)
{
// Id сессий можно посмотреть в диспетчере задач.
// Если залогиниться двумя пользователями, то они
// будут иметь номера сессий 0 и 1 в Windows XP, и
// 1 и 2 на Vista и более поздних системах (ввиду
// "Session 0 isolation").
DWORD AdminSessionId = 0; // 1 for Vista and later.
DWORD GuestSessionId = 1; // 2 for Vista and later.
RunInteractiveProcess(L"cmd.exe", AdminSessionId);
RunInteractiveProcess(L"calc.exe", AdminSessionId);
RunInteractiveProcess(L"cmd.exe", GuestSessionId);
RunInteractiveProcess(L"calc.exe", GuestSessionId);
// Необходимо сообщить менеджеру служб об остановке,
// иначе служба "повиснет".
SERVICE_STATUS_HANDLE hStatus = RegisterServiceCtrlHandlerExW(L"my_service",
HandlerEx,
NULL);
SERVICE_STATUS ss;
ZeroMemory(&ss, sizeof (ss));
ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ss.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN |
SERVICE_ACCEPT_SESSIONCHANGE | SERVICE_ACCEPT_STOP;
ss.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hStatus, &ss);
}
Ваша ошибка, скорее всего, связана либо с путаницей между ANSI- и Unicode-версиями функций,
либо с неправильной инициализацией структуры STARTUPINFO (в моем коде вызывается GetStartupInfo).
Здравствуйте, ononim, Вы писали:
O>>Кстати, Shell_NotifyIcon иногда возвращает ошибку, если пользователь уже вошел в систему, а O>>его интерактивное окружение (рабочий стол) еще не до конца загрузилось. O>>Надо просто организовать цикл и в нем вызывать Shell_NotifyIcon до тех пор, пока она O>>не вернет код успеха. Скажем, раз в секунду. Проверено. O>Не надо цикла, надо реагировать на сообщение с кодом, полученным от RegisterWindowMessage("TaskbarCreated"). O>Но это все равно не поможет топикстартеру.
Знаю, но на Vista и выше у этого подхода проблемы с User Interface Privilege Isolation (UIPI),
поэтому приходится еще вызывать ChangeWindowMessageFilter.
O>Знаю, но на Vista и выше у этого подхода проблемы с User Interface Privilege Isolation (UIPI), O>поэтому приходится еще вызывать ChangeWindowMessageFilter.
ну да, а че тут такого? цикла то все равно не надо
Как много веселых ребят, и все делают велосипед...
Здравствуйте, ononim, Вы писали:
O>>Знаю, но на Vista и выше у этого подхода проблемы с User Interface Privilege Isolation (UIPI), O>>поэтому приходится еще вызывать ChangeWindowMessageFilter. O>ну да, а че тут такого? цикла то все равно не надо
Да, но дело в том, что ChangeWindowMessageFilter(Ex) поддерживается только на Vista и выше.
Это значит, что для XP и Server 2003 нужно будет писать #ifdef или шаблон,
параметризированный номером версии NT. Либо получать функцию через LoadLibrary.
Цикл все же проще.
O>Да, но дело в том, что ChangeWindowMessageFilter(Ex) поддерживается только на Vista и выше. O>Это значит, что для XP и Server 2003 нужно будет писать #ifdef или шаблон, O>параметризированный номером версии NT. Либо получать функцию через LoadLibrary. O>Цикл все же проще.
1) Цикл не поможет от пропажи иконки изза скоропостижно скончавшегося (и автоматически перезапущенного системой) эксплорера, а месага — поможет
2) Pooling зло.
Как много веселых ребят, и все делают велосипед...
Здравствуйте, ononim, Вы писали:
O>>Да, но дело в том, что ChangeWindowMessageFilter(Ex) поддерживается только на Vista и выше. O>>Это значит, что для XP и Server 2003 нужно будет писать #ifdef или шаблон, O>>параметризированный номером версии NT. Либо получать функцию через LoadLibrary. O>>Цикл все же проще. O>1) Цикл не поможет от пропажи иконки изза скоропостижно скончавшегося (и автоматически перезапущенного системой) эксплорера, а месага — поможет
O>>2) Pooling зло. O>О чем конкретно речь ?
О том что pooling жрет CPU бес толку. Понятно, что если такая программа на компе одна и делает это не часто — это некритично. А когда таких прог куча и работают они на терминальном сервере с сотней-другой юзеров...
Как много веселых ребят, и все делают велосипед...