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

C++ Programmer's Cookbook

{C++ 基礎} {C++ 高級} {C#界面,C++核心算法} {設計模式} {C#基礎}

C++ COM

 

前言:為了介紹C#寫界面,C++寫算法的快捷交互開發方式,首先介紹c++,C#內部的DLL,COM調用。

一,COM
COM (Component Object Model),微軟為提高代碼的可從用性而開發的組件對象模型的軟件架構,在windows系統的開發中大量的使用了這種技術,使用這種技術我們盡可能的把我們的軟件劃分位許多組件,通過組件的組合調用最總實現軟件的目的,COM的使用不僅大大的提高了代碼的可從用性,而且減小了代碼間的耦合。更多的關于OLE,COM,COM+,DCOM,ActiveX的概念

二,COM的創建
一般COM的創建有2中方法,使用ATL Wizard 和不使用ATL。

1)使用ATL Wizard創建COM非常的簡單,可以參考下面2個鏈接,分別使用ATL6.0和ATL7.0,最新的類似:
     ATL7.0 COM: http://www.codeproject.com/atl/SimpleDlls.asp
     ATL6.0 com: http://www.codeproject.com/atl/com_atl.asp

2)不使用ATL,當然更沒有Wizard,只有手動的一步一步的實現,不過這也是學習COM最好的方法和必經之路。可以參考:
     http://www.codeproject.com/com/LocalCOMServerClient.asp
    具體的步驟如下:
    1)建立一個Win32的DLL。例如CarLocalServer。
    2)首先加入IDL接口描述文件CarLocalServerTypeInfo.idl,編譯后會生成4個文件CarLocalServerTypeInfo_h.h,CarLocalServerTypeInfo_i.cpp,CarLocalServerTypeInfo_p.cpp,      dlldata.cpp 。
    

import "oaidl.idl";
import 
"ocidl.idl";

// define IStats interface
[
object, uuid(FE78387F-D150-4089-832C-BBF02402C872),
 oleautomation, helpstring(
"Get the status information about this car")]
interface IStats : IUnknown
{
   HRESULT DisplayStats();
   HRESULT GetPetName([out,retval] BSTR
* petName);
};

// define the IEngine interface
[
object, uuid(E27972D8-717F-4516-A82D-B688DC70170C),
 oleautomation, helpstring(
"Rev your car and slow it down")]
interface IEngine : IUnknown
{
   HRESULT SpeedUp();
   HRESULT GetMaxSpeed([out,retval] 
int* maxSpeed);
   HRESULT GetCurSpeed([out,retval] 
int* curSpeed);
};

// define the ICreateMyCar interface
[
object, uuid(5DD52389-B1A4-4fe7-B131-0F8EF73DD175),
 oleautomation, helpstring(
"This lets you create a car object")]
interface ICreateMyCar : IUnknown
{
   HRESULT SetPetName([in]BSTR petName);
   HRESULT SetMaxSpeed([in] 
int maxSp);
};

// library statement
[uuid(957BF83F
-EE5A-42eb-8CE5-6267011F0EF9), version(1.0),
 helpstring(
"Car server with typeLib")]
library CarLocalServerLib
{
   importlib(
"stdole32.tlb");
   [uuid(1D66CBA8
-CCE2-4439-8596-82B47AA44E43)]
   coclass MyCar
   {
      [default] interface ICreateMyCar;
      interface IStats;
      interface IEngine;
   };
};


    3) 加入生命周期管理類managesycle.h
 

#pragma once

class CManageSycle
{
public:
    CManageSycle(void);
    ~CManageSycle(void);

    static void InObject()  {
++m_nObject;}
    static void DeObject()  {
--m_nObject;}
    static bool IsZeroObject() { return m_nObject
==0 ;}
    static void InLock()  {
++m_nLock;}
    static void DeLock()  {
--m_nLock;}
    static bool IsZeroLock() { return m_nLock
==0 ; }
private:
    static ULONG m_nObject;
    static ULONG m_nLock;
};

managesycle.cpp實現文件:

#include "StdAfx.h"
#include 
"managesycle.h"
ULONG CManageSycle::m_nObject
=0;
ULONG CManageSycle::m_nLock
=0;
CManageSycle::CManageSycle(void)
{
}

