拖拽的實現(com 基於windos sdk)



轉載於http://www.cnblogs.com/chunyou128/archive/2012/02/20/2360607.html

1.參考內容:

英文資料

中文翻譯


2.拖動涉及:源、目標、數據對象

2.1 鼠標左鍵按下並且移動,觸發拖動。

      構建源和數據對象。調用拖放函數DoDragDrop。

case WM_MOUSEMOVE:
 
    // if the mouse is held down then start a drag-drop
    if(fMouseDown)
    {
        IDataObject *pDataObject;
        IDropSource *pDropSource;
        DWORD        dwEffect;
        DWORD        dwResult;
 
        FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
        STGMEDIUM stgmed = { TYMED_HGLOBAL, { 0 }, 0 };
 
        // transfer the current selection into the IDataObject
        stgmed.hGlobal = CopySelection(hwndEdit);
 
        // Create IDataObject and IDropSource COM objects
        CreateDropSource(&pDropSource);
        CreateDataObject(&fmtetc, &stgmed, 1, &pDataObject);
 
        //
        //  ** ** ** The drag-drop operation starts here! ** ** **
        //
        dwResult = DoDragDrop(pDataObject, pDropSource, DROPEFFECT_COPY|DROPEFFECT_MOVE, &dwEffect);
 
        // success!
        if(dwResult == DRAGDROP_S_DROP)
        {
            if(dwEffect & DROPEFFECT_MOVE)
            {
                // remove selection from edit control
            }
        }
        // cancelled
        else if(dwResult == DRAGDROP_S_CANCEL)
        {
        }
 
        pDataObject->Release();
        pDropSource->Release();
 
        ReleaseCapture();
        fMouseDown = FALSE;
        fDidDragDrop = TRUE;
    }

 2.拖放的目標程序,需要調用RegisterDragDrop,爲拖放註冊。

void RegisterDropWindow(HWND hwnd, IDropTarget **ppDropTarget)
{
    CDropTarget *pDropTarget = new CDropTarget(hwnd);
 
    // acquire a strong lock
    CoLockObjectExternal(pDropTarget, TRUE, FALSE);
 
    // tell OLE that the window is a drop target
    RegisterDragDrop(hwnd, pDropTarget);
 
    *ppDropTarget = pDropTarget;
}
 
case WM_CREATE:
 
        hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "",
            WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_WANTRETURN|WS_VSCROLL,
            0,0,0,0, hwnd, 0, hInstance, 0);
 
        SendMessage(hwndEdit, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), 0);
 
        // make the Edit control into a DropTarget
        RegisterDropWindow(hwndEdit, &pDropTarget);


注意:如果你的程序是直接繼承自IDropTarget,CoLockObjectExternal(this, TRUE, FALSE);這麼寫的話,緊接着的下面一句(RegisterDropWindow(hwndEdit, &pDropTarget);)可能就不會執行。換句話說,拖放可能會失敗。

3.所有的一切,都由DoDragDrop發軔。這個函數,會調用一些虛函數。如:CDataObject::EnumFormatEtc

4.CDropTarget::Drop中響應事件操作。

注意:   初始化 、反初始化

OleInitialize(0);

OleUninitialize();
源文件

dropsource.h

//
//  DROPSOURCE.H
//
//  Implementation of the IDropSource COM interface
//
//  By J Brown 2004
//
//  www.catch22.net
//
 
 
#include <windows.h>
 
HANDLE StringToHandle(char *szText, int nTextLen);
HRESULT CreateDropSource(IDropSource **ppDropSource);
 
class CDropSource : public IDropSource
{
public:
    //
    // IUnknown members
    //
    HRESULT __stdcall QueryInterface    (REFIID iid, void ** ppvObject);
    ULONG   __stdcall AddRef            (void);
    ULONG   __stdcall Release           (void);
 
    //
    // IDropSource members
    //
    HRESULT __stdcall QueryContinueDrag (BOOL fEscapePressed, DWORD grfKeyState);
    HRESULT __stdcall GiveFeedback      (DWORD dwEffect);
 
    //
    // Constructor / Destructor
    //
    CDropSource();
    ~CDropSource();
 
private:
 
    //
    // private members and functions
    //
    LONG       m_lRefCount;
};


 dropsource.cpp


//
//  DROPSOURCE.CPP
//
//  Implementation of the IDropSource COM interface
//
//  By J Brown 2004
//
//  www.catch22.net
//
 
#include "../stdafx.h"
#include "dropsource.h"
 
HANDLE StringToHandle(char *szText, int nTextLen)
{
    void  *ptr;
 
    // if text length is -1 then treat as a nul-terminated string
    if(nTextLen == -1)
        nTextLen = lstrlen(szText) + 1;
 
    // allocate and lock a global memory buffer. Make it fixed
    // data so we don't have to use GlobalLock
    ptr = (void *)GlobalAlloc(GMEM_FIXED, nTextLen);
 
    // copy the string into the buffer
    memcpy(ptr, szText, nTextLen);
 
    return ptr;
}
 
//
//  Constructor
//
CDropSource::CDropSource()
{
    m_lRefCount = 1;
}
 
//
//  Destructor
//
CDropSource::~CDropSource()
{
}
 
//
//  IUnknown::AddRef
//
ULONG __stdcall CDropSource::AddRef(void)
{
    // increment object reference count
    return InterlockedIncrement(&m_lRefCount);
}
 
//
//  IUnknown::Release
//
ULONG __stdcall CDropSource::Release(void)
{
    // decrement object reference count
    LONG count = InterlockedDecrement(&m_lRefCount);
         
    if(count == 0)
    {
        delete this;
        return 0;
    }
    else
    {
        return count;
    }
}
 
//
//  IUnknown::QueryInterface
//
HRESULT __stdcall CDropSource::QueryInterface(REFIID iid, void **ppvObject)
{
    // check to see what interface has been requested
    if(iid == IID_IDropSource || iid == IID_IUnknown)
    {
        AddRef();
        *ppvObject = this;
        return S_OK;
    }
    else
    {
        *ppvObject = 0;
        return E_NOINTERFACE;
    }
}
 
//
//  CDropSource::QueryContinueDrag
//
//  Called by OLE whenever Escape/Control/Shift/Mouse buttons have changed
//
HRESULT __stdcall CDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{
    // if the <Escape> key has been pressed since the last call, cancel the drop
    if(fEscapePressed == TRUE)
        return DRAGDROP_S_CANCEL;  
 
    // if the <LeftMouse> button has been released, then do the drop!
    if((grfKeyState & MK_LBUTTON) == 0)
        return DRAGDROP_S_DROP;
 
    // continue with the drag-drop
    return S_OK;
}
 
//
//  CDropSource::GiveFeedback
//
//  Return either S_OK, or DRAGDROP_S_USEDEFAULTCURSORS to instruct OLE to use the
//  default mouse cursor images
//
HRESULT __stdcall CDropSource::GiveFeedback(DWORD dwEffect)
{
    return DRAGDROP_S_USEDEFAULTCURSORS;
}
 
//
//  Helper routine to create an IDropSource object
// 
HRESULT CreateDropSource(IDropSource **ppDropSource)
{
    if(ppDropSource == 0)
        return E_INVALIDARG;
 
    *ppDropSource = new CDropSource();
 
    return (*ppDropSource) ? S_OK : E_OUTOFMEMORY;
 
}


 droptarget.h


//
//  DROPTARGET.H
//
//  By J Brown 2004
//
//  www.catch22.net
//
 
#pragma once
#include <windows.h>
 
void DropData(HWND hwnd, IDataObject *pDataObject);
 
//
//  This is our definition of a class which implements
//  the IDropTarget interface
//
class CDropTarget : public IDropTarget
{
public:
    // IUnknown implementation
    HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject);
    ULONG   __stdcall AddRef (void);
    ULONG   __stdcall Release (void);
 
    // IDropTarget implementation
    HRESULT __stdcall DragEnter (IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
    HRESULT __stdcall DragOver (DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
    HRESULT __stdcall DragLeave (void);
    HRESULT __stdcall Drop (IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
 
    virtual void DropData(HWND hwnd, IDataObject *pDataObject) = 0;
    virtual const HWND GetWnd() = 0;
 
    // Constructor
    CDropTarget(/*HWND hwnd*/);
    ~CDropTarget();
 
private:
 
    // internal helper function
    DWORD DropEffect(DWORD grfKeyState, POINTL pt, DWORD dwAllowed);
    bool  QueryDataObject(IDataObject *pDataObject);
 
 
    // Private member variables
    LONG    m_lRefCount;
    bool    m_fAllowDrop;
 
    IDataObject *m_pDataObject;
 
};


droptarget.cpp


//
//  DROPTARGET.CPP
//
//  By J Brown 2004
//
//  www.catch22.net
//
 
#include "../stdafx.h"
#include "droptarget.h"
 
//
//  Constructor for the CDropTarget class
//
CDropTarget::CDropTarget(/*HWND hwnd*/)
{
    m_lRefCount  = 1;
    m_fAllowDrop = false;
}
 
//
//  Destructor for the CDropTarget class
//
CDropTarget::~CDropTarget()
{
     
}
 
//
//  Position the edit control's caret under the mouse
//
void PositionCursor(HWND hwndEdit, POINTL pt)
{
    DWORD curpos;
         
    // get the character position of mouse
    ScreenToClient(hwndEdit, (POINT *)&pt);
    curpos = SendMessage(hwndEdit, EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y));
 
    // set cursor position
    SendMessage(hwndEdit, EM_SETSEL, LOWORD(curpos), LOWORD(curpos));
}
 
//
//  IUnknown::QueryInterface
//
HRESULT __stdcall CDropTarget::QueryInterface (REFIID iid, void ** ppvObject)
{
    if(iid == IID_IDropTarget || iid == IID_IUnknown)
    {
        AddRef();
        *ppvObject = this;
        return S_OK;
    }
    else
    {
        *ppvObject = 0;
        return E_NOINTERFACE;
    }
}
 
//
//  IUnknown::AddRef
//
ULONG __stdcall CDropTarget::AddRef(void)
{
    return InterlockedIncrement(&m_lRefCount);
}  
 
//
//  IUnknown::Release
//
ULONG __stdcall CDropTarget::Release(void)
{
    LONG count = InterlockedDecrement(&m_lRefCount);
         
    if(count == 0)
    {
        return 0;
    }
    else
    {
        return count;
    }
}
 
//
//  QueryDataObject private helper routine
//
bool CDropTarget::QueryDataObject(IDataObject *pDataObject)
{
    FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
 
    // does the data object support CF_TEXT using a HGLOBAL?
    return pDataObject->QueryGetData(&fmtetc) == S_OK ? true : false;
}
 
//
//  DropEffect private helper routine
//
DWORD CDropTarget::DropEffect(DWORD grfKeyState, POINTL pt, DWORD dwAllowed)
{
    DWORD dwEffect = 0;
 
    // 1. check "pt" -> do we allow a drop at the specified coordinates?
     
    // 2. work out that the drop-effect should be based on grfKeyState
    if(grfKeyState & MK_CONTROL)
    {
        dwEffect = dwAllowed & DROPEFFECT_COPY;
    }
    else if(grfKeyState & MK_SHIFT)
    {
        dwEffect = dwAllowed & DROPEFFECT_MOVE;
    }
     
    // 3. no key-modifiers were specified (or drop effect not allowed), so
    //    base the effect on those allowed by the dropsource
    if(dwEffect == 0)
    {
        if(dwAllowed & DROPEFFECT_COPY) dwEffect = DROPEFFECT_COPY;
        if(dwAllowed & DROPEFFECT_MOVE) dwEffect = DROPEFFECT_MOVE;
    }
     
    return dwEffect;
}
 
 
//
//  IDropTarget::DragEnter
//
//
//
HRESULT __stdcall CDropTarget::DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
{
    // does the dataobject contain data we want?
    m_fAllowDrop = QueryDataObject(pDataObject);
     
    if(m_fAllowDrop)
    {
        // get the dropeffect based on keyboard state
        *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
 
        SetFocus(GetWnd());
 
        PositionCursor(GetWnd(), pt);
    }
    else
    {
        *pdwEffect = DROPEFFECT_NONE;
    }
 
    return S_OK;
}
 
//
//  IDropTarget::DragOver
//
//
//
HRESULT __stdcall CDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
{
    if(m_fAllowDrop)
    {
        *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
        PositionCursor(GetWnd(), pt);
    }
    else
    {
        *pdwEffect = DROPEFFECT_NONE;
    }
 
    return S_OK;
}
 
//
//  IDropTarget::DragLeave
//
HRESULT __stdcall CDropTarget::DragLeave(void)
{
    return S_OK;
}
 
//
//  IDropTarget::Drop
//
//
HRESULT __stdcall CDropTarget::Drop(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
{
    PositionCursor(GetWnd(), pt);
 
    if(m_fAllowDrop)
    {
        DropData(GetWnd(), pDataObject);
 
        *pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
    }
    else
    {
        *pdwEffect = DROPEFFECT_NONE;
    }
 
    return S_OK;
}
 
void DropData(HWND hwnd, IDataObject *pDataObject)
{
    // construct a FORMATETC object
    FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
    STGMEDIUM stgmed;
 
    // See if the dataobject contains any TEXT stored as a HGLOBAL
    if(pDataObject->QueryGetData(&fmtetc) == S_OK)
    {
        // Yippie! the data is there, so go get it!
        if(pDataObject->GetData(&fmtetc, &stgmed) == S_OK)
        {
            // we asked for the data as a HGLOBAL, so access it appropriately
            PVOID data = GlobalLock(stgmed.hGlobal);
 
            SetWindowText(hwnd, (char *)data);
 
            GlobalUnlock(stgmed.hGlobal);
 
            // release the data using the COM API
            ReleaseStgMedium(&stgmed);
        }
    }
}

dataobject.h


//
//  DATAOBJECT.H
//
//  Implementation of the IDataObject COM interface
//
//  By J Brown 2004
//
//  www.catch22.net
//
 
 
#include <windows.h>
 
// defined in enumformat.cpp
HRESULT CreateEnumFormatEtc(UINT nNumFormats, FORMATETC *pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc);
HRESULT CreateDataObject (FORMATETC *fmtetc, STGMEDIUM *stgmeds, UINT count, IDataObject **ppDataObject);
 
class CDataObject : public IDataObject
{
public:
    //
    // IUnknown members
    //
    HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject);
    ULONG   __stdcall AddRef (void);
    ULONG   __stdcall Release (void);
 
    //
    // IDataObject members
    //
    HRESULT __stdcall GetData               (FORMATETC *pFormatEtc,  STGMEDIUM *pMedium);
    HRESULT __stdcall GetDataHere           (FORMATETC *pFormatEtc,  STGMEDIUM *pMedium);
    HRESULT __stdcall QueryGetData          (FORMATETC *pFormatEtc);
    HRESULT __stdcall GetCanonicalFormatEtc (FORMATETC *pFormatEct,  FORMATETC *pFormatEtcOut);
    HRESULT __stdcall SetData               (FORMATETC *pFormatEtc,  STGMEDIUM *pMedium,  BOOL fRelease);
    HRESULT __stdcall EnumFormatEtc         (DWORD      dwDirection, IEnumFORMATETC **ppEnumFormatEtc);
    HRESULT __stdcall DAdvise               (FORMATETC *pFormatEtc,  DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
    HRESULT __stdcall DUnadvise             (DWORD      dwConnection);
    HRESULT __stdcall EnumDAdvise           (IEnumSTATDATA **ppEnumAdvise);
 
    //
    // Constructor / Destructor
    //
    CDataObject(FORMATETC *fmt, STGMEDIUM *stgmed, int count);
    ~CDataObject();
 
private:
 
    int LookupFormatEtc(FORMATETC *pFormatEtc);
 
    //
    // any private members and functions
    //
    LONG       m_lRefCount;
 
    FORMATETC *m_pFormatEtc;
    STGMEDIUM *m_pStgMedium;
    LONG       m_nNumFormats;
 
};


 dataobject.cpp


//
//  DATAOBJECT.CPP
//
//  Implementation of the IDataObject COM interface
//
//  By J Brown 2004
//
//  www.catch22.net
//
 
#include "../stdafx.h"
#include "dataobject.h"
 
//
//  Constructor
//
CDataObject::CDataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count)
{
    m_lRefCount  = 1;
    m_nNumFormats = count;
     
    m_pFormatEtc  = new FORMATETC[count];
    m_pStgMedium  = new STGMEDIUM[count];
 
    for(int i = 0; i < count; i++)
    {
        m_pFormatEtc[i] = fmtetc[i];
        m_pStgMedium[i] = stgmed[i];
    }
}
 
//
//  Destructor
//
CDataObject::~CDataObject()
{
    // cleanup
    if(m_pFormatEtc) delete[] m_pFormatEtc;
    if(m_pStgMedium) delete[] m_pStgMedium;
 
    OutputDebugString("oof\n");
}
 
//
//  IUnknown::AddRef
//
ULONG __stdcall CDataObject::AddRef(void)
{
    // increment object reference count
    return InterlockedIncrement(&m_lRefCount);
}
 
//
//  IUnknown::Release
//
ULONG __stdcall CDataObject::Release(void)
{
    // decrement object reference count
    LONG count = InterlockedDecrement(&m_lRefCount);
         
    if(count == 0)
    {
        delete this;
        return 0;
    }
    else
    {
        return count;
    }
}
 
//
//  IUnknown::QueryInterface
//
HRESULT __stdcall CDataObject::QueryInterface(REFIID iid, void **ppvObject)
{
    // check to see what interface has been requested
    if(iid == IID_IDataObject || iid == IID_IUnknown)
    {
        AddRef();
        *ppvObject = this;
        return S_OK;
    }
    else
    {
        *ppvObject = 0;
        return E_NOINTERFACE;
    }
}
 
HGLOBAL DupMem(HGLOBAL hMem)
{
    // lock the source memory object
    DWORD   len    = GlobalSize(hMem);
    PVOID   source = GlobalLock(hMem);
     
    // create a fixed "global" block - i.e. just
    // a regular lump of our process heap
    PVOID   dest   = GlobalAlloc(GMEM_FIXED, len);
 
    memcpy(dest, source, len);
 
    GlobalUnlock(hMem);
 
    return dest;
}
 
int CDataObject::LookupFormatEtc(FORMATETC *pFormatEtc)
{
    for(int i = 0; i < m_nNumFormats; i++)
    {
        if((pFormatEtc->tymed    &  m_pFormatEtc[i].tymed)   &&
            pFormatEtc->cfFormat == m_pFormatEtc[i].cfFormat &&
            pFormatEtc->dwAspect == m_pFormatEtc[i].dwAspect)
        {
            return i;
        }
    }
 
    return -1;
 
}
 
//
//  IDataObject::GetData
//
HRESULT __stdcall CDataObject::GetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium)
{
    int idx;
 
    //
    // try to match the requested FORMATETC with one of our supported formats
    //
    if((idx = LookupFormatEtc(pFormatEtc)) == -1)
    {
        return DV_E_FORMATETC;
    }
 
    //
    // found a match! transfer the data into the supplied storage-medium
    //
    pMedium->tymed            = m_pFormatEtc[idx].tymed;
    pMedium->pUnkForRelease  = 0;
     
    switch(m_pFormatEtc[idx].tymed)
    {
    case TYMED_HGLOBAL:
 
        pMedium->hGlobal = DupMem(m_pStgMedium[idx].hGlobal);
        //return S_OK;
        break;
 
    default:
        return DV_E_FORMATETC;
    }
 
    return S_OK;
}
 
//
//  IDataObject::GetDataHere
//
HRESULT __stdcall CDataObject::GetDataHere (FORMATETC *pFormatEtc, STGMEDIUM *pMedium)
{
    // GetDataHere is only required for IStream and IStorage mediums
    // It is an error to call GetDataHere for things like HGLOBAL and other clipboard formats
    //
    //  OleFlushClipboard
    //
    return DATA_E_FORMATETC;
}
 
//
//  IDataObject::QueryGetData
//
//  Called to see if the IDataObject supports the specified format of data
//
HRESULT __stdcall CDataObject::QueryGetData (FORMATETC *pFormatEtc)
{
    return (LookupFormatEtc(pFormatEtc) == -1) ? DV_E_FORMATETC : S_OK;
}
 
//
//  IDataObject::GetCanonicalFormatEtc
//
HRESULT __stdcall CDataObject::GetCanonicalFormatEtc (FORMATETC *pFormatEct, FORMATETC *pFormatEtcOut)
{
    // Apparently we have to set this field to NULL even though we don't do anything else
    pFormatEtcOut->ptd = NULL;
    return E_NOTIMPL;
}
 
//
//  IDataObject::SetData
//
HRESULT __stdcall CDataObject::SetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium,  BOOL fRelease)
{
    return E_NOTIMPL;
}
 
//
//  IDataObject::EnumFormatEtc
//
HRESULT __stdcall CDataObject::EnumFormatEtc (DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
{
    if(dwDirection == DATADIR_GET)
    {
        // for Win2k+ you can use the SHCreateStdEnumFmtEtc API call, however
        // to support all Windows platforms we need to implement IEnumFormatEtc ourselves.
        return CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc, ppEnumFormatEtc);
    }
    else
    {
        // the direction specified is not support for drag+drop
        return E_NOTIMPL;
    }
}
 
//
//  IDataObject::DAdvise
//
HRESULT __stdcall CDataObject::DAdvise (FORMATETC *pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
{
    return OLE_E_ADVISENOTSUPPORTED;
}
 
//
//  IDataObject::DUnadvise
//
HRESULT __stdcall CDataObject::DUnadvise (DWORD dwConnection)
{
    return OLE_E_ADVISENOTSUPPORTED;
}
 
//
//  IDataObject::EnumDAdvise
//
HRESULT __stdcall CDataObject::EnumDAdvise (IEnumSTATDATA **ppEnumAdvise)
{
    return OLE_E_ADVISENOTSUPPORTED;
}
 
//
//  Helper function
//
HRESULT CreateDataObject (FORMATETC *fmtetc, STGMEDIUM *stgmeds, UINT count, IDataObject **ppDataObject)
{
    if(ppDataObject == 0)
        return E_INVALIDARG;
 
    *ppDataObject = new CDataObject(fmtetc, stgmeds, count);
 
    return (*ppDataObject) ? S_OK : E_OUTOFMEMORY;
}


enumformat.h


//
//  ENUMFORMAT.H
//
//  By J Brown 2004
//
//  www.catch22.net
//
//  Implementation of the IEnumFORMATETC interface
//
//  For Win2K and above look at the SHCreateStdEnumFmtEtc API call!!
//
//  Apparently the order of formats in an IEnumFORMATETC object must be
//  the same as those that were stored in the clipboard
//
//
 
 
#include <windows.h>
 
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
};


enumformat.cpp



//
//  ENUMFORMAT.CPP
//
//  By J Brown 2004
//
//  www.catch22.net
//
//  Implementation of the IEnumFORMATETC interface
//
//  For Win2K and above look at the SHCreateStdEnumFmtEtc API call!!
//
//  Apparently the order of formats in an IEnumFORMATETC object must be
//  the same as those that were stored in the clipboard
//
//
 
#include "../stdafx.h"
#include "enumformat.h"
 
//
//  "Drop-in" replacement for SHCreateStdEnumFmtEtc. Called by CDataObject::EnumFormatEtc
//
HRESULT CreateEnumFormatEtc(UINT nNumFormats, FORMATETC *pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc)
{
    if(nNumFormats == 0 || pFormatEtc == 0 || ppEnumFormatEtc == 0)
        return E_INVALIDARG;
 
    *ppEnumFormatEtc = new CEnumFormatEtc(pFormatEtc, nNumFormats);
 
    return (*ppEnumFormatEtc) ? S_OK : E_OUTOFMEMORY;
}
 
//
//  Helper function to perform a "deep" copy of a FORMATETC
//
static 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);
    }
}
 
//
//  Constructor
//
CEnumFormatEtc::CEnumFormatEtc(FORMATETC *pFormatEtc, int nNumFormats)
{
    m_lRefCount   = 1;
    m_nIndex      = 0;
    m_nNumFormats = nNumFormats;
    m_pFormatEtc  = new FORMATETC[nNumFormats];
     
    // copy the FORMATETC structures
    for(int i = 0; i < nNumFormats; i++)
    {  
        DeepCopyFormatEtc(&m_pFormatEtc[i], &pFormatEtc[i]);
    }
}
 
//
//  Destructor
//
CEnumFormatEtc::~CEnumFormatEtc()
{
    if(m_pFormatEtc)
    {
        for(ULONG i = 0; i < m_nNumFormats; i++)
        {
            if(m_pFormatEtc[i].ptd)
                CoTaskMemFree(m_pFormatEtc[i].ptd);
        }
 
        delete[] m_pFormatEtc;
    }
}
 
//
//  IUnknown::AddRef
//
ULONG __stdcall CEnumFormatEtc::AddRef(void)
{
    // increment object reference count
    return InterlockedIncrement(&m_lRefCount);
}
 
//
//  IUnknown::Release
//
ULONG __stdcall CEnumFormatEtc::Release(void)
{
    // decrement object reference count
    LONG count = InterlockedDecrement(&m_lRefCount);
         
    if(count == 0)
    {
        delete this;
        return 0;
    }
    else
    {
        return count;
    }
}
 
//
//  IUnknown::QueryInterface
//
HRESULT __stdcall CEnumFormatEtc::QueryInterface(REFIID iid, void **ppvObject)
{
    // check to see what interface has been requested
    if(iid == IID_IEnumFORMATETC || iid == IID_IUnknown)
    {
        AddRef();
        *ppvObject = this;
        return S_OK;
    }
    else
    {
        *ppvObject = 0;
        return E_NOINTERFACE;
    }
}
 
//
//  IEnumFORMATETC::Next
//
//  If the returned FORMATETC structure contains a non-null "ptd" member, then
//  the caller must free this using CoTaskMemFree (stated in the COM documentation)
//
HRESULT __stdcall CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG * pceltFetched)
{
    ULONG copied  = 0;
 
    // validate arguments
    if(celt == 0 || pFormatEtc == 0)
        return E_INVALIDARG;
 
    // copy FORMATETC structures into 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;
}
 
//
//  IEnumFORMATETC::Skip
//
HRESULT __stdcall CEnumFormatEtc::Skip(ULONG celt)
{
    m_nIndex += celt;
    return (m_nIndex <= m_nNumFormats) ? S_OK : S_FALSE;
}
 
//
//  IEnumFORMATETC::Reset
//
HRESULT __stdcall CEnumFormatEtc::Reset(void)
{
    m_nIndex = 0;
    return S_OK;
}
 
//
//  IEnumFORMATETC::Clone
//
HRESULT __stdcall CEnumFormatEtc::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;
}




發佈了24 篇原創文章 · 獲贊 3 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章