{"id":100625,"date":"2019-01-03T07:00:00","date_gmt":"2019-01-03T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=100625"},"modified":"2019-03-13T00:02:17","modified_gmt":"2019-03-13T07:02:17","slug":"20190103-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190103-00\/?p=100625\/","title":{"rendered":"Why am I getting mojibake when I try to create a shell link?"},"content":{"rendered":"<p>A customer couldn&#8217;t get the <code>IShellLink<\/code> interface to work. They tried to set the shortcut target to a path, but it came out as <a HREF=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/\">Chinese mojibake<\/a>. <\/p>\n<p>Here&#8217;s a <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20131018-00\/?p=2893\">reduction<\/a> of their code to its simplest form. <\/p>\n<pre>\nHRESULT CreateLink()\n{\n  HRESULT hr;\n  IShellLinkA* psl;\n\n  hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,\n                        IID_IShellLink, (LPVOID*)&amp;psl);\n  if (SUCCEEDED(hr)) {\n    IPersistFile* ppf;\n\n    psl-&gt;SetPath(\"C:\\\\Windows\"); \/\/ this comes out as mojibake\n\n    hr = psl-&gt;QueryInterface(IID_IPersistFile, (LPVOID*)&amp;ppf);\n    if (SUCCEEDED(hr)) {\n      hr = ppf-&gt;Save(L\"C:\\\\Test\\\\Test.lnk\", TRUE);\n      ppf-&gt;Release();\n    }\n    psl-&gt;Release();\n  }\n  return hr;\n}\n<\/pre>\n<p>(You can see that this customer used to be a C programmer, because all variable declarations are at the start of blocks. Also, because they aren&#8217;t using RAII.) <\/p>\n<p>The problem is hidden in the call to <code>Co&shy;Create&shy;Instance<\/code>: <\/p>\n<pre>\n  hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,\n                        IID_IShellLink, (LPVOID*)&amp;psl);\n  \/\/                    --------------  -------------\n<\/pre>\n<p>Observe that the requested interface is <code>IID_<\/code><code>IShell&shy;Link<\/code>, but the result is placed into a pointer to <code>IShell&shy;LinkA<\/code>. This mismatch should raise a warning flag. <\/p>\n<p>It appears that the program is being compiled with Unicode as the default character set, which means that <code>IID_<\/code><code>IShell&shy;Link<\/code> is really <code>IID_<\/code><code>IShell&shy;LinkW<\/code>. Consequently, the requested interface is <code>IShell&shy;LinkW<\/code>, and the result is placed into a pointer to <code>IShell&shy;LinkA<\/code>. As a result of this mismatch, the call to <code>psl-&gt;SetPath<\/code> thinks that it&#8217;s calling <code>IShell&shy;LinkA::<\/code><code>Set&shy;Path<\/code>, but in reality it is calling <code>IShell&shy;LinkW::<\/code><code>Set&shy;Path<\/code>. (The <code>IShell&shy;LinkA<\/code> and <code>IShell&shy;LinkW<\/code> interfaces have the same methods in the same order, except that one uses ANSI strings and the other uses Unicode strings.) <\/p>\n<p>That is where the mojibake is coming from. An ANSI string is passed where a Unicode string is expected. <\/p>\n<p>Mismatches like this can be avoided by using the <code>IID_<\/code><code>PPV_<\/code><code>ARGS<\/code> macro. This macro looks at the type of the pointer you pass it and autogenerates the matching <code>REFIID<\/code>, as well as casting the pointer to <code>void**<\/code>. <\/p>\n<pre>\n  hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,\n                        <font COLOR=\"blue\">IID_PPV_ARGS(&amp;psl)<\/font>);\n<\/pre>\n<p>While they&#8217;re at it, the customer should consider abandoning the ANSI version altogether and just using the Unicode one. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Make sure the thing you ask for is the thing you want.<\/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-100625","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Make sure the thing you ask for is the thing you want.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/100625","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=100625"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/100625\/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=100625"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=100625"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=100625"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}