如何泵COM消息?

我想等Webbrowser控件完成导航。 所以我创build一个事件 ,然后我想等待它被设置:

procedure TContoso.NavigatetoEmpty(Webbrowser: IWebbrowser2); begin FEvent.ResetEvent; Webbrowser.Navigate2('about:blank'); //Event is signalled in the DocumentComplete event Self.WaitFor; end;

然后我在DocumentComplete事件中设置事件:

procedure TContoso.DocumentComplete(ASender: TObject; const pdisp: Idispatch; const URL: OleVariant); var doc: IHTMLDocument2; begin if (pdisp <> FWebbrowser.DefaultInterface) then begin //This DocumentComplete event is for another frame Exit; end; //Set the event that it's complete FEvent.SetEvent; end;

问题在于如何等待这个事件的发生。

等待它

第一反应就是等待事件被触发:

shell扩展不能在Windows-Explorer中工作,但在其他程序中工作?

如何通过Idispatch公开COM函数的服务器可以区分不同的客户端调用函数而不传递任何ID参数?

什么是操作HNet_ConnectionProperties的C ++代码

COM对象注册中断

COM与WMI提供的信息

procedure TContoso.WaitFor; begin FEvent.WaitFor; end;

问题在于DocumentComplete事件永远不会触发,因为应用程序永远不会空闲以允许COM事件通过。

忙碌的睡眠等待

我的第一反应是忙着睡觉,等着一面旗帜:

procedure TContoso.NavigatetoEmpty(Webbrowser: IWebbrowser2); begin FIsDocumentComplete := False; Webbrowser.Navigate2('about:blank'); //Flag is set in the DocumentComplete event Self.WaitFor; end; procedure TContoso.WaitFor; var n: Iterations; const MaxIterations = 25; //100ms each * 10 * 5 = 5 seconds begin while n < MaxIterations do begin if FIsDocumentComplete then Exit; Inc(n); Sleep(100); //100ms end; end;

Sleep问题在于它不允许应用程序进行足够的空闲以允许COM事件消息通过。

使用CoWaitForMultipleHandles

经过研究,似乎COM人创build了一个function正是为这种情况创build的:

当单线程公寓(STA)中的线程阻塞时,我们将为您抽出一些消息。 在阻塞期间的消息抽取是微软的黑色艺术之一。 过多抽取会导致重新进入,从而使您的应用程序所做的假设无效。 抽得太less导致僵局。 从Windows 2000开始,OLE32公开了CoWaitForMultipleHandles,这样你就可以抽取“恰到好处的数量”。

所以我试了一下:

procedure TContoso.WaitFor; var hr: HRESULT; dwIndex: DWORD; begin hr := CoWaitForMultipleHandles(0,5000,1,@FEvent.Handle,{out}dwIndex); OleCheck(hr); end;

问题是,只是不工作; 它不允许COM事件出现。

使用UseCOMWait等待

我也可以尝试delphi自己的秘密特征:使用COMWait

将UseCOMWait设置为True以确保当线程被阻塞并等待对象时,任何STA COM调用都可以返回到此线程中。

优秀! 让我们使用:

FEvent := TEvent.Create(True); function TContoso.WaitFor: Boolean; begin FEvent.WaitFor; end;

除此之外不行; 因为callback事件永远不会被触发。

MsgWaitForMultipleBugs

所以现在我开始深入研究可怕, 可怕 , 可怕可怕错误,容易出错,重新入侵诱导,马虎,需要鼠标微调,有时会崩溃MsgWaitForMultipleObjects世界:

function TContoso.WaitFor: Boolean; var // hr: HRESULT; // dwIndex: DWORD; // msg: TMsg; dwRes: DWORD; begin // hr := CoWaitForMultipleHandles(0,{out}dwIndex); // OleCheck(hr); // Result := (hr = S_OK); Result := False; while (True) do begin dwRes := MsgWaitForMultipleObjects(1,False,QS_SENDMESSAGE); if (dwRes = WAIT_OBJECT_0) then begin //Our event signalled Result := True; Exit; end else if (dwRes = WAIT_TIMEOUT) then begin //We waited our five seconds; give up Exit; end else if (dwRes = WAIT_ABANDONED_0) then begin //Our event object was destroyed; something's wrong Exit; end else if (dwRes = (WAIT_OBJECT_0+1)) then begin GetMessage(msg,0); if msg.message = WM_QUIT then begin { http://blogs.msdn.com/oldnewthing/archive/2005/02/22/378018.aspx PeekMessage will always return WM_QUIT. If we get it,we need to cancel what we're doing and "re-throw" the quit message. The other important thing about modality is that a WM_QUIT message always breaks the modal loop. Remember this in your own modal loops! If ever you call the PeekMessage function or The GetMessage function and get a WM_QUIT message,you must not only exit your modal loop,but you must also re-generate the WM_QUIT message (via the PostQuitMessage message) so the next outer layer will see the WM_QUIT message and do its cleanup as well. If you fail to propagate the message,the next outer layer will not kNow that it needs to quit,and the program will seem to "get stuck" in its shutdown code,forcing the user to terminate the process the hard way. } PostQuitMessage(msg.wParam); Exit; end; TranslateMessage(msg); dispatchMessage(msg); end; end;

