2013/12/20

VMware Bridged類型網卡不通

小弟在本機上先安裝了virtual box,並自動產生了virtual box所需的網路橋接裝置-->VirtualBox Host-Only Network,
其後又安裝了另外一套VMware workstation,並在VMware下建立了Guest OS(Fedora),
在GuestOS的Network Connection當中,設置為Bridged,以便於網路上的其他主機能直接存取Fedora,
Fedora的network settingk則是使用static ip的方式,
剛開始使用一切都正常,直到有天關機後再開啟,才發現Fedora無法對外連線,
但是VMware底下的其他Guest OS 只要是使用NAT的方式都能正常連線,唯獨bridge有問題,
查了一下才發現原理是這樣的--->
VMware安裝完後,會生成三個網路橋接裝置,分別為VMnet0,VMnet1,VMnet8(詳細請自己搜尋),
其中Bridged模式走的是VMnet0,此橋接裝置會將Guest OS的網卡導到Host實體機器的網卡上,
但是若實體機器有多張網卡時,則會依照設定值決定導到哪一張實體網卡上,
設定值有兩種:Automatic or 某一張實體網卡,
我在VMware安裝完後從未進來設定過,其預設值為Automatic,
But!!!VMware 將 VirtualBox Host-Only Network 也當作是實體網卡!!!
所以導致Fedora or Guest OS 不管怎麼修改設定,都無法連到真正的實體網路~~~><~~~

所以,解決方法就是
1.進入VMware Network Editor->點選VMnet0-->下方WMnet Information-->在Bridged to的下拉式選單中選擇一張實體網卡!
或是
2.右方的 Automatic Settings內,將VirtualBox Host-Only Ethernet Adapter的勾選取消,Bridged to的下拉選單仍維持 "Automatic"

搞定,收工!

ref: VMWare虛擬機Bridged類型網卡ping不通的原因和解決辦法

2013/11/21

[MFC] TreeCtrl使用問題

