程序員筆記: 利用memory dc解決畫面閃爍問題

程序員筆記: 利用memory dc解決畫面閃爍問題: "重繪時要避免畫面閃爍可以使用Invalidate(FALSE); 使重繪時不做清除底圖的動作,減少閃爍的情況,"

程序員筆記: 如何獲得GetLastError()的文字訊息

程序員筆記: 如何獲得GetLastError()的文字訊息: "在撰寫軟體時常常會接獲錯誤訊息,或在操作某些動作時發現錯誤, 也經常利用::GetLastError();這支Windows API來獲取錯誤代碼, 但是這支API回報的是DWORD型態,想知道得更詳細往往要再上網搜尋一番, 當然也有方法可以取得文字訊息,簡單的範例如下。"

from: http://ascii-iicsa.blogspot.com/2010/09/getlasterror.html

[Win]_msize()使用注意

在windows底下,對於使用mallocate出來的記憶體區塊,無法使用sizeof()來取得實際的buffer size。
因為sizeof()取得到的是pointer的size。

因此有一個_msize()的函式可以針對mallocate出來的記憶體區塊來取得其空間位置。

目前使用時,_msize()除了可使用於mallcate的記憶體區塊,也可以使用在以char szbuf[]方式產生的記憶體區塊。

目前測試在大部分的XP 32/x64, Vista x64, Win7 x64, server 2008 x64都可正常運行。
但目前發現在某些Win7 x64底下會發生crash事件,原因目前不明。

所以如有需要知道用 char[]宣告方式之buffer size,還是使用sizeof()比較安全。
_msize()還是盡量用在malloc()產生的記憶體區塊。

[MFC]在Picture Control內塞入系統圖示

先在介面拉一個Picture Control並將Type設為Icon。

在程式內則需這樣設定即可:
 this->m_icoPicType.SetIcon(::LoadIcon(NULL, IDI_INFORMATION));  

變更滑鼠指標圖示

在網路上找了很多改變滑鼠指標圖示資料,但目前測試只有這個有成功,至於目前有沒有什麼後遺症,我也不曉得XDDD
 HCURSOR hcur = ::LoadCursor(0, IDC_ARROW);  
::SetClassLong(this->m_hWnd, GCL_HCURSOR, (LONG)hcur);  


來源:http://kevincg.wordpress.com/category/vccc/page/2/

2010/12/28 - 補充
出現問題:在第一個Dialog使用後,如不設回預設的滑鼠指標圖示,當彈出的第二個Dialog上面也有相同物件出現時,則當滑鼠移到第二個Dialog的物件上時,也會顯示原先設定的滑鼠指標圖示。

所以要切換dialog的話,還是把滑鼠指標設回原本設定,比較不會有顯示問題。

問題點我想應該是SetClassLong()所造成的。

[CListCtrl]顯示單個儲存格之Tip

一樣內容也是臨時找的,並沒有整理,一定會雷同。

這邊需自行處理訊息,所以要加入兩個訊息
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
    ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)

然後也需要改寫CListCtrl::OnToolHitTest(),裡面是用來設定UID,用途目前不明,但缺少的話,tip會閃一下就消失了。
 int CXListCtrl::OnToolHitTest(CPoint point, TOOLINFO * pTI) const   
{  
//See if the point falls onto a list item  
//UINT nFlags = 0;  
LVHITTESTINFO lvhitTestInfo;  
lvhitTestInfo.pt    = point;  
int nItem = ListView_SubItemHitTest(  
this->m_hWnd,  
&lvhitTestInfo);  
int nSubItem = lvhitTestInfo.iSubItem;  
UINT nFlags =  lvhitTestInfo.flags;  
//nFlags is 0 if the SubItemHitTest fails  
//Therefore, 0 & <anything> will equal false  
if (nFlags & m_wHistMask){  
//If it did fall on a list item,  
//and it was also hit one of the  
//item specific sub-areas we wish to show tool tips for  
//Get the client (area occupied by this control  
RECT rcClient;  
GetClientRect( &rcClient );  
//Fill in the TOOLINFO structure  
pTI->hwnd = m_hWnd;  
pTI->uId = (UINT) (nItem * 100 + nSubItem);  
pTI->lpszText = LPSTR_TEXTCALLBACK;  
pTI->rect = rcClient;  
return pTI->uId; //By returning a unique value per listItem,  
//we ensure that when the mouse moves over another list item,  
//the tooltip will change  
}else{  
//Otherwise, we aren't interested, so let the message propagate  
return -1;  
}  
}  

