[WIN]變更程式執行優先順序

如有需要變更執行檔的執行優先順序,可呼叫SetPriorityClass Function()來達成需求。

第一個參數是目前程序的HANDLE,第二個參數則為要設定的順序參數。

目前測試結果是有效~~XDD

[C++]在Class內宣告靜態float常數

一般對compiler而言,要宣告class內的靜態常數,只能宣告成int的形態。

如果要宣告成
 static const float STATIC_FLOAT = 1.F;  

則Compiler會出現「a member of type "const float" cannot have a in-class initializer」

因此,如想要在class內宣告靜態的float,則需先在class內宣告個靜態的float,但不給予值。並在*.cpp給定此常數值即可:

*.h
 class CTestClass  
 {  
  static cosnt float STATIC_FLOAT;  
  ...  
  ...  
 }  

*.cpp
 const flaot CTestClass::STATIC_FLOAT = 1.F;  

參考連結:static const float in C++. why not?

[CListCtrl]欄位顯示多行文字

由於MFC提供的CListCtrl並無輸入多行文字功能,因此也需要從繪圖的部分下手。
由於ClistCtrl一次也只能顯示一行文字,因此在進行顯示多行文字之前,需先讓CListCtrl的欄位可以隨著文字段數變動。這邊可以參考[CListCtrl]改變行高 。(參考文獻在上述連結內都有)

在顯示多行文字部分,則是透過改寫DrawItem()來讓文字可以斷行。

使用前,需先將CListCtrl的Owner Draw Fixed屬性打開(坊間流傳的SetExtendedStyle(LVS_OWNERDRAWFIXED)並無效果)。(PS.在這邊浪費了好幾個小時@@,果然跑不起來還是要先查設定@@)

在.h部分
 afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);  

在.cpp部分
 void CXListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)   
 {  
     TCHAR lpBuffer[256];  
     LV_ITEM lvi;  
     lvi.mask = LVIF_TEXT | LVIF_PARAM ;  
     lvi.iItem = lpDrawItemStruct->itemID ;       
     lvi.iSubItem = 0;  
     lvi.pszText = lpBuffer ;  
     lvi.cchTextMax = sizeof(lpBuffer);  
     VERIFY(GetItem(&lvi));  
     LV_COLUMN lvc, lvcprev ;  
     ::ZeroMemory(&lvc, sizeof(lvc));  
     ::ZeroMemory(&lvcprev, sizeof(lvcprev));  
     lvc.mask = LVCF_WIDTH | LVCF_FMT;  
     lvcprev.mask = LVCF_WIDTH | LVCF_FMT;  
     for ( int nCol=0; GetColumn(nCol, &lvc); nCol++)  
     {  
         if ( nCol > 0 )   
         {  
             // Get Previous Column Width in order to move the next display item  
             GetColumn(nCol-1, &lvcprev) ;  
             lpDrawItemStruct->rcItem.left += lvcprev.cx ;  
             lpDrawItemStruct->rcItem.right += lpDrawItemStruct->rcItem.left ;      
         }

         // Get the text   
         ::ZeroMemory(&lvi, sizeof(lvi));  
         lvi.iItem = lpDrawItemStruct->itemID;  
         lvi.mask = LVIF_TEXT | LVIF_PARAM;  
         lvi.iSubItem = nCol;  
         lvi.pszText = lpBuffer;  
         lvi.cchTextMax = sizeof(lpBuffer);  
         VERIFY(GetItem(&lvi));  
         CDC* pDC;  
         pDC = CDC::FromHandle(lpDrawItemStruct->hDC);  
 //--------------- Full selection - highlight -----------------------  
         if ( lpDrawItemStruct->itemState & ODS_SELECTED )  
         {  
             pDC->FillSolidRect(&lpDrawItemStruct->rcItem, GetSysColor(COLOR_HIGHLIGHT)) ;   
             pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)) ;  
         }  
         else  
         {  
             pDC->FillSolidRect(&lpDrawItemStruct->rcItem, GetSysColor(COLOR_WINDOW)) ;  
             pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT)) ;   
         }  
 //--------------- Full selection - highlight -----------------------  
         pDC->SelectObject(GetStockObject(DEFAULT_GUI_FONT));  
         UINT        uFormat  = DT_LEFT ;  
         ::DrawText(lpDrawItemStruct->hDC, lpBuffer, strlen(lpBuffer),   
              &lpDrawItemStruct->rcItem, uFormat) ;  
         pDC->SelectStockObject(SYSTEM_FONT) ;  
 //Enable measureitem().  
         this->OnSetFont(NULL, NULL);  //配合MeasureItem()用的        
     }  
 }  

