The Old New Thing's Journal
 
[Most Recent Entries] [Calendar View] [Friends View]

Monday, December 30th, 2013

    Time Event
    3:00p
    There's no seating up there, so you just have to hang on for dear life

    I dreamed that through a friend, I got to join a handful of other people atop Prince Charles's carriage as it wound its way through London. There was no seating up there, so you just have to hang on for dear life. When we reached Buckingham Palace, the assembled crowd and reporters swarmed the carriage for an opportunity to meet the Prince. This provided a sufficient diversion to allow us to climb down from the roof and sneak into the palace undetected.

    We've come to the end of the year, so that's all for Monday dream blogging. For those of you who hated it: You can uncover your eyes now.

    3:00p
    How can I get the list of programs the same way that Programs and Features gets it?

    A customer wanted to get the list of programs the same way that the Programs and Features folder gets it.

    Here, here'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 Programs and Features folder obtains its contents (and those changes occur pretty often), your program will always match it, because you're just showing the same thing.

    Here's the basic idea, in scripting language since it's quicker:

    var shell = new ActiveXObject("Shell.Application");
    var programsFolder = shell.Namespace(
        "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\8\\" +
        "::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}");
    var items = programsFolder.Items();
    for (var i = 0; i < items.Count; i++) {
        var item = items.Item(i);
        WScript.StdOut.WriteLine(item);
        WScript.StdOut.WriteLine("Size = " + item.ExtendedProperty("System.Size"));
        WScript.StdOut.WriteLine("------------");
    }
    

    Okay, first of all, how did I get that magic string for the Programs and Features folder? I opened the Control Panel and dragged the Uninstall a program link onto the program from a few weeks ago.

    The program itself is pretty straightforward. It's the standard enumerate everything in a folder and print it program we've seen before. The only trick was finding the folder.

    As for the C++ version, it should also look familiar, because we've done it before more than once. The only difference is the way we create the folder and the details we choose to display. (For extra credit: Change this program to bind to the persisted pidl instead of the parsing name.)

    int __cdecl wmain(int argc, wchar_t **argv)
    {
     CCoInitialize init;
     CComPtr<IShellItem> spPrinters;
     SHCreateItemFromParsingName(
       L"::{26EE0668-A00A-44D7-9371-BEB064C98683}\\8\\"
       L"::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}", nullptr,
       IID_PPV_ARGS(&spPrograms));
     CComPtr<IEnumShellItems> spEnum;
     spPrograms->BindToHandler(nullptr, BHID_EnumItems,
                                  IID_PPV_ARGS(&spEnum));
     for (CComPtr<IShellItem> spProgram;
          spEnum->Next(1, &spProgram, nullptr) == S_OK;
          spProgram.Release()) {
      CComHeapPtr<wchar_t> spszName;
      spProgram->GetDisplayName(SIGDN_NORMALDISPLAY, &spszName);
      wprintf(L"%ls\n", spszName);
      PrintDetail(CComQIPtr<IShellItem2>(spProgram), &PKEY_Size, L"Size");</font>
     }
     return 0;
    }
    

    Bonus script: You can even see what verbs are available.

    var shell = new ActiveXObject("Shell.Application");
    var programsFolder = shell.Namespace(
        "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\8\\" +
        "::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}");
    var items = programsFolder.Items();
    for (var i = 0; i < items.Count; i++) {
        var item = items.Item(i);
        WScript.StdOut.WriteLine(item);
        WScript.StdOut.WriteLine("Size = " + item.ExtendedProperty("System.Size"));
        var verbs = item.Verbs();
        for (var j = 0; j < verbs.Count; j++) {
           var verb = verbs.Item(j);
           WScript.StdOut.WriteLine("Action: " + verb.Name);
        }
        WScript.StdOut.WriteLine("------------");
    }
    

    And if you're really ambitious, you can even call verb.DoIt to carry out the action. Don't use this power for evil.

    Note: Since we are working with the Programs and Features folder, we are necessarily targeting Windows Vista and later, since that was the version of Windows in which the Programs and Features folder was introduced. Therefore, I am free to use functionality introduced in Windows Vista.

    I've been doing Little Programs for a year now. I kind of like it, so I'm going to continue for another year, but I'm going to relax the rules a bit: The Little Programs are now just programs that I think are interesting for whatever reason. They don't need to actually solve a problem.

    << Previous Day 2013/12/30
    [Calendar]
    Next Day >>

The Old New Thing   About Sviesta Ciba