.net compact framework2.0 Wince智能设备开发项目经验分享 .net拖空间之进阶篇

    虽然是小项目,但也是麻雀虽小五脏俱全。第一次做嵌入式方面的实战开发,通过此项目的实战,个人积累了少许经验;现分享总结出来。但是希望各位看官不要喷太厉害;什么拖控件没技术含量、.net compact framework2.0不过是.net的精简版很好驾驭、嵌入式开发也不过如此等如此这般的评价本人不接受。请勿鄙视老鸟的智慧,由于项目也实际只有匆匆几天的开发时间,可能程序还存在重构、调优的空间;接受合理的建议。生产环境使用的设备是MC1000(摩托罗拉的扫描枪),内存只有30M,程序存储和程序的运行时占用的内存加起来才这30M,无奈EVC不会,.net compact framework2.0加上MC1000 的运行时、sqlce3.5运行时等就7M多了,程序倒很小,这样一来程序可用的内存只有15M左右;这设备显示屏还是黑白的。总之,我严重不同意这是没技术含量的开发,你得处处小心;一会跑得好好的程序在调试状态就死在设备上了,没有任何提示和异常触发;一会报资源没有释放...

      由于真机屏幕是240×240的很小,要截图还超不方便,还要去仓库MM那里借;总之很麻烦。所以上的图是使用仿真机,但是仿真机不支持MC1000的SDK,一些界面就截不了图了。设备最牛X和本程序最核心的需求是扫描条码,也就是说这里总结的不是业务啊需求什么的。就以下方面做些总结吧:

1.用户界面和程序架构

 

关于我做的这些界面不全部是拖控件实现的,使用了很多自定义控件,比如条码一般都比较长,显示的条码每4个字符分隔一下。窗体界面Enter键代替Tab键等。设备的Tab键很不好用需要和另一个键组合用,如果每个控件都去写KeyDown事件和Click事件是要累死人的,界面也没有统一的风格。我确实把WinForm的一些经验照搬过来了。

  • 自定义控件的使用

1)显示条码的控件,继承自TextBox。   

using System;

using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace Common
{
    /// <summary>
    /// 分割显示条码数据,条码一般都较长;不分割查看很费劲
    /// </summary>
    public class BarCodeTextCtrl : TextBox
    {
        /// <summary>
        /// 剔除分割符的原始条码文本
        /// </summary>
        public string BarCodeText
        {
            get
            {
                return Text.Replace("_", "");
            }
        }

        public BarCodeTextCtrl()
        {
            Font = new Font("Tahoma", 10F, FontStyle.Bold);
            ForeColor = Color.Black;
        }

        /// <summary>
        /// 响应输入后刷新显示
        /// </summary>
        /// <param name="e"></param>
        protected override void OnTextChanged(EventArgs e)
        {
            //不包含"_"和长度大于4,此条件符合扫码到的条码数据
            if ((Text.Length > 4) && (Text.IndexOf("_") == -1))
            {
                string result = string.Empty;
                var tmpTxt = this.Text;
                int cnt = Convert.ToInt32(Math.Ceiling((double)tmpTxt.Length / 4));
                for (int i = 0; i < cnt; i++)
                {
                    string fourChar = string.Empty;
                    if ((Text.Length - i * 4) >= 4)
                        fourChar = tmpTxt.Substring(i * 4, 4);
                    else fourChar = tmpTxt.Substring(i * 4, Text.Length - i * 4);
                    result += fourChar + "_";
                }
                Text = result.TrimEnd("_".ToCharArray());
                SelectionStart = result.Length - 1;
            }
            //手工输入
            if ((Text.Length > 4) && (Text.IndexOf("_") != -1))
            {
                string result = string.Empty;
                var tmpTxt = BarCodeText;
                int cnt = Convert.ToInt32(Math.Ceiling((double)tmpTxt.Length / 4));
                for (int i = 0; i < cnt; i++)
                {
                    string fourChar = string.Empty;
                    if ((BarCodeText.Length - i * 4) >= 4)
                        fourChar = tmpTxt.Substring(i * 4, 4);
                    else fourChar = tmpTxt.Substring(i * 4, BarCodeText.Length - i * 4);
                    result += fourChar + "_";
                }
                Text = result.TrimEnd("_".ToCharArray());
                SelectionStart = result.Length - 1;
            }
        }   
    }
}

2)主界面的类菜单项的按钮,继承自Button。

using System;

using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace Common
{
    /// <summary>
    /// 菜单按钮,自定义控件
    /// </summary>
    public class MenuButton : Button
    {
        const string activeFlag = "";
        public MenuButton()
        {
            BackColor = Color.White;
            ForeColor = Color.Black;
            Height = 28;
            Font = new Font("微软雅黑",14F,FontStyle.Bold);
            sf = new StringFormat();
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Center;
        }

        protected bool itemActiveFlag = false;
        /// <summary>
        /// 是否处于被选中状态
        /// </summary>
        public bool ItemActiveFlag
        {
            get { return itemActiveFlag; }
            set 
            {                 
                itemActiveFlag = value;
                //LED灯闪一下,体验下控制硬件的快感,~_~
                //DeviceMc1000Api.NotifyLED_CYCLE(300,200,1);
                if (value)
                    Text = activeFlag + Text;
                else Text = Text.Replace(activeFlag, ""); 
            }
        }

        private StringFormat sf;

        protected override void OnGotFocus(EventArgs e)
        {
            BackColor = SystemColors.Highlight;
            ForeColor = Color.White;
            ItemActiveFlag = true;         
        }

        protected override void OnLostFocus(EventArgs e)
        {
            BackColor = Color.White;
            ForeColor = Color.Black;
            ItemActiveFlag = false;               
        }
    }
}

 

  • 基类窗体的使用   
View Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Common;

