VS2010控制集中介绍
在使用VS的过程中,熟悉其相关控件的使用非常重要。接下来简单列出VS的控件并简单介绍一下它们的用途:
BackgroundWorker 组件:使表单或控件能够异步运行操作。
BindingNavigator 控件(Windows 为绑定到数据的控件提供导航和操作用户界面 (UI)。
BindingSource 组件:封装数据源以绑定到控件。
按钮控件(Windows 窗体):显示用户可以单击以执行操作的标准按钮。
CheckBox 控件(Windows 窗体):指示条件是打开还是关闭。 CheckedListBox 控件(Windows 窗体):显示项目列表,每个项目旁边都有一个复选框。 ColorDialog 组件(Windows 窗体):允许用户从调色板中选择颜色,并将自定义颜色添加到预配置对话框中的调色板中。 ComboBox 控件(Windows 窗体):在下拉组合框中显示数据。 ContextMenu 组件(Windows 窗体):为用户提供易于访问的菜单,其中包含与所选对象关联的常用命令。尽管 ContextMenuStrip 替换并添加了早期版本的 ContextMenu 控件的附加功能,但如果需要,可以保留 ContextMenu 以实现向后兼容和将来使用。 ContextMenuStrip控件:代表快捷菜单。尽管 ContextMenuStrip 替换并添加了早期版本的 ContextMenu 控件的附加功能,但如果需要,可以保留 ContextMenu 以实现向后兼容和将来使用。 DataGrid 控件(Windows 窗体):显示数据集中的表格数据并允许更新数据源。 DataGridView 控件(Windows 窗体):提供灵活、可扩展的系统来显示和编辑表格数据。 DateTimePicker 控件(Windows 窗体):允许用户从日期或时间列表中选择单个项目。对话框控件和组件(Windows 窗体):描述一组允许用户与应用程序或系统执行标准交互的控件。 DomainUpDown 控件(Windows 窗体):显示用户可以浏览和选择的文本字符串。 ErrorProvider 组件(Windows 窗体):以非侵入式方式向用户显示错误信息。 FlowLayoutPanel 控件(Windows 窗体):表示水平或垂直动态布局其内容的面板。 FolderBrowserDialog 组件(Windows 窗体):显示一个界面,用户可以通过该界面浏览和选择目录或创建新目录。 • FontDialog 组件(Windows 窗体):显示系统上当前安装的字体。格罗upBox 控件(Windows 窗体):为其他控件提供可识别的分组。 HelpProvider 组件(Windows 窗体):将 HTML 帮助文件与基于 Windows 的应用程序相关联。 HScrollBar 和 VScrollBar 控件(Windows 窗体):提供通过在应用程序或控件中水平或垂直滚动来导航项目列表或大量信息的能力。 ImageList 组件(Windows 窗体):在其他控件之上显示图像。标签控件(Windows 窗体):显示用户无法编辑的文本。 LinkLabel 控件(Windows 窗体):允许您将 Web 样式链接添加到 Windows 窗体应用程序。 ListBox 控件(Windows 窗体):允许用户从预定义列表中选择一项或多项。 ListView 控件(Windows 窗体):以 Windows 资源管理器的方式显示带有图标的项目列表。 MainMenu 组件(Windows 窗体):在运行时显示菜单。虽然 MenuStrip 取代了早期版本的 MainMenu 控件并添加了功能;您可以选择保留 MainMenu 以实现向后兼容和将来使用。 MaskedTextBox 控件(Windows 窗体):限制窗体中用户输入的格式。 MenuStrip 控件(Windows 窗体):为窗体提供菜单系统。虽然 MenuStrip 取代了早期版本的 MainMenu 控件并添加了功能;您可以选择保留 MainMenu 以实现向后兼容和将来使用。 MonthCalendar 控件(Windows 窗体):显示直观的图形界面,供用户查看和设置日期信息。 NotifyIcon 组件(Windows 窗体):显示在后台运行且没有用户界面的进程的图标。 NumericUpDown 控件(Windows 窗体):显示用户可以浏览和选择的数字。 OpenFileDialog 组件(Windows 窗体):允许用户使用预配置的对话框打开文件。 PageSetupDialog 组件(Windows 窗体):通过预配置的对话框设置用于打印的页面详细信息。面板控制(Windows 窗体):为其他控件提供可识别的分组并允许滚动。 PictureBox 控件(Windows 窗体):以位图、GIF、JPEG、图元文件或图标格式显示图形。 PrintDialog 组件(Windows 窗体):选择打印机、选择要打印的页面以及确定其他与打印相关的设置。 PrintDocument 组件(Windows 窗体):设置描述在基于 Windows 的应用程序中打印内容和打印文档的属性。 PrintPreviewControl 控件(Windows 窗体):允许您创建自己的 PrintPreview 组件或对话框,而不是使用预配置的版本。 PrintPreviewDialog 控件(Windows 窗体):显示将要打印的文档。 ProgressBar 控件(Windows 窗体):以图形方式指示操作的完成进度。 RadioButton 控件(Windows 窗体):向用户显示一组两个或多个互斥选项。 RichTextBox 控件(Windows 窗体):允许用户通过格式设置输入、显示和操作文本。 SaveFileDialog 组件(Windows 窗体):选择要保存的文件以及文件的保存位置。 SoundPlayer 类:使您能够轻松地将声音包含在应用程序中。 SplitContainer 控件(Windows 窗体):允许用户调整停靠控件的大小。拆分器控件(Windows 窗体):允许用户调整停靠控件的大小(.NET Framework 版本 1.x)。 StatusBar 控件(Windows 窗体):显示与具有焦点的控件相关的状态信息。尽管 StatusStrip 替换并扩展了 StatusBar 控件的早期版本,但您可以选择保留 StatusBar 以实现向后兼容和将来使用。 StatusStrip控件:代表Windows状态栏控件。尽管 StatusStrip 替换并扩展了 StatusBar 控件的早期版本,但您可以选择保留 StatusBar 以实现向后兼容和将来使用。 TabControl 控件(Windows 窗体)?显示可包含的多个图像切片或其他控件的选项卡。 TableLayoutPanel 控件(Windows 窗体):表示在行和列的网格中动态布局其内容的面板。 TextBox 控件(Windows 窗体):允许用户进行可编辑的多行输入的文本框。定时器组件(Windows 窗体):您可以定义时间中断并定期触发事件。工具栏控件(Windows 窗体):显示激活命令的菜单和位图按钮。您可以扩展控件的功能并修改其外观和行为。虽然 ToolStrip 取代了早期版本的 ToolBar 控件并添加了功能;您可以选择保留工具栏以实现向后兼容和将来使用。 ToolStrip 控件(Windows 窗体):在 Windows 窗体应用程序中创建自定义工具栏和菜单。虽然 ToolStrip 取代了早期版本的 ToolBar 控件并添加了功能;您可以选择保留工具栏以实现向后兼容和将来使用。 ToolStripContainer 控件:在窗体的四个侧面提供面板,用于停靠、浮动和排列 ToolStrip 控件,并为传统控件提供中央 ToolStripContentPanel。 ToolStripPanel 控件:提供用于停靠、浮动和排列 ToolStrip 控件的面板。 ToolStripProgressBar控件概述:以图形方式指示操作的完成进度。 ToolStripProgressBar 通常包含在 StatusStrip 中。 ToolStripStatusLabel 控件:代表 StatusStrip 控件中的一个面板。工具提示组件(Windows 窗体):当用户指向其他控件时显示文本。 TrackBar 控件(Windows 窗体):允许您浏览大量信息或直观地调整数字设置。 TreeView 控件(Windows 窗体):显示可以展开或折叠的节点层次结构。 WebBrowser 控件(Windows 窗体):托管网页并向应用程序提供 Internet Web 浏览功能。控制有两个概念。上面介绍的主要是VS自带的控件。另一种方式是根据自己的要求自己写一个定义好的控件,加载到系统中即可。多于这是按字母顺序简单介绍了VS的大部分控件。后面会介绍这些控件的相关属性的介绍和使用。
? ?
功能介绍:
1。支持下拉、文件打开、文本输入、点击项显示描述内容。
以下业务代码调用封装的类。
类别:属性类
显示名称:名称
描述符:描述内容
编辑:编辑
私有 PropertyManage _pmc=new PropertyManage();
///
/// 绑定PropertyGrid
///
///
公共对象 GetPropertyObject()
{
#区域方案配置
属性 pp = new Property("SchemeName", "test.xml", false, true);
pp.Category =“程序配置”;
pp.DisplayName = "计划";
pp.Editor = new PropertyGridFileEditor();
_pmc.Add(pp);
#endregion
#region 仪表规格
pp = new Property("MeterType", "1S");
pp.Category =“仪表规格”;
pp.DisplayName = "仪表类型";
字符串[] s = 新字符串[] { "1S", "2S", "3S" };
pp.Converter = new DropDownListConverter(s);
_pmc.Add(pp);
pp = new Property("RatedVolt","220");
pp.Category =“仪表规格”;
pp.DisplayName = "额定电压";
pp.Descriptor = "V";
_pmc.Add(pp);
pp = new Property("额定电流", "0");
pp.Category =“仪表规格”;
pp.DisplayName = "额定电流";
pp.Descriptor = "A";
_pmc.Add(pp);
pp = new Property("RatedFreq", "60");
pp.Category =“仪表规格”;
pp.DisplayName = "额定频率";
pp.Descriptor = "Hz";
_pmc.Add(pp);
pp = new Property("相","三相四线");
pp.Category =“仪表规格”;
pp.DisplayName = "接线方式";
s=new string[]{"三相四线","三相三相","单相"};
pp.Converter = new DropDownListConverter(s);
_pmc.Add(pp);
#endregion
返回_pmc;
}
//最后PropertyGrid控件调用
www.sychzs.cnedObject = GetPropertyObject();
以下封装代码可以直接复制。错误信息是没有引用相关的命名控件。右键分析会自动添加。 (PS:修改别人的结果)
region封装了PropertyGrid属性方法
? ? //属性管理类
? ?公共类 PropertyManage :CollectionBase、ICustomTypeDescriptor
? ? {
? ? ? ? public void Add(属性值)
? ? ? ? {
? ? ? ? ? ? int 标志 = -1;
? ? ? ? ? ? if(值!= null)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? if (base.List.Count > 0)
? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? IList
? ? ? ? ? ? ? ? ? ? for (int i = 0; i < base.List.Count; i++)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ?属性 p = base.List[i] 作为属性;
? ? ? ? ? ? ? ? ? ? ? ? if (www.sychzs.cn == www.sychzs.cn)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ?标志=我;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? mList.Add(p);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? if (标志==-1)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? mList.Add(值);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? base.List.Clear();
? ? ? ? ? ? ? ? ? ? foreach(mList 中的属性 p)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? base.List.Add(p);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ?不然
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? base.List.Add(值);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? public void 删除(属性值)
? ? ? ? {
? ? ? ? ? ? if (value != null && base.List.Count > 0)
? ? ? ? ? ? ? ? base.List.Remove(value);
? ? ? ? }
? ? ? ?公共属性 this[int index]
? ? ? ? {
? ? ? ? ? ?得到
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return (Property)base.List[索引];
? ? ? ? ? ? }
? ? ? ? ? ?套装
? ? ? ? ? ? {
? ? ? ? ? ? ? ? base.List[索引] = (属性)值;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? #region ICustomTypeDescriptor 成员
? ? ? ?公共 AttributeCollection GetAttributes()
? ? ? ? {
? ? ? ? ? ? return TypeDescriptor.GetAttributes(this, true);
? ? ? ? }
? ? ? ?公共字符串 GetClassName()
? ? ? ? {
? ? ? ? ? ? return TypeDescriptor.GetClassName(this, true);
? ? ? ? }
? ? ? ?公共字符串 GetComponentName()
? ? ? ? {
? ? ? ? ? ? return TypeDescriptor.GetComponentName(this, true);
? ? ? ? }
? ? ? ? public TypeConverter GetConverter()
? ? ? ? {
? ? ? ? ? ? return TypeDescriptor.GetConverter(this, true);
? ? ? ? }
? ? ? ?公共事件描述符 GetDefaultEvent()
? ? ? ? {
? ? ? ? ? ? return TypeDescriptor.GetDefaultEvent(this, true);
? ? ? ? }
? ? ? ?公共 PropertyDescriptor GetDefaultProperty()
? ? ? ? {
? ? ? ? ? ? return TypeDescriptor.GetDefaultProperty(this, true);
? ? ? ? }
? ? ? ?公共对象 GetEditor(Type editorBaseType)
? ? ? ? {
? ? ? ? ? ? return TypeDescriptor.GetEditor(this, editorBaseType, true);
? ? ? ? }
? ? ? ? public EventDescriptorCollection GetEvents(Attribute[] 属性)
? ? ? ? {
? ? ? ? ? ? return TypeDescriptor.GetEvents(this, 属性, true);
? ? ? ? }
? ? ? ?公共 EventDescriptorCollection GetEvents()
? ? ? ? {
? ? ? ? ? ? return TypeDescriptor.GetEvents(this, true);
? ? ? ? }
? ? ? ? public PropertyDescriptorCollection GetProperties(Attribute[] 属性)
? ? ? ? {
? ? ? ? ? ? PropertyDescriptor[] newProps = new PropertyDescriptor[this.Count];
? ? ? ? ? ? for (int i = 0; i < this.Count; i++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ?属性 prop = (属性)this[i];
? ? ? ? ? ? ? ? newProps[i] = new CustomPropertyDescriptor(ref prop, 属性);
? ? ? ? ? ? }
? ? ? ? ? ?返回新的 PropertyDescriptorCollection(newProps);
? ? ? ? }
? ? ? ?公共 PropertyDescriptorCollection GetProperties()
? ? ? ? {
? ? ? ? ? ? return TypeDescriptor.GetProperties(this, true);
? ? ? ? }
? ? ? ?公共对象 GetPropertyOwner(PropertyDescriptor pd)
? ? ? ? {
? ? ? ? ? ?返回此;
? ? ? ? }
? ? ? ? #endregion
? ? }
? ? // 属性类 ?
? ?公共类属性
? ? {
? ? ? ?私有字符串_name = string.Empty;
? ? ? ?私有对象_value = null;
? ? ? ?私人布尔_readonly = false;
? ? ? ?私人布尔_visible = true;
? ? ? ?私有字符串_category = string.Empty;
? ? ? ?私有字符串_descriptor = string.Empty;
? ? ? ?类型转换器_converter = null;
? ? ? ?对象_editor = null;
? ? ? ?私有字符串_displayname = string.Empty;
? ? ? ?公共属性(字符串sName,对象sValue)
? ? ? ? {
? ? ? ? ? ? this._name = sName;
? ? ? ? ? ? this._value = sValue;
? ? ? ? }
? ? ? ? public Property(string sName, object sValue, bool sReadonly, bool sVisible)
? ? ? ? {
? ? ? ? ? ? this._name = sName;
? ? ? ? ? ? this._value = sValue;
? ? ? ? ? ? this._readonly = sReadonly;
? ? ? ? ? ? this._visible = sVisible;
? ? ? ? }
? ? ? ? public string Name ?//获得属性名 ?
? ? ? ? {
? ? ? ? ? ?获取{return_name;}
? ? ? ? ? ?设置{_名称 = 值;}
? ? ? ? }
? ? ? ?公共字符串显示名称? // 属性显示名称 ?
? ? ? ? {
? ? ? ? ?获取{return_displayname;}
? ? ? ? ? ?设置{_显示名称 = 值;}
? ? ? ? }
? ? ? ? public TypeConverter Converter ?//类型转换器,制作下拉列表时需要吗?
? ? ? ? {
? ? ? ? ?获取{return_converter;}
? ? ? ? ? ?设置{_converter =值;}
? ? ? ? }
? ? ? ? public string Category ?//属性所属的类别 ?
? ? ? ? {
? ? ? ? ?获取{return_category;}
? ? ? ? ? ?设置{_category = 值;}
? ? ? ? }
? ? ? ? public object Value ?//属性值?
? ? ? ? {
? ? ? ? ?获取{返回值;}
? ? ? ? ? ?设置{_value = 值;}
? ? ? ? }
? ? ? ?公共字符串描述符
? ? ? ? {
? ? ? ? ? ?获取{返回_描述符; }
? ? ? ? ? ?设置 { _descriptor = 值; }
? ? ? ? }
? ? ? ? public bool ReadOnly ?//是否是只读属性?
? ? ? ? {
? ? ? ? ?获取{return _readonly;}
? ? ? ? ? ?设置{_readonly =值;}
? ? ? ? }
? ? ? ? public bool Visible ?//是否可见? ?
? ? ? ? {
? ? ? ? ?获取{return_visible;}
? ? ? ? ? ?设置{_visible =值;}
? ? ? ? }
? ? ? ?公共虚拟对象编辑器? //属性编辑器?
? ? ? ? {
? ? ? ? ? ?获取{返回_editor; }
? ? ? ? ? ?设置{_editor =值;}
? ? ? ? }
? ? }
? ? //属性描述类
? ?公共类 CustomPropertyDescriptor : PropertyDescriptor
? ? {
? ? ? ?属性 m_Property;
? ? ? ?公共 CustomPropertyDescriptor(ref Property myProperty, Attribute[] attrs): base(www.sychzs.cn, attrs)
? ? ? ? {
? ? ? ? ? ? m_Property = myProperty;
? ? ? ? }
? ? ? ? #region PropertyDescriptor 重写方法
? ? ? ? public override bool CanResetValue(对象组件)
? ? ? ? {
? ? ? ? ? ?返回错误;
? ? ? ? }
? ? ? ?公共覆盖类型 ComponentType
? ? ? ? {
? ? ? ? ?获取{返回null;}
? ? ? ? }
? ? ? ?公共覆盖对象GetValue(对象组件)
? ? ? ? {
? ? ? ? ? ?返回m_Property.Value;
? ? ? ? }
? ? ? ? public override string Description
? ? ? ? {
? ? ? ? ? ? get{ return m_Property.Descriptor;}
? ? ? ? }
? ? ? ? public override string Category
? ? ? ? {
? ? ? ? ? ? get{return m_Property.Category;}
? ? ? ? }
? ? ? ? public override string DisplayName
? ? ? ? {
? ? ? ? ? ? get{return m_Property.DisplayName != "" ? m_Property.DisplayName : m_www.sychzs.cn;}
? ? ? ? }
? ? ? ? public override bool IsReadOnly
? ? ? ? {
? ? ? ? ? ? get{return m_Property.ReadOnly;}
? ? ? ? }
? ? ? ? public override void ResetValue(object component)
? ? ? ? {
? ? ? ? ? ? //Have to implement ?
? ? ? ? }
? ? ? ? public override bool ShouldSerializeValue(object component)
? ? ? ? {
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? public override void SetValue(object component, object value)
? ? ? ? {
? ? ? ? ? ? m_Property.Value = value;
? ? ? ? }
? ? ? ? public override TypeConverter Converter
? ? ? ? {
? ? ? ? ? ? get{return m_Property.Converter;}
? ? ? ? }
? ? ? ? public override Type PropertyType
? ? ? ? {
? ? ? ? ? ? get { return m_Property.Value.GetType(); }
? ? ? ? }
? ? ? ? public override object GetEditor(Type editorBaseType)
? ? ? ? {
? ? ? ? ? ? return m_Property.Editor == null ? base.GetEditor(editorBaseType) : m_Property.Editor;
? ? ? ? }
? ? ? ? #endregion
? ? }
? ? //文件对话框编辑类
? ? public class PropertyGridFileEditor : UITypeEditor ?
? ? { ?
??
? ? ? ? public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context) ?
? ? ? ? { ?
? ? ? ? ? ? return UITypeEditorEditStyle.Modal; ?
? ? ? ? } ?
??
? ? ? ? public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value) ?
? ? ? ? { ?
? ? ? ? ? ? IWindowsFormsEditorService edSvc=(IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); ?
? ? ? ? ? ? if (edSvc != null) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? // 可以打开任何特定的对话框 ?
? ? ? ? ? ? ? ? OpenFileDialog dialog = new OpenFileDialog(); ?
? ? ? ? ? ? ? ? dialog.AddExtension = false; ?
? ? ? ? ? ? ? ? if (dialog.ShowDialog().Equals(DialogResult.OK)) ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? return dialog.FileName; ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? } ?
? ? ? ? ? ? return value; ?
? ? ? ? } ?
??
? ? }
? ? //文件下拉转换类
? ? public class DropDownListConverter : StringConverter
? ? {
? ? ? ? object[] m_Objects;
? ? ? ? public DropDownListConverter(object[] objects)
? ? ? ? {
? ? ? ? ? ? m_Objects = objects;
? ? ? ? }
? ? ? ? public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
? ? ? ? {
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) ?
? ? ? ? { ?
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? public override
? ? ? ? System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
? ? ? ? {
? ? ? ? ? ? return new StandardValuesCollection(m_Objects);//可以直接在内部定义一个数组,但并不建议这样做,这样对于下拉框的灵活 ? ? ? ? ? ? //性有很大影响 ?
? ? ? ? }
? ? }
? ? #endregion
?
最近做读卡器的B/S应用程序开发,由于读卡器厂商提供的手册都是C/S版本的,而且只有一个原始的Dll包,并没有web版的,那么就只好自己动手,丰衣足食了。 ?????????要开发Web版的读卡程序,大体思路如下:
1.???????使用C#对原始的Dll进行封装,这里要封装两部分内容,一部分是串口通信的功能,一部分是对卡读写的功能。
2.???????开发ActiveX控件调用封装后的Dll,使用串口通信来对卡进行读写。
3.???????打包并发布ActiveX控件。
4.? 使用ActiveX控件。
思路1中封装代码有2个类SerialInterfaceHelper,串口通信的帮助类,MifareOneHelper,M1卡的读写帮助类,我们放在了项目CardReader.Library中。
由于本文的重点是使用VS 2010(C#)进行ActiveX控件的开发,因此思路1中的内容就不进行详述了,后面会直接给出类库可以参考。本文的实例中演示C#开发
一个ActiveX读卡器控件,实现读取卡号并显示出卡号或异常信息的功能,分成三个大的步骤来实现:开发ActiveX控件、打包并发布ActiveX控件和使用
ActiveX控件。
?? 开发ActiveX控件
???? 常见的一些ActiveX大部分是使用VB、Delphi、C++开发,使用C#开发ActiveX要解决下面三个问题:
(1)使.NET组件可以被COM调用
(2)在客户机上注册后,ActiveX控件能通过IE的安全认证
(3)已在客户机上注册时,安装包能通过IE的签名认证
开发ActiveX步骤:
1.?创建Windows Forms Control Library项目CardReader.Controls,设置项目属性能够被COM调用。
右击CardReader.Controls,选择属性,设置项目的Assembly属性,如下图1所示:
?
图1
对Make Assembly Com-Visible选项划钩。
设置项目的编译选项,如图2所示:
图2
图2中对Register for COM Interop选中,对COM组件进行注册。(注意,此处如果实在debug状态下修改的,那在调到release状态下还需要再设置一次。)
设置应用程序的AssemblyInfo属性,右击项目的Properties,打开AssemblyInfo文件,Assembly:AllowPartiallyTrustedCallers,注意添加引用System.Security,代码如下:
using?System.Reflection;
using?System.Runtime.CompilerServices;
using?System.Runtime.InteropServices;
using?System.Security;
//?General?Information?about?an?assembly?is?controlled?through?the?following?
//?set?of?attributes.?Change?these?attribute?values?to?modify?the?information
//?associated?with?an?assembly.
[assembly:?AssemblyTitle("CardReader.Controls")]
[assembly:?AssemblyDescription("")]
[assembly:?AssemblyConfiguration("")]
[assembly:?AssemblyCompany("Microsoft")]
[assembly:?AssemblyProduct("CardReader.Controls")]
[assembly:?AssemblyCopyright("Copyright???Microsoft?2011")]
[assembly:?AssemblyTrademark("")]
[assembly:?AssemblyCulture("")]
?
[assembly:AllowPartiallyTrustedCallers()]
//?Setting?ComVisible?to?false?makes?the?types?in?this?assembly?not?visible?
//?to?COM?components.??If?you?need?to?access?a?type?in?this?assembly?from?
//?COM,?set?the?ComVisible?attribute?to?true?on?that?type.
[assembly:?ComVisible(true)]
?
//?The?following?GUID?is?for?the?ID?of?the?typelib?if?this?project?is?exposed?to?COM
[assembly:?Guid("15493d85-ec9e-4c75-a237-9009a997b780")]
?
//?Version?information?for?an?assembly?consists?of?the?following?four?values:
//
//??????Major?Version
//??????Minor?Version?
//??????Build?Number
//??????Revision
//
//?You?can?specify?all?the?values?or?you?can?default?the?Build?and?Revision?Numbers?
//?by?using?the?'*'?as?shown?below:
//?[assembly:?AssemblyVersion("1.0.*")]
[assembly:?AssemblyVersion("1.0.0.0")]
[assembly:?AssemblyFileVersion("1.0.0.0")]
?
?
2.?开发读卡器用户控件,这个用户控件包含三个部分:
一个TextBox,用以显示读出的卡号
一个Button,读卡
一个Label,显示错误信息
编写读卡按钮事件的代码,完成控件开发后,为了使该用户控件作为一个ActiveX控件进行使用,还需要做以下修改:
首先,为控件类创建一个唯一的GUID,这个编号将用于B/S系统的客户端调用时使用,注意这里的GUID不能和AssemblyInf中的GUID相同,生成GUID的方法如下,
在开始-》程序中打开Microsoft Windows SDK Tools,如下图3所示:?
?
?
?
图3
点击GUID Generator,生成GUID,如下图4所示:
?
图4
COPY生成的GUID到记事本,再拷贝GUID的字符串到控件类,代码如下所示:[Guid("E395359C-86F2-4D7B-A91A-5A64B9E3BA6C")] public?partial?class?ReadCardControl?:?UserControl
其次,为了让ActiveX控件获得客户端的信任,控件类还需要实现一个名为“IObjectSafety”的接口,要创建该接口(注意,不能修改该接口的GUID值),
IObjectSafety代码如下:
????[ComImport,?Guid("1D9AD540-F2C9-4368-8697-C4AAFCCE9C55")] ????[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] ????public?interface?IObjectSafety ????{ ????????[PreserveSig] ????????void?GetInterfacceSafyOptions( ????????int?riid, ????????out?int?pdwSupportedOptions, ????????out?int?pdwEnabledOptions); ? ????????[PreserveSig] ????????void?SetInterfaceSafetyOptions( ????????int?riid, ????????int?dwOptionsSetMask, ????????int?dwEnabledOptions); ????}
注意这里要添加引用:using?System.Runtime.InteropServices;
?
3.?修改控件类,使之继承IObjectSafety接口,代码清单如下:
[Guid("E395359C-86F2-4D7B-A91A-5A64B9E3BA6C")] ????public?partial?class?ReadCardControl?:?UserControl,IObjectSafety ????{ ????????public?int?icdev;?//?通讯设备标识符 ????????public?Int16?st; ????????public?int?sec; ? ????????public?ReadCardControl() ????????{ ????????????InitializeComponent(); ????????} ????????#region?IObjectSafety?成员 ? ????????public?void?GetInterfacceSafyOptions(int?riid,?out?int?pdwSupportedOptions,?out?int?pdwEnabledOptions) ????????{ ????????????pdwSupportedOptions?=?1; ????????????pdwEnabledOptions?=?2; ????????} ? ????????public?void?SetInterfaceSafetyOptions(int?riid,?int?dwOptionsSetMask,?int?dwEnabledOptions) ????????{ ????????????throw?new?NotImplementedException(); ????????} ? ????????#endregion }
?
?? 打包并发布ActiveX
???????? ActiveX控件开发完成后,我们要讲ActiveX控件打包和发布。ActiveX控件可以使用VS 2010的安装项目进行部署,使用VS 2010创建Windows Form的安装工程就可以将ActiveX的dll进行打包。在打包时注意将ActiveX控件项目作为主输出项目,并设置其Register属性为vsdrpCOM,创建打包项目如下图5所示:
图5
创建一个Windows 安装项目,并给项目添加项目输出,如下图6所示:
图6
在添加项目输出时,我们将ActiveX项目添加进来,在项目中选择ActiveX控件项目(CardReader.Controls),Primary Out(基本输出),如下图7所示:
图7
添加完项目输出以后,在Application Folder里已经有了三个文件:CardReader.Controls.tlb、CardReader.Libary.dll、Primary Output From CardReader.Controls,同时将mwrf32.dll也打进安装包里,右击添加文件,浏览到mwrf32.dll添加进来即可。注意首先要将mwrf32.dll拷贝到ActiveX控件
项目中的Bin中,添加文件时浏览到\\CardReader\CardReader.Controls\bin\Debug中的mwrf32.dll打包进去,否则会出现找不到mwrf32.dll的错误。
添加完文件后,设置Primary Output From CardReader.Controls的Register属性为vsdrpCOM。设置完成后右击安装工程SetupCardReader,
修改其属性,如下图8所示:
图8
?????????在上图中可以设置输出的文件名,这个文件名就是打包后安装文件.MSI的文件名。设置包文件、压缩方式,CAB size,这三项均选择默认值即可。
最后设置安装URL,这里的安装URL是用来发布或者测试ActiveX的URL地址的。上图中我们将在89端口下进行测试,因此URL设置为:
http://localhost:89/CardReader
这样打包文件就生成了,我们可以打开\\CardReader\SetupCardReader\Debug看到生成了2个文件,一个是setup.exe,一个是SetupCardReader.msi,
这里的Setup.exe就是我们在使用ActiveX时的codebase文件。
打包成exe文件以后,我们可以进一步对安装文件进行打包成.cab文件,安装隐藏了msi?安装界面,类似于cabarc?打包ocx?的效果
(点击install?之后其他的都后台做了),本文中暂不讨论,感兴趣的读者可以使用CAB SDK?中的工具CABARC.EXE (下载地址?http://www.sychzs.cn/kb/310618?)来进行。
?? 使用ActiveX
打包完成后,我们就可以在应用程序中使用打包好的ActiveX控件了,创建一个web项目(CardReader.Web),在测试页面的HTML代码中添加对ActiveX控件
的引用,修改default.aspx的代码如下:
????
注意这里的clsid:E395359C-86F2-4D7B-A91A-5A64B9E3BA6C的值是我们在开发ActiveX控件时的GUID。
运行的效果图下图9所示:
?
图9
?????????图9中,我们演示了不调用串口通信和读卡程序下的效果,至于要调用串口通信和读卡程序,我将在另一篇帖子里进行详细说明。
?????????至此,使用VS 2010开发ActiveX控件的大部分功能已经完成了,在VS 2010环境中使用C#开发ActiveX控件,技术并不太困难,但是要求客户端需要安装.NET Framework。鉴于ActiveX控件一般都是实现一些简单单一的功能,所以建议使用.NET Framework 2.0/.NET Framework 4.0下开发,
本实例中我们使用了.NET Framework 4.0。
?
以上我们介绍了开发、打包、发布、使用ActiveX控件的全过程。在演示程序中,我们没有调用串口通信和读卡器Dll程序,由于我们读卡器的原始Dll是使用其它语言进行开发的,对C#来说,是非托管代码,因此我们还需要在代码级别进行非托管代码的安全性设置。
?
?其实如果我们不进行设置,只是修改了代码,运行程序以后,其出错界面如下图1所示:
?
图1
抛出异常如下:
************** Exception Text **************
System.MethodAccessException: Attempt by security transparent method 'Rare.Card.Libary.Controls.
ReadCardControl.btnRead_Click(System.Object, System.EventArgs)' to call native code through method 'Rare.Card.Libary.MifareOneHelper.rf_read(Int32, Int32, Byte[])' failed.?Methods must be security critical or
security safe-critical to call native code.
?
通过查阅MSDN,对异常的解释如下:
在?Microsoft .NET Framework 4?中,公共语言运行时?(CLR)?安全模型发生了不少变化。其中一项变化,即采用?Level2?透明性
(与?Silverlight?的安全模型非常相似)很可能影响?AllowPartiallyTrustedCallers (APTCA)?库的作者。透明性属性有三种:SecurityTransparent、SecuritySafeCritical?和?SecurityCritical。
?
SecurityTransparent:标记为?SecurityTransparent?的代码从安全性角度而言是可靠的。它不能完成任何危险操作,例如声明权限、
执行无法验证的代码或调用本机代码。它也不能直接调用?SecurityCritical?代码。
如上文所述,出于安全的考虑,所有部分受信任代码都强制为?SecurityTransparent。这也是?APTCA?库的默认透明性。
SecurityCritical:与?SecurityTransparent?不同,SecurityCritical?代码能够执行任何所需操作。它能够执行声明、
调用本机代码和其他操作。它能够调用其他方法,且不受透明性标记的限制。
只有完全受信任代码才能为?SecurityCritical。事实上,(非?APTCA)完全受信任代码默认情况下属于?SecurityCritical,
从而保护其免受透明的部分受信任调用方的调用。
SecuritySafeCritical:SecuritySafeCritical?代码起着桥梁的作用,它允许透明代码调用关键方法。SecuritySafeCritical
代码与?SecurityCritical?代码的权限相同,但它可由?SecurityTransparent?代码调用。因此,SecuritySafeCritical?代码必须以安全方式公开基础?SecurityCritical?方法(以避免一些部分受信任的恶意代码尝试通过?SecuritySafeCritical?层攻击这些方法),这一点极为重要。
与?SecurityCritical?代码一样,SecuritySafeCritical?代码必须完全受信任。
具体可以参考:
http://www.sychzs.cn/zh-cn/magazine/ee336023.aspx
?
根据MSDN的解释,问题出在了封装原始Dll的C#类库CardReader.Library上,我们可以在代码级别设置透明性属性可以解决问题。
具体解决办法如下:
1.???????设置ActiveX控件读卡代码的透明属性为:SecuritySafeCritical,设置以后的代码清单如下:
????? ?[SecuritySafeCritical]
????????///?
????????///?读卡
????????///?
????????///?
????????///?
????????private?void?btnRead_Click(object?sender,?EventArgs?e)
????????{
????????????int?i?=?0;
????????????byte[]?data?=?new?byte[16];
????????????byte[]?buff?=?new?byte[32];
?
????????????for?(i?=?0;?i?16;?i++)
????????????????data[i]?=?0;
????????????for?(i?=?0;?i?32;?i++)
????????????????buff[i]?=?0;
?
????????????st?=?MifareOneHelper.rf_read(icdev,?sec?*?4?+?1,?data);
????????????if?(st?==?0)
????????????{
????????????????SerialInterfaceHelper.hex_a(data,?buff,?16);
????????????????txtCardID.Text?=?System.Text.Encoding.ASCII.GetString(buff);
????????????????lblMsg.Text?=?"读取卡号成功!";
????????????}
????????????else
????????????????lblMsg.Text?=?"读取卡号失败!";
?
????????????//test?method
????????????//if?(string.IsNullOrEmpty(txtCardID.Text))
????????????//{
????????????//????lblMsg.Text?=?"读取数据失败!";
????????????//}
????????????//else
????????????//{
????????????//????lblMsg.Text?=?string.Format("读取数据:{0}!",?txtCardID.Text);
????????????//}
????????}
注意要添加引用:using?System.Security;
在这里注掉了测试代码,使用了串口通信和读卡代码。
2.?设置封装原始读卡器Dll的透明属性。
设置M1读卡器帮助类MifareOneHelper的透明属性为:[SecurityCritical],同时设置调用的方法MifareOneHelper.rf_read的
透明属性为[SecurityCritical]。
????设置串口通信帮助类SerialInterfaceHelper的透明属性为:[SecurityCritical],同时设置调用的方法SerialInterfaceHelper.hex_a的
透明属性为[SecurityCritical]。
?
完整代码已提供,还有2个地方需要注意的是,客户端如果安装ActiveX失败,则把运行ActiveX的地址加入到信任站点里,
信任站点的安全级别降低到最低或者设置信任站点关于ActiveX的选项。
/Files/yungboy/CardReader.7
0条大神的评论