[轉貼] [C#.NET][Winform][Thread] 如何 使用 多執行緒 Thread / 跨執行緒 存取UI

2013年7月25日 星期四

[轉貼] http://www.dotblogs.com.tw/yc421206/archive/2009/02/13/7141.aspx

System.Threading 命名空間提供了執行緒的建立,讓開發者省去了不少程式碼。
使用多執行緒時先匯入System.Threading
如何建立執行緒
1.建立一個方法
              private void RunSample01()
              {
              Console.WriteLine("執行緒:{0}",Thread.CurrentThread.ManagedThreadId);
              }



2.建立ThreadStart委派,它是用來表示在執行緒上執行的方法。
       ThreadStart myRun = new ThreadStart(RunSample01);



3.建立Thread 類別,它是用來建立和控制執行緒,設定執行緒的優先權,並取得它的狀態。
       Thread myThread = new Thread(myRun);
4.啟動執行緒
       myThread.Start();



如何建立多重執行緒
              private void button2_Click(object sender, EventArgs e)
              {
              //1.建立ThreadStart委派
              ThreadStart myRun = new ThreadStart(RunSample01);
              for (int i = 0; i < 6; i++)
              {
              try
              {
              //2.建立Thread 類別
              Thread myThread = new Thread(myRun);
              //3.啟動執行緒
              myThread.Start();
              }
              catch (Exception)
              {
              //例外發生則終止迴圈執行
              break;
              }
              }
               
              }
如何傳遞參數給多執行緒
ThreadStart委派沒有傳遞參數的功能,在實際應用上我們常需要傳遞參數,這時就要改用ParameterizedThreadStart 委派。ParameterizedThreadStart 委派用法與ThreadStart委派大同小異,只是多了參數傳遞機制。
              private void button3_Click(object sender, EventArgs e)
              {
              //1.建立ParameterizedThreadStart委派
              ParameterizedThreadStart myPar = new ParameterizedThreadStart(RunSample02);
              //2.建立Thread 類別
              Thread myThread01 = new Thread(myPar);
              Thread myThread02 = new Thread(myPar);
              //3.啟動執行緒並帶入參數
              myThread01.Start("我是多執行緒第一號");
              myThread02.Start("我是多執行緒第二號");
              }       
              private void RunSample02(object o)
              {
              string myStr = o as string;
              //string myStr = (string)o;
              if (myStr == null)
              {
              myStr = (string)o;
              }
              else
              {
              for (int i = 0; i < 6; i++)
              {
              Console.WriteLine("{0}:{1}", myStr, Thread.CurrentThread.ManagedThreadId);
              Thread.Sleep(1000);
              }
              }
              }

如何跨執行緒存取UI
當我試著用WinFrom寫多執行緒時,卻出現了以下錯誤訊息
跨執行緒作業無效: 存取控制項 'textBox1' 時所使用的執行緒與建立控制項的執行緒不同。
詢問高手後有三種方法解決:
1.Form.CheckForIllegalCrossThreadCalls = False
2.建立委派
第一種方法,據說不安全,但我也不曉得哪裡不安全http://chhuang.googlepages.com/th_014_.gif,但用起來還蠻方便的。
第二種方法,比較正統使用委派的方式,若爾後需要改任何控制項的文字時(需有text屬性的),呼叫 myU即可。
              private delegate void myUICallBack(string myStr, Control ctl);
              private void myUI(string myStr, Control ctl)
              {
              if (this.InvokeRequired)
              {
              myUICallBack myUpdate = new myUICallBack(myUI);
              this.Invoke(myUpdate, myStr, ctl);
              }
              else
              {
              ctl.Text = myStr;
              }
              }




第三種方法,使用BackgroundWorker,更強大的功能讓我們省去了上述繁雜的動作。

更詳細的UI跨執行緒請參考:Windows Form UI優化入門課 – 非同步作業
C#範例下載:C#.NET多執行緒.rar
若有謬誤,煩請告知,新手發帖請多包涵http://www.dotblogs.com.tw/Providers/BlogEntryEditor/FCKeditor/editor/images/smiley/msn/regular_smile.gif


[轉貼]C# WinForm程序中使用熱鍵(HotKey)

[轉貼] http://dotnet.9sssd.com/winform/art/11

1、首先引入System.Runtime.InteropServices。
1
using System.Runtime.InteropServices;
2、在類內部聲明兩個API函數,它們的位置和類的成員變量等同 。
1
2
3
4
5
6
7
8
9
10
11
12
13
System.Runtime.InteropServices.DllImport("user32.dll")] //申明API函數
public static extern bool RegisterHotKey(
    IntPtr hWnd, // handle to window
    int id, // hot key identifier
    uint fsModifiers, // key-modifier options
    Keys vk // virtual-key code
);

