{"id":2233,"date":"2013-12-30T07:00:00","date_gmt":"2013-12-30T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/12\/30\/how-can-i-get-the-list-of-programs-the-same-way-that-programs-and-features-gets-it\/"},"modified":"2013-12-30T07:00:00","modified_gmt":"2013-12-30T07:00:00","slug":"how-can-i-get-the-list-of-programs-the-same-way-that-programs-and-features-gets-it","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20131230-00\/?p=2233","title":{"rendered":"How can I get the list of programs the same way that Programs and Features gets it?"},"content":{"rendered":"<p>\nA customer wanted to get the list of programs the same way that\nthe\nPrograms and Features folder gets it.\n<\/p>\n<p>\nHere, here&#8217;s an idea:\nInstead of trying to mimic the Programs and Features folder,\njust ask the Programs and Features folder for its contents!\nThat way, no matter what changes are made to how the\nPrograms and Features folder obtains its contents\n(and those changes occur pretty often),\nyour program will always match it,\nbecause you&#8217;re just showing the same thing.\n<\/p>\n<p>\nHere&#8217;s the basic idea, in scripting language since it&#8217;s quicker:<\/p>\n<pre>\nvar shell = new ActiveXObject(\"Shell.Application\");\nvar programsFolder = shell.Namespace(\n    \"::{26EE0668-A00A-44D7-9371-BEB064C98683}\\\\8\\\\\" +\n    \"::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}\");\nvar items = programsFolder.Items();\nfor (var i = 0; i &lt; items.Count; i++) {\n    var item = items.Item(i);\n    WScript.StdOut.WriteLine(item);\n    WScript.StdOut.WriteLine(\"Size = \" + item.ExtendedProperty(\"System.Size\"));\n    WScript.StdOut.WriteLine(\"------------\");\n}\n<\/pre>\n<p>\nOkay, first of all, how did I get that magic string\nfor the Programs and Features folder?\nI opened the Control Panel\nand dragged the <i>Uninstall a program<\/i>\nlink onto\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/02\/04\/10390725.aspx\">\nthe program from a few weeks ago<\/a>.\n<\/p>\n<p>\nThe program itself is pretty straightforward.\nIt&#8217;s the standard\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/01\/14\/10384593.aspx\">\n<i>enumerate everything in a folder and print it<\/i><\/a>\nprogram we&#8217;ve seen before.\nThe only trick was finding the folder.\n<\/p>\n<p>\nAs for the C++ version, it should also look familiar, because\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/08\/31\/10203215.aspx\">\nwe&#8217;ve done it before<\/a>\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/01\/28\/10388715.aspx\">\nmore than once<\/a>.\nThe only difference is the way we create the folder\nand the details we choose to display.\n(For extra credit:\nChange this program to\nbind to the persisted pidl instead of the parsing name.)\n<\/p>\n<pre>\nint __cdecl wmain(int argc, wchar_t **argv)\n{\n <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/05\/20\/135841.aspx\">CCoInitialize<\/a> init;\n CComPtr&lt;IShellItem&gt; spPrinters;\n <font COLOR=\"blue\"><a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/bb762134%28v=vs.85%29.aspx\">SHCreateItemFromParsingName<\/a>(\n   L\"::{26EE0668-A00A-44D7-9371-BEB064C98683}\\\\8\\\\\"\n   L\"::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}\",<\/font> nullptr,\n   IID_PPV_ARGS(&amp;spPrograms));\n CComPtr&lt;IEnumShellItems&gt; spEnum;\n spPrograms-&gt;BindToHandler(nullptr, BHID_EnumItems,\n                              IID_PPV_ARGS(&amp;spEnum));\n for (CComPtr&lt;IShellItem&gt; spProgram;\n      spEnum-&gt;Next(1, &amp;spProgram, nullptr) == S_OK;\n      spProgram.Release()) {\n  CComHeapPtr&lt;wchar_t&gt; spszName;\n  spProgram-&gt;GetDisplayName(SIGDN_NORMALDISPLAY, &amp;spszName);\n  wprintf(L\"%ls\\n\", spszName);\n  <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/08\/31\/10203215.aspx\">PrintDetail<\/a>(CComQIPtr&lt;IShellItem2&gt;(spProgram), &amp;PKEY_Size, L\"Size\");<\/font>\n }\n return 0;\n}\n<\/pre>\n<p>\nBonus script:\nYou can even see what verbs are available.\n<\/p>\n<pre>\nvar shell = new ActiveXObject(\"Shell.Application\");\nvar programsFolder = shell.Namespace(\n    \"::{26EE0668-A00A-44D7-9371-BEB064C98683}\\\\8\\\\\" +\n    \"::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}\");\nvar items = programsFolder.Items();\nfor (var i = 0; i &lt; items.Count; i++) {\n    var item = items.Item(i);\n    WScript.StdOut.WriteLine(item);\n    WScript.StdOut.WriteLine(\"Size = \" + item.ExtendedProperty(\"System.Size\"));\n    <font COLOR=\"blue\">var verbs = item.Verbs();\n    for (var j = 0; j &lt; verbs.Count; j++) {\n       var verb = verbs.Item(j);\n       WScript.StdOut.WriteLine(\"Action: \" + verb.Name);\n    }<\/font>\n    WScript.StdOut.WriteLine(\"------------\");\n}\n<\/pre>\n<p>\nAnd if you&#8217;re really ambitious,\nyou can even call\n<code>verb.DoIt<\/code> to carry out the action.\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2007\/03\/20\/1915586.aspx\">\nDon&#8217;t use this power for evil<\/a>.\n<\/p>\n<p>\n<b>Note<\/b>:\nSince we are working with the\nPrograms and Features folder,\nwe are necessarily targeting Windows Vista and later,\nsince that was the version of Windows in which the\nPrograms and Features folder was introduced.\nTherefore, I am free to use\nfunctionality introduced in Windows Vista.\n<\/p>\n<p>\nI&#8217;ve been doing Little Programs for a year now.\nI kind of like it,\nso I&#8217;m going to continue for another year,\nbut I&#8217;m going to relax the rules a bit:\nThe Little Programs are now just programs that I think\nare interesting for whatever reason.\nThey don&#8217;t need to actually solve a problem.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A customer wanted to get the list of programs the same way that the Programs and Features folder gets it. Here, here&#8217;s an idea: Instead of trying to mimic the Programs and Features folder, just ask the Programs and Features folder for its contents! That way, no matter what changes are made to how the [&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-2233","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A customer wanted to get the list of programs the same way that the Programs and Features folder gets it. Here, here&#8217;s an idea: Instead of trying to mimic the Programs and Features folder, just ask the Programs and Features folder for its contents! That way, no matter what changes are made to how the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/2233","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=2233"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/2233\/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=2233"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=2233"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=2233"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}