線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:8017
推到 Plurk!
推到 Facebook!

送中文到另一視窗 + Shell_NotifyIcon + 防止重複執行(兼詢問問題)

 
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-02-02 20:27:26 IP:140.113.xxx.xxx 未訂閱
各位程式同好大家好,這支小程式前不久我也有發表過, 只是現在更改了不少地方,也從站上學到不少東西。 相信有很多初學者,一開始也會跟我一樣,需要到處找資料, 所以小弟就把這次修改的心得,貼出來讓各位參考,順便也請教大家一些問題。    我這程式有什麼用? 最主要的功能就是儲存一些自己時常用到的字串,方便送出到另一軟體。 (雖然有使用者跟我回報,這程式對他們在工作上有很大幫助,我也不知是怎麼用的 :) ) 我想分享什麼? 1. 把包含有非英文的字串送到另一個視窗. 2. 用 Shell_NotifyIcon 寫一個 TrayIcon. 3. 防止程式重複執行. 哪裡可下載我的程式? 執行檔及原始碼已上傳,請點選上方的檔案連結即可. 檔案裡頭有個 dialog.hpp,是參考站上資料之後,改寫原本的 dialog.hpp 而來, 為的是解決 InputBox 無法正常顯示中文的問題。 請記得加入你的 Project. -- http://www.csie.nctu.edu.tw/~chtai/software.php 好用免費軟體的收集網頁,歡迎大家跟我分享或一同推廣免費軟體。 若您覺得這網頁不錯,也歡迎您將它傳出去 :)
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-02-02 20:44:35 IP:140.113.xxx.xxx 未訂閱
用 Shell_NotifyIcon 寫 TrayIcon 因為 BCB 本身的 TrayIcon 元件聽說有不少 bug, 小弟自己在使用,也是有遇過一些問題, 所以就參考站上資料,用 Win32 API 自己打造一個 TrayIcon. 範例如下: 首先要建立起一個 TrayIcon 的結構.
 
NOTIFYICONDATA IconData; // TrayIcon, 全域變數    void __fastcall TformMain::CreateMyIcon(void)
{
    IconData.cbSize = sizeof(NOTIFYICONDATA);
    IconData.hWnd = Handle;  //要用Handle, 不能用 Application->Handle
    IconData.uID = 1;
    IconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    IconData.uCallbackMessage = WM_USER 101;
    IconData.hIcon = this->Icon->Handle;//代表使用跟執行檔相同的圖示
    strcpy(IconData.szTip, formMain->Caption.c_str() );
}
以上這個函式,你可以在 Form 被 Create 的時候呼叫。 那要怎麼新增/移除/改變 icon 呢? 用以下三個函式就行。
 
Shell_NotifyIcon(NIM_ADD, &IconData);
Shell_NotifyIcon(NIM_DELETE, &IconData);
Shell_NotifyIcon(NIM_MODIFY, &IconData);
別忘了去 .h 檔裡頭加入處理 message 的函式
 
public:                // User declarations
    void __fastcall CreateMyIcon(void);
    void __fastcall MyIconMsg(TMessage &Msg);
    BEGIN_MESSAGE_MAP
        VCL_MESSAGE_HANDLER(WM_USER 101, TMessage, MyIconMsg);
    END_MESSAGE_MAP(TForm)
MyIconMsg() 就是處理 message 的函式啦, 別忘了在 .cpp 檔裡頭加入你要做的事。 在此我以按滑鼠左鍵秀出視窗,按右鍵秀出選單為例。
 