namespace PovosScanApp
{
    /// <summary>
    /// 项目基类窗体
    /// </summary>
    public class DeviceBaseForm : Form
    {
        private bool isScaleDown = true;
        /// <summary>
        /// 是否屏幕自适应
        /// </summary>
        public bool IsScaleDown
        {
            get { return isScaleDown; }
            set { isScaleDown = value; }
        }
      
        private bool enterToTab = true;
        /// <summary>
        /// 是否回车变Tab
        /// </summary>
        public bool EnterToTab
        {
            get { return enterToTab; }
            set { enterToTab = value; }
        }


        public DeviceBaseForm()
        {
            InitializeComponent();                      
        }

        /// <summary>
        /// 屏幕自适应
        /// </summary>
        /// <param name="frm"></param>
        private void ScaleDown()
        {
            int scrWidth = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width;
            int scrHeight = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height;
            if (scrWidth < this.Width)
                foreach (System.Windows.Forms.Control cntrl in this.Controls)
                {
                    cntrl.Width = ((cntrl.Width) * (scrWidth)) / (this.Width);
                    cntrl.Left = ((cntrl.Left) * (scrWidth)) / (this.Width);
                }
            if (scrHeight < this.Height)
                foreach (System.Windows.Forms.Control cntrl in this.Controls)
                {
                    cntrl.Height = ((cntrl.Height) * (scrHeight)) / (this.Height);
                    cntrl.Top = ((cntrl.Top) * (scrHeight)) / (this.Height);
                }
        }      

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // DeviceBaseForm
            // 
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
            this.ClientSize = new System.Drawing.Size(240, 240);
            this.KeyPreview = true;
            this.Font = new Font("Tahoma", 11F, FontStyle.Bold);
            this.ForeColor = Color.White;
            this.BackColor = Color.Black;
            this.Name = "DeviceBaseForm";
            this.ResumeLayout(false);

        }

        /// <summary>
        /// 递归控件 外接事件Enter变Tab
        /// </summary>
        /// <param name="ctrl"></param>
        void SetControlEnterToTab(Control ctrl)
        {
            foreach (Control subControl in ctrl.Controls)
            {
                if (subControl is TextBox || subControl is DateTimePicker || subControl is ComboBox || subControl is NumericUpDown)
                {
                    subControl.KeyDown += new KeyEventHandler(ctrl_KeyDown);
                }
                if (ctrl.Controls.Count > 0)
                    SetControlEnterToTab(subControl);
            }
        }

        void ctrl_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyValue == 13)
            {
                var ctrl = sender as Control;
                if (!string.IsNullOrEmpty(ctrl.Text) && ctrl is TextBox)
                {
                    var tbx = ctrl as TextBox;
                    tbx.SelectAll();
                }
                WinceApi.keybd_event(9, 0, 0, 0);
            } 
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            if (e.KeyValue == 27)
                this.Close();
        }

        protected override void OnLoad(EventArgs e)
        {
            if (IsScaleDown)
                ScaleDown();
            if (EnterToTab)
                SetControlEnterToTab(this);
            this.Width = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width - 2;
            this.Height = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height - 2;
            base.OnLoad(e);
        }
       
    }
}

2.编程规范、面向对象经验、设计模式的运用

1)编码规范

各位看架构截图和前面的代码,应该明白本人遵循了微软C#主流的开发规范了吧。下面随便抽取一点代码展示,这是WinCe开发常用的,有需要的直接Copy去用。本人没上过大学,不要太嫌我英语差啊。呵呵

