Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include <shlobj.h> |
michael@0 | 7 | |
michael@0 | 8 | #include "nsDataObjCollection.h" |
michael@0 | 9 | #include "nsClipboard.h" |
michael@0 | 10 | #include "IEnumFE.h" |
michael@0 | 11 | |
michael@0 | 12 | #include <ole2.h> |
michael@0 | 13 | |
michael@0 | 14 | // {25589C3E-1FAC-47b9-BF43-CAEA89B79533} |
michael@0 | 15 | const IID IID_IDataObjCollection = |
michael@0 | 16 | {0x25589c3e, 0x1fac, 0x47b9, {0xbf, 0x43, 0xca, 0xea, 0x89, 0xb7, 0x95, 0x33}}; |
michael@0 | 17 | |
michael@0 | 18 | /* |
michael@0 | 19 | * Class nsDataObjCollection |
michael@0 | 20 | */ |
michael@0 | 21 | |
michael@0 | 22 | nsDataObjCollection::nsDataObjCollection() |
michael@0 | 23 | : m_cRef(0), mIsAsyncMode(FALSE), mIsInOperation(FALSE) |
michael@0 | 24 | { |
michael@0 | 25 | m_enumFE = new CEnumFormatEtc(); |
michael@0 | 26 | m_enumFE->AddRef(); |
michael@0 | 27 | } |
michael@0 | 28 | |
michael@0 | 29 | nsDataObjCollection::~nsDataObjCollection() |
michael@0 | 30 | { |
michael@0 | 31 | mDataFlavors.Clear(); |
michael@0 | 32 | mDataObjects.Clear(); |
michael@0 | 33 | |
michael@0 | 34 | m_enumFE->Release(); |
michael@0 | 35 | } |
michael@0 | 36 | |
michael@0 | 37 | |
michael@0 | 38 | // IUnknown interface methods - see iunknown.h for documentation |
michael@0 | 39 | STDMETHODIMP nsDataObjCollection::QueryInterface(REFIID riid, void** ppv) |
michael@0 | 40 | { |
michael@0 | 41 | *ppv=nullptr; |
michael@0 | 42 | |
michael@0 | 43 | if ( (IID_IUnknown == riid) || (IID_IDataObject == riid) ) { |
michael@0 | 44 | *ppv = static_cast<IDataObject*>(this); |
michael@0 | 45 | AddRef(); |
michael@0 | 46 | return NOERROR; |
michael@0 | 47 | } |
michael@0 | 48 | |
michael@0 | 49 | if ( IID_IDataObjCollection == riid ) { |
michael@0 | 50 | *ppv = static_cast<nsIDataObjCollection*>(this); |
michael@0 | 51 | AddRef(); |
michael@0 | 52 | return NOERROR; |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | return E_NOINTERFACE; |
michael@0 | 56 | } |
michael@0 | 57 | |
michael@0 | 58 | STDMETHODIMP_(ULONG) nsDataObjCollection::AddRef() |
michael@0 | 59 | { |
michael@0 | 60 | return ++m_cRef; |
michael@0 | 61 | } |
michael@0 | 62 | |
michael@0 | 63 | STDMETHODIMP_(ULONG) nsDataObjCollection::Release() |
michael@0 | 64 | { |
michael@0 | 65 | if (0 != --m_cRef) |
michael@0 | 66 | return m_cRef; |
michael@0 | 67 | |
michael@0 | 68 | delete this; |
michael@0 | 69 | |
michael@0 | 70 | return 0; |
michael@0 | 71 | } |
michael@0 | 72 | |
michael@0 | 73 | BOOL nsDataObjCollection::FormatsMatch(const FORMATETC& source, |
michael@0 | 74 | const FORMATETC& target) const |
michael@0 | 75 | { |
michael@0 | 76 | if ((source.cfFormat == target.cfFormat) && |
michael@0 | 77 | (source.dwAspect & target.dwAspect) && |
michael@0 | 78 | (source.tymed & target.tymed)) { |
michael@0 | 79 | return TRUE; |
michael@0 | 80 | } else { |
michael@0 | 81 | return FALSE; |
michael@0 | 82 | } |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | // IDataObject methods |
michael@0 | 86 | STDMETHODIMP nsDataObjCollection::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM) |
michael@0 | 87 | { |
michael@0 | 88 | static CLIPFORMAT fileDescriptorFlavorA = |
michael@0 | 89 | ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA); |
michael@0 | 90 | static CLIPFORMAT fileDescriptorFlavorW = |
michael@0 | 91 | ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW); |
michael@0 | 92 | static CLIPFORMAT fileFlavor = ::RegisterClipboardFormat(CFSTR_FILECONTENTS); |
michael@0 | 93 | |
michael@0 | 94 | switch (pFE->cfFormat) { |
michael@0 | 95 | case CF_TEXT: |
michael@0 | 96 | case CF_UNICODETEXT: |
michael@0 | 97 | return GetText(pFE, pSTM); |
michael@0 | 98 | case CF_HDROP: |
michael@0 | 99 | return GetFile(pFE, pSTM); |
michael@0 | 100 | default: |
michael@0 | 101 | if (pFE->cfFormat == fileDescriptorFlavorA || |
michael@0 | 102 | pFE->cfFormat == fileDescriptorFlavorW) { |
michael@0 | 103 | return GetFileDescriptors(pFE, pSTM); |
michael@0 | 104 | } |
michael@0 | 105 | if (pFE->cfFormat == fileFlavor) { |
michael@0 | 106 | return GetFileContents(pFE, pSTM); |
michael@0 | 107 | } |
michael@0 | 108 | } |
michael@0 | 109 | return GetFirstSupporting(pFE, pSTM); |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | STDMETHODIMP nsDataObjCollection::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM) |
michael@0 | 113 | { |
michael@0 | 114 | return E_FAIL; |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | // Other objects querying to see if we support a particular format |
michael@0 | 118 | STDMETHODIMP nsDataObjCollection::QueryGetData(LPFORMATETC pFE) |
michael@0 | 119 | { |
michael@0 | 120 | UINT format = nsClipboard::GetFormat(MULTI_MIME); |
michael@0 | 121 | |
michael@0 | 122 | if (format == pFE->cfFormat) { |
michael@0 | 123 | return S_OK; |
michael@0 | 124 | } |
michael@0 | 125 | |
michael@0 | 126 | for (uint32_t i = 0; i < mDataObjects.Length(); ++i) { |
michael@0 | 127 | IDataObject * dataObj = mDataObjects.ElementAt(i); |
michael@0 | 128 | if (S_OK == dataObj->QueryGetData(pFE)) { |
michael@0 | 129 | return S_OK; |
michael@0 | 130 | } |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | return DV_E_FORMATETC; |
michael@0 | 134 | } |
michael@0 | 135 | |
michael@0 | 136 | STDMETHODIMP nsDataObjCollection::GetCanonicalFormatEtc(LPFORMATETC pFEIn, |
michael@0 | 137 | LPFORMATETC pFEOut) |
michael@0 | 138 | { |
michael@0 | 139 | return E_NOTIMPL; |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | STDMETHODIMP nsDataObjCollection::SetData(LPFORMATETC pFE, |
michael@0 | 143 | LPSTGMEDIUM pSTM, |
michael@0 | 144 | BOOL fRelease) |
michael@0 | 145 | { |
michael@0 | 146 | // Set arbitrary data formats on the first object in the collection and let |
michael@0 | 147 | // it handle the heavy lifting |
michael@0 | 148 | if (mDataObjects.Length() == 0) |
michael@0 | 149 | return E_FAIL; |
michael@0 | 150 | return mDataObjects.ElementAt(0)->SetData(pFE, pSTM, fRelease); |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | STDMETHODIMP nsDataObjCollection::EnumFormatEtc(DWORD dwDir, |
michael@0 | 154 | LPENUMFORMATETC *ppEnum) |
michael@0 | 155 | { |
michael@0 | 156 | if (dwDir == DATADIR_GET) { |
michael@0 | 157 | // Clone addref's the new enumerator. |
michael@0 | 158 | m_enumFE->Clone(ppEnum); |
michael@0 | 159 | if (!(*ppEnum)) |
michael@0 | 160 | return E_FAIL; |
michael@0 | 161 | (*ppEnum)->Reset(); |
michael@0 | 162 | return S_OK; |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | return E_NOTIMPL; |
michael@0 | 166 | } |
michael@0 | 167 | |
michael@0 | 168 | STDMETHODIMP nsDataObjCollection::DAdvise(LPFORMATETC pFE, |
michael@0 | 169 | DWORD dwFlags, |
michael@0 | 170 | LPADVISESINK pIAdviseSink, |
michael@0 | 171 | DWORD* pdwConn) |
michael@0 | 172 | { |
michael@0 | 173 | return OLE_E_ADVISENOTSUPPORTED; |
michael@0 | 174 | } |
michael@0 | 175 | |
michael@0 | 176 | STDMETHODIMP nsDataObjCollection::DUnadvise(DWORD dwConn) |
michael@0 | 177 | { |
michael@0 | 178 | return OLE_E_ADVISENOTSUPPORTED; |
michael@0 | 179 | } |
michael@0 | 180 | |
michael@0 | 181 | STDMETHODIMP nsDataObjCollection::EnumDAdvise(LPENUMSTATDATA *ppEnum) |
michael@0 | 182 | { |
michael@0 | 183 | return OLE_E_ADVISENOTSUPPORTED; |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | // GetData and SetData helper functions |
michael@0 | 187 | HRESULT nsDataObjCollection::AddSetFormat(FORMATETC& aFE) |
michael@0 | 188 | { |
michael@0 | 189 | return S_OK; |
michael@0 | 190 | } |
michael@0 | 191 | |
michael@0 | 192 | HRESULT nsDataObjCollection::AddGetFormat(FORMATETC& aFE) |
michael@0 | 193 | { |
michael@0 | 194 | return S_OK; |
michael@0 | 195 | } |
michael@0 | 196 | |
michael@0 | 197 | // Registers a DataFlavor/FE pair |
michael@0 | 198 | void nsDataObjCollection::AddDataFlavor(const char * aDataFlavor, |
michael@0 | 199 | LPFORMATETC aFE) |
michael@0 | 200 | { |
michael@0 | 201 | // Add the FormatEtc to our list if it's not already there. We don't care |
michael@0 | 202 | // about the internal aDataFlavor because nsDataObj handles that. |
michael@0 | 203 | IEnumFORMATETC * ifEtc; |
michael@0 | 204 | FORMATETC fEtc; |
michael@0 | 205 | ULONG num; |
michael@0 | 206 | if (S_OK != this->EnumFormatEtc(DATADIR_GET, &ifEtc)) |
michael@0 | 207 | return; |
michael@0 | 208 | while (S_OK == ifEtc->Next(1, &fEtc, &num)) { |
michael@0 | 209 | NS_ASSERTION(1 == num, |
michael@0 | 210 | "Bit off more than we can chew in nsDataObjCollection::AddDataFlavor"); |
michael@0 | 211 | if (FormatsMatch(fEtc, *aFE)) { |
michael@0 | 212 | ifEtc->Release(); |
michael@0 | 213 | return; |
michael@0 | 214 | } |
michael@0 | 215 | } // If we didn't find a matching format, add this one |
michael@0 | 216 | ifEtc->Release(); |
michael@0 | 217 | m_enumFE->AddFormatEtc(aFE); |
michael@0 | 218 | } |
michael@0 | 219 | |
michael@0 | 220 | // We accept ownership of the nsDataObj which we free on destruction |
michael@0 | 221 | void nsDataObjCollection::AddDataObject(IDataObject * aDataObj) |
michael@0 | 222 | { |
michael@0 | 223 | nsDataObj* dataObj = reinterpret_cast<nsDataObj*>(aDataObj); |
michael@0 | 224 | mDataObjects.AppendElement(dataObj); |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | // Methods for getting data |
michael@0 | 228 | HRESULT nsDataObjCollection::GetFile(LPFORMATETC pFE, LPSTGMEDIUM pSTM) |
michael@0 | 229 | { |
michael@0 | 230 | STGMEDIUM workingmedium; |
michael@0 | 231 | FORMATETC fe = *pFE; |
michael@0 | 232 | HGLOBAL hGlobalMemory; |
michael@0 | 233 | HRESULT hr; |
michael@0 | 234 | // Make enough space for the header and the trailing null |
michael@0 | 235 | uint32_t buffersize = sizeof(DROPFILES) + sizeof(char16_t); |
michael@0 | 236 | uint32_t alloclen = 0; |
michael@0 | 237 | char16_t* realbuffer; |
michael@0 | 238 | nsAutoString filename; |
michael@0 | 239 | |
michael@0 | 240 | hGlobalMemory = GlobalAlloc(GHND, buffersize); |
michael@0 | 241 | |
michael@0 | 242 | for (uint32_t i = 0; i < mDataObjects.Length(); ++i) { |
michael@0 | 243 | nsDataObj* dataObj = mDataObjects.ElementAt(i); |
michael@0 | 244 | hr = dataObj->GetData(&fe, &workingmedium); |
michael@0 | 245 | if (hr != S_OK) { |
michael@0 | 246 | switch (hr) { |
michael@0 | 247 | case DV_E_FORMATETC: |
michael@0 | 248 | continue; |
michael@0 | 249 | default: |
michael@0 | 250 | return hr; |
michael@0 | 251 | } |
michael@0 | 252 | } |
michael@0 | 253 | // Now we need to pull out the filename |
michael@0 | 254 | char16_t* buffer = (char16_t*)GlobalLock(workingmedium.hGlobal); |
michael@0 | 255 | if (buffer == nullptr) |
michael@0 | 256 | return E_FAIL; |
michael@0 | 257 | buffer += sizeof(DROPFILES)/sizeof(char16_t); |
michael@0 | 258 | filename = buffer; |
michael@0 | 259 | GlobalUnlock(workingmedium.hGlobal); |
michael@0 | 260 | ReleaseStgMedium(&workingmedium); |
michael@0 | 261 | // Now put the filename into our buffer |
michael@0 | 262 | alloclen = (filename.Length() + 1) * sizeof(char16_t); |
michael@0 | 263 | hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, GHND); |
michael@0 | 264 | if (hGlobalMemory == nullptr) |
michael@0 | 265 | return E_FAIL; |
michael@0 | 266 | realbuffer = (char16_t*)((char*)GlobalLock(hGlobalMemory) + buffersize); |
michael@0 | 267 | if (!realbuffer) |
michael@0 | 268 | return E_FAIL; |
michael@0 | 269 | realbuffer--; // Overwrite the preceding null |
michael@0 | 270 | memcpy(realbuffer, filename.get(), alloclen); |
michael@0 | 271 | GlobalUnlock(hGlobalMemory); |
michael@0 | 272 | buffersize += alloclen; |
michael@0 | 273 | } |
michael@0 | 274 | // We get the last null (on the double null terminator) for free since we used |
michael@0 | 275 | // the zero memory flag when we allocated. All we need to do is fill the |
michael@0 | 276 | // DROPFILES structure |
michael@0 | 277 | DROPFILES* df = (DROPFILES*)GlobalLock(hGlobalMemory); |
michael@0 | 278 | if (!df) |
michael@0 | 279 | return E_FAIL; |
michael@0 | 280 | df->pFiles = sizeof(DROPFILES); //Offset to start of file name string |
michael@0 | 281 | df->fNC = 0; |
michael@0 | 282 | df->pt.x = 0; |
michael@0 | 283 | df->pt.y = 0; |
michael@0 | 284 | df->fWide = TRUE; // utf-16 chars |
michael@0 | 285 | GlobalUnlock(hGlobalMemory); |
michael@0 | 286 | // Finally fill out the STGMEDIUM struct |
michael@0 | 287 | pSTM->tymed = TYMED_HGLOBAL; |
michael@0 | 288 | pSTM->pUnkForRelease = nullptr; // Caller gets to free the data |
michael@0 | 289 | pSTM->hGlobal = hGlobalMemory; |
michael@0 | 290 | return S_OK; |
michael@0 | 291 | } |
michael@0 | 292 | |
michael@0 | 293 | HRESULT nsDataObjCollection::GetText(LPFORMATETC pFE, LPSTGMEDIUM pSTM) |
michael@0 | 294 | { |
michael@0 | 295 | STGMEDIUM workingmedium; |
michael@0 | 296 | FORMATETC fe = *pFE; |
michael@0 | 297 | HGLOBAL hGlobalMemory; |
michael@0 | 298 | HRESULT hr; |
michael@0 | 299 | uint32_t buffersize = 1; |
michael@0 | 300 | uint32_t alloclen = 0; |
michael@0 | 301 | |
michael@0 | 302 | hGlobalMemory = GlobalAlloc(GHND, buffersize); |
michael@0 | 303 | |
michael@0 | 304 | if (pFE->cfFormat == CF_TEXT) { |
michael@0 | 305 | nsAutoCString text; |
michael@0 | 306 | for (uint32_t i = 0; i < mDataObjects.Length(); ++i) { |
michael@0 | 307 | nsDataObj* dataObj = mDataObjects.ElementAt(i); |
michael@0 | 308 | hr = dataObj->GetData(&fe, &workingmedium); |
michael@0 | 309 | if (hr != S_OK) { |
michael@0 | 310 | switch (hr) { |
michael@0 | 311 | case DV_E_FORMATETC: |
michael@0 | 312 | continue; |
michael@0 | 313 | default: |
michael@0 | 314 | return hr; |
michael@0 | 315 | } |
michael@0 | 316 | } |
michael@0 | 317 | // Now we need to pull out the text |
michael@0 | 318 | char* buffer = (char*)GlobalLock(workingmedium.hGlobal); |
michael@0 | 319 | if (buffer == nullptr) |
michael@0 | 320 | return E_FAIL; |
michael@0 | 321 | text = buffer; |
michael@0 | 322 | GlobalUnlock(workingmedium.hGlobal); |
michael@0 | 323 | ReleaseStgMedium(&workingmedium); |
michael@0 | 324 | // Now put the text into our buffer |
michael@0 | 325 | alloclen = text.Length(); |
michael@0 | 326 | hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, |
michael@0 | 327 | GHND); |
michael@0 | 328 | if (hGlobalMemory == nullptr) |
michael@0 | 329 | return E_FAIL; |
michael@0 | 330 | buffer = ((char*)GlobalLock(hGlobalMemory) + buffersize); |
michael@0 | 331 | if (!buffer) |
michael@0 | 332 | return E_FAIL; |
michael@0 | 333 | buffer--; // Overwrite the preceding null |
michael@0 | 334 | memcpy(buffer, text.get(), alloclen); |
michael@0 | 335 | GlobalUnlock(hGlobalMemory); |
michael@0 | 336 | buffersize += alloclen; |
michael@0 | 337 | } |
michael@0 | 338 | pSTM->tymed = TYMED_HGLOBAL; |
michael@0 | 339 | pSTM->pUnkForRelease = nullptr; // Caller gets to free the data |
michael@0 | 340 | pSTM->hGlobal = hGlobalMemory; |
michael@0 | 341 | return S_OK; |
michael@0 | 342 | } |
michael@0 | 343 | if (pFE->cfFormat == CF_UNICODETEXT) { |
michael@0 | 344 | buffersize = sizeof(char16_t); |
michael@0 | 345 | nsAutoString text; |
michael@0 | 346 | for (uint32_t i = 0; i < mDataObjects.Length(); ++i) { |
michael@0 | 347 | nsDataObj* dataObj = mDataObjects.ElementAt(i); |
michael@0 | 348 | hr = dataObj->GetData(&fe, &workingmedium); |
michael@0 | 349 | if (hr != S_OK) { |
michael@0 | 350 | switch (hr) { |
michael@0 | 351 | case DV_E_FORMATETC: |
michael@0 | 352 | continue; |
michael@0 | 353 | default: |
michael@0 | 354 | return hr; |
michael@0 | 355 | } |
michael@0 | 356 | } |
michael@0 | 357 | // Now we need to pull out the text |
michael@0 | 358 | char16_t* buffer = (char16_t*)GlobalLock(workingmedium.hGlobal); |
michael@0 | 359 | if (buffer == nullptr) |
michael@0 | 360 | return E_FAIL; |
michael@0 | 361 | text = buffer; |
michael@0 | 362 | GlobalUnlock(workingmedium.hGlobal); |
michael@0 | 363 | ReleaseStgMedium(&workingmedium); |
michael@0 | 364 | // Now put the text into our buffer |
michael@0 | 365 | alloclen = text.Length() * sizeof(char16_t); |
michael@0 | 366 | hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, |
michael@0 | 367 | GHND); |
michael@0 | 368 | if (hGlobalMemory == nullptr) |
michael@0 | 369 | return E_FAIL; |
michael@0 | 370 | buffer = (char16_t*)((char*)GlobalLock(hGlobalMemory) + buffersize); |
michael@0 | 371 | if (!buffer) |
michael@0 | 372 | return E_FAIL; |
michael@0 | 373 | buffer--; // Overwrite the preceding null |
michael@0 | 374 | memcpy(buffer, text.get(), alloclen); |
michael@0 | 375 | GlobalUnlock(hGlobalMemory); |
michael@0 | 376 | buffersize += alloclen; |
michael@0 | 377 | } |
michael@0 | 378 | pSTM->tymed = TYMED_HGLOBAL; |
michael@0 | 379 | pSTM->pUnkForRelease = nullptr; // Caller gets to free the data |
michael@0 | 380 | pSTM->hGlobal = hGlobalMemory; |
michael@0 | 381 | return S_OK; |
michael@0 | 382 | } |
michael@0 | 383 | |
michael@0 | 384 | return E_FAIL; |
michael@0 | 385 | } |
michael@0 | 386 | |
michael@0 | 387 | HRESULT nsDataObjCollection::GetFileDescriptors(LPFORMATETC pFE, |
michael@0 | 388 | LPSTGMEDIUM pSTM) |
michael@0 | 389 | { |
michael@0 | 390 | STGMEDIUM workingmedium; |
michael@0 | 391 | FORMATETC fe = *pFE; |
michael@0 | 392 | HGLOBAL hGlobalMemory; |
michael@0 | 393 | HRESULT hr; |
michael@0 | 394 | uint32_t buffersize = sizeof(FILEGROUPDESCRIPTOR); |
michael@0 | 395 | uint32_t alloclen = sizeof(FILEDESCRIPTOR); |
michael@0 | 396 | |
michael@0 | 397 | hGlobalMemory = GlobalAlloc(GHND, buffersize); |
michael@0 | 398 | |
michael@0 | 399 | for (uint32_t i = 0; i < mDataObjects.Length(); ++i) { |
michael@0 | 400 | nsDataObj* dataObj = mDataObjects.ElementAt(i); |
michael@0 | 401 | hr = dataObj->GetData(&fe, &workingmedium); |
michael@0 | 402 | if (hr != S_OK) { |
michael@0 | 403 | switch (hr) { |
michael@0 | 404 | case DV_E_FORMATETC: |
michael@0 | 405 | continue; |
michael@0 | 406 | default: |
michael@0 | 407 | return hr; |
michael@0 | 408 | } |
michael@0 | 409 | } |
michael@0 | 410 | // Now we need to pull out the filedescriptor |
michael@0 | 411 | FILEDESCRIPTOR* buffer = |
michael@0 | 412 | (FILEDESCRIPTOR*)((char*)GlobalLock(workingmedium.hGlobal) + sizeof(UINT)); |
michael@0 | 413 | if (buffer == nullptr) |
michael@0 | 414 | return E_FAIL; |
michael@0 | 415 | hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, GHND); |
michael@0 | 416 | if (hGlobalMemory == nullptr) |
michael@0 | 417 | return E_FAIL; |
michael@0 | 418 | FILEGROUPDESCRIPTOR* realbuffer = |
michael@0 | 419 | (FILEGROUPDESCRIPTOR*)GlobalLock(hGlobalMemory); |
michael@0 | 420 | if (!realbuffer) |
michael@0 | 421 | return E_FAIL; |
michael@0 | 422 | FILEDESCRIPTOR* copyloc = (FILEDESCRIPTOR*)((char*)realbuffer + buffersize); |
michael@0 | 423 | memcpy(copyloc, buffer, sizeof(FILEDESCRIPTOR)); |
michael@0 | 424 | realbuffer->cItems++; |
michael@0 | 425 | GlobalUnlock(hGlobalMemory); |
michael@0 | 426 | GlobalUnlock(workingmedium.hGlobal); |
michael@0 | 427 | ReleaseStgMedium(&workingmedium); |
michael@0 | 428 | buffersize += alloclen; |
michael@0 | 429 | } |
michael@0 | 430 | pSTM->tymed = TYMED_HGLOBAL; |
michael@0 | 431 | pSTM->pUnkForRelease = nullptr; // Caller gets to free the data |
michael@0 | 432 | pSTM->hGlobal = hGlobalMemory; |
michael@0 | 433 | return S_OK; |
michael@0 | 434 | } |
michael@0 | 435 | |
michael@0 | 436 | HRESULT nsDataObjCollection::GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM) |
michael@0 | 437 | { |
michael@0 | 438 | ULONG num = 0; |
michael@0 | 439 | ULONG numwanted = (pFE->lindex == -1) ? 0 : pFE->lindex; |
michael@0 | 440 | FORMATETC fEtc = *pFE; |
michael@0 | 441 | fEtc.lindex = -1; // We're lying to the data object so it thinks it's alone |
michael@0 | 442 | |
michael@0 | 443 | // The key for this data type is to figure out which data object the index |
michael@0 | 444 | // corresponds to and then just pass it along |
michael@0 | 445 | for (uint32_t i = 0; i < mDataObjects.Length(); ++i) { |
michael@0 | 446 | nsDataObj* dataObj = mDataObjects.ElementAt(i); |
michael@0 | 447 | if (dataObj->QueryGetData(&fEtc) != S_OK) |
michael@0 | 448 | continue; |
michael@0 | 449 | if (num == numwanted) |
michael@0 | 450 | return dataObj->GetData(pFE, pSTM); |
michael@0 | 451 | numwanted++; |
michael@0 | 452 | } |
michael@0 | 453 | return DV_E_LINDEX; |
michael@0 | 454 | } |
michael@0 | 455 | |
michael@0 | 456 | HRESULT nsDataObjCollection::GetFirstSupporting(LPFORMATETC pFE, |
michael@0 | 457 | LPSTGMEDIUM pSTM) |
michael@0 | 458 | { |
michael@0 | 459 | // There is no way to pass more than one of this, so just find the first data |
michael@0 | 460 | // object that supports it and pass it along |
michael@0 | 461 | for (uint32_t i = 0; i < mDataObjects.Length(); ++i) { |
michael@0 | 462 | if (mDataObjects.ElementAt(i)->QueryGetData(pFE) == S_OK) |
michael@0 | 463 | return mDataObjects.ElementAt(i)->GetData(pFE, pSTM); |
michael@0 | 464 | } |
michael@0 | 465 | return DV_E_FORMATETC; |
michael@0 | 466 | } |