Showing an additional modeless window with C++ and WinApi - c++

I have a class called GUIMain which registers, creates, and shows a main window for my program. On it is a button which, when the user clicks it, displays an additional window.
If I was writing this in C#, I would have two options:
AdditionalForm myForm = new AdditionalForm();
myForm.ShowDialog(this); // blocking. Returns when myForm is closed;
someOtherFunction();
or
AdditionalForm myForm = new AdditionalForm();
myForm.Show(this); // non-blocking.
someOtherFunction(); // runs while myForm is still visible
or, heck, even this would work:
AdditionalForm myForm = new AdditionalForm();
new Thread(new ThreadStart(delegate()
{
myForm.ShowDialog(this); // blocks in a separate thread
})).Start();
someOtherFunction(); // runs while myForm is still visible
But I'm writing this in C++, not C#.
I have an additional class called PreviewWindow which has the public member functions Register(), Create(), and Show(). The last function contains a message loop which basically makes it a blocking call - analogous to C#'s ShowDialog().
How can I either re-write PreviewWindow::Show() so that it doesn't have a blocking loop:
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Or alternatively, how can I call it on a separate thread?
I've currently got:
previewWindow = new PreviewWindow(hInstance, hWnd);
previewWindow->Register();
previewWindow->Create();
previewWindow->Show(); // blocks :(
previewWindow->DisplayImage(); // never runs.
I have tried CreateThread but it's not liking that the 3rd argument is a member function. I've tried making it a static member function but it doesn't seem to like that either. It's saying DWORD (__stdcall *)() isn't compatible with LPTHREAD_START_ROUTINE.

You should have only one event loop, it will handle all windows except modal ones (which run their own message loop to block the UI). Then your PreviewWindow::Show is just ShowWindow(handle, SW_SHOW);. Multi-threading should generally be saved for when it's absolutely necessary.

Related

wxWidgets wxThreadHelper Example Question

