1370b324cSopenharmony_ci// Windows/Shell.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci#include "../Common/MyCom.h"
6370b324cSopenharmony_ci#include "../Common/StringConvert.h"
7370b324cSopenharmony_ci
8370b324cSopenharmony_ci#include "COM.h"
9370b324cSopenharmony_ci#include "FileName.h"
10370b324cSopenharmony_ci#include "MemoryGlobal.h"
11370b324cSopenharmony_ci#include "Shell.h"
12370b324cSopenharmony_ci
13370b324cSopenharmony_ci#ifndef _UNICODE
14370b324cSopenharmony_ciextern bool g_IsNT;
15370b324cSopenharmony_ci#endif
16370b324cSopenharmony_ci
17370b324cSopenharmony_ci// MSVC6 and old SDK don't support this function:
18370b324cSopenharmony_ci// #define LWSTDAPI  EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
19370b324cSopenharmony_ci// LWSTDAPI StrRetToStrW(STRRET *pstr, LPCITEMIDLIST pidl, LPWSTR *ppsz);
20370b324cSopenharmony_ci
21370b324cSopenharmony_ci// #define SHOW_DEBUG_SHELL
22370b324cSopenharmony_ci
23370b324cSopenharmony_ci#ifdef SHOW_DEBUG_SHELL
24370b324cSopenharmony_ci
25370b324cSopenharmony_ci#include "../Common/IntToString.h"
26370b324cSopenharmony_ci
27370b324cSopenharmony_cistatic void Print_Number(UInt32 number, const char *s)
28370b324cSopenharmony_ci{
29370b324cSopenharmony_ci  AString s2;
30370b324cSopenharmony_ci  s2.Add_UInt32(number);
31370b324cSopenharmony_ci  s2.Add_Space();
32370b324cSopenharmony_ci  s2 += s;
33370b324cSopenharmony_ci  OutputDebugStringA(s2);
34370b324cSopenharmony_ci}
35370b324cSopenharmony_ci
36370b324cSopenharmony_ci#define ODS(sz) { OutputDebugStringA(sz); }
37370b324cSopenharmony_ci#define ODS_U(s) { OutputDebugStringW(s); }
38370b324cSopenharmony_ci#define ODS_(op) { op; }
39370b324cSopenharmony_ci
40370b324cSopenharmony_ci#else
41370b324cSopenharmony_ci
42370b324cSopenharmony_ci#define ODS(sz)
43370b324cSopenharmony_ci#define ODS_U(s)
44370b324cSopenharmony_ci#define ODS_(op)
45370b324cSopenharmony_ci
46370b324cSopenharmony_ci#endif
47370b324cSopenharmony_ci
48370b324cSopenharmony_ci
49370b324cSopenharmony_cinamespace NWindows {
50370b324cSopenharmony_cinamespace NShell {
51370b324cSopenharmony_ci
52370b324cSopenharmony_ci#ifndef UNDER_CE
53370b324cSopenharmony_ci
54370b324cSopenharmony_ci// SHGetMalloc is unsupported in Windows Mobile?
55370b324cSopenharmony_ci
56370b324cSopenharmony_civoid CItemIDList::Free()
57370b324cSopenharmony_ci{
58370b324cSopenharmony_ci  if (!m_Object)
59370b324cSopenharmony_ci    return;
60370b324cSopenharmony_ci  /* DOCs:
61370b324cSopenharmony_ci      SHGetMalloc was introduced in Windows 95 and Microsoft Windows NT 4.0,
62370b324cSopenharmony_ci      but as of Windows 2000 it is no longer necessary.
63370b324cSopenharmony_ci      In its place, programs can call the equivalent (and easier to use) CoTaskMemAlloc and CoTaskMemFree.
64370b324cSopenharmony_ci     Description from oldnewthings:
65370b324cSopenharmony_ci       shell functions could work without COM (if OLE32.DLL is not loaded),
66370b324cSopenharmony_ci       but now if OLE32.DLL is loaded, then shell functions and com functions do same things.
67370b324cSopenharmony_ci     22.02: so we use OLE32.DLL function to free memory:
68370b324cSopenharmony_ci  */
69370b324cSopenharmony_ci  /*
70370b324cSopenharmony_ci  CMyComPtr<IMalloc> shellMalloc;
71370b324cSopenharmony_ci  if (::SHGetMalloc(&shellMalloc) != NOERROR)
72370b324cSopenharmony_ci    throw 41099;
73370b324cSopenharmony_ci  shellMalloc->Free(m_Object);
74370b324cSopenharmony_ci  */
75370b324cSopenharmony_ci  CoTaskMemFree(m_Object);
76370b324cSopenharmony_ci  m_Object = NULL;
77370b324cSopenharmony_ci}
78370b324cSopenharmony_ci
79370b324cSopenharmony_ci/*
80370b324cSopenharmony_ciCItemIDList::(LPCITEMIDLIST itemIDList): m_Object(NULL)
81370b324cSopenharmony_ci  {  *this = itemIDList; }
82370b324cSopenharmony_ciCItemIDList::(const CItemIDList& itemIDList): m_Object(NULL)
83370b324cSopenharmony_ci  {  *this = itemIDList; }
84370b324cSopenharmony_ci
85370b324cSopenharmony_ciCItemIDList& CItemIDList::operator=(LPCITEMIDLIST object)
86370b324cSopenharmony_ci{
87370b324cSopenharmony_ci  Free();
88370b324cSopenharmony_ci  if (object != 0)
89370b324cSopenharmony_ci  {
90370b324cSopenharmony_ci    UINT32 size = GetSize(object);
91370b324cSopenharmony_ci    m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size);
92370b324cSopenharmony_ci    if (m_Object != NULL)
93370b324cSopenharmony_ci      MoveMemory(m_Object, object, size);
94370b324cSopenharmony_ci  }
95370b324cSopenharmony_ci  return *this;
96370b324cSopenharmony_ci}
97370b324cSopenharmony_ci
98370b324cSopenharmony_ciCItemIDList& CItemIDList::operator=(const CItemIDList &object)
99370b324cSopenharmony_ci{
100370b324cSopenharmony_ci  Free();
101370b324cSopenharmony_ci  if (object.m_Object != NULL)
102370b324cSopenharmony_ci  {
103370b324cSopenharmony_ci    UINT32 size = GetSize(object.m_Object);
104370b324cSopenharmony_ci    m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size);
105370b324cSopenharmony_ci    if (m_Object != NULL)
106370b324cSopenharmony_ci      MoveMemory(m_Object, object.m_Object, size);
107370b324cSopenharmony_ci  }
108370b324cSopenharmony_ci  return *this;
109370b324cSopenharmony_ci}
110370b324cSopenharmony_ci*/
111370b324cSopenharmony_ci
112370b324cSopenharmony_ci
113370b324cSopenharmony_cistatic HRESULT ReadUnicodeStrings(const wchar_t *p, size_t size, UStringVector &names)
114370b324cSopenharmony_ci{
115370b324cSopenharmony_ci  names.Clear();
116370b324cSopenharmony_ci  const wchar_t *lim = p + size;
117370b324cSopenharmony_ci  UString s;
118370b324cSopenharmony_ci  /*
119370b324cSopenharmony_ci  if (size == 0 || p[size - 1] != 0)
120370b324cSopenharmony_ci    return E_INVALIDARG;
121370b324cSopenharmony_ci  if (size == 1)
122370b324cSopenharmony_ci    return S_OK;
123370b324cSopenharmony_ci  if (p[size - 2] != 0)
124370b324cSopenharmony_ci    return E_INVALIDARG;
125370b324cSopenharmony_ci  */
126370b324cSopenharmony_ci  for (;;)
127370b324cSopenharmony_ci  {
128370b324cSopenharmony_ci    const wchar_t *start = p;
129370b324cSopenharmony_ci    for (;;)
130370b324cSopenharmony_ci    {
131370b324cSopenharmony_ci      if (p == lim) return E_INVALIDARG; // S_FALSE
132370b324cSopenharmony_ci      if (*p++ == 0)
133370b324cSopenharmony_ci        break;
134370b324cSopenharmony_ci    }
135370b324cSopenharmony_ci    const size_t num = (size_t)(p - start);
136370b324cSopenharmony_ci    if (num == 1)
137370b324cSopenharmony_ci    {
138370b324cSopenharmony_ci      if (p != lim) return E_INVALIDARG; // S_FALSE
139370b324cSopenharmony_ci      return S_OK;
140370b324cSopenharmony_ci    }
141370b324cSopenharmony_ci    s.SetFrom(start, (unsigned)(num - 1));
142370b324cSopenharmony_ci    ODS_U(s)
143370b324cSopenharmony_ci    names.Add(s);
144370b324cSopenharmony_ci    // names.ReserveOnePosition();
145370b324cSopenharmony_ci    // names.AddInReserved_Ptr_of_new(new UString((unsigned)num - 1, start));
146370b324cSopenharmony_ci  }
147370b324cSopenharmony_ci}
148370b324cSopenharmony_ci
149370b324cSopenharmony_ci
150370b324cSopenharmony_cistatic HRESULT ReadAnsiStrings(const char *p, size_t size, UStringVector &names)
151370b324cSopenharmony_ci{
152370b324cSopenharmony_ci  names.Clear();
153370b324cSopenharmony_ci  AString name;
154370b324cSopenharmony_ci  for (; size != 0; size--)
155370b324cSopenharmony_ci  {
156370b324cSopenharmony_ci    const char c = *p++;
157370b324cSopenharmony_ci    if (c == 0)
158370b324cSopenharmony_ci    {
159370b324cSopenharmony_ci      if (name.IsEmpty())
160370b324cSopenharmony_ci        return S_OK;
161370b324cSopenharmony_ci      names.Add(GetUnicodeString(name));
162370b324cSopenharmony_ci      name.Empty();
163370b324cSopenharmony_ci    }
164370b324cSopenharmony_ci    else
165370b324cSopenharmony_ci      name += c;
166370b324cSopenharmony_ci  }
167370b324cSopenharmony_ci  return E_INVALIDARG;
168370b324cSopenharmony_ci}
169370b324cSopenharmony_ci
170370b324cSopenharmony_ci
171370b324cSopenharmony_ci#define INIT_FORMATETC_HGLOBAL(type) { (type), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }
172370b324cSopenharmony_ci
173370b324cSopenharmony_cistatic HRESULT DataObject_GetData_HGLOBAL(IDataObject *dataObject, CLIPFORMAT cf, NCOM::CStgMedium &medium)
174370b324cSopenharmony_ci{
175370b324cSopenharmony_ci  FORMATETC etc = INIT_FORMATETC_HGLOBAL(cf);
176370b324cSopenharmony_ci  RINOK(dataObject->GetData(&etc, &medium))
177370b324cSopenharmony_ci  if (medium.tymed != TYMED_HGLOBAL)
178370b324cSopenharmony_ci    return E_INVALIDARG;
179370b324cSopenharmony_ci  return S_OK;
180370b324cSopenharmony_ci}
181370b324cSopenharmony_ci
182370b324cSopenharmony_cistatic HRESULT DataObject_GetData_HDROP_Names(IDataObject *dataObject, UStringVector &names)
183370b324cSopenharmony_ci{
184370b324cSopenharmony_ci  names.Clear();
185370b324cSopenharmony_ci  NCOM::CStgMedium medium;
186370b324cSopenharmony_ci
187370b324cSopenharmony_ci  /* Win10 : if (dataObject) is from IContextMenu::Initialize() and
188370b324cSopenharmony_ci    if (len_of_path >= MAX_PATH (260) for some file in data object)
189370b324cSopenharmony_ci    {
190370b324cSopenharmony_ci      GetData() returns HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
191370b324cSopenharmony_ci        "The data area passed to a system call is too small",
192370b324cSopenharmony_ci      Is there a way to fix this code for long paths?
193370b324cSopenharmony_ci    } */
194370b324cSopenharmony_ci
195370b324cSopenharmony_ci  RINOK(DataObject_GetData_HGLOBAL(dataObject, CF_HDROP, medium))
196370b324cSopenharmony_ci  const size_t blockSize = GlobalSize(medium.hGlobal);
197370b324cSopenharmony_ci  if (blockSize < sizeof(DROPFILES))
198370b324cSopenharmony_ci    return E_INVALIDARG;
199370b324cSopenharmony_ci  NMemory::CGlobalLock dropLock(medium.hGlobal);
200370b324cSopenharmony_ci  const DROPFILES *dropFiles = (const DROPFILES *)dropLock.GetPointer();
201370b324cSopenharmony_ci  if (!dropFiles)
202370b324cSopenharmony_ci    return E_INVALIDARG;
203370b324cSopenharmony_ci  if (blockSize < dropFiles->pFiles
204370b324cSopenharmony_ci      || dropFiles->pFiles < sizeof(DROPFILES)
205370b324cSopenharmony_ci      // || dropFiles->pFiles != sizeof(DROPFILES)
206370b324cSopenharmony_ci      )
207370b324cSopenharmony_ci    return E_INVALIDARG;
208370b324cSopenharmony_ci  const size_t size = blockSize - dropFiles->pFiles;
209370b324cSopenharmony_ci  const void *namesData = (const Byte *)(const void *)dropFiles + dropFiles->pFiles;
210370b324cSopenharmony_ci  HRESULT hres;
211370b324cSopenharmony_ci  if (dropFiles->fWide)
212370b324cSopenharmony_ci  {
213370b324cSopenharmony_ci    if (size % sizeof(wchar_t) != 0)
214370b324cSopenharmony_ci      return E_INVALIDARG;
215370b324cSopenharmony_ci    hres = ReadUnicodeStrings((const wchar_t *)namesData, size / sizeof(wchar_t), names);
216370b324cSopenharmony_ci  }
217370b324cSopenharmony_ci  else
218370b324cSopenharmony_ci    hres = ReadAnsiStrings((const char *)namesData, size, names);
219370b324cSopenharmony_ci
220370b324cSopenharmony_ci  ODS_(Print_Number(names.Size(), "DataObject_GetData_HDROP_Names"))
221370b324cSopenharmony_ci  return hres;
222370b324cSopenharmony_ci}
223370b324cSopenharmony_ci
224370b324cSopenharmony_ci
225370b324cSopenharmony_ci
226370b324cSopenharmony_ci// CF_IDLIST:
227370b324cSopenharmony_ci#define MYWIN_CFSTR_SHELLIDLIST  TEXT("Shell IDList Array")
228370b324cSopenharmony_ci
229370b324cSopenharmony_citypedef struct
230370b324cSopenharmony_ci{
231370b324cSopenharmony_ci  UINT cidl;
232370b324cSopenharmony_ci  UINT aoffset[1];
233370b324cSopenharmony_ci} MYWIN_CIDA;
234370b324cSopenharmony_ci/*
235370b324cSopenharmony_ci  cidl : number of PIDLs that are being transferred, not including the parent folder.
236370b324cSopenharmony_ci  aoffset : An array of offsets, relative to the beginning of this structure.
237370b324cSopenharmony_ci  aoffset[0] - fully qualified PIDL of a parent folder.
238370b324cSopenharmony_ci               If this PIDL is empty, the parent folder is the desktop.
239370b324cSopenharmony_ci  aoffset[1] ... aoffset[cidl] : offset to one of the PIDLs to be transferred.
240370b324cSopenharmony_ci  All of these PIDLs are relative to the PIDL of the parent folder.
241370b324cSopenharmony_ci*/
242370b324cSopenharmony_ci
243370b324cSopenharmony_cistatic HRESULT DataObject_GetData_IDLIST(IDataObject *dataObject, UStringVector &names)
244370b324cSopenharmony_ci{
245370b324cSopenharmony_ci  names.Clear();
246370b324cSopenharmony_ci  NCOM::CStgMedium medium;
247370b324cSopenharmony_ci  RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT)
248370b324cSopenharmony_ci      RegisterClipboardFormat(MYWIN_CFSTR_SHELLIDLIST), medium))
249370b324cSopenharmony_ci  const size_t blockSize = GlobalSize(medium.hGlobal);
250370b324cSopenharmony_ci  if (blockSize < sizeof(MYWIN_CIDA) || blockSize >= (UInt32)((UInt32)0 - 1))
251370b324cSopenharmony_ci    return E_INVALIDARG;
252370b324cSopenharmony_ci  NMemory::CGlobalLock dropLock(medium.hGlobal);
253370b324cSopenharmony_ci  const MYWIN_CIDA *cida = (const MYWIN_CIDA *)dropLock.GetPointer();
254370b324cSopenharmony_ci  if (!cida)
255370b324cSopenharmony_ci    return E_INVALIDARG;
256370b324cSopenharmony_ci  if (cida->cidl == 0)
257370b324cSopenharmony_ci  {
258370b324cSopenharmony_ci    // is it posssible to have no selected items?
259370b324cSopenharmony_ci    // it's unexpected case.
260370b324cSopenharmony_ci    return E_INVALIDARG;
261370b324cSopenharmony_ci  }
262370b324cSopenharmony_ci  if (cida->cidl >= (blockSize - (UInt32)sizeof(MYWIN_CIDA)) / sizeof(UINT))
263370b324cSopenharmony_ci    return E_INVALIDARG;
264370b324cSopenharmony_ci  const UInt32 start = cida->cidl * (UInt32)sizeof(UINT) + (UInt32)sizeof(MYWIN_CIDA);
265370b324cSopenharmony_ci
266370b324cSopenharmony_ci  STRRET strret;
267370b324cSopenharmony_ci  CMyComPtr<IShellFolder> parentFolder;
268370b324cSopenharmony_ci  {
269370b324cSopenharmony_ci    const UINT offset = cida->aoffset[0];
270370b324cSopenharmony_ci    if (offset < start || offset >= blockSize
271370b324cSopenharmony_ci        // || offset != start
272370b324cSopenharmony_ci        )
273370b324cSopenharmony_ci      return E_INVALIDARG;
274370b324cSopenharmony_ci
275370b324cSopenharmony_ci    CMyComPtr<IShellFolder> desktopFolder;
276370b324cSopenharmony_ci    RINOK(::SHGetDesktopFolder(&desktopFolder))
277370b324cSopenharmony_ci    if (!desktopFolder)
278370b324cSopenharmony_ci      return E_FAIL;
279370b324cSopenharmony_ci
280370b324cSopenharmony_ci    LPCITEMIDLIST const lpcItem = (LPCITEMIDLIST)(const void *)((const Byte *)cida + offset);
281370b324cSopenharmony_ci
282370b324cSopenharmony_ci   #ifdef SHOW_DEBUG_SHELL
283370b324cSopenharmony_ci    {
284370b324cSopenharmony_ci      const HRESULT res = desktopFolder->GetDisplayNameOf(
285370b324cSopenharmony_ci          lpcItem, SHGDN_FORPARSING, &strret);
286370b324cSopenharmony_ci      if (res == S_OK && strret.uType == STRRET_WSTR)
287370b324cSopenharmony_ci      {
288370b324cSopenharmony_ci        ODS_U(strret.pOleStr)
289370b324cSopenharmony_ci        /* if lpcItem is empty, the path will be
290370b324cSopenharmony_ci             "C:\Users\user_name\Desktop"
291370b324cSopenharmony_ci           if lpcItem is "My Computer" folder, the path will be
292370b324cSopenharmony_ci             "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" */
293370b324cSopenharmony_ci        CoTaskMemFree(strret.pOleStr);
294370b324cSopenharmony_ci      }
295370b324cSopenharmony_ci    }
296370b324cSopenharmony_ci   #endif
297370b324cSopenharmony_ci
298370b324cSopenharmony_ci    RINOK(desktopFolder->BindToObject(lpcItem,
299370b324cSopenharmony_ci        NULL, IID_IShellFolder, (void **)&parentFolder))
300370b324cSopenharmony_ci    if (!parentFolder)
301370b324cSopenharmony_ci      return E_FAIL;
302370b324cSopenharmony_ci  }
303370b324cSopenharmony_ci
304370b324cSopenharmony_ci  names.ClearAndReserve(cida->cidl);
305370b324cSopenharmony_ci  UString path;
306370b324cSopenharmony_ci
307370b324cSopenharmony_ci  // for (int y = 0; y < 1; y++) // for debug
308370b324cSopenharmony_ci  for (unsigned i = 1; i <= cida->cidl; i++)
309370b324cSopenharmony_ci  {
310370b324cSopenharmony_ci    const UINT offset = cida->aoffset[i];
311370b324cSopenharmony_ci    if (offset < start || offset >= blockSize)
312370b324cSopenharmony_ci      return E_INVALIDARG;
313370b324cSopenharmony_ci    const void *p = (const Byte *)(const void *)cida + offset;
314370b324cSopenharmony_ci    /* ITEMIDLIST of file can contain more than one SHITEMID item.
315370b324cSopenharmony_ci       In win10 only SHGDN_FORPARSING returns path that contains
316370b324cSopenharmony_ci       all path parts related to parts of ITEMIDLIST.
317370b324cSopenharmony_ci       So we can use only SHGDN_FORPARSING here.
318370b324cSopenharmony_ci       Don't use (SHGDN_INFOLDER)
319370b324cSopenharmony_ci       Don't use (SHGDN_INFOLDER | SHGDN_FORPARSING)
320370b324cSopenharmony_ci    */
321370b324cSopenharmony_ci    RINOK(parentFolder->GetDisplayNameOf((LPCITEMIDLIST)p, SHGDN_FORPARSING, &strret))
322370b324cSopenharmony_ci
323370b324cSopenharmony_ci    /*
324370b324cSopenharmony_ci    // MSVC6 and old SDK do not support StrRetToStrW().
325370b324cSopenharmony_ci    LPWSTR lpstr;
326370b324cSopenharmony_ci    RINOK (StrRetToStrW(&strret, NULL, &lpstr))
327370b324cSopenharmony_ci    ODS_U(lpstr)
328370b324cSopenharmony_ci    path = lpstr;
329370b324cSopenharmony_ci    CoTaskMemFree(lpstr);
330370b324cSopenharmony_ci    */
331370b324cSopenharmony_ci    if (strret.uType != STRRET_WSTR)
332370b324cSopenharmony_ci      return E_INVALIDARG;
333370b324cSopenharmony_ci    ODS_U(strret.pOleStr)
334370b324cSopenharmony_ci    path = strret.pOleStr;
335370b324cSopenharmony_ci    // the path could have super path prefix "\\\\?\\"
336370b324cSopenharmony_ci    // we can remove super path prefix here, if we don't need that prefix
337370b324cSopenharmony_ci  #ifdef Z7_LONG_PATH
338370b324cSopenharmony_ci    // we remove super prefix, if we can work without that prefix
339370b324cSopenharmony_ci    NFile::NName::If_IsSuperPath_RemoveSuperPrefix(path);
340370b324cSopenharmony_ci  #endif
341370b324cSopenharmony_ci    names.AddInReserved(path);
342370b324cSopenharmony_ci    CoTaskMemFree(strret.pOleStr);
343370b324cSopenharmony_ci  }
344370b324cSopenharmony_ci
345370b324cSopenharmony_ci  ODS_(Print_Number(cida->cidl, "CFSTR_SHELLIDLIST END"))
346370b324cSopenharmony_ci  return S_OK;
347370b324cSopenharmony_ci}
348370b324cSopenharmony_ci
349370b324cSopenharmony_ci
350370b324cSopenharmony_ciHRESULT DataObject_GetData_HDROP_or_IDLIST_Names(IDataObject *dataObject, UStringVector &paths)
351370b324cSopenharmony_ci{
352370b324cSopenharmony_ci  ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names START")
353370b324cSopenharmony_ci  HRESULT hres = NShell::DataObject_GetData_HDROP_Names(dataObject, paths);
354370b324cSopenharmony_ci  // if (hres == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
355370b324cSopenharmony_ci  if (hres != S_OK)
356370b324cSopenharmony_ci  {
357370b324cSopenharmony_ci    ODS("-- DataObject_GetData_IDLIST START")
358370b324cSopenharmony_ci    // for (int y = 0; y < 10000; y++) // for debug
359370b324cSopenharmony_ci    hres = NShell::DataObject_GetData_IDLIST(dataObject, paths);
360370b324cSopenharmony_ci  }
361370b324cSopenharmony_ci  ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names END")
362370b324cSopenharmony_ci  return hres;
363370b324cSopenharmony_ci}
364370b324cSopenharmony_ci
365370b324cSopenharmony_ci
366370b324cSopenharmony_ci
367370b324cSopenharmony_ci// #if (NTDDI_VERSION >= NTDDI_VISTA)
368370b324cSopenharmony_citypedef struct
369370b324cSopenharmony_ci{
370370b324cSopenharmony_ci  UINT cItems;                    // number of items in rgdwFileAttributes array
371370b324cSopenharmony_ci  DWORD dwSumFileAttributes;      // all of the attributes ORed together
372370b324cSopenharmony_ci  DWORD dwProductFileAttributes;  // all of the attributes ANDed together
373370b324cSopenharmony_ci  DWORD rgdwFileAttributes[1];    // array
374370b324cSopenharmony_ci} MYWIN_FILE_ATTRIBUTES_ARRAY;
375370b324cSopenharmony_ci
376370b324cSopenharmony_ci#define MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY  TEXT("File Attributes Array")
377370b324cSopenharmony_ci
378370b324cSopenharmony_ciHRESULT DataObject_GetData_FILE_ATTRS(IDataObject *dataObject, CFileAttribs &attribs)
379370b324cSopenharmony_ci{
380370b324cSopenharmony_ci  attribs.Clear();
381370b324cSopenharmony_ci  NCOM::CStgMedium medium;
382370b324cSopenharmony_ci  RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT)
383370b324cSopenharmony_ci      RegisterClipboardFormat(MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY), medium))
384370b324cSopenharmony_ci  const size_t blockSize = GlobalSize(medium.hGlobal);
385370b324cSopenharmony_ci  if (blockSize < sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY))
386370b324cSopenharmony_ci    return E_INVALIDARG;
387370b324cSopenharmony_ci  NMemory::CGlobalLock dropLock(medium.hGlobal);
388370b324cSopenharmony_ci  const MYWIN_FILE_ATTRIBUTES_ARRAY *faa = (const MYWIN_FILE_ATTRIBUTES_ARRAY *)dropLock.GetPointer();
389370b324cSopenharmony_ci  if (!faa)
390370b324cSopenharmony_ci    return E_INVALIDARG;
391370b324cSopenharmony_ci  const unsigned numFiles = faa->cItems;
392370b324cSopenharmony_ci  if (numFiles == 0)
393370b324cSopenharmony_ci  {
394370b324cSopenharmony_ci    // is it posssible to have empty array here?
395370b324cSopenharmony_ci    return E_INVALIDARG;
396370b324cSopenharmony_ci  }
397370b324cSopenharmony_ci  if ((blockSize - (sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY) - sizeof(DWORD)))
398370b324cSopenharmony_ci      / sizeof(DWORD) != numFiles)
399370b324cSopenharmony_ci    return E_INVALIDARG;
400370b324cSopenharmony_ci  // attribs.Sum = faa->dwSumFileAttributes;
401370b324cSopenharmony_ci  // attribs.Product = faa->dwProductFileAttributes;
402370b324cSopenharmony_ci  // attribs.Vals.SetFromArray(faa->rgdwFileAttributes, numFiles);
403370b324cSopenharmony_ci  // attribs.IsDirVector.ClearAndSetSize(numFiles);
404370b324cSopenharmony_ci
405370b324cSopenharmony_ci  if ((faa->dwSumFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
406370b324cSopenharmony_ci  {
407370b324cSopenharmony_ci    /* in win10: if selected items are volumes (c:\, d:\ ..) in  My Compter,
408370b324cSopenharmony_ci       all items have FILE_ATTRIBUTE_DIRECTORY attribute
409370b324cSopenharmony_ci       ntfs volume also have FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM
410370b324cSopenharmony_ci       udf volume: FILE_ATTRIBUTE_READONLY
411370b324cSopenharmony_ci       dvd-rom device: (-1) : all bits are set
412370b324cSopenharmony_ci    */
413370b324cSopenharmony_ci    const DWORD *attr = faa->rgdwFileAttributes;
414370b324cSopenharmony_ci    // DWORD product = (UInt32)0 - 1, sum = 0;
415370b324cSopenharmony_ci    for (unsigned i = 0; i < numFiles; i++)
416370b324cSopenharmony_ci    {
417370b324cSopenharmony_ci      if (attr[i] & FILE_ATTRIBUTE_DIRECTORY)
418370b324cSopenharmony_ci      {
419370b324cSopenharmony_ci        // attribs.ThereAreDirs = true;
420370b324cSopenharmony_ci        attribs.FirstDirIndex = (int)i;
421370b324cSopenharmony_ci        break;
422370b324cSopenharmony_ci      }
423370b324cSopenharmony_ci      // attribs.IsDirVector[i] = (attr[i] & FILE_ATTRIBUTE_DIRECTORY) != 0;
424370b324cSopenharmony_ci      // product &= v;
425370b324cSopenharmony_ci      // sum |= v;
426370b324cSopenharmony_ci    }
427370b324cSopenharmony_ci    // ODS_(Print_Number(product, "Product calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
428370b324cSopenharmony_ci    // ODS_(Print_Number(sum, "Sum calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
429370b324cSopenharmony_ci  }
430370b324cSopenharmony_ci  // ODS_(Print_Number(attribs.Product, "Product FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
431370b324cSopenharmony_ci  // ODS_(Print_Number(attribs.Sum, "Sum FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
432370b324cSopenharmony_ci  ODS_(Print_Number(numFiles, "FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
433370b324cSopenharmony_ci  return S_OK;
434370b324cSopenharmony_ci}
435370b324cSopenharmony_ci
436370b324cSopenharmony_ci
437370b324cSopenharmony_ci/////////////////////////////
438370b324cSopenharmony_ci// CDrop
439370b324cSopenharmony_ci
440370b324cSopenharmony_ci/*
441370b324cSopenharmony_ci  win10:
442370b324cSopenharmony_ci  DragQueryFile() implementation code is not effective because
443370b324cSopenharmony_ci  there is no pointer inside DROP internal file list, so
444370b324cSopenharmony_ci  DragQueryFile(fileIndex) runs all names in range [0, fileIndex].
445370b324cSopenharmony_ci  DragQueryFile(,, buf, bufSize)
446370b324cSopenharmony_ci  if (buf == NULL) by spec
447370b324cSopenharmony_ci  {
448370b324cSopenharmony_ci    returns value is the required size
449370b324cSopenharmony_ci    in characters, of the buffer, not including the terminating null character
450370b324cSopenharmony_ci    tests show that if (bufSize == 0), then it also returns  required size.
451370b324cSopenharmony_ci  }
452370b324cSopenharmony_ci  if (bufSize != NULL)
453370b324cSopenharmony_ci  {
454370b324cSopenharmony_ci    returns: the count of the characters copied, not including null character.
455370b324cSopenharmony_ci    win10: null character is also  copied at position buf[ret_count];
456370b324cSopenharmony_ci  }
457370b324cSopenharmony_ci*/
458370b324cSopenharmony_ci
459370b324cSopenharmony_ci/*
460370b324cSopenharmony_civoid CDrop::Attach(HDROP object)
461370b324cSopenharmony_ci{
462370b324cSopenharmony_ci  Free();
463370b324cSopenharmony_ci  m_Object = object;
464370b324cSopenharmony_ci  m_Assigned = true;
465370b324cSopenharmony_ci}
466370b324cSopenharmony_ci
467370b324cSopenharmony_civoid CDrop::Free()
468370b324cSopenharmony_ci{
469370b324cSopenharmony_ci  if (m_MustBeFinished && m_Assigned)
470370b324cSopenharmony_ci    Finish();
471370b324cSopenharmony_ci  m_Assigned = false;
472370b324cSopenharmony_ci}
473370b324cSopenharmony_ci
474370b324cSopenharmony_ciUINT CDrop::QueryCountOfFiles()
475370b324cSopenharmony_ci{
476370b324cSopenharmony_ci  return QueryFile(0xFFFFFFFF, (LPTSTR)NULL, 0);
477370b324cSopenharmony_ci}
478370b324cSopenharmony_ci
479370b324cSopenharmony_civoid CDrop::QueryFileName(UINT fileIndex, UString &fileName)
480370b324cSopenharmony_ci{
481370b324cSopenharmony_ci  #ifndef _UNICODE
482370b324cSopenharmony_ci  if (!g_IsNT)
483370b324cSopenharmony_ci  {
484370b324cSopenharmony_ci    AString fileNameA;
485370b324cSopenharmony_ci    const UINT len = QueryFile(fileIndex, (LPTSTR)NULL, 0);
486370b324cSopenharmony_ci    const UINT numCopied = QueryFile(fileIndex, fileNameA.GetBuf(len + 2), len + 2);
487370b324cSopenharmony_ci    fileNameA.ReleaseBuf_CalcLen(len);
488370b324cSopenharmony_ci    if (numCopied != len)
489370b324cSopenharmony_ci      throw 20221223;
490370b324cSopenharmony_ci    fileName = GetUnicodeString(fileNameA);
491370b324cSopenharmony_ci  }
492370b324cSopenharmony_ci  else
493370b324cSopenharmony_ci  #endif
494370b324cSopenharmony_ci  {
495370b324cSopenharmony_ci    // kReserve must be >= 3 for additional buffer size
496370b324cSopenharmony_ci    //   safety and for optimal performance
497370b324cSopenharmony_ci    const unsigned kReserve = 3;
498370b324cSopenharmony_ci    {
499370b324cSopenharmony_ci      unsigned len = 0;
500370b324cSopenharmony_ci      wchar_t *buf = fileName.GetBuf_GetMaxAvail(len);
501370b324cSopenharmony_ci      if (len >= kReserve)
502370b324cSopenharmony_ci      {
503370b324cSopenharmony_ci        const UINT numCopied = QueryFile(fileIndex, buf, len);
504370b324cSopenharmony_ci        if (numCopied < len - 1)
505370b324cSopenharmony_ci        {
506370b324cSopenharmony_ci          // (numCopied < len - 1) case means that it have copied full string.
507370b324cSopenharmony_ci          fileName.ReleaseBuf_CalcLen(numCopied);
508370b324cSopenharmony_ci          return;
509370b324cSopenharmony_ci        }
510370b324cSopenharmony_ci      }
511370b324cSopenharmony_ci    }
512370b324cSopenharmony_ci    const UINT len = QueryFile(fileIndex, (LPWSTR)NULL, 0);
513370b324cSopenharmony_ci    const UINT numCopied = QueryFile(fileIndex,
514370b324cSopenharmony_ci        fileName.GetBuf(len + kReserve), len + kReserve);
515370b324cSopenharmony_ci    fileName.ReleaseBuf_CalcLen(len);
516370b324cSopenharmony_ci    if (numCopied != len)
517370b324cSopenharmony_ci      throw 20221223;
518370b324cSopenharmony_ci  }
519370b324cSopenharmony_ci}
520370b324cSopenharmony_ci
521370b324cSopenharmony_ci
522370b324cSopenharmony_civoid CDrop::QueryFileNames(UStringVector &fileNames)
523370b324cSopenharmony_ci{
524370b324cSopenharmony_ci  UINT numFiles = QueryCountOfFiles();
525370b324cSopenharmony_ci
526370b324cSopenharmony_ci  Print_Number(numFiles, "\n====== CDrop::QueryFileNames START ===== \n");
527370b324cSopenharmony_ci
528370b324cSopenharmony_ci  fileNames.ClearAndReserve(numFiles);
529370b324cSopenharmony_ci  UString s;
530370b324cSopenharmony_ci  for (UINT i = 0; i < numFiles; i++)
531370b324cSopenharmony_ci  {
532370b324cSopenharmony_ci    QueryFileName(i, s);
533370b324cSopenharmony_ci    if (!s.IsEmpty())
534370b324cSopenharmony_ci      fileNames.AddInReserved(s);
535370b324cSopenharmony_ci  }
536370b324cSopenharmony_ci  Print_Number(numFiles, "\n====== CDrop::QueryFileNames END ===== \n");
537370b324cSopenharmony_ci}
538370b324cSopenharmony_ci*/
539370b324cSopenharmony_ci
540370b324cSopenharmony_ci
541370b324cSopenharmony_ci// #if (NTDDI_VERSION >= NTDDI_VISTA)
542370b324cSopenharmony_ci// SHGetPathFromIDListEx returns a win32 file system path for the item in the name space.
543370b324cSopenharmony_citypedef int Z7_WIN_GPFIDL_FLAGS;
544370b324cSopenharmony_ci
545370b324cSopenharmony_ciextern "C" {
546370b324cSopenharmony_citypedef BOOL (WINAPI * Func_SHGetPathFromIDListW)(LPCITEMIDLIST pidl, LPWSTR pszPath);
547370b324cSopenharmony_citypedef BOOL (WINAPI * Func_SHGetPathFromIDListEx)(LPCITEMIDLIST pidl, PWSTR pszPath, DWORD cchPath, Z7_WIN_GPFIDL_FLAGS uOpts);
548370b324cSopenharmony_ci}
549370b324cSopenharmony_ci
550370b324cSopenharmony_ci#ifndef _UNICODE
551370b324cSopenharmony_ci
552370b324cSopenharmony_cibool GetPathFromIDList(LPCITEMIDLIST itemIDList, AString &path)
553370b324cSopenharmony_ci{
554370b324cSopenharmony_ci  path.Empty();
555370b324cSopenharmony_ci  const unsigned len = MAX_PATH + 16;
556370b324cSopenharmony_ci  const bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len)));
557370b324cSopenharmony_ci  path.ReleaseBuf_CalcLen(len);
558370b324cSopenharmony_ci  return result;
559370b324cSopenharmony_ci}
560370b324cSopenharmony_ci
561370b324cSopenharmony_ci#endif
562370b324cSopenharmony_ci
563370b324cSopenharmony_cibool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path)
564370b324cSopenharmony_ci{
565370b324cSopenharmony_ci  path.Empty();
566370b324cSopenharmony_ci  unsigned len = MAX_PATH + 16;
567370b324cSopenharmony_ci
568370b324cSopenharmony_ci#ifdef _UNICODE
569370b324cSopenharmony_ci  bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len)));
570370b324cSopenharmony_ci#else
571370b324cSopenharmony_ci  const
572370b324cSopenharmony_ci  Func_SHGetPathFromIDListW
573370b324cSopenharmony_ci       shGetPathFromIDListW = Z7_GET_PROC_ADDRESS(
574370b324cSopenharmony_ci  Func_SHGetPathFromIDListW, ::GetModuleHandleW(L"shell32.dll"),
575370b324cSopenharmony_ci      "SHGetPathFromIDListW");
576370b324cSopenharmony_ci  if (!shGetPathFromIDListW)
577370b324cSopenharmony_ci    return false;
578370b324cSopenharmony_ci  bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len)));
579370b324cSopenharmony_ci#endif
580370b324cSopenharmony_ci
581370b324cSopenharmony_ci  if (!result)
582370b324cSopenharmony_ci  {
583370b324cSopenharmony_ci    ODS("==== GetPathFromIDList() SHGetPathFromIDList() returned false")
584370b324cSopenharmony_ci    /* for long path we need SHGetPathFromIDListEx().
585370b324cSopenharmony_ci      win10: SHGetPathFromIDListEx() for long path returns path with
586370b324cSopenharmony_ci             with super path prefix "\\\\?\\". */
587370b324cSopenharmony_ci    const
588370b324cSopenharmony_ci    Func_SHGetPathFromIDListEx
589370b324cSopenharmony_ci    func_SHGetPathFromIDListEx = Z7_GET_PROC_ADDRESS(
590370b324cSopenharmony_ci    Func_SHGetPathFromIDListEx, ::GetModuleHandleW(L"shell32.dll"),
591370b324cSopenharmony_ci        "SHGetPathFromIDListEx");
592370b324cSopenharmony_ci    if (func_SHGetPathFromIDListEx)
593370b324cSopenharmony_ci    {
594370b324cSopenharmony_ci      ODS("==== GetPathFromIDList() (SHGetPathFromIDListEx)")
595370b324cSopenharmony_ci      do
596370b324cSopenharmony_ci      {
597370b324cSopenharmony_ci        len *= 4;
598370b324cSopenharmony_ci        result = BOOLToBool(func_SHGetPathFromIDListEx(itemIDList, path.GetBuf(len), len, 0));
599370b324cSopenharmony_ci        if (result)
600370b324cSopenharmony_ci          break;
601370b324cSopenharmony_ci      }
602370b324cSopenharmony_ci      while (len <= (1 << 16));
603370b324cSopenharmony_ci    }
604370b324cSopenharmony_ci  }
605370b324cSopenharmony_ci
606370b324cSopenharmony_ci  path.ReleaseBuf_CalcLen(len);
607370b324cSopenharmony_ci  return result;
608370b324cSopenharmony_ci}
609370b324cSopenharmony_ci
610370b324cSopenharmony_ci#endif
611370b324cSopenharmony_ci
612370b324cSopenharmony_ci#ifdef UNDER_CE
613370b324cSopenharmony_ci
614370b324cSopenharmony_cibool BrowseForFolder(LPBROWSEINFO, CSysString)
615370b324cSopenharmony_ci{
616370b324cSopenharmony_ci  return false;
617370b324cSopenharmony_ci}
618370b324cSopenharmony_ci
619370b324cSopenharmony_cibool BrowseForFolder(HWND, LPCTSTR, UINT, LPCTSTR, CSysString &)
620370b324cSopenharmony_ci{
621370b324cSopenharmony_ci  return false;
622370b324cSopenharmony_ci}
623370b324cSopenharmony_ci
624370b324cSopenharmony_cibool BrowseForFolder(HWND /* owner */, LPCTSTR /* title */,
625370b324cSopenharmony_ci    LPCTSTR /* initialFolder */, CSysString & /* resultPath */)
626370b324cSopenharmony_ci{
627370b324cSopenharmony_ci  /*
628370b324cSopenharmony_ci  // SHBrowseForFolder doesn't work before CE 6.0 ?
629370b324cSopenharmony_ci  if (GetProcAddress(LoadLibrary(L"ceshell.dll", L"SHBrowseForFolder") == 0)
630370b324cSopenharmony_ci    MessageBoxW(0, L"no", L"", 0);
631370b324cSopenharmony_ci  else
632370b324cSopenharmony_ci    MessageBoxW(0, L"yes", L"", 0);
633370b324cSopenharmony_ci  */
634370b324cSopenharmony_ci  /*
635370b324cSopenharmony_ci  UString s = "all files";
636370b324cSopenharmony_ci  s += " (*.*)";
637370b324cSopenharmony_ci  return MyGetOpenFileName(owner, title, initialFolder, s, resultPath, true);
638370b324cSopenharmony_ci  */
639370b324cSopenharmony_ci  return false;
640370b324cSopenharmony_ci}
641370b324cSopenharmony_ci
642370b324cSopenharmony_ci#else
643370b324cSopenharmony_ci
644370b324cSopenharmony_ci/* win10: SHBrowseForFolder() doesn't support long paths,
645370b324cSopenharmony_ci   even if long path suppport is enabled in registry and in manifest.
646370b324cSopenharmony_ci   and SHBrowseForFolder() doesn't support super path prefix "\\\\?\\". */
647370b324cSopenharmony_ci
648370b324cSopenharmony_cibool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath)
649370b324cSopenharmony_ci{
650370b324cSopenharmony_ci  resultPath.Empty();
651370b324cSopenharmony_ci  NWindows::NCOM::CComInitializer comInitializer;
652370b324cSopenharmony_ci  LPITEMIDLIST itemIDList = ::SHBrowseForFolder(browseInfo);
653370b324cSopenharmony_ci  if (!itemIDList)
654370b324cSopenharmony_ci    return false;
655370b324cSopenharmony_ci  CItemIDList itemIDListHolder;
656370b324cSopenharmony_ci  itemIDListHolder.Attach(itemIDList);
657370b324cSopenharmony_ci  return GetPathFromIDList(itemIDList, resultPath);
658370b324cSopenharmony_ci}
659370b324cSopenharmony_ci
660370b324cSopenharmony_ci
661370b324cSopenharmony_cistatic int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data)
662370b324cSopenharmony_ci{
663370b324cSopenharmony_ci  #ifndef UNDER_CE
664370b324cSopenharmony_ci  switch (uMsg)
665370b324cSopenharmony_ci  {
666370b324cSopenharmony_ci    case BFFM_INITIALIZED:
667370b324cSopenharmony_ci    {
668370b324cSopenharmony_ci      SendMessage(hwnd, BFFM_SETSELECTION, TRUE, data);
669370b324cSopenharmony_ci      break;
670370b324cSopenharmony_ci    }
671370b324cSopenharmony_ci    /*
672370b324cSopenharmony_ci    case BFFM_SELCHANGED:
673370b324cSopenharmony_ci    {
674370b324cSopenharmony_ci      TCHAR dir[MAX_PATH];
675370b324cSopenharmony_ci      if (::SHGetPathFromIDList((LPITEMIDLIST) lp , dir))
676370b324cSopenharmony_ci        SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)dir);
677370b324cSopenharmony_ci      else
678370b324cSopenharmony_ci        SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)TEXT(""));
679370b324cSopenharmony_ci      break;
680370b324cSopenharmony_ci    }
681370b324cSopenharmony_ci    */
682370b324cSopenharmony_ci    default:
683370b324cSopenharmony_ci      break;
684370b324cSopenharmony_ci  }
685370b324cSopenharmony_ci  #endif
686370b324cSopenharmony_ci  return 0;
687370b324cSopenharmony_ci}
688370b324cSopenharmony_ci
689370b324cSopenharmony_ci
690370b324cSopenharmony_cistatic bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags,
691370b324cSopenharmony_ci    LPCTSTR initialFolder, CSysString &resultPath)
692370b324cSopenharmony_ci{
693370b324cSopenharmony_ci  CSysString displayName;
694370b324cSopenharmony_ci  BROWSEINFO browseInfo;
695370b324cSopenharmony_ci  browseInfo.hwndOwner = owner;
696370b324cSopenharmony_ci  browseInfo.pidlRoot = NULL;
697370b324cSopenharmony_ci
698370b324cSopenharmony_ci  // there are Unicode/Astring problems in some WinCE SDK ?
699370b324cSopenharmony_ci  /*
700370b324cSopenharmony_ci  #ifdef UNDER_CE
701370b324cSopenharmony_ci  browseInfo.pszDisplayName = (LPSTR)displayName.GetBuf(MAX_PATH);
702370b324cSopenharmony_ci  browseInfo.lpszTitle = (LPCSTR)title;
703370b324cSopenharmony_ci  #else
704370b324cSopenharmony_ci  */
705370b324cSopenharmony_ci  browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH);
706370b324cSopenharmony_ci  browseInfo.lpszTitle = title;
707370b324cSopenharmony_ci  // #endif
708370b324cSopenharmony_ci  browseInfo.ulFlags = ulFlags;
709370b324cSopenharmony_ci  browseInfo.lpfn = initialFolder ? BrowseCallbackProc : NULL;
710370b324cSopenharmony_ci  browseInfo.lParam = (LPARAM)initialFolder;
711370b324cSopenharmony_ci  return BrowseForFolder(&browseInfo, resultPath);
712370b324cSopenharmony_ci}
713370b324cSopenharmony_ci
714370b324cSopenharmony_ci#ifdef Z7_OLD_WIN_SDK
715370b324cSopenharmony_ci// ShlObj.h:
716370b324cSopenharmony_ci#ifndef BIF_NEWDIALOGSTYLE
717370b324cSopenharmony_ci#define BIF_NEWDIALOGSTYLE     0x0040
718370b324cSopenharmony_ci#endif
719370b324cSopenharmony_ci#endif
720370b324cSopenharmony_ci
721370b324cSopenharmony_cibool BrowseForFolder(HWND owner, LPCTSTR title,
722370b324cSopenharmony_ci    LPCTSTR initialFolder, CSysString &resultPath)
723370b324cSopenharmony_ci{
724370b324cSopenharmony_ci  return BrowseForFolder(owner, title,
725370b324cSopenharmony_ci      #ifndef UNDER_CE
726370b324cSopenharmony_ci      BIF_NEWDIALOGSTYLE |
727370b324cSopenharmony_ci      #endif
728370b324cSopenharmony_ci      BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT, initialFolder, resultPath);
729370b324cSopenharmony_ci  // BIF_STATUSTEXT; BIF_USENEWUI   (Version 5.0)
730370b324cSopenharmony_ci}
731370b324cSopenharmony_ci
732370b324cSopenharmony_ci#ifndef _UNICODE
733370b324cSopenharmony_ci
734370b324cSopenharmony_ciextern "C" {
735370b324cSopenharmony_citypedef LPITEMIDLIST (WINAPI * Func_SHBrowseForFolderW)(LPBROWSEINFOW lpbi);
736370b324cSopenharmony_ci}
737370b324cSopenharmony_ci
738370b324cSopenharmony_cistatic bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath)
739370b324cSopenharmony_ci{
740370b324cSopenharmony_ci  NWindows::NCOM::CComInitializer comInitializer;
741370b324cSopenharmony_ci  const
742370b324cSopenharmony_ci  Func_SHBrowseForFolderW
743370b324cSopenharmony_ci     f_SHBrowseForFolderW = Z7_GET_PROC_ADDRESS(
744370b324cSopenharmony_ci  Func_SHBrowseForFolderW, ::GetModuleHandleW(L"shell32.dll"),
745370b324cSopenharmony_ci      "SHBrowseForFolderW");
746370b324cSopenharmony_ci  if (!f_SHBrowseForFolderW)
747370b324cSopenharmony_ci    return false;
748370b324cSopenharmony_ci  LPITEMIDLIST itemIDList = f_SHBrowseForFolderW(browseInfo);
749370b324cSopenharmony_ci  if (!itemIDList)
750370b324cSopenharmony_ci    return false;
751370b324cSopenharmony_ci  CItemIDList itemIDListHolder;
752370b324cSopenharmony_ci  itemIDListHolder.Attach(itemIDList);
753370b324cSopenharmony_ci  return GetPathFromIDList(itemIDList, resultPath);
754370b324cSopenharmony_ci}
755370b324cSopenharmony_ci
756370b324cSopenharmony_cistatic
757370b324cSopenharmony_ciint CALLBACK BrowseCallbackProc2(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data)
758370b324cSopenharmony_ci{
759370b324cSopenharmony_ci  switch (uMsg)
760370b324cSopenharmony_ci  {
761370b324cSopenharmony_ci    case BFFM_INITIALIZED:
762370b324cSopenharmony_ci    {
763370b324cSopenharmony_ci      SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, data);
764370b324cSopenharmony_ci      break;
765370b324cSopenharmony_ci    }
766370b324cSopenharmony_ci    /*
767370b324cSopenharmony_ci    case BFFM_SELCHANGED:
768370b324cSopenharmony_ci    {
769370b324cSopenharmony_ci      wchar_t dir[MAX_PATH * 2];
770370b324cSopenharmony_ci
771370b324cSopenharmony_ci      if (shGetPathFromIDListW((LPITEMIDLIST)lp , dir))
772370b324cSopenharmony_ci        SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir);
773370b324cSopenharmony_ci      else
774370b324cSopenharmony_ci        SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)L"");
775370b324cSopenharmony_ci      break;
776370b324cSopenharmony_ci    }
777370b324cSopenharmony_ci    */
778370b324cSopenharmony_ci    default:
779370b324cSopenharmony_ci      break;
780370b324cSopenharmony_ci  }
781370b324cSopenharmony_ci  return 0;
782370b324cSopenharmony_ci}
783370b324cSopenharmony_ci
784370b324cSopenharmony_ci
785370b324cSopenharmony_cistatic bool BrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags,
786370b324cSopenharmony_ci    LPCWSTR initialFolder, UString &resultPath)
787370b324cSopenharmony_ci{
788370b324cSopenharmony_ci  UString displayName;
789370b324cSopenharmony_ci  BROWSEINFOW browseInfo;
790370b324cSopenharmony_ci  browseInfo.hwndOwner = owner;
791370b324cSopenharmony_ci  browseInfo.pidlRoot = NULL;
792370b324cSopenharmony_ci  browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH);
793370b324cSopenharmony_ci  browseInfo.lpszTitle = title;
794370b324cSopenharmony_ci  browseInfo.ulFlags = ulFlags;
795370b324cSopenharmony_ci  browseInfo.lpfn = initialFolder ? BrowseCallbackProc2 : NULL;
796370b324cSopenharmony_ci  browseInfo.lParam = (LPARAM)initialFolder;
797370b324cSopenharmony_ci  return BrowseForFolder(&browseInfo, resultPath);
798370b324cSopenharmony_ci}
799370b324cSopenharmony_ci
800370b324cSopenharmony_cibool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath)
801370b324cSopenharmony_ci{
802370b324cSopenharmony_ci  if (g_IsNT)
803370b324cSopenharmony_ci    return BrowseForFolder(owner, title,
804370b324cSopenharmony_ci      BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS
805370b324cSopenharmony_ci      //  | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified.
806370b324cSopenharmony_ci      , initialFolder, resultPath);
807370b324cSopenharmony_ci  // BIF_STATUSTEXT; BIF_USENEWUI   (Version 5.0)
808370b324cSopenharmony_ci  CSysString s;
809370b324cSopenharmony_ci  bool res = BrowseForFolder(owner, GetSystemString(title),
810370b324cSopenharmony_ci      BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS
811370b324cSopenharmony_ci      // | BIF_STATUSTEXT  // This flag is not supported when BIF_NEWDIALOGSTYLE is specified.
812370b324cSopenharmony_ci      , GetSystemString(initialFolder), s);
813370b324cSopenharmony_ci  resultPath = GetUnicodeString(s);
814370b324cSopenharmony_ci  return res;
815370b324cSopenharmony_ci}
816370b324cSopenharmony_ci
817370b324cSopenharmony_ci#endif
818370b324cSopenharmony_ci
819370b324cSopenharmony_ci#endif
820370b324cSopenharmony_ci
821370b324cSopenharmony_ci}}
822