2014年2月27日 星期四

[C#/winform] DataGridView 隨視窗大小變動/列的Header加入文字/隱藏行,列

DataGridView 隨視窗大小變動

將DataGridView放入Form中,調整Dock(選中間那個) = Fill即可。


DataGridView 列的Header加入文字

要讓Row的Header加入文字,只要輸入

DataGridView1.Rows[第幾列].HeaderCell.Value = 文字 即可。

隱藏行,列

DataGridView.Columns[第幾行].Visble = false; //行

DataGridView.Rows[第幾列].Visble = false; //列

小技巧,但有大功用喔!

End


[C#/win32 API] SendMessage() 與 PostMessage()

網路上比較少SendMessage()跟PostMessage資料

先給SendMessage範例




SendMessage會等到接收端check後才會繼續執行,而PostMessage則是丟入訊息queue,繼續做。

以下範例都要先加入 using System.Runtime.InteropServices;

SendMessage A端(控制端):

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

using System.Runtime.InteropServices;
namespace TestA
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        private static extern int SendMessage(IntPtr hwnd, uint wMsg, int wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern uint RegisterWindowMessage(string lpString);
        uint MSG_SHOW = RegisterWindowMessage("Show Message");

        [DllImport("user32.dll")]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
     

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            IntPtr form_name = FindWindow(null, "要控制的視窗元件名稱(text,不是name)");//找B的IntPtr 用來代表指標或控制代碼

            if (form_name != IntPtr.Zero)
            {
                try
                {
                    int iNum = 9527;
                    SendMessage(form_name, MSG_SHOW, iNum, IntPtr.Zero);
                }
                catch (Exception)
                {
                }
            }
        }
    }
}

SendMessage B端(接收端):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace TestB
{
    public partial class TestB_1 : Form
    {
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern uint RegisterWindowMessage(string lpString);
        uint MSG_SHOW = RegisterWindowMessage("Show Message");
        public TestB_1()
        {
            InitializeComponent();
        }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == MSG_SHOW)
            {
                label1.Text = (string)m.WParam.ToString();
            }
            base.WndProc(ref m);
        }
    }
}

PostMessage A端(呼叫端):

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

namespace postmessager
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        [DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)]
        private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int PostMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
 
        private void post()
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            IntPtr ptr = FindWindow(null, "post messager B");
            if (ptr != IntPtr.Zero)
            {
                int msg = 9527;
                PostMessage(ptr, msg, IntPtr.Zero, IntPtr.Zero);
            }
        }
    }
}

PostMessage B端(接收端):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace PostmessagerB
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 9527)//m.Msg == MSG_SHOW
            {
                //label1.Text = (string)m.WParam.ToString();
                MessageBox.Show("9527");
            }
            base.WndProc(ref m);
        }
    }
}

至於為何可以使用SendMessage(),PostMessage(),FindWindow(),RegisterWindowMessage(),都是要先

