天天看點

VC小知識總結

VC小知識總結  

(1)當文檔被修改時,如何在标題上加上标志'*'?

重載CDocument類的虛函數virtual SetModifiedFlag:

void CTest2Doc::SetModifiedFlag(BOOL bModified)

{

    CString strTitle = GetTitle();

    CString strDirtyFlag = " *"; // note space before the '*'

            // so we don't break Save As dialog

    if (!IsModified() && bModified)

    {

        SetTitle(strTitle + strDirtyFlag);

    }

    else if ( IsModified() && !bModified )

    {

        int nTitleLength = strTitle.GetLength();

        int nDirtyLength = strDirtyFlag.GetLength();

        SetTitle( strTitle.Left(nTitleLength - nDirtyLength) );

    }

    UpdateFrameCounts();

    CDocument::SetModifiedFlag(bModified);

}

(2)VC6.0對VC5.0的相容性?

很不幸,vc6.0在調試模式對vc5.0不相容,但發行模式沒有問題.原因在微軟改變了調試模式所用dll的格式,而保留了原檔案名. 是以,不要在vc6.0中打開vc5.0的調試版本工程.

(3)列印和列印機的問題?

我碰到這麼一個問題:在列印方法中使用了MM_LOMETRIC模式,在LOGFONT結構中改變了字型的大小,但不知道173(或者對于螢幕而言是25)是從哪來的,它是自動的.然而當我用另外一個列印機時173并不适合.我想知道的是:我如何對所有的列印來調整這個數字.

我以前也碰到過類似的問題,我讓使用者改變字型(大小,顔色等等).這些改變在螢幕上看起來挺好,但是列印時太小(我的同僚在程式包中加入一個放大類).原因非常簡單:列印機的分辨率可能是300dpi,而螢幕的分辨率則低得多.我是這麼解決的:在獲得螢幕字型資訊後,我擷取螢幕字型的毫米級大小(使用LPtoDP,然後将模式變為MM_LOMETRIC,調用DPtoLP),接着對列印機設定了相同的模式,再調用LPtoDP.切換回原來的模式之後,我調用了DPtoLP,這樣就得到了想要的字型高度和寬度. 在LOGFONT中使用這個值,并且帶有其它諸如下劃線,斜體等字型資訊,我實作了使用者的要求.

(4)CRichEditCtrl滾動條的問題?

我使用了CRichEditCtrl控制來顯示某個檔案中的資料(将該控制設定為隻讀).我已經設定了ES_MULTILINE | ES_AUTOVSCROLL,但當資料内容比控制顯示多的時候,滾動條并不出現,是不是因為設定了隻讀屬性而引起了其它的問題?

ES_AUTOVSCROLL | ES_AUTOHSCROLL屬性隻在控制是可編輯時有效.你可心使用下面的滾動條風格來使滾動條出現:WS_VSCROLL | WS_HSCROLL,但是這樣一來,不管你的資料量有多大,滾動條總是會出現.

(5)從資料庫中讀大于32k的内容?

我在從資料庫中讀資料時碰到了問題.當資料欄包含超過32k的内容時,我就讀不出來,我試過ODBC::SQLGetData()也不行.

哪種類型的資料庫?MS SQL,SYBASE... 試試設定一下大小:

BOOL CGetBlobStmt::Execute(LPCTSTR stmt)

{

m_cbSize = 0;

m_size = 0;

LPBYTE

  lpData;

lpData = (LPBYTE)GlobalLock(m_hData);

m_retcode = SQLSetStmtOption(GetHandle(),SQL_MAX_LENGTH,m_dwBytesLeft);

m_retcode = SQLExecDirect(GetHandle(),(UCHAR*)stmt,SQL_NTS);

if (m_retcode == SQL_SUCCESS)

{

  m_retcode = SQLFetch(GetHandle());

  if (m_retcode == SQL_SUCCESS ||m_retcode == SQL_SUCCESS_WITH_INFO)

  {

   m_retcode = SQLGetData(GetHandle(),1,SQL_C_BINARY,lpData,254,&m_cbSize);

   while(m_retcode == SQL_SUCCESS_WITH_INFO)

   {

    lpData+= 254;

    m_retcode = SQLGetData(GetHandle(),1,SQL_C_BINARY,lpData,254,&m_cbSize);

   }

   GetError();

  }

}

GlobalUnlock(m_hData);

#if TESTDATA

TRACE("%ld",m_size);

#endif

SaveFile();

return RETVALUE;

}

(6)如何獲得CRichEditCtrl中字元的位置?

我想在CRichEditCtrl中使用右鍵菜單,是以想判定光标處字元的位置,請指點.

檢視如下的幫助:

IRichEditOleCallback::GetContextMenu

EM_SETOLECALLBACK

(7)如何限制mdi子架構最大化時的大小?

用ptMaxTrackSize代替prMaxSize,如下所示:

void CChildFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)

{

   // TOD Add your message handler code here and/or call default

   CChildFrame::OnGetMinMaxInfo(lpMMI);

   lpMMI->ptMaxTrackSize.x = 300;

   lpMMI->ptMaxTrackSize.y = 400;

}

(8)如何切換視口而不破壞它們?

我建立了一個帶有靜态分隔區的sdi應用程式,左邊顯示工作區,右過顯示左邊選取的東西.我想達到的是如果在分隔區之間進行切換,而不覆寫或破壞原來的CView對象.

以下代碼是你所想要的:

class CExSplitterWnd : public CSplitterWnd

{

// Construction

public:

    CExSplitterWnd();

// Overrides

    // ClassWizard generated virtual function overrides

    //{{AFX_VIRTUAL(CExSplitterWnd)

    //}}AFX_VIRTUAL

// Implementation

    virtual ~CExSplitterWnd();

    BOOL AttachView(CWnd* pView, int row, int col);

    BOOL DetachView(int row, int col);

    // Generated message map functions

    //{{AFX_MSG(CExSplitterWnd)

        // NOTE - the ClassWizard will add and remove member functions here.

    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()

};

CExSplitterWnd::CExSplitterWnd()

{

}

CExSplitterWnd::~CExSplitterWnd()

{

}

BOOL CExSplitterWnd::AttachView(CWnd* pView, int row, int col)

{

    //Make sure the splitter window was created

    if (!IsWindow(m_hWnd))

    {

        ASSERT(0);

        TRACE(_T("Create the splitter window before attaching windows to panes"));

        return (FALSE);

    }

    //Make sure the row and col indices are within bounds

    if (row >= GetRowCount() || col >= GetColumnCount())

    {

        ASSERT(0);

        return FALSE;

    }

    //Is the window to be attached a valid one

    if (pView == NULL || (!IsWindow(pView->m_hWnd)))

    {

        ASSERT(0);

        return FALSE;

    }

    pView->SetDlgCtrlID(IdFromRowCol(row, col));

    pView->SetParent(this);

    pView->ShowWindow(SW_SHOW);

    pView->UpdateWindow();

    return (TRUE);

}

BOOL CExSplitterWnd::DetachView(int row, int col)

{

    //Make sure the splitter window was created

    if (!IsWindow(m_hWnd))

    {

        ASSERT(0);

        TRACE(_T("Create the splitter window before attaching windows to panes"));

        return (FALSE);

    }

    //Make sure the row and col indices are

    //within bounds

    if (row >= GetRowCount() || col >= GetColumnCount())

    {

        ASSERT(0);

        return FALSE;

    }

    CWnd* pWnd = GetPane(row, col);

    if (pWnd == NULL || (!IsWindow(pWnd->m_hWnd)))

    {

        ASSERT(0);

        return FALSE;

    }

    pWnd->ShowWindow(SW_HIDE);

    pWnd->UpdateWindow();

    //Set the parent window handle to NULL so that this child window is not

    //destroyed when the parent (splitter) is destroyed

    pWnd->SetParent(NULL);

    return (TRUE);

}

(9)改變清單控制時發生閃爍現象?

我建立了一個簡單的對話框,在對話框中設定了一個清單控件,這個控件占用了對話框的全部客戶區.對話框是可以改變大小的,是以我要保證清單控件在對話框中維持正确的位置,在對話框的ONSize()事件中我對清單控件使用了MoveWindow(),這起到了作用,但當使用者改變對話框的大小時,清單控件不停地閃爍.

要解決這個問題,在用MoveWindow之前,先用ShowWindow(SW_HIDE)隐藏清單控件,然後在MoveWindow之後用ShowWindow(SW_SHOW)來顯示清單控件.

(10)處理清單控件可見項的問題?

我在一個清單控件中加入了好多條目.我通過擷取某個條目是否可見或最後是哪個條目來進行處理.我看了CListCtrl::GetItem()的幫助,但是沒有找到如何判斷一個條目是否可見的方法.

如果你隻想處理可見的條目,你可以用GetTopIndex.它傳回最大可見條目的索引值,然後你再用GetCountPerPage來得到在可見區域的條目數.

(11)産生線程的問題?

我在使用CreateThread時碰到了問題.我想讓調用的函數和被調用的函數屬于同一個類,結果在我調用CreateThread時得到如下錯誤:

error C2440: 'type cast' : cannot convert from 'unsigned long (__stdcall Cdmi::*)(void *)' to 'unsigned long (__stdcall *)(void *)'

方法一:

