2018年7月10日
2014年9月18日
解決方法:
ShowDropDown();之后SetCursor(LoadCursor(NULL, IDC_ARROW));即可
2013年3月17日
2013年2月27日
有時候下拉框(MFC標準叫組合框,CComboBox)中條目文本很多,超過了下拉框的寬度,如果不加設置的話,超過的部分文本將無法顯示,查找MSDN,發現解決方法,代碼如下:
代碼
// The pointer to my combo box.
extern CComboBox* pmyComboBox;
// Set the height of every item so the item
// is completely visible.
CString str;
CSize sz;
int dx=0;
CDC* pDC = pmyComboBox->GetDC();
for (int i=0;i < pmyComboBox->GetCount();i++)
{
pmyComboBox->GetLBText( i, str );
sz = pDC->GetTextExtent(str);
// Only want to set the item height if the current height
// is not big enough.
if (pmyComboBox->GetItemHeight(i) < sz.cy)
pmyComboBox->SetItemHeight( i, sz.cy );
// Only want to set the item width if the current width
// is not big enough.
if (pmyComboBox->GetDroppedWidth() < sz.cx)
{
pmyComboBox->SetDroppedWidth(sz.cx + 20);
}
}
pmyComboBox->ReleaseDC(pDC);
效果圖:

2012年7月15日
2012年4月25日
1. 把你的虛擬網卡VMnet8(在Win系統的網上鄰居里)設置為自動獲得IP、自動獲得DNS服務器,啟用。
2.
把你虛擬機中操作系統的Editing Auto Ethernet->IPV4 Setting 設置成如上圖所示。
有些Linux可以如下設置:“本地連接”也設置為自動獲得IP、自動獲得DNS服務器(在虛擬機中,右鍵“本地連接”-雙擊“Internet 協議”,看看是不是自動的吧!固定IP的也在這里改?。?/p>
3.當然是將虛擬機的上網方式選為NAT咯。
右鍵你要設置的虛擬機選“設置”(因為有的不止虛擬一臺),在“硬件”中選“以太網”, 將右邊的網絡連接改為NAT-確定。
4.點菜單欄里的“編輯”-選“虛擬網絡設置”,先將“自動橋接”給去掉(去掉鉤鉤),再選“DHCP”開啟DHCP服務,點“開始”-應用,再按同樣的方法開啟“NAT”的功能。
5.最重要的是你的兩個服務必須開啟:VMware DHCP Service 和VMware NAT Service。
具體操作如下: 開始---設置--控制面板---管理工具---服務,確保 VMware DHCP Service 和VMware NAT Service 服務已經啟動
//====================================另外的方法
Ubuntu虛擬機共享主機上網
WinXP+VMware WorkStation+Ubuntu7.10
一.Bridged方式共享上網
1.設置Ubuntu的網絡連接方式為Bridged
2.共享ADSL連接
ADSL連接屬性中選中“Internet連接共享”,下拉列表中然后選擇“本地連接”,系統會自動把“本地連接”設置為192.168.0.1。注意此設置會在斷開連接并重啟后才生效
3.Ubuntu網絡設置
IP:192.168.0.X
網關:192.268.0.1
DNS:192.168.0.1(系統->系統管理->網絡->DNS)
二.NAT方式共享上網
1.設置Ubuntu的網絡連接方式為NAT
2.開啟VMware DHCP Service和VMware NAT Service兩個服務
3.Ubuntu中網絡設置為自動配置(DHCP)或者手動設置IP及DNS
手動設置方法:
1.XP中ipconfig,得到VMnet8的IP為192.168.93.1
2.Ubuntu中設置網絡IP為192.168.93.X(X為3-254,網上很多人說只能是128-254,自動分配時一般也是128,但經驗證3-254都行,DNS設置為192.168.93.2
以上方法均經驗證,絕無多余步驟。
2012年1月10日
1、 Dump文件放在哪里?
Dump文件不用非要放在你編譯出來的位置,你完全可以建立一個新的文件夾來放它。但若不是存放在編譯出來的位置,需要將編譯生成的PDB文件拷貝到Dump文件目錄,或是利用VS2005打開Dump文件后,設置PDB文件路徑。
2、 如何恢復當時的現場?可能你要問,怎么可能,這個dump文件可是用戶發給我的,我不可能去用戶家里調試吧?這個恢復現場可不是指的非要到那臺機器上去,而是要把產生dump文件對應的二進制文件拿到。
但是恢復現場需要所有的二進制文件都要對應,你一定要有導致用戶崩潰的那些Exe和DLL。既然是你發布的程序,Exe文件當然你會有。所以這里只考慮DLL就行了。
Dump文件中記錄了所有DLL文件的版本號和時間戳,所以你一定可以同過某種途徑拿到它。如果你能從用戶那里拿到最好,如果不方便,用戶不可能用的是我們平常不常用的操作系統,所以找個有對應系統的機器一般都會有。但是記住不僅是文件名稱要一致,還要核對版本和時間戳,如果不同一樣沒有辦法用。
如果客戶用了某個特殊的補丁怎么辦?
其實這個問題也很好解決,只要它不阻礙閱讀堆棧,就不用管它,調試Dump和運行程序不一樣,缺少一兩個DLL沒有任何問題。
3、 如果真的需要怎么辦?符號文件現在主要是指PDB文件。
如果沒有符號文件,那么調試的時候可能導致堆棧錯誤。
如果你丟失了這個發布版本中你編譯出來的那些exe和DLL的PDB,那么這個損失是嚴重的,重新編譯出來的版本是不能使用的。
我自己的DLL都有了,可是缺的是系統的DLL的對應PDB文件怎么辦?圖1.4中已經介紹了方法。微軟在它的符號數據庫上為我們提供了所有的PDB文件,還有部分非關鍵DLL。設置好后程序將自動下載需要的PDB及DLL文件。
4、 拿到需要的文件了,這些文件應該放在哪里?符號數據庫中的文件不用動,把其它的exe和DLL、PDB文件放在dump文件目錄里就行了。
5、 我用的是VS2005,明明有源代碼,為什么顯示不了?這個是dump調試的最頭痛問題,代碼可能已經改過了,即使你從SVN拿到當時的版本,時間戳也是錯的,VS2005就是不讓你顯示代碼。其實只要在
Tools/Options,Debugging/General中去掉
Require source files to exactly match the original version的復選就行了。
前言:利用drwtsn32或NTSD進行程序崩潰處理,都可以生成可用于調試的dmp格式文件。使用VS2005打開生成的DMP文件,能很方便的找出BUG所在位置。本文將討論以下內容:
1、 程序編譯選項
2、 利用VS2005 分析dump文件
3、 常見問題討論
一、 程序編譯選項
PDB files contains all debug information like type definition and function prototype. When application crashes, we need the PDB files to analyze the root cause, so make sure these PDB files will be created when building it. You must do the following setting:
C/C++/General/Debug Information Format=Program Database (/Zi).

圖1.1 調試信息格式
Linker/Debugging/Generate Program Database File=”Name and location of your PDB files”

圖1.2 PDB文件輸出路徑
PDB文件路徑最好設置在同一個文件夾中,這樣方便dmp文件調試時調用。
調試時,所有的PDB文件和源文件必須嚴格匹配(the PDB files should be the one generated by build the source code),并存儲在一個安全的位置。當客戶報告了一個錯誤時,你需要這些文件來幫忙以便定位錯誤于源代碼中并解決問題。
二、 VS2005 分析dump文件
In this simple application, there is an unhandled Access Violation Reading exception, because GetNameFromDatabase returns a NULL pointer, and this pointer is passed into IsPrefix and then it’s used directly without NULL pointer checking.

圖1.3 演示代碼
利用Release模式編譯該測試程序,在客戶機上運行該程序,將根據NTSD設置生成相對應的DMP格式文件。
可以使用Visual Studio.Net、NTSD或是其他的調試工具對DMP格式文件進行分析。
l Start Visual Studio.Net
Click File/Open Solution and make sure the files of type is *.dmp then click Open.

圖1.3 Open Dump File (GUI)
l Set Symbol Path
Click Tools/Options, Debugging/Symbols,增加PDB文件路徑。若調試的程序需要微軟基礎庫的PDB信息,可以增加一個路徑為:
http://msdl.microsoft.com/download/symbols
在界面下方Cache Symbol From symbol…選擇本地存儲這些Symbols的路徑。

圖1.4 Symbol Path
如果DMP文件沒有放入本身PDB文件所在目錄,也可以在此處增加一個本地目錄。點OK后,VS2005將從網絡中下載所需要的Symbols,需要等待一段時間。如果是多次調試同一個程序錯誤所生成的DMP文件,可以在對話框中選擇“Search the above locations only when symbols are loaded manually”。從而可以節省網絡帶寬。
l Set Source code path
Open Solution Property Pages and set the source code path.

圖1.5 屬性菜單

圖1.6 Debug Source Files
l Start to Debug the Dump File
Click the Debug menu, it will ask you to save as a solution, save it. Then it will go to the line which caused the crash of your application.

圖1.7 調試窗口,定位到源代碼
三、 常見問題討論
1、 Dump文件放在哪里?
Dump文件不用非要放在你編譯出來的位置,你完全可以建立一個新的文件夾來放它。但若不是存放在編譯出來的位置,需要將編譯生成的PDB文件拷貝到Dump文件目錄,或是利用VS2005打開Dump文件后,設置PDB文件路徑。參照圖1.4。
2、 如何恢復當時的現場?
可能你要問,怎么可能,這個dump文件可是用戶發給我的,我不可能去用戶家里調試吧?這個恢復現場可不是指的非要到那臺機器上去,而是要把產生dump文件對應的二進制文件拿到。
但是恢復現場需要所有的二進制文件都要對應,你一定要有導致用戶崩潰的那些Exe和DLL。既然是你發布的程序,Exe文件當然你會有。所以這里只考慮DLL就行了。
Dump文件中記錄了所有DLL文件的版本號和時間戳,所以你一定可以同過某種途徑拿到它。如果你能從用戶那里拿到最好,如果不方便,用戶不可能用的是我們平常不常用的操作系統,所以找個有對應系統的機器一般都會有。但是記住不僅是文件名稱要一致,還要核對版本和時間戳,如果不同一樣沒有辦法用。
如果客戶用了某個特殊的補丁怎么辦?
其實這個問題也很好解決,只要它不阻礙閱讀堆棧,就不用管它,調試Dump和運行程序不一樣,缺少一兩個DLL沒有任何問題。
3、 如果真的需要怎么辦?
符號文件現在主要是指PDB文件。
如果沒有符號文件,那么調試的時候可能導致堆棧錯誤。
如果你丟失了這個發布版本中你編譯出來的那些exe和DLL的PDB,那么這個損失是嚴重的,重新編譯出來的版本是不能使用的。
我自己的DLL都有了,可是缺的是系統的DLL的對應PDB文件怎么辦?圖1.4中已經介紹了方法。微軟在它的符號數據庫上為我們提供了所有的PDB文件,還有部分非關鍵DLL。設置好后程序將自動下載需要的PDB及DLL文件。
4、 拿到需要的文件了,這些文件應該放在哪里?
符號數據庫中的文件不用動,把其它的exe和DLL、PDB文件放在dump文件目錄里就行了。
5、 我用的是VS2005,明明有源代碼,為什么顯示不了?
這個是dump調試的最頭痛問題,代碼可能已經改過了,即使你從SVN拿到當時的版本,時間戳也是錯的,VS2005就是不讓你顯示代碼。其實只要在
Tools/Options,Debugging/General中去掉
Require source files to exactly match the original version的復選就行了。
2011年10月21日
映射表類(CMap)是MFC集合類中的一個模板類,也稱作為“字典”,就像一種只有兩列的表格,一列是關鍵字,一列是數據項,它們是一一對應的。關鍵字是唯一的,給出一個關鍵字,映射表類會很快找到對應的數據項。映射表的查找是以哈希表的方式進行的,因此在映射表中查找數值項的速度很快。映射類最適用于需要根據關鍵字進行快速檢索的場合,我們的程序中就用映射表來保存計時器標志值和類實例指針,用計時器的標志值作為關鍵字。
他這個有點像數組,比如你要查找a[index],不必先遍歷前面的index個元素,只不過數組的下標是哈希表鍵值,它是以鍵值對的形式出現的。舉個例子來說吧,公司的所有職員都有一個工號和自己的姓名,工號就是姓名的關鍵字,給出一個工號,就可以很快的找到相應的姓名。
舉例如下:
1、定義一個CMAP,向這個CMAP中增加數據項(鍵-值對)。
CMap<CString, LPCTSTR, CString, LPCTSTR>m_ItemMap;
CString strKey = _T(""), str = _T("");
int i;
for(i = 0; i < 5; i++)
{
strKey.Format("%d", i); //這個是鍵
str.Format("A%d", i); //鍵對應的值
m_ItemMap.SetAt(strKey, str);
}
2、遍歷正個CMAP的常用方法。
POSITION pos = m_ItemMap.GetStartPosition();
while(pos)
{
m_ItemMap.GetNextAssoc(pos, strKey, str);
cout<< strKey<< ":"<< str<< endl;
}
3、在CMAP中查找相應的數據項。
CString pReset;
if(m_ItemMap.Lookup("1", pReset))
{
cout<<pReset<<endl;
}
=======================================================================現在,我們來學習MFC中,最常用的數據結構中的最后一個CMap模板。之前,我們已經依次學完了CArray,CList,并且也對它們進行了初步的剖析。
其實,我一直認為CMap是最簡單的一個數據類型,如果說,大家對這個數據類型產生不良感覺的話,大多是因為對Hash表的陌生。
顯然,CMap就是對Hash表的一種實現。對于Hash表來說,我們需要提供成對的Key與Value進行操作,其實,也就是將我們日常使用的數組下標替換成現在Key,至于MFC是采用了什么樣的散列函數,我們不必知道。
Hash表可以認為是數組的一種優化,或者說是對數組缺陷的一種彌補,因為我們知道,數組在具備了高效存取性能的同時,無法動態的調整自身的大小,又嚴重的影響了它的使用效果。這給了Hash表可乘之機,Hash表總是使用了某種算法盡可能的來達到將成對的元素存儲到一個額定的離散的內存空間,它既繼承了鏈表對自身的動態調整,又盡可能的使讀寫維持在高速的水平,當然無論如何還是要比數組慢的多。
如果你非要讓我告訴你,Hash表是什么樣的一個數據結構的話,很遺憾,我無法準確的描述,這就相當于你問我“鳳凰是什么樣子”,不過我可以告訴你孔雀的樣子。常用的Hash表非常像一個十字數組,似乎十字數組又成為了眾多讀者的障礙,如果你暫時還不能理解的話,請你去翻閱Hash表的詳細論述,當然你也可以在不久之后,在本處看到這些經典數據結構的精講。
現在,我們來看一個CMap的用法,至于它的參數,你可以看本空間一篇專門描述CArray,CList以及CMap參數用法的文章《CArray,CList,CMap如何實化(實例化)》。下面是我自己編寫的例子:
class Point
{
public:
Point()
{
m_x = 0;
m_y = 0;
}
Point(int x, int y)
{
m_x = x;
m_y = y;
}
public:
int m_x;
int m_y;
};
typedef CMap<const char*, const char*, Point, Point&> CMapPnt; //請在使用之前定義
int main()
{
Point elem1(1, 100), elem2(2, 200), elem3(3, 300), point;
CMapPnt mp;
// insert 3 elements into map, #1
mp.SetAt("1st", elem1);
mp.SetAt("2nd", elem2);
mp.SetAt("3th", elem3);
// search a point named "2nd" from map #2
mp.Lookup("2nd", point);
printf("2nd: m_x: %d, m_y: %d\n", point.m_x, point.m_y);
// insert a new pair into map #3
Point elem4(4, 400);
mp["4th"] = elem4;
cout<<"count: "<<mp.GetCount()<<endl;
// traverse the entire map #4
size_t index = 0;
const char* pszKey;
POSITION ps = mp.GetStartPosition();
while( ps )
{
mp.GetNextAssoc(ps, pszKey, point);
printf("index: %d, m_x: %d, m_y: %d\n", ++index, point.m_x, point.m_y);
}
return 0;
}
代碼中,我已經給出了一些注釋,我同樣建議讀者們,用英文在代碼中注釋,這樣的好處實在是太多了。尤其在代碼需要在不同編碼的操作系統上調試的時候。
對于CMap這個類,我不得不著重啰嗦一下的是:遍歷操作以及取下標【】操作,當然還有那個令很多人困惑不已的ARG_KEY到底應該如何選擇的問題。
遍歷,看注釋#4,至于POSITION的含義,請在本空間,查看其它文章。先使用GetStartPosition()函數獲得表頭的位置,然后,我們可以使用GetNextAssoc函數來遍歷。GetNextAssoc(POSITION& rNextPosition, KEY& rKey, VALUE& rValue)函數的參數值得說明一下,大家看到,3個參數都是引用,而第一個是rNextPosition,顧名思義,在函數返回之后,它將會指像下一個元組,當然這是在表還未遍歷完的時候,否則,它將被置為空(NULL)。
【】,利用下標取元素的這個操作符,在CMap中被重載,用來返回指定Key值數據的引用,不過在注釋#3處,對于先取"4th"這個Point的引用然后賦值的用法,看起來,似乎有點聰明過了頭,因為在這之前,我們還沒有插入"4th"所對應的元組,但是,程序卻能正常的運行!為什么?其實,這樣的用法是十分正確的,因為CMap畢竟不是數組,它是沒有邊界的,當CMap在獲得一個它無法查詢到的Key值的時候,它會將這個Key以及一個空的數據類型追加到Hash表中去,從而保證了上面的程序可以無誤的運行。
我們已經說過,ARG_KEY是作為類型參數傳入CMap的,但并不是任何類型都可以作為ARG_KEY傳入的。為什么?看樣子,這次不得不簡單的說說Hash表的散列函數了。每個Hash表,總會使用一些散列函數,用來查找Key所對應的Value,理想狀態下,我們當然希望Hash表,就是一個數組,雖然這不可能,不過這樣理解,可以幫助我們更好的理解Hash表的物理結構,就讓我們暫時把它看成一個數組吧。數組總是使用下標來直接獲取元素的存儲地址,而下標,顯然應該是個非負整數,從而Hash表,也應該具備這樣的特性,至少必須存在某種算法可以使傳入的Key可以直接的轉化為一個非負的整數,這也就是ARG_KEY的選擇標準。從而對象、引用無論如何都不應該作為ARG_KEY成為CMap的類型參數,而int、unsigned int、指針以及地址就成為了ARG_KEY的常用類型參數,其實也就是那些類似于整型的數據類型。常??吹揭恍┤嗽谟肅Map的時候,試圖使用CString作為CMap中ARG_KEY的類型參數,這是應該被糾正的方向性錯誤,但有些人似乎會理直氣壯的反駁我,因為他們發現類型參數KEY是可以使用CString的,這很奇怪嗎?我說過KEY不能使用CString嗎?之所以KEY可以使用CString而ARG_KEY卻用的是LPCTSTR,那是因為CString重載了operator==(const char*)這個判等操作符,當CMap從Hash表中獲得KEY之后,它會將ARG_KEY與KEY直接相比較。真正存于CMap內部的是KEY,也就是CString。這也就是為什么,我們經常會看到CMap被實化成CMap<CString, LPCTSTR/*相當于const char*,非Unicode情況下*/, CString,CString&>這樣的一個四不像實化類的原因,至于CMap的效率優化問題,我們會在以后的文章中繼續與大家探討。
CMap的確是個很不錯的數據結構,尤其在你建立一個字典的時候。比如idealsoft的含義是"曳光科技",這就是一個元組,也就是一個Pair,Key是"idealsoft",而Value是"曳光科技"。
====================================================================
#include <afxwin.h>
#include <afxtempl.h>
void main()
{
AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0);
CMap <int, int, CString, CString> m_cMap;
m_cMap.SetAt(9923033, "張三 ");
m_cMap.SetAt(9826033, "張A ");
m_cMap.SetAt(9923063, "張B ");
m_cMap.SetAt(9923093, "張C ");
CString strName;
m_cMap.Lookup(9923063, strName);
AfxMessageBox(strName);
}
2011年8月26日
COLORMAP ColorMap[3] = {
{ RGB(128,128,128), ::GetSysColor(COLOR_BTNSHADOW) },
{ RGB(192,192,192), ::GetSysColor(COLOR_BTNFACE) },
{ RGB(255,255,255), ::GetSysColor(COLOR_BTNHILIGHT)}
};
CBitmap Bitmap;
Bitmap.LoadMappedBitmap(IDB_BITMAP, 0, ColorMap, 3);
BOOL LoadMappedBitmap(
UINT nIDBitmap, //位圖的標識
UINT nFlags = 0, //通常情況下為0,當將該位圖作
為屏蔽位圖使用時該參數為CMB_MASKED
LPCOLORMAP lpColorMap = NULL,
int nMapSize = 0);
【返回值】該成員函數調用成功返回一個非零值,否則返回零。
【參 數】
nIDBitmap
nFlags
通常情況下為0,當將該位圖作為屏蔽位圖使用時該參數為CMB_MASKED。
lpColorMap
一個指向COLORMAP數據類型數組的指針。COLORMAP的數據結構如下:
typedef struct _COLORMAP{
COLORREF from; // 邏輯調色板的顏色
COLORREF to; // 物理調色板的顏色
}COLORMAP, FAR* LPCOLORMAP;
nMapSize
指定數組中數組元素的個數。
【注 釋】本成員函數可以將一個設備無關位圖裝入CBitmap類的對象,并根據邏輯調色板與物理調色板的映射關系使系統正確地顯示該位圖。
_COLORMAP iColor[2]={{RGB(191,191,196),::GetSysColor(COLOR_3DFACE)},{RGB(192,192,192),::GetSysColor(COLOR_3DFACE)}};
m_bmToolbarHi.LoadMappedBitmap( IDB_TOOLBARHI,0,iColor,2);
m_wndToolBar.SetBitmap( (HBITMAP)m_bmToolbarHi );
這是我的代碼,可他不工作啊:~(
有個問題提醒一下:
庫中的LoadMappedBitmap函數對超過256色的圖像好像無效,而且會死掉。
對不超過256色的圖像是有效的。
我知道了,我的圖像是256色的,這不錯。但是轉換的顏色好像也算一種顏色。我把我導出的圖像色數改成128,結果就好了 :D