我在编写一个用作 IE 中工具栏的 COM 组件时遇到了一个有趣的问题。基本上,如果您在 IE 中同时打开多个选项卡,COM 对象的各个实例都会发生扭曲。请耐心听我说。
假设我通过右键单击几个不同的链接并在新选项卡中打开它们来同时打开五个浏览器选项卡。现在,我的工具栏的一个功能涉及在网页中选择文本,然后单击按钮将该文本复制到工具栏中。那么让我们在选项卡 3 中执行此操作。我们选择文本并单击按钮,但那里什么也没有。但是,如果我们在选项卡 2 中选择文本,然后返回到选项卡 3 并单击按钮,我们将在选项卡 2 中选择文本。所以...选项卡 3 中的工具栏从选项卡 2 获取内容。不好。
我将此问题追溯到 COM 对象(工具栏)内的静态引用。
[ComVisible(true), Guid("2CC75392-1182-470D-BECC-EFA33E629AB8")]
[CLSCompliant(false)]
public sealed class Toolbar : ADXIEToolbar
{
public static Toolbar Instance;
public Toolbar()
{
Instance = this;
InitializeComponent();
}
...other code...
}
请注意,每个 IE 选项卡仅存在一个工具栏实例。
该引用没有正确分配,几乎就像它不是线程安全的(它不是),而是不是域安全的或其他什么。有时它会引用另一个实例。与其他静态字段甚至线程安全单例相同。我不明白。
另请注意,如果我将此工具栏(在 InitializeComponent 内)的引用传递给控件,我也会遇到同样的问题。
this.publicationDateCb.Toolbar = this;
该引用有时会指向不同的选项卡。
如果我使用纯粹基于订阅的模型,静态引用绝对为零,并以工具栏作为裁判,那么事情似乎工作正常。这基本上意味着我必须重新设计程序,使类之间没有直接交互——它们触发工具栏订阅的事件,调用其他类中的方法。哎哟。
那么我应该采用该模型(这可能是理想的,但我在这里已经很远了)还是我在这里缺少一个简单的修复?
其他注意事项:
- 所有 IE 选项卡都在单独的进程中运行。
- BHO/工具栏与 IE 选项卡在同一进程中运行。
- 我正在使用 Internet Explorer 的 Add-In-Express 来处理 IE 集成。
- 该项目是为 .NET 3.5 编写的;加载程序使用.NET 2.0
I am having an interesting issue with a COM component written to function as a toolbar in IE. Basically if you open up several tabs at once in IE the individual instances of the COM objects get all twisted around. Bear with me here.
Say I open up five browser tabs all at once by right clicking several different links and opening them in new tabs. Now a function of my toolbar involves selecting text in the web page and then clicking a button to copy that text into the Toolbar. So let's do that in tab 3. We select text and click the button and nothing is there. However, if we select text in tab 2, then go back to tab 3 and click the button we get the text selected in tab 2. So...the toolbar in tab 3 getting stuff from tab 2. Not good.
I have traced this problem back to static references inside our COM object, the toolbar.
[ComVisible(true), Guid("2CC75392-1182-470D-BECC-EFA33E629AB8")]
[CLSCompliant(false)]
public sealed class Toolbar : ADXIEToolbar
{
public static Toolbar Instance;
public Toolbar()
{
Instance = this;
InitializeComponent();
}
...other code...
}
Note only one toolbar instance exists per each IE tab.
This reference doesn't get assigned properly, almost like it isn't thread safe (it isn't) but instead not domain safe or something. It will sometimes reference another instance down the line. Same with other static fields and even thread-safe singletons. I don't get it.
Also note that if I pass a reference to this toolbar (inside InitializeComponent) to a control I have the same issue.
this.publicationDateCb.Toolbar = this;
This reference will sometimes point to a different tab.
If I use a purely subscription based model with absolutely zero static references with the toolbar as the referee then things seem to work fine. This basically means I would have to re-design the program to where no classes interacted with each other directly - they fire events that the toolbar subscribes to, calling methods in other classes. Ouch.
So should I go with that model (which may be ideal but I am pretty far along here) or is there a simple fix I am missing here?
Other notes:
- All IE tabs are running in seperate processes.
- The BHO/Toolbar is running in the same process as the IE tab.
- I am using Add-In-Express for Internet Explorer to handle the IE integration.
- The project is written for .NET 3.5; the loader uses .NET 2.0
发布评论
评论(2)
如果您想在所有工具栏中共享所选文本,您可以查看:http://www.add-in-express.com/creating-addins-blog/2009/06/19/internet-explorer-plugin-settings-synchronize/
If you want to share your selected text within all your toolbars you can look at: http://www.add-in-express.com/creating-addins-blog/2009/06/19/internet-explorer-plugin-settings-synchronize/
问题解决了,但静态引用消失了。我做了一些事情:
首先,我将目标 .NET 版本更改为 4.0。显然,用 4.0 编写的 BHO 工作得更好 - 我找不到证实这一说法的链接,但我在某处读过它。
更重要的是,我完全取消了程序集中的静态引用。我摆脱了单例,而是为 Toolbar 类中的每个以前的单例类创建了一个属性,该属性始终是唯一的。然后,每当类需要引用以前的单例时,我都会传递对工具栏的引用。
所以...构造函数现在看起来像这样:
假设RegistryData 需要调用Messaging。
巨大的痛苦,对吗?工作时间。但问题解决了。如果这个问题仅与 Add-In-Express 有关,我不会感到震惊。
Problem solved but static references are gone. I did a few things:
First off, I changed the target .NET version to 4.0. Apparently BHOs written in 4.0 work better - I can't find a link to substantiate this claim but I have read it somewhere.
More importantly I did away with static references within the assembly altogether. I got rid of the singletons and instead created a property for each former singleton class in my Toolbar class, which will always be unique. I then passed a reference to the Toolbar whenever a class needed to reference a former singleton.
So...constructors look like this now:
And let's say RegistryData needs to call Messaging.
Huge pain, right? Hours of work. But problem solved. I would not be shocked if this issue were related exclusively to Add-In-Express.