How to avoid WM_APP - c++

I am writing a CFrameWnd wrapper and I have this line in the header file :
#define WM_CFW_MESSAGE (WM_APP + 100)
Is this is a good practice ? Does it require that users of this wrapper will have to remember not to use this particular number (WM_APP + 100) ?

No, it's not a good practice. The WM_USER range is more suitable. The WM_APP range is intended for messages that must be understood by multiple window classes in a single program. The WM_USER range is intended for messages that are intended for a single window class.
Therefore, you can safely use values in WM_USER range. You can write #define WM_CFW_MESSAGE (WM_USER+0) because you know that your window class has no other WM_USER messages. When you add a second custom message to the same window class, you can use (WM_USER+1), etcetera. If you implement another window class, it can start at WM_USER+0 again.

It would only be a problem if users tried to send that message to the window handle of your wrapper.

"users of this wrapper will have to remember not to use this particular number"
And why would they want to do that. Shouldn't you as the component writer, provide methods, rather than let your user accessing your control directly.
This is an "unwritten" rule that you might want to know.
WM_USER.
Use this message within you control.
Supposed, you write a control and some methods INSIDE YOUR CONTROLS need to alter your control, you might want to use WM_USER.
WM_APP.
If your application needs to send message to OBJECTS INSIDE YOU APPLICATION, you can use WM_APP.
RegisterWindowMessage
If you have two (more then one) applications which need to communicate each other, you should REGISTER your WINDOWS MESSAGE with RegisterWindowMessage.
Examples. This example uses Delphi
{ WM_USER }
procedure TYourControl.RefreshColor;
begin
SendMessage(Self.Handle,WM_USER+YourNumber,wParam,lParam);
{ Pay attention to Self.Handle, use WM_USER within YOUR CONTROL }
end;
{ WM_APP }
procedure CheckValue;
var
IResult: Integer;
begin
IResult:=SendMessage(OtherForm.Handle,WM_APP+YourConstant,wParam,lParam);
{ Watch OtherForm.Handle }
end;
{ RegisterWindowMessage }
procedure SendCommand(OtherAppHandle: Integer);
var
MessageNumber: Integer;
MessageName: ShortString;
begin
MessageName:='YourMessageName';
Inc(MessageName[0]);MessageName[Ord(MessageName[0])]:=#0;
MessageNumber:=RegisterWindowMessage(#MessageName[1]);
SendMessage(OtherAppHandle,MessageNumber,wParam,lParam);
end;
{ Hope this will help }

Related

Problems with PostMessage from C++ .dll to Delphi Forms application

I have Windows Forms Application written on Delphi 7 and C++ .dll written using MFC.
Currently I'm trying to implement basic message posting from .dll to main executable to show user calculation process on progressbar, but several problems were faced.
Let me describe my approach first. I register simple message in my Delphi application like:
WM_MSG := RegisterWindowMessage('WM_MSG');
and do the same at the library part:
UINT nMsgID = RegisterWindowMessage(_T("WM_MSG"));
This is OK: I can see same values on both sides when debugging.
My library function looks like this (just a dummy example to test progress bar):
extern "C" __declspec(dllexport) int MyFunction() {
UINT nMsgID = RegisterWindowMessage(_T("WM_MSG"));
HWND hWnd = FindWindow(NULL, "Form1");
if (hWnd > 0)
for (int i = 0; i < 100000; i++) {
int param = ceil(100 * (double) i / (double) 100000);
PostMessage(hWnd, nMsgID, param, NULL);
}
return 1;
}
Executable OnMessage event:
procedure TForm1.OnMessageEvent(var Msg: tagMSG; var Handled: Boolean);
begin
Handled := True;
if Msg.message = WM_MSG then
ProgressBar1.Position := Msg.wParam
else Handled := False;
end;
C++ function call from executable:
procedure TMyFunctionDLL.Execute;
var
i: Integer;
tHWND: HWND;
begin
tHWND := FindWindow(nil, 'mainF');
i := Func;
end;
First problem is that tHWND and hWnd variables values are inexplicably different. After some research I've discovered 3 situations:
1. Negative or positive huge hWnd
2. Zero hWnd
3. Undefined ('???')
In all cases variable hWnd is marked as unused and I don't know what does that mean. The most interesting thing is that code DOES work if I test it in very simple Delphi form (with only one unit). That simple Delphi form works well with my real C++ .dll code where real data is calculated. But when I use my general Delphi application (many units but still one form) it seems main application OnMessage event doesn't catch any events from C++ dll.
So, there are 2 questions:
1. why are hWnd values are always different and why are they 'unused'?
2. how can I force my main application to work correctly with progressbar?
I've been using different approaches to resolve this. Such as passing Application.Handle or Form1.Handle as function parameter to C++ library. None of them worked not even saying about parameter value changed while passing (I guess that should be separate question). Also I've tried using ::FindWindow() and ::PostMessage() instead of FindWindow() and PostMessage() (what is difference between them?), that didn't helped either. I'm trying to improve situtuation for whole day already but have no idea how to solve it. Help me with any ideas please.
In addition to what others have stated, a better design would be to have the EXE pass its HWND into the DLL directly, then the DLL does not have to go hunting for it. This has the added benefit that the EXE can then decide which HWND the DLL should post its messages to. I would use AllocateHWnd() to create a dedicated window for that.
Try this:
UINT nMsgID = RegisterWindowMessage(_T("WM_MSG"));
extern "C" __declspec(dllexport) int __stdcall MyFunction(HWND hWnd) {
if ((nMsgID != 0) && (hWnd != NULL)) {
for (int i = 0; i < 100000; i++) {
int param = ceil(100 * (double) i / (double) 100000);
PostMessage(hWnd, nMsgID, param, 0);
}
}
return 1;
}
.
unit Unit1;
interface
...
var
DllWnd: HWND = 0;
implementation
var
WM_MSG: UINT = 0;
procedure TForm1.FormCreate(Sender: TObject);
begin
DllWnd := AllocateHWnd(DllWndProc);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
if DllWnd <> 0 then
begin
DeallocateHWnd(DllWnd);
DllWnd := 0;
end;
end;
procedure TForm1.DllWndProc(var Message: TMessage);
begin
if (Message.Msg = WM_MSG) and (WM_MSG <> 0) then
ProgressBar1.Position := Message.WParam
else
Message.Result := DefWindowProc(DllWnd, Message.Msg, Message.WParam, Message.LParam);
end;
...
initialization
WM_MSG := RegisterWindowMessage('WM_MSG');
end.
.
uses
Unit1;
function DllFunc(Wnd: HWND): Integer; stdcall; external 'My.dll' name 'MyFunction';
procedure TMyFunctionDLL.Execute;
var
i: Integer;
begin
i := DllFunc(DllWnd);
end;
Results from FindWindow can either be zero or non-zero. Handle values don't lie on the number line. They're just distinct values, so it makes no sense to apply inequality operators to them. Put another way, handle values can appear to be negative, so don't assume that valid handles will always be greater than zero.
If the window-handle values don't match, then it's no wonder nothing else works. You're in no position to be debugging the functionality of your messages since you're not even sure you're sending them to the right window. Focus on fixing that first.
Only use FindWindow as a last resort. It has offers no facility for detecting when there are multiple windows that fit your search criteria. It always returns exactly one result. When possible, avoid searching at all. Instead, tell the sender exactly what window to send messages to. You say you tried this and failed, but I urge you to pursue that avenue some more. The problem you had was probably a mismatched calling convention. Make sure both the DLL and the host application use stdcall.
Once you're sure you're sending messages to the right window, then you can worry about why your messages aren't operating the progress bar correctly. I can see at least two reasons:
While the DLL function is running, your main program, which called the DLL, is not. It's waiting for the DLL code to return. That means your main program is not handling any messages. The DLL is posting a bunch of messages, but they're not getting handled yet. They won't get handled until the program gets back to its message loop.
The default size of the Windows message queue is 10,000. You're posting 10 times that many messages to the queue and not handling any before you stop, so even if the queue was completely empty before you started (which is unlikely, since you're probably triggering this functionality from keyboard or mouse input), you'd only get one-tenth the messages. When the queue is full, PostMessage just discards the message. And since the value you're sending with the message is an integer between 0 and 100, it's rather pointless to send 100,000 of them when only 101 of them will hold meaningful information.
If identical calls to FindWindow return different windows then you must have multiple windows with the name Form1. Try giving these different windows different names so that they can be uniquely identified.
The unused question is a little unclear. Perhaps you mean that the compiler has noticed that the value assigned to tHWND is never used and is thus pointless.
I would make a final comment that the question is imprecise and this is probably part of your problem. For example you say that all the variables are unused but we have no clear idea what you mean. You will have more success in debugging if you are more precise and methodical.
Allright, seems I've resolved the problem...
I tried Remy's proposal to declare exported function
function MyFunction (fHWND: HWND): Integer; cdecl; external 'My.dll'
with cdecl calling convention as David adviced. My previous function declaration looked like this
TMyFunction = function (fHWND: HWND): Integer;
and I suppose that was the problem. Thank you all for your help!
P.S. Now, how can I close the question?

