MFC六大技術之消息映射和命令傳遞

來自:http://blog.csdn.net/liyi268/article/details/623391

作為C++程序員,我們總是希望自己程序的所有代碼都是自己寫出來的,如果使用了其他的一些庫洞渤,也總是千方百計想弄清楚其中的類和函數(shù)的原理藐握,否則就會感覺不踏實。所以,我們對于在進行MFC視窗程序設計時經(jīng)常要用到的消息機制也不滿足于會使用驯用,而是希望能理解個中道理液兽。本文就為大家剖析MFC消息映射和命令傳遞的原理骂删。

理解MFC消息機制的必要性

說到消息,在MFC中四啰,“最熟悉的神秘”可以說是消息映射了宁玫,那是我們剛開始接觸MFC時就要面對的東西。有過SDK編程經(jīng)驗的朋友轉到MFC編程的時候柑晒,一下子覺得什么都變了樣欧瘪。特別是窗口消息及對消息的處理跟以前相比,更是風馬牛不相及的匙赞。如文檔不是窗口垂寥,是怎樣響應命令消息的呢严望?

初次用MFC編程,我們只會用MFC ClassWizard為我們做大量的東西,最主要的是添加消息響應疚宇。記憶中搞疗,如果是自已添加消息響應箍镜,我們應何等的小心翼翼贤姆,對BEGIN_MESSAGE_MAP()……END_MESSAGE_MAP()更要奉若神靈。它就是一個魔盒子猛拴,把我們的咒語放入恰當?shù)牡胤礁Γ蜁l(fā)生神奇的力量,放錯了愉昆,自己的程序就連“命”都沒有职员。

據(jù)說,知道得太多未必是好事跛溉。我也曾經(jīng)打算不去理解這神秘的區(qū)域焊切,覺得編程的時候知道自己想做什么就行了扮授。MFC外表上給我們提供了東西,直觀地說专肪,不但給了我個一個程序的外殼刹勃,更給我們許多方便。微軟的出發(fā)點可能是希望達到“傻瓜編程”的結果嚎尤,試想荔仁,誰不會用ClassWizard?大家知道芽死,Windows是基于消息的乏梁,有了ClassWizard,你又會添加類关贵,又會添加消息遇骑,那么你所學的東西似乎學到頭了。于是許多程序員認為“我們沒有必要走SDK的老路揖曾,直接用MFC編程落萎,新的東西通常是簡單、直觀翩肌、易學……”模暗。

到你真正想用MFC編程的時候,你會發(fā)覺光會ClassWizard的你是多么的愚蠢念祭。MFC不是一個普通的類庫,普通的類庫我們完全可以不理解里面的細節(jié)碍侦,只要知道這些類庫能干什么粱坤,接口參數(shù)如何就萬事大吉。如string類瓷产,操作順序是定義一個string對象站玄,然后修改屬性,調用方法濒旦。但對于MFC株旷,并不是在你的程序中寫上一句“#include <MFC.h>”,然后就使用MFC類庫的尔邓。

MFC是一塊包著糖衣的牛骨頭晾剖。你很輕松地寫出一個單文檔窗口,在窗口中間打印一句“I love MFC!”梯嗽,然后齿尽,惡夢開始了……想逃避,打算永遠不去理解MFC內幕灯节?門都沒有循头!在MFC這個黑暗神秘的洞中绵估,即使你打算摸著石頭前行,也注定找不到出口卡骂。對著MFC這塊牛骨頭国裳,微軟溫和、民主地告訴你“你當然可以選擇不啃掉它全跨,咳咳……但你必然會因此而餓死躏救!”

MFC消息機制與SDK的不同

消息映射與命令傳遞體現(xiàn)了MFC與SDK的不同。在SDK編程中螟蒸,沒有消息映射的概念盒使,它有明確的回調函數(shù),通過一個switch語句去判斷收到了何種消息七嫌,然后對這個消息進行處理少办。所以,在SDK編程中诵原,會發(fā)送消息和在回調函數(shù)中處理消息就差不多可以寫SDK程序了英妓。

在MFC中,看上去發(fā)送消息和處理消息比SDK更簡單绍赛、直接蔓纠,但可惜不直觀。舉個簡單的例子吗蚌,如果我們想自定義一個消息腿倚,SDK是非常簡單直觀的,用一條語句:SendMessage(hwnd,message/一個大于或等于WM_USER的數(shù)字/,wparam,lparam)蚯妇,之后就可以在回調函數(shù)中處理了敷燎。但MFC就不同了,因為你通常不直接去改寫窗口的回調函數(shù)箩言,所以只能亦步亦趨對照原來的MFC代碼硬贯,把消息放到恰當?shù)牡胤健_@確實是一樣很痛苦的勞動陨收。