WinCE 通用API
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace Common
{
    /// <summary>
    /// WinCE平台API调用类
    /// </summary>
    public class WinceApi
    {
        /// <summary>
        /// 模拟按下键
        /// </summary>
        /// <param name="bVk">9->tab 13->Enter 27->Esc ...</param>
        /// <param name="bScan"></param>
        /// <param name="dwFlags"></param>
        /// <param name="dwExtraInfo"></param>
        [DllImport("Coredll.dll", EntryPoint = "keybd_event")]
        public static extern void keybd_event(
            byte bVk,
            byte bScan,
            int dwFlags,
            int dwExtraInfo
        );

        [DllImport("Coredll.dll")]
        public static extern void GetLocalTime(SystemTime st);
        [DllImport("Coredll.dll")]
        public static extern void SetLocalTime(SystemTime st);

        [StructLayout(LayoutKind.Sequential)]
        public class SystemTime
        {
            public ushort wYear;
            public ushort wMonth;
            public ushort wDayOfWeek;
            public ushort wDay;
            public ushort wHour;
            public ushort wMinute;
            public ushort wSecond;
            public ushort wMilliseconds;
        }

        public struct MemoryStatus
        {
            //MEMORYSTATUS 结构的大小,在调 GlobalMemoryStatus 函数前用sizeof()函数求得   
            public Int32 dwLength;
            //返回一个介于 0~100 之间的值,用来指示当前系统内存的使用率   
            public Int32 dwMemoryLoad;
            //返回总的物理内存大小,以字节(byte)为单位   
            public Int32 dwTotalPhys;
            //返回可用的物理内存大小,以字节(byte)为单位   
            public Int32 dwAvailPhys;
            //显示可以存在页面文件中的字节数。注意这个数值并不表示在页面文件在磁盘上的真实物理大小   
            public Int32 dwTotalPageFile;
            //返回可用的页面文件大小,以字节(byte)为单位   
            public Int32 dwAvailPageFile;
            //返回调用进程的用户模式部分的全部可用虚拟地址空间,以字节(byte)为单位   
            public Int32 dwTotalVirtual;
            // 返回调用进程的用户模式部分的实际自由可用的虚拟地址空间,以字节(byte)为单位   
            public Int32 dwAvailVirtual;
        }

        /// <summary>
        /// 获取 wince 系统内存情况 
        /// </summary>
        /// <param name="msce"></param>
        [DllImport("coredll", EntryPoint = "GlobalMemoryStatus", SetLastError = false)]
        public static extern void GlobalMemoryStatusCE(out MemoryStatus msce);

        /// <summary>
        /// 获取存储设备的大小信息
        /// </summary>
        /// <param name="directoryName"></param>
        /// <param name="freeBytesAvailable"></param>
        /// <param name="totalBytes"></param>
        /// <param name="totaFreeBytes"></param>
        /// <returns></returns>
        [DllImport("coredll.dll")]
        private static extern bool GetDiskFreeSpaceEx(string directoryName, ref long freeBytesAvailable, ref long totalBytes, ref long totaFreeBytes);

        [DllImport("Coredll.dll")]
        extern static int KernelIoControl(int dwIoControlCode, IntPtr lpInBuf, int nInBufSize, IntPtr
        lpOutBuf, int nOutBufSize, ref int lpBytesReturned);

        [DllImport("Coredll.dll")]
        extern static void SetCleanRebootFlag();

        /// <summary>
        /// 系统重启(冷启动)
        /// </summary>
        public static void HardReset()
        {
            int IOCTL_HAL_REBOOT = 0x101003C;
            int bytesReturned = 0;
            SetCleanRebootFlag();
            KernelIoControl(IOCTL_HAL_REBOOT, IntPtr.Zero, 0, IntPtr.Zero, 0, ref bytesReturned);
        }

        /// <summary>
        /// 程序互斥,只允许运行一次
        /// </summary>
        public class Mutex
        {
            [DllImport("coredll.dll", EntryPoint = "CreateMutex", SetLastError = true)]
            public static extern IntPtr CreateMutex(
            IntPtr lpMutexAttributes,
            bool InitialOwner,
            string MutexName);

            [DllImport("coredll.dll", EntryPoint = "ReleaseMutex", SetLastError = true)]
            public static extern bool ReleaseMutex(IntPtr hMutex);

            private const int ERROR_ALREADY_EXISTS = 0183;

            /// <summary>
            /// 判断程序是否已经运行
            /// </summary>
            /// <returns>
            /// true: 程序已运行,则什么都不做
            /// false: 程序未运行,则启动程序
            /// </returns>
            public static bool IsExist()
            {
                string strAppName =
                System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
                IntPtr hMutex = CreateMutex(IntPtr.Zero, true, strAppName);
                if (hMutex == IntPtr.Zero)
                    throw new ApplicationException("Failure creating mutex: "
                    + Marshal.GetLastWin32Error().ToString("X"));
                if (Marshal.GetLastWin32Error() == ERROR_ALREADY_EXISTS)
                {
                    ReleaseMutex(hMutex);
                    return true;
                }
                return false;
            }
        } 
    }
}

2)面向对象编码经验

窗体也是一个类,代码写得合理、干净整洁;维护起来就是爽。这个我说我面向对象了,大家都笑了吧,我最常用的就是封装、继承。比如窗体间传值,我喜欢封装成属性,然后调用的窗口或者这个属性。总之经常使用索引器这些。感觉自己还是领略了面向对象的精神的,要说做得多好就不一定了。

 /// <summary>
        /// 工位
        /// </summary>
        public int PrdPosition
        {
            get { return rbMidBoxScan.Checked == true ? 1 : 2; }
        }

        /// <summary>
        /// 操作员
        /// </summary>
        public string Operator
        {
            get { return txtOper.Text.Trim(); }
        }

        /// <summary>
        /// 批号
        /// </summary>
        public string BatchNo
        {
            get { return txtBatchNo.Text.Trim(); }
        }
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using DataAccess;

namespace PovosScanApp
{
    public class OrderSelectItemCtrl : Common.MenuButton
    {
        /// <summary>
        /// 控件的数据行
        /// </summary>
        public OrderEntity ItemDataRow
        {
            get;
            set;
        }

        public OrderSelectItemCtrl()
        {
            //
        }
    }
}

3)设计模式的运用 

项目里只用到了单例(单件)模式。

Application里的全局对象
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;
using DataAccess;
using Common;

namespace PovosScanApp
{
    /// <summary>
    /// 全局对象,单例
    /// </summary>
    public sealed class GlobalData
    {
        private static readonly GlobalData instance = new GlobalData();
        public DBComponent LocalDb = null;
      
        private GlobalData()
        {
            string dbFile = "\\Application\\ScanLocalDb.sdf";
            LocalDb = new DBComponent(dbFile);
        }

        public static GlobalData GetInstance()
        {
            return instance;
        }

        /// <summary>
        /// 应用程序版本号
        /// </summary>
        public static string AppVersion
        {
            get { return "1.0.130115"; }
        }

        /// <summary>
        /// 本地数据库版本号
        /// </summary>
        public static string DbVersion
        {
            get { return "1.0.130115"; }
        }

        /// <summary>
        /// 设备UUID,唯一序列号
        /// </summary>
        public static string DeviceMac
        {
            get { return DeviceMc1000Api.GetDevid().TrimEnd("0".ToCharArray()); }        
        }

        /// <summary>
        /// 应用程序安装目录
        /// </summary>
        public static string AppBasePath
        {
            get { return Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName);}
        }

        /// <summary>
        /// 数据库连接字符串
        /// </summary>
        public static string DbConnectionString
        {
            get { return instance.LocalDb.ConnectionStr; }    
        }
    }
}

没了。

下面给众多伸手党兄弟一些福利吧:

SqlCe 数据库存取类
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlServerCe;
using System.Data;
using System.IO;

namespace DataAccess
{
    /// <summary>
    /// SQLCE数据库存取类
    /// </summary>
    public class DBComponent 
    {        
        public DBComponent(string dbFileName)
        {
            myDBName = dbFileName;
            myDBEncrypt = false;          
        }

