📄 pidl.c
字号:
/*
* pidl Handling
*
* Copyright 1998 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
*
* NOTES
* a pidl == NULL means desktop and is legal
*
*/
#include "config.h"
#include "wine/port.h"
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "objbase.h"
#include "shlguid.h"
#include "winerror.h"
#include "winnls.h"
#include "undocshell.h"
#include "shell32_main.h"
#include "shellapi.h"
#include "shlwapi.h"
#include "pidl.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(pidl);
WINE_DECLARE_DEBUG_CHANNEL(shell);
/* from comctl32.dll */
extern LPVOID WINAPI Alloc(INT);
extern BOOL WINAPI Free(LPVOID);
/*************************************************************************
* ILGetDisplayNameEx [SHELL32.186]
*
* Retrieves the display name of an ItemIDList
*
* PARAMS
* psf [I] Shell Folder to start with, if NULL the desktop is used
* pidl [I] ItemIDList relativ to the psf to get the display name for
* path [O] Filled in with the display name, assumed to be at least MAX_PATH long
* type [I] Type of display name to retrieve
* 0 = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR uses always the desktop as root
* 1 = SHGDN_NORMAL relative to the root folder
* 2 = SHGDN_INFOLDER relative to the root folder, only the last name
*
* RETURNS
* True if the display name could be retrieved successfully, False otherwise
*/
BOOL WINAPI ILGetDisplayNameExA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPSTR path, DWORD type)
{
BOOL ret = FALSE;
WCHAR wPath[MAX_PATH];
TRACE("%p %p %p %ld\n", psf, pidl, path, type);
if (!pidl || !path)
return FALSE;
ret = ILGetDisplayNameExW(psf, pidl, wPath, type);
WideCharToMultiByte(CP_ACP, 0, wPath, -1, path, MAX_PATH, NULL, NULL);
TRACE("%p %p %s\n", psf, pidl, debugstr_a(path));
return ret;
}
BOOL WINAPI ILGetDisplayNameExW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPWSTR path, DWORD type)
{
LPSHELLFOLDER psfParent, lsf = psf;
HRESULT ret = NO_ERROR;
LPCITEMIDLIST pidllast;
STRRET strret;
DWORD flag;
TRACE("%p %p %p %ld\n", psf, pidl, path, type);
if (!pidl || !path)
return FALSE;
if (!lsf)
{
ret = SHGetDesktopFolder(&lsf);
if (FAILED(ret))
return FALSE;
}
if (type >= 0 && type <= 2)
{
switch (type)
{
case ILGDN_FORPARSING:
flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR;
break;
case ILGDN_NORMAL:
flag = SHGDN_NORMAL;
break;
case ILGDN_INFOLDER:
flag = SHGDN_INFOLDER;
break;
default:
FIXME("Unknown type parameter = %lx\n", type);
flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR;
break;
}
if (!*(const WORD*)pidl || type == ILGDN_FORPARSING)
{
ret = IShellFolder_GetDisplayNameOf(lsf, pidl, flag, &strret);
if (SUCCEEDED(ret))
{
ret = StrRetToStrNW(path, MAX_PATH, &strret, pidl);
}
}
else
{
ret = SHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&psfParent, &pidllast);
if (SUCCEEDED(ret))
{
ret = IShellFolder_GetDisplayNameOf(psfParent, pidllast, flag, &strret);
if (SUCCEEDED(ret))
{
ret = StrRetToStrNW(path, MAX_PATH, &strret, pidllast);
}
IShellFolder_Release(psfParent);
}
}
}
TRACE("%p %p %s\n", psf, pidl, debugstr_w(path));
if (!psf)
IShellFolder_Release(lsf);
return SUCCEEDED(ret);
}
BOOL WINAPI ILGetDisplayNameEx(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPVOID path, DWORD type)
{
TRACE_(shell)("%p %p %p %ld\n", psf, pidl, path, type);
if (SHELL_OsIsUnicode())
return ILGetDisplayNameExW(psf, pidl, path, type);
return ILGetDisplayNameExA(psf, pidl, path, type);
}
/*************************************************************************
* ILGetDisplayName [SHELL32.15]
*/
BOOL WINAPI ILGetDisplayName(LPCITEMIDLIST pidl, LPVOID path)
{
TRACE_(shell)("%p %p\n", pidl, path);
if (SHELL_OsIsUnicode())
return ILGetDisplayNameExW(NULL, pidl, path, ILGDN_FORPARSING);
return ILGetDisplayNameExA(NULL, pidl, path, ILGDN_FORPARSING);
}
/*************************************************************************
* ILFindLastID [SHELL32.16]
*
* NOTES
* observed: pidl=Desktop return=pidl
*/
LPITEMIDLIST WINAPI ILFindLastID(LPCITEMIDLIST pidl)
{
LPCITEMIDLIST pidlLast = pidl;
TRACE("(pidl=%p)\n",pidl);
if (!pidl)
return NULL;
while (pidl->mkid.cb)
{
pidlLast = pidl;
pidl = ILGetNext(pidl);
}
return (LPITEMIDLIST)pidlLast;
}
/*************************************************************************
* ILRemoveLastID [SHELL32.17]
*
* NOTES
* when pidl=Desktop return=FALSE
*/
BOOL WINAPI ILRemoveLastID(LPITEMIDLIST pidl)
{
TRACE_(shell)("pidl=%p\n",pidl);
if (!pidl || !pidl->mkid.cb)
return 0;
ILFindLastID(pidl)->mkid.cb = 0;
return 1;
}
/*************************************************************************
* ILClone [SHELL32.18]
*
* NOTES
* duplicate an idlist
*/
LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
{
DWORD len;
LPITEMIDLIST newpidl;
if (!pidl)
return NULL;
len = ILGetSize(pidl);
newpidl = (LPITEMIDLIST)SHAlloc(len);
if (newpidl)
memcpy(newpidl,pidl,len);
TRACE("pidl=%p newpidl=%p\n",pidl, newpidl);
pdump(pidl);
return newpidl;
}
/*************************************************************************
* ILCloneFirst [SHELL32.19]
*
* NOTES
* duplicates the first idlist of a complex pidl
*/
LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl)
{
DWORD len;
LPITEMIDLIST pidlNew = NULL;
TRACE("pidl=%p\n", pidl);
pdump(pidl);
if (pidl)
{
len = pidl->mkid.cb;
pidlNew = (LPITEMIDLIST) SHAlloc (len+2);
if (pidlNew)
{
memcpy(pidlNew,pidl,len+2); /* 2 -> mind a desktop pidl */
if (len)
ILGetNext(pidlNew)->mkid.cb = 0x00;
}
}
TRACE("-- newpidl=%p\n",pidlNew);
return pidlNew;
}
/*************************************************************************
* ILLoadFromStream (SHELL32.26)
*
* NOTES
* the first two bytes are the len, the pidl is following then
*/
HRESULT WINAPI ILLoadFromStream (IStream * pStream, LPITEMIDLIST * ppPidl)
{
WORD wLen = 0;
DWORD dwBytesRead;
HRESULT ret = E_FAIL;
TRACE_(shell)("%p %p\n", pStream , ppPidl);
if (*ppPidl)
{
SHFree(*ppPidl);
*ppPidl = NULL;
}
IStream_AddRef (pStream);
if (SUCCEEDED(IStream_Read(pStream, (LPVOID)&wLen, 2, &dwBytesRead)))
{
TRACE("PIDL length is %d\n", wLen);
if (wLen != 0)
{
*ppPidl = SHAlloc (wLen);
if (SUCCEEDED(IStream_Read(pStream, *ppPidl , wLen, &dwBytesRead)))
{
TRACE("Stream read OK\n");
ret = S_OK;
}
else
{
WARN("reading pidl failed\n");
SHFree(*ppPidl);
*ppPidl = NULL;
}
}
else
{
*ppPidl = NULL;
ret = S_OK;
}
}
/* we are not yet fully compatible */
if (*ppPidl && !pcheck(*ppPidl))
{
WARN("Check failed\n");
SHFree(*ppPidl);
*ppPidl = NULL;
}
IStream_Release (pStream);
TRACE("done\n");
return ret;
}
/*************************************************************************
* ILSaveToStream (SHELL32.27)
*
* NOTES
* the first two bytes are the len, the pidl is following then
*/
HRESULT WINAPI ILSaveToStream (IStream * pStream, LPCITEMIDLIST pPidl)
{
LPCITEMIDLIST pidl;
WORD wLen = 0;
HRESULT ret = E_FAIL;
TRACE_(shell)("%p %p\n", pStream, pPidl);
IStream_AddRef (pStream);
pidl = pPidl;
while (pidl->mkid.cb)
{
wLen += sizeof(WORD) + pidl->mkid.cb;
pidl = ILGetNext(pidl);
}
if (SUCCEEDED(IStream_Write(pStream, (LPVOID)&wLen, 2, NULL)))
{
if (SUCCEEDED(IStream_Write(pStream, pPidl, wLen, NULL)))
ret = S_OK;
}
IStream_Release (pStream);
return ret;
}
/*************************************************************************
* SHILCreateFromPath [SHELL32.28]
*
* Create an ItemIDList from a path
*
* PARAMS
* path [I]
* ppidl [O]
* attributes [I/O] requested attributes on call and actual attributes when
* the function returns
*
* RETURNS
* NO_ERROR if successful, or an OLE errer code otherwise
*
* NOTES
* Wrapper for IShellFolder_ParseDisplayName().
*/
HRESULT WINAPI SHILCreateFromPathA(LPCSTR path, LPITEMIDLIST * ppidl, DWORD * attributes)
{
WCHAR lpszDisplayName[MAX_PATH];
TRACE_(shell)("%s %p 0x%08lx\n", path, ppidl, attributes ? *attributes : 0);
if (!MultiByteToWideChar(CP_ACP, 0, path, -1, lpszDisplayName, MAX_PATH))
lpszDisplayName[MAX_PATH-1] = 0;
return SHILCreateFromPathW(lpszDisplayName, ppidl, attributes);
}
HRESULT WINAPI SHILCreateFromPathW(LPCWSTR path, LPITEMIDLIST * ppidl, DWORD * attributes)
{
LPSHELLFOLDER sf;
DWORD pchEaten;
HRESULT ret = E_FAIL;
TRACE_(shell)("%s %p 0x%08lx\n", debugstr_w(path), ppidl, attributes ? *attributes : 0);
if (SUCCEEDED (SHGetDesktopFolder(&sf)))
{
ret = IShellFolder_ParseDisplayName(sf, 0, NULL, (LPWSTR)path, &pchEaten, ppidl, attributes);
IShellFolder_Release(sf);
}
return ret;
}
HRESULT WINAPI SHILCreateFromPathAW (LPCVOID path, LPITEMIDLIST * ppidl, DWORD * attributes)
{
if ( SHELL_OsIsUnicode())
return SHILCreateFromPathW (path, ppidl, attributes);
return SHILCreateFromPathA (path, ppidl, attributes);
}
/*************************************************************************
* SHCloneSpecialIDList [SHELL32.89]
*
* Create an ItemIDList to one of the special folders.
* PARAMS
* hwndOwner [in]
* nFolder [in] CSIDL_xxxxx
* fCreate [in] Create folder if it does not exist
*
* RETURNS
* Success: The newly created pidl
* Failure: NULL, if inputs are invalid.
*
* NOTES
* exported by ordinal.
* Caller is responsible for deallocating the returned ItemIDList with the
* shells IMalloc interface, aka ILFree.
*/
LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner, DWORD nFolder, BOOL fCreate)
{
LPITEMIDLIST ppidl;
TRACE_(shell)("(hwnd=%p,csidl=0x%lx,%s).\n", hwndOwner, nFolder, fCreate ? "T" : "F");
if (fCreate)
nFolder |= CSIDL_FLAG_CREATE;
SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl);
return ppidl;
}
/*************************************************************************
* ILGlobalClone [SHELL32.20]
*
* Clones an ItemIDList using Alloc.
*
* PARAMS
* pidl [I] ItemIDList to clone
*
* RETURNS
* Newly allocated ItemIDList.
*
* NOTES
* exported by ordinal.
*/
LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl)
{
DWORD len;
LPITEMIDLIST newpidl;
if (!pidl)
return NULL;
len = ILGetSize(pidl);
newpidl = (LPITEMIDLIST)Alloc(len);
if (newpidl)
memcpy(newpidl,pidl,len);
TRACE("pidl=%p newpidl=%p\n",pidl, newpidl);
pdump(pidl);
return newpidl;
}
/*************************************************************************
* ILIsEqual [SHELL32.21]
*
*/
BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
char szData1[MAX_PATH];
char szData2[MAX_PATH];
LPCITEMIDLIST pidltemp1 = pidl1;
LPCITEMIDLIST pidltemp2 = pidl2;
TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2);
/*
* Explorer reads from registry directly (StreamMRU),
* so we can only check here
*/
if (!pcheck(pidl1) || !pcheck (pidl2))
return FALSE;
pdump (pidl1);
pdump (pidl2);
if (!pidl1 || !pidl2)
return FALSE;
while (pidltemp1->mkid.cb && pidltemp2->mkid.cb)
{
_ILSimpleGetText(pidltemp1, szData1, MAX_PATH);
_ILSimpleGetText(pidltemp2, szData2, MAX_PATH);
if (strcasecmp( szData1, szData2 ))
return FALSE;
pidltemp1 = ILGetNext(pidltemp1);
pidltemp2 = ILGetNext(pidltemp2);
}
if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb)
return TRUE;
return FALSE;
}
/*************************************************************************
* ILIsParent [SHELL32.23]
*
* Verifies that pidlParent is indeed the (immediate) parent of pidlChild.
*
* PARAMS
* pidlParent [I]
* pidlChild [I]
* bImmediate [I] only return true if the parent is the direct parent
* of the child
*
* RETURNS
* True if the parent ItemIDlist is a complete part of the child ItemIdList,
* False otherwise.
*
* NOTES
* parent = a/b, child = a/b/c -> true, c is in folder a/b
* child = a/b/c/d -> false if bImmediate is true, d is not in folder a/b
* child = a/b/c/d -> true if bImmediate is false, d is in a subfolder of a/b
*/
BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate)
{
char szData1[MAX_PATH];
char szData2[MAX_PATH];
LPCITEMIDLIST pParent = pidlParent;
LPCITEMIDLIST pChild = pidlChild;
TRACE("%p %p %x\n", pidlParent, pidlChild, bImmediate);
if (!pParent || !pChild)
return FALSE;
while (pParent->mkid.cb && pChild->mkid.cb)
{
_ILSimpleGetText(pParent, szData1, MAX_PATH);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -