最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C/C++實現(xiàn)動態(tài)庫動態(tài)加載

 更新時間:2024年01月05日 09:49:32   作者:py_free-物聯(lián)智能  
在很多項目中,我們多少會用到第三方動態(tài)庫,這些動態(tài)庫一般都是相對固定,使用也很簡單,下面我們就來看看c/c++中如何實現(xiàn)動態(tài)庫動態(tài)加載吧

在很多項目中,我們多少會用到第三方動態(tài)庫,這些動態(tài)庫一般都是相對固定,使用也很簡單,在工程中包含其頭文件,并將動態(tài)庫在編譯時動態(tài)鏈接進去就能調(diào)用頭文件接口實現(xiàn)調(diào)用。

但也有不少這種情況,就是我們需要自己創(chuàng)建一個個功能模塊的動態(tài)庫,然后給我們集成軟件來調(diào)用。由于項目是不斷迭代及增量開發(fā),因此對于這些動態(tài)庫的使用就會有按需加載、按時加載、按配置加載等設(shè)計,并需要滿足不斷增加功能支持。

 一、動態(tài)庫加載實現(xiàn)

在win下,其LoadLibrary、LoadLibrary、FreeLibrary等API實現(xiàn)庫加載、卸載的能力,而GetProcAddress等API提供從加載模塊中檢索指定的動態(tài)鏈接庫(DLL)中的輸出庫函數(shù)地址,依據(jù)傳入模塊句柄、函數(shù)名稱相關(guān)參數(shù)就能實現(xiàn)動態(tài)鏈接庫接口調(diào)用。

注:動態(tài)庫本身必須使用關(guān)鍵字__declspec(dllexport),暴露dll中的變量或方法,編譯dll文件的時候,在dll頭文件聲明的變量名稱前添加dllexport。表明把 dll中的相關(guān)代碼(類,函數(shù),全局變量)暴露出來為以后其他應(yīng)用程序使用;對于調(diào)用庫文件的應(yīng)用程序,__declspec(dllexport)是不必要,與_declspec(dllexport)相呼應(yīng)的_declspec(dllimport),意思是當(dāng)其他工程要使用dll 內(nèi)部代碼(類,函數(shù),全局變量)時,就在dll頭文件中聲明的變量名稱前添加dllimport關(guān)鍵字,雖然不是必須,但加入了代碼會更明確,編譯器也可以生成更好的代碼;簡要來說就是,動態(tài)庫的cpp文件中加關(guān)鍵字__declspec(dllexport),動態(tài)庫的h文件中加關(guān)鍵字_declspec(dllimport)。

在linux下,類似的,其提供了dlopen、dlclose等API實現(xiàn)庫加載、卸載的能力,同等地,dlsym等API函數(shù)提供了從動態(tài)加載鏈接庫中獲取函數(shù)地址的能力,依據(jù)傳入模塊句柄、函數(shù)名稱相關(guān)參數(shù)能實現(xiàn)動態(tài)鏈接庫接口調(diào)用。

一般來說,動態(tài)庫提供的接口服務(wù)有函數(shù)服務(wù)接口和類服務(wù)接口,對于前者,直接獲取函數(shù)地址就可以實現(xiàn)調(diào)用,而對于類服務(wù)接口,則需要先獲取類實例地址,在取得實例地址后,就相當(dāng)于通常類使用那樣,然后通過實例句柄實現(xiàn)其內(nèi)部的函數(shù)調(diào)用。

二、代碼工程設(shè)計

本文將將win、linux加載、卸載動態(tài)庫,并從動態(tài)庫鏈接模塊中獲取類實例或函數(shù)地址等封裝成統(tǒng)一的API接口,并集成在dllLoad.h/dllLoad.cpp中實現(xiàn)。構(gòu)建一個注冊類RegisterM,內(nèi)置一個map容器,用來裝載加載的動態(tài)庫模塊,并統(tǒng)一提供模塊索引、及從模塊中實現(xiàn)類實例獲取、刪除、函數(shù)地址獲取等功能。

