Конференция "WinAPI" » Список запущенных приложений (тот что на панели задач).
 
  • Дмитрий С © (06.04.10 09:46) [0]
    Хочу написать програмку для переключения задач для Windows Mobile. Решил поэкспериментировать на обычном windows 7.
    Вобщем возникли вопросы:
    1. Как этот самый список получить. Пробую так, вроде работает, правильно ли:
    Wnd := GetWindow(Application.Handle, gw_HWndFirst);
         while Wnd <> 0 do
         begin { Не показываем: }
           if IsWindowVisible(Wnd)  { Невидимые окна }
           and (GetWindow(Wnd, gw_Owner) = 0) { Дочерние окна }
           and (GetWindowText(Wnd, buff, sizeof(buff)) <> 0) { Окна без заголовков }
           then
           begin
             GetWindowText(Wnd, buff, sizeof(buff));
             ListBox1.Items.AddObject(StrPas(buff), TObject(Wnd));
           end;
           Wnd := GetWindow(Wnd, gw_hWndNext);
         end;


    Пример взял из сети.
    Смущает такой факт: Откуда брать Application.Handle, если писать на winapi?
    Может есть более правильный пример?
    ToolHelp не хочу использовать.
    2. Как правильно получить заголовок окна.
    Теоретически ведь между GetWindowTextLength и GetWindowText заголовок окна может измениться, и выделенного буфера не хватит.
    3. Как правильно получить иконку приложения. Делаю так:
       Ico := SendMessage(HWnd(Items.Objects[Index]), WM_GETICON, ICON_SMALL2, 0);
       if Ico <= 0 then
         Ico := GetClassLong(HWnd(Items.Objects[Index]), GCL_HICONSM);
       if Ico > 0 then
         DrawIconEx(Canvas.Handle, Rect.Left + 1, Rect.Top + 1, Ico, 16, 16, 0, 0, DI_NORMAL);


    Нужно ли как-то освобождать Ico?

    4. Как правильно активировать то или иное приложение?
    Делаю так:
         Wnd := HWND(Items.Objects[ItemIndex]);
         if IsIconic(Wnd) then
           SendMessage(Wnd, WM_SYSCOMMAND, SC_RESTORE, 0);
         SetForegroundWindow(Wnd);



    5. Как правильно закрыть приложение.
    Тут пока я никак не делаю, но думаю посылать WM_CLOSE или WM_QUIT. Как правильно, не знаю.

    Подскажите, где что не так, где так и что почитать можно?
  • Leonid Troyanovsky © (06.04.10 11:34) [1]

    > Дмитрий С ©   (06.04.10 09:46)  

    > 1. Как этот самый список получить. Пробую так, вроде работает,
    >  правильно ли:

    Правильно - EnumWindows.
    Для определения наличия кнопки на таскбаре можно использовать
    нечто подобное http://rsdn.ru/forum/delphi/525933.aspx

    > Откуда брать Application.Handle, если писать на winapi?

    Брать то свое окно, которое имеет кнопку на таскбаре.

    > Теоретически ведь между GetWindowTextLength и GetWindowText
    > заголовок окна может измениться, и выделенного буфера не
    > хватит.

    GetWindowText возвращает количество считанного.
    Можно взять буфер с заведомым запасом.

    > Нужно ли как-то освобождать Ico?

    IMHO, не нужно.

    >      Wnd := HWND(Items.Objects[ItemIndex]);

    Хендлы окон не стоит хранить в списке, бо, необходимо поддерживать
    его актуальность. Если это необходимо, нужно ставить хуки на потоки, владеющие этими окнами, для получения уведомлений о их разрушении.

    > 5. Как правильно закрыть приложение.
    > Тут пока я никак не делаю, но думаю посылать WM_CLOSE или
    > WM_QUIT. Как правильно, не знаю.

    Например, WM_QUIT каждому GUI потоку приложения.
    Но, это тоже, не совсем корректно, бо с несохраненными данными
    можно попрощаться.
    Но, в любом случае, придется держать в запасе TeminateProcess.

    --
    Regards, LVT.
  • DVM © (06.04.10 15:53) [2]

    > Как этот самый список получить.

    EnumWindows() потом WH_SHELL ловушка или таймер и опять тот же EnumWindows(). Explorer похоже использует и таймер и WH_SHELL

    Я вот так проверял когда то:


    function IsAppWindow(Wnd: HWND): BOOL; stdcall;
    var
     Style, ExtStyle: LongInt;
     hOwner, hParent: HWND;
    begin
     Result := true;
     if not IsWindow(Wnd) then
       begin
         Result := false;
         exit;
       end;
     Style := GetWindowLong(Wnd, GWL_STYLE);
     ExtStyle := GetWindowLong(Wnd , GWL_EXSTYLE);
     hOwner := GetWindow(Wnd, GW_OWNER);
     hParent := GetParent(Wnd);
     if (Style and WS_CHILD) <> 0 then result := false;
     if (Style and WS_VISIBLE) = 0 then Result := false;
     if not IsWindowVisible(Wnd) then Result := false;
     if (ExtStyle and  WS_EX_TOOLWINDOW) <> 0 then Result := false;
     if (ExtStyle and  WS_EX_MDICHILD) <> 0 then Result := false;

     if (hOwner <> 0) and ((ExtStyle and WS_EX_APPWINDOW) = 0) then result := false;
     if (hOwner <> 0) and Result then Result := not IsAppWindow(hOwner);

     if hParent <> 0 then Result := false;
     if GetWindowLong(Wnd , GWL_USERDATA) = MagicDWord then Result := false;
    end; // End of function IsAppWindow;

  • DVM © (06.04.10 15:55) [3]

    > 2. Как правильно получить заголовок окна.
    > Теоретически ведь между GetWindowTextLength и GetWindowText
    > заголовок окна может измениться, и выделенного буфера не
    > хватит.

    WH_SHELL  кстати уведомляет об изменение заголовка или иконки


    function GetTextFromWindow(hWnd: HWND): string;
    var
     TextLength: integer;
     Text: PChar;
    begin
     TextLength := GetWindowTextLength(hWnd) + 1;
     GetMem(Text, TextLength * SizeOf(Char));
     GetWindowText(hWnd, Text, TextLength);
     Result := Text;
     FreeMem(Text, TextLength * SizeOf(Char));
    end; // End of function GetTextFromWindow




    > 3. Как правильно получить иконку приложения.


    function _GetFileAssociatedIcon(FileName: string; bSmall: boolean): HICON;
    var
     FileInfo: SHFILEINFO;
     BIG_OR_SMALL_ICON: integer;
    begin
     if bSmall then
       BIG_OR_SMALL_ICON := SHGFI_SMALLICON
     else
       BIG_OR_SMALL_ICON := SHGFI_LARGEICON;
     SHGetFileInfo(PChar(FileName),
                   FILE_ATTRIBUTE_NORMAL,
                   FileInfo,
                   SizeOf(FileInfo),
                   SHGFI_ICON or BIG_OR_SMALL_ICON or SHGFI_SYSICONINDEX);
     Result := FileInfo.hIcon;
    end;

    //------------------------------------------------------------------------------

    function _GetProcessFileNameByWindowHandle(Wnd: HWND): string;
    var
     hProcess: THandle;
     PID: Cardinal;
     FileName: array [1..MAX_PATH] of char;
     PE: TProcessEntry32;
     Snap: Cardinal;
     OsVerInfo: TOSVersionInfo;
    begin
     Result := '';
     GetWindowThreadProcessId(Wnd, @PID);
     hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, PID);
     OsVerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
     if GetVersionEx(osVerInfo) then
       begin
         if OsVerInfo.dwPlatformId = VER_PLATFORM_WIN32_NT then
           begin
             ZeroMemory(@Filename[1], SizeOf(Filename));
             GetModuleFileNameEx(hProcess, 0, @Filename[1], SizeOf(Filename));
             Result := FileName;
           end
         else
           begin
             Snap := CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, 0);
             if Snap <> -1 then
               begin
                 PE.dwSize:=SizeOf(PE);
                 if Process32First(Snap, PE) then
                   repeat
                     if PE.th32ProcessID = PID then Result := PE.szExeFile;
                   until not Process32Next(Snap, PE);
               end;
           end;
       end;
     CloseHandle(hProcess);
    end;

    //------------------------------------------------------------------------------

    function GetIconFromWindow(hWnd: HWND): HICON; stdcall;
    const
     ICON_SMALL2 = 2;
    begin
     Result := 0;
     // Get Small Icon From Window ...
     SendMessageTimeout(hWnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, Cardinal(Result));
     if Result = 0 then SendMessageTimeout(hWnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, Cardinal(Result));
     if Result = 0 then Result := GetClassLong(hWnd, GCL_HICONSM);
     if Result = 0 then SendMessageTimeout(hWnd, WM_GETICON, ICON_SMALL, 1,
                            SMTO_ABORTIFHUNG, 1000, Cardinal(Result));
     if Result = 0 then SendMessageTimeout(hWnd, WM_GETICON, ICON_SMALL2, 1,
                            SMTO_ABORTIFHUNG, 1000, Cardinal(Result));
     if Result = 0 then SendMessageTimeout(hWnd, WM_QUERYDRAGICON, ICON_SMALL,
                            0, SMTO_ABORTIFHUNG, 1000, Cardinal(Result));
     if Result = 0 then SendMessageTimeout(hWnd, WM_QUERYDRAGICON, ICON_SMALL2,
                           0, SMTO_ABORTIFHUNG, 1000, Cardinal(Result));
     // Get Big Icon From Window ...
     if Result = 0 then SendMessageTimeout(hWnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, Cardinal(Result));
     if Result = 0 then Result := GetClassLong(hWnd, GCL_HICON);
     if Result = 0 then SendMessageTimeout(hWnd, WM_GETICON, ICON_BIG, 1,
                          SMTO_ABORTIFHUNG, 1000, Cardinal(Result));
     if Result = 0 then SendMessageTimeout(hWnd, WM_QUERYDRAGICON, ICON_BIG,
                          0, SMTO_ABORTIFHUNG, 1000, Cardinal(Result));
     // Get Icon From File ...
     if Result = 0 then Result := _GetFileAssociatedIcon(_GetProcessFileNameByWindowHandle(hWnd), true);
     if Result = 0 then Result := _GetFileAssociatedIcon(_GetProcessFileNameByWindowHandle(hWnd), false);
     // Load Default Icon ...  }
     if Result = 0 then Result := LoadIcon(0, IDI_APPLICATION);
    end; // End of function GetIconFromWindow


  • DVM © (06.04.10 15:57) [4]

    > 4. Как правильно активировать то или иное приложение?

    Проводник пользуется недокументированной функцией SwitchToThesWindow, так что либо ей либо вот аналог


    function ForceForegroundWindow(hWnd: HWND): BOOL; stdcall;
    const
     SPI_GETFOREGROUNDLOCKTIMEOUT = $2000;
     SPI_SETFOREGROUNDLOCKTIMEOUT = $2001;
    var
     OsVerInfo: TOSVersionInfo;
     Win32MajorVersion: Integer;
     Win32MinorVersion: Integer;
     Win32Platform: Integer;
     ForegroundThreadID: DWORD;
     ThisThreadID: DWORD;
     Timeout: DWORD;
    begin
     OsVerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
     GetVersionEx(osVerInfo);
     Win32MajorVersion := OsVerInfo.dwMajorVersion;
     Win32MinorVersion := OsVerInfo.dwMinorVersion;
     Win32Platform := OsVerInfo.dwPlatformId;
     if IsIconic(hWnd) then ShowWindow(hWnd, SW_RESTORE);
     if GetForegroundWindow = hWnd then Result := True
     else
     begin
       if ((Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion > 4)) or
         ((Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and ((Win32MajorVersion > 4)
           or ((Win32MajorVersion = 4) and (Win32MinorVersion > 0)))) then
       begin
         Result := False;
         ForegroundThreadID := GetWindowThreadProcessID(GetForegroundWindow, nil);
         ThisThreadID := GetWindowThreadPRocessId(hWnd, nil);
         if AttachThreadInput(ThisThreadID, ForegroundThreadID, True) then
         begin
           BringWindowToTop(hWnd);
           SetForegroundWindow(hWnd);
           AttachThreadInput(ThisThreadID, ForegroundThreadID, False);
           Result := (GetForegroundWindow = hWnd);
         end;
         if not Result then
         begin
           SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @Timeout, 0);
           SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil,
             SPIF_SENDCHANGE);
           BringWindowToTop(hWnd);
           SetForegroundWindow(hWnd);
           SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(Timeout),
                                                                  SPIF_SENDCHANGE);
         end;
       end
       else
       begin
         BringWindowToTop(hWnd);
         SetForegroundWindow(hWnd);
       end;
       Result := (GetForegroundWindow = hWnd);
     end;
    end; // End of function ForceForegroundWindow

  • Anatoly Podgoretsky © (06.04.10 16:37) [5]

    > DVM ©   (06.04.10 15:57) [4]

    Только, только начали избавляться от попрыгунчиков, так ты тут со своим кодом вылез.
  • DVM © (06.04.10 16:40) [6]

    > Anatoly Podgoretsky ©   (06.04.10 16:37) [5]

    Ну тут как ни крути это надо. Если надо переключать окна как панель задач.
  • Anatoly Podgoretsky © (06.04.10 16:51) [7]
    > DVM  (06.04.2010 16:40:06)  [6]

    Мне за последствия страшно.
  • Дмитрий С © (07.04.10 03:00) [8]

    > DVM ©   (06.04.10 15:57) [4]

    Это сильно, конечно.
    AttachThreadInput нужен для SetForegroundWindow?


    > DVM ©   (06.04.10 15:55) [3]

    Спасибо за код. Вопрос только:
    Разве панель задач загружает иконку из ресурса exe файла, если из других мест достать не удалось?


    > Leonid Troyanovsky ©   (06.04.10 11:34) [1]

    Спасибо за ссылку, то что нужно. Сделал через EnumWindows, в таком случае своего окна не требуется вовсе.

    Так, все-таки как штатно закрыть приложение, чтобы в случае чего, оно могло отобразить диалог (запрос на сохранение), послать WM_CLOSE или WM_SYSCOMMAND, SC_CLOSE? И как не штатно (тут думаю TerminateProcess)?
  • Leonid Troyanovsky © (07.04.10 10:34) [9]

    > Дмитрий С ©   (07.04.10 03:00) [8]

    > AttachThreadInput нужен для SetForegroundWindow?

    Не нужен. Если SetForegroundWindow вызывается
    при выполнении условий, описанных в msdn,
    то фокус будет передан. Иначе, будет FlashWindow.

    > Так, все-таки как штатно закрыть приложение, чтобы в случае
    > чего, оно могло отобразить диалог (запрос на сохранение),

    WM_SYSCOMMAND SC_CLOSE окну, чья  кнопка на таскбаре, IMHO.
    Только, наверное, SendMessageTimeout. У оного есть и флаг SMTO_ABORTIFHUNG. .

    Ну, и TerminateProcess, на крайний случай.

    --
    Regards, LVT.
  • DVM © (07.04.10 12:13) [10]

    > Дмитрий С ©   (07.04.10 03:00) [8]


    > Разве панель задач загружает иконку из ресурса exe файла,
    >  если из других мест достать не удалось?

    По моим наблюдениям, которые я проводил лет 7 назад - да.


    > Дмитрий С ©   (07.04.10 03:00) [8]


    > AttachThreadInput нужен для SetForegroundWindow?

    http://codeguru.ru/windows/windows/common/%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D1%89%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BE%D0%BA%D0%BD%D0%B0-%D0%BD%D0%B0-%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%BD%D0%B8%D0%B9-%D0%BF%D0%BB%D0%B0%D0%BD.html
  • Anatoly Podgoretsky © (07.04.10 14:42) [11]
    > DVM  (07.04.2010 12:13:10)  [10]

    И даже наоборот, сначали из ресурса, а потом уж как нибудь.
    Поэтому в вход в папку с тысячами файлов так медленен, извлекаются иконки и уж как следствие проверка антивирусом.
  • Дмитрий С © (07.04.10 14:45) [12]

    > Anatoly Podgoretsky ©   (07.04.10 14:42) [11]

    Причем тут это-то?


    > По моим наблюдениям, которые я проводил лет 7 назад - да.

    Кстати в Win7 при группировке кнопок панели задач, таскбар именно из ресурса иконку и берет.


    > Leonid Troyanovsky ©   (07.04.10 10:34) [9]


    Чуть позже продолжу разбираться и тестировать на КПК, подниму тему, если будут вопросы, пока вопросов нет, большое спасибо.
  • Leonid Troyanovsky © (07.04.10 15:44) [13]

    > Дмитрий С ©   (07.04.10 14:45) [12]

    > Чуть позже продолжу разбираться и тестировать на КПК, подниму
    > тему, если будут вопросы,

    А далее я - пас, там, наверное, какой-нить WinCE.

    --
    Regards, LVT.
 
Конференция "WinAPI" » Список запущенных приложений (тот что на панели задач).
Есть новые Нет новых   [134432   +18][b:0][p:0.006]