Back out the patch from bug 267426 to fix Thunderbird (prometheus) build bustage.

This commit is contained in:
gavin%gavinsharp.com 2006-07-14 01:48:51 +00:00
parent d5b7146c6a
commit 3848b35d36
4 changed files with 510 additions and 514 deletions

View File

@ -68,7 +68,6 @@
#include "nsEscape.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsXPCOMStrings.h"
#if 0
#define PRNTDEBUG(_x) printf(_x);
@ -80,186 +79,6 @@
#define PRNTDEBUG3(_x1, _x2, _x3) // printf(_x1, _x2, _x3);
#endif
//-----------------------------------------------------------------------------
// CStream implementation
nsDataObj::CStream::CStream() : mRefCount(1)
{
}
//-----------------------------------------------------------------------------
nsDataObj::CStream::~CStream()
{
}
//-----------------------------------------------------------------------------
// helper - initializes the stream
nsresult nsDataObj::CStream::Init(nsIURI *pSourceURI)
{
nsresult rv;
rv = NS_NewChannel(getter_AddRefs(mChannel), pSourceURI);
NS_ENSURE_SUCCESS(rv, rv);
rv = mChannel->Open(getter_AddRefs(mInputStream));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
//-----------------------------------------------------------------------------
// IUnknown
STDMETHODIMP nsDataObj::CStream::QueryInterface(REFIID refiid, void** ppvResult)
{
*ppvResult = NULL;
if (IID_IUnknown == refiid ||
refiid == IID_IStream)
{
*ppvResult = this;
}
if (NULL != *ppvResult)
{
((LPUNKNOWN)*ppvResult)->AddRef();
return S_OK;
}
return ResultFromScode(E_NOINTERFACE);
}
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) nsDataObj::CStream::AddRef(void)
{
return ++mRefCount;
}
//-----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) nsDataObj::CStream::Release(void)
{
ULONG nCount = --mRefCount;
if (nCount == 0)
{
delete this;
return (ULONG)0;
}
return mRefCount;
}
//-----------------------------------------------------------------------------
// IStream
STDMETHODIMP nsDataObj::CStream::Clone(IStream** ppStream)
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
STDMETHODIMP nsDataObj::CStream::Commit(DWORD dwFrags)
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
STDMETHODIMP nsDataObj::CStream::CopyTo(IStream* pDestStream,
ULARGE_INTEGER nBytesToCopy,
ULARGE_INTEGER* nBytesRead,
ULARGE_INTEGER* nBytesWritten)
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
STDMETHODIMP nsDataObj::CStream::LockRegion(ULARGE_INTEGER nStart,
ULARGE_INTEGER nBytes,
DWORD dwFlags)
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
STDMETHODIMP nsDataObj::CStream::Read(void* pvBuffer,
ULONG nBytesToRead,
ULONG* nBytesRead)
{
NS_ENSURE_TRUE(mInputStream, E_FAIL);
nsresult rv;
PRUint32 read = 0;
rv = mInputStream->Read((char*)pvBuffer, nBytesToRead, &read);
*nBytesRead = read;
NS_ENSURE_SUCCESS(rv, S_FALSE);
return S_OK;
}
//-----------------------------------------------------------------------------
STDMETHODIMP nsDataObj::CStream::Revert(void)
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
STDMETHODIMP nsDataObj::CStream::Seek(LARGE_INTEGER nMove,
DWORD dwOrigin,
ULARGE_INTEGER* nNewPos)
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
STDMETHODIMP nsDataObj::CStream::SetSize(ULARGE_INTEGER nNewSize)
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
STDMETHODIMP nsDataObj::CStream::Stat(STATSTG* statstg, DWORD dwFlags)
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
STDMETHODIMP nsDataObj::CStream::UnlockRegion(ULARGE_INTEGER nStart,
ULARGE_INTEGER nBytes,
DWORD dwFlags)
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
STDMETHODIMP nsDataObj::CStream::Write(const void* pvBuffer,
ULONG nBytesToRead,
ULONG* nBytesRead)
{
return E_NOTIMPL;
}
//-----------------------------------------------------------------------------
HRESULT nsDataObj::CreateStream(IStream **outStream)
{
NS_ENSURE_TRUE(outStream, E_INVALIDARG);
nsresult rv = NS_ERROR_FAILURE;
nsAutoString wideFileName;
nsCOMPtr<nsIURI> sourceURI;
rv = GetDownloadDetails(getter_AddRefs(sourceURI),
wideFileName);
NS_ENSURE_SUCCESS(rv, rv);
nsDataObj::CStream *pStream = new nsDataObj::CStream();
NS_ENSURE_TRUE(pStream, E_OUTOFMEMORY);
rv = pStream->Init(sourceURI);
if (NS_FAILED(rv))
{
pStream->Release();
return E_FAIL;
}
*outStream = pStream;
return S_OK;
}
ULONG nsDataObj::g_cRef = 0;
EXTERN_C GUID CDECL CLSID_nsDataObj =
@ -294,9 +113,6 @@ nsDataObj::nsDataObj(nsIURI * uri)
// so it can create a SourceURL for CF_HTML flavour
uri->GetSpec(mSourceURL);
}
mIsAsyncMode = FALSE;
mIsInOperation = FALSE;
}
//-----------------------------------------------------
// destruction
@ -328,12 +144,8 @@ STDMETHODIMP nsDataObj::QueryInterface(REFIID riid, void** ppv)
if ( (IID_IUnknown == riid) || (IID_IDataObject == riid) ) {
*ppv = this;
AddRef();
return S_OK;
} else if (IID_IAsyncOperation == riid) {
*ppv = static_cast<IAsyncOperation*>(this);
AddRef();
return S_OK;
}
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
@ -413,7 +225,11 @@ STDMETHODIMP nsDataObj::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
case CF_TEXT:
case CF_UNICODETEXT:
return GetText(*df, *pFE, *pSTM);
#ifndef WINCE
case CF_HDROP:
return GetFile(*df, *pFE, *pSTM);
#endif
// Someone is asking for an image
case CF_DIB:
return GetDib(*df, *pFE, *pSTM);
@ -566,48 +382,6 @@ STDMETHODIMP nsDataObj::EnumDAdvise(LPENUMSTATDATA *ppEnum)
return ResultFromScode(E_FAIL);
}
// IAsyncOperation methods
STDMETHODIMP nsDataObj::EndOperation(HRESULT hResult,
IBindCtx *pbcReserved,
DWORD dwEffects)
{
mIsInOperation = FALSE;
Release();
return S_OK;
}
STDMETHODIMP nsDataObj::GetAsyncMode(BOOL *pfIsOpAsync)
{
if (!pfIsOpAsync)
return E_FAIL;
*pfIsOpAsync = mIsAsyncMode;
return S_OK;
}
STDMETHODIMP nsDataObj::InOperation(BOOL *pfInAsyncOp)
{
if (!pfInAsyncOp)
return E_FAIL;
*pfInAsyncOp = mIsInOperation;
return S_OK;
}
STDMETHODIMP nsDataObj::SetAsyncMode(BOOL fDoOpAsync)
{
mIsAsyncMode = fDoOpAsync;
return S_OK;
}
STDMETHODIMP nsDataObj::StartOperation(IBindCtx *pbcReserved)
{
mIsInOperation = TRUE;
return S_OK;
}
//-----------------------------------------------------
// other methods
//-----------------------------------------------------
@ -706,21 +480,12 @@ nsDataObj :: GetFileDescriptor ( FORMATETC& aFE, STGMEDIUM& aSTG, PRBool aIsUnic
// How we handle this depends on if we're dealing with an internet
// shortcut, since those are done under the covers.
if (IsFlavourPresent(kFilePromiseMime) ||
IsFlavourPresent(kFileMime))
{
if (aIsUnicode)
return GetFileDescriptor_IStreamW(aFE, aSTG);
else
return GetFileDescriptor_IStreamA(aFE, aSTG);
}
else if (IsFlavourPresent(kURLMime))
{
if ( IsInternetShortcut() ) {
if ( aIsUnicode )
res = GetFileDescriptorInternetShortcutW ( aFE, aSTG );
else
res = GetFileDescriptorInternetShortcutA ( aFE, aSTG );
}
}
else
NS_WARNING ( "Not yet implemented\n" );
@ -737,11 +502,8 @@ nsDataObj :: GetFileContents ( FORMATETC& aFE, STGMEDIUM& aSTG )
// How we handle this depends on if we're dealing with an internet
// shortcut, since those are done under the covers.
if (IsFlavourPresent(kFilePromiseMime) ||
IsFlavourPresent(kFileMime))
return GetFileContents_IStream(aFE, aSTG);
else if (IsFlavourPresent(kURLMime))
return GetFileContentsInternetShortcut ( aFE, aSTG );
if ( IsInternetShortcut() )
res = GetFileContentsInternetShortcut ( aFE, aSTG );
else
NS_WARNING ( "Not yet implemented\n" );
@ -892,11 +654,11 @@ nsDataObj :: GetFileDescriptorInternetShortcutA ( FORMATETC& aFE, STGMEDIUM& aST
// get a valid filename in the following order: 1) from the page title,
// 2) localized string for an untitled page, 3) just use "Untitled.URL"
if (!CreateFilenameFromTextA(title, ".URL",
fileGroupDescA->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) {
fileGroupDescA->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) {
nsXPIDLString untitled;
if (!GetLocalizedString(NS_LITERAL_STRING("noPageTitle").get(), untitled) ||
!CreateFilenameFromTextA(untitled, ".URL",
fileGroupDescA->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) {
fileGroupDescA->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) {
strcpy(fileGroupDescA->fgd[0].cFileName, "Untitled.URL");
}
}
@ -938,11 +700,11 @@ nsDataObj :: GetFileDescriptorInternetShortcutW ( FORMATETC& aFE, STGMEDIUM& aST
// get a valid filename in the following order: 1) from the page title,
// 2) localized string for an untitled page, 3) just use "Untitled.URL"
if (!CreateFilenameFromTextW(title, NS_LITERAL_STRING(".URL").get(),
fileGroupDescW->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) {
fileGroupDescW->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) {
nsXPIDLString untitled;
if (!GetLocalizedString(NS_LITERAL_STRING("noPageTitle").get(), untitled) ||
!CreateFilenameFromTextW(untitled, NS_LITERAL_STRING(".URL").get(),
fileGroupDescW->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) {
fileGroupDescW->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) {
wcscpy(fileGroupDescW->fgd[0].cFileName, NS_LITERAL_STRING("Untitled.URL").get());
}
}
@ -1009,28 +771,39 @@ nsDataObj :: GetFileContentsInternetShortcut ( FORMATETC& aFE, STGMEDIUM& aSTG )
#endif
} // GetFileContentsInternetShortcut
// check if specified flavour is present in the transferable
PRBool nsDataObj :: IsFlavourPresent(const char *inFlavour)
//
// IsInternetShortcut
//
// Is the data that we're handling destined for an internet shortcut if
// dragged to the desktop? We can tell because there will be a mime type
// of |kURLMime| present in the transferable
//
PRBool
nsDataObj :: IsInternetShortcut ( )
{
PRBool retval = PR_FALSE;
NS_ENSURE_TRUE(mTransferable, PR_FALSE);
if ( !mTransferable )
return PR_FALSE;
// get the list of flavors available in the transferable
nsCOMPtr<nsISupportsArray> flavorList;
mTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
NS_ENSURE_TRUE(flavorList, PR_FALSE);
// try to find requested flavour
mTransferable->FlavorsTransferableCanExport ( getter_AddRefs(flavorList) );
if ( !flavorList )
return PR_FALSE;
// go spelunking for the url flavor
PRUint32 cnt;
flavorList->Count(&cnt);
for (PRUint32 i = 0; i < cnt; ++i) {
for ( PRUint32 i = 0;i < cnt; ++i ) {
nsCOMPtr<nsISupports> genericFlavor;
flavorList->GetElementAt (i, getter_AddRefs(genericFlavor));
nsCOMPtr<nsISupportsCString> currentFlavor (do_QueryInterface(genericFlavor));
if (currentFlavor) {
nsCAutoString flavorStr;
currentFlavor->GetData(flavorStr);
if (flavorStr.Equals(inFlavour)) {
if ( flavorStr.Equals(kURLMime) ) {
retval = PR_TRUE; // found it!
break;
}
@ -1038,7 +811,8 @@ PRBool nsDataObj :: IsFlavourPresent(const char *inFlavour)
} // for each flavor
return retval;
}
} // IsInternetShortcut
HRESULT nsDataObj::GetPreferredDropEffect ( FORMATETC& aFE, STGMEDIUM& aSTG )
{
@ -1161,6 +935,93 @@ HRESULT nsDataObj::GetText(const nsACString & aDataFlavor, FORMATETC& aFE, STGME
return ResultFromScode(S_OK);
}
//-----------------------------------------------------
HRESULT nsDataObj::GetFile(const nsACString & aDataFlavor, FORMATETC& aFE, STGMEDIUM& aSTG)
{
HRESULT res = S_OK;
if (strcmp(PromiseFlatCString(aDataFlavor).get(), kFilePromiseMime) == 0) {
// If we have a cached file just pass it to HGLOBAL
// otherwise create an empty file in the temp location.
// The download will start after the user drops the file.
nsresult rv;
if (!mCachedTempFile) {
// Get system temp directory
nsCOMPtr<nsILocalFile> dropDirectory;
nsCOMPtr<nsIProperties> directoryService =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
if (!directoryService || NS_FAILED(rv))
return ResultFromScode(E_FAIL);
directoryService->Get(NS_OS_TEMP_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(dropDirectory));
nsCOMPtr<nsILocalFile> destFile = do_QueryInterface(dropDirectory);
if (!destFile)
return E_FAIL;
// Get the filename form the kFilePromiseURLFlavour
nsAutoString wideFileName;
nsCOMPtr<nsIURI> sourceURI;
rv = nsDataObj::GetDownloadDetails(mTransferable,
getter_AddRefs(sourceURI),
wideFileName);
if (NS_FAILED(rv))
return rv;
rv = destFile->Append(wideFileName);
if (NS_FAILED(rv))
return rv;
// Try to create the file.
rv = destFile->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
// Bail out if it fails for a reason other than the existence of the file.
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)
return rv;
mCachedTempFile = do_QueryInterface(destFile);
if (!mCachedTempFile)
return ResultFromScode(E_FAIL);
}
// Pass the file name back to the drop target so that it can copy to the drop location
nsAutoString path;
rv = mCachedTempFile->GetPath(path);
if (NS_FAILED(rv)) return ResultFromScode(E_FAIL);
// Two null characters are needed to terminate the file name list
PRUint32 allocLen = path.Length() + 2;
HGLOBAL hGlobalMemory = NULL;
aSTG.tymed = TYMED_HGLOBAL;
aSTG.pUnkForRelease = NULL;
hGlobalMemory = GlobalAlloc(GMEM_MOVEABLE, sizeof(DROPFILES) + allocLen * sizeof(PRUnichar));
if (hGlobalMemory) {
DROPFILES* pDropFile = NS_REINTERPRET_CAST(DROPFILES*, GlobalLock(hGlobalMemory));
// First, populate drop file structure
pDropFile->pFiles = sizeof(DROPFILES); // offset to start of file name char array
pDropFile->fNC = 0;
pDropFile->pt.x = 0;
pDropFile->pt.y = 0;
pDropFile->fWide = TRUE;
// Copy the filename right after the DROPFILES structure
PRUnichar* dest = NS_REINTERPRET_CAST(PRUnichar*, NS_REINTERPRET_CAST(char*, pDropFile) + pDropFile->pFiles);
memcpy(dest, path.get(), (allocLen - 1) * sizeof(PRUnichar)); // copies the null character in path as well
// Two null characters are needed at the end of the file name.
// Lookup the CF_HDROP shell clipboard format for more info.
// Add the second null character right after the first one.
dest[allocLen - 1] = L'\0';
GlobalUnlock(hGlobalMemory);
}
else {
res = E_OUTOFMEMORY;
}
aSTG.hGlobal = hGlobalMemory;
}
return res;
}
//-----------------------------------------------------
HRESULT nsDataObj::GetMetafilePict(FORMATETC&, STGMEDIUM&)
{
@ -1224,11 +1085,14 @@ void nsDataObj::AddDataFlavor(const char* aDataFlavor, LPFORMATETC aFE)
// so we will look up data flavor that corresponds to the FE
// and then ask the transferable for that type of data
// Just ignore the CF_HDROP here
// all file drags are now hangled by CFSTR_FileContents format
// Add CF_HDROP to the head of the list so that it is returned first
// when the drop target calls EnumFormatEtc to enumerate through the FE list
// We use the CF_HDROP format to copy file contents when an image is dragged
// from Mozilla to a drop target.
#ifndef WINCE
if (aFE->cfFormat == CF_HDROP) {
return;
mDataFlavors->InsertElementAt(new nsCAutoString(aDataFlavor), 0);
m_enumFE->InsertFEAt(aFE, 0);
}
else
#endif
@ -1452,7 +1316,7 @@ HRESULT
nsDataObj :: GetUniformResourceLocator( FORMATETC& aFE, STGMEDIUM& aSTG, PRBool aIsUnicode )
{
HRESULT res = S_OK;
if (IsFlavourPresent(kURLMime)) {
if ( IsInternetShortcut() ) {
if ( aIsUnicode )
res = ExtractUniformResourceLocatorW( aFE, aSTG );
else
@ -1520,145 +1384,58 @@ nsDataObj::ExtractUniformResourceLocatorW(FORMATETC& aFE, STGMEDIUM& aSTG )
return result;
}
// Gets the filename from the kFilePromiseURLMime flavour
nsresult nsDataObj::GetDownloadDetails(nsIURI **aSourceURI,
nsresult nsDataObj::GetDownloadDetails(nsITransferable *aTransferable,
nsIURI **aSourceURI,
nsAString &aFilename)
{
NS_ENSURE_TRUE(mTransferable, NS_ERROR_FAILURE);
if (!aTransferable)
return NS_ERROR_FAILURE;
// get the URI from the kFilePromiseURLMime flavor
nsCOMPtr<nsISupports> urlPrimitive;
PRUint32 dataSize = 0;
mTransferable->GetTransferData(kFilePromiseURLMime, getter_AddRefs(urlPrimitive), &dataSize);
nsCOMPtr<nsISupportsString> srcUrlPrimitive = do_QueryInterface(urlPrimitive);
NS_ENSURE_TRUE(srcUrlPrimitive, NS_ERROR_FAILURE);
// Get data for flavor
// The format of the data is (URLSTRING\nFILENAME)
nsAutoString strData;
srcUrlPrimitive->GetData(strData);
if (strData.IsEmpty())
return NS_ERROR_FAILURE;
// get the URI from the kFilePromiseURLMime flavor
nsCOMPtr<nsISupports> urlPrimitive;
PRUint32 dataSize = 0;
aTransferable->GetTransferData(kFilePromiseURLMime, getter_AddRefs(urlPrimitive), &dataSize);
nsCOMPtr<nsISupportsString> srcUrlPrimitive = do_QueryInterface(urlPrimitive);
if (!srcUrlPrimitive)
return NS_ERROR_FAILURE;
// Now figure if there is a "\n" delimiter in the data string.
// If there is, the string after the "\n" is a filename.
// If there is no delimiter then just get the filename from the url.
nsCAutoString strFileName;
nsCOMPtr<nsIURI> sourceURI;
// New line char is used as a delimiter (hardcoded)
PRInt32 nPos = strData.FindChar('\n');
// Store source uri
NS_NewURI(aSourceURI, Substring(strData, 0, nPos));
if (nPos != -1) {
// if there is delimiter
CopyUTF16toUTF8(Substring(strData, nPos + 1, strData.Length()), strFileName);
} else {
// no filename was supplied - try to get it from a URL
nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(*aSourceURI);
sourceURL->GetFileName(strFileName);
}
// check for an error; the URL must point to a file
if (strFileName.IsEmpty())
return NS_ERROR_FAILURE;
// Get data for flavor
// The format of the data is (URLSTRING\nFILENAME)
nsAutoString strData;
srcUrlPrimitive->GetData(strData);
if (strData.IsEmpty())
return NS_ERROR_FAILURE;
NS_UnescapeURL(strFileName);
NS_ConvertUTF8toUTF16 wideFileName(strFileName);
// Now figure if there is a "\n" delimiter in the data string.
// If there is, the string after the "\n" is a filename.
// If there is no delimiter then just get the filename from the url.
nsCAutoString strFileName;
nsCOMPtr<nsIURI> sourceURI;
// New line char is used as a delimiter (hardcoded)
PRInt32 nPos = strData.FindChar('\n');
// Store source uri
NS_NewURI(aSourceURI, Substring(strData, 0, nPos));
if (nPos != -1) {
// if there is delimiter
CopyUTF16toUTF8(Substring(strData, nPos + 1, strData.Length()), strFileName);
} else {
// no filename was supplied - try to get it from a URL
nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(*aSourceURI);
sourceURL->GetFileName(strFileName);
}
// check for an error; the URL must point to a file
if (strFileName.IsEmpty())
return NS_ERROR_FAILURE;
// make the name safe for the filesystem
MangleTextToValidFilename(wideFileName);
NS_UnescapeURL(strFileName);
NS_ConvertUTF8toUTF16 wideFileName(strFileName);
aFilename = wideFileName;
// make the name safe for the filesystem
MangleTextToValidFilename(wideFileName);
return NS_OK;
aFilename = wideFileName;
return NS_OK;
}
HRESULT nsDataObj::GetFileDescriptor_IStreamA(FORMATETC& aFE, STGMEDIUM& aSTG)
{
HGLOBAL fileGroupDescHandle = ::GlobalAlloc(GMEM_ZEROINIT|GMEM_SHARE,sizeof(FILEGROUPDESCRIPTORW));
NS_ENSURE_TRUE(fileGroupDescHandle, E_OUTOFMEMORY);
LPFILEGROUPDESCRIPTORA fileGroupDescA = NS_REINTERPRET_CAST(LPFILEGROUPDESCRIPTORA,
::GlobalLock(fileGroupDescHandle));
if (!fileGroupDescA) {
::GlobalFree(fileGroupDescHandle);
return E_OUTOFMEMORY;
}
nsAutoString wideFileName;
nsresult rv;
nsCOMPtr<nsIURI> sourceURI;
rv = GetDownloadDetails(getter_AddRefs(sourceURI),
wideFileName);
if (NS_FAILED(rv))
{
::GlobalFree(fileGroupDescHandle);
return E_FAIL;
}
nsCAutoString nativeFileName;
NS_UTF16ToCString(wideFileName, NS_CSTRING_ENCODING_NATIVE_FILESYSTEM, nativeFileName);
strncpy(fileGroupDescA->fgd[0].cFileName, nativeFileName.get(), NS_MAX_FILEDESCRIPTOR - 1);
fileGroupDescA->fgd[0].cFileName[NS_MAX_FILEDESCRIPTOR - 1] = '\0';
// one file in the file block
fileGroupDescA->cItems = 1;
fileGroupDescA->fgd[0].dwFlags = FD_PROGRESSUI;
::GlobalUnlock( fileGroupDescHandle );
aSTG.hGlobal = fileGroupDescHandle;
aSTG.tymed = TYMED_HGLOBAL;
return S_OK;
}
HRESULT nsDataObj::GetFileDescriptor_IStreamW(FORMATETC& aFE, STGMEDIUM& aSTG)
{
HGLOBAL fileGroupDescHandle = ::GlobalAlloc(GMEM_ZEROINIT|GMEM_SHARE,sizeof(FILEGROUPDESCRIPTORW));
NS_ENSURE_TRUE(fileGroupDescHandle, E_OUTOFMEMORY);
LPFILEGROUPDESCRIPTORW fileGroupDescW = NS_REINTERPRET_CAST(LPFILEGROUPDESCRIPTORW,
::GlobalLock(fileGroupDescHandle));
if (!fileGroupDescW) {
::GlobalFree(fileGroupDescHandle);
return E_OUTOFMEMORY;
}
nsAutoString wideFileName;
nsresult rv;
nsCOMPtr<nsIURI> sourceURI;
rv = GetDownloadDetails(getter_AddRefs(sourceURI),
wideFileName);
if (NS_FAILED(rv))
{
::GlobalFree(fileGroupDescHandle);
return E_FAIL;
}
wcsncpy(fileGroupDescW->fgd[0].cFileName, wideFileName.get(), NS_MAX_FILEDESCRIPTOR - 1);
fileGroupDescW->fgd[0].cFileName[NS_MAX_FILEDESCRIPTOR - 1] = '\0';
// one file in the file block
fileGroupDescW->cItems = 1;
fileGroupDescW->fgd[0].dwFlags = FD_PROGRESSUI;
::GlobalUnlock(fileGroupDescHandle);
aSTG.hGlobal = fileGroupDescHandle;
aSTG.tymed = TYMED_HGLOBAL;
return S_OK;
}
HRESULT nsDataObj::GetFileContents_IStream(FORMATETC& aFE, STGMEDIUM& aSTG)
{
IStream *pStream = NULL;
nsDataObj::CreateStream(&pStream);
NS_ENSURE_TRUE(pStream, E_FAIL);
aSTG.tymed = TYMED_ISTREAM;
aSTG.pstm = pStream;
aSTG.pUnkForRelease = pStream;
return S_OK;
}

View File

@ -48,8 +48,6 @@
#include "nsString.h"
#include "nsILocalFile.h"
#include "nsIURI.h"
#include "nsIInputStream.h"
#include "nsIChannel.h"
#define MAX_FORMATS 32
@ -114,8 +112,7 @@ class nsITransferable;
* can be adapted by an object derived from CfDragDrop. The CfDragDrop is
* associated with instances via SetDragDrop().
*/
class nsDataObj : public IDataObject,
public IAsyncOperation
class nsDataObj : public IDataObject
{
public: // construction, destruction
nsDataObj(nsIURI *uri = nsnull);
@ -180,13 +177,6 @@ class nsDataObj : public IDataObject,
// object.
STDMETHODIMP EnumDAdvise (LPENUMSTATDATA *ppEnum);
// IAsyncOperation methods
STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects);
STDMETHOD(GetAsyncMode)(BOOL *pfIsOpAsync);
STDMETHOD(InOperation)(BOOL *pfInAsyncOp);
STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync);
STDMETHOD(StartOperation)(IBindCtx *pbcReserved);
public: // other methods
// Return the total reference counts of all instances of this class.
@ -197,17 +187,20 @@ class nsDataObj : public IDataObject,
ULONG GetRefCount() const;
// Gets the filename from the kFilePromiseURLMime flavour
nsresult GetDownloadDetails(nsIURI **aSourceURI,
nsAString &aFilename);
static nsresult GetDownloadDetails(nsITransferable *aTransferable,
nsIURI **aSourceURI,
nsAString &aFilename);
protected:
// help determine the kind of drag
PRBool IsFlavourPresent(const char *inFlavour);
// Help determine if the drag should create an internet shortcut
PRBool IsInternetShortcut ( ) ;
virtual HRESULT AddSetFormat(FORMATETC& FE);
virtual HRESULT AddGetFormat(FORMATETC& FE);
virtual HRESULT GetText ( const nsACString& aDF, FORMATETC& aFE, STGMEDIUM & aSTG );
virtual HRESULT GetFile ( const nsACString& aDF, FORMATETC& aFE, STGMEDIUM& aSTG );
virtual HRESULT GetBitmap ( const nsACString& inFlavor, FORMATETC& FE, STGMEDIUM& STM);
virtual HRESULT GetDib ( const nsACString& inFlavor, FORMATETC &, STGMEDIUM & aSTG );
virtual HRESULT GetMetafilePict(FORMATETC& FE, STGMEDIUM& STM);
@ -229,11 +222,6 @@ class nsDataObj : public IDataObject,
virtual HRESULT GetFileDescriptorInternetShortcutW ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
virtual HRESULT GetFileContentsInternetShortcut ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
// IStream implementation
virtual HRESULT GetFileDescriptor_IStreamA ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
virtual HRESULT GetFileDescriptor_IStreamW ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
virtual HRESULT GetFileContents_IStream ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
nsresult ExtractShortcutURL ( nsString & outURL ) ;
nsresult ExtractShortcutTitle ( nsString & outTitle ) ;
@ -259,47 +247,6 @@ class nsDataObj : public IDataObject,
// nsDataObj owns and ref counts CEnumFormatEtc,
nsCOMPtr<nsILocalFile> mCachedTempFile;
BOOL mIsAsyncMode;
BOOL mIsInOperation;
///////////////////////////////////////////////////////////////////////////////
// CStream class implementation
// this class is used in Drag and drop with download sample
// called from IDataObject::GetData
class CStream : public IStream
{
ULONG mRefCount; // reference counting
nsCOMPtr<nsIInputStream> mInputStream;
nsCOMPtr<nsIChannel> mChannel;
protected:
virtual ~CStream();
// TODO: forbid copying and assignment
public:
CStream();
nsresult Init(nsIURI *pSourceURI);
// IUnknown
STDMETHOD(QueryInterface)(REFIID refiid, void** ppvResult);
STDMETHOD_(ULONG, AddRef)(void);
STDMETHOD_(ULONG, Release)(void);
// IStream
STDMETHOD(Clone)(IStream** ppStream);
STDMETHOD(Commit)(DWORD dwFrags);
STDMETHOD(CopyTo)(IStream* pDestStream, ULARGE_INTEGER nBytesToCopy, ULARGE_INTEGER* nBytesRead, ULARGE_INTEGER* nBytesWritten);
STDMETHOD(LockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags);
STDMETHOD(Read)(void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
STDMETHOD(Revert)(void);
STDMETHOD(Seek)(LARGE_INTEGER nMove, DWORD dwOrigin, ULARGE_INTEGER* nNewPos);
STDMETHOD(SetSize)(ULARGE_INTEGER nNewSize);
STDMETHOD(Stat)(STATSTG* statstg, DWORD dwFlags);
STDMETHOD(UnlockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags);
STDMETHOD(Write)(const void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
};
HRESULT CreateStream(IStream **outStream);
};

View File

@ -41,7 +41,6 @@
#include <ole2.h>
#include <oleidl.h>
#include <shlobj.h>
#include <shlwapi.h>
// shellapi.h is needed to build with WIN32_LEAN_AND_MEAN
#include <shellapi.h>
@ -72,6 +71,10 @@
#include "nsDirectoryServiceDefs.h"
#include "nsUnicharUtils.h"
// Static member declaration
PRUnichar *nsDragService::mDropPath;
PRUnichar *nsDragService::mFileName;
//-------------------------------------------------------------------------
//
// DragService constructor
@ -89,6 +92,11 @@ nsDragService::nsDragService()
//-------------------------------------------------------------------------
nsDragService::~nsDragService()
{
if (mFileName)
NS_Free(mFileName);
if (mDropPath)
NS_Free(mDropPath);
NS_IF_RELEASE(mNativeDragSrc);
NS_IF_RELEASE(mNativeDragTarget);
NS_IF_RELEASE(mDataObject);
@ -158,8 +166,110 @@ nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
}
} // else dragging a single object
// Before starting get the file name to monitor if there is any
nsAutoString strData; // holds kFilePromiseURLMime flavour data
PRBool bDownload = PR_FALSE; // Used after drag ends to fugure if the download should start
nsCOMPtr<nsIURI> sourceURI;
nsCOMPtr<nsISupports> urlPrimitive;
nsCOMPtr<nsISupports> transSupports;
anArrayTransferables->GetElementAt(0, getter_AddRefs(transSupports));
nsCOMPtr<nsITransferable> trans = (do_QueryInterface(transSupports));
if (trans) {
// Get the filename form the kFilePromiseURLFlavour
nsAutoString wideFileName;
// if this fails there is no kFilePromiseMime flavour or no filename
rv = nsDataObj::GetDownloadDetails(trans,
getter_AddRefs(sourceURI),
wideFileName);
if (SUCCEEDED(rv))
{
// Start listening to the shell notifications
if (StartWatchingShell(wideFileName)) {
// Set download flag if all went ok so far
bDownload = PR_TRUE;
}
}
}
// Kick off the native drag session
return StartInvokingDragSession(itemToDrag, aActionType);
rv = StartInvokingDragSession(itemToDrag, aActionType);
// Check if the download flag was set
// if not then we are done
if (!bDownload)
return rv;
if (NS_FAILED(rv)) // See if dragsession failed
{
::DestroyWindow(mHiddenWnd);
return rv;
}
// Construct target URI from nsILocalFile
// Init file for the download
nsCOMPtr<nsILocalFile> dropLocalFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
if (!dropLocalFile)
{
::DestroyWindow(mHiddenWnd);
return NS_ERROR_FAILURE;
}
// init with path we get from GetDropPath
// if it fails then there is no target path.
// This could happen if the drag operation was cancelled.
nsAutoString fileName;
if (!GetDropPath(fileName))
return NS_OK;
// hidden window is destroyed by now
rv = dropLocalFile->InitWithPath(fileName);
if (NS_FAILED(rv))
return rv;
// set the directory promise flavour
// if this fails it won't affect the drag so we can just continue
trans->SetTransferData(kFilePromiseDirectoryMime,
dropLocalFile,
sizeof(nsILocalFile*));
// Create a new FileURI to pass to the nsIDownload
nsCOMPtr<nsIURI> targetURI;
nsCOMPtr<nsIFile> file = do_QueryInterface(dropLocalFile);
if (!file)
return NS_ERROR_FAILURE;
rv = NS_NewFileURI(getter_AddRefs(targetURI), file);
if (NS_FAILED(rv))
return rv;
// Start download
nsCOMPtr<nsISupports> fileAsSupports = do_QueryInterface(dropLocalFile);
nsCOMPtr<nsIWebBrowserPersist> persist = do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsITransfer> transfer = do_CreateInstance("@mozilla.org/transfer;1", &rv);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIWebProgressListener> listener = do_QueryInterface(transfer);
rv = persist->SetProgressListener(listener);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsICancelable> cancelable = do_QueryInterface(persist);
rv = transfer->Init(sourceURI, targetURI, NS_LITERAL_STRING(""), nsnull, PR_Now(), nsnull, cancelable);
if (NS_FAILED(rv))
return rv;
rv = persist->SaveURI(sourceURI, nsnull, nsnull, nsnull, nsnull, fileAsSupports);
if (NS_FAILED(rv))
return rv;
return rv;
}
//-------------------------------------------------------------------------
@ -197,34 +307,9 @@ nsDragService::StartInvokingDragSession(IDataObject * aDataObj,
// Start dragging
StartDragSession();
// check shell32.dll version and do async drag if it is >= 5.0
PRUint64 lShellVersion = GetShellVersion();
IAsyncOperation *pAsyncOp = NULL;
PRBool isAsyncAvailable = LL_UCMP(lShellVersion, >=, LL_INIT(5, 0));
if (isAsyncAvailable)
{
// do async drag
if (SUCCEEDED(aDataObj->QueryInterface(IID_IAsyncOperation,
(void**)&pAsyncOp)))
pAsyncOp->SetAsyncMode(TRUE);
}
// Call the native D&D method
HRESULT res = ::DoDragDrop(aDataObj, mNativeDragSrc, effects, &dropRes);
if (isAsyncAvailable)
{
// if dragging async
// check for async operation
BOOL isAsync = FALSE;
if (pAsyncOp)
{
pAsyncOp->InOperation(&isAsync);
if (!isAsync)
aDataObj->Release();
}
}
// We're done dragging
EndDragSession();
@ -490,37 +575,189 @@ nsDragService::EndDragSession()
return NS_OK;
}
// Gets shell version as packed 64 bit int
PRUint64 nsDragService::GetShellVersion()
// Start monitoring shell events - when user drops we'll get a notification from shell
// containing drop location
// aFileName is a filename to monitor
// returns true if all went ok
// if hidden window was created and shell is watching out for files being created
PRBool nsDragService::StartWatchingShell(const nsAString& aFileName)
{
PRUint64 lVersion = LL_INIT(0, 0);
// init member varable with the file name to watch
if (mFileName)
NS_Free(mFileName);
// shell32.dll should be loaded already, so we ae not actually loading the library here
PRLibrary *libShell = PR_LoadLibrary("shell32.dll");
if (libShell == NULL)
return lVersion;
mFileName = ToNewUnicode(aFileName);
do
{
DLLGETVERSIONPROC versionProc = NULL;
versionProc = (DLLGETVERSIONPROC)PR_FindFunctionSymbol(libShell, "DllGetVersion");
if (versionProc == NULL)
break;
// Create hidden window to process shell notifications
WNDCLASS wc;
DLLVERSIONINFO versionInfo;
::ZeroMemory(&versionInfo, sizeof(DLLVERSIONINFO));
versionInfo.cbSize = sizeof(DLLVERSIONINFO);
if (FAILED(versionProc(&versionInfo)))
break;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)HiddenWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = NULL;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("DHHidden");
// why is this?
PRUint32 maji64 = versionInfo.dwMajorVersion;
PRUint32 mini64 = versionInfo.dwMinorVersion;
lVersion = LL_INIT(maj, min);
} while (false);
unsigned short res = RegisterClass(&wc);
PR_UnloadLibrary(libShell);
libShell = NULL;
mHiddenWnd = CreateWindowEx(WS_EX_TOOLWINDOW,
TEXT("DHHidden"),
TEXT("DHHidden"),
WS_POPUP,
0,
0,
100,
100,
NULL,
NULL,
NULL,
NULL);
if (mHiddenWnd == NULL)
return PR_FALSE;
return lVersion;
// Now let the explorer know what we want
// Get My Computer PIDL
LPITEMIDLIST pidl;
HRESULT hr = ::SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
if (SUCCEEDED(hr)) {
SHChangeNotifyStruct notify;
notify.pidl = pidl;
notify.fRecursive = TRUE;
HMODULE hShell32 = ::GetModuleHandleA("SHELL32.DLL");
if (hShell32 == NULL) {
::DestroyWindow(mHiddenWnd);
return PR_FALSE;
}
// Have to use ordinals in the call to GetProcAddress instead of function names.
// The reason for this is because on some older systems (prior to WinXP)
// this function has no name in shell32.dll.
DWORD dwOrdinal = 2;
// get reg func
SHCNRegPtr reg;
reg = (SHCNRegPtr)::GetProcAddress(hShell32, (LPCSTR)dwOrdinal);
if (reg == NULL) {
::DestroyWindow(mHiddenWnd);
return PR_FALSE;
}
mNotifyHandle = (reg)(mHiddenWnd,
0x2,
0x1,
WM_USER,
1,
&notify);
}
// destroy hidden window if failed to register notification handle
if (mNotifyHandle == 0) {
::DestroyWindow(mHiddenWnd);
}
return (mNotifyHandle != 0);
}
// Get the drop path if there is one:)
// returns true if there is a drop path
PRBool nsDragService::GetDropPath(nsAString& aDropPath) const
{
// we failed to create window so there is no drop path
if (mHiddenWnd == NULL)
return PR_FALSE;
// If we get 0 for this that means we failed to register notification callback
if (mNotifyHandle == 0)
return PR_FALSE;
// Do clean up stuff (reverses all that's been done in Start)
HMODULE hShell32 = ::GetModuleHandleA("SHELL32.DLL");
if (hShell32 == NULL)
return PR_FALSE;
// Have to use ordinals in the call to GetProcAddress instead of function names.
// The reason for this is because on some older systems (prior to WinXP)
// this function has no name in shell32.dll.
DWORD dwOrdinal = 4;
SHCNDeregPtr dereg;
dereg = (SHCNDeregPtr)::GetProcAddress(hShell32, (LPCSTR)dwOrdinal);
if (dereg == NULL)
return PR_FALSE;
(dereg)(mNotifyHandle);
::DestroyWindow(mHiddenWnd);
// if drop path is too short then there is no drop location
if (!mDropPath)
return PR_FALSE;
aDropPath.Assign(mDropPath);
return PR_TRUE;
}
// Hidden window procedure - this is where shell sends notifications
// When notification is received, perform some checking and copy path to the member variable
LRESULT WINAPI nsDragService::HiddenWndProc(HWND aWnd, UINT aMsg, WPARAM awParam, LPARAM alParam)
{
switch (aMsg) {
case WM_USER:
if (alParam == SHCNE_RENAMEITEM) {
// we got notification from shell
// as wParam we get 2 PIDL
LPCITEMIDLIST* ppidl = (LPCITEMIDLIST*)awParam;
// Get From path (where the file is comming from)
WCHAR szPathFrom[MAX_PATH + 1];
WCHAR szPathTo[MAX_PATH + 1];
::SHGetPathFromIDListW(ppidl[0], szPathFrom);
// Get To path (where the file is going to)
::SHGetPathFromIDListW(ppidl[1], szPathTo);
// first is from where the file is coming
// and the second is where the file is going
nsAutoString pathFrom(szPathFrom); // where the file is comming from
nsAutoString pathTo(szPathTo); // where the file is going to
// Get OS Temp directory
// Get system temp directory
nsresult rv;
nsCOMPtr<nsILocalFile> tempDir;
nsCOMPtr<nsIProperties> directoryService =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
if (!directoryService || NS_FAILED(rv))
return ResultFromScode(E_FAIL);
directoryService->Get(NS_OS_TEMP_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(tempDir));
// append file name to Temp directory string
nsAutoString tempPath;
tempDir->Append(nsDependentString(mFileName));
tempDir->GetPath(tempPath);
// Now check if there is our filename in the path
// and also check for the source directory - it should be OS Temp dir
// this way we can ensure that this is the file that we need
PRInt32 pathToLength = pathTo.Length();
if (Substring(pathTo, pathToLength - NS_strlen(mFileName), pathToLength).Equals(mFileName) &&
tempPath.Equals(pathFrom, nsCaseInsensitiveStringComparator()))
{
// This is what we wanted to get
if (mDropPath)
NS_Free(mDropPath);
mDropPath = ToNewUnicode(pathTo);
}
return 0;
}
break;
}
return ::DefWindowProc(aWnd, aMsg, awParam, alParam);
}

View File

@ -48,6 +48,30 @@ class nsNativeDragTarget;
class nsDataObjCollection;
class nsString;
// some older versions of MS PSDK do not have definitions for these, even though
// the functions are there and exported from the shell32.dll,
// so I had to add them manually. For example if one tries to build without those
// using VC6 standard libs one will get an error.
#ifndef SHCNE_RENAMEITEM_DEF
#define SHCNE_RENAMEITEM_DEF 0x00000001
// Structure
typedef struct {
LPCITEMIDLIST pidl;
BOOL fRecursive;
} SHChangeNotifyStruct;
#endif // SHCNE_RENAMEITEM_DEF
// Register for shell notifications func ptr
typedef WINSHELLAPI ULONG (WINAPI *SHCNRegPtr)(HWND hWnd, // Ordinal of 2
int fSources,
LONG fEvents,
UINT wMsg,
int cEntries,
SHChangeNotifyStruct *pschn);
// Unregister form from the shell notifications func ptr
typedef WINSHELLAPI BOOL (WINAPI *SHCNDeregPtr)(ULONG ulID); // Ordinal of 4
/**
* Native Win32 DragService wrapper
*/
@ -82,12 +106,23 @@ protected:
// collections
PRBool IsCollectionObject(IDataObject* inDataObj);
// gets shell version
PRUint64 GetShellVersion();
// Begin monitoring the shell for events (this would allow to figure drop location)
PRBool StartWatchingShell(const nsAString& aFileName);
// Should be called after drag is over to get the drop path (if any)
PRBool GetDropPath(nsAString& aDropPath) const;
// Hidden window procedure - here we shall receive notification from the shell
static LRESULT WINAPI HiddenWndProc(HWND aWnd, UINT aMsg, WPARAM awParam, LPARAM alParam);
IDropSource * mNativeDragSrc;
nsNativeDragTarget * mNativeDragTarget;
IDataObject * mDataObject;
static PRUnichar *mFileName; // File name to look for
static PRUnichar *mDropPath; // Drop path
HWND mHiddenWnd; // Handle to a hidden window for notifications
PRInt32 mNotifyHandle; // Handle to installed hook (SHChangeNotify)
};
#endif // nsDragService_h__