Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Win7 + TrayIcon + системная учетная запись, Работа с треем другого пользователя 
:(
    Опции темы
Romero
Дата 18.2.2011, 11:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 17.6.2005

Репутация: 1
Всего: 1



Добрый день, уважаемые знатоки.
Необходимо переписать один из своих старых проектов, который разрабатывался во времена Windows XP. Причина - некорректная работа в Windows 7. А именно...
Первая часть проекта - программа с иконкой в системном трее. Назовем ее "Программа".
Вторая часть - служба, запускаемая с правами системы. Она контролирует наличие запущенного процесса Программы: при необходимости выполняет ее запуск или перезапуск. При этом критично, чтобы Программа запускалась именно с правами системы (передаваемыми ей от службы).
Суть проблемы - в "семерке" иконка в трее запущенной службой Программы не отображается. Я так понял, что в Win7, в отличие от WinXP, у каждого пользователя свой рабочий стол, а соответственно и трей. Поэтому и иконка Программы "появляется" в трее системного аккаунта, а не активного пользователя.
Вопрос: как обойти сие нововведение Windows? Вероятно, создавая иконку, нужно каким-то образом указать "чужой" трей, но как это сделать - не нашел. Возможно, предложите свои решения. Обе части проекта написаны мной, можно механизм взаимодействия как угодно переписать. Вариант запуска службой Программы от имени активного пользователя - не подходит точно.
PM   Вверх
kami
Дата 18.2.2011, 18:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(Romero @  18.2.2011,  11:31 Найти цитируемый пост)
 Я так понял, что в Win7, в отличие от WinXP, у каждого пользователя свой рабочий стол, а соответственно и трей. Поэтому и иконка Программы "появляется" в трее системного аккаунта, а не активного пользователя.

Правильно.
Цитата(Romero @  18.2.2011,  11:31 Найти цитируемый пост)
 создавая иконку, нужно каким-то образом указать "чужой" трей, но как это сделать - не нашел.

И не найдете. "Чужой трей" находится на чужом рабочем столе, в чужой оконной станции и чужой терминальной сессии. Вы туда не влезете.
Цитата(Romero @  18.2.2011,  11:31 Найти цитируемый пост)
Вариант запуска службой Программы от имени активного пользователя - не подходит точно.

Тогда - CreateProcesAsUser или CreateProcessWithLogonW.
PM MAIL WWW   Вверх
bems
Дата 18.2.2011, 18:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 21
Всего: 88



Нет никакого трея системы. В остальном Ками прав.


Это сообщение отредактировал(а) bems - 18.2.2011, 19:11


--------------------
Обижено школьников: 8
PM MAIL   Вверх
kami
Дата 18.2.2011, 18:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



А, забыл - есть же еще планировщик заданий smile

Кстати, такая политика появилась не в Win7, а в Win Vista

Добавлено через 2 минуты и 54 секунды
Цитата(bems @  18.2.2011,  18:57 Найти цитируемый пост)
SetThreadDesktop

Не получится, я пробовал. Устанавливаемый десктоп должен принадлежать родной для процесса WinSta, а WinSta сервиса<> WinSta десктопного приложения.
Цитата

This desktop must be associated with the current window station for the process.

SetThreadDesktop
PM MAIL WWW   Вверх
bems
Дата 18.2.2011, 19:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 21
Всего: 88



Цитата(kami @  18.2.2011,  18:59 Найти цитируемый пост)
Устанавливаемый десктоп должен принадлежать родной для процесса WinSta, а WinSta сервиса<> WinSta десктопного приложения.
Да, в курсе. Для этого нужно сделать SetProcessWindowStation, а для этого нужна общая сессия.
Но из системной учетки это точно возможно, нужно только найти правильный путь.



--------------------
Обижено школьников: 8
PM MAIL   Вверх
CodeMonkey
Дата 18.2.2011, 19:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 16
Всего: 89



Цитата(Romero @  18.2.2011,  12:31 Найти цитируемый пост)
При этом критично, чтобы Программа запускалась именно с правами системы (передаваемыми ей от службы).


Почему это? Чую запах ###-кода.

Добавлено через 12 минут и 21 секунду
P.S. И гляньте ещё вот это.

Цитата(bems @  18.2.2011,  20:10 Найти цитируемый пост)
Но из системной учетки это точно возможно, нужно только найти правильный путь.


А откуда уверенность?


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
kami
Дата 18.2.2011, 19:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



В свое время пришлось очень плотно заниматься этой проблемой. Знаний и навыков было, конечно, гораздо меньше...
Результатом был отлов смены сессии (в HandlerEx) и запуск процесса через CreateProcessAsUser, с какими-то извращениями над полученным токеном.
PM MAIL WWW   Вверх
bems
Дата 18.2.2011, 20:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 21
Всего: 88



Цитата(CodeMonkey @  18.2.2011,  19:30 Найти цитируемый пост)
А откуда уверенность?

Потому что еще не было такого, чтобы ей что-то эффективно запретили. Весь вопрос только в количестве извращений на тысячу строк кода.
Это конечно не меняет того факта, что не нужно запускать интерактивные программы в контексте системы


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Romero
Дата 20.2.2011, 23:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 17.6.2005

Репутация: 1
Всего: 1



Спасибо огромное за ответы!
Насчет целесообразности запуска Программы именно с привилегиями системы я еще подумаю на неделе. Дело в том, что писалось это все несколько лет назад (опыта было меньше, винды еще не так к безопасности подходили...), и теперь, возможно, есть смысл более обдуманно подойти к проектированию. Системные права нужны (в подробности вдаваться не буду, если позволите), но другое дело, что можно перепоручить ту часть функционала, где они требуются, самой службе, а не Программе. А ей уж оставить лишь иконку, да окошки.
На всякий случае научился запускать Программу из службы с правами и в сеансе активного пользователя (надо только еще проверить хорошо, что везде и всегда работает - раньше не сталкивался с такими механизмами). Но с этим вариантом еще возникает ряд вопросов. Обмозгую хорошенько на свежую голову и спрошу здесь, коли не разберусь с чем.
PM   Вверх
kami
Дата 21.2.2011, 00:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(Romero @  20.2.2011,  23:56 Найти цитируемый пост)
проверить хорошо, что везде и всегда работает - раньше не сталкивался с такими механизмами

Большая просьба - если будет работать с быстрым переключением пользователей, т.е. десктопная часть будет запускаться под каждым из залогиненных пользователей - выложите код. Безумно интересно, как Вы справились с этой проблемой.
PM MAIL WWW   Вверх
Romero
Дата 21.2.2011, 12:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 17.6.2005

Репутация: 1
Всего: 1



kami, мне мыслится сей механизм так: в моей службе по таймеру проверяется наличие запущенного процесса Программы. В эту проверку можно добавить сравнение SID пользователя, от которого запущен процесс, с SID активного пользователя. Если не совпадают, запускать процесс под активным пользователем. С определением SID найденного процесса я разобрался, а с SID активного пользователя - нет. Не сталкивались с этим?
Для запуска Программы в контексте активного пользователя я использую JediWinAPI. Поэтому можно и SID пользователя определять ее средствами. Но я никак не могу найти толковой документации по данной библиотеке.
PM   Вверх
Romero
Дата 21.2.2011, 15:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 17.6.2005

Репутация: 1
Всего: 1



Кажется, получилось!  smile 
Действовал, как описал выше. Сейчас приберусь в коде, и выложу результат. Надеюсь, покажете, что и где оптимизировать можно - писал сумбурно, дергая отовсюду и адаптируя чужие куски кода.
PM   Вверх
Romero
Дата 21.2.2011, 17:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 17.6.2005

Репутация: 1
Всего: 1



Итак, вот что у меня получилось... Тестирование пока провел лишь на Windows 7 32bit. Остальные варианты позже тоже проверю (меня интересует еще по большому счету лишь Windows XP и 64-битные вариации обеих ОС). Помогите с оптимизацией алгоритма и кодов, плиз.
Код

uses
  ..., JwaWinBase, JwaWtsApi32;//Jedi я использовал для реализации запуска процесса в контексте активного пользователя; надо бы избавиться от этих библиотек, не успел еще разобраться, как...

type
  PWTS_PROCESS_INFO = ^WTS_PROCESS_INFO;
  WTS_PROCESS_INFO = packed record
    SessionId: DWORD;
    ProcessId: DWORD;
    pProcessName: PChar;
    pUserSid: PSID;
  end;

type
  procedure ConvertSidToStringSid(SID: PSID; var StringSid: LPSTR); stdcall;
    external advapi32 name 'ConvertSidToStringSidA';

  function WTSEnumerateProcesses(hServer: THandle; Reserved,Version: DWORD;
    var ppProcessInfo: PWTS_PROCESS_INFO;var Count: DWORD): BOOL; stdcall;
      external 'wtsapi32.dll' name 'WTSEnumerateProcessesA';

  procedure WTSFreeMemory(pMemory: Pointer); stdcall;
    external 'wtsapi32.dll' name 'WTSFreeMemory';

...

//получаем SID активного пользователя (того, кто монитором "владеет" на момент запуска)
function GetCurrentUserSID:string;
var
  hToken:THandle;
  ReturnLength:DWORD;
  UserToken:PSIDAndAttributes;
  res:LPSTR;
begin
  if WTSQueryUserToken(WtsGetActiveConsoleSessionID,hToken) then
  begin
    Windows.GetTokenInformation(hToken,TokenUser,UserToken,0,ReturnLength);//здесь и далее "Windows." указываю во избежание конфликтов с переопределенными в Jedi процедурами
    GetMem(UserToken,ReturnLength);
    try
      if Windows.GetTokenInformation(hToken,TokenUser,UserToken,ReturnLength,ReturnLength) then
        begin
          ConvertSidToStringSid(UserToken.Sid,res);
          Result:=res;
        end;
    finally
      FreeMem(UserToken);
    end;
  end;
end;

//запуск приложения от имени активного пользователя
procedure RunApp(FilePath:string);
var
  hToken:THandle;
  si:STARTUPINFOA;
  pi:PROCESS_INFORMATION;
begin
  if WTSQueryUserToken(WtsGetActiveConsoleSessionID,hToken) then
  begin
    ZeroMemory(@si,SizeOf(si));
    si.cb:=SizeOf(si);
    si.lpDesktop:=nil;
    CreateProcessAsUser(hToken,nil,PANSIChar(FilePath),nil,nil,False,0,nil,nil,si,pi);
  end;
end;

//поиск запущенного процесса по имени файла и SID пользователя; я проверяю наличие процесса по имени файла, но по-хорошему надо бы как-то иначе реализовать...
function CheckTask(ExeFileName,CurUserSID:string):Boolean;
var
  Count,i:DWORD;
  pProcessInfo,pCur:PWTS_PROCESS_INFO;
  UserSID:LPSTR;
begin
  Result:=false;
  if not WTSEnumerateProcesses(0,0,1,pProcessInfo,Count)then
    Exit;
  for i:=0 to Count-1 do
    begin
      pCur:=Ptr(DWORD(pProcessInfo)+(i*SizeOf(WTS_PROCESS_INFO)));
      if pCur.pProcessName=ExeFileName then
      begin
        ConvertSidToStringSid(pCur.pUserSid,UserSID);
        if UserSID=CurUserSID then
          Result:=true;
      end;
    end;
  WTSFreeMemory(pProcessInfo);
end;

В основной рабочей процедуре службы в цикле через заданный интервал проверяю наличие процесса и, если нужно, выполняю запуск:
Код

  if not CheckTask('program.exe',GetCurrentUserSID) then
    RunApp('path/program.exe');


PM   Вверх
kami
Дата 21.2.2011, 19:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(Romero @  21.2.2011,  17:24 Найти цитируемый пост)
WtsGetActiveConsoleSessionID

1. Не котируется в WinXP при использовании быстрого переключения пользователей, будет возвращать SessionID первого из залогиненных :(  (хотя, может и ошибаюсь, но у меня так не получалось) Upd. действительно, возвращается активный пользователь...  smile 
2. Попробуйте изначально войти под "гостем". Емнип, там какие-то траблы были с привилегиями как сервиса, так и полученного токена пользователя.
3. Ну и таймер - это...хотя, Ваше право. Тоже решение.


Это сообщение отредактировал(а) kami - 21.2.2011, 20:05
PM MAIL WWW   Вверх
Romero
Дата 22.2.2011, 09:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 17.6.2005

Репутация: 1
Всего: 1



1. В теории должно работать. Я когда этот способ нашел, читал, что для WinXP сработает. Но на практике позже проверю, когда время будет.
2. Что значит "изначально"? Установить службу, а затем переключиться в сеанс Гостя? Вообще, для Гостя мне не очень нужно, чтобы работало, но ради эксперимента попробую.
3. Не совсем таймер - цикл со слипом, пока службе не передается "SERVICE_STOP". Но тут других решений я не вижу. Нужно обеспечить постоянное присутствие одного процесса Программы. Поскольку она все же будет запущена с правами пользователя, на случай убийства пользователем процесса служба будет производить проверку каждые Х секунд.
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: WinAPI и системное программирование"
Snowybartram
MetalFanbems
PoseidonRrader
Riply

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Delphi обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • 99% ответов по WinAPI можно найти в MSDN Library, оставшиеся 1% здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема »


 




[ Время генерации скрипта: 0.1025 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.