Sonjli 6 Posted September 2, 2020 Hello, I hope not to be out of topic... I have a COM client (developed as NTService) that every 5 minutes need to reconnect to server (don't ask me why... the COM server kick out clients for "security" every 5 minutes). In every "connect" I do this: OleCheck(CoInitializeEx(nil, COINIT_MULTITHREADED)) Can this be a problem? I see that sometimes, after 30/40 reconnections, the COM server seems "locked". No other clients can connect correctly to the server until I kill my NTService. It is not fault of the "security" system, because I still tested that. Any ideas? Ask me for infos if you need. Thanks in advance, Eddy Share this post Link to post
Anders Melander 1784 Posted September 2, 2020 I think you need to post some more code and some more details. Does the OleCheck ever raise an exception? If so how do you handle this exception? Are you sure that you shouldn't be using COINIT_APARTMENTTHREADED instead? Are you sure there's a CoUninitialize for every CoInitializeEx? How does the server disconnect the client? Have you tried debugging the server to determine what it's doing when it "hangs"? 1 Share this post Link to post
Lars Fosdal 1792 Posted September 2, 2020 CoInit/CoUnInit should run only once per thread. 1 Share this post Link to post
Anders Melander 1784 Posted September 2, 2020 14 minutes ago, Lars Fosdal said: CoInit/CoUnInit should run only once per thread. https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex Quote CoInitializeEx must be called at least once, and is usually called only once, for each thread that uses the COM library. Multiple calls to CoInitializeEx by the same thread are allowed as long as they pass the same concurrency flag, but subsequent valid calls return S_FALSE. 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. Anyway, that's on the client and it shouldn't affect the server. 1 Share this post Link to post
Sonjli 6 Posted September 2, 2020 Is it possible that if I never call the CoUninitialize the server goes out of order or lock after a lot of calls? I call CoInitilize every 5 minutes but I forgot calling CoUninitialize... f**k. Share this post Link to post
Sonjli 6 Posted September 2, 2020 1 hour ago, Anders Melander said: I think you need to post some more code and some more details. Does the OleCheck ever raise an exception? If so how do you handle this exception? Never, I log this Are you sure that you shouldn't be using COINIT_APARTMENTTHREADED instead? Every NTService create a lot of threads, so I think COINIT_MULTITHREADED is the right choice... I think... Are you sure there's a CoUninitialize for every CoInitializeEx? No. I am very angry. I didn't see this How does the server disconnect the client? Mistery. It's a third party server. Poor documentation Have you tried debugging the server to determine what it's doing when it "hangs"? The logs of the server resides in a remote machine. The machine is a CNC. Very hard to get inside... Share this post Link to post
Anders Melander 1784 Posted September 2, 2020 Okay. Let's assume that the problem lies with the client. Apartment threading just means that ingoing COM calls are executed on the main thread. This is like using TThread.Synchronize to ensure that code that isn't thread safe is executed in the context of the main thread. If your code is thread safe or if you are sure that you're not using callbacks (e.g. COM events) then COINIT_MULTITHREADED is probably fine. The missing CoUninitialize will affect the client but assuming that you clear all references to server interfaces on disconnect then I can't see how that would affect the server. So your code logic should go something like this: CoInitializeEx(...); try Server := ConnectToServer; try Server.DoStuffWithServer; finally Server := nil; end; finally CoUninitialize; end; Share this post Link to post
Anders Melander 1784 Posted September 2, 2020 34 minutes ago, Sonjli said: How does the server disconnect the client? Mistery. It's a third party server. Poor documentation It's probably using CoDisconnectObject Share this post Link to post
FPiette 384 Posted September 2, 2020 3 hours ago, Sonjli said: In every "connect" I do this: OleCheck(CoInitializeEx(nil, COINIT_MULTITHREADED)) CoInitializeEx should be called only once. Better place is at program startup. Share this post Link to post
Anders Melander 1784 Posted September 2, 2020 8 minutes ago, FPiette said: CoInitializeEx should be called only once. Better place is at program startup. It's a service application so the COM stuff is presumably done in a thread. The CoInitializeEx/CoUninitialize should be done in the thread. Apart from it being inefficient there's nothing wrong with looping and wrapping the server interaction with local calls to CoInitializeEx/CoUninitialize inside the loop. Outside the loop would be much more efficient of course but it might be a good idea to start again with a fresh, clean COM environment after the server has disconnected the client. Share this post Link to post
Lars Fosdal 1792 Posted September 2, 2020 I checked our sources. We normally never use CoInitializeEx, explicitly, just CoInitialize, but I guess that depends on the requirements of the OLE control. Share this post Link to post
Anders Melander 1784 Posted September 2, 2020 6 minutes ago, Lars Fosdal said: I checked our sources. We normally never use CoInitializeEx, explicitly, just CoInitialize, but I guess that depends on the requirements of the OLE control. https://docs.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize Quote CoInitialize ... Initializes the COM library on the current thread and identifies the concurrency model as single-thread apartment (STA). New applications should call CoInitializeEx instead of CoInitialize. And the documentation for CoInitializeEx states: Quote Because OLE technologies are not thread-safe, the OleInitialize function calls CoInitializeEx with the COINIT_APARTMENTTHREADED flag. As a result, an apartment that is initialized for multithreaded object concurrency cannot use the features enabled by OleInitialize. Share this post Link to post
Lars Fosdal 1792 Posted September 2, 2020 I wonder what kind of effect that has on f.x. FireDAC? We use the SQLNCLI11 and MSOLEDBSQL drivers in heavily multithreaded services. We also use OLE objects in DLLs created a decade and a half ago against our ERP system. Share this post Link to post
Anders Melander 1784 Posted September 2, 2020 6 minutes ago, Lars Fosdal said: I wonder what kind of effect that has on f.x. FireDAC? CoInitialize etc. only affects the calling thread. If you access FireDAC from a thread, and you have called CoInitialize on that thread, then any inbound COM will be executed on the main thread (i.e. single threaded apartment a.k.a. apartment threaded). I'm guessing you are only doing outbound COM so the threading model shouldn't matter. Share this post Link to post
Lars Fosdal 1792 Posted September 2, 2020 Indeed it is only outbound. All inbound activity is TCP/UDP oriented. Share this post Link to post
Sonjli 6 Posted September 3, 2020 19 hours ago, Anders Melander said: Apartment threading just means that ingoing COM calls are executed on the main thread. This is like using TThread.Synchronize to ensure that code that isn't thread safe is executed in the context of the main thread. If your code is thread safe or if you are sure that you're not using callbacks (e.g. COM events) then COINIT_MULTITHREADED is probably fine. I DO use COM events... so, should I change COINIT_MULTITHREADED in COINIT_APARTMENTTHREADED? Can this make server unstable? Remark: the server is no more reachable from other clients until I close my "buggy" ntservice. When this issue happens, I stop my ntservice and the other clients connects correctly. I doubt it is a server issue, I am barely sure I am doing something wrong. Share this post Link to post
Anders Melander 1784 Posted September 3, 2020 59 minutes ago, Sonjli said: I DO use COM events... so, should I change COINIT_MULTITHREADED in COINIT_APARTMENTTHREADED? It depends. If you are sure that your event handlers are thread safe then COINIT_MULTITHREADED is fine. Otherwise change it to COINIT_APARTMENTTHREADED. 1 hour ago, Sonjli said: Can this make server unstable? Well if you code isn't thread safe then anything can happen but I think it's more likely that the missing CoUninitialize is the cause. 1 Share this post Link to post
DelphiUdIT 177 Posted September 3, 2020 I strongly doubt that the eventual problem is due to a "logic" error linked to multithreading, because normally this would generate exceptions with memory access errors recorded in the Windows system log. Many years ago I also made the mistake of calling CoInitialezeEx without CoUninitialize and there were several problems especially when closing the application. Since then I ALWAYS use the CoInitializeEx (nil, COINIT_MULTITHREADED) at the beginning of the threading EXECUTE method (not in the while block, of course) and the CoUninitialize at the end of EXECUTE (when the thread terminates. Obviously, ONLY within the EXECUTE method (or in the methods subsequently called by it) will it be possible to access the OLE / ACTIVEX resources for that thread. Share this post Link to post
maXcomX 3 Posted March 21, 2023 Why does a call to CoInitializeEx(nil, COINIT_APARTMENTTHREADED or COINIT_DISABLE_OLE1DDE); always returns 1 instead of 0 (S_OK)? Share this post Link to post
Remy Lebeau 1400 Posted March 21, 2023 (edited) 22 minutes ago, maXcomX said: Why does a call to CoInitializeEx() always returns 1 instead of 0 (S_OK)? 1 is S_FALSE. Per the documentation: https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex Quote Return value This function can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, and E_UNEXPECTED, as well as the following values. Return code Description S_OK The COM library was initialized successfully on this thread. S_FALSE The COM library is already initialized on this thread. RPC_E_CHANGED_MODE A previous call to CoInitializeEx specified the concurrency model for this thread as multithread apartment (MTA). This could also indicate that a change from neutral-threaded apartment to single-threaded apartment has occurred. Remarks CoInitializeEx must be called at least once, and is usually called only once, for each thread that uses the COM library. Multiple calls to CoInitializeEx by the same thread are allowed as long as they pass the same concurrency flag, but subsequent valid calls return S_FALSE. 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. This means that you are calling CoInitializeEx() on a thread that has already called CoInitialize/Ex() successfully, and you are specifying the same concurrency model that has already been assigned to the thread. For instance, are you calling CoInitializeEx() in the main UI thread? The RTL's System.Win.ComObj unit initializes COM in the main UI thread during program startup, using the global CoInitFlags variable to decide whether to use CoInitialize() or CoInitializeEx(). Edited March 21, 2023 by Remy Lebeau Share this post Link to post