在動態(tài)庫實現(xiàn)方面,提供一個虛擬元類MetaObject,然后在庫的cpp文件中建立子類繼承該類,實現(xiàn)其具體功能,并在cpp文件中直接提供函數(shù)API,這些API函數(shù)不在頭文件中聲明,需要extern關(guān)鍵字修飾。

dll_test
    bin            #程序輸出目錄及庫文件輸出父目錄
        Debug        #win debug 庫文件輸出目錄,編譯時自動創(chuàng)建
        linux        #Linux庫文件輸出目錄,編譯時自動創(chuàng)建
        Release      #win Release庫文件輸出目錄,編譯時自動創(chuàng)建
    build_linux
        lib          #Linux庫文件編譯過程文件存儲目錄,編譯時自動創(chuàng)建
    build_win
        lib          #win庫文件編譯過程文件存儲目錄,編譯時自動創(chuàng)建
    lib
        CMakeLists.txt    #win庫文件cmake工程
        metaObject.h    #win庫文件,調(diào)用庫文件的應(yīng)用程序需要該頭文件
        testlib.cpp     #庫文件功能實現(xiàn)
    src
        dllload.h    #動態(tài)庫加載、卸載、獲取實例或函數(shù)地址的API集合
        dllload.cpp
        register.h    #動態(tài)庫注冊、管理、注銷及庫的類實例或函數(shù)調(diào)用實現(xiàn)
        register.cpp
        test.cpp     #應(yīng)用程序,庫文件使用測試代碼
    CMakeLists.txt

metaObject.h

#ifndef METAOBJECT_H
#define METAOBJECT_H
 
class MetaObject
{
public:
    MetaObject(){};
    virtual ~MetaObject(){};
 
    virtual int add(int a, int b) const = 0;
    virtual void setVal(int _val) =0;
    virtual int getVal() const = 0;
};
 
//
typedef MetaObject* create_t();
typedef void destroy_t(MetaObject*);
//typedef _declspec(dllimport) void destroy_t(MetaObject*); //window
 
#endif

testlib.cpp

#include "metaObject.h"
 
#include <iostream>
#include <string>
 
#ifdef WIN32
#ifdef __cplusplus
#define EXPORT_DLL extern "C" __declspec(dllexport)
#else
#define EXPORT_DLL __declspec(dllexport)
#endif
#else
#define EXPORT_DLL extern "C"
#endif
 
class MetaObject_child : public MetaObject {
public:
    virtual int add(int a, int b) const
    {
        return a+b;
    };
    virtual void setVal(int _val){
        val = _val;
    };
    virtual int getVal() const{
        return val;
    };
private:
    int val;
};
 
// the class factories
EXPORT_DLL MetaObject* create() {
    return new MetaObject_child();
}
 
EXPORT_DLL void destroy(MetaObject* p) {
    delete p;
}
 
//the funs factories
EXPORT_DLL void testfunc01(int a)
{
    std::cout << "a="<<a<<std::endl;
}
 
EXPORT_DLL int testfunc02(int b)
{
    return b*b;
}

CMakeLists.txt,用于生成庫文件,作為subdir,被應(yīng)用程序CMakeLists.txt調(diào)用

#lib項目信息
project (testlib)
#
SET(source_h
    ${PROJECT_SOURCE_DIR}/metaObject.h
  )
  
SET(source_cpp
    ${PROJECT_SOURCE_DIR}/testlib.cpp
    )
  
#頭文件目錄
include_directories(${PROJECT_SOURCE_DIR})
#
 
if (${WIN_OS})
#將庫文件輸出到Debug或Release目錄下,文件目錄編譯時自動創(chuàng)建
set(LIBRARY_OUTPUT_PATH  ${PROJECT_SOURCE_DIR}/../bin)
 
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_library(testlibd SHARED ${source_h} ${source_cpp})
 
