Files
foobar2000-sdk/libPPUI/IDataObjectUtils.cpp
2021-12-14 00:28:25 -07:00

188 lines
6.3 KiB
C++

#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<ULONG>(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<IStream> 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<IDataObject> obj, UINT format, DWORD aspect, LONG index, pfc::array_t<t_uint8> & 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<t_uint8> & 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<t_size>(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<ULONG>(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<IDataObject> obj, UINT format, pfc::array_t<t_uint8> & out) {
return ExtractDataObjectContent(obj, format, DVASPECT_CONTENT, -1, out);
}
HRESULT IDataObjectUtils::ExtractDataObjectContentTest(pfc::com_ptr_t<IDataObject> 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<IDataObject> obj, UINT format) {
return ExtractDataObjectContentTest(obj,format,DVASPECT_CONTENT,-1);
}
HRESULT IDataObjectUtils::ExtractDataObjectString(pfc::com_ptr_t<IDataObject> obj, pfc::string_base & out) {
pfc::array_t<t_uint8> 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<IDataObject> 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<IDataObject> 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<IDataObject> obj, UINT format, DWORD & val) {
HRESULT state;
pfc::array_t<t_uint8> 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<IDataObject> obj, UINT format, DWORD val) {
return SetDataObjectContent(obj,format,DVASPECT_CONTENT,-1,&val,sizeof(val));
}
HRESULT IDataObjectUtils::PasteSucceeded(pfc::com_ptr_t<IDataObject> obj, DWORD effect) {
return SetDataObjectDWORD(obj, RegisterClipboardFormat(CFSTR_PASTESUCCEEDED), effect);
}