        /// <summary>
        /// 获取数据库连接字符串
        /// </summary>
        public string ConnectionStr
        {
            get
            {
                string connStr = "Data Source='" + myDBName + "'; LCID=1033; Password=\"" + myDBPassword + "\"; Encrypt = ";
                if (myDBEncrypt == true)
                    connStr += "TRUE;";
                else connStr += "FALSE;";
                return connStr;
            }
        }

        private string myDBName;
        // Gets or sets the database name
        public string DBName
        {
            get
            {
                return myDBName;
            }
            set
            {
                myDBName = value;
            }
        }

        private string myDBPassword;
        // Gets or sets the password for database
        public string DBPassword
        {
            get
            {
                return myDBPassword;
            }
            set
            {
                myDBPassword = value;
            }
        }

        private bool myDBEncrypt = true;
        // Enable or disable database encryption
        public bool DBEncrypt
        {
            get
            {
                return myDBEncrypt;
            }
            set
            {
                myDBEncrypt = value;
            }
        }

        // If set to true, delete the the database in DBCreate() if already exists and then create a new one. 
        // If set to false, use the existing one.  
        private bool myDBDelete = false;
        public bool DBDelete
        {
            get
            {
                return myDBDelete;
            }
            set
            {
                myDBDelete = value;
            }
        }

        //Create a databse using the name provided in DBName
        public void DBCreate()
        {
            if (myDBEncrypt == false && File.Exists(myDBName)) return;
            else File.Delete(myDBName);
            SqlCeEngine mySqlEngine = null;
            try
            {                 
                mySqlEngine = new SqlCeEngine(ConnectionStr);
                mySqlEngine.CreateDatabase();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                mySqlEngine.Dispose();
            }
        }

        // Query the database and return the resultset
        public DataSet DBQuery(string queryStr)
        {
            using (var mySqlConnection = new SqlCeConnection(ConnectionStr))
            {
                try
                {
                    mySqlConnection.Open();
                    using (var cmd = mySqlConnection.CreateCommand())
                    {
                        cmd.CommandText = queryStr;
                        var myDataSet = new DataSet();
                        var mySqlDataAdapter = new SqlCeDataAdapter(cmd);
                        mySqlDataAdapter.Fill(myDataSet);
                        return myDataSet;
                    }
                }
                catch (Exception ex)
                {
                    return null;
                    throw new Exception(ex.Message);
                }
                finally
                {
                    mySqlConnection.Close();
                }
            }            
        }

        // Execute Delete, Insert and Update commands
        public int DBExecute(string executeStr)
        {
            using (var mySqlConnection = new SqlCeConnection(ConnectionStr))
            {
                int rowsAffected = -1;
                try
                {
                    mySqlConnection.Open();
                    using (var cmd = mySqlConnection.CreateCommand())
                    {
                        cmd.CommandText = executeStr;
                        rowsAffected = cmd.ExecuteNonQuery();
                        return rowsAffected;
                    }
                }
                catch (Exception ex)
                {
                    return rowsAffected;
                    throw new Exception(ex.Message);
                }
                finally
                {
                    mySqlConnection.Close();
                }
            }            
        }

        // ExecuteScalar
        public object DBExecuteScalar(string executeStr)
        {
            using (var mySqlConnection = new SqlCeConnection(ConnectionStr))
            {
                try
                {
                    mySqlConnection.Open();
                    using (var cmd = mySqlConnection.CreateCommand())
                    {
                        cmd.CommandText = executeStr;
                        object rowsObj = cmd.ExecuteScalar();
                        return rowsObj;
                    }
                }
                catch (Exception ex)
                {
                    return null;
                    throw new Exception(ex.Message);
                }
                finally
                {
                    mySqlConnection.Close();
                }
            }            
        }
    }
}
WinCe电源管理通用类来自设备的SDK里的例子
using System;

using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using System.Collections;

namespace Common
{
    /// <summary>
    /// 设备电源管理类
    /// </summary>
    public class PowerManagement : IDisposable
    {
        #region ------------------Enumerations--------------------

        /// <summary>
        /// Defines the System power states
        /// </summary>
        public enum SystemPowerStates : uint
        {
            /// <summary>
            /// On state.
            /// </summary>
            On = 0x00010000,

            /// <summary>
            /// No power, full off.
            /// </summary>
            Off = 0x00020000,

            /// <summary>
            /// Critical off.
            /// </summary>
            Critical = 0x00040000,

            /// <summary>
            /// Boot state.
            /// </summary>
            Boot = 0x00080000,

            /// <summary>
            /// Idle state.
            /// </summary>
            Idle = 0x00100000,

            /// <summary>
            /// Suspend state.
            /// </summary>
            Suspend = 0x00200000,

            /// <summary>
            /// Reset state.
            /// </summary>
            Reset = 0x00800000
        }

        /// <summary>
        /// Defines the System power requirement flags
        /// </summary>
        public enum PowerReqFlags : uint
        {
            POWER_NAME = 0x00000001,
            POWER_FORCE = 0x00001000,
        }

        /// <summary>
        /// Defines the Device power states
        /// </summary>
        public enum DevicePowerStates
        {
            PwrDeviceUnspecified = -1,
            FullOn = 0,        // Full On: full power,  full functionality
            D0 = FullOn,
            LowOn,            // Low Power On: fully functional at low power/performance
            D1 = LowOn,
            StandBy,        // Standby: partially powered with automatic wake
            D2 = StandBy,
            Sleep,            // Sleep: partially powered with device initiated wake
            D3 = Sleep,
            Off,            // Off: unpowered
            D4 = Off,
            PwrDeviceMaximum
        }

