电竞比分网-中国电竞赛事及体育赛事平台

分享

C&C++ | 肆零玖陸

 junshuai103 2014-09-15

分類存檔: C&C++

基于MFC的ActiveX控件開發(fā)(6)

6.屬性頁

屬性頁使 ActiveX 控件用戶得以查看和更改 ActiveX 控件屬性??赏ㄟ^調用控件屬性對話框訪問這些屬性。該對話框包含一個或多個屬性頁,這些屬性頁提供自定義的圖形界面用于查看和編輯控件屬性。

使用默認屬性頁

創(chuàng)建ActiveX控件項目后,系統就自動為我們添加了一個屬性頁類,這里就是Cactivexdemo1PropPage。同時在對話框資源里也會有一個屬性頁對話框資源,這里就是IDD_PROPPAGE_ACTIVEXDEMO1。

在ActiveX控件測試容器中點擊工具欄上的屬性按鈕,就會看到這個屬性頁對話框。

比如就像下圖這樣。當然這個上面什么還沒有。

如果是在使用控件開發(fā)時,則在選中控件后,在屬性窗口中點擊屬性頁按鈕可以打開這個屬性頁,開發(fā)人員可以在這個彈出的屬性頁窗口中設定控件的屬性。

如果要通過屬性頁修改控件屬性,那么就要通過在屬性頁上放置一些控件給用戶來修改屬性值。比如我們上面添加了一個Caption屬性,我們要在屬性頁上提供修改這個屬性的功能一般就是要用一個文本輸入框。這樣我們在屬性頁的對話框上放置一個Edit控件,設id為IDC_EDIT_CAPTION。然后為這個Edit控件綁定一個變量。用右鍵點這個Edit控件,學則添加變量,打開

在添加成員變量向導中添加一個新變量,設為m_caption,這里注意要把類型設為Value,由于屬性是個字符串,所以這個地方變量類型也使用CString。

然后我們來看一下屬性頁類中的一個DoDataExchange函數。這個函數是由系統自動調用的,用來將控件與成員變量進行數據交換。由于我們剛把Edit控件綁定了m_caption變量,在DoDataExchange已經給我們寫入了這么一句DDX_Text(pDX, IDC_EDIT_CAPTION, m_caption);,就是這一句實現了m_caption與Edit控件之間的數據交換。但此時控件Caption屬性還不能自動從Edit控件中填寫的值獲得,還需要一個操作,即DDP_Text(pDX, IDC_EDIT_CAPTION, m_caption, _T(“Caption”));,這樣就把Caption屬性與與屬性頁中的m_caption變量綁定,這樣每當我們在修改了屬性頁窗口中的Edit控件內容后,就能修改控件的Caption。

那么完整的DoDataExchange函數就應該像下面這樣。

void Cactivexdemo1PropPage::DoDataExchange(CDataExchange* pDX)

{

DDX_Text(pDX, IDC_EDIT_CAPTION, m_caption);

DDP_Text(pDX, IDC_EDIT_CAPTION, m_caption, _T(“Caption”));

DDP_PostProcessing(pDX);

}

另外注意這個地方DDP_PostProcessing是系統自動生成的代碼,這句話一定要放在DDX_Text和DDP_Text的后面,否則不能實現控件屬性與屬性頁上控件的綁定。至此,我們就可以在設計時通過這個屬性頁來修改Caption屬性,而不必通過程序代碼來修改了。

添加其他自定義屬性頁

默認情況下只有一個屬性頁,如果需要設置的屬性太多就需要另外添加自定義屬性頁。

新添加屬性頁的方法是這樣的,打開VS的資源視圖,添加一個新的Dialog資源。

在這里我們選擇IDD_OLE_PROPPAGE_SMALL,當然也可以選和Large。給這個新資源ID指定為IDD_OLE_PROPPAGE_SMALL。

然后需要給這個資源新建一個關聯類。這個關聯類應當是MFC類,設類名為CPropPage1,基類應當是COlePropertyPage,對話框ID選擇我們新添加的這個對話框資源ID。

然后,打開控件類Cactivexdemo1Ctrl的cpp文件,找到屬性頁的宏聲明部分。

BEGIN_PROPPAGEIDS(Cactivexdemo1Ctrl, 1)

PROPPAGEID(Cactivexdemo1PropPage::guid)

END_PROPPAGEIDS(Cactivexdemo1Ctrl)

把我們新建的這個屬性頁添加進去,并將屬性頁計數加一。

// TODO: 按需要添加更多屬性頁。請記住增加計數!

BEGIN_PROPPAGEIDS(Cactivexdemo1Ctrl, 2)

PROPPAGEID(Cactivexdemo1PropPage::guid)

PROPPAGEID(CPropPage1::guid)

END_PROPPAGEIDS(Cactivexdemo1Ctrl)

這樣就把新添加的這個屬性頁附加到控件中去了,再打開控件的屬性頁就會看到多了一個屬性頁了。

常用屬性頁

除了可以根據需要自定義屬性頁外,系統還提供給開發(fā)人員一些預制的常用屬性頁,如顏色、字體等屬性頁。MFC 提供了三個與 ActiveX 控件一起使用的常用屬性頁:CLSID_CColorPropPage、CLSID_CFontPropPage  和 CLSID_CPicturePropPage。這些頁分別顯示常用顏色、字體和圖片屬性的用戶界面。

要將這些屬性頁合并到控件中,只需要請將它們的 ID 添加到初始化控件的屬性頁 ID 數組的代碼。也就是在類控件Cactivexdemo1Ctrl的cpp文件中的PROPPAGEIDS聲明處修改成如下形式。與自定義屬性頁中相同,也需要增加屬性頁計數。

// TODO: 按需要添加更多屬性頁。請記住增加計數!

BEGIN_PROPPAGEIDS(Cactivexdemo1Ctrl, 3)

PROPPAGEID(Cactivexdemo1PropPage::guid)

PROPPAGEID(CPropPage1::guid)

PROPPAGEID( CLSID_CColorPropPage )

END_PROPPAGEIDS(Cactivexdemo1Ctrl)

