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

<2008年3月>
2425262728291
2345678
9101112131415
16171819202122
23242526272829
303112345

統(tǒng)計(jì)

  • 隨筆 - 44
  • 文章 - 0
  • 評(píng)論 - 86
  • 引用 - 0

常用鏈接

留言簿(6)

隨筆分類(31)

隨筆檔案(44)

Mining

最新隨筆

搜索

  •  

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

如何禁用Tree Control 的節(jié)點(diǎn)

Tree Control : how to disable an item

Tree Control 不支持節(jié)點(diǎn)的禁用, 但是可以通過自繪實(shí)現(xiàn), 主要如下:

1. 標(biāo)記節(jié)點(diǎn)是否禁用. 可以用 SetItemData & GetItemData 來設(shè)置&獲取節(jié)點(diǎn)數(shù)據(jù)

2. 在禁用的節(jié)點(diǎn)上, 要過濾一些對(duì)節(jié)點(diǎn)操作, 如expanding, selecting, drag & drop 等.
TVN_SELCHANGING  節(jié)點(diǎn)選中改變時(shí)
TVN_ITEMEXPANDING 節(jié)點(diǎn)展開時(shí)
TVN_BEGINDRAG  節(jié)點(diǎn)開始被拖拉
TVN_BEGINLABELEDIT 節(jié)點(diǎn)被編輯

//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// 設(shè)置 *pResult=1 表示TVN_SELCHANGING 這個(gè)操作不能繼續(xù)
    return;
  }
  
*pResult = 0;
}


3. 對(duì)禁用節(jié)點(diǎn)進(jìn)行自畫, 用圖標(biāo),顏色將禁用節(jié)點(diǎn)和其他節(jié)點(diǎn)進(jìn)行區(qū)分
a) 直接在 WM_PAINT 中進(jìn)行自畫 (或?qū)ree Control的繪圖結(jié)果進(jìn)行修改)
 可以參考: 如何在樹型控件中使用背景位圖

b) 相應(yīng) WM_OWERDRAW 事件
 可以參考: Outlook風(fēng)格的單列使用不同的顏色顯示新郵件數(shù)


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

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

1. IClassFactory 的用途

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

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

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

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

"""
每次實(shí)現(xiàn)組件對(duì)象類的時(shí)候,都要寫一個(gè)旁類負(fù)責(zé)創(chuàng)建第一個(gè)組件對(duì)象類的實(shí)例。這個(gè)旁類就叫這個(gè)組件對(duì)象類的類工廠(class factory),其唯一目的是創(chuàng)建COM對(duì)象。之所以要一個(gè)類工廠,是因?yàn)檎Z(yǔ)言無關(guān)的緣故。COM本身并不創(chuàng)建對(duì)象,因?yàn)樗皇仟?dú)立于語(yǔ)言的也不是獨(dú)立于實(shí)現(xiàn)的。
當(dāng)某個(gè)客戶端想要?jiǎng)?chuàng)建一個(gè)COM對(duì)象時(shí),COM庫(kù)就從COM服務(wù)器請(qǐng)求類工廠。然后類工廠創(chuàng)建COM對(duì)象并將它返回客戶端。它們的通訊機(jī)制由函數(shù)DllGetClassObject()來提供。
"""

在<COM 技術(shù)內(nèi)幕> 中, 對(duì)類廠的引入也有描述.
主要是:
a. 在面向?qū)ο笙到y(tǒng)中, 對(duì)象創(chuàng)建是非常重要的, 因?yàn)橐褂盟仨毾葎?chuàng)建它. 所以盡可能靈活的創(chuàng)建對(duì)象(component)
b. 在CoCreateInstance 創(chuàng)建對(duì)象過程是: 傳給一共CLSID, 然后創(chuàng)建成相應(yīng)組件, 并返回所請(qǐng)求的指針. 其弊端在于無法提供給客戶一種控制對(duì)象創(chuàng)建過程的方法. (問題關(guān)鍵不在初始化, 而是控制創(chuàng)建對(duì)象過程)
c. IClassFactory2 成批的調(diào)用接口.