(1)'unsigned long (__stdcall Cdmi::*)(void *)'是指向Cdmi某個成員函數的指針.

(2)'unsigned long (__stdcall *)(void *)'僅僅隻是一個c形式函數的指針. 編譯器無法将(1)轉換為(2)是因為c++成員函數取第一個(隐藏)參數"this pointer"作為成員函數,但當是一個靜态的成員時則例外.可按如下方法解決.

class XMyThread

{

public:

    void StartThread(void);

    virtual UINT ThreadFunction(void);

    static UINT __bogusthreadfunc(LPVOID lpparam);

};

void XMyThread::StartThread()

{

    AfxBeginThread(__bogusthreadfunc,this);

}

UINT XMyThread::ThreadFunction(void)

{

    //here you do all your real work

    return 0;

}

UINT XMyThread::__bogusthreadfunc(LPVOID lpparam)

{

     XMyThread* This = dynamic_cast(lpparam);

     return This->ThreadFunction();

}

for the sake of clairty, I did not add StopThread and I did not save the

CWinThread* returned by AfxBeginThread.

If you wanted a thread that does other things, simply derive from XMyThread

and override ThreadFunction()

example:

class XAnotherThread : public XMyThread

{

    virtual UINT ThreadFunction(void);

};

UINT XAnotherThread :: ThreadFunction(void)

{

    //do some other work here

    return 0;

}

方法二:Cdmi::MonitorFiles()是個靜态的成員函數.

(12)CFile使用了緩沖區嗎?

請告訴我CFile到底有沒有使用緩沖區來處理檔案?

CFile沒有使用運作庫的I/O緩沖例程,從這個意義上講CFile并沒有使用緩沖.但是有可能作業系統在處理檔案時使用了緩沖區,如果你完全不需要緩沖區,你可以設定FILE_FLAG_NO_BUFFERING.CFile工作在這種模式下的唯一的方法是CFile::Attach().

(13)DAO的密碼?

我建立了一個使用資料庫的mfc應用程式.用類模闆生成CDaoRecordset直接打開資料庫(不通過ODBC),但問題是我如何打開有密碼保護的資料庫?

方法一:試試下面的代碼:

DAODBEngine* pDBEngine = AfxDaoGetEngine();

ASSERT(pDBEngine != NULL);

COleVariant varUserName (strUserName, VT_BSTRT);

COleVariant varPassword (strPassword, VT_BSTRT);

DAO_CHECK(pDBEngine->put_DefaultUser (V_BSTR(&varUserName));

DAO_CHECK(pDBEngine->put_DefaultPassword (V_BSTR(&varPassword));

方法二:你可以使用CDaoDatabase的Open方法來打開:

MyDaoDatabase->Open("C:/MyDatabaseFile.mdb",FALSE,FALSE,";PWD=MyPassWord");

btw:不要忘了PWD=前面的;号.

(14)如何知道CListBox什麼時候滾動了?

每次繪制清單框都要重繪某項,通過消息WM_CTLCOLOR從父視窗獲得DC顔色.是以每欠清單框的滾動你都可以用WM_CTLCOLOR來檢驗是否滾動.

HBRUSH CParentDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)

{

   // is the control _the_ list box we're interested in?

   if( nCtlColor == CTLCOLOR_LISTBOX &&

      pWnd->GetDlgCtrlID() == IDC_LIST )

   {

      // if the top index changed, the list box has been scrolled

      int iTop = ((CListBox*)pWnd)->GetTopIndex();

      if( iTop != m_iTopOld )

      {

         // keeps tracking of the top index changes

         m_iTopOld = iTop;

         // process scrolling

         ...

      }

   }

   HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

   return hbr;

}

使用這種方法可以不必為了實作這個功能而去産生一個繼承類.

(15)視口的不活動性如何處理?

有什麼方法使CListView成為類似WM_DIASBLED的風格,或者使它和背景色一緻.

方法一:你所要做的是處理CListView的WM_SETFOCUS消息,然後在TreeView中調用SetFocus,

這樣,ListView就永遠不會獲得焦點.

    afx_msg void CMyListView::OnSetFocus(CWnd* pOldWnd);

    {

        // assuming m_pwndTreeView points to the valid TreeView

        // on the left side

        m_pwndTreeView->SetFocus();

    }

方法二:重載PreTranslateMessage,然後當消息為WM_LBUTTONDOWN或WM_RBUTTONDOWN時傳回真即可.

(16)如何使用COleClientItem的IDispatch接口?

我建立了一個如何使用COleClientItem對象,我想使用它的自動化方法.有什麼方法來獲得IDispatch的接口?我試過以CCmdTarget為基類的的GetIDispatch函數但卻出錯,我用過EnableAutomation和GetIDispatch,卻什麼也沒得到.

MSDN中有一篇關于這個的文章(TN039).如下的代碼也可能是你所需要的:

LPDISPATCH CMyClientItem::GetIDispatch()

{

    ASSERT_VALID(this);

    ASSERT(m_lpObject != NULL);

    LPUNKNOWN lpUnk = m_lpObject;

    Run(); // must be running

    LPOLELINK lpOleLink = NULL;

    if (m_lpObject->QueryInterface(IID_IOleLink,

        (LPVOID FAR*)&lpOleLink) == NOERROR)

    {

        ASSERT(lpOleLink != NULL);

        lpUnk = NULL;

        if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR)

        {

            TRACE0("Warning: Link is not connected!/n");

            lpOleLink->Release();

            return NULL;

        }

        ASSERT(lpUnk != NULL);

    }

    LPDISPATCH lpDispatch = NULL;

    if (lpUnk->QueryInterface(IID_IDispatch, &lpDispatch)

        != NOERROR)

    {

        TRACE0("Warning: does not support IDispatch!/n");

        return NULL;

    }

    ASSERT(lpDispatch != NULL);

    return lpDispatch;

}

(17)關于使用者自定義的消息使用?

我寫了一個基于MFC應用程式的對話框,在這個程式中,我建立了等待網絡傳輸資料的線程,一旦該線程接收到資料,它就傳送一個使用者自定義的消息到對話框,使對話框知道有資料過來.但是為何在CMyDialog::PreTranslateMessage(MSG* pMsg)中能捕捉到WM_MYCMD這個消息,卻不能和OnMyCommand相映射?

将你所有自定義消息的基類設為WM_APP,而不是WM_USER.

(18)在打開一個文檔時退出?

我有一個mdi程式,在打開檔案的處理過程中,我想判斷該文檔是不是應用程式需要處理的文檔,是以,我檢測文檔中的某個數字是否符合要求,如何在發現不是該文檔時出現一個錯誤提示,然後不打開該文檔?

給文檔設定某個标志,如果文檔不是所要的就設定它.然後OnOpenDocument中檢測,當發現标志被設定後傳回FALSE.

(19)在CListCtrl控件中多選擇項的删除?

如何從在CListCtrl中删除多個選擇項?

按如下方法處理:如果你的在CListCtrl是m_list,to_delete是個整數數組.

i=3D0;

POSITION pos=3Dm_list.GetFirstSelectedItemPosition();

if(pos)

  while(pos)

   to_delete[i++]=3Dm_list.GetNextSelectedItem(pos);

然後用删除儲存在to_delete中的項目,用GetSelectedCount來得到已選項的個數.

(20)工作線程的登入狀态?

我使用循環删除了用AfxBeginThread建立的線程的好幾個執行個體.每個線程打開一個iNET連接配接,打開一個URL并傳回結果.我需要找出哪一個或者何時這些線程進入到登入狀态.

按如下方法處理:(僞代碼)

    // Start Threads

    for( unsigned u = 0; u < NUMBER_OF_THREADS; u++ )

{

    ThreadHandleArray[ u ] = AfxBeginThread( ...... )->m_hThread;

}

DWORD count = NUMBER_OF_THREADS

DWORD dwWait;

while( count )

{

    dwWait = ::WaitForMultipleObjects( count, ThreadHandleArray, FALSE,

INFINITE );

    if( dwWait >= WAIT_OBJECT_0 && dwWait < ( WAIT_OBJECT_0 + count ) )

    {

        dwWait -= WAIT_OBJECT_0;

        // dwWait now has index to thread that completed do whatever

you want to do with it

        // set array back up for next wait

        if( dwWait != ( count - 1 ) )

            ThreadHandleArray[ dwWait ] = ThreadHandleArray[

count - 1 ];

            count--;

    }

}

(21)如何增加視圖中ActiveX控件的事件處理函數?

如果我在對話框中加入微軟的網絡浏覽器,很容易通過類模闆加入對事件的處理.但我現在在視圖中用m_pBrowser=new CWebBrowser2加入了網絡浏覽器,我該如何對事件進行處理?

到www.vcdj.com(inet章節)去看看,有一篇文章名為"Building a Webbrowser in a Afternoon".如下的代碼也可能是你所需要的:

#include // For AFX_EVENT def.

BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)

{

    AFX_EVENT *pEvent = (AFX_EVENT *)pExtra;

    //If this is a control notification event.

    if (nCode == CN_EVENT)

    {

        // If we have information on this event.

        if (pEvent)

        {

            // Event DISPID is stored at pEvent->m_dispid

            // Event DISPPARAMS are stored at pEvent->m_pDispParams

            // Handle the event from here...

        }

    }

    return CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

}

(22)如何建立一個動态的Tree控件?