else(CMAKE_BUILD_TYPE)
add_library(testlib SHARED ${source_h} ${source_cpp})
endif (CMAKE_BUILD_TYPE)
 
else(${WIN_OS})
 
set(LIBRARY_OUTPUT_PATH  ${PROJECT_SOURCE_DIR}/../bin/linux)
# 指定生成目標(biāo)
add_library(testlib SHARED ${source_h} ${source_cpp})
 
endif(${WIN_OS})

dlload.h

#ifndef DLLOAD_H
#define DLLOAD_H
 
#if defined(WIN32)
#include <windows.h>
typedef HMODULE  MODULE_HANDLE;
#endif
 
#if defined(__linux__)
typedef void *  MODULE_HANDLE;
#endif
 
MODULE_HANDLE gdl_Open(const char *plname);
void gdl_Close(MODULE_HANDLE h);
void *gdl_GetProc(MODULE_HANDLE h, const char *pfname);
char* gdl_GetLastError();
 
#endif

dlload.cpp

#include "dlload.h"
 
#if defined(WIN32)
#include <windows.h>
#endif
 
#if defined(__linux__)
#include <dlfcn.h>
#endif
 
MODULE_HANDLE gdl_Open(const char *plname)
{
#if defined(WIN32)
    return LoadLibraryA (plname);
#endif
 
#if defined(__linux__)
   return dlopen( plname, RTLD_NOW|RTLD_GLOBAL);
#endif
};
 
void gdl_Close(MODULE_HANDLE h)
{
    if(h)
    {
#if defined(WIN32)
        FreeLibrary(h);
#endif
#if defined(__linux__)
        dlclose (h);
#endif
    }
};
 
void *gdl_GetProc(MODULE_HANDLE h, const char *pfname)
{
   if(h)
   {
#if defined(WIN32)
        return (void *)GetProcAddress(h, pfname);
#endif
 
#if defined(__linux__)
        return dlsym(h,pfname);
#endif
    }
    return 0;
};
 
char* gdl_GetLastError()
{
#if defined(WIN32)
    return (char*)::GetLastError();
#endif
 
#if defined(__linux__)
    return dlerror();
#endif
}

register.h

#ifndef REGISTER_H
#define REGISTER_H
 
#include <map>
 
#include "dlload.h"
#include "metaObject.h"
 
class RegisterM
{
public:
    enum MethodType { Method, Constructor };//函數(shù)類型
    enum Access { Private, Protected, Public };//訪問方式
    enum CallType {Asynchronous,Synchronous};//函數(shù)調(diào)用方式
    enum SetType {SetVal,getVal};//屬性值設(shè)置
public:
    RegisterM(){};
    ~RegisterM(){};
    //注冊類庫
    int registerObject(const char* objectName, const char* conf);
    //注銷類庫
    bool unregisterObject(const char* objectName);
    //創(chuàng)建實例類
    create_t* getInstance(const char* objectName);
    //析構(gòu)實例類
    destroy_t* rmInstance(const char* objectName);
    //函數(shù)調(diào)用
    void* getFunc(const char* objectName,char* funcName);
private:
    MODULE_HANDLE index ( const char * Name );
private:
    std::map<char *, MODULE_HANDLE> libmap;
};
 
#endif

register.cpp

#include "register.h"
 
#include <stdio.h>
#include <iostream>
 
int RegisterM::registerObject(const char* objectName, const char* conf)
{
    MODULE_HANDLE load_handle= gdl_Open(conf);
    if (!load_handle) {
        std::cerr << "Cannot load library: " << conf 
            << " Error:" << gdl_GetLastError() << '\n';
        return -1;
    }
    libmap[const_cast<char*>(objectName)]=load_handle;
    return 1;
}
 
bool RegisterM::unregisterObject(const char* objectName)
{
    std::map<char *, MODULE_HANDLE>::iterator it=libmap.find(const_cast<char*>(objectName));
    if (it!=libmap.end())
    {
        gdl_Close(it->second);
        libmap.erase(it);
        return true;
    }
    return false;
}
 
