Properties coding expedition #1 - Binding to an item

The goal of this first expedition is to print lists of properties from items. This will give insight into the origins and capabilities of these different properties. Feel free to follow along and try out different things. There's a lot to explore.

I am splitting this and future programming expeditions into segments so that I can talk about the details without posting miles of code. 

 #include <windows.h>
#include <propsys.h>
#include <propvarutil.h>
#include <propkey.h>
#include <shobjidl.h>
#include <stdio.h>

#pragma comment(lib, "propsys.lib") 
#pragma comment(lib, "ole32.lib") 
#pragma comment(lib, "shlwapi.lib") 
#pragma comment(lib, "shell32.lib") 

int wmain(__in int argc, __in_ecount(argc) WCHAR **argv)
{
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (SUCCEEDED(hr))
    {
        if (argc == 0)
        {
            wprintf(L"Usage: %s \n", argv[0]);
        }
        else
        {
            PCWSTR pszFile = argv[1];
            wprintf(L"Properties for '%s'\n", pszFile);

            WCHAR szDir[MAX_PATH];
            if (GetCurrentDirectory(ARRAYSIZE(szDir), szDir))
            {
                WCHAR szPath[MAX_PATH];
                if (PathCombineW(szPath, szDir, pszFile))
                {
                    IShellItem2 *psi;
                    hr = SHCreateItemFromParsingName(szPath, NULL, IID_PPV_ARGS(&psi));
                    if (SUCCEEDED(hr))
                    {
                        IPropertyStore *pps;
                        hr = psi->GetPropertyStore(GPS_DEFAULT, IID_PPV_ARGS(&pps));
                        if (SUCCEEDED(hr))
                        {
                            hr = _PrintPropertyStore(pps);
                            pps->Release();
                        }
                        psi->Release();
                    }
                }
            }
        }
        CoUninitialize();
    }
}

There's nothing too special about this code. Starting with some boilerplate, we figure out the path to the file, bind to it, and grab it's property store. Tomorrow I'll dive into the printing loop.

SHCreateItemFromParsingName is a nifty little function.  IShellItem has been around for some time, but it was never this easy to obtain. 

On Windows 2000, you had to:

  1. Call SHGetDesktopFolder to get the desktop's IShellFolder interface
  2. Call IShellFolder::ParseDisplayName to get the PIDLIST_RELATIVE for the item
  3. Call SHCreateShellItem to get the IShellItem interface

Windows XP made this easier with SHParseDisplayName which took care of steps 1 and 2.

Windows Vista provides SHCreateItemFromParsingName to take care of steps 1, 2 and 3 all at once!

-Ben Karas

goatpicture.png

Comments

  • Anonymous
    October 03, 2006
    here is a useful helper I created for some of my test apps.produce a shell item from the command line. deals with unquoting paths.STDAPI GetShellItemFromCommandLine(REFIID riid, void **ppv){   *ppv = NULL;   HRESULT hr = E_FAIL;   int cArgs;   PWSTR *ppszCmd = CommandLineToArgvW(GetCommandLineW(), &cArgs);   if (ppszCmd && cArgs > 1)   {       WCHAR szSpec[MAX_PATH];       StringCchCopyW(szSpec, ARRAYSIZE(szSpec), ppszCmd[1]);       PathUnquoteSpacesW(szSpec);       hr = szSpec[0] ? S_OK : E_FAIL; // protect against empty       if (SUCCEEDED(hr))       {           hr = SHCreateItemFromParsingName(szSpec, NULL, riid, ppv);           if (FAILED(hr))           {               WCHAR szFolder[MAX_PATH];               GetCurrentDirectoryW(ARRAYSIZE(szFolder), szFolder);               hr = PathAppendW(szFolder, szSpec) ? S_OK : E_FAIL;               if (SUCCEEDED(hr))               {                   hr = SHCreateItemFromParsingName(szFolder, NULL, riid, ppv);               }           }       }   }   return hr;}and here is sample usage       IShellItem *psi;       hr = GetShellItemFromCommandLine(IID_PPV_ARGS(&psi));       if (SUCCEEDED(hr))       {           PWSTR pszName;           hr = psi->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &pszName);           if (SUCCEEDED(hr))           {               CoTaskMemFree(pszName);           }           psi->Release();       }
  • Anonymous
    October 04, 2006
    Wow, I forgot about that attachment!  Ha!  It's the picture I'm going to use when testing this program.  It also shows what properties Window Vista chooses to show for this filetype.http://blogs.msdn.com/benkaras/attachment/777894.ashx
  • Anonymous
    November 05, 2006
    This coding expedition has developed a tool that can dump out all the properties on a file. If you are