        /// <summary>
        /// Defines the Power Status message type.
        /// </summary>
        [FlagsAttribute()]
        public enum MessageTypes : uint
        {
            /// <summary>
            /// System power state transition.
            /// </summary>
            Transition = 0x00000001,

            /// <summary>
            /// Resume from previous state.
            /// </summary>
            Resume = 0x00000002,

            /// <summary>
            /// Power supply switched to/from AC/DC.
            /// </summary>
            Change = 0x00000004,

            /// <summary>
            /// A member of the POWER_BROADCAST_POWER_INFO structure has changed.
            /// </summary>
            Status = 0x00000008
        }

        /// <summary>
        /// Defines the AC power status flags.
        /// </summary>
        public enum ACLineStatus : byte
        {
            /// <summary>
            /// AC power is offline.
            /// </summary>
            Offline = 0x00,

            /// <summary>
            /// AC power is online. 
            /// </summary>
            OnLine = 0x01,

            /// <summary>
            /// AC line status is unknown.
            /// </summary>
            Unknown = 0xff
        }

        /// <summary>
        /// Defines the Battery charge status flags.
        /// </summary>
        [FlagsAttribute()]
        public enum BatteryFlags : byte
        {
            /// <summary>
            /// High
            /// </summary>
            High = 0x01,

            /// <summary>
            /// Low
            /// </summary>
            Low = 0x02,

            /// <summary>
            /// Critical
            /// </summary>
            Critical = 0x04,

            /// <summary>
            /// Charging
            /// </summary>
            Charging = 0x08,

            /// <summary>
            /// Reserved1
            /// </summary>
            Reserved1 = 0x10,

            /// <summary>
            /// Reserved2
            /// </summary>
            Reserved2 = 0x20,

            /// <summary>
            /// Reserved3
            /// </summary>
            Reserved3 = 0x40,

            /// <summary>
            /// No system battery
            /// </summary>
            NoBattery = 0x80,

            /// <summary>
            /// Unknown status
            /// </summary>
            Unknown = High | Low | Critical | Charging | Reserved1 | Reserved2 | Reserved3 | NoBattery
        }

        /// <summary>
        /// Responses from <see cref="WaitForMultipleObjects"/> function.
        /// </summary>
        private enum Wait : uint
        {
            /// <summary>
            /// The state of the specified object is signaled.
            /// </summary>
            Object = 0x00000000,
            /// <summary>
            /// Wait abandoned.
            /// </summary>
            Abandoned = 0x00000080,
            /// <summary>
            /// Wait failed.
            /// </summary>
            Failed = 0xffffffff,
        }


        #endregion -----------------Enumerations-------------------

        #region --------------------Members-----------------------

        /// <summary>
        /// Indicates that an application would like to receive all types of 
        /// power notifications.
        /// </summary>
        private const uint POWER_NOTIFY_ALL = 0xFFFFFFFF;

        /// <summary>
        /// Indicates an infinite wait period
        /// </summary>
        private const int INFINITE = -1;

        /// <summary>
        /// Allocate message buffers on demand and free the message buffers after they are read.
        /// </summary>
        private const int MSGQUEUE_NOPRECOMMIT = 1;

        /// <summary>
        /// Event to wake up the worker thread so that it can close
        /// </summary>
        private AutoResetEvent powerThreadAbort;

        /// <summary>
        /// Flag requesting worker thread closure
        /// </summary>
        private bool abortPowerThread = false;

        /// <summary>
        /// Flag to indicate that the worker thread is running
        /// </summary>
        private bool powerThreadRunning = false;

        /// <summary>
        /// Thread interface queue
        /// </summary>
        private Queue powerQueue;

        /// <summary>
        /// Handle to the message queue
        /// </summary>
        private IntPtr hMsgQ = IntPtr.Zero;

        /// <summary>
        /// Handle returned from RequestPowerNotifications
        /// </summary>
        private IntPtr hReq = IntPtr.Zero;

        /// <summary>
        /// Boolean used to indicate if the object has been disposed
        /// </summary>
        private bool bDisposed = false;

        /// <summary>
        /// Occurs when there is some PowerNotify information available.
        /// </summary>
        public event EventHandler PowerNotify;

        #endregion --------------------Members--------------------

        #region -------------------Structures---------------------

        /// <summary>
        /// Contains information about a message queue.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct MessageQueueOptions
        {
            /// <summary>
            /// Size of the structure in bytes.
            /// </summary>
            public uint Size;

            /// <summary>
            /// Describes the behavior of the message queue. Set to MSGQUEUE_NOPRECOMMIT to 
            /// allocate message buffers on demand and to free the message buffers after 
            /// they are read, or set to MSGQUEUE_ALLOW_BROKEN to enable a read or write 
            /// operation to complete even if there is no corresponding writer or reader present.
            /// </summary>
            public uint Flags;

            /// <summary>
            /// Number of messages in the queue.
            /// </summary>
            public uint MaxMessages;

            /// <summary>
            /// Number of bytes for each message, do not set to zero.
            /// </summary>
            public uint MaxMessage;

            /// <summary>
            /// Set to TRUE to request read access to the queue. Set to FALSE to request write 
            /// access to the queue.
            /// </summary>
            public uint ReadAccess;
        };