2.
參考CoCreateInstance 的實(shí)現(xiàn)過程:
CoCreateInstance -> CoGetClassObject -[系統(tǒng)|組件代碼]-> DllGetClassObject -> new ClassFactory -> IClassFactory::CreateInstance() -> new Component

因?yàn)?DllGetClassObject -> new ClassFactory -> IClassFactory::CreateInstance() -> new Component 都是組件所來實(shí)現(xiàn)的, 而系統(tǒng)調(diào)用 CoCreateInstance 所提供的參數(shù), 和通過自己使用IClassFactory 來創(chuàng)建Component 的參數(shù)是沒有變化的, 所以如果省略 ClassFactory 應(yīng)該也可以.

CoCreateInstance -> CoGetClassObject -[系統(tǒng)|組件代碼]-> DllGetClassObject -> new Component

DllGetClassObject 完全可以完成<COM 技術(shù)內(nèi)幕說的> a. 靈活創(chuàng)建對(duì)象, b. 控制創(chuàng)建過程, c. IClassFactory2 , 而且這樣子的實(shí)現(xiàn)也與語(yǔ)言無關(guān). 
所以感覺沒有必要一定要用到IClassFactory 這個(gè)接口


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

DllGetClassObject()
{
new CCoClass
}

而不需要額外的用一個(gè)類單獨(dú)的去實(shí)現(xiàn)IClassFactory . 好像ATL 默認(rèn)的就是這么干的, 提供了一個(gè)CComCoClass<CCoClass, &CLSID_CCoClass)  實(shí)現(xiàn)類.

這個(gè)是我的對(duì)COM 的IClassFactory 的理解, 感覺沒必要多一個(gè)這個(gè)東西.

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


 

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

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


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

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


3. 總結(jié)

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


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


posted @ 2007-08-24 18:58 泡泡牛 閱讀(6906) | 評(píng)論 (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 之間存在沖突, 主要因?yàn)閂S 2005 的語(yǔ)法比VC6 & VS2003 更加嚴(yán)格, 所以一些DirectX 自帶的代碼需要更改以后才能編譯通過. 本來想自己改的, 不過在網(wǎng)上發(fā)現(xiàn)了有人已經(jīng)做了這個(gè):)


