Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / shell

When A File Is Not A File

4.77/5 (14 votes)
13 Nov 2016CPOL2 min read 17K   207  
Getting information about a file that does not yet exist

Introduction

This code is based around the excellent article on MSDN, Creating a simple pidl: For the times you care enough to send the very fake[^], who's ideas I converted to C#. It describes how to fool the Windows shell into believing a particular file exists, when in fact it is not there. This can be useful in order to discover how the shell is going to handle this file - What icon will it show? What sort of details are available?

Background

I am looking at setting various properties for files as I write the files. I thought that it would be nice to collect these properties before the file was saved, so I looked into getting what properties were available for particular file types. Although this system does not supply all of those answers, it was a path I went down in during the research, and I thought that this was worthy of its own article.

How It Works

When the shell obtains information for a file, it seeks it out in the file system, receiving a WIN32_FIND_DATA structure containing basic details about the file. What we do here is attach an IBindCtx to the shell, telling it not to bother looking for this particular file, but to ask our component for the WIN32_FIND_DATA instead. However the structure we pass to the shell is not real - we've just made it up. The shell still believes us, however, and uses our fake data as if it were a real file.

Under the covers, this is handled by our implementation of IFileSystemBindData, which provides the shell with the WIN32_FIND_DATA upon request. Once we have provided the shell with this, we then ask it to produce a PIDL for our fake file, which is a series of bytes that identifies the item to the shell. From this identifier, we can as the shell anything we want out the file it represents. This is all accomplished in just a few lines of code.

C#
void CreateBindCtx(out IBindCtx pbc) {
    System.Runtime.InteropServices.ComTypes.BIND_OPTS bo =
                new System.Runtime.InteropServices.ComTypes.BIND_OPTS() {
        cbStruct = Marshal.SizeOf(typeof(System.Runtime.InteropServices.ComTypes.BIND_OPTS)),
        dwTickCountDeadline = 0,
        grfFlags = 0,
        grfMode = STGM_CREATE
    };
    try {
        CreateBindCtx(0, out pbc);
        pbc.SetBindOptions(ref bo);
        pbc.RegisterObjectParam(STR_FILE_SYS_BIND_DATA, (IFileSystemBindData)this);
    }
    catch {
        pbc = null;
        throw;
    }
}

void CreateSimplePidl(string path) {
    IBindCtx pbc;
    uint sfgao;
    CreateBindCtx(out pbc);
    SHParseDisplayName(path, pbc, out _ppidl, 0, out sfgao);
}

Using the Code

Once the PIDL has been created, it can be used in a multitude of shell functions and objects. In this example, I have exposed two methods - one to create an IShellItem object, which provides access to information about the fake file itself, and one to create an IShellFolder object, to supply information about the folder that contains this fake file, and how it would display it. In the demo, I use these objects to obtain basic properties about the file (IShellItem2.GetPropertyStore), and to get the icon for the file (IShellFolder.GetUIObjectOf). The shell documentation provides a lot more that could be achieved by this.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)