{"id":111332,"date":"2025-07-02T07:00:00","date_gmt":"2025-07-02T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111332"},"modified":"2025-07-02T09:09:45","modified_gmt":"2025-07-02T16:09:45","slug":"20250702-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250702-00\/?p=111332","title":{"rendered":"Unintended yet somehow entirely expected consequences of marking a COM interface as local"},"content":{"rendered":"<p>A customer was adding an interface to their out-of-process COM server. They added their interface to the project&#8217;s existing IDL file and recompiled the resulting proxy stub DLL. But when they tried to connect to the server, the connection failed with error <code>0x80040155<\/code>, also known as <code>REGDB_<wbr \/>E_<wbr \/>IID\u00adNOT\u00adREG<\/code>: Interface not registered.<\/p>\n<p>They realized that they forgot to register the interface&#8217;s proxy, so they added an entry to <tt>[HKCR\\<wbr \/>Interface\\<wbr \/>{<span style=\"border: solid 1px currentcolor;\">iid<\/span>}\\<wbr \/><a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/com\/proxystubclsid32\">ProxyStubClsid32<\/a>]<\/tt> so that COM knew where to find the proxy stub. (They didn&#8217;t have to create a new CLSID entry for the proxy DLL because they were adding an interface to their existing IDL, so the proxy DLL was itself already registered by whoever set up that IDL file initially.)<\/p>\n<p>Upon trying again, the connection still failed. This time with the error <code>0x80004002<\/code>, the often-encountered <code>E_<wbr \/>NO\u00adINTERFACE<\/code>: No such interface supported.<\/p>\n<p>We learned that <a title=\"Why do I get E_NOINTERFACE when creating an object that supports that interface?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20041213-00\/?p=37043\"> one cause of this is a missing marshaler<\/a>.<\/p>\n<p>&#8220;But that doesn&#8217;t apply in this case, because I registered the interface and pointed it to the proxy DLL that holds the marshaler!&#8221;<\/p>\n<p>Does that proxy DLL hold the marshaler?<\/p>\n<p>We looked at the interface declaration.<\/p>\n<pre>[\r\n    object,\r\n    <span style=\"border: solid 1px currentcolor;\">local<\/span>,\r\n    uuid(iid)\r\n]\r\ninterface IWidgetFactory : IUnknown\r\n{\r\n    \u27e6 ... \u27e7\r\n}\r\n<\/pre>\n<p>The interface is marked as <code>local<\/code>. A local interface is one that never leaves its home apartment and therefore never needs to be marshalled. The IDL compiler does not generate marshallers for local interface because they would never be needed.<\/p>\n<p>I don&#8217;t know the history here. It&#8217;s possible that this interface started out as local because it was originally designed as an in-apartment object, but then the team decided to move the widget factory out of process (which now requires a marshaller) and forgot to remove the <code>local<\/code> attribute.<\/p>\n<p>Or maybe the <code>local<\/code> was just a copy-pasta from elsewhere in the IDL file that they forgot to remove. (Or they didn&#8217;t realize what it meant.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If it&#8217;s local-only, then it can&#8217;t be remote.<\/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-111332","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>If it&#8217;s local-only, then it can&#8217;t be remote.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111332","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=111332"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111332\/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=111332"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111332"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111332"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}