0X80040100

Fix DRAGDROP_E_NOTREGISTERED 0X80040100: Revoking an Unregistered Drop Target

Happens when you call RevokeDragDrop on a window that never called RegisterDragDrop. Fix: check the return value of RegisterDragDrop and only revoke if it succeeded.

Quick answer

Check if RegisterDragDrop succeeded before you ever call RevokeDragDrop—if it didn't, skip the revoke. The error means you're trying to unregister a drop target that was never registered.

Why this happens

What's actually happening here is that OLE's drag-and-drop subsystem keeps an internal map of window handles to IDropTarget pointers. When you call RevokeDragDrop(hwnd), it looks up that window in the map. If it doesn't find an entry, it returns DRAGDROP_E_NOTREGISTERED (0x80040100). The COM runtime isn't guessing—it literally can't find a registration for that handle.

Most people hit this when they write cleanup code that unconditionally calls RevokeDragDrop in a window's destructor or WM_NCDESTROY handler. But if RegisterDragDrop never ran, or ran and failed (say, because OLE wasn't initialized), you're revoking something that never existed. The classic scenario: you have a custom control that conditionally registers as a drop target only when a certain feature is enabled. You disable that feature, destroy the window, and boom—the destructor blindly calls RevokeDragDrop.

The fix

Stop revoking blindly. Track whether registration actually succeeded. Here's the pattern that works—I've used it in production C++ code for years:

  1. Store the result of RegisterDragDrop. Keep a simple bool m_dropRegistered member, or even just stash the HRESULT.
  2. Call RevokeDragDrop only if that flag is true. After revoking, set it back to false.
  3. Always call OleInitialize before any of this. If OLE isn't initialized, RegisterDragDrop returns CO_E_NOTINITIALIZED, and you'll never get a valid registration.

In code, it looks like this:

// Member variables
bool m_dropRegistered = false;

// Registration
HRESULT hr = OleInitialize(nullptr);
if (SUCCEEDED(hr)) {
    hr = RegisterDragDrop(m_hwnd, &m_dropTarget);
    m_dropRegistered = SUCCEEDED(hr);
}

// Cleanup
if (m_dropRegistered) {
    RevokeDragDrop(m_hwnd);
    m_dropRegistered = false;
}
OleUninitialize();

The reason this works is straightforward: you're only asking OLE to remove what you know you added. The flag is your source of truth, not the window's existence.

Alternative fixes when the main one fails

Maybe you're not writing the code—you're getting this error from a third-party app, or your code is already deployed and you can't change it easily. Try these:

  • Check for double revocation. If you call RevokeDragDrop twice on the same window, the second call returns this error. Some frameworks (older MFC, some ATL wrappers) do this internally. The fix is to wrap it in a guard or check the return value.
  • Verify the window handle is still valid. If the window was destroyed before you call RevokeDragDrop, OLE may have already cleaned up the registration. Passing a dead handle can produce this error. Make sure you revoke before DestroyWindow, not after.
  • If you're using managed code (C#/VB.NET), you might be P/Invoking RevokeDragDrop incorrectly. The signature needs IntPtr for the HWND, not an integer. A wrong type can truncate the handle, and OLE looks up a garbage window that was never registered.
  • For apps that suddenly show this on startup, check if you're running as administrator. UAC can change window handles in weird ways? No, that's nonsense—but it can cause OLE initialization to fail if the token is restricted. If OleInitialize fails, you'll never get a registration, and later revokes will fail with this error.

Prevention tip going forward

Don't treat RevokeDragDrop as a fire-and-forget call. Always pair it with the registration result. And here's a subtle one: if you have multiple windows in a hierarchy, each needs its own registration. A child window that delegates drop handling to its parent doesn't need its own RegisterDragDrop call—so don't revoke it either. Keep the registration and revocation in the same function or class, so they can't drift apart. That's the real fix—not checking error codes, but structuring the code so the mistake is impossible.

Related Errors in Windows Errors
0XC0190011 STATUS_CRM_PROTOCOL_NOT_FOUND (0XC0190011) Fix – DFSR or Cluster Fails 0XC00D10A2 Windows Media Player error 0XC00D10A2: alternate switch failed 0x80070490 Windows Update Agent Corrupted – Fix It Without Reinstalling 0X80280029 Fix TPM_E_BAD_MIGRATION (0X80280029): Key Migration Properties

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.