這樣就在屬性頁里添加了一個顏色屬性頁,但要想使用這個屬性頁還需要添加幾個常用屬性,比如說我們希望能通過這個屬性頁設定BackColor和ForeColor屬性,就參照常用屬性一節(jié)中的方法添加一個BackColor和一個ForeColor屬性,編譯生成控件后在ActiveX控件測試容器中點擊工具欄中的屬性。

在彈出的屬性窗口中就能看到有關這兩個屬性的設定了。

若要使用顏色屬性,則需要調用COleControl::TranslateColor成員函數。此函數的參數為顏色屬性值和可選的調色板句柄。返回值為 COLORREF 值,可以將它傳遞給 GDI 函數,如 SetTextColor 和 CreateSolidBrush。下例說明如何在繪制控件時使用這兩個顏色屬性。

CBrush bkBrush(TranslateColor(GetBackColor()));

COLORREF clrFore = TranslateColor(GetForeColor());

pdc->FillRect( rcBounds, &bkbrush );

pdc->SetTextColor( clrFore );

pdc->DrawText( InternalGetText(), -1, rcBounds, DT_SINGLELINE | DT_CENTER | DT_VCENTER );

全文完  全文下載

上一篇

基于MFC的ActiveX控件開發(fā)(5)

5.屬性

屬性是 ActiveX 控件中向所有容器公開的數據成員。與事件和方法類似,也分為常用屬性和自定義屬性。

常用屬性

常用屬性已由 COleControl 類實現。COleControl 類包含支持控件的通用屬性的預定義成員函數。某些通用屬性包括控件的標題以及前景色和背景色。

添加常用屬性的操作是在類視圖中打開庫節(jié)點,在本例中就是activexdemo1Lib節(jié)點。選中第二個節(jié)點,也就是本例中的_Dactivexdemo1,在右鍵菜單中選擇添加屬性,打開添加屬性向導。選中實現類型下的常用,在屬性名下選擇要添加的屬性,比如在此我們選擇的是Caption。

然后在類視圖中就能看到新添加的這個屬性。

這個Caption也就是我們在使用控件進行開發(fā)的時候,控件屬性窗口中的那個Caption屬性。

在開發(fā)環(huán)境中我們可以用控件變量的GetCaption和SetCaption來獲取和設定控件的這個屬性。

比如在測試項目中的DoClick按鈕的點擊事件函數中如下修改:

void Ct1Dlg::OnBnClickedButton1()

{

// TODO: 在此添加控件通知處理程序代碼

MessageBox(m_activexdemo.GetCaption());

m_activexdemo.SetCaption(_T(“change”));

MessageBox(m_activexdemo.GetCaption());

}

這樣在點擊DoClick按鈕的時候會顯示控件的Caption名稱對話框,然后修改名稱,再把修改后的名稱顯示在彈出的對話框中。

如果是在ActiveX控件測試容器中的話,我們還是打開調用方法窗口,在方法名中會看到Caption(ProPut)和Caption(ProGet)的方法,也就是對應上面的SetCaption 和GetCaption,同樣在這里也可以試著給Caption修改內容并獲取修改后的值。

自定義屬性

自定義屬性與常用屬性的區(qū)別在于,自定義屬性未由 COleControl 類實現。自定義屬性用于將 ActiveX 控件的某個狀態(tài)或外觀向使用該控件的程序員公開。

添加自定義屬性的操作是在類視圖中打開庫節(jié)點,在本例中就是activexdemo1Lib節(jié)點。選中第二個節(jié)點,也就是本例中的_Dactivexdemo1,在右鍵菜單中選擇添加屬性,打開添加屬性向導。這里自定義屬性有成員變量和Get/Set方法兩種。

成員變量屬性

我們先看一下成員變量這種屬性。根據需要選擇屬性的類型,并填入屬性名,同時變量名和通知函數會被自動填入,如不滿意默認的名稱也可以手動修改這兩個名稱。

其中這個變量名是作為控件類的一個成員變量來存儲控件屬性的,比如選中類視圖中的的控件類,也就是Cactivexdemo1Ctrl,就會在下面看到這個m_MyProp1成員變量。

這種自定義屬性的使用與常用屬性類似,在ActiveX控件測試容器中也是有著MyProp1(ProPut)和MyProp1 (ProGet)這樣的方法以供測試時調用,在開發(fā)時也會有屬性出現在控件的屬性窗口中,在程序中也是可以通過GetMyProp1和SetMyProp1來獲取和設置屬性值。

而通知函數是當這個屬性被修改是所觸發(fā)的一個函數。被定義為控件類中的一個成員函數。

舉個例子,假如我們在這個函數中寫入如下代碼:

void Cactivexdemo1Ctrl::OnMyProp1Changed(void)

{

AFX_MANAGE_STATE(AfxGetStaticModuleState());

// TODO: 在此添加屬性處理程序代碼

MessageBox(_T(“MyProp1 Changed.”));

SetModifiedFlag();

}

然后在ActiveX控件測試容器中調用MyProp1(PropPut)來修改這個屬性值,則會彈出這個對話框。同樣的,在開發(fā)時如果在屬性窗口中修改此屬性值或在代碼里修改此屬性值都會觸發(fā)這個通知函數,進而彈出我們代碼中的對話框。

Get/Set方法型屬性

添加Get/Set方法型屬性則是在添加屬性向導窗口中的實現類型中選中Get/Set方法,指定屬性類型和屬性名,向導會自動填入Get和Set函數,同時可以指定自定義的參數。

然后在控件類的定義中就會出現GetMyProp2(void)和SetMyProp2(LPCTSTR newVal)兩個函數,分別用于獲取和設置屬性值。但要注意的是,如果看一下這兩個函數的代碼的話,這兩個自動生成的函數實際上并沒有真正起到獲取和設置屬性值的功能,這只是兩個框架,基本上什么也沒做,如果放在ActiveX控件測試容器中調用這兩個函數的話會看不到什么反應,于是就還需要我們來手動定義函數的具體功能。

比如說我們可以為控件類添加一個成員變量用來存儲我們的屬性值,由于我們這個屬性定義的是BSTR類型,我們可以把添加的這個成員變量聲明為CString m_MyProp2,然后分別修改GetMyProp2(void)和SetMyProp2(LPCTSTR newVal)為如下:

BSTR Cactivexdemo1Ctrl::GetMyProp2(void)

{

AFX_MANAGE_STATE(AfxGetStaticModuleState());

CString strResult(m_MyProp2);

// TODO: 在此添加調度處理程序代碼

return strResult.AllocSysString();

}

void Cactivexdemo1Ctrl::SetMyProp2(LPCTSTR newVal)

{

AFX_MANAGE_STATE(AfxGetStaticModuleState());

// TODO: 在此添加屬性處理程序代碼

m_MyProp2=newVal;

SetModifiedFlag();

}

然后在ActiveX控件測試容器中先調用SetMyProp2給屬性賦值,然后用GetMyProp2就能返回剛才新賦的屬性值了。

另外要注意的是,剛才定義這個屬性的時候,參數列表是留空的,默認得到的就是上面SetMyProp2和GetMyProp2兩個函數,如果在參數列表里添加了其他參數的話,那么新加的參數就會被添加到這兩個函數的參數列表中去。比如我們添加個BSTR型屬性MyProp3,在參數列表里加上一個LONG arg參數,那么得到的兩個函數將是GetMyProp3(LONG arg)和SetMyProp3(LONG arg, BSTR newVal)。

上一篇 | 下一篇

基于MFC的ActiveX控件開發(fā)(4)

4.方法

方法就是控件開放給用戶使用的一些功能函數,類似于C++的類函數。控件方法分兩類,一類是常用方法,其實現由父類COleControl 提供。自定義方法由開發(fā)人員定義,由此向用戶提供自定義的功能實現。

常用方法

COleControl 支持兩個常用方法:DoClick 和 Refresh。Refresh 由控件的用戶調用,用以立即更新控件的外觀;而調用 DoClick 是用于引發(fā)控件的 Click 事件。

添加常用方法的操作是在類視圖中打開庫節(jié)點,在本例中就是activexdemo1Lib節(jié)點。選中第二個節(jié)點,也就是本例中的_Dactivexdemo1,在右鍵菜單中選擇添加方法,打開添加方法向導。

在方法名中選擇需要添加的常用方法。比如DoClick。

然后在類視圖中選中_Dactivexdemo1,就會在下面看到我們剛才添加的那個常用方法。同時,你也可以在這里看到有一個AboutBox方法,這是系統自動給我們添加進去的,功能是顯示一個About窗口,這個窗口可以在項目的資源視圖中的Dialog下找到并編輯。

同樣也要驗證一下這個新添加的方法。還是打開ActiveX控件測試容器,添加此控件,然后點擊工具欄上的這個紅色方框,也就是調用方法。

在調用方法對窗口的方法名中選中我們剛添加的這個DoClick方法,然后點擊調用。還記得這個DoClick是干什么的來著嗎?,對了,它是要引發(fā)Click事件的,上面介紹事件的時候我們已經添加了Click這個常用事件了,那么現在調用DoClick也就是要引發(fā)我們在上面添加的這個Click事件了,于是在測試容器主窗口的消息框中出現了activexdemo1 Control: Click。

那么在開發(fā)環(huán)境中是什么效果呢?

好,再回到剛才那個測試項目里。我們先在窗體上添加一個按鈕,就叫DoClick,等會用點擊它的方式來調用DoClick方法。

然后為了方便操作,我們先給剛才添加到對話框中的那個控件添加一個綁定的對象變量。鼠標右擊控件選擇添加變量。

在添加成員變量向導中添加與此控件綁定的控件變量,比如叫做m_activexdemo。

然后,雙擊剛才新加到窗體上的那個按鈕,即添加這個按鈕的鼠標點擊事件函數中,如下添加一行代碼,即調用控件的DoClick方法。

void CtestMFCDlg::OnBnClickedButton1()

{

// TODO: 在此添加控件通知處理程序代碼

m_activexdemo.DoClick();

}

最后,編譯運行測試程序,點擊DoClick按鈕,結果彈出Hi.對話框。這就是說,我們通過執(zhí)行控件對象的DoClick方法引發(fā)了控件的鼠標點擊事件,因此上文常用事件一節(jié)中我們添加的事件處理函數ClickActivexdemo1ctrl1被執(zhí)行了。

自定義方法

自定義方法與常用方法的區(qū)別在于,自定義方法未由 COleControl 實現。必須為添加到控件的每個自定義方法提供實現。

添加自定義方法的操作是在類視圖中打開庫節(jié)點,在本例中就是activexdemo1Lib節(jié)點。選中第二個節(jié)點,也就是本例中的_Dactivexdemo1,在右鍵菜單中選擇添加方法,打開添加方法向導。

在添加方法向導里添加需要自定義的方法的名稱、返回值和參數。

注意這里有個內部名稱,默認情況是與上面的方法名一樣,但是也可以修改為其他名,這個內部名稱是方法在控件類內的函數名稱,比如這里我們的方法名為MyThod,則選中類視圖中的庫接口下的第二個節(jié)點,下面會出現剛定義的MyMethod方法。

而選中控件類Cactivexdemo1Ctrl,下面會看到在這個類中定義的方法名稱就是我們上面指定內部名稱MyMethodInner。

而方法的具體功能也就是在這個內部函數中實現。比如我們如下定義MyMethodInner:

void Cactivexdemo1Ctrl::MyMethodInner(LPCTSTR msg)

{

AFX_MANAGE_STATE(AfxGetStaticModuleState());

// TODO: 在此添加調度處理程序代碼

MessageBox(msg);

}

也就是說要彈出一個消息對話框,消息內容就是參數中傳遞的字符串。

然后來測試一下效果,首先還是ActiveX控件測試容器,打開調用方法窗口,在方法名中會看到我們定一個MyMethod,選擇之,然悔會在參數區(qū)看到我們定義的msg參數,選中,然后在下面參數值中填入你想傳遞給參數的值,比如hello,然后點擊設置值,最后點擊調用,MyMethodInner就會被執(zhí)行,也就是彈出hello消息窗口。

然后再看一下使用控件開發(fā)的時候的效果。

回到測試項目,還記得那個DoClick按鈕吧,還是用這個,不過有點小問題,因為上面我們?yōu)檫@個控件綁定控件變量的時候還沒有這個自定義方法,所以在綁定的時候生成的控件類定義中沒有這個方法,就無法測試了。為了省事,我們就干脆新建一個項目,像前文提到的那樣添加控件,綁定控件變量,在DoClick的單擊事件中寫入如下代碼:

void Ct1Dlg::OnBnClickedButton1()

{

// TODO: 在此添加控件通知處理程序代碼

m_activexdemo.MyMethod(_T(“This is mymethod.”));

}

編譯執(zhí)行,點擊DoClick按鈕,就會看到那個This is mymethod消息框了。

上一篇 | 下一篇

基于MFC的ActiveX控件開發(fā)(3)

3.事件

ActiveX 控件使用事件通知容器控件上發(fā)生了某些事情。事件的常見示例包括單擊控件、使用鍵盤輸入數據和控件狀態(tài)更改。當發(fā)生這些操作時,控件將引發(fā)事件以提醒容器。

MFC 支持兩種事件:常用和自定義。常用事件是 COleControl 類自動處理的事件。自定義事件使控件得以在該控件特定的操作發(fā)生時通知容器??丶炔繝顟B(tài)發(fā)生更改或收到某個窗口消息即屬于此類事件。

常用事件

常用事件由 COleControl 類自動引發(fā)。COleControl 包含預定義成員函數,它們引發(fā)常見操作所導致的事件。一些由 COleControl  實現的常見操作包括單擊和雙擊控件、鍵盤事件和鼠標按鈕狀態(tài)發(fā)生更改。

添加常用事件的操作是在類視圖中右擊ActiveX 控件類,比如在此例中就是Caxtivexdemo1Ctrl。在菜單中選擇添加事件,打開添加事件向導。

在添加事件向導中的事件名稱中選擇Click,也就是鼠標點擊事件,添加到控件中。然后再選中類視圖中庫節(jié)點下的第三個節(jié)點,也就是Dactivexdemo1Events。在下面就能看到我們剛剛添加的這個事件。

然后生成新的控件程序,我們來看看測試一下這個新事件。

打開上面提到的ActiveX控件測試容器,把這個控件添加進來,用鼠標點擊控件,就會在程序下方的消息欄中看到activexdemo1 Control: Click這樣的消息,這就是我們添加進去的鼠標相應事件。

那在開發(fā)環(huán)境中使用控件的時候是什么樣子的呢?好,像上面提到過的那樣新建一個對話框項目,把控件放到對話框上。選中這個控件,在屬性窗口中的控件事件中就有這個Click事件了,如果在使用控件中需要相應鼠標點擊事件,就點添加ClickActivexdemo1ctrl1,事件響應函數中添加你需要的功能了。

比如像這樣:

void CtestMFCDlg::ClickActivexdemo1ctrl1()

{

// TODO: 在此處添加消息處理程序代碼

MessageBox(_T(“Hi.”));

}

編譯運行這個測試程序,點擊控件位置就會彈出帶有Hi.字樣的MessageBox。

自定義事件

自定義事件與常用事件的區(qū)別在于,自定義事件不由 COleControl 類自動引發(fā)。自定義事件將控件開發(fā)人員確定的某一操作識別為事件。

添加常用事件的操作是在類視圖中右擊ActiveX 控件類,比如在此例中就是Caxtivexdemo1Ctrl。在菜單中選擇添加事件,打開添加事件向導。定義一個叫做MyEvent的事件,事件可以帶參數,比如我們加個BSTR的參數msg。

然后,回到類視圖,這次選中庫節(jié)點下的第三個節(jié)點,也就是_Dactivexdemo1Events,在下面就會看到新添加的這個事件。

再選中類視圖中的控件類,即Cactivexdemo1Ctrl,下面也會出現一個MyEvent函數。

雙擊這個MyEvent可以看到定義代碼如下:

void MyEvent(BSTR  msg)

{

FireEvent(eventidMyEvent, EVENT_PARAM(VTS_PI1), msg);

}

這里的這個MyEvent(BSTR msg)函數就是用于觸發(fā)MyEvent事件用的,什么意思呢,就是說當在控件中需要出發(fā)自定義的這個MyEvent的時候調用這個MyEvent(BSTR msg)就可以了。下面結合例子看看是怎么回事。

比如說我們希望用戶鼠標雙擊左鍵的時候觸發(fā)這個事件,就這么來作。選中類視圖中的控件類,即Cactivexdemo1Ctrl,然后在消息窗口中找到WM_LBUTTONDBCLK,添加這個消息的處理函數。

在消息處理函數中如下修改:

void Cactivexdemo1Ctrl::OnLButtonDblClk(UINT nFlags, CPoint point)

{

// TODO: 在此添加消息處理程序代碼和/或調用默認值

MyEvent(_T(“HI, MyEvent.”));

COleControl::OnLButtonDblClk(nFlags, point);

}

這樣每次用戶在雙擊控件的時候就會觸發(fā)我們自定義的MyEvent事件了。

然后看一下測試效果。

打開ActiveX控件測試容器,添加這個控件,然后雙擊控件,看消息框里出現什么了?

由于雙擊自然也就是兩次單擊,所以會同時出現兩種事件。

activexdemo1 Control: MyEvent {msg=72}

activexdemo1 Control: Click

打開測試項目,控件的控件事件里就多了一個MyEvent事件。

添加一個針對此事件的處理函數MyEventActivexdemo1ctrl1 (LPCTSTR msg),msg就是我們定義事件時的那個msg參數,在上面的定義中我們是傳遞了一個”HI, MyEvent.”字符串消息?,F在看看是不是這個樣子。在MyEventActivexdemo1ctrl1函數中我們顯示一個MessageBox,把msg參數打印出來。

void CtestMFCDlg::MyEventActivexdemo1ctrl1(LPCTSTR msg)

{

// TODO: 在此處添加消息處理程序代碼

MessageBox(msg);

}

同時注意要把上面常用事件中定義的Click事件的處理函數ClickActivexdemo1ctrl1注釋掉,然后編譯運行程序后雙擊控件就會彈出HI, MyEvent.對話框。也就是說,由于雙擊操作觸發(fā)了我們定義的MyEvent事件,進而調用MyEvent的處理函數。

上一篇 | 下一篇

基于MFC的ActiveX控件開發(fā)(2)

2.生成并測試控件

好,現在我們就可以先來生成一下這個項目,當然到目前我們只是用系統自動生成的一個控件項目,什么功能都沒有,只是一個空框架。

幾秒鐘后,項目應該是順利生成??丶脖蛔詣幼缘较到y中去。那怎么才能測試一下這個控件呢?當然你可以再建個新項目,比如一個對話框程序,在對話框資源編輯窗口中右邊的工具箱里鼠標右鍵菜單里點選擇項。

從彈出窗口中的COM組件下找到我們剛剛生成的這個控件,打勾選中。

然后在工具箱里就會出現這個控件。

然后用鼠標拖到對話框里就能用這個控件了。

除了這種方法,VS還提供了一種簡便的控件測試工具。在VisualStudio中菜單的工具下有個ActiveX控件測試容器。

在工具欄里點新控件按鈕。

在插入控件對話框中找到并選擇我們的這個控件。

然后就能在這個容器中測試控件的各種功能了。

上一篇 | 下一篇

基于MFC的ActiveX控件開發(fā)(1)

ysm
cleverysm@gmail.com

全文下載

ActiveX 控件是基于組件對象模型 (COM) 的可重用軟件組件,廣泛應用于桌面及Web應用中。在VC下ActiveX控件的開發(fā)可以分為三種,一種是直接用COM的API來開發(fā),這樣做顯然非常的麻煩,對程序員要求也非常高,因此一般是不予考慮的;一種是基于傳統的MFC,采用面向對象的方式將COM的基本功能封裝在若干MFC的C++類中,開發(fā)者通過繼承這些類得到COM支持功能。MFC為廣大VC程序員所熟悉,易于上手學習,但缺點是MFC封裝的東西比較多,因此用MFC開發(fā)出來的控件相對會比較大,因此比較適于開發(fā)桌面ActivexX控件,尤其是有GUI界面的控件。第三種就是基于ATL的,ATL可以說是專門面向COM開發(fā)的一套框架,使用了C++的模板技術,在運行時不需要依賴于類似MFC程序所需要的龐大的代碼模塊,更適合于Web應用開發(fā)。

本文介紹的是采用第二種方式,即應用MFC進行桌面可視控件開發(fā)的方法步驟,開發(fā)環(huán)境則是基于VC2005。

1.創(chuàng)建控件項目

打開VC2005后,我們要先創(chuàng)建一個項目,在新建項目頁的左側選擇Visual C++-MFC,在右側選擇MFC ActiveX控件,填上解決方案和項目名稱,比如在這里我的項目名稱是activexdemo1,解決方案名稱是activexdemo。

然后進入控件向導頁,在向導的第二頁有個運行時許可證,選中這個的話會在生成控件的同時生成一個許可證文件,其他用戶在使用這個控件的時候必須同時附有這個許可證,在此我們保持默認狀態(tài),不選。

下一頁是關于項目中各部分的命名問題,可以根據需要自定義,這里就按默認的情況不做修改了。

下一頁是選擇控件基于哪種控件的擴展以及控件的一些基本特性。如果新建的控件是基于某種特定控件的話,就在創(chuàng)建的控件基于下選擇所要繼承的控件名,否則就保持none。下方的附加功能根據實際需要進行選擇,并且可以將鼠標放置于選項上方,功能的說明會自動顯示在動態(tài)出現的小提示信息窗口中。選擇完畢點擊完成,向導就根據你的選擇生成新項目。

進入開發(fā)環(huán)境,我們可以先看一下類視圖。

其中的Cactivexdemo1App是我們這個控件的主程序模塊,定義了控件的注冊(DllRegisterServer)、刪除(DllUnregisterServer)等功能,一般不用動,如有需要我們可以在其中的InitInstance和ExitInstance中定義我們自己的初始化和終止操作代碼,一般也就是一些資源的初始化和銷毀工作。

Caxtivexdemo1Ctrl是控件類,我們要做的控件功能基本上就是要在這個類中實現。

需要提一下的是在這個類中重寫了父類的OnDraw函數,有如下兩句代碼:

pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));

pdc->Ellipse(rcBounds);

也就是在控件上畫了一個橢圓,實際控件開發(fā)中可以根據功能需要修改重寫這個函數來繪制控件界面。

Caxtivexdemo1PropPage是屬性頁類,這個類實現了一個在開發(fā)時設定控件屬性的對話框。

activexdemo1Lib是為客戶程序提供本控件的屬性、方法以及可能響應的事件的接口的庫節(jié)點,在添加控件的這些功能的時候會用得到。

其中的Cactivexdemo1App是我們這個控件的主程序模塊,定義了控件的注冊(DllRegisterServer)、刪除(DllUnregisterServer)等功能,一般不用動,如有需要我們可以在其中的InitInstance和ExitInstance中定義我們自己的初始化和終止操作代碼,一般也就是一些資源的初始化和銷毀工作。

Caxtivexdemo1Ctrl是控件類,我們要做的控件功能基本上就是要在這個類中實現。

需要提一下的是在這個類中重寫了父類的OnDraw函數,有如下兩句代碼:

pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));

pdc->Ellipse(rcBounds);

也就是在控件上畫了一個橢圓,實際控件開發(fā)中可以根據功能需要修改重寫這個函數來繪制控件界面。

Caxtivexdemo1PropPage是屬性頁類,這個類實現了一個在開發(fā)時設定控件屬性的對話框。

activexdemo1Lib是為客戶程序提供本控件的屬性、方法以及可能響應的事件的接口的庫節(jié)點,在添加控件的這些功能的時候會用得到。

下一篇

VC2005下使用GSL

ysm

cleverysm@gmail.com

GSL是當今三大數學庫之一(據說哈),功能強大,可以用來替代臃腫龐大的matlab,是我這種喜歡拿C/C++寫程序的家伙的最佳選擇,今天拿來研究一下,順便總結一下安裝使用的方法。

GSL全稱GNU Scientific Lib,一看GNU就知道是Linux/Unix系統下的東東,可項目要在Windows下來做,型號有人做了windows下的版本,而且有針對VC2005的。能下載到的GSL我知道的有兩種,一個是在http://www6.in./~kiss/WinGsl.htm,這個地方有已經編譯好的庫,只不過這個網站上的許久沒更新了,也只有VC6和VC2003的庫文件,不過VC2003的應該也能用在VC2005下,今天不打算用這個,太舊了。

另一個是GNUWIN32下的,在http://gnuwin32./packages/gsl.htm,需要下載的是源文件Sources。下載下來是一個exe文件,執(zhí)行安裝。然后到C:\Program Files\GnuWin32\下找到一個src目錄,再往下進入\src\gsl\1.8\gsl-1.8(奇怪的目錄命名方式,開始菜單里也是如此),有個Readme_GnuWin32.txt文件,里面介紹了GunWin32的基本情況,根據文中最后一段的解釋,VC8所需要的文件就在C:\Program Files\GnuWin32\src\gsl\1.8\gsl-1.8\VC8中,進去,打開Readme_VC8.htm,里面介紹了在VC8下編譯的相關解決方案和項目。其中有3個解決方案sln,libgsl.sln、test_gsl.sln、gsl_examples.sln,分別是用于編譯gsl的庫文件、測試程序和示例程序。

首先我們需要打開libgsl.sln,其中又包含4個項目:libgsl就是用來編譯庫文件的;libgslcblas是用于編譯cblas,這個會在生成libgsl項目的同時編譯生成目標;copy_gsl_headers用于拷貝gsl所用的頭文件,這個是在編譯lib的時候調用的,可以不管它;install_libgsl則是將編譯生成的庫文件進行安裝拷貝,這個項目需在編譯完成庫文件后在執(zhí)行生成操作。每個項目都對應4個配置,分別是,Debug-DLL、Debug-StaticLib、Release-DLL和Release-StaticLib,其目標可以從名稱上明顯看出來。

然后開始編譯操作,選中l(wèi)ibgsl項目,分別在四種不同配置下生成項目,在libgsl和libgslcblas目錄下就會生成對應配置名稱的幾個文件夾,里面便是編譯過程中產生的中間文件和最終的庫文件。

最后是安裝這些lib和頭文件什么的,也就是生成install_libgsl項目。不過截至本文生成的這一天,從官網上下載下來的代碼的VC配置文件中有點小問題,如果你直接生成install_libgsl,會在C盤下生成一個libgsl-1.8目錄,下面會有l(wèi)ib、include等幾個目錄,但是檢查bin和lib目錄會發(fā)現下面什么都沒有,似乎那些lib和dll沒拷貝過來。為什么呢?經檢查,原因是install_libgsl項目的配置中有幾個目錄名字錯了。修改辦法是打開install_libgsl項目屬性中“配置屬性”-“生成事件”-“預生成事件”,查看右側的“命令行”,有如下幾行命令:

mkdir %LIBGSL_INSTALL_DIR%\bin

if exist .\..\libgsl\Debug – DLL\libgsl_d.dll copy .\..\libgsl\Debug – DLL\libgsl_d.dll %LIBGSL_INSTALL_DIR%\bin

if exist .\..\libgsl\Release – DLL\libgsl.dll copy .\..\libgsl\Release – DLL\libgsl.dll %LIBGSL_INSTALL_DIR%\bin

if exist .\..\libgsl\Debug – Static Lib\libgsl_d.lib copy .\..\libgsl\Debug – Static Lib\libgsl_d.lib %LIBGSL_INSTALL_DIR%\lib

if exist .\..\libgsl\Release – Static Lib\libgsl.lib copy .\..\libgsl\Release – Static Lib\libgsl.lib %LIBGSL_INSTALL_DIR%\lib可以看出來if exist .\..\libgsl\Debug – DLL\libgsl_d.dll和if exist .\..\libgsl\Debug – Static Lib\這么幾行中拷貝源目錄的路徑的Debug – DLL和Debug – Static Lib多了幾個空格,而libgsl項目生成的目標路徑中是沒有這些空格的,解決辦法就是刪掉這些個空格,改為Debug-DLL,要不就自己按照install_libgsl配置里的那幾個lib和dll文件自己拷出來得了,這個install_libgsl的四個配置其實都是一樣的,隨便生成哪一個都行。下面一段是我修改后的,懶得自己改的就把這段替換掉默認的就行。

mkdir %LIBGSL_INSTALL_DIR%\bin

if exist .\..\libgsl\Debug-DLL\libgsl_d.dll copy .\..\libgsl\Debug-DLL\libgsl_d.dll %LIBGSL_INSTALL_DIR%\bin

if exist .\..\libgsl\Release-DLL\libgsl.dll copy .\..\libgsl\Release-DLL\libgsl.dll %LIBGSL_INSTALL_DIR%\bin

if exist .\..\libgslcblas\Debug-DLL\libgslcblas_d.dll copy .\..\libgslcblas\Debug-DLL\libgslcblas_d.dll %LIBGSL_INSTALL_DIR%\bin

if exist .\..\libgslcblas\Release-DLL\libgslcblas.dll copy .\..\libgslcblas\Release-DLL\libgslcblas.dll %LIBGSL_INSTALL_DIR%\bin

mkdir %LIBGSL_INSTALL_DIR%\lib

if exist .\..\libgsl\Debug-StaticLib\libgsl_d.lib copy .\..\libgsl\Debug-StaticLib\libgsl_d.lib %LIBGSL_INSTALL_DIR%\lib

if exist .\..\libgsl\Release-StaticLib\libgsl.lib copy .\..\libgsl\Release-StaticLib\libgsl.lib %LIBGSL_INSTALL_DIR%\lib

if exist .\..\libgslcblas\Debug-StaticLib\libgslcblas_d.lib copy .\..\libgslcblas\Debug-StaticLib\libgslcblas_d.lib %LIBGSL_INSTALL_DIR%\lib

if exist .\..\libgslcblas\Release-StaticLib\libgslcblas.lib copy .\..\libgslcblas\Release-StaticLib\libgslcblas.lib %LIBGSL_INSTALL_DIR%\lib

