/*
 *	Shell Folder stuff
 *
 *	Copyright 1997	Marcus Meissner
 *	Copyright 1998, 1999	Juergen Schmied
 *	
 *	IShellFolder with IDropTarget, IPersistFolder
 *
 */

#include <stdlib.h>
#include <string.h>

#include "debugtools.h"
#include "winerror.h"

#include "oleidl.h"
#include "shlguid.h"

#include "pidl.h"
#include "wine/obj_base.h"
#include "wine/obj_dragdrop.h"
#include "wine/obj_shellfolder.h"
#include "wine/undocshell.h"
#include "shell32_main.h"

DEFAULT_DEBUG_CHANNEL(shell)

#define MEM_DEBUG 1

/***************************************************************************
 *  GetNextElement (internal function)
 *
 * gets a part of a string till the first backslash
 *
 * PARAMETERS
 *  pszNext [IN] string to get the element from
 *  pszOut  [IN] pointer to buffer whitch receives string
 *  dwOut   [IN] length of pszOut
 *
 *  RETURNS
 *    LPSTR pointer to first, not yet parsed char
 */

static LPCWSTR GetNextElementW(LPCWSTR pszNext,LPWSTR pszOut,DWORD dwOut)
{	LPCWSTR   pszTail = pszNext;
	DWORD dwCopy;
	TRACE("(%s %p 0x%08lx)\n",debugstr_w(pszNext),pszOut,dwOut);

	*pszOut=0x0000;
	
	if(!pszNext || !*pszNext)
	  return NULL;

	while(*pszTail && (*pszTail != (WCHAR)'\\'))
	  pszTail++;

	dwCopy = (WCHAR*)pszTail - (WCHAR*)pszNext + 1;
	lstrcpynW(pszOut, pszNext, (dwOut<dwCopy)? dwOut : dwCopy);

	if(*pszTail)
	   pszTail++;
	else
	   pszTail = NULL;

	TRACE("--(%s %s 0x%08lx %p)\n",debugstr_w(pszNext),debugstr_w(pszOut),dwOut,pszTail);
	return pszTail;
}

static HRESULT SHELL32_ParseNextElement(
	HWND hwndOwner,
	IShellFolder * psf,
	LPITEMIDLIST * pidlInOut,
	LPOLESTR szNext,
	DWORD *pEaten,
	DWORD *pdwAttributes)
{
	HRESULT		hr = E_OUTOFMEMORY;
	LPITEMIDLIST	pidlOut, pidlTemp = NULL;
	IShellFolder	*psfChild;
	
	TRACE("(%p %p %s)\n",psf, pidlInOut? *pidlInOut: NULL, debugstr_w(szNext));


	/* get the shellfolder for the child pidl and let it analyse further */
	hr = IShellFolder_BindToObject(psf, *pidlInOut, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);

	if (psfChild)
	{
	  hr = IShellFolder_ParseDisplayName(psfChild, hwndOwner, NULL, szNext, pEaten, &pidlOut, pdwAttributes);
	  IShellFolder_Release(psfChild);

	  pidlTemp = ILCombine(*pidlInOut, pidlOut);

	  if (pidlOut) 
	    ILFree(pidlOut);
	}

	ILFree(*pidlInOut);
	*pidlInOut = pidlTemp;

	TRACE("-- pidl=%p ret=0x%08lx\n", pidlInOut? *pidlInOut: NULL, hr);
	return hr;	
}

/***********************************************************************
 *	SHELL32_CoCreateInitSF
 *
 *	creates a initialized shell folder
 */
static HRESULT SHELL32_CoCreateInitSF (
	LPITEMIDLIST pidlRoot,
	LPITEMIDLIST pidlChild,
	REFCLSID clsid,
	REFIID iid,
	LPVOID * ppvOut)
{
	HRESULT hr;
	LPITEMIDLIST	absPidl;
	IShellFolder 	*pShellFolder;
	IPersistFolder	*pPersistFolder;

	TRACE("%p %p\n", pidlRoot, pidlChild);

	*ppvOut = NULL;
	
	/* we have to ask first for IPersistFolder, some special folders are expecting this */
	hr = SHCoCreateInstance(NULL, clsid, NULL, &IID_IPersistFolder, (LPVOID*)&pPersistFolder);
	if (SUCCEEDED(hr))
	{
	  hr = IPersistFolder_QueryInterface(pPersistFolder, iid, (LPVOID*)&pShellFolder);
	  if (SUCCEEDED(hr))
	  {
	    absPidl = ILCombine (pidlRoot, pidlChild);
	    hr = IPersistFolder_Initialize(pPersistFolder, absPidl);
	    IPersistFolder_Release(pPersistFolder);
	    SHFree(absPidl);
	    *ppvOut = pShellFolder;
	  }
	}

	TRACE("-- ret=0x%08lx\n", hr);
	return hr;
}

static HRESULT SHELL32_GetDisplayNameOfChild(
	IShellFolder * psf,
	LPCITEMIDLIST pidl,
	DWORD dwFlags,
	LPSTR szOut,
	DWORD dwOutLen)
{
	LPITEMIDLIST	pidlFirst, pidlNext;
	IShellFolder * 	psfChild;
	HRESULT		hr = E_OUTOFMEMORY;
	STRRET strTemp;
	
	TRACE("(%p)->(pidl=%p 0x%08lx %p 0x%08lx)\n",psf,pidl,dwFlags,szOut, dwOutLen);
	pdump(pidl);
	
	if ((pidlFirst = ILCloneFirst(pidl)))
	{ 
	  hr = IShellFolder_BindToObject(psf, pidlFirst, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
	  if (SUCCEEDED(hr))
	  {
	    pidlNext = ILGetNext(pidl);

	    hr = IShellFolder_GetDisplayNameOf(psfChild, pidlNext, dwFlags | SHGDN_INFOLDER, &strTemp);
	    if (SUCCEEDED(hr))
	    {
	      hr = StrRetToStrNA(szOut, dwOutLen, &strTemp, pidlNext);
	    }

	    IShellFolder_Release(psfChild);
	  }
	  ILFree(pidlFirst);
	}

	TRACE("-- ret=0x%08lx %s\n", hr, szOut);

	return hr;
}

/***********************************************************************
*   IShellFolder implementation
*/

typedef struct 
{
	ICOM_VTABLE(IShellFolder)*	lpvtbl;
	DWORD				ref;

	ICOM_VTABLE(IPersistFolder)*	lpvtblPersistFolder;
	ICOM_VTABLE(IDropTarget)*	lpvtblDropTarget;
	
	CLSID*				pclsid;

	LPSTR				sMyPath;
	LPITEMIDLIST			absPidl;	/* complete pidl */

	UINT		cfShellIDList;			/* clipboardformat for IDropTarget */
	BOOL		fAcceptFmt;			/* flag for pending Drop */
} IGenericSFImpl;

static struct ICOM_VTABLE(IShellFolder) sfvt;
static struct ICOM_VTABLE(IPersistFolder) psfvt;
static struct ICOM_VTABLE(IDropTarget) dtvt;

static IShellFolder * ISF_MyComputer_Constructor(void);

#define _IPersistFolder_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblPersistFolder))) 
#define _ICOM_THIS_From_IPersistFolder(class, name) class* This = (class*)(((char*)name)-_IPersistFolder_Offset); 
	
static struct ICOM_VTABLE(IDropTarget) dtvt;
#define _IDropTarget_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblDropTarget))) 
#define _ICOM_THIS_From_IDropTarget(class, name) class* This = (class*)(((char*)name)-_IDropTarget_Offset); 

/**************************************************************************
*	registers clipboardformat once
*/
static void SF_RegisterClipFmt (IShellFolder * iface)
{
	ICOM_THIS(IGenericSFImpl, iface);

	TRACE("(%p)\n", This);

	if (!This->cfShellIDList)
	{
	  This->cfShellIDList = RegisterClipboardFormatA(CFSTR_SHELLIDLIST);
	}
}

/**************************************************************************
*	  IShellFolder_Constructor
*
*/

static IShellFolder * IShellFolder_Constructor(
	IShellFolder * psf,
	LPITEMIDLIST pidl)
{
	IGenericSFImpl *	sf;
	IGenericSFImpl * 	sfParent = (IGenericSFImpl*) psf;
	DWORD			dwSize=0;

	sf=(IGenericSFImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IGenericSFImpl));
	sf->ref=1;

	sf->lpvtbl=&sfvt;
	sf->lpvtblPersistFolder=&psfvt;
	sf->lpvtblDropTarget=&dtvt;
	sf->pclsid = (CLSID*)&CLSID_SFFile;
	sf->cfShellIDList=0;
	sf->fAcceptFmt=FALSE;

	TRACE("(%p)->(parent=%p, pidl=%p)\n",sf,sfParent, pidl);
	pdump(pidl);
		
	if(pidl)						/* do we have a pidl? */
	{
	  int len;

	  sf->absPidl = ILCombine(sfParent->absPidl, pidl);	/* build a absolute pidl */

	  if (!_ILIsSpecialFolder(pidl))				/* only file system paths */
	  {
	    if(sfParent->sMyPath)				/* get the size of the parents path */
	    {
	      dwSize += strlen(sfParent->sMyPath) ;
	      TRACE("-- (%p)->(parent's path=%s)\n",sf, debugstr_a(sfParent->sMyPath));
	    }   

	    dwSize += _ILSimpleGetText(pidl,NULL,0);		/* add the size of our name*/
	    sf->sMyPath = SHAlloc(dwSize + 2);			/* '\0' and backslash */

	    if(!sf->sMyPath) return NULL;
	    *(sf->sMyPath)=0x00;

	    if(sfParent->sMyPath)				/* if the parent has a path, get it*/
	    {
	      strcpy(sf->sMyPath, sfParent->sMyPath);
	      PathAddBackslashA (sf->sMyPath);
	    }

	    len = strlen(sf->sMyPath);
	    _ILSimpleGetText(pidl, sf->sMyPath + len, dwSize - len + 1);
	  }

	  TRACE("-- (%p)->(my pidl=%p, my path=%s)\n",sf, sf->absPidl,debugstr_a(sf->sMyPath));

	  pdump (sf->absPidl);
	}

	shell32_ObjCount++;
	return (IShellFolder *)sf;
}
/**************************************************************************
 *  IShellFolder_fnQueryInterface
 *
 * PARAMETERS
 *  REFIID riid		[in ] Requested InterfaceID
 *  LPVOID* ppvObject	[out] Interface* to hold the result
 */
