26)CImageList控件中图象橙色被显示为黄色? 我使用了一个CImageList控件来装入位图,用于TREE控件,其它的色彩都很正常就是橙色被显示成为黄色. 你只能使用系统指定的20种颜色(橙色不包括在内);当然,你也可以用下面的方法来装载位图资源而不受颜色数的限制. HBITMAP LoadResourceBitmap(HINSTANCE hInstance, LPSTR lpString, HPALETTE FAR* lphPalette){ HRSRC hRsrc; HGLOBAL hGlobal; HBITMAP hBitmapFinal = NULL; LPBITMAPINFOHEADER lpbi; HDC hdc; int iNumColors; if (hRsrc = ::FindResource(hInstance, lpString, RT_BITMAP)){ hGlobal = ::LoadResource(hInstance, hRsrc); lpbi = (LPBITMAPINFOHEADER)LockResource(hGlobal); hdc = ::GetDC(NULL); *lphPalette = CreateDIBPalette ((LPBITMAPINFO)lpbi, &iNumColors); if (*lphPalette) { ::SelectPalette(hdc,*lphPalette,FALSE); ::RealizePalette(hdc); } hBitmapFinal = ::CreateDIBitmap(hdc, (LPBITMAPINFOHEADER)lpbi, (LONG)CBM_INIT, (LPSTR)lpbi + lpbi->biSize + iNumColors * sizeof(RGBQUAD), (LPBITMAPINFO)lpbi, DIB_RGB_COLORS ); ::ReleaseDC(NULL,hdc);// ::UnlockResource(hGlobal);// ::FreeResource(hGlobal);} return (hBitmapFinal);} // internally used by LoadResourceBitmapHPALETTE CreateDIBPalette (LPBITMAPINFO lpbmi, LPINT lpiNumColors){LPBITMAPINFOHEADER lpbi;LPLOGPALETTE lpPal;HANDLE hLogPal;HPALETTE hPal = NULL;int i;lpbi = (LPBITMAPINFOHEADER)lpbmi;if (lpbi->biBitCount <= 8) *lpiNumColors = (1 << lpbi->biBitCount);else *lpiNumColors = 0; // No palette needed for 24 BPP DIBif (lpbi->biClrUsed > 0) *lpiNumColors = lpbi->biClrUsed; // Use biClrUsedif (*lpiNumColors){ hLogPal = GlobalAlloc (GHND, sizeof (LOGPALETTE) + sizeof (PALETTEENTRY) * (*lpiNumColors)); lpPal = (LPLOGPALETTE) GlobalLock (hLogPal); lpPal->palVersion = 0x300; lpPal->palNumEntries = *lpiNumColors; for (i = 0; i < *lpiNumColors; i++) { lpPal->palPalEntry.peRed = lpbmi->bmiColors.rgbRed; lpPal->palPalEntry.peGreen = lpbmi->bmiColors.rgbGreen; lpPal->palPalEntry.peBlue = lpbmi->bmiColors.rgbBlue; if (i<=10 || i>=246) lpPal->palPalEntry.peFlags = PC_NOCOLLAPSE; else lpPal->palPalEntry.peFlags = 0; } hPal = CreatePalette (lpPal); GlobalUnlock (hLogPal); GlobalFree (hLogPal);}return hPal;}该函数也重载了位图调色板,这个功能被CBitmap::LoadBitmap忽略了(它假定位图只使用20种颜色).因此要保证在DC中有SelectPalette和RealizePalette. (27)无法正确改变应用程序的图标? 我有一个基于对话框的应用程序,在初始化时我使用了AfxGetApp()->LoadIcon(IDI_BRIEFCASE)来载入自己的图标,当把程序拷贝到桌面上时,图标是我所期望的.但在资源管理器中的图标却还是MFC的图标. 资源管理器仅使用16x16的小图标,可能你在资源编辑器中只修改了32x32的标准图标.你需要重建16x16的小图标. (28)工具条状态的问题? 在应用程序中我创建了三个工具条,我想让它们在应用程序启动的时候排成一行正好在主菜单的下面,我该如何去做? 在VC CDs上有一个例子: int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){//other stuff here... EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar,AFX_IDW_DOCKBAR_TOP); DockControlBarLeftOf(&m_wndListToolBar,&m_wndToolBar); return 0;} void CMainFrame::DockControlBarLeftOf(CToolBar* Bar,CToolBar* LeftOf){ CRect rect; DWORD dw; UINT n; // get MFC to adjust the dimensions of all docked ToolBars // so that GetWindowRect will be accurate RecalcLayout(); LeftOf->GetWindowRect(&rect); rect.OffsetRect(1,0); dw=LeftOf->GetBarStyle(); n = 0; n = (dw & CBRS_ALIGN_TOP) ? AFX_IDW_DOCKBAR_TOP :n; n = (dw & CBRS_ALIGN_BOTTOM && n==0) ? AFX_IDW_DOCKBAR_BOTTOM :n; n = (dw & CBRS_ALIGN_LEFT && n==0) ? AFX_IDW_DOCKBAR_LEFT :n; n = (dw & CBRS_ALIGN_RIGHT && n==0) ? AFX_IDW_DOCKBAR_RIGHT :n; // When we take the default parameters on rect, DockControlBar will dock // each Toolbar on a seperate line. By calculating a rectangle, we in effect // are simulating a Toolbar being dragged to that location and docked. DockControlBar(Bar,n,&rect);} (29)在SDI应用程序中使用Active控件? 我刚了解到如何在MFC应用程序中使用Active控件,文档上说只能在视图为CFormView和CDialog时使用,但要是其它的情况该怎么办呢? 你可以在你应用程序的任何地方使用Active控件,而不仅仅局限于CFormView和CDialog为视图基类的情况.DevStudio通过资源编辑器和对话框模板来使得在上述两个条件下使用Active控件更容易.因此,你也可以在任何视图中使用Active控件,条件是你直接操纵该控件,创建它并手工的布置好它的位置(这也是DevStudio为你所做的事). (30)有RichEdit控件的对话框无法正常显示? 我在对话框中放置了一个RichEdit控件,但是对话框却无法正常显示. 在你的应用程序InitInstance()中调用了::AfxInitRichEdit()吗? (31)DLL中的模板成员函数? 在一个DLL中,我在自己创建的类中使用了模板成员函数来代替预处理宏.但出现以下错误: error C2664: 'double Data::extract(double &)' : cannot convert parameter 1 from 'class CArray' to 'double &'为什么在匹配模板定义时它要寻找一个DOUBLE参数? 我觉得你可能是在表达成员函数(内联)时出现了问题,请参照下面的示例: class AFX_EXT_CLASS Data : public CObject //This is not a template { public: Data(); Data(BYTE * buffer,int size); template Data(const CArray& array); template CArray& extract(CArray& array) { CArchive ar(&buffer, CArchive::store); ar >> array; }; double extract(double&); (...) private: CMemFile buffer; } (32)CFormView中的上下文帮助? 我想在基于CFormView类的SDI应用程序中加入真正的上下文帮助,但没有成功. 你应该重载CMyFormView类的OnHelpHitTest函数: LRESULT CMyFormView::OnHelpHitTest(WPARAM, LPARAM lParam){ LRESULT lResult = (LRESULT)0x00; CWnd* pWndChild = ChildWindowFromPoint(CPoint(lParam),CWP_ALL|CWP_SKIPINVISIBLE); if (pWndChild && ::IsWindow(pWndChild->m_hWnd)) { lResult = ::GetWindowLong(pWndChild->m_hWnd, GWL_ID); if (lResult) lResult += HID_BASE_COMMAND; } if (lResult == (LRESULT)0x00) lResult = ::GetWindowLong(m_hWnd, GWL_ID) + HID_BASE_RESOURCE; return lResult;}然后你就可以使用平时用的帮助文件了,但你要保证有正确的前缀,请参照TN028:Context-Sensitive Help Support.例如:ID_SOME_MENU_ITEM_OR_COMMAND_BUTTONIDR_SOME_WINDOW_OR_DIALOGIDP_PROMPTIDW_CONTROL_THAT_IS_NOT_A_COMAND_BUTTON你要确认你所使用的控件的ID包含在文件resource.hm中. (33)CArchive类的WriteObject函数问题? 谁知道在使用CArchive类的WriteObject函数时,如何避免将类名写入文件吗? WriteObject函数不仅写入了类名,而且还写入PID(请查看TN02),如果你只想写进一个文本文件,并且你也想用串行化,你可以使用文件指针(用GetFile)来存储字符串.或者,你可以使用CFILE类来处理这个问题,如果是文本文件,你也可以用CStdioFile类. (34)RegisterWindowMessage中的BroadcastSystemMessage如何处理? 我想用BroadcastSystemMessage来在两个进程之间通讯,我从一个进程发送了一个用RegisterWindowMessage注册过的消息,但在目的进程中却没有收到该消息. 我认为你应该在两个进程的最高级窗口中都注册该消息.请看下例: static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand")); BEGIN_MESSAGE_MAP( Gui_Top_Level_MainFrame, Gui_MainFrame ) ON_REGISTERED_MESSAGE( sBroadcastCommand, onBroadcastCommand )END_MESSAGE_MAP() LRESULT Gui_MainFrame :: onBroadcastCommand( UINT aMsg, LPARAM lParam ){ your code...}然后发送进行应该包含:While the sending process would contain: static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand")); void Someclass :: someMethod( void ) { ::PostMessage( (HWND)HWND_BROADCAST, sBroadcastCommand, 0, yourMessageId ); } (35)CListCtrl中选择变化时如何获得通知? 我在Report View中使用了一个CListCtrl(自绘制类型),我想知道什么时候选择项发生了改变. 在选择项变化时,可以使用按钮有效或失效,按如下操作: 加入LVN_ITEMCHANGED消息处理.void CYourClassNameHere::OnItemchangedEventList(NMHDR* pNMHDR, LRESULT* pResult){NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;*pResult = 0; if (pNMListView->uChanged == LVIF_STATE){ if (pNMListView->uNewState) GetDlgItem(IDC_DELETE)->EnableWindow(TRUE); else GetDlgItem(IDC_DELETE)->EnableWindow(FALSE);}} (36)如何向ATL-COM对象传送一个数组? 我想创建一个函数来向ATL-COM对象传送数组. 如下代码的方法用于ACTIVEX中,可能对ATL-COM也有启发吧. CoInitialize(NULL);CLSID m_clsid;USES_CONVERSION;::CLSIDFromString(T2OLE("ROUNDANALOG.RoundAnlgAARCtrl.1"), &m_clsid);IDispatch FAR* pObj = (IDispatch FAR*)NULL;CString str = "UpdateControl";BSTR bstr = str.AllocSysString();HRESULT hr = CoCreateInstance(m_clsid, NULL, CLSCTX_ALL, IID_IDispatch,(void**)&pObj); SafeArrayAccessData(psa, (void**)&bstrArray);bstrArray[0] = str.AllocSysString();bstrArray[1] = str.AllocSysString();SafeArrayUnaccessData(psa); VARIANTARG* pvars = new VARIANTARG[1];VariantInit(&pvars[0]);pvars[0].vt = VT_ARRAY|VT_BYREF|VT_BSTR;pvars[0].pparray = &psa;DISPID dispid; hr = pObj->GetIDsOfNames(IID_NULL, &bstr, 1,LOCALE_USER_DEFAULT, &dispid); DISPPARAMS disp = {pvars, &dispid, 1,1};hr = pObj->Invoke(dispid, IID_NULL,LOCALE_USER_DEFAULT,DISPATCH_PROPERTYPUT,&disp,NULL, NULL, NULL);delete[] pvars;pObj->Release();CoUninitialize(); 在你的控制中建立如下并变量参考: void CRoundAnlgAARCtrl::SaveFunc(const VARIANT FAR& var){// TOD Add your dispatch handler code hereASSERT(var.vt == VT_ARRAY | VT_BYREF | VT_BSTR);SAFEARRAY* psa = *var.pparray;} (37)如何选择CTreeCtrl中的节点文本进行编辑? 在向CTreeCtrl中加入一项后,有什么方法可以编辑该节点的文本呢? 首先设置你的CcompTreeCtrl具有TVS_EDITLABELS属性.在设计时用控件属性来设置在运行时用GetStyle()/SetStyle()成员函数来设置.然后请看下述代码: HTREEITEM CCompTreeCtrl::AddSet(){static int setCnt =3D 1;HTREEITEM hItem;CString csSet; //create text for new note: New Set 1, New Set 2 ...csSet.Format( _T( "New Set %d" ), setCnt++ ); hItem =3D InsertItem( csSet, IMG_CLOSEDFOLDER, IMG_CLOSEDFOLDER ); if( hItem !=3D NULL ) EditLabel( hItem ); return hItem;} (38)如何改变默认的光标形状? 我试着将光标改变为其它的形状和颜色,但却没有变化. 在对话框/窗口/你需要的地方加上对WM_SETCURSOR消息的处理. BOOL MyDialog::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message){ // TOD Add your message handler code here and/or call default ::SetCursor(AfxGetApp()->LoadCursor(IDC_MYCURSOR)); return TRUE; //return CDialog::OnSetCursor(pWnd, nHitTest, message);}你没有成功的原因是因为窗口类光标风格不能为NULL. (39)如何用键盘滚动分割的视口? 我的问题是当我用鼠标滚动分割窗口时,视口滚动都很正常,但用键盘时,却什么也没有发生. 在你的视图继承类中加入如下两个函数,假定该类为CScrollerView: void CScrollerView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags){ BOOL processed; for (unsigned int i=0;i< nRepCnt&&processed;i++) processed=KeyScroll(nChar); if (!processed) CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);} BOOL CScrollerView::KeyScroll(UINT nChar){ switch (nChar) { case VK_UP: OnVScroll(SB_LINEUP,0,NULL); break; case VK_DOWN: OnVScroll(SB_LINEDOWN,0,NULL); break; case VK_LEFT: OnHScroll(SB_LINELEFT,0,NULL); break; case VK_RIGHT: OnHScroll(SB_LINERIGHT,0,NULL); break; case VK_HOME: OnHScroll(SB_LEFT,0,NULL); break; case VK_END: OnHScroll(SB_RIGHT,0,NULL); break; case VK_PRIOR: OnVScroll(SB_PAGEUP,0,NULL); break; case VK_NEXT: OnVScroll(SB_PAGEDOWN,0,NULL); break; default: return FALSE; // not for us // and let the default class // process it. } return TRUE;} (40)如何在线程中处理状态条?在我的应用程序CWnd的继承中有指针指向状态条,用pStatusBar->SetPaneText(0,status,TRUE)在状态条上显示一些文本都很正常.但在第二个线程中调用该函数却不行,出现hwnd警告. 当你传送一个CWnd的指针到另外一个线程时,m_hWnd将为空.我的办法是用PostThreadMessage传送消息到状态条的父类,让它对状态条进行处理. (41)如何阻止WINDOWS关闭? 我有一个应用程序会不停地工作.当该程序正常运行时,该如何避免用户关掉系统?是不是该用WM_QUERYENDSESSION. 是的,在你的主框架窗口类中使用. // in the class headerafx_msg BOOL OnQueryEndSession( WPARAM wReserved, LPARAM lEndReason ); // in the Message MapON_MESSAGE( WM_QUERYENDSESSION, OnQueryEndSession ) // in the class bodyBOOL CMainFrame::OnQueryEndSession( WPARAM wReserved, LPARAM lEndReason ){ if( lEndReason =3D=3D ENDSESSION_LOGOFF ) { // user is logging off else // Windows is going down return( bCanExit );} (42)如何使一个按钮Disable? 我使用下面代码来Disable一个为ID_BUTTON的按钮,为什么会没有变化.GetDlgItem(IDC_BUTTON)->EnableWindow(FALSE); CWnd类中的EnableWindow函数用来Enable或Disable一个窗口类的对象,因为CButton类继承于类CWnd,所以你可以使用来操作一个按钮.Enable一个基于窗口类的对象可以用以下代码: pWnd->EnableWindow(TRUE);Disable一个对象可用 pWnd->EnableWindow(FALSE);其中pWnd为一个指向窗口对象的指针VC++中消息WM_ENABLE告诉窗口它正在Disable或Enable,但它并不能使一个窗口Enable或Disable. (43)怎样从MFC扩展动态链结库(DLL)中显示一个对话框? 我在过去的几天中试着在DLL中定义的函数中显示一个对话框,可是已经在DLL中定义好的对话框资源,在常规DLL调用时,我可以正常的显示出来,为什么在扩展DLL中同样的资源我却不能显示. 当你在DLL中使用资源时,有些小细节需要注意,首先,在DLL运行时,必须保存DLL的实例,可以通过AfxInitExtensionModule static AFX_EXTENSION_MODULE extensionDLL; extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID){ if (dwReason == DLL_PROCESS_ATTACH) { // Extension DLL one-time initialization if (!AfxInitExtensionModule(extensionDLL, hInstance)) return false; } return(true);}然后,每次使用DLL资源时,你必须改变资源的句柄,使其指向DLL,并保存exe的资源,以便以后正确恢复 void get_DLL_resource(void){ /* this function changes the resource handle to that of the DLL */ //这个函数改变资源句柄使其指向DLL if (resource_counter == 0) { save_hInstance = AfxGetResourceHandle(); AfxSetResourceHandle(extensionDLL.hModule); } resource_counter++;}接着你需要其它函数来恢复资源句柄 void reset_DLL_resource(void){ /* this function restores the resource handle set by'get_DLL_resource()' */ if (resource_counter > 0) resource_counter--; if (resource_counter == 0) AfxSetResourceHandle(save_hInstance);}接下来一点非常重要,只要有可能就必须恢复资源句柄,否则,你将会遇到许多问题.原因是可执行文件必须重画工具条等等,比如说,如果用户移动DLL的对话框,如果资源句柄仍然为DLL的资源,程序就崩溃了,我发现最好恢复句柄的时机在对话框的OnInitDialog()中,这时对话框的模板等已经读出了. (44)想隐藏用户界面怎么办? 我编了一个小巧而有趣的工具,当用户使用时我不想让它显示出任何用户界面。听听各位有办法可将视关闭。 你可以注册一个新的窗口类型,它拥有除了WS_VISBLE属性外的任何属性,类似CFrameWnd,在PreCreateWindow方法中实现。另外,你能在OnCreate方法中通过设置m_nCmdShow为SW_HIDE来实现,具体方法如下: int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){ if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // hide our app AfxGetApp()->m_nCmdShow = SW_HIDE; return 0;} (45)如何实现SDI与MDI的转换? 我想将一个编好的SDI应用程序转换为MDI,很明显要有多处的改变。 你可以这样做:建立一个继承于CMDIChidWnd的类,不防设为CChldFrm.在CWinApp中作如下变化。 InitInstance(){. ... //instead of adding CSingleDocTemplate // Add CMultiDocTemplate. pDocTemplate = new CMultiDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CSDIDoc), RUNTIME_CLASS(CChldFrm),// For Main MDI Frame change this frame window from// CFrameWnd derivative ( i.e. CMainFrame )// to your CMDIChildWnd derived CChldFrm. RUNTIME_CLASS(CSDIView));/// After this it is required to create the main frame window// which will contain all the child windows. Now this window is// what was initially frame window for SDI. CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame;.....} 在从CMDIFrameWnd中继承的类CMainFrame代替CFramWnd后,所有的类都将从CMDIFrame继承,而不是CFrameWnd,编译运行后你就会发现程序已经从SDI变换到MDI。注意:在CMainFram中必须将构造函数从private改为public.否则会出错。

评论