Sandboxie/Sandboxie/core/dll/ole.cpp

1846 lines
48 KiB
C++

/*
* Copyright 2004-2020 Sandboxie Holdings, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// Ole32 -- Clipboard Management
//---------------------------------------------------------------------------
extern "C" {
#include "dll.h"
#include "gui_p.h"
#include "gdi.h"
#include "common/my_version.h"
}
#include <shellapi.h>
#include <shlobj.h>
#include <new>
#include <stdlib.h>
#undef WITH_PRINT_FORMAT
//---------------------------------------------------------------------------
// Function Pointers
//---------------------------------------------------------------------------
typedef HRESULT (*P_OleSetClipboard)(IDataObject *pDataObject);
typedef HRESULT (*P_ReleaseStgMedium)(STGMEDIUM *pmedium);
typedef HRESULT (*P_RegisterDragDrop)(HWND hwnd, IDropTarget *pDropTarget);
typedef HRESULT (*P_RevokeDragDrop)(HWND hwnd);
typedef void (*P_DragFinish)(HDROP hDrop);
typedef UINT (*P_DragQueryFile)(
HDROP hDrop, UINT iFile, WCHAR *lpszFile, UINT cch);
typedef LPITEMIDLIST (*P_ILCombine)(
LPCITEMIDLIST pidl1, LPCITEMIDLIST pid2);
typedef UINT (*P_ILGetSize)(LPCITEMIDLIST pidl);
typedef BOOL (*P_SHGetPathFromIDList)(
LPCITEMIDLIST pidl, void *pszPath);
typedef HRESULT (*P_SHILCreateFromPath)(
void *pszPath, LPITEMIDLIST *ppidl, ULONG *rgflnOut);
typedef void (*P_SHFree)(void *pv);
//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
static HRESULT Ole_OleSetClipboard(IDataObject *pDataObject);
static void Ole_ReleaseStgMedium(STGMEDIUM *pmedium);
static HDROP Ole_IsVirtualFile(IDataObject *pDataObject);
static BOOLEAN Ole_WriteStreamToFile(
IStream *pStream, ULONG StreamSize, WCHAR *Path);
static HRESULT Ole_RegisterDragDrop(HWND hwnd, IDropTarget *pDropTarget);
static HRESULT Ole_RevokeDragDrop(HWND hwnd);
static ULONG Ole_DoDragDrop_2(void *ThreadParam);
//---------------------------------------------------------------------------
// Variables
//---------------------------------------------------------------------------
static ULONG Ole_CF_FileNameA = 0;
static ULONG Ole_CF_FileNameW = 0;
static ULONG Ole_CF_ShellIdList = 0;
//---------------------------------------------------------------------------
static P_OleSetClipboard __sys_OleSetClipboard = NULL;
static P_ReleaseStgMedium __sys_ReleaseStgMedium = NULL;
static P_RegisterDragDrop __sys_RegisterDragDrop = NULL;
static P_RevokeDragDrop __sys_RevokeDragDrop = NULL;
static P_DragFinish __sys_DragFinish = NULL;
//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
extern "C" _FX BOOLEAN Ole_Init(HMODULE module)
{
void *OleSetClipboard;
void *ReleaseStgMedium;
void *RegisterDragDrop;
void *RevokeDragDrop;
// DisableComProxy BEGIN
if (!SbieApi_QueryConfBool(NULL, L"DisableComProxy", FALSE))
// DisableComProxy END
if (! SbieDll_IsOpenCOM()) {
Com_Init_Ole32(module);
RegisterDragDrop = GetProcAddress(module, "RegisterDragDrop");
RevokeDragDrop = GetProcAddress(module, "RevokeDragDrop");
if (Gui_RenameClasses && Config_GetSettingsForImageName_bool(L"UseDragDropHack", TRUE)) {
//
// don't hook drag and drop if using OpenWinClass=*
// because we have neither our Get/SetWindowLong hooks
// which maintain Gui_DropTargetProp_Atom, nor the window
// procedure hook to invoke Ole_DoDragDrop
//
SBIEDLL_HOOK(Ole_,RegisterDragDrop);
SBIEDLL_HOOK(Ole_,RevokeDragDrop);
}
}
ReleaseStgMedium = (P_ReleaseStgMedium)
GetProcAddress(module, "ReleaseStgMedium");
SBIEDLL_HOOK(Ole_, ReleaseStgMedium);
if (Dll_ImageType == DLL_IMAGE_SHELL_EXPLORER) {
OleSetClipboard = GetProcAddress(module, "OleSetClipboard");
SBIEDLL_HOOK(Ole_,OleSetClipboard);
}
return TRUE;
}
//---------------------------------------------------------------------------
// XEnumFormatEtc Class
//---------------------------------------------------------------------------
class XEnumFormatEtc : public IEnumFORMATETC
{
public:
STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
STDMETHOD(Next)(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);
STDMETHOD(Skip)(ULONG celt);
STDMETHOD(Reset)(void);
STDMETHOD(Clone)(IEnumFORMATETC **ppenum);
BOOL m_eof;
};
//---------------------------------------------------------------------------
// XEnumFormatEtc::IUnknown::QueryInterface
//---------------------------------------------------------------------------
_FX HRESULT XEnumFormatEtc::QueryInterface(REFIID iid, void **ppvObject)
{
if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IEnumFORMATETC))
*ppvObject = this;
else
return E_NOINTERFACE;
((IUnknown *)(*ppvObject))->AddRef();
return S_OK;
}
//---------------------------------------------------------------------------
// XEnumFormatEtc::IUnknown::AddRef
//---------------------------------------------------------------------------
_FX ULONG XEnumFormatEtc::AddRef()
{
return 1;
}
//---------------------------------------------------------------------------
// XEnumFormatEtc::IUnknown::Release
//---------------------------------------------------------------------------
_FX ULONG XEnumFormatEtc::Release()
{
return 1;
}
//---------------------------------------------------------------------------
// XEnumFormatEtc::IUnknown::Next
//---------------------------------------------------------------------------
_FX HRESULT XEnumFormatEtc::Next(
ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched)
{
if (m_eof) {
if (pceltFetched)
*pceltFetched = 0;
} else if (celt >= 1) {
m_eof = TRUE;
rgelt->cfFormat = CF_HDROP;
rgelt->ptd = NULL;
rgelt->dwAspect = DVASPECT_CONTENT;
rgelt->lindex = -1;
rgelt->tymed = TYMED_HGLOBAL;
if (pceltFetched)
*pceltFetched = 1;
if (celt == 1)
return S_OK;
}
return S_FALSE;
}
//---------------------------------------------------------------------------
// XEnumFormatEtc::IUnknown::Skip
//---------------------------------------------------------------------------
_FX HRESULT XEnumFormatEtc::Skip(ULONG celt)
{
if (m_eof || celt != 1)
return S_FALSE;
return S_OK;
}
//---------------------------------------------------------------------------
// XEnumFormatEtc::IUnknown::Reset
//---------------------------------------------------------------------------
_FX HRESULT XEnumFormatEtc::Reset(void)
{
m_eof = FALSE;
return S_OK;
}
//---------------------------------------------------------------------------
// XEnumFormatEtc::IUnknown::Clone
//---------------------------------------------------------------------------
_FX HRESULT XEnumFormatEtc::Clone(IEnumFORMATETC **ppenum)
{
*ppenum = this;
return S_OK;
}
//---------------------------------------------------------------------------
// XDataObject Class
//---------------------------------------------------------------------------
class XDataObject : public IDataObject
{
public:
XDataObject(IDataObject *pDataObject, HDROP hDrop);
protected:
void PrintFormat(const WCHAR *FuncName, const FORMATETC *pFormatetc)
#ifndef WITH_PRINT_FORMAT
{}
#endif
;
BOOLEAN IsValidFormat(const FORMATETC *pFormatetc);
HRESULT GetDataCommon(FORMATETC *format, STGMEDIUM *medium);
HGLOBAL InitFormatHDrop(HGLOBAL hData);
HANDLE OpenFileFromHDrop(HGLOBAL hData);
HGLOBAL InitFormatFileNameA(HGLOBAL hData);
HGLOBAL InitFormatFileNameW(HGLOBAL hData);
HGLOBAL InitFormatIdList(HGLOBAL hData);
//---------------------------------------------------------------------------
// IUnknown Methods
//---------------------------------------------------------------------------
public:
STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
//---------------------------------------------------------------------------
// IDataObject Methods
//---------------------------------------------------------------------------
protected:
STDMETHOD(DAdvise)(
FORMATETC *pFormatetc, DWORD advf, IAdviseSink *pAdvSink,
DWORD *pdwConnection);
STDMETHOD(DUnadvise)(DWORD dwConnection);
STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise);
STDMETHOD(EnumFormatEtc)(
DWORD dwDirection, IEnumFORMATETC **ppenumFormatetc);
STDMETHOD(GetCanonicalFormatEtc)(
FORMATETC *pFormatetcIn, FORMATETC *pFormatetcOut);
STDMETHOD(GetData)(FORMATETC *pFormatetc, STGMEDIUM *pmedium);
STDMETHOD(GetDataHere)(FORMATETC *pFormatetc, STGMEDIUM *pmedium);
STDMETHOD(QueryGetData)(FORMATETC *pFormatetc);
STDMETHOD(SetData)(
FORMATETC *pFormatetc, STGMEDIUM *pmedium, BOOL fRelease);
//---------------------------------------------------------------------------
// Variables
//---------------------------------------------------------------------------
protected:
IDataObject *m_pDataObject;
HDROP m_hDrop;
ULONG m_fileCount;
ULONG m_refCount;
XEnumFormatEtc m_EnumFormatEtc;
HMODULE __shell32;
P_DragQueryFile pDragQueryFileW;
P_ILCombine pILCombine;
P_ILGetSize pILGetSize;
P_SHGetPathFromIDList pSHGetPathFromIDList;
P_SHILCreateFromPath pSHILCreateFromPath;
P_SHFree pSHFree;
};
//---------------------------------------------------------------------------
// Constructor
//---------------------------------------------------------------------------
_FX XDataObject::XDataObject(IDataObject *pDataObject, HDROP hDrop)
{
//
//
//
__shell32 = LoadLibrary(L"shell32.dll");
if (__shell32) {
pDragQueryFileW = (P_DragQueryFile)
GetProcAddress(__shell32, "DragQueryFileW");
pILCombine = (P_ILCombine)GetProcAddress(__shell32, "ILCombine");
pILGetSize = (P_ILGetSize)GetProcAddress(__shell32, "ILGetSize");
pSHGetPathFromIDList = (P_SHGetPathFromIDList)
GetProcAddress(__shell32, "SHGetPathFromIDListW");
pSHILCreateFromPath = (P_SHILCreateFromPath)
GetProcAddress(__shell32, "SHILCreateFromPath");
pSHFree = (P_SHFree)GetProcAddress(__shell32, "SHFree");
if (! Ole_CF_FileNameA) {
Ole_CF_FileNameA =
__sys_RegisterClipboardFormatW(CFSTR_FILENAMEA);
}
if (! Ole_CF_FileNameW) {
Ole_CF_FileNameW =
__sys_RegisterClipboardFormatW(CFSTR_FILENAMEW);
}
if (! Ole_CF_ShellIdList) {
Ole_CF_ShellIdList =
__sys_RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
}
} else {
pDragQueryFileW = NULL;
pSHGetPathFromIDList = NULL;
pSHILCreateFromPath = NULL;
}
//
//
//
m_pDataObject = pDataObject;
if (m_pDataObject)
pDataObject->AddRef();
m_hDrop = hDrop;
if (m_hDrop && pDragQueryFileW) {
m_fileCount = pDragQueryFileW(m_hDrop, 0xFFFFFFFF, NULL, 0);
if (m_fileCount == -1)
m_fileCount = 0;
} else
m_fileCount = 0;
m_refCount = 1;
}
//---------------------------------------------------------------------------
// XDataObject::IUnknown::QueryInterface
//---------------------------------------------------------------------------
_FX HRESULT XDataObject::QueryInterface(REFIID iid, void **ppvObject)
{
if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IDataObject))
*ppvObject = this;
else
return E_NOINTERFACE;
((IUnknown *)(*ppvObject))->AddRef();
return S_OK;
}
//---------------------------------------------------------------------------
// XDataObject::IUnknown::AddRef
//---------------------------------------------------------------------------
_FX ULONG XDataObject::AddRef()
{
return ++m_refCount;
}
//---------------------------------------------------------------------------
// XDataObject::IUnknown::Release
//---------------------------------------------------------------------------
_FX ULONG XDataObject::Release()
{
--m_refCount;
if (m_refCount != 0)
return m_refCount;
if (m_pDataObject)
m_pDataObject->Release();
if (__shell32)
FreeLibrary(__shell32);
Dll_Free(this);
return 0;
}
//---------------------------------------------------------------------------
// IDataObject::DAdvise
//---------------------------------------------------------------------------
_FX HRESULT XDataObject::DAdvise(
FORMATETC *pFormatetc, DWORD advf, IAdviseSink *pAdvSink,
DWORD *pdwConnection)
{
if (! m_pDataObject)
return OLE_E_ADVISENOTSUPPORTED;
return m_pDataObject->DAdvise(pFormatetc, advf, pAdvSink, pdwConnection);
}
//---------------------------------------------------------------------------
// IDataObject::DUnadvise
//---------------------------------------------------------------------------
_FX HRESULT XDataObject::DUnadvise(DWORD dwConnection)
{
if (! m_pDataObject)
return OLE_E_ADVISENOTSUPPORTED;
return m_pDataObject->DUnadvise(dwConnection);
}
//---------------------------------------------------------------------------
// IDataObject::EnumDAdvise
//---------------------------------------------------------------------------
_FX HRESULT XDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
{
if (! m_pDataObject)
return OLE_E_ADVISENOTSUPPORTED;
return m_pDataObject->EnumDAdvise(ppenumAdvise);
}
//---------------------------------------------------------------------------
// IDataObject::EnumFormatEtc
//---------------------------------------------------------------------------
_FX HRESULT XDataObject::EnumFormatEtc(
DWORD dwDirection, IEnumFORMATETC **ppenumFormatetc)
{
if (! m_pDataObject) {
m_EnumFormatEtc.Reset();
*ppenumFormatetc = &m_EnumFormatEtc;
return S_OK;
}
return m_pDataObject->EnumFormatEtc(dwDirection, ppenumFormatetc);
}
//---------------------------------------------------------------------------
// IDataObject::GetCanonicalFormatEtc
//---------------------------------------------------------------------------
_FX HRESULT XDataObject::GetCanonicalFormatEtc(
FORMATETC *pFormatetcIn, FORMATETC *pFormatetcOut)
{
if (! m_pDataObject) {
memzero(pFormatetcOut, sizeof(FORMATETC));
return DATA_S_SAMEFORMATETC;
}
return m_pDataObject->GetCanonicalFormatEtc(pFormatetcIn, pFormatetcOut);
}
//---------------------------------------------------------------------------
// IDataObject::GetData
//---------------------------------------------------------------------------
_FX HRESULT XDataObject::GetData(
FORMATETC *pFormatetc, STGMEDIUM *pmedium)
{
HRESULT hr;
PrintFormat(L"GetData", pFormatetc);
if (m_pDataObject)
hr = m_pDataObject->GetData(pFormatetc, pmedium);
else if (! IsValidFormat(pFormatetc))
hr = DV_E_FORMATETC;
else if ((pFormatetc->tymed & TYMED_HGLOBAL) == 0)
hr = DV_E_TYMED;
else if (pFormatetc->lindex != -1)
hr = DV_E_LINDEX;
else if (pFormatetc->dwAspect != DVASPECT_CONTENT)
hr = DV_E_DVASPECT;
else {
SIZE_T hDropLen = GlobalSize(m_hDrop);
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, hDropLen);
if (! hGlobal)
hr = E_OUTOFMEMORY;
else {
void *ptrSrc = GlobalLock(m_hDrop);
void *ptrDst = GlobalLock(hGlobal);
memcpy(ptrDst, ptrSrc, hDropLen);
GlobalUnlock(m_hDrop);
GlobalUnlock(hGlobal);
pmedium->tymed = TYMED_HGLOBAL;
pmedium->hGlobal = hGlobal;
pmedium->pUnkForRelease = NULL;
hr = S_OK;
}
}
if (SUCCEEDED(hr))
hr = GetDataCommon(pFormatetc, pmedium);
return hr;
}
//---------------------------------------------------------------------------
// IDataObject::GetDataHere
//---------------------------------------------------------------------------
_FX HRESULT XDataObject::GetDataHere(
FORMATETC *pFormatetc, STGMEDIUM *pmedium)
{
if (! m_pDataObject)
return E_FAIL;
HRESULT hr = m_pDataObject->GetDataHere(pFormatetc, pmedium);
if (SUCCEEDED(hr))
hr = GetDataCommon(pFormatetc, pmedium);
return hr;
}
//---------------------------------------------------------------------------
// IDataObject::QueryGetData
//---------------------------------------------------------------------------
_FX HRESULT XDataObject::QueryGetData(FORMATETC *pFormatetc)
{
HRESULT hr;
PrintFormat(L"QueryGetData", pFormatetc);
if (m_pDataObject)
return m_pDataObject->QueryGetData(pFormatetc);
else if (! IsValidFormat(pFormatetc))
hr = DV_E_FORMATETC;
else if ((pFormatetc->tymed & TYMED_HGLOBAL) == 0)
hr = DV_E_TYMED;
else if (pFormatetc->lindex != -1)
hr = DV_E_LINDEX;
else if (pFormatetc->dwAspect != DVASPECT_CONTENT)
hr = DV_E_DVASPECT;
else
hr = S_OK;
return hr;
}
//---------------------------------------------------------------------------
// IDataObject::SetData
//---------------------------------------------------------------------------
_FX HRESULT XDataObject::SetData(
FORMATETC *pFormatetc, STGMEDIUM *pmedium, BOOL fRelease)
{
if (! m_pDataObject)
return E_NOTIMPL;
return m_pDataObject->SetData(pFormatetc, pmedium, fRelease);
}
//---------------------------------------------------------------------------
// PrintFormat
//---------------------------------------------------------------------------
#ifdef WITH_PRINT_FORMAT
#include <stdio.h>
_FX void XDataObject::PrintFormat(
const WCHAR *FuncName, const FORMATETC *pFormatetc)
{
const ULONG fmt = (ULONG)pFormatetc->cfFormat;
WCHAR text[128];
Sbie_snwprintf(text, 128, L"%-32.32s - <", FuncName);
if (fmt >= 0xC000 && fmt <= 0xFFFF)
__sys_GetClipboardFormatNameW(fmt, text + 36, 60);
else
Sbie_snwprintf(text + 36, 128 - 36, L"%08X", fmt);
wcscat(text, L">\n");
OutputDebugString(text);
}
#endif WITH_PRINT_FORMAT
//---------------------------------------------------------------------------
// IsValidFormat
//---------------------------------------------------------------------------
_FX BOOLEAN XDataObject::IsValidFormat(const FORMATETC *pFormatetc)
{
const UINT fmt = pFormatetc->cfFormat;
if (m_fileCount) {
BOOLEAN IsFileNameA = (Ole_CF_FileNameA && fmt == Ole_CF_FileNameA);
BOOLEAN IsFileNameW = (Ole_CF_FileNameW && fmt == Ole_CF_FileNameW);
if (IsFileNameA || IsFileNameW) {
if (m_fileCount == 1)
return TRUE;
else
return FALSE;
}
if (fmt == CF_HDROP)
return TRUE;
}
return FALSE;
}
//---------------------------------------------------------------------------
// GetDataCommon
//---------------------------------------------------------------------------
_FX HRESULT XDataObject::GetDataCommon(FORMATETC *format, STGMEDIUM *medium)
{
HRESULT hr = S_OK;
if (medium->tymed != TYMED_HGLOBAL)
return hr;
HGLOBAL hGlobal = NULL;
const UINT fmt = format->cfFormat;
PrintFormat(L"GetDataCommon", format);
if (fmt == CF_HDROP) {
hGlobal = InitFormatHDrop(medium->hGlobal);
} else {
if (Ole_CF_ShellIdList && fmt == Ole_CF_ShellIdList) {
hGlobal = InitFormatIdList(medium->hGlobal);
if (hGlobal == (HGLOBAL)-1) {
hGlobal = NULL;
hr = DV_E_FORMATETC;
}
}
else if (Ole_CF_FileNameA && fmt == Ole_CF_FileNameA)
hGlobal = InitFormatFileNameA(medium->hGlobal);
else if (Ole_CF_FileNameW && fmt == Ole_CF_FileNameW)
hGlobal = InitFormatFileNameW(medium->hGlobal);
}
if (hGlobal || hr != S_OK) {
if (medium->pUnkForRelease) {
medium->pUnkForRelease->Release();
medium->pUnkForRelease = NULL;
} else
GlobalFree(medium->hGlobal);
medium->hGlobal = hGlobal;
}
return hr;
}
//---------------------------------------------------------------------------
// InitFormatHDrop
//---------------------------------------------------------------------------
_FX HGLOBAL XDataObject::InitFormatHDrop(HGLOBAL hData)
{
if (! pDragQueryFileW)
return NULL;
//
// translate each path in the DROPFILES structure to a full
// path into the sandbox, if applicable. this is in case the
// paste operation is going to be done by a program running
// outside the sandbox
//
HDROP hDrop = (HDROP)hData;
bool sandboxed = false;
UINT count = pDragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0);
if (count == -1)
count = 0;
ULONG DropFiles_len = (count + 8) * MAX_PATH * 2 * sizeof(WCHAR);
DROPFILES *DropFiles = (DROPFILES *)Dll_Alloc(DropFiles_len);
memzero(DropFiles, DropFiles_len);
WCHAR *DropName = (WCHAR *)(DropFiles + 1);
DropFiles->pFiles = (DWORD)((UCHAR *)DropName - (UCHAR *)DropFiles);
DropFiles->fWide = TRUE;
for (UINT i = 0; i < count; ++i) {
pDragQueryFileW(hDrop, i, DropName, 510);
HANDLE hFile = CreateFileW(DropName,
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
BOOLEAN is_copy;
LONG status = SbieDll_GetHandlePath(hFile, DropName, &is_copy);
if (status == 0 && is_copy) {
SbieDll_TranslateNtToDosPath(DropName);
sandboxed = true;
} else {
wmemzero(DropName, 512);
pDragQueryFileW(hDrop, i, DropName, 510);
}
CloseHandle(hFile);
}
DropName += wcslen(DropName) + 1;
}
*DropName = L'\0';
++DropName;
//
// if we found any sandboxed files to translate to full paths, then
// create our own HGLOBAL data object
//
if (! sandboxed) {
hData = NULL;
} else {
ULONG_PTR len = (UCHAR *)DropName - (UCHAR *)DropFiles;
hData = GlobalAlloc(GMEM_MOVEABLE, len);
if (hData) {
void *ptr = GlobalLock(hData);
memcpy(ptr, DropFiles, len);
GlobalUnlock(hData);
}
}
Dll_Free(DropFiles);
return hData;
}
//---------------------------------------------------------------------------
// OpenFileFromHDrop
//---------------------------------------------------------------------------
_FX HANDLE XDataObject::OpenFileFromHDrop(HGLOBAL hData)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
WCHAR *FileName = (WCHAR *)Dll_Alloc(1024 * sizeof(WCHAR));
UINT count = pDragQueryFileW((HDROP)hData, 0, FileName, 1000);
if (count > 0 && count < 1000) {
FileName[count] = L'\0';
hFile = CreateFileW(FileName,
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
}
Dll_Free(FileName);
return hFile;
}
//---------------------------------------------------------------------------
// InitFormatFileNameA
//---------------------------------------------------------------------------
_FX HGLOBAL XDataObject::InitFormatFileNameA(HGLOBAL hData)
{
HGLOBAL hDataRet = NULL;
HANDLE hFile;
if (m_pDataObject) {
//
// hData is CF_FILENAMEA
//
char *FileNameA = (char *)GlobalLock(hData);
hFile = CreateFileA(FileNameA,
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
GlobalUnlock(hData);
} else {
//
// hData is CF_HDROP
//
hFile = OpenFileFromHDrop(hData);
}
if (hFile != INVALID_HANDLE_VALUE) {
BOOLEAN is_copy;
WCHAR *name = (WCHAR *)Dll_Alloc(8192);
LONG status = SbieDll_GetHandlePath(hFile, name, &is_copy);
if (! m_pDataObject) {
// hData was CF_HDROP so we don't have a default CF_FILENAMEA
// to return. we need to always create it regardless of is_copy
is_copy = TRUE;
}
if (status == 0 && is_copy) {
SbieDll_TranslateNtToDosPath(name);
UNICODE_STRING uni;
ANSI_STRING ansi;
RtlInitUnicodeString(&uni, name);
ansi.Length = 0;
ansi.MaximumLength = uni.Length / sizeof(WCHAR) + 1;
hDataRet = GlobalAlloc(GMEM_MOVEABLE, ansi.MaximumLength);
if (hDataRet) {
ansi.Buffer = (UCHAR *)GlobalLock(hDataRet);
RtlUnicodeStringToAnsiString(&ansi, &uni, FALSE);
GlobalUnlock(hDataRet);
}
}
Dll_Free(name);
CloseHandle(hFile);
}
return hDataRet;
}
//---------------------------------------------------------------------------
// InitFormatFileNameW
//---------------------------------------------------------------------------
_FX HGLOBAL XDataObject::InitFormatFileNameW(HGLOBAL hData)
{
HGLOBAL hDataRet = NULL;
HANDLE hFile;
if (m_pDataObject) {
//
// hData is CF_FILENAMEW
//
WCHAR *FileNameW = (WCHAR *)GlobalLock(hData);
hFile = CreateFileW(FileNameW,
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
GlobalUnlock(hData);
} else {
//
// hData is CF_HDROP
//
hFile = OpenFileFromHDrop(hData);
}
if (hFile != INVALID_HANDLE_VALUE) {
BOOLEAN is_copy;
WCHAR *name = (WCHAR *)Dll_Alloc(8192);
LONG status = SbieDll_GetHandlePath(hFile, name, &is_copy);
if (! m_pDataObject) {
// hData was CF_HDROP so we don't have a default CF_FILENAMEW
// to return. we need to always create it regardless of is_copy
is_copy = TRUE;
}
if (status == 0 && is_copy) {
SbieDll_TranslateNtToDosPath(name);
ULONG len = (wcslen(name) + 1) * sizeof(WCHAR);
hDataRet = GlobalAlloc(GMEM_MOVEABLE, len);
if (hDataRet) {
WCHAR *ptr = (WCHAR *)GlobalLock(hDataRet);
memcpy(ptr, name, len);
GlobalUnlock(hDataRet);
}
}
Dll_Free(name);
CloseHandle(hFile);
}
return hDataRet;
}
//---------------------------------------------------------------------------
// InitFormatIdList
//---------------------------------------------------------------------------
_FX HGLOBAL XDataObject::InitFormatIdList(HGLOBAL hData)
{
#define GetPidl(i) (LPCITEMIDLIST)(((LPBYTE)pIdList)+(pIdList)->aoffset[i])
if (! m_pDataObject) {
// if we don't have an underlying data object,
// then we shouldn't return an ID List
return (HGLOBAL)-1;
}
if ( (! pILCombine) || (! pILGetSize) || (! pSHFree)
|| (! pSHILCreateFromPath) || (! pSHGetPathFromIDList))
return NULL;
CIDA *pIdList = (CIDA *)GlobalLock(hData);
if (! pIdList)
return NULL;
BOOL ok;
HANDLE hFile;
WCHAR *path = (WCHAR *)Dll_AllocTemp(8192);
//
// check how many of the files in the Shell ID List Array
// have copies in the sandbox. we will prepare a new array
// only if all files have a copy in the sandbox
//
UINT num_in_box = 0;
UINT count;
for (count = 1; count <= pIdList->cidl; ++count) {
LPCITEMIDLIST pidl = pILCombine(GetPidl(0), GetPidl(count));
if (pidl) {
ok = pSHGetPathFromIDList(pidl, path);
if (ok) {
hFile = CreateFileW(path,
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
BOOLEAN is_copy;
LONG rc = SbieDll_GetHandlePath(hFile, path, &is_copy);
if (rc == 0 && is_copy)
++num_in_box;
CloseHandle(hFile);
}
}
pSHFree((void *)pidl);
}
}
//
// if none of the files are in the sandbox, if all of the files are
// in the sandbox then we create a new Shell ID List Array
//
// if some files are in the sandbox and others outside the sandbox
// then we can't return a Shell ID List Array and hopefully the
// caller can fallback on HDROP
//
HGLOBAL hDataRet = NULL;
if (num_in_box == 0)
goto finish;
if (num_in_box != pIdList->cidl) {
hDataRet = (HGLOBAL)-1;
goto finish;
}
//
// get the pidl for the parent folder in the sandbox
//
ok = pSHGetPathFromIDList(GetPidl(0), path);
if (!ok)
goto finish;
hFile = CreateFileW(path,
GENERIC_WRITE, FILE_SHARE_VALID_FLAGS, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile == INVALID_HANDLE_VALUE)
goto finish;
BOOLEAN is_copy;
LONG rc = SbieDll_GetHandlePath(hFile, path, &is_copy);
CloseHandle(hFile);
if (rc == STATUS_BAD_INITIAL_PC) {
//
// if the parent folder is a root folder, we have to open
// the file and get rid of the last path component
//
LPCITEMIDLIST pidl = pILCombine(GetPidl(0), GetPidl(1));
if (pidl) {
ok = pSHGetPathFromIDList(pidl, path);
if (ok) {
hFile = CreateFileW(path,
GENERIC_WRITE, FILE_SHARE_VALID_FLAGS, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
LONG rc2 = SbieDll_GetHandlePath(hFile, path, &is_copy);
CloseHandle(hFile);
if (rc2 == 0 && is_copy) {
WCHAR *ptr = wcsrchr(path, L'\\');
if (ptr) {
*ptr = L'\0';
rc = 0;
}
}
}
pSHFree((void *)pidl);
}
}
if (rc != 0 || (! is_copy))
goto finish;
//
// create a new pidl for the parent folder path in the sandbox
//
SbieDll_TranslateNtToDosPath(path);
HRESULT hr;
LPITEMIDLIST pidl;
ULONG flags = 0;
hr = pSHILCreateFromPath(path, &pidl, &flags);
if (FAILED(hr))
goto finish;
//
// create a new array where the pidl for the parent folder
// references the corresponding folder in the sandbox
//
ULONG new_idlist_len = (pIdList->cidl + 2) * sizeof(UINT)
+ pILGetSize(pidl);
for (count = 1; count <= pIdList->cidl; ++count)
new_idlist_len += pILGetSize(GetPidl(count));
hDataRet = GlobalAlloc(GMEM_MOVEABLE, new_idlist_len);
if (hDataRet) {
UCHAR *ptr0 = (UCHAR *)GlobalLock(hDataRet);
((CIDA *)ptr0)->cidl = pIdList->cidl;
UINT *offsets = ((CIDA *)ptr0)->aoffset;
UCHAR *ptr = (UCHAR *)&offsets[pIdList->cidl + 1];
ULONG pidl_len = pILGetSize(pidl);
memcpy(ptr, pidl, pidl_len);
offsets[0] = (USHORT)(ULONG_PTR)(ptr - ptr0);
ptr += pidl_len;
for (count = 1; count <= pIdList->cidl; ++count) {
pidl_len = pILGetSize(GetPidl(count));
memcpy(ptr, pidl, pidl_len);
offsets[count] = (USHORT)(ULONG_PTR)(ptr - ptr0);
ptr += pidl_len;
}
GlobalUnlock(hDataRet);
}
pSHFree(pidl);
finish:
Dll_Free(path);
GlobalUnlock(hData);
return hDataRet;
#undef GetPidl
}
//---------------------------------------------------------------------------
// Ole_ReleaseStgMedium
//---------------------------------------------------------------------------
_FX void Ole_ReleaseStgMedium(STGMEDIUM *pmedium)
{
if (pmedium != NULL)
{
if (((pmedium->tymed == TYMED_ENHMF && pmedium->hEnhMetaFile != 0 && pmedium->pUnkForRelease == 0) ||
(__sys_GetEnhMetaFileBits != 0 && 0 != __sys_GetEnhMetaFileBits(pmedium->hEnhMetaFile, 0, NULL))) &&
__sys_DeleteEnhMetaFile != 0)
{
__sys_DeleteEnhMetaFile(pmedium->hEnhMetaFile);
pmedium->tymed = TYMED_NULL;
return;
}
if (((pmedium->tymed == TYMED_GDI && pmedium->hBitmap != 0 && pmedium->pUnkForRelease == 0) ||
(__sys_GetBitmapBits != 0 && 0 != __sys_GetBitmapBits(pmedium->hBitmap, 0, NULL))) &&
__sys_DeleteObject != 0)
{
__sys_DeleteObject(pmedium->hBitmap);
pmedium->tymed = TYMED_NULL;
return;
}
}
((P_ReleaseStgMedium)__sys_ReleaseStgMedium)(pmedium);
}
//---------------------------------------------------------------------------
// Ole_OleSetClipboard
//---------------------------------------------------------------------------
_FX HRESULT Ole_OleSetClipboard(IDataObject *pDataObject)
{
if (pDataObject) {
ULONG len = sizeof(XDataObject);
void *buf = Dll_Alloc(len);
XDataObject *xDataObject;
HDROP hDrop = Ole_IsVirtualFile(pDataObject);
if (hDrop)
pDataObject = NULL;
xDataObject = new (buf) XDataObject(pDataObject, hDrop);
pDataObject = xDataObject;
}
return ((P_OleSetClipboard)__sys_OleSetClipboard)(pDataObject);
}
//---------------------------------------------------------------------------
// Ole_IsVirtualFile
//---------------------------------------------------------------------------
// this code doesn't seem to be necessary and causes tmp files to be created in the sandbox
_FX HDROP Ole_IsVirtualFile(IDataObject *pDataObject)
{
return NULL;
}
/*
//
// check for the clipboard formats that zip files publish:
// FileGroupDescriptorW and FileContents
//
if (! __sys_ReleaseStgMedium)
return NULL;
IEnumFORMATETC *pEnum;
HRESULT hr = pDataObject->EnumFormatEtc(DATADIR_GET, &pEnum);
if (FAILED(hr))
return NULL;
CLIPFORMAT cfFileDescriptor = 0;
CLIPFORMAT cfFileContents = 0;
FORMATETC format;
pEnum->Reset();
while (1) {
ULONG n;
hr = pEnum->Next(1, &format, &n);
if (FAILED(hr) || n == 0)
break;
WCHAR name[64];
CLIPFORMAT fmt = format.cfFormat;
name[0] = L'\0';
if (fmt >= 0xC000 && fmt <= 0xFFFF) {
__sys_GetClipboardFormatNameW(fmt, name, 60);
if (_wcsicmp(name, CFSTR_FILEDESCRIPTORW) == 0)
cfFileDescriptor = fmt;
else if (_wcsicmp(name, CFSTR_FILECONTENTS) == 0)
cfFileContents = fmt;
}
}
pEnum->Release();
if ((! cfFileDescriptor) || (! cfFileContents))
return NULL;
//
// get temporary output folder:
// C:\TEMP\SbieTemp\HHHHHHHHLLLLLLLL
//
WCHAR *TempPath = (WCHAR *)Dll_Alloc((MAX_PATH + 128) * sizeof(WCHAR));
wmemzero(TempPath, MAX_PATH + 128);
GetTempPath(MAX_PATH, TempPath);
wcscat(TempPath, SBIE L"_Temp\\");
CreateDirectory(TempPath, NULL);
WCHAR *TempFile = TempPath + wcslen(TempPath);
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
_itow(ft.dwHighDateTime, TempFile, 16);
TempFile += wcslen(TempFile);
_itow(ft.dwLowDateTime, TempFile, 16);
TempFile += wcslen(TempFile);
CreateDirectory(TempPath, NULL);
*TempFile = L'\\';
++TempFile;
//
// prepare the HDROP / DROPFILES output buffer
//
format.cfFormat = cfFileDescriptor;
format.ptd = NULL;
format.dwAspect = DVASPECT_CONTENT;
format.lindex = -1;
format.tymed = TYMED_HGLOBAL;
STGMEDIUM mediumFileDescriptor;
memzero(&mediumFileDescriptor, sizeof(mediumFileDescriptor));
hr = pDataObject->GetData(&format, &mediumFileDescriptor);
if (FAILED(hr) || mediumFileDescriptor.tymed != TYMED_HGLOBAL) {
Dll_Free(TempPath);
return NULL;
}
FILEGROUPDESCRIPTOR *Group =
(FILEGROUPDESCRIPTOR *)GlobalLock(mediumFileDescriptor.hGlobal);
ULONG DropFiles_len =
((ULONG)Group->cItems) * MAX_PATH * 2 * sizeof(WCHAR);
DROPFILES *DropFiles = (DROPFILES *)Dll_Alloc(DropFiles_len);
memzero(DropFiles, DropFiles_len);
WCHAR *DropName = (WCHAR *)(DropFiles + 1);
DropFiles->pFiles = (DWORD)((UCHAR *)DropName - (UCHAR *)DropFiles);
DropFiles->fWide = TRUE;
//
// extract each file into the temporary folder
//
const WCHAR *ParentDirPtr = NULL;
ULONG ParentDirLen = 0;
BOOLEAN AtLeastOne = FALSE;
for (UINT i = 0; i < Group->cItems; ++i) {
const WCHAR *cFileName = Group->fgd[i].cFileName;
//
// if the item is a directory, we're going to add it as a directory
// to DROPFILES, and make sure its children are extracted from
// the virtual container, but are not added to the DROPFILES
//
if ((Group->fgd[i].dwFlags & FD_ATTRIBUTES) &&
(Group->fgd[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
wcscpy(TempFile, cFileName);
CreateDirectory(TempPath, NULL);
//
// don't add the file explicitly to DROPFILES if its
// parent directory has already been added
//
BOOLEAN add = TRUE;
if (ParentDirLen &&
cFileName[ParentDirLen] == L'\\' &&
wcsncmp(cFileName, ParentDirPtr, ParentDirLen) == 0)
add = FALSE;
if (add) {
wcscpy(DropName, TempPath);
DropName += wcslen(DropName) + 1;
AtLeastOne = TRUE;
ParentDirPtr = cFileName;
ParentDirLen = wcslen(ParentDirPtr);
}
continue;
}
//
// otherwise the item is a file, extract only if not too large
//
if ((Group->fgd[i].dwFlags & FD_FILESIZE) == 0)
continue;
if (Group->fgd[i].nFileSizeHigh)
continue;
ULONG FileSize = Group->fgd[i].nFileSizeLow;
format.cfFormat = cfFileContents;
format.ptd = NULL;
format.dwAspect = DVASPECT_CONTENT;
format.lindex = i;
format.tymed = TYMED_ISTREAM;
STGMEDIUM medium;
memzero(&medium, sizeof(medium));
hr = pDataObject->GetData(&format, &medium);
if (FAILED(hr))
continue;
//
//
//
BOOLEAN reset = TRUE;
if (medium.tymed == TYMED_ISTREAM) {
wcscpy(TempFile, cFileName);
if (Ole_WriteStreamToFile(medium.pstm, FileSize, TempPath)) {
//
// don't add the file explicitly to DROPFILES if its
// parent directory has already been added
//
if (ParentDirLen &&
cFileName[ParentDirLen] == L'\\' &&
wcsncmp(cFileName, ParentDirPtr, ParentDirLen) == 0) {
reset = FALSE;
} else {
wcscpy(DropName, TempPath);
DropName += wcslen(DropName) + 1;
AtLeastOne = TRUE;
}
}
}
if (reset) {
ParentDirPtr = NULL;
ParentDirLen = 0;
}
__sys_ReleaseStgMedium(&medium);
}
//
// create HGLOBAL / HDROP for the DROPFILES buffer
//
HGLOBAL hData = NULL;
if (AtLeastOne) {
*DropName = L'\0';
++DropName;
ULONG_PTR len = (UCHAR *)DropName - (UCHAR *)DropFiles;
hData = GlobalAlloc(GMEM_MOVEABLE, len);
if (hData) {
void *ptr = GlobalLock(hData);
memcpy(ptr, DropFiles, len);
GlobalUnlock(hData);
}
}
GlobalUnlock(mediumFileDescriptor.hGlobal);
__sys_ReleaseStgMedium(&mediumFileDescriptor);
Dll_Free(DropFiles);
Dll_Free(TempPath);
return (HDROP)hData;
}
//---------------------------------------------------------------------------
// Ole_WriteStreamToFile
//---------------------------------------------------------------------------
_FX BOOLEAN Ole_WriteStreamToFile(
IStream *pStream, ULONG StreamSize, WCHAR *Path)
{
HANDLE hFile = CreateFileW(
Path, GENERIC_WRITE, FILE_SHARE_VALID_FLAGS, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
BOOLEAN ok = TRUE;
UCHAR *Buffer = (UCHAR *)Dll_Alloc(16384);
while (1) {
ULONG BytesRead = 0;
pStream->Read(Buffer, 16384, &BytesRead);
if (! BytesRead)
break;
ULONG BytesWritten = 0;
WriteFile(hFile, Buffer, BytesRead, &BytesWritten, NULL);
if (BytesWritten != BytesRead) {
ok = FALSE;
break;
}
}
Dll_Free(Buffer);
CloseHandle(hFile);
return ok;
}
*/
//---------------------------------------------------------------------------
// Ole_RegisterDragDrop
//---------------------------------------------------------------------------
_FX HRESULT Ole_RegisterDragDrop(HWND hwnd, IDropTarget *pDropTarget)
{
HRESULT hr = __sys_RegisterDragDrop(hwnd, pDropTarget);
if (SUCCEEDED(hr) && Gui_DropTargetProp_Atom) {
//
// our hook on SetProp renamed the DropTarget window properties
// set by the real RegisterDragDrop, and we enable the
// WS_EX_ACCEPTFILES style flag so we get the WM_DROPFILES message
// and turn it into an OLE drop operation in Ole_DoDragDrop
//
ULONG exstyle = __sys_GetWindowLongW(hwnd, GWL_EXSTYLE);
if ((exstyle & WS_EX_ACCEPTFILES) == 0) {
exstyle |= WS_EX_ACCEPTFILES;
__sys_SetWindowLongW(hwnd, GWL_EXSTYLE, exstyle);
__sys_SetPropW(hwnd, (LPCWSTR)Gui_DropTargetProp_Atom, pDropTarget);
if (! __sys_DragFinish) {
HMODULE shell32 = LoadLibrary(L"shell32.dll");
__sys_DragFinish =
(P_DragFinish)GetProcAddress(shell32, "DragFinish");
}
Gui_SetWindowProc(hwnd, TRUE);
}
}
return hr;
}
//---------------------------------------------------------------------------
// Ole_RevokeDragDrop
//---------------------------------------------------------------------------
_FX HRESULT Ole_RevokeDragDrop(HWND hwnd)
{
HRESULT hr = __sys_RevokeDragDrop(hwnd);
if (SUCCEEDED(hr) && Gui_DropTargetProp_Atom) {
//
// if we enabled the WS_EX_ACCEPTFILES style in Ole_RegisterDragDrop
// then we should now clear that style bit
//
void *pDropTarget =
__sys_RemovePropW(hwnd, (LPCWSTR)Gui_DropTargetProp_Atom);
if (pDropTarget) {
ULONG exstyle = __sys_GetWindowLongW(hwnd, GWL_EXSTYLE);
if ((exstyle & WS_EX_ACCEPTFILES) == WS_EX_ACCEPTFILES) {
exstyle &= ~WS_EX_ACCEPTFILES;
__sys_SetWindowLongW(hwnd, GWL_EXSTYLE, exstyle);
}
}
}
return hr;
}
//---------------------------------------------------------------------------
// Ole_DoDragDrop
//---------------------------------------------------------------------------
extern "C" _FX BOOLEAN Ole_DoDragDrop(
HWND hWnd, WPARAM wParam, LPARAM lParam)
{
if (! Gui_RenameClasses)
return FALSE;
if (wParam == tzuk) {
Ole_DoDragDrop_2((void *)lParam);
return TRUE;
}
//
//
//
IDropTarget *pDropTarget = NULL;
if (wParam) {
pDropTarget = (IDropTarget *)__sys_GetPropW(
hWnd, (LPCWSTR)Gui_DropTargetProp_Atom);
}
if (! pDropTarget)
return FALSE;
ULONG len = sizeof(XDataObject);
void *buf = Dll_Alloc(len);
XDataObject *xDataObject =
new (buf) XDataObject(NULL, (HDROP)wParam);
POINT ptx;
__sys_GetCursorPos(&ptx);
POINTL pt;
pt.x = ptx.x;
pt.y = ptx.y;
ULONG effect = DROPEFFECT_COPY;
BOOLEAN disregardEffect = FALSE;
HRESULT hr = pDropTarget->DragEnter(xDataObject, 0, pt, &effect);
if (SUCCEEDED(hr)) {
if (Dll_ImageType == DLL_IMAGE_INTERNET_EXPLORER ||
Dll_ImageType == DLL_IMAGE_MOZILLA_FIREFOX ||
Dll_ImageType == DLL_IMAGE_GOOGLE_CHROME) {
ULONG_PTR *Args =
(ULONG_PTR *)Dll_Alloc(sizeof(ULONG_PTR) * 8);
Args[0] = (ULONG_PTR)Args;
Args[1] = (ULONG_PTR)hWnd;
Args[2] = (ULONG_PTR)wParam;
Args[3] = (ULONG_PTR)pDropTarget;
Args[4] = (ULONG_PTR)xDataObject;
Args[5] = pt.x;
Args[6] = pt.y;
Args[7] = 1;
if (QueueUserWorkItem(
Ole_DoDragDrop_2, Args, WT_EXECUTELONGFUNCTION))
return TRUE;
Dll_Free(Args);
}
hr = pDropTarget->DragOver(0, pt, &effect);
if (effect == 0 && Dll_ImageType == DLL_IMAGE_WINDOWS_MEDIA_PLAYER)
disregardEffect = TRUE;
}
if (SUCCEEDED(hr) && (effect || disregardEffect))
pDropTarget->Drop(xDataObject, 0, pt, &effect);
xDataObject->Release();
__sys_DragFinish((HDROP)wParam);
return TRUE;
}
//---------------------------------------------------------------------------
// Ole_DoDragDrop_2
//---------------------------------------------------------------------------
_FX ULONG Ole_DoDragDrop_2(void *ThreadArgs)
{
ULONG_PTR *Args = (ULONG_PTR *)ThreadArgs;
__try {
if (*Args != (ULONG_PTR)Args)
Args = 0;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Args = 0;
}
if (! Args)
return 0;
HWND hWnd = (HWND)Args[1];
HDROP hDrop = (HDROP)Args[2];
IDropTarget *pDropTarget = (IDropTarget *)Args[3];
XDataObject *xDataObject = (XDataObject *)Args[4];
POINTL pt;
pt.x = (LONG)Args[5];
pt.y = (LONG)Args[6];
ULONG *step = (ULONG *)&Args[7];
//
// step 1: invoked by Ole_DoDragDrop after getting the first
// WM_DROPFILES message. record ThreadArgs in a window property,
// sleep for a short while, and post the second WM_DROPFILES
//
if (*step == 1) {
Sleep(250);
++(*step);
if (__sys_PostMessageW(hWnd, WM_DROPFILES, tzuk, (LPARAM)Args))
return 0;
}
//
// step 2: invoked by the second WM_DROPFILES
//
if (*step < 10) {
ULONG effect = DROPEFFECT_COPY;
HRESULT hr = pDropTarget->DragOver(0, pt, &effect);
if (SUCCEEDED(hr)) {
Sleep(100);
++(*step);
if ((*step) & 1) {
++Args[6];
++Args[7];
} else {
--Args[6];
--Args[7];
}
if (__sys_PostMessageW(hWnd, WM_DROPFILES, tzuk, (LPARAM)Args))
return 0;
}
}
//
// step 3: invoked by the third WM_DROPFILES
//
if (*step >= 10) {
ULONG effect = DROPEFFECT_COPY;
pDropTarget->Drop(xDataObject, 0, pt, &effect);
xDataObject->Release();
__sys_DragFinish(hDrop);
}
//
// clean up work data
//
Dll_Free(Args);
return 0;
}
//---------------------------------------------------------------------------
// Ole_XDataObject_From_IDataObject
//---------------------------------------------------------------------------
extern "C" _FX IDataObject *Ole_XDataObject_From_IDataObject(
IDataObject *pDataObject)
{
ULONG len = sizeof(XDataObject);
void *buf = Dll_Alloc(len);
XDataObject *xDataObject = new (buf) XDataObject(pDataObject, NULL);
return xDataObject;
}