再來就是上面自己定義的Function,tip所要顯示的文字就在這這裡面設定:
 BOOL CXListCtrl::OnToolTipText(UINT id, NMHDR* pNMHDR, LRESULT* pResult)  
{  
//Handle both ANSI and UNICODE versions of the message  
TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;  
TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;  
//Ignore messages from the built in tooltip, we are processing them internally  
if( (pNMHDR->idFrom == (UINT)m_hWnd) &&  
( ((pNMHDR->code == TTN_NEEDTEXTA) && (pTTTA->uFlags & 
TTF_IDISHWND)) ||  
      ((pNMHDR->code == TTN_NEEDTEXTW) && (pTTTW->uFlags & TTF_IDISHWND)) ) ){  
return FALSE;  
}  
*pResult = 0;  
CString strTipText;  
//Get the mouse position  
const MSG* pMessage;  
pMessage = GetCurrentMessage();  
ASSERT ( pMessage );  
CPoint pt;  
pt = pMessage->pt; //Get the point from the message  
ScreenToClient( &pt ); //Convert the point's coords to be relative to this control  
//See if the point falls onto a list item  
LVHITTESTINFO lvhitTestInfo;  
lvhitTestInfo.pt    = pt;  
int nItem = SubItemHitTest(&lvhitTestInfo);  
int nSubItem = lvhitTestInfo.iSubItem;  
UINT nFlags =  lvhitTestInfo.flags;  
//nFlags is 0 if the SubItemHitTest fails  
//Therefore, 0 & <anything> will equal false  
if( nFlags & m_wHistMask ){  
//If it did fall on a list item,  
//and it was also hit one of the  
//item specific sub-areas we wish to show tool tips for  
//Lookup the list item's text in the ToolTip Map  
CString strKey;  
strKey.Format(_T("%d"), nItem * 100 + nSubItem);  
if( m_ToolTipMap.Lookup(strKey, strTipText ) ){  
//If there was a CString associated with the list item,  
//copy it's text (up to 80 characters worth, limitation of the TOOLTIPTEXT structure)  
//into the TOOLTIPTEXT structure's szText member  
//Deal with UNICODE  
#ifndef _UNICODE  
if (pNMHDR->code == TTN_NEEDTEXTA)  
//lstrcpyn(pTTTA->szText, strTipText, 80);  
lstrcpyn(pTTTA->szText, "AAA", 80);  
else  
//_mbstowcsz(pTTTW->szText, strTipText, 80);  
_mbstowcsz(pTTTW->szText, "Double Click Me", 80);  
#else  
if (pNMHDR->code == TTN_NEEDTEXTA)  
_wcstombsz(pTTTA->szText, strTipText, 80);  
else  
lstrcpyn(pTTTW->szText, strTipText, 80);  
#endif  
return FALSE;  //We found a tool tip,  
//tell the framework this message has been handled  
////////////////////////////////////////////////////////////////////////////////  
// ****** Special note *****  
//  
// Still don't understand why the function must return FALSE for CListCtrl  
// so as not to cause flickering, as opposed to Nate Maynard's derivation  
// from CTreeCtrl.  
// I have experimented with disabling Tooltips for the control  
// and found out that a "ghost" tooltip appears for a fraction of a second...  
//  
// I am completely at a loss...  
// Seems to work, though...  
//  
////////////////////////////////////////////////////////////////////////////////  
}  
}  
return FALSE; //We didn't handle the message,  
}  

Reference:Handling TTN_NEEDTEXT Notification for Tool Tips

[CListCtrl]改變儲存格文字顏色

資料也是在網路上找來的,只是急著測試,就沒有記住來源了。所以一定會有雷同,找時間在把內容整理過嚕@@

需要用到NM_CUSTOMDRAW訊息,這要放在Dialog的message map內:
ON_NOTIFY(NM_CUSTOMDRAW, IDC_LIST, &CXListCtrl::OnNMCustomdrawLst)

