{"id":107621,"date":"2022-12-28T07:00:00","date_gmt":"2022-12-28T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107621"},"modified":"2022-12-15T16:15:23","modified_gmt":"2022-12-16T00:15:23","slug":"20221228-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20221228-00\/?p=107621","title":{"rendered":"After importing a TLB, how do I convert from one type of <CODE>_com_ptr_t<\/CODE> to another?"},"content":{"rendered":"<p>The Microsoft C++ compiler has <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/preprocessor\/hash-import-directive-cpp?view=msvc-160\"> this weird feature called <code>#import<\/code><\/a>. You give it a type library (TLB) file, and it converts the type library into a C++ header file that exposes the types in the type library in a form of bunch of smart pointer types.<\/p>\n<p>The documentation on how to uses these autogenerated smart pointers is <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/cpp\/compiler-com-support?view=msvc-160\"> kind of sparse<\/a>. One thing it neglects to mention is how to convert one kind of <code>_com_ptr_t<\/code> to another. Suppose you have an <code>IWidgetPtr<\/code> (representing an <code>IWidget<\/code>) and you want to get the <code>IToggleSwitchPtr<\/code> interface from it.<\/p>\n<p>Well, we see that <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/cpp\/com-ptr-t-queryinterface?view=msvc-160\"> there is a <code>QueryInterface<\/code> method<\/a>, but it appears to produce raw pointers, not fancy <code>_com_ptr_t<\/code> pointers.<\/p>\n<p>Aha, but we can ask for the raw pointer version of a <code>_com_ptr_t<\/code>: <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/cpp\/com-ptr-t-extractors?view=msvc-160\"> Use the <code>&amp;<\/code> operator<\/a>.<\/p>\n<pre>void FlipToggleSwitch(IWidgetPtr widget)\r\n{\r\n    IToggleSwitchPtr switch;\r\n    HRESULT hr = widget.QueryInterface(__uuidof(switch), &amp;switch);\r\n    if (FAILED(hr)) _com_raise_error(hr);\r\n    switch.Flip();\r\n}\r\n<\/pre>\n<p>The parameters to the <code>QueryInterface<\/code> can be simplified (and made less error-prone) with the help of the <code>IID_PPV_ARGS<\/code> macro:<\/p>\n<pre>HRESULT hr = widget.QueryInterface(IID_PPV_ARGS(&amp;switch));\r\n<\/pre>\n<p>There&#8217;s another way, which is even easier, but also even more invisible: Use <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/cpp\/com-ptr-t-com-ptr-t?view=msvc-160\"> the conversion constructor<\/a>.<\/p>\n<pre>void FlipToggleSwitch(IWidgetPtr widget)\r\n{\r\n    IToggleSwitchPtr switch = widget; \/\/ conversion constructor!\r\n    if (!switch) _com_raise_error(E_NOINTERFACE);\r\n    switch.Flip();\r\n}\r\n<\/pre>\n<p>The conversion constructor for <code>_com_ptr_t<\/code> lets you construct any type of <code>_com_ptr_t<\/code> from any other type of <code>_com_ptr_t<\/code>. It does so by using <code>QueryInterface<\/code> to get from one interface to the other. If the source is empty (wraps a <code>nullptr<\/code>) or if the query fails with <code>E_<wbr \/>NO\u00adINTERFACE<\/code>, then the constructed object is empty. If the query fails with any other error, then a <code>_com_error<\/code> exception is thrown.\u00b9<\/p>\n<p>This conversion operator is not marked <code>explicit<\/code>, so it can be implicitly invoked. This makes it super-convenient, but also super-eager to stick its nose in places it might not belong.<\/p>\n<pre>void SetInvertedPolarity(IWidgetPtr widget);\r\n\r\nvoid PrepareGadget(IGadgetPtr gadget)\r\n{\r\n    SetInvertedPolarity(gadget); \/\/ compiles!\r\n}\r\n<\/pre>\n<p>We are passing the wrong kind of smart pointer to <code>Set\u00adInverted\u00adPolarity<\/code>, but it compiles anyway! The compiler automatically converts the <code>IGadgetPtr<\/code> to an <code>IWidgetPtr<\/code> in order to pass it to <code>Set\u00adInverted\u00adPolarity<\/code>. This is great if gadgets are deluxe versions of widgets, and you expect the conversion to succeed. This is not so great if you didn&#8217;t mean to treat the gadget as a widget, and the attempt to call <code>Set\u00adInverted\u00adPolarity<\/code> was really a mistake. Depending on how the <code>Set\u00adInverted\u00adPolarity<\/code> function works, it may throw an exception or even crash on a null pointer if you give it a null widget. The super-eager conversion constructor led you into a trap.<\/p>\n<p>The inner workings of the <code>_com_ptr_t<\/code> can be found in the header file <code>comip.h<\/code>.<\/p>\n<p>\u00b9 If you set a custom COM error handler, then the custom error handler is called.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Digging into the source code.<\/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-107621","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Digging into the source code.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107621","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=107621"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107621\/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=107621"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107621"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107621"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}