CDockingManager GetPaneList() causes assertion failure in wincore.cpp?

So I thought this would be pretty simple, but I forgot it's MFC. Instead of registering a notification listener for data model changes that would possibly require a GUI update on each individual control I figure why not register it once and then send a message to all the open dock panes and allow them to update their controls as needed on their own terms for efficiency.
My callback function for handling the notification from the server looks something like this:
void CMainFrame::ChangeCallback(uint32_t nNewVersion, const std::vector<uint32_t>& anChangedObjectTypes)
{
CObList panes;
GetDockingManager()->GetPaneList(panes); // assert failure
if (!panes.IsEmpty())
{
POSITION pos = panes.GetHeadPosition();
while (pos)
{
CDockablePane* pPane = dynamic_cast<CDockablePane*>(panes.GetNext(pos));
if (pPane)
pPane->PostMessage(DM_REFRESH, nNewVersion);
}
}
}
The error I am getting is an assertion failure on line 926 of wincore.cpp
CHandleMap* pMap = afxMapHWND();
ASSERT(pMap != NULL); // right here
There is a comment below this saying this can happen if you pass controls across threads however this is a single threaded MFC application and this is all being done from the main frame.
Does anyone know what else can cause this?
If there is another way to go about sending a message to all the open CDockablePane derived windows in MFC that works as well ...
Here's the obvious workaround that I didn't want to have to do but after hours of debugging and no response here I guess this is a viable answer:
I added std::vector<CDockPane*> m_dockList; to the members of CMainFrame
Now after each call to AddPane in various places that can create and open new dock panes I make a subsequent call to push_back and then I override CDockablePane::OnClose like so:
CMainFrame* pMainFrame = reinterpret_cast<CMainFrame*>(AfxGetMainWnd());
if (pMainFrame)
{
std::vector<CDockPane*>::const_iterator found(
std::find(pMainFrame->DockList()->begin(), pMainFrame->DockList()->end(), this));
if (found != pMainFrame->DockList()->end())
pMainFrame->DockList()->erase(found);
}
CDockablePane::OnClose();
Now this list will only contain pointers to open dock panes which allows me to handle the event notification in my callback and simply do a for loop and PostMessage to each.