要了解MFC消息映射原理并不是一件輕松的事情饭豹。我們可以逆向思維,想象一下消息映射為我們做了什么工作务漩。MFC在自動化給我們提供了很大的方便拄衰,比如,所有的MFC窗口都使用同一窗口過程菲饼,即所有的MFC窗口都有一個默認的窗口過程肾砂。不像在SDK編程中,要為每個窗口類寫一個窗口過程宏悦。

消息隊列

對于每個用MFC開發(fā)的GUI程序镐确,他們都有一個CMy***App,該類繼承自CWinApp包吝,而CWinApp繼承自CWinThread, CWinApp是一個GUI線程,系統(tǒng)會為其維護一個THREADINFO結構源葫,

消息隊列包含在一個叫THREADINFO的結構中诗越,有四個隊列:

`Sent Message Queue     發(fā)送消息隊列 該隊列保存其他程序通過SendMessage給該線程發(fā)送的消息`

`Posted Message Queue   登記消息隊列 該隊列保存其他隊列通過PostMessage給該線程發(fā)送的消息 `

`Visualized Input Queue 輸入消息隊列 保存系統(tǒng)隊列分發(fā)過來的消息,比如鼠標或者鍵盤的消息`

`Reply Message Queue    應答消息隊列 保存向窗體發(fā)送消息后的結果息堂,
                      比如sendMessage操作結束后嚷狞,接收消息方會發(fā)送一個Reply消息
                      給發(fā)送方的Reply隊列中,以喚醒發(fā)送隊列荣堰。`

MFC消息映射原理

對于消息映射床未,最直截了當?shù)夭孪胧牵合⒂成渚褪怯靡粋€數(shù)據(jù)結構把“消息”與“響應消息函數(shù)名”串聯(lián)起來。這樣振坚,當窗口感知消息發(fā)生時薇搁,就對結構查找,找到相應的消息響應函數(shù)執(zhí)行渡八。其實這個想法也不能簡單地實現(xiàn):我們每個不同的MFC窗口類啃洋,對同一種消息,有不同的響應方式屎鳍。即是說宏娄,對同一種消息,不同的MFC窗口會有不同的消息響應函數(shù)逮壁。

這時孵坚,大家又想了一個可行的方法。我們設計窗口基類(CWnd)時貌踏,我們讓它對每種不同的消息都來一個消息響應十饥,并把這個消息響應函數(shù)定義為虛函數(shù)。這樣祖乳,從CWnd派生的窗口類對所有消息都有了一個空響應,我們要響應一個特定的消息就重載這個消息響應函數(shù)就可以了秉氧。但這樣做的結果眷昆,一個幾乎什么也不做的CWnd類要有幾百個“多余”的函數(shù),哪怕這些消息響應函數(shù)都為純虛函數(shù)汁咏,每個CWnd對象也要背負著一個巨大的虛擬表亚斋,這也是得不償失的。

許多朋友在學習消息映射時苦無突破攘滩,其原因是一開始就認為MFC的消息映射的目的是為了替代SDK窗口過程的編寫——這本來沒有理解錯帅刊。但他們還有多一層的理解,認為既然是替代“舊”的東西漂问,那么MFC消息映身應該是更高層次的抽象赖瞒、更簡單女揭、更容易認識。但結果是栏饮,如果我們不通過ClassWizard工具吧兔,手動添加消息是相當迷茫的一件事。

所以袍嬉,我們在學習MFC消息映射時境蔼,首先要弄清楚:消息映射的目的,不是為是更加快捷地向窗口過程添加代碼伺通,而是一種機制的改變箍土。如果不想改變窗口過程函數(shù),那么應該在哪里進行消息響應呢罐监?許多朋友一知半解地認為:我們可以用HOOK技術吴藻,搶在消息隊列前把消息抓取,把消息響應提到窗口過程的外面笑诅。再者调缨,不同的窗口,會有不同的感興趣的消息吆你,所以每個MFC窗口都應該有一個表把感興趣的消息和相應消息響應函數(shù)連系起來弦叶。然后得出——消息映射機制執(zhí)行步驟是:當消息發(fā)生,我們用HOOK技術把本來要發(fā)送到窗口過程的消息抓獲妇多,然后對照一下MFC窗口的消息映射表伤哺,如果是表里面有的消息,就執(zhí)行其對應的函數(shù)者祖。

