c#调api串口通讯

c#调api串口通讯
原文:c#调api串口通讯

在调试ICU通信设备的时候,由于串口通信老出现故障,所以就怀疑CF实现的SerialPort类是否有问题,所以最后决定用纯API函数实现串口读写。
先从网上搜索相关代码(关键字:C# API 串口),发现网上相关的资料大约来源于一个版本,那就是所谓的msdn提供的样例代码(msdn的具体出处,我没有考证),其它的代码大都是它的变种。
其实这个示例代码是有问题的,也就是说DCB结构体声明的有问题,虽然该代码可以正常通信,不过如果你设置了奇偶校验的话,你会发现奇偶校验无效。
VC中的DCB结构声明如下:
typedef struct _DCB {
DWORD DCBlength;      /* sizeof(DCB)                     */
DWORD BaudRate;       /* Baudrate at which running       */
DWORD fBinary: 1;     /* Binary Mode (skip EOF check)    */
DWORD fParity: 1;     /* Enable parity checking          */
DWORD fOutxCtsFlow:1; /* CTS handshaking on output       */
DWORD fOutxDsrFlow:1; /* DSR handshaking on output       */
DWORD fDtrControl:2; /* DTR Flow control                */
DWORD fDsrSensitivity:1; /* DSR Sensitivity              */
DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */
DWORD fOutX: 1;       /* Enable output X-ON/X-OFF        */
DWORD fInX: 1;        /* Enable input X-ON/X-OFF         */
DWORD fErrorChar: 1; /* Enable Err Replacement          */
DWORD fNull: 1;       /* Enable Null stripping           */
DWORD fRtsControl:2; /* Rts Flow control                */
DWORD fAbortOnError:1; /* Abort all reads and writes on Error */
DWORD fDummy2:17;     /* Reserved                        */
WORD wReserved;       /* Not currently used              */
WORD XonLim;          /* Transmit X-ON threshold         */
WORD XoffLim;         /* Transmit X-OFF threshold        */
BYTE ByteSize;        /* Number of bits/byte, 4-8        */
BYTE Parity;          /* 0-4=None,Odd,Even,Mark,Space    */
BYTE StopBits;        /* 0,1,2 = 1, 1.5, 2               */
char XonChar;         /* Tx and Rx X-ON character        */
char XoffChar;        /* Tx and Rx X-OFF character       */
char ErrorChar;       /* Error replacement char          */
char EofChar;         /* End of Input character          */
char EvtChar;         /* Received Event character        */
WORD wReserved1;      /* Fill for now.                   */
} DCB, *LPDCB;
有问题的代码DCB结构声明如下:
[StructLayout(LayoutKind.Sequential)]
        public struct DCB
        {
            public int DCBlength;
            public int BaudRate;
            public int fBinary;
            public int fParity;
            public int fOutxCtsFlow;
            public int fOutxDsrFlow;
            public int fDtrControl;
            public int fDsrSensitivity;
            public int fTXContinueOnXoff;
            public int fOutX;
            public int fInX;
            public int fErrorChar;
            public int fNull;
            public int fRtsControl;
            public int fAbortOnError;
            public int fDummy2;
            public uint flags;
            public ushort wReserved;
            public ushort XonLim;
            public ushort XoffLim;
            public byte ByteSize;
            public byte Parity;
            public byte StopBits;
            public byte XonChar;
            public byte XoffChar;
            public byte ErrorChar;
            public byte EofChar;
            public byte EvtChar;
            public ushort wReserved1;
        }
对C++比较熟悉网友应该知道,结构体中这种格式的声明,如DWORD fBinary: 1;是以位为单位进行变量设置的,DCB中相关位一共占4个字节,也就是相当于C#中的一个int变量所占的空间。很明显上面的DCB结构会有问题,实际上后面你设置的串口参数,如奇偶校验由于偏移有问题,虽然你设置了,其实都没有设置成功。
其实也不是我说人家的DCB声明错了就错了,在SerialPort类中你就可以找到微软官方自己的DCB声明(需要反编译SerialPort类),声明如下:
[StructLayout(LayoutKind.Sequential)]
        public struct DCB
        {
            public int DCBlength;
            public int BaudRate;
            public uint Flags;
            public ushort wReserved;
            public ushort XonLim;
            public ushort XoffLim;
            public byte ByteSize;
            public byte Parity;
            public byte StopBits;
            public byte XonChar;
            public byte XoffChar;
            public byte ErrorChar;
            public byte EofChar;
            public byte EvtChar;
            public ushort wReserved1;
        }
并且专门有一个设置位标志的函数,如下:
internal void SetDcbFlag(int whichFlag, int setting)
        {
            uint num;
            setting = setting << whichFlag;
            if ((whichFlag == 4) || (whichFlag == 12))
            {
                num = 3;
            }
            else if (whichFlag == 15)
            {
                num = 0x1ffff;
            }
            else
            {
                num = 1;
            }
            dcb.flags &= ~(num << whichFlag);
            dcb.flags |= (uint)setting;
        }
经过修改能正确运行的API代码如下(注意,由于我是在WinCE平台上运行,所以DLL的路径为"//windows//coredll.dll",你修改为"kernel32"后即可在PC机使用):
///<summary>
    /// API串口类 叶帆修改 http://blog.csdn.net/yefanqiu
    ///</summary>
    public class CommPort
    {
        ///<summary>
        ///端口名称(COM1,COM2...COM4...)
        ///</summary>
        public string Port = "COM1:";
        ///<summary>
        ///波特率9600
        ///</summary>
        public int BaudRate = 9600;
        ///<summary>
        ///数据位4-8
        ///</summary>
        public byte ByteSize = 8; //4-8
        ///<summary>
        ///奇偶校验0-4=no,odd,even,mark,space
        ///</summary>
        public byte Parity = 0;   //0-4=no,odd,even,mark,space
        ///<summary>
        ///停止位
        ///</summary>
        public byte StopBits = 0;   //0,1,2 = 1, 1.5, 2
        ///<summary>
        ///超时长
        ///</summary>
        public int ReadTimeout = 200;
        ///<summary>
        ///串口是否已经打开
        ///</summary>
        public bool Opened = false;
        ///<summary>
        /// COM口句柄
        ///</summary>
        private int hComm = -1;
        #region "API相关定义"
        private const string DLLPATH = "//windows//coredll.dll"; // "kernel32";
        ///<summary>
        /// WINAPI常量,写标志
        ///</summary>
        private const uint GENERIC_READ = 0x80000000;
        ///<summary>
        /// WINAPI常量,读标志
        ///</summary>
        private const uint GENERIC_WRITE = 0x40000000;
        ///<summary>
        /// WINAPI常量,打开已存在
        ///</summary>
        private const int OPEN_EXISTING = 3;
        ///<summary>
        /// WINAPI常量,无效句柄
        ///</summary>
        private const int INVALID_HANDLE_VALUE = -1;
        private const int PURGE_RXABORT = 0x2;
        private const int PURGE_RXCLEAR = 0x8;
        private const int PURGE_TXABORT = 0x1;
        private const int PURGE_TXCLEAR = 0x4;
        ///<summary>
        ///设备控制块结构体类型
        ///</summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct DCB
        {
           ///<summary>
            /// DCB长度
            ///</summary>
            public int DCBlength;
            ///<summary>
            ///指定当前波特率
            ///</summary>
            public int BaudRate;
            ///<summary>
            ///标志位
            ///</summary>
            public uint flags;
            ///<summary>
            ///未使用,必须为0
            ///</summary>
            public ushort wReserved;
            ///<summary>
            ///指定在XON字符发送这前接收缓冲区中可允许的最小字节数
            ///</summary>
            public ushort XonLim;
            ///<summary>
            ///指定在XOFF字符发送这前接收缓冲区中可允许的最小字节数
            ///</summary>
            public ushort XoffLim;
            ///<summary>
            ///指定端口当前使用的数据位
            ///</summary>
            public byte ByteSize;
            ///<summary>
            ///指定端口当前使用的奇偶校验方法,可能为:EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY 0-4=no,odd,even,mark,space
            ///</summary>
            public byte Parity;
            ///<summary>
            ///指定端口当前使用的停止位数,可能为:ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS 0,1,2 = 1, 1.5, 2
            ///</summary>
            public byte StopBits;
            ///<summary>
            ///指定用于发送和接收字符XON的值 Tx and Rx XON character
            ///</summary>
            public byte XonChar;
            ///<summary>
            ///指定用于发送和接收字符XOFF值 Tx and Rx XOFF character
            ///</summary>
            public byte XoffChar;
            ///<summary>
            ///本字符用来代替接收到的奇偶校验发生错误时的值
            ///</summary>
            public byte ErrorChar;
            ///<summary>
            ///当没有使用二进制模式时,本字符可用来指示数据的结束
            ///</summary>
            public byte EofChar;
            ///<summary>
            ///当接收到此字符时,会产生一个事件
            ///</summary>
            public byte EvtChar;
            ///<summary>
            ///未使用
            ///</summary>
            public ushort wReserved1;
        }
        ///<summary>
        ///串口超时时间结构体类型
        ///</summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct COMMTIMEOUTS
        {
            public int ReadIntervalTimeout;
            public int ReadTotalTimeoutMultiplier;
            public int ReadTotalTimeoutConstant;
            public int WriteTotalTimeoutMultiplier;
            public int WriteTotalTimeoutConstant;
        }
        ///<summary>
        ///溢出缓冲区结构体类型
        ///</summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct OVERLAPPED
        {
            public int Internal;
            public int InternalHigh;
            public int Offset;
            public int OffsetHigh;
            public int hEvent;
        }
        ///<summary>
        ///打开串口
        ///</summary>
        ///<param name="lpFileName">要打开的串口名称</param>
        ///<param name="dwDesiredAccess">指定串口的访问方式,一般设置为可读可写方式</param>
        ///<param name="dwShareMode">指定串口的共享模式,串口不能共享,所以设置为0</param>
        ///<param name="lpSecurityAttributes">设置串口的安全属性,WIN9X下不支持,应设为NULL</param>
        ///<param name="dwCreationDisposition">对于串口通信,创建方式只能为OPEN_EXISTING</param>
        ///<param name="dwFlagsAndAttributes">指定串口属性与标志,设置为FILE_FLAG_OVERLAPPED(重叠I/O操作),指定串口以异步方式通信</param>
        ///<param name="hTemplateFile">对于串口通信必须设置为NULL</param>
        [DllImport(DLLPATH)]
        private static extern int CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode,
        int lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile);
        ///<summary>
        ///得到串口状态
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpDCB">设备控制块DCB</param>
        [DllImport(DLLPATH)]
        private static extern bool GetCommState(int hFile, ref DCB lpDCB);
        ///<summary>
        ///建立串口设备控制块(嵌入版没有)
        ///</summary>
        ///<param name="lpDef">设备控制字符串</param>
        ///<param name="lpDCB">设备控制块</param>
        //[DllImport(DLLPATH)]
        //private static extern bool BuildCommDCB(string lpDef, ref DCB lpDCB);
        ///<summary>
        ///设置串口状态
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpDCB">设备控制块</param>
        [DllImport(DLLPATH)]
        private static extern bool SetCommState(int hFile, ref DCB lpDCB);
        ///<summary>
        ///读取串口超时时间
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpCommTimeouts">超时时间</param>
        [DllImport(DLLPATH)]
        private static extern bool GetCommTimeouts(int hFile, ref COMMTIMEOUTS lpCommTimeouts);
        ///<summary>
        ///设置串口超时时间
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpCommTimeouts">超时时间</param>
        [DllImport(DLLPATH)]
        private static extern bool SetCommTimeouts(int hFile, ref COMMTIMEOUTS lpCommTimeouts);
        ///<summary>
        ///读取串口数据
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpBuffer">数据缓冲区</param>
        ///<param name="nNumberOfBytesToRead">多少字节等待读取</param>
        ///<param name="lpNumberOfBytesRead">读取多少字节</param>
        ///<param name="lpOverlapped">溢出缓冲区</param>
        [DllImport(DLLPATH)]
        private static extern bool ReadFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToRead,
        ref int lpNumberOfBytesRead, ref OVERLAPPED lpOverlapped);
        ///<summary>
        ///写串口数据
        ///</summary>
        ///<param name="hFile">通信设备句柄</param>
        ///<param name="lpBuffer">数据缓冲区</param>
        ///<param name="nNumberOfBytesToWrite">多少字节等待写入</param>
        ///<param name="lpNumberOfBytesWritten">已经写入多少字节</param>
        ///<param name="lpOverlapped">溢出缓冲区</param>
        [DllImport(DLLPATH)]
        private static extern bool WriteFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToWrite,
        ref int lpNumberOfBytesWritten, ref OVERLAPPED lpOverlapped);
        [DllImport(DLLPATH, SetLastError = true)]
        private static extern bool FlushFileBuffers(int hFile);
        [DllImport(DLLPATH, SetLastError = true)]
        private static extern bool PurgeComm(int hFile, uint dwFlags);
        ///<summary>
        ///关闭串口
        ///</summary>
        ///<param name="hObject">通信设备句柄</param>
        [DllImport(DLLPATH)]
        private static extern bool CloseHandle(int hObject);
        ///<summary>
        ///得到串口最后一次返回的错误
        ///</summary>
        [DllImport(DLLPATH)]
        private static extern uint GetLastError();
        #endregion
        ///<summary>
        ///设置DCB标志位
        ///</summary>
        ///<param name="whichFlag"></param>
        ///<param name="setting"></param>
        ///<param name="dcb"></param>
        internal void SetDcbFlag(int whichFlag, int setting, DCB dcb)
        {
            uint num;
            setting = setting << whichFlag;
            if ((whichFlag == 4) || (whichFlag == 12))
            {
                num = 3;
            }
            else if (whichFlag == 15)
            {
                num = 0x1ffff;
            }
            else
            {
                num = 1;
            }
            dcb.flags &= ~(num << whichFlag);
            dcb.flags |= (uint)setting;
        }
        ///<summary>
        ///建立与串口的连接
        ///</summary>
        public int Open()
        {
            DCB dcb = new DCB();
            COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();
            // 打开串口
            hComm = CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
            if (hComm == INVALID_HANDLE_VALUE)
            {
                return -1;
            }
            // 设置通信超时时间
            GetCommTimeouts(hComm, ref ctoCommPort);
            ctoCommPort.ReadTotalTimeoutConstant = ReadTimeout;
            ctoCommPort.ReadTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutConstant = 0;
            SetCommTimeouts(hComm, ref ctoCommPort);
            //设置串口参数
            GetCommState(hComm, ref dcb);
            dcb.DCBlength = Marshal.SizeOf(dcb);
            dcb.BaudRate = BaudRate;
            dcb.flags = 0;
            dcb.ByteSize = (byte)ByteSize;
            dcb.StopBits = StopBits;
            dcb.Parity = (byte)Parity;
            //------------------------------
            SetDcbFlag(0, 1, dcb);            //二进制方式
            SetDcbFlag(1, (Parity == 0) ? 0 : 1, dcb);
            SetDcbFlag(2, 0, dcb);            //不用CTS检测发送流控制
            SetDcbFlag(3, 0, dcb);            //不用DSR检测发送流控制
            SetDcbFlag(4, 0, dcb);            //禁止DTR流量控制
            SetDcbFlag(6, 0, dcb);            //对DTR信号线不敏感
            SetDcbFlag(9, 1, dcb);            //检测接收缓冲区
            SetDcbFlag(8, 0, dcb);            //不做发送字符控制
            SetDcbFlag(10, 0, dcb);           //是否用指定字符替换校验错的字符
            SetDcbFlag(11, 0, dcb);           //保留NULL字符
            SetDcbFlag(12, 0, dcb);           //允许RTS流量控制
            SetDcbFlag(14, 0, dcb);           //发送错误后,继续进行下面的读写操作
            //--------------------------------
            dcb.wReserved = 0;                       //没有使用,必须为0      
            dcb.XonLim = 0;                          //指定在XOFF字符发送之前接收到缓冲区中可允许的最小字节数
            dcb.XoffLim = 0;                         //指定在XOFF字符发送之前缓冲区中可允许的最小可用字节数
            dcb.XonChar = 0;                         //发送和接收的XON字符
            dcb.XoffChar = 0;                        //发送和接收的XOFF字符
            dcb.ErrorChar = 0;                       //代替接收到奇偶校验错误的字符
            dcb.EofChar = 0;                         //用来表示数据的结束     
            dcb.EvtChar = 0;                         //事件字符,接收到此字符时,会产生一个事件       
            dcb.wReserved1 = 0;                      //没有使用
            if (!SetCommState(hComm, ref dcb))
            {
                return -2;
            }
            Opened = true;
            return 0;
        }
        ///<summary>
        ///关闭串口,结束通讯
        ///</summary>
        public void Close()
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                CloseHandle(hComm);
            }
        }
        ///<summary>
        ///读取串口返回的数据
        ///</summary>
        ///<param name="NumBytes">数据长度</param>
        public int Read(ref byte[] bytData, int NumBytes)
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                OVERLAPPED ovlCommPort = new OVERLAPPED();
                int BytesRead = 0;
                ReadFile(hComm, bytData, NumBytes, ref BytesRead, ref ovlCommPort);
                return BytesRead;
            }
            else
            {
                return -1;
            }
        }
        ///<summary>
        ///向串口写数据
        ///</summary>
        ///<param name="WriteBytes">数据数组</param>
        public int Write(byte[] WriteBytes, int intSize)
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                OVERLAPPED ovlCommPort = new OVERLAPPED();
                int BytesWritten = 0;
                WriteFile(hComm, WriteBytes, intSize, ref BytesWritten, ref ovlCommPort);
                return BytesWritten;
            }
            else
            {
                return -1;
            }
        }
        ///<summary>
        ///清除接收缓冲区
        ///</summary>
        ///<returns></returns>
        public void ClearReceiveBuf()
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                PurgeComm(hComm, PURGE_RXABORT | PURGE_RXCLEAR);
            }
        }
        ///<summary>
        ///清除发送缓冲区
        ///</summary>
        public void ClearSendBuf()
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR);
            }
        }
 }
