1:怎样更换wallpaper.
SystemParametersInfo(SPI_SETDESKWALLPAPER,0,"C:\\Windows\\Desktop.bmp",
WM_WININICHANGE);
2:写打印机Preview需要用什么函数?
1. onPreparePringing: 设置最大最小页码
2. OnBeginPrinting: 建 GDI objects
3. OnPrepareDC: 设置mapping模式.
4. OnPrint: 调用OnDraw
5. OnEndPrinting: 擦掉GDI objects
3:用MFC写了一个控件,如何在另一个县城里发事件?
可能有人想当然地认为只要
//县城函数
void AFX_CDECL MyWorkerThread(LPVOID pParam)
{
MYAPPCTL* pCTL = (MYAPPCTL*)pParam;
//...
pCTL->Fire??? //发事件
//..
}
//控件的某方法,
void CMYAPPCTL::InitThread()
{
//pass a "this" pointer to the thread!
AfxBeginThread(MyWorkThread, this);
...
}
如此这般就可在另一个县城里发事件了,其实这是完全错误的,这样根本就发不出事件.
下面俺来详细说说这问题.
先简要地回顾一下几个COM基本概念
1.所有COM相关的操作都必须在Apartment中发生.
2.Apartment分为STA(SingleThreadedApartment),MTA(MultiThreadedApartment),RTA(NT5才有)
3.县城中调用 hr = CoInitialize (NULL);后,该县城成为一个STA.
县城结束前必须相应的CoUninitialize( );
4.控件是一种STA的DLL型COM对象.
5.在一个Apartment里生成|得到的COM Interface(IStream除外),若要在另一个Apartment里使用的话,必须marshal.
6.所谓marshal是指:
把一个Interface的相关信息写入一个IStream中,
然后把该IStream传至另一个Apartment,
在该Apartment里从IStream再解出被marshal的那个Interface,使用之.
至此,我们已经可以明白上述的做法犯了两个根本性的错误:
既没有创建Apartment又没有marshal.
这第1个错误是很好解决的,加两句话就行.
第2个就复杂了,marshal谁?MFC的COleControl不是COM Interface,
是无法把一个COleControl的实例 marshal到另一个Apartment里去的.
于是不得不提到事件的本质.
"事件"是基于ConnectPoint的.
ConnectPoint?MD,又是一个新名词!?
嘿嘿,ConnectPoint可以理解为一组CALLBACK的规范.
COM中,CALLBACK也是通过Interface实现的,即Client提供一个Interface让Server来调用.
控件保存着容器通过ConnectPoint提供给他的"CALLBACK Interface",
所谓"发事件"就是调用那些"CALLBACK Interface".
现在事情就明朗化了,MFC的COleControl内部必然有相关的保存并处理"CALLBACK Interface"的部分,
只要把那些"CALLBACK Interface"找出来,marshal到另一个Apartment里去就行了.
具体的代码大家可以去察看1997年2月的MSJ存档,里面"ThreadDB"就是一个例子.
4:关于DIADOG背景图象
在CODEGURU看到一个MDI CLIENT以位图为背景的例子,
受到启发,在DIALOG中相似地模仿了以下,效果很好。
主要要点是处理背景擦除消息时在DIALOG CLIENT区域画
位图,代码如下:
BOOL CBmpbgDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(&rect);
BITMAP bm;
CDC dcMem;
m_pBmp->GetObject(sizeof(BITMAP),(LPVOID)&bm);
dcMem.CreateCompatibleDC(NULL);
CBitmap* pOldBitmap = dcMem.SelectObject(m_pBmp);
for (register int nX=0;nXBitBlt(nX,nY,bm.bmWidth,bm.bmHeight,&dcMem,0,0,SRCCOPY);
dcMem.SelectObject(pOldBitmap);
return TRUE;
}
5:如何显示随光标移动的提示窗口
一: 由CFrameWnd派生的窗口
CFrameWnd 本身已经实现了Enable ToolTips 功能,所以
只要各控件能附ToolTip就能显示。
二:非CFrameWnd类派生的窗口(如Dialog)
则首先要打开ToolTip开关(EnableToolTips()),这样当
鼠标移到控件上会产生TTN——NEEDTEXT消息,然后你处理
该消息即可。
过程如下:
1. 在OnInitDialog中加入代码:
EnableToolTips();
2. 在类定义中加入如下函数定义:
afx_msg BOOL ShowTips(UINT id,NMHDR* PNMHDR,
LRESULT* pResult);
3. 在消息映射宏中加入:
ON_NOTIFY_EX(TTN_NEEDTEXT,0,ShowTips)
4. 实现ShowTips函数:
BOOL CXXXDlg::ShowTips(UINT id,NMHDR* PNMHDR,
LRESULT* pResult)
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
UINT nID = pNMHDR->idFrom;
if (pTTT->uFlags & TTF_IDISHWND)
{
// idFrom is actually the HEND of the tool
nID = ::GetDlgCtrlID((HWND)nID);
if (nID)
{
pTTT->lpszText = MAKEINTRESOURCE(nID);
pTTT->hinst = AfxGetResourceHandle();
return(TRUE);
}
}
return(FALSE);
}
5 在String Table中为各Control加入对应的字串即可。