if exist .\..\libgsl\Debug-DLL\libgsl_dll_d.lib copy .\..\libgsl\Debug-DLL\libgsl_dll_d.lib %LIBGSL_INSTALL_DIR%\lib

if exist .\..\libgsl\Release-DLL\libgsl_dll.lib copy .\..\libgsl\Release-DLL\libgsl_dll.lib %LIBGSL_INSTALL_DIR%\lib

if exist .\..\libgslcblas\Debug-DLL\libgslcblas_dll_d.lib copy .\..\libgslcblas\Debug-DLL\libgslcblas_dll_d.lib %LIBGSL_INSTALL_DIR%\lib

if exist .\..\libgslcblas\Release-DLL\libgslcblas_dll.lib copy .\..\libgslcblas\Release-DLL\libgslcblas_dll.lib %LIBGSL_INSTALL_DIR%\lib

到此,gsl的編譯工作就完成了,開發(fā)過程中需要的是gsl的頭文件和庫文件,按照默認的安裝目錄,頭文件存放于C:\libgsl-1.8\include中,動態(tài)鏈接庫在C:\libgsl-1.8\bin,而靜態(tài)庫則在C:\libgsl-1.8\lib目錄中?,F在我們開始寫個簡單的程序來看看怎么使用gsl。

新建一個控制臺項目,在VC2005中將gsl的頭文件和庫文件路徑加到相應目錄中。以本文中編譯的項目來說,就是在VC2005的菜單中,選擇工具-選項,在項目和解決方案-VC++目錄下的包含文件目錄列表中加入C:\libgsl-1.8\include,在庫文件的目錄列表中添加C:\libgsl-1.8\lib,如果要使用gsl動態(tài)鏈接庫,還要將C:\libgsl-1.8\bin下的幾個dll置于環(huán)境變量PATH中的路徑下,或者簡單的說直接拷貝到Windows\system32目錄下。

然后,在程序中加入頭文件#include <gsl/gsl_math.h>,在main函數中加入代碼

double x = 5.0;
double y = gsl_pow_int(x,2);
cout&lt;&lt;
system("pause");

在項目屬性中的配置屬性-連接器-輸入-附加依賴項中填入libgsl_d.lib和libgslcblas_d.lib,當然libgslcblas_d.lib在現在這個簡單的程序中并不需要,但是在設計cblas的程序里也許用得著??梢詮膌ib的名字后綴_d中看出來,這是用于debug版的程序,用于release版的lib文件則是不帶_d后綴的,如果是要用gsl的dll動態(tài)鏈接,這個地方就要引入帶_dll的lib文件了。

編譯,運行,程序將輸出5的平方,也就是25,很簡單吧。

其他的各種數學函數和詳細的使用說明都可以從gnuwin32的網站上下到,下載那個Documentation就可以,有pdf、chm、html等不同的格式以供選擇。

利用注冊表遍歷COM口


ysm

cleverysm@gmail.com

要得到當前計算機上可用的COM口列表,一般有兩種方法,一是從COM1開始逐個試驗,看能不能正常打開端口,另一種方法是讀取注冊表的某個鍵值,下文就介紹從注冊表中獲取可用COM口的列表的方法。

有關COM口的信息存儲在HKEY_LOCAL_MACHINE下的HARDWARE\\DEVICEMAP\\SERIALCOMM子鍵中,如果打開regedit可以看到這個子鍵下左側有形如\Device\Serial0的設備列表,對應右側顯示其設備的名稱,即COM1、COM2等。我們要做的就是要遍歷這個子鍵下的所有設備,取出他們的數據值。

