青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

我們知道ATL(活動模板庫)是一套很小巧高效的COM開發(fā)庫,它本身的核心文件其實(shí)沒幾個,COM相關(guān)的(主要是atlbase.h, atlcom.h),另外還有一個窗口相關(guān)的(atlwin.h), 所以拿來學(xué)習(xí)應(yīng)該是很方便的。但是因?yàn)锳TL的代碼充滿了模板和宏,內(nèi)部還夾雜著匯編,所以如果沒有比較豐富的C++模板和系統(tǒng)底層的知識,一般人會看得一頭霧水。

下面我們主要分析一下ATL中的一些匯編代碼。

ATL中出現(xiàn)匯編代碼主要是2處,一處是通過Thunk技術(shù)來調(diào)用類成員函數(shù)處理消息;還有一處是通過打開_ATL_DEBUG_INTERFACES宏來跟蹤接口的引用計(jì)數(shù)。

通過Thunk技術(shù)來調(diào)用類成員函數(shù)

我們知道Windows窗口的消息處理函數(shù)要求是面向過程的C函數(shù),所以我們C++普通成員函數(shù)就不能作為窗口的消息處理函數(shù),所以這里的問題就是如何讓我們的C++成員函數(shù)和Windows的窗口的消息處理函數(shù)關(guān)聯(lián)起來?MFC是通過一個Map來實(shí)現(xiàn)的,而ATL選擇了更為高效的Thunk技術(shù)來實(shí)現(xiàn)。

我們將主要代碼貼出來,然后介紹它的創(chuàng)建過程:
template <class TBase, class TWinTraits>
HWND CWindowImplBaseT< TBase, TWinTraits >::Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName,
        DWORD dwStyle, DWORD dwExStyle, UINT nID, ATOM atom, LPVOID lpCreateParam)
{
    ATLASSERT(m_hWnd == NULL);

    if(atom == 0)
        return NULL;

    _Module.AddCreateWndData(&m_thunk.cd, this);

    if(nID == 0 && (dwStyle & WS_CHILD))
        nID = (UINT)this;

    HWND hWnd = ::CreateWindowEx(dwExStyle, (LPCTSTR)MAKELONG(atom, 0), szWindowName,
        dwStyle, rcPos.left, rcPos.top, rcPos.right - rcPos.left,
        rcPos.bottom - rcPos.top, hWndParent, (HMENU)nID,
        _Module.GetModuleInstance(), lpCreateParam);

    ATLASSERT(m_hWnd == hWnd);

    return hWnd;
}
    static LRESULT CALLBACK StartWindowProc(HWND hWnd, UINT uMsg,
        WPARAM wParam, LPARAM lParam)
    {
        CContainedWindowT< TBase >* pThis = (CContainedWindowT< TBase >*)_Module.ExtractCreateWndData();
        ATLASSERT(pThis != NULL);
        pThis->m_hWnd = hWnd;
        pThis->m_thunk.Init(WindowProc, pThis);
        WNDPROC pProc = (WNDPROC)&(pThis->m_thunk.thunk);
        WNDPROC pOldProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)pProc);
#ifdef _DEBUG
        // check if somebody has subclassed us already since we discard it
        if(pOldProc != StartWindowProc)
            ATLTRACE2(atlTraceWindowing, 0, _T("Subclassing through a hook discarded.\n"));
#else
        pOldProc;    // avoid unused warning
#endif
        return pProc(hWnd, uMsg, wParam, lParam);
    }