static HRESULT WINAPI IShellFolder_fnQueryInterface(
	IShellFolder * iface,
	REFIID riid,
	LPVOID *ppvObj)
{
	ICOM_THIS(IGenericSFImpl, iface);

	char	xriid[50];	
	WINE_StringFromCLSID((LPCLSID)riid,xriid);
	TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);

	*ppvObj = NULL;

	if(IsEqualIID(riid, &IID_IUnknown))
	{ *ppvObj = This; 
	}
	else if(IsEqualIID(riid, &IID_IShellFolder))
	{
	  *ppvObj = (IShellFolder*)This;
	}
	else if(IsEqualIID(riid, &IID_IPersist))
	{
	  *ppvObj = (IPersistFolder*)&(This->lpvtblPersistFolder);
	}
	else if(IsEqualIID(riid, &IID_IPersistFolder))
	{
	  *ppvObj = (IPersistFolder*)&(This->lpvtblPersistFolder);
	}
	else if(IsEqualIID(riid, &IID_IDropTarget))
	{
	  *ppvObj = (IDropTarget*)&(This->lpvtblDropTarget);
	  SF_RegisterClipFmt((IShellFolder*)This);
	}

	if(*ppvObj)
	{
	  IUnknown_AddRef((IUnknown*)(*ppvObj));
	  TRACE("-- Interface = %p\n", *ppvObj);
	  return S_OK;
	}
	TRACE("-- Interface: E_NOINTERFACE\n");
	return E_NOINTERFACE;
}

/**************************************************************************
*  IShellFolder_AddRef
*/

static ULONG WINAPI IShellFolder_fnAddRef(IShellFolder * iface)
{
	ICOM_THIS(IGenericSFImpl, iface);

#ifdef MEM_DEBUG
	TRACE("called from: 0x%08x\n", *( ((UINT*)&iface)-1 ));
#endif
	TRACE("(%p)->(count=%lu)\n",This,This->ref);

	shell32_ObjCount++;
	return ++(This->ref);
}

/**************************************************************************
 *  IShellFolder_fnRelease
 */
static ULONG WINAPI IShellFolder_fnRelease(IShellFolder * iface) 
{
	ICOM_THIS(IGenericSFImpl, iface);

#ifdef MEM_DEBUG
	TRACE("called from: 0x%08x\n", *( ((UINT*)&iface)-1 ));
#endif
	TRACE("(%p)->(count=%lu)\n",This,This->ref);

	shell32_ObjCount--;
	if (!--(This->ref)) 
	{ TRACE("-- destroying IShellFolder(%p)\n",This);

	  if (pdesktopfolder == iface)
	  { pdesktopfolder=NULL;
	    TRACE("-- destroyed IShellFolder(%p) was Desktopfolder\n",This);
	  }
	  if(This->absPidl)
	  { SHFree(This->absPidl);
	  }
	  if(This->sMyPath)
	  { SHFree(This->sMyPath);
	  }

	  HeapFree(GetProcessHeap(),0,This);

	  return 0;
	}
	return This->ref;
}
/**************************************************************************
*		IShellFolder_fnParseDisplayName
* PARAMETERS
*  HWND          hwndOwner,      //[in ] Parent window for any message's
*  LPBC          pbc,            //[in ] reserved
*  LPOLESTR      lpszDisplayName,//[in ] "Unicode" displayname.
*  ULONG*        pchEaten,       //[out] (unicode) characters processed
*  LPITEMIDLIST* ppidl,          //[out] complex pidl to item
*  ULONG*        pdwAttributes   //[out] items attributes
*
* NOTES
*  every folder trys to parse only it's own (the leftmost) pidl and creates a 
*  subfolder to evaluate the remaining parts
*  now we can parse into namespaces implemented by shell extensions
*
*  behaviour on win98:	lpszDisplayName=NULL -> chrash
*			lpszDisplayName="" -> returns mycoputer-pidl
*
* FIXME: 
*    pdwAttributes: not set
*    pchEaten: not set like in windows
*/
static HRESULT WINAPI IShellFolder_fnParseDisplayName(
	IShellFolder * iface,
	HWND hwndOwner,
	LPBC pbcReserved,
	LPOLESTR lpszDisplayName,
	DWORD *pchEaten,
	LPITEMIDLIST *ppidl,
	DWORD *pdwAttributes)
{
	ICOM_THIS(IGenericSFImpl, iface);

	HRESULT		hr = E_OUTOFMEMORY;
	LPCWSTR		szNext=NULL;
	WCHAR		szElement[MAX_PATH];
	CHAR		szTempA[MAX_PATH], szPath[MAX_PATH];
	LPITEMIDLIST	pidlTemp=NULL;
	
	TRACE("(%p)->(HWND=0x%08x,%p,%p=%s,%p,pidl=%p,%p)\n",
	This,hwndOwner,pbcReserved,lpszDisplayName,
	debugstr_w(lpszDisplayName),pchEaten,ppidl,pdwAttributes);

	if (pchEaten) *pchEaten = 0;	/* strange but like the original */
	
	if (*lpszDisplayName)
	{	
	  /* get the next element */
	  szNext = GetNextElementW(lpszDisplayName, szElement, MAX_PATH);

	  /* build the full pathname to the element */
	  WideCharToLocal(szTempA, szElement, lstrlenW(szElement) + 1);
	  strcpy(szPath, This->sMyPath);
	  PathAddBackslashA(szPath);
	  strcat(szPath, szTempA);

	  /* get the pidl */
	  pidlTemp = SHSimpleIDListFromPathA(szPath);

	  if (pidlTemp)
	  {
	    /* try to analyse the next element */
	    if (szNext && *szNext)
	    {
	      hr = SHELL32_ParseNextElement(hwndOwner, (IShellFolder*)This, &pidlTemp, (LPOLESTR)szNext, pchEaten, pdwAttributes);
	    }
	    else
	    {
	       hr = S_OK;
	    }
	  }
	}

	*ppidl = pidlTemp;

	TRACE("(%p)->(-- pidl=%p ret=0x%08lx)\n", This, ppidl? *ppidl:0, hr);

	return hr;	
}

