зеркало из https://github.com/mozilla/pjs.git
Back out the patch from bug 267426 to fix Thunderbird (prometheus) build bustage.
This commit is contained in:
Родитель
f142534c0c
Коммит
0c0955bd66
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
¬ify);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
|
@ -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__
|
||||
|
|
Загрузка…
Ссылка в новой задаче