因此要改寫CListCtrl::OnNMCustomdrawLst()
 void CXListCtrl::OnNMCustomdrawLst(NMHDR *pNMHDR, LRESULT *pResult)  
{  
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);  
NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);  
// TODO: Add your control notification handler code here  
*pResult = 0;  
if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )  
{  
*pResult = CDRF_NOTIFYITEMDRAW;  
}else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage ) {  
//  // This is the prepaint stage for an item. Here's where we set the  
//  // item's text color. Our return value will tell Windows to draw the  
//  // item itself, but it will use the new color we set here.  
//  // We'll cycle the colors through red, green, and light blue.  
*pResult = CDRF_NOTIFYSUBITEMDRAW;        //To Draw sub item request  
} else if ( (CDDS_ITEMPREPAINT | CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage ) {  
// This is the prepaint stage for a subitem. Here's where we set the  
// item's text and background colors. Our return value will tell   
// Windows to draw the subitem itself, but it will use the new colors  
// we set here.  
// The text color will cycle through red, green, and light blue.  
// The background color will be light blue for column 0, red for  
// column 1, and black for column 2.  
COLORREF crText, crBkgnd;  
//                Sub Item Index                                    Item Index  
if ( (3 == pLVCD->iSubItem && pLVCD->nmcd.dwItemSpec == 1) ||  
(3 == pLVCD->iSubItem && pLVCD->nmcd.dwItemSpec == 3) )  
{  
crText = RGB(255,0,0);  
//crBkgnd = RGB(128,128,255);  
}  
else if ( 1 == pLVCD->iSubItem )  
{  
crText = RGB(0,255,0);  
crBkgnd = RGB(255,0,0);  
}  
else  
{  
crText = RGB(128,128,255);  
crBkgnd = RGB(0,0,0);  
}  
// Store the colors back in the NMLVCUSTOMDRAW struct.  
pLVCD->clrText = crText;  
//pLVCD->clrTextBk = crBkgnd; 
// Tell Windows to paint the control itself.  
//*pResult = CDRF_DODEFAULT;  
*pResult = CDRF_NOTIFYPOSTPAINT|CDRF_NOTIFYSUBITEMDRAW;  
}  
}  

[CListCtrl]在滑鼠指標移過儲存格上方後,顯示底線

目前算只完成一半,因為字跟欄位有個距離,目前還沒辦法動態取得。
ON_WM_MOUSEMOVE()

一樣也是在CListCtrl::OnMouseMove()內處理。
     CRect rect1, rectParent; 
this->GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect1);   
this->GetWindowRect(&rectParent);   
CString cstrDisplayString =    this->GetItemText(nItem, nSubItem);   
int nStrWidth = this->GetStringWidth(cstrDisplayString);   
unsigned int nCurNumOfWorkArea = this->GetNumberOfWorkAreas();  
if ( point.x < rect1.right && point.x > rect1.left && point.y < rect1.bottom && point.y > rect1.top )       
{   
//Clean previous line   
if ( !this->m_PreRect.IsRectEmpty() )   
{   
CDC *pcdc = this->GetDC();   
CPen cp(PS_SOLID, 1, RGB(255,255,255));   
pcdc->SelectObject(cp.m_hObject);   
pcdc->MoveTo(this->m_PreRect.left, this->m_PreRect.bottom);   
pcdc->LineTo(this->m_PreRect.right, this->m_PreRect.bottom);   
this->m_PreRect.SetRectEmpty();   
}   
//Draw line   
CDC *pcdc = this->GetDC();   
CPen cp(PS_SOLID, 1, RGB(255,0,0));   
pcdc->SelectObject(cp.m_hObject);   
pcdc->MoveTo(rect1.left, rect1.bottom);  
pcdc->LineTo((rect1.left + nStrWidth), rect1.bottom);   
this->m_PreRect.SetRect(rect1.left, rect1.top, (rect1.left+nStrWidth), rect1.bottom);   
}else {  
         CDC *pcdc = this->GetDC();   
CPen cp(PS_SOLID, 1, RGB(255,255,255));   
pcdc->SelectObject(cp.m_hObject);   
pcdc->MoveTo(this->m_PreRect.left, this->m_PreRect.bottom);   
pcdc->LineTo(this->m_PreRect.right, this->m_PreRect.bottom);   
this->m_PreRect.SetRectEmpty();   
} 

this->ReleaseDC(pcdc);

[CListCtrl]取得目前滑鼠所在位置的儲存格座標

目前是應用在CListCtrl::OnMouseMove()裡,用來取得目前滑鼠所在位置。

     const MSG* pMsg = this->GetCurrentMessage();  
if ( pMsg == NULL ) {
return; };
CPoint ptMsg = pMsg->pt; //Get point from the message
this->ScreenToClient(&ptMsg); //Convert the point's coords to be relative to this control
LVHITTESTINFO lvItemInfo;
lvItemInfo.pt = ptMsg;
int nItem = this->SubItemHitTest(&lvItemInfo); //Row Index - 0 base
int nSubItem = 3;//lvItemInfo.iSubItem; //Col Index - 0 base

[VS]add/remove operation is impossible because the code element is read only

上google找一下,解決方法很簡單。
目前是在專案關閉的狀況下,把*.ncb刪除後就恢復正常了。

Build docker image from multiple build contexts

Build docker image from multiple build contexts ...