Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Активировать окно приложения (запуск из сервиса)


Автор: InvalidProperty 13.11.2009, 16:35
Привет,

возникла проблема:

имеется сервис, который в ответ на запрос клиента, должен запустить процесс от активного текущего пользователя (CreateProcessAsUser). Окно созданного процесса должно стать активным. В XP все работает отлично, т.к. первое созданное окно становится активным. В Viste наблюдается другое поведение: окно создается, но не становится активным. Что можно сделать, чтобы активировать окно?

Вот код со стороны сервиса, который создает процесс:

Код

 STARTUPINFOA        StartupInfo;

 memset(&StartupInfo, 0, sizeof(StartupInfo));
 StartupInfo.cb = sizeof(StartupInfo);
 StartupInfo.lpDesktop = "winsta0\\default";
 StartupInfo.dwFlags = STARTF_RUNFULLSCREEN | STARTF_USESHOWWINDOW;
 StartupInfo.wShowWindow = SW_SHOW;

 HANDLE hUserTokenDup;
 DWORD dSessId = WTSGetActiveConsoleSessionId();
 if(dSessId == 0xFFFFFFFF)
  throw CharException("%s", "no session is currently attached to the console");

 if(!WTSQueryUserToken(dSessId, &hUserTokenDup))
  throw CharException("%s", "can not query user token");

 CreateProcessAsUser(hUserTokenDup, "C:\\test.exe", 0, 0, 0, 0, 
    CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, 0, "C:\\",
    &StartupInfo, &_process_information);
 if(!_process_information.hProcess)
 {
  CloseHandle(hUserTokenDup);
  throw CharException("%s", "cannot create process");
 }

 CloseHandle(hUserTokenDup);


test.exe может быть любым приложением, в рамках которого создается окно

Автор: BEOWOLF 13.11.2009, 17:19
Можно через BringWindowToTop вывести...
Найти окно через FindWindow, если имя класса или заголовок - не известны, то тогда через EnumWindows пролистать главные окна и определить через GetWindowThreadProcessId нужное.

Автор: InvalidProperty 13.11.2009, 17:56
ключевое словосочетание: сервис под вистой. Под вистой findwindow для  сервиса не работает.
Если вызывать BringWindowToTop из test.exe, то окно также не будет активным.
Вот код, который я пробовал для test.exe. Ни одна из функций в потоке не делает активным окно:
Код

#include <windows.h>
#include <stdio.h>
#include "resource.h"

HWND    g_hwnd;

DWORD WINAPI ThreadProc(
  LPVOID lpParameter
)
{
 Sleep(1000);
 //ShowWindow(g_hwnd, SW_SHOWNORMAL);
 //SwitchToThisWindow(g_hwnd, FALSE);
 //SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
 SetForegroundWindow(g_hwnd);
 BringWindowToTop(g_hwnd);
 if(!SetWindowPos(g_hwnd, HWND_TOP, 100, 100, 150, 150, /*SWP_ASYNCWINDOWPOS | */SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW))
 {
  char s[234];
  itoa(GetLastError(), s, 10);
  MessageBox(g_hwnd, s, "asdf", MB_OK);
 }
 Beep(500, 1000);

 return 0;
}


BOOL CALLBACK DialogFun(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
 switch(msg)
 {
  case WM_INITDIALOG:
  {
   g_hwnd = hwnd;
   CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);   
  }
   break;

  case WM_CLOSE:
  {
   EndDialog(hwnd, 0);
  }
   break;
 }

 return FALSE;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
 DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogFun);

 return 0;
}

Автор: InvalidProperty 20.11.2009, 18:58
Товарищи, вопрос решен.

Решение следующее:

Сервис создает процесс как описано в первом посте, после чего только что созданный процесс производит следующие операции:
Код

   DWORD pr = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
   AttachThreadInput(pr, GetCurrentThreadId(), TRUE);
   SetForegroundWindow(g_hwnd);
   SetFocus(g_hwnd);
   AttachThreadInput(pr, GetCurrentThreadId(), FALSE);

, где g_hwnd - Handle главного окна созданного процесса
т.о. главное окно только что созданного процесса становится активным.

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

Автор: InvalidProperty 25.11.2009, 16:47
что странно, если текущим активным окном, является окно командной строки, то переключение активного окна не происходит, а AttachThreadInput завершается с ошибкой 87 :( . Это очень печалит, но меня пока устраивает вариант и без этого, так что, если кто-нибудь найдет решение для окна командной строки, буду очень признателен

Автор: dream2work 9.12.2009, 19:53
StartupInfo.lpDesktop = null;
тода окно создастся на рабоем столе юзера чей токен указан в CreateProcessAsUser

Автор: InvalidProperty 14.12.2009, 10:33
Цитата

By default, CreateProcessAsUser creates the new process on a noninteractive window station with a desktop that is not visible and cannot receive user input. To enable user interaction with the new process, you must specify the name of the default interactive window station and desktop, "winsta0\default", in the lpDesktop member of the STARTUPINFO structure. In addition, before calling CreateProcessAsUser, you must change the discretionary access control list (DACL) of both the default interactive window station and the default desktop. The DACLs for the window station and desktop must grant access to the user or the logon session represented by the hToken 


это MSDN. Откуда у тебя информация о нулевом десктопе?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)