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


Автор: artsb 10.5.2008, 18:32
Всем привет.

У меня в программе два окна. При запуске она сворачивается в трей. Мне не нужно, чтобы на панели задач отображалась кнопка приложения, даже если открыто одно из окон. Как вообще отключить эту кнопку? Пока сделал так: в обработчики OnShow форм написал:
Код

ShowWindow(Application->Handle,SW_HIDE);

Но может есть вариант получше?

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

PHide->Checked=!PHide->Checked;
if(PHide->Checked) ShowWindow(window,SW_HIDE);
else ShowWindow(window,SW_SHOW);

здесь window - это HWND окна.
Но заметил, что не всегда скрывается кнопка приложения с панели задач. Как это исправить?

Также, при отображении окна, оно не становится активным, а остаётся под другими окнами. Что можно сделать, чтобы при отображении окно становилось активным и поверх других окон. Попробовал добавить строку:
Код

SetActiveWindow(window);

но не помогло.

Спасибо.

Автор: THandle 10.5.2008, 19:13
1.
  
Код

 SetWindowLong(Application->Handle, GWL_EXSTYLE,
    GetWindowLong(Application->Handle, GWL_EXSTYLE) || WS_EX_TOOLWINDOW);


?

2. 

Код

SetForegroundWindow(Form1->Handle);



?

Автор: mrbrooks 10.5.2008, 20:39
Имхо http://forum.vingrad.ru/forum/topic-205587/anchor-entry1474441/0.html посмотри. В данной теме мы с комрадом разбирали тему как раз работу с треем и скрытием формы.
 Грубо говоря у формы есть метод Hide() Возможно тебе его и хватит smile 

Автор: artsb 10.5.2008, 22:22
THandle, спасибо.
1. Это помогло только при открытии дочернего окна. Если открыть главную форму кнопка появляется.
2. Работает. Спасибо.


mrbrooks, спасибо. Посмотрю.

Добавлено через 3 минуты и 41 секунду
Сделал так:
Код

SetWindowLong(Application->Handle, GWL_EXSTYLE, WS_EX_TOOLWINDOW);


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

Автор: THandle 10.5.2008, 22:29
artsb, поставь на OnCreate.

Добавлено через 1 минуту и 38 секунд
вот сам пример из FAQ, только на Delphi:

http://forum.vingrad.ru/faq/topic-183849.html

Автор: artsb 10.5.2008, 22:31
Так я там и ставил. Но уже этот вопрос решён. Спасибо.
Остаётся только кнопка чужого приложения.

Автор: artsb 10.5.2008, 23:11
Попробовал так:
Код

ShowWindow(FindWindowEx(FindWindow("Shell_TrayWnd",NULL),NULL,"Button",Edit2->Text.c_str()),SW_HIDE);
ShowWindow(FindWindowEx(FindWindow("Shell_TrayWnd",NULL),NULL,"Button",Edit2->Text.c_str()),SW_SHOW);

Не работает.

Автор: 586 10.5.2008, 23:21
Интерфейс ITaskbarList должен помочь: http://msdn.microsoft.com/en-us/library/bb774652(VS.85).aspx

Автор: artsb 10.5.2008, 23:32
586, спасибо. Но я не понял как с ним работать. Можно примерчик. Спасибо.

Автор: 586 10.5.2008, 23:47
http://www.rsdn.ru/forum/message/21650.flat.aspx

Автор: artsb 11.5.2008, 14:57
586, спасибо. Почитал. Интересно...
Там VladD2 пишет:
Код

HWND hWnd = ::FindWindow(_T("Notepad"), NULL);
if(!hWnd)
    return;
// Если окно уже имеет парента...
if(::GetWindowLong(hWnd, GWL_HWNDPARENT))
    // урать его, тем самым показав в таскбаре...
    ::SetWindowLong(hWnd, GWL_HWNDPARENT, NULL);
else
    // иначе ставим его парантом к DesktopWindow, тем самым убирая из таскбара.
    ::SetWindowLong(hWnd, GWL_HWNDPARENT, (LONG)::GetDesktopWindow());

А как получить хэндл кнопки? Так пойдёт:
Код

HWND hWnd = FindWindowEx(FindWindow("Shell_TrayWnd",NULL),NULL,"Button",Edit2->Text.c_str());
if(!hWnd)
    return;
// Если окно уже имеет парента...
if(GetWindowLong(hWnd, GWL_HWNDPARENT))
    // урать его, тем самым показав в таскбаре...
    SetWindowLong(hWnd, GWL_HWNDPARENT, NULL);
else
    // иначе ставим его парантом к DesktopWindow, тем самым убирая из таскбара.
    SetWindowLong(hWnd, GWL_HWNDPARENT, (LONG)GetDesktopWindow());