目前這個範例裡面還看不出是怎麼讓文字斷行的,但可確定的是,由於這個function會重新變更欄位的字體與背景顏色。因此當同時還有使用到OnNMCustomdrawLst()的話,OnNMCustomdrawLst()所繪製的顏色會被DrawItem()所覆蓋掉(因OnNMCustomdrawLst()比DrawItem()早執行),所以這邊要注意。
如有找到換行的方法,之後再補上。
PS.測試結果,DrawText似乎會在遇到newline時,就會把後面的文字自動輸出到下一行。

Problem:
1.在移動欄位title時,欄位內顯示之文字並不會像CListCtrl一樣,會加上"..."來代表有文字被遮蓋。
看來這邊是需要自行處理。(變更欄位大小時,畫面不會更新到其他地方)
2.上一次顯示文字之尾端總是會殘留在下一個欄位的開頭,這邊也需要另外再處理。
3.此範例所繪製的文字會貼齊於Cell的最左側邊界,會與CListCtrl顯示結果不同。

新找到的:Multi-line List Control
這篇提供的方法可以解決P.1、P.2、P3的問題。
差別在於,這篇提供的畫文字方法是CDC::DrawTextEx。這樣就可以讓CListCtrl自行去處理上述之問題,不然要手動處理的話,倒是挺麻煩的。如此一來,函式也變得比較乾淨了。

修改過後的函式如下:
 void CXListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)   
 {  
     LPDRAWITEMSTRUCT lpDrawHighLight = new DRAWITEMSTRUCT();  
     CString cstrSubitemText = "";  
     CRect rcSubItemRect;          
     CDC* pDC =     CDC::FromHandle(lpDrawItemStruct->hDC);        //不用釋放  
     LV_ITEM lvi;  
     rcSubItemRect.SetRectEmpty();  
     LV_COLUMN lvc, lvcprev ;  
     ::ZeroMemory(&lvc, sizeof(lvc));  
     ::ZeroMemory(&lvcprev, sizeof(lvcprev));  
     lvc.mask = LVCF_WIDTH | LVCF_FMT;  
     lvcprev.mask = LVCF_WIDTH | LVCF_FMT;  
     //lpDrawItemStruct->rcItem為目前所要畫出文字的row的邊界。  
     for ( int nCol=0; GetColumn(nCol, &lvc); nCol++)  
     {  
         // Get Previous Column Width in order to move the next display item  
         if ( nCol > 0 )   
         {              
             GetColumn(nCol-1, &lvcprev) ;  
             lpDrawItemStruct->rcItem.left += lvcprev.cx;  
             //lpDrawItemStruct->rcItem.right += lpDrawItemStruct->rcItem.left;            //會影響到最後一個SubItem的顯示長度。  
         }  
 //--------------- Full selection - highlight -----------------------  
         //Let Drawed highlight like the CListCtrl do it.  
         ::memcpy(lpDrawHighLight, lpDrawItemStruct, sizeof(DRAWITEMSTRUCT));  
         lpDrawHighLight->rcItem.left += this->GetStringWidth(" ");        //保留開頭的空白。讓行為同CListCtrl。  
         if ( lpDrawItemStruct->itemState & ODS_SELECTED )  
         {  
             pDC->FillSolidRect(&lpDrawHighLight->rcItem, GetSysColor(COLOR_HIGHLIGHT)) ;   
             pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)) ;  
         }  
         else  
         {  
             pDC->FillSolidRect(&lpDrawHighLight->rcItem, GetSysColor(COLOR_WINDOW)) ;  
             pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT)) ;   
         }  
 //--------------- Full selection - highlight -----------------------  
 //-------------- Draw item -------------------------  
         pDC->SelectObject(GetStockObject(DEFAULT_GUI_FONT));  
         if ( !this->GetSubItemRect(lpDrawItemStruct->itemID, nCol, LVIR_BOUNDS, rcSubItemRect) ) {  
             continue;    };  
         //::DrawText(lpDrawItemStruct->hDC, lpDisplayBuf, nShowWordsLen, &lpDrawText->rcItem, uFormat) ;  
         rcSubItemRect.left += this->GetStringWidth(" ");  
         rcSubItemRect.right -= this->GetStringWidth(" ");  
         cstrSubitemText = this->GetItemText(lpDrawItemStruct->itemID, nCol);  
         pDC->DrawTextEx(cstrSubitemText, rcSubItemRect, (DT_LEFT|DT_NOPREFIX|DT_TOP|DT_WORD_ELLIPSIS), NULL);  
         pDC->SelectStockObject(SYSTEM_FONT) ;  
 //-------------- Draw item -------------------------  
 //Enable measureitem().  
         this->OnSetFont(NULL, NULL);          
     }    //End of for ( int nCol=0; GetColumn(nCol, &lvc); nCol++)  
     if ( lpDrawHighLight != NULL )    {  
         delete lpDrawHighLight;  
         lpDrawHighLight = NULL;  
     }  
 }  

