Thread: CoCreateInstance dies silently and kills DLL return value with it

  1. #1
    Registered User
    Join Date
    Sep 2021
    Posts
    10

    CoCreateInstance dies silently and kills DLL return value with it

    Hey guys,


    So I've been slamming my head hard against this one for about a day now, and I'm at that point of wit's end. Here's a little background: a few years ago, I built a program in C# that does some automation using the UIA ("Microsoft UI Automation") API. Then Windows 10 hit, and with it came a bug that made managed UIA painfully slow. So I wrote a DLL in C++ to do the heavy lifting. All the DLL functions rely on this:
    Code:
    /**
     * Loads UIA :)
     * @returns The UIA COM object, or nullptr if it fails
     */
    IUIAutomation* LoadUIA() {
        IUIAutomation* uia = nullptr;
        HRESULT startUIA = CoCreateInstance(CLSID_CUIAutomation, nullptr,
            CLSCTX_INPROC_SERVER, IID_IUIAutomation,
            reinterpret_cast<void**>(&uia));
        if (FAILED(startUIA) || uia == nullptr) {
            printf("LoadUIA failed with code %x\r\n", startUIA);
            return nullptr;
        }
        return uia;
    }
    And in literally every other scenario, for the past year or so, it has worked like a charm. But now, for reasons only God and Bill Gates could ever understand, it just... "evaporates" (to borrow a very apt description from one of the many SO posts I've poured over today). It doesn't hang or freeze or crash or show any error. The HRESULT doesn't contain an error code (well it might if I could see it) and there's nothing from .NOT (no managed error like "Unhandled System.This.That.These.Those.WhoCaresWhichObjectEx ception"). Speaking of .NOT, the interesting part is that after the DLL function falls on its sword, it also prevents further execution of the C# code. The C# code is supposed to play a sound letting the user know the automation is done; this should happen regardless of whether there was an error or not. It doesn't, because STOP!!!! lol...

    From there, i decided, the heck with LoadUIA or even fail-checks; let me just try the part that's self-destructing on me and see what the HRESULT says...
    Code:
    // "interesting" (more like annoying, infuriatng)...
        IUIAutomation* uia = nullptr;
        HRESULT startUIA = CoCreateInstance(CLSID_CUIAutomation, nullptr,
            CLSCTX_INPROC_SERVER, IID_IUIAutomation,
            reinterpret_cast<void**>(&uia));
        printf("startUIA = %x\r\n", startUIA);        // It never prints this.
    I tried using NULL instead of nullptr (I'm a die hard C guy myself, not at all a fan of C++, so idk what the subtle differences are between NULL and nullptr, but whatever). Same result.

    I tried some other values instead of CLSCTX_INPROC_SERVER (I will admit, I know very little about this enum or whatever funky client/server thing COM/UIA uses under the hood). Same result.

    I tried rebooting. I tried deleting the ".vs" folder (cuz at one point Visual Studio was flagging text in comments as having syntax errors, but that's just typical VS garbage - VS is just junk sometimes). And of course I've also tried "GetLastError" (always zero) and perror (always "No error"), and of course I've been over the docs for CoCreateInstance; again, there's nothing there that would explain this. Of course I called CoInitialize before it and made sure that call didn't fail (so it's not like I forgot to load COM first)............................................ .................................................. .....

    This bug defies all human reason or understanding. It laughs at logic, spits at sense, and screams "kiss my bits, puny human!" at anyone who dares to try and fix it Why would a block of code that works perfectly in LITERALLY EVERY OTHER SITUATION - other DLL functions in this project, other projects, etc. - do something so bizarre? Is there some kind of undocumented limit of how many functions a DLL can have, or how many functions of a DLL are allowed to use COM, or some... oh dad burn it I don't know!

    Has anyone here ever dealt with COM dot bomb randomness like this?

    PS: Sorry it's all one giant CODE tag. This stupid forum keeps yelling at me about "surrounding my code with code tags". I DID! I DID! WHY CAN'T YOU UNDERSTAND THAT! GRRRRRRRRRRR.....
    lol sorry, guess the forum hates me as bad as Windows. this is the kinda day that sends me screaming back to my Linux terminal.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,439
    It carped about code tags because you used braces to surround some piece of non-code text.
    You're the first person in 20 years to do such a thing.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,439
    IANAWP, so ....

    CoInitialize function (objbase.h) - Win32 apps | Microsoft Learn
    A couple of potential gotcha's
    1. You need at least one call per thread, and NOT change the threading model.
    2. Calls are reference counted, so you need to CoUninitialize the same number of times.
    3. Don't call them from DllMain
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Sep 2021
    Posts
    10
    Quote Originally Posted by Salem View Post
    IANAWP, so ....

    CoInitialize function (objbase.h) - Win32 apps | Microsoft Learn
    A couple of potential gotcha's
    1. You need at least one call per thread, and NOT change the threading model.
    2. Calls are reference counted, so you need to CoUninitialize the same number of times.
    3. Don't call them from DllMain
    So two thoughts here:

    1. Never read "IANAWP" before (assuming "I am not a Windows programmer" lol - I'll have to use that sometime cuz I'm really a C/Linux guy myself ).
    2. I believe your second idea might be what's going on here. Maybe the .NOT code is calling CoInitialize somewhere before my DLL runs. My program doesn't do any crazy threading stuff, and I checked DllMain (which I never use). So I did something crazy, that I would never do in production, just to test this theory:

    Code:
    for (int lol = 0; lol < 100; lol++) {
        CoUninitialize();
    }
    And what do you know? It works every time. It still doesn't make a whole lot of sense, considering that (a) the call to CoInitialize in my DLL function is the first time it is used (in my code), and more importantly (b) it doesn't fail - I had a check in place for that, so you'd think there would be an error. Nah, that would make too much sense (and sense is not a word I usually associate with COM, or C++ in general).

    Anyway, I wonder if there is a way to check if there is a COM instance already open - cuz then it's a simple if-statement; check if COM is already initialized, and if not don't try to init it again. That little goof I wrote above is the nuclear option, cuz obviously if there is some COM thing trying to do something else, I probably need it to stay open... on the other hand, it could just be a call to CoUninitialize failed because of some object I forgot to "Release" (COM is weird lol - it's object-oriented, cuz somebody wanted that, but u still have to free the memory yourself like in C).

    Bottom line: **THANK YOU SO MUCH!!**

  5. #5
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    635
    Might be a good idea to figure out where you're corrupting memory and fix it before you run out of pointless nonsense you can use to keep your app running.

  6. #6
    Registered User
    Join Date
    Sep 2021
    Posts
    10
    Quote Originally Posted by adeyblue View Post
    Might be a good idea to figure out where you're corrupting memory and fix it before you run out of pointless nonsense you can use to keep your app running.
    Okay, so how would one do that? When I hear "corrupted memory" I think common-sensical stuff like "did I de-reference a NULL pointer somewhere?" or "did a malloc/calloc/free call fail?" etc... but this is Windows and Windows is for the birds. COM is such a convoluted over-engineered maze of nightmares that I have no idea where to even start. Clearly not in the first call to CoInitialize... so something on the .NOT side maybe (is C# all COM crap under the hood?). There is no place where I would clearly run into any kind of "corrupted memory" in the traditional sense. Would it have killed MS to just give me a lib I can link to like a sane person would want?

    Is there any kind of advanced debugging mechanism I don't know of specifically for COM? Some log file someplace, or a function like GetLastError but specific to COM? I'm so sick of it "silently dying" for no apparent reason, I actually WISH for errors! Even a lousy Linux-style "segmentation fault (core dumped)" would be more information than what I have currently.

    Also - and this is kind of unrelated - any good tutorials on telling Visual Studio where to look for the "pre-compiled headers" it created? In release mode the DLL compiles fine, but in debug mode it's gripe-gripe-gripe, pre-compiled yabadabadooski-mumbo-mc-jumbo. The headers exist! They were created BY VISUAL STUDIO! I didn't edit them, change, them, or really use them in any way - their whole purpose for being is that VS wants them. If I can somehow tell it, "HERE are those files you need, created by you and for you and untouched by me, right where you put them ya quirkmongery pile of..." lol obviously, I'm so sick of wit's end. The dad-burned piece of you-know-what is pulling the same stunt again (and no, I didn't do that goofy example like in my last post - I actually found some places where I didn't call CoUninitialize and fixed it "the right way" lol). But I'm guessing that, if I can coax/force/convince it to compile in debug mode, it might lead to a lead someday. Maybe with the right VS junk attached, instead of just quitting on me, it'll actually give me some meaningful clue. Until then, I guess my best bet is to continue in prayer and review all many-thoustands-of-lines of code in hopes of finding something. it's a dice-roll, but with God ntohing is impossible. Not even this epic headache generator. Man I miss Valgrind.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,439
    Regarding precompiled headers, it might be an idea to turn it off in the project settings.
    The milliseconds it saves isn't balanced by the hours of effort taken whenever it screws up.

    It's a 30 year old hack from when machines and disks were much slower.

    The "we're fabulous puff piece"
    Precompiled Header (PCH) issues and recommendations - C++ Team Blog

    How to turn it off
    Precompiled Header Files | Microsoft Learn

    How to empty the diapers
    Is it safe to delete "ipch" folder - Pre-compiled headers?



    > Is there any kind of advanced debugging mechanism I don't know of specifically for COM?
    Using the debugger, I think what I might try would be to put counting breakpoints on these functions, just to see what's happening.
    - CoInitialize
    - CoUninitialize
    - CoCreateInstance

    At a guess, you'll see a few global instances created at startup, then additional ones created on demand in response to user activity.
    If particular user actions result in unbalanced calls, it would give you some idea where to start looking.

    Is all this code under version control?

    > 1. Never read "IANAWP" before (assuming "I am not a Windows programmer" l
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Sep 2021
    Posts
    10
    Man, Visual Studio just... stinks. I ended up doing a total rewrite, completely eliminating the C# part entirely, and now finally I get usable info. ironically it wasn't a COM thing at all, but a double-free (well, double "Release" I guess). Between having meltdowns over files it created, and having meltdowns over misinterpreting ITS OWN code due to syntax errors, and just... idk, it's an ice cream cone in a campfire. Sends me back to Linux every time lol...

    Anyway, thanks for the links on pre-compiled headers! Definitely gonna check those out, cuz I'm sure it won't be the last time VS melts down over stuff that has little-to-nothing to do with me.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. return value CoCreateInstance not documented in MSDN
    By George2 in forum C++ Programming
    Replies: 1
    Last Post: 08-05-2007, 03:45 AM
  2. Replies: 3
    Last Post: 07-17-2007, 03:12 PM
  3. Replies: 3
    Last Post: 10-15-2005, 09:13 AM
  4. UI dies during data processing
    By fatinez in forum Windows Programming
    Replies: 5
    Last Post: 05-04-2005, 03:42 AM
  5. Johnny Carson dies at age of 79
    By PJYelton in forum A Brief History of Cprogramming.com
    Replies: 8
    Last Post: 01-23-2005, 10:08 PM

Tags for this Thread