You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行时创建窗口与主窗口任务栏缩略图分组显示异常求助

解决Windows任务栏主窗口与子窗体缩略图分组问题

问题现象

使用VCL开发应用时,设置Application->MainFormOnTaskBar = true后,运行时创建的子窗体缩略图会覆盖主窗口的缩略图,无法实现任务栏悬停时显示主窗口+子窗体的分组缩略图效果。已尝试ITaskbarList3的RegisterTab接口,但问题未解决。

问题原因

  1. 子窗体提前在_tWinMain中创建,此时任务栏接口可能尚未初始化完成,导致RegisterTab未生效
  2. VCL窗体默认的窗口样式可能导致子窗体被识别为独立任务栏项,而非主窗口的标签页
  3. SetTabOrder参数使用错误,未正确指定子窗体在分组中的位置

解决方案

步骤1:修改子窗体创建时机

不在_tWinMain中提前创建Form2,改为在按钮点击时动态创建,确保任务栏接口已初始化。

步骤2:调整子窗体窗口属性

修改子窗体的扩展样式,移除WS_EX_APPWINDOW,避免子窗体生成独立任务栏按钮。

步骤3:修正ITaskbarList3的使用逻辑

确保TaskbarButtonCreated消息正确处理,RegisterTab在子窗体显示后正确调用,同时修正SetTabOrder的参数。

修改后的完整代码

WINAPI部分

#include <vcl.h>
#pragma hdrstop
#include <tchar.h>
//---------------------------------------------------------------------------
USEFORM("Unit1.cpp", Form1);
//---------------------------------------------------------------------------
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
    try
    {
        Application->Initialize();
        Application->MainFormOnTaskBar = true;
        Application->CreateForm(__classid(TForm1), &Form1);
        // 移除提前创建Form2的代码
        Application->Run();
    }
    catch (Exception &exception)
    {
        Application->ShowException(&exception);
    }
    catch (...)
    {
        try
        {
            throw Exception("");
        }
        catch (Exception &exception)
        {
            Application->ShowException(&exception);
        }
    }
    return 0;
}

Form1代码

#include <vcl.h>
#include <windows.h>
#include <shobjidl.h>  // Required for ITaskbarList3
#pragma hdrstop

#include "Unit1.h"
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
UINT TaskBarBtnCreatedId;
ITaskbarList3* pTaskbar=NULL;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    CoInitialize(NULL);
    Application->OnMessage=MainWndProc;
    TaskBarBtnCreatedId=RegisterWindowMessageA("TaskbarButtonCreated");
    ChangeWindowMessageFilterEx(Handle, TaskBarBtnCreatedId, MSGFLT_ALLOW, NULL);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::MainWndProc(tagMSG  &uMsg, bool& Handled){
    if(uMsg.message==TaskBarBtnCreatedId){
        if(pTaskbar==NULL){
            HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void**)&pTaskbar);
            if(SUCCEEDED(hr)){
                pTaskbar->HrInit(); // 必须调用初始化
            }
        }
        Handled = true;
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    // 动态创建子窗体
    TForm2 *Form2 = new TForm2(this);
    Form2->Show();
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
    if(pTaskbar){
        pTaskbar->Release();
        pTaskbar = NULL;
    }
    CoUninitialize();
}

Form2代码

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
    : TForm(Owner)
{
    // 移除独立任务栏项样式,添加工具窗口样式
    SetWindowLongPtr(Handle, GWL_EXSTYLE, GetWindowLongPtr(Handle, GWL_EXSTYLE) & ~WS_EX_APPWINDOW);
    SetWindowLongPtr(Handle, GWL_EXSTYLE, GetWindowLongPtr(Handle, GWL_EXSTYLE) | WS_EX_TOOLWINDOW);
}
//---------------------------------------------------------------------------
void __fastcall TForm2::FormShow(TObject *Sender)
{
    HWND hWnd = Handle;
    HWND hMainWnd = Application->MainForm->Handle;

    if(pTaskbar){
        HRESULT res=pTaskbar->RegisterTab(hWnd, hMainWnd);
        if(res!=S_OK){
            ShowMessage("Taskbar cannot register tab");
        } else {
            // 设置子窗体在主窗口之后的顺序
            pTaskbar->SetTabOrder(hWnd, hMainWnd);
        }
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action)
{
    if (pTaskbar) {
        pTaskbar->UnregisterTab(Handle);
    }
    Action = caFree; // 关闭时释放窗体资源
}

关键说明

  • 动态创建子窗体确保任务栏接口已完成初始化
  • 移除WS_EX_APPWINDOW样式,避免系统将子窗体识别为独立应用窗口
  • SetTabOrder参数改为hMainWnd,确保子窗体作为主窗口的后续标签页显示
  • 增加ITaskbarList3的释放和CoUninitialize调用,避免资源泄漏

内容的提问来源于stack exchange,提问作者Bodo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 19:24:51