Автор: 586 11.5.2008, 15:12
Цитата(artsb @  11.5.2008,  15:57 Найти цитируемый пост)
спасибо. Почитал. Интересно...

Там пример внизу есть, тот что ты просил. С интерфейсом ITaskbarList.
Код
#include <ShlObj.h>

   CoInitialize(NULL);
   ITaskbarList *pTaskBar = 0;
   HRESULT hr = CoCreateInstance(CLSID_TaskbarList, 0,
                                 CLSCTX_ALL, IID_ITaskbarList, (void**)&pTaskBar);
   if(SUCCEEDED(hr))
   {
        pTaskBar->DeleteTab(hWnd);
        pTaskBar->Release();
   }     
   CoUninitialize();

Автор: artsb 11.5.2008, 15:17
Не совсем понял, где здесь указывать кнопку, которую я хочу скрыть? :(

Добавлено через 3 минуты и 28 секунд
Код

pTaskBar->DeleteTab(/* ---> */hWnd/* <--- */);  // оно?

Автор: artsb 11.5.2008, 15:41
Попробовал так:
Код

void __fastcall TfMain::PHideClick(TObject *Sender)
{
PHide->Checked=!PHide->Checked;
if(PHide->Checked)
{
ShowWindow(window,SW_HIDE);
if(button)
{
   CoInitialize(NULL);
   ITaskbarList *pTaskBar = 0;
   HRESULT hr = CoCreateInstance(CLSID_TaskbarList, 0,
                                 CLSCTX_ALL, IID_ITaskbarList, (void**)&pTaskBar);
   if(SUCCEEDED(hr))
   {
        pTaskBar->DeleteTab(button);
        pTaskBar->Release();
   }
   CoUninitialize();
}
}
else
{
ShowWindow(window,SW_SHOW);
SetForegroundWindow(window);
if(button)
{
   CoInitialize(NULL);
   ITaskbarList *pTaskBar = 0;
   HRESULT hr = CoCreateInstance(CLSID_TaskbarList, 0,
                                 CLSCTX_ALL, IID_ITaskbarList, (void**)&pTaskBar);
   if(SUCCEEDED(hr))
   {
        pTaskBar->AddTab(button);
        pTaskBar->Release();
   }
   CoUninitialize();
}
}
}

кнопку ищу так:
Код

button=FindWindowEx(FindWindow("Shell_TrayWnd",NULL),NULL,"Button",Edit2->Text.c_str());

При компиляции пишет:
  [C++ Error] shobjidl.h(2193): E2238 Multiple declaration for 'FOLDERSETTINGS'
  [C++ Error] shobjidl.h(8095): E2238 Multiple declaration for 'DESKBANDINFO'
  [C++ Error] ShlObj.h(1422): E2238 Multiple declaration for 'FVSHOWINFO'
  [C++ Error] ShlObj.h(3457): E2238 Multiple declaration for 'SHELLFLAGSTATE'
Как с этим бороться?

Автор: 586 11.5.2008, 15:49
В начале кода напиши:
Код
#define NO_WIN32_LEAN_AND_MEAN

hWnd - это хендл окна, а не кнопки smile

Автор: artsb 11.5.2008, 16:55
Цитата(586 @  11.5.2008,  15:49 Найти цитируемый пост)
В начале кода напиши:

Не помогло :(

Кстати, а зачем при подключении некоторых библиотек нужно вставлять такие конструкции?


Цитата(586 @  11.5.2008,  15:49 Найти цитируемый пост)
hWnd - это хендл окна, а не кнопки

Значит, я указываю окно, а скрывается кнопка окна? Так?
А что делать если на экране отображается не главное окно, а дочернее (похоже в моём случае именно так, т.к. некоторые другие окна скрываются вместе с кнопками).

Автор: 586 11.5.2008, 17:27
Цитата(artsb @  11.5.2008,  17:55 Найти цитируемый пост)
Не помогло :(

Значит не там написал.
Код
#define NO_WIN32_LEAN_AND_MEAN   // в самом начале
#include <vcl.h>
#include <shlobj.h>

А ещё лучше по всему проекту определи эту дерективу: Project -> Options-> Directories/Conditionals -> Conditionals -> "_DEBUG;NO_WIN32_LEAN_AND_MEAN"
Цитата(artsb @  11.5.2008,  17:55 Найти цитируемый пост)
зачем при подключении некоторых библиотек нужно вставлять такие конструкции?

Конфликт с VCL. На Visual С++ всё без этого идёт.
Цитата(artsb @  11.5.2008,  17:55 Найти цитируемый пост)
А что делать если на экране отображается не главное окно, а дочернее (похоже в моём случае именно так, т.к. некоторые другие окна скрываются вместе с кнопками).

Передавай то окно, которое привязано к панели задач (Application->Handle). (???)

Автор: artsb 11.5.2008, 19:09
Цитата(586 @  11.5.2008,  17:27 Найти цитируемый пост)
Значит не там написал.

Действительно. Проверил. Нужно ставить до #include <vcl.h>
Спасибо.
Я проверяю работу своей программы на Extract Icon Tool. Окно этой программы имеет заголовок "Extract Icon Tool v1.80", а на кнопке написано "Extract Icon Tool". Применил приведённый вами код. Окно программы скрылось, а кнопка нет. А вот после того как отобразил окно появилась ещё одна кнопка с таким же названием как и заголовок окна!
Что ещё можно сделать, чтобы скрыть кнопку? Нельзя ли сделать поиск кнопки по названию и применить к ней ShowWindow? У меня не получается найти хэндл кнопки.

Цитата(586 @  11.5.2008,  17:27 Найти цитируемый пост)
Передавай то окно, которое привязано к панели задач (Application->Handle)

Не понял. Я говорю про чужие окна. Как я узнаю их Application->Handle?

Автор: artsb 11.5.2008, 20:19
Попробовал так:
Код

button=FindWindowEx(FindWindow("Shell_TrayWnd",NULL),NULL,"ReBarWindow32",NULL);
if(button)
{
        ShowMessage("ReBarWindow32");
        button=FindWindowEx(button,NULL,"ToolbarWindow32",NULL);
        if(button)
        {
                ShowMessage("ToolbarWindow32");
                button=FindWindowEx(button,NULL,NULL,Edit2->Text.c_str());
                if(button)  ShowMessage("Button");
        }
}

Но сообщения "Button" не появляется. Как получить доступ к кнопке?

Добавлено через 14 минут и 46 секунд
Сделал следующее:
Скачал программу InqSoft Window Scaner. После её запуска, в качестве окна указал "ToolbarWindow32". Нажал в окне программы "Инструменты"->"Сканер toolbar'ов".Открылось дополнительное окно. Там нажал "Просканировать Toolbar". Программа показала список всех кнопок! Более того, можно управлять состоянием этих кнопок! Как она это делает?
user posted image
Если нажать на кнопку со стрелачками напротив выделенной надписи, кнопка прячется и отображается.

Автор: 586 11.5.2008, 21:59
deleted

Автор: artsb 12.5.2008, 06:45
не понял.

Автор: 586 12.5.2008, 21:34
Почитай в MSDN про изменение состояний toolbar-кнопок (TB_GETBUTTONINFO / TB_SETBUTTONINFO). Т.к. будет передаваться структура, это придётся делать к контексте процесса explorer.exe (через dll или VirtualAllocEx). 

Автор: artsb 12.5.2008, 23:11
Ого, что-то сложно ты написал. Для меня это тяжело. Можешь как-нибудь попроще объяснить на каком-нибудь примере. Тем более, сначала надо получить доступ к кнопке. Как это сделать?

Автор: 586 12.5.2008, 23:51
Дело в том, что при работе с common-контролами (ListView, TreeView, TabCtrl, Toolbar и др.) используется структура. Т.к. адрес структуры недействителен в другом процессе, структура должна принадлежать к адресному пространству процесса. По идее, это должно применяться ко всем контролам (Button, Static и др.), но MS это оставил для совместимости с Win16, а вот common-контролы изменять не стал.
Код
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    HWND hWnd = FindWindow("Shell_TrayWnd", NULL);
    hWnd = FindWindowEx(hWnd, NULL, "ReBarWindow32", NULL);
    hWnd = FindWindowEx(hWnd, NULL, "MSTaskSwWClass", NULL);
    hWnd = FindWindowEx(hWnd, NULL, "ToolbarWindow32", NULL);
    if(!hWnd) {
        Caption = "Window not found";
        return;
    }

    DWORD pid;
    GetWindowThreadProcessId(hWnd, &pid);
    HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, pid);
    if(!hProcess) {
        Caption = GetLastError();
        return;
    }

    LPVOID pMem = VirtualAllocEx(hProcess, NULL, 1024 /*с запасом*/, MEM_COMMIT, PAGE_READWRITE);

    if(!pMem) {
        Caption = "Can't alocate memory";
        return;
    }

    TBBUTTONINFO tbi;
    tbi.cbSize = sizeof(TBBUTTONINFO);
    tbi.dwMask = TBIF_TEXT | TBIF_BYINDEX;
    tbi.pszText = (char*)((DWORD)pMem+sizeof(TBBUTTONINFO));  // строка будет записана после структуры
    tbi.cchText = 260;

    char buff[260];
    WriteProcessMemory(hProcess, pMem, &tbi, sizeof(tbi), NULL);
    SendMessage(hWnd, TB_GETBUTTONINFO, /*index*/1, (LPARAM)pMem);
    ReadProcessMemory(hProcess, (void*)((DWORD)pMem+sizeof(TBBUTTONINFO)), buff, 260, NULL);
    Label1->Caption = buff;

    VirtualFreeEx(hProcess, pMem, 1024, MEM_DECOMMIT);
    CloseHandle(hProcess);
}

Автор: artsb 13.5.2008, 16:21
586, спасибо. А где здесь скрыть/показать кнопку?

Автор: 586 14.5.2008, 19:57
Всё намного проще:
Код
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    HWND hWnd = FindWindow("Shell_TrayWnd", NULL);
    hWnd = FindWindowEx(hWnd, NULL, "ReBarWindow32", NULL);
    hWnd = FindWindowEx(hWnd, NULL, "MSTaskSwWClass", NULL);
    hWnd = FindWindowEx(hWnd, NULL, "ToolbarWindow32", NULL);
    if(!hWnd) {
        Caption = "Window not found";
        return;
    }

    long state = SendMessage(hWnd, TB_GETSTATE, /*index*/1, 0);
    //state |= TBSTATE_HIDDEN;    // скрыть
    //state &= ~TBSTATE_HIDDEN;   // показать
    state ^= TBSTATE_HIDDEN;

    SendMessage(hWnd, TB_SETSTATE, /*index*/1, state);
}


