HRESULT BuildHDropList(FORMATETC *pftc,STGMEDIUM *pstg,
	const std::list<std::wstring> &FilenameList)
{
	SetFORMATETC(pftc,CF_HDROP,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL);

	UINT uSize = 0;

	uSize = sizeof(DROPFILES);

	for each(auto Filename in FilenameList)
	{
		uSize += static_cast<UINT>((Filename.length() + 1) * sizeof(TCHAR));
	}

	/* The last string is double-null terminated. */
	uSize += (1 * sizeof(TCHAR));

	HGLOBAL hglbHDrop = GlobalAlloc(GMEM_MOVEABLE,uSize);

	if(hglbHDrop == NULL)
	{
		return E_FAIL;
	}

	LPVOID pcidaData = static_cast<LPVOID>(GlobalLock(hglbHDrop));

	DROPFILES *pdf = static_cast<DROPFILES *>(pcidaData);

	pdf->pFiles = sizeof(DROPFILES);
	pdf->fNC = FALSE;
	pdf->pt.x = 0;
	pdf->pt.y = 0;
	pdf->fWide = TRUE;

	LPBYTE pData;
	UINT uOffset = 0;

	TCHAR chNull = '\0';

	for each(auto Filename in FilenameList)
	{
		pData = static_cast<LPBYTE>(pcidaData) + sizeof(DROPFILES) + uOffset;

		memcpy(pData,Filename.c_str(),(Filename.length() + 1) * sizeof(TCHAR));
		uOffset += static_cast<UINT>((Filename.length() + 1) * sizeof(TCHAR));
	}
void Explorerplusplus::OnAddressBarBeginDrag(void)
{
	IDragSourceHelper *pDragSourceHelper = NULL;
	IDropSource *pDropSource = NULL;
	HRESULT hr;

	hr = CoCreateInstance(CLSID_DragDropHelper,NULL,CLSCTX_ALL,
		IID_IDragSourceHelper,(LPVOID *)&pDragSourceHelper);

	if(SUCCEEDED(hr))
	{
		hr = CreateDropSource(&pDropSource,DRAG_TYPE_LEFTCLICK);

		if(SUCCEEDED(hr))
		{
			LPITEMIDLIST pidlDirectory = m_pActiveShellBrowser->QueryCurrentDirectoryIdl();

			FORMATETC ftc[2];
			STGMEDIUM stg[2];

			SetFORMATETC(&ftc[0],(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR),
				NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL);

			HGLOBAL hglb = GlobalAlloc(GMEM_MOVEABLE,1000);

			FILEGROUPDESCRIPTOR *pfgd = static_cast<FILEGROUPDESCRIPTOR *>(GlobalLock(hglb));

			pfgd->cItems = 1;

			FILEDESCRIPTOR *pfd = (FILEDESCRIPTOR *)((LPBYTE)pfgd + sizeof(UINT));

			/* File information (name, size, date created, etc). */
			pfd[0].dwFlags			= FD_ATTRIBUTES|FD_FILESIZE;
			pfd[0].dwFileAttributes	= FILE_ATTRIBUTE_NORMAL;
			pfd[0].nFileSizeLow		= 16384;
			pfd[0].nFileSizeHigh	= 0;

			/* The name of the file will be the folder name, followed by .lnk. */
			TCHAR szDisplayName[MAX_PATH];
			GetDisplayName(pidlDirectory,szDisplayName,SHGDN_INFOLDER);
			StringCchCat(szDisplayName,SIZEOF_ARRAY(szDisplayName),_T(".lnk"));
			StringCchCopy(pfd[0].cFileName,SIZEOF_ARRAY(pfd[0].cFileName),szDisplayName);

			GlobalUnlock(hglb);

			stg[0].pUnkForRelease	= 0;
			stg[0].hGlobal			= hglb;
			stg[0].tymed			= TYMED_HGLOBAL;

			/* File contents. */
			SetFORMATETC(&ftc[1],(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS),
				NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL);

			hglb = GlobalAlloc(GMEM_MOVEABLE,16384);

			IShellLink *pShellLink = NULL;
			IPersistStream *pPersistStream = NULL;
			HRESULT hr;

			hr = CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,
				IID_IShellLink,(LPVOID*)&pShellLink);

			if(SUCCEEDED(hr))
			{
				TCHAR szPath[MAX_PATH];

				GetDisplayName(pidlDirectory,szPath,SHGDN_FORPARSING);

				pShellLink->SetPath(szPath);

				hr = pShellLink->QueryInterface(IID_IPersistStream,(LPVOID*)&pPersistStream);

				if(SUCCEEDED(hr))
				{
					IStream *pStream = NULL;

					CreateStreamOnHGlobal(hglb,FALSE,&pStream);

					hr = pPersistStream->Save(pStream,TRUE);
				}
			}

			GlobalUnlock(hglb);

			stg[1].pUnkForRelease	= 0;
			stg[1].hGlobal			= hglb;
			stg[1].tymed			= TYMED_HGLOBAL;

			IDataObject *pDataObject = NULL;
			POINT pt = {0,0};

			hr = CreateDataObject(ftc,stg,&pDataObject,2);

			pDragSourceHelper->InitializeFromWindow(m_hAddressBar,&pt,pDataObject);

			DWORD dwEffect;

			DoDragDrop(pDataObject,pDropSource,DROPEFFECT_LINK,&dwEffect);

			CoTaskMemFree(pidlDirectory);

			pDataObject->Release();
			pDropSource->Release();
		}

		pDragSourceHelper->Release();
	}
}
HRESULT CDropHandler::CopyFileDescriptorData(IDataObject *pDataObject,
	list<PastedFile_t> *pPastedFileList)
{
	STGMEDIUM stg;
	HRESULT hr;

	hr = pDataObject->GetData(&m_ftcFileDescriptor,&stg);

	if(hr == S_OK)
	{
		FILEGROUPDESCRIPTOR *pfgd = (FILEGROUPDESCRIPTOR *)GlobalLock(stg.hGlobal);

		if(pfgd != NULL)
		{
			FILETIME *pftCreationTime = NULL;
			FILETIME *pftLastAccessTime = NULL;
			FILETIME *pftLastWriteTime = NULL;
			DWORD dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
			DWORD nBytesToWrite = 0;

			for(unsigned int i = 0;i < pfgd->cItems;i++)
			{
				if(pfgd->fgd[i].dwFlags & FD_ATTRIBUTES)
				{
					dwFileAttributes = pfgd->fgd[i].dwFileAttributes;
				}

				if(pfgd->fgd[i].dwFlags & FD_FILESIZE)
				{
					nBytesToWrite = pfgd->fgd[i].nFileSizeLow;
				}

				if(pfgd->fgd[i].dwFlags & FD_LINKUI)
				{
					/* TODO: Complete. */
				}

				if(pfgd->fgd[i].dwFlags & FD_CREATETIME)
				{
					pftCreationTime = &pfgd->fgd[i].ftCreationTime;
				}

				if(pfgd->fgd[i].dwFlags & FD_ACCESSTIME)
				{
					pftLastAccessTime = &pfgd->fgd[i].ftLastAccessTime;
				}

				if(pfgd->fgd[i].dwFlags & FD_WRITESTIME)
				{
					pftLastWriteTime = &pfgd->fgd[i].ftLastWriteTime;
				}

				/*if(pfgd->fgd[i].dwFlags & FD_UNICODE)
				{
				}*/

				FORMATETC ftcfchg;
				FORMATETC ftcfcis;
				FORMATETC ftcfcstg;
				STGMEDIUM stgFileContents = {0};
				BOOL bDataRetrieved = FALSE;
				LPBYTE pBuffer = NULL;

				SetFORMATETC(&ftcfchg,(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS),
					NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL);
				SetFORMATETC(&ftcfcis,(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS),
					NULL,DVASPECT_CONTENT,-1,TYMED_ISTREAM);
				SetFORMATETC(&ftcfcstg,(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS),
					NULL,DVASPECT_CONTENT,-1,TYMED_ISTORAGE);

				if(pDataObject->QueryGetData(&ftcfchg) == S_OK)
				{
					ftcfchg.lindex = i;

					hr = pDataObject->GetData(&ftcfchg,&stgFileContents);

					if(hr == S_OK)
					{
						pBuffer = (LPBYTE)malloc(GlobalSize(stgFileContents.hGlobal) * sizeof(BYTE));

						if(pBuffer != NULL)
						{
							if(!(pfgd->fgd[i].dwFlags & FD_FILESIZE))
								nBytesToWrite = (DWORD)GlobalSize(stgFileContents.hGlobal);

							LPBYTE pTemp = (LPBYTE)GlobalLock(stgFileContents.hGlobal);

							if(pTemp != NULL)
							{
								memcpy(pBuffer,pTemp,GlobalSize(stgFileContents.hGlobal));

								GlobalUnlock(stgFileContents.hGlobal);

								bDataRetrieved = TRUE;
							}

							ReleaseStgMedium(&stgFileContents);
						}
					}
				}
				else if(pDataObject->QueryGetData(&ftcfcis) == S_OK)
				{
					STATSTG sstg;
					ULONG cbRead;

					ftcfcis.lindex = i;

					hr = pDataObject->GetData(&ftcfcis,&stgFileContents);

					if(hr == S_OK)
					{
						hr = stgFileContents.pstm->Stat(&sstg,STATFLAG_NONAME);

						if(hr == S_OK)
						{
							pBuffer = (LPBYTE)malloc(sstg.cbSize.LowPart * sizeof(BYTE));

							if(pBuffer != NULL)
							{
								/* If the file size isn't explicitly given,
								use the size of the stream. */
								if(!(pfgd->fgd[i].dwFlags & FD_FILESIZE))
									nBytesToWrite = sstg.cbSize.LowPart;

								stgFileContents.pstm->Read(pBuffer,sstg.cbSize.LowPart,&cbRead);

								bDataRetrieved = TRUE;
							}
						}

						ReleaseStgMedium(&stgFileContents);
					}
				}
				else if(pDataObject->QueryGetData(&ftcfcstg) == S_OK)
				{
					IStream *pStream;
					STATSTG sstg;
					ULONG cbRead;

					ftcfcstg.lindex = i;

					hr = pDataObject->GetData(&ftcfcstg,&stgFileContents);

					if(hr == S_OK)
					{
						hr = stgFileContents.pstg->Stat(&sstg,STATFLAG_DEFAULT);

						if(hr == S_OK)
						{
							hr = stgFileContents.pstg->OpenStream(sstg.pwcsName,NULL,
								STGM_READ|STGM_SHARE_EXCLUSIVE,0,&pStream);

							if(hr == S_OK)
							{
								CoTaskMemFree(sstg.pwcsName);

								hr = pStream->Stat(&sstg,STATFLAG_NONAME);

								if(hr == S_OK)
								{
									pBuffer = (LPBYTE)malloc(sstg.cbSize.LowPart * sizeof(BYTE));

									if(pBuffer != NULL)
									{
										/* If the file size isn't explicitly given,
										use the size of the stream. */
										if(!(pfgd->fgd[i].dwFlags & FD_FILESIZE))
											nBytesToWrite = sstg.cbSize.LowPart;

										pStream->Read(pBuffer,sstg.cbSize.LowPart,&cbRead);

										bDataRetrieved = TRUE;
									}
								}
							}
						}

						ReleaseStgMedium(&stgFileContents);
					}
				}

				if(bDataRetrieved)
				{
					TCHAR szFullFileName[MAX_PATH];

					StringCchCopy(szFullFileName,SIZEOF_ARRAY(szFullFileName),m_szDestDirectory);
					PathAppend(szFullFileName,pfgd->fgd[i].cFileName);

					HANDLE hFile = CreateFile(szFullFileName,GENERIC_WRITE,0,NULL,
						CREATE_ALWAYS,dwFileAttributes,NULL);

					if(hFile != INVALID_HANDLE_VALUE)
					{
						PastedFile_t pf;
						DWORD nBytesWritten;

						SetFileTime(hFile,pftCreationTime,pftLastAccessTime,pftLastWriteTime);

						WriteFile(hFile,pBuffer,nBytesToWrite,&nBytesWritten,NULL);

						CloseHandle(hFile);

						StringCchCopy(pf.szFileName,SIZEOF_ARRAY(pf.szFileName),szFullFileName);
						PathStripPath(pf.szFileName);

						pPastedFileList->push_back(pf);
					}

					HGLOBAL hglb = NULL;
					DWORD *pdwCopyEffect = NULL;
					FORMATETC ftc;
					STGMEDIUM stg1;

					ftc.cfFormat	= (CLIPFORMAT)RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
					ftc.ptd			= NULL;
					ftc.dwAspect	= DVASPECT_CONTENT;
					ftc.lindex		= -1;
					ftc.tymed		= TYMED_HGLOBAL;

					hglb = GlobalAlloc(GMEM_MOVEABLE,sizeof(DWORD));

					pdwCopyEffect = (DWORD *)GlobalLock(hglb);

					*pdwCopyEffect = DROPEFFECT_COPY;

					GlobalUnlock(hglb);

					stg1.tymed			= TYMED_HGLOBAL;
					stg1.pUnkForRelease	= 0;
					stg1.hGlobal		= hglb;

					pDataObject->SetData(&ftc,&stg1,FALSE);
				}

				if(pBuffer != NULL)
				{
					free(pBuffer);
				}
			}

			GlobalUnlock(stg.hGlobal);
		}

		ReleaseStgMedium(&stg);
	}

	return hr;
}
void CDropHandler::HandleLeftClickDrop(IDataObject *pDataObject,POINTL *pptl)
{
	FORMATETC ftc;
	STGMEDIUM stg;
	DWORD *pdwEffect = NULL;
	DWORD dwEffect = DROPEFFECT_NONE;
	BOOL bPrefferedEffect = FALSE;
	POINT pt;

	pt.x = pptl->x;
	pt.y = pptl->y;

	SetFORMATETC(&ftc,(CLIPFORMAT)RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT),
		NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL);

	/* Check if the data has a preffered drop effect
	(i.e. copy or move). */
	HRESULT hr = pDataObject->GetData(&ftc,&stg);

	if(hr == S_OK)
	{
		pdwEffect = (DWORD *)GlobalLock(stg.hGlobal);

		if(pdwEffect != NULL)
		{
			if(*pdwEffect != DROPEFFECT_NONE)
			{
				dwEffect = *pdwEffect;
				bPrefferedEffect = TRUE;

				GlobalUnlock(stg.hGlobal);
			}
		}

		ReleaseStgMedium(&stg);
	}

	HRESULT hrCopy = E_FAIL;
	list<PastedFile_t> PastedFileList;

	if(pDataObject->QueryGetData(&m_ftcHDrop) == S_OK)
	{
		hrCopy = CopyHDropData(pDataObject,bPrefferedEffect,dwEffect,
			&PastedFileList);
	}
	else if(pDataObject->QueryGetData(&m_ftcShellIDList) == S_OK)
	{
		hrCopy = CopyShellIDListData(pDataObject,&PastedFileList);
	}
	else if(pDataObject->QueryGetData(&m_ftcFileDescriptor) == S_OK)
	{
		hrCopy = CopyFileDescriptorData(pDataObject,&PastedFileList);
	}
	else if(pDataObject->QueryGetData(&m_ftcUnicodeText) == S_OK)
	{
		hrCopy = CopyUnicodeTextData(pDataObject,&PastedFileList);
	}
	else if(pDataObject->QueryGetData(&m_ftcText) == S_OK)
	{
		hrCopy = CopyAnsiTextData(pDataObject,&PastedFileList);
	}
	else if(pDataObject->QueryGetData(&m_ftcDIBV5) == S_OK)
	{
		hrCopy = CopyDIBV5Data(pDataObject,&PastedFileList);
	}

	if(hrCopy == S_OK &&
		PastedFileList.size() > 0)
	{
		/* The data was copied successfully, so notify
		the caller via the specified callback interface. */
		if(m_pDropFilesCallback != NULL)
			m_pDropFilesCallback->OnDropFile(&PastedFileList,&pt);
	}
}