I'm relatively new to wxWidgets and trying to get a grasp on how to properly implement threading and events and all that good stuff. I was able to get a simple frame running in my projects directory just fine, but as I ran into issues when trying to add in threading.
I ran the Thread demo given in the "samples" of the repo without issue but as I understand it, the more recent preferred method is to use wxThreadHelper because you don't need to pass around frame pointers.
I'm essentially starting off in the wxThreadHelper example that's given here. All I really did was separate things into header and src.
Header:
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#if !wxUSE_THREADS
#error "This sample requires thread support!"
#endif // wxUSE_THREADS
wxDECLARE_EVENT(EVT_COMMS_UPDATE, wxThreadEvent);
enum {LAYOUT_TEST_PROPORTIONS = wxID_HIGHEST+1,
LAYOUT_TEST_SIZER,
LAYOUT_TEST_NB_SIZER
};
class wxMainFrame : public wxFrame, public wxThreadHelper, private wxLog {
private:
public:
wxMainFrame();
~wxMainFrame(){
// it's better to do any thread cleanup in the OnClose()
// event handler, rather than in the destructor.
// This is because the event loop for a top-level window is not
// active anymore when its destructor is called and if the thread
// sends events when ending, they won't be processed unless
// you ended the thread from OnClose.
// See #ref overview_windowdeletion for more info.
}
void onCommsUpdate_t();
void OnClose(wxCloseEvent& evt);
wxTextCtrl * m_txtctrl;
protected:
virtual wxThread::ExitCode Entry();
//fields update from threads
double data_t;
wxCriticalSection m_dataCS; // protects field above - i don't really know how this thing scopes the CS
wxDECLARE_EVENT_TABLE();
};
SRC:
#include "wxMainFrame.h"
wxDEFINE_EVENT(EVT_COMMS_UPDATE, wxThreadEvent)
wxBEGIN_EVENT_TABLE(wxMainFrame, wxFrame)
EVT_THREAD(EVT_COMMS_UPDATE, wxMainFrame::onCommsUpdate_t)
EVT_CLOSE(wxMainFrame::OnClose)
wxEND_EVENT_TABLE()
wxMainFrame::wxMainFrame() : wxFrame(NULL, wxID_ANY, "wxWidgets Layout Demo") {
//Enable thread
if (CreateThread(wxTHREAD_JOINABLE) != wxTHREAD_NO_ERROR){
wxLogError("Could not create the worker thread!");
return;
}
// go!
if (GetThread()->Run() != wxTHREAD_NO_ERROR) {
wxLogError("Could not run the worker thread!");
return;
}
this->data_t = 0;
// Make a menubar
wxMenu *file_menu = new wxMenu;
file_menu->Append(LAYOUT_TEST_PROPORTIONS, "&Proportions demo...\tF1");
file_menu->Append(LAYOUT_TEST_SIZER, "Test wx&FlexSizer...\tF2");
file_menu->Append(LAYOUT_TEST_NB_SIZER, "Test &notebook sizers...\tF3");
wxMenuBar *menu_bar = new wxMenuBar;
menu_bar->Append(file_menu, "&File");
// Associate the menu bar with the frame
SetMenuBar(menu_bar);
// create the logging text control and a header showing the meaning of the
// different columns
wxTextCtrl *header = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize,
wxTE_READONLY);
//DoLogLine(header, " Time", " Thread", "Message");
m_txtctrl = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxTE_READONLY);
wxLog::SetActiveTarget(this);
// use fixed width font to align output in nice columns
wxFont font(wxFontInfo().Family(wxFONTFAMILY_TELETYPE));
header ->SetFont(font);
m_txtctrl ->SetFont(font);
m_txtctrl->SetFocus(); //Field to have focus on startu
// layout and show the frame
wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(header, wxSizerFlags().Expand());
sizer->Add(m_txtctrl, wxSizerFlags(1).Expand());
SetSizer(sizer);
SetSize(600, 350);
}
wxThread::ExitCode wxMainFrame::Entry(){
// IMPORTANT: this function gets executed in the secondary thread context!
while (!GetThread()->TestDestroy()) {
// since this Entry() is implemented in MyFrame context we don't
// need any pointer to access the m_data, m_processedData, m_dataCS
// variables... very nice!
wxCriticalSectionLocker lock(m_dataCS);
this->data_t++;
// VERY IMPORTANT: do not call any GUI function inside this
// function; rather use wxQueueEvent():
wxQueueEvent(this, new wxThreadEvent(EVT_COMMS_UPDATE));
}
// TestDestroy() returned true (which means the main thread asked us
// to terminate as soon as possible) or we ended the long task...
return (wxThread::ExitCode)0;
}
void wxMainFrame::onCommsUpdate_t(){
//Do thread stuff
//wxCriticalSectionLocker lock(m_dataCS);
//std::cout << this->data_t;
}
void wxMainFrame::OnClose(wxCloseEvent& evt){
// important: before terminating, we _must_ wait for our joinable
// thread to end, if it's running; in fact it uses variables of this
// instance and posts events to *this event handler
if (GetThread() && // DoStartALongTask() may have not been called
GetThread()->IsRunning())
GetThread()->Wait();
Destroy();
}
Which results in this compilation error:
In file included from /usr/local/include/wx-3.1/wx/wx.h:24,
from includes/wxMainFrame.h:10,
from src/wxMainFrame.cpp:2:
/usr/local/include/wx-3.1/wx/event.h:4350:5: error: expected ‘,’ or ‘;’ before ‘ const’
4350 | const wxEventTable theClass::sm_eventTable = \
| ^~~~~
src/wxMainFrame.cpp:5:1: note: in expansion of macro ‘wxBEGIN_EVENT_TABLE’
5 | wxBEGIN_EVENT_TABLE(wxMainFrame, wxFrame)
As you can see this is a basic syntax error that I can see/fix if I go into /usr/local/include/wx-3.1/wx/event.h:4350
but this doesn't make sense, I can't be the first person to find a simple syntax error? Something must be wrong on my machine (ubuntu). This is the header that's added to my sys includes from make install right? How would a syntax error appear if the demos/Samples built from the source all work fine. Just thinking out loud I suppose.
I built the lib from source using the suggestions from here.
I also saw this post on wxWidget's forum here. Who didn't seem to have the same syntax issue I'm having. But also, I didn't really understand how to use the suggested macro because the wiki says the macro is actually wrapped by wx__DECLARE_EVT2. If this is the solution perhaps a simple example would be helpful to show me how to use it properly.
I appreciate any input. Thanks!
PS I've tried posting this question on the forum but was unable to register (tried with multiple browsers) so here I am.
There are many issues here. First, the compilation error you mention is due to a missing semicolon, the line:
wxDEFINE_EVENT(EVT_COMMS_UPDATE, wxThreadEvent)
should be
wxDEFINE_EVENT(EVT_COMMS_UPDATE, wxThreadEvent);
Second, the onCommsUpdate_t method needs to take a wxThreadEvent& parameter
void onCommsUpdate_t(wxThreadEvent&);
Obviously, the definition for the method needs to be updated too.
Third, I honestly don't how the EVT_THREAD macro is supposed to work, but I know the line
EVT_THREAD(EVT_COMMS_UPDATE, wxMainFrame::onCommsUpdate_t)
doesn't work. The easiest way to handle a thread event is to use the Bind method. Add a line like this to the frame constructor to handle the event
Bind(EVT_COMMS_UPDATE,&wxMainFrame::onCommsUpdate_t,this);
Fourth, as written, your wxMainFrame::Entry method will be constantly spamming the event queue freezing up the application. In a real application, presumably the thread will do some work before queuing each event. Since in this example, no work is being done, you should add a line like
wxMilliSleep(500);
to the end of the while loop to make the thread sleep for a little bit before sending each event.
Fifth, you never actually signal your thread to shutdown and it never shuts down on its own. Consequently the line GetThread()->Wait(); will be an infinite loop. There are many ways to signal the thread, but the easiest might be to add a bool member named something like m_shutdown to the frame class. Then
a. initialize m_shutdown to false in the frame constructor.
b. In the wxMainFrame::OnClose, use the critical section to set it to true before calling Wait:
if (GetThread() && // DoStartALongTask() may have not been called
GetThread()->IsRunning())
{
{
wxCriticalSectionLocker lock(m_dataCS);
m_shutdown = true;
}
GetThread()->Wait();
}
c. In the wxMainFrame::Entry method, add a check for the value of m_shutdown in the while loop (guarded by the critical section).
while (!GetThread()->TestDestroy()) {
// since this Entry() is implemented in MyFrame context we don't
// need any pointer to access the m_data, m_processedData, m_dataCS
// variables... very nice!
{
wxCriticalSectionLocker lock(m_dataCS);
this->data_t++;
if ( m_shutdown )
break;
}
...
Sixth, I don't know what the line
wxLog::SetActiveTarget(this);
is supposed to do, but it causes a crash at program exit. If you need this, you'll need to store the initial log target and restore it either in the frame destructor or in the close event handler.

Drawing a Graph in C++ MFC App

I am writing a C++ MFC application to control a machine in a manufacturing setting. This app also needs to analyze a lot of information in a very short cycle time.
For testing purposes and long term maintenance, I need to be able to graph data coming from a sensor on the console. I may have totally overlooked an option (feel free to propose other options) but my research has taken me to using a picture control.
I am successfully drawing in this control by use of OnPaint(). My issue is that I need to redraw a new image every few seconds and I cannot call OnPaint() repetitively or pass data to it.
How can I create a new function that can be used to draw on the picture control repetitively? Also, this is my first foray into an MFC app so please explain on an appropriate level. Thanks!
class CPicture : public CStatic
{
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
};
BEGIN_MESSAGE_MAP(CPicture, CStatic)
ON_WM_PAINT()
END_MESSAGE_MAP()
void CPicture::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SelectStockObject(BLACK_BRUSH);
dc.Rectangle(5, 50, 1000, 51);
}
I guess the question is how and where to access this
//Picture
class CPicture : public CStatic
{
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
vector<Coordinates> GraphData;
};
void CPicture::OnPaint()
{
// device context for painting
CPaintDC dc(this);
// save current brush
CBrush *pOldBrush = (CBrush*)dc.SelectStockObject(BLACK_BRUSH);
int NumPoints = GraphData.size() - 1;
for (int N = 0; N <= NumPoints; N++) {
dc.Rectangle(GraphData[N].x, GraphData[N].y, GraphData[N].x, GraphData[N].y);
}
// select original brush into device contect
dc.SelectObject(pOldBrush);
}
You can call Invalidate() on your control when new data arrives, or use RedrawWindow() to force an immediate redraw:
CPicture myPicture;
myPicture.Invalidate();
or
myPicture.RedrawWindow();
I cannot call OnPaint() repetitively or pass data to it.
To pass data, a structure containg the data can be declared inside your CPicture class (or some place else in your program), and that data can then be accessed from within OnPaint():
struct myData {
int value1;
int value2; // or an array, or some other data structure
}
class CPicture : public CStatic
{
DECLARE_MESSAGE_MAP()
public:
myData m_data;
afx_msg void OnPaint();
};
In OnPaint() (you should also select the original brush back into the device context to avoid resource leaks):
void CPicture::OnPaint()
{
CPaintDC dc(this); // device context for painting
// save current brush
CBrush *pOldBrush = (CBrush*)dc.SelectStockObject(BLACK_BRUSH);
// check pOldBrush - could be NULL
// dc.Rectangle(5, 50, 1000, 51);
// access m_data here, for example
dc.Rectangle(m_data.value1, m_data.value2, 1000, 51);
// select original brush into device contect
dc.SelectObject(pOldBrush);
}
Update (working with threads):
Assuming the following (from the comments):
for the main thread you have a dialog CLongbowDlg.
for the graph, you have a PicControl derived from CStatic, and that control is placed on the dialog.
from the main thread, a worker thread is started to read the data.
PicControl and CLongbowDlg are defined in the same header, but are
independent of each other. I need to be able to call Invalidate() or
RedrawWindow() from inside CLongbowDlg's functions because they
represent the primary thread.
I'll try to give a short description of one of the possibilities here, because this should actually be a seperate question.
Firstly, an object of PicControl has to be a member of CLongbowDlg, which I assume is the case (let's call it m_PicControl) - So, in class CLongbowDlg:
PicControl m_PicControl;
For the data (I'll be using the above myData as example data): in your main thread (the Dialog), create a variable of type myData: m_data (for larger data you could allocate space on the heap, or use CArray or some other container):
myData m_data;
In PicControl create a member variable of type myData* and set it to NULL in the PicControl constructor.
myData *m_pData;
In OnInitDialog() (main dialog), provide m_picControl with a pointer to the data (or better create a function to do that in PicControl):
m_picControl.m_pData = &m_data;
When starting the worker thread, also provide it a pointer to m_data and/or a pointer to the dialog itself (this).
Make sure to protect the data with a critical section.
When data comes in, the worker thread can write to it via the provided pointer.
In PicControl::OnPaint(), the same data can be accessed through m_pData.
To initiate a redraw, there are several ways:
use a timer inside PicControl or in the main dialog, and call Invalidate() every time the timer fires.
to control the redrawing from the worker thread (when a certain amount of new data has arrived for example) a message can be posted, using PostMessage(), to the main dialog (using the pointer that was provided when starting the thread - the this pointer).
To receive the message you'll have to create a message handler in the main dialog, and from there call Invalidate() on m_picControl (you could also post a message directly to PicControl, but I prefer to do it via the main window).

C++ - WINAPI - Object-oriented approach to closing a window

While trying to create a nice wrapper around Win32 specific GUI components, I eventually ran into a problem. The problem is that I'm unable to close the application after the windows I created no longer exist.
My API works like this:
/// ----------------------------
/// #author God
/// #project Helixirr Widgets
/// ----------------------------
#include <helixirrwidgets/HelixirrWidgets.hpp>
int main(void){
HelixirrWidgets::Window __windows[2] = {HelixirrWidgets::Window("Big Window"), HelixirrWidgets::Window()};
__windows[0].position(200, 200);
__windows[0].size(800, 600);
__windows[0].visible(true);
__windows[0].save_changes();
__windows[1].name("Tiny Window");
__windows[1].position(10, 100);
__windows[1].size(400, 200);
__windows[1].visible(true);
__windows[1].save_changes();
while(__windows[0].active() || __windows[1].active()){
if(__windows[0].visible()){
__windows[0].show();
}
if(__windows[1].visible()){
__windows[1].show();
}
}
return 0;
}
In method of HelixirrWidgets::Window called "active", which is declared like this
inline bool active(void) const noexcept;
I can check, whether my window is active or not.
This method basically return a const reference to a boolean member variable of an instance. This member variable is modified in "show"-method of the same class. Here's the definition:
void Window::show(void){
if(GetMessage(&_m_opHelper->message, _m_opHelper->handle_window, 0, 0)){
if(_m_opHelper->message.message == WM_CLOSE){
_m_bActive = false;
return;
}
TranslateMessage(&_m_opHelper->message);
DispatchMessage(&_m_opHelper->message);
ShowWindow(_m_opHelper->handle_window, SW_SHOWDEFAULT);
UpdateWindow(_m_opHelper->handle_window);
_m_bActive = true;
return;
}
_m_bActive = false;
}
Do note I use pimpl-idiom to hide platform-specific structures ("_m_opHelper" is pointer to implementation).
It may look like it works, but it doesn't and I can't understand why. It all comes down to a simple question: how can I close my window implemented using WINAPI specific functions and structures to be closed appropriately by a user of my application?
I guess the cause of the issue is related to the fact WM_CLOSE simply is not last message HWND gets. Messages like WM_DESTROY, WM_NCDESTROY and possibly more (depending on the particlar window and its state) will come after WM_CLOSE, leading to the assignment _m_bActive = TRUE.
I.e. the window becomes inactive for very short time, and (likely) they will never be inactive at the same time, causing an endless loop in main().

Add visible window titles to combobox MFC

I want to add visible window titles to a combobox. Here is my source:
BOOL CALLBACK EnumWindowsProc(HWND hWnd, long lParam)
{
TCHAR buff[255];
CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_PROCESS);
if (IsWindowVisible(hWnd))
{
GetWindowText(hWnd, buff, 254);
pComboBox->AddString(buff);
}
return TRUE;
}
void CFindProcess::OnDropdownComboProcess()
{
EnumWindows(EnumWindowsProc, 0);
}
but I get error:
error C2660: 'GetDlgItem' : function does not take 1 arguments 60
How I can correctly add titles to combo?
MFC objects are thread-sensitive, GetDlgItem works well in the thread that created the object, probably the main UI thread. Function EnumWindows probably creates a worker thread to access the callback function, and that is why GetDlgItem failed to get a valid handle of the combobox.
To access the combobox properly in another thread, you have to use the static function: CWnd::FromHandle with the raw handle of the combobox object as follows:
BOOL CALLBACK EnumWindowsProc(HWND hWnd, long lParam)
{
if (IsWindowVisible(hWnd))
{ TCHAR szBuffer[255];
INT nLength = GetWindowText(hWnd, szBuffer, 254);
if (nLength>0)
{ // only add windows that has a caption
CComboBox *pComboBox = (CComboBox*)CWnd::FromHandle((HWND)lParam);
pComboBox->AddString(szBuffer);
}
}
return TRUE;
}
// call EnumWindows --------------------
CComboBox *pComboBox = (CComboBox *)GetDlgItem(IDC_COMBO1);
// passing the raw handle of the combobox as parameter
EnumWindows(EnumWindowsProc, (LPARAM)pComboBox->m_hWnd);
Firstly, your GetDlgItem has two parameters, and the first is a handle to the dialog box that contains the control.
So it expects a HWND parameter of the dialog that contains this control, I would presume that will be the HWND you pass as a parameter to your function.
CComboBox* pComboBox = (CComboBox*)GetDlgItem(hWnd,IDC_COMBO_PROCESS);
^^^^ added parameter
If you look at EnumWindows in MSDN, you'll see you have to pass a callback and it has a HWND parameter, if you look at what this parameter is for it says:
A handle to a top-level window.
This is exactly what you have to pass to GetDlgItem.
Also, you should check the return value of GetWindowText as this returns the number of characters written to the buff you passed it.
int ret = GetWindowText(hWnd, buff, 254);
if (ret > 0) pComboBox->AddString(buff); // only add non-empty strings.
In addition to what user #mfc has provided, I would not do UI update from a different thread. I believe EnumWindows does not create thread for enumeration. It would call the callbacks within the call-stack of current thread.
This, in turn, means that UI may freeze for a while. Thus, it is recommended to create a thread for enumeration. More over, I would not directly update UI from different thread. May be a vector of string, or a PostMessage (on each iteration) I would have used.
It is true that EnumWindows may perform quite fast. But when you move to enumerate other (kernel) objects like file, printers, users etc - the UI is definitely going to freeze. So, better practice writing multithreaded code. Initially writing MT-code would be a pain, but later you'd love it, appreciate it, and cannot live without it.

How can I create an ITaskbarList3 in C++ Builder?

I'm trying to use the ITaskbarList3 interface introduced with Windows 7 so that I can show task progress for a lengthy task in my taskbar icon. The documentation states that I should wait for a TaskbarButtonCreated message before trying to initialize my ITaskbarList3 component, but I don't seem to be getting any TaskbarButtonCreated messages.
Here is what I have so far:
I have a global variable in my .cpp file to store the custom message ID for TaskbarButtonCreated.
static const UINT m_uTaskbarBtnCreatedMsg =
RegisterWindowMessage( _T("TaskbarButtonCreated") );
I created a separate WndProc function to handle the new message.
void __fastcall TForm1::WndProcExt(TMessage &Message)
{
if(Message.Msg == uTaskbarBtnCreatedMsg && uTaskbarBtnCreatedMsg != 0) {
OnTaskbarBtnCreated();
}
else {
WndProc(Message);
}
}
In my form constructor, the very first line sets the WindowProc property to WndProcExt to route messages. I also tried tossing in a ChangeWindowMessageFilter to see if the TaskbarButtonCreated message was being filtered for some reason.
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
WindowProc = WndProcExt;
ChangeWindowMessageFilterEx(Handle, uTaskbarBtnCreatedMsg, MSGFLT_ALLOW, NULL);
...
}
In the debugger, the return value from ChangeWindowMessageFilterEx is always true. I've also confirmed my WndProcExt function receives all kinds of Windows messages, just not the one I'm looking for. The OnTaskbarBtnCreated function never gets called.
Am I missing a step? Is the message being filtered out or sent before my message handler is ready for it?
It is not a good idea to have the TForm assign a value to its own WindowProc property. For starters, the Handle window may have already been allocated before your constructor is even entered, due to DFM streaming, so you would miss all of the window's initial messages (which there can be several) before your constructor starts running. You need to override the virtual WndProc() method instead, and do pass the TaskbarButtonCreated message to the default handler, don't block it:
static const UINT m_uTaskbarBtnCreatedMsg = RegisterWindowMessage( _T("TaskbarButtonCreated") );
void __fastcall TForm1::WndProc(TMessage &Message)
{
TForm::WndProc(Message);
if ((Message.Msg == uTaskbarBtnCreatedMsg) && (uTaskbarBtnCreatedMsg != 0))
OnTaskbarBtnCreated();
}
As for ChangeWindowMessageFilterEx(), you need to call that every time the TForm's Handle window gets (re)allocated (which can happen multiple times during the Form's lifetime), so you need to override the virtual CreateWnd() method instead:
void __fastcall TForm1::CreateWnd()
{
TForm::CreateWnd();
if (CheckWin32Version(6, 1) && (uTaskbarBtnCreatedMsg != 0))
ChangeWindowMessageFilterEx(Handle, uTaskbarBtnCreatedMsg, MSGFLT_ALLOW, NULL);
// any other Handle-specific registrations, etc...
}
void __fastcall TForm1::DestroyWindowHandle()
{
// any Handle-specific de-registrations, etc...
TForm::DestroyWindowHandle();
}
Lastly, set the TApplication::ShowMainFormOnTaskbar property to true in the project's WinMain() function before your MainForm is created so its window, rather than the TApplication window, is managing the taskbar button (and to enable other Vista+ related features, like Flip 3D and Taskbar previews). Otherwise, you will have to use the TApplication::HookMainWindow() method to intercept any "TaskbarButtonCreated" messages that may get sent to the TApplication window.