import user32.dll (也就是[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 後面為參數)

然後接收端使用WndProc (WindowProcess,我個人理解縮寫函意)去接收。

大部分程式碼也是參考網路上的,但大家都抄來抄去,而且我有修改程式碼,所以就不註明出處了(因為也不知道原始是誰的),當然我的版本是比較精簡化。

End

2014年2月19日 星期三

[C#/winform] 主Form / 副 Form 如何製作+連結2個Form

在VS2012裡面按 專案-> 加入windows form

你設定的檔名ex : form2

回到主Form,在要顯示的地方加入

Form2 frm2(這名稱可以改) =  new Form2();

frm2.showdialog(this); //show 副form

this.show(); //回到主form

即可。

[C#/Error] 不一致的存取範圍: 欄位型別 ...... 比欄位 ..... 存取範圍低

通常初學者寫Class不會特別宣告型別

但如果你宣告

public static Class名稱;
public Form
{
    ....
    ....
}
Class 名稱
{
    ......
}

這樣就有問題了!! 因為基本設定 Class沒加任何型別 = internal(內部可用)


Public > internal  所以 造成 "不一致的存取範圍: 欄位型別 ...... 比欄位 ..... 存取範圍低"的Error!

public static Class名稱;
public Form
{
    ....
    ....
}
public Class 名稱
{
    ......
}

這樣才對

End


[C#] List的基本用法

在寫程式常常會遇到要動態陣列,C#也很貼心的做了一個功能----泛型List<T>

但我想主要不是用在這邊....沒關係,還是講解一下List的用法

一開始一定就是

List<任意型態> 名稱 = new List<跟前面一樣的任意型態>();   //new給它一個空間

然後就可以在迴圈裡面丟給它值(它可以任意變動長度)

丟值的方法為: 名稱.Add(值);

如果要從中取出值就跟陣列一樣

名稱[0] (陣列位置可以改,這邊只是範例)

如果要長度 :名稱.Count 就會跟平常的.Length一樣囉!

範例:

List<byte> modbus = new List<byte>();

for (int i = 0; i < 30; i++)
{
       if (Modbus_save[i] == true) //這邊只是設一個條件而已
      {
            modbus.Add(Convert.ToByte(i)); //把i轉byte型態,存入List<T>
       }
}

End

2014年2月18日 星期二

[C#/winform] Form與Form之間 傳值

有許多方法可以傳值,包括Properties/Class/ini檔..等

這邊講兩個

1.Properties

使用時機: 需要儲存使用者設定時。

使用方法: 先到專案-> xxx屬性->設定,設定幾個需要使用的變數(型態要調好)

然後Form2內將變數代入Properties.Settings.Default.(設的變數名稱),

接著再去Form1內將Properties.Settings.Default.(設的變數名稱) 帶回form1(設一個新的變數去接)

記得要儲存使用者設定要加入Properties.Settings.Default.Save();


2.Class

使用時機: 滿廣泛的,但關掉無法儲存

使用方法: Form2內設一個public 變數

ex:

Public int a {get; set;}

public Form2{

....
}

回到Form1以後就可以用了,記得要寫在ShowDialog();的下方

Form2 frm2 = new Form2();

frm2.ShowDialog(this);

(寫在這邊)

當然要接值的話,型別也要對就是了。

End

2014年2月14日 星期五

[C#/winform] smtp傳送電子郵件(email)

using System.Net.Mail;
using System.Net;

   class Email
    {
        public string From {get;set; }
        public string To { get; set; }
        public string Subject { get; set; }
        public string Body { get; set; }
        public string Account { get; set; }
        public string Password { get; set; }
        public string Server { get; set; }
        public string Port { get; set; }
       
        public void Send_email()
        {
           //這邊先設定From,To,Subject,Body,Account,Password,Server,Port

            SmtpClient theSmtpClient = new SmtpClient(Server);
            NetworkCredential networkcredential = new NetworkCredential(Account, Password);//帳密
            theSmtpClient.UseDefaultCredentials = false;
            theSmtpClient.Credentials = networkcredential;
            int Int_port = Convert.ToInt32(Port);
            if (Int_port == 587)
            {
                theSmtpClient.EnableSsl = true;
            }
            else//不是587 就是 25
            {
                theSmtpClient.EnableSsl = false;
            }
            theSmtpClient.Port = Int_port;

            try
            {
                theSmtpClient.Send(From, To, Subject, Body);
            }
            catch (Exception)
            {

            }
        }
    }

十分簡單,不過要注意的地方就是Port在有SSL加密認證的環境下要用587(ex:gmail),沒有的話則用25即可,然後Using要加入net / net.mail

End

2014年2月13日 星期四

[C#/winform] 呼叫外部程式(傳入參數) + 不會顯示出來 + 結束強制關閉程式

本篇分成三部份來講

a)呼叫外部程式

//呼叫程式(啟動)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Diagnostics;

namespace Activate_exe
{
    static class Program
    {
        /// <summary>
        /// 應用程式的主要進入點。
        /// </summary>
        [STAThread]
        static void Main()
        {
            string target = 目標路徑;

            ProcessStartInfo pInfo = new ProcessStartInfo(target);
            pInfo.Arguments = "我是參數";
            using (Process p = new Process())
            {
                p.StartInfo = pInfo;
                p.Start();
            }

        }
    }
}


//主程式(被呼叫)
//在Program.cs內部
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace (被呼叫的程式,名稱自行更改)
{
    static class Program
    {
        /// <summary>
        /// 應用程式的主要進入點。
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            //Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            if (args.Length == 0)
            {
                Application.Run(new Form1());
            }
            else
            {
                Application.Run(new Form1(args[0].ToString()));
            }
        }
    }
}

呼叫程式十分簡單,也不需要用到winform,就直接寫在Program.cs即可

一開始記得要加入"using System.Diagnostics;"不然ProcessStartInfo 沒法用,

new一個ProcessStartInfo(要呼叫的程式路徑),然後 ProcessStartInfo.Argument內就是要傳的參數。

(參數遇到空格 疑似可以用\" (http://blogs.msdn.com/b/csharpfaq/archive/2004/03/12/88415.aspx)來解決)

傳多個參數,就是使用空格作為分隔 參數A空格B,在Form1値得注意的地方就是有兩個多載,當

沒有參數傳來的時後就用Form1(),有則Form1(args[])



-----------------------------------------------------------------------------------------------------------

被呼叫的程式要接參數,所以main(string[] args

主程式//Form1.cs

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

namespace Argument_IN_exe
{
    public partial class Form1 : Form
    {
        private string _args;
        public Form1()
        {
            InitializeComponent();

        }

        public Form1(string value)
        {
            InitializeComponent();
            if (!string.IsNullOrEmpty(value))
            {
                _args = value;
                MessageBox.Show(_args);
            }
        }
    }
}

b)不會顯示出來

要讓程式一開啟就不顯示出來,目前只知道這個方法(最小化+不顯是在系統列)

寫在Form load事件當中,一讀就縮最小,但是有個問題就是你無法停止它(所以才需要

c.強制關閉程式)

private void Form1_Load_1(object sender, EventArgs e)
{
       this.WindowState = FormWindowState.Minimized;
       this.ShowInTaskbar = false;
       this.Hide();
}

private void Form1_Shown(object sender, EventArgs e)
{
      this.Hide();
}


c)結束強制關閉程式

光有Close()是不夠的,可以試試看Ctrl+Alt+Del,會發現沒有全部關完。

加入Enviroment這行吧!

this.Close();
Environment.Exit(Environment.ExitCode);

參考: http://www.dotblogs.com.tw/atowngit/archive/2009/12/26/12681.aspx


2014年2月12日 星期三

[C#/winform] Notifyicon(系統列圖示) + ContextMenuStrip(右鍵選單) 設定

首先,先到工具列拉出NotifyIcon 與 ContextMenuStrip兩個工具

NotifyIcon是系統列工具,可以改變圖示(如果覺得它很醜)

ContextMenuStrip則是應用在圖示上面按滑鼠右鍵會出現的選單

如果一開始就不要讓程式show出來,請寫入

            this.WindowState = FormWindowState.Minimized;
            this.ShowInTaskbar = false;

這樣起始畫面就會縮到最小。(這段要寫再Form Load事件裡面!!)

在ContextMenuStrip當中新增一個選項ex: Exit ,接著點它兩下

進入程式部分:(這邊看要怎樣打都可以)

 this.Close();//exit代表關掉程式

最後,在Notify icon的工具欄當中把ContextMenuStrip那一欄改為你所拉進來的ContextMenuStrip的

名稱,這樣它會直接去抓那個工具,很簡單,但是很實用喔!

End


2014年2月11日 星期二

[C#/Serialize] 簡易版本-Serailize/Deserialize

上一篇序列化/反序列化比較難,這次寫一點簡單的。

首先一樣先建一個類別庫(新增專案->類別庫)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Solar_stucture
{
    [Serializable]
    public class Solar_read
    {
        public byte Adress = 0;
        public byte Function_code = 0;
        public byte Byte_count = 0;
    }
}

然後建製(F9) 會產生錯誤,很正常。但不是錯誤。(在Debug資料夾內會有.dll檔)

接著,開個新的專案。然後  專案->加入參考...(瀏覽->選剛剛產生的dll檔)

在主程式(或任何你想要加的地方)加入

Solar_read Read_protocol = new Solar_read();

然後使用Read_protocol.Adress,你會發現可以使用!!

沒錯,就把東西存進去(型別要對)

都加完了以後,開始寫入檔案。

            IFormatter formatter = new BinaryFormatter();
            Stream stream = new FileStream("Read Protocol.dat", FileMode.Create, FileAccess.Write,       FileShare.Read);
            formatter.Serialize(stream, Read_protocol);
            stream.Close();

記得dll檔那邊要有[Serializable]不然這邊執行上會出現serialize的異常。序列化到此結束!


基本的反序列化也十分簡單:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Solar_stucture;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace SolarControl_Front
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            IFormatter formatter = new BinaryFormatter();
            Stream stream = new FileStream(序列化存的檔案路徑, FileMode.Open, FileAccess.Read, FileShare.Read);
            Solar_read read = (Solar_read)formatter.Deserialize(stream);
            MessageBox.Show(read.Adress.ToString());
            stream.Close();

        }
    }
}

一樣的東西,只是變成Deserialize(Stream stream),接的格式是用你所創建的Class格式喔!

MessageBox只是確認有弄對而已。 Over

[C#/進制轉換] byte資料 轉換 ASCII碼

先看看程式碼

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

namespace ByteToASCII
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

        }

        private void button1_Click(object sender, EventArgs e)
        {
            byte[] toASCII = new byte[4];
            toASCII[0] = Convert.ToByte(textBox1.Text,10);
            toASCII[1] = Convert.ToByte(textBox2.Text,10);
            toASCII[2] = Convert.ToByte(textBox3.Text,10);
            toASCII[3] = Convert.ToByte(textBox4.Text,10);

            textBox5.Text = System.Text.Encoding.ASCII.GetString(toASCII);
        }
    }
}

先new一個byte陣列,利用Convert.ToByte(String,多少進位)來轉換,存如byte陣列當中

之後用Sytem.Text.Encoding.ASCII.GetString(byte陣列) 即可轉換

End

2014年2月10日 星期一

[C#/Serialize] 在不同檔案間傳遞結構(structure)利用Serialize和Deserialize

首先必須先創建一個"類別庫"(新增->類別庫 in VS2012)

一定要有關鍵字[Serializable]否則無法,然後建立一個Struct

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.ComponentModel;

namespace PassingStruct
{
    public class Class1
    {
    }

    [Serializable]
    public struct MemberList
    {
        private BindingList<Member> _MemberCollection;
        public BindingList<Member> MemberCollection
        {
            get
            {
                if (this._MemberCollection == null)
                    this._MemberCollection = new BindingList<Member>();
                return this._MemberCollection;
            }
        }
    }

    [Serializable]
    public struct Member
    {
        public int ID { get; set; }
        public int age { get; set; }
        public string name { get; set; }
        public int number { get; set; }
        public string sex { get; set; }
    }
}

編譯時會產生錯誤訊息,但其實還是成功(在Debug資料夾內)會有一個dll檔產生。

OK,到這邊,需要將dll檔加入參考到要序列化的程式碼。

以下為序列化程式碼

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


using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using PassingStruct;

namespace Binary_filestreame
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
         
        }

        private void button1_Click(object sender, EventArgs e)
        {

            PassingStruct.MemberList list = CreateClass();
            SerializeToBinary("list.dat", list);
        }
        public PassingStruct.MemberList CreateClass()
        {
            PassingStruct.MemberList list = new PassingStruct.MemberList();
            list.MemberCollection.Add(new PassingStruct.Member() { ID = 1, age = 18, name = "paul walker", number = 999, sex = "male" });
            list.MemberCollection.Add(new PassingStruct.Member() { ID = 2, age = 20, name = "jonathan brewster", number = 123, sex = "female" });
            return list;
        }
        public static void SerializeToBinary(string FileName, object Object)
        {
            Stream stream = null;
            IFormatter/*用於格式化已經序列化的東西*/ format = new BinaryFormatter();//以二進位格式序列化和還原序列化物件
            try
            {
                stream = new FileStream(FileName,FileMode.Create,FileAccess.Write,FileShare.Read);
                format.Serialize(stream, Object);
            }
            catch(Exception ex)
            {
                throw ex;
            }
            finally
            {
                stream.Close();
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            PassingStruct.MemberList list = DeserializeFromBinary<PassingStruct.MemberList>("list.dat");
        }

        public static T DeserializeFromBinary<T>(string FileName)
        {
            IFormatter formatter = new BinaryFormatter();
            Stream stream = null;
            try
            {
                stream = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read);
                object obj = formatter.Deserialize(stream);
                if (obj == null)
                    return default(T);
                else
                    return (T)obj;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                stream.Close();
            }
        }
    }
}

