{"id":533,"date":"2014-07-10T07:00:00","date_gmt":"2014-07-10T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2014\/07\/10\/using-the-refiidvoid-pattern-for-returning-com-objects-for-future-proofing-and-to-avoid-problems-with-dependencies\/"},"modified":"2014-07-10T07:00:00","modified_gmt":"2014-07-10T07:00:00","slug":"using-the-refiidvoid-pattern-for-returning-com-objects-for-future-proofing-and-to-avoid-problems-with-dependencies","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20140710-00\/?p=533","title":{"rendered":"Using the REFIID\/void** pattern for returning COM objects for future-proofing and to avoid problems with dependencies"},"content":{"rendered":"<p>\nSuppose you have a function that creates a reference to a COM object:\n<\/p>\n<pre>\n\/\/ pixie.h\nSTDAPI CreateShellItemFromPixieDust(\n    const PIXIEDUST *ppd,\n    IShellItem **ppsi);\n<\/pre>\n<p>\nThere are a few issues with this design.\n<\/p>\n<p>\nFirst of all, it requires that whoever uses your header file\nmust have included <code>shlobj.h<\/code> first,\nsince that&#8217;s where <code>IShell&shy;Item<\/code> is defined.\nYou could solve that problem by putting\n<code>#include &lt;shlobj.h&gt;<\/code> at the top of\n<code>pixie.h<\/code>,\nbut that creates its own problems.\nFor example, many header files alter their behavior based\non symbols that have been <code>#define<\/code>d,\nand including that other header file as part of\n<code>pixie.h<\/code> means that it&#8217;s going to use the settings\nthat were active at the time <code>pixie.h<\/code> was included\n(which may not be what the clients of your header file are expecting).\nFor example:\n<\/p>\n<pre>\n#include &lt;windows.h&gt;\n#include &lt;ole2.h&gt;\n#include &lt;pixie.h&gt;\n#define <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/01\/24\/10387757.aspx\">STRICT_TYPED_ITEMIDS<\/a>\n#include &lt;shlobj.h&gt;\n<\/pre>\n<p>\nThis program wants to use strict typed item IDs,\nso it defines the magic symbol before including\n<code>shlobj.h<\/code>.\nUnfortunately, that request is ignored because\nthe <code>pixie.h<\/code> header file secretly included\n<code>shlobj.h<\/code> prematurely.\n<\/p>\n<p>\nThis can get particularly messy if somebody wants to\ninclude <code>shlobj.h<\/code> with particular preprocessor\ntricks temporarily active.\n<\/p>\n<pre>\n#include &lt;windows.h&gt;\n#include &lt;ole2.h&gt;\n#include &lt;pixie.h&gt;\n\/\/ The WINDOWDATA structure added in Windows Vista conflicts\n\/\/ with the one we defined back in 2000, so rename it to\n\/\/ WINDOWDATA_WINDOWS.\n#define WINDOWDATA WINDOWDATA_WINDOWS\n#include &lt;shlobj.h&gt;\n#undef WINDOWDATA\n\/\/ Here's our version of WINDOWDATA\n#include &lt;contosotypes.h&gt;\n<\/pre>\n<p>\nThis code works around a naming conflict that was created\nwhen Windows Vista added a structure called\n<code>WINDOW&shy;DATA<\/code> to <code>shlobj.h<\/code>.\nThe application already had a structure with the same name,\nso it has to rename the one in <code>shlobj.h<\/code> to\nsome other name to avoid a redefinition error.\n<\/p>\n<p>\nIf you made <code>pixie.h<\/code> include\n<code>shlobj.h<\/code> on its own,\nit would do so without this fancy renaming, and the\ndevelopers of that code will curse and say something like this:\n<\/p>\n<pre>\n#include &lt;windows.h&gt;\n#include &lt;ole2.h&gt;\n\/\/ The WINDOWDATA structure added in Windows Vista conflicts\n\/\/ with the one we defined back in 2000, so rename it to\n\/\/ WINDOWDATA_WINDOWS.\n#define WINDOWDATA WINDOWDATA_WINDOWS\n<font COLOR=\"blue\">\/\/ pixie.h secretly includes shlobj.h so we have to put its #include\n\/\/ under WINDOWDATA protection.\n#include &lt;pixie.h&gt;<\/font>\n#include &lt;shlobj.h&gt;\n#undef WINDOWDATA\n\/\/ Here's our version of WINDOWDATA\n#include &lt;contosotypes.h&gt;\n<\/pre>\n<p>\nAnother problem with the\n<code>Create&shy;Shell&shy;Item&shy;From&shy;Pixie&shy;Dust<\/code>\nfunction is that it hard-codes the output interface to\n<code>IShell&shy;Item<\/code>.\nWhen everybody moves on to\n<code>IShell&shy;Item2<\/code>,\nall the callers will have to\nfollow the\n<code>Create&shy;Shell&shy;Item&shy;From&shy;Pixie&shy;Dust<\/code>\ncall with a <code>Query&shy;Interface<\/code> to get the interface\nthey really want.\n(Which, if your object is out-of-process,\ncould mean another round trip to the server.)\n<\/p>\n<p>\nThe solution to both of these problems is to simply make the\ncaller specify what type of object they want.\n<\/p>\n<pre>\n\/\/ pixie.h\nSTDAPI CreateShellItemFromPixieDust(\n    const PIXIEDUST *ppd,\n    REFIID riid,\n    void **ppv);\n<\/pre>\n<p>\nNow that we are no longer mentioning\n<code>IShell&shy;Item<\/code> explicitly,\nwe don&#8217;t need to include <code>shlobj.h<\/code> any more.\nAnd if the caller wants <code>IShell&shy;Item2<\/code>,\nthey can just ask for it.\n<\/p>\n<p>\nYour creation function used to look like this:\n<\/p>\n<pre>\nSTDAPI CreateShellItemFromPixieDust(\n    const PIXIEDUST *ppd,\n    IShellItem **ppsi)\n{\n    *ppsi = nullptr;\n    IShellItem *psiResult;\n    HRESULT hr = ... do whatever ...;\n    if (SUCCEEDED(hr))\n    {\n       *ppsi = psiResult;\n    }\n    return hr;\n}\n<\/pre>\n<p>\nYou simply have to tweak the way you return the pointer:\n<\/p>\n<pre>\nSTDAPI CreateShellItemFromPixieDust(\n    const PIXIEDUST *ppd,\n    <font COLOR=\"blue\">REFIID riid,\n    void **ppv<\/font>)\n{\n    *ppv = nullptr;\n    IShellItem *psiResult;\n    HRESULT hr = ... do whatever ...;\n    if (SUCCEEDED(hr))\n    {\n       <font COLOR=\"blue\">hr = psiResult-&gt;QueryInterface(riid, ppv);\n       psiResult-&gt;Release();<\/font>\n    }\n    return hr;\n}\n<\/pre>\n<p>\nCallers of your function would go from\n<\/p>\n<pre>\nIShellItem *psi;\nhr = CreateShellItemFromPixieDust(ppd, &amp;psi);\n<\/pre>\n<p>\nto\n<\/p>\n<pre>\nIShellItem *psi;\nhr = CreateShellItemFromPixieDust(ppd, <font COLOR=\"blue\">IID_PPV_ARGS(&amp;psi)<\/font>);\n<\/pre>\n<p>\nIf the caller decides that they really want an\n<code>IShell&shy;Item2<\/code>,\nthey merely have to change their variable declaration;\nthe call to the creation function is unchanged.\n<\/p>\n<pre>\n<font COLOR=\"blue\">IShellItem2 *psi;<\/font>\nhr = CreateShellItemFromPixieDust(ppd, IID_PPV_ARGS(&amp;psi));\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Suppose you have a function that creates a reference to a COM object: \/\/ pixie.h STDAPI CreateShellItemFromPixieDust( const PIXIEDUST *ppd, IShellItem **ppsi); There are a few issues with this design. First of all, it requires that whoever uses your header file must have included shlobj.h first, since that&#8217;s where IShell&shy;Item is defined. You could solve [&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-533","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Suppose you have a function that creates a reference to a COM object: \/\/ pixie.h STDAPI CreateShellItemFromPixieDust( const PIXIEDUST *ppd, IShellItem **ppsi); There are a few issues with this design. First of all, it requires that whoever uses your header file must have included shlobj.h first, since that&#8217;s where IShell&shy;Item is defined. You could solve [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/533","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=533"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/533\/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=533"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=533"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=533"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}