[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 泡泡牛 閱讀(2311) | 評(píng)論 (2)編輯 收藏
利用IE 實(shí)現(xiàn)Web 頁(yè)面截圖

1. 目的

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

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


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


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

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

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

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

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


在用的時(shí)候, 發(fā)現(xiàn)整個(gè)瀏覽器沒有使用一個(gè)Windows 控件, 所有的控件都是由用GDI 級(jí)來繪制成的... 包括菜單, 輸入框, 按鈕, 樹形控件等等等

Orz... 一把

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

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

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


1、 VML
VML是微軟1999年9月附帶IE5.0發(fā)布的,全稱是Vector Markup Language(矢量可標(biāo)記語(yǔ)言),其實(shí)是Word和HTML結(jié)合的產(chǎn)物。可以將Word文檔另存為HTML,其中的文本和圖片可以很容易的轉(zhuǎn)換,但如果是手繪制的圖形在以往的IE里面就無法解釋了,如果都轉(zhuǎn)換成圖形文件又不太現(xiàn)實(shí)。于是微軟把Word里面的圖形控件結(jié)合到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應(yīng)用標(biāo)準(zhǔn)。它有著許多的優(yōu)點(diǎn),比如可擴(kuò)充性(scalable),動(dòng)態(tài)的,交互性強(qiáng)。SVG支持無極放大,對(duì)SVG圖片進(jìn)行任意比例的放大都不會(huì)損害圖片的顯示(沒有太多的失真),其他諸如BMP,JPEG格式的圖片都不支持無級(jí)放大。SVG有動(dòng)畫元素,只要在SVG文件中嵌入SVG動(dòng)畫元素就可以實(shí)現(xiàn)動(dòng)畫效果了。同時(shí)SVG也定義了豐富的事件,包括鼠標(biāo)事件和鍵盤事件,只要對(duì)SVG進(jìn)行相關(guān)的腳本編程就可以實(shí)現(xiàn)SVG文件的交互操作。


相關(guān)示例:

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

SVM & SVG 相關(guān)的庫(kù)和應(yīng)用有
Prototype Graphic Framework
   http://prototype-graphic.xilinus.com/
Cumulate Draw 很強(qiáng)大的一個(gè)畫圖工具, 基本上實(shí)現(xiàn)了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 很強(qiáng)大的一個(gè)流程圖畫板
   http://www.mxgraph.com/demo/mxgraph/editors/diagrameditor.html

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


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

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

4、Java Applet
在SVM 和 SVG 出現(xiàn)以前,有網(wǎng)絡(luò)涂鴉,就是用Applet 做成的,但是現(xiàn)在好像用的不多了。

ref:
Tools for Creating Charts and Diagrams 一篇英文的文章, 對(duì)現(xiàn)有的流程圖創(chuàng)建工具有一個(gè)很好的介紹

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

IE7 近幾天發(fā)布了, 英文版可以通過下面的鏈接下載.
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

在安裝中要求正版驗(yàn)證.?不過在網(wǎng)上已經(jīng)出現(xiàn)了破解方法,?在 http://green.crsky.com/soft/4012.html?可以下載破解過的IE7.

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

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

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

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

posted @ 2006-10-19 14:38 泡泡牛 閱讀(1107) | 評(píng)論 (1)編輯 收藏
用BoundsChecker檢測(cè)內(nèi)存泄漏 (zz)

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

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

  需要被截獲的函數(shù)可能在DLL中,也可能在程序的代碼里。比如,如果靜態(tài)連結(jié)C-Runtime Library,那么malloc函數(shù)的代碼會(huì)被連結(jié)到程序里。為了截獲住對(duì)這類函數(shù)的調(diào)用,BoundsChecker會(huì)動(dòng)態(tài)修改這些函數(shù)的指令。

  以下兩段匯編代碼,一段沒有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:?}

  當(dāng)BoundsChecker介入后,函數(shù)malloc的前三條匯編指令被替換成一條jmp指令,原來的三條指令被搬到地址01F41EC8處了。當(dāng)程序進(jìn)入malloc后先jmp到01F41EC8,執(zhí)行原來的三條指令,然后就是BoundsChecker的天下了。大致上它會(huì)先記錄函數(shù)的返回地址(函數(shù)的返回地址在stack上,所以很容易修改),然后把返回地址指向?qū)儆贐oundsChecker的代碼,接著跳到malloc函數(shù)原來的指令,也就是在00403c15的地方。當(dāng)malloc函數(shù)結(jié)束的時(shí)候,由于返回地址被修改,它會(huì)返回到BoundsChecker的代碼中,此時(shí)BoundsChecker會(huì)記錄由malloc分配的內(nèi)存的指針,然后再跳轉(zhuǎn)到到原來的返回地址去。

  如果內(nèi)存分配/釋放函數(shù)在DLL中,BoundsChecker則采用另一種方法來截獲對(duì)這些函數(shù)的調(diào)用。BoundsChecker通過修改程序的DLL Import Table讓table中的函數(shù)地址指向自己的地址,以達(dá)到截獲的目的。

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

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();
 …
}
當(dāng)調(diào)用ShowYItemMenu()時(shí),我們故意造成HMENU的泄漏。但是,對(duì)于BoundsChecker來說被泄漏的HMENU是在class CMenu::CreatePopupMenu()中分配的。假設(shè)的你的程序有許多地方使用了CMenu的CreatePopupMenu()函數(shù),如CMenu::CreatePopupMenu()造成的,你依然無法確認(rèn)問題的根結(jié)到底在哪里,在ShowXItemMenu()中還是在ShowYItemMenu()中,或者還有其它的地方也使用了CreatePopupMenu()?有了Call Stack的信息,問題就容易了。BoundsChecker會(huì)如下報(bào)告泄漏的HMENU的信息:
Function
File
Line

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