我想建立一個動态的tree控件,就象彈出視窗一樣,但它并不象想象中那麼容易.

方法一:用CreateWindow(SDK)建立風格為WS_POPUP,WS_CAPTION和WS_TICKFRAME的視窗,并作為父視窗.

方法二:建立一個包含Tree控件的對話框.

(23)SDI程式開始時不打開文檔?

我建立了一個SDI應用,但每次啟動時它都會打開一個文檔("untitled"),如何不讓它打開該文檔呢?

看看InitInstance函數中有沒有關于OnFileNew的調用,去掉它即可.

(24)List控件中整欄選擇?

我在處理List控件時碰到了麻煩,我想建立一個ListView,來依據Tree控件的選擇同時在ListView和ReportView中顯示清單的資訊.以下是相關的代碼:

// Set full line select

ListView_SetExtendedListViewStyle(m_plstCustomers->GetSafeHwnd(),

LVS_EX_FULLROWSELECT);

按如下方法處理:

// -------------------- begin of snippet --------------------------------

bool CCommCtrlUtil32::ListCtrl_ModifyExtendedStyle(CListCtrl& p_rListCtrl,

                                   const DWORD p_dwStyleEx,

                                   const bool p_bAdd)

{

    HWND t_hWnd = p_rListCtrl.GetSafeHwnd();

    DWORD t_dwStyleEx = ListView_GetExtendedListViewStyle(t_hWnd);

    if(p_bAdd)

    {

        if(0 == (p_dwStyleEx & t_dwStyleEx))

        {

            // add style

            t_dwStyleEx |= p_dwStyleEx;

        }

    }

    else

    {

        if(0 != (p_dwStyleEx & t_dwStyleEx))

        {

            // remove style

            t_dwStyleEx &= ~p_dwStyleEx;

        }

    }

    ListView_SetExtendedListViewStyle(t_hWnd, t_dwStyleEx);

    return true;

}

(25)如何重載MRU檔案?

我建立了一個應用程式可以載入圖象檔案,但當我點選FILE菜單下MRU檔案清單時,卻不能從磁盤載入以前曾經打開過的檔案.

下面是我所能想到的解決方案:

(1)在文檔類中定義一個成員函數(例如:CMyDoc::Reopen)來處理重新打開這個問題,指明參數和傳回值.

(2)産生一個CMultiDocTemplate的繼承類(如CMyDocTemplate),定義一個構造函數,取和基類相同的參數,不做任何事,隻是調用基類的構造函數.

(3)重載MatchDocType:

CMyDocTemplate::Confidence CMyDocTemplate::MatchDocType(

    LPCTSTR lpszPath,

    CDocument *&rpDocMatch

    )

{

    Confidence match = CMultiDocTemplate::MatchDocType(lpszPath, rpDocMatch);

    if(yesAlreadyOpen == match) // clear enough

    {

        ASSERT_KINDOF(CMyDoc, rpDocMatch);

        ((CMyDoc *) rpDocMatch)->Reopen();

        // you can take any other actions here...

    }

    return match;

}

當這個函數傳回"yesAlreadyOpen"時,你的文檔架構将會被激活.

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 LoadResourceBitmap

HPALETTE 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 DIB

if (lpbi->biClrUsed > 0)

  *lpiNumColors = lpbi->biClrUsed; // Use biClrUsed

if (*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->pal

PalEntry.

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_BUTTON

IDR_SOME_WINDOW_OR_DIALOG

IDP_PROMPT

IDW_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 here

ASSERT(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 header

afx_msg BOOL OnQueryEndSession( WPARAM wReserved, LPARAM lEndReason );

// in the Message Map

ON_MESSAGE( WM_QUERYENDSESSION, OnQueryEndSession )

// in the class body

BOOL 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)

{

   //這個函數改變資源句柄使其指向DLL

   if (resource_counter == 0)

      {

      save_hInstance = AfxGetResourceHandle();

      AfxSetResourceHandle(extensionDLL.hModule);

      }

   resource_counter++;

}

接着你需要其它函數來恢複資源句柄

void reset_DLL_resource(void)

{

   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.否則會出錯。

46) CDC中的豎排文本?

在OnDraw成員函數中我想讓文本豎直對齊,但CDC類似乎不支援該處理

方法一:如果你的豎直對齊是指旋轉文本的話,下面的代碼會對你有幫助:該代碼檢查一個Check box控制,檢視文本是否需要旋轉.

// m_pcfYTitle is a CFont* to the selected font.

// m_bTotateYTitle is a bool (==TRUE if rotated)

void CPage1::OnRotateytitle()

{

LOGFONT lgf;

m_pcfYTitle->GetLogFont(&lgf);

m_bRotateYTitle=

        ((CButton*)GetDlgItem(IDC_ROTATEYTITLE))->GetCheck()>0;

// escapement is reckoned clockwise in 1/10ths of a degree:

lgf.lfEscapement=-(m_bRotateYTitle*900);

m_pcfYTitle->DeleteObject();

m_pcfYTitle->CreateFontIndirect(&lgf);

DrawSampleChart();

}

注意如果你從CFontDialog中選擇了不同的字型,你應該自己設定LOGFONT的lfEscapement成員.将初始化後的lfEscapement值傳到CFontDialog中.

方法二:還有一段代碼可參考:

LOGFONT LocalLogFont;

strcpy(LocalLogFont.lfFaceName, TypeFace);

LocalLogFont.lfWeight = fWeight;

LocalLogFont.lfEscapement = Orient;

LocalLogFont.lfOrientation = Orient;

if (MyFont.CreateFontIndirect(&LocalLogFont))

   {

   cMyOldFont = cdc->SelectObject(&MyFont);

   }

(47)如何激活變灰的彈出菜單?

在設計菜單時設定為GRAYED的菜單項,如何在運作時激活它?

請看下面的示例代碼:

void CMyView::OnRButtonDown(UINT nFlags, CPoint point)

{

CScrollView::OnRButtonDown(nFlags, point);

CMenu *menu, *popup;

menu = new CMenu();

// load menu from resource file

menu->LoadMenu( IDR_POPUPMENU );

popup = menu->GetSubMenu(0); // item 0 is DUMMY

UINT nEnable;

nEnable = MF_BYCOMMAND|MF_GRAYED;

if( your test )

{

  nEnable = MF_BYCOMMAND|MF_ENABLED;

}

popup->EnableMenuItem( ID_YOUR_ID, nEnable );

//display menu

ClientToScreen(&point);

popup->TrackPopupMenu(

   TPM_LEFTALIGN | TPM_RIGHTBUTTON,

   point.x, point.y, this );

delete menu;

}

(48)線程消息?

如何正确地線上程之間傳送消息?

下面的代碼将會幫你的忙:

void CThread::OnUserOpen( WPARAM wParm, LPARAM lParm )

{

    UNUSED( wParm ) ;

    UNUSED( lParm ) ;

    AfxMessageBox("User Open", MB_OK|MB_ICONEXCLAMATION);

}

當然,也别忘了以下聲明:

class CThread : public CWinThread

{

     DECLARE_DYNCREATE(CThread)

protected:

     CThread(); // protected constructor used by dynamic creation

     afx_msg void OnUserOpen( WPARAM wParm, LPARAM lParm );

(49)TreeCtrl控制的顯示速度太慢?

我從CTreeCtrl繼承了一個TREE控制類,重載主要是為了改寫每個節點的文本.我在 OnPaint函數中寫了一些代碼,但這嚴重地影響了TREE控制的滾動速度.

OnPaint函數

1.可見節點,對于GetFirstVisibleItem和GetNextVisibleItem來講,是:

  a.根節點;b.父節點已展開的節點;是以,"可見"意味着"沒有被未展開的父節點隐藏".當節點滾動到客戶外時,它對上述兩個函數來講仍是可見的.

2.當TREE的内容改變時,它預設隻将變為可見的節點重繪.另外其它已經是可見的節點沒有必要重繪,TREE隻是滾動DC的位圖而已.

上面的意思是不要繪制你不需要看的節點,那會導緻速度降低.建議,測試節點矩形是否在客戶區,使得隻有需要繪制的節點才會被繪制.

void CIndentTree::OnPaint()

{

   CPaintDC dc(this); // device context for painting

   HTREEITEM hItem = NULL;

   DRAWITEMSTRUCT dis;

   CRect rc;

   // redraw only visible items with indentation

   for(

      hItem = GetFirstVisibleItem();

      hItem; hItem = GetNextVisibleItem( hItem ) )

   {

      if( !GetItemRect( hItem, rc, FALSE ) )

         continue;

      if( rc.top <= dc.m_ps.rcPaint.bottom &&

         rc.bottom > dc.m_ps.rcPaint.top &&=20

         rc.left <= dc.m_ps.rcPaint.right &&

         rc.right > dc.m_ps.rcPaint.left )

      {

         dis.hwndItem = (HWND)hItem;

         dis.rcItem = rc;

         OnDrawItem(0, &dis, &dc);

      }

   }

}

OnDrawItem函數

1.删掉如下代碼:

      IMAGEINFO* pinfo = new IMAGEINFO;

      ...

      delete pinfo;

沒有必要使用動态的IMAGEINFO變量,你可以将其定義為堆棧變量.

2.GetItemState和GetItemText都是使用的GetItem,是以,你隻需調用一次, 就可以從節點獲得你要的所有資訊.

(50)關于工具條?

我需要在程式中做一個FLAT工具條,于是我加入一個變量m_wndToolBar. 在程式主體視窗的OnCreate()函數中修改工具條狀态(0,TBSTYLE_FLAT). 在NT中運作正常,為什麼在95中工具條變得透明?

在COMCTL32.DLL中的舊版本中有些小bug,繪畫時會帶來一些問題, 你可以使用一些定制代碼,在www.codeguru.com站點上有下載下傳,如果你使用的是6.0版本,你也可以使用下列代碼(摘自我的mainfrm.cpp檔案)

m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP |

CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

用CreateEx替換ModifyStyle在同一尺寸的工具條中有些不同((CreateEx 建立的略小些),試一下,如果你仍然有這個問題,檢查一下COMCTL32.DLL的版本使用标準按鈕替換FLAT.

(51)關于線程消息?

真奇怪,OnUserOpen()函數和OnUserOpen(WPARAM, LPARAM)函數竟然不是一個函數,編譯器在查到OnUserOpen(WPARAM, LPARAM)時,不會調用OnUserOpen 莫非有人在消息映象做了什麼手腳?

其實,這是MFC嚴密的表現,處理時,通過函數指針來調用,而該指針是由發生的事件所決定的.如果句柄不正确定義的話,調用當然是非法的

(52)關于控件的焦點?

有誰能給我一個有效的方法:當一個控件失去焦點時,怎樣管理才能使對話框的焦點進入到正确的控件.

我有一個可運作的程式來實作,不一定很全面,但能工作.

const int WM_VALIDATE_PARAMS WM_APP + 101;

void CMyDlg::OnKillfocusName()

{

    PostMessage(WM_VALIDATE_PARAMS, ED_NAME, 0L);

}

void CMyDlg::OnKillfocusAddress()

{

    PostMessage(WM_VALIDATE_PARAMS, ED_ADDRESS, 0L);

}

bool CMyDlg::OnValidateParams(WPARAM rcId, LPARAM)

{

        switch( rcId )

        {

        case ED_NAME:

        if( !validateName() )

            m_edName.SetFocus();

        break;

        case ED_ADDRESS:

        if( !validateAddress() )

            m_edAddress.SetFocus();

        break;

    default:

        break;

    }

    return true;

}

上面的代碼可以在使用者使用TAB鍵或滑鼠操縱時,使用焦點跳至下一個控制.當你想DISABLE一個控件或重設焦點時,會有些問題,特别是在Killfocus事件中。

(53)如何捕獲鍵盤按鍵?

在CTabCtrl的子對話框怎樣才能捕獲ALT+0組合鍵

可以在PreTranslateMessage中截取鍵盤消息。

(54)怎樣實作3D效果?

在對話框中怎樣實作Edit和Listboxes控件的3D效果?(環境95/NT VC5.0)

1). 使用帶WS_EX_CLIENTEDGE标志的::CreateWindowEx來替換::CreateWindow 或者用CWnd::CreateEx替換CWnd::Create.

2).在建立控件之後,調用ModifyStyleEx(0, WS_EX_CLIENTEDGE).

(55)怎樣建立客戶CSocket?

我有一個客戶socket想在socket中建立一個局域聯接.我使用下列順序:

CSocket* m_pSocket;

m_pSocket = new CSMSSocket(this);

m_pSocket->Create();

m_pSocket->Bind(m_intHostPort, m_strHostIPAddress);

m_pSocket->Connect(lpszAddress, nPort);

但每次Windows Socket都定向到别的端口,怎樣才能定向到同一個端口(環境:95/NT VC5.0).

1).如果你想用Client Socket,你就不能在connect()之前調用bind(),因為局域端口位址由TCP/IP設定,我們不可能知道下一次将使用那一個端口,我想我們不必這做.

