|
1
|
1 #pragma once
|
|
|
2
|
|
|
3 #include <shlobj.h>
|
|
|
4 #include <ShlDisp.h> // IAsyncOperation
|
|
|
5 #include "pp-COM-macros.h"
|
|
|
6
|
|
|
7 namespace IDataObjectUtils {
|
|
|
8
|
|
|
9 class ReleaseStgMediumScope {
|
|
|
10 public:
|
|
|
11 ReleaseStgMediumScope(STGMEDIUM * medium) : m_medium(medium) {}
|
|
|
12 ~ReleaseStgMediumScope() {if (m_medium != NULL) ReleaseStgMedium(m_medium);}
|
|
|
13 private:
|
|
|
14 STGMEDIUM * m_medium;
|
|
|
15
|
|
|
16 PFC_CLASS_NOT_COPYABLE_EX(ReleaseStgMediumScope)
|
|
|
17 };
|
|
|
18
|
|
|
19 static constexpr DWORD DataBlockToSTGMEDIUM_SupportedTymeds = TYMED_ISTREAM | TYMED_HGLOBAL;
|
|
|
20 static constexpr DWORD ExtractDataObjectContent_SupportedTymeds = TYMED_ISTREAM | TYMED_HGLOBAL;
|
|
|
21
|
|
|
22 HRESULT DataBlockToSTGMEDIUM(const void * blockPtr, t_size blockSize, STGMEDIUM * medium, DWORD tymed, bool bHere) throw();
|
|
|
23
|
|
|
24 HGLOBAL HGlobalFromMemblock(const void * ptr,t_size size);
|
|
|
25
|
|
|
26 HRESULT ExtractDataObjectContent(pfc::com_ptr_t<IDataObject> obj, UINT format, DWORD aspect, LONG index, pfc::array_t<t_uint8> & out);
|
|
|
27 HRESULT ExtractDataObjectContent(pfc::com_ptr_t<IDataObject> obj, UINT format, pfc::array_t<t_uint8> & out);
|
|
|
28
|
|
|
29 HRESULT ExtractDataObjectContentTest(pfc::com_ptr_t<IDataObject> obj, UINT format, DWORD aspect, LONG index);
|
|
|
30 HRESULT ExtractDataObjectContentTest(pfc::com_ptr_t<IDataObject> obj, UINT format);
|
|
|
31
|
|
|
32 HRESULT ExtractDataObjectString(pfc::com_ptr_t<IDataObject> obj, pfc::string_base & out);
|
|
|
33 HRESULT SetDataObjectString(pfc::com_ptr_t<IDataObject> obj, const char * str);
|
|
|
34
|
|
|
35 HRESULT SetDataObjectContent(pfc::com_ptr_t<IDataObject> obj, UINT format, DWORD aspect, LONG index, const void * data, t_size dataSize);
|
|
|
36
|
|
|
37 HRESULT STGMEDIUMToDataBlock(const STGMEDIUM & med, pfc::array_t<t_uint8> & out);
|
|
|
38
|
|
|
39 HRESULT ExtractDataObjectDWORD(pfc::com_ptr_t<IDataObject> obj, UINT format, DWORD & val);
|
|
|
40 HRESULT SetDataObjectDWORD(pfc::com_ptr_t<IDataObject> obj, UINT format, DWORD val);
|
|
|
41
|
|
|
42 HRESULT PasteSucceeded(pfc::com_ptr_t<IDataObject> obj, DWORD effect);
|
|
|
43
|
|
|
44 class comparator_FORMATETC {
|
|
|
45 public:
|
|
|
46 static int compare(const FORMATETC & v1, const FORMATETC & v2) {
|
|
|
47 int val;
|
|
|
48 val = pfc::compare_t(v1.cfFormat,v2.cfFormat); if (val != 0) return val;
|
|
|
49 val = pfc::compare_t(v1.dwAspect,v2.dwAspect); if (val != 0) return val;
|
|
|
50 val = pfc::compare_t(v1.lindex, v2.lindex ); if (val != 0) return val;
|
|
|
51 return 0;
|
|
|
52 }
|
|
|
53 };
|
|
|
54
|
|
|
55 class CDataObjectBase : public IDataObject {
|
|
|
56 public:
|
|
|
57 COM_QI_SIMPLE(IDataObject)
|
|
|
58
|
|
|
59 HRESULT STDMETHODCALLTYPE GetData(FORMATETC * formatetc, STGMEDIUM * medium) override {
|
|
|
60 return GetData_internal(formatetc,medium,false);
|
|
|
61 }
|
|
|
62
|
|
|
63 HRESULT STDMETHODCALLTYPE GetDataHere(FORMATETC * formatetc, STGMEDIUM * medium) override {
|
|
|
64 return GetData_internal(formatetc,medium,true);
|
|
|
65 }
|
|
|
66
|
|
|
67 HRESULT STDMETHODCALLTYPE QueryGetData(FORMATETC * formatetc) override {
|
|
|
68 if (formatetc == NULL) return E_INVALIDARG;
|
|
|
69
|
|
|
70 if ((DataBlockToSTGMEDIUM_SupportedTymeds & formatetc->tymed) == 0) return DV_E_TYMED;
|
|
|
71
|
|
|
72 try {
|
|
|
73 return RenderDataTest(formatetc->cfFormat,formatetc->dwAspect,formatetc->lindex);
|
|
|
74 } PP_COM_CATCH;
|
|
|
75 }
|
|
|
76
|
|
|
77
|
|
|
78 HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc(FORMATETC * in, FORMATETC * out) override {
|
|
|
79 //check this again
|
|
|
80 if (in == NULL || out == NULL)
|
|
|
81 return E_INVALIDARG;
|
|
|
82 *out = *in;
|
|
|
83 return DATA_S_SAMEFORMATETC;
|
|
|
84 }
|
|
|
85
|
|
|
86 HRESULT STDMETHODCALLTYPE EnumFormatEtc(DWORD dwDirection,IEnumFORMATETC ** ppenumFormatetc) override {
|
|
|
87 if (dwDirection == DATADIR_GET) {
|
|
|
88 if (ppenumFormatetc == NULL) return E_INVALIDARG;
|
|
|
89 return CreateIEnumFORMATETC(ppenumFormatetc);
|
|
|
90 } else if (dwDirection == DATADIR_SET) {
|
|
|
91 return E_NOTIMPL;
|
|
|
92 } else {
|
|
|
93 return E_INVALIDARG;
|
|
|
94 }
|
|
|
95 }
|
|
|
96
|
|
|
97 HRESULT STDMETHODCALLTYPE SetData(FORMATETC * pFormatetc, STGMEDIUM * pmedium, BOOL fRelease) override {
|
|
|
98 try {
|
|
|
99 ReleaseStgMediumScope relScope(fRelease ? pmedium : NULL);
|
|
|
100 if (pFormatetc == NULL || pmedium == NULL) return E_INVALIDARG;
|
|
|
101
|
|
|
102 /*TCHAR buf[256];
|
|
|
103 if (GetClipboardFormatName(pFormatetc->cfFormat,buf,PFC_TABSIZE(buf)) > 0) {
|
|
|
104 buf[PFC_TABSIZE(buf)-1] = 0;
|
|
|
105 OutputDebugString(TEXT("SetData: ")); OutputDebugString(buf); OutputDebugString(TEXT("\n"));
|
|
|
106 } else {
|
|
|
107 OutputDebugString(TEXT("SetData: unknown clipboard format.\n"));
|
|
|
108 }*/
|
|
|
109
|
|
|
110 pfc::array_t<t_uint8> temp;
|
|
|
111 HRESULT state = STGMEDIUMToDataBlock(*pmedium,temp);
|
|
|
112 if (FAILED(state)) return state;
|
|
|
113 m_entries.set(*pFormatetc,temp);
|
|
|
114 return S_OK;
|
|
|
115 } PP_COM_CATCH;
|
|
|
116 }
|
|
|
117 HRESULT STDMETHODCALLTYPE DAdvise(FORMATETC* pFormatetc, DWORD advf, IAdviseSink* pAdvSink, DWORD* pdwConnection) override { (void)pFormatetc; (void)advf; (void)pAdvSink; (void)pdwConnection; return OLE_E_ADVISENOTSUPPORTED; }
|
|
|
118 HRESULT STDMETHODCALLTYPE DUnadvise(DWORD dwConnection) override { (void)dwConnection; return OLE_E_ADVISENOTSUPPORTED; }
|
|
|
119 HRESULT STDMETHODCALLTYPE EnumDAdvise(IEnumSTATDATA** ppenumAdvise) override { (void)ppenumAdvise; return OLE_E_ADVISENOTSUPPORTED; }
|
|
|
120 protected:
|
|
|
121 typedef pfc::array_t<uint8_t> data_t;
|
|
|
122 virtual HRESULT RenderData(UINT format,DWORD aspect,LONG dataIndex, data_t & out) const {
|
|
|
123 FORMATETC fmt = {};
|
|
|
124 fmt.cfFormat = (CLIPFORMAT)format; fmt.dwAspect = aspect; fmt.lindex = dataIndex;
|
|
|
125 const pfc::array_t<t_uint8> * entry = m_entries.query_ptr(fmt);
|
|
|
126 if (entry != NULL) {
|
|
|
127 out = * entry;
|
|
|
128 return S_OK;
|
|
|
129 }
|
|
|
130 return DV_E_FORMATETC;
|
|
|
131 }
|
|
|
132 virtual HRESULT RenderDataTest(UINT format,DWORD aspect,LONG dataIndex) const {
|
|
|
133 FORMATETC fmt = {};
|
|
|
134 fmt.cfFormat = (CLIPFORMAT)format; fmt.dwAspect = aspect; fmt.lindex = dataIndex;
|
|
|
135 if (m_entries.have_item(fmt)) return S_OK;
|
|
|
136 return DV_E_FORMATETC;
|
|
|
137 }
|
|
|
138 typedef pfc::list_base_t<FORMATETC> TFormatList;
|
|
|
139
|
|
|
140 static void AddFormat(TFormatList & out,UINT code) {
|
|
|
141 FORMATETC fmt = {};
|
|
|
142 fmt.dwAspect = DVASPECT_CONTENT;
|
|
|
143 fmt.lindex = -1;
|
|
|
144 fmt.cfFormat = (CLIPFORMAT)code;
|
|
|
145 for(t_size medWalk = 0; medWalk < 32; ++medWalk) {
|
|
|
146 const DWORD med = 1 << medWalk;
|
|
|
147 if ((DataBlockToSTGMEDIUM_SupportedTymeds & med) != 0) {
|
|
|
148 fmt.tymed = med;
|
|
|
149 out.add_item(fmt);
|
|
|
150 }
|
|
|
151 }
|
|
|
152 }
|
|
|
153
|
|
|
154 virtual void EnumFormats(TFormatList & out) const {
|
|
|
155 pfc::avltree_t<UINT> formats;
|
|
|
156 for(auto walk = m_entries.cfirst(); walk.is_valid(); ++walk) {
|
|
|
157 formats.add_item( walk->m_key.cfFormat );
|
|
|
158 }
|
|
|
159 for(auto walk = formats.cfirst(); walk.is_valid(); ++walk) {
|
|
|
160 AddFormat(out, *walk);
|
|
|
161 }
|
|
|
162 }
|
|
|
163 HRESULT CreateIEnumFORMATETC(IEnumFORMATETC ** outptr) const throw() {
|
|
|
164 try {
|
|
|
165 pfc::list_t<FORMATETC> out;
|
|
|
166 EnumFormats(out);
|
|
|
167 return SHCreateStdEnumFmtEtc((UINT)out.get_count(), out.get_ptr(), outptr);
|
|
|
168 } PP_COM_CATCH;
|
|
|
169 }
|
|
|
170 private:
|
|
|
171 HRESULT GetData_internal(FORMATETC * formatetc, STGMEDIUM * medium,bool bHere) {
|
|
|
172 if (formatetc == NULL || medium == NULL) return E_INVALIDARG;
|
|
|
173
|
|
|
174 try {
|
|
|
175 data_t out;
|
|
|
176 HRESULT hr = RenderData(formatetc->cfFormat,formatetc->dwAspect,formatetc->lindex,out);
|
|
|
177 if (FAILED(hr)) return hr;
|
|
|
178 return DataBlockToSTGMEDIUM(out.get_ptr(),out.get_size(),medium,formatetc->tymed,bHere);
|
|
|
179 } PP_COM_CATCH;
|
|
|
180 }
|
|
|
181
|
|
|
182 typedef pfc::map_t<FORMATETC, pfc::array_t<t_uint8>, comparator_FORMATETC> t_entries;
|
|
|
183 t_entries m_entries;
|
|
|
184 };
|
|
|
185
|
|
|
186 #ifdef __IDataObjectAsyncCapability_INTERFACE_DEFINED__
|
|
|
187 typedef IDataObjectAsyncCapability IDataObjectAsyncCapability_t;
|
|
|
188 #else
|
|
|
189 typedef IAsyncOperation IDataObjectAsyncCapability_t;
|
|
|
190 #endif
|
|
|
191
|
|
|
192 class CAsyncDataObjectBase : public CDataObjectBase, public IDataObjectAsyncCapability_t {
|
|
|
193 BOOL m_inOperation = FALSE;
|
|
|
194 BOOL m_asyncMode = TRUE;
|
|
|
195 protected:
|
|
|
196 COM_QI_BEGIN()
|
|
|
197 COM_QI_CHAIN(CDataObjectBase)
|
|
|
198 COM_QI_ENTRY(IDataObjectAsyncCapability_t)
|
|
|
199 COM_QI_END()
|
|
|
200 public:
|
|
|
201 HRESULT STDMETHODCALLTYPE SetAsyncMode(BOOL fDoOpAsync) override {
|
|
|
202 m_asyncMode = fDoOpAsync;
|
|
|
203 return S_OK;
|
|
|
204 }
|
|
|
205
|
|
|
206 HRESULT STDMETHODCALLTYPE GetAsyncMode(BOOL *pfIsOpAsync) override {
|
|
|
207 if ( pfIsOpAsync == nullptr ) return E_INVALIDARG;
|
|
|
208 *pfIsOpAsync = m_asyncMode;
|
|
|
209 return S_OK;
|
|
|
210 }
|
|
|
211
|
|
|
212 HRESULT STDMETHODCALLTYPE StartOperation(IBindCtx *pbcReserved) override {
|
|
|
213 (void)pbcReserved;
|
|
|
214 m_inOperation = TRUE;
|
|
|
215 return S_OK;
|
|
|
216 }
|
|
|
217
|
|
|
218 HRESULT STDMETHODCALLTYPE InOperation(BOOL *pfInAsyncOp) override {
|
|
|
219 if ( pfInAsyncOp == nullptr ) return E_INVALIDARG;
|
|
|
220 *pfInAsyncOp = m_inOperation;
|
|
|
221 return S_OK;
|
|
|
222 }
|
|
|
223
|
|
|
224 HRESULT STDMETHODCALLTYPE EndOperation(HRESULT hResult,IBindCtx *pbcReserved,DWORD dwEffects) override {
|
|
|
225 (void)hResult; (void)pbcReserved; (void)dwEffects;
|
|
|
226 m_inOperation = FALSE;
|
|
|
227 return S_OK;
|
|
|
228 }
|
|
|
229 };
|
|
|
230 }
|