We have developed an STA ATL COM OOP Server and all works fine, almost. We are facing a problem: As the COM client internally gets the result of any COM call through a windows message the WM_PAINT message (or any other message i guess) can be processed while waiting for an answer of a COM call. That can be a problem in itself, but the big problem is that until previous COM call finishes all the calls to the server will fail (HRESULT=0x80010005), and this is quite a big issue as its happening really often in our application. We cant remove the COM calls from the paint.
I've been researching quite a bit about this and could not find anything regarding it (aside from this 2006 article that states the problem and some solutions that cant be applied in our case), but for what I see not only the WM_PAINT will be dangerous, any call to the server we perform inside of any windows event (message) will potentially cause the same problem.
So basically we can have different solutions but no clue about which COM methods to use or how:
1- A method that waits until last COM call is processed and value returned
2- A method to know if there is any pending to answer call in the server and a method to process the COM answers (all called from the client)
3- Know if we can implement an IMessageFilter class in the client and how to handle it and process the calls and so.
Thank you!
As the COM client internally gets the result of any COM call through a windows message the WM_PAINT message (or any other message i guess) can be processed while waiting for an answer of a COM call.
There is nothing connecting COM calls with WM_PAINT processing. The two tasks exist concurrently, but as you chose STA to be the model, both these tasks run on the same thread and might be blocking one another.
There is little you can do about painting itself, since you eventually will have a message handler to do the painting. However you can alter your COM server, and your paint handler to not interfere with COM.
You don't need to do COM calls right from WM_PAINT. Structure your server so that it posts all UI updates asynchronously and paint handler just uses most recent data available.
Also you can move your server to another apartment, STA or MTA, so that it does not share thread with UI and run in parallel.
We have fixed the problem implementing an IMessageFilter class in the client project (C++):
MessageFilter.h:
#include <atlbase.h>
#include <atlcom.h>
namespace SDKCOMSrvInterface
{
class MessageFilter : public CComObjectRootEx<CComSingleThreadModel>, public IMessageFilter
{
BEGIN_COM_MAP(MessageFilter)
COM_INTERFACE_ENTRY(IMessageFilter)
END_COM_MAP()
// Implement IMessageFilter methods here
STDMETHODIMP_(DWORD) HandleInComingCall(
DWORD dwCallType,
HTASK threadIDCaller,
DWORD dwTickCount,
LPINTERFACEINFO lpInterfaceInfo)
{
return E_NOTIMPL;
}
STDMETHODIMP_(DWORD) RetryRejectedCall(
HTASK threadIDCallee,
DWORD dwTimeOut,
DWORD dwRejectType)
{
return SERVERCALL_RETRYLATER;
}
STDMETHODIMP_(DWORD) MessagePending(
HTASK threadIDCallee,
DWORD dwTickCount,
DWORD dwPendingType)
{
return PENDINGMSG_WAITDEFPROCESS;
}
};
}
And registering it just after CoInitialize(NULL):
CComObject<MessageFilter>* l_MessageFilter = NULL;
CComObject<MessageFilter>::CreateInstance(&l_MessageFilter);
CComPtr<IMessageFilter> l_OldMessageFilter;
hr = CoRegisterMessageFilter(l_MessageFilter, &l_OldMessageFilter);
This will ensure that if we try to call the server from the client and the server is busy, the COM call will be retried until the server processes the previous call, which is exactly what is needed to solve the concurrency problem.
Related
I have an COM STA, that hosts an ICoreWebView2.
I try to get the complete HTML block and I found a documentation to achieve this with a script. Here my code:
hr = m_spWebView->ExecuteScript(L"document.body.outerHTML",
Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
[&val](HRESULT hr, LPCWSTR result) -> HRESULT
{
if (SUCCEEDED(hr))
val = result;
return S_OK;
}
).Get()
);
This code works, but it is executed asynchronous. So it takes some time to get the result. In fact I can see that the result arrives when the message pump is executed the next time (as I expect for an STA).
In C# I would use an await to wait for the completion.
But using C++ there is nothing like this. Using an event wouldn't work, because I have an STA I would block the thread and the answer will never arrive.
Is there any way to call a function that waits for the completion in C++? Or another help would be to use ExecuteScript synchron.
You have to implement an IDispatch interface (COM stuf), and add it with:
m_spWebView->AddHostObjectToScript(L"host", &disp);
Then you let JavaScript call it when the documment is loaded.
struct CDispatch : IDispatch
{
...
} cdisp;
You will get the HTML as a parameter in a Invoke call. Don't need to worry about the other methods, just confirm for IID_IDispatch in QueryInterface and watch for the Invoke.
window.chrome.webview.hostObjects.host(document.body.outerHTML);
I tried here and managed to do what you are willing to do.
If you have an STA then rather than explicitly waiting for completion, you can start your message loop or return back and allow your message loop to continue processing messages.
If you need to block execution and process messages without returning back to your message loop, you can try using CoWaitForMultipleHandles with COWAIT_DISPATCH_WINDOW_MESSAGES to ensure you process window messages which is necessary for WebView2 callbacks to execute. However, this can open up your app to reentrancy or other synchronization issues and depending on how the rest of your app deals with this, could be a problem.
Generally the better solution is to return back to your message loop.
I currently am using asynchronous callback to get the motion data through Window's Sensor API. For now I want to test the functionalities through a Windows 10 Console application (NOT a Windows Application). To simplify things, I am currently having the exact same problem as How to cause my C++ program to wait for sensor events for ever and not terminate, where
while(true) { hr = sensor->SetEventSink(pMyEvents); } fires the event and I get consistent data, but the proper usage should be just
hr = sensor->SetEventSink(pMyEvents);, which will trigger the event asynchronously.
I also used CoInitializeEx(NULL, COINIT_MULTITHREADED); to allow multithreading in COM.
In the comments in the above SO link, two users mention that "You're forgetting the Windows message event loop." I do not want to have a graphical interface for this program, and more importantly I do not get why "COM will not work without a message loop." This seems to apply only for Windows Application Projects. Could someone elaborate on this, and how to properly use SetEventSink(ISensorEvent) to keep receiving the data for a regular console application?
I have confirmed that other code such as for initialization/decoding dataworks by using the synchronous method - GetData().
In a COM RPC Model, if the Server is running on a separate process, is it possible to know, the Process ID of the client Process communicating with the Server?
Use Case
I have an Out Process RPC Server which can receive request from one or more client process. Occasionally, the server needs to know the Client Process to write data back to the client address space using Write Process Memory.
Also Note, the API Signatures, the way the buffer is getting allocated and the APIs are getting called are beyond my control.
I know that I'm almost 9 years late but just answering this in case anyone in the future needed it.
So there's a way to do this.... but through a private/undocumented COM interface, which is ICallingProcessInfo
Interface definition:
MIDL_INTERFACE("68C6A1B9-DE39-42C3-8D28-BF40A5126541")
ICallingProcessInfo : public IUnknown
{
public:
virtual STDMETHOD(OpenCallerProcessHandle)(DWORD dwDesiredAccess, HANDLE* handle) = 0;
};
Usage:
HANDLE handle;
ComPtr<ICallingProcessInfo> callingProcessInfo; // ComPtr is from WRL, you can use the interface directly instead
CoGetCallContext(__uuidof(ICallingProcessInfo), (void**)callingProcessInfo.GetAddressOf());
callingProcessInfo->OpenCallerProcessHandle(PROCESS_QUERY_LIMITED_INFORMATION, &handle);
auto pid = GetProcessId(handle);
I tested this on a WinRT OOP Server but since WinRT Servers are just COM Servers it should work with normal COM Servers too
Trying to understand What is IConnectionPoint and how this is connected to IConnectionPointContainer,IEnumConnectionPoints,IEnumConnections and EventHandling.
Read the artcicles from MSDN and CodeProject which is explaining a about other methods like: QueryInterface() and otherthings.
I am unable to figure out how all these things(IConnectionPointContainer,IEnumConnectionPoints,IEnumConnections) are interconnected with eachother and event Handling.
I just want to create a simpleClient which Will trigger an event in COM object.
If there are any articles or code snippet that can explain how things are related to each other with simple and small chunk of code will be helpfull.
Worth mentioning that I have started development in C recently, a beginner.
Edit #sharptooth
For the Line "typically your client will receive events and the COM object will trigger those events. "
From many articles, What I understood is When we use connection points at that point,
the client exposes a set of methods that the server uses.
I am just Outlining portion of the article from TechRepublich:
Client server vs. sink source
So the main difference between normal programming with COM in a standard client-server system and using connection points is that in the standard client-server case, the server exposes a list of methods that the client employs, and in the connection point case, the client exposes a set of methods that the server uses.
Looks like you get the big picture wrong. Typically your client will receive events and the COM object will trigger those events. To achieve this the client requests (QueryInterface()) the IConnectionPointContainer interface, calls IConnectionPointContainer::FindConnectionPoint() and IConnectionPoint::Advise() and passes a pointer to itself or some subobject there.
The client will have to implement some events interface (the one GUID of which is passed into IConnectionPointContainer::FindConnectionPoint()). Once subscribed (advised) the client will receive calls from the COM server - the events.
Typically the COM server does something routinely and decides to notify clients of it (say a user moves the mouse in an ActiveX control) - it just gets an array of pointers to event receivers and calls a method it wants on that interface.
COM events are in fact an implementation of callbacks. The same way you use callback in C++ (or C or any other languages supporting function pointers or interfaces) you use events in COM. Yes, you're right that when the server triggers the event the client in fact acts as a server reacting to the event. That's a callback scenario - the other code calls your functionality. In this case the server calls your implementation of the events interface.
These two articles provide useful information:
https://devblogs.microsoft.com/oldnewthing/?p=4113
https://devblogs.microsoft.com/oldnewthing/20130612-00/?p=4103
What #sharptooth forgot to mention is, the pointer passed to IConnectionPoint::Advise must be a pointer to a COM object.
This means It must not only implement the particular events interface but also the IUnknown interface.
I am having a problem in a large scale application that seems related to windows messaging on the Pocket PC. What I have is a PocketPC application written in c++. It has only one standard message loop.
while (GetMessage (&msg, NULL, 0, 0))
{
{ TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
We also have standard dlgProc's. In the switch of the dlgProc, we will call a proprietary 3rd party API. This API uses a socket connection to communicate with another process. The problem I am seeing is this: whenever two of the same messages come in quickly (from the user clicking the screen twice too fast and shouldn't be) it seems as though recursion is created. Windows begins processing the first message, gets the api into a thread safe state, and then jumps to process the next (identical ui) message. Well since the second message also makes the API call, the call fails because it is locked. Because of the design of this legacy system, the API will be locked until the recursion comes back out (which also is triggered by the user; so it could be locked the entire working day). I am struggling to figure out exactly why this is happening and what I can do about it. Is this because windows recognizes the socket communication will take time and preempts it? Is there a way I can force this API call to complete before preemption? Is there a way I can slow down the message processing or re-queue the message to ensure the first will execute (capturing it and doing a PostMessage back to itself didnt work). We don't want to lock the ui down while the first call completes.
Any insight is greatly appreciated! Thanks!!
You could synchronize the access to the API through e.g. a mutex and hold incoming jobs in a local container until the current job finished working with it.