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

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 夢在天涯 閱讀(9143) 評論(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

搜索

  •  

積分與排名

  • 積分 - 1817650
  • 排名 - 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>
              欧美一区三区二区在线观看| 国产精品成人一区二区网站软件| 老司机久久99久久精品播放免费| 国产主播一区二区三区四区| 久久久久久伊人| 亚洲福利视频专区| 一本久久a久久免费精品不卡| 欧美日韩亚洲一区| 亚洲欧美精品在线观看| 久久国产精品一区二区| 雨宫琴音一区二区在线| 欧美刺激性大交免费视频| 99在线精品观看| 久久久99精品免费观看不卡| 一区免费在线| 欧美日韩一区在线| 午夜精品偷拍| 亚洲国产99精品国自产| 亚洲免费视频一区二区| 在线不卡中文字幕| 欧美精品xxxxbbbb| 午夜精品久久久久久久久久久久久 | 夜夜爽www精品| 欧美影院精品一区| 亚洲福利视频一区| 国产精品成av人在线视午夜片| 午夜精品久久| 亚洲精品一级| 狂野欧美激情性xxxx| 中日韩高清电影网| 极品中文字幕一区| 欧美私人网站| 久久野战av| 亚洲欧美日韩爽爽影院| 亚洲成色999久久网站| 亚洲免费一区二区| 亚洲欧洲精品一区二区三区| 国产精品久久久久永久免费观看| 久久综合中文| 午夜精品在线观看| 亚洲美女中文字幕| 免费亚洲电影在线| 欧美一区二区三区成人| 亚洲美洲欧洲综合国产一区| 国产一区再线| 国产精品中文在线| 欧美精品乱码久久久久久按摩| 久久国产精品第一页| 一区二区三区免费网站| 欧美成人中文字幕| 久久性天堂网| 久久激情视频| 小黄鸭精品aⅴ导航网站入口| 亚洲精品在线观看免费| 1000部精品久久久久久久久| 国产精品色网| 国产精品户外野外| 欧美视频一区二区三区| 欧美黄色一区| 免费一级欧美在线大片| 久久久99爱| 欧美一区二区三区精品电影| 亚洲欧美日韩视频一区| 亚洲午夜久久久久久尤物 | 久久久综合精品| 欧美一区二区成人6969| 亚洲午夜精品一区二区| 宅男噜噜噜66一区二区| 日韩亚洲欧美综合| 亚洲乱亚洲高清| 夜夜嗨av一区二区三区| 亚洲裸体视频| 夜夜夜久久久| 亚洲一级在线| 亚洲宅男天堂在线观看无病毒| 一本色道久久88亚洲综合88| 一区二区三区四区国产精品| 一区二区日韩| 亚洲一区亚洲| 欧美亚洲色图校园春色| 香港成人在线视频| 久久精品在这里| 久久久久中文| 欧美不卡视频一区发布| 欧美不卡激情三级在线观看| 欧美精品1区2区| 国产精品成人观看视频国产奇米| 欧美性片在线观看| 国产日本欧美一区二区| 国内成人精品视频| 尤物精品国产第一福利三区| 在线欧美不卡| 99国内精品| 午夜精品久久久久久久99水蜜桃| 欧美一区二区三区免费看| 久久精品国产亚洲高清剧情介绍| 蜜臀av国产精品久久久久| 欧美激情一区二区三区| 日韩亚洲精品在线| 亚洲欧美日韩一区二区三区在线| 欧美在线免费视屏| 麻豆91精品91久久久的内涵| 欧美日本不卡高清| 国产精品一二三四区| 狠狠久久婷婷| 日韩系列欧美系列| 午夜精品影院| 欧美国产高清| 亚洲一区二区精品| 久久亚洲电影| 国产精品都在这里| 尤物在线观看一区| 一区二区三区欧美亚洲| 久久国产天堂福利天堂| 亚洲国产裸拍裸体视频在线观看乱了中文| 亚洲美女精品久久| 欧美一区二区精美| 欧美日本免费| 激情久久五月天| 亚洲一区二区三区高清不卡| 久热这里只精品99re8久| 日韩视频国产视频| 久久精品欧洲| 国产精品久久久久久久7电影| 永久91嫩草亚洲精品人人| 亚洲一区二区免费视频| 欧美.www| 欧美在线二区| 欧美小视频在线| 亚洲欧洲免费视频| 久久精品国产精品亚洲| 亚洲精品亚洲人成人网| 玖玖玖国产精品| 国产日韩高清一区二区三区在线| 一区二区三区欧美| 欧美成人精品一区二区三区| 亚洲欧美另类在线| 欧美日韩一区二区三| 亚洲国产乱码最新视频| 久久精品观看| 在线亚洲自拍| 欧美日韩精品是欧美日韩精品| 亚洲二区精品| 久久综合网色—综合色88| 亚洲一区一卡| 欧美午夜电影在线观看| 日韩视频在线一区二区| 亚洲电影观看| 久久在线91| 亚洲电影在线观看| 久久精品夜夜夜夜久久| 亚洲资源在线观看| 国产精品九九久久久久久久| 一个色综合导航| 亚洲欧洲久久| 欧美喷潮久久久xxxxx| 亚洲黄色成人| 欧美电影免费| 久久综合久久美利坚合众国| 永久555www成人免费| 久久综合激情| 久热精品视频| 亚洲电影在线免费观看| 免播放器亚洲| 老司机凹凸av亚洲导航| 在线日本高清免费不卡| 狂野欧美激情性xxxx欧美| 久久成人一区| 在线观看欧美亚洲| 欧美二区不卡| 欧美黑人多人双交| 9l国产精品久久久久麻豆| 亚洲欧洲日韩综合二区| 欧美日本国产在线| 亚洲视频1区| 亚洲一区在线直播| 国产亚洲精品激情久久| 久久综合九色欧美综合狠狠| 玖玖玖国产精品| 一个色综合导航| 亚洲一区二区三区国产| 国产欧美精品一区aⅴ影院| 久久成人精品电影| 久久久久欧美| 99在线视频精品| 中国亚洲黄色| 一区二区三区在线免费观看| 嫩草成人www欧美| 欧美精品福利在线| 亚洲欧美三级伦理| 久久久久久伊人| 一本一道久久综合狠狠老精东影业| 日韩网站免费观看| 国产伦精品一区二区三区免费 | 国产精品美女久久久久久免费| 欧美一区二区视频在线| 久久手机免费观看| 一区二区三区国产精华| 午夜免费日韩视频| 最近看过的日韩成人|