后记:我的串口程序修改为API方式后,实际发现与SerialPort类遇到同样的问题,所以SerialPort类还是值得信任的。该API方式的代码在WinCE平台和PC平台都调试通过。
 
posted on 2018-09-30 08:58 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/9727888.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/464840.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手机充电IC设置电流与实测电流不一致问题剖析

大家好&#xff0c;我是写代码的篮球球痴&#xff0c;转一篇我朋友记得诚的文章本文转载来自一位基带大佬&#xff0c;解决问题的思路很重要。原文链接&#xff1a;https://blog.csdn.net/AirCity123/article/details/104428325?spm1001.2014.3001.5502某手机的充电架构如下&a…

今天面试了家公司

2011-07-08 不知不觉&#xff0c;做管理软件已经四五年了&#xff0c;今天面试了家做多媒体的公司&#xff0c;感觉不错&#xff0c;想转去做多媒体。转载于:https://blog.51cto.com/3298226/606809

checkbox居中 editor_radio 或 CheckBox 关联 其他元素 整体选择

场景&#xff1a; list组件中&#xff0c;每一行 需要显示多个radio 或者 checkBox&#xff0c;并且每一行显示选择的类型都不一样&#xff01;radio 或checkBox 的选择数据源是存放另一个data组件中&#xff01;&#xff01; 思路&#xff1a;正常的想法是每一行放一个radioGr…