2).看一下Create()的幫助,裡面告訴我們必須給Create()指定一個端口值, 預設的情況為0,也就是由Window為我們選擇一個端口,通過Create()将會自動捆綁. 3).我不認為你應該完成所有的工作,但想總是用一個相同的端口來連接配接遠端機器是一個不正确的想法.

問題出在端口數/位址結合必須唯一,如果你想在Create()中指一個固定的端口數,你隻能與遠端機器建一個單個連接配接.在你所寫的代碼中是允許局域端口數可變化,可以打開多個連接配接來取得相同的位址.在偵聽(listening)Socket中有許多理由使用一個固定端口,但在連接配接(connecting Socket中我想沒有太多的必要.

(56)Disable一個非模态對話框的客戶區?

我在OCX(對象連接配接和嵌入客戶控制程式)有一個非模态對話框.它有一個菜單以及工具條.現在我想Disable客戶區(隻是客戶區,例如:設定特殊變量時顯示一個等待光标,區域裡的所有控制都不可以處理)但在客戶區的所有控制要看上去沒有變化(也就是不可以Disable)

可以這樣試一下,建立一個子視窗,覆寫對話框的全部的使用者區域,用WS_EX_TRANSPAPENT 透明類型,然後調用函數EnableWindow(FALSE),使用SetClassLong或者别的方法,在子視窗調用"忙"光标,這時光标就正确了,但對話框中的菜單還能正常使用.(說白了就是建立一個透明的子視窗蓋住所有的使用者區域,然後Disable該透明視窗,在這個視窗中設定光标為"忙") 這個方法我沒有試過,但在一些老的Windows的書介紹過這種方法.

(57)關于使用SetClassLong和SetCapture問題

我用SetClassLong設定對話框光标時遇到了一些問題,當我使用SetCapture捕獲滑鼠時,

光标形狀并沒有變化時,以下為原代碼:

void CMouseMoveSimDlg::OnLButtonDown(UINT nFlags, CPoint point)

{

  myDragging = TRUE;

  myhPrevCursor = (HCURSOR)SetClassLong( m_hWnd, GCL_HCURSOR,

   (long)LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_SELECTCURSOR )));

  SetCapture(m_hWnd);

CDialog::OnLButtonDown(nFlags, point);

}

如果移去SetCapture這一行,光标就會正确的設定,但它就不能正确的捕獲滑鼠消息.那兒出問題了(環境NT4.0 VC6.0)?

1).如果我沒有記錯的話,SetClassLong隻影響調用它以後的建立的視窗.可以使用 SetWindowLong來改變已存在的視窗的屬性.(為什麼要用SetClassLong來改變光标形狀, 為什麼不在消息WM_SETCURSOR中替換.)

2).我也不清楚問題出在那兒,但下面的方法可以克服SetCapture帶來的問題,它是從我的程式裡面提出來的:

void CScribbleView::OnLButtonDown(UINT nFlags, CPoint point)

{

    ........

    SetCapture(); // Capture the mouse until button up

    myhPrevCursor = (HCURSOR)SetClassLong( m_hWnd, GCL_HCURSOR,

(long)LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_CURSOR1)));

SetCursor(LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_CURSOR1)));

    ........

}

void CScribbleView::OnLButtonUp(UINT nFlags, CPoint point)

{

    if( GetCapture() != this )

        return;

    ........

    ReleaseCapture();

    SetClassLong( m_hWnd, GCL_HCURSOR, (long)myhPrevCursor);

    return;

}

(58)動畫控件?

我在對話框中使用一個動畫控件,通常我都是用CAnimated的open成員函數,并加上avi的檔案名來使用動畫控件,怎樣在資源檔案加入一個avi檔案,作為資源使用?

1).簡單,将avi檔案引入資源,按你的喜歡來決定是屬于那一種類型的,通過ID來代替檔案的名字,這樣你就可以使用了.

2).在資源視窗中單擊右鍵,在彈出的菜單中選擇"Import".這時會打開檔案選擇框,選擇所要的檔案,這時系統将會詢問自定義資源類型,輸入avi.一個AVIS的資源組将會創立,你所選的avi檔案将會出現在該組中并擁有一個ID.

3).手動在資源檔案中加入一個AVI資源說明,比如:

//在這手工編輯資源檔案

IDR_ANIMATION AVI res/animate.avi

(59)錯誤聲明的消息?

我給一個視發送一條消息

pView->SendMessage (MY_MESSAGE, wparam, lparam);

消息聲明被認為是不正确的

afx_msg void OnMyMessage();

高手一看就知道這是一條指令錯誤的聲明對象,正确的聲明應該為:

afx_msg LERSULT OnMyMessage (WPAPRAM wparam, LPARAM lparam);

因為我不使用參數,程式工作也很好,是以我不知道為什麼會有這種錯誤,該過程處理完之後也沒有任何錯誤的資訊出現.但現在release版本中有一個奇怪的現象(debug版本中沒有)程式會非正常終止,通常這現象發生在SendMessage()傳回之後。為什麼?

1.相信問題是出在錯誤的堆棧上,"thiscall"調用後就應該清除堆棧,調用者調用時将兩個參數壓入堆棧,但參數卻沒有被清除.如果你真的不需要WPARAM,LPARAM,也不需要傳回值的話,你可以使用ON_MESSAGE_VOID 消息聲明.在afxpriv.h中定義,是非文檔的,意思就是它不會有什麼提示或可能中斷程式, 另外,需要注意一下線程消息,注意線程消息是可變的,它們将傳回void,沒有LRESULT,同樣的聲明.

