• <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>

            思勤無邪

            上學時,因我年齡最小,個頭也最小,上課時,就像大猩猩堆里的猴一般。如今,這猴偶爾也把最近的一些情況寫在這里。

               :: 首頁 :: 聯系 :: 聚合  :: 管理
              132 Posts :: 1 Stories :: 178 Comments :: 0 Trackbacks

            公告

                 吾日常三省吾身,曰思、曰勤、曰無邪。

            積分與排名

            • 積分 - 183658
            • 排名 - 141

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

             最近在寫Shell Extension方面的東西,看到了這篇文章,抄在這里。
            原文地址http://blog.csdn.net/vcbear/archive/2002/01/25/5990.aspx
            同時也找到了一個與Drag and Drop有關的例子,地址:http://www.codeproject.com/useritems/NSExtDragDrop.asp

            vcbear

            關于

            Windows 的外殼擴展編程,拖放是比較簡單的一種,在網上可以找到不少介紹這個技巧的文章。大部分是介紹使用 MFC COleDropTarget 實現的,我覺得一般使用 COleDropTarget 已經很好了,但是我習慣在一些程序模塊中,完全的不使用 MFC, 比如純 SDK 編程 , 還有用在 ATL 的時候 ,MFC 是相當累贅的。所以 COleDropTarget 在這個意義上講不夠完美。

            參考了

            MSDN 以及 www.CodeProject.com 的相關文章和代碼( by Thomas Blenkers )之后,我發現拖放實際上主要使用了 IDropTarget 的接口方法,非常簡單,不妨直接面對原始 IDropTarget 實現自己的拖放類。

            作為學習筆記,就有了這么一篇文字,以拋磚引玉:

            IDropTarget

            是系統留給支持拖放的客戶程序的一個純虛接口,事先沒有對接口的任何函數進行實現,而是讓用戶通過實現接口函數來接管拖放的結果。IDropTarget接口有以下成員函數:

            • 基本
            COM成員函數

             

            QueryInterface

            AddRef

            Release

            • 接管拖放事件的成員函數:

               

              DragEnter

              DragOver

              DragLeave

              Drop

              也就是說,要在客戶程序里實現以上

              7個函數的實體。

              系統在檢測到拖放發生的時候,會在合適的時候依次調用客戶程序里實現的

              IDropTarget接口相應函數,檢查用戶在這些函數里返回的標志,決定鼠標外觀表現和拖放結果。

               


               

               

              實現

              IDropTarget接口

              為此建立一個基類為IDropTarget的類:

              class CDropTargetEx : public IDropTarget

              IDropTarget接口在OLEIDL.h里定義,為純虛接口。

              CDropTargetEx里依次聲明接口所包含的7個函數,原形為:

              HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject);

              ULONG STDMETHODCALLTYPE AddRef(void);

              ULONG STDMETHODCALLTYPE Release(void);

              HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState,

              POINTL pt,

              DWORD *pdwEffect);

              HRESULT STDMETHODCALLTYPE DragEnter(IDataObject * pDataObject,

              DWORD grfKeyState, POINTL pt,

              DWORD * pdwEffect);

              HRESULT STDMETHODCALLTYPE DragLeave(void);

              HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj,

              DWORD grfKeyState,

              POINTL pt,

              DWORD __RPC_FAR *pdwEffect);

              (為了實現Addref計數,還有一個ULONG tb_RefCount成員變量是必須的。QueryInterfaceAddRef,Release3個函數的實現是COM知識中最基本的,請參見附例)

              在講解

              IDropTarget其他函數的具體實現之前,有必要介紹一下一個你可能永遠不會直接調用但是確實存在的函數:DoDragDrop函數.此函數在某數據源的數據被拖動的時候就被調用,它負責

              • 檢測目標窗口是否支持拖放,發現目標窗口的
              IDropTarget接口

               

            • 隨時跟蹤鼠標和鍵盤的狀態,根據狀態決定調用其DrageEnter,DragMove,DropDragLeave接口

               

            • 從這些接口獲取客戶程序的返回值,根據這些值和用戶界面以及數據源進行交互。

               

              可以說

              DoDragDrop控制拖放的整個過程,我們要做的,只是將這個過程里發生的事件,接管下來并得到相應的信息,和DoDragDrop進行交互而已。了解了這一點有助于我們理解為什么通過區區一個接口4個函數就可以實現了拖放的效果,因為系統為我們已經做了很多。

              另一個非常重要的

              APIRegisterDragDrop,這個函數的原形是這樣的:

              WINOLEAPI RegisterDragDrop(

              HWND hwnd,

              IDropTarget * pDropTarget

              );

              不用被

              WINOLEAPI嚇到,這是一個宏:

              #define STDAPI EXTERN_C HRESULT STDAPICALLTYPE

              也就是表示一個標準的

              WIN API函數,返回一個HRESULT的值。

              函數

              RegisterDragDrop的作用是告訴系統:某個窗口(hwnd參數指定)可以接受拖放,接管拖放的接口是pDropTarget

              記住在調用

              RegisterDragDrop之前,一定要先調用OleInitialize初始化OLE環境。

              在類

              CDropTargetEx里設計了一個函數

              BOOL CDropTargetEx::DragDropRegister(HWND hWnd,

              DWORD AcceptKeyState=|MK_LBUTTON)

              {

              if(!IsWindow(hWnd))return false;

              HRESULT s = ::RegisterDragDrop (hWnd,this);

              if(SUCCEEDED(s))

              {

              m_hTargetWnd = hWnd;

              m_AcceptKeyState = AcceptKeyState;

              return true;

              }

              else { return false; }

              }

              在這個函數里調用

              RegisterDragDrop,this指針傳入,表示本類實現了IDropTarget.,由本類接管拖放事件。另外順便定義了一下拖放鼠標和鍵盤特性常數,對這個類來說,我希望默認的只接受鼠標左鍵的拖放,所以,默認的AcceptKeyState值是MK_LBUTTON。相關的鍵盤鼠標常數還有MK_SHIFT,MK_ALT,MK_RBOTTON,MK_MBUTTON,MK_BOTTON等幾個,我想這個幾個常數從字面上就可以理解它的意思了。這些常數可以用“位與”的操作組合。

              以下具體討論

              IDropTarget的拖放相關接口函數(4個),這里的拖放對象以文本和文件為主。

               


               

              • DragEnter

                 

                當你用鼠標選中了某一個文件或一段文本,并且將鼠標移到某個可以接受拖放(已經調用過

                RegisterDragDrop)的窗口里,DragEnter將第一時間被調用。再看一下其原形:

                HRESULT DragEnter( IDataObject * pDataObject,

                     DWORD grfKeyState,

                     POINTL pt,

                      DWORD * pdwEffect   )

                pDataobject

                是從拖放的原數據中傳遞過來的一個IDataObject接口實例,包含數據對象的一些相關方法,可以通過此接口獲得數據。

                grfKeyState

                DragEnter被調用時當前的鍵盤和鼠標的狀態,包含上面介紹過的鍵盤鼠標狀態常數。

                pt

                表示鼠標所在的點。是以整個屏幕為參考坐標的。

                pdwEffect

                DoDragDrop提供的一個DWORD指針,客戶程序通過這個指針給DoDragDrop返回特定的狀態。有效的狀態包括:

                DROPEFFECT_NONE=0 表示此窗口不能接受拖放。

                DROPEFFECT_MOVE=1 表示拖放的結果將使源對象被刪除

                DROPEFFECT_COPY=2 表示拖放將引起源對象的復制。

                DROPEFFECT_LINK =4 表示拖放源對象創建了一個對自己的連接

                DROPEFFECT_SCROLL=0x80000000表示拖放目標窗口正在或將要進行卷滾。此標志可以和其他幾個合用

                對于拖放對象來說,一般只要使用DROPEFFECT_NONEDROPEFFECT_COPY即可。

                DragEnter里要做什么呢?主要是告知拖放已經進入窗口區域,并判斷是否支持某具體類型的拖放。

                首先,要判斷鍵盤的狀態。在調用DragDropRegister時我傳入了一個AcceptKeyState并將其保存在m_AcceptKeyState成員變量里,現在可以拿它跟這里得到的grfKeyState比較:

                if(grfKeyState!=m_AcceptKeyState )

                {

                *pdwEffect = DROPEFFECT_NONE;

                return S_OK;

                }

                如果鍵盤和鼠標的狀態和我期望的不一樣,那么

                pdwEffect里返回DROPEFFECT_NONE表示不接受拖放。

                然后

                ,判斷拖放過來的IDataObject對象里有沒有我感興趣的數據。

                這里要介紹的是兩個關鍵的結構體

                FORMATETCSTDMEDIUM

                FORMATETC

                OLE數據交換的一個關鍵結構,對某種設備,數據,和相關媒體做了格式上的描述。

                其定義為

                typedef struct tagFORMATETC

                {

                CLIPFORMAT cfFormat;

                DVTARGETDEVICE *ptd;

                DWORD dwAspect;

                LONG lindex;

                DWORD tymed;

                }

                FORMATETC, *LPFORMATETC;

                在這里我們最感興趣的是

                cfFormattymed兩個數據。cfFormat是標準的“粘帖板”數據類型比如CF_TEXT之類。tymed表示數據所依附的媒介,比如內存,磁盤文件,存儲對象等等。其他的成員可以參見MSDN

                一個典型的

                FORMATETC結構變量定義如下:

                FORMATETC cFmt = {(CLIPFORMAT) CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};

                IDataObject提供了一個GetData接口來獲取其實例里包含的數據,比如:

                STGMEDIUM stgMedium;

                ret = pDataObject->GetData(&cFmt, &stgMedium);

                GetData傳入cFmt,以指出所感興趣的數據,并將返回在stgMedium結構里。

                STGMEDIUM

                的定義如下1

                typedef struct tagSTGMEDIUM

                {

                DWORD tymed;

                [switch_type(DWORD), switch_is((DWORD) tymed)]

                union {

                [case(TYMED_GDI)] HBITMAP hBitmap;

                [case(TYMED_MFPICT)] HMETAFILEPICT hMetaFilePict;

                [case(TYMED_ENHMF)] HENHMETAFILE hEnhMetaFile;

                [case(TYMED_HGLOBAL)] HGLOBAL hGlobal;

                [case(TYMED_FILE)] LPWSTR lpszFileName;

                [case(TYMED_ISTREAM)] IStream *pstm;

                [case(TYMED_ISTORAGE)] IStorage *pstg;

                [default] ;

                };

                [unique] IUnknown *pUnkForRelease;

                }STGMEDIUM;

                typedef STGMEDIUM *LPSTGMEDIUM;

                看起來頗為復雜,其實主要是一系列句柄或數據對象接口的聯合,根據數據具體的類型,使用其中之一即可。

                tymedFORMATETC里一樣,指出數據的載體類型(遺憾的是它不能指出具體的標準類型比如CF_TEXT或者其他)。至于pUnkForRelease,是源數據指定的一個接口,用來傳遞給ReleaseStgMedium函數,如果它不為NULL,則ReleaseStgMedium函數使用這個接口釋放數據。如果為NULL,ReleaseStgMedium函數使用默認的IUnknown接口。對于常規的拖放來說,這個對象指針應該為NULL.

                得到了句柄或數據對象接口,也相當于得到了拖放的數據。

                定義一個特定的

                FORMATETC結構實例傳遞給IDataObjectGetData,可以直接詢問和獲取某一種特定的數據。如果我們對我們想要的數據是非常確定的,這是比較有效率的方法。但是如果我們期望能夠對拖放的對象進行自適應的話,我們可以采取枚舉IDataObject里包含的所有數據類型的方案。這就要用到IEnumFORMATETC接口了。

                IEnumFORMATETC接口從IDataObject接口里獲取:

                IEnumFormatETC *pEnumFmt = NULL;

                ret = pDataObject->EnumFormatEtc (DATADIR_GET,&pEnumFmt);

                如果獲取成功,則可以通過

                IEnumFORMATETC接口的Next方法,來枚舉所有的數據格式:

                pEnumFmt->Reset ();

                HRESULT Ret=S_OK

                while(Ret!=S_OK)

                {

                Ret

                =pEnumFmt->Next(1,&cFmt,&Fetched);

                if(SUCCEEDED(ret))

                if( cFmt.cfFormat == CF_TEXT

                ||cFmt.cfFormat == CF_HDROP)

                {

                if(GetDragData(pDataObject,cFmt))

                EnterResult = true;

                }

                }

                第一個參數表示一次獲取的

                FORMATETC結構數據的數量,cFmt是一個FORMATETC指針,指向一個數據緩沖,用來返回FORMATETC數據。,FetchedNext調用后得到的FORMATETC數據個數。一般一次獲取一個,直到Next返回不為S_OK。

                我們可以對每個得到

                cFmt調用IDataObject->GetData方法,但是一般來說,一個數據對象包含的數據不止一種,而且一般有一些自定義的數據類型(關于自定義數據類型,參見:RegisterClipboardFormat,如果要自己實現Drag/Drop源數據,這個函數是有用的),對此我們不感興趣,因為這里只要求處理文本和文件的拖動,為此,只處理cfFormatCF_TEXTCF_HROP的數據:

                GetDragData

                CDropTargetEx類的一個成員函數:

                ///////////////////////////////////////////////////

                //Get The DragData from IDataObject ,save in HANDEL

                BOOL CDropTargetEx::GetDragData(IDataObject *pDataObject,FORMATETC cFmt)

                {

                HRESULT ret=S_OK;

                STGMEDIUM stgMedium;

                ret = pDataObject->GetData(&cFmt, &stgMedium);//GetData(CF_TEXT, &stgMedium);

                if (FAILED(ret))

                {

                return FALSE;

                }

                if (stgMedium.pUnkForRelease != NULL)

                {

                return FALSE;

                }

                ///////////////////////////////////////////

                switch (stgMedium.tymed)

                {

                case TYMED_HGLOBAL:

                {

                LPDRAGDATA pData = new DRAGDATA;

                pData->cfFormat = cFmt.cfFormat ;

                memcpy(&pData->stgMedium,&stgMedium,sizeof(STGMEDIUM));

                m_Array.push_back(pData);

                return true;

                break;

                }

                default:

                // type not supported, so return error

                {

                ::ReleaseStgMedium(&stgMedium);

                }

                break;

                }

                return false;

                }

                在這個成員函數里,根據

                cFmt,調用IDataObject->GetData函數獲得數據(對于CF_TEXTCF_HROP來說,數據的媒介載體tymed都是HGLOBAL類型的)。

                在具體實現的時候,我定義了一個結構:

                typedef struct _DRAGDATA

                {

                int cfFormat;

                STGMEDIUM stgMedium;

                }DRAGDATA,*LPDRAGDATA;

                 

                STGMEDIUM和數據類型(比如CF_TEXT,記錄在cfFormat)都記錄在DRAGDATA里。并且使用了一個vector數組,將這個結構保存在數組里。對于不是我們想要的STGMEDIUM數據,我們馬上調用ReleaseStgMedium函數進行釋放,免得造成內存泄露。

                這樣,

                DragEnter的工作就基本完成了,最后需要做的就是給DoDragDrop返回相應的狀態:如果我們獲得了想要的數據就給* pdwEffect賦值為DROPEFFECT_COPY,否則,就是DROPEFFECT_NONE

                如果支持拖放,鼠標形狀將變成一個有接受意義的圖標,否則,是一個拒絕意義的圖標。

                 


                 

                • DragOver

                   

                  鼠標拖動對象進入窗口之后,將會在窗口范圍內移動,這時

                  DoDragDrop就會調用IDropTargetDragOver接口。其原形為:

                  HRESULT DragOver(

                  DWORD grfKeyState

                  POINTL pt,

                  DWORD * pdwEffect

                  )

                  相對來說對于這個接口方法的實現可以簡單的多:只要根據

                  grfKeyState判斷鍵盤和鼠標的狀態是否符合要求,根據pt傳入的鼠標點判斷該點是否支持拖放(比如將拖放區域限制在窗口的一部分的話),然后為*pdwEffect賦值為DROPEFFECT_COPYDROPEFFECT_NONE.當然,還可以做一些你喜歡的事情,比如把鼠標坐標打印到屏幕上。不過為了性能和安全起見,建議不要做延時明顯的操作。

                   


                   

                  • DragLeave:

                     

                    這個方法沒有傳入參數,相當簡單。

                    當拖動的鼠標離開了窗口區域,這個方法將被調用,你可以在這里寫一些清理內存的代碼。在

                    CDropTargetEx類里,由于在DragEnternew了一些數據結構,并加到一個指針數組里,所以我必須在這里對此數據進行清理,對此結構里的STDMEDIUM調用ReleaseStgMedium然后Delete該結構。

                    另外,如果需要的話,可以通知用戶鼠標指針已經離開了拖放區域。

                     


                     

                    • Drop

                      如果鼠標沒有離開窗口,而是在窗口內釋放按紐,那么拖放時間的“放”就在這時發生,

                      IDropTarget接口的Drop方法被調用。其原形為

                      HRESULT Drop(

                      IDataObject * pDataObject,

                       

                      DWORD grfKeyState,

                      POINTL pt,

                       

                      DWORD * pdwEffect

                       

                      )

                      有些資料建議在這里才調用

                      pDataObject->GetData方法獲取數據,在CDropTargetEx類里,數據實際上已經在DragEnter里獲取了。這樣做的理由是我希望一開始就獲得數據,從它本身進行判斷是否支持拖放,而不是在“放”的時候才判斷是否合法數據。

                      既然數據已經獲得,那么我就可以從保存數據的指針數組里提取出

                      STGMEDIUM數據來,并根據數據的具體格式進行處理(最后一定要記住對STGMEDIUM進行ReleaseStgMedium

                      對于

                      CF_TEXT類型的數據,STGMEDIUM的成員hGlobal里包含的是一段全局內存數據。獲取這些數據的方法是:

                      TCHAR *pBuff = NULL;

                      pBuff=(LPSTR)GlobalLock(hText);

                      GlobalUnlock(hText);

                      則得到一個指向內存數據的指針pBuff。在我這個例子里一般是一段

                      "\0"結尾的文本字符串。這樣就實現了文本的拖放。

                      對于

                      CF_HDROP類型的數據,STGMEDIUM成員hGlobal是一個HDROP類型的句柄。通過這個句柄,可以獲得拖放的文件列表。如:

                      BOOL CDropTargetEx::ProcessDrop(HDROP hDrop)

                      {

                      UINT iFiles,ich =0;

                      TCHAR Buffer[MAX_PATH]="";

                      memset(&iFiles,0xff,sizeof(iFiles));

                      int Count = ::DragQueryFile(hDrop,iFiles,Buffer,0); //Get the Drag _Files Number.

                       

                      if(Count)

                      for (int i=0;i<Count;i++)

                      {

                      if(::DragQueryFile(hDrop,i,Buffer,sizeof(Buffer)))

                      {

                      //Got the FileName in Buffer

                      }

                      }

                       

                      ::DragFinish(hDrop);

                      return true;

                      }

                      獲得的

                      Buffer是就是拖放的文件名,如果拖放的是多個文件,在for循環里可以依次獲取這些文件的文件名。這樣就實現了文件的拖放。

                       


                       

                       

                      CDropTargetEx

                      類使用非常簡單:

                      在客戶窗口的相關文件中,定義一個

                      CDropTargetEx實例:CDropTargetEx DropTarget;

                      在窗口創建之后,將窗口句柄進行拖放注冊:

                      DropTarget.DragDropRegister(hWnd);

                      或者

                      DropTarget.DragDropRegister(hWndMK_CONTROL|MK_LBUTTON);

                      表示鼠標左鍵按下并且按住

                      Ctrl鍵的拖放有效;

                      對于獲取拖放的結果,我使用的是回調函數方式:

                      回調原形

                      typedef VOID (_stdcall *DROPCALLBACK)(LPCSTR Buffer,int type);

                      在適當的地方(比如窗口的實現

                      CPP里)定義函數DropCallback

                      void _stdcall DropCallBack(LPCSTR Buffer,int type)

                      并且將其地址賦于

                      DropTarget實例:

                      DropTarget.SetCallBack(DropCallBack);

                      這樣,拖放文本到客戶窗口,回調函數將被調用,參數

                      Buffer為拖放的文本,formatCF_TEXT。而拖放文件的時候,對每個被拖放的文件都調用一次回調函數,參數Buffer為文件全路徑名,formatCF_HDROP

                      示例的

                      DropCallBack代碼為:

                      void _stdcall DropCallBack(LPCSTR Buffer,int format)

                      {

                      switch(format)

                      {

                      case CF_TEXT:

                      {

                      SetWindowText(hEdit,Buffer);

                      break;

                      }

                      case CF_HDROP:

                      {

                      TCHAR Buf[2048]="";

                      sprintf(Buf,"File : <%s> is Drag and Drop to this Windows ,Open it?",Buffer);

                      if(MessageBox(hMainWnd,Buf,"Question",MB_YESNO)==IDYES)

                      {

                      ShellExecute(0,"open",Buffer,"","",SW_SHOW);

                      }

                      }

                      default:

                      break;

                      }

                      }

                       

                      總結

                      :使用
                      IDropTarget實現通用的拖放,只要實現其7個接口,并且對得到的IDataObject用正確的格式(FORMATETC)調用正確的GetData獲取數據,返回DROPEFFECT決定拖放的特征和結果,并處理拖放結果即可。

                      要注意的小問題是:

                      • 要調用OleInitialize而不是CoInitialize或CoInitializeEx對COM進行初始,否則RegisterDragDrop將不會成功,返回的錯誤是E_OUTOFMEMORY--內存不夠,無法進行該操作。

                         

                      • 調用ReleaseStgMedium釋放STGMEDIUM里的數據,而不是直接對其hGlobal成員調用CloseHandle.

                         

                      • 拖放操作關系到兩個進程的數據交換,會將兩個進程都堵塞,直到拖放完成為止,所以,在接管拖放的接口方法中,不要進行過于耗時的運算。

                         

                      這個例子相當簡單,還可以簡化,比如取消

                      vector,將獲得HGLOBAL句柄作為成員變量存儲,或者將獲取數據的操作全部放到Drop方法里。

                      對于拖放文件,還有一個更簡單的方法:響應

                      WM_DROPFILES消息。步驟是:

                      • 對客戶窗口調用
                      DropAccepFiles,使該窗口可以接受文件拖放。

                       

                    • 響應WM_DROPFILES消息,其wParam就是HDROP句柄

                       

                    • 對此句柄調用DropQueryFiles獲取拖放文件列表并結束拖放,參見上面關于ProcessDrop的代碼

                       

                      對于拖放的全面闡述,請參見

                      MSDN->PlatformSDK Document->User Interface Services->Windows Shell里關于Transferring Shell Objects with Drag-and-Drop and the Clipboard”一章。Windows Shell系統提供了很多接口,讓用戶利用和擴充這些接口,很方便的開發和使用豐富的shell服務,確實是一種很聰明的設計。

                       

                      例子和代碼
                    • posted on 2007-03-05 12:52 思勤無邪 閱讀(5266) 評論(0)  編輯 收藏 引用 所屬分類: C++
                      久久婷婷色综合一区二区| 曰曰摸天天摸人人看久久久| 久久99热这里只有精品国产| 日韩电影久久久被窝网| 亚洲精品蜜桃久久久久久| 亚洲国产二区三区久久| 午夜精品久久久久9999高清| 国产亚洲欧美精品久久久| 国产69精品久久久久99尤物| 久久亚洲国产精品成人AV秋霞 | 久久久久久免费视频| 久久久久成人精品无码中文字幕| 国产成人AV综合久久| 久久久久久人妻无码| 日本精品久久久久久久久免费| 大伊人青草狠狠久久| 国产亚洲美女精品久久久2020| 精品久久久久久无码中文字幕 | 奇米综合四色77777久久| 狠狠久久综合| 久久免费高清视频| 无码人妻久久一区二区三区免费| 久久99久久成人免费播放| 97久久精品无码一区二区天美| 狠狠色丁香久久婷婷综合_中 | 久久www免费人成精品香蕉| 粉嫩小泬无遮挡久久久久久| 久久精品国产亚洲αv忘忧草| 久久久久亚洲AV无码去区首| 青青国产成人久久91网| 久久精品aⅴ无码中文字字幕不卡| 亚洲伊人久久综合中文成人网| 久久久WWW成人免费毛片| 国产精品免费久久| 四虎国产永久免费久久| 国产精品欧美久久久天天影视| 精品久久8x国产免费观看| 996久久国产精品线观看| 九九久久99综合一区二区| 久久91精品国产91久久麻豆| 久久91亚洲人成电影网站|