class CWndProcThunk
{
public:
union
{
_AtlCreateWndData cd;
_WndProcThunk thunk;
};
void Init(WNDPROC proc, void* pThis)
{
#if defined (_M_IX86)
thunk.m_mov = 0x042444C7;  //C7 44 24 0C
thunk.m_this = (DWORD)pThis;
thunk.m_jmp = 0xe9;
thunk.m_relproc = (int)proc - ((int)this+sizeof(_WndProcThunk));
#elif defined (_M_ALPHA)
thunk.ldah_at = (0x279f0000 | HIWORD(proc)) + (LOWORD(proc)>>15);
thunk.ldah_a0 = (0x261f0000 | HIWORD(pThis)) + (LOWORD(pThis)>>15);
thunk.lda_at = 0x239c0000 | LOWORD(proc);
thunk.lda_a0 = 0x22100000 | LOWORD(pThis);
thunk.jmp = 0x6bfc0000;
#endif
// write block from data cache and
//  flush from instruction cache
FlushInstructionCache(GetCurrentProcess(), &thunk, sizeof(thunk));
}
};
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CContainedWindowT< TBase >* pThis = (CContainedWindowT< TBase >*)hWnd;
ATLASSERT(pThis->m_hWnd != NULL);
ATLASSERT(pThis->m_pObject != NULL);
// set a ptr to this message and save the old value
MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } };
const MSG* pOldMsg = pThis->m_pCurrentMsg;
pThis->m_pCurrentMsg = &msg;
// pass to the message map to process
LRESULT lRes;
BOOL bRet = pThis->m_pObject->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, pThis->m_dwMsgMapID);
// restore saved value for the current message
ATLASSERT(pThis->m_pCurrentMsg == &msg);
pThis->m_pCurrentMsg = pOldMsg;
// do the default processing if message was not handled
if(!bRet)
{
if(uMsg != WM_NCDESTROY)
lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
else
{
// unsubclass, if needed
LONG pfnWndProc = ::GetWindowLong(pThis->m_hWnd, GWL_WNDPROC);
lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLong(pThis->m_hWnd, GWL_WNDPROC) == pfnWndProc)
::SetWindowLong(pThis->m_hWnd, GWL_WNDPROC, (LONG)pThis->m_pfnSuperWindowProc);
// clear out window handle
pThis->m_hWnd = NULL;
}
}
return lRes;
}

(1)通過調(diào)用類成員函數(shù)Create來創(chuàng)建窗口, Create時通過
_Module.AddCreateWndData(&m_thunk.cd, this)將this指針保存起來.

(2)因?yàn)樽詴r將StartWindowProc設(shè)為窗口消息的回調(diào)處理函數(shù),所以第一個窗口消息會進(jìn)入到該函數(shù),在函數(shù)入口通過_Module.ExtractCreateWndData()將保存的This指針取出來。

(3)將窗口函數(shù)WindowProc和This指針傳給Thunk進(jìn)行初始化。

Thunk初始化時寫入一些匯編代碼thunk.m_mov = 0x042444C7;thunk.m_this = (DWORD)pThis;這2行代碼表示匯編代碼mov dword ptr [esp+0x4], pThis, 而esp+0x4對應(yīng)的是我們的第一個參數(shù)hWnd, 所以這個代碼表示把我們的第一參數(shù)hWnd用This替代。

接下來匯編代碼thunk.m_jmp = 0xe9; thunk.m_relproc = (int)proc - ((int)this+sizeof(_WndProcThunk));表示通過相對地址JMP跳轉(zhuǎn)到WindowProc。

(4)回到StartWindowProc, 將Thunk地址作為我們新的窗口消息處理函數(shù)地址, 這樣以后有任何新的窗口消息,調(diào)用的都是我們新的Thunk代碼了。

(5)下一個窗口消息到來,調(diào)用我們新的Thunk代碼,我們的Thunk代碼將第一個hWnd參數(shù)替換成This指針,然后跳轉(zhuǎn)到WindowProc

(6)在WindowProc函數(shù)中的第一參數(shù)已經(jīng)被轉(zhuǎn)成This指針,接下來我們就可以根據(jù)這個This指針調(diào)用它的虛函數(shù)ProcessWindowMessage了。

我們可以看到ATL這種通過Thunk關(guān)聯(lián)類成員函數(shù)處理消息的方法非常高效,只是參數(shù)修改和跳轉(zhuǎn),基本上沒有任何性能損失。

打開_ATL_DEBUG_INTERFACES宏來跟蹤接口的引用計(jì)數(shù)