create_t* RegisterM::getInstance(const char* objectName)
{
    MODULE_HANDLE _handle = index(objectName);
    if (NULL!=_handle)
    {
        create_t* create_instance = (create_t*) gdl_GetProc(_handle, "create");
        const char* dlsym_error = gdl_GetLastError();
        if (dlsym_error) {
            std::cerr << "Cannot load symbol create error: " << dlsym_error << '\n';
            return NULL;
        }else{
            return create_instance;
        }
    }
    return NULL;
}
 
destroy_t* RegisterM::rmInstance(const char* objectName)
{
    MODULE_HANDLE _handle = index(objectName);
    if (NULL!=_handle)
    {
        destroy_t* destroy_instance = (destroy_t*) gdl_GetProc(_handle, "destroy");
        const char* dlsym_error = gdl_GetLastError();
        if (dlsym_error) {
            std::cerr << "Cannot load symbol create: " << dlsym_error << '\n';
            return NULL;
        }else{
            return destroy_instance;
        }
    }
    return NULL;
}
 
void* RegisterM::getFunc(const char* objectName,char* funcName)
{
    MODULE_HANDLE _handle = index(objectName);
    if (NULL!=_handle)
    {
        void* ret = gdl_GetProc(_handle,funcName);
        const char* dlsym_error = gdl_GetLastError();
        if (dlsym_error) {
            std::cerr << "Cannot load symbol create: " << dlsym_error << '\n';
            return NULL;
        }else{
            return ret;
        }
    }
    return NULL;
}
 
MODULE_HANDLE RegisterM::index ( const char * Name )
{
    std::map<char *, MODULE_HANDLE>::iterator it=libmap.find(const_cast<char*>(Name));
    if (it!=libmap.end())
    {
        return it->second;
    }else{
        std::cerr << "Cannot find library: " << Name << '\n';    
    }
    return NULL;
}

test.cpp

#include "register.h"
 
#include <stdint.h>
#include <iostream>
#include <string>
 
int main(int argc, char **argv) {
 
    RegisterM *rm = new RegisterM();
    char libname[128] = "test";
    #ifdef WIN32
    #ifdef _DEBUG
    char libpath[128] = ".\\Debug\\testlibd.dll";
    #else
    char libpath[128] = ".\\Release\\testlib.dll";
    #endif
    #endif
    #ifdef __linux__
    char libpath[128] = "./linux/libtestlib.so";
    #endif
    int ret = rm->registerObject(libname,libpath);
    if (ret>0)
    {
        std::cout<<"registerObject success"<<std::endl;
        create_t* create_instance = rm->getInstance(libname);
        if (NULL!=create_instance)
        {
            std::cout<<"getInstance success"<<std::endl;
            MetaObject* _instance = create_instance();
            int _sum = _instance->add(7,8);
            std::cout<<"sum="<<_sum<<std::endl;
            _instance->setVal(15);
            std::cout<<"_instance->val="<<_instance->getVal()<<std::endl;
 
            void (*pa)(int a);
            *(void**)(&pa) = rm->getFunc((char*)libname,(char*)"testfunc01");
            pa(6);
            int (*fa)(int a);
            *(void**)(&fa) = rm->getFunc((char*)libname,(char*)"testfunc02");
            std::cout<<"fa(5)="<<fa(5)<<std::endl;
 
            destroy_t* destroy_instance = rm->rmInstance(libname);
            if (NULL!=destroy_instance)
            {
                std::cout<<"rmInstance success"<<std::endl;
                destroy_instance(_instance);
            }
        }else{
            std::cout<<"getInstance failed"<<std::endl;
        }
        bool re = rm->unregisterObject(libname);
        if (re)
        {
            std::cout<<"unregisterObject success"<<std::endl;
        }
    }
    return 0;
};

CMakeLists.txt

