Как начать разработку расширений Internet Explorer?
есть ли у кого-нибудь здесь опыт работы с/в разработке расширений IE, которые могут поделиться своими знаниями? Это будет включать примеры кода или ссылки на хорошие, или документацию по процессу, или что-нибудь еще.
Я действительно хочу это сделать, но я натыкаюсь на гигантскую стену с паршивой документацией, паршивым кодом/примером кода/его отсутствием. Любая помощь / ресурсы, которые вы могли бы предложить, будут очень признательны.
в частности, я хотел бы начать с того как получить доступ чтобы / манипулировать DOM из расширения IE.
редактировать, еще больше деталей:
В идеале, я хотел бы установить кнопку на панели инструментов, которая при нажатии выскочила меню, содержащее ссылки на внешние сайты. Я также хотел бы получить доступ к DOM и установить JavaScript на странице в зависимости от некоторых условий.
каков наилучший способ сохранения информации в расширении IE? В Firefox / Chrome / большинстве современных браузеров вы используете window.localStorage, но, очевидно, с IE8/IE7, это не вариант. Может быть, SQLite DB или такой? Можно предположить, что .NET 4.0 будет установлен на компьютере пользователя?
Я не хочу использовать Spice IE, как я хочу построить тот, который совместим с IE9, а также. Я также добавил тег C++ к этому вопросу, потому что если его лучше построить в C++, я могу это сделать.
10 ответов:
человек... это была большая работа! Мне было так любопытно, как это сделать, что я сделал это сам.
прежде всего... кредит-это не для меня. Это компиляция того, что я нашел, на этих сайтах:
- статья CodeProject, как сделать БХО;
- 15 секунд, но это было не 15 секунд, это заняло около 7 часов;
- учебник Microsoft, помог мне добавить команду кнопка.
- и это социальное.тема msdn, это помогло мне понять, что сборка должна быть в GAC.
- это недавнее сообщение в блоге MSDN содержит полностью рабочий пример
- многие другие сайты, в процессе обнаружения...
и, конечно, я хотел, чтобы мой ответ имел функции, которые вы спросили:
- DOM обход, чтобы найти что-то;
- кнопка, которая показывает окно (в моем случае для установки)
- сохранять настройки (я буду использовать regitry для этого)
- и, наконец, выполнить JavaScript.
я опишу его шаг за шагом, как мне удалось это сделать, работая с Internet Explorer 8, в Windows 7 x64... обратите внимание, что я не мог проверить в другой конфигурации. Надеюсь, вы понимаете =)
создание рабочего Internet Explorer 8 аддон
Я использую Visual Studio 2010,C# 4, .Net Framework 4, поэтому некоторые из этих шагов могут немного отличаться для вас.
создал библиотеку классов. Я назвал свой InternetExplorerExtension.
добавить эти ссылки в проект:
- взаимодействия.SHDocVw
- Microsoft.mshtml
примечание: эти ссылки могут быть в разных местах в каждом компьютер.
это то, что мои ссылки раздел в csproj содержит:
<Reference Include="Interop.SHDocVw, Version=1.1.0.0, Culture=neutral, PublicKeyToken=90ba9c70f846762e, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> <EmbedInteropTypes>True</EmbedInteropTypes> <HintPath>C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\Interop.SHDocVw.dll</HintPath> </Reference> <Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <EmbedInteropTypes>True</EmbedInteropTypes> </Reference> <Reference Include="System" /> <Reference Include="System.Data" /> <Reference Include="System.Drawing" /> <Reference Include="System.Windows.Forms" /> <Reference Include="System.Xml" />создайте следующие файлы:
IEAddon.cs
using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Windows.Forms; using Microsoft.Win32; using mshtml; using SHDocVw; namespace InternetExplorerExtension { [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] [Guid("D40C654D-7C51-4EB3-95B2-1E23905C2A2D")] [ProgId("MyBHO.WordHighlighter")] public class WordHighlighterBHO : IObjectWithSite, IOleCommandTarget { const string DefaultTextToHighlight = "browser"; IWebBrowser2 browser; private object site; #region Highlight Text void OnDocumentComplete(object pDisp, ref object URL) { try { // @Eric Stob: Thanks for this hint! // This will prevent this method being executed more than once. if (pDisp != this.site) return; var document2 = browser.Document as IHTMLDocument2; var document3 = browser.Document as IHTMLDocument3; var window = document2.parentWindow; window.execScript(@"function FncAddedByAddon() { alert('Message added by addon.'); }"); Queue<IHTMLDOMNode> queue = new Queue<IHTMLDOMNode>(); foreach (IHTMLDOMNode eachChild in document3.childNodes) queue.Enqueue(eachChild); while (queue.Count > 0) { // replacing desired text with a highlighted version of it var domNode = queue.Dequeue(); var textNode = domNode as IHTMLDOMTextNode; if (textNode != null) { if (textNode.data.Contains(TextToHighlight)) { var newText = textNode.data.Replace(TextToHighlight, "<span style='background-color: yellow; cursor: hand;' onclick='javascript:FncAddedByAddon()' title='Click to open script based alert window.'>" + TextToHighlight + "</span>"); var newNode = document2.createElement("span"); newNode.innerHTML = newText; domNode.replaceNode((IHTMLDOMNode)newNode); } } else { // adding children to collection var x = (IHTMLDOMChildrenCollection)(domNode.childNodes); foreach (IHTMLDOMNode eachChild in x) { if (eachChild is mshtml.IHTMLScriptElement) continue; if (eachChild is mshtml.IHTMLStyleElement) continue; queue.Enqueue(eachChild); } } } } catch (Exception ex) { MessageBox.Show(ex.Message); } } #endregion #region Load and Save Data static string TextToHighlight = DefaultTextToHighlight; public static string RegData = "Software\MyIEExtension"; [DllImport("ieframe.dll")] public static extern int IEGetWriteableHKCU(ref IntPtr phKey); private static void SaveOptions() { // In IE 7,8,9,(desktop)10 tabs run in Protected Mode // which prohibits writes to HKLM, HKCU. // Must ask IE for "Writable" registry section pointer // which will be something like HKU/S-1-7***/Software/AppDataLow/ // In "metro" IE 10 mode, tabs run in "Enhanced Protected Mode" // where BHOs are not allowed to run, except in edge cases. // see http://blogs.msdn.com/b/ieinternals/archive/2012/03/23/understanding-ie10-enhanced-protected-mode-network-security-addons-cookies-metro-desktop.aspx IntPtr phKey = new IntPtr(); var answer = IEGetWriteableHKCU(ref phKey); RegistryKey writeable_registry = RegistryKey.FromHandle( new Microsoft.Win32.SafeHandles.SafeRegistryHandle(phKey, true) ); RegistryKey registryKey = writeable_registry.OpenSubKey(RegData, true); if (registryKey == null) registryKey = writeable_registry.CreateSubKey(RegData); registryKey.SetValue("Data", TextToHighlight); writeable_registry.Close(); } private static void LoadOptions() { // In IE 7,8,9,(desktop)10 tabs run in Protected Mode // which prohibits writes to HKLM, HKCU. // Must ask IE for "Writable" registry section pointer // which will be something like HKU/S-1-7***/Software/AppDataLow/ // In "metro" IE 10 mode, tabs run in "Enhanced Protected Mode" // where BHOs are not allowed to run, except in edge cases. // see http://blogs.msdn.com/b/ieinternals/archive/2012/03/23/understanding-ie10-enhanced-protected-mode-network-security-addons-cookies-metro-desktop.aspx IntPtr phKey = new IntPtr(); var answer = IEGetWriteableHKCU(ref phKey); RegistryKey writeable_registry = RegistryKey.FromHandle( new Microsoft.Win32.SafeHandles.SafeRegistryHandle(phKey, true) ); RegistryKey registryKey = writeable_registry.OpenSubKey(RegData, true); if (registryKey == null) registryKey = writeable_registry.CreateSubKey(RegData); registryKey.SetValue("Data", TextToHighlight); if (registryKey == null) { TextToHighlight = DefaultTextToHighlight; } else { TextToHighlight = (string)registryKey.GetValue("Data"); } writeable_registry.Close(); } #endregion [Guid("6D5140C1-7436-11CE-8034-00AA006009FA")] [InterfaceType(1)] public interface IServiceProvider { int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject); } #region Implementation of IObjectWithSite int IObjectWithSite.SetSite(object site) { this.site = site; if (site != null) { LoadOptions(); var serviceProv = (IServiceProvider)this.site; var guidIWebBrowserApp = Marshal.GenerateGuidForType(typeof(IWebBrowserApp)); // new Guid("0002DF05-0000-0000-C000-000000000046"); var guidIWebBrowser2 = Marshal.GenerateGuidForType(typeof(IWebBrowser2)); // new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"); IntPtr intPtr; serviceProv.QueryService(ref guidIWebBrowserApp, ref guidIWebBrowser2, out intPtr); browser = (IWebBrowser2)Marshal.GetObjectForIUnknown(intPtr); ((DWebBrowserEvents2_Event)browser).DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete); } else { ((DWebBrowserEvents2_Event)browser).DocumentComplete -= new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete); browser = null; } return 0; } int IObjectWithSite.GetSite(ref Guid guid, out IntPtr ppvSite) { IntPtr punk = Marshal.GetIUnknownForObject(browser); int hr = Marshal.QueryInterface(punk, ref guid, out ppvSite); Marshal.Release(punk); return hr; } #endregion #region Implementation of IOleCommandTarget int IOleCommandTarget.QueryStatus(IntPtr pguidCmdGroup, uint cCmds, ref OLECMD prgCmds, IntPtr pCmdText) { return 0; } int IOleCommandTarget.Exec(IntPtr pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { try { // Accessing the document from the command-bar. var document = browser.Document as IHTMLDocument2; var window = document.parentWindow; var result = window.execScript(@"alert('You will now be allowed to configure the text to highlight...');"); var form = new HighlighterOptionsForm(); form.InputText = TextToHighlight; if (form.ShowDialog() != DialogResult.Cancel) { TextToHighlight = form.InputText; SaveOptions(); } } catch (Exception ex) { MessageBox.Show(ex.Message); } return 0; } #endregion #region Registering with regasm public static string RegBHO = "Software\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects"; public static string RegCmd = "Software\Microsoft\Internet Explorer\Extensions"; [ComRegisterFunction] public static void RegisterBHO(Type type) { string guid = type.GUID.ToString("B"); // BHO { RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegBHO, true); if (registryKey == null) registryKey = Registry.LocalMachine.CreateSubKey(RegBHO); RegistryKey key = registryKey.OpenSubKey(guid); if (key == null) key = registryKey.CreateSubKey(guid); key.SetValue("Alright", 1); registryKey.Close(); key.Close(); } // Command { RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegCmd, true); if (registryKey == null) registryKey = Registry.LocalMachine.CreateSubKey(RegCmd); RegistryKey key = registryKey.OpenSubKey(guid); if (key == null) key = registryKey.CreateSubKey(guid); key.SetValue("ButtonText", "Highlighter options"); key.SetValue("CLSID", "{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}"); key.SetValue("ClsidExtension", guid); key.SetValue("Icon", ""); key.SetValue("HotIcon", ""); key.SetValue("Default Visible", "Yes"); key.SetValue("MenuText", "&Highlighter options"); key.SetValue("ToolTip", "Highlighter options"); //key.SetValue("KeyPath", "no"); registryKey.Close(); key.Close(); } } [ComUnregisterFunction] public static void UnregisterBHO(Type type) { string guid = type.GUID.ToString("B"); // BHO { RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegBHO, true); if (registryKey != null) registryKey.DeleteSubKey(guid, false); } // Command { RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegCmd, true); if (registryKey != null) registryKey.DeleteSubKey(guid, false); } } #endregion } }взаимодействия.cs
using System; using System.Runtime.InteropServices; namespace InternetExplorerExtension { [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")] public interface IObjectWithSite { [PreserveSig] int SetSite([MarshalAs(UnmanagedType.IUnknown)]object site); [PreserveSig] int GetSite(ref Guid guid, [MarshalAs(UnmanagedType.IUnknown)]out IntPtr ppvSite); } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct OLECMDTEXT { public uint cmdtextf; public uint cwActual; public uint cwBuf; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)] public char rgwz; } [StructLayout(LayoutKind.Sequential)] public struct OLECMD { public uint cmdID; public uint cmdf; } [ComImport(), ComVisible(true), Guid("B722BCCB-4E68-101B-A2BC-00AA00404770"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] public interface IOleCommandTarget { [return: MarshalAs(UnmanagedType.I4)] [PreserveSig] int QueryStatus( [In] IntPtr pguidCmdGroup, [In, MarshalAs(UnmanagedType.U4)] uint cCmds, [In, Out, MarshalAs(UnmanagedType.Struct)] ref OLECMD prgCmds, //This parameter must be IntPtr, as it can be null [In, Out] IntPtr pCmdText); [return: MarshalAs(UnmanagedType.I4)] [PreserveSig] int Exec( //[In] ref Guid pguidCmdGroup, //have to be IntPtr, since null values are unacceptable //and null is used as default group! [In] IntPtr pguidCmdGroup, [In, MarshalAs(UnmanagedType.U4)] uint nCmdID, [In, MarshalAs(UnmanagedType.U4)] uint nCmdexecopt, [In] IntPtr pvaIn, [In, Out] IntPtr pvaOut); } }и, наконец, форма, которую мы будем использовать для настройки параметров. В таком виде поставить
TextBoxи ОКButton. Установите DialogResult кнопки ОК. Поместите этот код в форму код:using System.Windows.Forms; namespace InternetExplorerExtension { public partial class HighlighterOptionsForm : Form { public HighlighterOptionsForm() { InitializeComponent(); } public string InputText { get { return this.textBox1.Text; } set { this.textBox1.Text = value; } } } }в свойствах проекта выполните следующие действия:
- подписать сборку сильным ключом;
- на вкладке "отладка" установить Запустить Внешнюю Программу до
C:\Program Files (x86)\Internet Explorer\iexplore.exe- на вкладке "отладка" установить Аргументы Командной Строки до
http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouchна вкладке События сборки установите командная строка событий после сборки к:
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\gacutil.exe" /f /i "$(TargetDir)$(TargetFileName)" "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" /unregister "$(TargetDir)$(TargetFileName)" "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"внимание: поскольку мой компьютер x64, есть определенный x64 внутри пути исполняемого файла gacutil на моей машине, который может отличаться на вашем.
64bit IE нужна 64бит-составлен и 64bit зарегистрирована БДО. Использовать 64бит RegAsm.exe (обычно живет в C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe)
как работает этот аддон
он пересекает все DOM дерево, заменяющее текст, настроенное с помощью кнопки, само по себе с желтым фоном. Если вы нажмете на пожелтевшие тексты, он вызывает функцию JavaScript, которая была вставлена на страницу динамически. По умолчанию слово "браузер", так что он соответствует многим из них! EDIT: после изменения строки, которая должна быть выделена, необходимо щелкнуть поле URL и нажать Enter... F5 не будет работать, я думаю, что это потому, что F5 рассматривается как "навигация", и это потребует прослушивания перейдите событие (возможно). Я постараюсь исправить это позже.
теперь, пора идти. Я очень устал. Не стесняйтесь задавать вопросы... может быть, я не смогу ответить, так как я собираюсь в путешествие... через 3 дня я вернусь, но я постараюсь приехать сюда в то же время.
еще один классный подход будет проверить:
это платформа, основанная на JS с jquery, которая позволяет разрабатывать браузеры расширения для IE, FF и Chrome, используя один общий код JS. В основном фреймворк делает всю неприятную работу, и вы остаетесь с написанием кода приложений.
состояние для расширений IE на самом деле довольно грустно. У вас есть старая модель IE5 Browser Helper Object (да, те печально известные BHOs, которые все любили блокировать в тот же день), панели инструментов и новые ускорители для IE. Даже тогда совместимость иногда будет нарушаться. Раньше я поддерживал расширение для IE6, которое сломалось с IE7, поэтому есть некоторые вещи, которые изменились. По большей части, насколько я знаю (я не касался BHOs в течение многих лет) вам все еще нужно кодировать их с помощью Active Библиотеки шаблонов (вроде как STL для microsoft COM) и как таковые только для C++. Вы можете сделать com-взаимодействие с C# и уйти от этого в C#, но, вероятно, это будет слишком сложно для того, что стоит. Во всяком случае, если вы заинтересованы в кодировании своего собственного расширения для IE (что вполне вероятно, если вы хотите, чтобы ваши расширения были доступны во всех основных браузерах) вот официальные Microsoft Ресурсы.
http://msdn.microsoft.com/en-us/library/aa753587 (v=vs. 85). aspx
и для ускорителей, которые являются новыми в IE8 вы можете проверить это.
http://msdn.microsoft.com/en-us/library/cc289775 (v=vs. 85). aspx
Я согласен, что документация ужасна, и API-интерфейсы довольно устарели. И все же я надеюсь, что это поможет.
EDIT: я думаю, я могу бросить один последний источник информации здесь. Я смотрел через мои заметки о прошлом, когда я работал над BHOs. И это статья, которая заставила меня начать с ними. Он довольно старый, но имеет хорошее объяснение интерфейсов ATL, которые вы будете использовать при работе с IE BHOs (например, IObjectWithSite). Я думаю, что это довольно хорошо объяснил и помог мне много тогда. http://msdn.microsoft.com/en-us/library/bb250436.aspx Я также проверил пример, который опубликовал GregC. Он работает по крайней мере с IE8, и он совместим с VS 2010, поэтому, если вы хотите сделать C#, вы можете начать там и взглянуть на книгу Джона Скита. (C# In Depth 2nd edition) В главе 13 содержится много информации о новых функциях в C# 4, которые можно использовать для улучшения взаимодействия с COM. (Я бы все равно рекомендовал вам сделать ваш addin в C++)
разработка C# BHOs-это боль в заднице. Он включает в себя много неприглядного COM-кода и вызовов p/invoke.
У меня есть в основном готовый C# BHO здесь, который вы можете использовать источник для все, что вы хотите. Я говорю "больше", потому что я никогда не выяснить, как сохранить appdata в IE защищенном режиме.
Я уже много лет работаю с управлением WebBrowser IE, и в течение них снова и снова появляется одно имя с полезными сообщениями: Игорь Тандетник
Если бы я разрабатывал расширение, я бы нацелился на BHO и начал гуглить для:
БДО Игорь Tandetnik
или
Browser Helper Object Игорь Тандетник
его сообщения часто очень подробно, и он знает, что он говорит о.
вы окажетесь по уши в программировании COM и ATL. По учебнику, проверить: http://msdn.microsoft.com/en-us/library/ms976373.aspx
Я согласен с Робертом Харви, C# 4.0 имеет улучшенное com-взаимодействие. Вот немного старого кода C#, отчаянно нуждающегося в переписывании.
http://www.codeproject.com/KB/cs/Attach_BHO_with_C_.aspx
Это попытка упростить вещи, избегая ATL и идя с Spartan COM:
Если вы не пытаетесь изобрести колесо, вы можете попробовать добавить в экспресс для IE . Я использовал продукт для ВСТО вещи, и это довольно хорошо. Также у них есть полезный форум и быстрая поддержка.
Это, очевидно, решена, но для других пользователей, я бы рекомендовал основы SpicIE. Я сделал свое собственное расширение на его основе. Он поддерживает только Internet Explorer 7/8 officialy, но я проверено, что на Internet Explorer 6-10 (от Windows XP до Windows 8 Consumer Preview) и это работает отлично. К сожалению, в последнем выпуске были некоторые ошибки, поэтому мне пришлось их исправить и сделать свой собственный освобождать: http://archive.msdn.microsoft.com/SpicIE/Thread/View.aspx?ThreadId=5251
Я горячо предлагаю вам этот пост Павла Зольникова, опубликованный в 2002 году!
http://www.codeproject.com/Articles/2219/Extending-Explorer-with-Band-Objects-using-NET-and
Он основан на использовании объектов Band и компилируется с использованием .Net 2.0. Исходный код предоставляется и открывается и компилируется в Visual Studio 2013 с. Как вы прочитаете в комментариях к сообщению, он отлично работает для IE 11 и на Windows 7 и Windows 10. Он работал отлично ну для меня на Windows 7 + SP1 и IE 11 Наслаждайтесь!
на вкладке События сборки установите в командной строке события после сборки значение: (x64) указано ниже
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\gacutil.exe" /if "$(TargetDir)$(TargetFileName)" "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" /u "$(TargetDir)$(TargetFileName)" "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"Я хочу вкладку события сборки, установить командную строку событий после сборки (32-разрядная операционная система)
"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\gacutil.exe" /if "$(TargetDir)$(TargetFileName)" "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" /u "$(TargetDir)$(TargetFileName)" "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"

Comments