00001 #include <shlobj.h>
00002
00003 namespace IDataObjectUtils {
00004
00005 class ReleaseStgMediumScope {
00006 public:
00007 ReleaseStgMediumScope(STGMEDIUM * medium) : m_medium(medium) {}
00008 ~ReleaseStgMediumScope() {if (m_medium != NULL) ReleaseStgMedium(m_medium);}
00009 private:
00010 STGMEDIUM * m_medium;
00011
00012 PFC_CLASS_NOT_COPYABLE_EX(ReleaseStgMediumScope)
00013 };
00014
00015 static const DWORD DataBlockToSTGMEDIUM_SupportedTymeds = TYMED_ISTREAM | TYMED_HGLOBAL;
00016 static const DWORD ExtractDataObjectContent_SupportedTymeds = TYMED_ISTREAM | TYMED_HGLOBAL;
00017
00018 HRESULT DataBlockToSTGMEDIUM(const void * blockPtr, t_size blockSize, STGMEDIUM * medium, DWORD tymed, bool bHere) throw();
00019
00020 HGLOBAL HGlobalFromMemblock(const void * ptr,t_size size);
00021
00022 HRESULT ExtractDataObjectContent(pfc::com_ptr_t<IDataObject> obj, UINT format, DWORD aspect, LONG index, pfc::array_t<t_uint8> & out);
00023 HRESULT ExtractDataObjectContent(pfc::com_ptr_t<IDataObject> obj, UINT format, pfc::array_t<t_uint8> & out);
00024
00025 HRESULT ExtractDataObjectContentTest(pfc::com_ptr_t<IDataObject> obj, UINT format, DWORD aspect, LONG index);
00026 HRESULT ExtractDataObjectContentTest(pfc::com_ptr_t<IDataObject> obj, UINT format);
00027
00028 HRESULT ExtractDataObjectString(pfc::com_ptr_t<IDataObject> obj, pfc::string_base & out);
00029 HRESULT SetDataObjectString(pfc::com_ptr_t<IDataObject> obj, const char * str);
00030
00031 HRESULT SetDataObjectContent(pfc::com_ptr_t<IDataObject> obj, UINT format, DWORD aspect, LONG index, const void * data, t_size dataSize);
00032
00033 HRESULT STGMEDIUMToDataBlock(const STGMEDIUM & med, pfc::array_t<t_uint8> & out);
00034
00035 HRESULT ExtractDataObjectDWORD(pfc::com_ptr_t<IDataObject> obj, UINT format, DWORD & val);
00036 HRESULT SetDataObjectDWORD(pfc::com_ptr_t<IDataObject> obj, UINT format, DWORD val);
00037
00038 HRESULT PasteSucceeded(pfc::com_ptr_t<IDataObject> obj, DWORD effect);
00039
00040 class comparator_FORMATETC {
00041 public:
00042 static int compare(const FORMATETC & v1, const FORMATETC & v2) {
00043 int val;
00044 val = pfc::compare_t(v1.cfFormat,v2.cfFormat); if (val != 0) return val;
00045 val = pfc::compare_t(v1.dwAspect,v2.dwAspect); if (val != 0) return val;
00046 val = pfc::compare_t(v1.lindex, v2.lindex ); if (val != 0) return val;
00047 return 0;
00048 }
00049 };
00050
00051 class CDataObjectBase : public IDataObject {
00052 public:
00053 COM_QI_BEGIN()
00054 COM_QI_ENTRY(IUnknown)
00055 COM_QI_ENTRY(IDataObject)
00056 COM_QI_END()
00057
00058 HRESULT STDMETHODCALLTYPE GetData(FORMATETC * formatetc, STGMEDIUM * medium) {
00059 return GetData_internal(formatetc,medium,false);
00060 }
00061
00062 HRESULT STDMETHODCALLTYPE GetDataHere(FORMATETC * formatetc, STGMEDIUM * medium) {
00063 return GetData_internal(formatetc,medium,true);
00064 }
00065
00066 HRESULT STDMETHODCALLTYPE QueryGetData(FORMATETC * formatetc) {
00067 if (formatetc == NULL) return E_INVALIDARG;
00068
00069 if ((DataBlockToSTGMEDIUM_SupportedTymeds & formatetc->tymed) == 0) return DV_E_TYMED;
00070
00071 try {
00072 return RenderDataTest(formatetc->cfFormat,formatetc->dwAspect,formatetc->lindex);
00073 } FB2K_COM_CATCH;
00074 }
00075
00076
00077 HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc(FORMATETC * in, FORMATETC * out) {
00078
00079 if (in == NULL || out == NULL)
00080 return E_INVALIDARG;
00081 *out = *in;
00082 return DATA_S_SAMEFORMATETC;
00083 }
00084
00085 HRESULT STDMETHODCALLTYPE EnumFormatEtc(DWORD dwDirection,IEnumFORMATETC ** ppenumFormatetc) {
00086 if (dwDirection == DATADIR_GET) {
00087 if (ppenumFormatetc == NULL) return E_INVALIDARG;
00088 return CreateIEnumFORMATETC(ppenumFormatetc);
00089 } else if (dwDirection == DATADIR_SET) {
00090 return E_NOTIMPL;
00091 } else {
00092 return E_INVALIDARG;
00093 }
00094 }
00095
00096 HRESULT STDMETHODCALLTYPE SetData(FORMATETC * pFormatetc, STGMEDIUM * pmedium, BOOL fRelease) {
00097 try {
00098 ReleaseStgMediumScope relScope(fRelease ? pmedium : NULL);
00099 if (pFormatetc == NULL || pmedium == NULL) return E_INVALIDARG;
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 pfc::array_t<t_uint8> temp;
00110 HRESULT state = STGMEDIUMToDataBlock(*pmedium,temp);
00111 if (FAILED(state)) return state;
00112 m_entries.set(*pFormatetc,temp);
00113 return S_OK;
00114 } FB2K_COM_CATCH;
00115 }
00116 HRESULT STDMETHODCALLTYPE DAdvise(FORMATETC * pFormatetc, DWORD advf, IAdviseSink * pAdvSink, DWORD * pdwConnection) {return OLE_E_ADVISENOTSUPPORTED;}
00117 HRESULT STDMETHODCALLTYPE DUnadvise(DWORD dwConnection) {return OLE_E_ADVISENOTSUPPORTED;}
00118 HRESULT STDMETHODCALLTYPE EnumDAdvise(IEnumSTATDATA ** ppenumAdvise) {return OLE_E_ADVISENOTSUPPORTED;}
00119 protected:
00120 virtual HRESULT RenderData(UINT format,DWORD aspect,LONG dataIndex,stream_writer_formatter<> & out) const {
00121 FORMATETC fmt = {};
00122 fmt.cfFormat = format; fmt.dwAspect = aspect; fmt.lindex = dataIndex;
00123 const pfc::array_t<t_uint8> * entry = m_entries.query_ptr(fmt);
00124 if (entry != NULL) {
00125 out.write_raw(entry->get_ptr(), entry->get_size());
00126 return S_OK;
00127 }
00128 return DV_E_FORMATETC;
00129 }
00130 virtual HRESULT RenderDataTest(UINT format,DWORD aspect, LONG dataIndex) const {
00131 FORMATETC fmt = {};
00132 fmt.cfFormat = format; fmt.dwAspect = aspect; fmt.lindex = dataIndex;
00133 if (m_entries.have_item(fmt)) return S_OK;
00134 return DV_E_FORMATETC;
00135 }
00136 typedef pfc::list_base_t<FORMATETC> TFormatList;
00137
00138 static void AddFormat(TFormatList & out,UINT code) {
00139 FORMATETC fmt = {};
00140 fmt.dwAspect = DVASPECT_CONTENT;
00141 fmt.lindex = -1;
00142 fmt.cfFormat = code;
00143 for(t_size medWalk = 0; medWalk < 32; ++medWalk) {
00144 const DWORD med = 1 << medWalk;
00145 if ((DataBlockToSTGMEDIUM_SupportedTymeds & med) != 0) {
00146 fmt.tymed = med;
00147 out.add_item(fmt);
00148 }
00149 }
00150 }
00151
00152 virtual void EnumFormats(TFormatList & out) const {
00153 pfc::avltree_t<UINT> formats;
00154 for(t_entries::const_iterator walk = m_entries.first(); walk.is_valid(); ++walk) {
00155 formats.add_item( walk->m_key.cfFormat );
00156 }
00157 for(pfc::const_iterator<UINT> walk = formats.first(); walk.is_valid(); ++walk) {
00158 AddFormat(out, *walk);
00159 }
00160 }
00161 HRESULT CreateIEnumFORMATETC(IEnumFORMATETC ** outptr) const throw() {
00162 try {
00163 pfc::list_t<FORMATETC> out;
00164 EnumFormats(out);
00165 return SHCreateStdEnumFmtEtc((UINT)out.get_count(), out.get_ptr(), outptr);
00166 } FB2K_COM_CATCH;
00167 }
00168 private:
00169 HRESULT GetData_internal(FORMATETC * formatetc, STGMEDIUM * medium,bool bHere) {
00170 if (formatetc == NULL || medium == NULL) return E_INVALIDARG;
00171
00172 try {
00173 stream_writer_formatter_simple<> out;
00174 HRESULT hr = RenderData(formatetc->cfFormat,formatetc->dwAspect,formatetc->lindex,out);
00175 if (FAILED(hr)) return hr;
00176 return DataBlockToSTGMEDIUM(out.m_buffer.get_ptr(),out.m_buffer.get_size(),medium,formatetc->tymed,bHere);
00177 } FB2K_COM_CATCH;
00178 }
00179
00180 typedef pfc::map_t<FORMATETC, pfc::array_t<t_uint8>, comparator_FORMATETC> t_entries;
00181 t_entries m_entries;
00182 };
00183 }