#define MAX_VALUE_NAME 16383
#define MAX_VALUE_LENGTH 1024
//遍歷COM口,輸出到arrayComs
void EnumComs(CStringArray&amp; arrayComs)
{
    TCHAR    achClass[MAX_PATH] = TEXT("");  // buffer for class name
    DWORD    cchClassName = MAX_PATH;  // size of class string
    DWORD    cSubKeys=0;               // number of subkeys
    DWORD    cbMaxSubKey;              // longest subkey size
    DWORD    cchMaxClass;              // longest class string
    DWORD    cValues;              // number of values for key
    DWORD    cchMaxValue;          // longest value name
    DWORD    cbMaxValueData;       // longest value data
    DWORD    cbSecurityDescriptor; // size of security descriptor
    FILETIME ftLastWriteTime;      // last write time 
 
	CString subKey= _T("HARDWARE\\DEVICEMAP\\SERIALCOMM");
 
	CString str;
	CString strValue;
	CStringArray arrayNames;
 
	HKEY hNewKey;
	long lResult;
	DWORD dwType;
 
	TCHAR  achValue[MAX_VALUE_NAME];
    DWORD cchValue = MAX_VALUE_NAME;
	DWORD dwBufferSize = 10;
	TCHAR buffer[MAX_VALUE_LENGTH];
 
	//打開注冊表
	lResult=RegOpenKeyEx( HKEY_LOCAL_MACHINE, subKey, 0, KEY_ALL_ACCESS, &amp;hNewKey);
 
	if(lResult!=ERROR_SUCCESS)
	{
		return;
	}
 
    //獲取此子鍵的相關信息
    lResult = RegQueryInfoKey(
        hNewKey,                    // key handle
        achClass,                // buffer for class name
        &amp;cchClassName,           // size of class string
        NULL,                    // reserved
        &amp;cSubKeys,               // number of subkeys
        &amp;cbMaxSubKey,            // longest subkey size
        &amp;cchMaxClass,            // longest class string
        &amp;cValues,                // number of values for this key
        &amp;cchMaxValue,            // longest value name
        &amp;cbMaxValueData,         // longest value data
        &amp;cbSecurityDescriptor,   // security descriptor
        &amp;ftLastWriteTime);       // last write time 
 
	//遍歷此鍵下的參數名稱
    if (cValues)
    {
        for (DWORD i=0; i

在主函數中。

CStringArray arrayComs;
EnumComs(arrayComs);
for(int i=0;i

VC2005下用MSComm開發(fā)串口程序

ysm

cleverysm@gmail.com

前幾天需要做一個COM口的通訊程序,主要是要接收一個傳感器送來的船舶航行狀態(tài)參數。過去沒有接觸過COM口編程,上網查查VC6下有個Communication Control可用,挺方便的,遂研究研究拿來用,整理一下學習筆記存檔,并與網友分享。

首先,我用的是VC2005,但在VC2005下沒有這個控件,所以要借用一下VC6??丶荕SCOMM32.OCX,如果安裝了VC6或VB6的話,就能在/WINDOWS/System32下找到MSCOMM32.OCX,MSCOMM32.SRG,MSCOMM32.DEP三個文件。如果在開發(fā)的機器上沒有安裝VC6或VB6,同時也沒有安裝過使用的這個控件,則首先要對這個控件進行注冊。注冊方法是使用命令regsvr32 MSCOMM32.OCX,比如我就直接把找來的這三個文件放到我的System32下,同時新建一個文本文件,把命令regsvr32 MSCOMM32.OCX寫到文本文件中,改擴展名為bat,直接雙擊這個bat就完成空間注冊。另外,為了在VC2005中開發(fā)的時候能正常使用這個控件,還需要修改一下注冊表,否則會出錯。修改方法是將以下內容寫到一個文本文件中,擴展名改為reg,然后雙擊這個文件導入就可以了。(此處注冊表修改的內容也可以在MSCOMM32.SRG中找到)

REGEDIT

HKEY_CLASSES_ROOT\Licenses = Licensing: Copying the keys may be a violation of established copyrights.

// Comm Control 6.0 license key

HKEY_CLASSES_ROOT\Licenses\4250E830-6AC2-11cf-8ADB-00AA00C00905 = kjljvjjjoquqmjjjvpqqkqmqykypoqjquoun

完成以上的控件注冊和注冊表的修改后就可以開始程序的開發(fā)了。首先新建一個MFC對話框程序。然后在IDE的右側打開“工具箱”,鼠標右擊,在彈出菜單中點擊“選擇項”,在COM組件下找到Microsoft Communications Control,在其前面的選擇框中打勾,一個黃色電話圖標就會出現在工具箱里,用鼠標把這個圖標拖進對話框資源編輯器里,控件就被添加到項目的程序中。

為了便于使用,我們可以給這個控件綁定一個控件變量,比如叫做m_mscomm,程序會自動添加一個CMscomm類封裝這個控件,而m_mscomm就是這個類的一個對象。接下來就可以以此控件變量來使用控件了。

在正式開始收發(fā)數據前,要給控件設置適當的幾個參數來初始化。

首先是指定端口號,使用方法m_mscomm.put_CommPort(1);,參數就是端口號,比如此處程序要使用COM1端口。

然后是波特率、奇偶校驗、數據位和停止位,使用方法put_Settings(LPCTSTR newValue),參數是一個形如”*,*,*,*”字符串,比如我需要波特率4800,無奇偶校驗,8位數據位和1作為停止位就可以如此操作,m_mscomm.put_Settings(_T(“4800, n, 8, 1”))。

m_mscomm.put_RThreshold(1)和m_mscomm.put_SThreshold(0)分別設定接收和發(fā)送數據的時候,引發(fā)接收數據的OnComm事件時緩沖區(qū)中的字符數量,0表示不觸發(fā)OnComm事件,比如put_RThreshold(1)表示每接收到一個字符就處罰OnComm事件。

m_mscomm.put_InputLen(100)設定當前接收區(qū)數據長度為0,表示全部讀取。

m_mscomm.put_InputMode(0)用來設定數據接收模式,1表示二進制,0表示文本。

m_mscomm.put_OutBufferSize(1024)和m_mscomm.put_InBufferSize(1024)分別設定輸出和接收的緩沖區(qū)大小,單位是字節(jié)。

比如,現在要接收數據的話,可以如下初始化程序。

m_mscomm.put_CommPort(1);
m_mscomm.put_Settings(_T(4800, n, 8, 1));
m_mscomm.put_RThreshold(1);
m_mscomm.put_SThreshold(0);
m_mscomm.put_InputLen(100);
m_mscomm.put_InputMode(0);
m_mscomm.put_InBufferSize(1024);

初始化完成后就可以用m_mscomm.put_PortOpen(TRUE)來打開端口開始接收數據了。

根據我們在RThreshold中設定的參數,程序會在接收到參數中指定的字符后觸發(fā)一個OnComm事件,我們就需要處理這個事件來提取接收到的數據。我們需要通過查詢m_mscomm.get_CommEvent()來確定具體的事件類型,比如可能是發(fā)送也可能接收到了數據,比如在此我們要提取接收數據,事件對應的返回值應當是2。然后獲得的數據就可以用m_mscomm.get_Input()來獲得,這個函數返回一個VARIANT結構變量,如果我們接收的是字符串數據,那就是保存在bstrVal中,比如下面的代碼就是在接收到數據時將接收到的字符串保存在str變量中。

void CMScomDlg::OnCommMscomm()
{
// TODO: 在此處添加消息處理程序代碼
CString str;
switch(m_mscomm.get_CommEvent())
{
case 2:
str=CString(m_mscomm.get_Input().bstrVal);
break;
default:
break;
}
}

如果要發(fā)送數據的話,只需調用m_mscomm.put_Output(VARIANT newValue)將保存在newValue中的數據發(fā)送出去。在此我們可以使用一個COleVariant類對象來代替直接使用VARIANT類型變量,COleVariant直接提供了將字符串變量轉化為兼容VARIANT類型的構造函數,比如我們將數據保存在CString類型的str變量中,然后用COleVariant 包一下送給put_Output ,如m_mscomm.put_Output(COleVariant(str))就可以將str中的字符通過串口發(fā)送出去。

VS2005與IE8沖突問題

近日把IE升級到8,結果發(fā)現在VC2005下新建類的窗口出錯,不能正常使用,網上搜來解決辦法,把如下文本拷到一個文本文件中,改擴展名為reg,雙擊導入注冊表即可。

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1000]
“1207″=dword:00000000

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1000]

“1207″=dword:00000000

VS2008貌似也有同樣問題,解決方法相同。

http://blogs./vcblog/archive/2009/03/28/some-vs2005-and-vs2008-wizards-pop-up-script-error.aspx

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多