        /// <summary>
        /// Contains information about the power status of the system  
        /// as received from the Power Status message queue.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct PowerInfo
        {
            /// <summary>
            /// Defines the event type.
            /// </summary>
            /// <see cref="MessageTypes"/>
            public MessageTypes Message;

            /// <summary>
            /// One of the system power flags.
            /// </summary>
            /// <see cref="SystemPowerStates"/>
            public SystemPowerStates Flags;

            /// <summary>
            /// The byte count of SystemPowerState that follows. 
            /// </summary>
            public uint Length;

            /// <summary>
            /// Levels available in battery flag fields
            /// </summary>
            public uint NumLevels;

            /// <summary>
            /// Number of seconds of battery life remaining, 
            /// or 0xFFFFFFFF if remaining seconds are unknown.
            /// </summary>
            public uint BatteryLifeTime;

            /// <summary>
            /// Number of seconds of battery life when at full charge, 
            /// or 0xFFFFFFFF if full battery lifetime is unknown.
            /// </summary>
            public uint BatteryFullLifeTime;

            /// <summary>
            /// Number of seconds of backup battery life remaining, 
            /// or BATTERY_LIFE_UNKNOWN if remaining seconds are unknown.
            /// </summary>
            public uint BackupBatteryLifeTime;

            /// <summary>
            /// Number of seconds of backup battery life when at full charge, 
            /// or BATTERY_LIFE_UNKNOWN if full battery lifetime is unknown.
            /// </summary>
            public uint BackupBatteryFullLifeTime;

            /// <summary>
            /// AC power status. 
            /// </summary>
            /// <see cref="ACLineStatus"/>
            public ACLineStatus ACLineStatus;

            /// <summary>
            /// Battery charge status. 
            /// </summary>
            /// <see cref="BatteryFlags"/>
            public BatteryFlags BatteryFlag;

            /// <summary>
            /// Percentage of full battery charge remaining. 
            /// This member can be a value in the range 0 (zero) to 100, or 255 
            /// if the status is unknown. All other values are reserved.
            /// </summary>
            public byte BatteryLifePercent;

            /// <summary>
            /// Backup battery charge status. 
            /// </summary>
            public byte BackupBatteryFlag;

            /// <summary>
            /// Percentage of full backup battery charge remaining. 
            /// This value must be in the range of 0 to 100, or BATTERY_PERCENTAGE_UNKNOWN.
            /// </summary>
            public byte BackupBatteryLifePercent;
        };

        #endregion -------------------Structures------------------

        #region ---------------------Methods----------------------

        /// <summary>
        /// Ensures that resources are freed when the garbage collector reclaims the object.
        /// </summary>
        ~PowerManagement()
        {
            Dispose();
        }

        /// <summary>
        /// Releases the resources used by the object.
        /// </summary>
        public void Dispose()
        {
            if (!bDisposed)
            {
                // Try disabling notifications and ending the thread
                DisableNotifications();
                bDisposed = true;

                // SupressFinalize to take this object off the finalization queue 
                // and prevent finalization code for this object from executing a second time.
                GC.SuppressFinalize(this);
            }
        }

        /// <summary>
        /// Sets the system power state to the requested value.
        /// </summary>
        /// <param name="systemState">The system power state to set the device to.</param>
        /// <returns>Win32 error code</returns>
        /// <remarks>Should be used with extreme care since it may result in an unexpected 
        /// application or system behavior.</remarks>
        public int SetSystemPowerState(SystemPowerStates systemState)
        {
            uint nError = 0;

            nError = CESetSystemPowerState(
                IntPtr.Zero,
                (uint)systemState,
                0);

            return (int)nError;
        }

        /// <summary>
        /// Returns the current system power state currently in effect.
        /// </summary>
        /// <param name="systemStateName">Receives the system power state name</param>
        /// <param name="systemState">Receives the system power state</param>
        /// <returns>Win32 error code</returns>
        public int GetSystemPowerState(StringBuilder systemStateName, out SystemPowerStates systemState)
        {
            uint nError = 0;

            nError = CEGetSystemPowerState(systemStateName, (uint)systemStateName.Capacity, out systemState);

            return (int)nError;
        }

        /// <summary>
        /// Requests that the Power Manager change the power state of a device.
        /// </summary>
        /// <param name="deviceName">Specifies the device name, for example, COM1:.</param>
        /// <param name="deviceState">Indicates the device power state</param>
        /// <returns>Win32 error code</returns>
        /// <remarks>Should be used with extreme care since it may result in an unexpected 
        /// application or system behavior.</remarks>
        public int DevicePowerNotify(string deviceName, DevicePowerStates deviceState)
        {
            uint nError = 0;

            nError = CEDevicePowerNotify(deviceName, (uint)deviceState, (uint)PowerReqFlags.POWER_NAME);

            return (int)nError;
        }

        /// <summary>
        /// Activates notification events. An application can now register to PowerNotify and be 
        /// notified when a power notification is received.
        /// </summary>
        public void EnableNotifications()
        {
            // Set the message queue options
            MessageQueueOptions Options = new MessageQueueOptions();

            // Size in bytes ( 5 * 4)
            Options.Size = (uint)Marshal.SizeOf(Options);
            // Allocate message buffers on demand and to free the message buffers after they are read
            Options.Flags = MSGQUEUE_NOPRECOMMIT;
            // Number of messages in the queue.
            Options.MaxMessages = 32;
            // Number of bytes for each message, do not set to zero.
            Options.MaxMessage = 512;
            // Set to true to request read access to the queue.
            Options.ReadAccess = 1;    // True

            // Create the queue and request power notifications on it
            hMsgQ = CECreateMsgQueue("PowerNotifications", ref Options);

            hReq = CERequestPowerNotifications(hMsgQ, POWER_NOTIFY_ALL);

            // If the above succeed
            if (hMsgQ != IntPtr.Zero && hReq != IntPtr.Zero)
            {
                powerQueue = new Queue();

                // Create an event so that we can kill the thread when we want
                powerThreadAbort = new AutoResetEvent(false);

                // Create the power watcher thread
                new Thread(new ThreadStart(PowerNotifyThread)).Start();
            }
        }

