我正在为.net WebBrowser控件提供自定义命名空间和二进制行为,并且在特定情况下它可以正常工作。使用以下代码,断点(标有●
)全部命中,我的命名空间已正确实现,并完成了以下行为:
int IServiceProvider.QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
{
int hr = Native.E_NOINTERFACE;
ppvObject = IntPtr.Zero;
if (riid == IidClsid.IID_IElementBehaviorFactory)
{
// Returning S_OK tells the html host to query for our IHostBehaviorInit.
● hr = Native.S_OK;
}
else if (riid == IidClsid.IID_IHostBehaviorInit)
{
ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IHostBehaviorInit));
● hr = Native.S_OK;
}
else if (guidService == IidClsid.IID_IInternetSecurityManager)
{
ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IInternetSecurityManager));
● hr = Native.S_OK;
}
return hr;
}
但是,由于测试页中的脚本错误,第一个和第二个断点仅被命中。如果我修复错误或抑制错误,断点永远不会命中。例如,以下代码阻止我的名称空间和行为被注册:
WebBrowser.Document.Window.Error += OnWebBrowserDocumentWindowError;
public void OnWebBrowserDocumentWindowError (object sender, IHTMLEventObj e)
{
e.Handled = true;
}
这就是MSDN documentation for IHostBehaviorInit所说的:
MSHTML调用主机应用程序的
IServiceProvider::QueryService
来请求IElementBehaviorFactory
接口,并向主机请求IHostBehaviorInit
接口。如果IHostBehaviorInit
接口可用,则MSHTML会调用IHostBehaviorInit::PopulateNamespaceTable
方法。然后,宿主应用程序可以查询MSHTML以查找IElementNamespaceTable
接口,并使用IElementNamespaceTable::AddNamespace
方法将其他命名空间附加到命名空间表。
我注意到,如果我点击<select>
打开下拉列表,第一个和第二个断点会突然发生。这真是奇怪的行为,任何人都可以帮我解决这个问题吗?
答案 0 :(得分:2)
这可能不会直接回答这个问题,但对于一个简单的评论来说,它太冗长了。
为什么在前两种情况下比较riid
而不是guidService
?看起来像是一个错误,请改用guidService
。
此外,一旦您确定了所请求的服务,就不应该使用Marshal.GetComInterfaceForObject
,因为riid
和guidService
可能会有所不同。相反,请使用Marshal.GetIUnknownForObject
和Marshal.QueryInterface
:
IntPtr unk = Marshal.GetIUnknownForObject(this);
try
{
return Marshal.QueryInterface(unk, ref riid, out ppvObject);
}
finally
{
Marshal.Release(unk);
}
此外,您实施IServiceProvider
的方式可能会影响MSHTML如何选择。我建议您使用IProfferService
。我有一个关于如何将IProfferService
与WebBrowser
here一起使用的完整示例。