#include "stdafx.h" #include "IDataObjectUtils.h" HRESULT IDataObjectUtils::DataBlockToSTGMEDIUM(const void * blockPtr, t_size blockSize, STGMEDIUM * medium, DWORD tymed, bool bHere) throw() { try { if (bHere) { switch(tymed) { case TYMED_ISTREAM: { if (medium->pstm == NULL) return E_INVALIDARG; ULONG written = 0; HRESULT state; state = medium->pstm->Write(blockPtr, pfc::downcast_guarded(blockSize),&written); if (FAILED(state)) return state; if (written != blockSize) return STG_E_MEDIUMFULL; return S_OK; } default: return DV_E_TYMED; } } else { if (tymed & TYMED_HGLOBAL) { HGLOBAL hMem = HGlobalFromMemblock(blockPtr, blockSize); if (hMem == NULL) return E_OUTOFMEMORY; medium->tymed = TYMED_HGLOBAL; medium->hGlobal = hMem; medium->pUnkForRelease = NULL; return S_OK; } if (tymed & TYMED_ISTREAM) { HRESULT state; HGLOBAL hMem = HGlobalFromMemblock(blockPtr, blockSize); if (hMem == NULL) return E_OUTOFMEMORY; medium->tymed = TYMED_ISTREAM; pfc::com_ptr_t stream; if (FAILED( state = CreateStreamOnHGlobal(hMem,TRUE,stream.receive_ptr()) ) ) { GlobalFree(hMem); return state; } { LARGE_INTEGER wtf = {}; if (FAILED( state = stream->Seek(wtf,STREAM_SEEK_END,NULL) ) ) { return state; } } medium->pstm = stream.detach(); medium->pUnkForRelease = NULL; return S_OK; } return DV_E_TYMED; } } catch(pfc::exception_not_implemented) { return E_NOTIMPL; } catch(std::bad_alloc) { return E_OUTOFMEMORY; } catch(...) { return E_UNEXPECTED; } } HGLOBAL IDataObjectUtils::HGlobalFromMemblock(const void * ptr,t_size size) { HGLOBAL handle = GlobalAlloc(GMEM_MOVEABLE,size); if (handle != NULL) { void * destptr = GlobalLock(handle); if (destptr == NULL) { GlobalFree(handle); handle = NULL; } else { memcpy(destptr,ptr,size); GlobalUnlock(handle); } } return handle; } HRESULT IDataObjectUtils::ExtractDataObjectContent(pfc::com_ptr_t obj, UINT format, DWORD aspect, LONG index, pfc::array_t & out) { FORMATETC fmt = {}; fmt.cfFormat = format; fmt.dwAspect = aspect; fmt.lindex = index; fmt.tymed = TYMED_HGLOBAL /* | TYMED_ISTREAM*/; STGMEDIUM med = {}; HRESULT state; if (FAILED( state = obj->GetData(&fmt,&med) ) ) return state; ReleaseStgMediumScope relScope(&med); return STGMEDIUMToDataBlock(med, out); } HRESULT IDataObjectUtils::STGMEDIUMToDataBlock(const STGMEDIUM & med, pfc::array_t & out) { switch(med.tymed) { case TYMED_HGLOBAL: { CGlobalLockScope lock(med.hGlobal); out.set_data_fromptr( (const t_uint8*) lock.GetPtr(), lock.GetSize() ); } return S_OK; case TYMED_ISTREAM: { HRESULT state; IStream * stream = med.pstm; LARGE_INTEGER offset = {}; STATSTG stats = {}; if (FAILED( state = stream->Stat(&stats,STATFLAG_NONAME ) ) ) return state; t_size toRead = pfc::downcast_guarded(stats.cbSize.QuadPart); out.set_size(toRead); if (FAILED( state = stream->Seek(offset,STREAM_SEEK_SET,NULL) ) ) return state; ULONG cbRead = 0; if (FAILED( state = stream->Read(out.get_ptr(), pfc::downcast_guarded(toRead), &cbRead) ) ) return state; if (cbRead != toRead) return E_UNEXPECTED; } return S_OK; default: return DV_E_TYMED; } } HRESULT IDataObjectUtils::ExtractDataObjectContent(pfc::com_ptr_t obj, UINT format, pfc::array_t & out) { return ExtractDataObjectContent(obj, format, DVASPECT_CONTENT, -1, out); } HRESULT IDataObjectUtils::ExtractDataObjectContentTest(pfc::com_ptr_t obj, UINT format, DWORD aspect, LONG index) { FORMATETC fmt = {}; fmt.cfFormat = format; fmt.dwAspect = aspect; fmt.lindex = index; for(t_uint32 walk = 0; walk < 32; ++walk) { const DWORD tymed = 1 << walk; if ((ExtractDataObjectContent_SupportedTymeds & tymed) != 0) { fmt.tymed = tymed; HRESULT state = obj->QueryGetData(&fmt); if (SUCCEEDED(state)) { if (state == S_OK) return S_OK; } else { if (state != DV_E_TYMED) return state; } } } return E_FAIL; } HRESULT IDataObjectUtils::ExtractDataObjectContentTest(pfc::com_ptr_t obj, UINT format) { return ExtractDataObjectContentTest(obj,format,DVASPECT_CONTENT,-1); } HRESULT IDataObjectUtils::ExtractDataObjectString(pfc::com_ptr_t obj, pfc::string_base & out) { pfc::array_t data; HRESULT state; state = ExtractDataObjectContent(obj,CF_UNICODETEXT,data); if (SUCCEEDED(state)) { out = pfc::stringcvt::string_utf8_from_os_ex( (const wchar_t*) data.get_ptr(), data.get_size() / sizeof(wchar_t) ); return S_OK; } state = ExtractDataObjectContent(obj,CF_TEXT,data); if (SUCCEEDED(state)) { out = pfc::stringcvt::string_utf8_from_os_ex( (const char*) data.get_ptr(), data.get_size() / sizeof(char) ); return S_OK; } return E_FAIL; } HRESULT IDataObjectUtils::SetDataObjectContent(pfc::com_ptr_t obj, UINT format, DWORD aspect, LONG index, const void * data, t_size dataSize) { STGMEDIUM med = {}; FORMATETC fmt = {}; fmt.cfFormat = format; fmt.dwAspect = aspect; fmt.lindex = index; fmt.tymed = TYMED_HGLOBAL; HRESULT state; if (FAILED(state = DataBlockToSTGMEDIUM(data,dataSize,&med,TYMED_HGLOBAL,false))) return state; return obj->SetData(&fmt,&med,TRUE); } HRESULT IDataObjectUtils::SetDataObjectString(pfc::com_ptr_t obj, const char * str) { pfc::stringcvt::string_wide_from_utf8 s(str); return SetDataObjectContent(obj,CF_UNICODETEXT,DVASPECT_CONTENT,-1,s.get_ptr(), (s.length()+1) * sizeof(s[0])); } HRESULT IDataObjectUtils::ExtractDataObjectDWORD(pfc::com_ptr_t obj, UINT format, DWORD & val) { HRESULT state; pfc::array_t buffer; if (FAILED( state = ExtractDataObjectContent(obj, format, DVASPECT_CONTENT, -1, buffer) ) ) return state; if (buffer.get_size() < sizeof(val)) return E_UNEXPECTED; val = *(DWORD*) buffer.get_ptr(); return S_OK; } HRESULT IDataObjectUtils::SetDataObjectDWORD(pfc::com_ptr_t obj, UINT format, DWORD val) { return SetDataObjectContent(obj,format,DVASPECT_CONTENT,-1,&val,sizeof(val)); } HRESULT IDataObjectUtils::PasteSucceeded(pfc::com_ptr_t obj, DWORD effect) { return SetDataObjectDWORD(obj, RegisterClipboardFormat(CFSTR_PASTESUCCEEDED), effect); }