        /// <summary>
        /// Disables power notification events.
        /// </summary>
        public void DisableNotifications()
        {
            // If we are already closed just exit
            if (!powerThreadRunning)
                return;

            // Stop receiving power notifications
            if (hReq != IntPtr.Zero)
                CEStopPowerNotifications(hReq);

            // Attempt to end the PowerNotifyThread
            abortPowerThread = true;
            powerThreadAbort.Set();

            // Wait for the thread to stop
            int count = 0;
            while (powerThreadRunning)
            {
                Thread.Sleep(100);

                // If it did not stop it time record this and give up
                if (count++ > 50)
                    break;
            }
        }

        /// <summary>
        /// Obtain the next PowerInfo structure
        /// </summary>
        public PowerInfo GetNextPowerInfo()
        {
            // Get the next item from the queue in a thread safe manner
            lock (powerQueue.SyncRoot)
                return (PowerInfo)powerQueue.Dequeue();
        }

        /// <summary>
        /// Worker thread that creates and reads a message queue for power notifications
        /// </summary>
        private void PowerNotifyThread()
        {
            powerThreadRunning = true;

            // Keep going util we are asked to quit
            while (!abortPowerThread)
            {
                IntPtr[] Handles = new IntPtr[2];

                Handles[0] = hMsgQ;
                Handles[1] = powerThreadAbort.Handle;

                // Wait on two handles because the message queue will never
                // return from a read unless messages are posted.
                Wait res = (Wait)CEWaitForMultipleObjects(
                                                        (uint)Handles.Length,
                                                        Handles,
                                                        false,
                                                        INFINITE);

                // Exit the loop if an abort was requested
                if (abortPowerThread)
                    break;

                // Else
                switch (res)
                {
                    // This must be an error - Exit loop and thread
                    case Wait.Abandoned:
                        abortPowerThread = true;
                        break;

                    // Timeout - Continue after a brief sleep
                    case Wait.Failed:
                        Thread.Sleep(500);
                        break;

                    // Read the message from the queue
                    case Wait.Object:
                        {
                            // Create a new structure to read into
                            PowerInfo Power = new PowerInfo();

                            uint PowerSize = (uint)Marshal.SizeOf(Power);
                            uint BytesRead = 0;
                            uint Flags = 0;

                            // Read the message
                            if (CEReadMsgQueue(hMsgQ, ref Power, PowerSize,
                                                ref BytesRead, 0, ref Flags))
                            {
                                // Set value to zero if percentage is not known
                                if ((Power.BatteryLifePercent < 0) || (Power.BatteryLifePercent > 100))
                                    Power.BatteryLifePercent = 0;

                                if ((Power.BackupBatteryLifePercent < 0) || (Power.BackupBatteryLifePercent > 100))
                                    Power.BackupBatteryLifePercent = 0;

                                // Add the power structure to the queue so that the 
                                // UI thread can get it
                                lock (powerQueue.SyncRoot)
                                    powerQueue.Enqueue(Power);

                                // Fire an event to notify the UI
                                if (PowerNotify != null)
                                    PowerNotify(this, null);
                            }

                            break;
                        }
                }
            }

            // Close the message queue
            if (hMsgQ != IntPtr.Zero)
                CECloseMsgQueue(hMsgQ);

            powerThreadRunning = false;
        }


        #endregion -----------------Methods---------------------

        #region ---------Native Power Management Imports----------

        [DllImport("coredll.dll", EntryPoint = "RequestPowerNotifications")]
        private static extern IntPtr CERequestPowerNotifications(IntPtr hMsgQ, uint Flags);

        [DllImport("coredll.dll", EntryPoint = "StopPowerNotifications")]
        private static extern bool CEStopPowerNotifications(IntPtr hReq);

        [DllImport("coredll.dll", EntryPoint = "SetDevicePower")]
        private static extern uint CESetDevicePower(string Device, uint dwDeviceFlags, uint DeviceState);

        [DllImport("coredll.dll", EntryPoint = "GetDevicePower")]
        private static extern uint CEGetDevicePower(string Device, uint dwDeviceFlags, uint DeviceState);

        [DllImport("coredll.dll", EntryPoint = "DevicePowerNotify")]
        private static extern uint CEDevicePowerNotify(string Device, uint DeviceState, uint Flags);

        [DllImport("coredll.dll", EntryPoint = "SetSystemPowerState")]
        private static extern uint CESetSystemPowerState(IntPtr sState, uint StateFlags, uint Options);

        [DllImport("coredll.dll", EntryPoint = "GetSystemPowerState")]
        private static extern uint CEGetSystemPowerState(StringBuilder Buffer, uint Length, out SystemPowerStates Flags);

        [DllImport("coredll.dll", EntryPoint = "CreateMsgQueue")]
        private static extern IntPtr CECreateMsgQueue(string Name, ref MessageQueueOptions Options);

        [DllImport("coredll.dll", EntryPoint = "CloseMsgQueue")]
        private static extern bool CECloseMsgQueue(IntPtr hMsgQ);

        [DllImport("coredll.dll", EntryPoint = "ReadMsgQueue")]
        private static extern bool CEReadMsgQueue(IntPtr hMsgQ, ref PowerInfo Power, uint BuffSize, ref uint BytesRead, uint Timeout, ref uint Flags);

        [DllImport("coredll.dll", EntryPoint = "WaitForMultipleObjects", SetLastError = true)]
        private static extern int CEWaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, int dwMilliseconds);

        #endregion ---------Native Power Management Imports----------
    }
}
WinCE Socket
using System;
using System.Collections.Generic;
using System.Text;

using System.Net;
using System.Net.Sockets;
using System.Threading;


namespace Common
{
    /// <summary>
    /// Socket notification events.
    /// </summary>
    public enum NotifyEvents
    {
        Connected,
        DataSent,
        DataReceived,
        Disconnected,
        ConnectError,
        SendError,
        ReceiveError,
        DisconnectError,
        OtherError
    }