/**************************************************************************
*		IShellFolder_fnEnumObjects
* PARAMETERS
*  HWND          hwndOwner,    //[in ] Parent Window
*  DWORD         grfFlags,     //[in ] SHCONTF enumeration mask
*  LPENUMIDLIST* ppenumIDList  //[out] IEnumIDList interface
*/
static HRESULT WINAPI IShellFolder_fnEnumObjects(
	IShellFolder * iface,
	HWND hwndOwner,
	DWORD dwFlags,
	LPENUMIDLIST* ppEnumIDList)
{
	ICOM_THIS(IGenericSFImpl, iface);

	TRACE("(%p)->(HWND=0x%08x flags=0x%08lx pplist=%p)\n",This,hwndOwner,dwFlags,ppEnumIDList);

	*ppEnumIDList = NULL;
	*ppEnumIDList = IEnumIDList_Constructor (This->sMyPath, dwFlags, EIDL_FILE);

	TRACE("-- (%p)->(new ID List: %p)\n",This,*ppEnumIDList);

	if(!*ppEnumIDList) return E_OUTOFMEMORY;

	return S_OK;		
}

/**************************************************************************
*		IShellFolder_fnBindToObject
* PARAMETERS
*  LPCITEMIDLIST pidl,       //[in ] relative pidl to open
*  LPBC          pbc,        //[in ] reserved
*  REFIID        riid,       //[in ] Initial Interface
*  LPVOID*       ppvObject   //[out] Interface*
*/
static HRESULT WINAPI IShellFolder_fnBindToObject( IShellFolder * iface, LPCITEMIDLIST pidl,
			LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
{
	ICOM_THIS(IGenericSFImpl, iface);
	GUID		const * iid;
	char		xriid[50];
	IShellFolder	*pShellFolder, *pSubFolder;
	IPersistFolder 	*pPersistFolder;
	LPITEMIDLIST	absPidl;
	
	WINE_StringFromCLSID(riid,xriid);

	TRACE("(%p)->(pidl=%p,%p,\n\tIID:\t%s,%p)\n",This,pidl,pbcReserved,xriid,ppvOut);

	*ppvOut = NULL;

	if ((iid=_ILGetGUIDPointer(pidl)))
	{
	  /* we have to create a alien folder */
	  if (  SUCCEEDED(SHCoCreateInstance(NULL, iid, NULL, riid, (LPVOID*)&pShellFolder))
	     && SUCCEEDED(IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder, (LPVOID*)&pPersistFolder)))
	    {
	      absPidl = ILCombine (This->absPidl, pidl);
	      IPersistFolder_Initialize(pPersistFolder, absPidl);
	      IPersistFolder_Release(pPersistFolder);
	      SHFree(absPidl);
	    }
	    else
	    {
	      return E_FAIL;
	    }
	}
	else
	{
	  LPITEMIDLIST pidltemp = ILCloneFirst(pidl);
	  pShellFolder = IShellFolder_Constructor((IShellFolder*)This, pidltemp);
	  ILFree(pidltemp);
	}
	
	if (_ILIsPidlSimple(pidl))
	{
	  *ppvOut = pShellFolder;
	}
	else
	{
	  IShellFolder_BindToObject(pShellFolder, ILGetNext(pidl), NULL, &IID_IShellFolder, (LPVOID)&pSubFolder);
	  IShellFolder_Release(pShellFolder);
	  *ppvOut = pSubFolder;
	}

	TRACE("-- (%p) returning (%p)\n",This, *ppvOut);

	return S_OK;
}

/**************************************************************************
*  IShellFolder_fnBindToStorage
* PARAMETERS
*  LPCITEMIDLIST pidl,       //[in ] complex pidl to store
*  LPBC          pbc,        //[in ] reserved
*  REFIID        riid,       //[in ] Initial storage interface 
*  LPVOID*       ppvObject   //[out] Interface* returned
*/
static HRESULT WINAPI IShellFolder_fnBindToStorage(
	IShellFolder * iface,
	LPCITEMIDLIST pidl,
	LPBC pbcReserved,
	REFIID riid,
	LPVOID *ppvOut)
{
	ICOM_THIS(IGenericSFImpl, iface);

	char xriid[50];
	WINE_StringFromCLSID(riid,xriid);

	FIXME("(%p)->(pidl=%p,%p,\n\tIID:%s,%p) stub\n",This,pidl,pbcReserved,xriid,ppvOut);

	*ppvOut = NULL;
	return E_NOTIMPL;
}

/**************************************************************************
*  IShellFolder_fnCompareIDs
*
* PARMETERS
*  LPARAM        lParam, //[in ] Column?
*  LPCITEMIDLIST pidl1,  //[in ] simple pidl
*  LPCITEMIDLIST pidl2)  //[in ] simple pidl
*
* NOTES
*   Special case - If one of the items is a Path and the other is a File,
*   always make the Path come before the File.
*
* NOTES 
*  use SCODE_CODE() on the return value to get the result
*/

static HRESULT WINAPI  IShellFolder_fnCompareIDs(
	IShellFolder * iface,
	LPARAM lParam,
	LPCITEMIDLIST pidl1,
	LPCITEMIDLIST pidl2)
{
	ICOM_THIS(IGenericSFImpl, iface);

	CHAR szTemp1[MAX_PATH];
	CHAR szTemp2[MAX_PATH];
	int   nReturn;
	IShellFolder * psf;
	HRESULT hr = E_OUTOFMEMORY;
	LPCITEMIDLIST  pidlTemp;
	PIDLTYPE pt1, pt2;

	TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n",This,lParam,pidl1,pidl2);
	pdump (pidl1);
	pdump (pidl2);
	
	if (!pidl1 && !pidl2)
	{
	  hr = ResultFromShort(0);
	}
	else if (!pidl1)
	{
	  hr = ResultFromShort(-1);
	}
	else if (!pidl2)
	{
	  hr = ResultFromShort(1);
	}
	else
	{
	  LPPIDLDATA pd1, pd2;
	  pd1 = _ILGetDataPointer(pidl1);
	  pd2 = _ILGetDataPointer(pidl2);
	
	  /* compate the types. sort order is the PT_* constant */
	  pt1 = ( pd1 ? pd1->type: PT_DESKTOP);
	  pt2 = ( pd2 ? pd2->type: PT_DESKTOP);

	  if (pt1 != pt2)
	  {
	    hr = ResultFromShort(pt1-pt2);
	  }
	  else						/* same type of pidl */
	  {
	    _ILSimpleGetText(pidl1, szTemp1, MAX_PATH);
	    _ILSimpleGetText(pidl2, szTemp2, MAX_PATH);
	    nReturn = strcasecmp(szTemp1, szTemp2);
	
	    if (nReturn == 0)				/* first pidl different ? */
	    {
	      pidl1 = ILGetNext(pidl1);

	      if (pidl1 && pidl1->mkid.cb)		/* go deeper? */	
	      {
	        pidlTemp = ILCloneFirst(pidl1);
	        pidl2 = ILGetNext(pidl2);
	
	        hr = IShellFolder_BindToObject((IShellFolder*)This, pidlTemp, NULL, &IID_IShellFolder, (LPVOID*)&psf);
	        if (SUCCEEDED(hr))
	        { 
	          nReturn = IShellFolder_CompareIDs(psf, 0, pidl1, pidl2);
	          IShellFolder_Release(psf);
	          hr = ResultFromShort(nReturn);
	        }
	        ILFree(pidlTemp);
	      }
	      else
	      {
	        hr = ResultFromShort(nReturn);		/* two equal simple pidls */
	      }
	    }
	    else
	    {
	      hr = ResultFromShort(nReturn);		/* two different simple pidls */
	    }
	  }
	}
	
	TRACE("-- res=0x%08lx\n", hr);
	return hr;
}

/**************************************************************************
*	IShellFolder_fnCreateViewObject
*/
static HRESULT WINAPI IShellFolder_fnCreateViewObject( IShellFolder * iface,
		 HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
{
	ICOM_THIS(IGenericSFImpl, iface);

	LPSHELLVIEW	pShellView;
	char		xriid[50];
	HRESULT		hr = E_INVALIDARG;

	WINE_StringFromCLSID(riid,xriid);
	TRACE("(%p)->(hwnd=0x%x,\n\tIID:\t%s,%p)\n",This,hwndOwner,xriid,ppvOut);
	
	if(ppvOut)
	{
	  *ppvOut = NULL;

	  if(IsEqualIID(riid, &IID_IDropTarget))
	  {
	    hr = IShellFolder_QueryInterface((IShellFolder*)This, &IID_IDropTarget, ppvOut);
	  }
	  else if(IsEqualIID(riid, &IID_IContextMenu))
	  {
	    FIXME("IContextMenu not implemented\n");
	    hr = E_NOTIMPL;
	  }
	  else if(IsEqualIID(riid, &IID_IShellView))
	  {
	    pShellView = IShellView_Constructor((IShellFolder *) This);
	    if(pShellView)
	    {
	      hr = IShellView_QueryInterface(pShellView, riid, ppvOut);
	      IShellView_Release(pShellView);
	    }
	  }
	}
	TRACE("-- (%p)->(interface=%p)\n",This, ppvOut);
	return hr; 
}

/**************************************************************************
*  IShellFolder_fnGetAttributesOf
*
* PARAMETERS
*  UINT            cidl,     //[in ] num elements in pidl array
*  LPCITEMIDLIST*  apidl,    //[in ] simple pidl array 
*  ULONG*          rgfInOut) //[out] result array  
*
*/
static HRESULT WINAPI IShellFolder_fnGetAttributesOf(IShellFolder * iface,UINT cidl,LPCITEMIDLIST *apidl,DWORD *rgfInOut)
{
	ICOM_THIS(IGenericSFImpl, iface);

	HRESULT hr = S_OK;

	TRACE("(%p)->(cidl=%d apidl=%p mask=0x%08lx)\n",This,cidl,apidl,*rgfInOut);

	if ( (!cidl) || (!apidl) || (!rgfInOut))
	  return E_INVALIDARG;

	while (cidl > 0 && *apidl)
	{
	  pdump (*apidl);
	  if (_ILIsFolder( *apidl))
	  {
	    *rgfInOut &= 0xe0000177;
	    goto next;
	  }
	  else if (_ILIsValue( *apidl))
	  {
	    *rgfInOut &= 0x40000177;
	    goto next;
	  }
	  hr = E_INVALIDARG;

next:	  apidl++;
	  cidl--;
	} 

	TRACE("-- result=0x%08lx\n",*rgfInOut);

	return hr;
}
/**************************************************************************
*  IShellFolder_fnGetUIObjectOf
*
* PARAMETERS
*  HWND           hwndOwner, //[in ] Parent window for any output
*  UINT           cidl,      //[in ] array size
*  LPCITEMIDLIST* apidl,     //[in ] simple pidl array
*  REFIID         riid,      //[in ] Requested Interface
*  UINT*          prgfInOut, //[   ] reserved 
*  LPVOID*        ppvObject) //[out] Resulting Interface
*
* NOTES
*  This function gets asked to return "view objects" for one or more (multiple select)
*  items:
*  The viewobject typically is an COM object with one of the following interfaces:
*  IExtractIcon,IDataObject,IContextMenu
*  In order to support icon positions in the default Listview your DataObject
*  must implement the SetData method (in addition to GetData :) - the shell passes
*  a barely documented "Icon positions" structure to SetData when the drag starts,
*  and GetData's it if the drop is in another explorer window that needs the positions.
*/
static HRESULT WINAPI IShellFolder_fnGetUIObjectOf( 
	IShellFolder *	iface,
	HWND		hwndOwner,
	UINT		cidl,
	LPCITEMIDLIST *	apidl, 
	REFIID		riid, 
	UINT *		prgfInOut,
	LPVOID *	ppvOut)
{	
	ICOM_THIS(IGenericSFImpl, iface);

	char		xclsid[50];
	LPITEMIDLIST	pidl;
	IUnknown*	pObj = NULL; 
	HRESULT		hr = E_INVALIDARG;
	
	WINE_StringFromCLSID(riid,xclsid);

	TRACE("(%p)->(%u,%u,apidl=%p,\n\tIID:%s,%p,%p)\n",
	  This,hwndOwner,cidl,apidl,xclsid,prgfInOut,ppvOut);

	if (ppvOut)
	{
	  *ppvOut = NULL;

	  if(IsEqualIID(riid, &IID_IContextMenu) && (cidl >= 1))
	  {
	    pObj  = (LPUNKNOWN)IContextMenu_Constructor((IShellFolder *)This, This->absPidl, apidl, cidl);
	  }
	  else if (IsEqualIID(riid, &IID_IDataObject) &&(cidl >= 1))
	  {
	    pObj = (LPUNKNOWN)IDataObject_Constructor (hwndOwner, This->absPidl, apidl, cidl);
	    hr = S_OK;
	  }
	  else if (IsEqualIID(riid, &IID_IExtractIconA) && (cidl == 1))
	  {
	    pidl = ILCombine(This->absPidl,apidl[0]);
	    pObj = (LPUNKNOWN)IExtractIconA_Constructor( pidl );
	    SHFree(pidl);
	    hr = S_OK;
	  } 
	  else if (IsEqualIID(riid, &IID_IDropTarget) && (cidl >= 1))
	  {
	    hr = IShellFolder_QueryInterface((IShellFolder*)This, &IID_IDropTarget, (LPVOID*)&pObj);
	  }
	  else
	  { 
	    hr = E_NOINTERFACE;
	  }

	  if(!pObj)
	    hr = E_OUTOFMEMORY;

	  *ppvOut = pObj;
	}
	TRACE("(%p)->hr=0x%08lx\n",This, hr);
	return hr;
}

/**************************************************************************
*  IShellFolder_fnGetDisplayNameOf
*  Retrieves the display name for the specified file object or subfolder
*
* PARAMETERS
*  LPCITEMIDLIST pidl,    //[in ] complex pidl to item
*  DWORD         dwFlags, //[in ] SHGNO formatting flags
*  LPSTRRET      lpName)  //[out] Returned display name
*
* FIXME
*  if the name is in the pidl the ret value should be a STRRET_OFFSET
*/
#define GET_SHGDN_FOR(dwFlags)         ((DWORD)dwFlags & (DWORD)0x0000FF00)
#define GET_SHGDN_RELATION(dwFlags)    ((DWORD)dwFlags & (DWORD)0x000000FF)

static HRESULT WINAPI IShellFolder_fnGetDisplayNameOf(
	IShellFolder * iface,
	LPCITEMIDLIST pidl,
	DWORD dwFlags,
	LPSTRRET strRet)
{
	ICOM_THIS(IGenericSFImpl, iface);

	CHAR		szPath[MAX_PATH]= "";
	int		len = 0;
	BOOL		bSimplePidl;
		
	TRACE("(%p)->(pidl=%p,0x%08lx,%p)\n",This,pidl,dwFlags,strRet);
	pdump(pidl);
	
	if(!pidl || !strRet) return E_INVALIDARG;
	
	bSimplePidl = _ILIsPidlSimple(pidl);

	/* take names of special folders only if its only this folder */
	if (_ILIsSpecialFolder(pidl))
	{
	  if ( bSimplePidl)
	  {
	    _ILSimpleGetText(pidl, szPath, MAX_PATH); /* append my own path */
	  }
	}
	else
	{
	  if (!(dwFlags & SHGDN_INFOLDER) && (dwFlags & SHGDN_FORPARSING) && This->sMyPath)
	  {
	    strcpy (szPath, This->sMyPath);			/* get path to root*/
	    PathAddBackslashA(szPath);
	    len = strlen(szPath);
	  }
	  _ILSimpleGetText(pidl, szPath + len, MAX_PATH - len);	/* append my own path */
	}
	
	if ( (dwFlags & SHGDN_FORPARSING) && !bSimplePidl)	/* go deeper if needed */
	{
	  PathAddBackslashA(szPath);
	  len = strlen(szPath);

	  if (!SUCCEEDED(SHELL32_GetDisplayNameOfChild((IShellFolder*)This, pidl, dwFlags, szPath + len, MAX_PATH - len)))
	    return E_OUTOFMEMORY;
	}
	strRet->uType = STRRET_CSTRA;
	lstrcpynA(strRet->u.cStr, szPath, MAX_PATH);

	TRACE("-- (%p)->(%s)\n", This, szPath);
	return S_OK;
}

/**************************************************************************
*  IShellFolder_fnSetNameOf
*  Changes the name of a file object or subfolder, possibly changing its item
*  identifier in the process.
*
* PARAMETERS
*  HWND          hwndOwner,  //[in ] Owner window for output
*  LPCITEMIDLIST pidl,       //[in ] simple pidl of item to change
*  LPCOLESTR     lpszName,   //[in ] the items new display name
*  DWORD         dwFlags,    //[in ] SHGNO formatting flags
*  LPITEMIDLIST* ppidlOut)   //[out] simple pidl returned
*/
static HRESULT WINAPI IShellFolder_fnSetNameOf(
	IShellFolder * iface,
	HWND hwndOwner, 
	LPCITEMIDLIST pidl, /*simple pidl*/
	LPCOLESTR lpName, 
	DWORD dw, 
	LPITEMIDLIST *pPidlOut)
{
	ICOM_THIS(IGenericSFImpl, iface);

	FIXME("(%p)->(%u,pidl=%p,%s,%lu,%p),stub!\n",
	This,hwndOwner,pidl,debugstr_w(lpName),dw,pPidlOut);

	return E_NOTIMPL;
}

/**************************************************************************
*  IShellFolder_fnGetFolderPath
*/
static HRESULT WINAPI IShellFolder_fnGetFolderPath(IShellFolder * iface, LPSTR lpszOut, DWORD dwOutSize)
{
	ICOM_THIS(IGenericSFImpl, iface);
	
	TRACE("(%p)->(%p %lu)\n",This, lpszOut, dwOutSize);

	if (!lpszOut) return FALSE;

	*lpszOut=0;

	if (! This->sMyPath) return FALSE;

	lstrcpynA(lpszOut, This->sMyPath, dwOutSize);

	TRACE("-- (%p)->(return=%s)\n",This, lpszOut);
	return TRUE;
}

static ICOM_VTABLE(IShellFolder) sfvt = 
{	
	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
	IShellFolder_fnQueryInterface,
	IShellFolder_fnAddRef,
	IShellFolder_fnRelease,
	IShellFolder_fnParseDisplayName,
	IShellFolder_fnEnumObjects,
	IShellFolder_fnBindToObject,
	IShellFolder_fnBindToStorage,
	IShellFolder_fnCompareIDs,
	IShellFolder_fnCreateViewObject,
	IShellFolder_fnGetAttributesOf,
	IShellFolder_fnGetUIObjectOf,
	IShellFolder_fnGetDisplayNameOf,
	IShellFolder_fnSetNameOf,
	IShellFolder_fnGetFolderPath
};

/***********************************************************************
* 	[Desktopfolder]	IShellFolder implementation
*/
static struct ICOM_VTABLE(IShellFolder) sfdvt;

/**************************************************************************
*	ISF_Desktop_Constructor
*
*/
IShellFolder * ISF_Desktop_Constructor()
{
	IGenericSFImpl *	sf;

	sf=(IGenericSFImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IGenericSFImpl));
	sf->ref=1;
	sf->lpvtbl=&sfdvt;
	sf->absPidl=_ILCreateDesktop();	/* my qualified pidl */

	TRACE("(%p)\n",sf);

	shell32_ObjCount++;
	return (IShellFolder *)sf;
}