void __fastcall TformMain::MyIconMsg(TMessage &Msg)
{
    switch(Msg.LParam)
    {
        case WM_LBUTTONUP:  // 按一次左鍵, 還原視窗
            Application->Restore();
            break;
        case WM_RBUTTONUP:  // 按一次右鍵, 跳出右鍵選單
            POINT p;
            ::GetCursorPos(&p);
            PopupMenu1->Popup(p.x, p.y); // 你得自己拉一個 PopupMenu 元件到 Form 裡頭.
            break;
    }
    // 還有其他的LParam可使用,請自行看help
}
以上,就是個簡單,而且還算完整的範例了 --
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-02-02 20:53:30 IP:140.113.xxx.xxx 未訂閱
再來分享要如何防止程式重複執行,這也是在站上找到的,剛好符合我的需求,只是我一時找不到出處了,真是抱歉 < class="code"> HANDLE Mutex; // 這是全域變數 void __fastcall TformMain::FormCreate(TObject *Sender) { Application->Title = formMain->Caption; HANDLE PrevInstHandle; Mutex = OpenMutex(SYNCHRONIZE, false, Application->Title.c_str()); if (Mutex != NULL) { String AppTitle = Application->Title; Application->ShowMainForm = false; SetWindowText(Application->Handle, NULL); PrevInstHandle = FindWindow("TApplication", AppTitle.c_str()); if (IsIconic(PrevInstHandle)) ShowWindow(PrevInstHandle, SW_RESTORE); else { BringWindowToTop(PrevInstHandle); SetForegroundWindow(PrevInstHandle); } Application->Terminate(); } else Mutex = CreateMutex(NULL, false, Application->Title.c_str()); } void __fastcall TformMain::FormClose(TObject *Sender, TCloseAction &Action) { ReleaseMutex(Mutex); //別忘了在程式結束時要 release } 這樣就可以啦 ^^ 當然方法不只一種,若是這種對你不合用,站上再搜尋一下又是一堆 --
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-02-02 21:06:41 IP:140.113.xxx.xxx 未訂閱
最後來講講要怎麼傳送中文字串到別的視窗 說真的,傳送字串給自己程式產生出來的視窗,一點都不難。 可是傳給別的程式的視窗,真的是很令人頭大的一件事。 以下範例感謝 pwipwi大哥 以及 ConvertZ作者 提供 首先你要拉一個 class="code"> void __fastcall TformMain::ApplicationEvents1Idle(TObject *Sender, bool &Done) { HWND ForeWindow = ::GetForegroundWindow(); if(ForeWindow != Handle) { LastEditHandle = ForeWindow; char str[255]; SendMessage(LastEditHandle, WM_GETTEXT, 255, (long)str); ListBox1->Hint = AnsiString("傳送到 - ") str; } } void __fastcall TformMain::ListBox1DblClick(TObject *Sender) { HWND hFocusWin; if(!IsWindow(LastEditHandle)) return; if( IsZoomed(LastEditHandle) ) ShowWindow(LastEditHandle, SW_SHOWMAXIMIZED); // 若是最大化, 就最大化顯示 else ShowWindow(LastEditHandle, SW_SHOWNORMAL); // 不然就直接顯示 SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_SENDCHANGE); BringWindowToTop(LastEditHandle); // SetForegroundWindow(LastEditHandle); if( AttachThreadInput(GetCurrentThreadId(), GetWindowThreadProcessId(LastEditHandle, NULL), true) ) { BringWindowToTop(LastEditHandle); // SetForegroundWindow(LastEditHandle); Application->ProcessMessages(); hFocusWin = GetFocus(); AttachThreadInput(GetCurrentThreadId(), GetWindowThreadProcessId(LastEditHandle, NULL), false); if( hFocusWin != NULL ) { int i; Byte ch; AnsiString str = ListBox1->Items->Strings[ListBox1->ItemIndex]; for( i = 1; i <= str.Length(); i ) // 注意: 是從 1 開始, 不是從 0 開始 { ch = Byte(str[i]); if( IsDBCSLeadByte(ch) ) // 若是雙位元的字, 就和下一個byte合成一個字 PostMessage(hFocusWin, WM_IME_CHAR, MAKEWORD(Byte(str[ i]), ch), 0); else // 不然就直接送出 PostMessage(hFocusWin, WM_IME_CHAR, WORD(ch), 0); } } else ShowMessage("GetFocus() failed!"); } else ShowMessage("AttachThreadInput() failed!!"); } 以上就是送出的方式了,我用的是逐一檢查的方式,若是 DBCS 的 Leading Byte,就跟下個 byte 合成一個 word 再送出。 另外根據我自己的實驗結果,用 BringWindotToTop 比 SetForegroundWindow 好,字串都能成功送達並顯示出來。 -- http://www.csie.nctu.edu.tw/~chtai/software.php 好用免費軟體的收集網頁,歡迎大家跟我分享或一同推廣免費軟體。 若您覺得這網頁不錯,也歡迎您將它傳出去 :)
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-02-02 21:24:57 IP:140.113.xxx.xxx 未訂閱
呼~~一連貼了四篇,希望大家不會覺得我是在灌水阿 < >,因為我覺得這樣看起來比較有條理嘛 < > 最後就是要來問問題啦,還請大家能幫我想想,幫我看看,到底是哪裡出了問題。這困擾了我好久,而我一直沒有找到合適的解法。 問題一: 這個範例對 Maxthon 無效,送出的字串無法顯示出來。(Maxthon 是一款瀏覽器,前身是 MyIE2) 解法很簡單,只要把第三個範例裡頭的程式碼略改如下即可
 
        BringWindowToTop(LastEditHandle);
//        SetForegroundWindow(LastEditHandle);
        if(ListBox1->Hint.Pos("Maxthon"))
            ::SetFocus(LastEditHandle);
        Application->ProcessMessages();
        hFocusWin = GetFocus();
沒錯,只要加上 ::SetFocus() 即可解決,但是若是加了這句, 反而別的軟體會無法顯示出字串了,所以要判斷是 Maxthon 才 SetFocus(). 為什麼會這樣呢???? 或者,有沒有什麼更好取得 handle 的做法呢? 問題二: 就我的使用經驗,我的程式對 MSN 跟 Skype 送出字串之後會變成亂碼。 MSN 還好,只有某些字元像是︶︿之類的上下括號會變成(?)問號. Skype 就敗了,全部都是亂碼 < >< > 可是若是把這些字串用複製貼上的,或是手動用鍵盤輸入, 又是完全能顯示出來。 為什麼會這樣呢 < >< > 問題三: 不是每個人的電腦都會這樣,但就是有些人無法使用這程式, 不管送到哪個軟體的視窗,都會有亂碼的產生。 似乎沒有特定在哪個作業系統才會有這問題。 像我用 XP 就一切ok,我同學也是 XP 卻總是亂碼。 為什麼 Q___Q 所有的程式碼以及字串檔都上傳了,小弟真的找不到問題到底是怎樣產生的, 希望站上的各位前輩們,能幫我想想, 你們的經驗比較多,或許可以看到我沒看到的地方 --
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-02-23 22:49:26 IP:211.74.xxx.xxx 未訂閱
有時候若是在 TrayIcon 加上了 PopupMenu, 但是你沒有去點選 PopupMenu 的任一個項目時, 這時,PopupMenu 就會一直留在那邊,直到你點了一個項目之後才會消失。    這似乎與我們預期的使用方式不太一樣。 底下的 code 可以解決這個問題。 你只要在 PopupMenu 的 OnPopup 裡頭加上這行即可。
 
    SetForegroundWindow(this->Handle);
-- http://www.csie.nctu.edu.tw/~chtai/software.php 好用免費軟體的收集網頁,歡迎大家跟我分享或一同推廣免費軟體。 若您覺得這網頁不錯,也歡迎您將它傳出去 :)
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
chtai
高階會員


發表:68
回覆:238
積分:116
註冊:2004-05-21

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-07-30 13:37:15 IP:211.72.xxx.xxx 未訂閱
前文提到,有時會有亂碼產生,有時會有在 XP 無法使用的情形產生。 後來我使用的方法是,若是 NT 系列就送出 Unicode, 若是 9x/ME 系列就送出 ANSI。 如此一來似乎解決問題了。 作法如下 :
        OSVERSIONINFO os_info;
        os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
        GetVersionEx(&os_info);
        LPINPUT myInput = new INPUT;
        myInput->type = INPUT_KEYBOARD;
        myInput->ki.wVk = 0;
        myInput->ki.time = 0;
        myInput->ki.dwExtraInfo = GetMessageExtraInfo();
        if (os_info.dwPlatformId == VER_PLATFORM_WIN32_NT) // 若是 NT 系列就 Unicode 逐字輸出
        {
                WideString str = WideString(ListBox1->Items->Strings[ListBox1->ItemIndex]);
                for (int i = 1; i <= str.Length();   i)
                {
                        myInput->ki.wScan = str[i];
                        myInput->ki.dwFlags = KEYEVENTF_UNICODE;
                        SendInput( 1, myInput , sizeof(INPUT) );
                        myInput->ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
                        SendInput( 1, myInput , sizeof(INPUT) );
                }
        }
        else    // 若是 9X 系列就 Ansi 逐字輸出
        {
                AnsiString str = ListBox1->Items->Strings[ListBox1->ItemIndex];
                for (int i = 1; i <= str.Length();   i)
                {
                        myInput->ki.wScan = str[i];
                        myInput->ki.dwFlags = KEYEVENTF_SCANCODE;
                        SendInput( 1, myInput , sizeof(INPUT) );
                        myInput->ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
                        SendInput( 1, myInput , sizeof(INPUT) );
                }
        }
以上,給大家參考看看 :) -- http://www.csie.nctu.edu.tw/~chtai/software.php 好用免費軟體的收集網頁
------
My Web: http://nelson.csie.us
My Blog: http://blog.nelson.csie.us
ADSL5
一般會員


發表:1
回覆:3
積分:0
註冊:2006-07-10

發送簡訊給我
#8 引用回覆 回覆 發表時間:2007-01-19 10:49:50 IP:140.134.xxx.xxx 訂閱
您好!
看過你發佈的"64701_常用字串輸入工具.zip"
,於我的電腦執行時,發生個error。
[Linker Fatal Error] Fatal: Unable to open file 'DIALOGS.OBJ'
請問該如何解決呢?謝謝
系統時間:2024-03-29 14:17:25
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!