C++ subclassing a form to trap F1 - F12 keys

The main form opens a child form that has a handful of button CONTROLs on it. I need to trap keyboard events so I subclassed one of the controls. All is good until the control loses focus of course.
Ideally, as long as this child form is open I would like to assign the focus to this control and thus trap all the keystrokes, no matter where the user clicks.
I suspect superclassing might be a better way to go but I am not as familiar with it.
Perhaps what I should do is use accelerators on the main form?
ADDED:
I should mention that the main form has a large listview control that is subclassed to recover up/down arrows and mousewheel etc.
The traditional way is to install a keyboard hook (SetWindowsHookEx), but you need to inject it into every application, and it doesn't work across 32/64 bit boundaries.
What you can do however, and quite easily at that, is to poll the keyboard with GetKeyboardState on a timer and check whether your f1-f12 keys are activated. The timer can be as slow ticking as 100ms and it will catch almost everything while using virtually no resources.
Assuming that this is within Windows and the Win32 API, one option is to look for messages in your main GetMessage, TranslateMessage, DispatchMessage loop. You can special-case any message within this loop, irrespective of which window it's aimed at.
You should probably use IsChild to check that the message is intended for a control on your main window (as opposed to some dialog box or message box that might be displayed separately). Getting the logic right can be fiddly, too. It would be best to only intercept messages when you know your control has lost the focus, and only intercept the exact messages you need to.
Years ago, I wrote a library message loop with a lot of this built in. I had a simple manager class that held pointers to instances of my own little window class. The loop knew the difference between dialogs and normal windows, gave each window class a chance to spy on its childrens messages, and so on. You won't be able to run this directly and the conventions are a bit strange, but you might find this useful...
int c_Window_List::Message_Loop (void)
{
MSG msg;
bool l_Handled;
while (GetMessage (&msg, NULL, 0, 0))
{
l_Handled = false;
c_Windows::c_Cursor l_Cursor;
bool ok;
for (ok = l_Cursor.Find_First (g_Windows); ok; ok = l_Cursor.Step_Next ())
{
if (IsChild (l_Cursor.Key (), msg.hwnd))
{
if (l_Cursor.Data ().f_Accelerators != NULL)
{
l_Handled = TranslateAccelerator (l_Cursor.Key (), l_Cursor.Data ().f_Accelerators, &msg);
if (l_Handled) break;
}
if (l_Cursor.Data ().f_Manager != 0)
{
l_Handled = l_Cursor.Data ().f_Manager->Spy_Msg (l_Cursor.Key (), msg);
}
if (l_Handled) break;
if (l_Cursor.Data ().f_Is_Dialog)
{
l_Handled = IsDialogMessage (l_Cursor.Key (), &msg);
if (l_Handled) break;
}
}
}
if (!l_Handled)
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
if (g_Windows.Size () == 0)
{
// When all windows have closed, exit
PostQuitMessage (0);
}
}
return msg.wParam;
}
The f_ prefixes mean field - I picked up the m_ convention later, but this code hasn't been revisited in a very long time. f_Manager in particular points to an instance of my c_Window_Base class. The c_Cursor class is a kind of iterator, used to step through all the windows stored in the g_Windows variable (actually a static class member rather than a global).

