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

C++ Programmer's Cookbook

{C++ 基礎(chǔ)} {C++ 高級(jí)} {C#界面,C++核心算法} {設(shè)計(jì)模式} {C#基礎(chǔ)}

C++ COM

 

前言:為了介紹C#寫界面,C++寫算法的快捷交互開發(fā)方式,首先介紹c++,C#內(nèi)部的DLL,COM調(diào)用。

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

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

1)使用ATL Wizard創(chuàng)建COM非常的簡(jiǎn)單,可以參考下面2個(gè)鏈接,分別使用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,當(dāng)然更沒有Wizard,只有手動(dòng)的一步一步的實(shí)現(xiàn),不過這也是學(xué)習(xí)COM最好的方法和必經(jīng)之路。可以參考:
     http://www.codeproject.com/com/LocalCOMServerClient.asp
    具體的步驟如下:
    1)建立一個(gè)Win32的DLL。例如CarLocalServer。
    2)首先加入IDL接口描述文件CarLocalServerTypeInfo.idl,編譯后會(huì)生成4個(gè)文件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實(shí)現(xiàn)文件:

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

CManageSycle::~CManageSycle(void)
{
}


    4)加入真正的com的接口的實(shí)現(xiàn)類,MyCar.h (除了實(shí)現(xiàn)COM的接口,還必須實(shí)現(xiàn)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,(實(shí)現(xiàn)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)實(shí)現(xiàn)COM入口和自注冊(cè)函數(shù)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的調(diào)用過程
通過一個(gè)創(chuàng)建COM組件的最小框架結(jié)構(gòu),然后看一看其內(nèi)部處理流程是怎樣的

    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();

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

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

這段話的意思就是先得到類廠對(duì)象,再通過類廠創(chuàng)建組件從而得到IUnknown指針。繼續(xù)深入一步,看看CoGetClassObject的內(nèi)部偽碼:

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


四,COM的調(diào)用方法
對(duì)上面手動(dòng)創(chuàng)建的COM的調(diào)用實(shí)例:

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;
}


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

方法二:使用#import導(dǎo)入tlb

可以使用: CComBSTR ,CComPtr<> 和 CComQIPtr<> 等來簡(jiǎn)化調(diào)用。

五,總結(jié)
COM比一般的DLL有很多的優(yōu)點(diǎn),COM沒有重名問題,因?yàn)楦静皇峭ㄟ^函數(shù)名來調(diào)用函數(shù),而是通過虛函數(shù)表,自然也不會(huì)有函數(shù)名修飾的問題。路徑問題也不復(fù)存在,因?yàn)槭峭ㄟ^查注冊(cè)表來找組件的,放在什么地方都可以,即使在別的機(jī)器上也可以。也不用考慮和EXE的依賴關(guān)系了,它們二者之間是松散的結(jié)合在一起,可以輕松的換上組件的一個(gè)新版本,而應(yīng)用程序混然不覺。

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

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

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

評(píng)論

# re: C++ COM 2007-05-28 21:39 夢(mèng)在天涯

以上的手動(dòng)創(chuàng)建COM實(shí)例,還有一定的問題,有那位高手愿意指點(diǎn),使我改正,共同進(jìn)步,還有COM的其他的調(diào)用方法,還有文章中的其他的問題,請(qǐng)幫忙指出,我將非常的感謝!

勇于共享!  回復(fù)  更多評(píng)論   

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

其實(shí)代碼邏輯可以用C++抽象機(jī)制+設(shè)計(jì)模式去實(shí)現(xiàn),而com的重點(diǎn)在夸語言平臺(tái),把它作為一種interop手段是再好不過。在開發(fā)后期如果設(shè)計(jì)得當(dāng),用com做一層wrapper是很容易的事情。  回復(fù)  更多評(píng)論   

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

其實(shí)增加一層wrapper也是一件很ugly的事,如果效率是可以接受的,建議直接在對(duì)象模型上去實(shí)現(xiàn)。在wrapper同樣會(huì)把效率降的更低。  回復(fù)  更多評(píng)論   

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

學(xué)習(xí)中  回復(fù)  更多評(píng)論   

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

MARK  回復(fù)  更多評(píng)論   

公告

EMail:itech001#126.com

導(dǎo)航

統(tǒng)計(jì)

  • 隨筆 - 461
  • 文章 - 4
  • 評(píng)論 - 746
  • 引用 - 0

常用鏈接

隨筆分類

隨筆檔案

收藏夾

Blogs

c#(csharp)

C++(cpp)

Enlish

Forums(bbs)

My self

Often go

Useful Webs

Xml/Uml/html

搜索

  •  

積分與排名

  • 積分 - 1811979
  • 排名 - 5

最新評(píng)論