ShowYItemMenu
E:\testmemleak\mytest.cpp
100
  
這里省略了其他的函數(shù)調(diào)用

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

  記錄Call Stack信息會(huì)使程序的運(yùn)行變得非常慢,因此默認(rèn)情況下BoundsChecker不會(huì)記錄Call Stack信息。可以按照以下的步驟打開記錄Call Stack信息的選項(xiàng)開關(guān):

  1. 打開菜單:BoundsChecker|Setting…

  2. 在Error Detection頁(yè)中,在Error Detection Scheme的List中選擇Custom

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

  4. 鉤上Report Call Stack復(fù)選框

  5. 點(diǎn)擊Ok

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

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

  使用Performance Monitor檢測(cè)內(nèi)存泄漏

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

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

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

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

  總結(jié)

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


posted @ 2006-10-19 13:45 泡泡牛 閱讀(9189) | 評(píng)論 (2)編輯 收藏
C語(yǔ)言中可變參數(shù)的用法

我們?cè)贑語(yǔ)言編程中會(huì)遇到一些參數(shù)個(gè)數(shù)可變的函數(shù),例如printf()這個(gè)函數(shù),這里將介紹可變函數(shù)的寫法以及原理.

* 1. 可變參數(shù)的宏

一般在調(diào)試打印Debug 信息的時(shí)候, 需要可變參數(shù)的宏. 從C99開始可以使編譯器標(biāo)準(zhǔn)支持可變參數(shù)宏(variadic macros), 另外GCC 也支持可變參數(shù)宏, 但是兩種在細(xì)節(jié)上可能存在區(qū)別.

1. __VA_ARGS__

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

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

2. GCC 的復(fù)雜宏

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

這和上面舉的那個(gè)定義的宏例子是完全一樣的,但是這么寫可讀性更強(qiáng)并且更容易進(jìn)行描述。

3. ##__VA_ARGS__

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

#define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
這里,如果可變參數(shù)被忽略或?yàn)榭眨?#’操作將使預(yù)處理器(preprocessor)去除掉它前面的那個(gè)逗號(hào)。如果你在宏調(diào)用時(shí),確實(shí)提供了一些可變參數(shù),GNU CPP也會(huì)工作正常,它會(huì)把這些可變參數(shù)放到逗號(hào)的后面。

4. 其他方法

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


* 2. 可變參數(shù)的函數(shù)

寫可變參數(shù)的C函數(shù)要在程序中用到以下這些宏:
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(可變參數(shù))的意思,這些宏定義在stdarg.h中.下面我們寫一個(gè)簡(jiǎn)單的可變參數(shù)的函數(shù),該函數(shù)至少有一個(gè)整數(shù)參數(shù),第二個(gè)參數(shù)也是整數(shù),是可選的.函數(shù)只是打印這兩個(gè)參數(shù)的值.
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;
}

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

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

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

我們看到第一種調(diào)用有錯(cuò)誤,第二種調(diào)用正確,第三種調(diào)用盡管結(jié)果正確,但和我們函數(shù)最初的設(shè)計(jì)有沖突.下面一節(jié)我們探討出現(xiàn)這些結(jié)果的原因和可變參數(shù)在編譯器中是如何處理的.
* 3. 可變參數(shù)函數(shù)原理

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

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)主要是為了內(nèi)存對(duì)齊,C語(yǔ)言的函數(shù)是從右向左壓入堆棧的(設(shè)數(shù)據(jù)進(jìn)棧方向?yàn)閺母叩刂废虻偷刂钒l(fā)展,即首先壓入的數(shù)據(jù)在高地址). 下圖是函數(shù)的參數(shù)在堆棧中的分布位置:

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

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

