加载中…
个人资料
吴超
吴超
  • 博客等级:
  • 博客积分:0
  • 博客访问:1,562,389
  • 关注人气:211
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

aspx网页访问服务器和客户端串口

(2019-02-22 13:55:37)
标签:

aspx网页

html网页

访问服务器串口

访问客户端串口

杂谈

分类: 代码天地
aspx网页访问服务器和客户端串口
aspx网页访问服务器端的串口,控制服务器方面的设备;通过自己制作的ActiveX的用户控件访问客户端串口,控制客户端的设备。
为了简单名称尽量使用默认值,也参考了网上一些内容, 环境 VS2010 ,win7 , IE8以上。

一 创建和测试用户控件的动态库

涉及的图片和代码 可以参考 《调试C#动态库DLL方式的用户控件》,这里只是列出步骤。

(一) 创建 类库

文件 -- 新建 -- 项目 -- 类库 -- ClassLibrary1 -- 确定


(二) 创建 用户控件

  右击 解决方案资源管理器之下的 ClassLibrary1  添加 -- 新建项 -- 用户控件 -- UserControl1.cs -- 添加

  添加 按钮 文本框 列表框 如下: 

 1 用户控件上放置 3个按钮btnOpen,btnSend,btnClose, 一个组合框comboBox_port,一个文本框textBox1,一个列表框listBox1
 2 代码附加到最后
 3 菜单 生成--生成ClassLibrary1,直到完全正确
 3 菜单 生成--生成解决方案,直到完全正确


(三) 将用户控件添加到工具箱

 1 鼠标放到左侧边栏的工具箱上--展开后--右击 公共控件 栏--选择项
 2 浏览--C:\Users\x\Desktop\ClassLibrary1\ClassLibrary1\bin\Debug--
      点选 ClassLibrary1.dll--打开--确定
 3 用户控件放到工具箱 公共控件 栏内


(四) 添加测试的 From1

1 文件--添加--新建项目--Visual C#--Windows--WindowFormApplication1--确定
2 点选From1 设计页面,从工具箱中拖用户控件到其上面
3 菜单 生成--生成解决方案,直到完全正确


二 C#开发 ActiveX控件

继续在上面的解决方案内操作

(一)设置属性

1 右击解决方案之下的类库ClassLibrary1 -- 属性 
2 在【应用程序】选项页,点击 “程序集信息”
3 勾选 使程序集COM可见,确定

aspx网页访问服务器和客户端串口


4 在【生成】选项页,勾选“为COM互操作注册”
5 菜单 生成 -- 生成解决方案,直到完全正确

aspx网页访问服务器和客户端串口

(二)创建GUID

菜单 工具 -- 创建GUID -- 新建GUID -- 点选格式 5 -- 复制

aspx网页访问服务器和客户端串口


粘贴到用户控件类的开头为:

namespace ClassLibrary1
{
    [Guid("8E5DCEE1-A3BB-4A37-95C2-D4B99FA773FA")]
    public partial class UserControl1 : UserControl
    {


注意这里的GUID,与(一)设置属性 3中的GUID不能完全一样,至少要一个字符不同,否则编译通不过,出现错误:

错误 1 未能将程序集“ClassLibrary1.dll”转换为类型库。
类型库导出程序在处理“ClassLibrary1.UserControl1, ClassLibrary1”时遇到了错误。
错误: 找不到元素。 ClassLibrary1


(三)IObjectSafety接口

为了让ActiveX控件获得客户端的信任,控件类需要实现一个名为“IObjectSafety”接口,

1 右击解决方案之下的类库ClassLibrary1 -- 添加 -- 接口 -- 名称为 IObjectSafety -- 添加
2 注意:IObjectSafety接口的GUID值不能修改,接口代码如下:

aspx网页访问服务器和客户端串口




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ClassLibrary1
{
 [ComImport, Guid("A51D26F2-9057-4008-B910-9C21BE65D1E3")]
 [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
 public interface IObjectSafety
 {
      [PreserveSig]
      int GetInterfaceSafetyOptions(ref Guid riid,
     [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions,
     [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
  
[PreserveSig()]
int SetInterfaceSafetyOptions(ref Guid riid,
       [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask,
       [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
 }
}

(四) 改变用户控件类基于接口IObjectSafety, 并实现其接口函数,完整代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.Runtime.InteropServices;
using System.Text.RegularEx pressions; 

namespace ClassLibrary1
{
    [Guid("8E5DCEE1-A3BB-4A37-95C2-D4B99FA773FA")]
    public partial class UserControl1 : UserControl, IObjectSafety
    {

        SerialPort serial_port = new SerialPort();
        int recv_len = 0;
        int[] crc_data1 = { 0, 0 };
        byte[] in_data = { 0, 0, 0, 0, 0, 0, 0, 0 };

        public UserControl1()
        {
            InitializeComponent();
            string[] ports = SerialPort.GetPortNames();
            Array.Sort(ports);
            comboBox_port.Items.AddRange(ports);
            comboBox_port.SelectedIndex = comboBox_port.Items.Count > 0 ? 0 : -1;
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            try
            {
                if (serial_port.IsOpen) serial_port.Close();
                serial_port.PortName = comboBox_port.Text.ToString();//选择串口号
                serial_port.BaudRate = 9600;
                serial_port.Parity = Parity.None;       //奇偶效验
                serial_port.StopBits = StopBits.One;    //效验
                serial_port.DataBits = 8;               //每个字节的数据位长度
                serial_port.DataReceived += new SerialDataReceivedEventHandler(serial_port_DataReceived);
                serial_port.Open();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return;
            }
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            List  <  byte > buf = new List  <  byte > ();//填充到这个临时列表中 

            string[] str = textBox1.Text.ToString().Split(' ');//空格分割

            //16进制 
            foreach (string m in str)
            {
                buf.Add(byte.Parse(m, System.Globalization.NumberStyles.HexNumber));
            }

            //转换列表为数组后发送 
            serial_port.Write(buf.ToArray(), 0, buf.Count);
            //记录发送的字节数 
            // int send_len = buf.Count; 
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            if (serial_port.IsOpen) serial_port.Close();

        }
        private void serial_port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            System.Threading.Thread.Sleep(100);

            recv_len = serial_port.Read(in_data, 0, 8);
            this.BeginInvoke(new EventHandler(process_data));
        }
        private void process_data(object sender, EventArgs e)
        {
            if (in_data[0] == 1) //ok
            {
                string str = "";
                for (int i = 0; i  <  8; i++)
                {
                    str += (in_data[i].ToString("X2") + " ");
                }
                listBox1.Items.Add(str);

                int crc1 = Crc16(in_data, recv_len - 2);
                int crc2 = (int)(in_data[6] + in_data[7] * 256);

                if (crc1 == crc2)//校验CRC
                {
                   serial_port.Write(in_data, 0, 8);//正确的话,回答发来的
                }
                else
                    MessageBox.Show("校验码错误,数据无效!", "");
            }
            for (int i = 0; i  <  8; i++) in_data[i] = 0;
        }

        private int Crc16(byte[] puchMsg, int usDataLen)
        {
            System.UInt16 temp = 0xffff, temp1, i;
            byte j;
            for (i = 0; i  <  usDataLen; i++)
            {
                temp ^= puchMsg[i];// * (puchMsg++);
                for (j = 0; j  <  8; j++)
                {
                    temp1 = temp;
                    temp >>= 1;
                    if ((temp1 & 0x0001) == 0x0001)
                    { temp ^= 0xa001; }
                }
            }
            return (temp);
        }
//接口函数
        #region IObjectSafety
        private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
        private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
        private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
        private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
        private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";

        private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
        private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
        private const int S_OK = 0;
        private const int E_FAIL = unchecked((int)0x80004005);
        private const int E_NOINTERFACE = unchecked((int)0x80004002);

        private bool _fSafeForScripting = true;
        private bool _fSafeForInitializing = true;
        public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
        {
            int Rslt = E_FAIL;

            string strGUID = riid.ToString("B");
            pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
            switch (strGUID)
            {
                case _IID_IDispatch:
                case _IID_IDispatchEx:
                    Rslt = S_OK;
                    pdwEnabledOptions = 0;
                    if (_fSafeForScripting == true)
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
                    break;
                case _IID_IPersistStorage:
                case _IID_IPersistStream:
                case _IID_IPersistPropertyBag:
                    Rslt = S_OK;
                    pdwEnabledOptions = 0;
                    if (_fSafeForInitializing == true)
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
                    break;
                default:
                    Rslt = E_NOINTERFACE;
                    break;
            }

            return Rslt;
        }

        public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
        {
            int Rslt = E_FAIL;

            string strGUID = riid.ToString("B");
            switch (strGUID)
            {
                case _IID_IDispatch:
                case _IID_IDispatchEx:
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) &&
                            (_fSafeForScripting == true))
                        Rslt = S_OK;
                    break;
                case _IID_IPersistStorage:
                case _IID_IPersistStream:
                case _IID_IPersistPropertyBag:
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) &&
                            (_fSafeForInitializing == true))
                        Rslt = S_OK;
                    break;
                default:
                    Rslt = E_NOINTERFACE;
                    break;
            }

            return Rslt;
        }
        #endregion

    }
}


(五)重新生成 
 菜单 生成 -- 生成解决方案,直到完全正确,并在From1中运行测试


三 制作安装包

上面的程序在Form1.cs下是可以执行的,不过目的是让其他用户在浏览器使用。

文件 -- 添加 -- 新建项目 -- 其他项目类型 -- 安装和部署 --Visual Studio Installer
-- 安装项目 -- Setup1 -- 确定

1 选择 主输出
  右击  应用程序文件夹 --  添加 -- 项目输出 

  项目 选择 ClassLibrary1,主输出 -- 确定
 自动检测到依赖Microsoft.NET Framework

aspx网页访问服务器和客户端串口

2 查看依赖包版本
 在解决方案之下,找到Setup1,
双击“Microsoft.NET Framework”,打开启动条件页
右下边的属性中,改变依赖程序版本为,Version:.NET Framework 4。

aspx网页访问服务器和客户端串口

3 设置“主输出”的属性
 在解决方案之下,找到Setup1,
 点击 主输出来来自ClassLibrary1(活动),在其属性中,
设置Register的值为:vsdrpCOM。

aspx网页访问服务器和客户端串口

4 设置安装项目注册表版本

注意:这部分也可以不做。

右击 安装项目Setup1 -- 视图 -- 注册表,(也可以点击解决方案资源管理器之下的工具条)
打开如图:

在“HKEY_CLASSES_ROOT”下添加键
1 “CLSID”和“{GUID值}”(你的类的GUID),8E5DCEE1-A3BB-4A37-95C2-D4B99FA773FA
2 “InstalledVersion”,右键新建“字符串值”,写上版本,注意,版本用逗号“,”不是“.”号。
如下图所示:

aspx网页访问服务器和客户端串口


InstalledVersion这个版本号要和以下三处设置一致:

(1)是ClassLibrary1工程属性的“程序集信息”一样,如下:
(2)和安装项目Setup1的属性一样
(3)和IE页面的 < object>标签一样,

3 选中“Setup1”右键 -- 生成。
就可以生成Setup1.msi和Setup.EXE文件了,双击两者之一就可以在你电脑上安装你写的ActiveX控件。



四 添加 web 应用程序


(一)HTML格式的文件调用


         < object id="helloworld" classid="clsid:8E5DCEE1-A3BB-4A37-95C2-D4B99FA773FA"
            width="284" height="280"  
            codebase="ClassLibrary1.dll">
         < /object>

(二)aspx方式的 web 应用程序


这才是我们的最终使用方式

1 文件 -- 添加 -- 新建项目 -- Visual C# -- Web -- ASP.NET Web 应用程序 -- WebApplication1 -- 确定

aspx网页访问服务器和客户端串口 

 注意这里:
 选择是 文件 -- 添加 -- 新建[项目],可以管理更大的网站。
 而不是 文件 -- 添加 -- 新建[网站],这样管理是小的网站。

2 前端 Default.aspx 页面文件 添加控件

 拖放一些按钮等到页面,其中的 runat="server",就代表执行在服务器端。

 < div>
         1 服务器端 的串口收发
  
         < asp:Button ID="btnOpen" runat="server" onclick="btnOpen_Click" Text="open" />
         < asp:DropDownList ID="comboBox_port" runat="server">
         < /asp:DropDownList>
    
        
         < asp:Button ID="btnSend" runat="server" onclick="btnSend_Click" Text="发送" />
         < asp:TextBox ID="textBox1" runat="server"> < /asp:TextBox>
         < asp:Button ID="btnClose" runat="server" onclick="btnClose_Click" 
            Text="close" />   
  
         < asp:ListBox ID="listBox1" runat="server" Height="85px" 
            style="margin-top: 0px" Width="375px"> < /asp:ListBox>

        2 客户端 的串口收发

         < object id="helloworld" classid="clsid:8E5DCEE1-A3BB-4A37-95C2-D4B99FA773FA"
            width="284" height="280"  
            codebase="ClassLibrary1.dll">
         < /object>

  < /div>

3 后台代码,与用户控件几乎一样

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO.Ports;
namespace WebApplication1
{
    public partial class _Default : System.Web.UI.Page
    {
        static SerialPort serial_port = new SerialPort();
        int recv_len = 0;
        int[] crc_data1 = { 0, 0 };
        byte[] in_data = { 0, 0, 0, 0, 0, 0, 0, 0 };

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                string[] ports = SerialPort.GetPortNames();
              comboBox_port.DataBind();
                comboBox_port.SelectedIndex = comboBox_port.Items.Count > 0 ? 0 : -1;
            }

        }

        protected void btnOpen_Click(object sender, EventArgs e)
        {
            try
            {
                if (serial_port.IsOpen) serial_port.Close();
                serial_port.PortName = comboBox_port.Text.ToString();//选择串口号
                serial_port.BaudRate = 9600;
                serial_port.Parity = Parity.None;       //奇偶效验
                serial_port.StopBits = StopBits.One;    //效验
                serial_port.DataBits = 8;               //每个字节的数据位长度
                serial_port.DataReceived += new SerialDataReceivedEventHandler(serial_port_DataReceived);

                serial_port.Open();

            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
                return;
            }

        }

        protected void btnSend_Click(object sender, EventArgs e)
        {
            List < byte> buf = new List < byte>();//填充到这个临时列表中 
           string str0 = textBox1.Text.ToString();
            str0.TrimEnd();
            string[] str = str0.Split(' '); 

            //16进制添加 
            foreach (string m in str)
            {
                if (m == "")
                {
                    continue;
                }
                buf.Add(byte.Parse(m, System.Globalization.NumberStyles.HexNumber));
            }

            //转换列表为数组后发送 
            serial_port.Write(buf.ToArray(), 0, buf.Count);
            //记录发送的字节数 
            // n = buf.Count; 
        }

        protected void btnClose_Click(object sender, EventArgs e)
        {
            if (serial_port.IsOpen) serial_port.Close();
        }
        private void serial_port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            System.Threading.Thread.Sleep(100);

            recv_len = serial_port.Read(in_data, 0, 8);
             process_data();
        }

        private void process_data()
        {
            if (in_data[0] == 1) //ok
            {
                string str = "";
                for (int i = 0; i  <  8; i++)
                {
                    str += (in_data[i].ToString("X2") + " ");
                }
                listBox1.Items.Add(str);

                int crc1 = Crc16(in_data, recv_len - 2);
                int crc2 = (int)(in_data[6] + in_data[7] * 256);

                if (crc1 == crc2)//校验CRC
                {
                    byte[] out_data = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0a }; //发送温度传感器数据
                    serial_port.Write(in_data, 0, 8);//正确的话,回答发来的
                }
                else
                {
                    
                }
            }
            for (int i = 0; i  <  8; i++) in_data[i] = 0;
        }
         