2.如果你不使用WParam和LParam,為什麼不在視中定義一個使用者函數來處理自己想做的?

(59)怎樣模拟滑鼠動作?

這是困擾我多時的一個問題,怎樣才能實作模拟滑鼠的動作,就是說要使一個程式實作滑鼠的單擊,輕按兩下,拖放等功能.我認為必須要實作相應的消息傳遞,但每次都不成功.

比如說,我想關閉記事本視窗,可以傳送WM_lBUTTONDOWN和WM_LBUTTONUP(X,Y值為記事本的右上角關閉按鈕的位置)給記事本視窗,但視窗并沒有關閉.當然,我也知道關閉一個視窗可以通過傳送WM_QUIT或WM_CLOSE來實作,但滑鼠的消息為什麼會丢失?

請教各位大師,怎樣模式模拟實作滑鼠的動作,或者給我一些怎樣發送消息來關閉視窗的建議(不是WM_CLOSE或WM_QUIT)

1).試一下window hooks,你可以使用SetWindowsHookEx和JournalPlayback來處理滑鼠事件.

2).你可以使用文檔中的SendInput(),它能實作模拟鍵盤或滑鼠事件.如果你使用NT,那也可以用老的函數像mouse_event(),keyb_event等,在Win98中,SendInput()一樣可以使用.

3).抱歉不能給你一個滿意的回答,你可以在網站http://www.microsoft.com/enable/dev/tooldev.htm 中找到一篇關于模拟輸入的文章.

4).在NT中可以使用mouse_event()傳遞事件,文檔上說這種方法已經過時了,那麼你可以用 SendInput()替換,但找不到關于此函數的使用說明,是以我依然使用mouse_event,沒有任何問題.

(60)改變對話框标題字型?

怎樣改變對話框标題檔案的字型,改變資源中對話框屬性中的字型,将改變所有的控件的字型, 卻沒有改變标題,但我隻想改變标題字型,不改基餘控件的屬性.是不是我錯過一些明顯的選項. 通過查找一些MFC代碼,我發現有一個CDialog子產品,裡面調用了一引起字型方法,但該對話框不是公用的,我相信它不會給我任何幫助.

1).就我所知,對話框的标題字型和其它的視窗标題一樣,它可以通過系統--顯示器--屬性--外觀來設定,如果自己想這樣做,我想你應該取得WM_NCPAINT句柄自己來畫出非使用者區域(包括标題在内),我從未做這樣做過,可能是個錯誤的方向.

2).如果你是在CView繼承的,那你可以在構造函數中看見如下代碼:

if( !my_CFont .CreatePointFont( 180,"Helvetica",NULL ) )

        return false;

GetEditCtrl().SetFont( &my_CFont ,true )

接下來如果你想改變在對話框中的一個CEdit控件字型時,可以使用以下代碼:

if( !my_CFont .CreatePointFont( 180,"Helvetica",NULL ) )

        return false;

( GetDlgItem (ID_ANY_CEDIT) ) ->SetFont( &my_CFont );

(61)怎樣知道CWinThread對象的狀态?

怎樣才能知道一個線程是在運作還是已經終止?

可以利用線程句柄所指的::GetExitCodeThread()函數,如果線程已經結束, 它将傳回一個退出代碼,如果還在運作,則傳回一個STILL_ACTIVE.不過在之此前,先将 CWinThread成員對象m_bAutoDelete設定為FALSE.另外對象線上程結束時會自動檢測到.

(62)如何調整控件對話框條的大小?

我想讓使用者能夠在控制條出現時控制它的大小,在所有的例子中,在控件浮動時,改變尺寸還可以,但在工具條停靠在架構上時就無法調整其大小,該怎樣實作?

1)也許你錯過了一些注意點,我用的是codeguru站點上下載下傳的CCoolDialogBar類, 在工具條停靠時也可以重新改變其大小.

2)我開發了一個應用程式,它的界面跟你所說的差不多,讓我試着解釋一下我是怎樣做的.

1.從CDialogBar類中繼承一個類,名為CMyBar;

2.在CMyBar中增加一個成員變量,int m_iWidth;

3.在CMyBar中的OnPaint和OnNcPaint中畫出工具條(grab bar);

4.拖動工具條時在滑鼠事件時繪出軌迹;

5.釋放滑鼠時,計算CMyBar新寬度.可以通過取得目前軌迹位置,使m_iWidth等于新的寬度;

6.(重要)GetDockingFrame()->RecalcLayout();

7.在CMybar中增加一個成員方法CalcDynamicLayout;

8.在CalcDynamicLayout中,當工具條停靠時,通過計算m_iWidth傳回值.

當然,這隻是一個很簡單的方法,你可以做得比這更好.

3)可以試一下VC6.0中的CReBar類

(63)如何頂端顯示CStatic類文字?

我正寫一個小的應用程式,我想顯示一串文本(CStatic)并且無論别的應用程式運作時是否覆寫,這些文字總會在最上面顯示.

1)用CreateEx來建立一個WS_POPUP視窗,使這個視窗總在最上面(always on top) 然後在該視窗中實作文字顯示.

2)建立視窗時用SetWindowPos()函數,用&wndTopMost作為第一個參數,這樣就可以完成你想做的了.

(64)消息句柄出了什麼事?

我在CParentView中為WM_LBUTTONDOWN定義一個句柄,但我建個新的CChildView, 句柄得不到處理.

1)仔細看一下你ChildView檔案中的MESSAGE_MAP,可能在第兩個參數比對 BEGIN_MESSAGE_MAP(Child,Parent)中有着錯誤的基類.如果你是用向導生成器, 那麼你很容易就會發生這種事情.

2)檢查一下消息映象宏中的類名和父類名是否正确,比如BEGIN_MESSAGE_MAP (CChildView,CParentView).

如果你用自己的消息句柄手工代替了向導所做的,确信你的改動是正确的, 一個錯誤的參數或者加了一個"const"将會改變消息映象而不會被正确調用.

3)我猜想你一定是用類向導生成器來建立你的CChildView,而且在基類的選擇中一定是選了CView,自己動手在消息映象中把它修改過來.

(65)樹形控件為何閃爍?

我從CTreeCtrl中繼承了一個類,以縮進的格式顯示節點,現在我碰上些問題,當樹被重畫兩次之後(一次為預設,另一次為對齊文本時)點選節點樹就會閃爍.

1)試一下LockWindowUpdate()API函數。

2)試一下加入TVS——HASBUTTONS标志,

ModifyStyleEx(TVS_HASBUTTONS, 0);

....//drawing

ModifyStyleEx(0, TVS_HASBUTTONS);

如果它不再閃爍,那麼在将其定義為自畫屬性,用PreCreateWindow()中加入CS——OWNDC。

(66)怎樣才能關閉樹形控件中的滾動條?

我想關閉樹形控件的滾動條,但它依然顯示出來,怎樣才能隐藏它?

1)在建立時加入TVS_NOSCROLL,注意此時你就不可以用鍵盤來實作翻頁,這種類型需要comct32.dll4.71版本以上才可以,并且要在commctrl.h中定義如#define TVS_NOSCROLL 0x2000.

2)值得這樣試一下 ModifyStyle(WS_VSCROLL,0),将這段代碼放在建立之後,顯示之前。

(67)如何建立一個帶滾動條的視窗?

我想建立一個帶滾動的子視窗,但我沒有用向導生成器。

如果你讓你的視窗有一個滾動條,你必須首先初始化。如下

   SCROLLINFO si;

   si.cbSize = sizeof( SCROLLINFO );

   si.fMask = SIF_PAGE | SIF_RANGE;

   si.nMin = 0;

   si.nMax = 100;

   si.nPage = 10;

   SetScrollInfo( SB_HORZ, &si );

   si.nMin = 0;

   si.nMax = 50;

   si.nPage = 5;

   SetScrollInfo( SB_VERT, &si );

如果程式運作時你的視窗内容已經改變或者視窗被改變大小而重畫時,你必須重新設定滾動條。在MFC中包含類CScrollView,它已内建滾動條。

(68)如何實作對話框的拖放?

我有一個對話框程式,想讓它實作拖放。但無論用OnDrag或OnDrop等等,所有的的消息都發送給CView類而不是CDialog類,為什麼?

你應該使用COleDropTarget類,試一下這些:

class CMyOleDropTarget: public COleDropTarget

{

protected:

    virtual DROPEFFECT OnDragEnter( CWnd* pWnd, COleDataObject*

pDataObject, DWORD dwKeyState, CPoint point )

    {

        TRACE( "DRAG Enter/n" );

        return DROPEFFECT_MOVE;

    };

    virtual DROPEFFECT OnDragOver( CWnd* pWnd, COleDataObject*

pDataObject, DWORD dwKeyState, CPoint point )

    {

        TRACE( "DRAG Over/n" );

        return DROPEFFECT_MOVE;

    };

};

CMyOleDropTarget DropTarget;

BOOL CDlgDlg::OnInitDialog()

{

    CDialog::OnInitDialog();

    DropTarget.Register( this );

不要忘記調用AfxOleInit()

BOOL CDlgApp::InitInstance()

{

    AfxEnableControlContainer();

    AfxOleInit();

}

(69)TrackMouseEvent()怎麼了

我使用TrackMouseEvent()函數來跟蹤滑鼠是否已經離開我的視窗,但在MFC中,如果我使用 ::TrackMouseEvent()系統告訴我沒有定義,為什麼?

1).請使用_TrackMouseEvent

2).在commctrl.h顯示為_TrackMouseEvent(),請注意下劃線.

3).可能TrackMouseEvent()不支援Win98(在NT中工作得非常好),建議你結合WM_MOUSEMOVE消息和 SetCapture()函數,當滑鼠移出視窗時你依然可以控制.

(70)奇怪的組合框控件

我有一個對話框程式,裡面隻有幾個下拉式給合框.但當滑鼠箭頭移動到組合框的上下按鈕時,會變成"6"或"9",一會兒又恢複到原狀,這是為什麼?

1)也許是你的作業系統有問題,不防重新起動一次也許就行了(機率非常小8%-())你也可以試一下系統清除工具,如果這事情經常發生,可能你真的需要重裝一下95或NT,這也是個好的建議,每隔半年左右可以重裝一下系統.

2).我猜想可能是comctl32.dll檔案被破壞了.

3).這個問題的原因很有可能是系統的資源不夠,你可以試着關閉一些程式、減少螢幕的分辨率來增加一些系統資源。

(71)關于使用MS SANS SERIF字型

我看過好多關于建立對話框、組合框等等使用MS SANS SERIF的例子,自己也做過多次。如: m_font.CreatePointFont (80, _T("MS Sans Serif")); 或 m_font.Create (-8, ....., _T("MS Sans Serif")); 那麼想問一下:1)該字型是否在所有的版本中都能實作(包括國際版本) 2)在控制台上有沒有更好的字型代替“SYSTEM”字型?如果有人這樣做了,那又是怎樣設定字型大小等相關設定的?我希望有一個徹底的方法來選擇組合框等的字型。

1)有件事情我做過,在我所有的程式界面中都改變了字型.消息框來顯示使用者選擇的字型. 菜單,工具條以及其他控件的字型都随使用者意願改變.但在對話框中最好還是用對話框編輯器, 其基本字型都是MS SANS SERIF,是以我也以這種字型來作為所有的使用者界面. 以下為我所做的代碼:

// here's the font I use:

SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);

m_fntUI.CreateFontIndirect(&ncm.lfMessageFont);

// here's the code to change the font for a wnd and all it's children, and

resize the controls appropriately

void ChangeDialogFont(CWnd* pWnd, CFont* pFont, int nFlag)

{

CRect windowRect;

// grab old and new text metrics

TEXTMETRIC tmOld, tmNew;

CDC * pDC = pWnd->GetDC();

CFont * pSavedFont = pDC->SelectObject(pWnd->GetFont());

pDC->GetTextMetrics(&tmOld);

pDC->SelectObject(pFont);

pDC->GetTextMetrics(&tmNew);

pDC->SelectObject(pSavedFont);

pWnd->ReleaseDC(pDC);

long oldHeight = tmOld.tmHeight+tmOld.tmExternalLeading;

long newHeight = tmNew.tmHeight+tmNew.tmExternalLeading;

if (nFlag != CDF_NONE)

{

  // calculate new dialog window rectangle

  CRect clientRect, newClientRect, newWindowRect;

  pWnd->GetWindowRect(windowRect);

  pWnd->GetClientRect(clientRect);

  long xDiff = windowRect.Width() - clientRect.Width();

  long yDiff = windowRect.Height() - clientRect.Height();

  newClientRect.left = newClientRect.top = 0;

  newClientRect.right = clientRect.right * tmNew.tmAveCharWidth /

tmOld.tmAveCharWidth;

  newClientRect.bottom = clientRect.bottom * newHeight / oldHeight;

  if (nFlag == CDF_TOPLEFT) // resize with origin at top/left of window

  {

   newWindowRect.left = windowRect.left;

   newWindowRect.top = windowRect.top;

   newWindowRect.right = windowRect.left + newClientRect.right + xDiff;

   newWindowRect.bottom = windowRect.top + newClientRect.bottom + yDiff;

  }

  else if (nFlag == CDF_CENTER) // resize with origin at center of window

  {

   newWindowRect.left = windowRect.left -

       (newClientRect.right - clientRect.right)/2;

   newWindowRect.top = windowRect.top -

       (newClientRect.bottom - clientRect.bottom)/2;

   newWindowRect.right = newWindowRect.left + newClientRect.right + xDiff;

   newWindowRect.bottom = newWindowRect.top + newClientRect.bottom + yDiff;

  }

  pWnd->MoveWindow(newWindowRect);

}

pWnd->SetFont(pFont);

// iterate through and move all child windows and change their font.

CWnd* pChildWnd = pWnd->GetWindow(GW_CHILD);

while (pChildWnd)

{

  pChildWnd->SetFont(pFont);

  pChildWnd->GetWindowRect(windowRect);

  CString strClass;

  ::GetClassName(pChildWnd->m_hWnd, strClass.GetBufferSetLength(32), 31);

  strClass.MakeUpper();

  if(strClass==_T("COMBOBOX"))

  {

   CRect rect;

   pChildWnd->SendMessage(CB_GETDROPPEDCONTROLRECT,0,(LPARAM) &rect);

   windowRect.right = rect.right;

   windowRect.bottom = rect.bottom;

  }

  pWnd->ScreenToClient(windowRect);

  windowRect.left = windowRect.left * tmNew.tmAveCharWidth /

tmOld.tmAveCharWidth;

  windowRect.right = windowRect.right * tmNew.tmAveCharWidth /

tmOld.tmAveCharWidth;

  windowRect.top = windowRect.top * newHeight / oldHeight;

  windowRect.bottom = windowRect.bottom * newHeight / oldHeight;

  pChildWnd->MoveWindow(windowRect);

  pChildWnd = pChildWnd->GetWindow(GW_HWNDNEXT);

}

}

(72)為什麼DLL在字元串表中找不到字元串

我用向導生成器中的"Use MFC in a Shared DLL"選項建立一個DLL,在字元串表資源中加一個字元串,當我使用csMyString.LoadString( IDS_MY_STRING ) csMyString 是空的,為什麼會這樣?

1)MFC是由AfxGetResourceHandle調用資源的.是以,如果你想在你的DLL中讀出資源應該使用 AfxSetResourceHandle.你也可以在LoadLibrary的傳回值中得到它,如果不想調用該DLL時也可以使用DLLMain函數的hInstance參數.

2)試一下在你函數打頭處使用AFX_MANAGE_STATE(AfxGetStaticModuleState()) (事實上每個被外部DLL調用的每一個函數都會使用它)

3)我記得先前的清單講過這個問題,試一下以下兩種方法: 如果你是用LoadLibrary()來調用DLL的,它會傳回一個句柄,你可以在 AfxSetResourceHandle()中使用它.如:

   hinstnew = Loadbrary(...);

   ...

   hinstOld = AfxGetResourceHandle();

   AfxSetResourceHandle(hinstnew);

   LoadString(IDS_MY_STRING);

   AfxSetResourceHandle(hinstOld); // remember to set this back,

                           // or your night won't be nice.

如果你不是用LoadLibrary來調用DLL又該怎樣辦呢?你可以使用 GetModule("You DLL Name")來取得使用者句柄,剩下的就好辦了.

(73)關于複選框的文本顔色

有誰知道怎樣才能改變複選框中的文本選項的顔色?

1)你有沒有試過在控件中使用OnCtlColor,它将在重畫任何控件之前被調用,是以你可以有機會來改變文本選項的顔色。

2)為什麼你一定要用PreDrawItem()?你是想在裡面做一些特定的代碼?我認為DrawItem() 也能處理。在調用重畫函數之前取得索引号并改變顔色。

(74)系列化與版本的問題

我需要使用系列化來讀取我的檔案,為了保證檔案能在各個版本中都能實作,我作了盡可能的努力,為什麼會不成功.

答:下面的代碼是我過去使用過的,希望能對你有所幫助

// Use this macro to fix the versioning problem in the MFC

// Place it at the beginning of your CMyObject::Serialize implementation -

// it will guarantee that the correct version of the class is written to

// and read from the archive

//

// Usage: SERIALIZE_VERSION(CMyObject)

#define SERIALIZE_VERSION(this_class)     ar.SerializeClass(this_class::GetRuntimeClass());

// For classes which cannot use IMPLEMENT_SERIAL (such as abstract

// base classes). This guarantees the object can have

[Read/Write][Class/Object]

// called on it by placing a schema number in it. It also puts it in the

// list of known class names (AFX_CLASSINIT).

// Note: this is almost the same as IMPLEMENT_SERIAL_ABC

// in "MFC Internals", but this version uses AFX_CLASSINIT,

// with the result that it works!

#define DECLARE_DYNAMIC_SERIAL(class_name)     DECLARE_SERIAL(class_name)

#define IMPLEMENT_DYNAMIC_SERIAL(class_name, base_class_name, wSchema)     _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, NULL)    static const AFX_CLASSINIT

_init_##class_name(RUNTIME_CLASS(class_name));     CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb)         { pOb = (class_name*)

ar.ReadObject(RUNTIME_CLASS(class_name));             return ar; }

或者也可以這樣實作:

CMySerialRootDerivedClass::Serialize(CArchive& ar)

