Add-in Express™ for Internet Explorer® and Microsoft® .netAdd-in Express Home > Add-in Express for Internet Explorer > Online Guide > How an IE add-on works: tabs, windows, threads, instancing How your add-on loads into IE
Shims
Internet Explorer is unmanaged while an Add-in Express based add-on is a managed class library. Therefore, there must be some software located between IE and your add-on;
the software, or the shim, follows the rules for IE add-ons and, at appropriate moment, loads the .NET Framework and starts the add-on.
Add-in Express Loader
An Add-in Express based IE add-on is supplied with a special precompiled shim - Add-in Express Loader. The loader supplied as 32-bit and 64-bit
DLLs (adxloader.dll, adxloader64.dll) is designed to fulfill the following basic tasks: it loads the .NET Framework, creates a
unique AppDomain for the add-on, and loads the add-on into the AppDomain. Advanced options are provided to the developer by the manifest file
(adxloader.dll.manifest) that may have the following look:
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<assemblyIdentity name="MyIEAddon14, PublicKeyToken=f9f39773da5c568a" />
<loaderSettings generateLogFile="true" shadowCopyEnabled="true"
privileges="administrator" configFileName="app.config"
clrVersion="{major[[.minor].build]}">
<logFileLocation>C:\MyLog.txt</logFileLocation>
</loaderSettings>
</configuration>
The loader allows generating a log file containing useful information about errors on the add-in loading stage. The file is located here:
My Documents\Add-in Express\adxloader.log. Also, you can disable the Shadow Copy feature of the Add-in Express Loader, which is enabled by default
(see Deploying - shadow copy?). The privileges attribute accepts the "user"
string indicating that the installer generated by an Add-in Express based setup project can be run with non-administrator privileges.
The only user-installable IE extension type is IE Bar. All other project types require using the "administrator" string for this attribute.
When an Add-in Express based project is being built, the loader files are copied from the Loader folder of your project to the output directory
of the setup project(s).
How your IE add-on works
On using Add-in Express for IE modules
The version of IE is available in theModule.IEVersion. The IE application object (it's a COM object) is available in theModule.IEObj.
For the document loaded in the current IE tab, see theModule.HTMLDocument; it returns an object of the mshtml.HTMLDocument type, it's a COM object, too.
Note that COM objects (and all classes defined in mshtml are COM classes) cannot cross the process boundaries. That is, when implementing any sort of
communication between instances of your module, you may need to create a method returning information provided by a COM object rather than using the
COM object directly in your code. For example, consider an add-on that deals with documents opened in different IE tabs. If such an add-on acquires
HTMLDocument.documentElement from another module instance and uses it directly, this can result in an exception because HTMLDocument.documentElement
returns a COM object and no COM object can cross the boundaries of the process in which it was created. The approach allowing you to avoid such an
exception can be found in the code of the Advanced Search sample add-on (download it here ): check how the GetHTMLText property is defined and used.
IEModule plus IE bars and toolbars: there and back again
To access the IE bar (IE toolbar) from your IE module, you use theModule.Bars (theModule.Toolbars) to get a collection of ADXIEBarItem
(ADXIEToolBarItem) objects; every object provides access to the BarObj (ToolBarObj) property, which returns the corresponding ADXIEBar (ADXIEToolbar).
For instance, the code below demonstrates calling a public method defined in an ADXIEBar from the IE module:
VB.NET
Dim barItem As AddinExpress.IE.ADXIEBarItem = Me.Bars(0)
Dim barObj As AddinExpress.IE.ADXIEBar = barItem.BarObj
Dim myBar As MyIEAddon1.MyIEBar1 = CType(aBar, MyIEAddon1.MyIEBar1)
myBar.MyMethod()
C#
AddinExpress.IE.ADXIEBarItem barItem = this.Bars[0];
AddinExpress.IE.ADXIEBar barObj = barItem.BarObj;
MyIEAddon1.MyIEBar1 myBar = barObj as MyIEAddon1.MyIEBar1;
myBar.MyMethod();
To access the IE module form the IE bar (IE toolbar), use ADXIEBar.Module (ADXIEToolbar.Module).
Tabbing
The ADXIEModule.IsTabbedBrowsingEnabled property informs you whether tabbing is enabled or not. When the user opens a tab, the
OnTabCreated and then OnTabActivated events are raised. At appropriate moments OnTabMoved and OnTabClosed occur. You can activate
any given tab programmatically only if ADXIEModule.IsQuickTabsEnabled is true; this means that the Quick Tabs feature of IE7, IE8
and IE9 is enabled. To activate a tab, you call ADXIEModule.TabActivate; this causes the OnTabChanging and OnTabChanged events to fire.
In IE6, you use the OnConnect event of the module to get to know when a window is opened and use the HTML Events component to handle
the OnActivate event of the Window HTML element.
Note that all tab-related methods work asynchronously. The tab-related methods are TabActivate, TabFirst, TabLast, TabNext and
TabPrevious methods that activate the current, first, last, next and previous tabs respectively. Another tab-related method is TabClose.
It closes the current tab (also asynchronously). All the methods above are available in ADXIEModule only.
Windowing and threading
IE opens its windows in separate threads. Once an IE window is opened, IE creates an instance of your IE module, toolbar (IE toolbar module),
or IE bar (IE bar module); the instance fires the OnConnect event; the instance fires the OnDisconnect event when the current tab (window in IE6)
is closing. You can identify an instance of the IE module by the ID of the thread that opens that tab (window). Below you will find how different
IE versions open their windows.
IE6 opens IE windows in several threads running within several processes.
IE7 may open several main windows in the same or in different processes if tabbing is enabled and depending on the way you open
IE windows; each main window contains tab windows running in threads of their own.
IE8 and IE9 may open several main windows. Each of them runs in several threads of the same process and contains tab
windows that run in threads of their own if tabbing is enabled and depending on the way you open IE windows as well on the operating system that you use.
And here are some useful properties:
- Process ID - theModule.ProcessID
- Thread ID - theModule.ThreadID
- IE main window - theModule.MainWindowHandle
- IE tab window - theModule.ParentHandle; in IE6, this property returns the same value as theModule.MainWindowHandle
- Tabbing is enabled - ADXIEModule.IsTabbedBrowsingEnabled
- IE Module - ADXIEBar.Module, ADXIEToolbar.Module
Instancing
In whatever way a tab (or window in IE6) is opened, this creates a new instance of the add-on (ADXIEModule), toolbar (ADXIEToolbar,
ADXIEToolbarModule) or IE bar (ADXIEBar, ADXIEBarModule). This also creates new instances of main menu items and context menu items;
all of them work in the same thread identifiable via theModule.ThreadID. The only thing that works in another thread or even process
(IE8, IE9) is the commands that you add onto the Command Bar toolbar (IE7, IE8 and IE9); an instance of a command is created for every
main IE window identifiable via theModule.MainWindowHandle.
So, the module of your IE extension is created for every IE tab. The total number of module instances is available in the GetModuleCount property
(GetBarCount,GetToolbarCount). You can access any instance using either GetModuleByIndex or GetModuleByThread (GetBarByIndex, GetBarByThread,
GetToolbarByIndex, GetToolbarByThread); make sure that you supply these methods with proper values provided by GetModuleIndex (GetBarIndex,
GetToolbarIndex) and ThreadID.
You can call any public property or method of any module instance even if it runs in another process. This is implemented via Remoting.
For that reason, such calls are synchronous.
Note.Mshtml-related classes cannot cross process boundaries; instead of returning such an object in a property/method, you need to return the
actual information needed such as the URL string or HTML code.
The sample code below demonstrates using a method defined in the module in order to get the URL of the HTML document opened in the current
tab (window in IE6). The method is invoked from an Explorer bar; the resulting value is used to fill in a ListBox on the IE bar.
'...
Public Class MyIEBar1
Inherits AddinExpress.IE.ADXIEBar
Friend WithEvents ListBox1 As System.Windows.Forms.ListBox
Friend WithEvents Button1 As System.Windows.Forms.Button
'...
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
'System.Diagnostics.Debugger.Launch()
Me.ListBox1.Items.Clear()
Dim theModule As MyIEAddon1.IEModule = _
CType(Me.Module, MyIEAddon1.IEModule)
For i As Integer = 0 To theModule.GetModuleCount - 1
Dim aModule As MyIEAddon1.IEModule = _
CType(theModule.GetModuleByIndex(i), MyIEAddon1.IEModule)
Me.ListBox1.Items.Add(aModule.GetURL())
Next
End Sub
End Class
'...
Public Class IEModule
Inherits AddinExpress.IE.ADXIEModule
'...
Friend Function GetURL() As String
Return Me.HTMLDocument.url
End Function
End Class
Messaging
Here we talk about features available for ADXIEModule, ADXIEBarModule, ADXIEBar, ADXIEToolbarModule, and ADXIEToolbar.
The SendMessage, SendMessageToInstance and SendMessageToAll methods provide an asynchronous way to invoke the functionality of the current,
specified or of all instances of a module, toolbar, or Explorer bar. This is implemented by sending a WinAPI message to a hidden window
that Add-in Express maintains. For that reason, SendMessageToInstance provides the nativeHandle parameter, a proper value for which
can be obtained using the NativeWindowHandle property. You can also use the FindNativeWindows method; it allows finding hidden windows
that belong to the same main window or process in IE. On the receiver side, you filter incoming messages (there will be a huge lot of
non-related window messages!) and invoke the functionality required in the OnSendMessage event.
The code below demonstrates using SendMessageToAll to keep the same state of a checkbox through all instances of an IE bar.
Friend Class MessageConstants
'window messages
Public Shared ReadOnly WM_USER As Integer = 1024
'custom
Public Shared ReadOnly WM_CHECKED As Integer = WM_USER + 10000
Public Shared ReadOnly WM_UNCHECKED As Integer = WM_USER + 10001
End Class
'...
Public Class MyIEBar1
Inherits AddinExpress.IE.ADXIEBar
Friend WithEvents CheckBox1 As System.Windows.Forms.CheckBox
Private IsProgrammaticChange As Boolean = False
'...
Private Sub CheckBox1_CheckedChanged( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles CheckBox1.CheckedChanged
'System.Diagnostics.Debugger.Launch()
If IsProgrammaticChange Then Exit Sub
'do my stuff
If Me.CheckBox1.Checked Then
Me.SendMessageToAll(MessageConstants.WM_CHECKED, _
IntPtr.Zero, IntPtr.Zero)
Else
Me.SendMessageToAll(MessageConstants.WM_UNCHECKED, _
IntPtr.Zero, IntPtr.Zero)
End If
End Sub
Private Sub MyIEBar1_OnSendMessage( _
ByVal e As AddinExpress.IE.ADXIESendMessageEventArgs) _
Handles MyBase.OnSendMessage
If e.Message = MessageConstants.WM_CHECKED Then
IsProgrammaticChange = True
Me.CheckBox1.Checked = True
IsProgrammaticChange = False
ElseIf e.Message = MessageConstants.WM_UNCHECKED Then
IsProgrammaticChange = True
Me.CheckBox1.Checked = False
IsProgrammaticChange = False
End If
End Sub
End Class
Back to Add-in Express for Internet Explorer homepage |