[System.Runtime.InteropServices.DllImport("user32.dll")] //申明API函數
public static extern bool UnregisterHotKey(
    IntPtr hWnd, // handle to window
    int id // hot key identifier
);
3、定義一個KeyModifiers的枚舉,以便出現組合鍵。
1
2
3
4
5
6
7
8
public enum KeyModifiers
{
 None = 0,
 Alt = 1,
 Control = 2,
 Shift = 4,
 Windows = 8
}
4、在類的構造函數出註冊系統熱鍵。
示例,下例註冊了四個熱鍵:
1
2
3
4
5
6
7
8
9
10
11
public MainForm()
{
 InitializeComponent();

 RegisterHotKey(Handle, 100, 2, Keys.Left); // 熱鍵一:Control +光標左箭頭
 RegisterHotKey(Handle, 200, 2, Keys.Right); //熱鍵一:Control +光標右箭頭
 RegisterHotKey(Handle, 300, 2, Keys.Up); // 熱鍵一:Control +光標上箭頭
 RegisterHotKey(Handle, 400, 2, Keys.Down); // 熱鍵一:Control +光標下箭頭

 ....;
}
5、重寫WndProc()方法,通過監視系統消息,來調用過程。
示例:
1
2
3
4
5
6
7
8
9
10
11
protected override void WndProc(ref Message m)//監視Windows消息
{
 const int WM_HOTKEY = 0x0312; //如果m.Msg的值為0x0312那麼表示用戶按下了熱鍵
 switch (m.Msg)
 {
  case WM_HOTKEY:
  ProcessHotkey(m); //按下熱鍵時調用ProcessHotkey()函數
  break;
 }
 base.WndProc(ref m); //將系統消息傳遞自父類的WndProc
}
6、不用說,我們接下來需要實現ProcessHotkey函數:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//按下設定的鍵時調用該函數
private void ProcessHotkey(Message m)
{
 IntPtr id = m.WParam; //IntPtr用於表示指針或句柄的平台特定類型
 //MessageBox.Show(id.ToString());
 string sid = id.ToString();
 switch (sid)
 {
  case "100": DecreseVolumnb(); break; // 按下Control +光標左箭頭,調用函數DecreseVolumnb();
  case "200": AddVolumnb(); break; // 按下Control +光標右箭頭,調用函數AddVolumnb()
  case "300":// 按下Control +光標上箭頭,顯示窗體
   this.Visible = true;
   break;
  case "400":// 按下Control +光標下箭頭,隱藏窗體
   this.Visible = false;
   break;
 }
}
很明顯接下來分別實現函數DecreseVolumnb(); 和AddVolumnb(); 即可.
7、最後別忘了在程序退出時取消熱鍵的註冊
1
2
3
4
5
6
7
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
 UnregisterHotKey(Handle, 100); //卸載第1個快捷鍵
 UnregisterHotKey(Handle, 200); //缷載第2個快捷鍵
 UnregisterHotKey(Handle, 300); //卸載第3個快捷鍵
 UnregisterHotKey(Handle, 400); //缷載第4個快捷鍵
}
以上就是在C#程序中使用系統熱鍵的詳細過程,希望對你瞭解C# WinForm程序使用熱鍵有所幫助。


