最近项目中,因为需要在WEB页面上操作串口,包括串口查询、打开、发送指令、接收数据、关闭串口等功能。如下所示:
考虑使用ActiveX来实现。因为以前没有这方面的经验,开发过程中也是遇到各种问题。废话不多说,下面进入正题:
1:打开VS2008,新建项目,以下是具体代码:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Windows.Forms; 4 using System.IO.Ports; 5 using System.IO; 6 using System.Reflection; 7 using System.Runtime.InteropServices; 8 using mshtml; 9 using System.Text; 10 using Microsoft.Win32; 11 using System.Threading; 12 13 namespace WebSerial 14 { 15 [ProgId("WebSerial")]//控件名称 16 [ClassInterface(ClassInterfaceType.AutoDual), ComSourceInterfaces(typeof(ControlEvents))] 17 [Guid("6C6A0DE4-193A-48f5-BA91-3C180558785B")]//控件的GUID,用于COM注册和HTML中Object对象classid引用 18 [ComVisible(true)] 19 public partial class SerialPortControl : UserControl,IObjectSafety 20 { 21 ExSerialPort serialPort; 22 List%26lt;byte%26gt; buffer = new List%26lt;byte%26gt;(4096); 23 24 /// %26lt;summary%26gt; 25 /// 是否准备关闭串口 26 /// %26lt;/summary%26gt; 27 private static bool m_IsTryToClosePort = false; 28 /// %26lt;summary%26gt; 29 /// 是否正在接收数据 30 /// %26lt;/summary%26gt; 31 private static bool m_IsReceiving = false; 32 public SerialPortControl() 33 { 34 35 } 36 37 /// %26lt;summary%26gt; 38 /// 获取本地串口列表,以逗号隔开 39 /// %26lt;/summary%26gt; 40 /// %26lt;returns%26gt;%26lt;/returns%26gt; 41 public string getComPorts() 42 { 43 string ports = ""; 44 foreach (string s in ExSerialPort.GetPortNames()) 45 { 46 ports += "," + s; 47 } 48 return ports.Length %26gt; 0 ? ports.Substring(1) : ""; 49 } 50 51 /// %26lt;summary%26gt; 52 /// 以指定串口号和波特率连接串口 53 /// %26lt;/summary%26gt; 54 /// %26lt;param name="com"%26gt;端口号%26lt;/param%26gt; 55 /// %26lt;param name="baudRate"%26gt;波特率%26lt;/param%26gt; 56 /// %26lt;returns%26gt;%26lt;/returns%26gt; 57 [ComVisible(true)] 58 public string connect(string com, int baudRate) 59 { 60 close(); 61 serialPort = null; 62 serialPort = new ExSerialPort(com); 63 serialPort.BaudRate = baudRate; 64 serialPort.Parity = Parity.None; 65 serialPort.DataBits = 8; 66 serialPort.Encoding = Encoding.ASCII; 67 serialPort.ReceivedBytesThreshold = 5; 68 serialPort.ReadBufferSize = 102400; 69 70 try 71 { 72 serialPort.Open(); 73 if (serialPort.IsOpen) 74 { 75 m_IsTryToClosePort = false; 76 this.clear(); 77 serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived); 78 return "true"; 79 } 80 } 81 catch { } 82 83 return "false"; 84 } 85 86 /// %26lt;summary%26gt; 87 /// 清理串口数据并关闭串口 88 /// %26lt;/summary%26gt; 89 [ComVisible(true)] 90 public void close() 91 { 92 m_IsTryToClosePort = true; 93 while (m_IsReceiving) 94 { 95 Application.DoEvents(); 96 } 97 98 if (serialPort != null) 99 { 100 serialPort.Dispose(); 101 } 102 } 103 104 /// %26lt;summary%26gt; 105 /// 清理串口数据 106 /// %26lt;/summary%26gt; 107 [ComVisible(true)] 108 public void clear() 109 { 110 if (serialPort != null %26amp;%26amp; serialPort.IsOpen) 111 { 112 serialPort.Clear(); 113 } 114 } 115 116 /// %26lt;summary%26gt; 117 /// 发送字符串 118 /// %26lt;/summary%26gt; 119 /// %26lt;param name="s"%26gt;%26lt;/param%26gt; 120 [ComVisible(true)] 121 public void writeString(string hexString) 122 { 123 if (serialPort != null %26amp;%26amp; serialPort.IsOpen) 124 { 125 byte[] bytes = strToToHexByte(hexString); 126 serialPort.Write(bytes, 0, bytes.Length); 127 } 128 } 129 130 /// %26lt;summary%26gt; 131 /// 字符串转16进制字节数组 132 /// %26lt;/summary%26gt; 133 /// %26lt;param name="hexString"%26gt;%26lt;/param%26gt; 134 /// %26lt;returns%26gt;%26lt;/returns%26gt; 135 private static byte[] strToToHexByte(string hexString) 136 { 137 hexString = hexString.Replace(" ", ""); 138 if ((hexString.Length % 2) != 0) 139 hexString += " "; 140 byte[] returnBytes = new byte[hexString.Length / 2]; 141 for (int i = 0; i %26lt; returnBytes.Length; i++) 142 returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); 143 return returnBytes; 144 } 145 146 /// %26lt;summary%26gt; 147 /// 字节数组转字符串16进制 148 /// %26lt;/summary%26gt; 149 /// %26lt;param name="InBytes"%26gt; 二进制字节 %26lt;/param%26gt; 150 /// %26lt;returns%26gt;类似"01 02 0F" %26lt;/returns%26gt; 151 public static string ByteToString(byte[] InBytes) 152 { 153 string StringOut = ""; 154 foreach (byte InByte in InBytes) 155 { 156 //StringOut += String.Format("{0:X2}", InByte) + " "; 157 StringOut += " " + InByte.ToString("X").PadLeft(2, '0'); 158 } 159 160 return StringOut.Trim(); 161 } 162 163 /// %26lt;summary%26gt; 164 /// 接收数据 165 /// %26lt;/summary%26gt; 166 /// %26lt;param name="sender"%26gt;%26lt;/param%26gt; 167 /// %26lt;param name="e"%26gt;%26lt;/param%26gt; 168 void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) 169 { 170 if (m_IsTryToClosePort) 171 { 172 return; 173 } 174 175 m_IsReceiving = true; 176 177 try 178 { 179 int n = serialPort.BytesToRead; 180 if (n %26gt; 0) 181 { 182 byte[] buf = new byte[n]; 183 serialPort.Read(buf, 0, n); 184 string dataString = ByteToString(buf); 185 Receive(dataString); 186 } 187 188 ////1.缓存数据 189 //buffer.AddRange(buf); 190 ////2.完整性判断 191 //while (buffer.Count %26gt;= 5) //至少包含帧头(2字节)、长度(1字节)、校验位(1字节);根据设计不同而不同 192 //{ 193 // //2.1 查找数据头 194 // if (buffer[0] == 0xff %26amp;%26amp; buffer[1] == 0x55) //传输数据有帧头,用于判断 195 // { 196 // int len = buffer[2]; 197 // if (buffer.Count %26lt; len + 4) //数据区尚未接收完整 198 // { 199 // break; 200 // } 201 // //得到完整的数据,复制到ReceiveBytes中进行校验 202 // byte[] ReceiveBytes = new byte[len + 4]; 203 // buffer.CopyTo(0, ReceiveBytes, 0, len + 4); 204 205 // byte checkByte = ReceiveBytes[len + 3];//获取校验字节 206 // byte realCheckByte = 0x00; 207 // realCheckByte -= buffer[2]; 208 // for (int packIndex = 0; packIndex %26lt; len; packIndex++)//将后面的数据加起来 209 // { 210 // realCheckByte -= ReceiveBytes[packIndex + 3]; 211 // } 212 213 // if (checkByte == realCheckByte)//验证,看数据是否合格 214 // { 215 // string dataString = ByteToString(ReceiveBytes); 216 // Receive(dataString); 217 // } 218 // buffer.RemoveRange(0, len + 4); 219 // } 220 // else //帧头不正确时,清除 221 // { 222 // buffer.RemoveAt(0); 223 // } 224 225 //} 226 } 227 finally 228 { 229 m_IsReceiving = false; 230 } 231 } 232 233 public event ControlEventHandler OnReceive; 234 [ComVisible(true)] 235 private void Receive(string dataString) 236 { 237 if (OnReceive != null) 238 { 239 OnReceive(dataString); //Calling event that will be catched in JS 240 } 241 } 242 243 /// %26lt;summary%26gt; 244 /// Register the class as a control and set it's CodeBase entry 245 /// %26lt;/summary%26gt; 246 /// %26lt;param name="key"%26gt;The registry key of the control%26lt;/param%26gt; 247 [ComRegisterFunction()] 248 public static void RegisterClass(string key) 249 { 250 // Strip off HKEY_CLASSES_ROOT\ from the passed key as I don't need it 251 StringBuilder sb = new StringBuilder(key); 252 253 sb.Replace(@"HKEY_CLASSES_ROOT\", ""); 254 // Open the CLSID\{guid} key for write access 255 RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true); 256 257 // And create the 'Control' key - this allows it to show up in 258 // the ActiveX control container 259 RegistryKey ctrl = k.CreateSubKey("Control"); 260 ctrl.Close(); 261 262 // Next create the CodeBase entry - needed if not string named and GACced. 263 RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true); 264 inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase); 265 inprocServer32.Close(); 266 // Finally close the main key 267 k.Close(); 268 MessageBox.Show("Registered"); 269 } 270 271 /// %26lt;summary%26gt; 272 /// Called to unregister the control 273 /// %26lt;/summary%26gt; 274 /// %26lt;param name="key"%26gt;Tke registry key%26lt;/param%26gt; 275 [ComUnregisterFunction()] 276 public static void UnregisterClass(string key) 277 { 278 StringBuilder sb = new StringBuilder(key); 279 sb.Replace(@"HKEY_CLASSES_ROOT\", ""); 280 281 // Open HKCR\CLSID\{guid} for write access 282 RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true); 283 284 // Delete the 'Control' key, but don't throw an exception if it does not exist 285 k.DeleteSubKey("Control", false); 286 287 // Next open up InprocServer32 288 //RegistryKey inprocServer32 = 289 k.OpenSubKey("InprocServer32", true); 290 291 // And delete the CodeBase key, again not throwing if missing 292 k.DeleteSubKey("CodeBase", false); 293 294 // Finally close the main key 295 k.Close(); 296 MessageBox.Show("UnRegistered"); 297 } 298 299 #region IObjectSafety 成员 300 public void GetInterfacceSafyOptions(int riid, out int pdwSupportedOptions, out int pdwEnabledOptions) 301 { 302 pdwSupportedOptions = 1; 303 pdwEnabledOptions = 2; 304 } 305 public void SetInterfaceSafetyOptions(int riid, int dwOptionsSetMask, int dwEnabledOptions) 306 { 307 throw new NotImplementedException(); 308 } 309 #endregion 310 311 #region IObjectSafety 成员 312 313 private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}"; 314 private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}"; 315 private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}"; 316 private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}"; 317 private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}"; 318 319 private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001; 320 private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002; 321 private const int S_OK = 0; 322 private const int E_FAIL = unchecked((int)0x80004005); 323 private const int E_NOINTERFACE = unchecked((int)0x80004002); 324 325 private bool _fSafeForScripting = true; 326 private bool _fSafeForInitializing = true; 327 328 329 public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions) 330 { 331 int Rslt = E_FAIL; 332 333 string strGUID = riid.ToString("B"); 334 pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA; 335 switch (strGUID) 336 { 337 case _IID_IDispatch: 338 case _IID_IDispatchEx: 339 Rslt = S_OK; 340 pdwEnabledOptions = 0; 341 if (_fSafeForScripting == true) 342 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER; 343 break; 344 case _IID_IPersistStorage: 345 case _IID_IPersistStream: 346 case _IID_IPersistPropertyBag: 347 Rslt = S_OK; 348 pdwEnabledOptions = 0; 349 if (_fSafeForInitializing == true) 350 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA; 351 break; 352 default: 353 Rslt = E_NOINTERFACE; 354 break; 355 } 356 357 return Rslt; 358 } 359 360 public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions) 361 { 362 int Rslt = E_FAIL; 363 364 string strGUID = riid.ToString("B"); 365 switch (strGUID) 366 { 367 case _IID_IDispatch: 368 case _IID_IDispatchEx: 369 if (((dwEnabledOptions %26amp; dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) %26amp;%26amp; 370 (_fSafeForScripting == true)) 371 Rslt = S_OK; 372 break; 373 case _IID_IPersistStorage: 374 case _IID_IPersistStream: 375 case _IID_IPersistPropertyBag: 376 if (((dwEnabledOptions %26amp; dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) %26amp;%26amp; 377 (_fSafeForInitializing == true)) 378 Rslt = S_OK; 379 break; 380 default: 381 Rslt = E_NOINTERFACE; 382 break; 383 } 384 385 return Rslt; 386 } 387 388 #endregion 389 } 390 391 /// %26lt;summary%26gt; 392 /// Event handler for events that will be visible from JavaScript 393 /// %26lt;/summary%26gt; 394 public delegate void ControlEventHandler(string dataString); 395 396 /// %26lt;summary%26gt; 397 /// This interface shows events to javascript 398 /// %26lt;/summary%26gt; 399 [Guid("68BD4E0D-D7BC-4cf6-BEB7-CAB950161E79")] 400 [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 401 public interface ControlEvents 402 { 403 //Add a DispIdAttribute to any members in the source interface to specify the COM DispId. 404 [DispId(0x60020001)] 405 void OnReceive(string dataString); //This method will be visible from JS 406 } 407 408 public class ExSerialPort : SerialPort 409 { 410 public ExSerialPort(string name) 411 : base(name) 412 { 413 } 414 415 public void Clear() 416 { 417 try 418 { 419 if (this.IsOpen) 420 { 421 this.DiscardInBuffer(); 422 this.DiscardOutBuffer(); 423 } 424 } 425 catch { } 426 } 427 428 protected override void Dispose(bool disposing) 429 { 430 Clear(); 431 432 var stream = (Stream)typeof(SerialPort).GetField("internalSerialStream", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this); 433 434 if (stream != null) 435 { 436 stream.Dispose(); 437 } 438 439 base.Dispose(disposing); 440 } 441 } 442 }
2:新建安装项目,将上面项目DLL打包生成Msi安装文件。这里不多说,网上大把文章教你怎么做。
3:新建Web项目,具体代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 %26lt;html%26gt; 2 %26lt;head%26gt; 3 %26lt;title%26gt;JavaScript串口测试%26lt;/title%26gt; 4 %26lt;meta http-equiv="Content-Type" content="text/html; charset=GB2312" /%26gt; 5 %26lt;script language="javascript" type="text/javascript"%26gt; 6 %26lt;!-- 7 function getComPorts() 8 { 9 var ports = webSerial.getComPorts(); 10 var arr = ports.split(','); 11 var ctl = document.getElementById("ComName"); 12 if(ctl) 13 { 14 ctl.options.length = 0; 15 for(var i=0;i%26lt;arr.length;i++) 16 { 17 ctl.options[i] = new Option(arr[i],arr[i]); 18 } 19 } 20 } 21 22 function connectComPort() 23 { 24 var com = document.getElementById("ComName").value.toString(); 25 var baudRate = document.getElementById("BaudRate").value; 26 var result = webSerial.connect(com,baudRate); 27 alert(result); 28 } 29 30 function clearComPort() 31 { 32 webSerial.clear(); 33 alert("清理串口成功!"); 34 } 35 36 function closeComPort() 37 { 38 webSerial.close(); 39 alert("关闭串口成功!"); 40 } 41 42 function writeString() 43 { 44 var hexString = document.getElementById("txtSend").value.toString(); 45 webSerial.writeString(hexString); 46 alert("发送指令成功!"); 47 } 48 49 function clearSend() 50 { 51 document.getElementById("txtSend").innerText=""; 52 } 53 54 function clearReceive() 55 { 56 document.getElementById("txtReceive").innerText=""; 57 } 58 59 function startTime() 60 { 61 var today=new Date() 62 var h=today.getHours() 63 var m=today.getMinutes() 64 var s=today.getSeconds() 65 // add a zero in front of numbers%26lt;10 66 m=checkTime(m) 67 s=checkTime(s) 68 document.getElementById('lblTime').innerHTML=h+":"+m+":"+s 69 t=setTimeout('startTime()',500) 70 } 71 72 function checkTime(i) 73 { 74 if (i%26lt;10) 75 {i="0" + i} 76 return i 77 } 78 79 --%26gt; 80 %26lt;/script%26gt; 81 82 %26lt;/head%26gt; 83 %26lt;body οnlοad="startTime()" οnunlοad="closeComPort()"%26gt; 84 %26lt;form name="form1"%26gt; 85 %26lt;fieldset style="width:225px;height:180px;text-align:center;"%26gt; 86 %26lt;legend%26gt;串口%26lt;/legend%26gt; 87 %26lt;div style="float:left;width:250px"%26gt; 88 %26lt;br/%26gt; 89 %26lt;span%26gt;串口号:%26lt;/span%26gt; 90 %26lt;select name="ComName" id="ComName" style="width:100px" %26gt; 91 %26lt;/select%26gt; 92 %26lt;br/%26gt; 93 %26lt;span%26gt;波特率:%26lt;/span%26gt; 94 %26lt;select name="BaudRate" id="BaudRate" style="width:100px" %26gt; 95 %26lt;option value="9600" selected="selected"%26gt;9600%26lt;/option%26gt; 96 %26lt;option value="57600" %26gt;57600%26lt;/option%26gt; 97 %26lt;option value="115200" %26gt;115200%26lt;/option%26gt; 98 %26lt;option value="1382400" %26gt;1382400%26lt;/option%26gt; 99 %26lt;option value="3000000" %26gt;3000000%26lt;/option%26gt; 100 %26lt;/select%26gt; 101 %26lt;br/%26gt; 102 %26lt;br/%26gt; 103 %26lt;input type="button" id="btnGetPort" style="width:80px;height:30px;font-size:13px" name="btnGetPort" value="获取串口" οnclick="getComPorts()"/%26gt; 104 %26lt;input type="button" id="btnOpenPort" style="width:80px;height:30px;font-size:13px" name="btnOpenPort" value="打开串口" οnclick="connectComPort()"/%26gt; 105 %26lt;input type="button" id="btnClearPort" style="width:80px;height:30px;font-size:13px" name="btnClearPort" value="清理串口" οnclick="clearComPort()"/%26gt; 106 %26lt;input type="button" id="btnClosePort" style="width:80px;height:30px;font-size:13px" name="btnClosePort" value="关闭串口" οnclick="closeComPort()"/%26gt; 107 %26lt;/div%26gt; 108 %26lt;/fieldset%26gt; 109 %26lt;br /%26gt;%26lt;br /%26gt; 110 %26lt;fieldset style="width:800px;height:150px;text-align:center;"%26gt; 111 %26lt;legend%26gt;发送区域%26lt;/legend%26gt; 112 %26lt;div align="left"%26gt;V6-握手指令: FF 55 01 01 FE%26lt;/div%26gt; 113 %26lt;div align="left"%26gt;V6-50HZ采集:FF 55 05 03 20 4E 00 00 8A%26lt;/div%26gt; 114 %26lt;div align="left"%26gt;V6-停止指令: FF 55 01 10 EF%26lt;/div%26gt; 115 %26lt;div style="float:left;"%26gt; 116 %26lt;textarea id="txtSend" name="txtSend" style="width:800px;height:80px"%26gt;%26lt;/textarea%26gt; 117 %26lt;br/%26gt; 118 %26lt;input type="button" id="btnSend" style="width:100px;height:30px" name="btnSend" value="发送" οnclick="writeString()"/%26gt; 119 %26lt;input type="button" id="btnClearSend" style="width:100px;height:30px" name="btnClearSend" value="清空" οnclick="clearSend()"/%26gt; 120 %26lt;/div%26gt; 121 %26lt;/fieldset%26gt; 122 %26lt;br /%26gt;%26lt;br /%26gt; 123 %26lt;fieldset style="width:800px;height:500px;text-align:center;"%26gt; 124 %26lt;legend%26gt;接收区域%26lt;/legend%26gt; 125 %26lt;div style="float:left;"%26gt; 126 %26lt;textarea id="txtReceive" readonly="readonly" name="txtReceive" style="width:800px;height:430px"%26gt;%26lt;/textarea%26gt; 127 %26lt;br/%26gt; 128 %26lt;input type="button" id="btnClearReceive" style="width:100px;height:30px" name="btnClearReceive" value="清空" οnclick="clearReceive()"/%26gt; 129 %26lt;/div%26gt; 130 %26lt;/fieldset%26gt; 131 %26lt;span id="lblTime"%26gt;%26lt;/span%26gt; 132 %26lt;/form%26gt; 133 134 %26lt;p%26gt; 135 136 %26lt;object classid="clsid:6C6A0DE4-193A-48f5-BA91-3C180558785B" codebase="../WebSerialSetup.msi" width="442" height="87" id="webSerial" name="webSerial"%26gt; 137 %26lt;/object%26gt; 138 %26lt;/p%26gt; 139 140 %26lt;!-- Attaching to an ActiveX event--%26gt; 141 %26lt;script language="javascript" type="text/javascript"%26gt; 142 function webSerial::OnReceive(dataString) 143 { 144 document.getElementById("txtReceive").value += dataString+"\r\n";; 145 } 146 %26lt;/script%26gt; 147 %26lt;/body%26gt; 148 %26lt;/html%26gt;
%26nbsp; %26nbsp; %26nbsp; 在使用JS调用ActiveX的时候碰上问题一:方法可以成功调用,而事件却调用失败。网上文章大都是说JS如何调ActiveX,而ActiveX这边的方法或者事件需要满足什么条件才能被JS成功调用却少有涉及。正当我山穷水尽疑无路的时候,事情有了转折,无意中看到一篇老外写的文章。链接地址是:http://www.codeproject.com/Articles/24089/Create-ActiveX-in-NET-Step-by-Step。才知道事件需要实现一个接口才能被JS识别。所以这部分代码后面被加上去了:
/// %26lt;summary%26gt; /// Event handler for events that will be visible from JavaScript /// %26lt;/summary%26gt; public delegate void ControlEventHandler(string dataString); /// %26lt;summary%26gt; /// This interface shows events to javascript /// %26lt;/summary%26gt; [Guid("68BD4E0D-D7BC-4cf6-BEB7-CAB950161E79")] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface ControlEvents { //Add a DispIdAttribute to any members in the source interface to specify the COM DispId. [DispId(0x60020001)] void OnReceive(string dataString); //This method will be visible from JS }
控件类名前面也加上这个
[ClassInterface(ClassInterfaceType.AutoDual), ComSourceInterfaces(typeof(ControlEvents))]
事件定义如下:
public event ControlEventHandler OnReceive; [ComVisible(true)] private void Receive(string dataString) { if (OnReceive != null) { OnReceive(dataString); //Calling event that will be catched in JS } }
本地打开网页,执行全部功能,操作正常,大功告成!!!
%26nbsp;
随后我把网页在本地发布并使用局域网中其他电脑(操作系统WIN7)IE访问该网页。那么问题来了:
1:机器弹出对话框拒绝安装当前ActiveX。经过对IE internet选项设置,放开对无签名ActiveX访问限制后。有的机器能弹出安装对话框,有的机器仍然坚决禁止。而且就算是弹出安装对话框,在确认安装后,对话框消失,插件也没装上。。。
好吧,这个问题也是没搞明白啥原因。后面时间紧迫,只好给客户一个下载链接,自己去点击下载。
2:下载安装包并安装完毕后,在客户机器上操作网页功能。前面几个按钮功能都OK,但是在填入指令点击发送,网页出现崩溃重新刷新的情况,而且换了几台机器都是这样。后面想起在生成安装包的时候,有弹出一个对话框,提示Visual Studio registry capture utility 已停止工作。百度一番后,找到解决方法:在Microsoft%26nbsp;Visual%26nbsp;Studio%26nbsp;9.0/Common7/Tools/Deployment%26nbsp;路径下面的regcap.exe文件,点击右键在属性页面中,选择兼容性页面,选中%26ldquo;以兼容模式运行%26rdquo;框就好了。兼容win7%26nbsp;就行。
相应设置后,重新生成安装文件。。。在客户机上安装后,一切正常!!!