CManageSycle::~CManageSycle(void)
{
}


    4)加入真正的com的接口的實現類,MyCar.h (除了實現COM的接口,還必須實現IUnKnown接口)


#pragma once

#include 
"unknwn.h"
#include 
"CarLocalServerTypeInfo_h.h"

const int MAX_SPEED = 500;
const int MAX_NAME_LENGTH = 20;

class MyCar : 
    
public IEngine, 
    
public ICreateMyCar, 
    
public IStats  
{
public:
    MyCar();
    virtual ~MyCar();

    
// IUnknown
    STDMETHODIMP QueryInterface(REFIID riid, void
** pIFace);
    STDMETHODIMP_(DWORD)AddRef();
    STDMETHODIMP_(DWORD)Release();

    
// IEngine
    STDMETHODIMP SpeedUp();
    STDMETHODIMP GetMaxSpeed(
int* maxSpeed);
    STDMETHODIMP GetCurSpeed(
int* curSpeed);
    
    
// IStats
    STDMETHODIMP DisplayStats();
    STDMETHODIMP GetPetName(BSTR
* petName);

    
// ICreateMyCar
    STDMETHODIMP SetPetName(BSTR petName);
    STDMETHODIMP SetMaxSpeed(
int maxSp);

private:
    DWORD    m_refCount;
    BSTR    m_petName;
    
int        m_maxSpeed;
    
int        m_currSpeed;
};



MyCar.cpp

#include "stdafx.h"
#include 
<stdio.h> 

#include 
"CarLocalServerTypeInfo_i.c"
#include 
"MyCar.h"
#include 
"ManageSycle.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
MyCar::MyCar() : m_refCount(
0), m_currSpeed(0), m_maxSpeed(0)
{
    m_refCount
=0;
    CManageSycle::InObject();
    m_petName 
= SysAllocString(L"Default Pet Name");
    
}

MyCar::~MyCar()
{
    CManageSycle::DeObject();
    
if(m_petName) SysFreeString(m_petName);
    MessageBox(
NULL,
    L
"MyCar is being distructed. Make sure you see this message, if not, you might have memory leak!",
    L
"Destructor",MB_OK | MB_SETFOREGROUND);
}

// IUnknown
STDMETHODIMP MyCar::QueryInterface(REFIID riid, void
** pIFace)
{
    
// Which aspect of me do they want?
    
if(riid == IID_IUnknown)
    {
        
*pIFace = (IUnknown*)(IEngine*)this;
        
// MessageBox(NULL"Handed out IUnknown","QI",MB_OK | MB_SETFOREGROUND);
    }
    
    
else if(riid == IID_IEngine)
    {
        
*pIFace = (IEngine*)this;
        
// MessageBox(NULL"Handed out IEngine","QI",MB_OK | MB_SETFOREGROUND);
    }
    
    
else if(riid == IID_IStats)
    {
        
*pIFace = (IStats*)this;
        
// MessageBox(NULL"Handed out IStats","QI",MB_OK | MB_SETFOREGROUND);
    }
    
    
else if(riid == IID_ICreateMyCar)
    {
        
*pIFace = (ICreateMyCar*)this;
        
// MessageBox(NULL"Handed out ICreateMyCar","QI",MB_OK | MB_SETFOREGROUND);
    }
    
else
    {
        
*pIFace = NULL;
        return E_NOINTERFACE;
    }

    ((IUnknown
*)(*pIFace))->AddRef();
    return S_OK;
}

STDMETHODIMP_(DWORD) MyCar::AddRef()
{
    
++m_refCount;
    return m_refCount;
}

STDMETHODIMP_(DWORD) MyCar::Release()
{
    
if(--m_refCount == 0)
    {
        delete this;
        return 
0;
    }
    
else
        return m_refCount;
}

// IEngine
STDMETHODIMP MyCar::SpeedUp()
{
    m_currSpeed 
+= 10;
    return S_OK;
}

STDMETHODIMP MyCar::GetMaxSpeed(
int* maxSpeed)
{
    
*maxSpeed = m_maxSpeed;
    return S_OK;
}

STDMETHODIMP MyCar::GetCurSpeed(
int* curSpeed)
{
    
*curSpeed = m_currSpeed;
    return S_OK;
}


