diff options
Diffstat (limited to '3rdparty/lzma/CPP/Windows/Shell.cpp')
-rw-r--r-- | 3rdparty/lzma/CPP/Windows/Shell.cpp | 569 |
1 files changed, 525 insertions, 44 deletions
diff --git a/3rdparty/lzma/CPP/Windows/Shell.cpp b/3rdparty/lzma/CPP/Windows/Shell.cpp index 8e82c14a726..b2a3489870d 100644 --- a/3rdparty/lzma/CPP/Windows/Shell.cpp +++ b/3rdparty/lzma/CPP/Windows/Shell.cpp @@ -3,17 +3,49 @@ #include "StdAfx.h" #include "../Common/MyCom.h" -#ifndef _UNICODE #include "../Common/StringConvert.h" -#endif #include "COM.h" +#include "FileName.h" +#include "MemoryGlobal.h" #include "Shell.h" #ifndef _UNICODE extern bool g_IsNT; #endif +// MSVC6 and old SDK don't support this function: +// #define LWSTDAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE +// LWSTDAPI StrRetToStrW(STRRET *pstr, LPCITEMIDLIST pidl, LPWSTR *ppsz); + +// #define SHOW_DEBUG_SHELL + +#ifdef SHOW_DEBUG_SHELL + +#include "../Common/IntToString.h" + +static void Print_Number(UInt32 number, const char *s) +{ + AString s2; + s2.Add_UInt32(number); + s2.Add_Space(); + s2 += s; + OutputDebugStringA(s2); +} + +#define ODS(sz) { OutputDebugStringA(sz); } +#define ODS_U(s) { OutputDebugStringW(s); } +#define ODS_(op) { op; } + +#else + +#define ODS(sz) +#define ODS_U(s) +#define ODS_(op) + +#endif + + namespace NWindows { namespace NShell { @@ -23,12 +55,24 @@ namespace NShell { void CItemIDList::Free() { - if (m_Object == NULL) + if (!m_Object) return; + /* DOCs: + SHGetMalloc was introduced in Windows 95 and Microsoft Windows NT 4.0, + but as of Windows 2000 it is no longer necessary. + In its place, programs can call the equivalent (and easier to use) CoTaskMemAlloc and CoTaskMemFree. + Description from oldnewthings: + shell functions could work without COM (if OLE32.DLL is not loaded), + but now if OLE32.DLL is loaded, then shell functions and com functions do same things. + 22.02: so we use OLE32.DLL function to free memory: + */ + /* CMyComPtr<IMalloc> shellMalloc; if (::SHGetMalloc(&shellMalloc) != NOERROR) throw 41099; shellMalloc->Free(m_Object); + */ + CoTaskMemFree(m_Object); m_Object = NULL; } @@ -65,9 +109,354 @@ CItemIDList& CItemIDList::operator=(const CItemIDList &object) } */ + +static HRESULT ReadUnicodeStrings(const wchar_t *p, size_t size, UStringVector &names) +{ + names.Clear(); + const wchar_t *lim = p + size; + UString s; + /* + if (size == 0 || p[size - 1] != 0) + return E_INVALIDARG; + if (size == 1) + return S_OK; + if (p[size - 2] != 0) + return E_INVALIDARG; + */ + for (;;) + { + const wchar_t *start = p; + for (;;) + { + if (p == lim) return E_INVALIDARG; // S_FALSE + if (*p++ == 0) + break; + } + const size_t num = (size_t)(p - start); + if (num == 1) + { + if (p != lim) return E_INVALIDARG; // S_FALSE + return S_OK; + } + s.SetFrom(start, (unsigned)(num - 1)); + ODS_U(s) + names.Add(s); + // names.ReserveOnePosition(); + // names.AddInReserved_Ptr_of_new(new UString((unsigned)num - 1, start)); + } +} + + +static HRESULT ReadAnsiStrings(const char *p, size_t size, UStringVector &names) +{ + names.Clear(); + AString name; + for (; size != 0; size--) + { + const char c = *p++; + if (c == 0) + { + if (name.IsEmpty()) + return S_OK; + names.Add(GetUnicodeString(name)); + name.Empty(); + } + else + name += c; + } + return E_INVALIDARG; +} + + +#define INIT_FORMATETC_HGLOBAL(type) { (type), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } + +static HRESULT DataObject_GetData_HGLOBAL(IDataObject *dataObject, CLIPFORMAT cf, NCOM::CStgMedium &medium) +{ + FORMATETC etc = INIT_FORMATETC_HGLOBAL(cf); + RINOK(dataObject->GetData(&etc, &medium)) + if (medium.tymed != TYMED_HGLOBAL) + return E_INVALIDARG; + return S_OK; +} + +static HRESULT DataObject_GetData_HDROP_Names(IDataObject *dataObject, UStringVector &names) +{ + names.Clear(); + NCOM::CStgMedium medium; + + /* Win10 : if (dataObject) is from IContextMenu::Initialize() and + if (len_of_path >= MAX_PATH (260) for some file in data object) + { + GetData() returns HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) + "The data area passed to a system call is too small", + Is there a way to fix this code for long paths? + } */ + + RINOK(DataObject_GetData_HGLOBAL(dataObject, CF_HDROP, medium)) + const size_t blockSize = GlobalSize(medium.hGlobal); + if (blockSize < sizeof(DROPFILES)) + return E_INVALIDARG; + NMemory::CGlobalLock dropLock(medium.hGlobal); + const DROPFILES *dropFiles = (const DROPFILES *)dropLock.GetPointer(); + if (!dropFiles) + return E_INVALIDARG; + if (blockSize < dropFiles->pFiles + || dropFiles->pFiles < sizeof(DROPFILES) + // || dropFiles->pFiles != sizeof(DROPFILES) + ) + return E_INVALIDARG; + const size_t size = blockSize - dropFiles->pFiles; + const void *namesData = (const Byte *)(const void *)dropFiles + dropFiles->pFiles; + HRESULT hres; + if (dropFiles->fWide) + { + if (size % sizeof(wchar_t) != 0) + return E_INVALIDARG; + hres = ReadUnicodeStrings((const wchar_t *)namesData, size / sizeof(wchar_t), names); + } + else + hres = ReadAnsiStrings((const char *)namesData, size, names); + + ODS_(Print_Number(names.Size(), "DataObject_GetData_HDROP_Names")) + return hres; +} + + + +// CF_IDLIST: +#define MYWIN_CFSTR_SHELLIDLIST TEXT("Shell IDList Array") + +typedef struct +{ + UINT cidl; + UINT aoffset[1]; +} MYWIN_CIDA; +/* + cidl : number of PIDLs that are being transferred, not including the parent folder. + aoffset : An array of offsets, relative to the beginning of this structure. + aoffset[0] - fully qualified PIDL of a parent folder. + If this PIDL is empty, the parent folder is the desktop. + aoffset[1] ... aoffset[cidl] : offset to one of the PIDLs to be transferred. + All of these PIDLs are relative to the PIDL of the parent folder. +*/ + +static HRESULT DataObject_GetData_IDLIST(IDataObject *dataObject, UStringVector &names) +{ + names.Clear(); + NCOM::CStgMedium medium; + RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT) + RegisterClipboardFormat(MYWIN_CFSTR_SHELLIDLIST), medium)) + const size_t blockSize = GlobalSize(medium.hGlobal); + if (blockSize < sizeof(MYWIN_CIDA) || blockSize >= (UInt32)((UInt32)0 - 1)) + return E_INVALIDARG; + NMemory::CGlobalLock dropLock(medium.hGlobal); + const MYWIN_CIDA *cida = (const MYWIN_CIDA *)dropLock.GetPointer(); + if (!cida) + return E_INVALIDARG; + if (cida->cidl == 0) + { + // is it posssible to have no selected items? + // it's unexpected case. + return E_INVALIDARG; + } + if (cida->cidl >= (blockSize - (UInt32)sizeof(MYWIN_CIDA)) / sizeof(UINT)) + return E_INVALIDARG; + const UInt32 start = cida->cidl * (UInt32)sizeof(UINT) + (UInt32)sizeof(MYWIN_CIDA); + + STRRET strret; + CMyComPtr<IShellFolder> parentFolder; + { + const UINT offset = cida->aoffset[0]; + if (offset < start || offset >= blockSize + // || offset != start + ) + return E_INVALIDARG; + + CMyComPtr<IShellFolder> desktopFolder; + RINOK(::SHGetDesktopFolder(&desktopFolder)) + if (!desktopFolder) + return E_FAIL; + + LPCITEMIDLIST const lpcItem = (LPCITEMIDLIST)(const void *)((const Byte *)cida + offset); + + #ifdef SHOW_DEBUG_SHELL + { + const HRESULT res = desktopFolder->GetDisplayNameOf( + lpcItem, SHGDN_FORPARSING, &strret); + if (res == S_OK && strret.uType == STRRET_WSTR) + { + ODS_U(strret.pOleStr) + /* if lpcItem is empty, the path will be + "C:\Users\user_name\Desktop" + if lpcItem is "My Computer" folder, the path will be + "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" */ + CoTaskMemFree(strret.pOleStr); + } + } + #endif + + RINOK(desktopFolder->BindToObject(lpcItem, + NULL, IID_IShellFolder, (void **)&parentFolder)) + if (!parentFolder) + return E_FAIL; + } + + names.ClearAndReserve(cida->cidl); + UString path; + + // for (int y = 0; y < 1; y++) // for debug + for (unsigned i = 1; i <= cida->cidl; i++) + { + const UINT offset = cida->aoffset[i]; + if (offset < start || offset >= blockSize) + return E_INVALIDARG; + const void *p = (const Byte *)(const void *)cida + offset; + /* ITEMIDLIST of file can contain more than one SHITEMID item. + In win10 only SHGDN_FORPARSING returns path that contains + all path parts related to parts of ITEMIDLIST. + So we can use only SHGDN_FORPARSING here. + Don't use (SHGDN_INFOLDER) + Don't use (SHGDN_INFOLDER | SHGDN_FORPARSING) + */ + RINOK(parentFolder->GetDisplayNameOf((LPCITEMIDLIST)p, SHGDN_FORPARSING, &strret)) + + /* + // MSVC6 and old SDK do not support StrRetToStrW(). + LPWSTR lpstr; + RINOK (StrRetToStrW(&strret, NULL, &lpstr)) + ODS_U(lpstr) + path = lpstr; + CoTaskMemFree(lpstr); + */ + if (strret.uType != STRRET_WSTR) + return E_INVALIDARG; + ODS_U(strret.pOleStr) + path = strret.pOleStr; + // the path could have super path prefix "\\\\?\\" + // we can remove super path prefix here, if we don't need that prefix + #ifdef Z7_LONG_PATH + // we remove super prefix, if we can work without that prefix + NFile::NName::If_IsSuperPath_RemoveSuperPrefix(path); + #endif + names.AddInReserved(path); + CoTaskMemFree(strret.pOleStr); + } + + ODS_(Print_Number(cida->cidl, "CFSTR_SHELLIDLIST END")) + return S_OK; +} + + +HRESULT DataObject_GetData_HDROP_or_IDLIST_Names(IDataObject *dataObject, UStringVector &paths) +{ + ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names START") + HRESULT hres = NShell::DataObject_GetData_HDROP_Names(dataObject, paths); + // if (hres == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) + if (hres != S_OK) + { + ODS("-- DataObject_GetData_IDLIST START") + // for (int y = 0; y < 10000; y++) // for debug + hres = NShell::DataObject_GetData_IDLIST(dataObject, paths); + } + ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names END") + return hres; +} + + + +// #if (NTDDI_VERSION >= NTDDI_VISTA) +typedef struct +{ + UINT cItems; // number of items in rgdwFileAttributes array + DWORD dwSumFileAttributes; // all of the attributes ORed together + DWORD dwProductFileAttributes; // all of the attributes ANDed together + DWORD rgdwFileAttributes[1]; // array +} MYWIN_FILE_ATTRIBUTES_ARRAY; + +#define MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY TEXT("File Attributes Array") + +HRESULT DataObject_GetData_FILE_ATTRS(IDataObject *dataObject, CFileAttribs &attribs) +{ + attribs.Clear(); + NCOM::CStgMedium medium; + RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT) + RegisterClipboardFormat(MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY), medium)) + const size_t blockSize = GlobalSize(medium.hGlobal); + if (blockSize < sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY)) + return E_INVALIDARG; + NMemory::CGlobalLock dropLock(medium.hGlobal); + const MYWIN_FILE_ATTRIBUTES_ARRAY *faa = (const MYWIN_FILE_ATTRIBUTES_ARRAY *)dropLock.GetPointer(); + if (!faa) + return E_INVALIDARG; + const unsigned numFiles = faa->cItems; + if (numFiles == 0) + { + // is it posssible to have empty array here? + return E_INVALIDARG; + } + if ((blockSize - (sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY) - sizeof(DWORD))) + / sizeof(DWORD) != numFiles) + return E_INVALIDARG; + // attribs.Sum = faa->dwSumFileAttributes; + // attribs.Product = faa->dwProductFileAttributes; + // attribs.Vals.SetFromArray(faa->rgdwFileAttributes, numFiles); + // attribs.IsDirVector.ClearAndSetSize(numFiles); + + if ((faa->dwSumFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) + { + /* in win10: if selected items are volumes (c:\, d:\ ..) in My Compter, + all items have FILE_ATTRIBUTE_DIRECTORY attribute + ntfs volume also have FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM + udf volume: FILE_ATTRIBUTE_READONLY + dvd-rom device: (-1) : all bits are set + */ + const DWORD *attr = faa->rgdwFileAttributes; + // DWORD product = (UInt32)0 - 1, sum = 0; + for (unsigned i = 0; i < numFiles; i++) + { + if (attr[i] & FILE_ATTRIBUTE_DIRECTORY) + { + // attribs.ThereAreDirs = true; + attribs.FirstDirIndex = (int)i; + break; + } + // attribs.IsDirVector[i] = (attr[i] & FILE_ATTRIBUTE_DIRECTORY) != 0; + // product &= v; + // sum |= v; + } + // ODS_(Print_Number(product, "Product calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) + // ODS_(Print_Number(sum, "Sum calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) + } + // ODS_(Print_Number(attribs.Product, "Product FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) + // ODS_(Print_Number(attribs.Sum, "Sum FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) + ODS_(Print_Number(numFiles, "FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) + return S_OK; +} + + ///////////////////////////// // CDrop +/* + win10: + DragQueryFile() implementation code is not effective because + there is no pointer inside DROP internal file list, so + DragQueryFile(fileIndex) runs all names in range [0, fileIndex]. + DragQueryFile(,, buf, bufSize) + if (buf == NULL) by spec + { + returns value is the required size + in characters, of the buffer, not including the terminating null character + tests show that if (bufSize == 0), then it also returns required size. + } + if (bufSize != NULL) + { + returns: the count of the characters copied, not including null character. + win10: null character is also copied at position buf[ret_count]; + } +*/ + +/* void CDrop::Attach(HDROP object) { Free(); @@ -87,43 +476,133 @@ UINT CDrop::QueryCountOfFiles() return QueryFile(0xFFFFFFFF, (LPTSTR)NULL, 0); } -UString CDrop::QueryFileName(UINT fileIndex) +void CDrop::QueryFileName(UINT fileIndex, UString &fileName) { - UString fileName; #ifndef _UNICODE if (!g_IsNT) { AString fileNameA; - UINT bufferSize = QueryFile(fileIndex, (LPTSTR)NULL, 0); - const unsigned len = bufferSize + 2; - QueryFile(fileIndex, fileNameA.GetBuf(len), bufferSize + 1); + const UINT len = QueryFile(fileIndex, (LPTSTR)NULL, 0); + const UINT numCopied = QueryFile(fileIndex, fileNameA.GetBuf(len + 2), len + 2); fileNameA.ReleaseBuf_CalcLen(len); + if (numCopied != len) + throw 20221223; fileName = GetUnicodeString(fileNameA); } else #endif { - UINT bufferSize = QueryFile(fileIndex, (LPWSTR)NULL, 0); - const unsigned len = bufferSize + 2; - QueryFile(fileIndex, fileName.GetBuf(len), bufferSize + 1); + // kReserve must be >= 3 for additional buffer size + // safety and for optimal performance + const unsigned kReserve = 3; + { + unsigned len = 0; + wchar_t *buf = fileName.GetBuf_GetMaxAvail(len); + if (len >= kReserve) + { + const UINT numCopied = QueryFile(fileIndex, buf, len); + if (numCopied < len - 1) + { + // (numCopied < len - 1) case means that it have copied full string. + fileName.ReleaseBuf_CalcLen(numCopied); + return; + } + } + } + const UINT len = QueryFile(fileIndex, (LPWSTR)NULL, 0); + const UINT numCopied = QueryFile(fileIndex, + fileName.GetBuf(len + kReserve), len + kReserve); fileName.ReleaseBuf_CalcLen(len); + if (numCopied != len) + throw 20221223; } - return fileName; } + void CDrop::QueryFileNames(UStringVector &fileNames) { UINT numFiles = QueryCountOfFiles(); + + Print_Number(numFiles, "\n====== CDrop::QueryFileNames START ===== \n"); + fileNames.ClearAndReserve(numFiles); + UString s; for (UINT i = 0; i < numFiles; i++) - fileNames.AddInReserved(QueryFileName(i)); + { + QueryFileName(i, s); + if (!s.IsEmpty()) + fileNames.AddInReserved(s); + } + Print_Number(numFiles, "\n====== CDrop::QueryFileNames END ===== \n"); } +*/ -bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path) +// #if (NTDDI_VERSION >= NTDDI_VISTA) +// SHGetPathFromIDListEx returns a win32 file system path for the item in the name space. +typedef int Z7_WIN_GPFIDL_FLAGS; + +extern "C" { +typedef BOOL (WINAPI * Func_SHGetPathFromIDListW)(LPCITEMIDLIST pidl, LPWSTR pszPath); +typedef BOOL (WINAPI * Func_SHGetPathFromIDListEx)(LPCITEMIDLIST pidl, PWSTR pszPath, DWORD cchPath, Z7_WIN_GPFIDL_FLAGS uOpts); +} + +#ifndef _UNICODE + +bool GetPathFromIDList(LPCITEMIDLIST itemIDList, AString &path) { - const unsigned len = MAX_PATH * 2; + path.Empty(); + const unsigned len = MAX_PATH + 16; + const bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len))); + path.ReleaseBuf_CalcLen(len); + return result; +} + +#endif + +bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path) +{ + path.Empty(); + unsigned len = MAX_PATH + 16; + +#ifdef _UNICODE bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len))); +#else + const + Func_SHGetPathFromIDListW + shGetPathFromIDListW = Z7_GET_PROC_ADDRESS( + Func_SHGetPathFromIDListW, ::GetModuleHandleW(L"shell32.dll"), + "SHGetPathFromIDListW"); + if (!shGetPathFromIDListW) + return false; + bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len))); +#endif + + if (!result) + { + ODS("==== GetPathFromIDList() SHGetPathFromIDList() returned false") + /* for long path we need SHGetPathFromIDListEx(). + win10: SHGetPathFromIDListEx() for long path returns path with + with super path prefix "\\\\?\\". */ + const + Func_SHGetPathFromIDListEx + func_SHGetPathFromIDListEx = Z7_GET_PROC_ADDRESS( + Func_SHGetPathFromIDListEx, ::GetModuleHandleW(L"shell32.dll"), + "SHGetPathFromIDListEx"); + if (func_SHGetPathFromIDListEx) + { + ODS("==== GetPathFromIDList() (SHGetPathFromIDListEx)") + do + { + len *= 4; + result = BOOLToBool(func_SHGetPathFromIDListEx(itemIDList, path.GetBuf(len), len, 0)); + if (result) + break; + } + while (len <= (1 << 16)); + } + } + path.ReleaseBuf_CalcLen(len); return result; } @@ -153,8 +632,8 @@ bool BrowseForFolder(HWND /* owner */, LPCTSTR /* title */, MessageBoxW(0, L"yes", L"", 0); */ /* - UString s = L"all files"; - s += L" (*.*)"; + UString s = "all files"; + s += " (*.*)"; return MyGetOpenFileName(owner, title, initialFolder, s, resultPath, true); */ return false; @@ -162,11 +641,16 @@ bool BrowseForFolder(HWND /* owner */, LPCTSTR /* title */, #else +/* win10: SHBrowseForFolder() doesn't support long paths, + even if long path suppport is enabled in registry and in manifest. + and SHBrowseForFolder() doesn't support super path prefix "\\\\?\\". */ + bool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath) { + resultPath.Empty(); NWindows::NCOM::CComInitializer comInitializer; LPITEMIDLIST itemIDList = ::SHBrowseForFolder(browseInfo); - if (itemIDList == NULL) + if (!itemIDList) return false; CItemIDList itemIDListHolder; itemIDListHolder.Attach(itemIDList); @@ -174,7 +658,7 @@ bool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath) } -int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) +static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) { #ifndef UNDER_CE switch (uMsg) @@ -203,7 +687,7 @@ int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM da } -bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags, +static bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags, LPCTSTR initialFolder, CSysString &resultPath) { CSysString displayName; @@ -222,11 +706,18 @@ bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags, browseInfo.lpszTitle = title; // #endif browseInfo.ulFlags = ulFlags; - browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc : NULL; + browseInfo.lpfn = initialFolder ? BrowseCallbackProc : NULL; browseInfo.lParam = (LPARAM)initialFolder; return BrowseForFolder(&browseInfo, resultPath); } +#ifdef Z7_OLD_WIN_SDK +// ShlObj.h: +#ifndef BIF_NEWDIALOGSTYLE +#define BIF_NEWDIALOGSTYLE 0x0040 +#endif +#endif + bool BrowseForFolder(HWND owner, LPCTSTR title, LPCTSTR initialFolder, CSysString &resultPath) { @@ -240,39 +731,29 @@ bool BrowseForFolder(HWND owner, LPCTSTR title, #ifndef _UNICODE -typedef BOOL (WINAPI * SHGetPathFromIDListWP)(LPCITEMIDLIST pidl, LPWSTR pszPath); - -bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path) -{ - path.Empty(); - SHGetPathFromIDListWP shGetPathFromIDListW = (SHGetPathFromIDListWP) - ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetPathFromIDListW"); - if (shGetPathFromIDListW == 0) - return false; - const unsigned len = MAX_PATH * 2; - bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len))); - path.ReleaseBuf_CalcLen(len); - return result; +extern "C" { +typedef LPITEMIDLIST (WINAPI * Func_SHBrowseForFolderW)(LPBROWSEINFOW lpbi); } -typedef LPITEMIDLIST (WINAPI * SHBrowseForFolderWP)(LPBROWSEINFOW lpbi); - -bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath) +static bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath) { NWindows::NCOM::CComInitializer comInitializer; - SHBrowseForFolderWP shBrowseForFolderW = (SHBrowseForFolderWP) - ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHBrowseForFolderW"); - if (shBrowseForFolderW == 0) + const + Func_SHBrowseForFolderW + f_SHBrowseForFolderW = Z7_GET_PROC_ADDRESS( + Func_SHBrowseForFolderW, ::GetModuleHandleW(L"shell32.dll"), + "SHBrowseForFolderW"); + if (!f_SHBrowseForFolderW) return false; - LPITEMIDLIST itemIDList = shBrowseForFolderW(browseInfo); - if (itemIDList == NULL) + LPITEMIDLIST itemIDList = f_SHBrowseForFolderW(browseInfo); + if (!itemIDList) return false; CItemIDList itemIDListHolder; itemIDListHolder.Attach(itemIDList); return GetPathFromIDList(itemIDList, resultPath); } - +static int CALLBACK BrowseCallbackProc2(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) { switch (uMsg) @@ -311,7 +792,7 @@ static bool BrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags, browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH); browseInfo.lpszTitle = title; browseInfo.ulFlags = ulFlags; - browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc2 : NULL; + browseInfo.lpfn = initialFolder ? BrowseCallbackProc2 : NULL; browseInfo.lParam = (LPARAM)initialFolder; return BrowseForFolder(&browseInfo, resultPath); } |