Добавлено через 10 минут и 9 секунд
А вот для TB_GETBUTTONTEXT придётся выделять память.

Автор: artsb 15.5.2008, 21:46
586, спасибо. Приведённый вами код работает. Только вот не устраивает то, что нужно обращаться по индексу кнопки (есть ведь скрытые кнопки, которые трогать не нужно, а они отображаются smile).
Попробовал искать по надписи:
Код

    char *st=new char[256];
    SendMessage(hWnd,TB_GETBUTTONTEXT,1,(LPARAM)(LPSTR)st);
    ShowMessage(st);
    delete st;

Но в сообщении три закорючки и всё. Что я не так делаю? Вроде всё по справке:
Цитата

The TB_GETBUTTONTEXT message retrieves the text of a button in a toolbar. 

TB_GETBUTTONTEXT  
wParam = (WPARAM) idButton; 
lParam = (LPARAM) (LPSTR) lpszText; 
 

Parameters

idButton

Command identifier of the button whose text is to be retrieved. 

lpszText

Pointer to a buffer that receives the button text.

Автор: 586 15.5.2008, 22:36
Цитата(586 @  14.5.2008,  20:57 Найти цитируемый пост)
А вот для TB_GETBUTTONTEXT придётся выделять память. 

Цитата(artsb @  15.5.2008,  22:46 Найти цитируемый пост)
char *st=new char[256];

