dataobject.c 12 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4 5
/*
 *	IEnumFORMATETC, IDataObject
 *
 * selecting and droping objects within the shell and/or common dialogs
 *
6
 *	Copyright 1998, 1999	<juergen.schmied@metronet.de>
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
21
 */
22 23
#include <string.h>

24
#define COBJMACROS
25 26
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
27

28 29
#include "windef.h"
#include "wingdi.h"
30
#include "pidl.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
31 32
#include "winerror.h"
#include "shell32_main.h"
33
#include "wine/debug.h"
34
#include "undocshell.h"
35

36
WINE_DEFAULT_DEBUG_CHANNEL(shell);
37

Alexandre Julliard's avatar
Alexandre Julliard committed
38 39 40
/***********************************************************************
*   IEnumFORMATETC implementation
*/
41

42
typedef struct
43 44
{
    /* IUnknown fields */
45
    const IEnumFORMATETCVtbl *lpVtbl;
Mike McCormack's avatar
Mike McCormack committed
46
    LONG                      ref;
47
    /* IEnumFORMATETC fields */
48 49 50
    UINT        posFmt;
    UINT        countFmt;
    LPFORMATETC pFmt;
51
} IEnumFORMATETCImpl;
52

53 54
static HRESULT WINAPI IEnumFORMATETC_fnQueryInterface(
               LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
55
{
56
	IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
57
	TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
Alexandre Julliard's avatar
Alexandre Julliard committed
58

59
	*ppvObj = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
60 61

	if(IsEqualIID(riid, &IID_IUnknown))
62
	{
63
	  *ppvObj = This;
Alexandre Julliard's avatar
Alexandre Julliard committed
64 65
	}
	else if(IsEqualIID(riid, &IID_IEnumFORMATETC))
66 67
	{
	  *ppvObj = (IEnumFORMATETC*)This;
68
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
69 70

	if(*ppvObj)
71 72
	{
	  IUnknown_AddRef((IUnknown*)(*ppvObj));
73
	  TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
Alexandre Julliard's avatar
Alexandre Julliard committed
74 75
	  return S_OK;
	}
76
	TRACE("-- Interface: E_NOINTERFACE\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
77 78
	return E_NOINTERFACE;
}
79

80
static ULONG WINAPI IEnumFORMATETC_fnAddRef(LPENUMFORMATETC iface)
81
{
82
	IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
83 84
	ULONG refCount = InterlockedIncrement(&This->ref);

85
	TRACE("(%p)->(count=%u)\n", This, refCount - 1);
86 87

	return refCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
88
}
89

90
static ULONG WINAPI IEnumFORMATETC_fnRelease(LPENUMFORMATETC iface)
91
{
92
	IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
93
	ULONG refCount = InterlockedDecrement(&This->ref);
94

95
	TRACE("(%p)->(%u)\n", This, refCount + 1);
96 97

	if (!refCount)
98 99
	{
	  TRACE(" destroying IEnumFORMATETC(%p)\n",This);
100
	  SHFree (This->pFmt);
101
	  HeapFree(GetProcessHeap(),0,This);
Alexandre Julliard's avatar
Alexandre Julliard committed
102 103
	  return 0;
	}
104
	return refCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
105
}
106

107
static HRESULT WINAPI IEnumFORMATETC_fnNext(LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
108
{
109
	IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
110
	UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
111

112
	TRACE("(%p)->(%u,%p)\n", This, celt, rgelt);
Alexandre Julliard's avatar
Alexandre Julliard committed
113

114 115 116
	if(!This->pFmt)return S_FALSE;
	if(!rgelt) return E_INVALIDARG;
	if (pceltFethed)  *pceltFethed = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
117

118 119 120
	for(i = 0; This->posFmt < This->countFmt && celt > i; i++)
   	{
	  *rgelt++ = This->pFmt[This->posFmt++];
121
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
122

123 124 125
	if (pceltFethed) *pceltFethed = i;

	return ((i == celt) ? S_OK : S_FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
126
}
127

128 129
static HRESULT WINAPI IEnumFORMATETC_fnSkip(LPENUMFORMATETC iface, ULONG celt)
{
130
	IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
131
	TRACE("(%p)->(num=%u)\n", This, celt);
Alexandre Julliard's avatar
Alexandre Julliard committed
132

133
	if((This->posFmt + celt) >= This->countFmt) return S_FALSE;
134
	This->posFmt += celt;
Alexandre Julliard's avatar
Alexandre Julliard committed
135 136
	return S_OK;
}
137

138 139
static HRESULT WINAPI IEnumFORMATETC_fnReset(LPENUMFORMATETC iface)
{
140
	IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
141
	TRACE("(%p)->()\n", This);
Alexandre Julliard's avatar
Alexandre Julliard committed
142

143
        This->posFmt = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
144 145
        return S_OK;
}
146

147 148
static HRESULT WINAPI IEnumFORMATETC_fnClone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum)
{
149
	IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
150
	TRACE("(%p)->(ppenum=%p)\n", This, ppenum);
Alexandre Julliard's avatar
Alexandre Julliard committed
151

152 153
	if (!ppenum) return E_INVALIDARG;
	*ppenum = IEnumFORMATETC_Constructor(This->countFmt, This->pFmt);
154 155
        if(*ppenum)
           IEnumFORMATETC_fnSkip(*ppenum, This->posFmt);
156
	return S_OK;
157 158
}

159
static const IEnumFORMATETCVtbl efvt =
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
{
    IEnumFORMATETC_fnQueryInterface,
    IEnumFORMATETC_fnAddRef,
    IEnumFORMATETC_fnRelease,
    IEnumFORMATETC_fnNext,
    IEnumFORMATETC_fnSkip,
    IEnumFORMATETC_fnReset,
    IEnumFORMATETC_fnClone
};

LPENUMFORMATETC IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[])
{
    IEnumFORMATETCImpl* ef;
    DWORD size=cfmt * sizeof(FORMATETC);

    ef = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl));

    if(ef)
    {
        ef->ref=1;
        ef->lpVtbl=&efvt;

        ef->countFmt = cfmt;
        ef->pFmt = SHAlloc (size);

        if (ef->pFmt)
            memcpy(ef->pFmt, afmt, size);
    }

    TRACE("(%p)->(%u,%p)\n",ef, cfmt, afmt);
    return (LPENUMFORMATETC)ef;
}

193

Alexandre Julliard's avatar
Alexandre Julliard committed
194 195 196
/***********************************************************************
*   IDataObject implementation
*/
197

198
/* number of supported formats */
199
#define MAX_FORMATS 4
200

201
typedef struct
202
{
203
	/* IUnknown fields */
204
	const IDataObjectVtbl *lpVtbl;
Mike McCormack's avatar
Mike McCormack committed
205
	LONG		ref;
206

207 208
	/* IDataObject fields */
	LPITEMIDLIST	pidl;
209 210
	LPITEMIDLIST *	apidl;
	UINT		cidl;
211

212 213
	FORMATETC	pFormatEtc[MAX_FORMATS];
	UINT		cfShellIDList;
214 215
	UINT		cfFileNameA;
	UINT		cfFileNameW;
216 217 218

} IDataObjectImpl;

Alexandre Julliard's avatar
Alexandre Julliard committed
219 220 221
/***************************************************************************
*  IDataObject_QueryInterface
*/
222
static HRESULT WINAPI IDataObject_fnQueryInterface(LPDATAOBJECT iface, REFIID riid, LPVOID * ppvObj)
223
{
224
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
225
	TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
Alexandre Julliard's avatar
Alexandre Julliard committed
226 227 228 229

	*ppvObj = NULL;

	if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
230
	{
231
	  *ppvObj = This;
Alexandre Julliard's avatar
Alexandre Julliard committed
232 233
	}
	else if(IsEqualIID(riid, &IID_IDataObject))  /*IDataObject*/
234 235
	{
	  *ppvObj = (IDataObject*)This;
236
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
237 238

	if(*ppvObj)
239
	{
240
	  IUnknown_AddRef((IUnknown*)*ppvObj);
241
	  TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
Alexandre Julliard's avatar
Alexandre Julliard committed
242 243
	  return S_OK;
	}
244
	TRACE("-- Interface: E_NOINTERFACE\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
245
	return E_NOINTERFACE;
246
}
247

Alexandre Julliard's avatar
Alexandre Julliard committed
248 249 250
/**************************************************************************
*  IDataObject_AddRef
*/
251
static ULONG WINAPI IDataObject_fnAddRef(LPDATAOBJECT iface)
252
{
253
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
254 255
	ULONG refCount = InterlockedIncrement(&This->ref);

256
	TRACE("(%p)->(count=%u)\n", This, refCount - 1);
257 258

	return refCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
259
}
260

Alexandre Julliard's avatar
Alexandre Julliard committed
261 262 263
/**************************************************************************
*  IDataObject_Release
*/
264
static ULONG WINAPI IDataObject_fnRelease(LPDATAOBJECT iface)
265
{
266
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
267 268
	ULONG refCount = InterlockedDecrement(&This->ref);

269
	TRACE("(%p)->(%u)\n", This, refCount + 1);
270

271
	if (!refCount)
272 273 274
	{
	  TRACE(" destroying IDataObject(%p)\n",This);
	  _ILFreeaPidl(This->apidl, This->cidl);
275
	  ILFree(This->pidl),
276
	  HeapFree(GetProcessHeap(),0,This);
Alexandre Julliard's avatar
Alexandre Julliard committed
277
	}
278
	return refCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
279
}
280 281

/**************************************************************************
282
* IDataObject_fnGetData
283
*/
284
static HRESULT WINAPI IDataObject_fnGetData(LPDATAOBJECT iface, LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
285
{
286
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
287 288

	char	szTemp[256];
289

290
	szTemp[0]=0;
291 292
	GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256);
	TRACE("(%p)->(%p %p format=%s)\n", This, pformatetcIn, pmedium, szTemp);
293

294 295 296 297 298 299
	if (pformatetcIn->cfFormat == This->cfShellIDList)
	{
	  if (This->cidl < 1) return(E_UNEXPECTED);
	  pmedium->u.hGlobal = RenderSHELLIDLIST(This->pidl, This->apidl, This->cidl);
	}
	else if	(pformatetcIn->cfFormat == CF_HDROP)
300
	{
301 302 303
	  if (This->cidl < 1) return(E_UNEXPECTED);
	  pmedium->u.hGlobal = RenderHDROP(This->pidl, This->apidl, This->cidl);
	}
304
	else if	(pformatetcIn->cfFormat == This->cfFileNameA)
305 306
	{
	  if (This->cidl < 1) return(E_UNEXPECTED);
307 308 309 310 311 312
	  pmedium->u.hGlobal = RenderFILENAMEA(This->pidl, This->apidl, This->cidl);
	}
	else if	(pformatetcIn->cfFormat == This->cfFileNameW)
	{
	  if (This->cidl < 1) return(E_UNEXPECTED);
	  pmedium->u.hGlobal = RenderFILENAMEW(This->pidl, This->apidl, This->cidl);
313 314 315 316
	}
	else
	{
	  FIXME("-- expected clipformat not implemented\n");
317 318
	  return (E_INVALIDARG);
	}
319
	if (pmedium->u.hGlobal)
320 321 322
	{
	  pmedium->tymed = TYMED_HGLOBAL;
	  pmedium->pUnkForRelease = NULL;
323
	  return S_OK;
324
	}
325
	return E_OUTOFMEMORY;
Alexandre Julliard's avatar
Alexandre Julliard committed
326
}
327

328
static HRESULT WINAPI IDataObject_fnGetDataHere(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium)
329
{
330
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
331
	FIXME("(%p)->()\n", This);
Alexandre Julliard's avatar
Alexandre Julliard committed
332 333
	return E_NOTIMPL;
}
334

335
static HRESULT WINAPI IDataObject_fnQueryGetData(LPDATAOBJECT iface, LPFORMATETC pformatetc)
336
{
337
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
338
	UINT i;
339

340
	TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", This, pformatetc->cfFormat, pformatetc->tymed);
341

342 343 344 345 346 347 348 349 350 351 352 353 354 355
	if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
	  return DV_E_DVASPECT;

	/* check our formats table what we have */
	for (i=0; i<MAX_FORMATS; i++)
	{
	  if ((This->pFormatEtc[i].cfFormat == pformatetc->cfFormat)
	   && (This->pFormatEtc[i].tymed == pformatetc->tymed))
	  {
	    return S_OK;
	  }
	}

	return DV_E_TYMED;
Alexandre Julliard's avatar
Alexandre Julliard committed
356
}
357

358
static HRESULT WINAPI IDataObject_fnGetCanonicalFormatEtc(LPDATAOBJECT iface, LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
359
{
360
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
361
	FIXME("(%p)->()\n", This);
Alexandre Julliard's avatar
Alexandre Julliard committed
362 363
	return E_NOTIMPL;
}
364

365
static HRESULT WINAPI IDataObject_fnSetData(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
366
{
367
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
368
	FIXME("(%p)->()\n", This);
Alexandre Julliard's avatar
Alexandre Julliard committed
369 370
	return E_NOTIMPL;
}
371

372 373
static HRESULT WINAPI IDataObject_fnEnumFormatEtc(LPDATAOBJECT iface, DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
{
374
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
375 376 377 378 379 380 381 382 383 384

	TRACE("(%p)->()\n", This);
	*ppenumFormatEtc=NULL;

	/* only get data */
	if (DATADIR_GET == dwDirection)
	{
	  *ppenumFormatEtc = IEnumFORMATETC_Constructor(MAX_FORMATS, This->pFormatEtc);
	  return (*ppenumFormatEtc) ? S_OK : E_FAIL;
	}
385

Alexandre Julliard's avatar
Alexandre Julliard committed
386 387
	return E_NOTIMPL;
}
388

389
static HRESULT WINAPI IDataObject_fnDAdvise(LPDATAOBJECT iface, FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
390
{
391
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
392
	FIXME("(%p)->()\n", This);
Alexandre Julliard's avatar
Alexandre Julliard committed
393 394
	return E_NOTIMPL;
}
395 396
static HRESULT WINAPI IDataObject_fnDUnadvise(LPDATAOBJECT iface, DWORD dwConnection)
{
397
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
398
	FIXME("(%p)->()\n", This);
Alexandre Julliard's avatar
Alexandre Julliard committed
399 400
	return E_NOTIMPL;
}
401 402
static HRESULT WINAPI IDataObject_fnEnumDAdvise(LPDATAOBJECT iface, IEnumSTATDATA **ppenumAdvise)
{
403
	IDataObjectImpl *This = (IDataObjectImpl *)iface;
404
	FIXME("(%p)->()\n", This);
Alexandre Julliard's avatar
Alexandre Julliard committed
405 406
	return E_NOTIMPL;
}
407

408
static const IDataObjectVtbl dtovt =
409 410 411 412 413 414 415 416 417 418 419 420 421 422
{
	IDataObject_fnQueryInterface,
	IDataObject_fnAddRef,
	IDataObject_fnRelease,
	IDataObject_fnGetData,
	IDataObject_fnGetDataHere,
	IDataObject_fnQueryGetData,
	IDataObject_fnGetCanonicalFormatEtc,
	IDataObject_fnSetData,
	IDataObject_fnEnumFormatEtc,
	IDataObject_fnDAdvise,
	IDataObject_fnDUnadvise,
	IDataObject_fnEnumDAdvise
};
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453

/**************************************************************************
*  IDataObject_Constructor
*/
LPDATAOBJECT IDataObject_Constructor(HWND hwndOwner,
               LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidl, UINT cidl)
{
    IDataObjectImpl* dto;

    dto = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDataObjectImpl));

    if (dto)
    {
        dto->ref = 1;
        dto->lpVtbl = &dtovt;
        dto->pidl = ILClone(pMyPidl);
        dto->apidl = _ILCopyaPidl(apidl, cidl);
        dto->cidl = cidl;

        dto->cfShellIDList = RegisterClipboardFormatA(CFSTR_SHELLIDLIST);
        dto->cfFileNameA = RegisterClipboardFormatA(CFSTR_FILENAMEA);
        dto->cfFileNameW = RegisterClipboardFormatA(CFSTR_FILENAMEW);
        InitFormatEtc(dto->pFormatEtc[0], dto->cfShellIDList, TYMED_HGLOBAL);
        InitFormatEtc(dto->pFormatEtc[1], CF_HDROP, TYMED_HGLOBAL);
        InitFormatEtc(dto->pFormatEtc[2], dto->cfFileNameA, TYMED_HGLOBAL);
        InitFormatEtc(dto->pFormatEtc[3], dto->cfFileNameW, TYMED_HGLOBAL);
    }

    TRACE("(%p)->(apidl=%p cidl=%u)\n",dto, apidl, cidl);
    return (LPDATAOBJECT)dto;
}