當然立莉,用HOOK技術,我們理論上可以在不改變窗口過程函數(shù)的情況下七问,可以完成消息響應蜓耻。MFC確實是這樣做的,但實際操作起來可能跟你的想象差別很大械巡。

現(xiàn)在我們來編寫消息映射表刹淌,我們先定義一個結構,這個結構至少有兩個項:一是消息ID讥耗,二是響應該消息的函數(shù)有勾。如下:

struct AFX_MSGMAP_ENTRY   
{       
      UINT nMessage;           //感興趣的消息       
      AFX_PMSG pfn;          //響應以上消息的函數(shù)指針   
}  

當然,只有兩個成員的結構連接起來的消息映射表是不成熟的古程。Windows消息分為標準消息蔼卡、控件消息和命令消息,每類型的消息都是包含數(shù)百不同ID挣磨、不同意義雇逞、不同參數(shù)的消息荤懂。我們要準確地判別發(fā)生了何種消息,必須再增加幾個成員喝峦。還有势誊,對于AFX_PMSG pfn,實際上等于作以下聲明:

      void (CCmdTarget::*pfn)();    // 提示:AFX_PMSG為類型標識谣蠢,
      具體聲明是:
      typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);

pfn是一個不帶參數(shù)和返回值的CCmdTarget類型成員函數(shù)指針粟耻,只能指向CCmdTarget類中不帶參數(shù)和返回值的成員函數(shù),這樣pfn更為通用眉踱,但我們響應消息的函數(shù)許多需要傳入?yún)?shù)的挤忙。為了解決這個矛盾,我們還要增加一個表示參數(shù)類型的成員谈喳。當然册烈,還有其它……

最后,MFC我們消息映射表成員結構如下定義:

struct AFX_MSGMAP_ENTRY   
{       
      UINT nMessage;           //Windows 消息ID       
      UINT nCode;                // 控制消息的通知碼       
      UINT nID;                   //命令消息ID范圍的起始值       
      UINT nLastID;             //命令消息ID范圍的終點       
      UINT nSig;                   // 消息的動作標識       
      AFX_PMSG pfn;   
};

有了以上消息映射表成員結構婿禽,我們就可以定義一個AFX_MSGMAP_ENTRY類型的數(shù)組赏僧,用來容納消息映射項。定義如下:

   AFX_MSGMAP_ENTRY _messageEntries[];

但這樣還不夠扭倾,每個AFX_MSGMAP_ENTRY數(shù)組淀零,只能保存著當前類感興趣的消息,而這僅僅是我們想處理的消息中的一部分膛壹。對于一個MFC程序驾中,一般有多個窗口類,里面都應該有一個AFX_MSGMAP_ENTRY數(shù)組模聋。

我們知道肩民,MFC還有一個消息傳遞機制,可以把自己不處理的消息傳送給別的類進行處理链方。為了能查找各下MFC對象的消息映射表持痰,我們還要增加一個結構,把所有的AFX_MSGMAP_ENTRY數(shù)組串聯(lián)起來祟蚀。于是共啃,我們定義了一個新結構體:

struct AFX_MSGMAP   
{       
      const AFX_MSGMAP* pBaseMap;                    //指向別的類的AFX_MSGMAP對象       
      const AFX_MSGMAP_ENTRY* lpEntries;          //指向自身的消息表   
};

之后,在每個打算響應消息的類中聲明這樣一個變量:AFX_MSGMAP messageMap暂题,讓其中的pBaseMap指向基類或另一個類的messageMap,那么將得到一個AFX_MSGMAP元素的單向鏈表究珊。這樣薪者,所有的消息映射信息形成了一張消息網(wǎng)。

當然剿涮,僅有消息映射表還不夠言津,它只能把各個MFC對象的消息攻人、參數(shù)與相應的消息響應函數(shù)連成一張網(wǎng)。為了方便查找悬槽,MFC在上面的類中插入了兩個函數(shù)(其中theClass代表當前類):

一個是_GetBaseMessageMap()怀吻,用來得到基類消息映射的函數(shù)。函數(shù)原型如下:

const AFX_MSGMAP* PASCAL theClass::_GetBaseMessageMap() /           
                 { return &baseClass::messageMap; } /   

另一個是GetMessageMap() 初婆,用來得到自身消息映射的函數(shù)蓬坡。函數(shù)原型如下:

const AFX_MSGMAP* theClass::GetMessageMap() const /             
                { return &theClass::messageMap; } /   

有了消息映射表之后,我們得討論到問題的關鍵磅叛,那就是消息發(fā)生以后屑咳,其對應的響應函數(shù)如何被調用。大家知道弊琴,所有的MFC窗口兆龙,都有一個同樣的窗口過程——AfxWndProc(…)。在這里順便要提一下的是敲董,看過MFC源代碼的朋友都得紫皇,從AfxWndProc函數(shù)進去,會遇到一大堆曲折與迷團腋寨,因為對于這個龐大的消息映射機制聪铺,MFC要做的事情很多,如優(yōu)化消息精置,增強兼容性等计寇,這一大量的工作,有些甚至用匯編語言來完成脂倦,對此番宁,我們很難深究它。所以我們要省略大量代碼赖阻,理性地分析它蝶押。

對已定型的AfxWndProc來說,對所有消息火欧,最多只能提供一種默認的處理方式棋电。這當然不是我們想要的。我們想通過AfxWndProc最終執(zhí)行消息映射網(wǎng)中對應的函數(shù)苇侵。那么赶盔,這個執(zhí)行路線是怎么樣的呢?

從AfxWndProc下去榆浓,最終會調用到一個函數(shù)OnWndMsg于未。請看代碼:

LRESULT CALLBACK AfxWndProc(HWND hWnd,UINT nMsg,WPARAM wParam, LPARAM lParam)   
{       
       ……          
      CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); //把對句柄的操作轉換成對CWnd對象。
      Return AfxCallWndProc(pWnd,hWnd,nMsg,wParam,lParam);   
}  

把對句柄的操作轉換成對CWnd對象是很重要的一件事,因為AfxWndProc只是一個全局函數(shù)烘浦,當然不知怎么樣去處理各種windows窗口消息抖坪,所以它聰明地把處理權交給windows窗口所關聯(lián)的MFC窗口對象。

現(xiàn)在闷叉,大家?guī)缀蹩梢韵胂蟮玫紸fxCallWndProc要做的事情擦俐,不錯,它當中有一句:

pWnd->WindowProc(nMsg,wParam,lParam);

到此握侧,MFC窗口過程函數(shù)變成了自己的一個成員函數(shù)蚯瞧。WindowProc是一個虛函數(shù),我們甚至可以通過改寫這個函數(shù)去響應不同的消息藕咏,當然状知,這是題外話。

WindowProc會調用到CWnd對象的另一個成員函數(shù)OnWndMsg孽查,下面看看大概的函數(shù)原型是怎么樣的:

