{"id":103362,"date":"2020-01-24T07:00:00","date_gmt":"2020-01-24T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103362"},"modified":"2020-01-23T18:43:55","modified_gmt":"2020-01-24T02:43:55","slug":"20200124-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200124-00\/?p=103362","title":{"rendered":"Peeking inside C++\/CX delegates"},"content":{"rendered":"<p>Let&#8217;s hope you never need to do this, but if you are forced to debug code written in C++\/CX, and you have a C++\/CX delegate and want to know what it is, well, here goes.<\/p>\n<pre>0:005&gt; dps 0x00000295`0d3a0ab0\r\n00000295`0d3a0ab0  00007ff9`c0238fd8 contoso!RoutedEventHandler::`vftable'\r\n00000295`0d3a0ab8  00007ff9`c0238f98 contoso!RoutedEventHandler::`vftable'\r\n00000295`0d3a0ac0  00007ff9`c0238f68 contoso!RoutedEventHandler::`vftable'\r\n00000295`0d3a0ac8  00000295`7d9f8ee0\r\n00000295`0d3a0ad0  ffffffff`ffffffff\r\n00000295`0d3a0ad8  00007ff9`c0252f08 contoso!`RoutedEventHandler&lt;Widget,\r\n                                      void (Widget::*)(Object ^,RoutedEventArgs ^)&gt;'::\r\n                                      `2'::__abi_PointerToMemberWeakRefCapture::`vftable'\r\n00000295`0d3a0ae0  00000295`469826e0\r\n00000295`0d3a0ae8  00007ff9`bfff2e80 contoso!Widget::OnColorChanged\r\n<\/pre>\n<p>The object starts with some vtables and other bookkeeping. But the interesting thing is the next vtable, because that one tells you what kind of delegate you have.<\/p>\n<p>In this case, it&#8217;s a vtable for a &#8220;pointer to member weak ref capture&#8221;, which tells us that our delegate is a weak pointer plus a pointer to member function.<\/p>\n<p>The next two pointers are the weak reference and the member function pointer.<\/p>\n<p>Most C++\/CX delegates are of the &#8220;weak pointer plus method pointer&#8221; variety, but the other flavor is the &#8220;functor&#8221;, where the handler is an arbitrary object that supports the function call operator.<\/p>\n<p>For example, a delegate that refers to a static method looks like this:<\/p>\n<pre>0:000&gt; dps 08062190\r\n08062190  0116a2f4 contoso!RoutedEventHandler::`vftable'\r\n08062194  0116a310 contoso!RoutedEventHandler::`vftable'\r\n08062198  0116a334 contoso!RoutedEventHandler::`vftable'\r\n0806219c  08068a10\r\n080621a0  ffffffff\r\n080621a4  0116a378 contoso!__abi_FunctorCapture&lt;\r\n                   void (__cdecl*)(Object ^,RoutedEventArgs ^),\r\n                   void,\r\n                   Object ^,\r\n                   RoutedEventArgs ^&gt;::`vftable'\r\n080621a8  00f9371c contoso!OnColorChanged\r\n<\/pre>\n<p>The vtable in position 5 says that this is a functor that captured a plain old function pointer, and the plain old function pointer comes immediately after: It&#8217;s <code>contoso!OnColorChanged<\/code>.<\/p>\n<p>For a class that supports the function call operator, you get a customized function for that class. In this example, the class is a lambda:<\/p>\n<pre>08062240  0116a2f4 contoso!RoutedEventHandler::`vftable'\r\n08062244  0116a310 contoso!RoutedEventHandler::`vftable'\r\n08062248  0116a334 contoso!RoutedEventHandler::`vftable'\r\n0806224c  080689b0\r\n08062250  ffffffff\r\n08062254  0116a388 contoso!__abi_FunctorCapture&lt;\r\n                   &lt;lambda_484c5c4112f278281e0294b32780c5b6&gt;,\r\n                   void,\r\n                   Object ^,\r\n                   RoutedEventArgs ^&gt;::`vftable'\r\n08062258  08053480 \/\/ lambda contents start here\r\n0806225c  00000000\r\n<\/pre>\n<p>If the lambda is large (bigger than than 16 pointers), then it is stored in a separate memory allocation. You can find a pointer to the wrapper for the captured lambda 16 pointers later:<\/p>\n<pre>07a2c2f0  00e57324 contoso!RoutedEventHandler::`vftable'\r\n07a2c2f4  00e57340 contoso!RoutedEventHandler::`vftable'\r\n07a2c2f8  00e57364 contoso!RoutedEventHandler::`vftable'\r\n07a2c2fc  07a36278\r\n07a2c300  ffffffff\r\n07a2c304  00000000 (unused slot 0)\r\n07a2c308  00000000 (unused slot 1)\r\n07a2c30c  00000000 (unused slot 2)\r\n07a2c310  00000000 (unused slot 3)\r\n07a2c314  00000000 (unused slot 4)\r\n07a2c318  00000000 (unused slot 5)\r\n07a2c31c  00000000 (unused slot 6)\r\n07a2c320  00000000 (unused slot 7)\r\n07a2c324  00000000 (unused slot 8)\r\n07a2c328  00000000 (unused slot 9)\r\n07a2c32c  00000000 (unused slot 10)\r\n07a2c330  00000000 (unused slot 11)\r\n07a2c334  00000000 (unused slot 12)\r\n07a2c338  00000000 (unused slot 13)\r\n07a2c33c  00000000 (unused slot 14)\r\n07a2c340  00000000 (unused slot 15)\r\n07a2c344  01212a48 \/\/ pointer to functor\r\n\r\n01212a48  00e57388 contoso!__abi_FunctorCapture&lt;\r\n                   &lt;lambda_51d3f9ef4e98c0ae34c7116adc4d714e&gt;,\r\n                   void,\r\n                   Object ^,\r\n                   RoutedEventArgs ^&gt;::`vftable'\r\n01212a4c  07a1f3d0 \/\/ lambda contents start here\r\n01212a50  00000000\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>If you ever have to debug one of these things.<\/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-103362","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>If you ever have to debug one of these things.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103362","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=103362"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103362\/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=103362"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103362"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103362"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}