送中文到另一視窗 + Shell_NotifyIcon + 防止重複執行(兼詢問問題) |
|
chtai
高階會員 發表:68 回覆:238 積分:116 註冊:2004-05-21 發送簡訊給我 |
各位程式同好大家好,這支小程式前不久我也有發表過,
只是現在更改了不少地方,也從站上學到不少東西。
相信有很多初學者,一開始也會跟我一樣,需要到處找資料,
所以小弟就把這次修改的心得,貼出來讓各位參考,順便也請教大家一些問題。 我這程式有什麼用?
最主要的功能就是儲存一些自己時常用到的字串,方便送出到另一軟體。
(雖然有使用者跟我回報,這程式對他們在工作上有很大幫助,我也不知是怎麼用的 :) ) 我想分享什麼?
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
附加檔案:64701_常用字串輸入工具.zip
|
chtai
高階會員 發表:68 回覆:238 積分:116 註冊:2004-05-21 發送簡訊給我 |
用 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 發送簡訊給我 |
再來分享要如何防止程式重複執行,這也是在站上找到的,剛好符合我的需求,只是我一時找不到出處了,真是抱歉
< 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 發送簡訊給我 |
最後來講講要怎麼傳送中文字串到別的視窗
說真的,傳送字串給自己程式產生出來的視窗,一點都不難。
可是傳給別的程式的視窗,真的是很令人頭大的一件事。 以下範例感謝 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 發送簡訊給我 |
呼~~一連貼了四篇,希望大家不會覺得我是在灌水阿 < >,因為我覺得這樣看起來比較有條理嘛 < > 最後就是要來問問題啦,還請大家能幫我想想,幫我看看,到底是哪裡出了問題。這困擾了我好久,而我一直沒有找到合適的解法。 問題一:
這個範例對 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 發送簡訊給我 |
有時候若是在 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 發送簡訊給我 |
前文提到,有時會有亂碼產生,有時會有在 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 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |