Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« : 13-09-2016 07:07 » |
|
насколько я понял, в винде 7 из службы невозможно отобразить окно напрямую ?
Или это особенности Qt-шной реализации (пробую кутешное GUI-приложение запустить как службу через QtService)
Если это так, то как там окна, скажем, для настроек или мониторинга отображаются ?
Сама служба вроде работает
|
|
« Последнее редактирование: 13-09-2016 07:10 от Алексей++ »
|
Записан
|
|
|
|
zubr
Гость
|
|
« Ответ #1 : 13-09-2016 07:48 » |
|
Алексей++, 2 варианта: 1. Сделать сервис интерактивным. Для этого в процедуре сервиса надо указать тип SERVICE_INTERACTIVE_PROCESS функция SetServiceStatus 2. Из сервиса запустить ГУИ-процесс. CreateProcessAsUser
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #2 : 13-09-2016 12:44 » |
|
zubr, 1 - в исходниках Qt вроде они так и указали bool QtServiceBasePrivate::sysInit() { sysd = new QtServiceSysPrivate();
sysd->serviceStatus = 0; sysd->status.dwServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS; sysd->status.dwCurrentState = SERVICE_STOPPED; sysd->status.dwControlsAccepted = sysd->serviceFlags(serviceFlags); sysd->status.dwWin32ExitCode = NO_ERROR; sysd->status.dwServiceSpecificExitCode = 0; sysd->status.dwCheckPoint = 0; sysd->status.dwWaitHint = 0;
return true; }
так что это не прокатывает, похоже 2 - тоже так подумал. Служба будет запускать процесс, если он не запущен спасибо Добавлено через 6 минут и 48 секунд:ещё вот нашёл https://msdn.microsoft.com/en-us/library/windows/desktop/ms683502(v=vs.85).aspxфлаг в реестре глянул - там 0, но всё равно не показывается окно . Но даже если было бы значение 1, то ковыряться в чужом реесте, полагаю, было бы лишнее )) Так что вариант №2 буду пробовать
|
|
« Последнее редактирование: 13-09-2016 12:51 от Алексей1153 »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #3 : 15-09-2016 11:59 » |
|
очередная непонятность. Пытаюсь запустить хоть что-то из сервиса, к примеру - калькулятор QString serverfullpath="C:/Windows/System32/calc.exe"; int result = (int)::ShellExecuteA(0, "open", serverfullpath.toUtf8().constData(), 0, 0, SW_SHOWNORMAL); uint32_t err=GetLastError();
процесс не запускается, в диспетчере тоже ничего не отображается нового result==42 в мсдн по ShellExecuteA непонятно, что за значение https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspxGetLastError==183 - "Невозможно создать файл, так как он уже существует. " что не так и куда смотреть ? Добавлено через 11 минут и 11 секунд:насчёт правильности пути - файл то он видит. Если подправить на неправильный путь - говорит, что файл не найден Добавлено через 29 секунд:из обычного приложение - не сервиса - запуск производится нормально
|
|
« Последнее редактирование: 15-09-2016 12:11 от Алексей1153 »
|
Записан
|
|
|
|
Aether
|
|
« Ответ #4 : 15-09-2016 12:11 » |
|
ShellExecuteA по идее должен принимать в качестве аргументов строки не UTF. Должно быть также ShellExecuteW. Возможна ли путаница в кодировках использующихся в Qt и WinAPI? То есть вместо Calc он что-то пытается запустить, не находит и всё.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #5 : 15-09-2016 12:18 » |
|
Aether, из "не сервиса" код запуска то работает. Но я пробовал и не utf8 , всё так же.
Тут хитрость именно в том, что запускаю из сервиса, но вот что именно ковырять ?
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #6 : 15-09-2016 12:19 » |
|
CoInitializeEx было? там что то про это... непонятное сказано вроде
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Aether
|
|
« Ответ #7 : 15-09-2016 12:22 » |
|
Aether, из "не сервиса" код запуска то работает. Но я пробовал и не utf8 , всё так же.
Тут хитрость именно в том, что запускаю из сервиса, но вот что именно ковырять ?
Можно попробовать изменить SW_SHOWNORMAL на SW_HIDE просто для оценки результата?
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #8 : 15-09-2016 12:23 » |
|
микрософт пишет Scr_hDC = GetDesktopWindow() StartDoc = ShellExecute(Scr_hDC, "Open", DocName, "", "C:\", SW_SHOWNORMAL)
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #9 : 15-09-2016 12:32 » |
|
Aether, без изменений Ochkarik, хендл GetDesktopWindow() добавил, но изменений нету про CoInitializeEx не знаю, почитаю, что там Добавлено через 3 минуты и 21 секунду:Ochkarik, в таком виде ::ShellExecuteA(Scr_hDC, "open", "calc.exe", 0, "C:/Windows/System32/", SW_SHOWNORMAL); тоже всё по прежнему
|
|
« Последнее редактирование: 15-09-2016 12:35 от Алексей1153 »
|
Записан
|
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #11 : 15-09-2016 12:48 » |
|
Ochkarik, так что ж делать то
Добавлено через 1 минуту и 35 секунд: CreateProcess попробовать предлагаешь ? Дома попробую )
|
|
« Последнее редактирование: 15-09-2016 12:50 от Алексей1153 »
|
Записан
|
|
|
|
zubr
Гость
|
|
« Ответ #12 : 15-09-2016 13:47 » |
|
Алексей++, я же тебе написал CreateProcessAsUser. Сервис работает под системой, естественно он не может запустить процесс под юзером, используя ShellExecut или CreateProcess.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #13 : 15-09-2016 15:51 » |
|
zubr, ага, я не заметил, оказывается. Уже с CreateProcess попробовал - ровно то же самое происходит.
Смотрю параметры CreateProcessAsUser - кроме первого всё понятно, откуда брать первый пытаюсь понять
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #14 : 15-09-2016 16:08 » |
|
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #15 : 15-09-2016 16:20 » |
|
Я не совсем понимаю ситуацию, зачем из под сервиса запускать GUI? Сервис запускается еше до того, как пользователь залогинился. Следовательно куда он должен запускать GUI?
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #16 : 15-09-2016 16:23 » |
|
Finch, заказчик пожелал GUI-программы оформить в виде сервиса. И тут понеслось - пытаюсь хоть что-то из сервиса запустить
пусть даже сначала нет юзера, но когда система загрузилась - юзер же появился ? Где его хендл взять ?
Добавлено через 1 минуту и 10 секунд: я к тому, что когда я наконец-то найду этот хендл - тогда и запущу приложение. А если не нахожу - жду некоторое время, потом снова пытаюсь
|
|
« Последнее редактирование: 15-09-2016 16:24 от Алексей1153 »
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #17 : 15-09-2016 16:25 » |
|
А сделать отдельно сервис и отдельно GUI? Пускай программа с GUI висит как Watchdog. И мониторить сервис. Тогда много проблем решаться сами собой.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #18 : 15-09-2016 16:29 » |
|
Finch, как раз наоборот - сервис как вачдог. Если программа не запущена, мне надо её запустить
Добавлено через 1 минуту: до этого гуи сидел себе в автозагрузке. И тут заказчику захотелось как сервис запускать
|
|
« Последнее редактирование: 15-09-2016 16:30 от Алексей1153 »
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #19 : 15-09-2016 16:35 » |
|
Точно не скажу за винду. В *nix системах, Сервис отличается от простой программы только тем, что у него отключены все хендды консолей. Следовательно при запуске из него других программ, у этих программ тоже будут отключены хендлы.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #20 : 15-09-2016 16:36 » |
|
Finch, вот сейчас я остановился на том, как правильно вызвать LogonUserW - где брать имя, домен и логин юзера ?
по ТЗ, юзер неважен. Значит, надо как-то текущего загруженного юзера туда указать
|
|
« Последнее редактирование: 15-09-2016 16:41 от Алексей++ »
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #21 : 15-09-2016 16:40 » |
|
Ну логины скорее всего есть в реестре. А вот с паролями у тебя будет засада. В реестре скорее всего будут хранится хеши паролей.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #22 : 15-09-2016 16:42 » |
|
Finch, допустим, пароль у них будет пустой. А домен - это что и где ?
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #23 : 15-09-2016 16:43 » |
|
Тоже должен быть в реестре. По умолчанию localdomain:localhost Может быть есть фунуция по типу GetLocalDomainName. Точнее нужно искать в MSDN.
|
|
« Последнее редактирование: 15-09-2016 16:46 от Finch »
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #24 : 15-09-2016 17:01 » |
|
ну вот, к примеру, зашёл я под юзером "xxx" . Пароля нет. HANDLE hToken=0; int res=LogonUserW(L"xxx", 0, 0, LOGON32_LOGON_SERVICE, LOGON32_PROVIDER_DEFAULT, &hToken); res==0 hToken==0 Такое чуйство, что фигнёй занимаюсь какой-то. Наверное, нужно предложить заместо сервиса в автозапуск положить минимальную простейшую апликуху, которая будет ту же функцию выполнять - а виснуть там нечему, потому что она элементарнейшая
|
|
« Последнее редактирование: 15-09-2016 17:15 от Алексей++ »
|
Записан
|
|
|
|
Aether
|
|
« Ответ #25 : 15-09-2016 17:35 » |
|
По идее, как это видится: запущенный сервис, помимо своей основной роли также следит: залогинился ли какой-нибудь пользователь? Если пользователь обнаружен, то он создаёт процесс в его пространстве, а тот уже открывает окно или что нужно.
Интересно: чем заказчик аргументирует своё желание к конечному исполнению? Главное же в том, чтобы работало и просто настраивалось.
|
|
|
Записан
|
|
|
|
Aether
|
|
« Ответ #26 : 15-09-2016 17:37 » |
|
Тоже должен быть в реестре. По умолчанию localdomain:localhost Может быть есть фунуция по типу GetLocalDomainName. Точнее нужно искать в MSDN.
А если пользователь зашёл через RDP, например? Тут должен быть какой-то механизм опроса: сколько пользователей подключено и кто они.
|
|
|
Записан
|
|
|
|
zubr
Гость
|
|
« Ответ #27 : 15-09-2016 17:49 » |
|
Делал когда то: BOOL Gl::CreateUserProcess(PWCHAR commandLine, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { DWORD sid; HANDLE hToken = NULL, hNewToken = NULL; BOOL result = FALSE; PVOID lpEnvironment;
sid = WTSGetActiveConsoleSessionId(); if(!WTSQueryUserToken(sid, &hToken)) { return FALSE; }
while(1) { if(!DuplicateTokenEx(hToken, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, NULL, SecurityAnonymous, TokenPrimary, &hNewToken)) break;
if(!CreateEnvironmentBlock(&lpEnvironment, hNewToken, FALSE)) break; RtlZeroMemory(lpStartupInfo, sizeof(STARTUPINFO)); RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION)); lpStartupInfo->cb = sizeof(STARTUPINFO); lpStartupInfo->lpDesktop = L"Winsta0\\Default"; result = CreateProcessAsUser(hNewToken, NULL, commandLine, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, lpEnvironment, NULL, lpStartupInfo, lpProcessInformation); break; } if(hToken) CloseHandle(hToken); if(hNewToken) CloseHandle(hNewToken);
return result; }
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #28 : 16-09-2016 05:13 » |
|
zubr, а что тут делается ?
|
|
|
Записан
|
|
|
|
zubr
Гость
|
|
« Ответ #29 : 16-09-2016 06:07 » |
|
1. Получаем индентификатор активной сессии 2. По полученному индентификатору получаем токен текущего юзера. 3. Создаем новый токен на основе полученного со своими параметрами доступа. Нужно, чтобы выделить блок окружения для процесса. 4. Создаем блок окружения под созданным токеном. Нужно для создания процесса под юзером. 5. Запускаем процесс под текущим юзером.
|
|
|
Записан
|
|
|
|
|