⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pidl.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 *    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 + -