# CMake 最低版本號要求
cmake_minimum_required (VERSION 2.8)
# 項目信息
project (dll_test)
#
if(WIN32)
    message(STATUS "windows compiling...")
    add_definitions(-D_PLATFORM_IS_WINDOWS_)
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
    set(WIN_OS true)
else(WIN32)
    message(STATUS "linux compiling...")
    add_definitions( -D_PLATFORM_IS_LINUX_)
    add_definitions("-Wno-invalid-source-encoding")
      # add_definitions("-O2")
    set(UNIX_OS true)
    set(_DEBUG true)
    
endif(WIN32)
 
#
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
 
# 指定源文件的目錄,并將名稱保存到變量
SET(source_h_lib
    ${PROJECT_SOURCE_DIR}/lib/metaObject.h
  )
  
SET(source_h_src
    ${PROJECT_SOURCE_DIR}/src/dlload.h
    ${PROJECT_SOURCE_DIR}/src/register.h
  )
  
SET(source_cpp_src
    ${PROJECT_SOURCE_DIR}/src/dlload.cpp
    ${PROJECT_SOURCE_DIR}/src/register.cpp
    ${PROJECT_SOURCE_DIR}/src/test.cpp
  )
  
#頭文件目錄
include_directories(
    ${PROJECT_SOURCE_DIR}/lib
    ${PROJECT_SOURCE_DIR}/src
    )
    
add_subdirectory(${PROJECT_SOURCE_DIR}/lib ./lib)
 
if (${UNIX_OS})
 
add_definitions(
  "-W"
  "-fPIC"
  "-Wall"
  # "-Wall -g"
  "-Werror"
  "-Wshadow"
  "-Wformat"
  "-Wpointer-arith"
  "-D_REENTRANT"
  "-D_USE_FAST_MACRO"
  "-Wno-long-long"
  "-Wuninitialized"
  "-D_POSIX_PTHREAD_SEMANTICS"
  "-DACL_PREPARE_COMPILE"
  "-Wno-unused-parameter"
  "-fexceptions"
  )
  
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
 
link_directories(
    "${EXECUTABLE_OUTPUT_PATH}"/linux
)
 
# 指定生成目標(biāo)
add_executable(dll_test ${source_h_lib} ${source_h_src} ${source_cpp_src})
#link
target_link_libraries(dll_test testlib -ldl)
 
endif(${UNIX_OS})
 
if (${WIN_OS})
 
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4819")
 
add_definitions(
  "-D_CRT_SECURE_NO_WARNINGS"
  "-D_WINSOCK_DEPRECATED_NO_WARNINGS"
  "-DNO_WARN_MBCS_MFC_DEPRECATION"
  "-DWIN32_LEAN_AND_MEAN"
)
 
#link_directories()
  
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
 
# 指定生成目標(biāo)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/bin)
# 指定生成目標(biāo)
add_executable(dll_testd ${source_h_lib} ${source_h_src} ${source_cpp_src})
 
link_directories(
    "${EXECUTABLE_OUTPUT_PATH}"/Debug
)
 
else(CMAKE_BUILD_TYPE)
 
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/bin)
# 指定生成目標(biāo)
add_executable(dll_test ${source_h_lib} ${source_h_src} ${source_cpp_src})
 
link_directories(
    "${EXECUTABLE_OUTPUT_PATH}"/Release
)
 
endif (CMAKE_BUILD_TYPE)
 
endif(${WIN_OS})

三、編譯及測試

win編譯時采用cmake+vs編譯,具體編譯版本可以依據(jù)自身電腦安裝版本決定

cd dll_test && mkdir build_win && cd build_win
cmake -G "Visual Studio 10 2010 Win64" -DCMAKE_BUILD_TYPE=Release ..
msbuild dll_test.sln /p:Configuration="Release" /p:Platform="x64"

運行效果:

D:\workForMy\workspace\dll_test\bin>dll_testd.exe
registerObject success
getInstance success
sum=15
_instance->val=15
a=6
fa(5)=25
rmInstance success
unregisterObject success
 
D:\workForMy\workspace\dll_test\bin>

Linux下

        cd dll_test
        mkdir build_linux
        cd build_linux
        cmake ..
        make

運行效果:

[py@pyfree bin]$ ./dll_test 
registerObject success
getInstance success
sum=15
_instance->val=15
a=6
fa(5)=25
rmInstance success
unregisterObject success
[py@pyfree bin]$ 

以上就是C/C++實現(xiàn)動態(tài)庫動態(tài)加載的詳細(xì)內(nèi)容,更多關(guān)于C++動態(tài)庫的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解C++ STL vector容量(capacity)和大小(size)的區(qū)別

    詳解C++ STL vector容量(capacity)和大小(size)的區(qū)別

    這篇文章主要介紹了詳解C++ STL vector容量(capacity)和大小(size)的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • Qt QML使用虛擬鍵盤的示例代碼

    Qt QML使用虛擬鍵盤的示例代碼

    這篇文章主要為大家詳細(xì)介紹了Qt QML使用虛擬鍵盤的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • Java C++題解leetcode915分割數(shù)組示例

    Java C++題解leetcode915分割數(shù)組示例

    這篇文章主要為大家介紹了Java C++題解leetcode915分割數(shù)組示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • 為什么獲取環(huán)境變量getenv小心有坑

    為什么獲取環(huán)境變量getenv小心有坑

    這篇文章主要介紹了獲取環(huán)境變量getenv小心有坑問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • C++實現(xiàn)簡單校園導(dǎo)游系統(tǒng)

    C++實現(xiàn)簡單校園導(dǎo)游系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++實現(xiàn)簡單校園導(dǎo)游系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Qt6安裝教程(使用國內(nèi)源)

    Qt6安裝教程(使用國內(nèi)源)

    本文主要介紹了Qt6安裝教程(使用國內(nèi)源),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • 一篇文章帶你了解C語言內(nèi)存對齊

    一篇文章帶你了解C語言內(nèi)存對齊

    在單片機下使用C語言編程時,內(nèi)存對齊的知識點必須掌握。掌握內(nèi)存對齊后,可以防止內(nèi)存碎片化,并且證明你有能力優(yōu)化內(nèi)存。嵌入式單片機開發(fā)的后階段,無非就是優(yōu)化內(nèi)存與優(yōu)化代碼執(zhí)行效率。
    2021-08-08
  • VS未找到框架“.NETFramework,Version=v4.6.1”引用程序集的解決辦法

    VS未找到框架“.NETFramework,Version=v4.6.1”引用程序集的解決辦法

    本文主要介紹了VS未找到框架“.NETFramework,Version=v4.6.1”引用程序集的解決辦法,具有一定的參考價值,感興趣的可以了解一下
    2023-10-10
  • OpenCV實現(xiàn)簡單套索工具

    OpenCV實現(xiàn)簡單套索工具

    這篇文章主要為大家詳細(xì)介紹了OpenCV實現(xiàn)簡單套索工具,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++設(shè)計模式之組合模式(Composite)

    C++設(shè)計模式之組合模式(Composite)

    這篇文章主要為大家詳細(xì)介紹了C++設(shè)計模式之組合模式Composite,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-04-04

最新評論

康平县| 阜新| 凤山市| 宁远县| 桃源县| 贵阳市| 晴隆县| 远安县| 德安县| 东光县| 花莲县| 渝北区| 靖宇县| 乐都县| 威海市| 尼勒克县| 屯门区| 天镇县| 留坝县| 弥渡县| 汉源县| 饶平县| 青田县| 新疆| 道真| 栾川县| 黄浦区| 开江县| 霍邱县| 桐梓县| 自贡市| 洱源县| 米易县| 浦城县| 蒲江县| 杭州市| 普兰县| 新田县| 永年县| 香港| 台中县|