Tome's Land of IT

IT Notes from the Powertoe – Tome Tanasovski

Invoking the GetDiskSpaceInformation method of the IOfflineFilesCache COM interface with C++

This is a two-part post.  If you only care about solving this problem in C# and PowerShell, feel free to skip this and move to Part II.

My friend at work came to me with a problem.  There are some functions for offline files that only exist in the API.  Knowing my affinity for taking on bizarre pinvoke API calls, he came to me and asked whether or not I could get this function to work in PowerShell.  We’ll go into PowerShell and C# in Part II of this post, but to put it simply, this was an extremely difficult puzzle to figure out.  It was something I have never done and it is something I have never read anyone else do (I did a lot of googling and some begging on twitter – so if anyone does have a first post, please post it in the comments).  After failing at C# and PowerShell, I decided to try failing at implementing this in C++.

GetDiskSpaceInformation

The method in question is GetDiskSpaceInformation.  When looking at the documentation, you get a few clues through the two DLLs listed and the one Header, i.e., CscSvc.dll, CscObj.dll, and CscObj.h.  As you can see, there are no examples.  After some poking, I was able to find an example for another function, GetEncryptionStatus.  However, this is the easy part.  To me, this is just C++ and I could figure this out.  The hard part is called out in the code example for GetEncryptionStatus with an assumption on the first line of comments.  It says that we “Assume we already have a cache ptr”, referring to the IOfflineFilesCache *pCache interface.

IOfflineFilesCache Interface

The documentation for this also has no examples nor do any of the additional interfaces.  Sigh – this I think is why fewer people do C++ at all in the Microsoft world.  It’s a very frustrating web of documentation.  Regardless, the clue to figuring out how to implement this interface is in a single line in the IOfflineFilesCache interface documentation underneath the “When to use” section of the doc:

Create this object as an in-proc COM server using the class ID CLSID_OfflineFilesCache.

So this is COM – but not your C#-managed-code COM.  No, that would be too easy.

In-proc COM server client

I will spare you the hours of searching and tinkering to get this right.  The end result is that you must use a specific function called CoCreateInstance.  Of course, you will find zero posts that show exactly how to do this.  So finally, here it is:

IOfflineFilesCache *pCache;
HRESULT hr;
CoInitialize(nullptr);
hr = CoCreateInstance(CLSID_OfflineFilesCache, NULL, CLSCTX_INPROC_SERVER, IID_IOfflineFilesCache, (void**)&pCache);
if (FAILED(hr)) {
    std::cerr << "ERROR: " << hr << "\n";
    return 0;
}

I have the following includes in my code when invoking the above:

#include “stdafx.h”
#include
#include

The final code and ultimate solution

Without further ado, here is the full C++ code to invoke this function.  It displays the 5 values returned to stdout.

#include "stdafx.h"
#include <cscobj.h>
#include <iostream>
int _tmain()
{
    IOfflineFilesCache *pCache;
    HRESULT hr;
    CoInitialize(nullptr);
    hr = CoCreateInstance(CLSID_OfflineFilesCache, NULL, CLSCTX_INPROC_SERVER, IID_IOfflineFilesCache, (void**)&pCache);
    if (FAILED(hr)) {
        std::cerr << "ERROR: " << hr << "\n";
        return 0;
    }
    ULONGLONG pcbVolumeTotal;
    ULONGLONG pcbLimit;
    ULONGLONG pcbUsed;
    ULONGLONG pcbUnpinnedLimit;
    ULONGLONG pcbUnpinnedUsed;
    hr = pCache->GetDiskSpaceInformation(&pcbVolumeTotal, &pcbLimit, &pcbUsed, &pcbUnpinnedLimit, &pcbUnpinnedUsed);
    if (FAILED(hr)) {
        std::cerr << "ERROR: " << hr << "\n";
        return 0;
    }
    std::cout << "VolumeTotal:\t"    << pcbVolumeTotal    << "\n";
    std::cout << "Limit:\t\t"        << pcbLimit            << "\n";
    std::cout << "Used:\t\t"        << pcbUsed            << "\n";
    std::cout << "UnpinnedLimit:\t" << pcbUnpinnedLimit << "\n";
    std::cout << "UnpinnedUsed:\t"    << pcbUnpinnedUsed    << "\n";
    return 1;
}

The code can also be found on github.
Note: This was done on a windows 8.1 box using Visual Studio 2013 (important, because the libs are not in all versions of windows).

Tada

Once compiled, you have a nice utility that wraps this function:

offlinefilescachexe

In part II of this article, I will show you how the above is done in C#.  Once in C#, it’s just a copy/paste to get it to work in PowerShell via Add-Type.

Advertisements

One response to “Invoking the GetDiskSpaceInformation method of the IOfflineFilesCache COM interface with C++

  1. Pingback: Invoking the GetDiskSpaceInformation method of the IOfflineFilesCache COM interface with C# and PowerShell | Tome's Land of IT

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: