問題的引入:
我希望在程式中有一個日誌輸出的視窗。最簡單的就是在FORM上放一個LISTVIEW。然後程式各地調用日誌輸出的時候,在這個LISTVIEW中可以將日誌寫上去。
就像
LogForm1->WriteLog("系統訊息...");
但是...由於感覺Form比較重,因為輸出日誌的地方很多(可能漫山遍野都輸出日誌),而且還不是一個工程裡,而且還不一定是Form程式。如果要求寫日誌就要別人include個LogForm1.h什麼的也太過分了吧。
就像我有三個工程:
MainUI :介面展示
DataProc :資料和業務的處理
msql :mysql封裝
其構建關係和依賴關係是mysql獨立,DataProc依賴於mysql, MainUI依賴於DataProc。
出於潔癖的考慮,DataProc沒有介面。MainUI中可以放一個輸出日誌的Form。
顯然DataProc再扭過頭來use MainUI實在是強人所難。
so,DataProc發送一個WindowsMessage給介面,通過SendMessage讓介面展示就好了。
這裡邊涉及System::String轉換,new一個buffer,然後由接收端收到後展示完free。
CmdbLog::CmdbLog(void *pHwnd,UINT wm_id){m_MainHwnd = (HWND)pHwnd;m_MessageID = wm_id;}void CmdbLog::WriteLog(System::String ^ pString,...array<System::Object ^>^pOArray){pin_ptr<const wchar_t> wch = PtrToStringChars(pString);char*pc;int ipc;System::String ^ o;o = System::String::Format(pString,pOArray);ipc = wcslen(wch) + 1;ipc *= sizeof(wchar_t);pc= new char[ipc];memcpy(pc,wch,ipc);::SendMessage(m_MainHwnd,m_MessageID,0,(LPARAM)pc);}
主Form(LogForm中響應這個訊息)
const UINT wm_LogMessageID = ::RegisterWindowMessageA( "LOGEVENT" );
[SecurityPermission(SecurityAction::Demand, Flags=SecurityPermissionFlag::UnmanagedCode)] virtual void WndProc( Message% m ) override //重載視窗過程處理訊息 { if( m.Msg == wm_LogMessageID) {System::String^ m_sShowMessageString;m_sShowMessageString = gcnew System::String((const wchar_t*)(void*)m.LParam); MessageBox::Show(m_sShowMessageString); //接收自訂訊息 並處理AddLogRow(m_sShowMessageString);delete [] (char*)(void*)m.LParam;// 釋放這個buffer } Form::WndProc( m ); }
m_vars->InitCmdbLog((void*)this->Handle,wm_LogMessageID);
void Form1::AddLogRow(System::String^ pString)
{array<System::String^> ^ pItem = pString->Split(',',':');array<System::String^> ^ps = gcnew array<System::String^>(2);System::Windows::Forms::ListViewItem^pListViewItem;if (pItem->Length > 1){ps[0] = pItem[0];ps[1] = pString->Substring(pItem[0]->Length + 1,pString->Length - pItem[0]->Length -1);}else{ps[0] = "預設";ps[1] = pString;}pListViewItem = gcnew System::Windows::Forms::ListViewItem(ps,-1);listView1->BeginUpdate();listView1->Items->Add(pListViewItem);listView1->EndUpdate();}