控件自动注册到VS2005工具箱的方法非常简单,尝试中我使用了两种方法,其实核心都只要掌握DTE,EnvDTE80的使用。
方法一(参考网文):
一、系统环境说明:
1.系统盘为C盘
2.VS2005安装目录:C:/Program Files/Microsoft Visual Studio 8
二、操作步骤:
1.整理要注册到工具箱的控件DLL文件
首先,在C:/Documents and Settings/[你的用户名]/My Documents/Visual Studio 2005/目录下查找是否有名为[Controls]的文件夹,如果没有则新建此文件夹;然后再在[Controls]文件夹下新建一文件夹,名称自定义(注意,此文件夹的名称就是注册成功后在[工具箱]里的[选项卡]的名称)。这里我把文件夹取名为“MyControls”,之后把要注册到工具箱的控件DLL文件放入“MyControls”文件夹内。
2.制作注册程序
(1)新建一个控制台项目;
(2)添加引用:
EnvDTE
文件路径:C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/PublicAssemblies/EnvDTE.dll
EnvDTE80
文件路径:C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/PublicAssemblies/EnvDTE80.dll
Microsoft.VisualBasic
文件路径:Microsoft.VisualBasic C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Microsoft.VisualBasic.dll
(3)制作控件的安装程序
try
{
if (myDTE2 == null)
{
MessageBox.Show("无法调用DTE!");
return;
}
myDTE2.ExecuteCommand("Tools.InstallCommunityControls", string.Empty);
System.Runtime.InteropServices.Marshal.ReleaseComObject(myDTE2);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
(4)编译
3.运行注册
关闭VS2005的所有进程,然后运行上一步制作的注册程序。运行完毕后,打开VS2005,我们就可以看到新增加的一个选项卡[MyControls]了,展开此选项卡,就可以看到自己的控件了! ^_^
另外请注意:
多次运行注册时,如果注册不成功的话,请打开注册表,搜索HKEY_USERS/[名称不同]/Software/Microsoft/VisualStudio/8.0/UserToolBoxControls下是否有你现在要注册的选项卡名,例如:“MyControls”,如果有请先删除,再运行注册程序。
很久没有把方法二补上,真的很累,五一就要到了,又没有假,只有在周末稍微有点时间的时候,再加点东西吧。
方法二:
一、创建一个新的控制台程序项目,别忘了添加DTE引用哦,具体就参考方法一。
二、建立控件注册类StandardToolBoxCreator,其中包括一个子类ComponentData,你也可以把独立出来:
/// 控件数据类
/// </summary>
public class ComponentData
{
public ComponentData(string name, string fullPath)
{
this._name = name;
this._fullPath = fullPath;
}
private string _name;
private string _fullPath;
/**//// <summary>
/// 控件类型的完全限定名称
/// </summary>
public string Name
{
get { return _name; }
set { _name = value; }
}
/**//// <summary>
/// 控件文件的完全路径
/// </summary>
public string FullPath
{
get { return _fullPath; }
set { _fullPath = value; }
}
}
1.对象初始化的时候读取控件DLL文件列表INI文件ComponentList.ini,每个DLL文件之间用“;”隔开,可以是相对路径也可以是绝对路径,其方法是GetDllFiles();
2.如果有可用的DLL文件则进行注册操作RunCreator(DTE dte)
首先打开一个临时Solution激活DTE,然后获得DTE的工具箱窗体Window中的工具箱ToolBox,再通过工具箱获取选项卡集合,并创建自己的选项卡,最后在自己的选项卡内注册控件。
static string INIFILE = "ComponentList.ini";
static string TABLABLE = "Mr.Cell控件";
ArrayList DllFileList = new ArrayList();
List<ComponentData> ComponentDataList = new List<ComponentData>();
#endregion
构造函数 #region 构造函数
/**//// <summary>
/// 构造函数
/// </summary>
public ToolBoxCreator()
{
GetDllFiles();
}
#endregion
获取需要安装的控件Dll文件 #region 获取需要安装的控件Dll文件
/**//// <summary>
/// 获取需要安装的控件Dll文件
/// <remarks>
/// DllFileList 控件Dll文件的绝对路径集合
/// </remarks>
/// </summary>
private void GetDllFiles()
{
try
{
string text = new StreamReader(INIFILE,Encoding.GetEncoding("GB2312")).ReadLine();
if (text == null) return;
ArrayList list = new ArrayList();
list.AddRange(text.Split(new char[] { ';' }));
Console.WriteLine("需要安装的控件文件:/n {0}", text);
if (list.Count < 1) return;
foreach (string strFile in list)
{
string fileFullPath = Path.GetFullPath(strFile);
if (!File.Exists(fileFullPath))
{
Console.WriteLine("找不到文件:{0}", strFile);
continue;
}
this.DllFileList.Add(fileFullPath);
}
}
catch
{
throw;
}
}
#endregion
获取所有需要安装的控件数据 #region 获取所有需要安装的控件数据
/**//// <summary>
/// 获取所有需要安装的控件数据
/// <remarks>
/// <see cref="ComponetData"/>类型的对象集合
/// </remarks>
/// </summary>
public List<ComponentData> GetAllComponentsData()
{
List<ComponentData> list = new List<ComponentData>();
for (int i = 0; i < this.DllFileList.Count; i++)
{
if (this.DllFileList[i].ToString().Trim() == string.Empty)
continue;
GetAllComponents(this.DllFileList[i].ToString().Trim(), list);
}
return list;
}
#endregion
获取所有需要安装的控件类型 #region 获取所有需要安装的控件类型
/**//// <summary>
/// 获取所有需要安装的控件类型
/// </summary>
/// <param name="dllFile">Dll文件</param>
/// <param name="list"></param>
private void GetAllComponents(string dllFile, List<ComponentData> list)
{
Assembly assembly;
try
{
assembly = Assembly.LoadFrom(dllFile);
foreach (Type type in assembly.GetTypes())
{
try
{
if ((type.IsPublic && !type.IsAbstract) && ((type.IsSubclassOf(typeof(Component)) || typeof(IComponent).IsAssignableFrom(type)) || type.IsSubclassOf(typeof(Control))))
{
ToolboxItemAttribute attribute = (ToolboxItemAttribute)TypeDescriptor.GetAttributes(type)[typeof(ToolboxItemAttribute)];
if ((attribute != null) && (attribute.ToolboxItemTypeName != ""))
{
ToolboxItemFilterAttribute filterAttribute = (ToolboxItemFilterAttribute)TypeDescriptor.GetAttributes(type)[typeof(ToolboxItemFilterAttribute)];
if ((((filterAttribute == null) || (filterAttribute.FilterType != ToolboxItemFilterType.Require))) && (type.GetConstructor(new Type[0]) != null))
{
list.Add(new ComponentData(type.FullName,dllFile));
}
}
}
}
catch
{
Console.WriteLine("类型分析错误!- {0}", new object[] { type.Name });
return;
}
}
}
catch
{
Console.WriteLine(dllFile + "文件错误!");
return;
}
}
#endregion
控件注册到工具箱的方法 #region 控件注册到工具箱的方法
/**//// <summary>
/// 控件注册到工具箱的方法
/// </summary>
/// <param name="dte"></param>
public void RunCreator(DTE dte)
{
if (DllFileList.Count < 1)
{
Console.WriteLine("没有任何需要安装的控件文件!");
return;
}
string tempProjPath = Path.Combine(Path.GetTempPath(), "tempProj");
if (Directory.Exists(tempProjPath))
{
Directory.Delete(tempProjPath, true);
}
string fileName = ((Solution2)dte.Solution).GetProjectTemplate("WindowsApplication.zip", "CSharp");
switch (fileName)
{
case null:
case "":
fileName = ((Solution2)dte.Solution).GetProjectTemplate("WindowsApplication.zip", "VisualBasic");
break;
}
if ((fileName == null) || (fileName == string.Empty))
{
fileName = ((Solution2)dte.Solution).GetProjectTemplate("WindowsApplication.zip", "csharp");
}
dte.Solution.AddFromTemplate(fileName, tempProjPath, "temp.cproj", false);
dte.Solution.Close(false);
//dte.ExecuteCommand("View.PropertiesWindow", "");
Window window = dte.Windows.Item(EnvDTE.Constants.vsWindowKindToolbox);
window.Activate();
ToolBox box = window.Object as ToolBox;
ToolBoxTabs tabs = box.ToolBoxTabs;
ToolBoxTab tab;
try
{
tab = FindOrCreateTab(tabs, TABLABLE, false);
if (tab != null)
{
tab.Delete();
Console.WriteLine("删除工具箱标签[" + TABLABLE + "]");
}
tab = FindOrCreateTab(tabs, TABLABLE, true);
dte.ExecuteCommand("View.PropertiesWindow", "");
tab.Activate();
this.ComponentDataList = this.GetAllComponentsData();
if (ComponentDataList.Count < 1) return;
Console.WriteLine("开始注册控件");
foreach (ComponentData componentData in this.ComponentDataList)
{
RegComponent(tab, componentData);
}
Console.WriteLine("添加控件成功!");
}
catch
{
throw;
}
}
#endregion
注册组件 #region 注册组件
/**//// <summary>
/// 注册组件
/// </summary>
/// <param name="tab"></param>
/// <param name="componentData"></param>
private void RegComponent(ToolBoxTab tab, ComponentData componentData)
{
string data = string.Format("{0},{1}", componentData.Name, componentData.FullPath);
tab.ToolBoxItems.Add(componentData.Name, data, vsToolBoxItemFormat.vsToolBoxItemFormatDotNETComponent);
Console.WriteLine(componentData.Name);
}
#endregion
查找标签或创建标签 #region 查找标签或创建标签
/**//// <summary>
/// 查找标签或创建标签
/// </summary>
/// <param name="tabs">工具箱的标签集合</param>
/// <param name="name">标签名称</param>
/// <param name="create">如果找不到,是否以查找名称为新的标签名称来进行创建</param>
/// <returns>查找到的标签对象或新建的标签对象</returns>
private ToolBoxTab FindOrCreateTab(ToolBoxTabs tabs, string name, bool create)
{
if (tabs != null)
{
for (int i = 1; i <= tabs.Count; i++)
{
ToolBoxTab tab = tabs.Item(i);
if (tab.Name == name)
{
return tab;
}
}
if (create)
{
Console.WriteLine("创建工具箱标签[" + TABLABLE + "]");
return tabs.Add(name);
}
}
return null;
}
#endregion
三、改写Main方法,代码如下:
{
try
{
if (Program.IsOpenVS())
{
Console.WriteLine("请关闭VS2005!");
}
else
{
Type typeFromProgID = Type.GetTypeFromProgID("VisualStudio.DTE.8.0", false);
DTE myDTE = (DTE)Activator.CreateInstance(typeFromProgID);
if (myDTE == null)
{
Console.WriteLine("无法打开DTE!");
return;
}
MessageFilter.Register();
try
{
ToolBoxCreator creator = new ToolBoxCreator();
creator.RunCreator(myDTE);
}
catch
{
throw;
}
finally
{
myDTE.Quit();
MessageFilter.Revoke();
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
IsOpenVS()方法用来判断VS2005是否启动,如果启动,注册控件到工具箱将不会成功!
/// 是否打开VS2005
/// </summary>
/// <returns></returns>
public static bool IsOpenVS()
{
foreach (System.Diagnostics.Process process in System.Diagnostics.Process.GetProcesses())
{
if (process.ProcessName == "devenv")
{
return true;
}
}
return false;
}
接下就启动DTE,如果成功则进行消息过滤器注册,这样主要为了避免程序在进行注册时发生中断。过滤器实现IMessageFilter接口,为了避免与System.Windows.Form.IMessageFilter接口重名,这里改作IOleMessageFilter:
/// 用来处理当前线程的并发事件,只有一个消息过滤器能够注册到单线程中,多线程没有消息过滤器
/// <remarks>
/// MessageFilter:消息过滤器
/// </remarks>
/// </summary>
[ComImport, Guid( " 00000016-0000-0000-C000-000000000046 " ), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IOleMessageFilter
{
[PreserveSig]
int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);
[PreserveSig]
int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
[PreserveSig]
int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
}
}
实现类:
/// 消息过滤器类
/// </summary>
internal class MessageFilter : IOleMessageFilter
{
/**//// <summary>
/// 向OLE 注册登记 IOleMessageFilter(IMessageFilter) 实例
/// </summary>
/// <param name="newfilter">将被注册到当前线程中的消息过滤器</param>
/// <param name="oldfilter">以前注册到当前线程中的消息过滤器,如果没有则为NULL</param>
/// <returns>
/// S_OK 注册或取消注册成功;
/// S_FALSE 注册或取消注册失败。
/// </returns>
[DllImport("Ole32.dll")]
private static extern int CoRegisterMessageFilter(IOleMessageFilter newfilter, out IOleMessageFilter oldfilter);
/**//// <summary>
/// 注册消息过滤器
/// </summary>
public static void Register()
{
IOleMessageFilter newfilter = new MessageFilter();
IOleMessageFilter oldfilter = null;
CoRegisterMessageFilter(newfilter, out oldfilter);
}
/**//// <summary>
/// 取消注册
/// </summary>
public static void Revoke()
{
IOleMessageFilter oldfilter = null;
CoRegisterMessageFilter(null, out oldfilter);
}
/**//// <summary>
///
/// </summary>
/// <param name="dwCallType"></param>
/// <param name="hTaskCaller"></param>
/// <param name="dwTickCount"></param>
/// <param name="lpInterfaceInfo"></param>
/// <returns>
/// SERVERCALL_ISHANDLED
/// SERVERCALL_REJECTED
/// SERVERCALL_RETRYLATER
/// </returns>
int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo)
{
return 0;//SERVERCALL_ISHANDLED
}
/**//// <summary>
/// 当COM等待远程调用回复的时候,有Windows消息出现在COM应用程序消息队列中时调用
/// </summary>
/// <param name="hTaskCallee"></param>
/// <param name="dwTickCount"></param>
/// <param name="dwPendingType"></param>
/// <returns>
/// PENDINGMSG_CANCELCALL
/// PENDINGMSG_WAITNOPROCESS
/// PENDINGMSG_WAITDEFPROCESS
/// </returns>
int IOleMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
{
return 2;//PENDINGMSG_WAITDEFPROCESS
}
/**//// <summary>
///
/// </summary>
/// <param name="hTaskCallee"></param>
/// <param name="dwTickCount"></param>
/// <param name="dwRejectType">SERVERCALL_REJECTED 或 SERVERCALL_RETRYLATER</param>
/// <returns>
/// -1 取消调用
/// Value >= 0 & < 100 立即重试
/// Value >= 100 等待Value毫秒再重新调用
/// </returns>
int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
{
if (dwRejectType == 2) //SERVERCALL_RETRYLATER
{
return 99; //如果返回值>=0 & <100 立即重试
}
return -1; //取消调用
}
}