[CListCtrl]改變行高

由於MFC裡的CListCtrl並無提供改變行高的函式,因此就需要透過改變繪圖方式,來達到改變行高的效果。

這邊找到的參考資料如下:
1.Report control - with category
2.Changing Row Height in an owner drawn Control
3.CListCtrl 行高问题最终解决方法

裡面提到的方式都是使用OnSetFont()以及MeasureItem()來搭配使用。

另一種就是直接在OnNMCustomdrawLst()裡面,進行文字繪製。
Expandable List Control to Accept Multilines

OnNMCustomdrawLst()使用方式可參考[CListCtrl]改變儲存格文字顏色

由於使用OnNMCustomdrawLst()的方式比較複雜,所以底下就針對DrawItem()以及MeasureItem()兩個函式來說明。

在.h的部份:(SetFont()的部分稍後說明)
 void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) ;  
 afx_msg LRESULT    OnSetFont(WPARAM wParam, LPARAM lParam);  
 afx_msg void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);  

在message map部分:(無效的部份稍後說明)
 BEGIN_MESSAGE_MAP(CXListCtrl, CListCtrl)  
 //Multi-line  
     ON_MESSAGE(WM_SETFONT, OnSetFont)    //NOTE:無效  
     ON_WM_MEASUREITEM_REFLECT()        //NOTE:無效  
     ON_WM_MEASUREITEM()                //NOTE:無效  
 END_MESSAGE_MAP()  

在.cpp裡面要加上下列4個函式:
1.OnMeasureItem()
 void CXListCtrl::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)   
 {  
   CListCtrl::OnMeasureItem(nIDCtl, lpMeasureItemStruct);  
 }  

這邊為何要又呼叫一次CListCtrl::OnMeasureItem我就不曉得原因了,因上面參考連結是有這項。但程式卻都沒進入到此函式。所以不加應該也沒關係吧?!XD

2.MeasureItem()
 void CXListCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)   
 {  
     // Get the LOGFONT for the current font.  
     LOGFONT lf;  
     ::ZeroMemory(&lf, sizeof(lf));  
     CFont* pFont = GetFont();  
     ASSERT_VALID(pFont);  
     if (pFont)   
         VERIFY(pFont->GetLogFont(&lf));  
     int nAdj(2) ;        //Sample is 4  
     m_nLinesPerRow = max(m_nLinesPerRow, 1);  
     if (lf.lfHeight < 0)   
         lpMeasureItemStruct->itemHeight = ((-lf.lfHeight+nAdj) * (m_nLinesPerRow));  
     else   
         lpMeasureItemStruct->itemHeight = ((lf.lfHeight+nAdj) * (m_nLinesPerRow));  
 }  

這邊實際上用來變更高度的是lpMeasureItemStruct->itemHeight,但由於抓到的並不是完整的文字高度,單行沒問題,三行以上就出錯了。所以在範例的部份,有加上平移值。這邊測試結果,如果平移值與顯示行數差值大於等於2時,最後一行文字就會被蓋掉。所以這個值還是要做動態的會比較好。
如有需要做到每行高度不同的話,後面乘上的顯示行數就需要針對顯示文字的行是做動態處理。
目前還沒想到好作法,之後再回來補充。

3.OnSetFont()
 LRESULT CXListCtrl::OnSetFont(WPARAM wParam, LPARAM lParam)  
 {  
     CRect rc;  
     GetWindowRect(&rc);  
     WINDOWPOS wp;  
     wp.hwnd = this->m_hWnd;  
     wp.cx = rc.Width() ;  
     wp.cy = rc.Height() ;  
     wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;  
     LRESULT lrReturn(Default());  
     SendMessage(WM_WINDOWPOSCHANGED, 0, reinterpret_cast<LPARAM> (&wp));  
     return lrReturn;  
 }  

在範例裡,這個函式僅是用來觸發MeasureItem()更新動作的一個事件而已。觸發MeasureItem()的事件很獨特,就是讓畫面有所變動,然後系統就會送回重新繪製item的訊息,接下來就會進到MeasureItem()來重新繪製每個item的狀況。
此方法在範例中能成功,但我不管怎麼試,就是試不出來,也找不到原因。最後就在DrawItem()結束後,直接送出視窗訊息。

以上就是改變行高的作法

程序員筆記: 不使用temp變數交換兩個整數

程序員筆記: 不使用temp變數交換兩個整數: "在交換兩個整數時往往需要一個暫存變數,舉例如下。"

程序員筆記: 利用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

Build docker image from multiple build contexts

Build docker image from multiple build contexts ...