BOOL CWnd::OnWndMsg(UINT message,WPARAM wParam,LPARAM lParam,LRESULT* pResult)   
{         
      if(message==WM_COMMAND)         
      {               
            OnCommand(wParam,lParam);               
            ……         
      }         
      if(message==WM_NOTIFY)         
      {               
            OnCommand(wParam,lParam,&lResult);               
            ……         
       }         
      const AFX_MSGMAP* pMessageMap;       
      pMessageMap=GetMessageMap();         
      const AFX_MSGMAP_ENTRY* lpEntry; 
        
      /*************************************************************
      以下代碼作用為:用AfxFindMessageEntry函數(shù)從消息入口pMessageMap處查找指定消息饥悴,
      如果找到,返回指定消息映射表成員的指針給lpEntry盲再。然后執(zhí)行該結構成員的pfn所指向的函數(shù)
      *************************************************************/
      if((lpEntry=AfxFindMessageEntry(pMessageMap->lpEntries,message,0,0)!=NULL)         
      {              
              lpEntry->pfn();
      /*************************************************************
      注意:真正MFC代碼中沒有用這一條語句西设。
      上面提到,不同的消息參數(shù)代表不同的意義和不同的消息響應函數(shù)有不同類型的返回值答朋。
      而pfn是一個不帶參數(shù)的函數(shù)指針贷揽,所以真正的MFC代碼中,
      要根據(jù)對象lpEntry的消息的動作標識nSig給消息處理函數(shù)傳遞參數(shù)類型梦碗。
      這個過程包含很復雜的宏代換禽绪,大家在此知道:找到匹配消息,執(zhí)行相應函數(shù)就行洪规!
      *************************************************************/        
      }   
}  

MFC命令傳遞

在上面的代碼中印屁,大家看到了OnWndMsg能根據(jù)傳進來的消息參數(shù),查找到匹配的消息和執(zhí)行相應的消息響應斩例。但這還不夠雄人,我們平常響應菜單命令消息的時候,原本屬于框架窗口(CFrameWnd)的WM_COMMAND消息念赶,卻可以放到視對象或文檔對象中去響應础钠。其原理如下:

我們看上面函數(shù)OnWndMsg原型中看到以下代碼:

if(message==WM_COMMAND)
{   
      OnCommand(wParam,lParam);                 
      ……
}

即對于命令消息,實際上是交給OnCommand函數(shù)處理叉谜。而OnCommand是一個虛函數(shù)旗吁,即WM_COMMAND消息發(fā)生時,最終是發(fā)生該消息所對應的MFC對象去執(zhí)行OnCommand停局。比如點框架窗口菜單阵漏,即向CFrameWnd發(fā)送一個WM_COMMAND驻民,將會導致CFrameWnd::OnCommand(wParam,lParam)的執(zhí)行。且看該函數(shù)原型:

BOOL CFrameWnd::OnCommand(WPARAM wParam,LPARAM lParam)   
{          
      ……          
      return CWnd:: OnCommand(wParam,lParam);   
}  

可以看出履怯,它最后把該消息交給CWnd:: OnCommand處理。再看:

BOOL CWnd::OnCommand(WPARAM wParam,LPARAM lParam)   
{          
      ……          
      return OnCmdMsg(nID,nCode,NULL,NULL);   
}  

這里包含了一個C++多態(tài)性很經(jīng)典的問題裆泳。在這里叹洲,雖然是執(zhí)行CWnd類的函數(shù),但由于這個函數(shù)在CFrameWnd:: OnCmdMsg里執(zhí)行工禾,即當前指針是CFrameWnd類指針运提,再有OnCmdMsg是一個虛函數(shù),所以如果CFrameWnd改寫了OnCommand闻葵,程序會執(zhí)行CFrameWnd::OnCmdMsg(…)民泵。

對CFrameWnd::OnCmdMsg(…)函數(shù)的原理扼要分析如下:

BOOL CFrameWnd:: OnCmdMsg(…)   
{          
      CView pView = GetActiveView();//得到活動視指針。          
      if(pView-> OnCmdMsg(…))         
            return TRUE; //如果CView類對象或其派生類對象已經(jīng)處理該消息槽畔,則返回栈妆。          
      …… //否則,同理向下執(zhí)行厢钧,交給文檔鳞尔、框架、及應用程序執(zhí)行自身的OnCmdMsg早直。   
}  

到此寥假,CFrameWnd:: OnCmdMsg完成了把WM_COMMAND消息傳遞到視對象、文檔對象及應用程序對象實現(xiàn)消息響應霞扬。

寫了這么多糕韧,我們已經(jīng)清楚了MFC消息映射與命令傳遞的大致過程。

一個按鈕點擊事件的過程如下:

CWinThread::PumpMessage -> CWnd::PretranslateMessage -> /
CWnd::WalkPreTranslateMessate -> CD1Dlg::PreTranslateMessage -> /
CDialog::PreTranslateMessage -> CWnd::PreTranslateInput   -> /
CWnd::IsDialogMessageA -> USER32內核 - > AfxWndProcBase ->  /
AfxWndProc -> AfxCallWndProc -> CWnd::WindowProc -> /
CWnd::OnWndMsg -> CWnd::OnCommand -> CDialog::OnCmdMsg -> /
CCmdTarget::OnCmdMsg -> _AfxDispatchCmdMsg -> CD1Dlg::OnButton1()

MFC消息映射宏

現(xiàn)在喻圃,我們來看MFC“神秘代碼”萤彩,會發(fā)覺好看多了。

先看DECLARE_MESSAGE_MAP()宏级及,它在MFC中定義如下:

#define DECLARE_MESSAGE_MAP() /   
private: /          
      static const AFX_MSGMAP_ENTRY _messageEntries[]; /           
protected: /          
      static AFX_DATA const AFX_MSGMAP messageMap; /          
      virtual const AFX_MSGMAP* GetMessageMap() const; / 

可以看出DECLARE_MESSAGE_MAP()定義了我們熟悉的兩個結構和一個函數(shù)乒疏,顯而易見,這個宏為每個需要實現(xiàn)消息映射的類提供了相關變量和函數(shù)饮焦。

現(xiàn)在集中精力來看一下:

  BEGIN_MESSAGE_MAP怕吴,
  END_MESSAGE_MAP
  ON_COMMAND

三個宏,它們在MFC中定義如下(其中ON_COMMAND與另外兩個宏并沒有定義在同一個文件中县踢,把它放到一起是為了好看):

#define BEGIN_MESSAGE_MAP(theClass, baseClass) /       
      const AFX_MSGMAP* theClass::GetMessageMap() const /                
      { return &theClass::messageMap; } /       
      AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = /               
      { &baseClass::messageMap, &theClass::_messageEntries[0] }; /       
      AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = /                
      { /        

#define ON_COMMAND(id, memberFxn) /      
      { WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)&memberFxn },    
 
#define END_MESSAGE_MAP() /       
      {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } /   
}; /

