{"id":1963,"date":"2014-01-27T07:00:00","date_gmt":"2014-01-27T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2014\/01\/27\/how-can-i-make-a-callback-function-a-member-of-my-c-class\/"},"modified":"2014-01-27T07:00:00","modified_gmt":"2014-01-27T07:00:00","slug":"how-can-i-make-a-callback-function-a-member-of-my-c-class","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20140127-00\/?p=1963","title":{"rendered":"How can I make a callback function a member of my C++ class?"},"content":{"rendered":"<p>\nInstead of a Little Program today, I&#8217;m going to answer a Little Question.\nThis is a common beginner question,\nbut I figure I&#8217;ll just spell it out right here for posterity.\n<\/p>\n<p>\nFirst of all, you probably noticed that you can&#8217;t do this:\n<\/p>\n<pre>\n<i>class CountWindows\n{\npublic:\n  int CountThem();\nprivate:\n  BOOL CALLBACK WndEnumProc(HWND hwnd, LPARAM lParam);\n  int m_count;\n};\nBOOL CountWindows::WndEnumProc(HWND hwnd, LPARAM lParam)\n{\n   m_count++;\n   return TRUE;\n}\nint CountWindows::CountThem()\n{\n  m_count = 0;\n  EnumWindows(WndEnumProc, 0); \/\/ compiler error here\n  return m_count;\n}\n<\/i><\/pre>\n<p>\nThat&#8217;s because the <code>WNDENUMPROC<\/code>\nis declared as a so-called <i>free function<\/i>,\nbut member functions are not free.\nNeither are <i>function objects<\/i> (also known as\n<i>functors<\/i>)\nso you can&#8217;t use a\n<code>boost::function<\/code> as a window procedure either.\nThe reason is that member functions and functors need to have\na hidden <code>this<\/code> parameter,\nbut free functions do not have a hidden <code>this<\/code> parameter.\n<\/p>\n<p>\nOn the other hand, static methods are free functions.\nThey can get away with it because they don&#8217;t have\na hidden <code>this<\/code> parameter either.\n<\/p>\n<p>\nWin32 has a general principle that\ncallback functions have a special parameter where you can\npass any information you like\n(known as <i>context<\/i> or <i>reference data<\/i>),\nand that same value is passed back to your callback function\nso it knows what&#8217;s going on.\nIn practice, most people will pass a pointer to a\nclass or structure.\n<\/p>\n<p>\nIn other words, the reference data parameter makes explicit\nwhat C++ hides (the <code>this<\/code> parameter).\n<\/p>\n<pre>\nclass CountWindows\n{\npublic:\n  int CountThem();\nprivate:\n  <font COLOR=\"blue\">static<\/font> BOOL CALLBACK <font COLOR=\"blue\">Static<\/font>WndEnumProc(HWND hwnd, LPARAM lParam);\n  int m_count;\n};\nBOOL CountWindows::<font COLOR=\"blue\">Static<\/font>WndEnumProc(HWND hwnd, LPARAM lParam)\n{\n   <font COLOR=\"blue\">CountWindows *pThis = reinterpret_cast&lt;CountWindows *&gt;(lParam);<\/font>\n   <font COLOR=\"blue\">pThis-&gt;<\/font>m_count++;\n   return TRUE;\n}\nint CountWindows::CountThem()\n{\n  m_count = 0;\n  EnumWindows(<font COLOR=\"blue\">Static<\/font>WndEnumProc, <font COLOR=\"blue\">reinterpret_cast&lt;LPARAM&gt;(this)<\/font>);\n  return m_count;\n}\n<\/pre>\n<p>\nWhat we did was pass our <code>this<\/code> parameter explicitly\nas the reference data to the <code>Enum&shy;Windows<\/code> function,\nand then in the callback, cast the reference data back to <code>this<\/code>\nso that we can use it to access our member variables.\n<\/p>\n<p>\nIf the <code>Wnd&shy;Enum&shy;Proc<\/code> is long,\nthen it can get tedious typing <code>pThis-&gt;<\/code> in front\nof everything,\nso a common follow-up technique is to make the static member\nfunction a wrapper that calls a normal member function.\n<\/p>\n<pre>\nclass CountWindows\n{\npublic:\n  int CountThem();\nprivate:\n  static BOOL CALLBACK StaticWndEnumProc(HWND hwnd, LPARAM lParam);\n  <font COLOR=\"blue\">BOOL WndEnumProc(HWND hwnd);<\/font>\n  int m_count;\n};\nBOOL CountWindows::StaticWndEnumProc(HWND hwnd, LPARAM lParam)\n{\n   CountWindows *pThis = reinterpret_cast&lt;CountWindows* &gt;(lParam);\n   <font COLOR=\"blue\">return pThis-&gt;WndEnumProc(hwnd);<\/font>\n}\n<font COLOR=\"blue\">BOOL CountWindows::WndEnumProc(HWND hwnd)\n{\n    m_count++;\n    return TRUE;\n}<\/font>\nint CountWindows::CountThem()\n{\n  m_count = 0;\n  EnumWindows(StaticWndEnumProc, reinterpret_cast&lt;LPARAM&gt;(this));\n  return m_count;\n}\n<\/pre>\n<p>\nObserve that by putting all the real work inside the\ntraditional member function\n<code>Count&shy;Windows::Wnd&shy;Enum&shy;Proc<\/code>,\nwe avoid having to type <code>pThis-&gt;<\/code> in front of\neverything.\n<\/p>\n<p>\nThis principle of using reference data to pass context\nthrough a callback is very common in Windows programming.\nWe&#8217;ll see a few more examples in the future,\nbut I&#8217;m not going to jam all the beginner articles in a row\nbecause that would bore my regular readers.\n<\/p>\n<p>\n<b>Historical note<\/b>:\nThe term <i>reference data<\/i> was used in 16-bit Windows,\nbut the Windows&nbsp;NT folks preferred to use the term\n<i>context<\/i>.\nYou can tell which team introduced a particular callback\nfunction by seeing what they call that extra parameter.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Instead of a Little Program today, I&#8217;m going to answer a Little Question. This is a common beginner question, but I figure I&#8217;ll just spell it out right here for posterity. First of all, you probably noticed that you can&#8217;t do this: class CountWindows { public: int CountThem(); private: BOOL CALLBACK WndEnumProc(HWND hwnd, LPARAM lParam); [&hellip;]<\/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-1963","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Instead of a Little Program today, I&#8217;m going to answer a Little Question. This is a common beginner question, but I figure I&#8217;ll just spell it out right here for posterity. First of all, you probably noticed that you can&#8217;t do this: class CountWindows { public: int CountThem(); private: BOOL CALLBACK WndEnumProc(HWND hwnd, LPARAM lParam); [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/1963","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=1963"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/1963\/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=1963"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=1963"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=1963"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}