在不同的操作系統(tǒng)和硬件平臺(tái)的定義有些不同,但原理卻是相似的.


* 4. 小結(jié)

對(duì)于可變參數(shù)的函數(shù),因?yàn)関a_start, va_arg, va_end等定義成宏,所以它顯得很愚蠢,可變參數(shù)的類型和個(gè)數(shù)需要在該函數(shù)中由程序代碼控制;另外,編譯器對(duì)可變參數(shù)的函數(shù)的原型檢查不夠嚴(yán)格,對(duì)編程查錯(cuò)不利.
所以我們寫一個(gè)可變函數(shù)的C函數(shù)時(shí),有利也有弊,所以在不必要的場(chǎng)合,無需用到可變參數(shù).如果在C++里,我們應(yīng)該利用C++的多態(tài)性來實(shí)現(xiàn)可變參數(shù)的功能,盡量避免用C語(yǔ)言的方式來實(shí)現(xiàn).


* 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... 實(shí)現(xiàn)
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 泡泡牛 閱讀(3731) | 評(píng)論 (1)編輯 收藏
僅列出標(biāo)題
共5頁(yè): 1 2 3 4 5 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲国产高清自拍| 久久精品一区二区三区四区| 国内成人在线| 欧美午夜一区二区| 免费在线成人av| 久久激情一区| 亚洲天堂av在线免费| 亚洲国产欧美在线| 毛片精品免费在线观看| 欧美在线一级视频| 亚洲一区日韩在线| 99热免费精品| 亚洲欧洲日夜超级视频| 伊人久久大香线| 韩国一区二区在线观看| 国产精品综合| 国产精品乱码妇女bbbb| 欧美日韩国产综合视频在线观看| 久久先锋影音| 久久久久久久久岛国免费| 欧美一区二区三区免费视频| 午夜一区二区三视频在线观看| 一区二区三区日韩精品| 99精品久久久| 99re6热只有精品免费观看| 亚洲经典一区| 亚洲欧洲日本在线| 亚洲人体1000| 亚洲精品资源美女情侣酒店| 亚洲精品乱码久久久久久| 亚洲国产精品专区久久| 亚洲福利视频网| 亚洲国产精品免费| 91久久在线观看| 亚洲久久一区| 亚洲视频axxx| 亚洲一区二区三区在线视频| 亚洲综合丁香| 欧美一级视频精品观看| 欧美一区2区三区4区公司二百| 欧美一区二区三区免费视频| 久久激五月天综合精品| 久久夜色精品国产| 免费在线日韩av| 欧美日韩播放| 国产精品毛片a∨一区二区三区|国| 国产精品美女午夜av| 国产视频精品网| 精品盗摄一区二区三区| 亚洲精品国产精品乱码不99按摩| 一本色道久久综合亚洲91 | 亚洲视频综合| 性欧美精品高清| 久久午夜电影网| 亚洲高清在线视频| 中文在线不卡| 久久久精品免费视频| 欧美福利一区二区| 国产精品久久久久久亚洲调教| 国产亚洲欧美一区二区三区| 亚洲国产你懂的| 亚洲视频免费看| 久久久久青草大香线综合精品| 欧美激情1区2区3区| 亚洲美女中文字幕| 久久精品免视看| 欧美激情精品久久久久久大尺度 | 国产日韩精品入口| 在线观看91精品国产入口| aa日韩免费精品视频一| 久久精品国产精品| 亚洲福利专区| 午夜精品福利一区二区蜜股av| 久久久噜噜噜久久久| 欧美午夜电影完整版| 狠狠操狠狠色综合网| 亚洲色图综合久久| 久久久午夜精品| 99热精品在线| 久久亚洲精品一区| 国产精品高潮呻吟| 91久久国产自产拍夜夜嗨| 午夜精品偷拍| 亚洲区免费影片| 久久精品国产免费观看| 欧美日韩亚洲一区三区| 在线欧美日韩| 久久福利毛片| 宅男精品视频| 欧美精品一区二区三区久久久竹菊| 国产日韩欧美三区| 亚洲一级片在线看| 亚洲激情网站免费观看| 久久国产天堂福利天堂| 国产精品美女999| 一本色道久久综合亚洲精品婷婷| 久热综合在线亚洲精品| 亚洲女同在线| 欧美三级视频在线观看| 亚洲欧洲日产国产网站| 久久五月天婷婷| 亚洲欧美综合精品久久成人| 欧美日韩一二三四五区| 日韩视频在线一区二区| 女生裸体视频一区二区三区| 午夜久久黄色| 国产精品视频免费观看| 一区二区三区久久网| 亚洲国产日日夜夜| 老司机精品视频网站| 一区二区三区在线免费播放| 久久久久国产精品午夜一区| 亚洲一区三区电影在线观看| 欧美日韩综合视频| 一卡二卡3卡四卡高清精品视频| 欧美不卡视频一区| 久久综合免费视频影院| 黄色在线一区| 蜜臀av性久久久久蜜臀aⅴ| 久久成人精品| 激情成人av| 毛片基地黄久久久久久天堂| 久久精品国产精品亚洲综合| 国产日韩欧美在线| 久久av一区| 欧美制服丝袜第一页| 韩国在线一区| 美女精品国产| 欧美freesex8一10精品| 亚洲人体大胆视频| 亚洲日本电影在线| 欧美日本不卡| 亚洲专区在线| 午夜欧美视频| 精品福利免费观看| 久久婷婷激情| 免费不卡在线观看| 亚洲理论电影网| 一本一道久久综合狠狠老精东影业| 欧美日韩一区二区三区高清| 亚洲男人天堂2024| 午夜激情亚洲| 在线播放视频一区| 亚洲国产精品久久人人爱蜜臀 | 亚洲婷婷免费| 国产日韩欧美精品| 免费的成人av| 欧美国产日韩一区二区三区| 亚洲一区二区三区色| 亚洲欧美日韩中文播放| 激情婷婷欧美| 亚洲国产婷婷| 国产精品v欧美精品v日本精品动漫| 欧美一区二区在线观看| 久久久久高清| 99精品国产在热久久下载| 亚洲天天影视| 尤物精品在线| 99爱精品视频| 国产一区二区三区在线免费观看| 女生裸体视频一区二区三区| 欧美日产国产成人免费图片| 欧美在线free| 奶水喷射视频一区| 午夜免费久久久久| 两个人的视频www国产精品| 中文在线一区| 久久精品盗摄| 亚洲图片欧美一区| 久久久久国产免费免费| 在线一区二区三区做爰视频网站| 午夜久久电影网| 99综合在线| 久久精品99国产精品| 在线午夜精品| 久久久久一区二区三区| 亚洲午夜激情网站| 久久亚洲一区| 欧美一区1区三区3区公司| 欧美国产一区二区在线观看 | 黄色成人在线观看| 亚洲精选视频免费看| 黑人一区二区三区四区五区| 99视频精品全国免费| 在线日本成人| 亚洲欧美日韩精品久久亚洲区| 亚洲人成在线播放| 久久成人国产| 午夜精品视频在线观看一区二区| 欧美国产三级| 蜜桃av综合| 国产区欧美区日韩区| 一本大道久久精品懂色aⅴ| 亚洲国产精品嫩草影院| 欧美在线观看视频| 亚洲欧美国产日韩天堂区| 欧美激情久久久久| 欧美1区2区视频| 国内久久精品视频| 香蕉久久a毛片|