[轉貼][C#] 偵側桌面上程式視窗名稱 (仿 Spy++ )

2013年7月24日 星期三



轉貼自http://www.dotblogs.com.tw/optimist9266/archive/2011/06/08/27315.aspx



以下會利用SetWindowsHookEx原生方法來達到接收全域鍵盤事件的效果。
原生方法的宣告請參考[常用Windows原生方法整理(Windows API)]。
原生方法用到的常數請參考[Windows 原生指令常數 (Windows API Constansts)]。
原生方法用到的結構請參考[常用Windows原生結構]。
使用這個類別時必須注意,在這個類別引發的所有事件中查詢引發事件的按鍵狀態,將會收到與預期不同的結果。
因為範例程式碼中使用的是低階WinHook,因此當Windows都還沒收到訊號時就會執行事件委派,如果在這些委派中透過API查詢按鍵狀態,將不會是最新的按鍵狀態,因為Windows還沒有為其更新狀態。



public static class KeyboardHook
{
    /// 
    /// 取得或設定是否獨佔所有鍵盤事件。
    /// 
    public static bool Monopolize { get; set; }

    /// 
    /// 不論是否擁有焦點,當鍵盤按下時引發此事件。
    /// 
    public static event EventHandler GlobalKeyDown;
    /// 
    /// 不論是否擁有焦點,當鍵盤放開時引發此事件。
    /// 
    public static event EventHandler GlobalKeyUp;
    /// 
    /// 取得或設定是否開始接收全域鍵盤事件。
    /// 
    public static bool Enabled
    {
        get { return m_Enabled; }
        set
        {
            if (m_Enabled != value)
            {
                m_Enabled = value;
                if (value)
                    Install();
                else
                    Uninstall();
            }
        }
    }
    private static bool m_Enabled = false;

    private static int m_HookHandle = 0;
    private static NativeStructs.HookProc m_HookProc;

    /// 
    /// 向Windows註冊Hook。
    /// 
    private static void Install()
    {
        if (m_HookHandle == 0)
        {
            Process curProcess = Process.GetCurrentProcess();
            ProcessModule curModule = curProcess.MainModule;

            m_HookProc = new NativeStructs.HookProc(HookProc);
            m_HookHandle = NativeMethods.SetWindowsHookEx(NativeContansts.WH_KEYBOARD_LL, m_HookProc, NativeMethods.GetModuleHandle(curModule.ModuleName), 0);

            curModule.Dispose();
            curProcess.Dispose();

            if (m_HookHandle == 0)
                throw new Exception("Install Hook Faild.");
        }
    }
    private static void Uninstall()
    {
        if (m_HookHandle != 0)
        {
            bool ret = NativeMethods.UnhookWindowsHookEx(m_HookHandle);

            if (ret)
                m_HookHandle = 0;
            else
                throw new Exception("Uninstall Hook Faild.");
        }
    }

    /// 
    /// 註冊Windows Hook時用到的委派方法,當全域事件發生時會執行這個方法,並提供全域事件資料。
    /// 
    private static int HookProc(int nCode, IntPtr wParam, IntPtr lParam)
    {
        KeyEventArgs e = null;
        int wParam_Int32 = wParam.ToInt32();
        if (nCode >= 0)
        {
            NativeStructs.KEYBOARDLLHookStruct keyboardHookStruct = (NativeStructs.KEYBOARDLLHookStruct)Marshal.PtrToStructure(lParam, typeof(NativeStructs.KEYBOARDLLHookStruct));
            if (GlobalKeyDown != null && (wParam_Int32 == NativeContansts.WM_KEYDOWN || wParam_Int32 == NativeContansts.WM_SYSKEYDOWN))
            {
                e = new KeyEventArgs(keyboardHookStruct.VirtualKeyCode);
                GlobalKeyDown.Invoke(null, e);
            }
            else if (GlobalKeyUp != null && (wParam_Int32 == NativeContansts.WM_KEYUP || wParam_Int32 == NativeContansts.WM_SYSKEYUP))
            {
                e = new KeyEventArgs(keyboardHookStruct.VirtualKeyCode);
                GlobalKeyUp.Invoke(null, e);
            }
        }

        if (Monopolize || (e != null && e.Handled))
            return -1;
        return NativeMethods.CallNextHookEx(m_HookHandle, nCode, wParam, lParam);
    }

    /// 
    /// 提供 GlobalKeyDown 或 GlobalKeyUp 事件的資料。
    /// 
    public class KeyEventArgs : EventArgs
    {
        /// 
        /// 取得或設定值,指出是否處理事件。
        /// 
        public bool Handled { get; set; }
        /// 
        /// 取得值,虛擬鍵盤碼的System.Windows.Forms.Keys表示。
        /// 
        public System.Windows.Forms.Keys Keys { get { return (System.Windows.Forms.Keys)VirtualKeyCode; } }
        /// 
        /// 取得值,虛擬鍵盤碼的System.Windows.Input.Key表示。
        /// 
        public System.Windows.Input.Key Key { get { return System.Windows.Input.KeyInterop.KeyFromVirtualKey(VirtualKeyCode); } }
        /// 
        /// 取得值,指出是否按下 ALT 鍵。
        /// 
        public bool Alt
        {
            get
            {
                return KeyIsDown((int)System.Windows.Forms.Keys.LMenu) || KeyIsDown((int)System.Windows.Forms.Keys.RMenu);
            }
        }
        /// 
        /// 取得值,指出是否按下 CTRL 鍵。
        /// 
        public bool Control
        {
            get
            {
                return KeyIsDown((int)System.Windows.Forms.Keys.LControlKey) || KeyIsDown((int)System.Windows.Forms.Keys.RControlKey);
            }
        }
        /// 
        /// 取得值,指出是否按下 SHIFT 鍵。
        /// 
        public bool Shift
        {
            get
            {
                return KeyIsDown((int)System.Windows.Forms.Keys.LShiftKey) || KeyIsDown((int)System.Windows.Forms.Keys.RShiftKey);
            }
        }
        /// 
        /// 取得值,引發事件的虛擬鍵盤碼。
        /// 
        public int VirtualKeyCode { get; private set; }
        internal KeyEventArgs(int virtualKey)
        {
            this.Handled = false;
            this.VirtualKeyCode = virtualKey;
        }

        private static bool KeyIsDown(int KeyCode)
        {
            if ((NativeMethods.GetKeyState(KeyCode) & 0x80) == 0x80)
                return true;
            else
                return false;
        }
    }
}