Я понял, почему народ кодит на JS, поглядев на современный энтерпрайзный C++
https://devblogs.microsoft.com/oldnewthing/20220222-00/?p=10...You can substitute any other object that follows this same pattern. You don’t even have to have a real kernel object. You just need something that can pretend to be a kernel object enough to satisfy the ISynchronize contract.
struct MySynchronize : winrt::implements<MySynchronize, ::ISynchronize>
{
winrt::com_ptr<::IUnknown> m_inner;
int32_t query_interface_tearoff(winrt::guid const& id, void** object)
const noexcept override {
if (m_inner) return m_inner.as(id, object);
return E_NOINTERFACE;
}
wil::slim_event ready;
STDMETHODIMP Reset() { ready.ResetEvent(); return S_OK; }
STDMETHODIMP Signal() { ready.SetEvent();
printf("Call completed!\n"); // do cool stuff here
return S_OK; }
STDMETHODIMP Wait(DWORD flags, DWORD timeout) {
assert(is_mta()); // we won't be pumping messages
assert(!(flags & COWAIT_ALERTABLE)); // we won't be waiting alertably
return ready.wait(timeout) ? S_OK : RPC_S_CALLPENDING;
}
static bool is_mta() {
APTTYPE type;
APTTYPEQUALIFIER qualifier;
THROW_IF_FAILED(CoGetApartmentType(&type, &qualifier));
return type == APTTYPE_MTA;
}
};
A simpler way is to delegate the ISynchronize methods back to the call object:
struct MySynchronize :
winrt::implements<MySynchronize, ::ISynchronize, winrt::non_agile>
{
winrt::com_ptr<::IUnknown> m_inner;
int32_t query_interface_tearoff(winrt::guid const& id, void** object)
const noexcept override {
if (m_inner) return m_inner.as(id, object);
return E_NOINTERFACE;
}
auto Sync() { return m_inner.as<ISynchronize>(); }
STDMETHODIMP Reset() { return Sync()->Reset(); }
STDMETHODIMP Signal() {
auto hr = return Sync()->Signal();
printf("Call completed!\n"); // do cool stuff here
return hr;
}
STDMETHODIMP Wait(DWORD flags, DWORD timeout) {
return Sync()->Wait(flags, timeout);
}
};
Let’s take this out for a spin.
int main(int, char**)
{
winrt::init_apartment(winrt::apartment_type::multi_threaded);
auto pipe = CreateSlowPipeOnOtherThread();
auto outer = winrt::make_self<MySynchronize>();
auto factory = pipe.as<ICallFactory>();
winrt::check_hresult(factory->CreateCall(
__uuidof(::AsyncIPipeByte), winrt::get_unknown(*outer),
__uuidof(::IUnknown), outer->m_inner.put()));
auto call = outer.as<::AsyncIPipeByte>();
printf("Beginning the Pull\n");
winrt::check_hresult(call->Begin_Pull(100));
printf("Doing something else for a while...\n");
Sleep(100);
printf("Getting the answer\n");
BYTE buffer[100];
ULONG actual;
winrt::check_hresult(call->Finish_Pull(buffer, &actual));
printf("Pulled %lu bytes\n", actual);
return 0;
}