Spring系列(六) Spring Web MVC 应用构建分析

DispatcherServlet DispatcherServlet 是Spring MVC的前端控制器名称, 用户的请求到达这里进行集中处理, 在Spring MVC中, 它的作用是为不同请求匹配对应的处理器, 将结果传递给视图解析器最终呈现给客户端. 前端控制器模式&#xff08;Front Controller Pattern&#xff09;是…

做个好人,加个晚班

我和建平在腾讯加班的日子前几天&#xff0c;他让我给他发照片&#xff0c;因为公司里年末要发照片墙&#xff0c;他说要把我的和他的照片放上去&#xff0c;然后我硬是找了几张觉得不错的给他&#xff0c;然后他也真的放上去了。再看那些照片&#xff0c;拍出来的效果都不咋样…

使用use index优化sql查询

转自&#xff1a;http://www.cnblogs.com/edwardlost/archive/2010/12/31/1923105.html 先看一下arena_match_index的表结构&#xff0c;大家注意表的索引结构 CREATE TABLE arena_match_index ( tid int(10) unsigned NOT NULL DEFAULT 0, mid int(10) unsigned NOT NULL …

中ridge_10种线性代数在数据科学中的强大应用(内附多种资源)

原文选自 | Analytics Vidhya作者 | Khyati Mahendru本文转载自 TalkingData数据学堂 &#xff0c;未经允许禁止转载本文摘要线性代数为各种各样的数据科学算法和应用提供支持在这里&#xff0c;我会向您介绍通过线性代数帮助您成为更好的数据科学家的10种实际应用我们已将这些…

