问题的引入:
我希望在程序中有一个日志输出的窗口。最简单的就是在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(); }