{"id":109174,"date":"2023-12-21T07:00:00","date_gmt":"2023-12-21T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109174"},"modified":"2023-12-21T09:17:46","modified_gmt":"2023-12-21T17:17:46","slug":"20231221-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231221-00\/?p=109174","title":{"rendered":"How do I get access to the <CODE>wParam<\/CODE> and <CODE>lParam<\/CODE> of the <CODE>WM_<WBR>QUERY&shy;END&shy;SESSION<\/CODE> method from my MFC message handler?"},"content":{"rendered":"<p>The Microsoft Foundation Classes (MFC) framework provides a set of macros for building message handler tables. The handler for the <code>WM_<wbr \/>QUERY\u00adEND\u00adSESSION<\/code> message has the signature<\/p>\n<pre>BOOL OnQueryEndSession();\r\n<\/pre>\n<p>and it does not have access to the <code>wParam<\/code> and <code>lParam<\/code> parameters.\u00b9 How can you get the values of those parameters?<\/p>\n<p>Don&#8217;t be afraid to learn how things work. That often leads to insights on how to use them better.<\/p>\n<p>In our case, <code>ON_<wbr \/>WM_<wbr \/>QUERY\u00adEND\u00adSESSION<\/code> goes like this:<\/p>\n<pre>#define ON_WM_QUERYENDESSION() \\\r\n    { WM_QUERYENDSESSION, 0, 0, 0, AfxSig_bv, \\\r\n        (AFX_PMSG)(AFX_PMSGW)(BOOL (AFX_MSG_CALL CWnd::*)(void))\r\n        &amp;OnQueryEndSession },\r\n<\/pre>\n<p>If you read the comment block at the top of the file, it says that message map entries can take many forms, including<\/p>\n<pre>7) constant windows messages\r\n    nMessage, 0, 0, 0, signature type, member function\r\n    (eg: WM_PAINT, 0, ...)\r\n<\/pre>\n<p>From the structure of the table and the pattern of the macros, and the internal documentation, it&#8217;s apparent that the message map is a table of message number and instructions on how to handle the message. The signature <code>AfxSig_bv<\/code> is documented in the header file as<\/p>\n<pre>    Afx_bv = Afx_wv,    \/\/ BOOL (void)\r\n<\/pre>\n<p>Apparently, what happens is that the message dispatcher looks through the table for a matching message number, and once it finds a match, it calls the associated function using the specified signature, and then returns the result as the message result.<\/p>\n<p>We can therefore just create our own entry for <code>WM_<wbr \/>QUERY\u00adEND\u00adSESSION<\/code> that uses a different signature. And it turns out that the <code>ON_<wbr \/>MESSAGE<\/code> macro exists specifically for generic messages:<\/p>\n<pre>#define ON_MESSAGE(message, memberFxn) \\\r\n    { message, 0, 0, 0, AfxSig_lwl, \\\r\n        (AFX_PMSG)(AFX_PMSGW)(BOOL (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM))\r\n        &amp;memberFxn },\r\n<\/pre>\n<p>Solution: Treat <code>WM_<wbr \/>QUERY\u00adEND\u00adSESSION<\/code> as a custom message:<\/p>\n<pre>    ON_MESSAGE(WM_QUERYENDSESSION, OnQueryEndSession)\r\n\r\n    LRESULT AFX_MSG_CALL OnQueryEndSession(WPARAM wParam, LPARAM lParam);\r\n<\/pre>\n<p><b>Bonus chatter<\/b>: There apparently used to be a <code>CWnd::GetCurrentMessage()<\/code> function for getting a copy of the current message being handled by MFC. (I don&#8217;t know this for sure, but I see references to it.) It doesn&#8217;t exist anymore (or maybe never existed), so it&#8217;s not really an option.<\/p>\n<p>\u00b9 The reason is that at the time that MFC was written, there was no information encoded in those parameters.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Don&#8217;t be afraid to see how the macros are built.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-109174","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Don&#8217;t be afraid to see how the macros are built.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109174","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=109174"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109174\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=109174"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109174"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109174"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}