📄 shfldr_fs.c
字号:
/*
* file system folder
*
* Copyright 1997 Marcus Meissner
* Copyright 1998, 1999, 2002 Juergen Schmied
*
* 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
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "wine/port.h"
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "winerror.h"
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "wingdi.h"
#include "winuser.h"
#include "ole2.h"
#include "shlguid.h"
#include "enumidlist.h"
#include "pidl.h"
#include "undocshell.h"
#include "shell32_main.h"
#include "shresdef.h"
#include "shlwapi.h"
#include "shellfolder.h"
#include "wine/debug.h"
#include "debughlp.h"
#include "shfldr.h"
WINE_DEFAULT_DEBUG_CHANNEL (shell);
/***********************************************************************
* IShellFolder implementation
*/
typedef struct {
const IUnknownVtbl *lpVtbl;
LONG ref;
const IShellFolder2Vtbl *lpvtblShellFolder;
const IPersistFolder3Vtbl *lpvtblPersistFolder3;
const IDropTargetVtbl *lpvtblDropTarget;
const ISFHelperVtbl *lpvtblSFHelper;
IUnknown *pUnkOuter; /* used for aggregation */
CLSID *pclsid;
/* both paths are parsible from the desktop */
LPSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
LPITEMIDLIST pidlRoot; /* absolute pidl */
UINT cfShellIDList; /* clipboardformat for IDropTarget */
BOOL fAcceptFmt; /* flag for pending Drop */
} IGenericSFImpl;
static const IUnknownVtbl unkvt;
static const IShellFolder2Vtbl sfvt;
static const IPersistFolder3Vtbl vt_FSFldr_PersistFolder3; /* IPersistFolder3 for a FS_Folder */
static const IDropTargetVtbl dtvt;
static const ISFHelperVtbl shvt;
static inline IGenericSFImpl *impl_from_IShellFolder2( IShellFolder2 *iface )
{
return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblShellFolder));
}
static inline IGenericSFImpl *impl_from_IPersistFolder3( IPersistFolder3 *iface )
{
return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblPersistFolder3));
}
static inline IGenericSFImpl *impl_from_IDropTarget( IDropTarget *iface )
{
return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblDropTarget));
}
static inline IGenericSFImpl *impl_from_ISFHelper( ISFHelper *iface )
{
return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblSFHelper));
}
/*
converts This to an interface pointer
*/
#define _IUnknown_(This) (IUnknown*)&(This->lpVtbl)
#define _IShellFolder_(This) (IShellFolder*)&(This->lpvtblShellFolder)
#define _IShellFolder2_(This) (IShellFolder2*)&(This->lpvtblShellFolder)
#define _IPersist_(This) (IPersist*)&(This->lpvtblPersistFolder3)
#define _IPersistFolder_(This) (IPersistFolder*)&(This->lpvtblPersistFolder3)
#define _IPersistFolder2_(This) (IPersistFolder2*)&(This->lpvtblPersistFolder3)
#define _IPersistFolder3_(This) (IPersistFolder3*)&(This->lpvtblPersistFolder3)
#define _IDropTarget_(This) (IDropTarget*)&(This->lpvtblDropTarget)
#define _ISFHelper_(This) (ISFHelper*)&(This->lpvtblSFHelper)
/**************************************************************************
* registers clipboardformat once
*/
static void SF_RegisterClipFmt (IGenericSFImpl * This)
{
TRACE ("(%p)\n", This);
if (!This->cfShellIDList) {
This->cfShellIDList = RegisterClipboardFormatA (CFSTR_SHELLIDLIST);
}
}
/**************************************************************************
* we need a separate IUnknown to handle aggregation
* (inner IUnknown)
*/
static HRESULT WINAPI IUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppvObj)
{
IGenericSFImpl *This = (IGenericSFImpl *)iface;
TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
*ppvObj = NULL;
if (IsEqualIID (riid, &IID_IUnknown))
*ppvObj = _IUnknown_ (This);
else if (IsEqualIID (riid, &IID_IShellFolder))
*ppvObj = _IShellFolder_ (This);
else if (IsEqualIID (riid, &IID_IShellFolder2))
*ppvObj = _IShellFolder_ (This);
else if (IsEqualIID (riid, &IID_IPersist))
*ppvObj = _IPersist_ (This);
else if (IsEqualIID (riid, &IID_IPersistFolder))
*ppvObj = _IPersistFolder_ (This);
else if (IsEqualIID (riid, &IID_IPersistFolder2))
*ppvObj = _IPersistFolder2_ (This);
else if (IsEqualIID (riid, &IID_IPersistFolder3))
*ppvObj = _IPersistFolder3_ (This);
else if (IsEqualIID (riid, &IID_ISFHelper))
*ppvObj = _ISFHelper_ (This);
else if (IsEqualIID (riid, &IID_IDropTarget)) {
*ppvObj = _IDropTarget_ (This);
SF_RegisterClipFmt (This);
}
if (*ppvObj) {
IUnknown_AddRef ((IUnknown *) (*ppvObj));
TRACE ("-- Interface = %p\n", *ppvObj);
return S_OK;
}
TRACE ("-- Interface: E_NOINTERFACE\n");
return E_NOINTERFACE;
}
static ULONG WINAPI IUnknown_fnAddRef (IUnknown * iface)
{
IGenericSFImpl *This = (IGenericSFImpl *)iface;
ULONG refCount = InterlockedIncrement(&This->ref);
TRACE ("(%p)->(count=%lu)\n", This, refCount - 1);
return refCount;
}
static ULONG WINAPI IUnknown_fnRelease (IUnknown * iface)
{
IGenericSFImpl *This = (IGenericSFImpl *)iface;
ULONG refCount = InterlockedDecrement(&This->ref);
TRACE ("(%p)->(count=%lu)\n", This, refCount + 1);
if (!refCount) {
TRACE ("-- destroying IShellFolder(%p)\n", This);
if (This->pidlRoot)
SHFree (This->pidlRoot);
if (This->sPathTarget)
SHFree (This->sPathTarget);
LocalFree ((HLOCAL) This);
}
return refCount;
}
static const IUnknownVtbl unkvt =
{
IUnknown_fnQueryInterface,
IUnknown_fnAddRef,
IUnknown_fnRelease,
};
static shvheader GenericSFHeader[] = {
{IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
{IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
{IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
{IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
{IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
};
#define GENERICSHELLVIEWCOLUMNS 5
/**************************************************************************
* IFSFolder_Constructor
*
* NOTES
* creating undocumented ShellFS_Folder as part of an aggregation
* {F3364BA0-65B9-11CE-A9BA-00AA004AE837}
*
*/
HRESULT WINAPI
IFSFolder_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
{
IGenericSFImpl *sf;
TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
return CLASS_E_NOAGGREGATION;
sf = (IGenericSFImpl *) LocalAlloc (LMEM_ZEROINIT, sizeof (IGenericSFImpl));
if (!sf)
return E_OUTOFMEMORY;
sf->ref = 0;
sf->lpVtbl = &unkvt;
sf->lpvtblShellFolder = &sfvt;
sf->lpvtblPersistFolder3 = &vt_FSFldr_PersistFolder3;
sf->lpvtblDropTarget = &dtvt;
sf->lpvtblSFHelper = &shvt;
sf->pclsid = (CLSID *) & CLSID_ShellFSFolder;
sf->pUnkOuter = pUnkOuter ? pUnkOuter : _IUnknown_ (sf);
if (!SUCCEEDED (IUnknown_QueryInterface (_IUnknown_ (sf), riid, ppv))) {
IUnknown_Release (_IUnknown_ (sf));
return E_NOINTERFACE;
}
TRACE ("--%p\n", *ppv);
return S_OK;
}
/**************************************************************************
* IShellFolder_fnQueryInterface
*
* PARAMETERS
* REFIID riid [in ] Requested InterfaceID
* LPVOID* ppvObject [out] Interface* to hold the result
*/
static HRESULT WINAPI
IShellFolder_fnQueryInterface (IShellFolder2 * iface, REFIID riid,
LPVOID * ppvObj)
{
IGenericSFImpl *This = impl_from_IShellFolder2(iface);
TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
}
/**************************************************************************
* IShellFolder_AddRef
*/
static ULONG WINAPI IShellFolder_fnAddRef (IShellFolder2 * iface)
{
IGenericSFImpl *This = impl_from_IShellFolder2(iface);
TRACE ("(%p)->(count=%lu)\n", This, This->ref);
return IUnknown_AddRef (This->pUnkOuter);
}
/**************************************************************************
* IShellFolder_fnRelease
*/
static ULONG WINAPI IShellFolder_fnRelease (IShellFolder2 * iface)
{
IGenericSFImpl *This = impl_from_IShellFolder2(iface);
TRACE ("(%p)->(count=%lu)\n", This, This->ref);
return IUnknown_Release (This->pUnkOuter);
}
/**************************************************************************
* SHELL32_CreatePidlFromBindCtx [internal]
*
* If the caller bound File System Bind Data, assume it is the
* find data for the path.
* This allows binding of paths that don't exist.
*/
LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
{
static const WCHAR szfsbc[] = {
'F','i','l','e',' ','S','y','s','t','e','m',' ',
'B','i','n','d',' ','D','a','t','a',0 };
IFileSystemBindData *fsbd = NULL;
LPITEMIDLIST pidl = NULL;
IUnknown *param = NULL;
WIN32_FIND_DATAW wfd;
HRESULT r;
TRACE("%p %s\n", pbc, debugstr_w(path));
if (!pbc)
return NULL;
/* see if the caller bound File System Bind Data */
r = IBindCtx_GetObjectParam( pbc, (LPOLESTR) szfsbc, ¶m );
if (FAILED(r))
return NULL;
r = IUnknown_QueryInterface( param, &IID_IFileSystemBindData,
(LPVOID*) &fsbd );
if (SUCCEEDED(r))
{
r = IFileSystemBindData_GetFindData( fsbd, &wfd );
if (SUCCEEDED(r))
{
lstrcpynW( &wfd.cFileName[0], path, MAX_PATH );
pidl = _ILCreateFromFindDataW( &wfd );
}
IFileSystemBindData_Release( fsbd );
}
return pidl;
}
/**************************************************************************
* IShellFolder_ParseDisplayName {SHELL32}
*
* Parse a display name.
*
* PARAMS
* hwndOwner [in] Parent window for any message's
* pbc [in] optional FileSystemBindData context
* lpszDisplayName [in] Unicode displayname.
* pchEaten [out] (unicode) characters processed
* ppidl [out] complex pidl to item
* pdwAttributes [out] items attributes
*
* NOTES
* Every folder tries to parse only its 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 -> crash
* lpszDisplayName="" -> returns mycoputer-pidl
*
* FIXME
* pdwAttributes is not set
* pchEaten is not set like in windows
*/
static HRESULT WINAPI
IShellFolder_fnParseDisplayName (IShellFolder2 * iface,
HWND hwndOwner,
LPBC pbc,
LPOLESTR lpszDisplayName,
DWORD * pchEaten, LPITEMIDLIST * ppidl,
DWORD * pdwAttributes)
{
IGenericSFImpl *This = impl_from_IShellFolder2(iface);
HRESULT hr = E_INVALIDARG;
LPCWSTR szNext = NULL;
WCHAR szElement[MAX_PATH];
WCHAR szPath[MAX_PATH];
LPITEMIDLIST pidlTemp = NULL;
DWORD len;
TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
This, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
pchEaten, ppidl, pdwAttributes);
if (!lpszDisplayName || !ppidl)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -