Date: prev next · Thread: first prev next last
2020 Archives by date, by thread · List index


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:
https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex.

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?
    return;
  <code in parent working with COM> // FAIL! COM not initialized!
  CoUninitialize();

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:

  main()
  {
    auto hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
    assert(SUCCEEDED(hr));
    hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
    assert(SUCCEEDED(hr));
    CoUninitialize();
    hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    assert(FAILED(hr));
    CoUninitialize();
    hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    assert(SUCCEEDED(hr));
  }

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

Attachment: pEpkey.asc
Description: application/pgp-keys


Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.