[英]How to get started with developing Internet Explorer extensions?
这里有没有人有开发 IE 扩展的经验,可以分享他们的知识? 这将包括代码示例、良好示例的链接、流程文档或任何内容。
我真的很想这样做,但是我遇到了糟糕的文档,糟糕的代码/示例代码/缺乏的巨大墙壁。 您可以提供的任何帮助/资源将不胜感激。
具体来说,我想从如何从 IE 扩展中访问/操作 DOM 开始。
编辑,更多细节:
理想情况下,我想放置一个工具栏按钮,单击该按钮时,会弹出一个包含指向外部站点链接的菜单。 我还想根据某些条件访问 DOM 并在页面上植入 JavaScript。
在 IE 扩展中保留信息的最佳方法是什么? 在 Firefox/Chrome/大多数现代浏览器中,您使用window.localStorage
,但显然对于 IE8/IE7,这不是一个选项。 也许是 SQLite DB 之类的? 可以假设 .NET 4.0 将安装在用户的计算机上吗?
我不想使用 Spice IE,因为我也想构建一个与 IE9 兼容的。 我也在这个问题中添加了 C++ 标签,因为如果用 C++ 构建一个更好,我可以做到。
[更新] 我正在更新此答案以在Windows 10 x64和Visual Studio 2017 Community 中使用Internet Explorer 11 。 此答案的先前版本(适用于 Windows 7 x64 和 Visual Studio 2010 中的 Internet Explorer 8)位于此答案的底部。
我使用的是Visual Studio 2017 Community 、 C# 、.Net Framework 4.6.1 ,所以其中一些步骤对您来说可能略有不同。
您需要以管理员身份打开 Visual Studio来构建解决方案,以便构建后脚本可以注册 BHO(需要注册表访问权限)。
首先创建一个类库。 我打电话给我的InternetExplorerExtension 。
将这些引用添加到项目中:
"Microsoft Internet Controls"
"Microsoft.mshtml"
注意:不知何故,MSHTML 没有在我的系统中注册,即使我可以在添加引用窗口中找到。 这在构建时导致错误:
找不到类型库“MSHTML”的包装程序集
可以在http://techninotes.blogspot.com/2016/08/fixing-cannot-find-wrapper-assembly-for.html找到修复程序,或者,您可以运行此批处理脚本:
"%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat"
cd "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\IDE\PublicAssemblies"
regasm Microsoft.mshtml.dll
gacutil /i Microsoft.mshtml.dll
创建以下文件:
IE插件
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 was used to prevent this method being executed more than once in IE8... but now it seems to not work anymore.
//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
}
}
互操作文件
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
和一个 Ok Button
。 将按钮的DialogResult设置为Ok 。 将此代码放在表单代码中:
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
在构建事件选项卡中,将构建后事件命令行设置为:
"%ProgramFiles(x86)%\\Microsoft SDKs\\Windows\\v10.0A\\bin\\NETFX 4.6.1 Tools\\gacutil.exe" /f /i "$(TargetDir)$(TargetFileName)"\n\n "%windir%\\Microsoft.NET\\Framework\\v4.0.30319\\RegAsm.exe" /取消注册 "$(TargetDir)$(TargetFileName)"\n\n "%windir%\\Microsoft.NET\\Framework\\v4.0.30319\\RegAsm.exe" "$(TargetDir)$(TargetFileName)"
注意:即使我的计算机是 x64,我也使用了非 x64 gacutil.exe
的路径并且它可以工作......特定于 x64 的路径是:
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\gacutil.exe
64 位 IE需要 64 位编译和 64 位注册 BHO。 虽然我只能使用 32 位 IE11 进行调试,但 32 位注册扩展也可以通过运行 64 位 IE11 来运行。
这个答案似乎有一些关于这个的额外信息: https : //stackoverflow.com/a/23004613/195417
如果需要,可以使用 64 位 regasm:
%windir%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe
此附加组件的工作原理
我没有改变附加组件的行为...看看下面的 IE8 部分的描述。
伙计……这工作量很大! 我很好奇如何做到这一点,所以我自己做了。
首先……功劳不全是我的。 这是我在这些网站上发现的内容的汇编:
当然,我希望我的回答具有您所问的功能:
我将逐步描述它,我如何设法在Windows 7 x64 中使用Internet Explorer 8做到这一点……请注意,我无法在其他配置中进行测试。 希望你明白=)
我使用的是Visual Studio 2010 、 C# 4 、 .Net Framework 4 ,因此其中一些步骤对您来说可能略有不同。
创建了一个类库。 我打电话给我的InternetExplorerExtension 。
将这些引用添加到项目中:
注意:这些引用可能位于每台计算机的不同位置。
这是我在 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" />
以与更新的 IE11 文件相同的方式创建文件。
IE插件
您可以从 IE11 版本中取消注释以下行:
...
// @Eric Stob: Thanks for this hint!
// This was used to prevent this method being executed more than once in IE8... but now it seems to not work anymore.
if (pDisp != this.site)
return;
...
互操作文件
与 IE11 版本相同。
最后是一个表单,我们将使用它来配置选项。 在这个表单中放置一个TextBox
和一个 Ok Button
。 将按钮的DialogResult设置为Ok 。 IE11插件的代码相同。
在项目属性中,执行以下操作:
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)"\n\n "C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\RegAsm.exe" /取消注册 "$(TargetDir)$(TargetFileName)"\n\n "C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\RegAsm.exe" "$(TargetDir)$(TargetFileName)"
注意:由于我的电脑是 x64,所以我的机器上 gacutil 可执行文件的路径中有一个特定的 x64,在你的机器上可能会有所不同。
64 位 IE需要 64 位编译和 64 位注册 BHO。 使用 64 位 RegAsm.exe(通常位于 C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\RegAsm.exe)
此附加组件的工作原理
它遍历所有 DOM 树,替换使用按钮配置的文本,本身带有黄色背景。 如果您单击泛黄的文本,它会调用动态插入页面的 javascript 函数。 默认词是“浏览器”,所以它匹配很多! 编辑:更改要突出显示的字符串后,您必须单击 URL 框并按 Enter... F5 不起作用,我认为这是因为 F5 被视为“导航”,并且需要监听导航事件(也许)。 稍后我会尝试修复它。
现在,是时候离开了。 我很累。 随意提问……因为我要去旅行,所以我可能无法回答……3天后我回来了,但我会在此期间尝试来这里。
IE 扩展的状态实际上非常令人难过。 您拥有 IE5 浏览器助手对象的旧模型(是的,那些臭名昭著的 BHO,当时每个人都喜欢阻止)、工具栏和新的 IE 加速器。 即便如此,兼容性有时也会中断。 我曾经为 IE6 维护一个与 IE7 中断的扩展,所以有些东西已经改变了。 在大多数情况下,据我所知(我已经很多年没有接触过 BHO),您仍然需要使用活动模板库(有点像 Microsoft 的 COM 的 STL)对它们进行编码,而且仅适用于 C++。 你可以用 C# 做 COM Interop,然后用 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 已经过时了。 我仍然希望这会有所帮助。
编辑:我想我可以在这里抛出最后一个信息来源。 当我在 BHO 上工作时,我正在查看我的笔记。 这篇文章让我开始接触它们。 它有点旧,但是很好地解释了您在使用 IE BHO(例如 IObjectWithSite)时将使用的 ATL 接口。 我认为它解释得很好,当时对我帮助很大。 http://msdn.microsoft.com/en-us/library/bb250436.aspx我还检查了 GregC 发布的示例。 它至少适用于 IE8,并且与 VS 2010 兼容,因此如果您想使用 C#,您可以从那里开始并查看 Jon Skeet 的书。 (C# in Depth 2nd edition)第 13 章提供了大量有关 C# 4 中新功能的信息,您可以使用这些信息使与 COM 的交互更好。 (我仍然建议你用 C++ 做你的插件)
另一种很酷的方法是检查:
它是一个基于 JS 和 jquery 的框架,它允许您使用单个通用 JS 代码为 IE、FF 和 Chrome 开发浏览器扩展。 基本上,框架完成了所有繁琐的工作,剩下的就是编写应用程序代码。
开发 C# BHO 是一件麻烦事。 它涉及大量令人讨厌的 COM 代码和 p/invoke 调用。
我在这里有一个基本完成的 C# BHO,你可以随意使用它的源代码。 我说“主要” ,因为我从来没有弄清楚如何在 IE 保护模式下保存 appdata 。
多年来,我一直在使用 IE 的网络浏览器控件,在此过程中,一个名字一遍又一遍地出现并发布了有用的帖子:Igor Tandetnik
如果我正在开发一个扩展,我会瞄准一个 BHO,然后开始搜索:
BHO 伊戈尔·坦德尼克
或者
浏览器助手对象 Igor Tandetnik
他的帖子往往非常详细,他知道自己在说什么。
您会发现自己在 COM 和 ATL 编程中耳目一新。 有关示例演练,请查看: http : //msdn.microsoft.com/en-us/library/ms976373.aspx
显然已经解决了,但对于其他用户,我会推荐SpicIE framework 。 我已经基于它做了我自己的扩展。 它只支持 Internet Explorer 7/8 官方,但我在 Internet Explorer 6-10 (从 Windows XP 到 Windows 8 Consumer Preview)上测试了它并且它工作正常。 不幸的是,最新版本中存在一些错误,因此我必须修复它们并发布自己的版本: http : //archive.msdn.microsoft.com/SpicIE/Thread/View.aspx?ThreadId=5251
我同意 Robert Harvey 的观点,C# 4.0 具有改进的 COM 互操作性。 这是一些较旧的 C# 代码,迫切需要重写。
http://www.codeproject.com/KB/cs/Attach_BHO_with_C_.aspx
这是通过避免 ATL 并使用 Spartan COM 来简化事情的尝试:
如果您不想重新发明轮子,则可以尝试Add In Express for IE 。 我已经将该产品用于VSTO 的东西,它非常好。 他们还有一个有用的论坛和快速的支持。
我热烈推荐您这篇 Pavel Zolnikov 于 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 享受吧!
在 Build Events 选项卡中,将 Post-build events 命令行设置为:(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)"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.