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

旅途

如果想飛得高,就該把地平線忘掉

關于如何換膚、子類化的解決方案

 對于應用程序的換膚及子類化。下面是我嘗試過一些方法,以在CAboutDlg中子類化其中的Button為例:

第一種:直接用現成的類

1、自己寫一個類class CButtonXP : public CButton{/*...*/}

用MessageMap處理感興趣的消息。

2、用CButtonXP代替CButton來聲明變量m_btn;

3、在void CAboutDlg:DoDataExchange(CDataExchange* pDX)中加上一句:
DDX_Control(pDX, IDB_BUTTON1, m_edit);

或者在 InitDialog() 中加上

m_btn.SubclassDlgItem(IDB_BUTTON1, this);

這兩種效果差不多的。

第二種:在 Hook 中使用現成的類

1、自己寫一個類 class CButtonXP : public CButton{/*...*/}

用 MessageMap 處理感興趣的消息。

2、使用 SetWindowsHookEx 安裝一個鉤子:

g_hWndProcHook = ::SetWindowsHookEx(WH_CALLWNDPROC,WndProcHook,NULL,::GetCurrentThreadId());

3、在 WndProcHook 中處理窗口創建和銷毀的消息:

LRESULT CALLBACK WndProcHook(int code, WPARAM wParam, LPARAM lParam){	if (code == HC_ACTION)	{		switch (((CWPSTRUCT*) lParam)->message)		{		case WM_CREATE:			BeginSubclassing(((CWPSTRUCT*) lParam)->hwnd);			break;		case WM_NCDESTROY:			// TODO: clear subclass info.			EndSubclassing(((CWPSTRUCT*) lParam)->hwnd);			break;		default:			break;		}	}	return CallNextHookEx(g_hWndProcHook, code, wParam, lParam);}      
4、在 BeginSubclassing 中用 GetClassName 得到類名,例如 "Button",然后用 CButtonXP 類進行子類化。
CButtonXP pButton = new CButtonXP;VERIFY(pButton ->SubclassWindow(hWnd));

第三種 在Hook中使用窗口過程

1、自己寫一個按鈕的窗口過程

WNDPROC oldProc;LRESULT CALLBACK ProcButton(HWND hWnd,			UINT uMsg,			WPARAM wParam,			LPARAM lParam){	ASSERT(oldProc != 0);	if (oldProc == 0) return TRUE;	switch (uMsg)	{	case WM_ERASEBKGND:		break;		//......	default:		break;	}		return CallWindowProc(oldProc, hWnd, uMsg, wParam, lParam);}      
2、同第二種
3、同第二種

4、在 BeginSubclassing 中得到類名后,用 SetWindowLong 的方式子類化:
oldProc = (WNDPROC) GetWindowLong(hWnd, GWL_WNDPROC);SetWindowLong(hWnd, GWL_WNDPROC, (LONG) ProcButton);      
第四種:不用 Hook

在一個對話框的 OnInitDialog 中枚舉它的所有子窗體,例如用下面兩句來實現:
hWnd=GetWindow(hDlg,GW_CHILD); hWnd=GetWindow(hWnd,GW_HWNDNEXT);

對每個子窗體進行子類化處理,處理過程同第二種與第三種。

第五種:如果是在XP下運行,可以使用manifest,也就是如下的一個XML文件
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity name="Microsoft.Windows.XXXX"                   processorArchitecture="x86"                   version="5.1.0.0"                   type="win32"/> <description>Windows Shell</description> <dependency> <dependentAssembly> <assemblyIdentity type="win32"                   name="Microsoft.Windows.Common-Controls"                   version="6.0.0.0"                   processorArchitecture="x86"                   publicKeyToken="6595b64144ccf1df"                   language="*"/> </dependentAssembly> </dependency> </assembly>       
  把它存為應用程序名 .manifest,放到和應用程序對應的目錄下,或者把它作為資源類型為24的資源編譯進應用程序中。這樣程序在XP下就自動擁有了XP的風格。
六種:使用第三方的庫Skin++(www.uipower.com)實現換膚

第七種:用第三方應用程序給整個windows換膚(windowblinds)

  以上七種方式各有優缺點。我在使用過程中也遇到不少問題,現在一一道來,希望和大家共同解決問題。先排除幾種不準備深入探討的方式:

第五種,manifest 方式最快速和簡潔,但是功能有限,存在嚴重的平臺限制,不過好處在于應用程序可以和windows共一種風格。
第六種,使用第三方的庫 Skin++(www.uipower.com) 實現換膚方式使用起來很簡單,定制性也不錯,可供選擇的皮膚種類非常的多,支持的語言非常廣泛,可以稱得上是換膚功能的終結者,對于共享軟件開發者和注重界面的企業來說是個不錯的解決方案,他的換膚理念很新,有些地方做得很獨特,比如可以對 BCG 換膚等,有些技術點,很多同類產品都沒有做到,比如 ComboBox 的滾動條,系統對話框(open or close Dialog)的菜單等等。
第七種,屬于自娛性質的,也就不多說了。
第一種,直接使用現成的類,屬于很常見的一種用法,一般來說使用上不會出什么問題,缺點就不說了,如果這種方式讓我滿意,我就不必發這篇帖子了。

下面看看第二三四種:

第二種是用 HOOK+ 窗口類,實現起來比較方便,和做一個自繪控件的工作量其實是一樣的。
第三種是用HOOK+窗口過程,實現起來比較麻煩,需要自己處理一堆switch case, 自己轉換消息參數,自己找地方維護一堆狀態變量,工作量很大。
第四種不用 HOOK 的方式,有個缺點:對被換膚的程序的源代碼的修改比較多。當然,直接到進程中去找窗口句柄,然后子類化那么就不用源代碼了,不過這樣的話還不如用HOOK呢。
  實際上,HOOK機制和枚舉窗體雖然過程不同,不過最終目的是一樣的,都是為了子類化窗口。所以在此不去探討孰優孰劣了。現在切入正題,談談在子類化過程中遇到的問題:
一個是重復 subclass 的問題,上面提到,子類化的兩種方式:用窗口類或者用窗口過程。使用窗口類是從CWnd派生一個類,調用CWnd 的 protected 函數 SubclassWindow。可是如果正常使用一個窗口類(聲明成員變量,加入DDX_Control),實際上在 DDX_Control 中也是是用了 SubclassWindow 的。假如為一個控件聲明變量,而在 Hook 中又進行了子類化,結果會怎么樣呢?答案是:程序崩潰或彈出消息框"不支持的操作"。因為 SubclassWindow 函數調用前是要先 Attach 到一個HWND上去的。重復的 Attach 看來是不允許。要避免程序崩潰也有辦法:

1、只為控件聲明一個指針變量,動態的去獲取CWnd類的實例,但是這樣就達不到換膚的目的了。
2、 還有一種方法,經過我試驗,如果兩個SubclassWindow的調用位于不同的模塊,例如一個位于exe,一個位于dll(我是通過exe中調用 dll中的函數顯示該dll中的對話框來測試的),那么就不會出現問題。在還沒有找到更好的方法之前,這也姑且算是一種解決方法吧。
  但是如果使用窗口過程來子類化,就不存在重復subclass的問題了,只要小心處理,子類化無數次都沒問題,但是對于復雜的自繪事件,在一個窗口過程中來寫switch語句,好像很麻煩。
我嘗試過自己寫一個新的SubclassWindow函數來嘗試借用CWnd的窗口過程,這樣就可以按照MFC的方式來寫消息響應函數了。只可惜,最終 還是無功而返,因為SubclassWindow不是虛函數,而CWnd的窗口過程是作為一個protected成員存在的。所以沒法在外部借用MFC的 消息機制。所以,自己寫代碼處理 wParam 和 lParam 看來在所難免。
  零一個是子類化系統對話框的問題,系統的對話框和自己的對話框表現的總不一樣。目前我還沒有對所有的系統對話框進行測試。在 MessageBox 彈出的對話框中遇到的問題可以見我這一片帖子:
http://community.csdn.net/Expert/To....asp?id=3103399

  在文件對話框中我遇到一個問題,子類化過的 CStatic 的背景好像沒有重繪一樣,照理說應該由CStatic的父窗體負責背景的。

  我在我的 CStaticNew 類中只重載了 OnPaint,里面只處理文字和圖標的繪制,背景的繪制留給父窗體完成。這樣的處理在 MessageBox 和自己的 AboutDlg 中都沒有問題,Static 控件的背景就是父窗口的背景,可是在 CFileDlg 中背景就沒有重繪了:

void CStaticNew::OnPaint() {	CPaintDC dc(this); // device context for painting	// TODO: Add your message handler code here	CRect rt;	GetWindowRect(rt);		// 繪制背景	dc.SetBkMode(TRANSPARENT);		// 繪制文字	CFont *pfont, * pOldFont;	pfont = GetFont();	if (pfont)		pOldFont = dc.SelectObject(pfont);		CString szTitle;	GetWindowText(szTitle);	dc.DrawText(szTitle, CRect(0, 0, rt.Width(), rt.Height()), DT_LEFT | DT_WORDBREAK );		if (pfont)		dc.SelectObject(pOldFont);		// 繪制圖標	if ((GetStyle() & SS_ICON) != 0)	{		dc.DrawIcon(0, 0, GetIcon());	}	// Do not call CStatic::OnPaint() for painting messages}      
類名的識別問題,到現在為止,我所使用的子類化方法都是基于GetClassName這個函數獲得窗口類名,再根據用spy++所得到的知識,如 "#32770"表示對話框,"ToolbarWindow32"是工具欄,等等。但是窗口類名是可以在創建時任意指定的呀,而像CMainFrame的 類名根本就不能夠確定,例如記事本主窗體的類名是"Notepad",寫字板主窗體的類名是"WordPadClass"。這樣的話,子類化如何去進行呢。真想知道windows是怎么做的,skinmagic又是怎么做的。目前主要就是這三個問題了。希望大家能展開討論,給出一個換膚的完善的解決方案。
  我寫了一個簡化的CWnd類來解決重復子類化問題和簡化窗口過程,不過它不支持對自己的重復子類化(即只能用于沒有被子類化的或者被CWnd子類化的HWND)。
  因為不想弄得和MessageMap那樣復雜,所以功能也有限:須手工轉化WPARAM和LPARAM、消息處理無法繼承、不支持多線程。使用很簡單:
CWndNew* pWnd = new CWndNew;pWnd->SubclassWindow(hWnd);

用完了,記得釋放處理:

pWnd->UnsubclassWindow();delete pWnd;

如果要進行功能擴充(繼承),就改寫那幾個虛函數:

class CWndNew {public:	CWndNew();	virtual ~CWndNew();	bool SubclassWindow(HWND hWnd);	void UnsubclassWindow();

  關于子類化及其撤銷的順序問題,當用自己的類或者過程子類化窗口時,需要處理好與MFC類
子類化的順序沖突。假設我們自己的類叫CWndNew,那么不管CWnd和CWndNew誰先子類化一個窗口,最終兩者協同工作的結果應該是該窗口的窗口
過程還原到未子類化之前的狀態。首先,不要在HOOK過程中處理WM_NCDESTROY消息。理由:如果CWndNew比CWnd先子類化,由于
HOOK的原因,你仍然會先處理WM_NCDESTROY,這時候如果你撤銷子類化,那么CWnd類就得不到機會清理。而如果你不撤銷子類化,CWnd沒
有能力把被子類化的窗口還原到最初狀態。在HOOK過程中,不能通過調用SendMessage函數讓CWnd先行處理,然后你自己再處理,因為
SendMessage后,消息又會被HOOK攔截。
  由于上述原因,在CWndNew的消息過程中處理WM_NCDESTROY是很不錯的選擇,MFC也是這樣做的。參照如下的代碼進行解釋:
case WM_NCDESTROY:{ LRESULT lret; WNDPROC wndproc; wndproc = (WNDPROC)GetWindowLong(m_hWnd, GWL_WNDPROC); if (wndproc == CWndNew::StaticWindowProc) { HWND hWnd = m_hWnd; UnsubclassWindow(); lret = CallWindowProc(m_oldProc, hWnd, uMsg, wParam, lParam); } else { lret = CallWindowProc(m_oldProc, m_hWnd, uMsg, wParam, lParam); if(wndproc == (WNDPROC)GetWindowLong(m_hWnd, GWL_WNDPROC)) UnsubclassWindow(); } delete this; return lret;}   首先判斷該窗口的WNDPROC是否發生過變動,如果沒有的話是最好的,趕緊撤銷子類化,再把消息傳遞給之前窗口過程,然后功成身退,不問世事了。
 
 如果發生過變動,那么也就是說有別的類在CWndNew子類化以后又進行了子類化,而現在又把WM_NCDESTROY傳給了CWndNew。這好辦,
如法炮制,把消息繼續往前傳,如果WNDPROC又發生了改變,說明之前的某個窗口過程已經作了處理,就不需要再進行撤銷子類化的操作了。這點MFC的
CWnd類也是這樣做的。
  另外還有一個問題不解,就是Edit,ListBox,ListCtrl等等控件的內嵌的滾動條是怎么換膚的?網上
一般介紹的方法是隱藏原來的,然后換上自己重新實現的。這種在Spy++中一看就能現出原形,可是Skin++
換膚后的滾動條就不知道是怎么實現的了?我看過coolsb這個文章,他能實現給滾動條換膚的功能,但是對Combobox支持不好。


posted on 2007-07-17 23:57 旅途 閱讀(544) 評論(0)  編輯 收藏 引用 所屬分類: 深入windows

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美日韩国产一级| 亚洲精品视频啊美女在线直播| 91久久午夜| 欧美国产在线视频| 欧美777四色影视在线| 亚洲区中文字幕| 亚洲精品永久免费| 欧美日韩精品| 欧美一级专区| 麻豆成人91精品二区三区| 亚洲精品专区| 亚洲一级免费视频| 国产一区二区观看| 欧美黄色一区| 欧美视频精品在线观看| 久久成人久久爱| 美女久久网站| 亚洲在线视频一区| 久久久久国内| 一本色道久久综合亚洲二区三区| 亚洲男人的天堂在线aⅴ视频| 国产无一区二区| 亚洲二区视频在线| 国产精品成人在线观看| 美女视频网站黄色亚洲| 欧美日产在线观看| 久久久久久亚洲综合影院红桃| 欧美刺激性大交免费视频 | 欧美11—12娇小xxxx| 亚洲精品乱码久久久久久| 一区二区三区欧美在线| 国产亚洲精品一区二555| 亚洲国产精品成人| 国产情侣一区| 亚洲精品自在久久| 一区二区三区在线免费播放| 日韩视频在线一区二区| 狠狠色综合网站久久久久久久| 日韩视频三区| 亚洲人成网站777色婷婷| 欧美伊人影院| 亚洲影院一区| 欧美激情综合亚洲一二区| 久久久精品国产一区二区三区| 欧美日韩国产123| 欧美成人一区二区在线| 狠狠网亚洲精品| 亚洲一区二区三区四区视频| 亚洲精品之草原avav久久| 久久一区二区三区四区| 久久久精品tv| 国产亚洲欧美激情| 亚洲一区免费网站| 亚洲特级毛片| 欧美精品久久久久a| 久久久久久9999| 国产色综合网| 亚洲女人天堂成人av在线| 亚洲午夜精品久久久久久app| 欧美风情在线| 亚洲国产一二三| 91久久精品美女高潮| 久久综合九色| 欧美成人日本| 91久久线看在观草草青青| 美日韩精品免费观看视频| 欧美v亚洲v综合ⅴ国产v| 黄色综合网站| 蜜臀av一级做a爰片久久| 老司机免费视频一区二区三区| 黄色成人片子| 玖玖视频精品| 亚洲国产精品一区二区第四页av | 亚洲欧美日韩综合aⅴ视频| 欧美精品一区二区视频| 亚洲乱码日产精品bd| 一区二区三区你懂的| 欧美日韩成人综合| 亚洲午夜性刺激影院| 欧美一级大片在线免费观看| 国产精品在线看| 欧美自拍偷拍| 美国成人直播| 亚洲日本欧美在线| 欧美日韩免费一区| 亚洲欧美视频在线| 欧美99久久| 日韩午夜精品视频| 国产精品人成在线观看免费| 香蕉乱码成人久久天堂爱免费| 久久久久久久久一区二区| 亚洲国产婷婷香蕉久久久久久| 欧美mv日韩mv亚洲| 一本一道久久综合狠狠老精东影业 | 久久国产主播| 精品av久久久久电影| 欧美黄色影院| 欧美一区二区三区啪啪| 亚洲国产一区二区三区高清| 亚洲一区二区在线免费观看| 国产日韩欧美中文| 欧美a一区二区| 午夜视频久久久久久| 欧美国产日韩视频| 欧美伊人久久大香线蕉综合69| 在线观看的日韩av| 欧美午夜三级| 你懂的国产精品| 亚洲欧美偷拍卡通变态| 亚洲第一天堂av| 久久国产精品免费一区| 亚洲精品久久久久久久久久久 | 欧美在线免费看| 亚洲精品黄网在线观看| 久久精品国产免费观看| 日韩一区二区精品在线观看| 国产一区99| 国产精品盗摄久久久| 欧美成人精品在线观看| 欧美一区=区| 99精品99久久久久久宅男| 欧美jizz19性欧美| 久久精品一区二区国产| 亚洲在线观看免费视频| 日韩视频免费观看高清在线视频| 国产一区二区三区视频在线观看| 欧美视频一区二区三区在线观看 | 老司机一区二区| 午夜影院日韩| 亚洲欧美韩国| 国产精品99久久久久久有的能看| 亚洲激情在线观看| 亚洲第一精品福利| 久久综合成人精品亚洲另类欧美| 亚洲欧美日韩一区二区三区在线观看 | 欧美aⅴ99久久黑人专区| 久久精品国产亚洲一区二区三区 | 亚洲一区www| 日韩一级片网址| 亚洲国产欧美一区| 一区二区在线视频| 精品999网站| 娇妻被交换粗又大又硬视频欧美| 国产精品视屏| 国产女主播一区二区| 国产精品视频免费在线观看| 欧美午夜精品理论片a级按摩| 欧美日韩免费高清| 国产精品v片在线观看不卡 | 欧美区在线观看| 欧美/亚洲一区| 欧美成人激情在线| 欧美成人一区二区三区在线观看 | 国产精品福利久久久| 欧美天堂亚洲电影院在线观看| 欧美日韩午夜剧场| 国产精品久久久久久妇女6080| 欧美色图五月天| 国产乱人伦精品一区二区 | 国产午夜精品久久久久久免费视| 国产欧美精品日韩精品| 国产一区二区三区的电影 | 亚洲精品视频在线观看网站 | 在线日本高清免费不卡| 亚洲激情在线观看视频免费| 99国内精品| 先锋影院在线亚洲| 久久婷婷国产综合尤物精品| 你懂的国产精品| 亚洲欧洲日本专区| 在线视频中文亚洲| 久久国产欧美日韩精品| 美女尤物久久精品| 欧美日韩另类一区| 国产欧美日韩综合一区在线播放| 黄网动漫久久久| 夜夜嗨av一区二区三区中文字幕| 亚洲一区二区三区免费观看| 久久久精品免费视频| 亚洲高清自拍| 亚洲一区二区三区精品视频| 久久精品99国产精品日本| 欧美成人性网| 国产伦精品一区二区三区高清版| 在线看成人片| 亚洲一区免费观看| 免费欧美高清视频| 亚洲香蕉视频| 欧美 日韩 国产精品免费观看| 国产精品专区h在线观看| 亚洲国产精品va在线观看黑人| 亚洲一区二区精品在线观看| 美日韩精品视频| 亚洲永久精品国产| 欧美大片免费观看在线观看网站推荐| 国产精品视频免费在线观看| 亚洲精品一区在线观看香蕉| 久久久久国产精品一区三寸| 日韩视频不卡中文| 久久综合成人精品亚洲另类欧美 |