zoukankan      html  css  js  c++  java
  • C# ActiveX开发及安装部署

      最近项目中,因为需要在WEB页面上操作串口,包括串口查询、打开、发送指令、接收数据、关闭串口等功能。如下所示:

      考虑使用ActiveX来实现。因为以前没有这方面的经验,开发过程中也是遇到各种问题。废话不多说,下面进入正题:

      1:打开VS2008,新建项目,以下是具体代码:

      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<byte> buffer = new List<byte>(4096);
     23 
     24         /// <summary>
     25         /// 是否准备关闭串口
     26         /// </summary>
     27         private static bool m_IsTryToClosePort = false;
     28         /// <summary>
     29         /// 是否正在接收数据
     30         /// </summary>
     31         private static bool m_IsReceiving = false;
     32         public SerialPortControl()
     33         {
     34 
     35         }
     36 
     37         /// <summary>
     38         /// 获取本地串口列表,以逗号隔开
     39         /// </summary>
     40         /// <returns></returns>
     41         public string getComPorts()
     42         {
     43             string ports = "";
     44             foreach (string s in ExSerialPort.GetPortNames())
     45             {
     46                 ports += "," + s;
     47             }
     48             return ports.Length > 0 ? ports.Substring(1) : "";
     49         }
     50 
     51         /// <summary>
     52         /// 以指定串口号和波特率连接串口
     53         /// </summary>
     54         /// <param name="com">端口号</param>
     55         /// <param name="baudRate">波特率</param>
     56         /// <returns></returns>
     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         /// <summary>
     87         /// 清理串口数据并关闭串口
     88         /// </summary>
     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         /// <summary>
    105         /// 清理串口数据
    106         /// </summary>
    107         [ComVisible(true)]
    108         public void clear()
    109         {
    110             if (serialPort != null && serialPort.IsOpen)
    111             {
    112                 serialPort.Clear();
    113             }
    114         }
    115 
    116         /// <summary>
    117         /// 发送字符串
    118         /// </summary>
    119         /// <param name="s"></param>
    120         [ComVisible(true)]
    121         public void writeString(string hexString)
    122         {
    123             if (serialPort != null && serialPort.IsOpen)
    124             {
    125                 byte[] bytes = strToToHexByte(hexString);
    126                 serialPort.Write(bytes, 0, bytes.Length);
    127             }
    128         }
    129 
    130         /// <summary>
    131         /// 字符串转16进制字节数组
    132         /// </summary>
    133         /// <param name="hexString"></param>
    134         /// <returns></returns>
    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 < returnBytes.Length; i++)
    142                 returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
    143             return returnBytes;
    144         }
    145 
    146         ///  <summary>  
    147         /// 字节数组转字符串16进制  
    148         ///  </summary>  
    149         ///  <param name="InBytes"> 二进制字节 </param>  
    150         ///  <returns>类似"01 02 0F" </returns>  
    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         /// <summary>
    164         /// 接收数据
    165         /// </summary>
    166         /// <param name="sender"></param>
    167         /// <param name="e"></param>
    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 > 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 >= 5) //至少包含帧头(2字节)、长度(1字节)、校验位(1字节);根据设计不同而不同
    192                 //{
    193                 //    //2.1 查找数据头
    194                 //    if (buffer[0] == 0xff && buffer[1] == 0x55) //传输数据有帧头,用于判断
    195                 //    {
    196                 //        int len = buffer[2];
    197                 //        if (buffer.Count < 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 < 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         ///    <summary>
    244         ///    Register the class as a    control    and    set    it's CodeBase entry
    245         ///    </summary>
    246         ///    <param name="key">The registry key of the control</param>
    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         ///    <summary>
    272         ///    Called to unregister the control
    273         ///    </summary>
    274         ///    <param name="key">Tke registry key</param>
    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    HKCRCLSID{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 & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) &&
    370                          (_fSafeForScripting == true))
    371                         Rslt = S_OK;
    372                     break;
    373                 case _IID_IPersistStorage:
    374                 case _IID_IPersistStream:
    375                 case _IID_IPersistPropertyBag:
    376                     if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) &&
    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     /// <summary>
    392     /// Event handler for events that will be visible from JavaScript
    393     /// </summary>
    394     public delegate void ControlEventHandler(string dataString);
    395 
    396     /// <summary>
    397     /// This interface shows events to javascript
    398     /// </summary>
    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 }
    View Code

      2:新建安装项目,将上面项目DLL打包生成Msi安装文件。这里不多说,网上大把文章教你怎么做。

      3:新建Web项目,具体代码如下:

      1 <html> 
      2 <head> 
      3 <title>JavaScript串口测试</title>
      4 <meta http-equiv="Content-Type" content="text/html; charset=GB2312" />
      5 <script   language="javascript"   type="text/javascript"> 
      6 <!-- 
      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<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<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<10) 
     75           {i="0" + i}
     76           return i
     77     }
     78 
     79 --> 
     80 </script>   
     81 
     82 </head> 
     83 <body onload="startTime()" onunload="closeComPort()">
     84 <form name="form1">     
     85 <fieldset style="225px;height:180px;text-align:center;">
     86    <legend>串口</legend>
     87    <div style="float:left;250px">   
     88        <br/>   
     89        <span>串口号:</span>
     90        <select name="ComName" id="ComName" style="100px" >  
     91        </select>
     92        <br/>   
     93        <span>波特率:</span>
     94    <select name="BaudRate" id="BaudRate" style="100px" >
     95    <option value="9600" selected="selected">9600</option>
     96    <option value="57600"  >57600</option>
     97    <option value="115200" >115200</option>   
     98    <option value="1382400" >1382400</option>  
     99    <option value="3000000" >3000000</option>  
    100    </select>   
    101    <br/>
    102        <br/>
    103        <input   type="button" id="btnGetPort" style="80px;height:30px;font-size:13px"   name="btnGetPort"   value="获取串口"   onclick="getComPorts()"/>       
    104        <input   type="button" id="btnOpenPort" style="80px;height:30px;font-size:13px"   name="btnOpenPort"   value="打开串口"   onclick="connectComPort()"/>     
    105        <input   type="button" id="btnClearPort" style="80px;height:30px;font-size:13px"   name="btnClearPort"   value="清理串口"   onclick="clearComPort()"/>         
    106        <input   type="button" id="btnClosePort" style="80px;height:30px;font-size:13px"   name="btnClosePort"   value="关闭串口"   onclick="closeComPort()"/>       
    107     </div> 
    108 </fieldset>
    109 <br /><br />
    110 <fieldset style="800px;height:150px;text-align:center;">
    111    <legend>发送区域</legend>
    112    <div align="left">V6-握手指令: FF 55 01 01 FE</div>
    113    <div align="left">V6-50HZ采集:FF 55 05 03 20 4E 00 00 8A</div>
    114    <div align="left">V6-停止指令: FF 55 01 10 EF</div>
    115    <div style="float:left;">
    116        <textarea id="txtSend"  name="txtSend" style="800px;height:80px"></textarea> 
    117        <br/>
    118        <input   type="button" id="btnSend" style="100px;height:30px"   name="btnSend"   value="发送"   onclick="writeString()"/>   
    119        <input  type="button" id="btnClearSend" style="100px;height:30px"   name="btnClearSend"   value="清空"   onclick="clearSend()"/>
    120    </div> 
    121 </fieldset>
    122 <br /><br />
    123 <fieldset style="800px;height:500px;text-align:center;">
    124    <legend>接收区域</legend>   
    125    <div style="float:left;">
    126    <textarea id="txtReceive"  readonly="readonly" name="txtReceive" style="800px;height:430px"></textarea>  
    127    <br/>
    128    <input  type="button" id="btnClearReceive" style="100px;height:30px"   name="btnClearReceive"   value="清空"   onclick="clearReceive()"/>
    129    </div>
    130 </fieldset>   
    131 <span id="lblTime"></span>
    132 </form> 
    133 
    134 <p>
    135 
    136 <object classid="clsid:6C6A0DE4-193A-48f5-BA91-3C180558785B" codebase="../WebSerialSetup.msi" width="442" height="87" id="webSerial" name="webSerial">
    137         </object>
    138 </p>
    139 
    140  <!-- Attaching to an ActiveX event-->
    141 <script language="javascript" type="text/javascript">
    142     function webSerial::OnReceive(dataString)
    143     {
    144         document.getElementById("txtReceive").value += dataString+"
    ";;   
    145     }
    146 </script>
    147 </body> 
    148 </html>  
    View Code

          在使用JS调用ActiveX的时候碰上问题一:方法可以成功调用,而事件却调用失败。网上文章大都是说JS如何调ActiveX,而ActiveX这边的方法或者事件需要满足什么条件才能被JS成功调用却少有涉及。正当我山穷水尽疑无路的时候,事情有了转折,无意中看到一篇老外写的文章。链接地址是:http://www.codeproject.com/Articles/24089/Create-ActiveX-in-NET-Step-by-Step。才知道事件需要实现一个接口才能被JS识别。所以这部分代码后面被加上去了:

      

    /// <summary>
        /// Event handler for events that will be visible from JavaScript
        /// </summary>
        public delegate void ControlEventHandler(string dataString);
    
        /// <summary>
        /// This interface shows events to javascript
        /// </summary>
        [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
                }
            }

      本地打开网页,执行全部功能,操作正常,大功告成!!!

      随后我把网页在本地发布并使用局域网中其他电脑(操作系统WIN7)IE访问该网页。那么问题来了:

      1:机器弹出对话框拒绝安装当前ActiveX。经过对IE internet选项设置,放开对无签名ActiveX访问限制后。有的机器能弹出安装对话框,有的机器仍然坚决禁止。而且就算是弹出安装对话框,在确认安装后,对话框消失,插件也没装上。。。

      好吧,这个问题也是没搞明白啥原因。后面时间紧迫,只好给客户一个下载链接,自己去点击下载。

      2:下载安装包并安装完毕后,在客户机器上操作网页功能。前面几个按钮功能都OK,但是在填入指令点击发送,网页出现崩溃重新刷新的情况,而且换了几台机器都是这样。后面想起在生成安装包的时候,有弹出一个对话框,提示Visual Studio registry capture utility 已停止工作。百度一番后,找到解决方法:在Microsoft Visual Studio 9.0/Common7/Tools/Deployment 路径下面的regcap.exe文件,点击右键在属性页面中,选择兼容性页面,选中“以兼容模式运行”框就好了。兼容win7 就行。

    相应设置后,重新生成安装文件。。。在客户机上安装后,一切正常!!!

      最后附上完整项目代码:http://pan.baidu.com/s/1hq8MzJ2

  • 相关阅读:
    04Windows频繁打开和关闭端口可能引发的问题 | 07.杂项
    04WebFinger的利用 | 02.技术预研 | Social
    Hunch:自动问答和决策机
    03PubSubHubbub 和 twisted 的 Persistent connections 能力 | 07.杂项 | Python
    01获取 Twitter User Profile 的三条路径 | 07.杂项
    大中华之事件监测
    一个如此简单的杀手级应用
    07爬虫的多线程调度 | 01.数据抓取 | Python
    02Twisted 构建 Web Server 的 Socket 长链接问题 | 07.杂项 | Python
    关于Cutt.com关于Topic Engine
  • 原文地址:https://www.cnblogs.com/springxie/p/4707040.html
Copyright © 2011-2022 走看看