C++/MFC: Handling multiple CListCtrl's headers HDN_ITEMCLICK events

I'm coding an MFC application in which i have a dialog box with multiple CListCtrls in report view. I want one of them to be sortable.
So i handled the HDM_ITEMCLICK event, and everything works just fine .. Except that if i click on the headers of another CListCtrl, it does sort the OTHER CListCtrl, which does look kind of dumb.
This is apparently due to the fact that headers have an ID of 0, which make the entry in the message map look like this :
ON_NOTIFY(HDN_ITEMCLICK, 0, &Ccreationprogramme::OnHdnItemclickList5)
But since all the headers have an id of zero, apparently every header of my dialog sends the message.
Is there an easy way around this problem ?
EDIT: Maybe i wasn't clear, but i did check the values inside the NMHDR structure. The HwndFrom pointer is different depending on which header is clicked, which doesn't help me a lot since it's value is obviously different at each runtime. The idFrom value is 0, for the very reasons i explained above, because that's the id of every header. Thanks
EDIT2: The hwnd pointer values do also not correspond to the CListCtrl, probably because it's coming from a different object entirely.
Check the values of the NMHDR structure.
http://msdn.microsoft.com/en-us/library/bb775514%28VS.85%29.aspx
Ok i found a solution, though i find it a bit dirty but it works, so i'll post it for future reference.
You can get the Header through the GetHeaderCtrl member function of CListCtrl. You can then get it's handler thru m_hWnd. So all you got to do is to test if that handler is the same as the one in the NMHDR structure, so the code looks like this :
void Ccreationprogramme::OnHdnItemclickList5(NMHDR *pNMHDR, LRESULT *pResult)
{
if (pNMHDR->hwndFrom == LC_gen_schedules.GetHeaderCtrl()->mhWnd)
{
// Code goes here
}
*pResult = 0;
}
Thanks all for the help
The LPARAM passed to your message handler is actually a pointer to an NMHEADER structure, which contains an NMHDR structure, which in turn contains the HWND and control ID of the control which sent the message. You may be able to compare that to your list controls' HWNDs to determine which window's header control was clicked.
Alternatively, you could derive a class from CListCtrl and reflect the HDN_ITEMCLICK messages back to the list control. That way, each list control object handles its own header's notifications.