        private int Crc16(byte[] puchMsg, int usDataLen)
        {
            System.UInt16 temp = 0xffff, temp1, i;
            byte j;
            for (i = 0; i  <  usDataLen; i++)
            {
                temp ^= puchMsg[i]; 
                for (j = 0; j  <  8; j++)
                {
                    temp1 = temp;
                    temp >>= 1;
                    if ((temp1 & 0x0001) == 0x0001)
                    { temp ^= 0xa001; }
                }
            }
            return (temp);
        }


    }
}


4 生成发布网站
  
  有关的生成发布网站的详细信息参看


 1 右击  WebApplication1 -- 重新生成
 2 右击  WebApplication1 -- 发布
   发布方法,文件系统
   目标位置,指定一个位置,比如 D:\vs2010\Web1
   点选 发布前删除所有现有文件
   按 发布,直到成功为止。


五 IE浏览器的设置

 启动浏览器 -- 工具 --Internet选项  

(一) 受信任站点设置

 1 转到 安全 页 -- 点击 受信任的站点 -- 按 站点 
 2 将用到的自己网站, http://dell-pc-15 按 添加 加入
 3 不要勾选 对该区域中的所有站点要求服务器验证(https:)

aspx网页访问服务器和客户端串口


(二)设置自定义安全级别

 1 转到 安全 页 -- 本地 Intranet -- 按 自定义级别  
 2 在ActiveX 控件和插件节,所有的都启用

aspx网页访问服务器和客户端串口


六 执行效果

 http://dell-pc-15:8030/default.aspx

  1 其中上部的串口是服务器端的,有若干个,操作服务器的串口,控制服务器的设备

  2 下部的串口是客户端自己的串口,只有一个,操作本地的串口,控制自己的设备

aspx网页访问服务器和客户端串口
  

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有