{

    //CMySerialRoot::Serialize(ar); // <- do not call this here

    if (ar.IsStoring())

    {

        ... store derived stuff here

    }

    else

    {

        int nVersion = ar.GetObjectSchema();

        switch(nVersion)

        {

        case 1:

            ... load derived version 1 stuff here

            break;

        case 2:

            ... load derived version 2 stuff here

            break;

        default:

            // report unknown version of

            // this object

            break;

        }

    }

    // serialize the base class version information

    // -> then serialize the base class

    ar.SerializeClass(RUNTIME_CLASS(CMySerialRoot));

    CMySerialRoot::Serialize( ar );

}

(75)在一個控件内檢測并使用ON_COMMAND消息

有一個控件(繼承CWnd)在CRormView.可不可以将它的ID在ON_COMMAND消息中發出,如果用pCtrl->OnCommand(ID_VIEW_ZOOMIN,..), 編譯器會報告參數不比對,該怎麼辦?

1)為什麼不用pCtrl->Post/SendMessage (WM_COMMAND, ID_VIEW_ZOOMIN)

2)通過重載CYourFormView::OnCmdMsg就可以.如:

BOOL CYourFormView::OnCmdMsg(UINT nID, int nCode, void* pExtra,

AFX_CMDHANDLERINFO* pHandlerInfo)

{

return pCtrl->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)

  || CFormView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

}

3)使用WM_COMMAND消息,看一下關于WM_COMMAND和CWnd::PostMessage()的幫助.

DWORD wParam;

HIWORD(wParam) = wNotifyCode; // notification code

LOWORD(wParam) = ID_VIEW_ZOOMIN;

pCtrl->PostMessage(WM_COMMAND,(WPARAM)wParam, pCtrl->m_hWnd);

4)能夠這樣做,但不是象你們做法,你們必須得到控件的句柄或CWnd指針然後在句柄中使用::SendMessage() or ::PostMessage();在CWnd中使用 CWnd::SendMessage() or CWnd::PostMessage() 試一下這個.

CMyCtrl *pCtrl;

pCtrl = ( CMyCtrl * )GetDlgItem( IDC_MYCONTROL );

if( pCtrl != NULL && ::IsWindow( pCtrl->GetSafeHwnd( ) )

pCtrl->SendMessage( WM_COMMAND, , );

// see WM_COMMAND description on help/MSDN for a detailed explanation of

// {W|L}PARAM

(76)為何MDI程式中有子視窗打開時主應用程式不能關.

我在MDI程式中增加了一個CRichEditView文檔模闆,在子視窗視中我增加了下面一些代碼.

StartReport (void)

{

CReportFrame *rpt;

CReportDoc *rptDoc;

   // First get the right document template

POSITION pPos = theApp.GetFirstDocTemplatePosition();

theApp.GetNextDocTemplate ( pPos );

theApp.GetNextDocTemplate ( pPos );

CDocTemplate *pTemplate = theApp.GetNextDocTemplate ( pPos );

   // Verify validity

ASSERT(pTemplate != NULL);

ASSERT_KINDOF(CDocTemplate, pTemplate);

   // Create the frame

rptDoc = new CReportDoc;

rpt = (CReportFrame*)pTemplate->CreateNewFrame ( rptDoc, NULL );

pTemplate->InitialUpdateFrame (rpt, rptDoc);

   // Get access to the display area

CReportView *rptView = static_cast(rpt->GetActiveView());

CRichEditCtrl &rptCtrl = rptView->GetRichEditCtrl();

}

CReportFrame繼承于CMDIChildWnd

CReportDoc繼承于CRichEditDoc

CReportView繼承于from CRichEditView

  如果我關閉程式前不關閉建立的視,調試器将認為程式依然在運作(程式管理器中依然存在) 我需要用調試菜單中的stop debugging來關閉程式;如果我手工關閉該視,程式将會正常關閉.如果有什麼不同的話,在手工關閉新的視之前程式會詢問是否儲存. 那麼怎樣我才能關閉程式呢?

1)我也碰上過對話框,視窗不能自動關閉的情況,這主要是因為繼承的對象不正确所造成的。通常應該在主程式中設定AfxGetMainWnd().

  你的程式讓我搞糊塗了,一連使用了多個GetNextDocTemplate(pPos),在這些文檔指針是NULL時通常會引起一些循環.在你的文檔模闆中是否已經精心算好了數目?這樣可能會産生些bugs 我建議找出目前的文檔模闆用CDocTemplate::CreateNewDocument()來代替你的"new CReportDoc"

2) 記住一個公共規則,關閉程式前要關閉所有的視.

(77)滾動視中LPtoDP失敗

在WINDOWS98/95中,當你給光标指針位置大于32767或者小于-21768函數CDC::LPtoDP 将失敗,程式工作在NT上但在95/98中用滾動視工作時卻出現了問題. LPtoDP是在下面函數中被調用的:

      SetScrollSizes(MM_HIMETRIC, sizeTotal);

函數是在CScrollView中調用的.我使用的是HIMETRIC映射方式,在我想将A4擴大150%時這個問題就會出現。怎樣才能解決這個問題?

1)在95中确實存在這樣的問題,95中的GDI不是32位的.當我們開發一個程式有編輯矢量圖象時手動而不是由LPtoDP()函數來完成轉換.(在NT中也存在同樣的問題)

2)簡言之,CScrollView或CWnd之是以32位參數會失敗是因為95/98并不是真正的32 位作業系統,裡面仍然包含16位代碼.比如Scrollbars還是隻接受16位的值來調整範圍. NT是一個真正的32位作業系統,就沒有這些困惑.

  在95中不得不面對類似的滾動大文檔的問題時,我們隻能另外寫些代碼來實作滾動的實際位置,當它超出-32K或+32K時,你也必須在你的應用中做些映射.

  作為一個有關的注意點(可能你已經碰上過這個問題)如果在MFC處理滾動消息時,如: void CSomeWnd::OnVScroll (UINT nSBCode,UINT nPos, CScrollBar *pscrollBar) 中的 nPos參數隻有16位長.克服這個限制可以使用SCROOLINFO結構運作::GetScrollInfo.SCROLLINFO 結構中的nTrackPos是一個真正的32位。

(78)ODBC許可問題

我有個程式想通過ODBC來使用一個MS Access資料庫,但是卻碰上了錯誤,系統顯示 "Records can't be read; no read permission on table SESSION".(記錄不能讀, 表單不允許讀)

)首先我假設access資料庫有一個預設的使用者為"admin",可以這樣完成"ODBC;UID=admin". 然後,當你繼承CRecordset類時你就不必帶參數打開,但下面的方法可能更好些:

Open(CRecordset::dynaset, NULL,CRecordset::useBookmarks | CRecordset::skipDeletedRecords)

  當然你必須提供DSN表示連接配接名字的資料庫在ODBC之下.

(79)怪異的字型

我們有一個MFC應用程式,主視窗是在客戶區域内畫些文本和圖形. 我們希望能在客戶區域内顯示文本,在不需要時則擦除.是以我們先得到一個DC(CClientDC), 然後設定字型和文本顔色就開始寫文本,在擦除時,我們用同樣的字型,同樣的地方用背景色重寫文本.

  這種方法絕大部分情況下都工作得很好,但偶爾文本并不能完全擦除,有些像素點依然可見. 好象在寫文本時比通常略微胖了些,就象用粗體一樣.字型是在寫文本時使用的,以後也沒有進行過任何的調整. 下面是我們使用的寫與擦除的函數.

void CSign::DrawSignName(CDC* pDC)

{

int OldBkMode;

// select the appropriate font

CFont* pOldFont = (CFont*) pDC->SelectObject(pSignNameFont);

OldBkMode = pDC->SetBkMode(TRANSPARENT);

// determine the colour of the text

if (IsSignNameVisible())

  pDC->SetTextColor(aColours[SIGN_NAME_COLOUR]);

else

  pDC->SetTextColor(aColours[DEVICE_INVISIBLE_COLOUR]);

// draw the text

pDC->TextOut(m_pointNameCoords.x, m_pointNameCoords.y, m_strName);

// restore the previously used font and background mode

pDC->SelectObject(pOldFont);

pDC->SetBkMode(OldBkMode);

} // DrawSignName

  函數是在消息句柄中調用的,而參數中的DC是這樣建立的:

CClientDC dc(AfxGetMainWnd()).

  字型是在程式初始化時建立的:

pSignNameFont = new CFont;

pSignNameFont->CreateFont(10,5,0,0,150,

       FALSE,FALSE,0,

       ANSI_CHARSET, OUT_DEFAULT_PRECIS,

       CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,

       DEFAULT_PITCH | FF_SWISS, "Helvetica");

  是不是一次使用兩個指向同一個客戶視窗的DC有問題?程式中的DrawSignName()被多個消息句柄調用。

1)加入以下代碼:

{

m_strName.Empty();

Invalidate();

UpdateWindow();

more stuff;;;

}

  上面代碼會産生一個WM_ERASEBKGND消息,将會用背景色填滿視窗,然後再調用OnDraw(),這時隻要将字元串置空即可。

2)我不清楚為什麼程式不能正常工作,但我有個主意(它會更快些)可以在顯示文本的地方用一個背景色的矩形畫一下即可。我也不清楚為什麼你們為什麼要用透明文本,它将會給圖形系統帶來大量的工作。字型之是以有這種情況,是否你們安裝了文本輸出的圖形保真軟體?它會給你們帶來困惑的。