// IStats
STDMETHODIMP MyCar::DisplayStats()
{
    
// Need to transfer a BSTR to a char array.
    char buff[MAX_NAME_LENGTH];
    WideCharToMultiByte(CP_ACP, 
NULL, m_petName, -1, buff, 
                        MAX_NAME_LENGTH, 
NULLNULL);

    
//MessageBox(NULL, buff, L"Pet Name",MB_OK | MB_SETFOREGROUND);
    memset(buff, 
0, sizeof(buff));
    sprintf(buff, 
"%d", m_maxSpeed);
    
//MessageBox(NULL, buff,L"Max Speed", MB_OK| MB_SETFOREGROUND);
    return S_OK;
}

STDMETHODIMP MyCar::GetPetName(BSTR
* petName)
{
    
*petName = SysAllocString(m_petName);
    return S_OK;
}


// ICreateMyCar
STDMETHODIMP MyCar::SetPetName(BSTR petName)
{
    SysReAllocString(
&m_petName, petName);
    return S_OK;
}

STDMETHODIMP MyCar::SetMaxSpeed(
int maxSp)
{
    
if(maxSp < MAX_SPEED)
        m_maxSpeed 
= maxSp;
    return S_OK;
}


    5)加入工廠類MyCarClassFactory.h,(實現IUnKnown接口和IClassFactory接口)

// the class object (class factory) for CoMyCar class

#pragma once

class MyCarClassFactory : 
public IClassFactory
{
public:
    MyCarClassFactory();
    virtual ~MyCarClassFactory();

    
// IUnknown
    STDMETHODIMP QueryInterface(REFIID riid,void
** pIFace);
    STDMETHODIMP_(ULONG)AddRef();
    STDMETHODIMP_(ULONG)Release();

    
// IClassFactory
    STDMETHODIMP LockServer(BOOL fLock);
    STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter,REFIID riid,void
** ppv);

private:

    ULONG m_refCount;

};

MyCarClassFactory.cpp

#include "stdafx.h"
#include 
"MyCar.h"
#include 
"MyCarClassFactory.h"
#include 
"locks.h"
#include 
"ManageSycle.h"

MyCarClassFactory::MyCarClassFactory()
{
    m_refCount 
= 0;
}

MyCarClassFactory::~MyCarClassFactory()
{
    MessageBox(
NULL,
    L
"MyCarClassFactory is being distructed. Make sure you see this message, if not, you might have memory leak!",
    L
"Destructor",MB_OK | MB_SETFOREGROUND);
}

STDMETHODIMP_(ULONG) MyCarClassFactory::AddRef()
{
    
//return ++m_refCount;
    return 
10;
}

STDMETHODIMP_(ULONG) MyCarClassFactory::Release()
{
    
/*
    
if ( --m_refCount == 0 )
    {
        delete this;
        return 
0;
    }
    return m_refCount;
    
*/
    return 
20;
}

STDMETHODIMP MyCarClassFactory::QueryInterface(REFIID riid,void
** pIFace)
{
    
if ( riid == IID_IUnknown )
        
*pIFace = (IUnknown*)this;
    
else if ( riid == IID_IClassFactory )
        
*pIFace = (IClassFactory*)this;
    
else
    {
        
*pIFace = NULL;
        return E_NOINTERFACE;
    }
    ((IUnknown
*)(*pIFace))->AddRef();
    return S_OK;
}

STDMETHODIMP MyCarClassFactory::LockServer(BOOL fLock)
{
    (VARIANT_TRUE 
== fLock) ? CManageSycle::InLock() : CManageSycle::DeLock();
    return S_OK;
}

STDMETHODIMP MyCarClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,REFIID riid,void
** ppv)
{
    
if ( pUnkOuter != NULL ) return CLASS_E_NOAGGREGATION;

    MyCar
* pMyCarObj = NULL;
    HRESULT hr;

    pMyCarObj 
= new MyCar();
    hr 
= pMyCarObj->QueryInterface(riid,ppv);

    
if ( FAILED(hr) ) delete pMyCarObj;
    return hr;
}


    6)實現COM入口和自注冊函數CarLocalServer.cpp,

// CarLocalServer.cpp : Defines the entry point for the DLL application.
//

#include 
"stdafx.h"
#include 
<iostream>    
#include 
<string.h>

#include 
"CarLocalServerTypeInfo_h.h"
//#include "CarLocalServerTypeInfo_i.c"
#include 
"MyCarClassFactory.h"    
#include 
"ManageSycle.h"

using namespace std;

#ifdef _MANAGED
#pragma managed(push, off)
#endif

HMODULE g_hmodule;

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
{
    g_hmodule 
= static_cast<HMODULE>(hModule);
    return 
TRUE;
}


STDAPI DllCanUnloadNow()
{
    bool bDllCanUnloadNow 
= CManageSycle::IsZeroObject() && CManageSycle::IsZeroLock();
    return bDllCanUnloadNow ? S_OK : S_FALSE;
}

STDAPI DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID
* ppv)
{
    
*ppv = NULL;
    
if(__uuidof(MyCar) != rclsid)
    {
        return E_NOINTERFACE;
    }

    MyCarClassFactory
* pBirdFactory = new MyCarClassFactory();
    
if(NULL == pBirdFactory)
    {
        return E_OUTOFMEMORY;
    }

    HRESULT hr 
= pBirdFactory->QueryInterface(riid,ppv);
    
if(FAILED(hr))
    {
        delete pBirdFactory;
    }
    return hr;
}

STDAPI DllRegisterServer()
{
    HKEY hRoot, hNew;
    ::RegOpenKey(HKEY_CLASSES_ROOT,L
"CLSID",&hRoot);
    ::RegCreateKey(hRoot,L
"{1F0A9759-FCBE-4870-8336-971BD19A7452}\\InprocServer32",&hNew);
    wchar_t strFile[MAX_PATH];
    ::GetModuleFileName(g_hmodule,strFile,MAX_PATH);
    ::RegSetValue(hNew,
NULL,REG_SZ,strFile,MAX_PATH);
    ::RegCloseKey(hRoot);
    return S_OK;
}

STDAPI DllUnregisterServer()
{
    HKEY hRoot;
    ::RegOpenKey(HKEY_CLASSES_ROOT,L
"CLSID",&hRoot);
    ::RegDeleteKey(hRoot,L
"{1F0A9759-FCBE-4870-8336-971BD19A7452}");
    ::RegDeleteKey(hRoot,L
"{1F0A9759-FCBE-4870-8336-971BD19A7452}\\InprocServer32");
    ::RegCloseKey(hRoot);
    return S_OK;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif


    7)增加def到處文件CarLocalServer.def,

LIBRARY    "CarLocalServer"

EXPORTS
    DllCanUnloadNow                
PRIVATE
    DllGetClassObject               
PRIVATE
    DllRegisterServer               
PRIVATE
    DllUnregisterServer            
PRIVATE


  

三,COM的調用過程
通過一個創建COM組件的最小框架結構,然后看一看其內部處理流程是怎樣的

    IUnknown *pUnk=NULL;
    IObject *pObject=NULL;
    CoInitialize(NULL);
    CoCreateInstance(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IUnknown, (void**)&pUnk);
    pUnk->QueryInterface(IID_IOjbect, (void**)&pObject);
    pUnk->Release();
    pObject->Func();
    pObject->Release();
    CoUninitialize();

這就是一個典型的創建COM組件的框架,不過我的興趣在CoCreateInstance身上,讓我們來看看它內部做了一些什么事情。
以下是它內部實現的一個偽代碼
:

    CoCreateInstance(....)
    {
    .......
    IClassFactory *pClassFactory=NULL;
    CoGetClassObject(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **)&pClassFactory);
    pClassFactory->CreateInstance(NULL, IID_IUnknown, (void**)&pUnk);
    pClassFactory->Release();
    ........
   }

這段話的意思就是先得到類廠對象,再通過類廠創建組件從而得到IUnknown指針。繼續深入一步,看看CoGetClassObject的內部偽碼:

   CoGetClassObject(.....)
   {
    //通過查注冊表CLSID_Object,得知組件DLL的位置、文件名
    //裝入DLL
    //使用函數GetProcAddress(...)得到DLL庫中函數DllGetClassObject的函數指針。
    //調用DllGetClassObject
   }
DllGetClassObject是干什么的,它是用來獲得類廠對象的。只有先得到類廠才能去創建組件.
    下面是DllGetClassObject的偽碼:
    DllGetClassObject(...)
    {
    ......
    CFactory* pFactory= new CFactory; //類廠對象
    pFactory->QueryInterface(IID_IClassFactory, (void**)&pClassFactory);
    //查詢IClassFactory指針
    pFactory->Release();
    ......
    }
    CoGetClassObject的流程已經到此為止,現在返回CoCreateInstance,看看CreateInstance的偽碼:
    CFactory::CreateInstance(.....)
    {
    ...........
    CObject *pObject = new CObject; //組件對象
    pObject->QueryInterface(IID_IUnknown, (void**)&pUnk);
    pObject->Release();
    ...........
    }


四,COM的調用方法
對上面手動創建的COM的調用實例:

int main()
{
    
// initialize the COM runtime
    cout 
<< "Initialize the COM runtime";
    CoInitialize(
NULL);
    cout 
<< "success." << endl;

    
// declare variables
    HRESULT hr;
    IClassFactory
* pICF = NULL;
    ICreateMyCar
*  pICreateMyCar = NULL;
    IEngine
*       pIEngine = NULL;
    IStats
*        pIStats = NULL;

    cout 
<< endl << "Get the class factory interface for the Car class";
    hr 
= CoGetClassObject(CLSID_MyCar,CLSCTX_LOCAL_SERVER,NULL,IID_IClassFactory,(void**)&pICF);
    
if ( FAILED(hr) )
    {
        cout
<<"fail";
        
exit(1);
    }
    
else cout << "success." << endl;
    
    cout 
<< "Create the Car object and get back the ICreateMyCar interface";
    hr 
= pICF->CreateInstance(NULL,IID_ICreateMyCar,(void**)&pICreateMyCar);
    
if ( FAILED(hr) )
    {
        
//ShowErrorMessage("CoGetClassObject()",hr);
        
exit(1);
    }
    
else cout << "success." << endl;
    
    
// set parameters on the car
    cout 
<< endl << "Set different parameters on the car";
    pICreateMyCar
->SetMaxSpeed(30);
    BSTR carName 
= SysAllocString(OLESTR("COMCar?!"));
    pICreateMyCar
->SetPetName(carName);
    SysFreeString(carName);
    cout 
<< "success." << endl;

    cout 
<< endl << "Query the IStats interface";
    pICreateMyCar
->QueryInterface(IID_IStats,(void**)&pIStats);
    cout 
<< "success." << endl;

    cout 
<< endl << "Use the IStats interface to display the status of the car:" << endl;
    pIStats
->DisplayStats();

    cout 
<< endl << "Query the IEngine interface";
    pICreateMyCar
->QueryInterface(IID_IEngine,(void**)&pIEngine);
    cout 
<< "success." << endl;

    cout 
<< endl << "Start to use the engine" << endl;
    
int curSp = 0;
    
int maxSp = 0;
    pIEngine
->GetMaxSpeed(&maxSp);
    
do
    {
        pIEngine
->SpeedUp();
        pIEngine
->GetCurSpeed(&curSp);
        cout 
<< "current speed is: " << curSp << endl;
    } 
while (curSp <= maxSp);

    cout 
<< endl << "Report status again: " << endl;
    pIStats
->DisplayStats();

    
if ( pICF )         pICF->Release();
    
if ( pICreateMyCar) pICreateMyCar->Release();
    
if ( pIStats )      pIStats->Release();
    
if ( pIEngine )     pIEngine->Release();

    cout 
<< endl << "Close the COM runtime";
    CoUninitialize();
    cout 
<< "success." << endl;

    return 
0;
}


方法一:向上面的調用,通過包含#include "../CarLocalServer/CarLocalServerTypeInfo_h.h"和#include "../CarLocalServer/CarLocalServerTypeInfo_i.c"

方法二:使用#import導入tlb

可以使用: CComBSTR ,CComPtr<> 和 CComQIPtr<> 等來簡化調用。

五,總結
COM比一般的DLL有很多的優點,COM沒有重名問題,因為根本不是通過函數名來調用函數,而是通過虛函數表,自然也不會有函數名修飾的問題。路徑問題也不復存在,因為是通過查注冊表來找組件的,放在什么地方都可以,即使在別的機器上也可以。也不用考慮和EXE的依賴關系了,它們二者之間是松散的結合在一起,可以輕松的換上組件的一個新版本,而應用程序混然不覺。

但是COM仍然是有問題的,比如說版本控制的問題,.NET將逐步代替COM的使用。

六,參考
1)OLE/COM/COM+/DCOM/ActiveX/ActiveX contorl ( 概念)
2)用VC進行COM編程所必須掌握的理論知識
3)COM編程入門(1)
4)COM編程入門(2)
5)c++中使用com的方法

posted on 2007-05-28 19:45 夢在天涯 閱讀(9133) 評論(5)  編輯 收藏 引用 所屬分類: CPlusPlus

評論

# re: C++ COM 2007-05-28 21:39 夢在天涯

以上的手動創建COM實例,還有一定的問題,有那位高手愿意指點,使我改正,共同進步,還有COM的其他的調用方法,還有文章中的其他的問題,請幫忙指出,我將非常的感謝!

勇于共享!  回復  更多評論   

# re: C++ COM 2007-05-28 22:32 萬連文

其實代碼邏輯可以用C++抽象機制+設計模式去實現,而com的重點在夸語言平臺,把它作為一種interop手段是再好不過。在開發后期如果設計得當,用com做一層wrapper是很容易的事情。  回復  更多評論   

# re: C++ COM 2007-05-29 00:15 meet-dream

其實增加一層wrapper也是一件很ugly的事,如果效率是可以接受的,建議直接在對象模型上去實現。在wrapper同樣會把效率降的更低。  回復  更多評論   

# re: C++ COM 2007-06-22 12:26 .net編程

學習中  回復  更多評論   

# re: C++ COM 2014-02-10 15:49 sunnyes2008

MARK  回復  更多評論   

公告

EMail:itech001#126.com

導航

統計

  • 隨筆 - 461
  • 文章 - 4
  • 評論 - 746
  • 引用 - 0

常用鏈接

隨筆分類

隨筆檔案

收藏夾

Blogs

c#(csharp)

C++(cpp)

Enlish

Forums(bbs)

My self

Often go

Useful Webs

Xml/Uml/html

搜索

  •  

積分與排名

  • 積分 - 1812202
  • 排名 - 5

最新評論

閱讀排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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一区二区| 欧美日韩综合在线| 欧美日韩在线播放一区二区| 欧美日韩一区二区三区视频| 国产精品成人av性教育| 国产精品综合av一区二区国产馆| 国产乱码精品一区二区三区不卡| 国产欧美精品日韩区二区麻豆天美| 国产拍揄自揄精品视频麻豆| 国产综合香蕉五月婷在线| 亚洲第一精品福利| 亚洲一区久久久| 老色鬼久久亚洲一区二区| 亚洲国产乱码最新视频| 亚洲美女区一区| 亚洲欧美精品伊人久久| 麻豆精品视频| 国产精品网站视频| 亚洲精品乱码视频| 久久精品盗摄| 99国产精品久久久久久久成人热| 欧美一区二区三区视频在线观看 | 欧美成人午夜剧场免费观看| 亚洲日本一区二区三区| 午夜精品在线| 欧美日韩调教| 亚洲国内自拍| 久久理论片午夜琪琪电影网| 亚洲黄色高清| 久久激五月天综合精品| 国产精品yjizz| 亚洲精品视频免费在线观看| 久久国产精品久久久| 91久久精品国产91性色| 久久精品一区二区三区四区 | 免费成人黄色| 国产日韩精品入口| 亚洲一区二区在线视频| 亚洲第一在线视频| 久久久久网址| 一区二区三区在线免费播放| 亚洲欧美一区二区三区久久 | 最新中文字幕一区二区三区| 久久久久国产免费免费| 一本久久a久久精品亚洲| 免费的成人av| 亚洲淫性视频| 欧美日韩精品在线视频| 亚洲国产精品ⅴa在线观看| 久久久99久久精品女同性| 亚洲午夜精品久久久久久浪潮| 欧美精品福利在线| 亚洲精品一区久久久久久| 欧美激情偷拍| 蜜桃久久精品一区二区| 1024成人| 欧美高清不卡| 欧美福利精品| 一区二区免费在线视频| 亚洲理伦电影| 国产精品国产三级国产专播精品人| 亚洲一区二区av电影| 中国女人久久久| 国产精品久久久久av免费| 亚洲一区欧美二区| 亚洲欧美国产一区二区三区| 国产精品日本精品| 欧美资源在线| 久久亚洲综合色一区二区三区| 亚洲福利国产| 亚洲区一区二| 国产精品你懂的在线| 欧美一区视频| 免费中文字幕日韩欧美| 99视频+国产日韩欧美| 亚洲神马久久| 在线日韩av片| 这里只有视频精品| 一区在线免费观看| 99riav1国产精品视频| 国产亚洲午夜| 亚洲欧洲日韩在线| 国产精品色婷婷久久58| 裸体一区二区| 国产精品高清一区二区三区| 久久一区二区三区四区| 欧美精品一区二区蜜臀亚洲 | 一区二区三区欧美| 午夜在线精品偷拍| 99精品视频免费观看视频| 亚洲一区二区在线看| 在线成人中文字幕| 一区二区三区精品久久久| 经典三级久久| 在线视频精品一| 在线精品视频在线观看高清| 日韩西西人体444www| 好看不卡的中文字幕| 日韩亚洲视频在线| 亚洲国产mv| 午夜精品久久久久久久蜜桃app | 欧美凹凸一区二区三区视频| 亚洲精品国产精品乱码不99| 欧美一级午夜免费电影| 国产欧美三级| 亚洲国产日韩欧美| 国产精品欧美日韩| 最新国产成人av网站网址麻豆| 国产精品伦子伦免费视频| 欧美丰满高潮xxxx喷水动漫| 国产精品一区二区三区免费观看| 亚洲国产精品久久| 有码中文亚洲精品| 性欧美超级视频| 午夜欧美精品| 欧美性做爰毛片| 亚洲免费黄色| 日韩一级免费观看| 免费成人网www| 免费视频一区| 影音国产精品| 久久免费精品视频| 久久人人爽国产| 国产亚洲综合精品| 性伦欧美刺激片在线观看| 午夜精品视频| 国产精品日韩一区二区| 亚洲天堂av在线免费观看| 中文在线资源观看网站视频免费不卡 | 久久精品中文字幕一区二区三区| 欧美亚洲视频在线看网址| 欧美日韩成人网| 亚洲国产高清aⅴ视频| 亚洲国产精品视频一区| 老色鬼精品视频在线观看播放| 蜜桃av综合| 亚洲高清在线播放| 欧美aaa级| 99国产麻豆精品| 亚洲欧美日韩在线不卡| 国产精品久久国产三级国电话系列 | 亚洲性感美女99在线| 亚洲一区二区视频在线| 欧美日韩一区二区三区在线看| 日韩一区二区精品| 亚洲男人天堂2024| 国产日产欧产精品推荐色 | 久久精品亚洲精品| 久久中文在线| 亚洲麻豆一区| 国产精品毛片a∨一区二区三区| 亚洲欧美成人一区二区在线电影| 久久久噜噜噜久久人人看| 亚洲大片免费看| 欧美日韩国产综合视频在线观看中文 | 国产精品制服诱惑| 亚洲人人精品| 欧美成人免费在线视频| 久久精品国产精品亚洲精品| 亚洲伊人网站| 国产在线观看一区| 久久这里有精品视频| 欧美成人精品1314www| 最新亚洲电影| 欧美电影免费观看高清| 亚洲午夜视频| 久久久久久综合| 亚洲精品一区二区三区99| 欧美日韩免费区域视频在线观看| 正在播放日韩| 欧美顶级少妇做爰| 性欧美video另类hd性玩具| 一色屋精品视频免费看| 欧美三级中文字幕在线观看| 久久不射2019中文字幕| 亚洲美女免费精品视频在线观看| 欧美一区二区在线看| 亚洲精品国产日韩| 国产综合香蕉五月婷在线| 欧美日韩久久不卡| 久久久99免费视频| 亚洲一级电影| 亚洲精品视频一区| 裸体一区二区| 久久精品视频在线播放| 亚洲视频第一页| 亚洲精品久久久一区二区三区| 国产日产欧美a一级在线| 欧美日韩国产专区| 欧美1区视频| 久久精品国产综合| 亚洲视频图片小说| 亚洲三级免费电影| 亚洲高清激情| 欧美国产日本| 欧美v日韩v国产v| 久久免费视频网| 久久福利精品|