上面的代码错误的,因为:

我不知道是什么样的消息来唤醒(com事件发送?)

我不知道我不想调用GetMessage,因为它获取消息; 我只想得到COM消息(见第一点)

我可能应该使用PeekMessage(请参阅第2点)

我不知道是否必须在循环中调用GetMessage,直到它返回false(请参阅旧的新事物 )

我已经编程了足够长的时间,如果我要抽出我自己的信息,就远远地逃走。

问题

所以我有四个问题。 所有相关。 这篇文章是四个之一:

如何使Webbrower.Navigate2同步?

如何泵COM消息?

泵COM消息是否导致COM事件callback?

如何使用CoWaitForMultipleHandles

我在写,并使用delphi。 但是显然任何本地代码都可以工作(C,C ++,Assembly,Machine code)。

也可以看看

MSDN博客: pipe理阻止 – 克里斯Brumme

CoWaitForMultipleHandles API的行为不像logging

Visual Studio论坛: 如何使用“CoWaitForMultipleHandles”?

MSDN: CoWaitForMultipleHandles函数

MSDN博客: 公寓和在CLR泵 – 克里斯Brumme

哪些阻塞操作导致STA线程抽取COM消息?

debugging在dllhost.exe中运行的inproc com服务器

如何使COM对象的方法不在主线程中运行

MIDL(常量)引用

是否有shell扩展点击处理程序

TYPE_E_BUFFERTOOSMALL和disP_E_BUFFERTOOSMALL HRESULT值有什么区别?

总之,你必须正常地收集所有消息,你不能自己挑选COM消息(此外,没有记录的消息,你可以自己偷看/泵,他们只知道COM的内部)。

如何使Webbrower.Navigate2同步?

你不能。 但是,您不必等待OnDocumentComplete事件。 您可以在NavigatetoEmpty()本身内忙闲循环,直到Webbrowser的ReadyState属性为READYSTATE_COMPLETE ,当消息等待处理时抽取消息队列:

procedure TContoso.NavigatetoEmpty(Webbrowser: IWebbrowser2); begin Webbrowser.Navigate2('about:blank'); while (Webbrowser.ReadyState <> READYSTATE_COMPLETE) and (not Application.Terminated) do begin // if MsgWaitForMultipleObjects(0,Pointer(nil)^,QS_ALLINPUT) = WAIT_OBJECT_0 then // if GetQueueStatus(QS_ALLINPUT) <> 0 then Application.ProcessMessages; end; end;

如何泵COM消息?

你不能,不能自己反正。 抽出一切,并准备好处理由此导致的任何折返问题。

泵COM消息是否导致COM事件回调?

是。

如何使用CoWaitForMultipleHandles

尝试这样的事情:

procedure TContoso.NavigatetoEmpty(Webbrowser: IWebbrowser2); var hEvent: THandle; dwIndex: DWORD; hr: HRESULT; begin // when UseCOMWait() is true,TEvent.WaitFor() does not wait for,or // notify,when messages are pending in the queue,so use // CoWaitForMultipleHandles() directly instead. But you have to still // use a waitable object,just don't signal it... hEvent := CreateEvent(nil,True,nil); if hEvent = 0 then RaiseLastOSError; try Webbrowser.Navigate2('about:blank'); while (Webbrowser.ReadyState <> READYSTATE_COMPLETE) and (not Application.Terminated) do begin hr := CoWaitForMultipleHandles(COWAIT_INPUTAVAILABLE,hEvent,dwIndex); case hr of S_OK: Application.ProcessMessages; RPC_S_CALLPENDING,RPC_E_TIMEOUT: begin end; else RaiseLastOSError(hr); end; end; finally CloseHandle(hEvent); end; end;

相关文章

### 创建一个gRPC服务项目(grpc服务端)和一个 webapi项目(...
一、SiganlR 使用的协议类型 1.websocket即时通讯协议 2.Ser...
.Net 6 WebApi 项目 在Linux系统上 打包成Docker镜像,发布为...
一、 PD简介PowerDesigner 是一个集所有现代建模技术于一身的...
一、存储过程 存储过程就像数据库中运行的方法(函数) 优点:...
一、Ueditor的下载 1、百度编辑器下载地址:http://ueditor....