我們知道COM中引用計(jì)數(shù)的管理一直是個難題,因?yàn)槟愕慕涌谑谴蠹夜灿玫模绻阋糜?jì)數(shù)管理出錯,就會導(dǎo)致一些非常難查的問題,因此ATL中我們可以通過打開_ATL_DEBUG_INTERFACES宏 ,讓我們通過Debug信息察看每個接口的引用計(jì)數(shù)情況。那么ATL是如何做到的呢?

相信用過ATL的人都會看到過這個代碼:
struct _QIThunk
{

    STDMETHOD(f3)();
    STDMETHOD(f4)();
    STDMETHOD(f5)();
         
         
    STDMETHOD(f1022)();
    STDMETHOD(f1023)();
    STDMETHOD(f1024)();
        .
};
里面有1000多個方法,相信很多人到現(xiàn)在還不知道這些東西有什么用,其實(shí)我以前一直也沒看懂這個東西。

下面我們來分析下ATL跟蹤接口引用計(jì)數(shù)的過程,同樣先貼代碼:
    static HRESULT WINAPI InternalQueryInterface(void* pThis,
        const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
    {
        ATLASSERT(pThis != NULL);
        // First entry in the com map should be a simple map entry
        ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
    #if defined(_ATL_DEBUG_INTERFACES) || defined(_ATL_DEBUG_QI)
        LPCTSTR pszClassName = (LPCTSTR) pEntries[-1].dw;
    #endif // _ATL_DEBUG_INTERFACES
        HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);
    #ifdef _ATL_DEBUG_INTERFACES
        _Module.AddThunk((IUnknown**)ppvObject, pszClassName, iid);
    #endif // _ATL_DEBUG_INTERFACES
        return _ATLDUMPIID(iid, pszClassName, hRes);
    }

HRESULT AddThunk(IUnknown** pp, LPCTSTR lpsz, REFIID iid)
{
if ((pp == NULL) || (*pp == NULL))
return E_POINTER;
IUnknown* p = *pp;
_QIThunk* pThunk = NULL;
EnterCriticalSection(&m_csObjMap);
// Check if exists already for identity
if (InlineIsEqualUnknown(iid))
{
for (int i = 0; i < m_paThunks->GetSize(); i++)
{
if (m_paThunks->operator[](i)->pUnk == p)
{
m_paThunks->operator[](i)->InternalAddRef();
pThunk = m_paThunks->operator[](i);
break;
}
}
}
if (pThunk == NULL)
{
++m_nIndexQI;
if (m_nIndexBreakAt == m_nIndexQI)
DebugBreak();
ATLTRY(pThunk = new _QIThunk(p, lpsz, iid, m_nIndexQI, (m_nIndexBreakAt == m_nIndexQI)));
if (pThunk == NULL)
return E_OUTOFMEMORY;
pThunk->InternalAddRef();
m_paThunks->Add(pThunk);
}
LeaveCriticalSection(&m_csObjMap);
*pp = (IUnknown*)pThunk;
return S_OK;
}


struct _QIThunk
{
STDMETHOD(QueryInterface)(REFIID iid, void** pp)
{
ATLASSERT(m_dwRef >= 0);
return pUnk->QueryInterface(iid, pp);
}
STDMETHOD_(ULONG, AddRef)()
{
if (bBreak)
DebugBreak();
pUnk->AddRef();
return InternalAddRef();
}
ULONG InternalAddRef()
{
if (bBreak)
DebugBreak();
ATLASSERT(m_dwRef >= 0);
long l = InterlockedIncrement(&m_dwRef);
ATLTRACE(_T("%d> "), m_dwRef);
AtlDumpIID(iid, lpszClassName, S_OK);
if (l > m_dwMaxRef)
m_dwMaxRef = l;
return l;
}
STDMETHOD_(ULONG, Release)();
STDMETHOD(f3)();
STDMETHOD(f4)();
         ....
STDMETHOD(f1023)();
STDMETHOD(f1024)();
_QIThunk(IUnknown* pOrig, LPCTSTR p, const IID& i, UINT n, bool b)
{
lpszClassName = p;
iid = i;
nIndex = n;
m_dwRef = 0;
m_dwMaxRef = 0;
pUnk = pOrig;
bBreak = b;
bNonAddRefThunk = false;
}
IUnknown* pUnk;
long m_dwRef;
long m_dwMaxRef;
LPCTSTR lpszClassName;
IID iid;
UINT nIndex;
bool bBreak;
bool bNonAddRefThunk;
};


#define IMPL_THUNK(n)\
__declspec(naked) inline HRESULT _QIThunk::f##n()\
{\
    __asm mov eax, [esp+4]\
    __asm cmp dword ptr [eax+8], 0\
    __asm jg goodref\
    __asm call atlBadThunkCall\
    __asm goodref:\
    __asm mov eax, [esp+4]\
    __asm mov eax, dword ptr [eax+4]\
    __asm mov [esp+4], eax\
    __asm mov eax, dword ptr [eax]\
    __asm mov eax, dword ptr [eax+4*n]\
    __asm jmp eax\
}

IMPL_THUNK(3)
IMPL_THUNK(4)
IMPL_THUNK(5)
....

(1)ATL內(nèi)部是通過調(diào)用InternalQueryInterface來查詢接口(QueryInterface)的,我們看到如果定義了宏_ATL_DEBUG_INTERFACES,它會增加一行代碼 _Module.AddThunk((IUnknown**)ppvObject, pszClassName, iid)。

(2)AddThunk會創(chuàng)建一個_QIThunk,然后把我們的指針改成它新建的_QIThunk指針,這意味著我們上面QueryInterface的得到的指針已經(jīng)被改成_QIThunk指針了, 因?yàn)槲覀兯械腃OM接口指針都是通過QueryInterface得到的,所以接下來任何COM接口的調(diào)用都會跑到_QIThunk中。

(3)_QIThunk是嚴(yán)格按照IUnknow布局的,它虛表函數(shù)依次是QueryInterface, AddRef, Release, f3, f4, ... f1023, f1024。現(xiàn)在任何AddRef和Release的調(diào)用我們都可以攔截到了,這樣我們也就能跟蹤每個接口的引用計(jì)數(shù)情況了。

(4)那如果調(diào)用其他接口函數(shù)怎么辦?因?yàn)樘摵瘮?shù)的調(diào)用實(shí)際上是根據(jù)虛表中索引位置來調(diào)用的,所以調(diào)用其他虛函數(shù)實(shí)際上就是調(diào)用f3, f4 ... f1024等。現(xiàn)在我們應(yīng)該知道我們這1000多個虛函數(shù)的作用了。對,他們實(shí)際上只是占位函數(shù),ATL假設(shè)任何接口都不會超過1024個方法。所以我們這些占位函數(shù)要實(shí)現(xiàn)的功能就是如何通過我們保存的原始IUnknown* pUnk, 轉(zhuǎn)去調(diào)用它真正的虛函數(shù)。

(5)我們可以看到每個占位函數(shù)的實(shí)現(xiàn)都是一樣的,他們會去調(diào)用一段匯編代碼,我們看到這段匯編是裸代碼(naked),下面我們來分析這段匯編代碼.
根據(jù)QIThunk的內(nèi)存布局, 前4個字節(jié)是虛表指針,4-8字節(jié)是保存的原始接口指針IUnknown* pUnk,8-12字節(jié)是引用計(jì)數(shù)long m_dwRef

#define IMPL_THUNK(n)\
__declspec(naked) inline HRESULT _QIThunk::f##n()\
{\
    __asm mov eax, [esp+4]\       //將第一參數(shù),即pQIThunk保存到eax
    __asm cmp dword ptr [eax+8], 0\      //判斷QIThunk的引用計(jì)數(shù)是否為0
    __asm jg goodref\       //大于0才是正確的
    __asm call atlBadThunkCall\
    __asm goodref:\
    __asm mov eax, [esp+4]\         //將第一參數(shù),即pQIThunk保存到eax
    __asm mov eax, dword ptr [eax+4]\        //取出QIThunk的原始接口指針IUnknown* pUnk
    __asm mov [esp+4], eax\         //將原始接口指針保存替換剛調(diào)用過來的第一參數(shù)
    __asm mov eax, dword ptr [eax]\        //取出原始接口指針保存的虛表地址,保存到eax
    __asm mov eax, dword ptr [eax+4*n]\       //根據(jù)索引,取出原始虛表中對應(yīng)的函數(shù)地址
    __asm jmp eax\        //跳轉(zhuǎn)到該函數(shù)地址
}