排序算法之冒泡排序(JAVA)

//冒泡排序算法 平均时间复杂度 O(n*n) 稳定的排序算法 下面的是改进版的冒泡排序算法&#xff0c;使用exchange 标志位进行控制 public class bubbleSort { public static void bubbleSort(int[] data) { int i 0; int j 0; int tmp 0; int len …

C语言中变量的储存类别

C语言中变量的储存类别C语言中变量的储存类别1.动态存储方式与静态动态存储方式&#xff1a;从变量值存在的作时间&#xff08;即生存期&#xff09;角度来分&#xff0c;可以分为静态存储方式和动态存储方式。静态存储方式&#xff1a;是指在程序运行期间分配固定的存储空间的…

语言与golang语言运行速度_Golang语言情怀第13期 Go 语言设计模式 介绍

设计模式是什么俗话说&#xff1a;站在别人的肩膀上&#xff0c;我们会看得更远。设计模式的出现可以让我们站在前人的肩膀上&#xff0c;通过一些成熟的设计方案来指导新项目的开发和设计&#xff0c;以便于我们开发出具有更好的灵活性和可扩展性&#xff0c;也更易于复用的软…

blog发布测试

blog发布测试转载于:https://www.cnblogs.com/aj407blogs/p/9736120.html

字符串2在字符串1中第一次出现的位置strstr()

