I'm experimenting with WTL, and I'd like to separate a large message map to two or more files. For example, I'd like to move the tray icon logic into a separate file. I'm aware of CHAIN_MSG_MAP and CHAIN_MSG_MAP_MEMBER, but what should I use in this case?
Also, how will I be able to access the window handle from the second class?
You may be looking for something like this (not tested; my WTL is rather rusty; caveat emptor).
class TrayIconHandler : public CWindow, public CMessageMap {
public:
BEGIN_MSG_MAP(TrayIconHandler)
// Message handlers to taste
END_MSG_MAP()
};
class MainWindow : public CWindowImpl<MainWindow> {
public:
BEGIN_MSG_MAP(MainWindow)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
// Other message handlers
CHAIN_MSG_MAP_MEMBER(tray_icon_)
END_MSG_MAP()
LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&) {
tray_icon_.m_hWnd = m_hWnd;
}
private:
TrayIconHandler tray_icon_;
};
The two classes may be in different source files and/or headers, of course.
Related
working on implementing an Serial receive library for a specific hardware sending information to a ESP8266 device, I came across the following issue
for some background:
I use sloeber the eclipse IDE for arduino programming, with Arduino IDE the same issue exists
__cplusplus gives me 201103, so I assume I am on c++11
explanation of the setup:
I have derived classes which represents interpreted packages received from serial
these classes are all derived form on base class which implements some common methods, here methodA (in reality: length of
data, and getter for the data)
to forward these packets around I have created a class which has a member of a struct (sData) which has a tagged union inside. for simplicity I only use sData here not the class containing it.
the union uUnion is the one holding the packets content in form of derived packages, only one at a time, but able to contain every derived class available.
i do not use any dynamic object creation (no new), to prevent memory leaks
maybe there are better solution to this problem. Ideas are appreciated. But I would like to focus on why my implementation is not working
problem
the usage of the members-functions of the derived classes out of the union.
I can call them directly without problem.
But I am not able to create a pointer out of the union to the derived class instance and call that member.
//this is the base class
class cBaseA{
public:
virtual void methodA(void){
Serial.print(" A ");
Serial.println(i);
}
int i; //some attribute to work with
private:
};
//first derived class
class cDerivedA: public cBaseA{
public:
void methodA(void) {
Serial.print(" DerivedA ");
Serial.print(i);
Serial.print(" ");
Serial.println(ii);
}
int ii; //additional attribute
private:
};
//second derived class
class cDerivedB: public cBaseA{
public:
void methodA(void) {
Serial.print(" DerivedB ");
Serial.print(i);
Serial.print(" ");
Serial.println(ii);
}
int ii;
private:
};
//third derived class
class cDerivedC: public cBaseA{
public:
void methodA(void) {
Serial.print(" DerivedC");
Serial.print(i);
Serial.print(" ");
Serial.println(ii);
}
int ii;
private:
};
//this is the structure to pass different derived instances around
struct sData{
enum eDataType{
eunkown,
eDerivedA,
eDerivedB,
eDerivedC
} DataType;
union uUnion{
cDerivedA DerivedA;
cDerivedB DerivedB;
cDerivedC DerivedC;
~uUnion(){};
uUnion(){};
} ;
uUnion DataUnion;
sData(void){DataType=eDataType::eunkown;};
sData(const sData &Data){
this->DataType=Data.DataType;
switch(this->DataType){
case eDataType::eDerivedA:
this->DataUnion.DerivedA=Data.DataUnion.DerivedA;break;
case eDataType::eDerivedB:
this->DataUnion.DerivedB=Data.DataUnion.DerivedB;break;
case eDataType::eDerivedC:
this->DataUnion.DerivedC=Data.DataUnion.DerivedC;break;
case eDataType::eunkown:
break;
}
}
~sData(){};
};
void DataFunction(struct sData *Data){
Serial.println("A1:");
Data->DataUnion.DerivedB.methodA(); //works fine
cDerivedB *DerivedB;
DerivedB=&(Data->DataUnion.DerivedB); //this works
DerivedB->methodA(); //compiles, but execution exception, code 28
}
void setup(){
Serial.begin(9600);
delay(2000);
sData Data;
cDerivedB DerivedB1;
DerivedB1.i=1;
DerivedB1.ii=2;
Data.DataType=sData::eDataType::eDerivedB;
Data.DataUnion.DerivedB=DerivedB1;
DataFunction(&Data);
}
what I tried so far:
the absence of the virtual destructor of cBaseA has no influence (I tried already with it)
to make the union anonymous did not changed anything
to make a reference to the unions content results in the same error:
cDerivedB &DerivedB;
DerivedB=&(Data->DataUnion.DerivedB);
DerivedB.methodA();
I am able to make copy to out of the union to the base class, but this causes slicing, and the call ends in the base class, not as I need in the derived class
the question is: why does this exception happen, if the direct call is possible?
What is the right way to get a handle (pointer, reference) of the unions content and call the member? I know that there are discussions out there, that unions should only contain simple data types. Is this just a flaw of the compiler (c+11) letting me write this?
But still, direct access is possible. Why not via pointer?
many thanks in advance if somebody is able to put that cloud away I can not see through.
How can I know that for a particular ComboBox which Dialog Style is being used? Is there any Win32 API which can give me that information?
I am using CDialog for a few ComboBox, CDialogEx for some, and an in-house Dialog class, let's say Ctl3dDialogEx, for others. GetClassName() will return the Class name of the ComboBox (if I am passing a ComboBox Handler) which can be "CComboBox".
Is there any Win32 API where I will pass the ComboBox Handler and it will return back to me the Dialog class name, for eg : "CDialog", "CDialogEx", "Ctl3dDialogEx", etc?
Below code will help to understand maybe:
void ComboBox_DoSomeManipulation( HWND hldg , int n )
{
/*"hldg" is the handler of the Current ComBobox */
LPTSTR lpClassName;
int nMaxCount = 256;
/*This will return "CComboBox" as value in lpClassName */
GetClassName(hldg , lpClassName , _count_of(nMaxCount));
/*Is there any WIN API like above which can give */
/* Dialog class information like CDialog, CDialogEx */
/* which the ComboBox is using ? */
}
If your combo-box can somehow get hold of a genuine pointer to its parent window, then you can use dynamic_cast<CDialogEx*>(pParent) to see if it's CDialogEx (returns nullptr if not). You will need several separate checks, starting from the most derived class! So, if your Ctl3dDialogEx is derived from CDialogEx, then:
. . .
CWnd *pParent = pCombo->GetParent(); // This, as is, is not valid code!
if (dynamic_cast<Ctl3dDialogEx*>(pParent) != nullptr) {
// It's a Ctl3dDialogEx parent
}
else if (dynamic_cast<CDialogEx*>(pParent) != nullptr) {
// It's a CDialogEx
}
else { // Assuming no other options …
// It's a CDialog
}
I would recommend making an accessible (static?) copy of the parent window's this pointer during initialisation, if you can. But there are other ways …
For example, assuming you have control over the definition of ComboBox_DoSomeManipulation and when it's called, change the first argument from an HWND to a CWnd* and, when you call it, use this rather than this->m_hwnd. (But this depends on the structure of your code!)
There is no Windows API help since all those dialogs will be subclassing the Windows DIALOG class. If this is all in process, and you are using the same MFC instance, you might be able to do this:
CWnd* pWnd = CWnd::FromHandlePermanent(hdlg);
if (pWnd != NULL)
{
if (pWnd->GetRuntimeClass() == RUNTIME_CLASS(CDialog))
{
}
else if (pWnd->GetRuntimeClass() == RUNTIME_CLASS(CDialogEx))
{
}
else if (pWnd->GetRuntimeClass() == RUNTIME_CLASS(CDialogxyz))
{
}
}
Back in the old days, MS compilers used with MFC didn't play well with dynamic_cast<>, so generally, when using MFC, I don't use it. I probably should have more trust in it, but I was stuck using Visual C++ 6 until 2008, so I am probably a little jaded. The more "standard" "MFC way" is to use the MFC macros...
Another possible ways is something like:
if (CDialogxyz* pDlgxyz = DYNAMIC_DOWNCAST(CDialogxyz, pWnd))
{
}
else if (CDialogEx* pDlgEx = DYNAMIC_DOWNCAST(CDialogEx, pWnd))
{
}
else if (CDialog* pDlg = DYNAMIC_DOWNCAST(CDialog, pWnd))
{
}
I have a COM interface exposed from my application which is used by the third party plugins. Now, I need to add a new method to this interface but can not change the GUID of the interface as it will break all the existing plugins. I was told that if I add the new methods at the end of the interface it will work without issues as finally COM interface is a table of function pointers. These new methods will only be used by newly written plugins. I read this post and the first comment in Raymond Chen's blog: http://blogs.msdn.com/b/oldnewthing/archive/2005/11/01/487658.aspx but the situation mentioned in comment won't happen in my case as it is Windows only application. I know theoretically I should change the interface GUID. What would be the correct solution in this case? or will this approach work?
You can usually get away with adding new methods to the end of an existing interface without breaking compatibility. But as you have been reading, there are subtle cases where this can break. Especially when multiple inheritance is already being used.
The correct solution is to simply declare a new interface for the new methods. Leave your existing interfaces alone. Then have your existing objects implement both interfaces or use inheritance to have the new interface inherit from the old.
For example, if this is our original code. (I'll pretend this is done without IDL files for brevity).
Original code:
class IPublicInterface : public IUnknown
{
public:
virtual void M1() = 0;
virtual void M2() = 0;
}
class MyPublicClass : IPublicInterface
{
public:
// IPublicInterface
void M1();
void M2();
// IUnknown
HRESULT QueryInterface(...);
ULONG AddRef();
ULONG Release();
};
Now let's say we want to add a new method to this object called M3 without breaking users of the existing interface and object. The correct solution would be to add a new interface. For convenience, it can just inherit from the original interface.
class IPublicInterface2 : public IPublicInterface
{
public:
virtual void M3() = 0;
};
Now modify the class to inherit from both this new derived interface:
class MyPublicClass : public IPublicInterface2
{
public:
// IPublicInterface
void M1();
void M2();
// IPublicInterface2
void M3();
// IUnknown
HRESULT QueryInterface(...);
ULONG AddRef();
ULONG Release();
};
Update QueryInterface to support both calls for both the original UUID of IPublicInterface as well as IPublicInterface2.
HRESULT MyPublicClass::QueryInterface(GUID& iid, void** ppv)
{
// QI request for original interface
if ((iid == uuidof(IPublicInterface) || (iid == uuidof(IUnknown))
{
*ppv = (IPublicInterface*)this;
AddRef();
return S_OK;
}
else if (iid == uuidof(IPublicInterface2)
{
*ppv = (IPublicInterface2*)this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
Alternatively, IPublicInterface2 does not need to inherit from the original IPublicInterface. In that case, the implementing class inherits from both interfaces. In the QueryInterface implementation, you will need to be consistent about how you handle a possible ambiguous cast to IUnknown.
Let's say my main class has a private member that is a class derived from a CTreeView control. How can I handle the messages from this tree view control on the main class itself?
This is similar to the MDI base application that Visual Studios builds for you, where you have two dockable tree view controls named CClassView and CFileView and each has a private member that's derived from CTreeView.
Can I pass the message from the child member control CViewTree to my CFileView class with like this?
void CViewTree::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
GetParent()->SendMessage(WM_NOTIFY, 0, (LPARAM)pNMHDR);
}
This code throws an exception, but if this does work, how would I handle the TVN_SELCHANGED message in the parent class?
Edit:
So I've tried the following suggestions but haven't had much luck with either one.
//First try, in the parent .h file:
afx_msg BOOL OnSelChange(NMHDR *pNMHDR, LRESULT *pResult);
//In the .cpp file:
ON_NOTIFY_REFLECT_EX(TVN_SELCHANGED, OnSelChange)
//and
BOOL ParentClass::OnSelChange(NMHDR *pNMHDR, LRESULT *pResult)
{
AfxMessageBox(L"in handler");
Return TRUE;
}
Second try:
//in the parent .h file:
afx_msg void OnSelChange(NMHDR *pNMHDR, LRESULT *pResult);
//In the .cpp file:
ON_NOTIFY(TVN_SELCHANGED, AFX_IDW_PANE_FIRST, OnSelChange)
//and
void ParentClass::OnSelChange(NMHDR *pNMHDR, LRESULT *pResult)
{
AfxMessageBox(L"in handler");
}
Not sure why you want to do this, you have less code reusability as you have a tight coupling between the view and the parent. If you want to reuse the selection logic, you can extract it out into a separate class like the DRAWCLI sample does.
TVN_SELCHANGED is already sent to the parent. However MFC's message reflection routes the notification to the child window's message map when ON_NOTIFY_REFLECT is present in the child.
If you want the parent to have a say in the message processing as well, you can change ON_NOTIFY_REFLECT to ON_NOTIFY_REFLECT_EX and return FALSE in the reflected message handler.
You will get a WM_NOTIFY at the parent so the way you handle the notification is to add a ON_NOTIFY macro to the parent of the tree view like you normally do for a tree control on a dialog. The view's id is likely AFX_IDW_PANE_FIRST if you haven't specified one.
Sheng was able to figure out my problem, which looking back now was quite trivial. Maybe this will help others who might have the same question.
In the MDI w/ visual studio style program that I generated from Visual Studio 2010, the CFileView has a child member instance of CViewTree. CViewTree was derived from CTreeCtrl.
By default, MFC is already passing the messages up the child-to-parent chain. The answer is determining the control ID to get notification messages from in your parent class.
So, first things first, we need to know the ID of the tree control. In the OnCreate method of CFileView, you can see this code:
if (!m_wndFileView.Create(dwViewStyle, rectDummy, this, 4))
MSDN has the following for the Create method:
virtual BOOL Create(
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID
);
In my example, the id is 4. Now in the parent (CFileView in this case), just create your ON_NOTIFY macro as such:
BEGIN_MESSAGE_MAP(CFileView, CDockablePane) //precreated for you
ON_NOTIFY(TVN_SELCHANGED, 4, OnSelChanged) //you create this
END_MESSAGE_MAP() //precreated for you
I had to type the line above by hand because the class wizard or message property for the parent didn't have a =TVN_SELCHANGED message. Next, make sure your handler method OnSelChanged is declared in the CFileView.h file as:
afx_msg void OnSelChanged(NMHDR *pNMHDR, LRESULT *pResult);
Now I'm able to handle the TVN_SELCHANGED message like this (back in the CFileView.cpp):
void CFileView::OnSelChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
HTREEITEM item = m_wndFileView.GetSelectedItem();
AfxMessageBox(m_wndFileView.GetItemText(item));
}
In the described case if you want to notify parent CFileView from control CViewTree with WM_NOTIFY TVN_SELCHANGED message, you should do it in virtual OnNotify function, not using message map. If OnNotify doesn't met correct handler, message would go to parent CMainFrame, and there you can use message map.
BOOL CFileView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
if (nmHdr->idFrom != 4)
return CDockablePane::OnNotify(wParam, lParam, pResult);
if (nmHdr->code == TVN_SELCHANGED)
{
OnItemsSelChanged((NMHDR*)lParam, pResult);
return TRUE;
}
return FALSE;
}
I am developing a NPAPI plugin using firebreath. I am using a third party dll to integrate to a gaming device.The inputs on the devices are propagated to the plugin through a message only window(HWND) registered while opening a channel to the device.
Initially, handshake with the device driver,
handshake(HWND,...) and after which on user input, a callback is made on CustomWinProc() to notify.
I did the following,
-Created an Header&CPP file under the WIN-CustomCallbackHandler.h ,
#include "Win\PluginWindowWin.h"
#include "Win\WindowContextWin.h"
class CustomCallbackHandler : public FB::PluginWindowWin
{
public:
CustomCallbackHandler (const FB::WindowContextWin& ctx);
protected:
virtual bool CustomWinProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM
lParamm,LRESULT & lRes);
};
-CustomCallbackHandler.cpp
[code]
#include "CustomCallbackHandler.h"
#include "PluginWindowForwardDecl.h"
#include "Win\WindowContextWin.h"
#include "Win\PluginWindowWin.h"
CustomCallbackHandler::CustomCallbackHandler(const FB::WindowContextWin& ctx) :
FB::PluginWindowWin(ctx){
}
bool CustomCallbackHandler::CustomWinProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM
lParamm,LRESULT & lRes){
//if WPARAM is something some operation has to be performed.
return false;
}
[/code]
-Factory.cpp - Added the following method to override the PluginWindowWin
FB::PluginWindowWin* createPluginWindowWin(const FB::WindowContextWin& ctx)
{
return new CustomCallbackHandler(ctx);
}
-MyFirstPluginAPI.cpp-(The auto generated JSAPIAuto subclass)- JS method.
bool MyFirstPluginAPI::handshake(FB::JSObjectPtr &callback)
{
FB::WinMessageWindow window;
thirdpartymethod(window.getHWND());
}
Now,When I debug I could see the customcallbackhandler being invoked a couple of times for the regular plugin events but the events generated by the devices are not available.I believe a different instance of message window is passed on to the dll.
-How do I get the handle of the PluginWindowWin?
-Once I receive a callback on the CustomCallbackHandler,How do I generate a custom sendEvent()?
Your help is highly appreciated.
I am a Java developer and don't have much experience in C++ programming. I believe I am missing something fundamental.
What you want is to use WinMessageWindow:
https://github.com/firebreath/FireBreath/blob/master/src/PluginCore/Win/WinMessageWindow.h
You don't want to use PluginWindowWin; that's too specific for other things. WinMessageWindow was created specifically to do the types of things you are trying to do, and it allows you to make a winproc handler on the containing class.
I recently posted an example of using WinMessageWindow in order to receive WM_DEVICENOTIFY messages; I'm sure you can use it as an example of how the class works to get you started.