Quick answer (for pros)
Call CoInitializeSecurity once, before any CoMarshalInterThreadInterfaceInStream or CoUnmarshalInterface calls. Do it right after CoInitializeEx in your main thread.
What this error actually means
You're seeing 0X80010119 (RPC_E_TOO_LATE) because your program tried to set COM security settings after COM already used them. COM is picky: once you start marshaling or unmarshaling interfaces, the security settings lock in. Trying to change them after that point gives you this error.
This pops up most often in C++ programs that use multiple threads with COM, or in older VB6 apps that call COM objects. I've seen it happen when someone writes a plugin for an app that already initialized COM—then their own code tries to call CoInitializeSecurity again. Doesn't work.
Step-by-step fix
- Find where you call CoInitializeEx or CoInitialize. Look at your main thread startup, usually in
WinMain,DllMain, or the first form load in VB6. - Right after that call, call CoInitializeSecurity. Do this before any
CoCreateInstanceorCoMarshalInterThreadInterfaceInStream. The exact order matters. - Use safe parameters. Here's the C++ code I use:
If you're using VB6 or VBA, you can useHRESULT hr = CoInitializeSecurity( NULL, // security descriptor -1, // count of auth services NULL, // list of auth services NULL, // reserved RPC_C_AUTHN_LEVEL_DEFAULT, // authentication level RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level NULL, // auth info EOAC_NONE, // additional capabilities NULL // reserved ); if (FAILED(hr)) { // handle error - but if it's RPC_E_TOO_LATE, you called it too late }CoInitializeSecurityviaole32.dllwith the same params. - Call it only once. You cannot call CoInitializeSecurity more than once in a process. If something else already called it, skip your call.
- Test your fix. Build and run. The error should go away. If it doesn't, check if another library or plugin called CoInitializeSecurity before your code.
Alternative fixes if the main one doesn't work
Sometimes you can't control when COM security gets set. Maybe you're writing a plugin for a host app. Here's what to do:
- Check if CoInitializeSecurity was already called. There's no direct API to check, but you can wrap your call in a try-catch or check the error code. If you get
0X80010119, don't panic—just skip your call. - Use a different COM threading model. Try
COINIT_MULTITHREADEDinstead ofCOINIT_APARTMENTTHREADEDin some rare cases. I've seen this fix it for certain COM objects. - Restructure your code. Move all marshaling and unmarshaling to happen after your CoInitializeSecurity call. Put that call at the very top of your program, before any COM work.
- For VB6: Use InitCommonControls before COM. This sometimes triggers an early CoInitializeSecurity. Call it first, then do your COM stuff.
How to prevent this permanently
Follow this rule: call CoInitializeSecurity right after CoInitializeEx, before any other COM call. I always put it in a helper function that I call once at startup. That way I never forget.
Also, if you're writing a library or plugin, don't call CoInitializeSecurity at all—let the host app do it. Check if it's safe by calling CoQueryClientBlanket first. If that works, security is already set.
One more thing: avoid calling COM functions from DllMain. That's a whole world of hurt. Do all COM init in a separate init function that the host calls after loading your library.