程序員筆記: 利用memory dc解決畫面閃爍問題
程序員筆記: 利用memory dc解決畫面閃爍問題: "重繪時要避免畫面閃爍可以使用Invalidate(FALSE); 使重繪時不做清除底圖的動作,減少閃爍的情況,"
程序員筆記: 如何獲得GetLastError()的文字訊息
程序員筆記: 如何獲得GetLastError()的文字訊息: "在撰寫軟體時常常會接獲錯誤訊息,或在操作某些動作時發現錯誤, 也經常利用::GetLastError();這支Windows API來獲取錯誤代碼, 但是這支API回報的是DWORD型態,想知道得更詳細往往要再上網搜尋一番, 當然也有方法可以取得文字訊息,簡單的範例如下。"
from: http://ascii-iicsa.blogspot.com/2010/09/getlasterror.html
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()產生的記憶體區塊。
因為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
來源:http://kevincg.wordpress.com/category/vccc/page/2/
2010/12/28 - 補充
出現問題:在第一個Dialog使用後,如不設回預設的滑鼠指標圖示,當彈出的第二個Dialog上面也有相同物件出現時,則當滑鼠移到第二個Dialog的物件上時,也會顯示原先設定的滑鼠指標圖示。
所以要切換dialog的話,還是把滑鼠指標設回原本設定,比較不會有顯示問題。
問題點我想應該是SetClassLong()所造成的。
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會閃一下就消失了。
再來就是上面自己定義的Function,tip所要顯示的文字就在這這裡面設定:
Reference:Handling TTN_NEEDTEXT Notification for Tool Tips
這邊需自行處理訊息,所以要加入兩個訊息
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()
需要用到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()內處理。
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刪除後就恢復正常了。
目前是在專案關閉的狀況下,把*.ncb刪除後就恢復正常了。
[C]快速判斷字串是否為空字串
寫法很簡單,就像下列寫法:
因為*szStr == szStr[0],且char[]是以NULL-Terminate來判定字串是否結束,所以只要判定陣列的第一個值是不是為零,就可知道是否為空字串。
如需檢查是否為空字串則在指標前面加上NOT operator即可。
相同的方法也可以應用在其他的陣列結尾檢查,例如:
按照Jacob的說法,只要在陣列的結尾塞個0,或是NULL,當迴圈跑到false或是NULL的時候,就會自動結束,這樣也就減少了 n個 if檢查。
if(*szStr)
{
....
}
{
....
}
因為*szStr == szStr[0],且char[]是以NULL-Terminate來判定字串是否結束,所以只要判定陣列的第一個值是不是為零,就可知道是否為空字串。
如需檢查是否為空字串則在指標前面加上NOT operator即可。
相同的方法也可以應用在其他的陣列結尾檢查,例如:
for ( int i = 0 ; arrVar[i] ; i++ )
{
....
}
{
....
}
按照Jacob的說法,只要在陣列的結尾塞個0,或是NULL,當迴圈跑到false或是NULL的時候,就會自動結束,這樣也就減少了 n個 if檢查。
[C++]傳遞Class Member function pointer至其他Class
困擾已久的傳遞Class的Member function到其他class的問題,在今天仔細參詳了半天高手的code以後,終於把之前的疑惑解決了。
原本都知道要用第三個class來處理這問題,但由於一直搞不懂第三個要怎麼做,所以就一直寫不出來。
目前參考的方法是使用一個Base class來當做傳遞Function pointer的介面,然後一個Template class來讓內層使用的class來使用function pointer,也避開兩個互相參照的class的交互參照之問題。
處理方式如下:
Class Processer (底下稱CP)有工作要麻煩 Class Thread (底下稱CT)處理,但是為了讓Main thread不要卡住,所以CT是另外開一個Thread來處理CP要求的工作。
然而當CT在處理工作時如遇到了例外,並無法立即讓CP知道目前的狀況,所以就需要讓CP開個管道(Function Pointer)來讓CT可以在遇到問題時,回來告知CP。
原本是打算用PostMessage()來達成這樣的需求,但是CT所在的dll可能會移植到別的平台上,所以如果使用PostMessage()來做的話,那麼在移植上,還需要去針對不同平台處理。
但是此時的需求只是要把CT遇到的狀況告知給CP,並由CP來告知使用者而已,所以不會造成CT的程序block,所以這邊就採用Class的 callback方式處理。(如果會發生blocking的話,那還是只能用Windows Message的方式處理會比較好處理,不然Thread也是可以。)
底下範例使用
Class CallBackBase:
Template Class:
Class Thread:
Class Process:
Main program:
執行結果:
程式碼亂跑的問題再另外找解@@
原本都知道要用第三個class來處理這問題,但由於一直搞不懂第三個要怎麼做,所以就一直寫不出來。
目前參考的方法是使用一個Base class來當做傳遞Function pointer的介面,然後一個Template class來讓內層使用的class來使用function pointer,也避開兩個互相參照的class的交互參照之問題。
處理方式如下:
Class Processer (底下稱CP)有工作要麻煩 Class Thread (底下稱CT)處理,但是為了讓Main thread不要卡住,所以CT是另外開一個Thread來處理CP要求的工作。
然而當CT在處理工作時如遇到了例外,並無法立即讓CP知道目前的狀況,所以就需要讓CP開個管道(Function Pointer)來讓CT可以在遇到問題時,回來告知CP。
原本是打算用PostMessage()來達成這樣的需求,但是CT所在的dll可能會移植到別的平台上,所以如果使用PostMessage()來做的話,那麼在移植上,還需要去針對不同平台處理。
但是此時的需求只是要把CT遇到的狀況告知給CP,並由CP來告知使用者而已,所以不會造成CT的程序block,所以這邊就採用Class的 callback方式處理。(如果會發生blocking的話,那還是只能用Windows Message的方式處理會比較好處理,不然Thread也是可以。)
底下範例使用
Class CallBackBase:
class CCallBackBase
{
public:
CCallBackBase(){};
~CCallBackBase(){};
virtual bool Execute(void *Param) const = 0;
};
Template Class:
template < class cTarClass >
class CTestCallBack : public CCallBackBase
{
public:
typedef bool (cTarClass::*LPFUNC)(void *Param);
protected:
cTarClass *m_pTarClass;
LPFUNC m_pTarFunc;
public:
CTestCallBack() {
m_pTarClass = NULL;
};
~CTestCallBack() {};
void SetCallBack(cTarClass *cTarClassPtr, LPFUNC pFuncPtr){
m_pTarClass = cTarClassPtr;
m_pTarFunc = pFuncPtr;
};
virtual bool Execute(void *Param) const //Execute的參數要與function pointer一致是因為操作者是使用此介面來使用function pointer
{
if (m_pTarClass)
{
return (m_pTarClass->*m_pTarFunc)(Param);
}else{
::printf("ERROR: The call back funciton is not set!!");
}
return false;
};
};
Class Thread:
class CProcessThread
{
protected:
CCallBackBase *m_pCallBack;
HANDLE m_hThread;
public:
CProcessThread(){
m_pCallBack = NULL;
m_hThread = NULL;
};
~CProcessThread(){
if ( m_hThread != NULL ) {
DWORD dwExitCode = 0;
::TerminateThread(this->m_hThread, dwExitCode);
HANDLE hThread = this->m_hThread;
this->m_hThread = NULL;
::CloseHandle(hThread);
}
};
void StartProcessThread(void)
{
this->m_hThread = CreateThread( NULL, 0, ProcessThread, (LPVOID)this, 0, NULL);
};
void SetCallBack(CCallBackBase *pCallBack){
m_pCallBack = pCallBack;
};
protected:
static DWORD WINAPI ProcessThread(LPVOID lpParam)
{
CProcessThread *pcmxProcessThread = (CProcessThread*) lpParam;
return pcmxProcessThread->ProcessFunc();
};
DWORD ProcessFunc(void)
{
//Set callback data to upper class
m_pCallBack->Execute((void*) "This message is pass from ProcessThread::ProcessFunc() in Thread!!\n");
if ( m_hThread != NULL ) {
DWORD dwExitCode = 0;
::TerminateThread(this->m_hThread, dwExitCode);
HANDLE hThread = this->m_hThread;
this->m_hThread = NULL;
::CloseHandle(hThread);
}
return 0;
};
};
Class Process:
class CProcess
{
protected:
CTestCallBack<CProcess> m_CallBack;
CProcessThread m_ProcessThread;
public:
CProcess() {
m_CallBack.SetCallBack(this, &CProcess::CallBackShower);
m_ProcessThread.SetCallBack(&m_CallBack);
};
~CProcess() {};
void StartProcess(void)
{
m_ProcessThread.StartProcessThread();
};
bool CallBackShower(void *Param)
{
char szMsg[512];
strcpy(szMsg, (char*)Param);
::printf("The Pass message from call back is \nMsg = %s", szMsg);
return true;
};
};
Main program:
int _tmain(int argc, char* argv[])
{
CProcess Process;
Process.StartProcess();
system("pause");
return 0;
}
執行結果:
程式碼亂跑的問題再另外找解@@
[WINAPI]取得磁碟空間
可使用GetDiskFreeSpaceEx()來取得目前可使用的磁碟空間、總磁碟空間以及總剩餘磁碟空間。
使用方式如下:
使用方式如下:
char szDiskDir[MAX_PATH] = "C:\\";
//A pointer to a variable that receives the total number of free bytes on a disk that are available to the user who is associated with the calling thread.
//This parameter can be NULL.
//If per-user quotas are being used, this value may be less than the total number of free bytes on a disk.
__int64 n64AvailableFreeDiskBytes;
//A pointer to a variable that receives the total number of bytes on a disk that are available to the user who is associated with the calling thread.
//This parameter can be NULL.
//If per-user quotas are being used, this value may be less than the total number of bytes on a disk.
//To determine the total number of bytes on a disk or volume, use IOCTL_DISK_GET_LENGTH_INFO.
__int64 n64TotalDiskBytes;
//A pointer to a variable that receives the total number of free bytes on a disk.
//This parameter can be NULL.
__int64 n64TotalFreeDiskBytes;
if ( !::GetDiskFreeSpaceEx(szDiskDir, (PULARGE_INTEGER) &n64AvailableFreeDiskBytes, (PULARGE_INTEGER) &n64TotalDiskBytes,
(PULARGE_INTEGER) &n64TotalFreeDiskBytes) )
{
printf("Fail to get disk fress space in %s (Err = %d).\n", szDiskDir, ::GetLastError());
}else{
printf("%s has %lld bytes available free disk.\nTotal disk size is %lld bytes.\nTotal free space is %lld bytes.\n",
szDiskDir, n64AvailableFreeDiskBytes, n64TotalDiskBytes, n64TotalFreeDiskBytes);
}
[CListCtrl]排序Contorl List內之資料
這邊以檔案清單來說明,需要的欄位有:檔案名稱、副檔名、檔案路徑。
首先先建立用來排序用的資料結構
再來建立給CListCtrl::SortItems()使用的Call back函式,函式內部就放需要用來sort比對的方法
Head File
Cpp File
再來是建立接收到滑鼠事件後需要執行的函式,在函式內就把先前建立好的Call back函式,SortFunc塞給CListCtrl::SortItems()。
Head File
Cpp File
然後在message map鍵入
來接收滑鼠點選List的欄位標題時的訊息。
以上動作完成後,就可以利用點擊欄位標題來進行排序了。
首先先建立用來排序用的資料結構
typedef struct {
char pszFileName[_MAX_FNAME];
char pszExtName[_MAX_EXT];
char pszFilePath[MAX_PATH];
} ITEMDATA, *PITEMDATA;
再來建立給CListCtrl::SortItems()使用的Call back函式,函式內部就放需要用來sort比對的方法
Head File
friend int CALLBACK SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
Cpp File
int CALLBACK SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
int nRetVal = 0;
PITEMDATA pData1 = (PITEMDATA)lParam1;
PITEMDATA pData2 = (PITEMDATA)lParam2;
switch(lParamSort)
{
case 0: // File Name
nRetVal = strcmp(pData1->pszFileName, pData2->pszFileName);
break;
case 1: // Extension File Name
nRetVal = strcmp(pData1->pszExtName, pData2->pszExtName);
break;
case 2: // TerFile Path
nRetVal = strcmp(pData1->pszFilePath, pData2->pszFilePath);
break;
default:
break;
}
return nRetVal;
}
再來是建立接收到滑鼠事件後需要執行的函式,在函式內就把先前建立好的Call back函式,SortFunc塞給CListCtrl::SortItems()。
Head File
afx_msg void OnItemClick2Sort(NMHDR* pNMHDR, LRESULT* pResult);
Cpp File
void CFileSearchDlg::OnItemClick2Sort(NMHDR* pNMHDR, LRESULT* pResult)
{
NMLISTVIEW *pLV = (NMLISTVIEW *) pNMHDR;
m_lstFileItem.SortItems(SortFunc, pLV->iSubItem);
*pResult = 0;
}
然後在message map鍵入
ON_NOTIFY(LVN_COLUMNCLICK, IDC_LST_FILE, OnItemClick2Sort)
來接收滑鼠點選List的欄位標題時的訊息。
以上動作完成後,就可以利用點擊欄位標題來進行排序了。
[WINDOWS]延遲載入的特定服務的方式
根據MS技術支援的文件內顯示:
1.先至服務的登陸子機碼,HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ < 服務名稱 >
2.在此子機碼內新增 DependOnService 值(可擴充字串值)
3. 鍵入與此服務之前啟動的服務名稱
4.之後在電腦啟動時,它會使用這個項目,來確認啟動服務或服務列在這個值,再嘗試啟動相依的服務。
測試平台:Win7 x64
測試結果:有效
Ref:延遲載入的特定服務的方式
1.先至服務的登陸子機碼,HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ < 服務名稱 >
2.在此子機碼內新增 DependOnService 值(可擴充字串值)
3. 鍵入與此服務之前啟動的服務名稱
4.之後在電腦啟動時,它會使用這個項目,來確認啟動服務或服務列在這個值,再嘗試啟動相依的服務。
測試平台:Win7 x64
測試結果:有效
Ref:延遲載入的特定服務的方式
[MFC]設定RichEdit內顯示文字顏色
設定文字插入位置
改變顯示顏色
Memo用,可直接使用,需再新增其他功能時,要再修改與測試。
//移動游標
m_RichEdit
.
SendMessage(EM_LINEINDEX,
m_RichEdit
.
GetLineCount(), 0); //移到最底行
m_RichEdit
.
SendMessage(EM_SETSEL,
m_RichEdit
.
GetWindowTextLength(),
m_RichEdit
.
GetWindowTextLength()); //移到最後一個字元後面
改變顯示顏色
CHARFORMAT chFormat; ::ZeroMemory(&chFormat, sizeof(CHARFORMAT)); m_RichEdit.GetSelectionCharFormat(chFormat);
//取得目前文字格式
chFormat.dwMask |= CFM_COLOR; //設定修改顏色屬性 chFormat.dwEffects &= ~CFE_AUTOCOLOR; //移除 CFE_AUTOCOLOR chFormat.crTextColor = RGB(255, 0, 0);
m_RichEdit
.SetSelectionCharFormat(chFormat);
m_RichEdit
.ReplaceSel(str); //因為沒有選擇文字,所以會將str塞到最後面
Memo用,可直接使用,需再新增其他功能時,要再修改與測試。
[C] String Copy
while (*s++ = *t++);
1. *s = *t
2. *s+=1 and *t+=1
3. *t == NULL || -> Exit
*t != NULL -> do 1
1. *s = *t
2. *s+=1 and *t+=1
3. *t == NULL || -> Exit
*t != NULL -> do 1
[MFC]Timer
.h
afx_msg void OnTimer(UINT_PTR nIDEvent)
Message map
ON_WM_TIMER()
void CDialog:: OnTimer(UINT nIDEvent)
{
CView:: OnTimer(nIDEvent);
switch (nIDEvent) ...
}
//OnInitialDialog
SetTimer(ANIMATE_MFT, 20, NULL);
//When Used
OnTimer(ANIMATE_TIMER);
OnTimer(ANIMATE_MFT);
//Destructor
KillTimer(ANIMATE_TIMER);
afx_msg void OnTimer(UINT_PTR nIDEvent)
Message map
ON_WM_TIMER()
void CDialog:: OnTimer(UINT nIDEvent)
{
CView:: OnTimer(nIDEvent);
switch (nIDEvent) ...
}
//OnInitialDialog
SetTimer(ANIMATE_MFT, 20, NULL);
//When Used
OnTimer(ANIMATE_TIMER);
OnTimer(ANIMATE_MFT);
//Destructor
KillTimer(ANIMATE_TIMER);
[MFC]Rich Edit 2.0 Control
在使用Rich Edit 2.0 Control時,要在App::InitInstance()裡,產生Dialog物件之前呼叫AfxInitRichEdit2()。
這樣才能使得編譯出來的程式可以執行,不然會在.DoModal()的時候就會出現handle錯誤而結束。
這樣才能使得編譯出來的程式可以執行,不然會在.DoModal()的時候就會出現handle錯誤而結束。
SMTP Client - send mail
目前參照http://www.codeproject.com/KB/IP/CSmtp.aspx?fid=1525693&df=90&mpp=25&noise=3&sort=Position&view=Quick&fr=26所做出來的client端程式可正常運行。
唯獨在附加檔案的部份,一開始測試是讀取8k資料並傳送之,但是用outlook卻都收不到郵件。
由此可推測,是否是單一個section大小過大導致SMTP server拒絕接收郵件資料。
後來根據sample裡面設定的section大小(5k)來傳送,則可正常收到郵件。
故此目前先暫時用5k的section大小來傳遞檔案,以後有空的時候在來研究一下RFC。
Ref:RFC5246、 RFC2487。
Mail Format:(以下每一段建立後皆立即送出,括弧內或是藍色文字為註解)
唯獨在附加檔案的部份,一開始測試是讀取8k資料並傳送之,但是用outlook卻都收不到郵件。
由此可推測,是否是單一個section大小過大導致SMTP server拒絕接收郵件資料。
後來根據sample裡面設定的section大小(5k)來傳送,則可正常收到郵件。
故此目前先暫時用5k的section大小來傳遞檔案,以後有空的時候在來研究一下RFC。
Ref:RFC5246、 RFC2487。
Mail Format:(以下每一段建立後皆立即送出,括弧內或是藍色文字為註解)
Mail From:<SP>UserName<MailAddress><CRLF>
RCPT To:<SP>UserName<MailAddress><CRLF>(包含副本跟密件副本的收件人)
DATA (以下為郵件本體)
Header Content Start
Date:<SP>day<SP>month<SP>year<SP>hour:min:sec<SP>zone<CRLF>
From:<SP>UserName<MailAddress><CRLF>
X-Mailer:<SP>X-Mailer<CRLF>
Reply-To:<SP>MailAddress<CRLF>
X-Priority:<SP>Priority<CRLF>
To:UserName<MailAddress>,UserName<MailAddress>,...<CRLF>
Cc:UserName<MailAddress>,UserName<MailAddress>,...<CRLF>
Bcc:UserName<MailAddress>,UserName<MailAddress>,...<CRLF>
Subject:<SP>Subject<CRLF>
MIME-Version:<SP>version<CRLF>
(無附加檔)
Content-type: text/plain; charset=US-ASCII<CRLF>
Content-Transfer-Encoding: 7bit<CRLF><CRLF>
(*有附加檔,BOUNDARY_TEXT自定,網路上範例都將內容寫的很長)
Content-Type: multipart/mixed; boundary="BOUNDARY_TEXT"<CRLF><CRLF>
--BOUNDARY_TEXT<CRLF>
Content-type: text/plain; charset=US-ASCII<CRLF>
Content-Transfer-Encoding: 7bit<CRLF><CRLF>
Header Content End
Message body<CRLF>
(每一行資料後面都要有crlf,但測試只有lf也是可以的。這邊郵件內容長度無限制,最好是一次送出)
(加入附加檔內容)
--BOUNDARY_TEXT<CRLF>
Content-Type: application/x-msdownload; name="FileName.ext"<CRLF>
Content-Transfer-Encoding: base64<CRLF>
Content-Disposition: attachment; filename="FileName.ext"<CRLF><CRLF>
(由Base64加密過的檔案內容,每一送出的Section大小不可超過6k)
(重覆做*,到所有檔案傳完為止)
--BOUNDARY_TEXT--(附加檔結束)
<CRLF>.<CRLF> (郵件內容傳送完畢)
QUIT<CRLF> (離開)
_SplitPath
C:\abc\123.txt => Drive = C:, Path = \abc\, FileName = 123, Extension = .txt
C:\abc\123.12.txt => Drive = C:, Path = \abc\, FileName = 123.12, Extension = .txt
C:\abc\123.txt.12 => Drive = C:, Path = \abc\, FileName = 123.txt, Extension = .12
\\192.168.1.1\abc\123.txt => Drive = "", Path = \\192.168.1.1\abc\, FileName = 123, Extension = .txt
C:\abc\123.12.txt => Drive = C:, Path = \abc\, FileName = 123.12, Extension = .txt
C:\abc\123.txt.12 => Drive = C:, Path = \abc\, FileName = 123.txt, Extension = .12
\\192.168.1.1\abc\123.txt => Drive = "", Path = \\192.168.1.1\abc\, FileName = 123, Extension = .txt
[Win]Service存取網路磁碟
目前測試在要進行存取時,先呼叫LogonUser()
之後就可以用所輸入的使用者帳號來存取網路磁碟了。
存取完後需使用CloseHandle()來關閉Token並釋放記憶體即可。
dwLogonType設成 LOGON32_LOGON_INTERACTIVE或是LOGON32_LOGON_NEW_CREDENTIALS則都可以。
只是網路磁碟的路徑要使用UNC路徑才行,不然還是一樣會找不到路徑。
mapping過的路徑目前測試結果是service是一定讀不到檔案,原因則目前不明。
如有需讀取mapping路徑內之資料,請參考[Win]Mapping Disk的紀錄位置
PS.如有需要讓呼叫的執行檔也有同樣的權時,dwLogonType需設成LOGON32_LOGON_INTERACTIVE;dwLogonProvider則要設為LOGON32_PROVIDER_DEFAULT。
之後再使用 CreateProcessAsUser()來執行執行檔即可。需傳入的Token則為先前使用LogonUser()所取得的token。
之後就可以用所輸入的使用者帳號來存取網路磁碟了。
存取完後需使用CloseHandle()來關閉Token並釋放記憶體即可。
dwLogonType設成 LOGON32_LOGON_INTERACTIVE或是LOGON32_LOGON_NEW_CREDENTIALS則都可以。
只是網路磁碟的路徑要使用UNC路徑才行,不然還是一樣會找不到路徑。
mapping過的路徑目前測試結果是service是一定讀不到檔案,原因則目前不明。
如有需讀取mapping路徑內之資料,請參考[Win]Mapping Disk的紀錄位置
PS.如有需要讓呼叫的執行檔也有同樣的權時,dwLogonType需設成LOGON32_LOGON_INTERACTIVE;dwLogonProvider則要設為LOGON32_PROVIDER_DEFAULT。
之後再使用 CreateProcessAsUser()來執行執行檔即可。需傳入的Token則為先前使用LogonUser()所取得的token。
Subscribe to:
Posts (Atom)
Build docker image from multiple build contexts
Build docker image from multiple build contexts ...
-
參考資料: Input Input Manager 測試手把 :PS Analog gamepad Script語言:C# Unity 版本:3.4 Unity提供了3種輸入裝置可以使用,鍵盤、滑鼠、以及遊戲手把。 ...
-
寫法很簡單,就像下列寫法: if ( *szStr ) { .... } 因為*szStr == szStr[0],且char[]是以NULL-Terminate來判定字串是否結束,所以只要判定陣列的第一個值是不是為零,就可知道是否為空字串。 如需檢查是否為空字...