/**************************************************************************
 *	ISF_Desktop_fnQueryInterface
 *
 * NOTES supports not IPersist/IPersistFolder
 */
static HRESULT WINAPI ISF_Desktop_fnQueryInterface(
	IShellFolder * iface,
	REFIID riid,
	LPVOID *ppvObj)
{
	ICOM_THIS(IGenericSFImpl, iface);

	char	xriid[50];	
	WINE_StringFromCLSID((LPCLSID)riid,xriid);
	TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);

	*ppvObj = NULL;

	if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
	{ *ppvObj = This; 
	}
	else if(IsEqualIID(riid, &IID_IShellFolder))  /*IShellFolder*/
	{    *ppvObj = (IShellFolder*)This;
	}   

	if(*ppvObj)
	{
	  IUnknown_AddRef((IUnknown*)(*ppvObj));
	  TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
	  return S_OK;
	}
	TRACE("-- Interface: E_NOINTERFACE\n");
	return E_NOINTERFACE;
}

/**************************************************************************
*	ISF_Desktop_fnParseDisplayName
*
* NOTES
*	"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
*	to MyComputer
*/
static HRESULT WINAPI ISF_Desktop_fnParseDisplayName(
	IShellFolder * iface,
	HWND hwndOwner,
	LPBC pbcReserved,
	LPOLESTR lpszDisplayName,
	DWORD *pchEaten,
	LPITEMIDLIST *ppidl,
	DWORD *pdwAttributes)
{
	ICOM_THIS(IGenericSFImpl, iface);

	LPCWSTR		szNext=NULL;
	LPITEMIDLIST	pidlTemp=NULL;
	HRESULT		hr=E_OUTOFMEMORY;
	
	TRACE("(%p)->(HWND=0x%08x,%p,%p=%s,%p,pidl=%p,%p)\n",
	This,hwndOwner,pbcReserved,lpszDisplayName,
	debugstr_w(lpszDisplayName),pchEaten,ppidl,pdwAttributes);

	*ppidl = 0;
	if (pchEaten) *pchEaten = 0;	/* strange but like the original */
	
	/* fixme no real parsing implemented */
	pidlTemp = _ILCreateMyComputer();
	szNext = lpszDisplayName;

	if (szNext && *szNext)
	{
	  hr = SHELL32_ParseNextElement(hwndOwner, (IShellFolder*)This, &pidlTemp, (LPOLESTR)szNext, pchEaten, pdwAttributes);
	}
	else
	{
	  hr = S_OK;
	}

	*ppidl = pidlTemp;

	TRACE("(%p)->(-- ret=0x%08lx)\n", This, hr);

	return hr;	
}

/**************************************************************************
*		ISF_Desktop_fnEnumObjects
*/
static HRESULT WINAPI ISF_Desktop_fnEnumObjects(
	IShellFolder * iface,
	HWND hwndOwner,
	DWORD dwFlags,
	LPENUMIDLIST* ppEnumIDList)
{
	ICOM_THIS(IGenericSFImpl, iface);

	TRACE("(%p)->(HWND=0x%08x flags=0x%08lx pplist=%p)\n",This,hwndOwner,dwFlags,ppEnumIDList);

	*ppEnumIDList = NULL;
	*ppEnumIDList = IEnumIDList_Constructor (NULL, dwFlags, EIDL_DESK);

	TRACE("-- (%p)->(new ID List: %p)\n",This,*ppEnumIDList);

	if(!*ppEnumIDList) return E_OUTOFMEMORY;

	return S_OK;		
}