//字符串2在字符串1中第一次出现的位置&#xff0c;采用遍历的思想&#xff0c;移动str1的位置与str2进行匹配char *strstr(const char *str1, const char *str2) {int i 0;if (NULL str1){return NULL;}if (NULL str2){return (char *)str1;}if (*str2 ! \0){while (*str1 …

苦练IoT应用开发,还能加速变现,这个机会别错过

都说人间大事&#xff0c;不过吃喝二字。厨房经济近年来显示出了巨大发展潜力&#xff0c;智能厨电已成为潮流趋势。智慧厨电究竟是如何——让厨房小白做出一顿可口大餐&#xff1f;让懒人摆脱厨房油烟和洗碗的困扰&#xff1f;让怕冷的人喝到永远55℃的热水&#xff1f;……在…

jquery UI集合

http://www.cnblogs.com/leoxie2011/archive/2011/04/08/2009978.html

android人脸识别demo_零门槛解决Windows人脸识别应用开发难题

自人脸识别免费SDK——ArcFace3.0上线以来&#xff0c;凭借对人脸识别、活体检测、年龄检测、性别检测等核心算法模型进行全面升级&#xff0c;大幅提升算法鲁棒性&#xff0c;显著降低接入门槛&#xff0c;同时支持Windows、iOS、Android&#xff08;包含Android10&#xff09…