可以看到,通過上面的匯編代碼,將原來是針對QIThunk的調(diào)用又轉(zhuǎn)回到了我們原始的接口中。呵呵, 實(shí)際上應(yīng)該是
ATL攔截了我們原始的接口調(diào)用,轉(zhuǎn)到了QIThunk中,而QIThunk最終又通過Thunk機(jī)制轉(zhuǎn)回了原始的接口調(diào)用。

通過上面一些介紹,希望可以幫助你理解ATL, 我們可以看到Thunk本質(zhì)上只是通過匯編實(shí)現(xiàn)參數(shù)的修改和指令的跳轉(zhuǎn)。

以前我看ATL也很吃力,以我個人的經(jīng)驗(yàn),一些東西剛開始看不太懂就放一放,先去看一些基本的東西,比如不懂COM,先去學(xué)下C++ 中的虛函數(shù);不懂C++模板,先去學(xué)下STL;不懂Thunk,先去看一下匯編,等有了一定的積累,回頭再看,一切就覺得沒這么難了。
posted on 2012-10-23 00:23 Richard Wei 閱讀(3305) 評論(0)  編輯 收藏 引用 所屬分類: 匯編

只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美国产日本在线| 国产精品看片你懂得| 久久亚洲国产精品日日av夜夜| 狠狠色香婷婷久久亚洲精品| 欧美性生交xxxxx久久久| 久久精品视频免费播放| 午夜一级久久| 久久人人爽爽爽人久久久| 久久电影一区| 久久久亚洲国产天美传媒修理工| 久久久久se| 久久久精品一区| 久久九九免费| 亚洲国产专区| 亚洲黄色一区二区三区| 欧美电影电视剧在线观看| 久久动漫亚洲| 欧美成人精品影院| 欧美国产日韩亚洲一区| 亚洲国产精品视频| 亚洲欧洲美洲综合色网| 亚洲精品视频在线观看免费| 亚洲韩日在线| 亚洲欧美影音先锋| 久久精品视频网| 久久综合给合| 99视频一区二区| 欧美一区二区三区久久精品| 久久精品欧洲| 亚洲私人影院在线观看| 亚洲性视频网站| 亚洲欧美清纯在线制服| 亚洲精品免费一区二区三区| 一区二区免费在线视频| 久久九九免费视频| 99热精品在线观看| 午夜日韩av| 两个人的视频www国产精品| 国产精品户外野外| 噜噜噜躁狠狠躁狠狠精品视频 | 久久激情五月丁香伊人| 亚洲一区二区三区四区五区黄| 亚洲在线视频免费观看| 美女主播精品视频一二三四| 国产精品激情| 亚洲激情视频在线播放| 午夜亚洲一区| 国产精品99久久久久久久久| 久久成人一区| a4yy欧美一区二区三区| 老牛影视一区二区三区| 国产精品99一区| 国产偷久久久精品专区| 午夜精品久久久久久99热软件| 欧美大色视频| 午夜精品在线观看| 一二美女精品欧洲| 欧美不卡一区| 亚洲欧洲精品一区二区三区波多野1战4| 亚洲欧美日韩专区| 亚洲日本中文字幕区| 欧美不卡视频一区发布| 1024精品一区二区三区| 久久久水蜜桃| 久久激情一区| 国产欧美日韩一区二区三区在线观看 | av不卡在线看| 欧美日韩另类字幕中文| 在线观看亚洲视频啊啊啊啊| 日韩午夜激情电影| 最新热久久免费视频| 麻豆av一区二区三区| 欧美激情亚洲| 欧美日韩免费| 一区二区国产精品| 亚洲午夜精品一区二区| 欧美三区在线| 亚洲欧美日韩一区二区在线| 欧美一级黄色录像| 国产农村妇女精品一二区| 欧美中文在线视频| 欧美gay视频激情| 欧美伊人久久久久久午夜久久久久| 欧美成ee人免费视频| 欧美影院久久久| 黄色成人在线免费| 久久一区国产| 亚洲午夜在线| 狠狠88综合久久久久综合网| 久久久久国产精品厨房| 亚洲免费影视第一页| 午夜精品一区二区三区在线播放| 国产模特精品视频久久久久| 亚洲色在线视频| 亚洲欧美日韩久久精品 | 午夜欧美不卡精品aaaaa| 洋洋av久久久久久久一区| 奶水喷射视频一区| 六月婷婷一区| 一区二区三区高清| 久久国产精品一区二区三区四区 | 午夜日韩av| 亚洲国产女人aaa毛片在线| 91久久久久久久久| 欧美性一区二区| 你懂的国产精品| 欧美区日韩区| 亚洲欧美另类久久久精品2019| 久久成人一区| 夜夜爽99久久国产综合精品女不卡 | 久久9热精品视频| 在线观看亚洲视频| 亚洲一区二区欧美| 亚洲国产高清一区| 男女激情视频一区| 国产精品社区| 亚洲第一主播视频| 欧美日韩在线第一页| 久久九九99| 欧美视频一区二| 亚洲国产专区校园欧美| 国产精品永久| 日韩视频在线免费| 亚洲黄色在线看| 亚洲欧美色一区| 亚洲一区二区三区高清不卡| 久久亚洲精品视频| 一区二区国产日产| 欧美高清在线一区| 久久精品最新地址| 国产日韩欧美高清| 国产精品尤物| 国产美女精品视频| aa日韩免费精品视频一| 伊人男人综合视频网| 亚洲欧美在线aaa| 日韩视频在线观看| 久久久久亚洲综合| 男女激情视频一区| 激情文学一区| 欧美亚洲免费电影| 欧美一区网站| 欧美日韩视频不卡| 亚洲国产精品va在线看黑人动漫| 精品电影一区| 久久久久国产一区二区三区四区| 久久看片网站| 国内欧美视频一区二区| 亚洲欧美亚洲| 欧美亚洲第一页| 免费日韩成人| 国产精品高清免费在线观看| 一本色道久久88综合日韩精品 | 国产欧美高清| 亚洲欧美国产视频| 亚洲欧美日韩国产| 国产日产欧产精品推荐色 | 欧美日本在线看| 亚洲高清视频在线观看| 一本色道久久综合| 欧美日韩国内| 一区二区三区高清不卡| 欧美日韩一区二区三区免费看| 亚洲欧洲在线一区| 亚洲已满18点击进入久久| 欧美日韩在线不卡| 亚洲人成网站精品片在线观看| 欧美成人精品在线| 亚洲男人av电影| 韩国精品久久久999| 久久久噜噜噜久久中文字免| 亚洲女女做受ⅹxx高潮| 国产精品综合| 久久久99免费视频| 亚洲精品小视频| 午夜精品在线视频| 亚洲国产精品专区久久| 欧美日韩国产精品自在自线| 亚洲欧美国产va在线影院| 老牛影视一区二区三区| 99re66热这里只有精品4| 国产欧美日韩不卡| 狂野欧美激情性xxxx欧美| 亚洲影院高清在线| 欧美黄色片免费观看| 午夜视频在线观看一区二区| 国语自产精品视频在线看| 久久久久久9| 99pao成人国产永久免费视频| 久久一区国产| 一本色道久久加勒比精品| 久久精品99国产精品酒店日本| 日韩视频在线一区| 国产一区亚洲| 国产精品成人免费| 久久躁日日躁aaaaxxxx| 亚洲系列中文字幕| 亚洲美女黄色片| 一二三四社区欧美黄| 国产精品自拍在线|