When This Error Hits
You're running a classic ASP page, a VB6 app, or an old automation script. It's been working fine for years. Then one day — or on a new machine — you get MK_E_NEEDGENERIC (0X800401E2). The error message reads "Moniker needs to be generic." I've seen this most commonly when someone's trying to create a moniker from a path like file://C:\SomeApp\SomeFile.doc instead of a generic OLE moniker. It also shows up in Excel automation via COM when you try to bind a moniker to a specific instance instead of a generic class.
Root Cause in Plain English
COM monikers are like shortcuts — they tell Windows how to find and activate COM objects. A generic moniker points to a class (e.g., clsid:XXXX), while a specific moniker includes file paths, machine names, or even running instances. The error means your code built a moniker that's too specific for the operation you're trying to do. The COM runtime refuses to run it because it can't guarantee the binding will work reliably.
The culprit here is almost always your call to MkParseDisplayName or CreateFileMoniker with a path that includes a local file system reference. COM expects a class moniker (using CLSID) or a file moniker for a document, but not a hybrid. Another common trigger: BindMoniker called on a moniker that already contains a running object table (ROT) entry — that's a no-go.
The Fix
You've got two paths. Pick the one that matches your scenario. Don't bother chasing registry settings or reinstalling COM components — that rarely fixes this.
- Use a generic moniker instead of a file moniker. If your code does something like:
CreateFileMoniker(L"C:\MyApp\MyDoc.doc", &pMoniker);
Change it to build a class moniker using the CLSID of the COM component:
CLSID clsid;
CLSIDFromProgID(L"MyApp.Application", &clsid);
CreateClassMoniker(clsid, &pMoniker);
Then use that moniker with BindMoniker or MkParseDisplayName.
- Skip the moniker entirely and use
CoCreateInstance. If you just need an object instance, don't mess with monikers at all. Direct instantiation is simpler and sidesteps this error completely:
CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (void**)&pUnk);
- If you're stuck with a specific path (e.g., loading a document), use
BindMonikerwith a file moniker only. Make sure you don't combine it with a class moniker. And never callBindMonikeron a moniker that's already in the ROT.
CComPtr<IMoniker> pFileMoniker;
CreateFileMoniker(L"C:\Docs\report.doc", &pFileMoniker);
CComPtr<IBindCtx> pBC;
CreateBindCtx(0, &pBC);
CComPtr<IUnknown> pUnk;
pFileMoniker->BindToObject(pBC, NULL, IID_IUnknown, (void**)&pUnk);
If It Still Fails
Check these three things:
- The COM component is registered correctly. Run
regsvr32on the DLL or reinstall the app. Missing registries cause all sorts of moniker grief. - You're not accidentally mixing 32-bit and 64-bit. A 32-bit moniker can't bind to a 64-bit component. Make sure your application's bitness matches the COM server.
- No stale ROT entries. If a moniker was left in the Running Object Table from a previous failed run, it can block a new bind. Use the
CreateFileMonikerapproach above — that doesn't touch the ROT.
That's it. I've fixed this same error in half a dozen legacy projects. Moniker misuse is always the root cause. Stick with generic monikers or direct CoCreateInstance calls and you'll be fine.