nsresult Do_CheckOneFile() { nsresult rv; nsCOMPtr<nsITransferable> transferable; nsCOMPtr<nsISupportsArray> transferableArray; nsCOMPtr<nsISupports> genericWrapper; nsRefPtr<IDataObject> dataObj; rv = NS_NewISupportsArray(getter_AddRefs(transferableArray)); if (NS_FAILED(rv)) { fail("Could not create the necessary nsISupportsArray"); return rv; } rv = GetTransferableFile(transferable); if (NS_FAILED(rv)) { fail("Could not create the proper nsITransferable!"); return rv; } genericWrapper = do_QueryInterface(transferable); rv = transferableArray->AppendElement(genericWrapper); if (NS_FAILED(rv)) { fail("Could not append element to transferable array"); return rv; } rv = MakeDataObject(transferableArray, dataObj); if (NS_FAILED(rv)) { fail("Could not create data object"); return rv; } FORMATETC fe; SET_FORMATETC(fe, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); if (dataObj->QueryGetData(&fe) != S_OK) { fail("File data object does not support the file data type!"); return NS_ERROR_UNEXPECTED; } STGMEDIUM* stg; stg = (STGMEDIUM*)CoTaskMemAlloc(sizeof(STGMEDIUM)); if (dataObj->GetData(&fe, stg) != S_OK) { fail("File data object did not provide data on request"); return NS_ERROR_UNEXPECTED; } rv = CheckValidHDROP(stg); if (NS_FAILED(rv)) { fail("HDROP was invalid"); return rv; } ReleaseStgMedium(stg); return NS_OK; }
//------------------------------------------------------------------------- static HRESULT FillSTGMedium(IDataObject * aDataObject, UINT aFormat, LPFORMATETC pFE, LPSTGMEDIUM pSTM, DWORD aTymed) { SET_FORMATETC(*pFE, aFormat, 0, DVASPECT_CONTENT, -1, aTymed); // Starting by querying for the data to see if we can get it as from global memory HRESULT hres = S_FALSE; hres = aDataObject->QueryGetData(pFE); DisplayErrCode(hres); if (S_OK == hres) { hres = aDataObject->GetData(pFE, pSTM); DisplayErrCode(hres); } return hres; }
//------------------------------------------------------------------------- NS_IMETHODIMP nsDragService::GetNumDropItems(uint32_t * aNumItems) { if (!mDataObject) { *aNumItems = 0; return NS_OK; } if (IsCollectionObject(mDataObject)) { nsDataObjCollection * dataObjCol = GetDataObjCollection(mDataObject); if (dataObjCol) { *aNumItems = dataObjCol->GetNumDataObjects(); } else { // If the count cannot be determined just return 0. // This can happen if we have collection data of type // MULTI_MIME ("Mozilla/IDataObjectCollectionFormat") on the clipboard // from another process but we can't obtain an IID_IDataObjCollection // from this process. *aNumItems = 0; } } else { // Next check if we have a file drop. Return the number of files in // the file drop as the number of items we have, pretending like we // actually have > 1 drag item. FORMATETC fe2; SET_FORMATETC(fe2, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); if (mDataObject->QueryGetData(&fe2) == S_OK) { STGMEDIUM stm; if (mDataObject->GetData(&fe2, &stm) == S_OK) { HDROP hdrop = (HDROP)GlobalLock(stm.hGlobal); *aNumItems = ::DragQueryFileW(hdrop, 0xFFFFFFFF, NULL, 0); ::GlobalUnlock(stm.hGlobal); ::ReleaseStgMedium(&stm); // Data may be provided later, so assume we have 1 item if (*aNumItems == 0) *aNumItems = 1; } else *aNumItems = 1; } else *aNumItems = 1; } return NS_OK; }
//------------------------------------------------------------------------- NS_IMETHODIMP nsDragService::GetData(nsITransferable * aTransferable, PRUint32 anItem) { // This typcially happens on a drop, the target would be asking // for it's transferable to be filled in // Use a static clipboard utility method for this if (!mDataObject) return NS_ERROR_FAILURE; nsresult dataFound = NS_ERROR_FAILURE; if (IsCollectionObject(mDataObject)) { // multiple items, use |anItem| as an index into our collection nsDataObjCollection * dataObjCol = GetDataObjCollection(mDataObject); PRUint32 cnt = dataObjCol->GetNumDataObjects(); if (anItem >= 0 && anItem < cnt) { IDataObject * dataObj = dataObjCol->GetDataObjectAt(anItem); dataFound = nsClipboard::GetDataFromDataObject(dataObj, 0, nsnull, aTransferable); } else NS_WARNING("Index out of range!"); } else { // If they are asking for item "0", we can just get it... if (anItem == 0) { dataFound = nsClipboard::GetDataFromDataObject(mDataObject, anItem, nsnull, aTransferable); } else { // It better be a file drop, or else non-zero indexes are invalid! FORMATETC fe2; SET_FORMATETC(fe2, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); if (mDataObject->QueryGetData(&fe2) == S_OK) dataFound = nsClipboard::GetDataFromDataObject(mDataObject, anItem, nsnull, aTransferable); else NS_WARNING("Reqesting non-zero index, but clipboard data is not a collection!"); } } return dataFound; }
// // IsCollectionObject // // Determine if this is a single |IDataObject| or one of our private // collection objects. We know the difference because our collection // object will respond to supporting the private |MULTI_MIME| format. // PRBool nsDragService::IsCollectionObject(IDataObject* inDataObj) { PRBool isCollection = PR_FALSE; // setup the format object to ask for the MULTI_MIME format. We only // need to do this once static UINT sFormat = 0; static FORMATETC sFE; if (!sFormat) { sFormat = nsClipboard::GetFormat(MULTI_MIME); SET_FORMATETC(sFE, sFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); } // ask the object if it supports it. If yes, we have a collection // object if (inDataObj->QueryGetData(&sFE) == S_OK) isCollection = PR_TRUE; return isCollection; } // IsCollectionObject
//------------------------------------------------------------------------- NS_IMETHODIMP nsDragService::IsDataFlavorSupported(const char *aDataFlavor, PRBool *_retval) { if (!aDataFlavor || !mDataObject || !_retval) return NS_ERROR_FAILURE; #ifdef NS_DEBUG if (strcmp(aDataFlavor, kTextMime) == 0) NS_WARNING("DO NOT USE THE text/plain DATA FLAVOR ANY MORE. USE text/unicode INSTEAD"); #endif *_retval = PR_FALSE; FORMATETC fe; UINT format = 0; if (IsCollectionObject(mDataObject)) { // We know we have one of our special collection objects. format = nsClipboard::GetFormat(aDataFlavor); SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI); // See if any one of the IDataObjects in the collection supports // this data type nsDataObjCollection* dataObjCol = GetDataObjCollection(mDataObject); if (dataObjCol) { PRUint32 cnt = dataObjCol->GetNumDataObjects(); for (PRUint32 i=0;i<cnt;++i) { IDataObject * dataObj = dataObjCol->GetDataObjectAt(i); if (S_OK == dataObj->QueryGetData(&fe)) *_retval = PR_TRUE; // found it! } } } // if special collection object else { // Ok, so we have a single object. Check to see if has the correct // data type. Since this can come from an outside app, we also // need to see if we need to perform text->unicode conversion if // the client asked for unicode and it wasn't available. format = nsClipboard::GetFormat(aDataFlavor); SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI); if (mDataObject->QueryGetData(&fe) == S_OK) *_retval = PR_TRUE; // found it! else { // We haven't found the exact flavor the client asked for, but // maybe we can still find it from something else that's on the // clipboard if (strcmp(aDataFlavor, kUnicodeMime) == 0) { // client asked for unicode and it wasn't present, check if we // have CF_TEXT. We'll handle the actual data substitution in // the data object. format = nsClipboard::GetFormat(kTextMime); SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI); if (mDataObject->QueryGetData(&fe) == S_OK) *_retval = PR_TRUE; // found it! } else if (strcmp(aDataFlavor, kURLMime) == 0) { // client asked for a url and it wasn't present, but if we // have a file, then we have a URL to give them (the path, or // the internal URL if an InternetShortcut). format = nsClipboard::GetFormat(kFileMime); SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI); if (mDataObject->QueryGetData(&fe) == S_OK) *_retval = PR_TRUE; // found it! } } // else try again } return NS_OK; }
//------------------------------------------------------------------------- nsresult nsClipboard::SetupNativeDataObject(nsITransferable * aTransferable, IDataObject * aDataObj) { if (nullptr == aTransferable || nullptr == aDataObj) { return NS_ERROR_FAILURE; } nsDataObj * dObj = static_cast<nsDataObj *>(aDataObj); // Now give the Transferable to the DataObject // for getting the data out of it dObj->SetTransferable(aTransferable); // Get the transferable list of data flavors nsCOMPtr<nsISupportsArray> dfList; aTransferable->FlavorsTransferableCanExport(getter_AddRefs(dfList)); // Walk through flavors that contain data and register them // into the DataObj as supported flavors PRUint32 i; PRUint32 cnt; dfList->Count(&cnt); for (i=0;i<cnt;i++) { nsCOMPtr<nsISupports> genericFlavor; dfList->GetElementAt ( i, getter_AddRefs(genericFlavor) ); nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) ); if ( currentFlavor ) { nsXPIDLCString flavorStr; currentFlavor->ToString(getter_Copies(flavorStr)); UINT format = GetFormat(flavorStr); // Now tell the native IDataObject about both our mime type and // the native data format FORMATETC fe; SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); dObj->AddDataFlavor(flavorStr, &fe); // Do various things internal to the implementation, like map one // flavor to another or add additional flavors based on what's required // for the win32 impl. if ( strcmp(flavorStr, kUnicodeMime) == 0 ) { // if we find text/unicode, also advertise text/plain (which we will convert // on our own in nsDataObj::GetText(). FORMATETC textFE; SET_FORMATETC(textFE, CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); dObj->AddDataFlavor(kTextMime, &textFE); } else if ( strcmp(flavorStr, kHTMLMime) == 0 ) { // if we find text/html, also advertise win32's html flavor (which we will convert // on our own in nsDataObj::GetText(). FORMATETC htmlFE; SET_FORMATETC(htmlFE, CF_HTML, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); dObj->AddDataFlavor(kHTMLMime, &htmlFE); } else if ( strcmp(flavorStr, kURLMime) == 0 ) { // if we're a url, in addition to also being text, we need to register // the "file" flavors so that the win32 shell knows to create an internet // shortcut when it sees one of these beasts. FORMATETC shortcutFE; SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) dObj->AddDataFlavor(kURLMime, &shortcutFE); SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) dObj->AddDataFlavor(kURLMime, &shortcutFE); SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_FILECONTENTS), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) dObj->AddDataFlavor(kURLMime, &shortcutFE); SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_INETURLA), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) dObj->AddDataFlavor(kURLMime, &shortcutFE); SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_INETURLW), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) dObj->AddDataFlavor(kURLMime, &shortcutFE); } else if ( strcmp(flavorStr, kPNGImageMime) == 0 || strcmp(flavorStr, kJPEGImageMime) == 0 || strcmp(flavorStr, kJPGImageMime) == 0 || strcmp(flavorStr, kGIFImageMime) == 0 || strcmp(flavorStr, kNativeImageMime) == 0 ) { // if we're an image, register the native bitmap flavor FORMATETC imageFE; SET_FORMATETC(imageFE, CF_DIBV5, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) dObj->AddDataFlavor(flavorStr, &imageFE); } else if ( strcmp(flavorStr, kFilePromiseMime) == 0 ) { // if we're a file promise flavor, also register the // CFSTR_PREFERREDDROPEFFECT format. The data object // returns a value of DROPEFFECTS_MOVE to the drop target // when it asks for the value of this format. This causes // the file to be moved from the temporary location instead // of being copied. The right thing to do here is to call // SetData() on the data object and set the value of this format // to DROPEFFECTS_MOVE on this particular data object. But, // since all the other clipboard formats follow the model of setting // data on the data object only when the drop object calls GetData(), // I am leaving this format's value hard coded in the data object. // We can change this if other consumers of this format get added to this // codebase and they need different values. FORMATETC shortcutFE; SET_FORMATETC(shortcutFE, ::RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT), 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL) dObj->AddDataFlavor(kFilePromiseMime, &shortcutFE); } } } return NS_OK; }
nsresult Do_CheckSetArbitraryData(bool aMultiple) { nsresult rv; nsCOMPtr<nsITransferable> transferable; nsCOMPtr<nsISupportsArray> transferableArray; nsCOMPtr<nsISupports> genericWrapper; nsRefPtr<IDataObject> dataObj; rv = NS_NewISupportsArray(getter_AddRefs(transferableArray)); if (NS_FAILED(rv)) { fail("Could not create the necessary nsISupportsArray"); return rv; } rv = GetTransferableText(transferable); if (NS_FAILED(rv)) { fail("Could not create the proper nsITransferable!"); return rv; } genericWrapper = do_QueryInterface(transferable); rv = transferableArray->AppendElement(genericWrapper); if (NS_FAILED(rv)) { fail("Could not append element to transferable array"); return rv; } if (aMultiple) { rv = GetTransferableText(transferable); if (NS_FAILED(rv)) { fail("Could not create the proper nsITransferable!"); return rv; } genericWrapper = do_QueryInterface(transferable); rv = transferableArray->AppendElement(genericWrapper); if (NS_FAILED(rv)) { fail("Could not append element to transferable array"); return rv; } } rv = MakeDataObject(transferableArray, dataObj); if (NS_FAILED(rv)) { fail("Could not create data object"); return rv; } static CLIPFORMAT mozArbitraryFormat = ::RegisterClipboardFormatW(L"MozillaTestFormat"); FORMATETC fe; STGMEDIUM stg; SET_FORMATETC(fe, mozArbitraryFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); HGLOBAL hg = GlobalAlloc(GPTR, 1024); stg.tymed = TYMED_HGLOBAL; stg.hGlobal = hg; stg.pUnkForRelease = nullptr; if (dataObj->SetData(&fe, &stg, true) != S_OK) { if (aMultiple) { fail("Unable to set arbitrary data type on data object collection!"); } else { fail("Unable to set arbitrary data type on data object!"); } return NS_ERROR_UNEXPECTED; } if (dataObj->QueryGetData(&fe) != S_OK) { fail("Arbitrary data set on data object is not advertised!"); return NS_ERROR_UNEXPECTED; } STGMEDIUM* stg2; stg2 = (STGMEDIUM*)CoTaskMemAlloc(sizeof(STGMEDIUM)); if (dataObj->GetData(&fe, stg2) != S_OK) { fail("Data object did not provide arbitrary data upon request!"); return NS_ERROR_UNEXPECTED; } if (stg2->hGlobal != hg) { fail("Arbitrary data was not returned properly!"); return rv; } ReleaseStgMedium(stg2); return NS_OK; }
nsresult Do_CheckTwoStrings() { nsresult rv; nsCOMPtr<nsITransferable> transferable; nsCOMPtr<nsIMutableArray> transferableArray = nsArray::Create(); nsCOMPtr<nsISupports> genericWrapper; RefPtr<IDataObject> dataObj; rv = GetTransferableText(transferable); if (NS_FAILED(rv)) { fail("Could not create the proper nsITransferable!"); return rv; } genericWrapper = do_QueryInterface(transferable); rv = transferableArray->AppendElement(genericWrapper); if (NS_FAILED(rv)) { fail("Could not append element to transferable array"); return rv; } rv = GetTransferableTextTwo(transferable); if (NS_FAILED(rv)) { fail("Could not create the proper nsITransferable!"); return rv; } genericWrapper = do_QueryInterface(transferable); rv = transferableArray->AppendElement(genericWrapper); if (NS_FAILED(rv)) { fail("Could not append element to transferable array"); return rv; } rv = MakeDataObject(transferableArray, dataObj); if (NS_FAILED(rv)) { fail("Could not create data object"); return rv; } FORMATETC fe; SET_FORMATETC(fe, CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); if (dataObj->QueryGetData(&fe) != S_OK) { fail("String data object does not support the ASCII text data type!"); return NS_ERROR_UNEXPECTED; } STGMEDIUM* stg; stg = (STGMEDIUM*)CoTaskMemAlloc(sizeof(STGMEDIUM)); if (dataObj->GetData(&fe, stg) != S_OK) { fail("String data object did not provide ASCII data on request"); return NS_ERROR_UNEXPECTED; } rv = CheckValidTEXTTwo(stg); if (NS_FAILED(rv)) { fail("TEXT was invalid"); return rv; } ReleaseStgMedium(stg); SET_FORMATETC(fe, CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL); if (dataObj->QueryGetData(&fe) != S_OK) { fail("String data object does not support the wide text data type!"); return NS_ERROR_UNEXPECTED; } if (dataObj->GetData(&fe, stg) != S_OK) { fail("String data object did not provide wide data on request"); return NS_ERROR_UNEXPECTED; } rv = CheckValidUNICODETwo(stg); if (NS_FAILED(rv)) { fail("UNICODE was invalid"); return rv; } return NS_OK; }