Loading AI tools
来自维基百科,自由的百科全书
微軟基礎類別館(英語:Microsoft Foundation Classes,簡稱MFC)是一個微軟公司提供的類別館(class libraries),以C++類的形式封裝了Windows API,並且包含一個(也是微軟產品的唯一一個)應用程式框架,以減少應用程式開發人員的工作量。其中包含的類包含大量Windows控制代碼封裝類和很多Windows的內建控制項和組件的封裝類。
Visual C++包含MFC應用程式精靈,可用於相容MFC的應用程式[1]。在ATL程式中也可以手動添加MFC支援[2]。在精靈中有各種選項以客製化生成的程式的功能,例如介面風格、語種、資料庫開發支援、列印支援、自動化支援、ActiveX支援、網路支援、基於HTML的說明文件支援等等。
在COM開發方面,相對於ATL來說,MFC的組件比較大,代碼不夠短小精悍,但是支援的功能也比較多,例如有對ActiveX Document的封裝類[3]。
在介面開發方面,MFC提供對訊息迴圈的封裝,使用訊息對映來避免虛擬函式的開銷。MFC也提供常用Windows通用控制項的封裝類。
MFC擴充DLL的介面使得MFC程式可以直接呼叫MFC擴充DLL中的MFC類。MFC也支援在標準DLL中被使用。
MFC是在1992年隨微軟的Microsoft C/C++ 7.0編譯器發布的,用於面向16位元Windows的軟體開發。起初,MFC是作為一個應用程式框架開發的,所以定名為Application Framework eXtensions(AFX)。[4]
隨著.NET框架的發布,曾經一度被微軟重點推薦的MFC被Visual Basic .NET、C#、Windows Forms搶走了不少市場份額,但是MFC繼續在非代管軟體開發中占據重要地位。在代管開發方面,MFC中也包括對Windows Forms和代管/非代管互操作的封裝。微軟在Windows Vista和Windows 7發布之後在MFC中增加了對新的Windows API支援[5][6]。
MFC的主要優點是可以用物件導向的方法來呼叫Windows API,以及能夠更加便捷地開發應用程式。MFC將很多應用程式開發中常用的功能自動化,並且提供了文件框架視圖結構和活動文件這樣的便於自訂的應用程式框架。同時,在Visual C++內部也內建了很多對MFC的例如類精靈這樣的支援以減少軟體開發的時間,使用類精靈可以快速生成Hello World程式。
雖然MFC的原始碼對使用者是完全開放的,但是MFC的一些封裝過程過於複雜,以致於新使用者很難迅速掌握MFC的應用程式框架,以及在除錯中定位問題的位置。同時,很多MFC對象不是執行緒安全的,致使在跨執行緒訪問MFC對象時需要編寫額外的代碼。另外,MFC的很多類依賴於應用程式精靈生成的代碼,使得在使用Visual C++中其他類型的應用程式精靈生成的工程中添加MFC支援的難度大大增加。
很多商用類別館在MFC的基礎上進一步實現了外觀、漸變風格、多頂層窗口程式、屬性列表等較受歡迎的功能;同時,在C++線上社群中,很大一部分開放的原始碼也是基於MFC的。
產品 | 程式庫 | 版本 | 發佈日期 | |
---|---|---|---|---|
名稱 | 版本 | |||
Microsoft C/C++ 7.0 | mafxcw.lib | MFC 1.0 | 1992 | |
Microsoft Visual C++ 1.0 | Visual C++ 1.0 | mfc200.dll | MFC 2.0 | |
Visual C++ 1.5 | mfc250.dll | MFC 2.5 | ||
Visual C++ 1.51 | mfc250.dll | MFC 2.51 | ||
Visual C++ 1.52c | mfc250.dll | MFC 2.5 ( Windows 3.x 的最後發展平台 ) | ||
Microsoft Visual C++ 2.0 | Visual C++ 2.0 | mfc30.dll | MFC 3.0 | |
Visual C++ 2.1 | mfc30.dll | MFC 3.1 | ||
Visual C++ 2.2 | mfc30.dll | MFC 3.2 | ||
Microsoft Visual C++ 4.0 | Visual C++ 4.0 | mfc40.dll | MFC 4.0 (mfc40.dll 包含於 Windows 95) | 1995年8月 |
Visual C++ 4.1 | mfc40.dll | MFC 4.1 | ||
Visual C++ 4.2 | mfc42.dll | MFC 4.2 (mfc42.dll 包含於 Windows 98 初版) | 1998年3月 | |
內含於 Visual C++ 3.0 | mfc42.dll | MFC 4.2 | ||
Microsoft Visual C++ 5.0 | Visual C++ 5.0 | mfc42.dll | MFC 4.21, 是 MFC 4.2 的主要更新 | |
Microsoft Visual C++ 6.0 | Visual C++ 6.0 | mfc42.dll | MFC 6.0 | 1998年 |
內含於 Visual C++ 4.0 | mfcce400.dll | MFC 6.0 | ||
Microsoft Visual C++ .NET 2002 | Visual C++ .NET 2002 (Visual C++ 7.0) | mfc70.dll | MFC 7.0 | 2002年2月13日 |
Microsoft Visual C++ .NET 2003 | Visual C++ .NET 2003 (Visual C++ 7.1) | mfc71.dll | MFC 7.1 | 2003年4月24日 |
Visual C++ .NET 2003 + MS11-025 (KB2465373)[7] | MFC 7.10.6119.0 | 2011年4月12日 | ||
Microsoft Visual C++ 2005 | Visual C++ 2005 (Visual C++ 8.0) | mfc80.dll | 8.0.50727.42 | 2006年4月10日 |
Visual C++ 2005 SP1 | 8.0.50727.762 | 2007年8月27日 | ||
Visual C++ 2005 SP1 + MS09-035 (KB973544)[8][9] | 8.0.50727.4053 | 2009年7月28日 | ||
Visual C++ 2005 SP1 + MS11-025 (KB2467175)[7] | 8.0.50727.5592 | 2011年4月12日 | ||
Visual C++ 2005 SP1 + MS11-025 (KB2538242)[7][10] | 8.0.50727.6195 (包含於 redist 8.0.61000/8.0.61001[11]) | 2011年6月14日 | ||
Microsoft Visual C++ 2008 | Visual C++ 2008 (Visual C++ 9.0) | mfc90.dll | 9.0.21022.8 | 2007年11月19日 |
Visual C++ 2008 + MS09-035 (KB973551)[8][9] | 9.0.21022.218 | 2009年7月28日 | ||
Visual C++ 2008 含Feature Pack | 9.0.30411 | 2008年4月22日 | ||
Visual C++ 2008 SP1 | 9.0.30729.1 | 2008年8月11日 | ||
Visual C++ 2008 SP1 + MS09-035 (KB973552)[8][9] | 9.0.30729.4148 | 2009年7月28日 | ||
Visual C++ 2008 SP1 + MS11-025 (KB2467174)[7] | 9.0.30729.5570 | 2011年4月12日 | ||
Visual C++ 2008 SP1 + MS11-025 (KB2538243)[7] | 9.0.30729.6161 (安裝程式版本 9.0.30729.5677) | 2011年6月14日 | ||
Microsoft Visual C++ 2010 | Visual C++ 2010 (Visual C++ 10.0) | mfc100.dll | 10.0.30319.1 | 2010年4月12日[12] |
Visual C++ 2010 + MS11-025 (KB2467173)[7] | 10.0.30319.415 | 2011年4月12日 | ||
Visual C++ 2010 SP1 | 10.0.40219.1 | 2011年3月10日 | ||
Visual C++ 2010 SP1 + MS11-025 (KB2565063)[7] | 10.0.40219.325 | 2011年8月9日 | ||
Microsoft Visual C++ 2012 | Visual C++ 2012 (Visual C++ 11.0) | mfc110.dll | 11.0.50727.1 | 2012年9月12日 |
Visual C++ 2012 Update 1 | 11.0.51106.1 | 2012年11月26日 | ||
Visual C++ 2012 Update 3 | 11.0.60610.1 | 2013年6月26日 | ||
Visual C++ 2012 Update 4 | 11.0.61030.0 | 2013年11月13日 | ||
Microsoft Visual C++ 2013 | Visual C++ 2013 (Visual C++ 12.0) | mfc120.dll | 12.0.21005.1 | 2013年10月17日 |
Visual C++ 2013 Update 2 | 12.0.30501.0 | 2014年5月12日 | ||
Visual C++ 2013 Update 5 + KB3138367 | 12.0.40649.5 | 2016年2月? | ||
Visual C++ 2013 Update 5 + KB3179560 | 12.0.40660.0 | 2016年7月8日[13] | ||
Visual C++ 2013 Update 5 + KB4032938 | 12.0.40664.0 | 2017年7月18日[14] | ||
Microsoft Visual C++ 2015 | Visual C++ 2015 (Visual C++ 14.0) | mfc140.dll | 14.0.23026.0 | 2015年7月20日 |
Visual C++ 2015 Update 1 | 14.0.23506.0 | 2015年11月30日[15] | ||
Visual C++ 2015 Update 2 | 14.0.23918.0 | 2016年3月30日[16] | ||
Visual C++ 2015 Update 3 | 14.0.24210.0 | 2016年6月27日[17] | ||
Visual C++ 2015 Update 3 | 14.0.24212.0 | 2016年8月18日 | ||
Visual C++ 2015 Update 3 + KB3165756 | 14.0.24215.1 | 2016年9月15日[18] | ||
Microsoft Visual C++ 2017 | Visual C++ 15.0 | mfc140.dll | 14.10.25008.0 | 2017年3月7日 |
Visual C++ 15.1? | 14.10.25017.0 | 2017年4月5日? | ||
Visual C++ 15.2 | 14.11.25325.0 | 2017年5月10日 | ||
Visual C++ 15.4 | 14.12.25810.0 | 2017年10月9日 | ||
Visual C++ 15.6 | 14.13.26020.0 | 2018年3月5日 | ||
Visual C++ 15.7 | 14.14.26405.0 | 2018年5月7日 | ||
Visual C++ 15.7.3? | 14.14.26429.4 | 2018年5月31日 | ||
Visual C++ 15.8 | 14.15.26706.0 | 2018年8月14日 | ||
Visual C++ 15.9 | 14.16.27012.6 | 2018年11月13日 | ||
Visual C++ 15.9.5 | 14.16.27024.1 | 2019年1月8日 | ||
Visual C++ 15.9.6 | 14.16.27026.1 | 2019年1月24日 | ||
Visual C++ 15.9.9 | 14.16.27027.1 | 2019年3月12日 | ||
Visual C++ 15.9.15 | 14.16.27033.0 | 2019年8月13日 | ||
Microsoft Visual C++ 2019 | Visual C++ 16.0.0 | mfc140.dll | 14.20.27508.1 | 2019年4月2日? |
Visual C++ 16.1.0 | 14.21.27702.2 | 2019年5月21日 | ||
Visual C++ 16.2.0 | 14.22.27821.0 | 2019年7月24日 | ||
Visual C++ 16.3.0 | 14.23.27820.0 | 2019年9月23日 | ||
Visual C++ 16.4.0 | 14.24.28127.4 | 2019年12月3日 | ||
Visual C++ 16.5.0 | 14.25.28508.3 | 2020年3月16日 | ||
Visual C++ 16.6.0 | 14.26.28720.3 | 2020年5月19日 | ||
Visual C++ 16.6.3 | 14.26.28808.1 | 2020年7月30日 | ||
Visual C++ 16.7.0 | 14.27.29016.0 | 2020年8月5日 | ||
Visual C++ 16.7.5 | 14.27.29112.0 | 2020年9月29日 | ||
Visual C++ 16.8.0 | 14.28.29325.2 | 2020年11月10日 | ||
Visual C++ 16.8.2 | 14.28.29334.0 | 2020年11月19日 | ||
Visual C++ 16.9.0 | 14.28.29910.0 | 2021年3月2日 | ||
Visual C++ 16.9.2 | 14.28.29913.0 | 2021年3月16日 | ||
Visual C++ 16.9.4 | 14.28.29914.0 | 2021年4月13日 | ||
Visual C++ 16.10.0 | 14.29.30037.0 | 2021年5月25日 | ||
Visual C++ 16.10.2 | 14.29.30038.0 | 2021年6月15日 | ||
Visual C++ 16.10.4 | 14.29.30040.0 | 2021年7月20日 | ||
Visual C++ 16.11.0 | 14.29.30133.0 | 2021年8月10日 | ||
Visual C++ 16.11.4 | 14.29.30135.0 | 2021年10月5日 | ||
Microsoft Visual C++ 2022 | Visual C++ 17.0.0RC | mfc140.dll | 14.30.30704.0 | 2021年10月13日 |
作為一個應用程式的開發框架,必須滿足各方面的功能需求。
基於MFC開發的應用程式在啟動時,Windows作業系統:
分類 | 訊息 | 對映宏 | 訊息處理常式原型 | 注釋 |
---|---|---|---|---|
系統訊息 | 標準Windows訊息 | MFC使用專用的相關的宏。如ON_WM_CREATE() | MFC使用專用的訊息處理成員函式 | 一般地由窗口對象來處理這類訊息 |
命令訊息 WM_COMMAND | ON_COMMAND(id, memberFxn) | void OnXXX () | 通過識別碼ID來區分來自哪個選單項、工具列按鈕或者加速鍵等 | |
ON_COMMAND_RANGE(id, idLast, memberFxn) | void OnXXX (UINT id) | 批次處理一定範圍內的標示符ID | ||
ON_UPDATE_COMMAND_UI(id, idLast, memberFxn) | void OxXXX(CCmdUI* pCmdUI) | 程式空閒時發的介面更新訊息的宏 | ||
ON_UPDATE_COMMAND_UI_RANGE(id, idLast, memberFxn) | void OxXXX(CCmdUI* pCmdUI) | |||
ON_CONTROL(id, idLast, memberFxn) | void OnXXX () | 父窗口回應控制項傳送的訊息 | ||
ON_CONTROL_RANGE(id, idLast, memberFxn) | void OnXXX (UINT id) | |||
ON_CONTROL_REFLECT(id, idLast, memberFxn) | void OnXXX () | 子控制項回應父窗口反射回來的通知訊息 | ||
通知訊息WM_NOTIFY | ON_NOTIFY(wNotifyCode,id,memberFxn) | afx_msg void memberFxn(NMHDR * pNotifyStruct, LRESULT* result) | wParam為控制項ID,lParam指向NMHDR結構體,結構體的code域值為控制項通知碼用來表示控制項上的動作,如NM_CLICK.一般地由父窗口對象來處理這類訊息。 | |
ON_NOTIFY_RANGE( wNotifyCode, id, idLast, memberFxn ) | 可手工添加(class wizard不支援),處理控制項id連續的一批控制項的同一通知碼訊息。 | |||
ON_NOTIFY_EX | 允許通知訊息在多處被處理 | |||
ON_NOTIFY_EX_RANGE | ||||
ON_NOTIFY_REFLECT | afx_msg void memberFxn(NMHDR * pNotifyStruct, LRESULT* result) | 複雜子控制項回應父窗口反射回來的通知訊息 | ||
自訂訊息 | 窗口類內部自訂訊息WM_USER到WM_APP-1 | ON_MESSAGE(訊息名,memberFxn) | afx_msg LRESULT OnMyMessageXXX(WPARAM wParam, LPARAM lParam) | 範例 |
程式內部自訂訊息WM_APP到0xBFFF | ON_THREAD_MESSAGE(WM_THREADMSG,OnThreadMessage) | afx_msg void OnThreadMessage(WPARAM wParam,LPARAM lParam); | 範例 | |
ON_REGISTERED_THREAD_MESSAGE | afx_msg void OnMyRegisterdThreadMsg(WPARAM, LPARAM); | RegisterWindowMessage()使用一個字串來登記一個自訂的訊息ID | ||
應用程式之間自訂訊息0xC000到0xFFFF | ON_REGISTERED_MESSAGE | LRESULT OnMyMessageXXX(WPARAM wParam, LPARAM lParam) | RegisterWindowMessage()使用一個字串來登記一個自訂的訊息ID,便於跨行程應用 |
表單上的控制項,應當向父表單通報控制項發生的各種事件,如被點擊、繪製、內容改變等等,稱為通知訊息(notification message )。在 Windows 3.x的16位元程式設計時代,控制項向父表單傳送WM_COMMAND訊息,由父表單的代碼負責實現這些事件。其中wParam的低16位元是 control ID,高16位元是notification code (例如BN_CLICKED);lParam是控制項控制代碼。因此,再無可能傳遞其它資訊給父表單。為此,為傳遞具有特別內容的控制項事件,Windows 3.x定義了一批特殊的通知訊息(notification messages):
早於4.0版本的MFC,在控制項類提供了虛擬函式處理這些通知訊息,這一辦法已經被下述的「訊息反射」取代(但仍然向下相容繼續支援)。
隨著Windows 95開始了32位元程式時代,伴之而來的是Win32 API 與 MFC 4.0。 Win32增加了很多複雜的控制項,需要使用更多的通知訊息傳遞很多複雜的資料給父表單。Win32 API僅僅增加了一個訊息WM_NOTIFY,就實現了這些功能。lParam參數開頭是NMHDR資料結構,其後是與該通知類型相關的特定資料結構。
typedef struct tagNMHDR {
HWND hwndFrom;
UINT idFrom;
UINT code;
} NMHDR;
CWnd::OnNotify函式處理通知訊息。它的預設實現是檢查訊息對映表(message map)尋找通知的處理器函式並呼叫。一般說來,不必覆蓋OnNotify;而應該寫一個處理器函式並增加為該窗口類的訊息對映表條目。
ON_NOTIFY(wNotifyCode, id, memberFxn)
成員函式應該寫為:
afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result);
MFC 4.0提供了一種特性「訊息反射」(message reflection),[19]允許控制項通知訊息既可以在父窗口中,也可以在控制項中被處理。可以對控制項建立一個衍生的控制項類,實現對從父窗口反射回來的指定類型訊息的處理。訊息反射是MFC而不是Win32的特性,因此父窗口的類必須是從CWnd衍生,從而父窗口在CWnd::OnNotify函式中處理控制項的WM_NOTIFY時,首先呼叫CWnd::ReflectLastMsg把訊息反射回控制項的CWnd::SendChildNotifyLastMsg函式去處理;ReflectLastMsg返回值就是在控制項的訊息對映中使用ON_NOTIFY_REFLECT_EX()聲明的反射訊息處理常式的返回值,可以通知父窗口該訊息是否已經被控制項處理。控制項的CWnd::SendChildNotifyLastMsg函式,首先獲得執行緒的最後一條message,然後呼叫傳送窗口的虛擬函式OnChildNotify函式。在子窗口處理反射回來的控制項訊息,第一種方法是多載控制項窗口的OnChildNotify虛擬函式;第二種辦法是由CWnd::OnChildNotify預設處理去呼叫CWnd::ReflectChildNotify函式,進入控制項子窗口的MFC訊息對映的標準處理(子窗口處理的訊息被譯成WM_REFLECT_BASE+WM_NOTIFY訊息)。對於WM_NOTIFY,僅當在控制項的訊息對映(message map)中,控制項沒有通過ON_NOTIFY_REFLECT()聲明的反射訊息處理常式,父窗口的相應的通知訊息處理常式才會被呼叫(在父窗口訊息對映中使用宏ON_NOTIFY聲明)。控制項中通過ON_NOTIFY_REFLECT_EX()聲明的反射訊息處理常式可以返回真或假,以決定父窗口是否繼續處理該通知訊息。WM_NOTIFY以外的其它通知訊息,父窗口在第一時間有機會處理它,控制項對它的處理排在第二位。反射訊息處理常式通常使用特定的名字,對應的訊息反射宏的名字是在訊息名字加上字首ON_,字尾_REFLECT。如WM_CTLCOLOR對應ON_WM_CTLCOLOR_REFLECT。但以下三種情況,反射訊息處理常式可以隨意自行起名,對應的訊息反射宏的名字分別為:
MFC類體系中,Windows訊息傳遞處理機制是基於CCmdTarget類及其衍生類別的靜態成員函式GetThisMessageMap()內部定義的靜態資料成員:
在標頭檔的類別定義中使用宏DECLARE_MESSAGE_MAP()來聲明靜態成員函式GetThisMessageMap與虛擬函式GetMessageMap
使用者所寫的類的Windows訊息處理常式(例如OnCommand)必須轉換為CCmdTarget::*的成員函式指標類型AFX_PMSG,儲存在該類的_messageEntries陣列中。
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // windows消息代号
UINT nCode; // WM_NOTIFY的控制代码
UINT nID; // WM_COMMAND下面的ID号,如果为其他的消息,则这个数字为0
UINT nLastID; //和前面的ID一起组成一个范围,用于发送一次消息,处理执行多次
UINT nSig; // 标志消息处理函数的类型
AFX_PMSG pfn; // 函数调用指针
};
typedef void (CCmdTarget::*AFX_PMSG)(void);
呼叫使用者類中該訊息處理常式時,根據該函式儲存在_messageEntries中的signature(一個無符號整型表示的函式的形參類型列表與返回值類型),把類型為void (CCmdTarget::*AFX_PMSG)(void)的成員函式指標強制轉為其它類型的CCmdTarget成員函式指標(例如void (AFX_MSG_CALL CWnd::*pfn_v_i_i)(int, int),目前在union MessageMapFunctions中列出了近百種CCmdTarget成員函式指標),然後呼叫轉換後的成員函式指標。這是基於Visual C++編譯器把單繼承的成員函式指標編譯為只儲存了函式的主記憶體起始位址,因此可以在同一個單繼承類中把一種類型的成員函式指標強制轉換為另一種成員函式指標,或者把單繼承衍生類別的成員函式指標強制轉換為基礎類別成員函式指標。這是打破了C++標準的違例辦法。例如,對於CWnd::OnCommand函式,轉換過程是:
BOOL (CWnd::*)(WPARAM, LPARAM lParam) => void (CWnd::*)() => void (CCmdTarget::*)()
CString是MFC中最常見的類之一,用於封裝字串資料結構。它只有一個資料成員m_pszData,其值為字串的首位址,其資料類型為wchar_t*或char*。在CString的m_pszData的前面實際還分配了CSringData資料塊,包含了管理資料:
IAtlStringMgr* pStringMgr;
int nDataLength;
int nAllocLength;
int nRefs;
由下而上,CAtlStringMgr提供主記憶體管理,CStringData提供共享管理,CString提供字串操作。
CAtlStringMgr的一個成員是IAtlMemMgr介面,這是策略模式,可以參照某個主記憶體管理類。CAtlStringMgr的另一個成員是CNilStringData。
因此,每次為CString動態分配位址空間,實際分配長度為:(nChars+1)*nCharSize+sizeof(CStringData)
。通過 Attach 操作,將這個 CStringData* 與 CSimpleStringT::m_pszData 執行了關聯。當執行CString的預設建構函式生成一個空字串時,實際上都是構造一個CnilStringData對象。CNilStringData 衍生自 CStringData,額外擁有一個 achNil 的陣列成員,這個陣列初始化為空字串。通過這個 achNil,保證了一個經過呼叫預設建構函式初始化的 CString,其指向的真正的字串是一個空字串。
部分編譯器對std::string放棄了寫時複製(Copy On Write)機制。但是,CString一直採取這一機制。CSimpleStringT::Fork 函式就提供了這樣一個操作,具體分為下面幾步:
GetString方法返回的是唯讀的字串位址;而GetBuffer方法返回的是可寫的字串位址(如果資料區是共享的,則寫時複製),如果修改了字串內容,這時需要呼叫ReleaseBuffer方法把新的字串長度修改到元資料中(並在尾部增加2個0位元組)。[20]
CString對象用作可變參數函式(如printf)的實參時,由於無法通過形參類型確定呼叫哪個CString的類型轉換運算子函式,因此有必要顯式指明要轉換的類型。如果需要在函式的參數傳遞CString,由於CString使用了參照計數,因此函式參數傳遞一個CString對象是可行的;不需要修改其內容時,推薦使用const CString&。
使用Visual C++可以開發3種DLL:
由於DLL與呼叫它的應用程式都可以有自己的MFC全域資料與控制代碼對映(handle mapping),如果控制代碼值相同,則預設使用應用程式的對映到的資源。為了不互相干擾,允許DLL內部使用自己的資源,必須在DLL函式的入口處把資源模組控制代碼從預設的應用程式切換為該DLL。辦法是:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ))
[21]。函式AfxGetStaticModuleState的功能是在執行棧上建立一個AFX_MODULE_STATE類別的實例,對其進行設定,函式返回值為AFX_MODULE_STATE的指標。AFX_MODULE_STATE類利用其建構函式和解構函式進行模組狀態現場儲存及恢復。Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.