How to handle messages from dynamically created controls in an MFC app?

Imagine I have a CDialog which creates controls dynamically when the user clicks a button. It could be like this:
// We don't know which is the first id for the new buttons until runtime (!)
MyDialog::MyDialog(/*whatever parameters needed*/, first_id)
: next_id_(first_id)
{ /*...*/ }
BOOL MyDialog::OnSomeButtonClicked()
{
CButton* new_button = new CButton;
new_button->Create("Caption", WS_CHILD | WS_VISIBLE, this->new_button_rect_,
this, this->next_id_++);
}
Then my question would be: How could I handle messages from this button? Is it possible to use the MFC message map facility?
The solution should work in both vs6 and vs2005.
Thank you!
These are the solutions I've found so far in order of relevance:
Use ON_COMMAND_RANGE if you can define the range of the control IDs you want to handle.
Overload CWnd::PreTranslateMessage() and do whatever stuff you want with the messages received. NOTE: When dealing with buttons, take into account that the BN_CLICKED event is NOT sent to PreTranslateMessage but directly sent to the window procedure.
Overload CWnd::WindowProc() and do whatever stuff you want with the messages received. NOTE that when dealing with buttons this is the ONLY WAY I've found to handle the BN_CLICKED event.
Interesting links:
Please help with PreTranslateMessage and user defined messages handling.
TN006: Message Maps
I hope this helps... thank you all for your contributions.
Eventhough you dont know the exact values of the id, if you know the possible range of IDs then the following macro can be used.
BEGIN_MESSAGE_MAP(MyDialog, CDialog)
...
...
ON_COMMAND_RANGE(1000, 5000, OnButtonDynamic)
END_MESSAGE_MAP()
void MyDialog::OnButtonDynamic(UINT nID)
{
}
This will work for ids in the range 1000 - 5000.
I'm a few years late to this party, but the solution to this is to assign the same control id to each button (no need to 'reserve' id's in resource.h, and no artificial restrictions on the amount of controls that can be created), to save the window handle and to use GetCurrentMessage() in the handler for that button:
// resource.h
#define IDC_DYNAMIC_BUTTON 123
// In message map
ON_BN_CLICKED(IDC_DYNAMIC_BUTTON, OnDynamicButtonClicked)
// Store the window handles when creating them in a member:
std::map<HWND, SomeStruct> m_Buttons;
... fill this map when creating the buttons, presumably in OnInitDialog()
// Actual handler
void MyDialog::OnDynamicButtonClicked()
{
const MSG* message = GetCurrentMessage();
if (m_Buttons.find((HWND)message->lParam) != m_Buttons.end()) {
// Do something with m_Buttons[(HWND)message->lParam]
}
}
I believe this article explains it pretty well and has source code. I have not tried this so I can't guarantee it works, but in the time I have thought it might help.
Article
You can find details (+ a lot more) on modeless dialogs there.
insert the entry of ID of the handler in Resouce.h
Then insert the entry in the message map of the handler like ON_BN_CLICKED(IDC_BTNCREATE, OnBnClickedrunCreated)
or you can directly use the integer ID like ON_BN_CLICKED(1200, OnBnClickedrunCreated). If you use 2nd version then there is
no need to insert entry in resource.h. Give defination and declaration of the handler in .h and .cpp file. you will get your answer.
Use this way: ON_CONTROL_RANGE(wNotifyCode, id1, id2, memberFxn ).
for example:
ON_CONTROL_RANGE(EN_UPDATE, IDC_EDIT_START, IDC_EDIT_END, OnEnUpdateEditParams)