3)你隻想簡單的用一個指針來儲存一個指向DC的GDI對象,并試圖再次調用它時期望它能指向正确的對象。恕我直言,這不是正确的方法(我不知道是否這是顯示不正常的唯一原因)将它轉化為一個Windows句柄才是正确的:

//

// Creating:

//

pSignNameFont = new CFont;

pSignNameFont->CreateFont(10,5,0,0,150,

        FALSE,FALSE,0,

        ANSI_CHARSET, OUT_DEFAULT_PRECIS,

        CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,

        DEFAULT_PITCH | FF_SWISS, "Helvetica");

// Now converting into a windows handle

m_hSNFont = (HFONT) pSignNameFont->GetSafeHandle();

  直接儲存一個對象是不安全的。

(80)自畫清單框樣例

很久以前,有人散發關于自畫清單框控件代碼,而自畫清單框外觀就象一個标準清單框,在那時我就有個想法想把程式員開發的所有自畫控件的代碼懼收集起來,這樣程式員們就可以使用現存的代碼了。

我想問一下在1996年關于MFC站點那兒有才能關于清單框或其它控件的代碼?

1)自畫清單框代碼如下,看看是不是你所想要的。

Header file

class CCustomListBox : public CListBox

{

public:

// Operations

    DECLARE_DYNCREATE(CCustomListBox)

    int AddLBItem(LPSTR);

    void HandleSelectionState(LPDRAWITEMSTRUCT lpdis);

    void HandleFocusState(LPDRAWITEMSTRUCT lpdis);

    virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);

};

cpp file

IMPLEMENT_DYNCREATE(CCustomListBox, CListBox)

int CCustomListBox::AddLBItem(LPSTR itemStr)

{

    AddString((LPCSTR)itemStr);

    return 0;

}

void CCustomListBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)

{

    CDC* pDC = CDC::FromHandle(lpDIS->hDC);

    if ((lpDIS->itemState & ODS_SELECTED) &&

        (lpDIS->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)))

    {

        pDC->InvertRect(&lpDIS->rcItem);

        pDC->DrawFocusRect(&lpDIS->rcItem);

    }

    if (!(lpDIS->itemState & ODS_SELECTED) &&

        (lpDIS->itemAction & ODA_SELECT))

    {

        pDC->InvertRect(&lpDIS->rcItem);

        pDC->DrawFocusRect(&lpDIS->rcItem);

    }

}

void CCustomListBox::HandleSelectionState(LPDRAWITEMSTRUCT lpdis)

{

// Ordinarily could check for "if (lpdis->itemState & ODS_SELECTED)"

// and do drawing for selected state, "else" draw non-selected state.

// But second call to InvertRect restores rectangle to original

// state, so will just call function whether selected or unselected.

    ::InvertRect (lpdis->hDC, (LPRECT)&lpdis->rcItem);

}

void CCustomListBox::HandleFocusState(LPDRAWITEMSTRUCT lpdis)

{

// Ordinarily would check for "if (lpdis->itemState & ODS_FOCUS)"

// and do drawing for focus state, "else" draw non-focus state.

// But second call to DrawFocusRect restores rectangle to original

// state, so will just call function whether focus or non-focus.

// New to Windows 3.0, this function draws a black dashed-rect

// border on the border of the specified rectangle

    ::DrawFocusRect( lpdis->hDC, (LPRECT) &lpdis->rcItem );

}

2)http://toronto.planeteer.com/~zalmoxe/

(81)CWnd::GetMenu()的問題

我有個程式用下面代碼:

    CWnd *pWnd = CWnd::GeForegroundWindow();

    if (pWnd == NULL) return FALSE;

    CMenu *pMenu = pWnd->GetMenu();

    if (pMenu == NULL) return FALSE;

    for (int i = 0; i < pMenu->GetMenuItemCount; i++) {

      pMenu->GetMenuItemID(...);

      pMenu->GetMenuString(...);

    }

  上述代碼工作除了在IE視窗外,别的視窗工作都很正常,請問怎樣才能在IE視窗中正常使用,如果不是用這種方法,那又該用什麼方法?

IE有一個定義菜單,是用自定義系列控件中的彈出菜單。是以你就不能再使用枚舉這種方法了,試一下處理WM_INITMENUPOPUP或WM_INITMENU。在VC的CD中有類似的例子(關于剪切與複制)你得到消息句柄時就可以列出所有的菜單項。上面的代碼之所不工作可能是因為微軟的自畫菜單項的儲存菜單項用了不同的格式,想要明白菜單和畫标是否是自畫的,你可以用這種方法測試lpmii->fType & MFT_OWNERDRAW.Ipmii是一個菜單結構,傳回得到的菜單項資訊。lpmii->dwTypeData 傳回(菜單)項目的類型,如果dwTypeData傳回的值沒有什麼用的話還有一個機會,lpmii->dwItemData将指向一個(程式)開始時的菜單項中的字元串結構。以上方法比較好,因為現在好多程式都使用自定義菜單。

(82)用MFC制作彈出視窗

我正在試着用MFC來制作彈出視窗,我看過一些關于建立彈出視窗的文章,它們是使用 CWnd對象的。但在文檔,視窗結構中是怎樣實作的?

你可以建立一個非模态對話框(使用Create函數),你可以在任何建立視窗,子視窗等。如果你一定要在文檔、視窗結構中實作,你也可以用CCreateContest類。下面是建立MDI視窗的例子:

{

    LPCTSTR lpszClassName = NULL;

    CCreateContext cContext;

    cContext.m_pNewViewClass = RUNTIME_CLASS ( CMyView )

    DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW &

~WS_THICKFRAME & ~WS_MAXIMIZEBOX;

    // TOD Add your specialized code here and/or call the base class

    if ( CMDIChildWnd::Create(lpszClassName, lpszWindowName, dwStyle,

pParentWnd->rectDefault, pParentWnd, &cContext) )

    {

        InitialUpdateFrame ( NULL, TRUE );

        CScrollView *pView = ( CScrollView* ) GetActiveView();

        if ( pView )

            pView->ResizeParentToFit ( FALSE );

        return TRUE;

    }

    else

        return FALSE;

}

  CCreateContext有一個成員為m_pCurrentDoc,你可以用它來将一個文檔配置設定到相應的視窗上.

(83)怎樣取消一個彈出式菜單

我有一個應用程式不顯示視窗(建立視窗時使用了SW_HIDE參數),它隻在任務條顯示一個圖示,我是這樣做的:

        NOTIFYICONDATA tnid;

        tnid.cbSize = sizeof(NOTIFYICONDATA);

        tnid.hWnd = m_hWnd;

        tnid.uID = 1;

        tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;

        tnid.uCallbackMessage = MYWM_NOTIFYICON;

        tnid.hIcon = AfxGetApp()->LoadIcon( IDI_ICON1 );

        lstrcpyn(tnid.szTip, "Giroimag Image Mail Exchange", strlen("Giroimag Image Mail Exchange")+1);

        Shell_NotifyIcon(NIM_ADD, &tnid);

  當我點選任務條時,程式會顯示一個彈出菜單:

        CMenu m_Menu;

        m_Menu.CreatePopupMenu();

        m_Menu.AppendMenu( MF_STRING, IDM_ABOUT, "Op&1" );

        m_Menu.AppendMenu( MF_SEPARATOR, 0 );

        m_Menu.AppendMenu( MF_STRING, IDM_CONFIG, "Op&2" );

        m_Menu.AppendMenu( MF_STRING, IDM_STATUS, ""Op&3" );

        m_Menu.AppendMenu( MF_SEPARATOR, 0 );

        m_Menu.AppendMenu( MF_STRING, IDM_SEND, "Op&4" );

        m_Menu.AppendMenu( MF_STRING, IDM_RECEIVE, "Op&5" );

        m_Menu.AppendMenu( MF_SEPARATOR, 0 );

        m_Menu.AppendMenu( MF_STRING, IDM_CLOSE, "Op&6" );

        POINT p;

        GetCursorPos( & p );

        m_Menu.TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, this );

  到這為止,程式運作很正常,問題在于如果我不選擇任何菜單該怎樣取消它?我以為按ESC或者在菜單外面點選就可以取消,但事實并不是這樣。我也試過用WIN32API中的TrackPopupMenuEx函數但沒有用,到底我該怎麼做?

1)最簡單的方法在消息映象中加"Cancel Menu"指令即可。

2)盡管你的主視窗不可見,但在你可以在調用m_Menu.TrackPopupMenu();時将其置為最前。

3)在你彈出菜單之前,設定你的視窗為最前視窗,調用下面的代碼,問題就會迎刃而解。

POINT p;

GetCursorPos( & p );

// Increase the thread priority by invoking SetForegroundWindow.

SetForegroundWindow();

m_Menu.TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, p.x, p.y, this );

  4)調用TrackPopupMenu()之前,你必須先調用SetForegroundWindow( m_hWnd ),然後調用PostMessage( m_hWnd, WM_NULL, 0, 0 ):

         POINT point;

         GetCursorPos( &point );

         SetForegroundWindow( m_hWnd );

         TrackPopupMenu( hPopup,

            TPM_RIGHTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,

            point.x,

            point.y,

            0,

            m_hWnd, 0 );

         PostMessage( m_hWnd, WM_NULL, 0, 0 );