How to Enable Drag and Drop for an Elevated MFC Application on Windows

Finding good information on how to enable drag and drop for MFC applications is hard enough (why?). But just when you think you should have it working, you hit a very solid wall: UIPI (User Interface Privilege Isolation, a variant of UAC, User Account Control). Because of “security” reasons, UIPI disables drag and drop from medium integrity processes (Explorer) to high integrity (aka elevated) processes by filtering out most window messages, including those required for drag and drop. In essence drag and drop from Explorer to your elevated application does not work.

To waste your time, Microsoft added the API function ChangeWindowMessageFilter that lets specific window messages through (punching a hole in the UIPI “firewall”), but just adding WM_DROPFILES to the list of allowed messages does not help. Drag and drop uses more than just WM_DROPFILES. But where is a list of the window messages required for drag and drop? Even the venerable Raymond Chen refused to explain how to make it work. Well, here is how.

Basic Drag and Drop

This assumes you have a dialog-based MFC application. I have implemented this with Visual Studio 2008 SP1.

Step 1: Enable Drag And Drop

In your dialog’s OnInitDialog method, enable drag and drop. You can either do this for the entire dialog or a specific control:

DragAcceptFiles (); // entire dialog
m_oPath.DragAcceptFiles (); // control represented by variable m_oPath

Step 2: Message Map

Add ON_WM_DROPFILES() to your message map, e.g.:

BEGIN_MESSAGE_MAP(<dialog class name>, CDialog)
   ON_WM_DROPFILES()
END_MESSAGE_MAP()

Step 3: Drop Event Handler

Add an event handler for drop events. In your dialog’s header file:

afx_msg void OnDropFiles(HDROP hDropInfo);

And in the CPP file:

void <dialog class name>::OnDropFiles (HDROP dropInfo)
{
    CString    sFile;
    DWORD      nBuffer    = 0;
    // Get the number of files dropped
    UINT nFilesDropped    = DragQueryFile (dropInfo, 0xFFFFFFFF, NULL, 0);
    // If more than one, only use the first
    if (nFilesDropped > 0)
    {
        // Get the buffer size for the first filename
        nBuffer = DragQueryFile (dropInfo, 0, NULL, 0);
        // Get path and name of the first file
        DragQueryFile (dropInfo, 0, sFile.GetBuffer (nBuffer + 1), nBuffer + 1);
        sFile.ReleaseBuffer ();
        // Do something with the path
    }
    // Free the memory block containing the dropped-file information
    DragFinish(dropInfo);
}

UAC and Elevation

Now comes the interesting part. All of the above will work - unless your application runs elevated. As mentioned earlier, WM_DROPFILES messages are simply filtered out by UIPI. You can re-enable individual messages by calling ChangeWindowMessageFilter (, MSGFLT_ADD), but enabling WM_DROPFILES alone is not sufficient. Here is my first attempt to work around that:

for (int i = 0; i <= WM_DROPFILES; i++)
{
    ChangeWindowMessageFilter (i, MSGFLT_ADD);
}

Hooray! Drag and drop works! But letting all messages through is probably a little bit too much. So I tried to narrow things down.

Step 4: Allow Messages Through the UIPI Filter

After some trial and error I came up with the following list of messages you need to allow through the UIPI filter in order to enable drag and drop:

ChangeWindowMessageFilter (WM_DROPFILES, MSGFLT_ADD);
ChangeWindowMessageFilter (WM_COPYDATA, MSGFLT_ADD);
ChangeWindowMessageFilter (0x0049, MSGFLT_ADD);

Comments

Related Posts

Visual Studio: Fixing Broken $(WindowsSdkDir) Variable

If you get weird errors in Visual Studio that basically state files like Windows.h cannot be found, the reason may be a missing or incorrect WindowsSdkDir variable. In my case, working with Visual Studio 2008 SP1 (32 bit) on Windows 7 x64 (64 bit) everything was fine until I installed the Windows 7 SDK. After that, no SDK files could be found any more and nothing would compile. Uninstalling the SDK (which I did not really need anyway - I had installed it only to get at XPerf) did not help. After some research, I found out that the Visual Studio internal variable WindowsSdkDir (which is not an environment variable) was missing from the registry. After adding the following, everything worked like a charm again:
Software development

DsGetDcName Timeout

Today I was looking for the source of frequent delays when setting permissions from my new application SetACL Studio. I sprinkled the code with timestamped debug statements like these… System.Diagnostics.Debug.WriteLine(DateTime.Now + " - 1"); // Do something System.Diagnostics.Debug.WriteLine(DateTime.Now + " - 2"); …and found that the delays always had a duration of seven seconds. Wait - “inexplicable” delays of constant length - that smells of timeouts!
Software development

Latest Posts

Beautiful Slide Decks from Markdown: Presenting with Slidev

Beautiful Slide Decks from Markdown: Presenting with Slidev
Would you like to get away from PowerPoint and author slide decks in Markdown? Then Slidev may be just what you’re looking for. It’s a web app for presentations. The fact that it’s geared towards developers shouldn’t put you off. After all, who isn’t a developer these days, with AI? Slidev comes with the beautiful Tahta themes and supports features like syntax highlighting and animations. Export options to PDF and PPTX allow for easy sharing. This article shows how to get started.
Applications