注意到在using這邊
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using PassingStruct;//這個就是dll檔,除了在Visual Studio專案裡面選擇 專案->加入參考->瀏覽->dll檔,還要加入這一行

然後,序列化基本上就完成了。接著就是反序列化:(以下為反序列化程式碼)

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

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using PassingStruct;

namespace serialize_transfer
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            //File.wr
        }

        public static T DeserializeFromBinary<T>(string FilePath)
        {
            IFormatter formatter = new BinaryFormatter();
            Stream stream = null;
            try
            {
                stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                object obj = formatter.Deserialize(stream);//問題出在這邊
                if (obj == null)
                    return default(T);
                else
                    return (T)obj;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                stream.Close();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            PassingStruct.MemberList list = DeserializeFromBinary<PassingStruct.MemberList>(@"C:\Users\daniel\Dropbox\Visual Studio 2012\Projects\Binary_filestreame\Binary_filestreame\bin\Debug\list.dat");
        }
    }
}

同樣也需要加入參考以及+using的程式碼 記得反序列化路徑要弄對就好了。

應用的部分,可使用在DataGridView上面

BindingSource Source = new BindingSource();
public void Form1_Load(object sender, EventArgs e)
{
    this.Source.DataSource = CreateClass().MemberCollection;

    this.dataGridView1.DataSource = this.Source;
    this.bindingNavigator1.BindingSource = this.Source;
    this.textBox1.DataBindings.Add("Text", this.Source, "ID");
    this.textBox2.DataBindings.Add("Text", this.Source, "name");
    this.textBox3.DataBindings.Add("Text", this.Source, "age");
    this.textBox4.DataBindings.Add("Text", this.Source, "phone");
    this.textBox5.DataBindings.Add("Text", this.Source, "sex");
}

End

參考資料: 余小章.net教學


2014年2月7日 星期五

[C#/winform] RS-232/SerialPort 傳送及接收

1.先從工具箱拉SerialPort元件(要記得程式碼加入System.IO.Ports)

2.點選元件可以調整BaudRate.DataBit.ParityBit.HandShake...等

3.也可以從程式碼中新增: serialPort1 = new SerialPort(COM幾(String), 9600, Parity.None, 8, StopBits.One);

4.如果要抓取電腦現有的COM,可以使用string[] port_name = SerialPort.GetPortName();
可以用foreach() loop + comboBox的add來新增到comboBox裡面

5.讀取部分
           private byte[] Port_read()
        {
            //---------------------------讀取部分---------------------------------//
            int B2R = serialPort1.BytesToRead;//有多少
            byte[] Buffer = new byte[B2R];//new多少byte 陣列
            if (B2R > 0)
            {
                serialPort1.Read(Buffer, 0, B2R);//有多少就讀入多少(共85byte)
            }
            return Buffer;
            //---------------------------讀取部分-End------------------------------//
        }

6.寫入部分
          //---------------------------寫入部分----------------------------------//
            //先檢查有幾個modbus,
            try
            {
                serialPort1.Write(byte陣列, 0, 寫多少byte);
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show("關閉通訊埠");//關閉通訊埠
            }
            catch (IOException IOE)
            {
                MessageBox.Show(IOE.Message);
                MessageBox.Show("IO錯誤");//IO exception
            }

大致上就完成簡單的通訊程式

其餘比較有用的:

System.Text.Encoding.Default.GetBytes(String); //string轉byte[]

System.Text.Encoding.Default.GetString(byte[]);//byte[]轉String

[C#] Class小記 - 以 CRC 16為例

先看程式碼,如下  

class CRC_16
    {
        public byte CRC_1 { get; set; }
        public byte CRC_2 { get; set; }

        public void CRC16_counter(byte[] data, int CRC_length) //跑兩個  1.送出去產生CRC(length = 6) 產生後 = 8
        {                                                    //        2.接收時驗證CRC(length = 83) 產生後 = 85
            ushort CRCFull = 0xFFFF;
            byte CRChigh = 0xFF, CRClow = 0xFF;
            char CRC_LSB;

            for (int i = 0; i < CRC_length; i++)
            {
                CRCFull = (ushort)(CRCFull ^ data[i]); //指令的第i組數字與CRCFull做XOR

                for (int j = 0; j < 8; j++)//8bit,所以跑八次
                {
                    CRC_LSB = (char)(CRCFull & 0x00000001);//取得最後一個位元的值
                    CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF); //右移一位,第一位補0
                    //檢查
                    if (CRC_LSB == 0) //如果右移的值為0
                    {
                        //就把剛剛右移+第一位補零的數值存入暫存(不過已經做了,這邊只是註解)
                    }
                    if (CRC_LSB == 1) // 如果右移的值為1
                    {
                        CRCFull = (ushort)(CRCFull ^ 0xA001);  //跟0xA001去做XOR,存入暫存器
                    }
                }
            }
            //跑完要讓高低register對調
            //CRChigh = (byte)((CRCFull >> 8) & 0xFF); //右移8Bit,也就是變成低位元,跟FF(1111 1111)做& 0還是0 1還是1
            //CRClow = (byte)(CRCFull & 0xFF); //低的變成高的
            CRChigh = (byte)(CRCFull >> 8); //右移8Bit,也就是變成低位元,跟FF(1111 1111)做& 0還是0 1還是1,不用&0xff也可
            CRClow = (byte)CRCFull; //低的變成高的,不用&0xff也可
            if (CRC_length == 6)
            {
                CRC_2 = CRChigh;//現在是低
                CRC_1 = CRClow; //現在是高
            }
            if (CRC_length == 83)
            {
                CRC_2 = CRChigh;//現在是低
                CRC_1 = CRClow; //現在是高
            }
        }
    }

本例Protocol有兩種1.傳送(8byte)2.接收(85byte)

因此先用6byte 算出CRC(最後2byte) = 8 / 83byte 算出CRC(最後2byte) = 85,

用以驗證CRC-16是否正確。

Class部份假如要使用到CRC_1,CRC_2 則需要 這樣呼叫

1.先new好Class
   CRC_16 CRC = new CRC_16();
2.存取Class內部資料
   CRC.CRC_1 ,CRC.CRC_2
3.如果內部將CRC_1宣告成 public static .... ,則呼叫需改為
   namespace名稱.Class名稱.CRC_1




2014年2月6日 星期四

[C#/winform] 讀寫ini檔

ini檔為windows內常用來儲存setting的檔案,C#範例如下。

dllimport為必須要的,會動態連結到system32的檔案,


WritePrivateProfileString(string section, string key, string val, string filePath)寫入ini檔案


GetPrivateProfileString( string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString,uint nSize, string lpFileName)讀取ini檔案

P.S.此範例為自動抓取RS-232 port放入comboBox1內,尚未寫完,但讀寫ini的部分是完整的

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

namespace Test_INI
{
    public partial class Form1 : Form
    {
        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);

        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
 
        public Form1()
        {
            InitializeComponent();

            string[] port_list = SerialPort.GetPortNames();
            foreach (string port in port_list)
            {
                //MessageBox.Show("本機可用serial port: " + port); //測試用
                comboBox1.Items.Add(port);
            }
            //當select port index換的時候 ,加入WritePrivateProfileString("Port Name", "name", 選擇的port
            //string, @"D:\myConfig.ini");//寫入ini檔
            WritePrivateProfileString("Port Name", "name", "COM1", @"D:\myConfig.ini");//寫入ini檔
            WritePrivateProfileString("ModBus", "number", "1", @"D:\myConfig.ini");//寫入ini檔
            WritePrivateProfileString("ModBus", "number", "2", @"D:\myConfig.ini");//寫入ini檔
        }

        private void button1_Click(object sender, EventArgs e)
        {
            StringBuilder data = new StringBuilder(255);
            GetPrivateProfileString("Port Name", "name", "NA", data, 255,          
            @"D:\myConfig.ini");//section/key/def/ stringbuilder的變數/長度/路徑
            MessageBox.Show(data.ToString());
        }
    }
}

[C#/winform] 不同解析度調整視窗大小

利用DPI取得螢幕解析度比例,進而改變WinForm的大小

如上,DPI可能為
DPI大小百分比
96100%
120125%
144150%

廢話不多說

// 找出字體大小,並算出比例
float dpiX, dpiY;
Graphics graphics = this.CreateGraphics();
dpiX = graphics.DpiX;
dpiY = graphics.DpiY;
int intPercent = (dpiX == 96) ? 100 : (dpiX == 120) ? 125 : 150;

// 針對字體變更Form的大小
this.Height = this.Height * intPercent / 100;
this.Width = this.Width * intPercent / 100;


end.