• <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>
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統計

            • 隨筆 - 44
            • 文章 - 0
            • 評論 - 86
            • 引用 - 0

            常用鏈接

            留言簿(6)

            隨筆分類(31)

            隨筆檔案(44)

            Mining

            最新隨筆

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            如何禁用Tree Control 的節點

            Tree Control : how to disable an item

            Tree Control 不支持節點的禁用, 但是可以通過自繪實現, 主要如下:

            1. 標記節點是否禁用. 可以用 SetItemData & GetItemData 來設置&獲取節點數據

            2. 在禁用的節點上, 要過濾一些對節點操作, 如expanding, selecting, drag & drop 等.
            TVN_SELCHANGING  節點選中改變時
            TVN_ITEMEXPANDING 節點展開時
            TVN_BEGINDRAG  節點開始被拖拉
            TVN_BEGINLABELEDIT 節點被編輯

            //Preventing selection: (handle TVN_SELCHANGING)
            void CYourDialog::OnSelchangingTree(NMHDR* pNMHDR, LRESULT* pResult) 
            {
              NM_TREEVIEW
            * pNMTreeView = (NM_TREEVIEW*) pNMHDR;
              
            if(((CItemStruct *) m_tree.GetItemData(pNMTreeView->iNewItem))->m_bDisabled)
              {
                
            *pResult = 1// 設置 *pResult=1 表示TVN_SELCHANGING 這個操作不能繼續
                return;
              }
              
            *pResult = 0;
            }


            3. 對禁用節點進行自畫, 用圖標,顏色將禁用節點和其他節點進行區分
            a) 直接在 WM_PAINT 中進行自畫 (或對Tree Control的繪圖結果進行修改)
             可以參考: 如何在樹型控件中使用背景位圖

            b) 相應 WM_OWERDRAW 事件
             可以參考: Outlook風格的單列使用不同的顏色顯示新郵件數


            參考:
            MFC Tree Control: How to disable an item? 
            Setting color and font attribute for individual items

            posted @ 2008-01-14 19:16 泡泡牛 閱讀(1939) | 評論 (1)編輯 收藏
            COM 類工廠有必要存在嗎

            1. IClassFactory 的用途

            http://www.80diy.com/home/20041120/19/3572410.html 看到幾段關于COM 的類廠的話,

            """
            類廠用來抽象組件的create過程,客戶不需要知道組件的詳細情況,也不需要知道類廠的詳細情況,只要知道CoCreateInstance可以創建組件即可。而CoCreateInstance內部調用DllGetClassObject來生成該組件的類廠,由于類廠有組件的作者撰寫,所以對組件類可謂知根知底,由類廠來生成組件完全行得通,這樣客戶和組件就進一步劃分,客戶只能查詢該組件是否支持某借口,而對組件的其他情況一無所知,這樣的劃分可以使組件和客戶間的耦合更小。
            """

            """
            組件如果將某接口的全部方法都實現了,就稱該組件支持某接口,com并沒有規定組件和接口之間是虛函數繼承的關系,只是在c++中以這種方法來實現最好而已。  
            IClassFactory說穿了就是專門構造組件的類,這樣做是為了抽象,因為客戶沒有必要知道組件是什么,如果由客戶直接構造組件,客戶勢必要知道組件的信息,com就失去了它的意義了,所以,規定了一個類廠(支持IClassFactory接口),每個組件的類廠都很清楚并且也只清楚該組件的信息,而客戶只需要調用com庫函數CoCreateInstance就可以了。  
            下面是流程圖:  
              CoCreateInstance -> CoGetClassObject -> DllGetClassObject -> new ClassFactory -> IClassFactory::CreateInstance() -> new Component
            """

            并且在 http://www.codeproject.com/com/comintro2.asp 也看到幾段話

            """
            每次實現組件對象類的時候,都要寫一個旁類負責創建第一個組件對象類的實例。這個旁類就叫這個組件對象類的類工廠(class factory),其唯一目的是創建COM對象。之所以要一個類工廠,是因為語言無關的緣故。COM本身并不創建對象,因為它不是獨立于語言的也不是獨立于實現的。
            當某個客戶端想要創建一個COM對象時,COM庫就從COM服務器請求類工廠。然后類工廠創建COM對象并將它返回客戶端。它們的通訊機制由函數DllGetClassObject()來提供。
            """

            在<COM 技術內幕> 中, 對類廠的引入也有描述.
            主要是:
            a. 在面向對象系統中, 對象創建是非常重要的, 因為要使用它必須先創建它. 所以盡可能靈活的創建對象(component)
            b. 在CoCreateInstance 創建對象過程是: 傳給一共CLSID, 然后創建成相應組件, 并返回所請求的指針. 其弊端在于無法提供給客戶一種控制對象創建過程的方法. (問題關鍵不在初始化, 而是控制創建對象過程)
            c. IClassFactory2 成批的調用接口.


            2.
            參考CoCreateInstance 的實現過程:
            CoCreateInstance -> CoGetClassObject -[系統|組件代碼]-> DllGetClassObject -> new ClassFactory -> IClassFactory::CreateInstance() -> new Component

            因為 DllGetClassObject -> new ClassFactory -> IClassFactory::CreateInstance() -> new Component 都是組件所來實現的, 而系統調用 CoCreateInstance 所提供的參數, 和通過自己使用IClassFactory 來創建Component 的參數是沒有變化的, 所以如果省略 ClassFactory 應該也可以.

            CoCreateInstance -> CoGetClassObject -[系統|組件代碼]-> DllGetClassObject -> new Component

            DllGetClassObject 完全可以完成<COM 技術內幕說的> a. 靈活創建對象, b. 控制創建過程, c. IClassFactory2 , 而且這樣子的實現也與語言無關. 
            所以感覺沒有必要一定要用到IClassFactory 這個接口


            3.
            因此在實現的時候, 完全可以這樣子的實現組件
            CCoClass : public IA, public IB, public IClassFactory
            {
            ......
            }

            DllGetClassObject()
            {
            new CCoClass
            }

            而不需要額外的用一個類單獨的去實現IClassFactory . 好像ATL 默認的就是這么干的, 提供了一個CComCoClass<CCoClass, &CLSID_CCoClass)  實現類.

            這個是我的對COM 的IClassFactory 的理解, 感覺沒必要多一個這個東西.

            不知道大家是如何看待這個東西的:)


             

            posted @ 2007-11-18 22:53 泡泡牛 閱讀(4023) | 評論 (6)編輯 收藏
            窗口的子類化與超類化

            1. 子類化
            改變一個已經存在的窗口實例的性質:消息處理與其他實例屬性。
            在SDK編程范疇內,子類化就是改變一個窗口實例的窗口函數(通過GetWindowLong()和SetWindowLong()),子類化所要做的就是為某窗口實例編寫新的窗口函數。其操作是在實例級別上進行的。
            在MFC中子類化的情況有所不同:所有MFC窗口有相同的窗口函數,由該窗口函數根據窗口句柄查找窗口實例,在把消息映射到該窗口類(class)得消息處理函數上。為了利用MFC的消息映射機制,不宜改變窗口函數(名),MFC也把子類化封裝在函數SubclassWindow()中。但子類化的本質沒有變:在實例級別影響窗口的消息及其處理。例:
            Class  B :public A
            {
              ……
            }
            A  a;
            B  b;
            HWND ha=a.GetSafeHwnd();
            b.SubclassWindow(ha); #當然A 和B 不一定是繼承關系。
            注意:在被子類化的窗口銷毀之前,必須執行窗口的反子類化:
            b.UnSubclassWindow();


            2 超類化
            窗口超類化是在窗口類——WNDCLASS或WNDCLASSEX(非MFC類概念)級別進行的改變窗口類特征的
            使用過程:首先獲得一個已存在的窗口類,然后設置窗口類,最后注冊該窗口類。
            例:
            WNDCLASSEX  wc;
            wc.cbSize=sizeof(wc); //Windows用來進行版本檢查的,與窗口特征無關
            GetClassInfoEx(hinst,”XXXXXX”,&wc);
             // hinst—定義窗口類XXXXXX的模塊的句柄,如為系統定義的窗口類(如:EDIT、BUTTON)則hinst=NULL.。
            wc.lpszClassName = “YYYYYYY”;//必須改變窗口類的名字
            wc.hbrBackGround = CreateSolidBrush(RGB(0,0.0));//改變背景刷
            wc.lpfnWndProc = NewWndProc;//改變窗口函數
            ……
            RegisterClassEx(&wc);// 注冊新窗口類
            //使用窗口類
            ……
            ::CreateWindow(_T(“YYYYYYYY”,……);

            故超類化只能改變自己創建的窗口的特征,而不能用于由Windows創建的窗口(如對話框上的按鈕就不能進行超類化) 。而子類化是實例級別上的,只要能獲得窗口的實例,就可對其子類化,這是唯一的子類化對于超類化的優勢。另外,凡是子類化可實現的,超類化都可實現,不過超類化用起來較麻煩。


            3. 總結

            (0) 子類化修改窗口過程函數,  超類化修改窗口類(新的窗口類名)
            (1) 子類化是在窗口實例級別上的,超類化是在窗口類(WNDCLASS)級別上的。
            (2) 超類化可以完成比子類化更復雜的功能,在SDK范疇上,可以認為子類化是超類化的子集。
            (3) 子類化只能改變窗口創建后的性質,對于窗口創建期間無能為力(無法截獲ON_CREATE 事件),而超類化可以實現;超類化不能用于Windows創建的窗口,子類化可以。 


            4. 其他
            眼見為實(2):介紹Windows的窗口、消息、子類化和超類化 這里有一個例子..
            可以得出結論
            a) 子類化的classname 是不會變化的, 而超類化使用新注冊classname
            b) 子類化 & 超類化 描述的是一個動作 和實現方法沒什么關系..... 主要是子類化是SubclassWindow, SubclassDlgItem, 而超類化是RegisterClassEx(&newwindowclass)
            c) 感覺具體沒有必要區分這些, 實現功能就行了, 呵呵


            posted @ 2007-08-24 18:58 泡泡牛 閱讀(6850) | 評論 (7)編輯 收藏
            Some DirectShow Samples Break in Visual Studio 2005

            zt: http://blogs.msdn.com/mikewasson/archive/2005/05/23/some-directshow-samples-break-in-visual-studio-2005.aspx

            DirectX 9.0 與 VS 2005 之間存在沖突, 主要因為VS 2005 的語法比VC6 & VS2003 更加嚴格, 所以一些DirectX 自帶的代碼需要更改以后才能編譯通過. 本來想自己改的, 不過在網上發現了有人已經做了這個:)


            [Note: This post applies to the Platform SDK for Windows Server 2003 SP1 and Server 2003 R2. These issues were fixed in the Windows SDK for Vista.]  

            Some of the DirectShow samples break if you install Visual Studio 2005 Beta 2. Most of the errors that I found fall into three categories:

            • C4430: Missing type specifier. To conform with C++, undeclared types do not default to int. All types must be declared. Fix: Declare the type, or suppress the warning with the "/wd4430" flag.
            • C4996: ' xxxx' was declared deprecated. You may be including an older version of strsafe.h from the DirectX SDK or the Platform SDK. You should include the version installed with Visual Studio. (But it's probably harmless to ignore this warning.) 
            • C2065: 'xxx': undeclared identifier. To conform with C++, the scope of a variable declared inside a "for" loop is restricted to the loop. Fixes: (a) Move the declaration outside the for loop. (b) Redeclare the variable in multiple scopes, if you don't need it to persist outside the loop. (c) Set the /Zc:forScope flag. (You can find this under Project, Properties, Configuration Properties, C/C++, Language, Force Conformance In For Loop Scope. Set to "No".)

            Here are the specific fixes that I made. Warning: I have not thoroughly tested these, and I only tried them under the "Windows XP 32-bit Debug" environment in Platform SDK. You should use your own judgment before making any of these fixes.

            • BaseClasses\ctlutil.h (278)  
                  (LONG) operator=(LONG);
            • BaseClasses\wxdebug.cpp (564)
                  static DWORD g_dwLastRefresh = 0;
            • BaseClasses\winutil.cpp (2092)
                 UINT Count;
                 for (Count = 0;Count < Result;Count++) {
            •  BaseClasses\outputq.cpp (635)
                 long iDone = 0;
                 for (iDone = 0;
            • Capture\AmCap\amcap.cpp (691)
                  for(int i = 0; i < NUMELMS(gcap.rgpmAudioMenu); i++)
            • Capture\AmCap\amcap (2795)
                  for(int i = 0; i < NUMELMS(gcap.rgpmAudioMenu); i++)
            • DMODemo\dsutil.cpp (686)
                  DWORD i = 0;
                  for( i=0; i<m_dwNumBuffers; i++ )
            • dmoimpl.h (622)   [In the Platform SDK headers]
                  for (DWORD dw = 0; dw < NUMBEROFOUTPUTS; dw++) {
            • DMO\GargleDMO\MedParamBase\param.cpp (91)
                  for (DWORD dwIndex = 0; dwIndex < cParams; dwIndex++)
            • DMO\GargleDMO\MedParamBase\param.cpp (309)
                  CCurveItem *pCurve = NULL;
                  for (pCurve = pCurveHead;
            • DMO\GargleDMO\gargle.cpp (145)
                  for (DWORD i = 0; i < cOutputStreams && SUCCEEDED(hr); ++i)
            • Filters\Dump\dump.cpp (426)
                  for (int Loop = 0;Loop < (DataLength % BYTES_PER_LINE);Loop++)
            • Filters\Gargle\gargle.cpp (212)
                  static int m_nInstanceCount; // total instances
            • Filters\RGBFilters\RateSource\ratesource.cpp (382)
                  for( int y = 0 ; y < DEFAULT_HEIGHT ; y++ )
            • Filters\RGBFilters\RateSource\ratesource.cpp (387)
                  for( int y = 0 ; y < DEFAULT_WIDTH ; y++ )
            • VMR\VMRXclBasic and VMR\Ticker: LNK1181: cannot open input file 'dxguid.lib'. This was an error in the makefile. Change to read:
                  DXLIB="$(DXSDK_DIR)\Lib\x86"  (currently says "x32")
            • VMR\VMRXcl and VMR\VMRMulti: C1083: Cannot open include file: 'd3dxmath.h': No such file or directory. This is an old DX header that is no longer included in DX or in Visual Studio. Unfortunately the only fix is to download an older version of the DirectX SDK.
            • VMR9\MultiVMR9\GamePlayer\character.cpp (383)
                  DWORD i = 0;
                  for (i = 0; i < pMeshContainer->NumInfl; ++i)
            • VMR9\MultiVMR9\DLL\MixerControl.h (28)
                  static const DWORD MultiVMR9Mixer_DefaultFVF = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;
            • VMR9\VMRAllocator: error LNK2019: unresolved external symbol "wchar_t * __stdcall _com_util::ConvertStringToBSTR(char const *)" (etc).  Add this to the makefile:
                  LINK32_LIBS = \
                  comsuppw.lib \
                  shell32.lib \

             

            posted @ 2007-06-26 11:07 泡泡牛 閱讀(2287) | 評論 (2)編輯 收藏
            利用IE 實現Web 頁面截圖

            1. 目的

               在Codeproject 中看到有人做這個,  稍微做了下修改, 做成了命令行的, 使用方法是 
               iesnap.exe url filename
                  用以抓取 URL 對于的Web, 并且將Web 的截圖保存在Filename 中.
                  url : 要截圖的網址
                  filename: 截圖保存文件名
                   
            2. 思路
               
             主要使用WebBrowser Control 和 MSHTML 來完成.
             a. 創建WebBrowser control
             b. 從WebBrowser Control 獲取 IWebBrowser2 接口, 用 IWebBrowser2::Navigate2 來訪問URL
             c. 獲得IHTMLElementRender (WebBrowser -> IHTMLDocument2 -> IHTMLElement -> IHTMLElementRender), 使用該接口的DrawToDC 來獲取URL 對應的頁面截圖內容.
             d. 用GDI 的 Image 來保存截圖到Filename

            3. 
               可以看看原文以得到更好的解答   
               我看的那個文章: Capture an HTML document as an image
               另外一篇C# 的文章: Image Capture Whole Web Page using C#


            4. 問題
                   
             a. DocumentComplete 事件會在URL 對應頁面的每個元素下載完畢的時候都會發生, 所以:( 還不知道哪個事件是整個頁面下載完畢的事件:/
             b. 現在是通過MFC 來創建WebBrowser Control 的, 不知道怎么在Win32 Application 中創建這個控件.
             c. 不知道如何得到整個頁面的大小, 現在只能保存頁面截圖的一部分:(
               這個已經知道怎么做了. 
               IHTMLElement2 的 scrollWidth & scrollHeight 加上 scrollLeft & scrollTop 來實現, 但是不知道為什么, put_scrollTop & put_scrollLeft 這些函數好像不對, 只能截獲到一部分頁面截圖.:( 不知道為什么
               


             代碼可以在這里下載: http://www.shnenglu.com/Files/bigsml/iesnapshot.zip

            posted @ 2007-06-10 18:55 泡泡牛 閱讀(4971) | 評論 (2)編輯 收藏
            YC 瀏覽器

            這款瀏覽器,稱之為Yang C/C++ Compiler & Internet Browser或者YC編譯型瀏覽器..

            最開始是在程序員看到相關的文章的, 開始以為是在吹..但是今天用他的程序的時候, 感覺真的很nb..

            """
            記者在楊曉兵處觀摩了該產品的演示,發現它是由如下五個部分組成:HTML解析器;XML解析器(目前完成一部分);javascript腳本解釋器,C/C++腳本解釋器;C/C++編譯器;文本及二進制編輯器.其中最令人矚目的功能,自然是他所內嵌的C/C++實時編譯功能了,這樣使得C/C++的運行效果看上去類似動態語言,它不僅使得HTML支持腳本化的標準C/C++語言,而且使得C/C++ 能夠與象JacaScript這樣的動態語言可以互相調用.楊曉兵說“這將是軟件開發方式的革新.通過這個實時編譯功能,每個軟件可以同時分割成若干模塊,相互之間可以獨立運行.”該編譯器,與主流的C/C++編譯器相比,YC++在功能進行了一些刪減和改良,比如去掉了標準C/C++的函數重載、運算符重載、模板等,而改良的方向,主要側重增加與網頁開發環境(HTML4.0、CSS2.JavaScript)的互相支持和調用.令人頗感意外的是,該產品包括編譯器、HTML解析器等在內的五個模塊的所有代碼,都與由楊曉兵獨自一個人用C語言開發完成,從未借鑒參考任何其他源代碼.楊曉兵解釋說主要是為了便于調試和控制.這是相當大的工作量,整整花了他六年時間.從演示的運行效果來看,這款由一人手工完成的作品,編譯速度竟然比VC++還要快一些.據透露是源自其許多算法的優化,如專門為變量參數作了可供快速查找的字典表等.
            """


            在用的時候, 發現整個瀏覽器沒有使用一個Windows 控件, 所有的控件都是由用GDI 級來繪制成的... 包括菜單, 輸入框, 按鈕, 樹形控件等等等

            Orz... 一把

            可以在這里下載試用, 解壓縮3個壓縮包就行了.
            /Files/bigsml/setyc.part01.rar
            /Files/bigsml/setyc.part02.rar
            /Files/bigsml/setyc.part03.rar

            posted @ 2007-04-25 17:07 泡泡牛 閱讀(3836) | 評論 (18)編輯 收藏
            如何在IE頁面上顯示和編輯流程圖

            在Web 要實現地圖,流程圖,涂鴉等功能的時候,可以選擇VML,SVG,Javaapplet,或者Flash。百度的map 搜索的地圖展示就是使用VML 的。


            1、 VML
            VML是微軟1999年9月附帶IE5.0發布的,全稱是Vector Markup Language(矢量可標記語言),其實是Word和HTML結合的產物。可以將Word文檔另存為HTML,其中的文本和圖片可以很容易的轉換,但如果是手繪制的圖形在以往的IE里面就無法解釋了,如果都轉換成圖形文件又不太現實。于是微軟把Word里面的圖形控件結合到IE里面,使IE也具備了繪圖功能。

            VML 的資料:

            MS 的 How to Use VML on Web Pages
               http://msdn.microsoft.com/library/default.asp?url=/workshop/author/VML/ref/basic1.asp
            Think In VML(VML基本教程)
               http://www.itlearner.com/code/vml/index.html

            VML畫板 
               http://www.tool.la/VMLPalette/

            VML編輯器
               http://www.dynamicdrive.com/dynamicindex11/editor.htm

            流程圖
               http://cosoft.org.cn/projects/webflow

            How to Implement Vector Markup Language (VML) on Web Pages?
               http://www.tudjarov.hit.bg/vml/vmlbt.html

            VML Chart 控件
               http://dev.csdn.net/article/23/23770.shtm

            Chart Demo
               http://webfx.eae.net/dhtml/chart/demo.html

             


            2、SVG
            SVG,全稱為Scalable Vector Graphics(可伸縮矢量圖形)。它是W3C制定的、用矢量描述圖形的XML應用標準。它有著許多的優點,比如可擴充性(scalable),動態的,交互性強。SVG支持無極放大,對SVG圖片進行任意比例的放大都不會損害圖片的顯示(沒有太多的失真),其他諸如BMP,JPEG格式的圖片都不支持無級放大。SVG有動畫元素,只要在SVG文件中嵌入SVG動畫元素就可以實現動畫效果了。同時SVG也定義了豐富的事件,包括鼠標事件和鍵盤事件,只要對SVG進行相關的腳本編程就可以實現SVG文件的交互操作。


            相關示例:

            SVG腳本編程
            http://dev.csdn.net/article/26/26676.shtm
            http://www.adobe.com/svg/examples.html

            SVM & SVG 相關的庫和應用有
            Prototype Graphic Framework
               http://prototype-graphic.xilinus.com/
            Cumulate Draw 很強大的一個畫圖工具, 基本上實現了Visio 的功能
               http://www.cumulatelabs.com/cumulatedraw/
            RichDraw - Simple VML/SVG Editor
               http://starkravingfinkle.org/blog/2006/04/richdraw-simple-vmlsvg-editor/
            Mapbar 地圖
               http://main.mapbar.com/
            mxDraw 很強大的一個流程圖畫板
               http://www.mxgraph.com/demo/mxgraph/editors/diagrameditor.html

            Del.icio.us
               http://del.icio.us/hedgerwang/VML


            3、Flash
            Flash的強大功能就不用介紹了,相信它完全可以實現任何流程圖的操作功能。但是,Flash的學習成本太高了,它的ActionScript讓我們這些寫慣了java、js的開發人員一頭霧水。而且相關的網絡資源實在是太少了,當初我google了N久,才勉強找到一個通過讀取xml文件顯示流程圖的example,功能僅僅是顯示xml文件中配置的流程節點(有需要源碼的朋友可以mail我)。所以,要想實現強大的流程圖編輯功能,Flash只推薦高手使用。
            商用的軟件有
            Gliff    http://www.gliffy.com/ 
            DrawAnywhere  http://drawanywhere.com/

            Google code有一個開源項目 http://code.google.com/p/flexvizgraphlib/ , 其代碼可以在
            http://groups.google.com/group/flexvizgraphlib/web/FlexVisualGraph.zip 下載到

            4、Java Applet
            在SVM 和 SVG 出現以前,有網絡涂鴉,就是用Applet 做成的,但是現在好像用的不多了。

            ref:
            Tools for Creating Charts and Diagrams 一篇英文的文章, 對現有的流程圖創建工具有一個很好的介紹

            posted @ 2007-01-11 12:06 泡泡牛 閱讀(8897) | 評論 (7)編輯 收藏
            Internet Explorer 7 Final(漢化+繞正版驗證安裝方法)

            IE7 近幾天發布了, 英文版可以通過下面的鏈接下載.
            XP w/sp2
            http://download.microsoft.com/download/3/8/8/38889DC1-848C-4BF2-8335-86C573AD86D9/IE7-WindowsXP-x86-enu.exe
            2003
            http://download.microsoft.com/download/D/1/3/D1346F12-F3A0-4AC6-8F5C-2BEA2A184957/IE7-WindowsServer2003-x86-enu.exe
            xp&2003 64bit
            http://download.microsoft.com/download/1/1/4/114D5B07-4DBC-42F3-96FA-2097E207D0AF/IE7-WindowsServer2003-x64-enu.exe
            2003 ia64
            http://download.microsoft.com/download/4/E/3/4E3E332E-4A7B-4E85-9F45-8209472F2FD2/IE7-WindowsServer2003-ia64-enu.exe

            在安裝中要求正版驗證.?不過在網上已經出現了破解方法,?在 http://green.crsky.com/soft/4012.html?可以下載破解過的IE7.

            1.先把IE7的安裝文件用WinRAR解開.
            2.將破解iecustom.dll放進Update目錄,覆蓋原有文件.
            3.執行update.exe安裝,這個時候先勾選安裝界面的"Do not restart now",先不要重啟,如下圖:
            20060826_022703_414.gif

            4.復制下載來的normaliz.dll到Windows的System32目錄(必須執行,否則系統將故障)
            5.重新啟動.
            6.執行Update目錄下的xmllitesetup.exe更新一下就可以了

            一定一定要記住安裝后勾選安裝界面的"Do not restart now",先不要重啟!等復制normaliz.dll到Windows的System32目錄下再重啟!其實先復制normaliz.dll到Windows的System32目錄下也是可以的!下面2個不同版本都適合上面的方法!

            Internet Explorer 7 正式版(Final)版本號7.0.5730.11;Internet Explorer 7 (RC1)版本號7.0.5700.6

            posted @ 2006-10-19 14:38 泡泡牛 閱讀(1082) | 評論 (1)編輯 收藏
            用BoundsChecker檢測內存泄漏 (zz)

              BoundsChecker采用一種被稱為 Code Injection的技術,來截獲對分配內存和釋放內存的函數的調用。簡單地說,當你的程序開始運行時,BoundsChecker的DLL被自動載入進程的地址空間(這可以通過system-level的Hook實現),然后它會修改進程中對內存分配和釋放的函數調用,讓這些調用首先轉入它的代碼,然后再執行原來的代碼。BoundsChecker在做這些動作的時,無須修改被調試程序的源代碼或工程配置文件,這使得使用它非常的簡便、直接。

              這里我們以malloc函數為例,截獲其他的函數方法與此類似。

              需要被截獲的函數可能在DLL中,也可能在程序的代碼里。比如,如果靜態連結C-Runtime Library,那么malloc函數的代碼會被連結到程序里。為了截獲住對這類函數的調用,BoundsChecker會動態修改這些函數的指令。

              以下兩段匯編代碼,一段沒有BoundsChecker介入,另一段則有BoundsChecker的介入:

            126:?_CRTIMP?void?*?__cdecl?malloc?(
            127:?size_t?nSize
            128:?)
            129:?{

            00403C10?push?ebp
            00403C11?mov?ebp,esp
            130:?return?_nh_malloc_dbg(nSize,?_newmode,?_NORMAL_BLOCK,?NULL,?0);
            00403C13?push?
            0
            00403C15?push?
            0
            00403C17?push?
            1
            00403C19?mov?eax,[__newmode?(0042376c)]
            00403C1E?push?eax
            00403C1F?mov?ecx,dword?ptr?[nSize]
            00403C22?push?ecx
            00403C23?call?_nh_malloc_dbg?(00403c80)
            00403C28?add?esp,14h
            131:?}
            以下這一段代碼有BoundsChecker介入:
            126:?_CRTIMP?void?*?__cdecl?malloc?(
            127:?size_t?nSize
            128:?)
            129:?{

            00403C10?jmp?01F41EC8
            00403C15?push?
            0
            00403C17?push?
            1
            00403C19?mov?eax,[__newmode?(0042376c)]
            00403C1E?push?eax
            00403C1F?mov?ecx,dword?ptr?[nSize]
            00403C22?push?ecx
            00403C23?call?_nh_malloc_dbg?(00403c80)
            00403C28?add?esp,14h
            131:?}

              當BoundsChecker介入后,函數malloc的前三條匯編指令被替換成一條jmp指令,原來的三條指令被搬到地址01F41EC8處了。當程序進入malloc后先jmp到01F41EC8,執行原來的三條指令,然后就是BoundsChecker的天下了。大致上它會先記錄函數的返回地址(函數的返回地址在stack上,所以很容易修改),然后把返回地址指向屬于BoundsChecker的代碼,接著跳到malloc函數原來的指令,也就是在00403c15的地方。當malloc函數結束的時候,由于返回地址被修改,它會返回到BoundsChecker的代碼中,此時BoundsChecker會記錄由malloc分配的內存的指針,然后再跳轉到到原來的返回地址去。

              如果內存分配/釋放函數在DLL中,BoundsChecker則采用另一種方法來截獲對這些函數的調用。BoundsChecker通過修改程序的DLL Import Table讓table中的函數地址指向自己的地址,以達到截獲的目的。

              截獲住這些分配和釋放函數,BoundsChecker就能記錄被分配的內存或資源的生命周期。接下來的問題是如何與源代碼相關,也就是說當BoundsChecker檢測到內存泄漏,它如何報告這塊內存塊是哪段代碼分配的。答案是調試信息(Debug Information)。當我們編譯一個Debug版的程序時,編譯器會把源代碼和二進制代碼之間的對應關系記錄下來,放到一個單獨的文件里(.pdb)或者直接連結進目標程序,通過直接讀取調試信息就能得到分配某塊內存的源代碼在哪個文件,哪一行上。使用Code Injection和Debug Information,使BoundsChecker不但能記錄呼叫分配函數的源代碼的位置,而且還能記錄分配時的Call Stack,以及Call Stack上的函數的源代碼位置。這在使用像MFC這樣的類庫時非常有用,以下我用一個例子來說明:

            void?ShowXItemMenu()
            {
             …
             CMenu?menu;

             menu.CreatePopupMenu();
             
            //add?menu?items.
             menu.TrackPropupMenu();
             …
            }

            void?ShowYItemMenu(?)
            {
             …
             CMenu?menu;
             menu.CreatePopupMenu();
             
            //add?menu?items.
             menu.TrackPropupMenu();
             menu.Detach();
            //this?will?cause?HMENU?leak
             …
            }

            BOOL?CMenu::CreatePopupMenu()
            {
             …
             hMenu?
            =?CreatePopupMenu();
             …
            }
            當調用ShowYItemMenu()時,我們故意造成HMENU的泄漏。但是,對于BoundsChecker來說被泄漏的HMENU是在class CMenu::CreatePopupMenu()中分配的。假設的你的程序有許多地方使用了CMenu的CreatePopupMenu()函數,如CMenu::CreatePopupMenu()造成的,你依然無法確認問題的根結到底在哪里,在ShowXItemMenu()中還是在ShowYItemMenu()中,或者還有其它的地方也使用了CreatePopupMenu()?有了Call Stack的信息,問題就容易了。BoundsChecker會如下報告泄漏的HMENU的信息:
            Function
            File
            Line

            CMenu::CreatePopupMenu
            E:\
            8168\vc98\mfc\mfc\include\afxwin1.inl
            1009

            ShowYItemMenu
            E:\testmemleak\mytest.cpp
            100
              
            這里省略了其他的函數調用

            如此,我們很容易找到發生問題的函數是ShowYItemMenu()。當使用MFC之類的類庫編程時,大部分的API調用都被封裝在類庫的class里,有了Call Stack信息,我們就可以非常容易的追蹤到真正發生泄漏的代碼。

              記錄Call Stack信息會使程序的運行變得非常慢,因此默認情況下BoundsChecker不會記錄Call Stack信息。可以按照以下的步驟打開記錄Call Stack信息的選項開關:

              1. 打開菜單:BoundsChecker|Setting…

              2. 在Error Detection頁中,在Error Detection Scheme的List中選擇Custom

              3. 在Category的Combox中選擇 Pointer and leak error check

              4. 鉤上Report Call Stack復選框

              5. 點擊Ok

              基于Code Injection,BoundsChecker還提供了API Parameter的校驗功能,memory over run等功能。這些功能對于程序的開發都非常有益。由于這些內容不屬于本文的主題,所以不在此詳述了。

              盡管BoundsChecker的功能如此強大,但是面對隱式內存泄漏仍然顯得蒼白無力。所以接下來我們看看如何用Performance Monitor檢測內存泄漏。

              使用Performance Monitor檢測內存泄漏

              NT的內核在設計過程中已經加入了系統監視功能,比如CPU的使用率,內存的使用情況,I/O操作的頻繁度等都作為一個個Counter,應用程序可以通過讀取這些Counter了解整個系統的或者某個進程的運行狀況。Performance Monitor就是這樣一個應用程序。

              為了檢測內存泄漏,我們一般可以監視Process對象的Handle Count,Virutal Bytes 和Working Set三個Counter。Handle Count記錄了進程當前打開的HANDLE的個數,監視這個Counter有助于我們發現程序是否有Handle泄漏;Virtual Bytes記錄了該進程當前在虛地址空間上使用的虛擬內存的大小,NT的內存分配采用了兩步走的方法,首先,在虛地址空間上保留一段空間,這時操作系統并沒有分配物理內存,只是保留了一段地址。然后,再提交這段空間,這時操作系統才會分配物理內存。所以,Virtual Bytes一般總大于程序的Working Set。監視Virutal Bytes可以幫助我們發現一些系統底層的問題; Working Set記錄了操作系統為進程已提交的內存的總量,這個值和程序申請的內存總量存在密切的關系,如果程序存在內存的泄漏這個值會持續增加,但是Virtual Bytes卻是跳躍式增加的。

              監視這些Counter可以讓我們了解進程使用內存的情況,如果發生了泄漏,即使是隱式內存泄漏,這些Counter的值也會持續增加。但是,我們知道有問題卻不知道哪里有問題,所以一般使用Performance Monitor來驗證是否有內存泄漏,而使用BoundsChecker來找到和解決。

              當Performance Monitor顯示有內存泄漏,而BoundsChecker卻無法檢測到,這時有兩種可能:第一種,發生了偶發性內存泄漏。這時你要確保使用Performance Monitor和使用BoundsChecker時,程序的運行環境和操作方法是一致的。第二種,發生了隱式的內存泄漏。這時你要重新審查程序的設計,然后仔細研究Performance Monitor記錄的Counter的值的變化圖,分析其中的變化和程序運行邏輯的關系,找到一些可能的原因。這是一個痛苦的過程,充滿了假設、猜想、驗證、失敗,但這也是一個積累經驗的絕好機會。

              總結

              內存泄漏是個大而復雜的問題,即使是Java和.Net這樣有Gabarge Collection機制的環境,也存在著泄漏的可能,比如隱式內存泄漏。由于篇幅和能力的限制,本文只能對這個主題做一個粗淺的研究。其他的問題,比如多模塊下的泄漏檢測,如何在程序運行時對內存使用情況進行分析等等,都是可以深入研究的題目。如果您有什么想法,建議或發現了某些錯誤,歡迎和我交流。


            posted @ 2006-10-19 13:45 泡泡牛 閱讀(9141) | 評論 (2)編輯 收藏
            C語言中可變參數的用法

            我們在C語言編程中會遇到一些參數個數可變的函數,例如printf()這個函數,這里將介紹可變函數的寫法以及原理.

            * 1. 可變參數的宏

            一般在調試打印Debug 信息的時候, 需要可變參數的宏. 從C99開始可以使編譯器標準支持可變參數宏(variadic macros), 另外GCC 也支持可變參數宏, 但是兩種在細節上可能存在區別.

            1. __VA_ARGS__

            __VA_ARGS__ 將"..." 傳遞給宏.如
            #define debug(format, ...) fprintf(stderr, fmt, __VA_ARGS__)

            在GCC中也支持這類表示, 但是在G++ 中不支持這個表示.

            2. GCC 的復雜宏

            GCC使用一種不同的語法從而可以使你可以給可變參數一個名字,如同其它參數一樣。
            #define debug(format, args...) fprintf (stderr, format, args)

            這和上面舉的那個定義的宏例子是完全一樣的,但是這么寫可讀性更強并且更容易進行描述。

            3. ##__VA_ARGS__

            上面兩個定義的宏, 如果出現debug("A Message") 的時候, 由于宏展開后有個多余的逗號, 所以將導致編譯錯誤. 為了解決這個問題,CPP使用一個特殊的‘##’操作。

            #define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
            這里,如果可變參數被忽略或為空,‘##’操作將使預處理器(preprocessor)去除掉它前面的那個逗號。如果你在宏調用時,確實提供了一些可變參數,GNU CPP也會工作正常,它會把這些可變參數放到逗號的后面。

            4. 其他方法

            一種流行的技巧是用一個單獨的用括弧括起來的的 "參數" 定義和調用宏, 參數在宏擴展的時候成為類似 printf() 那樣的函數的整個參數列表。
            #define DEBUG(args) (printf("DEBUG: "), printf(args))


            * 2. 可變參數的函數

            寫可變參數的C函數要在程序中用到以下這些宏:
            void va_start( va_list arg_ptr, prev_param )
            type va_arg( va_list arg_ptr, type )
            void va_end( va_list arg_ptr )

            va在這里是variable-argument(可變參數)的意思,這些宏定義在stdarg.h中.下面我們寫一個簡單的可變參數的函數,該函數至少有一個整數參數,第二個參數也是整數,是可選的.函數只是打印這兩個參數的值.
            void simple_va_fun(int i, ...)
            {
            ?? ?va_list arg_ptr;
            ?? ?int j=0;
            ?? ?
            ?? ?va_start(arg_ptr, i);
            ?? ?j=va_arg(arg_ptr, int);
            ?? ?va_end(arg_ptr);
            ?? ?printf("%d %d\n", i, j);
            ?? ?return;
            }

            在程序中可以這樣調用:
            simple_va_fun(100);
            simple_va_fun(100,200);

            從這個函數的實現可以看到,使用可變參數應該有以下步驟:
            1)首先在函數里定義一個va_list型的變量,這里是arg_ptr,這個變量是指向參數的指針.
            2)然后用va_start宏初始化變量arg_ptr,這個宏的第二個參數是第一個可變參數的前一個參數,是一個固定的參數.
            3)然后用va_arg返回可變的參數,并賦值給整數j. va_arg的第二個參數是你要返回的參數的類型,這里是int型.
            4)最后用va_end宏結束可變參數的獲取.然后你就可以在函數里使用第二個參數了.如果函數有多個可變參數的,依次調用va_arg獲取各個參數.

            如果我們用下面三種方法調用的話,都是合法的,但結果卻不一樣:
            1)simple_va_fun(100);
            結果是:100 -123456789(會變的值)
            2)simple_va_fun(100,200);
            結果是:100 200
            3)simple_va_fun(100,200,300);
            結果是:100 200

            我們看到第一種調用有錯誤,第二種調用正確,第三種調用盡管結果正確,但和我們函數最初的設計有沖突.下面一節我們探討出現這些結果的原因和可變參數在編譯器中是如何處理的.
            * 3. 可變參數函數原理

            va_start,va_arg,va_end是在stdarg.h中被定義成宏的,由于硬件平臺的不同,編譯器的不同,所以定義的宏也有所不同,下面以VC++中stdarg.h里x86平臺的宏定義摘錄如下:

            typedef char * va_list;
            #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
            #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
            #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
            #define va_end(ap) ( ap = (va_list)0 )

            定義_INTSIZEOF(n)主要是為了內存對齊,C語言的函數是從右向左壓入堆棧的(設數據進棧方向為從高地址向低地址發展,即首先壓入的數據在高地址). 下圖是函數的參數在堆棧中的分布位置:

            低地址?? ?|-----------------------------|<-- &v
            ?? ??? ?|第n-1個參數(最后一個固定參數)|
            ?? ??? ?|-----------------------------|<--va_start后ap指向
            ?? ??? ?|第n個參數(第一個可變參數) |
            ?? ??? ?|-----------------------------|
            ?? ??? ?|....... |
            ?? ??? ?|-----------------------------|
            ?? ??? ?|函數返回地址 |
            高地址? |-----------------------------|

            1. va_list 被定義為char *
            2. va_start 將地址ap定義為 &v+_INTSIZEOF(v),而&v是固定參數在堆棧的地址,所以va_start(ap, v)以后,ap指向第一個可變參數在堆棧的地址
            3. va_arg 取得類型t的可變參數值,以int型為例,va_arg取int型的返回值:
            ?? j= ( *(int*)((ap += _INTSIZEOF(int))-_INTSIZEOF(int)) );
            4. va_end 使ap不再指向堆棧,而是跟NULL一樣.這樣編譯器不會為va_end產生代碼.

            在不同的操作系統和硬件平臺的定義有些不同,但原理卻是相似的.


            * 4. 小結

            對于可變參數的函數,因為va_start, va_arg, va_end等定義成宏,所以它顯得很愚蠢,可變參數的類型和個數需要在該函數中由程序代碼控制;另外,編譯器對可變參數的函數的原型檢查不夠嚴格,對編程查錯不利.
            所以我們寫一個可變函數的C函數時,有利也有弊,所以在不必要的場合,無需用到可變參數.如果在C++里,我們應該利用C++的多態性來實現可變參數的功能,盡量避免用C語言的方式來實現.


            * 5. 附一些代碼

            #define debug(format, ...) fprintf(stderr, fmt, __VA_ARGS__)
            #define debug(format, args...) fprintf (stderr, format, args)
            #define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)

            // 使用va... 實現
            void debug(const char *fmt, ...)
            {
            ??? int nBuf;
            ??? char szBuffer[1024];
            ??? va_list args;

            ??? va_start(args, fmt);
            ??? nBuf = vsprintf(szBuffer, fmt, args) ;
            ??? assert(nBuf >= 0);

            ??? printf("QDOGC ERROR:%s\n",szBuffer);
            ??? va_end(args);
            }

            posted @ 2006-10-19 12:55 泡泡牛 閱讀(3699) | 評論 (1)編輯 收藏
            僅列出標題
            共5頁: 1 2 3 4 5 
            久久婷婷综合中文字幕| 欧美精品福利视频一区二区三区久久久精品| 精品久久久久久99人妻| 久久久久久av无码免费看大片| 一本久久a久久精品综合香蕉| 精品久久久无码人妻中文字幕| 久久精品aⅴ无码中文字字幕重口| 久久99国产亚洲高清观看首页| 国产成人无码精品久久久久免费 | 国内精品久久国产| 精品人妻伦九区久久AAA片69| 精品精品国产自在久久高清 | 青青青青久久精品国产| 欧美与黑人午夜性猛交久久久| 少妇高潮惨叫久久久久久| 国产精品欧美久久久久无广告| 精品国产乱码久久久久软件| 久久综合九色综合精品| 久久久噜噜噜久久中文福利| 亚洲国产综合久久天堂| 久久九九青青国产精品| 亚洲国产精品无码久久一区二区 | 国产精品无码久久四虎| 亚洲午夜久久久影院| 日本欧美国产精品第一页久久| 国产成人精品久久免费动漫| 国产美女亚洲精品久久久综合| 久久综合狠狠综合久久97色| 久久亚洲精品视频| 久久99热只有频精品8| 一本一本久久a久久综合精品蜜桃| 日韩美女18网站久久精品| 9191精品国产免费久久| 草草久久久无码国产专区| 人人狠狠综合久久亚洲88| 99久久国产综合精品麻豆| 国产精品一区二区久久| 精品一区二区久久| 久久福利片| 色播久久人人爽人人爽人人片aV| 久久综合成人网|