国产精品青草久-国产精品情侣愉拍-国产精品区网红主-国产精品区一区二-国产精品热久久-国产精品热热热-国产精品人aⅴ-国产精品人成在线-国产精品人妻人伦-国产精品人人

金喜正规买球

深入分析基于VCL派生的ActiveX控件的實(shí)現(xiàn)原理及應(yīng)用

翻譯|其它|編輯:郝浩|2004-01-12 21:31:00.000|閱讀 1779 次

概述:

# 界面/圖表報(bào)表/文檔/IDE等千款熱門(mén)軟控件火熱銷(xiāo)售中 >>

前言

這篇文章雖然是以VCL為題,但卻是基于BCB的,也就是說(shuō)是在VCL基礎(chǔ)上使用ATL實(shí)現(xiàn)的ActiveX的原理分析,如果你是Delphi程序員,這篇文章可能不適合你,不過(guò)作者如果有時(shí)間會(huì)再寫(xiě)一篇“Delphi版的深入分析”,本篇文章比較深入的分析了VCL實(shí)現(xiàn)ActiveX控件的原理、事件機(jī)制、屬性頁(yè)和ActiveX控件編寫(xiě)的相關(guān)知識(shí)。希望大家已經(jīng)掌握了VCL編寫(xiě)元件(Component)的知識(shí),COM原理及ATL/模板的相關(guān)知識(shí),因?yàn)樽髡卟粫?huì)對(duì)文章中探討的相關(guān)知識(shí)做詳細(xì)介紹,所以你可能因?yàn)槿狈ο鄳?yīng)知識(shí)而遇到一些困難,不過(guò)作者會(huì)盡量用簡(jiǎn)單的語(yǔ)言來(lái)闡述一切。另,作者本來(lái)水平有限,在寫(xiě)這篇文章的時(shí)候僅是參考了幫助文檔、分析了VCL源代碼再加上一些猜測(cè),如果有任何理解錯(cuò)誤敬請(qǐng)大家指教,好我們開(kāi)始吧!

從向?qū)ч_(kāi)始


 為了有分析的對(duì)象,我們就從最基本的開(kāi)始,由向?qū)腡Button派生一個(gè)TButtonX的ActiveX控件(以下出現(xiàn)TButtonX都是指ActiveX控件),注意在向?qū)е羞x中“產(chǎn)生關(guān)于對(duì)話框”的選項(xiàng),這樣生成的TButtonX會(huì)有一個(gè)關(guān)于對(duì)話框。現(xiàn)在我們得到了ButtonImpl,ButtonXContrl_TLB這兩個(gè)主要的單元,所有的奧秘也在這里,我們進(jìn)入看看。

在ButtonImpl.h文件中,有這樣的申明:

class ATL_NO_VTABLE TButtonXImpl:
VCLCONTROL_IMPL(TButtonXImpl, ButtonX, TButton, IButtonX, DIID_IButtonXEvents)
{

}



這個(gè)TButtonXImpl實(shí)現(xiàn)了TButtonX,一般情況下針對(duì)ActiveX的工作都可以在這個(gè)單元內(nèi)完成,不過(guò)這個(gè)類看起來(lái)還是很奇怪:首先ATL_NO_VTABLE是個(gè)什么東西?這是一個(gè)宏,經(jīng)過(guò)豫編譯處理后,這個(gè)宏最終替換為_(kāi)_declspec(novtable),而這又是一個(gè)編譯器指示字,用于指示編譯器不要產(chǎn)生vtable(準(zhǔn)確的說(shuō),是不初始化vtable指針,這樣連接器可以排除那些需要vtable才能調(diào)用的函數(shù),比如虛函數(shù)),這又為什么?
 我們知道COM是語(yǔ)言無(wú)關(guān)的,但是vtable的機(jī)制不是所有的語(yǔ)言都有,比如VB等,而我們編寫(xiě)ActiveX控件肯定是要拿到這些開(kāi)發(fā)工具上使用的,所以為了使得C++開(kāi)發(fā)的COM元件可以在VB下使用,我們不能使用vtable機(jī)制,而且ActiveX還要是自動(dòng)化對(duì)象,這在后面再討論。

還有一個(gè)宏VCLCONTROL_IMPL,這個(gè)宏是關(guān)鍵,它隱藏了VCL實(shí)現(xiàn)ActiveX控件的全部奧秘,看來(lái)必須分析它才能撥開(kāi)全部迷霧:

VCLCONTROL_IMPL 宏,封裝了ActiveX控件繼承的基類,展開(kāi)后:

#define VCLCONTROL_IMPL(cppClass, CoClass, VclClass, intf, EventID) \
public TVclControlImpl<cppClass, VclClass, &CLSID_##CoClass, \
&IID_##intf, &EventID, LIBID_OF_##CoClass>,\
public IDispatchImpl<intf, &IID_##intf, LIBID_OF_##CoClass>, \
public TEvents_##CoClass<cppClass>



cppClass是C++實(shí)現(xiàn)的類的名字,
CoClass是ActiveX的類名,
VclClass是ActiveX控件繼承的VCL基類的名字,
intf是ActiveX控件實(shí)現(xiàn)的IDispatch接口,
EventID是ActiveX控件事件接口的標(biāo)示符。

TVclControlImpl它封裝了VclClass指定的VCL類,通過(guò)它的窗口管理和消息處理機(jī)制,使得它可以工作在ActiveX的宿主環(huán)境下。TVclControlImpl實(shí)現(xiàn)了標(biāo)準(zhǔn)的ActiveX控件需要的接口,因?yàn)樗g接繼承自CComObjectRootEx和CComCoClass,使得它可以工作在C++ Builder的基與ATL的COM應(yīng)用程序中。

IDispatchImpl,它實(shí)現(xiàn)了IDispatch接口,所以從這個(gè)類派生的子類的屬性和方法可以被自動(dòng)化(Automation)操作。上面說(shuō)了ActiveX必須是自動(dòng)化對(duì)象,而自動(dòng)化對(duì)象必須繼承自IDispatch接口,這里正好說(shuō)明這一點(diǎn)。

TEvents_##CoClass(或者TEvents_CoClassName),提供了VCL控件的事件觸發(fā)機(jī)制,IDE會(huì)根據(jù)創(chuàng)建的VCL控件自動(dòng)產(chǎn)生這個(gè)類,通過(guò)這個(gè)類,ActiveX控件可以在事件觸發(fā)的時(shí)候調(diào)用相應(yīng)的方法來(lái)處理這些事件。

注意上面的##的編譯器指示字,它是用來(lái)連接2個(gè)宏參數(shù)的,比如TEvents_##CoClass會(huì)被替換為T(mén)Events_ButtonX,這也是一個(gè)類,不過(guò)是用IDE自動(dòng)產(chǎn)生的,用于支持事件機(jī)制。

而上面展開(kāi)代碼的關(guān)鍵在于TVclControlImpl這個(gè)類,我們?cè)倏纯此?/p>

template <class T, // User class implementing Control
class TVCL, // Underlying VCL type used in One-Step Conversion
const CLSID* pclsid, // Class ID of Control
const IID* piid, // Primary interface of Control
const IID* peventsid, // Event (outgoing) interface of Control
const GUID* plibid> // GUID of TypeLibrary
class ATL_NO_VTABLE TVclControlImpl:
public CComObjectRootEx<CComObjectThreadModel>,
public CComCoClass<T, pclsid>,
public TVclComControl<T, TVCL>,
public IProvideClassInfo2Impl<pclsid, peventsid, plibid>,
public IPersistStorageImpl<T>,
public IPersistStreamInitImpl<T>,
public IQuickActivateImpl<T>,
public IOleControlImpl<T>,
public IOleObjectImpl<T>,
public IOleInPlaceActiveObjectImpl<T>,
public IViewObjectExImpl<T>,
public IOleInPlaceObjectWindowlessImpl<T>,
public IDataObjectImpl<T>,
public ISpecifyPropertyPagesImpl<T>,
public IConnectionPointContainerImpl<T>,
public IPropertyNotifySinkCP<T, CComDynamicUnkArray>,
public ISupportErrorInfo,
public ISimpleFrameSiteImpl<T>
{

}


 可以看到,這個(gè)類實(shí)現(xiàn)了所有ActiveX控件必要實(shí)現(xiàn)的接口,除此之外,這個(gè)類也是VCL和ATL轉(zhuǎn)換的關(guān)鍵,他有很多關(guān)鍵的方法,比如:

HRESULT OnDraw(ATL_DRAWINFO& di)
{
try
{
if (m_VclCtl)
m_VclCtl->PaintTo(di.hdcDraw, di.prcBounds->left, di.prcBounds->top);
}
catch (Exception& e)
{
return (static_cast<T*>(this))->Error(e.Message.c_str());
}
return S_OK;
}



這個(gè)方法可以把VCL元件的界面畫(huà)在ActiveX宿主窗體上。

經(jīng)過(guò)層層撥絲,我們現(xiàn)在終于搞明白了TButtonXImpl的實(shí)現(xiàn)框架,但ActiveX運(yùn)作的原理和如何同VCL交互的還是不清楚,好,我們現(xiàn)在再來(lái)看看,TButtonXImpl的實(shí)現(xiàn)代碼:

void __fastcall ClickEvent(TObject *Sender);
void __fastcall KeyPressEvent(TObject *Sender, char &Key);
public:
TVclControlImpl
void InitializeControl()
{
m_VclCtl->OnClick = ClickEvent;
m_VclCtl->OnKeyPress = KeyPressEvent;
}
BEGIN_COM_MAP(TButtonXImpl)
VCL_CONTROL_COM_INTERFACE_ENTRIES(IButtonX)
END_COM_MAP()
DECLARE_VCL_CONTROL_PERSISTENCE(TButtonXImpl, TButton);
DECLARE_ACTIVEXCONTROL_REGISTRY("ButtonXControl.ButtonX", 1);
protected:
STDMETHOD(_set_Font(IFontDisp** Value));
STDMETHOD(AboutBox());
STDMETHOD(DrawTextBiDiModeFlagsReadingOnly(long* Value));
...



又是很多的宏,不過(guò)作者不打算介紹了,他們?cè)贐CB生成的代碼注釋(這里被刪除)里解釋的很清楚了,大家可以自己看,我就提示一點(diǎn),很多朋友問(wèn):如何改變ActiveX控件的圖標(biāo)?更改這個(gè)


DECLARE_ACTIVEXCONTROL_REGISTRY(“ButtonXControl.ButtonX”, 1);


 宏的參數(shù)就可以了,比如你已經(jīng)將圖標(biāo)資源(Bitmap),加入工程,并且這個(gè)資源ID為2,則你可以這樣更改:


DECLARE_ACTIVEXCONTROL_REGISTRY(“ButtonXControl.ButtonX”, 2);


再看,在protected下有很多屬性、方法的申明,在cpp文件中,這些申明也得到了實(shí)現(xiàn),但問(wèn)題在于為什么是保護(hù)類型的?這樣ActiveX控件豈不是訪問(wèn)不到這些屬性、方法?申明了又有什么用?
 是否還記得TButtonXImpl繼承了IButtonX接口呢?我們現(xiàn)在要到那里去看看,為此我們要分析一下ButtonXContrl_TLB單元,這個(gè)單元文件是由IDE維護(hù)的,一般情況是不需要理會(huì)這個(gè)文件的內(nèi)容,Borland也不建議你更改這個(gè)文件,不過(guò)今天我們必須要跨入禁區(qū)了,于是就有了IButtonX的實(shí)現(xiàn)代碼:

interface IButtonX : public IDispatch
{
public:
virtual HRESULT STDMETHODCALLTYPE get_Cancel(VARIANT_BOOL* Value/*[out,retval]*/) = 0; // [1]
virtual HRESULT STDMETHODCALLTYPE set_Cancel(VARIANT_BOOL Value/*[in]*/) = 0; // [1]
virtual HRESULT STDMETHODCALLTYPE get_Caption(BSTR* Value/*[out,retval]*/) = 0; // [-518]
...
#if !defined(__TLB_NO_INTERFACE_WRAPPERS)

VARIANT_BOOL __fastcall get_Cancel(void)
{
VARIANT_BOOL Value;
OLECHECK(this->get_Cancel((VARIANT_BOOL*)&Value));
return Value;
}
...
__property VARIANT_BOOL Cancel = {read = get_Cancel, write = set_Cancel};
__property BSTR Caption = {read = get_Caption};
__property VARIANT_BOOL Default = {read = get_Default, write = set_Default};
__property short DragCursor = {read = get_DragCursor, write = set_DragCursor};
...
}


 可以看到IButtonX同樣繼承自IDispatch接口,所以這也是一個(gè)自動(dòng)化的接口,而且終于有了public,所以那些接口方法和屬性被公開(kāi)了,我們不難得出這樣一張類的布局圖:



另外請(qǐng)大家注意:

VARIANT_BOOL __fastcall get_Default(void)
{
VARIANT_BOOL Value;
OLECHECK(this->get_Default((VARIANT_BOOL*)&Value));
return Value;
}



上面的實(shí)現(xiàn)代碼,OLECHECK用于檢查函數(shù)的執(zhí)行結(jié)果,如果有錯(cuò)誤,那么還有一個(gè)機(jī)會(huì)去處理錯(cuò)誤。
 方法和屬性都有了,對(duì)于一個(gè)ActiveX控件還差事件,沒(méi)有事件支持的ActiveX控件就像一個(gè)沒(méi)有發(fā)條的鐘是不會(huì)動(dòng)的,下面,我們?cè)賮?lái)看一下VCL是如何實(shí)現(xiàn)ActiveX控件的事件機(jī)制的。

事件機(jī)制

還是上面的代碼:

void __fastcall ClickEvent(TObject *Sender);
void __fastcall KeyPressEvent(TObject *Sender, char &Key);
public:
TVclControlImpl
void InitializeControl()
{
m_VclCtl->OnClick = ClickEvent;
m_VclCtl->OnKeyPress = KeyPressEvent;
}
...



看起來(lái)像是事件的處理代碼,啊?好像?有沒(méi)有搞錯(cuò)?沒(méi)有搞錯(cuò),確實(shí)是好像,而且是表面的


m_VclCtl->OnClick = ClickEvent;
m_VclCtl->OnKeyPress = KeyPressEvent;


 是標(biāo)準(zhǔn)的VCL消息處理函數(shù)機(jī)制,m_VclCtl通過(guò)模板參數(shù)最終對(duì)應(yīng)于相應(yīng)的VCL原類,這樣m_VclCtl的OnClick事件的處理就會(huì)轉(zhuǎn)交給ClickEvent函數(shù),而OnKeyPress事件的處理也就交給了KeyPressEvent函數(shù)處理,有VCL經(jīng)驗(yàn)的人,都能猜到ClickEvent和KeyPressEvent函數(shù)是如何實(shí)現(xiàn)的,例如:


void __fastcall TButtonXImpl::KeyPressEvent(TObject *Sender, char &Key)
{
short TempKey;
TempKey = (short)Key;
Fire_OnKeyPress(&TempKey);
Key = (short)TempKey;
}


又跳轉(zhuǎn)了,忽略Sender參數(shù),然后把Key又傳遞給了Fire_OnKeyPress函數(shù)處理,為了保證VCL KeyPress事件的結(jié)構(gòu),Key參數(shù)先被保存到TempKey,然后傳遞,最后返回Key參數(shù),注意:TempKey參數(shù)可能在ActiveX事件處理中被修改,這也符合Visual Basic的KeyPress事件結(jié)構(gòu)。
 不過(guò)問(wèn)題在于Fire_OnKeyPress函數(shù)是從哪里來(lái)的?要搞清楚這個(gè)問(wèn)題,我們還要看看前面那個(gè)復(fù)雜的宏定義:

#define VCLCONTROL_IMPL(cppClass, CoClass, VclClass, intf, EventID) \
public TVclControlImpl<cppClass, VclClass, &CLSID_##CoClass, \
&IID_##intf, &EventID, LIBID_OF_##CoClass>,\
public IDispatchImpl<intf, &IID_##intf, LIBID_OF_##CoClass>, \
public TEvents_##CoClass<cppClass>



 其中,TEvents_##CoClass(或者TEvents_CoClassName),提供了VCL控件的事件觸發(fā)機(jī)制,IDE會(huì)根據(jù)創(chuàng)建的VCL控件自動(dòng)產(chǎn)生這個(gè)類,通過(guò)這個(gè)類,ActiveX控件可以在事件觸發(fā)的時(shí)候調(diào)用相應(yīng)的方法來(lái)處理這些事件。

注意上面的##的編譯器指示字,它是用來(lái)連接2個(gè)宏參數(shù)的,比如TEvents_##CoClass會(huì)被替換為T(mén)Events_ButtonX,這也是一個(gè)類,不過(guò)是用IDE自動(dòng)產(chǎn)生的,用于支持事件機(jī)制。
 所以所有的事件奧秘都應(yīng)該隱藏在這個(gè)TEvents_ButtonX類里,如果你夠大膽的話,你可以猜測(cè)那個(gè)Fire_OnKeyPress函數(shù)就在這個(gè)類里?再次跨越禁區(qū),我們得到代碼:

template <class T>
class TEvents_ButtonX : public IConnectionPointImpl<T,
&DIID_IButtonXEvents,
CComUnkArray<CONNECTIONPOINT_ARRAY_SIZE> >
{
public:
void Fire_OnClick(void);
void Fire_OnKeyPress(short* Key);
void Fire_OnMouseMove(int Button, int X, int Y);
protected:
IButtonXEventsDisp m_EventIntfObj;
};



看到了確實(shí)如此,我們?cè)賮?lái)看看Fire_OnKeyPress是如何實(shí)現(xiàn)的?

template <class T> void
TEvents_ButtonX<T>::Fire_OnKeyPress(short* Key)
{
T * pT = (T*)this;
pT->Lock();
IUnknown ** pp = m_vec.begin();
while (pp < m_vec.end())
{
if (*pp != NULL)
{
m_EventIntfObj.Attach(*pp);
m_EventIntfObj.OnKeyPress(Key);
m_EventIntfObj.Attach(0);
}
pp++;
}
pT->Unlock();
}



剔除不必要的多線程訪問(wèn)互斥代碼、對(duì)控件數(shù)組事件的支持代碼,關(guān)鍵在于:
m_EventIntfObj.OnKeyPress(Key);
看來(lái)我們又要跳轉(zhuǎn)了,最后來(lái)到:

template <class T> void __fastcall
IButtonXEventsDispT<T>::OnKeyPress(short* Key/*[in,out]*/)
{
_TDispID _dispid(/* OnKeyPress */ DISPID(8));
TAutoArgs<1> _args;
_args[1] = Key /*[VT_I2:1]*/;
OleProcedure(_dispid, _args);
}



至此,如果有ATL/COM知識(shí)的人,都可以看出來(lái)這是一套標(biāo)準(zhǔn)的OLE方法調(diào)用機(jī)制,如果你還想跟蹤下去,你會(huì)發(fā)現(xiàn)它就是調(diào)用IDispatch接口的Invoke方法來(lái)負(fù)責(zé)方法、屬性的調(diào)用的,不過(guò)這里還可以注意一下:
_TDispID _dispid(/* OnKeyPress */ DISPID(8));
這里DISPID(8)是接口方法的標(biāo)識(shí)符,這個(gè)值來(lái)自于你設(shè)計(jì)IButtonXEvents接口時(shí)定義的ID號(hào),所以Invoke方法會(huì)唯一的定位到這個(gè)方法來(lái)完成事件機(jī)制的最后一步:調(diào)用客戶代碼-也就是你在VB中提供的事件的代碼。
于是我們又得到了這樣一幅消息、事件流向圖:



 VCL就是這樣一步一步實(shí)現(xiàn)ActiveX控件的事件機(jī)制的,可以看出來(lái),他的實(shí)現(xiàn)還是挺麻煩的,不過(guò)考慮到COM原理本來(lái)的復(fù)雜性,這樣的實(shí)現(xiàn)復(fù)雜度還是可以接受的。


簡(jiǎn)單的測(cè)試


由控件向?qū)傻腡ButtonX代碼,不需要任何改動(dòng),直接編譯就會(huì)產(chǎn)生一個(gè)TButtonX ActiveX控件,我們現(xiàn)在測(cè)試一下,點(diǎn)Register Active Server菜單,注冊(cè)這個(gè)控件,然后在開(kāi)啟Visual Basic開(kāi)發(fā)環(huán)境,加入剛才注冊(cè)的控件,發(fā)現(xiàn)它確實(shí)是按照我們的設(shè)計(jì)工作的,注意:如果你在開(kāi)始創(chuàng)建這個(gè)控件的時(shí)候,選擇了生成About對(duì)話框的選項(xiàng),那么還有一個(gè)About屬性用于顯示關(guān)于對(duì)話框。
那么這個(gè)關(guān)于對(duì)話框又是怎么回事?代碼為我們展示這點(diǎn):

void ShowButtonXAbout(void)
{
TButtonXAbout* Form;
Form = new TButtonXAbout(NULL);
try
{
Form->ShowModal();
}
catch(...)
{
Form->Free();
return;
}
Form->Free();
}



 在TButtonImpl的AboutBox函數(shù)中調(diào)用了上面的函數(shù)來(lái)顯示對(duì)話框,不過(guò)有一點(diǎn)作者也不太清楚,就是:


Form->Free();


本來(lái)按照Borland的說(shuō)法,在BCB中不推薦使用Free來(lái)釋放內(nèi)存,而應(yīng)該使用delete這個(gè)關(guān)鍵字,但這里為什么這樣使用?不過(guò)作者做了測(cè)試,使用delete也是可以的,沒(méi)有發(fā)現(xiàn)什么問(wèn)題,所以作者猜測(cè),這里可能是Borland沒(méi)有更新那個(gè)代碼向?qū)б赃m應(yīng)BCB的開(kāi)發(fā)(可能本來(lái)是為Delphi設(shè)計(jì)的,而B(niǎo)orland只是簡(jiǎn)單的做了一下Delphi到BCB的轉(zhuǎn)換)。
 最后需要說(shuō)明的是AboutBox函數(shù)的DISPID必須是-552,這樣ActiveX會(huì)把這個(gè)函數(shù)作為About來(lái)對(duì)待,其實(shí)DISPID的設(shè)置還是有強(qiáng)制性,很多標(biāo)準(zhǔn)屬性必須是特定的DISPID,這些DISPID都是負(fù)值,有興趣的朋友可以看看MSDN或者COM原理的書(shū)籍。


重用 繼承?


 上面的TButtonX控件簡(jiǎn)單的通過(guò)繼承VCL的TButton的實(shí)現(xiàn)了一個(gè)按鈕的AcitiveX控件,如果是其他的VCL能不能同樣這樣簡(jiǎn)單的繼承就可以方便的生成ActiveX控件呢?在問(wèn)答前,我們先做一個(gè)試驗(yàn),把剛才這個(gè)TButtonX放在Visual Basic開(kāi)發(fā)環(huán)境中,然后使用Spy++這樣工具(這里作者使用作者自己開(kāi)發(fā)的MySpy,可以到下載)看看他的類名:



發(fā)現(xiàn)它的類名并不是ActiveX的控件的TButtonX,而是原來(lái)VCL的TButton,這能說(shuō)明什么?這從一個(gè)側(cè)面說(shuō)明了,在BCB下我們開(kāi)發(fā)ActiveX控件其實(shí)就是設(shè)計(jì)相應(yīng)的VCL控件,而在最后把他再封裝成為ActiveX控件,那么到底什么樣的VCL控件都可以封裝成為ActiveX控件呢?通常來(lái)說(shuō)只要從TWinControl繼承的VCL元件都可以封裝成為ActiveX。而這樣VCL元件具有如下特征:
? 可以獲得焦點(diǎn)
? 可以包含其他控件(僅是具有這樣能力,不代表一定具備)
? 擁有窗口句柄
還記得這段代碼嗎:

HRESULT OnDraw(ATL_DRAWINFO& di)
{
try
{
if (m_VclCtl)
m_VclCtl->PaintTo(di.hdcDraw, di.prcBounds->left, di.prcBounds->top);
}
catch (Exception& e)
{
return (static_cast<T*>(this))->Error(e.Message.c_str());
}
return S_OK;
}


前面說(shuō)這是BCB實(shí)現(xiàn)ActiveX機(jī)制的關(guān)鍵類TVclControlImpl所具有的代碼,用于把控件畫(huà)在ActiveX宿主窗體上,而這個(gè)方法就是來(lái)源于TWinControl,所以ActiveX控件的必須繼承自這個(gè)類(當(dāng)然如果是自己實(shí)現(xiàn)了,就另當(dāng)別論),這樣,很容易想到的是像TLabel這樣的VCL控件是無(wú)法實(shí)現(xiàn)為ActiveX控件的。
 那么是不是從TWinControl繼承的VCL元件都可以被封裝為ActiveX呢?這也不一定,如果你已經(jīng)把相應(yīng)的的unit添加進(jìn)入工程或者已經(jīng)把它安裝了,則這個(gè)VCL元件可能不會(huì)出現(xiàn)在那個(gè)DropDown 列表里,還有就是這個(gè)類沒(méi)有用RegisterNonActiveX函數(shù)注冊(cè),這個(gè)函數(shù)專門(mén)用來(lái)設(shè)置那些類不能被封裝為ActiveX,這個(gè)函數(shù)很復(fù)雜:


extern PACKAGE void __fastcall RegisterNonActiveX(System::TMetaClass*,
const * ComponentClasses,
const int ComponentClasses_Size,
TActiveXRegType AxRegType);


 具體的使用方法可以參考幫助。在CSDN上和Borland新聞組作者也看到過(guò)網(wǎng)友詢問(wèn)“為什么我的控件不能出現(xiàn)在AcitveX的生成向?qū)Ю铩保M麓慰催^(guò)這篇文章的朋友下次可以解決這個(gè)問(wèn)題。


再完善一些


再回到剛才Visual Basic的開(kāi)發(fā)環(huán)境,我們來(lái)看看到底那些屬性和方法被表露了:
 而同樣的TButton在BCB中卻具有非常多的屬性,為什么呢?開(kāi)始作者認(rèn)為所有的VCL元件都是表露這些基本的屬性和方法,但后來(lái)作者又做了一個(gè)試驗(yàn),就是簡(jiǎn)單的封裝了TEdit后發(fā)現(xiàn)他表露其他的更多屬性和方法,參考了一下幫助文檔,發(fā)現(xiàn)原來(lái)有如下規(guī)則:

  • 數(shù)據(jù)感知屬性不表露。
  • 任何與自動(dòng)化不兼容的類型定義不表露。
  • 可以表露在VCL中未發(fā)布的屬性,但這樣做不保證持久性(persist)。


如果VCL的屬性或方法不符合上述規(guī)則,我們就需要自己實(shí)現(xiàn)相應(yīng)ActiveX代碼來(lái)表露他們;相反如果符合上述規(guī)定,而你又不想表露給最終用戶,你可以在Type Library Editor中刪除它們,刷新代碼后再刪除單元文件中相應(yīng)的生成代碼。
這里需要強(qiáng)調(diào)的是:在BCB中設(shè)計(jì)ActiveX控件在很大程度上是先設(shè)計(jì)對(duì)應(yīng)的VCL后再封裝為ActiveX,而不是像VC那樣直接開(kāi)發(fā)ActiveX(其實(shí)BCB也可以像VC那樣開(kāi)發(fā)ActiveX,畢竟都是使用ATL嘛),這樣設(shè)計(jì)不管是從難易程度還是調(diào)試都是非常輕松的。
知道了原理,我們現(xiàn)在要做的是在這個(gè)半成品的TButtonX中加入新的事件和屬性頁(yè),使它看起來(lái)更像一個(gè)專業(yè)的ActiveX控件,對(duì)于屬性和方法,因?yàn)榫帉?xiě)這些代碼非常簡(jiǎn)單,為了節(jié)省篇幅,這里就不實(shí)際添加屬性和方法了。
 從TButton封裝得到的AcitiveX缺少了一個(gè)重要的事件,OnMouseMove,下面我們就寫(xiě)代碼來(lái)表露這個(gè)事件,根據(jù)我們上面講述的原理,完成這部分很容易,首先就是在Type Library Editor里的事件支持接口添加相應(yīng)方法,如圖:



 刷新后IDE自動(dòng)產(chǎn)生相應(yīng)代碼,在Impl單元文件中,加入VCL的OnMouseMove消息處理的轉(zhuǎn)移代碼,如下黑體部分:

class ATL_NO_VTABLE TButtonXImpl:
VCLCONTROL_IMPL(TButtonXImpl, ButtonX, TButton, IButtonX, DIID_IButtonXEvents)
{
void __fastcall ClickEvent(TObject *Sender);
void __fastcall KeyPressEvent(TObject *Sender, char &Key);
void __fastcall MouseMoveEvent(TObject *Sender, TShiftState Shift, int X,
int Y);
public:

void InitializeControl()
{
m_VclCtl->OnClick = ClickEvent;
m_VclCtl->OnKeyPress = KeyPressEvent;
m_VclCtl->OnMouseMove = MouseMoveEvent;
}



 這里的m_VclCtl其實(shí)就是TButton,他是通過(guò)模板參數(shù)替換的,所以通過(guò)上面的代碼TButton的OnMouseMove消息的處理過(guò)程轉(zhuǎn)向了MouseMoveEvent,現(xiàn)在我們最后的工作就是編寫(xiě)MouseMoveEvent這個(gè)函數(shù)處理OnMouseMove消息:

void __fastcall TButtonXImpl::MouseMoveEvent(TObject *Sender,
TShiftState Shift, int X, int Y)
{
int ss=0;
if(Shift.Contains(ssLeft))
ss=1;
else if(Shift.Contains(ssRight))
ss=2;
Fire_OnMouseMove(ss,X,Y);
}



 忽略Sender參數(shù)后,再次轉(zhuǎn)發(fā)消息流,F(xiàn)ire_OnMouseMove這個(gè)函數(shù)是由IDE自動(dòng)產(chǎn)生的,我們直接調(diào)用就可以了,它的代碼如下:

template <class T> void
TEvents_ButtonX<T>::Fire_OnMouseMove(int Button, int X, int Y)
{
T * pT = (T*)this;
pT->Lock();
IUnknown ** pp = m_vec.begin();
while (pp < m_vec.end())
{
if (*pp != NULL)
{
m_EventIntfObj.Attach(*pp);
m_EventIntfObj.OnMouseMove(Button, X, Y);
m_EventIntfObj.Attach(0);
}
pp++;
}
pT->Unlock();
}



可以看到這部分代碼與缺省的Fire_OnClick是一致的,這樣添加OnMouseMove事件支持的代碼就完成了。
接下來(lái)是添加一個(gè)屬性頁(yè),由于VCL的封裝,使得開(kāi)發(fā)設(shè)計(jì)屬性頁(yè)變得非常簡(jiǎn)單,首先生成一個(gè)新的Property Page,這樣BCB會(huì)為我們產(chǎn)生一個(gè)Form,這個(gè)Form與普通的Win32開(kāi)發(fā)中Form的最大區(qū)別在于它繼承自TPropertyPage,所以它有一些獨(dú)有的方法是我們?cè)谠O(shè)計(jì)需要注意的,為了簡(jiǎn)單起見(jiàn),屬性頁(yè)里只簡(jiǎn)單地更改、反饋Caption屬性,在實(shí)際開(kāi)發(fā)中復(fù)雜的屬性頁(yè)是類似的。
屬性頁(yè)與ActiveX交互就是通過(guò)2個(gè)函數(shù)來(lái)進(jìn)行的,而這兩個(gè)函數(shù)都是來(lái)自于TPropertyPage類,在缺省生成的Property Page Form里已經(jīng)加入了這個(gè)兩個(gè)函數(shù)的缺省代碼,我們要做就是完成這2個(gè)函數(shù):
UpdatePropertyPage(void),在打開(kāi)屬性頁(yè)時(shí),系統(tǒng)會(huì)調(diào)用這個(gè)函數(shù),你可以在這個(gè)函數(shù)里添加代碼用以反映ActiveX的屬性在屬性頁(yè)里的顯示。
UpdateObject(void),在應(yīng)用屬性時(shí),系統(tǒng)會(huì)調(diào)用這個(gè)函數(shù),你可以把屬性頁(yè)中改變的數(shù)據(jù)應(yīng)用到實(shí)際的ActiveX控件中。
 按照BCB的幫助這兩個(gè)函數(shù)實(shí)現(xiàn)起來(lái)非常簡(jiǎn)單,比如UpdateObject(void),就只需要如下代碼:


void __fastcall TPropertyPage1::UpdateObject(void)
{
OleObject.OlePropertySet<WideString>("EditMask", WideString(InputMast->Text).Copy());
}


 就可以把ActiveX控件的屬性更改為屬性頁(yè)中設(shè)置的數(shù)據(jù),但在作者的計(jì)算機(jī)上(BCB6+sp4),上面的代碼怎么都無(wú)法通過(guò)編譯,無(wú)奈之下,作者只好使用原始的方法,代碼如下:

void __fastcall TpageNormal::UpdatePropertyPage(void)
{
// Update your controls from OleObjects
IDispatch* ctrl=OleObject;
CComPtr<IButtonX> btnctrl;
ctrl->QueryInterface<IButtonX>(&btnctrl);
edtcaption->Text=String(btnctrl->get_Caption());
}
//---------------------------------------------------------------------------
void __fastcall TpageNormal::UpdateObject(void)
{
// Update OleObjects from your controls
IDispatch* ctrl=OleObject;
CComPtr<IButtonX> btnctrl;
ctrl->QueryInterface<IButtonX>(&btnctrl);
btnctrl->set_Caption(WideString(edtcaption->Text));
}


對(duì)于沒(méi)有ATL、COM知識(shí)的讀者上面的代碼可能比較難懂,建議找些相關(guān)書(shū)籍熟悉一下。
 通過(guò)上面的代碼,ActiveX控件和屬性頁(yè)之間就可以完美的交互了,最后在ButtonImpl.h文件中加入如下宏映:


BEGIN_PROPERTY_MAP(TButtonXImpl)
PROP_PAGE(CLSID_pageNormal)
END_PROPERTY_MAP()


關(guān)于這些宏的說(shuō)明和原理因篇幅關(guān)系這里就不討論了,BCB的幫助和源碼注釋里都寫(xiě)的很清楚,感興趣的朋友可以自己研究一下。至于上面的CLSID_pageNormal是生成屬性頁(yè)時(shí),IDE自動(dòng)為改屬性頁(yè)生成的ClassID。
 這樣一個(gè)比較完善的ActiveX控件就寫(xiě)完了,是不是非常簡(jiǎn)單,詳細(xì)代碼可以到CSDN網(wǎng)站下載。


寫(xiě)在最后


由于篇幅關(guān)系,本來(lái)很多內(nèi)容可以展開(kāi)詳細(xì)討論,但作者都省略了,本文就當(dāng)拋磚引玉,感興趣的讀者可以再深入研究。作者想再次強(qiáng)調(diào)的是,不管開(kāi)發(fā)ActiveX控件還是Active Form,最好的方法都是封裝(或者轉(zhuǎn)換)為ActiveX,而不是一切從頭來(lái),比如你有一個(gè)工程,想以ActiveForm的形式用在Web上,那么最好的方法是拿出單獨(dú)的Form然后轉(zhuǎn)換為ActiveForm,這不需要多復(fù)雜的代碼,這也是Borland新聞組上專家給的建議。
由于編寫(xiě)ActiveX控件的調(diào)試復(fù)雜性,所以保證代碼質(zhì)量非常重要,除此之外就是善于利用一些工具來(lái)幫助調(diào)試,比如Visual Basic、ActiveX Control Test Container等工具,如果有機(jī)會(huì)作者會(huì)寫(xiě)一些實(shí)際開(kāi)發(fā)中可能遇到的調(diào)試問(wèn)題和經(jīng)驗(yàn)。
參考文獻(xiàn):

  • Borland C++ Builder5 Help Document
  • Borland VCL Source and Comment

標(biāo)簽:

本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn


為你推薦

掃碼咨詢


添加微信 立即咨詢

電話咨詢

客服熱線
023-68661681