前提:TreeCtrl需帶有 "Check Boxes"屬性
問題一:
OnInitDialog時,在treectrl內新增item後,需要將此項目的checkbox勾選,但是SetCheck卻無效?
回答一:
若要在初始化時期就設定treectrl's check box狀態,且在UI上表現出來,需在設定check box前,重新設定一次tree ctrl屬性!
若是在OnInitDialog以後的function內設定treectrl's check box,則無此問題。
BOOL TestDlg::OnInitDialog() { CDialog::OnInitDialog(); //TODO: mTreectrl.ModifyStyle( TVS_CHECKBOXES, 0 ); mTreectrl.ModifyStyle( 0, TVS_CHECKBOXES ); //在這之後新增的item就可以設定check box為有勾選狀態 HTREEITEM hCurItem = mTreectrl.InsertItem("Test"); mTreectrl.SetCheck(hCurItem,true); }
問題二:
當勾選/取消溝選Tree上任一Item後,要如何自動選擇目前的Item,而非總是選擇第一個Item?
回答二:
需要在Click事件動手腳!
方法1:
void TestDlg::OnNMClickTree(NMHDR *pNMHDR, LRESULT *pResult) { // TODO: 在此加入控制項告知處理常式程式碼 *pResult = 0; //不正當寫法 //copy from OnTvnSelchangedTree LPNMTREEVIEW pNMTreeView = reinterpret_cast(pNMHDR); // pNMTreeView->ptDrag; //此point無法直接換算取得目前點擊的Item CPoint pt; pt.x = pNMTreeView->ptDrag.y; // 此point位置無法理解. pt.y = pNMTreeView->itemNew.lParam; // 此point位置無法理解. HTREEITEM hCurItem = mTreectrl.HitTest(pt); if(hCurItem == NULL) return; //CString szText = mTreectrl.GetItemText(hCurItem);//驗證用,非必須. mTreectrl.SelectItem(hCurItem); }
方法2:
void TestDlg::OnNMClickTree(NMHDR *pNMHDR, LRESULT *pResult) { // TODO: 在此加入控制項告知處理常式程式碼 *pResult = 0; //正常寫法 CPoint pt; GetCursorPos(&pt); mTreectrl.ScreenToClient(&pt); HTREEITEM hCurItem = mTreectrl.HitTest(pt); if(hCurItem == NULL) return; //CString szText = mTreectrl.GetItemText(hCurItem);//驗證用,非必須. mTreectrl.SelectItem(hCurItem); }
方法1知道原理的朋友,歡迎留言解釋一下,感恩!

2013/08/29

[VC]GDI+繪圖

上次寫了一個GDI+做漸層效果,今天要再用就忘了一些步驟,所以把整個流程寫上來。

Step1.在stdafx.h中加入GDI+的Header file

#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")

Step2.在CWinApp中加入成員變數

GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
在CWinApp::InitInstance()中初始化GDI+資源

GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

Step3.至此,你的程式即可開始使用GDI+囉~

Step4.程式結束前,需釋放GDI+資源,請在CWinApp::ExitInstance()中加入:

GdiplusShutdown(gdiplusToken);

以小弟需求來說--->漸層<---以下程式碼請參考:
/*****MyClass.h*****/
class CMyClass:public CWnd
{
DECLARE_DYNAMIC(CMyClass)
public:
 CMyClass();
 virtual ~CMyClass();  

protected:
 afx_msg void OnPaint();
 
private:
 Gdiplus::PointF  m_gdiPoint1,m_gdiPoint2;
 Gdiplus::Color  m_gdiColor1,m_gdiColor2;
};

/*****MyClass.cpp*****/
CMyClass::CMyClass()
{
 vm_gdiPoint1 =PointF(0,0);
 vm_gdiPoint2 =PointF(0,18);
 vm_gdiColor1 =Color(255,255,255);
 vm_gdiColor2 =Color(0,0,0);
}

void CMyClass::OnPaint()
{
 CPaintDC dc(this);
 CRect rcBar;
 GetClientRect(&rcBar);
 //GDI+
 Gdiplus::LinearGradientBrush  gdiBrush(m_gdiPoint1,m_gdiPoint2,m_gdiColor1,m_gdiColor2);
 Gdiplus::RectF gdiRc((Gdiplus::REAL)rcBar.left,(Gdiplus::REAL)rcBar.top, (Gdiplus::REAL)rcBar.Width(),(Gdiplus::REAL)rcBar.Height());
 Graphics grThis(dc.m_hDC);
 grThis.FillRectangle( &gdiBrush, gdiRc);
}

ref:CodeProject_GDI+
ref:MSDN_GDI+

2013/08/06

[VC] UNICODE 下的字串

從前寫好的ANSI CODE,在要編譯成UNICODE時,常會遇到字元bytes數問題,
往往都需在字串前強制加上L轉型成wchar;不過L到底是啥意思咧?

以下簡單介紹:

1. L"string"
表示將 ANSI字串轉換成unicode字串,就是每個英數字佔用兩個byte。

2. _T("string")
根據你的環境設置,編譯器會根據編譯目標環境選擇合適的(Unicode還是ANSI)字符處理方式。
如果你定義了UNICODE,那麼_T會把字符串前面加一個L。即此時的 _T("ABCD") 等同於 L"ABCD"。 
如果沒有定義 UNICODE,那麼_T不會在字符串前面加那個L,_T("ABCD") 就等價於 "ABCD"

3. TEXT("str")、_TEXT("str")、_T("str")
這三個MACRO都是一樣的意思,即交由編譯器自動判斷。
如下面三語句:   
TCHAR   szStr1[]   =   TEXT("str1");   
char   szStr2[]   =   "str2";   
WCHAR   szStr3[]   =   L("str3");   

當環境設置為UNICODE時,szStr1與str3所佔bytes數相等,
當環境未設置為UNICODE時,szStr1與str2所佔bytes數相等,

無論環境是否設置UNICODE,
str2永遠生成ANSI字串
str3永遠生成UNICODE字串

引用結論:為了程序的可移植性,建議盡量使用_T()表示字串。   

ref. http://www.cnblogs.com/txwsh1/archive/2008/03/06/1093335.html

2013/07/08

[MFC]CButton類如何響應WM_LBUTTONDOWN or WM_LBUTTONUP

建立一個button在dialog上的時候,他預設只有兩種事件可以響應,一是BN_CLICKED,另一則是BN_DOUBLECLICKED,那我要滑鼠左鍵按下與彈上的事件該怎麼做呢?

VC6是這樣做的:
1.在原Dialog下新增一CMyButton類別,其父類別為CButton。
2.為MyButton類別添加WM_LBUTTONDOWN與WM_LBUTTONUP的消息響應。
3.在Dialog下宣告一個MyButton的成員變數。
4.在MyButton.cpp->CMyButton::OnLButtonDown 內編輯你要滑鼠左鍵按下時,要做什麼事。

2013/07/04

[MFC] Tree Control Item 如何辨識唯一值

當我們在TreeCtrl上新增Item完後,若要在之後的操作中,判別此Item是否為唯一項目,目前只知道能用ItemText來判斷,但萬一ItemText非唯一值時,這樣的判斷方式就會有問題!
為了避免這樣的狀況發生,我在新增Item時,偷用一個欄位:lParam
先在.h定義一個與Item相關的其他訊息結構:
typedef struct _treeItemInfo;
{
long nId;
//也可以放入其他需要紀錄的資訊,如 char sTextEx[8];
} ITEMINFO, *PITEMINFO;

然後在.cpp內修改tree insert的部份:

void CMyDlg::InsertNewItem()
{
HTREEITEM hSubItem;//新增Item後會回傳Item handle
TV_INSERTSTRUCT tvis;
TV_ITEM tvi;//set item member data
tvi.mask= TVIF_TEXT;
tvi.pszText= "test";//顯示在Item上的文字
//set insert struct;
member data
tvis.item= tvi;//insert items into CTreeCtrl
tvis.hParent= NULL;//此為根結點,故父節點為NULL
tvis.hInsertAfter= TVI_ROOT;//此為根結點
hSubItem = m_tree.InsertItem(tvis);

//方法1
PITEMINFO l_pItemEx = new ITEMINFO;
l_pItemEx->nId = 1000;
strcpy(l_pItemEx->sTextEx,"MyInfo");
m_tree.SetItemData( hSubItem, l_pItemEx);//將序號結構地址與此節點綁在一起
//方法2
DWORD dItemId = 1000;//表示Item序號
m_tree.SetItemData( hSubItem, dItemId);//將序號與此節點綁在一起
}

當滑鼠拖曳某項Item時,會響應TVN_BEGINDRAG消息,這時從響應函式內將ID取出。
void CMyDlg::OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast LPNMTREEVIEW(pNMHDR);
*pResult = 0;
// TODO: 在此加入控制項告知處理常式程式碼

DWORD tmpId;
//方法1
HTREEITEM hDragItem = ((NM_TREEVIEW*)pNMHDR)->itemNew.hItem;
PITEMINFO l_pTmpItemEx = (PITEMINFO)m_tree.GetItemData(hDragItem);
tmpId = m_tree.GetItemData(hDragItem);
}

//方法2
TVITEM tvitem= ((NM_TREEVIEW*)pNMHDR)->itemNew;
tmpId = tvitem.lParam;
//取得ID後,作你想做的事吧!

ps.方法1&2選一個用即可。

參考:StackOverflow  how to create new Property for MFC(VC++) treeview Control?

[MFC]多消息響應同一函式

以前的寫法都是 one message mapping one function,
但有時候其實多個消息要做的事情,都會對到同一個對象,只是做的動作不同,
例如對同一個表單做新增、刪除、修改、查詢這樣的狀況,
這時候就可以用 ON_COMMAND_RANGE囉~

舊做法:
ON_COMMAND(ID_TREEITEM_ADD, &CMyDialog::OnTreeItemAdd)
ON_COMMAND(ID_TREEITEM_DEL, &CMyDialog::OnTreeItemDel)
ON_COMMAND(ID_TREEITEM_MODIFY, &CMyDialog::OnTreeItemModify)

void CMyDialog::OnTreeItemAdd()
{
m_tree.add(hItem);
}

void CMyDialog::OnTreeItemDel()
{
m_tree.delete(hItem);
}


void CMyDialog::OnTreeItemModify()
{
m_tree.Modify(hItem);
}

改為:

ON_COMMAND_RANGE(ID_TREEITEM_ADD,ID_TREEITEM_MODIFY, &CMyDialog::OnTreeItem)

//此作法需注意:ID_TREEITEM_ADD、ID_TREEITEM_DEL、ID_TREEITEM_MODIFY在resource.h中必須為連續數,如1、2、3。

void CMyDialog::OnTreeItem(UINT nID)
{
    switch(nID)
    {
    case ID_TREEITEM_ADD:
    m_tree.add(hItem);
    break;
    case ID_TREEITEM_DEL:
        m_tree.del(hItem);
        break;
    case ID_TREEITEM_MODIFY:
        m_tree.Modify(hItem);
        break;
    default:
        break;
    }
}

//m_tree的add del modify只是示意,並非真的有此member function,詳見msdn CTreeCtrl

本篇參考:msdn ON_MESSAGE_RANGE