動態改變MessageBox的按鈕文本的語言

通過設置CultureUIInfo無法改變MessageBox的按鈕的文本語言,因爲這個文本是根據你所安裝的操作系統的語言決定的:你裝的英文操作系統,
那麼就是"Yes""No";你裝的中文操作系統,那麼就是“是”“否”。
所以對於可以改變語言版本的應用程序,就會遇到英文版應用程序下的MessageBox的按鈕顯示“是”“否”(中文操作系統);中文版應用程序下的
MessageBox的按鈕顯示"Yes""No"。傻呼呼。
想達到目的,還是可以的,只是比較麻煩,要不擇手段。要使用win-API函數,以及Hook技術
下面是我參照着C++代碼寫的C#代碼
一、首先聲明Hook的類型
   public enum HookType
        {
            Keyboard = 2,//鍵盤操作
            CBT = 5,//窗口操作
            Mouse = 7, //鼠標操作
        };
二、聲明API函數
        [DllImport("kernel32.dll")]
        static extern int GetCurrentThreadId();//得到當前的線程ID
        [DllImport("user32.dll")]
        static extern int GetDlgItem(IntPtr hDlg, int nIDDlgItem);//得到Dialog窗口的子項
        [DllImport("user32", EntryPoint = "SetDlgItemText")]
        static extern int SetDlgItemTextA(IntPtr hDlg, int nIDDlgItem, string lpString);//設置Dialog窗口子項的文本
        [DllImport("user32.dll")]
        static extern void UnhookWindowsHookEx(IntPtr handle);//解掉掛鉤
        [DllImport("user32.dll")]
        static extern IntPtr SetWindowsHookEx(int idHook, [MarshalAs(UnmanagedType.FunctionPtr)] HookProc lpfn, IntPtr
hInstance, int threadID);//設置掛鉤
        [DllImport("user32.dll")]
        static extern IntPtr CallNextHookEx(IntPtr handle, int code, IntPtr wparam, IntPtr lparam);//進行下一個掛鉤,如果有的話
三、定義局部變量
        static IntPtr _nextHookPtr;
        static HookProc myProc = new HookProc(MyHookProc);//must be global, or it will be Collected by GC, then no callback
func can be used for the Hook
 delegate IntPtr HookProc(int code, IntPtr wparam, IntPtr lparam);
四、自定義HookProck邏輯,這是最關鍵的部分,如何劫持人質,如何勒索人質,如何釋放人質
   static IntPtr MyHookProc(int code, IntPtr wparam, IntPtr lparam)
          {
            IntPtr hChildWnd;// msgbox is "child"
            // notification that a window is about to be activated
            // window handle is wParam
            if (code == 5)//HCBT_ACTIVATE = 5
            {
                // set window handles of messagebox
                hChildWnd = wparam;
                //to get the text of yes button
                int result;
                if (GetDlgItem(hChildWnd, 6) != 0)//IDYES = 6
                {
                    result = SetDlgItemTextA(hChildWnd, 6, Properties.Resources.YES);//在Project.Resources裏自定義文本
                }
                if (GetDlgItem(hChildWnd, 7) != 0)//IDNO = 7
                {
                    result = SetDlgItemTextA(hChildWnd, 7, Properties.Resources.NO);
                }
            }
            else
            {
                CallNextHookEx(_nextHookPtr, code, wparam, lparam);// otherwise, continue with any possible chained hooks
            }
            //return (IntPtr)1; //直接返回了,該消息就處理結束了
            return IntPtr.Zero;//返回,讓後面的程序處理該消息
        }
五、提供給外部調用的Hook方法,如在Form_Load時SetHook,Form_Closing時UnHook.
  public static void SetHook()
        {
            if (_nextHookPtr != IntPtr.Zero)//Hooked already
            {
                return;
            }
            _nextHookPtr = SetWindowsHookEx((int)HookType.CBT, myProc, IntPtr.Zero, GetCurrentThreadId());

        }
        public static void UnHook()
        {
            if (_nextHookPtr != IntPtr.Zero)
            {
                UnhookWindowsHookEx(_nextHookPtr);
                _nextHookPtr = IntPtr.Zero;
            }
        }
上面的代碼可以放在一個獨立文件如APIHelper.cs,供User使用。
目的達到了,看代碼就知道,這樣不僅可以讓button的文本可以根據語言改變,文本的內容也可以自定義。
事實證明搶劫的收穫是誘人的,但是風險成本也是很高的,
1.對於掛鉤Hook技術,我們還不是很熟悉,比如什麼死後SetHook(),什麼時候UnHook()就是值得考慮的一個問題,你也可以在程序啓動就
SetHook,也可以在進行某項操作後就SetHook,但是一定不要忘了UnHook,否則你的Hook會造成你意想不到的範圍的影響。
2.回調函數要判斷消息號,所有的Form在Activate的時候都是code = 5,但是我們只有在彈出MessageBox的時候設置Button的文本。所以如果我
們在啓動程序的時候就SetHook(),必然會讓每次消息處理多走了幾段代碼,雖然肉眼無法識別這些差別,但是的確不必要。
如果SetHook和UnHook的成本不高,我們可以考慮在MessageBox.Show()的地方進行掛鉤和解鉤。假如這樣,那麼如果你的程序裏面散佈着
MessageBox.show(),你就哭吧;TMS真是英明,把MessageBox.Show()的功能都抽取到了一個全局靜態類裏面,我只要改這個全局方法就可以了。
可見抽取共用邏輯還是很重要的!
結論:就讓我們的程序傻傻的,傻傻要比傻B強得多。
      至少我們知道了,這個問題有解決方案。
原文:http://whatsthematrix.spaces.live.com/blog/cns!52A6BFE11C08D828!158.entry
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章