//------------------------------------------------------------- // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: dragdrop.cpp // // Contents: The cpp file to implement IDataObject and IDragSource // // History: March-9th-98 xiaohs created // //-------------------------------------------------------------- #include #include #include "dragdrop.h" #include "unicode.h" //========================================================================= // // The APIs to establish the drag source BLOB and start the drag and drop // operations // //========================================================================= HRESULT CertMgrUIStartDragDrop(LPNMLISTVIEW pvmn, HWND hwndControl, DWORD dwExportFormat, BOOL fExportChain) { HRESULT hr=E_FAIL; IDropSource *pdsrc=NULL; IDataObject *pdtobj=NULL; DWORD dwEffect=0; DWORD dwCount=0; LPWSTR *prgwszFileName=NULL; BYTE **prgBlob=NULL; DWORD *prgdwSize=NULL; if(!pvmn || !hwndControl) { hr=E_INVALIDARG; goto CLEANUP; } //get the list of file names and their BLOBs if(!GetFileNameAndContent(pvmn, hwndControl, dwExportFormat, fExportChain, &dwCount, &prgwszFileName, &prgBlob, &prgdwSize)) { hr=GetLastError(); goto CLEANUP; } if(!SUCCEEDED(hr=CDataObj_CreateInstance(dwCount, prgwszFileName, prgBlob, prgdwSize, &pdtobj))) goto CLEANUP; if(!SUCCEEDED(hr=CDropSource_CreateInstance(&pdsrc))) goto CLEANUP; __try { DoDragDrop(pdtobj, pdsrc, DROPEFFECT_COPY, &dwEffect); } __except(EXCEPTION_EXECUTE_HANDLER) { hr = GetExceptionCode(); goto CLEANUP; } pdsrc->lpVtbl->Release(pdsrc); pdsrc=NULL; pdtobj->lpVtbl->Release(pdtobj); pdtobj=NULL; hr=S_OK; CLEANUP: FreeFileNameAndContent(dwCount, prgwszFileName, prgBlob, prgdwSize); if(pdsrc) pdsrc->lpVtbl->Release(pdsrc); if(pdtobj) pdtobj->lpVtbl->Release(pdtobj); return hr; } //========================================================================= // // IEnumFORMATETC implementation // //========================================================================= typedef struct _StdEnumFmt // idt { IEnumFORMATETC efmt; UINT cRef; UINT ifmt; UINT cfmt; FORMATETC afmt[1]; } CStdEnumFmt; extern IEnumFORMATETCVtbl c_CStdEnumFmtVtbl; // forward HRESULT CreateStdEnumFmtEtc(UINT cfmt, const FORMATETC afmt[], LPENUMFORMATETC *ppenumFormatEtc) { CStdEnumFmt * this = (CStdEnumFmt*)LocalAlloc( LPTR, sizeof(CStdEnumFmt) + (cfmt - 1) * sizeof(FORMATETC)); if (this) { this->efmt.lpVtbl = &c_CStdEnumFmtVtbl; this->cRef = 1; this->cfmt = cfmt; MoveMemory(this->afmt, afmt, cfmt * sizeof(FORMATETC)); *ppenumFormatEtc = &this->efmt; return S_OK; } else { *ppenumFormatEtc = NULL; return E_OUTOFMEMORY; } } HRESULT CStdEnumFmt_QueryInterface(LPENUMFORMATETC pefmt, REFIID riid, LPVOID * ppvObj) { CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt); if (IsEqualIID(riid, &IID_IEnumFORMATETC) || IsEqualIID(riid, &IID_IUnknown)) { *ppvObj = &this->efmt; this->cRef++; return S_OK; } *ppvObj = NULL; return E_NOINTERFACE; } ULONG CStdEnumFmt_AddRef(LPENUMFORMATETC pefmt) { CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt); return ++this->cRef; } ULONG CStdEnumFmt_Release(LPENUMFORMATETC pefmt) { CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt); this->cRef--; if (this->cRef > 0) return this->cRef; LocalFree((HLOCAL)this); return 0; } HRESULT CStdEnumFmt_Next(LPENUMFORMATETC pefmt, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) { CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt); UINT cfetch; HRESULT hres = S_FALSE; // assume less numbers if (this->ifmt < this->cfmt) { cfetch = this->cfmt - this->ifmt; if (cfetch >= celt) { cfetch = celt; hres = S_OK; } CopyMemory(rgelt, &this->afmt[this->ifmt], cfetch * sizeof(FORMATETC)); this->ifmt += cfetch; } else { cfetch = 0; } if (pceltFethed) *pceltFethed = cfetch; return hres; } HRESULT CStdEnumFmt_Skip(LPENUMFORMATETC pefmt, ULONG celt) { CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt); this->ifmt += celt; if (this->ifmt > this->cfmt) { this->ifmt = this->cfmt; return S_FALSE; } return S_OK; } HRESULT CStdEnumFmt_Reset(LPENUMFORMATETC pefmt) { CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt); this->ifmt = 0; return S_OK; } HRESULT CStdEnumFmt_Clone(LPENUMFORMATETC pefmt, IEnumFORMATETC ** ppenum) { CStdEnumFmt *this = IToClass(CStdEnumFmt, efmt, pefmt); return CreateStdEnumFmtEtc(this->cfmt, this->afmt, ppenum); } #pragma data_seg(".text", "CODE") IEnumFORMATETCVtbl c_CStdEnumFmtVtbl = { CStdEnumFmt_QueryInterface, CStdEnumFmt_AddRef, CStdEnumFmt_Release, CStdEnumFmt_Next, CStdEnumFmt_Skip, CStdEnumFmt_Reset, CStdEnumFmt_Clone, }; #pragma data_seg() //=========================================================================== // // IDataObject implementation // //========================================================================= typedef struct { IDataObject dtobj; UINT cRef; DWORD dwCount; LPWSTR *prgwszFileName; BYTE **prgBlob; DWORD *prgdwSize; } CDataObj; // registered clipboard formats UINT g_cfFileContents = 0; UINT g_cfFileGroupDescriptorA = 0; UINT g_cfFileGroupDescriptorW = 0; #pragma data_seg(".text", "CODE") const char c_szFileContents[] = CFSTR_FILECONTENTS; // "FileContents" const char c_szFileGroupDescriptorA[] = CFSTR_FILEDESCRIPTORA; // "FileGroupDescriptor" const char c_szFileGroupDescriptorW[] = CFSTR_FILEDESCRIPTORW; // "FileGroupDescriptorW" #pragma data_seg() IDataObjectVtbl c_CDataObjVtbl; // forward decl HRESULT CDataObj_CreateInstance(DWORD dwCount, LPWSTR *prgwszFileName, BYTE **prgBlob, DWORD *prgdwSize, IDataObject **ppdtobj) { CDataObj *this = (CDataObj *)LocalAlloc(LPTR, sizeof(CDataObj)); if (this) { this->dtobj.lpVtbl = &c_CDataObjVtbl; this->cRef = 1; this->dwCount = dwCount; this->prgwszFileName = prgwszFileName; this->prgBlob = prgBlob; this->prgdwSize = prgdwSize; *ppdtobj = &this->dtobj; if (g_cfFileContents == 0) { g_cfFileContents = RegisterClipboardFormat(c_szFileContents); g_cfFileGroupDescriptorW = RegisterClipboardFormat(c_szFileGroupDescriptorW); g_cfFileGroupDescriptorA = RegisterClipboardFormat(c_szFileGroupDescriptorA); } return S_OK; } *ppdtobj = NULL; return E_OUTOFMEMORY; } HRESULT CDataObj_QueryInterface(IDataObject *pdtobj, REFIID riid, LPVOID * ppvObj) { CDataObj *this = IToClass(CDataObj, dtobj, pdtobj); if (IsEqualIID(riid, &IID_IDataObject) || IsEqualIID(riid, &IID_IUnknown)) { *ppvObj = this; this->cRef++; return S_OK; } *ppvObj = NULL; return E_NOINTERFACE; } ULONG CDataObj_AddRef(IDataObject *pdtobj) { CDataObj *this = IToClass(CDataObj, dtobj, pdtobj); this->cRef++; return this->cRef; } ULONG CDataObj_Release(IDataObject *pdtobj) { CDataObj *this = IToClass(CDataObj, dtobj, pdtobj); this->cRef--; if (this->cRef > 0) return this->cRef; LocalFree((HLOCAL)this); return 0; } HRESULT CDataObj_GetData(IDataObject *pdtobj, FORMATETC *pformatetcIn, STGMEDIUM *pmedium) { CDataObj *this = IToClass(CDataObj, dtobj, pdtobj); HRESULT hres = E_INVALIDARG; DWORD dwIndex=0; LPSTR psz=NULL; pmedium->hGlobal = NULL; pmedium->pUnkForRelease = NULL; if ( ((g_cfFileGroupDescriptorA == pformatetcIn->cfFormat) && (pformatetcIn->tymed & TYMED_HGLOBAL)) || ((g_cfFileGroupDescriptorW == pformatetcIn->cfFormat) && (pformatetcIn->tymed & TYMED_HGLOBAL)) ) { if(g_cfFileGroupDescriptorA == pformatetcIn->cfFormat) { if(!FIsWinNT()) { //allocate dwCount-1 file descrptors pmedium->hGlobal = GlobalAlloc(GPTR, (sizeof(FILEGROUPDESCRIPTORA)+(this->dwCount -1 )*sizeof(FILEDESCRIPTORA))); if(NULL == pmedium->hGlobal) return E_OUTOFMEMORY; #define pdesc ((FILEGROUPDESCRIPTORA *)pmedium->hGlobal) //populate all the file descriptors for(dwIndex =0; dwIndex < this->dwCount; dwIndex++) { //get the anscii version of the file name if(((this->prgwszFileName)[dwIndex] == NULL) || (!MkMBStr(NULL, 0, (this->prgwszFileName)[dwIndex], &psz))) return E_OUTOFMEMORY; lstrcpy(pdesc->fgd[dwIndex].cFileName, psz); // specify the file for our HGLOBAL since GlobalSize() will round up pdesc->fgd[dwIndex].dwFlags = FD_FILESIZE; pdesc->fgd[dwIndex].nFileSizeLow = (this->prgdwSize)[dwIndex]; FreeMBStr(NULL,psz); psz=NULL; } //specify the number of files pdesc->cItems = this->dwCount; #undef pdesc } else return E_INVALIDARG; } else { //allocate dwCount-1 file descrptors pmedium->hGlobal = GlobalAlloc(GPTR, (sizeof(FILEGROUPDESCRIPTORW)+(this->dwCount -1 )*sizeof(FILEDESCRIPTORW))); if(NULL == pmedium->hGlobal) return E_OUTOFMEMORY; #define pdesc ((FILEGROUPDESCRIPTORW *)pmedium->hGlobal) //populate all the file descriptors for(dwIndex =0; dwIndex < this->dwCount; dwIndex++) { wcscpy(pdesc->fgd[dwIndex].cFileName, (this->prgwszFileName)[dwIndex]); // specify the file for our HGLOBAL since GlobalSize() will round up pdesc->fgd[dwIndex].dwFlags = FD_FILESIZE; pdesc->fgd[dwIndex].nFileSizeLow = (this->prgdwSize)[dwIndex]; } //specify the number of files pdesc->cItems = this->dwCount; #undef pdesc } pmedium->tymed = TYMED_HGLOBAL; hres = S_OK; } else if ((g_cfFileContents == pformatetcIn->cfFormat) && (pformatetcIn->tymed & TYMED_HGLOBAL)) { if((pformatetcIn->lindex) < (int)(this->dwCount)) { pmedium->hGlobal = GlobalAlloc(GPTR, (this->prgdwSize)[pformatetcIn->lindex]); if (pmedium->hGlobal) { CopyMemory(pmedium->hGlobal, (this->prgBlob)[pformatetcIn->lindex], (this->prgdwSize)[pformatetcIn->lindex]); pmedium->tymed = TYMED_HGLOBAL; hres = S_OK; } else hres=E_OUTOFMEMORY; } else hres = E_INVALIDARG; } return hres; } HRESULT CDataObj_GetDataHere(IDataObject *pdtobj, FORMATETC *pformatetc, STGMEDIUM *pmedium) { return E_NOTIMPL; } HRESULT CDataObj_QueryGetData(IDataObject *pdtobj, LPFORMATETC pformatetcIn) { CDataObj *this = IToClass(CDataObj, dtobj, pdtobj); if (((pformatetcIn->cfFormat == g_cfFileContents) && (pformatetcIn->tymed & TYMED_HGLOBAL ))|| ((pformatetcIn->cfFormat == g_cfFileGroupDescriptorW) && (pformatetcIn->tymed & TYMED_HGLOBAL)) ) { return S_OK; } else { //on NT, we do not support A version in order to be //unicode compliant. The shell query the A version first on NT. if(!FIsWinNT()) { if((pformatetcIn->cfFormat == g_cfFileGroupDescriptorA) && (pformatetcIn->tymed & TYMED_HGLOBAL)) return S_OK; else return S_FALSE; } else return S_FALSE; } } HRESULT CDataObj_GetCanonicalFormatEtc(IDataObject *pdtobj, FORMATETC *pformatetc, FORMATETC *pformatetcOut) { return DATA_S_SAMEFORMATETC; } HRESULT CDataObj_SetData(IDataObject *pdtobj, FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) { return E_NOTIMPL; } HRESULT CDataObj_EnumFormatEtc(IDataObject *pdtobj, DWORD dwDirection, LPENUMFORMATETC *ppenumFormatEtc) { CDataObj *this = IToClass(CDataObj, dtobj, pdtobj); FORMATETC fmte[3] = { {(WORD)g_cfFileContents, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, {(WORD)g_cfFileGroupDescriptorA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, {(WORD)g_cfFileGroupDescriptorW, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, }; return CreateStdEnumFmtEtc(ARRAYSIZE(fmte), fmte, ppenumFormatEtc); } HRESULT CDataObj_Advise(IDataObject *pdtobj, FORMATETC *pFormatetc, DWORD advf, LPADVISESINK pAdvSink, DWORD *pdwConnection) { return OLE_E_ADVISENOTSUPPORTED; } HRESULT CDataObj_Unadvise(IDataObject *pdtobj, DWORD dwConnection) { return OLE_E_ADVISENOTSUPPORTED; } HRESULT CDataObj_EnumAdvise(IDataObject *pdtobj, LPENUMSTATDATA *ppenumAdvise) { return OLE_E_ADVISENOTSUPPORTED; } #pragma data_seg(".text", "CODE") IDataObjectVtbl c_CDataObjVtbl = { CDataObj_QueryInterface, CDataObj_AddRef, CDataObj_Release, CDataObj_GetData, CDataObj_GetDataHere, CDataObj_QueryGetData, CDataObj_GetCanonicalFormatEtc, CDataObj_SetData, CDataObj_EnumFormatEtc, CDataObj_Advise, CDataObj_Unadvise, CDataObj_EnumAdvise }; #pragma data_seg() //========================================================================= // // IDropSource implementation // //========================================================================= typedef struct { IDropSource dsrc; UINT cRef; DWORD grfInitialKeyState; } CDropSource; IDropSourceVtbl c_CDropSourceVtbl; // forward decl HRESULT CDropSource_CreateInstance(IDropSource **ppdsrc) { CDropSource *this = (CDropSource *)LocalAlloc(LPTR, sizeof(CDropSource)); if (this) { this->dsrc.lpVtbl = &c_CDropSourceVtbl; this->cRef = 1; *ppdsrc = &this->dsrc; return S_OK; } else { *ppdsrc = NULL; return E_OUTOFMEMORY; } } HRESULT CDropSource_QueryInterface(IDropSource *pdsrc, REFIID riid, LPVOID *ppvObj) { CDropSource *this = IToClass(CDropSource, dsrc, pdsrc); if (IsEqualIID(riid, &IID_IDropSource) || IsEqualIID(riid, &IID_IUnknown)) { *ppvObj = this; this->cRef++; return S_OK; } *ppvObj = NULL; return E_NOINTERFACE; } ULONG CDropSource_AddRef(IDropSource *pdsrc) { CDropSource *this = IToClass(CDropSource, dsrc, pdsrc); this->cRef++; return this->cRef; } ULONG CDropSource_Release(IDropSource *pdsrc) { CDropSource *this = IToClass(CDropSource, dsrc, pdsrc); this->cRef--; if (this->cRef > 0) return this->cRef; LocalFree((HLOCAL)this); return 0; } HRESULT CDropSource_QueryContinueDrag(IDropSource *pdsrc, BOOL fEscapePressed, DWORD grfKeyState) { CDropSource *this = IToClass(CDropSource, dsrc, pdsrc); if (fEscapePressed) return DRAGDROP_S_CANCEL; // initialize ourself with the drag begin button if (this->grfInitialKeyState == 0) this->grfInitialKeyState = (grfKeyState & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)); if (!(grfKeyState & this->grfInitialKeyState)) return DRAGDROP_S_DROP; else return S_OK; } HRESULT CDropSource_GiveFeedback(IDropSource *pdsrc, DWORD dwEffect) { CDropSource *this = IToClass(CDropSource, dsrc, pdsrc); return DRAGDROP_S_USEDEFAULTCURSORS; } #pragma data_seg(".text", "CODE") IDropSourceVtbl c_CDropSourceVtbl = { CDropSource_QueryInterface, CDropSource_AddRef, CDropSource_Release, CDropSource_QueryContinueDrag, CDropSource_GiveFeedback }; #pragma data_seg()