/**************************************************************************
*		ISF_Desktop_fnBindToObject
*/
static HRESULT WINAPI ISF_Desktop_fnBindToObject( IShellFolder * iface, LPCITEMIDLIST pidl,
			LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
{
	ICOM_THIS(IGenericSFImpl, iface);
	GUID		const * clsid;
	char		xriid[50];
	IShellFolder	*pShellFolder, *pSubFolder;
	
	WINE_StringFromCLSID(riid,xriid);

	TRACE("(%p)->(pidl=%p,%p,\n\tIID:\t%s,%p)\n",This,pidl,pbcReserved,xriid,ppvOut);

	*ppvOut = NULL;

	if ((clsid=_ILGetGUIDPointer(pidl)))
	{
	  if ( IsEqualIID(clsid, &IID_MyComputer))
	  {
	    pShellFolder = ISF_MyComputer_Constructor();
	  }
	  else 
	  {
	     /* shell extension */
	     if (!SUCCEEDED(SHELL32_CoCreateInitSF (This->absPidl, pidl, clsid, riid, (LPVOID*)&pShellFolder)))
	     {
	       return E_INVALIDARG;
	     }
	  }
	} 
	else
	{
	  /* file system folder on the desktop */
	  LPITEMIDLIST pidltemp = ILCloneFirst(pidl);
	  pShellFolder = IShellFolder_Constructor((IShellFolder*)This, pidltemp);
	  ILFree(pidltemp);
	}
	
	if (_ILIsPidlSimple(pidl))	/* no sub folders */
	{
	  *ppvOut = pShellFolder;
	}
	else				/* go deeper */
	{
	  IShellFolder_BindToObject(pShellFolder, ILGetNext(pidl), NULL, riid, (LPVOID)&pSubFolder);
	  IShellFolder_Release(pShellFolder);
	  *ppvOut = pSubFolder;
	}

	TRACE("-- (%p) returning (%p)\n",This, *ppvOut);

	return S_OK;
}

/**************************************************************************
*	ISF_Desktop_fnCreateViewObject
*/
static HRESULT WINAPI ISF_Desktop_fnCreateViewObject( IShellFolder * iface,
		 HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
{
	ICOM_THIS(IGenericSFImpl, iface);

	LPSHELLVIEW	pShellView;
	char		xriid[50];
	HRESULT		hr = E_INVALIDARG;

	WINE_StringFromCLSID(riid,xriid);
	TRACE("(%p)->(hwnd=0x%x,\n\tIID:\t%s,%p)\n",This,hwndOwner,xriid,ppvOut);
	
	if(ppvOut)
	{
	  *ppvOut = NULL;

	  if(IsEqualIID(riid, &IID_IDropTarget))
	  {
	    FIXME("IDropTarget not implemented\n");
	    hr = E_NOTIMPL;
	  }
	  else if(IsEqualIID(riid, &IID_IContextMenu))
	  {
	    FIXME("IContextMenu not implemented\n");
	    hr = E_NOTIMPL;
	  }
	  else if(IsEqualIID(riid, &IID_IShellView))
	  {
	    pShellView = IShellView_Constructor((IShellFolder *) This);
	    if(pShellView)
	    {
	      hr = IShellView_QueryInterface(pShellView, riid, ppvOut);
	      IShellView_Release(pShellView);
	    }
	  }
	}
	TRACE("-- (%p)->(interface=%p)\n",This, ppvOut);
	return hr; 
}

/**************************************************************************
*  ISF_Desktop_fnGetAttributesOf
*/
static HRESULT WINAPI ISF_Desktop_fnGetAttributesOf(IShellFolder * iface,UINT cidl,LPCITEMIDLIST *apidl,DWORD *rgfInOut)
{
	ICOM_THIS(IGenericSFImpl, iface);

	GUID		const * clsid;
	DWORD		attributes;
	HRESULT		hr = S_OK;

	TRACE("(%p)->(cidl=%d apidl=%p mask=0x%08lx)\n",This,cidl,apidl, *rgfInOut);

	if ( (!cidl) || (!apidl) || (!rgfInOut))
	  return E_INVALIDARG;

	while (cidl > 0 && *apidl)
	{
	  pdump (*apidl);

	  if ((clsid=_ILGetGUIDPointer(*apidl)))
	  {
	    if (IsEqualIID(clsid, &IID_MyComputer))
	    {
	      *rgfInOut &= 0xb0000154;
	      goto next;
	    }
	    else if (HCR_GetFolderAttributes(clsid, &attributes))
	    {
	      *rgfInOut &= attributes;
	      goto next;
	    }
	    else
	    { /* some shell-extension */
	      *rgfInOut &= 0xb0000154;
	    }
	  }
	  else if (_ILIsFolder( *apidl))
	  {
	    *rgfInOut &= 0xe0000177;
	    goto next;
	  }
	  else if (_ILIsValue( *apidl))
	  {
	    *rgfInOut &= 0x40000177;
	    goto next;
	  }
	  hr = E_INVALIDARG;

next:	  apidl++;
	  cidl--;
	}

	TRACE("-- result=0x%08lx\n",*rgfInOut);

	return hr;
}

/**************************************************************************
*	ISF_Desktop_fnGetDisplayNameOf
*
* NOTES
*	special case: pidl = null gives desktop-name back
*/
static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf(
	IShellFolder * iface,
	LPCITEMIDLIST pidl,
	DWORD dwFlags,
	LPSTRRET strRet)
{
	ICOM_THIS(IGenericSFImpl, iface);

	CHAR		szPath[MAX_PATH]= "";
		
	TRACE("(%p)->(pidl=%p,0x%08lx,%p)\n",This,pidl,dwFlags,strRet);
	pdump(pidl);
	
	if(!strRet) return E_INVALIDARG;
	
	if(!pidl)
	{
	  HCR_GetClassName(&CLSID_ShellDesktop, szPath, MAX_PATH);
	}
	else if ( _ILIsPidlSimple(pidl) )
	{
	  _ILSimpleGetText(pidl, szPath, MAX_PATH);
	}
	else
	{ 
	  if (!SUCCEEDED(SHELL32_GetDisplayNameOfChild((IShellFolder*)This, pidl, dwFlags, szPath, MAX_PATH)))
	    return E_OUTOFMEMORY;
	}
	strRet->uType = STRRET_CSTRA;
	lstrcpynA(strRet->u.cStr, szPath, MAX_PATH);


	TRACE("-- (%p)->(%s)\n", This, szPath);
	return S_OK;
}

static ICOM_VTABLE(IShellFolder) sfdvt = 
{	
	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
	ISF_Desktop_fnQueryInterface,
	IShellFolder_fnAddRef,
	IShellFolder_fnRelease,
	ISF_Desktop_fnParseDisplayName,
	ISF_Desktop_fnEnumObjects,
	ISF_Desktop_fnBindToObject,
	IShellFolder_fnBindToStorage,
	IShellFolder_fnCompareIDs,
	ISF_Desktop_fnCreateViewObject,
	ISF_Desktop_fnGetAttributesOf,
	IShellFolder_fnGetUIObjectOf,
	ISF_Desktop_fnGetDisplayNameOf,
	IShellFolder_fnSetNameOf,
	IShellFolder_fnGetFolderPath
};


/***********************************************************************
*   IShellFolder [MyComputer] implementation
*/

static struct ICOM_VTABLE(IShellFolder) sfmcvt;

/**************************************************************************
*	ISF_MyComputer_Constructor
*/
static IShellFolder * ISF_MyComputer_Constructor(void)
{
	IGenericSFImpl *	sf;

	sf=(IGenericSFImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IGenericSFImpl));
	sf->ref=1;

	sf->lpvtbl = &sfmcvt;
	sf->lpvtblPersistFolder = &psfvt;
	sf->pclsid = (CLSID*)&CLSID_SFMyComp;
	sf->absPidl=_ILCreateMyComputer();	/* my qualified pidl */

	TRACE("(%p)\n",sf);

	shell32_ObjCount++;
	return (IShellFolder *)sf;
}

/**************************************************************************
*	ISF_MyComputer_fnParseDisplayName
*/
static HRESULT WINAPI ISF_MyComputer_fnParseDisplayName(
	IShellFolder * iface,
	HWND hwndOwner,
	LPBC pbcReserved,
	LPOLESTR lpszDisplayName,
	DWORD *pchEaten,
	LPITEMIDLIST *ppidl,
	DWORD *pdwAttributes)
{
	ICOM_THIS(IGenericSFImpl, iface);

	HRESULT		hr = E_OUTOFMEMORY;
	LPCWSTR		szNext=NULL;
	WCHAR		szElement[MAX_PATH];
	CHAR		szTempA[MAX_PATH];
	LPITEMIDLIST	pidlTemp;
	
	TRACE("(%p)->(HWND=0x%08x,%p,%p=%s,%p,pidl=%p,%p)\n",
	This,hwndOwner,pbcReserved,lpszDisplayName,
	debugstr_w(lpszDisplayName),pchEaten,ppidl,pdwAttributes);

	*ppidl = 0;
	if (pchEaten) *pchEaten = 0;	/* strange but like the original */
	
	if (PathIsRootW(lpszDisplayName))
	{
	  szNext = GetNextElementW(lpszDisplayName, szElement, MAX_PATH);
	  WideCharToLocal(szTempA, szElement, lstrlenW(szElement) + 1);
	  pidlTemp = _ILCreateDrive(szTempA);

	  if (szNext && *szNext)
	  {
	    hr = SHELL32_ParseNextElement(hwndOwner, (IShellFolder*)This, &pidlTemp, (LPOLESTR)szNext, pchEaten, pdwAttributes);
	  }
	  else
	  {
	    hr = S_OK;
	  }
	  *ppidl = pidlTemp;
	}

	TRACE("(%p)->(-- ret=0x%08lx)\n", This, hr);

	return hr;	
}

/**************************************************************************
*		ISF_MyComputer_fnEnumObjects
*/
static HRESULT WINAPI ISF_MyComputer_fnEnumObjects(
	IShellFolder * iface,
	HWND hwndOwner,
	DWORD dwFlags,
	LPENUMIDLIST* ppEnumIDList)
{
	ICOM_THIS(IGenericSFImpl, iface);

	TRACE("(%p)->(HWND=0x%08x flags=0x%08lx pplist=%p)\n",This,hwndOwner,dwFlags,ppEnumIDList);

	*ppEnumIDList = NULL;
	*ppEnumIDList = IEnumIDList_Constructor (NULL, dwFlags, EIDL_MYCOMP);

	TRACE("-- (%p)->(new ID List: %p)\n",This,*ppEnumIDList);

	if(!*ppEnumIDList) return E_OUTOFMEMORY;

	return S_OK;		
}

/**************************************************************************
*		ISF_MyComputer_fnBindToObject
*/
static HRESULT WINAPI ISF_MyComputer_fnBindToObject( IShellFolder * iface, LPCITEMIDLIST pidl,
			LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
{
	ICOM_THIS(IGenericSFImpl, iface);
	GUID		const * clsid;
	char		xriid[50];
	IShellFolder	*pShellFolder, *pSubFolder;
	LPITEMIDLIST	pidltemp;
	
	WINE_StringFromCLSID(riid,xriid);

	TRACE("(%p)->(pidl=%p,%p,\n\tIID:\t%s,%p)\n",This,pidl,pbcReserved,xriid,ppvOut);

	*ppvOut = NULL;

	if ((clsid=_ILGetGUIDPointer(pidl)) && !IsEqualIID(clsid, &IID_MyComputer))
	{
	   if (!SUCCEEDED(SHELL32_CoCreateInitSF (This->absPidl, pidl, clsid, riid, (LPVOID*)&pShellFolder)))
	   {
	     return E_FAIL;
	   }
	}
	else
	{
	  if (!_ILIsDrive(pidl)) return E_INVALIDARG;

	  pidltemp = ILCloneFirst(pidl);
	  pShellFolder = IShellFolder_Constructor((IShellFolder*)This, pidltemp);
	  ILFree(pidltemp);
	}

	if (_ILIsPidlSimple(pidl))	/* no sub folders */
	{
	  *ppvOut = pShellFolder;
	}
	else				/* go deeper */
	{
	  IShellFolder_BindToObject(pShellFolder, ILGetNext(pidl), NULL, &IID_IShellFolder, (LPVOID)&pSubFolder);
	  IShellFolder_Release(pShellFolder);
	  *ppvOut = pSubFolder;
	}

	TRACE("-- (%p) returning (%p)\n",This, *ppvOut);

	return S_OK;
}

/**************************************************************************
*	ISF_MyComputer_fnCreateViewObject
*/
static HRESULT WINAPI ISF_MyComputer_fnCreateViewObject( IShellFolder * iface,
		 HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
{
	ICOM_THIS(IGenericSFImpl, iface);

	LPSHELLVIEW	pShellView;
	char		xriid[50];
	HRESULT		hr = E_INVALIDARG;

	WINE_StringFromCLSID(riid,xriid);
	TRACE("(%p)->(hwnd=0x%x,\n\tIID:\t%s,%p)\n",This,hwndOwner,xriid,ppvOut);
	
	if(ppvOut)
	{
	  *ppvOut = NULL;

	  if(IsEqualIID(riid, &IID_IDropTarget))
	  {
	    FIXME("IDropTarget not implemented\n");
	    hr = E_NOTIMPL;
	  }
	  else if(IsEqualIID(riid, &IID_IContextMenu))
	  {
	    FIXME("IContextMenu not implemented\n");
	    hr = E_NOTIMPL;
	  }
	  else if(IsEqualIID(riid, &IID_IShellView))
	  {
	    pShellView = IShellView_Constructor((IShellFolder *) This);
	    if(pShellView)
	    {
	      hr = IShellView_QueryInterface(pShellView, riid, ppvOut);
	      IShellView_Release(pShellView);
	    }
	  }
	}
	TRACE("-- (%p)->(interface=%p)\n",This, ppvOut);
	return hr; 
}

/**************************************************************************
*  ISF_MyComputer_fnGetAttributesOf
*/
static HRESULT WINAPI ISF_MyComputer_fnGetAttributesOf(IShellFolder * iface,UINT cidl,LPCITEMIDLIST *apidl,DWORD *rgfInOut)
{
	ICOM_THIS(IGenericSFImpl, iface);

	GUID		const * clsid;
	DWORD		attributes;
	HRESULT		hr = S_OK;

	TRACE("(%p)->(cidl=%d apidl=%p mask=0x%08lx)\n",This,cidl,apidl,*rgfInOut);

	if ( (!cidl) || (!apidl) || (!rgfInOut))
	  return E_INVALIDARG;

	*rgfInOut = 0xffffffff;

	while (cidl > 0 && *apidl)
	{
	  pdump (*apidl);

	  if (_ILIsDrive(*apidl))
	  {
	    *rgfInOut &= 0xf0000144;
	    goto next;
	  }
	  else if ((clsid=_ILGetGUIDPointer(*apidl)))
	  {
	    if (HCR_GetFolderAttributes(clsid, &attributes))
	    {
	      *rgfInOut &= attributes;
	      goto next;
	    }
	  }
	  hr = E_INVALIDARG;

next:	  apidl++;
	  cidl--;
	}

	TRACE("-- result=0x%08lx\n",*rgfInOut);
	return hr;
}

/**************************************************************************
*	ISF_MyComputer_fnGetDisplayNameOf
*
* NOTES
*	The desktopfolder creates only complete paths (SHGDN_FORPARSING).
*	SHGDN_INFOLDER makes no sense.
*/
static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf(
	IShellFolder * iface,
	LPCITEMIDLIST pidl,
	DWORD dwFlags,
	LPSTRRET strRet)
{
	ICOM_THIS(IGenericSFImpl, iface);

	char		szPath[MAX_PATH], szDrive[18];
	int		len = 0;
	BOOL		bSimplePidl;
		
	TRACE("(%p)->(pidl=%p,0x%08lx,%p)\n",This,pidl,dwFlags,strRet);
	pdump(pidl);
	
	if(!strRet) return E_INVALIDARG;
	
	szPath[0]=0x00; szDrive[0]=0x00;
	
	
	bSimplePidl = _ILIsPidlSimple(pidl);
	
	if (_ILIsSpecialFolder(pidl))
	{
	  /* take names of special folders only if its only this folder */
	  if ( bSimplePidl )
	  {
	    _ILSimpleGetText(pidl, szPath, MAX_PATH); /* append my own path */
	  }
	}
	else
	{
	  if (!_ILIsDrive(pidl))
	  {
	    ERR("Wrong pidl type\n");
	    return E_INVALIDARG;
	  }

	  _ILSimpleGetText(pidl, szPath, MAX_PATH);	/* append my own path */

	  /* long view "lw_name (C:)" */
	  if ( bSimplePidl && !(dwFlags & SHGDN_FORPARSING))
	  {
	    DWORD dwVolumeSerialNumber,dwMaximumComponetLength,dwFileSystemFlags;

	    GetVolumeInformationA(szPath,szDrive,12,&dwVolumeSerialNumber,&dwMaximumComponetLength,&dwFileSystemFlags,NULL,0);
	    strcat (szDrive," (");
	    strncat (szDrive, szPath, 2);
	    strcat (szDrive,")");
	    strcpy (szPath, szDrive);
	  }
	}
	
	if (!bSimplePidl)	/* go deeper if needed */
	{ 
	  PathAddBackslashA(szPath);
	  len = strlen(szPath);

	  if (!SUCCEEDED(SHELL32_GetDisplayNameOfChild((IShellFolder*)This, pidl, dwFlags | SHGDN_FORPARSING, szPath + len, MAX_PATH - len)))
	    return E_OUTOFMEMORY;
	}
	strRet->uType = STRRET_CSTRA;
	lstrcpynA(strRet->u.cStr, szPath, MAX_PATH);


	TRACE("-- (%p)->(%s)\n", This, szPath);
	return S_OK;
}

static ICOM_VTABLE(IShellFolder) sfmcvt = 
{	
	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
	IShellFolder_fnQueryInterface,
	IShellFolder_fnAddRef,
	IShellFolder_fnRelease,
	ISF_MyComputer_fnParseDisplayName,
	ISF_MyComputer_fnEnumObjects,
	ISF_MyComputer_fnBindToObject,
	IShellFolder_fnBindToStorage,
	IShellFolder_fnCompareIDs,
	ISF_MyComputer_fnCreateViewObject,
	ISF_MyComputer_fnGetAttributesOf,
	IShellFolder_fnGetUIObjectOf,
	ISF_MyComputer_fnGetDisplayNameOf,
	IShellFolder_fnSetNameOf,
	IShellFolder_fnGetFolderPath
};


/************************************************************************
 * ISFPersistFolder_QueryInterface (IUnknown)
 *
 */
static HRESULT WINAPI ISFPersistFolder_QueryInterface(
	IPersistFolder *	iface,
	REFIID			iid,
	LPVOID*			ppvObj)
{
	_ICOM_THIS_From_IPersistFolder(IGenericSFImpl, iface);

	TRACE("(%p)\n", This);

	return IShellFolder_QueryInterface((IShellFolder*)This, iid, ppvObj);
}

/************************************************************************
 * ISFPersistFolder_AddRef (IUnknown)
 *
 */
static ULONG WINAPI ISFPersistFolder_AddRef(
	IPersistFolder *	iface)
{
	_ICOM_THIS_From_IPersistFolder(IShellFolder, iface);

	TRACE("(%p)\n", This);

	return IShellFolder_AddRef((IShellFolder*)This);
}

/************************************************************************
 * ISFPersistFolder_Release (IUnknown)
 *
 */
static ULONG WINAPI ISFPersistFolder_Release(
	IPersistFolder *	iface)
{
	_ICOM_THIS_From_IPersistFolder(IGenericSFImpl, iface);

	TRACE("(%p)\n", This);

	return IShellFolder_Release((IShellFolder*)This);
}

/************************************************************************
 * ISFPersistFolder_GetClassID (IPersist)
 */
static HRESULT WINAPI ISFPersistFolder_GetClassID(
	IPersistFolder *	iface,
	CLSID *			lpClassId)
{
	_ICOM_THIS_From_IPersistFolder(IGenericSFImpl, iface);

	TRACE("(%p)\n", This);

	if (!lpClassId) return E_POINTER;
	*lpClassId = *This->pclsid;

	return S_OK;
}

/************************************************************************
 * ISFPersistFolder_Initialize (IPersistFolder)
 *
 * NOTES
 *  sMyPath is not set. Don't know how to handle in a non rooted environment.
 */
static HRESULT WINAPI ISFPersistFolder_Initialize(
	IPersistFolder *	iface,
	LPCITEMIDLIST		pidl)
{
	_ICOM_THIS_From_IPersistFolder(IGenericSFImpl, iface);

	TRACE("(%p)\n", This);

	if(This->absPidl)
	{
	  SHFree(This->absPidl);
	  This->absPidl = NULL;
	}
	This->absPidl = ILClone(pidl);
	return S_OK;
}

static ICOM_VTABLE(IPersistFolder) psfvt = 
{
	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
	ISFPersistFolder_QueryInterface,
	ISFPersistFolder_AddRef,
	ISFPersistFolder_Release,
	ISFPersistFolder_GetClassID,
	ISFPersistFolder_Initialize
};

/****************************************************************************
 * ISFDropTarget implementation
 */
static BOOL ISFDropTarget_QueryDrop(
	IDropTarget *iface,
	DWORD dwKeyState,
	LPDWORD pdwEffect)
{
	DWORD dwEffect = *pdwEffect;

	_ICOM_THIS_From_IDropTarget(IGenericSFImpl,iface);
	
	*pdwEffect = DROPEFFECT_NONE;

	if (This->fAcceptFmt)
	{ /* Does our interpretation of the keystate ... */
	  *pdwEffect = KeyStateToDropEffect(dwKeyState);
	  
	  /* ... matches the desired effect ? */
	  if (dwEffect & *pdwEffect)
	  {
	    return TRUE;
	  }
	}
	return FALSE;
}

static HRESULT WINAPI ISFDropTarget_QueryInterface(
	IDropTarget *iface,
	REFIID riid,
	LPVOID *ppvObj)
{
	_ICOM_THIS_From_IDropTarget(IGenericSFImpl,iface);

	TRACE("(%p)\n", This);

	return IShellFolder_QueryInterface((IShellFolder*)This, riid, ppvObj);
}

static ULONG WINAPI ISFDropTarget_AddRef( IDropTarget *iface)
{
	_ICOM_THIS_From_IDropTarget(IGenericSFImpl,iface);

	TRACE("(%p)\n", This);

	return IShellFolder_AddRef((IShellFolder*)This);
}

static ULONG WINAPI ISFDropTarget_Release( IDropTarget *iface)
{
	_ICOM_THIS_From_IDropTarget(IGenericSFImpl,iface);

	TRACE("(%p)\n", This);

	return IShellFolder_Release((IShellFolder*)This);
}

static HRESULT WINAPI ISFDropTarget_DragEnter(
	IDropTarget 	*iface,
	IDataObject	*pDataObject,
	DWORD		dwKeyState,
	POINTL		pt,
	DWORD		*pdwEffect)
{	
	FORMATETC	fmt;
	
	_ICOM_THIS_From_IDropTarget(IGenericSFImpl,iface);

	TRACE("(%p)->(DataObject=%p)\n",This,pDataObject);

	InitFormatEtc(fmt, This->cfShellIDList, TYMED_HGLOBAL);

	This->fAcceptFmt = (S_OK == IDataObject_QueryGetData(pDataObject, &fmt)) ? TRUE : FALSE;

	ISFDropTarget_QueryDrop(iface, dwKeyState, pdwEffect);

	return S_OK;
}

static HRESULT WINAPI ISFDropTarget_DragOver(
	IDropTarget	*iface,
	DWORD		dwKeyState,
	POINTL		pt,
	DWORD		*pdwEffect)
{
	_ICOM_THIS_From_IDropTarget(IGenericSFImpl,iface);

	TRACE("(%p)\n",This);
	
	if(!pdwEffect) return E_INVALIDARG;

	ISFDropTarget_QueryDrop(iface, dwKeyState, pdwEffect);

	return S_OK;
}

static HRESULT WINAPI ISFDropTarget_DragLeave(
	IDropTarget	*iface)
{
	_ICOM_THIS_From_IDropTarget(IGenericSFImpl,iface);

	TRACE("(%p)\n",This);

	This->fAcceptFmt = FALSE;
	
	return S_OK;
}

static HRESULT WINAPI ISFDropTarget_Drop(
	IDropTarget	*iface,
	IDataObject*	pDataObject,
	DWORD		dwKeyState,
	POINTL		pt,
	DWORD		*pdwEffect)
{
	_ICOM_THIS_From_IDropTarget(IGenericSFImpl,iface);

	FIXME("(%p) object dropped\n",This);

	return E_NOTIMPL;
}

static struct ICOM_VTABLE(IDropTarget) dtvt = 
{
	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
	ISFDropTarget_QueryInterface,
	ISFDropTarget_AddRef,
	ISFDropTarget_Release,
	ISFDropTarget_DragEnter,
	ISFDropTarget_DragOver,
	ISFDropTarget_DragLeave,
 	ISFDropTarget_Drop
};

