About CoInitializeEx

Mike Kaganski mikekaganski at hotmail.com
Sat May 30 07:15:12 UTC 2020

On 30.05.2020 1:06, Julien Nabet wrote:
> On 29/05/2020 17:19, Mike Kaganski wrote:
>> On 29.05.2020 17:41, julien2412 wrote:
>>> ...
>> Ctor of ODriver should store the previous status if COM initialization,
>> if it wants to re-initialize it with a specific concurrency. It should
>> check the failure code to detect if it was rejected because of different
>> mode (RPC_E_CHANGED_MODE); and if so, it should call CoUninitialize as
>> many times as needed to succeed with CoInitializeEx; then it needs to
>> additionally call CoInitializeEx the same number of times (so that the
>> total number of initializations is increased by 1). Then in dtor, it
>> should reverse that: if it hadn't needed to change mode in ctor, then
>> just call CoUninitialize once; otherwise, call CoUninitialize as many
>> times as needed to CoInitializeEx with old mode to succeed, then call
>> CoInitializeEx as many times that total initialize count is decremented
>> by 1 compared to before entering dtor. That should account for possible
>> intermediate unpaired calls to CoInitialize(Ex)/CoUninitialize in the
>> same thread, and make sure that the calling code is in ~consistent state
>> ... (however even this is a hack, and it would be better to find out why
>> does it need to change the mode at all - i.e., if we can make sure it
>> always used in appartment-threaded code).
> Thank you for your feedback Mike.
> I submitted on gerrit https://gerrit.libreoffice.org/c/core/+/95174.
> Just quote the comment I put in gerrit:
> "It seems we don't need to count the number of times CoInitializeEx has
> been called. From
> https://docs.microsoft.com/en-us/windows/win32/learnwin32/error-handling-in-com:
> "The success code S_FALSE deserves mention. Some methods use S_FALSE to
> mean, roughly, a negative condition that is not a failure. It can also
> indicate a "no-op"—the method succeeded, but had no effect. For example,
> the CoInitializeEx function returns S_FALSE if you call it a second time
> from the same thread"

That document can't be completely correct, when compared to another one:

It tells: "To close the COM library gracefully on a thread, each
successful call to CoInitialize or CoInitializeEx, _including any call
that returns S_FALSE_, must be balanced by a corresponding call to
CoUninitialize". Note the "including any call that returns S_FALSE"
part. If that call would be a no op, then the following would
necessarily fail:

  CoInitializeEx(...); // Initializes COM on thread for the first time
  <some code using COM objects>
  <call to some function>
    CoInitializeEx(...); // returns S_FALSE - no-op?
    CoUninitialize(); // If the previous call was no-op, then it
                      // actually uninitializes COM?
  <code in parent working with COM> // FAIL! COM not initialized!

But that must be the predominant pattern, and failing that would mean
most existing COM code failing.

In fact, each successful call to CoInitialize(Ex) - including S_FALSE
(which is a success code), must increment some internal ref counter.
This may be tested using something like this:

    auto hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
    hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
    hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);

I haven't tried that, actually; what I wrote is speculation - but I
suggest you to actually test that to make sure.

Either "no-op" was an error, or just used in a very narrow sense (as
"not actually calling initialization code") - I will file an issue there
in the MS documentation, when I'm sure.

Best regards,
Mike Kaganski
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pEpkey.asc
Type: application/pgp-keys
Size: 1769 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/libreoffice/attachments/20200530/953ba98c/attachment.key>

More information about the LibreOffice mailing list