一下子看三個宏覺得有點復雜转绷,但這僅僅是復雜,公式性的文字代換并不是很難硼啤。且看下面例子议经,假設我們框架中有一菜單項為“Test”,即定義了如下宏:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)         
ON_COMMAND(ID_TEST, OnTest)   
END_MESSAGE_MAP()  

那么宏展開之后得到如下代碼:

const AFX_MSGMAP* CMainFrame::GetMessageMap() const              
{ 
      return &CMainFrame::messageMap; 
}      
///以下填入消息表映射信息   
const AFX_MSGMAP CMainFrame::messageMap =                     
      { &CFrameWnd::messageMap, &CMainFrame::_messageEntries[0] };     
//下面填入保存著當前類感興趣的消息,可填入多個AFX_MSGMAP_ENTRY對象   
const AFX_MSGMAP_ENTRY CMainFrame::_messageEntries[] =    
{            
       //加入的ID_TEST消息參數(shù)           
      {WM_COMMAND, CN_COMMAND, (WORD)ID_TEST, (WORD)ID_TEST, AfxSig_vv, (AFX_PMSG)&OnTest },
      //本類的消息映射的結束項   
      {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
}; 

大家知道煞肾,要完成ID_TEST消息映射咧织,還要定義和實現(xiàn)OnTest函數(shù)。即在頭文件中寫afx_msg void OnTest()并在源文件中實現(xiàn)它籍救。根據(jù)以上所學的東西习绢,我們知道了當ID為ID_TEST的命令消息發(fā)生,最終會執(zhí)行到我們寫的OnTest函數(shù)蝙昙。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末闪萄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子奇颠,更是在濱河造成了極大的恐慌败去,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烈拒,死亡現(xiàn)場離奇詭異圆裕,居然都是意外死亡,警方通過查閱死者的電腦和手機缺菌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門葫辐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人伴郁,你說我怎么就攤上這事耿战。” “怎么了焊傅?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵剂陡,是天一觀的道長。 經(jīng)常有香客問我狐胎,道長鸭栖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任握巢,我火速辦了婚禮晕鹊,結果婚禮上,老公的妹妹穿的比我還像新娘暴浦。我一直安慰自己溅话,他們只是感情好,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布歌焦。 她就那樣靜靜地躺著飞几,像睡著了一般。 火紅的嫁衣襯著肌膚如雪独撇。 梳的紋絲不亂的頭發(fā)上屑墨,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天躁锁,我揣著相機與錄音,去河邊找鬼卵史。 笑死战转,一個胖子當著我的面吹牛,可吹牛的內容都是我干的程腹。 我是一名探鬼主播匣吊,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼寸潦!你這毒婦竟也來了?” 一聲冷哼從身側響起社痛,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤见转,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蒜哀,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斩箫,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年撵儿,在試婚紗的時候發(fā)現(xiàn)自己被綠了乘客。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡淀歇,死狀恐怖易核,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情浪默,我是刑警寧澤牡直,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站纳决,受9級特大地震影響碰逸,放射性物質發(fā)生泄漏。R本人自食惡果不足惜阔加,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一饵史、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胜榔,春花似錦胳喷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至摔癣,卻和暖如春奴饮,著一層夾襖步出監(jiān)牢的瞬間纬向,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工戴卜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逾条,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓投剥,卻偏偏與公主長得像师脂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子江锨,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內容