В процессе нужно выделять память.
Код
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    HWND hWnd = FindWindow("Shell_TrayWnd", NULL);
    hWnd = FindWindowEx(hWnd, NULL, "ReBarWindow32", NULL);
    hWnd = FindWindowEx(hWnd, NULL, "MSTaskSwWClass", NULL);
    hWnd = FindWindowEx(hWnd, NULL, "ToolbarWindow32", NULL);
    if(!hWnd) {
        Caption = "Window not found";
        return;
    }
    DWORD pid;
    GetWindowThreadProcessId(hWnd, &pid);
    HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, pid);
    if(!hProcess) {
        Caption = GetLastError();
        return;
    }

    char buf[260];

    LPVOID pMem = VirtualAllocEx(hProcess, NULL, 260, MEM_COMMIT, PAGE_READWRITE);

    SendMessage(hWnd,TB_GETBUTTONTEXT,2,(LPARAM)pMem);
    ReadProcessMemory(hProcess, pMem,buf, 260, NULL);
    buf[259] = 0;  // buffer overflow protect
    Caption = buf;

    VirtualFreeEx(hProcess, pMem, 260, MEM_DECOMMIT);
    CloseHandle(hProcess);
}

Автор: artsb 16.5.2008, 21:47
Работает! 
586, респект вам. И ещё раз спасибо.

Где вы берёте эту информацию? Как её ищете? Если не секрет.
ЗЫ извиняюсь за офтоп.

Автор: 586 16.5.2008, 22:01
Цитата(artsb @  16.5.2008,  22:47 Найти цитируемый пост)
Где вы берёте эту информацию? Как её ищете? Если не секрет.

http://www.google.ru/  smile  smile 

Автор: artsb 17.5.2008, 15:59
Я так и знал!  smile  smile  smile 

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