    // Socket communications will be done asynchronously
    public class DeviceSocket
    {
        // The Socket class provides a rich set of methods and properties for network communications via sockets. 
        // Although Socket class supports both synchronous and asynchronous data transfers, we choose asynchronous 
        // method here
        public Socket mySocket = null;

        // Used to synchronize the shutdown process, terminate
        // any pending async calls before Disconnect returns
        ManualResetEvent asyncEvent = new ManualResetEvent(true);

        // private string terminator = "<END_OF_RECORD>";

        public string receiveBuf = null;
        private const int BUFFER_SIZE = 1024;

        // notification event
        public delegate void NotifyEventHandler(NotifyEvents nEvent, object data);
        public event NotifyEventHandler Notify;

        // Closing flag
        private bool closing = false;
        byte[] bRcvd = new byte[BUFFER_SIZE];

        /// <summary>
        /// Connect to the specified address and port number.
        /// </summary>
        public void Connect(String ip, int port)
        {
            // Create a socket object
            // The addressFamily parameter (Address for IP version 4) specifies the addressing scheme the Socket class 
            // The socketType parameter specifies the type of the Socket class
            // The protocolType parameter (tcp - Transmission Control Protocol) specifies the protocol used by Socket
            mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // Sets the state of the event to nonsignaled, causing threads to block
            asyncEvent.Reset();

            // Prepare for async connection
            IPAddress ipAddress = IPAddress.Parse(ip);
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, port);

            // Begins an asynchronous request for a remote host connection
            mySocket.BeginConnect(ipEndPoint, new AsyncCallback(OnConnect), null);

            // wait for any async operations to complete
            asyncEvent.WaitOne();
        }

        /// <summary>
        /// The property Socket.Connected does not always indicate if the socket is currently 
        /// connected, this polls the socket to determine the latest connection state.
        /// 
        /// Returns True or False
        /// </summary>
        public bool IsConnected
        {
            get
            {
                if (mySocket == null)   return false;

                // the socket is not connected if the Connected property is false
                if (!mySocket.Connected)    return false;

                // there is no guarantee that the socket is connected even if the
                // Connected property is true
                try
                {
                    // poll for error to see if socket is connected
                    return !mySocket.Poll(1, SelectMode.SelectError);
                }
                catch
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Async connect callback
        /// </summary>
        private void OnConnect(IAsyncResult ar)
        {
            try
            {
                // Ends a pending asynchronous connection request
                mySocket.EndConnect(ar);

                // Assert: Connected. Notify the app.
                NotifyCaller(NotifyEvents.Connected, null);
            }
            catch (Exception ex)
            {
                NotifyCaller(NotifyEvents.ConnectError, ex.Message);
            }
        }

        /// <summary>
        /// Disconnect a connected socket
        /// </summary>
        public void Disconnect()
        {
            // if the socket is not created
            if (mySocket == null) return;

            closing = true;

            try
            {
                // first, shutdown the socket
                mySocket.Shutdown(SocketShutdown.Both);
            }
            catch { }

            try
            {
                // next, close the socket which terminates any pending
                // async operations
                mySocket.Close();

                // wait for any async operations to complete
                asyncEvent.WaitOne();
            }
            catch { }

            closing = false;

        }

        /// <summary>
        /// Send data to the server.
        /// </summary>
        public void Send(String data)
        {
            try
            {
                // String must be converted to byet[]
                byte[] byteArray = new ASCIIEncoding().GetBytes(data);

                // Send the data to the connected socket
                // mySocket.BeginSend(byteArray, 0, byteArray.Length, SocketFlags.None, null, null);
                mySocket.BeginSend(byteArray, 0, byteArray.Length, SocketFlags.None, new AsyncCallback(OnSend), null);

                asyncEvent.Reset();

                // Send the terminator
                // mySocket.BeginSend(new ASCIIEncoding().GetBytes(terminator), 0, terminator.Length, SocketFlags.None, new AsyncCallback(OnSend), true);
            }
            catch (Exception ex)
            {
                NotifyCaller(NotifyEvents.SendError, ex.Message);
            }

        }

        /// <summary>
        /// Async send callback
        /// </summary>
        private void OnSend(IAsyncResult ar)
        {
            try
            {
                mySocket.EndSend(ar);

                // ASSERT: Data sent successfully
                NotifyCaller(NotifyEvents.DataSent, null);
            }
            catch (Exception ex)
            {
                NotifyCaller(NotifyEvents.SendError, ex.Message);
            }
        }

        /// <summary>
        /// Receive data from the server.
        /// </summary>
        public void Receive()
        {
            try
            {
                asyncEvent.Reset();

                mySocket.BeginReceive(bRcvd, 0, BUFFER_SIZE, SocketFlags.None, new AsyncCallback(OnReceive), null);

                //Thread.Sleep(1000);
            }
            catch (Exception ex)
            {
                NotifyCaller(NotifyEvents.ReceiveError, ex.Message);
            }
        }

        /// <summary>
        /// Async send callback
        /// </summary>
        private void OnReceive(IAsyncResult ar)
        {
            try
            {
                int len = mySocket.EndReceive(ar);
                receiveBuf = ASCIIEncoding.ASCII.GetString(bRcvd, 0, len);

                // ASSERT: Data receieved successfully
                NotifyCaller(NotifyEvents.DataReceived, receiveBuf);
            }
            catch (Exception ex)
            {
                NotifyCaller(NotifyEvents.ReceiveError, ex.Message);
            }
        }

        /// <summary>
        /// Notify the app
        /// </summary>
        private void NotifyCaller(NotifyEvents nEvent, object data)
        {
            // the async operation has completed
            asyncEvent.Set();

            // don't raise notification events when disconnecting
            if ((this.Notify != null) && !closing)
                Notify(nEvent, data);
        }

    }
}

 

posted @ 2013-01-15 14:18  数据酷软件  阅读(3039)  评论(8编辑  收藏  举报