strcpy()源代码

将源字符串拷贝到目的字符串中 char *strcpy(char *dest, const char *src) {assert((NULL ! dest) && (NULL ! src));char *ret dest;while ((*dest *src) ! \0){;}return ret; }

Visual Studio会让嵌入式开发变得更香

在几个月之前&#xff0c;我一直非常喜欢用Source Insight看代码&#xff0c;主要是习惯了原来的风格。从Source Insight 转到vscode 的原因是&#xff0c;在腾讯使用samba连接Source Insight看代码非常非常卡&#xff0c;让我觉得很难受。然后是在同事的建议下更换了vscode,里…

类和继承

所有的类都派生自Object;派生类引用可以转换成基类&#xff1b;屏蔽基类成员使用关键字new则可以屏蔽基类成员&#xff1b;虚方法和覆写方法基类的方法被标记为virtual 在派生类中有匹配的override方法 For Example&#xff1a; class MyBaseClass{ Virtual public void printf…

现实世界的Windows Azure:采访InishTech的销售及市场部主管Andrew O’Connor

MSDN: 告诉我们关于你们公司的信息以及您为Windows Azure创建的解决方案。O’Connor: InishTech 有点不寻常。我们的软件许可和保护服务&#xff08;SLPS&#xff09;平台是一个传统的多租户Windows Azure应用程序&#xff0c;利用Windows Azure SDK、 Windows Azure Dev Fabri…

python第2位的值_Python组通过匹配元组列表中的第二个元组值

在本教程中&#xff0c;我们将编写一个程序&#xff0c;该程序将列表中具有与第二个元素相同的元素的所有元组分组。让我们看一个例子来清楚地理解它。输入值[(Python, nhooos), (Management, other), (Django, nhooos), (React,nhooos), (Social, other), (Business, other)]输…