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

Dict.CN 在線詞典, 英語學習, 在線翻譯

學海苦作舟,書山勤為徑

留下點回憶

常用鏈接

統(tǒng)計

積分與排名

Denoise

English study

Web技術

數(shù)據(jù)壓縮

一些連接

最新評論

第四部分:枚舉FORMATETC(OLE drag&drop之旅)

本章注重于實現(xiàn)一個暴露IEnumFORMATETC接口的COM對象,這里有兩部分代碼可以下載。第一包含一個完整的通用的IEnumFORMATETC實現(xiàn),你可以將它用到你的程序中。另一部分代碼是一個叫做IDataObject Viewer的所有代碼。這是PlatformSDK同名程序的替代品,它是一個怎么樣使用IEnumFORMATETC接口的基本介紹,而不是寫這個接口。更重要的是,它在調(diào)式OLE拖放代碼是非常有用,你可以拖動任何格式的IDataObject到它上面,它會顯示顯示數(shù)據(jù)包含的可用格式。

IEnumFORMATETC接口在開始拖放時經(jīng)常不會注意到,在許多情況下它是不必要的,但為了你的IDataObject可以在所有條件下保證100%工作,提供該接口的完整實現(xiàn)是必要的。

IEnumFORMATETC 方法

描述

Next

返回枚舉中的下一個FORMATETC結構體

Skip

跳過指定數(shù)量的FORMATETC structures (例如,不返回他們).

Reset

返回枚舉的開始狀態(tài)

Clone

返回與當前結構相同的IEnumFORMATETC 接口, 并且有相同的低層狀態(tài)

下圖應該可以能夠幫助你描述IEnumFORMATETC接口:

dragdrop07.gif


枚舉包含3項,枚舉索引初始化在第一項(索引是0)。

1.         Next方法在索引0時返回第一個FORMATETC結構,并且枚舉指針指向索引1

2.         Skip方法以參數(shù)2來調(diào)用,跳過兩個位置,到達枚舉的尾部(索引3)。

3.         Reset方法返回到索引的開始(索引0)。

IEnumFORMATETC實際上非常簡單,僅僅需要實現(xiàn)四個方法:

class CEnumFormatEtc : public IEnumFORMATETC
{
public:
    //
    // IUnknown members
    //
    HRESULT __stdcall  QueryInterface (REFIID iid, void ** ppvObject);
    ULONG   __stdcall  AddRef (void);
    ULONG   __stdcall  Release (void);
    //
    // IEnumFormatEtc members
    //
    HRESULT __stdcall  Next  (ULONG celt, FORMATETC * rgelt, ULONG * pceltFetched);
    HRESULT __stdcall  Skip  (ULONG celt); 
    HRESULT __stdcall  Reset (void);
    HRESULT __stdcall  Clone (IEnumFORMATETC ** ppEnumFormatEtc);
 
    //
    // Construction / Destruction
    //
    CEnumFormatEtc(FORMATETC *pFormatEtc, int nNumFormats);
    ~CEnumFormatEtc();
 
private:
 
    LONG        m_lRefCount;        // Reference count for this COM interface
    ULONG       m_nIndex;           // current enumerator index
    ULONG       m_nNumFormats;      // number of FORMATETC members
    FORMATETC * m_pFormatEtc;       // array of FORMATETC objects
};

構造一個IEnumFORMATETC對象

IEnumFORMATETC最復雜的事情是創(chuàng)建對象,在這時候?qū)崿F(xiàn)COM方法真的非常簡單,好了,創(chuàng)建一個對象是非茶館內(nèi)容易的,因為我所需要的就是使用C++操作符new來做這件事情:

IEnumFORMATETC *pEnumFormatEtc = new CEnumFormatEtc (fmtetc, numfmts);
CEnumFormatEtc::CFormatEtc (FORMATETC *pFormatEtc, int nNumFormats)
{
    m_lRefCount   = 1;
    m_nIndex      = 0;
    m_nNumFormats = nNumFormats;
    m_pFormatEtc  = new FORMATETC[nNumFormats];
    // make a new copy of each FORMATETC structure
    for(int i = 0; i < nNumFormats; i++)
    {
        DeepCopyFormatEtc (&m_pFormatEtc[i], &pFormatEtc[i]);
    }
}

我們來看以下這個C++構造函數(shù)做了什么,它有兩個參數(shù):一個指向FORMATETC結構的數(shù)組,另外一個是表示數(shù)組中有多少元素的整數(shù)。

第一行初始化對象引用記數(shù),這是所有COM對象的標準,我們應該非常熟悉它,因此我這里不在做更多的介紹。

下一步就是初始化枚舉狀態(tài),成員變量m_nIndex表示枚舉中的當前位置,因此它以0開始是很自然的,同樣,m_nNumFormats變量用來表示枚舉的結尾,有了這兩個變量,我們可以跟蹤枚舉當前的位置和結束位置。

最重要的一步是分配參數(shù)中的FORMATETC結構體的一個新數(shù)組副本。一個數(shù)據(jù)被分配(m_pFormatEtc)其保存所有要被枚舉的結構體,每個枚舉需要有自己的私有FORMATETC結構的緩存,關鍵細節(jié)是復制FORMATETC結構的方法,這里,我們引入一個叫DeepCopyFormatEtc新的函數(shù)。

void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source)
{
    // copy the source FORMATETC into dest
    *dest = *source;
        
    if(source->ptd)
    {
        // allocate memory for the DVTARGETDEVICE if necessary
        dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
 
        // copy the contents of the source DVTARGETDEVICE into dest->ptd
        *(dest->ptd) = *(source->ptd);
    }
}

函數(shù)的第一行非常簡單:

*dest = *source;

這個實際上是一個標準的C函數(shù)memcpy。實際上,這幾乎在所有的情況都是需要的,因為他能正確的執(zhí)行一個二進制的結構體到結構體的復制,問題是當源FORMATETC::ptd成員的已經(jīng)被初始化為指向一個DVTAGETDEVIDE結構,就不能正確復制了。

僅僅在FORMATETC上執(zhí)行memcpy是不夠的,因為兩個FORMATETC結構體都指向原來的DVTARGETDEVICE;因此我們私有的結構體復制函數(shù)是需要的。

IEnumFORMATETC::Next文檔聲明調(diào)用這使用CoTaskMemFree這個API來釋放DVTARGETDEVICE結構體,邏輯上意味著這個結構必須首先已經(jīng)使用CoTaskMemAlloc來分配了棵,因此這就是深度復制所做的,使用CoTaskMemAlloc來分配一個新的DVTARGETDEVICE結構體,并且設置dest->ptd指向原來的,那么source->DVTARGETDEVICE結構體就被復制到新的指針上了。

清理一個IEnumFORMATETC對象

CEnumFormatEtc類的C++析構函數(shù)必須清理所有在構造函數(shù)分配的內(nèi)存:

CEnumFormatEtc::~CEnumFormatEtc()
{
    // first free any DVTARGETDEVICE structures
    for(ULONG i = 0; i < m_nNumFormats; i++)
    {
        if(m_pFormatEtc[i].ptd)
            CoTaskMemFree(m_pFormatEtc[i].ptd);
    }
    // now free the main array
    delete[] m_pFormatEtc;
}

這是一個簡單的任務,調(diào)用CoTaskMemFree來釋放所有在構造函數(shù)中分配的DVTAGETDEVICE結構體,一旦這些已經(jīng)釋放完了,m_pFormatEtc數(shù)組也應該被釋放。

取代SHCreateStdEnumFmtEtc

你可能會問,在該指南中,我們?yōu)槭裁磿恢边@么煩心來,因為SHCreateStdEnumFmtEtc API調(diào)用可以用來創(chuàng)建IEnumFORMATETC接口,但不幸的是,它只能在WINDOS2000以上的版本使用,看原型:

HRESULT SHCreateStdEnumFmtEtc(UINT cfmt, const FORMATETC afmt[], IEnumFORMATETC **ppenumFormatEtc);

因此如果你不準備向下兼容老的版本Windows的拖放操作,否則我們總是需要實現(xiàn)IEnumFORMATETC。我們需要做的就是寫一個SHCreateStdEnumFmtEtcdrop-in替代版本,我們可以在僅僅支持windows2000的時候很容易切換,我們的版本是這樣的:

HRESULT CreateEnumFormatEtc (UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc)
{
    if (cfmt == 0 || afmt == 0 || ppEnumFormatEtc == 0)
        return E_INVALIDARG;
    *ppEnumFormatEtc = new CEnumFormatEtc (afmt, cfmt);
    return (*ppEnumFormatEtc) ? S_OK: E_OUTOFMEMORY;
}

函數(shù)非常簡單,因為所有的工作都在CEnumFormatEtc構造函數(shù)中調(diào)用,我們需要做的就是創(chuàng)建一個類的實例,然后以最后一個參數(shù)返回;其余的代碼是錯誤檢查。

使用API是也很簡單:

FORMATETC fmtetc = {CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
IEnumFORMATETC *pEnumFormatEtc; 
CreateEnumFormatEtc (1, &fmtetc, &pEnumFormatEtc);

這似乎是枚舉一些簡單FORMATETC結構的許多工作,但這是值得的,因為我們的COM枚舉器現(xiàn)在真正的獨立了,剩下的接口就非常簡單了。

IEnumFORMATETC::Reset

這個成員非常簡單,設置枚舉到開始的位置:

HRESULT CEnumFormatEtc::Reset (void)
{
    m_nIndex = 0;
    return S_OK;
}

上面的實現(xiàn)可以自解釋。

IEnumFORMATETC::Skip

該實現(xiàn)直接向前移動,簡直不需要解釋:

HRESULT IEnumFORMATETC::Skip (ULONG celt)
{
    m_nIndex += celt;
    return (m_nIndex <= m_nNumFormats) ? S_OK : S_FALSE;
}

該函數(shù)僅僅向前移動枚舉指定單元。注意,盡管這里沒有保證索引在枚舉范圍內(nèi),但一個返回值用來指示是否前進的太多。

IEnumFORMATETC::Clone

Clone函數(shù)起先看起來優(yōu)點神秘;盡管我很少看到這個函數(shù)調(diào)用,它實際上很容易實現(xiàn):

HRESULT IEnumFORMATETC::Clone(IEnumFORMATETC **ppEnumFormatEtc)
{
    HRESULT hResult;
    // make a duplicate enumerator
    hResult = CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc, ppEnumFormatEtc);
    if(hResult == S_OK)
    {
        // manually set the index state
        ((CEnumFormatEtc *)*ppEnumFormatEtc)->m_nIndex = m_nIndex;
    }
    return hResult;
}

上面代碼很簡單地創(chuàng)建了一個IEnumFORMATETC接口的實例,使用我們前面寫的CreateEnumFormatEtc函數(shù);使用當前的枚舉內(nèi)部狀態(tài),因此結果就是復制接口的當前內(nèi)部狀態(tài)。

if從句中的轉(zhuǎn)型看起來有點復雜,其用來保留枚舉的索引位置,轉(zhuǎn)型是必須的,因為IEnumFORMATETC接口并可以訪問內(nèi)部變量,然而,我們知道ppEnumFormatEtc實際上就是一個CEnumFormatEtc,所以這個轉(zhuǎn)換能安全的執(zhí)行。轉(zhuǎn)換操作看起來復雜的原因是我們必須引用ppEnumFormatEtc參數(shù)來訪問指向IEnumFORMATETC的指針。

IEnumFORMATETC::Next

Next成員函數(shù)比其他的稍微棘手一點:

HRESULT CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched)
{
    ULONG copied = 0;
    // copy the FORMATETC structures into the caller's buffer
    while (m_nIndex < m_nNumFormats && copied < celt) 
    {
        DeepCopyFormatEtc (&pFormatEtc [copied], &m_pFormatEtc [m_nIndex]);
        copied++;
        m_nIndex++;
    }
    // store result
    if(pceltFetched != 0) 
        *pceltFetched = copied;
    // did we copy all that was requested?
    return (copied == celt) ? S_OK : S_FALSE;
}

這個函數(shù)看起來有點復雜,但可以被分解成三個重要的操作;主要的部分是while循環(huán)部分,它負責復制FORMATETC結構(使用深度復制程序),循環(huán)僅僅復制范圍內(nèi)的元素到提供的緩沖區(qū)中。

第二部分是返回實際復制的相數(shù),且返回一個錯誤值來指示是否所有需要復制的元素都被復制了。

最后一部分就是錯誤代碼來指示復制指定數(shù)量的項數(shù)的操作成功和失敗。

posted on 2006-03-03 10:12 笨笨 閱讀(4690) 評論(4)  編輯 收藏 引用 所屬分類: OLE Drag&Drop

評論

# re: 第四部分:枚舉FORMATETC(OLE drag&drop之旅) 2006-03-04 13:04

very good
樓主的文章很有功力  回復  更多評論   

# re: 第四部分:枚舉FORMATETC(OLE drag&drop之旅) 2006-03-04 22:50 笨笨

謝謝,但我必須說清楚,這是翻譯的文章  回復  更多評論   

# re: 第四部分:枚舉FORMATETC(OLE drag&drop之旅) 2006-06-09 16:25 QQ8080761

太厲害了,找了半天的資料,看英文都看疼了,總算找到一篇好的,多謝多謝  回復  更多評論   

# re: 第四部分:枚舉FORMATETC(OLE drag&drop之旅) 2008-04-29 16:51 紅馬天下

不錯!  回復  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            免费成人高清在线视频| 久久精品最新地址| 牛牛影视久久网| 一个人看的www久久| 一区二区三区蜜桃网| 国产欧美一区二区精品秋霞影院| 久久一二三国产| 欧美日韩免费一区二区三区| 久久精品免费看| 欧美日韩另类一区| 久久综合九色| 国产精品日韩在线播放| 蜜臀av在线播放一区二区三区| 欧美日韩免费观看一区| 欧美成年人视频网站| 国产精品xxx在线观看www| 欧美激情一区| 黄色成人小视频| 亚洲最新合集| 亚洲精选久久| 久久亚洲综合网| 欧美一区国产在线| 欧美国产精品中文字幕| 麻豆成人小视频| 国产亚洲欧美日韩一区二区| 一区二区三区高清| 日韩一级网站| 蜜桃av久久久亚洲精品| 久久精品一区二区国产| 国产精品久久久久久久久久妞妞| 亚洲福利精品| 国内外成人免费视频| 亚洲午夜精品久久久久久浪潮 | 久久久精品999| 国产精品美女在线| aa亚洲婷婷| 亚洲午夜精品久久| 欧美人交a欧美精品| 亚洲国产成人91精品| 韩国精品一区二区三区| 在线观看成人网| 欧美一区二区啪啪| 欧美一区二区精品| 国产日本欧美一区二区三区在线| 日韩视频在线免费| 日韩视频在线一区二区| 欧美ed2k| 亚洲激情视频网| 亚洲精品国产品国语在线app| 久久久久久综合网天天| 欧美成人乱码一区二区三区| 在线精品国精品国产尤物884a| 午夜一区二区三视频在线观看| 欧美一区午夜精品| 国产亚洲福利| 久久久久久久高潮| 欧美国产日韩一区二区三区| 亚洲片国产一区一级在线观看| 美女日韩在线中文字幕| 亚洲国产精品一区二区三区| 99国产精品久久久| 欧美视频一区二区三区…| 一本色道久久综合亚洲精品按摩 | 久久免费视频网站| 欧美国产日韩一区二区| 99re66热这里只有精品3直播| 欧美日韩蜜桃| 欧美一级欧美一级在线播放| 美女视频黄免费的久久| 日韩视频在线一区| 国产精品免费电影| 久久国产婷婷国产香蕉| 亚洲成人直播| 亚洲自拍三区| 精品成人久久| 欧美激情精品久久久| 亚洲精品中文字幕女同| 欧美在现视频| 亚洲日本一区二区| 亚洲欧美国产视频| 国内成人自拍视频| 欧美精品九九99久久| 亚洲一区二区三区影院| 久久综合激情| 亚洲综合日本| 亚洲国产高清高潮精品美女| 欧美啪啪成人vr| 午夜精品久久| 亚洲国产另类久久精品| 亚洲欧美区自拍先锋| 精品成人在线视频| 欧美日韩在线播放一区| 久久久www免费人成黑人精品| 亚洲精选中文字幕| 久久男女视频| 亚洲手机在线| 在线观看欧美日韩国产| 欧美日韩亚洲另类| 老牛影视一区二区三区| 一本一道久久综合狠狠老精东影业| 欧美中文字幕视频在线观看| 91久久久国产精品| 国产一区二区无遮挡| 欧美激情亚洲一区| 久久婷婷久久| 夜夜嗨av一区二区三区中文字幕| 久久久欧美一区二区| 亚洲一区二区免费| 亚洲国产影院| 国产曰批免费观看久久久| 裸体一区二区| 免费短视频成人日韩| 亚洲国产成人精品久久| 国产精品视频免费一区| 欧美日韩国产综合新一区| 久久三级福利| 久久精品国产一区二区三区免费看| 99re8这里有精品热视频免费| 亚洲国产成人久久综合| 免费在线欧美黄色| 久久视频在线看| 久久久精品久久久久| 香蕉亚洲视频| 亚洲小少妇裸体bbw| 亚洲精品一区中文| 亚洲国产精品悠悠久久琪琪| 韩国av一区二区| 国产日韩精品入口| 国产精品入口| 国产精品毛片| 国产精品mm| 欧美日韩在线视频一区| 欧美日韩亚洲网| 欧美成人精品1314www| 美女精品一区| 六十路精品视频| 欧美a级片网站| 免费在线一区二区| 欧美v日韩v国产v| 女同一区二区| 欧美国产日韩视频| 久久精品三级| 久久一区精品| 欧美va天堂在线| 亚洲国产一区二区三区a毛片| 欧美大片一区二区| 欧美一区二区三区视频在线观看| 亚洲淫性视频| 欧美一区二区在线免费观看| 久久精品国产亚洲一区二区三区| 欧美亚洲视频一区二区| 久久精品伊人| 欧美77777| 亚洲人永久免费| 一区二区三区四区五区在线| 亚洲午夜一二三区视频| 欧美一区二区黄| 乱人伦精品视频在线观看| 欧美肥婆bbw| 国产精品国产三级国产| 国产欧美韩国高清| 尹人成人综合网| 99国产精品视频免费观看一公开| 一片黄亚洲嫩模| 久久精品五月| 亚洲国产精品第一区二区三区 | 狠狠入ady亚洲精品经典电影| 精品成人在线| 亚洲一卡二卡三卡四卡五卡| 久久精品国产69国产精品亚洲| 米奇777在线欧美播放| 亚洲国内自拍| 欧美一区二区三区视频免费| 美女任你摸久久| 国产精品系列在线| **网站欧美大片在线观看| 亚洲视频中文| 欧美高清视频www夜色资源网| 一区二区国产精品| 一区二区三区鲁丝不卡| 久久综合九色综合久99| 欧美午夜不卡| 亚洲人屁股眼子交8| 欧美一区在线视频| 亚洲韩国日本中文字幕| 欧美一级欧美一级在线播放| 欧美国产日韩在线| 国产欧美69| 一本色道久久综合狠狠躁篇的优点| 欧美一区二区视频在线观看| 亚洲国产精品成人| 久久精品日韩欧美| 亚洲激情在线观看视频免费| 久久综合久久美利坚合众国| 蜜月aⅴ免费一区二区三区 | 亚洲女人av| 欧美精品一区二区三区蜜桃 | 久久久久9999亚洲精品| 国产精品毛片在线| 妖精视频成人观看www|