TOP
亚洲国产精品午夜在线观看 | 国产传媒一二三区av | 亚洲综合色aaa成人无码 | 97爽a高清免费在线观 | 国产视频福利久久久久精品 | 成年黄页网站大全免费 | 国产一二三四区中 | 欧美伦理一区二区 | 无码精品视频一区二区三区 | 天天插天天干 | 日韩av福利在线免费看 | 欧美精品成人a在线 | 亚洲鲁起秋霞a | 精品欧美一区视频在线观看 | 丰满少妇夜夜爽爽高潮水 | 国产麻豆精品国产传媒av | 国产精品亚洲精品日韩已方 | 99er热精品视频 | 久久av无码乱码a片无码 | 国产成人av一区二区三区在线观看 | 精品免费看国产免费 | 国产成人精品aa毛片 | 亚洲国产日产无码精品 | 精品啪在线观看国产老湿机 | 卡通动漫精品综 | 少妇高潮喷水久久久久久久久 | 国产精久久一区二区三区 | 国产精品白丝jk黑袜喷水视频 | 国产午夜福利电影在线观看2 | 日本精品久久久久中文字幕 | 91视频管网 | 国产96在线视频播放网站 | 亚洲精品第一国产综合高清 | 岛国大片精品视频免费在线播放 | 亚洲av无码乱观看明星换脸va | 国产a∨天天免费观看美女18 | 国产精品臀控福利在线观看 | 国产精品夜夜春夜夜爽久久 | 国产亚洲精品久久久ai换脸 | 日本高清一区二区三区 | 国产精品网友自拍 | 最新国产精品鲁鲁免费视频 | 高清无码一区波多野结衣x99av | 九九热在线视频观看这里只有精品 | 亚洲国产成人久久精品软件 | 91精品国产综合久久久动漫百度 | 91无人区卡一卡二卡三乱码 | 性色av蜜臀av人妻无码 | 欧美亚洲综合久 | 欧美精品黄页免费高清在线 | 中日av乱码一区 | 日日干夜夜操 | 国产伦精品一 | 国产色无码专区在线观看 | 97精品国产91久久久久久 | 国产精品网站 | 国产成人无码精品一区在线观看 | 国产一区二区三区四区三区 | 亚洲日本人成中文字幕 | 国产91在线视频 | 国产a不卡片精品免费观看 国产a国产国产片 | 精品久久久久久无码专区不卡 | 国产午夜成人无码免费 | 国产成人精品综合久久久久性色 | 国产精品婷婷久久久久久 | av人摸人人人澡人人 | 国产高清无密码一区二区三区 | 国产成人久久综合区 | 亚洲国产99在线视频 | 亚洲精品高清视频 | 亚洲无码精品在线播放 | 一级做a爱全免费视频免费 一级做a爰片 | 日本一区二区精品理论电影 | 十八禁无码免费视频在线观看 | 国产成人无码aa精品一区 | 成人午夜啪啪免费网站 | 国产综合精品91久久久 | 久久91精品国产一区二区 | 91麻豆最新国产网址 | 国产裸体舞一区二区三区 | 丝袜人妻| 国产男女无遮挡猛进猛出 | 91亚洲国产成人久久精品网站 | 亚洲综合色成在线观看 | 99国产精品99久久久久久 | 99人妻日韩精品一区二区传媒 | 国产精品秘入口久久熟女 | 三颗国产精品视频一区二区免费 | 亚洲av无码成人精品区在线观 | 国产中文字幕乱人伦在线 | 国产在线aaa片一区二区99 | 日本精品 | 成人激情五月天 | 亚洲日本aⅴ片在线观看香蕉 | 97se亚洲国产综合自在线尤物 | 国产成人午夜福利在线播放 | 韩国三级a视频在线观看 | 国产aⅴ激情无码久久久无码 | 亚洲欧美日韩一本无线码专区 | 亚洲国产精久久久久久久 | 韩国三级中文字幕hd久久精品 | 亚洲欧美一区二区三区不卡 | 精品国产91高清在线观看 | 丰满爆乳一 | 国产真人无遮挡作爱免费视频 | 国产一级毛片视频在线! | 日韩伦理片 | 日日躁夜夜躁狠狠久久av | 98国产在线观看精品 | 国产精品精品自在线拍 | 97人妻精品一区二区三区免 | 99视频免费在线观看 | 欧美一级一区二区 | 91精品国产91久久久久 | 97精品人妻无码专区在线 | 国产精品人成在线二区 | 国产全肉乱妇杂乱视频 | 国产成人欧美日本在线观看 | 日韩无码久久 | 国产欧美成人精品 | 91精品一区国产高清在线gif | 国产成人高清精品亚洲网站 | 91精品一区二区三区在线观看 | 丰满人妻av | av小簧片在线亚洲天堂在线 | 国产成人无码免费视频9 | 日本最新最全无码不卡免费 | 国精品无码一区二区三区 | 97视频在线精 | 午夜成人精品福利网站在线观看 | 无码在线免费播放 | 久久99精品久久久久久无毒不 | 欧美日韩不卡合集视频 | 精品国产无码av | 日韩极品av人人爽 | 欧美日韩午 | 久久99热狠狠色精品 | 97人人澡人人爽91综合色区 | 香蕉久久一区二区三区电影 | 成人欧美一区在线视频在线观看 | 国产一视频在线观看 | 日本高清不卡中文字幕网 | 亚洲午夜无码极品久久 | 国产乱子伦农村叉叉叉 | 国产日产高清欧美一区二区三区 | 福利影视| 国产在线播放线99视频大全 | 亚洲午夜一区二区三区在线 | 一区二区三区久久 | 中文字幕亚洲综合久久2025 | 亚洲综合色成在线播放 | 人妻少妇精品视频二区 | 国产公开免费人成视频 | 色香欲综合天天 | 成人黄色在线观看 | 美奶福利视频一区二区三区 | 国产午夜理论不卡在线观看 | 99精品久久久久久久久久综合 | 久久99精品无码一区二区 | 在线看片人成免费视频播放 | 91精品人妻一区二区三区蜜桃 | 天天综合网站 | 亚洲av永久无码精品网站 | 高清无码1区2区3区 高清无码不卡视频 | 麻豆成人91精品二区三区 | 欧美全免费aa | 欧美日韩免费专区在线观看 | 在线观看视频中文字幕三区 | 国产精品无码无卡无需播放器 | 日本久久久久久久久毛 | 91亚洲精品自 | 91精品国产偷窥一区二区 | 亚洲无码在线小视频 | 午夜精品免费视频观看在线 | 国产婷婷色一区二区三区在线 | 日韩一区二区综合精品 | 国产午夜福利100集发布 | 无码激情做a爰片毛片av片 | 国产伦精品一区二区三区免.费 | 一级特黄国产免费大片 | 亚洲精品国产第一综合99久久 | 国产精品第一页在线观看 | 国产成人麻豆精品午夜福利在 | 麻豆视频观看网站 | 日本欧美一区二区三区不卡视频 | 国产激情无码一区二区视频 | 中文字幕免费在线 | a级国产乱理论片在 | 日本ⅴ精品一区二区三区久久 | 欧美午夜激情影院 | 国产精品高潮呻吟久久v | 亚洲国产911在线观看 | 精品黑人一区二区三区 | 欧洲女人牲交 | 国产精品午夜一级毛片密呀 | 成人午夜看片 | 91成人网址| 亚洲国产成人久久99精品 | 亚洲精品码一区二区三区 | 无码人妻一区二区三区免费看 | 九月婷婷人人澡人人添 | 国产爆乳无码视频在 | 亚洲自拍清纯综合图区 | 国产真人无码免费视频 | 亚洲成av人片乱码色午夜浪潮 | 亚洲伊人精品国产欧美目韩 | 中文字幕无码在线观看 | 国产精品妇女一二三区 | 麻豆亚洲精品无码不卡在线播 | 精品一区二区三区五 | 久久www免费| av一道无码字幕 | 国产欧美不卡在线观看视频 | 日本经典电影在线观看 | 无人视频免费观看免费视频 | 动漫3d精品一区二区三区乱码 | 91制片厂制作果冻传媒八夷兔子 | 亚洲中文字幕一区二区 | 精品欧美一区二区三区 | 国内精品自在自线视频香蕉 | 国产福利小视频在线免费观看 | 国产精品亚洲а∨天堂2025 | 中文精品久久久久国产网址 | 精品一本之道久久久久久无码中文 | a在线v欧美 | 在线观看播放欧美国产 | 国产精品原创巨作无遮挡 | 在线精品91青草国产在线观 | 国产不卡一区二区三区視频。 | 神马午夜影院 | 国产成人亚洲精品91专区高清 | 国产av永久无码精品网站 | 亚洲国产综合精品一区在线播放 | 亚洲久热无码中文字幕人妖 | 在线视频91 | 中文字幕人妻偷伦在线视频 | 很黄很色裸乳视频网站 | 成人免费a级毛片无码片在线播放 | 91麻豆国产级在线 | 无限国产资源好片2025 | 亚洲sss整片av在线播放 | 爆乳护士一区二区三区在线播放 | 国产在线观看色 | 欧美精品黑人粗大 | 欧美日韩精品一区二区三区高清视频 | 国模大胆一区二区三区 | 亚洲国产精品无码久久 | 国产va免费精品高清在线 | 福利一区二区三区四区视频 | 欧洲精品视频一二三区视频 | 国产精品无码久久综合网 | 麻豆视频观看网站 | 精品日本久久久久久久久久 | 黄色视频 | 亚洲日韩欧美另类蜜桃 | 国产99视| 十大最污日本动漫都是少儿不宜啊! | 亚洲无码精品在线观看 | 亚洲精品一区二区三区午夜不卡片 | 最新国产v亚洲v欧美v专区 | 欧美日韩国产成人高清视频久久国产 | 精品国产综合成人亚洲区 | 在线看片人成免费视频播放 | 国产av一区二区三区传媒 | 高潮胡言乱语对白刺激国产 | 午夜成人在线视频 | 国产精品国产三级国产专播 | 精品一区二区三区无码免费直 | 亚洲成a人片在线观看国产 亚洲成a人片在线观看老师 | 日韩三级在线免费观看 | 国产aaaa| 午夜福利精品在线播放 | 日本午夜免费理论片 | 国产精品三级在线观看无码 | 国产精品嫩草影院免费 | 日韩亚洲欧美久久久www综合网 | 韩国无码无遮挡在线观看不卡 | 97久久精品久久免费观看 | 97伦理手机高清免费在线观看 | 国产精品伦理一区二区三区 | 91在线码无精品秘?入口九色 | 十大免费无广告污软件推荐 | 午夜国产毛片v区一区二区三区 | 国产自在现偷国产精品国产日韩 | 欧美精品网站一区二区三区 | 精品人妻少妇一区二区大牛影视 | 91免费国产自产地址入 | 亚洲综合精品一区二区三区中文 | 国产区1、2、3有什么区别 | 精品91自产拍 | 91精品国产91久久久久久青草 | 99热在线免| 日韩精品午夜视频一区二区三区 | 国产婷婷色一区二区三区在线 | 精品欧美日韩在线视频 | 91国精产品秘一区二区三区有何不同 | 二区三区在线观看 | 国产无套码aⅴ在线观看在 国产无套内射又大又 | 国产成人精品综合久久久久 | 囯产精品一品二区三区 | 欧美人成国产91视频 | 国产精品高清一区二区三区久久你 | 无码中文字幕人妻在线一区 | 国产午夜精品一区二区 | 欧美一级特黄大片色欧美精品 | 中文字幕亚洲男人的天堂网络 | 国产午夜福利伦理无码观看 | 国产成人手机在线视频在线观看 | 午夜理论片无码 | 日韩av一级毛片无码 | 国产精品亚洲а∨天堂2025 | 精品亚洲无码一区 | www.一区二区 | 99爱国产精品免费高清在线 | 精品久久久久久久久午夜福利 | 国产精品特级露脸av毛片 | 色一情一乱一伦一区二区三区 | 无码少妇一区二区三区视频 | 无码久久中文字幕 | 国产成人亚洲精品无码av | 国产免费不卡av在线播放 | 中文字幕乱码字幕在线视频 | 亚洲另类激情综合偷自拍 | 天美传媒免费观看一二三在线 | 国产无码在线观看免费在 | 91亚色视频| 国产极品在线观看视频 | 中文字幕无码中文字幕有码a | 99精品人妻少妇一区二区 | 国产精品美女乱子伦高潮 | 插逼网站 | 亚洲日本一区二区一本一道 | 91国在线观看 | 伊人小蛇婷婷色香综合缴缴情 | 波多野结衣乳喷高潮视频 | 丰满人妻一区二区三区46 | 精品日本久久久久久久久久 | 成年免费视频黄网站 | 欧美日韩在线一区二区三区 | 国产系列丝袜熟女精品视频 | 国产午夜福利播放 | 亚洲日韩天堂一区二区免费 | 成人网址在线观 | 特级毛片a级毛片在线播放www | 91桃色午夜福利国产在线观看 | 亚洲av理论在线电影网 | 国内精品视频成人一区二区 | 亚洲avav天堂av在线精品一 | аv天堂手机版在线观看 | 亚洲熟妇自偷自拍另类图片站 | 99久久精品无码一区二区毛片 | 99热视热频这 | 亚洲手机在线观看不卡av | 久久av无码aⅴ高潮av喷吹 | av在线亚洲无码 | 欧美一区二区三区成人片在线 | 日本一道在线播放高清 | 91久久香蕉国产线看观看软件 | 精品无码人妻被多人侵犯av | 成人精品第一区二区三区 | 国产激爽大片高清在线观看 | 国产呦系列视频网 | 亚洲精品中文字幕无乱码 | 波多野结衣的av一区二区三区 | 丰满人妻av | 少妇高潮惨叫久久久久久 | 99久久国产精品免费一区二区 | 欧美成人精品高清在线观看 | 午夜福利在线视频亚洲 | 欧美午夜精品久久久久久 | 人人妻人人澡人人爽欧美一区双 | 亚洲成av人片在线观看无 | 国产亚洲欧美精品永久app | 成人色综合 | www国产无套内射久久 | 国产精品99 | 在线精品91青草国产在线观 | 亚洲av无码一区东京热不卡 | 97爱爱 | 99午夜福利精品视频 | 国产精品人成在线播放新网站 | 无码国产乱伦三级 | www.色| 午夜成人av乱码无码午夜 | 麻豆久久久9性大片 | 色偷偷8888欧美精品久久 | 精品无码中出 | 日韩av一区二区精品不卡 | 亚洲国产av无码专区亚洲av | 极品白丝国产在线视频 | 中文字幕久久久久 | 欧美午夜精品 | 丰满少妇被猛男猛烈进入久久 | 欧洲国产成人久久精品综合 | 国内精品少妇久久精品 | 国产在线视频一区二区三区 | 精品精品国产自在久久精品 | 国产美女免费 | www.1515国产一二三区 | 无人一码二码三码4码免费 无人影院手机版在线观看免费 | 久久99精品久久久久久野外 | 国语自产精 | 亚洲无码成人最 | 黄色网页大全 | 一区二三区国产 | 99精品一区二区三区无码吞精 | av播放在线观看播放 | 97色永久全国免费视频 | 国产三级高清视频在线观看 | 少妇高潮对白在线 | 国产精品欧美视频另类专区 | 天天日天天射伊人色综合久久 | 91精品福利资源在线观看 | 91桃色大香蕉 | 91精品国产乱 | 国产手机在线片无 | 99久久久无码国产精精品 | 天天操天 | 精品久久久无码人妻中文字幕 | 国产av一区二区精品久 | 中文字幕亚洲综合久久菠萝蜜 | 精品乱子伦一区二区三区 | 老司机视频在线www 老司机午夜 | 国产福利观 | 中文字幕av专区无码不卡久久 | 97se狠狠狠狠狼鲁亚洲综 | 精品福利在线观看 | 美女18禁黄无遮挡网站 | 国产精品美女久久久久av超清 | 深夜福利视频大全在线观看 | 欧美精品一区二区三区91 | 国产成人亚洲欧美二区综合 | 国产欧美日韩视频在线观看 | 亚洲精品成人片在线观看精品字幕 | 国产一级a爱做片免费看 | 中文无码精品一区二区三区 | 91精品一区二区三区在线观看 | 97se狠狠狠狠狼鲁亚洲综合色 | 日本精品成人一区二区三区视频 | 91久久91久久精品麻豆 | 国产午夜精品久久久久九九电影 | 国产成人午夜福利在线观看视 | 国产久爱青草视频在线观看 | a成在线观看网站 | 日韩av | 91插插插网站 | 欧美最猛性xxxxxx | 少妇高潮流白浆在线观看 | 国产成人精品麻豆视频 | 精品久久久久久久久一起玩 | 国内精品久久久久 | 国产麻豆剧传媒免费观看 | 日韩欧美国精品一区二区三区 | 无码av喷白浆在线播放 | 麻豆影视在线播放 | 成人麻豆精品激情视频在线观看 | 亚洲无码精品免费一区 | 日韩中文字幕制服 | 亚洲国产欧美日韩v一区二区 | 国产av寂寞骚妇 | 午夜亚洲av日韩aⅴ无码大全 | 日本高清色本在线www游戏 | 精品国产综合久久久久 | 国产精品剧情久久久久 | 亚洲精品亚洲人成人网 | 精品国产影片在线观看 | 国产精品一级无码免费播放 | 中文字幕久久最新 | 中文字幕av无码 | 国产成人无码aa精品一区 | 国产av人人夜夜澡人人爽 | 国产精品日韩欧美一区二区三区 | 欧美在线观看免费人成 | 欧美日韩综合在线视频免费看 | 波多野42部无 | 国产乱人视频在线观看ktv | 亚洲av理论在线电影网 | 日本高清| 国产免费爽爽视频免费可以看 | 婷婷色中文在线观看 | 91看片| 狠狠色噜噜狠狠狠888米奇视频 | 国产第一在 | 一区二区精品在线 | 国产在线午夜不卡精品影院 | 亚洲欧美日韩另类丝袜一区 | 国产成人免费在线观看 | 亚洲国产成人精品久久久 | 黄页成人免费网站 | 91免费精品国偷自产在线在线 | 丰满少妇粗大猛烈进高清播放 | 国产精华最好的产 | 日韩经典精品无码一区 | 99精品国产在热久久无毒 | 无码区国产区在线播放 | 在线播放亚洲第一字幕 | 97蜜桃电影在线观看 | 国产欧美日韩视频在线观看一区 | 国产av综合第一页 | 国产一区二区在线影院 | 成年女人毛片免费视频播放器 | 国产高清在线 | 精品国产美女福到在线直播 | 亚洲综合偷自成人网第页色 | 亚洲第一天堂久久 | 91精品国产白丝在线观看 | 动漫精品一区二 | 午夜精品久久久无码 | 国产精品乱码一区二区三区软件 | av天堂最新手机网址 | 在线观看成人视频免费 | 亚洲av无码精品色午 | 国产99视频精品免费视频76 | 精品欧美成人高清在线观看 | 亚洲日韩欧美一区二区三区 | 日本aⅴ深夜私人噜噜噜视频 | 国产va在线播放 | 午夜在线亚洲 | 国产精品无码大片在线观看 | 99久久国产综合精品网成人影院电影 | 亚洲一区二区免费 | 日韩无码三级 | 人妻中文字幕无码老熟妇 | 欧美日韩一卡2卡3卡4卡国色天香 | 国产黄片av免费观看 | 日韩精品欧美高清区 | 国产精品高清一区二区 | av午夜午夜快憣免费观看 | 动漫精品专区一区二区三区不卡 | 麻豆一区二区三区精品视频 | 亚洲日本1区2区3区二区 | 蜜臀av性久久久久蜜臀aⅴ麻豆 | 无码在线免费播放 | 中文精品久久久久中文 | 国产乱子经典视频在线观看 | 亚洲av无码久久久久久精品 | 国产成人精品一区二区三区… | 亚洲a∨无码男人的天堂 | 国产精选秘免费进入竹菊影视 | 国产一区二区三区视频精品 | а√最新版亚洲毛多色婷婷 | 国产在线精品一区二区三区 | 国偷自愉自产产区91区 | 国产精品日韩无码一区二区 | 国产高清在线精品一区 | 日韩成人毛片高清视频免费看 | 波多野结衣(波多野結衣) | 天天av翘人人添亚洲综合网 | 中文国产成人精品 | 日本一二三不卡免费视频 | 精品亚洲精品中文字幕乱码 | 东京热人妻无码一区二区av | 国产精品无码亚洲精品2025 | 黄色a级毛片一级毛片 | 亚洲v无码专区日韩乱码不卡 | 91麻豆精产国品一二三系列产品测评 | 日韩在线a视频免费播放 | 韩国激情一区二区无码在线 | 国产淫荡 | 99玖玖爱免费热在 | 91嫩草国产在线无码观看 | 无码视频一区二区三区 | 国产精品免费久久久久久久蜜桃 | 亚洲国产成人在人网站天堂 | 成人在线高清 | 国产美女裸体无遮掩免费牛牛 | 极品中文字幕国产视频 | 亚洲精品无码a√中文字幕网站 | 91制片厂制作果冻传媒八夷兔子 | 国产av午夜精品一区二区入口 | 高清无码在线观看视频 | 精品少妇人妻av无码久久 | 97se亚洲国产综合自 | 人人片av麻烦 | 亚洲国产成人精品福利 | 精品国产精品人妻久久无码五月天 | 亚洲中文字幕无码永久在 | 国产成人综合怡春院 | 99精品国产兔费观看久久 | 亚洲精品中文字幕不卡在线 | 99久久精品免费看国产一区二区三 | 亚洲av无码av专区在线观看 | 国99精品无码一区二区三区 | 黄色网站哪里可以看呜呜呜 | 精品亚洲专区无码 | 精品一区二区三区无码 | 成人黄片免费观看 | 免费一级成人毛片 | 免费无码又爽又刺激视频在线 | 人人超人人超碰超国产97超碰 | 国产高清在线精品一区 | 日本综合国产欧美 | 亚洲一区二区三区播放在线 | 国产高清色播视频免费看 | av中文色综合不卡 | 99er国产这里只有精品视频免费 | 欧美日韩在线播放 | 国产精品露脸国语对白 | 国产伦精品一区二区三区视频痴 | 九九热在线视频观看 | 成年女人免费视频播放7777 | 欧美精品 | 国产精品白丝喷水在线观看 | 国产三级精品三级在线观看专 | 欧洲精品 | 欧美一区二区三区黑人免费 | 亚洲午夜精品 | 97人人模人人爽人人喊 | 精品高潮呻吟99av无码视频 | 91天堂素人搭讪在线观看 | 午夜福利网国产a | 天天躁狠狠躁狠狠躁夜夜躁 | 国外免费人妖网视频在线观看 | 亚洲jizz| 国产91短视频 | 日夜夜操天天爽在欧美亚 | 无码人妻久久久一区二区三区 | 亚洲av无码一区二区三区在线观 | 国偷自拍视频在线观看 | 日产国产亚洲系列 | 成人在线精品视频 | 国产美女视频一区 | 色网站免费观看 | 国产午夜福利免费看片 | 午夜性色福利视频 | 99精品视频久久精 | 91麻豆网 | 在线观看91精品国产 | 国产日韩欧美久久 | b毛多的女人图片 | www亚洲福利姬在线观看 | 93精品国产成人观看 | 日韩高清在线观看不卡一区二区 | 欧美日韩一区二区三 | 午夜无码一区二区三区在线观看 | 国产精欧美一区二区三区 | 无码在线啊啊啊 | 欧美精品白浆一区二区三区 | 日韩精品无码免费专区午夜不卡 | 日本成a人片 | 91男女免费福利 | 91精品一区国产高清在线 | 午夜播放器app2025最新 | 97国产婷婷综合在线视 | 亚洲精品亚洲九 | 欧美激情一区二区久久久 | 日本久久综合网站点击 | 91久久国产口精品久久久 | 亚洲欧美日韩久久精品黄色片 | 天堂资源官网在线资源 | 91啪在线观看国产在线 | 动漫精品一区二区三区四 | 国产女主播在线观看 | 日韩美女色高清在线看 | 色欲av蜜臀av在线观看麻豆 | 国产对白刺激 | 国产一区二区三区久久精品 | 国产午夜福 | 亚洲爱啪视 | 国产91精品不卡在线 | 欧美精品久久久久精品 | 国产香港日本三级在线观看 | 国产精品毛片va一区二区三区 | 亚洲va成高清在线播放人 | 福利官方导航 | 国产精品亚洲а∨天堂免下 | 午夜免费小视频 | 国产资源无限好片 | 无码精品人妻一区二区三区爱剪 | 91精品秘密秘在线观看 | 国产成人免费在线观看 | 黄色视频在线 | 国产久爱免费精品视频 | 丰满少妇人妻无码区 | 国产乱人视频在线观看ktv | 自拍视频91 | 国产成人影院 | 国产成人午夜福利免费无码r | 三级三级三级a级全黄三 | 日本视频在线免费观看 | 国产亚洲精品福利片 | 一区二区三区日 | 99久久国产热无码精品免费 | 亚洲国产亚洲片在线观看播放 | 午夜午夜精品一区二区三区文 | 99久无码中文字幕 | 欧美一级黄色片免费看 | 亚洲毛片av日韩av无码 | 亚洲乱理伦片在线看中字 | 亚洲最大无码av网站 | 99久久精品熟女高潮喷水免费 | av色综合久久天堂av色综合 | 97人妻人人揉人人躁人人 | 亚洲欧美人成综合导航 | 欧美视频一区二区三区 | 91人妻| 国产免费伦精品一区二区三区 | 国产亚洲精品久久久美女 | 日本午夜专区一 | 国产欧美日韩综合在线成 | 精品福利一区二区在线观看 | 精品无码成人久久久久久动漫 | 午夜插元素背景大全 | 99久久无色码中文字幕人妻 | 亚洲aⅴ无码天堂在线观看 亚洲aⅴ无码专区在线观看 | 国产成人精品一区二三区在线观看 | 国产日韩综合在线视频 | 精品国产不卡一区二区三区 | 成人午夜精品一区二区 | 午夜三级毛片欧美国产精品 | 日韩免费高清大片在线 | 91亚洲精品国产自在现线 | 亚洲久热无码中文字幕人妖 | av午夜午夜快憣免费软件 | 黑色午夜| 午夜亚洲国产 | 无码人妻精 | 色婷婷国产精品欧美毛片 | 亚洲a在线观看无码 | 毛片成人久久久国产一级a毛 | 国产精品国产精 | 国产成人啪精品视频免费网 | 国产日韩免费视频 | 日韩精品极品视频在线观看免费 | 无码国产伦一区二区三区视频 | 国产福利在线视频 | 国产精品激情无码视频 | 亚洲成a人片在线 | 国产青草视频在线观看 | 精品福利一区二区三区精品 | 亚洲欧美日97影 | 三级视频在线 | 99ri在线精品视频 | 国产一区二区三区免费在线 | 国产成本人片免费av | 精品人妻无码一区二区三区四川人 | 成人女人爽到高潮的a片羞羞动漫 | 日本一道在线播放高清 | 在线观看国产麻豆 | 成人免费 | 国产精品亚洲αv天堂无码 国产精品亚洲а∨天堂2025 | 亚洲精品成人av免费在线观看 | 成人午夜性a一级毛片免费 成人午夜性a一级毛片免费看 | 亚洲毛片无码不卡v在线播放 | 无码欧精品亚洲日韩一区 | 国产学生真实初次破初视频网站 | 精品国产3p一区二区三区 | 国产亚洲av网站在线观看 | 九九操人人操 | 麻豆视频传媒入口 | 91精品国产91久无码网站 | 亚洲国产精品成人va在线观看 | 成人黄色网站视频麻豆8 | 囯产精品一区二区三区线 | 九九精品一区二区三区 | 天堂网www最新版资源在线 | 午夜男女很黄的视频 | 国产精品理论片在线观看 | 国产欧美亚洲三区久在线观看 | 欧美成人精品一区二区三区 | 欧美男生射精高潮视频网站 | 国产91视频在线观看 | 午夜视频国产99在线看 | 中文字幕一区二区三区 | 桃色在线观看 | 日本啪视频在线观看精品综合 | 成人网站精品久久久久 | 欧美日韩国产无线码一区 | 国产精品99精品久久免费 | 福利在线一区 | 国产男人的天堂 | 免费一级片观看 | 国内精品一级毛片免费看 | а√天堂资源bt在线官网 | 午夜影院试看 | 天天操天天舔天天干 | 欧美日韩国产码高清综合人成 | av成人无码无在线观看 | 97se狠狠狠狠狼亚洲综合网 | 国产av一区二区精品久 | 人妻久久无码五月天 | 成人动漫1区2区3区 成人动漫h在线观看 | 国产白丝精品久久av网站 | 91国内外精 | 国产精品秘麻豆免费版 | 日韩中文字幕无码一区二区三 | 波多野结衣高潮喷水在线观看 | 国产精品自产拍在线观看一 | 国产夫妇| 欧美大片天天 | 日本久久久久久久久毛 | 一区二区三区美女视频免费观看 | 国产91精品在线观看导航 | 国产色综合久 | 国产亚洲av手机在线观看 | 自拍视频91| 国产精品鲁一鲁 | 精品人妻无码一区二区三 | 精品无码专区免费播放 |