a non static member reference must be relative to a specific object - c++

I have been building a simple application which requires a separate thread to run some background code in a while loop. I have a text box which I want to send messages to from the code running in the separate thread however I am unable to.
A non static member reference must be relative to a specific object. From my understanding to run an additional thread it seems that I have to make the function static. However when I try and write a message to m_Console I see the error:
A non static member reference must be relative to a specific object.
I tried initialising the object but it doesn't do anything.
CMFCApplication1Dlg obj;
obj.m_Console = "Test"
The code that uses a separate thread is:
static UINT checkSomething(LPVOID pParam);
The text box variable is:
CString m_Console;
void CMFCApplication1Dlg::OnBnClickedBtnAdd(){
m_Console = "Parser is now running..";
AfxBeginThread(checkSomething,"");
I have tried the suggestion:
UINT CMFCApplication1Dlg::checkSomething(LPVOID pParam){
CMFCApplication1Dlg* pObject = (CMFCApplication1Dlg*)pParam;
pObject->m_Console = "I am in thread";
But it throws an access violation error on: pObject->m_Console = "I am in thread";
Exception thrown at 0x0FE90DBD (mfc140ud.dll) in MFCApplication1.exe: 0xC0000005: Access violation reading location 0xFFFFFFFC.
Here is the code:
MFCApplication1Dlg.cpp
void CMFCApplication1Dlg::OnBnClickedBtnAdd(){
m_Console = "Something Parser is now running..";
AfxBeginThread(checkSomething,"");
CWnd* okbtn = GetDlgItem(IDC_BTN_ADD);
if (okbtn) {
okbtn->EnableWindow(FALSE);
}
// without UpdateData() status area will _NOT_ be updated.
UpdateData(FALSE);}
INT CMFCApplication1Dlg::checkSomething(LPVOID pParam){
CMFCApplication1Dlg* pObject = (CMFCApplication1Dlg*)pParam;
pObject->m_Console = "I am in thread";
MFCApplication1Dlg.h
public:
afx_msg void OnBnClickedBtnAdd();
static int messenger();
static UINT checkSomething(LPVOID pParam);
CString m_Console;
Textbox:
IDC_Console
Category: value
Access: public
Control type: LText
Name: m_Console
Variable type: CString
From reading everyone's comments, it seems as if this is something that I am not supposed to do in C++, question is then, what if I had a background task running a loop in in a separate thread which needed to update the status box on the UI? To me that seems a logical thing someone might wish to do but if I'm not supposed to do that then how would that be done? I am running the task in a separate thread because it uses a while loop and if I don't use a separate thread it just freezes the whole application.

You can deliver the object of CMFCApplication1Dlg as parameter for the Thread function.
e.g
UINT MyThreadProc( LPVOID pParam )
{
CMFCApplication1Dlg * pObject = (CMFCApplication1Dlg *)pParam;
pObject->m_Console = "I am in thread";
}
// .... .... ...
AfxBeginThread(MyThreadProc, this);
I hope this answer will work for you.

Changed
AfxBeginThread(checkSomething,""); to
AfxBeginThread(checkSomething,this);
as suggested by ysk silver, thanks!
I needed to add a Timer Function which I followed this article:
https://www.tutorialspoint.com/mfc/mfc_multithreading.htm
Once I did this, the UI box updates.
int currValue;int maxValue;BOOL stopNow;string output;
BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_ERASEBKGND()
ON_WM_CTLCOLOR()
ON_WM_TIMER() //TIMER
ON_BN_CLICKED(IDC_BTN_ADD, &CMFCApplication1Dlg::OnBnClickedBtnAdd)
END_MESSAGE_MAP()
void CMFCApplication1Dlg::OnTimer(UINT_PTR nIDEvent) {
CDialogEx::OnTimer(nIDEvent);
UpdateData(FALSE);}
void CMFCApplication1Dlg::OnBnClickedBtnAdd(){
SetTimer(1234, 333, 0); // 3 times per second
m_Console = "Parser is now running..";
AfxBeginThread(checkSomething,this);
I then can change the text in the checkSomething method:
CMFCApplication1Dlg* pObject = (CMFCApplication1Dlg*)pParam;
output = "I am in thread";
pObject->messenger(output);
//OR
pObject->m_Console = "I am in thread";
And the textbox updates!

Related

How can I execute the function when button in wxYES_NO is pressed?

Maybe my title is unclear, so I will tell here a more precise explanation:
I am just learning WxWidgets, and I am now trying to make two files: main.cpp and Quit.h. Main.cpp will have the core of the application, and Quit.h will have the class for the quit dialog: Do you really want to quit this application (Yes / No).
Now this is my Quit.h file (without include part):
class Quit : public wxFrame
{
public:
Quit(const wxString& tekst);
};
Quit::Quit(const wxString& tekst)
{
wxMessageDialog* dial = new wxMessageDialog(NULL, _("Do you really want to quit?"), _("Quit"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
dial->ShowModal();
}
And here I am stuck. I tried with wxDECLARE_EVENT_TABLE(), but I don't know which event stands for this: "on the press of yes button (in wxYES_NO system of buttons)". I can't say: on the press of wxYES_NO because these are two buttons (both YES and NO).
So how can I execute the function when the button YES is pressed?
Thank you!
P.S.
I really apologize for this unclear question, but I hope, that you'll understand. Note that I am just a beginner, so please don't use so many "technical" words and expressions in the answer. I read the documentation, but it uses so many technical expressions and explanation. Also, I read this book.
P.P.S.
Have you noticed that there are a lot of questions on SE now, while there is COVID-19 on its way?
EDIT: When I was making the program on, I came to the other error. Minimal code:
Quit.h
class Quit : public wxFrame
{
public:
Quit(const wxWindow* parent, const wxString& text);
};
Quit::Quit(const wxWindow* parent, const wxString& text)
{
int dialog_return_value = wxNO;
wxMessageDialog* dial = new wxMessageDialog(NULL, text, _("Exit"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
dialog_return_value = dial->ShowModal();
switch (dialog_return_value)
{
case wxYES:
Close(true);
break;
case wxNO:
Close(false);
break;
default:
Close(false);
};
}
and then I have this line in main.cpp:
void MyFrame::CloseWindow(wxCommandEvent& event)
{
Quit* quit = new Quit(this, _("Do you really want to close the App?"));
}
And then it doesn't work. I can't find the solution, so, if you have some time, please help.
Thank you again!
I would suggest using the wxEvtHandler::Bind<>() function as detailed in the wxWidgets documentaton at https://docs.wxwidgets.org/3.0/overview_events.html. The Bind() function allows dynamic binding of events and the syntax is one line of code as compared to setting up tables to link events to objects.
Additionally see this wxWidgets user forum thread which has detailed explanation for calling member and nonmember methods https://forums.wxwidgets.org/viewtopic.php?t=39817
wxYES_NO is a style flag that tells wxWidgets framework that you want both yes and no buttons in your dialog. Check if the return value of ShowModal() is equal to one of the builtin macros defined as wxYES and wxNO.
See here for the macro definitions https://docs.wxwidgets.org/trunk/defs_8h.html
And you should read up on wxDiaglog. Start here https://docs.wxwidgets.org/trunk/classwx_dialog.html
Do you want to return the value to the caller of Quit::Quit()? Constructors do not return values, you can set a member variable to the value but remember that if the object is destroyed then your member variable is gone too. You have not provided enough information to know what needs to be done for cleanup when you Quit() so I will provide you with the code to check the return value, just fill in what you need in the case body.
Here is how you would check the return value:
class Quit : public wxFrame
{
public:
Quit(const wxString& tekst);
};
Quit::Quit(const wxString& tekst)
{
int dialog_return_value = wxNO; // initialize to a sane default value
wxMessageDialog* dial = new wxMessageDialog(NULL, _("Do you really want to quit?"), _("Quit"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION);
dialog_return_value = dial->ShowModal();
// You do not have cancel button so only check wxYES and wxNO
switch( dialog_return_value) // Use switch, scales to more buttons later
{
case wxYES :
/* do something */
break;
case wxNO :
/* do something */
break;
default : /* ignore or handle error */ ;
};
}
You are doing a technical task, it is reasonable to expect that learning "technical" words will be involved.
I checked the code return values are not the same as the input style values, we need to check the return value with wxID_YES instead of wxYES!
I was trying to stick to using as much as possible your code but it makes no sense to me using a plain class to close the application. In that case with wxWidgets you still need to reference your main frame to accomplish the closure. There are easier ways as shown in the example below.
Following is a full working example of an application which simply has a quit button on a frame. You click the button and get the quit message dialog. wxWidgets allows creating dialogs on the stack as opposed to the heap and that is what you need here because the dialog is trivial and will not be reused.
You can copy/paste/compile/run the following code as long as you are using wxWidgets 3+ (I am pretty sure Bind() was added then, may have been slightly earlier)
#include <wx/wx.h>
// toolkit requires defining a wxApp class, OnInit() will be called automatically
// when the wxIMPLEMENT_APP macro is invoked below
class MyApp : public wxApp
{
public:
virtual bool OnInit();
};
class MyFrame : public wxFrame
{
public:
MyFrame();
~MyFrame();
private:
void OnExit( wxCommandEvent& event );
// these pointer are owned by the wxWidgets toolkit, do not delete them
// but you need them in a "real" app to add items to the sizer or change
// button properties
wxSizer* m_frame_sizer;
wxButton* m_quit_button;
};
// toolkit requires calling this macro with a wxApp object to bootstrap the GUI framework
wxIMPLEMENT_APP( MyApp );
// OnInit is loosely synonymous with main(), it is where the GUI thread is started
bool MyApp::OnInit()
{
// Create a frame with button
MyFrame* frame = new MyFrame();
// Show the frame with its button
frame->Show( true );
// If return value is false, the wxWidgets framework will kill the app
return true;
}
MyFrame::MyFrame() : wxFrame( NULL, wxID_ANY, "Test Exit" )
{
// wxWidgets requires all controls to be placed in a sizer
m_frame_sizer = new wxBoxSizer( wxVERTICAL );
// Assign the sizer to the frame
this->SetSizer( m_frame_sizer );
m_quit_button = new wxButton( this, wxID_EXIT, "Quit" );
// Put the button into the sizer
m_frame_sizer->Add( m_quit_button, wxSizerFlags().Center() );
// Here we bind the button click event to the OnExit method of MyFrame
// keep in mind that this technique will bind all buttons with id wxID_EXIT to the method
// m_quit_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnExit, this) will also work
// to handle the event for just the m_quit_button (notice the lack of wxID_EXIT, it is not needed in this case)
Bind( wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnExit, this, wxID_EXIT );
}
MyFrame::~MyFrame()
{
// for illustration, not strictly needed here becasue the entire app is shutting down
Unbind( wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnExit, this, wxID_EXIT );
// OR m_quit_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnExit, this) for the alternative form
}
void MyFrame::OnExit( wxCommandEvent& event )
{
// Setup a message box with (in order below) the user query text, a title, and style which puts yes/no button and a question mark icon
// Create the message box on the stack as opposed to the heap becasue we only need it here
int answer = wxMessageBox( "Do you rally want to quit?", "Exit App", wxYES_NO | wxICON_QUESTION );
if( answer == wxYES )
{
this->Close( true );
}
// else just return
}
wxYES is a different value than wxID_YES (the codes are 2 vs. 5103). wxMessageDialog::ShowModal returns "one of wxID_OK, wxID_CANCEL, wxID_YES, wxID_NO or wxID_HELP". So the switch statement as written will always trigger the default case. This applies for wx3.1- hopefully those variables will be consolidated in the future as the redundant values do lend themselves to mistakes.
For completeness, the provided switch statement should be:
switch (dialog_return_value)
{
case wxID_YES: //Subtly different from wxYES
Close(true);
break;
case wxID_NO: //Not wxNO
Close(false);
break;
default:
Close(false);
};

ShowWindow fails to focus on Win10 Calculator app [duplicate]

I have an application which may only have one instance of itself open at a time. To enforce this, I use this code:
System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcesses();
System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess();
foreach (System.Diagnostics.Process p in myProcesses)
{
if (p.ProcessName == me.ProcessName)
if (p.Id != me.Id)
{
//if already running, abort this copy.
return;
}
}
//launch the application.
//...
It works fine. I would also like it to be able to focus the form of the already-running copy. That is, before returning, I want to bring the other instance of this application into the foreground.
How do I do that?
SetForegroundWindow works, to a point:
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
// ...
if (p.Id != me.Id)
{
//if already running, focus it, and then abort this copy.
SetForegroundWindow(p.MainWindowHandle);
return;
}
// ...
This does bring the window to the foreground if it is not minimized. Awesome.
If the window IS minimized, however, it remains minimized.
It needs to un-minimize.
Solution via SwitchToThisWindow (Works!):
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
[STAThread]
static void Main()
{
System.Diagnostics.Process me = System.Diagnostics.Process.GetCurrentProcess();
System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcessesByName(me.ProcessName);
foreach (System.Diagnostics.Process p in myProcesses)
{
if (p.Id != me.Id)
{
SwitchToThisWindow(p.MainWindowHandle, true);
return;
}
}
//now go ahead and start our application ;-)
}
I had the same problem and SwitchToThisWindow() worked the best for me. The only limitation is that you must have XP sp1 installed. I played with SetForegroundWindow, ShowWindow, and they both had problems pulling the window into view.
C# equivalent of Tom Juergens's answer. Works like a charm for me.
private const int SW_SHOWNORMAL = 1;
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool SetForegroundWindow(IntPtr hwnd);
public void SetForeground()
{
Process[] processes = Process.GetProcessesByName("process name");
foreach (Process p in processes) {
ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL);
SetForegroundWindow(p.MainWindowHandle);
}
}
Same as OP, I found that SetForegroundWindow alone wasn't enough when the window was minimized. Since I didn't want to use SwitchToThisWindow, I chose ShowWindow followed by SetForegroundWindow.
Works well for me!
private const SW_SHOWNORMAL = 1
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Function ShowWindow(ByVal hwnd As IntPtr, ByVal nCmdShow As integer) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Function SetForegroundWindow(ByVal hwnd As IntPtr) As Boolean
End Function
Sub SetForeground()
Dim processes As Process() = Process.GetProcessesByName("myprocess")
For Each p as Process in processes
ShowWindow(p.MainWindowHandle, SW_SHOWNORMAL)
SetForegroundWindow(p.MainWindowHandle)
Next
End Sub
I believe you will want to use SetForegroundWindow
MSDN Example
Complete Side Note...
You can use
Process.GetProcessesByName(me.ProcessName)
instead of looping over all the processes running on the system...
UPDATE
PInvoke Rules for this sort of thing...
Can you grab MainWindowHandle property of the Process object and send it a WM_USER message that you can interpret as "some other instance wants to bring me to the front".
It is a very frequent behavior in desktop applications, I regularly have to do this when I create a new WPF application. So I have created a SingletonApp class which inherits from Application :
public class SingletonApp : Application
{
private static readonly System.Threading.Mutex mutex;
private static readonly string processName;
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int flags);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hwnd);
static SingletonApp()
{
processName = Process.GetCurrentProcess().ProcessName;
mutex = new System.Threading.Mutex(false, $"Local\\{processName}");
}
/// <summary>
/// A base class for application needing to prevent multiple instances
/// </summary>
public SingletonApp()
{
if (!mutex.WaitOne(0, false))
{
// Give focus to existing instance before shutdown
BringToFront(processName);
Current.Shutdown();
}
}
public void BringToFront(string processName)
{
Process process = Process.GetProcessesByName(processName).FirstOrDefault();
if (process != null)
{
// In case of window is minimized
ShowWindow(process.MainWindowHandle, 1); // 1 = Normal
SetForegroundWindow(process.MainWindowHandle);
}
}
}
To use it, you just have to inherit from SingletonApp instead of Application in your App.xaml.cs :
public partial class App : SingletonApp
Don't forget to update App.xaml too :
<utils:SingletonApp x:Class="MyApp.App"
[...]
xmlns:utils="clr-namespace:MyApp.Utils"
Startup="App_OnStartup">
With this it becomes very easy to implement this behavior in every new desktop client.

MS Visual C++ Multithreading accessing allocated variables causes access violation

I have an issue with an MFC dialog based application build with MSVC 2013. To make the main dialog accessible also during more elaborate functions, I'm using multi-threading. A click on a button in the dialog calls a "worker function" that is worked out by another thread.
Here's an excerpt of the class:
class CpiezcamDlg : public CDialogEx
{
protected:
virtual BOOL OnInitDialog();
public:
CWinThread *m_thread1;
void StartSweepAndImageThread()
{
m_thread1 = AfxBeginThread(SweepAndImageThreadProc, this);
}
private:
static UINT SweepAndImageThreadProc(LPVOID pParam)
{
CpiezcamDlg *pThis = (CpiezcamDlg *)pParam;
UINT nRet = pThis->DoSweepAndImage();
return nRet;
}
UINT DoSweepAndImage();
UINT16 steps;
CString *imgs_name;
};
Clicking a button calls StartSweepAndImageThread which itself calls SweepAndImageThreadProc and finally DoSweepAndImage. In the function DoSweepAndImage, variables of the class are accessed (read and write). Amongst others, there is imgs_name. The usage is:
UINT CpiezcamDlg::DoSweepAndImage()
{
// ...
CString str;
str.Format(_T("Test"));
AddStageListText(str);
imgs_name[i] = str;
// ...
}
while imgs_name is initialized like
steps = 4;
imgs_name = new CString[steps];
in the OnInitDialog function.
The problem is that when pressing the mention button I receive
0xC0000005: Access violation reading location 0xFDFDFDF9.
exactly on imgs_name[i] = str;. When using a statical array, that is instead of CString *imgs_name; I define CString imgs_name[4];, everything works well. However, I very much would like to have that CString variable a dynamical one. Thanks in advance for your help!
PS: When I evaluated this in a serial way, i.e. when running the DoSweepAndImage function in the main thread, everything goes well. That's why I assume the access violation is due to the multi-threading.
#Wimmel: The loop over i in DoSweepAndImage is
for (UINT16 i = 0; i < steps; i++)

Application with multiple windows as instances of a class, C++

I wrote an application. There is a class named APP, with handle to the window, and message loop inside it, and all this stuff.
It is intended to "run" some objects of this class, each with its own window based on a set of variables necessary for a standard window.
Message loop is allowed for public use, it is ran by RunMessageLoop method.
int nCmdShow - of course, it is used to tell how to display a window.
Now, when i create some objects like this:
vector <APP *> App;
for (int i=0; i<3; i++)
{
App.push_back(&APP(nCmdShow))
App[i]->RunMessageLoop();
}
program waits for each message loop to end before it starts another.
I figured out to make it this way:
vector <APP *> App;
for (int i=0; i<3; i++)
{
App.push_back(&APP(nCmdShow))
}
for (int i=0; i<3; i++)
{
App[i]->RunMessageLoop();
}
When i know how many windows I want at startup to be run, it seems to be ok.
But I don't know how to create new windows dynamically, with complete independence of other windows. It should invoke message loops and immediately return to WinMain() without ending message loops.
I thought about multi-threaded app, each thread per one instance of an APP class. But don't know how to build multithreaded app, though.
Any ideas for a possible solution?
I see what you are trying to do now, I have achieved this in my application framework called Lucid (it is still a work in progress). For the sake of the answer, your window class will be called Window instead of APP.
This is done by passing a global procedure to every window you create. All windows share this same procedure. Every time any window gets a message, that message is sent to the global procedure, the global procedure checks if the HWND belongs to a Window that you created, and if it does, sends the message to that Windows' procedure. Here's an overview of how this works.
class Window
{
public:
// The contents of this function can vary from window to window
// provided that you make a subclass and override this method.
virtual LRESULT procedure(HWND wnd, UINT msg, WPARAM wp, LPARAM lp);
// When you create a Window object, add a pointer to it in this map.
// Eg. if (this->hwnd != NULL) createdWindows[this->hwnd] = this;
static map<HWND, Window*> createdWindows;
// When you create a window, make this its procedure.
static LRESULT CALLBACK routeMessage(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
if (createdWindows.find(wnd) != createdWindows.end()) {
// Message belongs to one of our 'Window' objects.
// Pass the message to that window and return the result.
return createdWindows[wnd]->procedure(wnd, msg, wp, lp);
} else {
// It seems you made 'routeMessage' the procedure
// of a window that doesn't belong in the map. Go ahead
// and process the message in the default manner.
return DefWindowProc(wnd, msg, wp, lp);
}
}
};
Now you will only need a single message loop and a single thread. I have a test project using Lucid that creates 2 windows with different procedures on a single thread with a single message loop:
#include "Lucid.h"
using namespace Lucid;
void sayBye(MessageEventArgs& e)
{
MessageBox(NULL, "Goodbye!", "Form 2", MB_OK);
e.handled = true;
}
void Program::onStart()
{
Form* myForm1 = new Form("Hello World!");
myForm1->show();
Form* myForm2 = new Form("Hello World!");
myForm2->addMessageHandler(WM_CLOSE, sayBye);
myForm2->show();
// This Program::onStart() function is called
// immediately before the single message loop is entered.
}
Create the threads with _beginthreadex equal to the number of window you need to run. Then, run message loop in the thread procedure and wait until all thread has been terminated with WaitForMultipleObjects.

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.