2009年5月10日 星期日

BCB 單一執行 與 訊息傳遞

//===============================================================
// 20090505 知識 +
// http://tw.knowledge.yahoo.com/question/question?qid=1509050500004
// 發問者 :(在糞坑裡乘涼的屎虫) http://tw.knowledge.yahoo.com/my/my?show=AD01457526
//===============================================================

【問題】
我要把訊息傳進我的程式,我想到的方法是我可以把它當參數,例如『我的程式.exe msg 』,我就把msg(訊息)送進我的程式,但問題是,假如『我的程式.exe』是一直執行中,我只能在第一次啟動時,將msg送進去,如果我要再送第二次、第三次....我只能執行很多次『我的程式.exe』,我可以只執行一次『我的程式.exe』,但可以餵很多次msg給他嗎(一樣用 『我的程式.exe msg』)?有沒較正確的方法?就是像網路程式一樣,我的程式可以一直聽........

【實作】

可使用 FindWindow 並配合用 SendMessage(WM_COPYDATA) 的方式來達成.
假設 Form 的 Class 名稱是 TForm1, 而要顯示於標頭的文字是 "RunMsg";則可以用 FindWindow( "TForm1", FormTitle ) 來尋找這個Form是否存在? 若已存在則將 命令參數打包, 透過SendMessage以WM_COPYDATA訊息傳遞.
因此, 在專案的 .cpp WinMain() 內要增加程式 :

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try

{
char FormTitle[] = "RunMsg"; // Form的標頭文字先在此聲明
HWND hWnd = FindWindow( "TForm1", FormTitle );
if (hWnd!=NULL)
{
if (ParamCount()>0)
{
COPYDATASTRUCT Data;
Data.dwData = 0;
Data.lpData = ParamStr(1).c_str();
Data.cbData = lstrlen((char *) Data.lpData)+1;
SendMessage( hWnd, WM_COPYDATA, NULL, (LPARAM) &Data);
}
return 0;
}
Application->Title = FormTitle; // 為方便設定Form的標頭, 先設定在Application
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
catch (...)
{
try
{
throw Exception("");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
}
return 0;
}


而在Form部分, 要增加程式碼來可以接受 WM_COPYDATA 的訊息.所以先在 Form 的.h 內 class public 段末端 添增

class TForm1 : public TForm
{
__published: // IDE-managed Components
TLabel *Label1;
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);

void __fastcall OnWmCopyData(TMessage& Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_COPYDATA, TMessage, OnWmCopyData);
END_MESSAGE_MAP(TForm);
};


最後, 在 Form 的.cpp 內 --

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
this->Caption = Application->Title;

if (ParamCount()>0)
Label1->Caption = ParamStr(1);
}
//-----------------------------------------------------------
void __fastcall TForm1::OnWmCopyData(TMessage& Message)
{
COPYDATASTRUCT * p = (COPYDATASTRUCT *) Message.LParam;

Label1->Caption = (char *)p->lpData;
}



若From的標頭夠奇特的不會跟其它Form一樣, 可簡化為用 FindWindow( NULL, FormTitle ), 甚至可也不用透過Application->Title; 只要能確定 所要找的 FormTitle 是與已啟動Form上的標頭文字一致即可.

沒有留言:

張貼留言