閱讀排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
              一区二区免费在线播放| 久久久久久亚洲精品不卡4k岛国| 在线播放日韩| 国产精品萝li| 欧美另类久久久品| 久久av资源网站| 亚洲精品视频一区二区三区| 一区二区三区中文在线观看| 国产亚洲欧美一区| 国产专区一区| 国产伊人精品| 久久久噜噜噜久久| 欧美在线观看网站| 麻豆av福利av久久av| 国产在线观看精品一区二区三区| 久久精品天堂| 欧美亚洲一区三区| 久久精品道一区二区三区| 久久久久国色av免费观看性色| 女主播福利一区| 欧美影视一区| 一区二区三区 在线观看视| 在线视频欧美一区| 久久这里只有| 嫩草伊人久久精品少妇av杨幂| 亚洲欧美日韩中文播放| 国产精品欧美精品| 亚洲激情在线视频| 亚洲经典三级| 久久久久久久久久久久久女国产乱| 黑人巨大精品欧美黑白配亚洲| 欧美成人免费在线观看| 女人天堂亚洲aⅴ在线观看| 亚洲婷婷在线| 久久精品国产2020观看福利| 欧美成人午夜影院| 正在播放亚洲| 亚洲国产欧美久久| 亚洲国产毛片完整版 | 欧美激情亚洲另类| 欧美超级免费视 在线| 亚洲人成人99网站| 久久综合影视| 一区二区在线观看视频在线观看| 欧美日韩国产精品成人| 欧美视频中文字幕在线| 欧美高清视频在线| 国产精品二区三区四区| 欧美日韩成人综合| 欧美日韩一区二区在线播放| 欧美日韩精品在线| 国产精品久久久一区麻豆最新章节| 国产日韩欧美在线播放| 日韩小视频在线观看专区| 在线欧美小视频| 国产欧美日韩一区二区三区在线| 亚洲视频一区二区在线观看 | 国产三级精品在线不卡| 国产欧美一区二区三区久久人妖 | 亚洲一区二区欧美| 欧美国产一区二区在线观看 | 一区二区精品| 亚洲区一区二| 久久久久久婷| 老色批av在线精品| 亚洲午夜av在线| 欧美在线二区| 国产日本欧美一区二区三区在线| 亚洲视频综合| 这里是久久伊人| 亚洲美女中文字幕| 99这里只有精品| 男女av一区三区二区色多| 午夜在线视频观看日韩17c| 欧美日韩三级| 一区二区欧美在线| 亚洲区一区二| 欧美国产视频在线观看| 亚洲日本免费| 欧美在线观看视频| 欧美国产日韩亚洲一区| 一区二区三区欧美激情| 国产精品日产欧美久久久久| 亚洲欧美国产一区二区三区| 这里是久久伊人| 亚洲免费在线播放| 欧美午夜不卡视频| 狠狠色噜噜狠狠色综合久| 欧美成人性网| 久久在线免费观看视频| 欧美另类一区二区三区| 亚洲日本va在线观看| 欧美成人乱码一区二区三区| 老司机精品导航| 国产欧美精品在线播放| 亚洲电影免费在线| 欧美二区在线看| 亚洲精品中文字幕有码专区| 亚洲日本va午夜在线电影| 国产精品专区h在线观看| 亚洲精品国产无天堂网2021| 亚洲综合日韩在线| 亚洲影院免费观看| 欧美制服丝袜| 欧美视频中文在线看| 久久精品国产999大香线蕉| 欧美视频四区| 香蕉免费一区二区三区在线观看| 男女精品网站| 免费成人av在线看| 久久久久国产精品麻豆ai换脸| 免费一区二区三区| 日韩视频免费在线观看| 巨乳诱惑日韩免费av| 亚洲综合视频一区| 免费黄网站欧美| 亚洲国产专区校园欧美| 久久婷婷丁香| 另类激情亚洲| 在线成人激情视频| 99re视频这里只有精品| 国产精品永久免费在线| 一本色道久久综合亚洲精品婷婷 | 午夜精品久久久久久久男人的天堂 | 久久蜜桃精品| 免费人成网站在线观看欧美高清| 亚洲第一黄色网| 欧美精品成人| 免费欧美电影| 国产精品一区二区在线| 欧美国产欧美亚洲国产日韩mv天天看完整 | 欧美在线一二三四区| 日韩特黄影片| 亚洲精品免费看| 欧美一区91| 国产精品国产精品| 欧美一区二区三区男人的天堂| 欧美国产日本| 久久成年人视频| 国产精品一区免费观看| 久久综合图片| 欧美亚洲一区二区在线观看| 亚洲人成小说网站色在线| 亚洲黄色有码视频| 国产伦理一区| 欧美一区二区三区在| 亚洲人成毛片在线播放女女| 日韩视频专区| 黑人巨大精品欧美一区二区小视频| 欧美亚洲自偷自偷| 亚洲毛片在线观看| 亚洲视频在线观看免费| 一区在线影院| 国产伪娘ts一区| 国产精品一区二区欧美| 欧美人成在线| 午夜精品在线| 亚洲国产专区校园欧美| 极品少妇一区二区三区| 欧美成在线视频| 亚洲一区二区免费视频| 欧美大片一区二区| 91久久久亚洲精品| 久久精品国产99| 午夜精品久久久久久久| 国产一区二区成人| 欧美亚洲第一区| 亚洲制服丝袜在线| 一区二区三区产品免费精品久久75 | 在线综合亚洲| 99国产精品一区| 午夜国产精品视频| 国产日韩欧美电影在线观看| 99精品久久久| 欧美精选在线| av成人免费在线| 日韩一区二区免费看| 在线免费观看日本欧美| 欧美成人69| 免费人成精品欧美精品| 日韩一区二区福利| 久久国产手机看片| 欧美永久精品| 久久久久高清| 麻豆国产精品一区二区三区| 蜜月aⅴ免费一区二区三区| 免费日韩精品中文字幕视频在线| 欧美jjzz| 国产精品三上| 国产精品久久久久毛片软件| 悠悠资源网亚洲青| 午夜精品视频在线观看一区二区 | 亚洲激情影视| 欧美日韩在线三级| 欧美日韩一级黄| 国产伦精品一区二区三区照片91| 国产一区二区剧情av在线| 好吊色欧美一区二区三区视频| 亚洲第一精品电影| 国产日产欧产精品推荐色|