Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192/* * PROJECT: shell32 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) * PURPOSE: Utility functions * COPYRIGHT: Copyright 2023-2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> */
#include "precomp.h"#include <lmcons.h>#include <lmapibuf.h>#include <lmaccess.h>#include <lmserver.h>#include <secext.h>
WINE_DEFAULT_DEBUG_CHANNEL(shell);
static PCSTR StrEndNA(_In_ PCSTR psz, _In_ INT_PTR cch){ PCSTR pch, pchEnd = &psz[cch]; for (pch = psz; *pch && pch < pchEnd; pch = CharNextA(pch)) ; if (pchEnd < pch) // A double-byte character detected at last? pch -= 2; // The width of a double-byte character is 2 return pch;}
static PCWSTR StrEndNW(_In_ PCWSTR psz, _In_ INT_PTR cch){ PCWSTR pch, pchEnd = &psz[cch]; for (pch = psz; *pch && pch < pchEnd; ++pch) ; return pch;}
/************************************************************************* * StrRStrA [SHELL32.389] */EXTERN_CPSTR WINAPIStrRStrA( _In_ PCSTR pszSrc, _In_opt_ PCSTR pszLast, _In_ PCSTR pszSearch){ INT cchSearch = lstrlenA(pszSearch);
PCSTR pchEnd = pszLast ? pszLast : &pszSrc[lstrlenA(pszSrc)]; if (pchEnd == pszSrc) return NULL;
INT_PTR cchEnd = pchEnd - pszSrc; for (;;) { --pchEnd; --cchEnd; if (!pchEnd) break; if (!StrCmpNA(pchEnd, pszSearch, cchSearch) && pchEnd == StrEndNA(pszSrc, cchEnd)) break; if (pchEnd == pszSrc) return NULL; }
return const_cast<PSTR>(pchEnd);}
/************************************************************************* * StrRStrW [SHELL32.392] */EXTERN_CPWSTR WINAPIStrRStrW( _In_ PCWSTR pszSrc, _In_opt_ PCWSTR pszLast, _In_ PCWSTR pszSearch){ INT cchSearch = lstrlenW(pszSearch);
PCWSTR pchEnd = pszLast ? pszLast : &pszSrc[lstrlenW(pszSrc)]; if (pchEnd == pszSrc) return NULL;
INT_PTR cchEnd = pchEnd - pszSrc; for (;;) { --pchEnd; --cchEnd; if (!pchEnd) break; if (!StrCmpNW(pchEnd, pszSearch, cchSearch) && pchEnd == StrEndNW(pszSrc, cchEnd)) break; if (pchEnd == pszSrc) return NULL; }
return const_cast<PWSTR>(pchEnd);}
HWNDCStubWindow32::FindStubWindow(UINT Type, LPCWSTR Path){ for (HWND hWnd, hWndAfter = NULL;;) { hWnd = hWndAfter = FindWindowExW(NULL, hWndAfter, CSTUBWINDOW32_CLASSNAME, Path); if (!hWnd || !Path) return NULL; if (GetPropW(hWnd, GetTypePropName()) == ULongToHandle(Type)) return hWnd; }}
HRESULTCStubWindow32::CreateStub(UINT Type, LPCWSTR Path, const POINT *pPt){ if (HWND hWnd = FindStubWindow(Type, Path)) { ::SwitchToThisWindow(::GetLastActivePopup(hWnd), TRUE); return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); } RECT rcPosition = { pPt ? pPt->x : CW_USEDEFAULT, pPt ? pPt->y : CW_USEDEFAULT, 0, 0 }; DWORD Style = WS_DISABLED | WS_CLIPSIBLINGS | WS_CAPTION; DWORD ExStyle = WS_EX_WINDOWEDGE | WS_EX_APPWINDOW; if (!Create(NULL, rcPosition, Path, Style, ExStyle)) { ERR("StubWindow32 creation failed\n"); return E_FAIL; } ::SetPropW(*this, GetTypePropName(), ULongToHandle(Type)); return S_OK;}
HRESULTSHILClone( _In_opt_ LPCITEMIDLIST pidl, _Outptr_ LPITEMIDLIST *ppidl){ if (!pidl) { *ppidl = NULL; return S_OK; } *ppidl = ILClone(pidl); return (*ppidl ? S_OK : E_OUTOFMEMORY);}
BOOL PathIsDotOrDotDotW(_In_ LPCWSTR pszPath){ if (pszPath[0] != L'.') return FALSE; return !pszPath[1] || (pszPath[1] == L'.' && !pszPath[2]);}
#define PATH_VALID_ELEMENT ( \ PATH_CHAR_CLASS_DOT | PATH_CHAR_CLASS_SEMICOLON | PATH_CHAR_CLASS_COMMA | \ PATH_CHAR_CLASS_SPACE | PATH_CHAR_CLASS_OTHER_VALID \)
BOOL PathIsValidElement(_In_ LPCWSTR pszPath){ if (!*pszPath || PathIsDotOrDotDotW(pszPath)) return FALSE;
for (LPCWSTR pch = pszPath; *pch; ++pch) { if (!PathIsValidCharW(*pch, PATH_VALID_ELEMENT)) return FALSE; }
return TRUE;}
BOOL PathIsDosDevice(_In_ LPCWSTR pszName){ WCHAR szPath[MAX_PATH]; StringCchCopyW(szPath, _countof(szPath), pszName); PathRemoveExtensionW(szPath);
if (lstrcmpiW(szPath, L"NUL") == 0 || lstrcmpiW(szPath, L"PRN") == 0 || lstrcmpiW(szPath, L"CON") == 0 || lstrcmpiW(szPath, L"AUX") == 0) { return TRUE; }
if (_wcsnicmp(szPath, L"LPT", 3) == 0 || _wcsnicmp(szPath, L"COM", 3) == 0) { if ((L'0' <= szPath[3] && szPath[3] <= L'9') && szPath[4] == UNICODE_NULL) return TRUE; }
return FALSE;}
HRESULT SHILAppend(_Inout_ LPITEMIDLIST pidl, _Inout_ LPITEMIDLIST *ppidl){ LPITEMIDLIST pidlOld = *ppidl; if (!pidlOld) { *ppidl = pidl; return S_OK; }
HRESULT hr = SHILCombine(*ppidl, pidl, ppidl); ILFree(pidlOld); ILFree(pidl); return hr;}
/************************************************************************* * SHShouldShowWizards [SHELL32.237] * * Used by printer and network features. * @see https://undoc.airesoft.co.uk/shell32.dll/SHShouldShowWizards.php */EXTERN_CHRESULT WINAPISHShouldShowWizards(_In_ IUnknown *pUnknown){ HRESULT hr; IShellBrowser *pBrowser;
hr = IUnknown_QueryService(pUnknown, SID_STopWindow, IID_PPV_ARG(IShellBrowser, &pBrowser)); if (FAILED(hr)) return hr;
SHELLSTATE state; SHGetSetSettings(&state, SSF_WEBVIEW, FALSE); if (state.fWebView && !SHRegGetBoolUSValueW(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", L"ShowWizardsTEST", FALSE, FALSE)) { hr = S_FALSE; }
pBrowser->Release(); return hr;}
static BOOLOpenEffectiveToken( _In_ DWORD DesiredAccess, _Out_ HANDLE *phToken){ BOOL ret;
if (phToken == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
*phToken = NULL;
ret = OpenThreadToken(GetCurrentThread(), DesiredAccess, FALSE, phToken); if (!ret && GetLastError() == ERROR_NO_TOKEN) ret = OpenProcessToken(GetCurrentProcess(), DesiredAccess, phToken);
return ret;}
BOOL BindCtx_ContainsObject(_In_ IBindCtx *pBindCtx, _In_ LPCWSTR pszName){ CComPtr<IUnknown> punk; if (!pBindCtx || FAILED(pBindCtx->GetObjectParam(const_cast<LPWSTR>(pszName), &punk))) return FALSE; return TRUE;}
DWORD BindCtx_GetMode(_In_ IBindCtx *pbc, _In_ DWORD dwDefault){ if (!pbc) return dwDefault;
BIND_OPTS BindOpts = { sizeof(BindOpts) }; HRESULT hr = pbc->GetBindOptions(&BindOpts); if (FAILED(hr)) return dwDefault;
return BindOpts.grfMode;}
BOOL SHSkipJunctionBinding(_In_ IBindCtx *pbc, _In_ CLSID *pclsid){ if (!pbc) return FALSE;
BIND_OPTS BindOps = { sizeof(BindOps) }; if (SUCCEEDED(pbc->GetBindOptions(&BindOps)) && BindOps.grfFlags == OLECONTF_LINKS) return TRUE;
return pclsid && SHSkipJunction(pbc, pclsid);}
HRESULT SHIsFileSysBindCtx(_In_ IBindCtx *pBindCtx, _Out_opt_ WIN32_FIND_DATAW *pFindData){ CComPtr<IUnknown> punk; CComPtr<IFileSystemBindData> pBindData;
if (!pBindCtx || FAILED(pBindCtx->GetObjectParam((LPWSTR)STR_FILE_SYS_BIND_DATA, &punk))) return S_FALSE;
if (FAILED(punk->QueryInterface(IID_PPV_ARG(IFileSystemBindData, &pBindData)))) return S_FALSE;
if (pFindData) pBindData->GetFindData(pFindData);
return S_OK;}
BOOL Shell_FailForceReturn(_In_ HRESULT hr){ DWORD code = HRESULT_CODE(hr);
switch (code) { case ERROR_BAD_NETPATH: case ERROR_BAD_NET_NAME: case ERROR_CANCELLED: return TRUE;
default: return (ERROR_FILE_NOT_FOUND <= code && code <= ERROR_PATH_NOT_FOUND); }}
HRESULTSHBindToObjectEx( _In_opt_ IShellFolder *pShellFolder, _In_ LPCITEMIDLIST pidl, _In_opt_ IBindCtx *pBindCtx, _In_ REFIID riid, _Out_ void **ppvObj){ CComPtr<IShellFolder> psfDesktop;
*ppvObj = NULL;
if (!pShellFolder) { SHGetDesktopFolder(&psfDesktop); if (!psfDesktop) return E_FAIL;
pShellFolder = psfDesktop; }
HRESULT hr; if (_ILIsDesktop(pidl)) hr = pShellFolder->QueryInterface(riid, ppvObj); else hr = pShellFolder->BindToObject(pidl, pBindCtx, riid, ppvObj);
if (SUCCEEDED(hr) && !*ppvObj) hr = E_FAIL;
return hr;}
EXTERN_CHRESULT SHBindToObject( _In_opt_ IShellFolder *psf, _In_ LPCITEMIDLIST pidl, _In_ REFIID riid, _Out_ void **ppvObj){ return SHBindToObjectEx(psf, pidl, NULL, riid, ppvObj);}
EXTERN_C HRESULTSHELL_GetUIObjectOfAbsoluteItem( _In_opt_ HWND hWnd, _In_ PCIDLIST_ABSOLUTE pidl, _In_ REFIID riid, _Out_ void **ppvObj){ if (!ppvObj) return E_INVALIDARG; *ppvObj = NULL; IShellFolder *psf; PCUITEMID_CHILD pidlChild; HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild); if (SUCCEEDED(hr)) { hr = psf->GetUIObjectOf(hWnd, 1, &pidlChild, riid, NULL, ppvObj); psf->Release(); if (SUCCEEDED(hr)) { if (*ppvObj) return hr; hr = E_FAIL; } } return hr;}
HRESULTSHELL_DisplayNameOf( _In_opt_ IShellFolder *psf, _In_ LPCITEMIDLIST pidl, _In_opt_ UINT Flags, _Out_ PWSTR *ppStr){ HRESULT hr; CComPtr<IShellFolder> psfRoot; if (!psf) { PCUITEMID_CHILD pidlChild; hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psfRoot), &pidlChild); if (FAILED(hr)) return hr; psf = psfRoot; pidl = pidlChild; } STRRET sr; hr = psf->GetDisplayNameOf((PCUITEMID_CHILD)pidl, Flags, &sr); return SUCCEEDED(hr) ? StrRetToStrW(&sr, pidl, ppStr) : hr;}
/*********************************************************************** * DisplayNameOfW [SHELL32.757] (Vista+) */EXTERN_C HRESULT WINAPIDisplayNameOfW( _In_ IShellFolder *psf, _In_ LPCITEMIDLIST pidl, _In_ DWORD dwFlags, _Out_ LPWSTR pszBuf, _In_ UINT cchBuf){ *pszBuf = UNICODE_NULL; STRRET sr; HRESULT hr = psf->GetDisplayNameOf(pidl, dwFlags, &sr); if (FAILED(hr)) return hr; return StrRetToBufW(&sr, pidl, pszBuf, cchBuf);}
DWORDSHGetAttributes(_In_ IShellFolder *psf, _In_ LPCITEMIDLIST pidl, _In_ DWORD dwAttributes){ LPCITEMIDLIST pidlLast = pidl; IShellFolder *release = NULL;
if (!psf) { SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast); if (!psf) return 0; release = psf; }
DWORD oldAttrs = dwAttributes; if (FAILED(psf->GetAttributesOf(1, &pidlLast, &dwAttributes))) dwAttributes = 0; else dwAttributes &= oldAttrs;
if ((dwAttributes & SFGAO_FOLDER) && (dwAttributes & SFGAO_STREAM) && !(dwAttributes & SFGAO_STORAGEANCESTOR) && (oldAttrs & SFGAO_STORAGEANCESTOR) && (SHGetObjectCompatFlags(psf, NULL) & 0x200)) { dwAttributes &= ~(SFGAO_STREAM | SFGAO_STORAGEANCESTOR); dwAttributes |= SFGAO_STORAGEANCESTOR; }
if (release) release->Release(); return dwAttributes;}
HRESULT SHELL_GetIDListTarget(_In_ LPCITEMIDLIST pidl, _Out_ PIDLIST_ABSOLUTE *ppidl){ IShellLink *pSL; HRESULT hr = SHBindToObject(NULL, pidl, IID_PPV_ARG(IShellLink, &pSL)); if (SUCCEEDED(hr)) { hr = pSL->GetIDList(ppidl); // Note: Returns S_FALSE if no target pidl pSL->Release(); } return hr;}
HRESULT SHCoInitializeAnyApartment(VOID){ HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); if (FAILED(hr)) hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE); return hr;}
HRESULTSHGetNameAndFlagsW( _In_ LPCITEMIDLIST pidl, _In_ DWORD dwFlags, _Out_opt_ LPWSTR pszText, _In_ UINT cchBuf, _Inout_opt_ DWORD *pdwAttributes){ if (pszText) *pszText = UNICODE_NULL;
HRESULT hrCoInit = SHCoInitializeAnyApartment();
CComPtr<IShellFolder> psfFolder; LPCITEMIDLIST ppidlLast; HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psfFolder), &ppidlLast); if (SUCCEEDED(hr)) { if (pszText) hr = DisplayNameOfW(psfFolder, ppidlLast, dwFlags, pszText, cchBuf);
if (SUCCEEDED(hr)) { if (pdwAttributes) *pdwAttributes = SHGetAttributes(psfFolder, ppidlLast, *pdwAttributes); } }
if (SUCCEEDED(hrCoInit)) CoUninitialize();
return hr;}
EXTERN_C HWNDBindCtx_GetUIWindow(_In_ IBindCtx *pBindCtx){ HWND hWnd = NULL;
CComPtr<IUnknown> punk; if (pBindCtx && SUCCEEDED(pBindCtx->GetObjectParam((LPWSTR)L"UI During Binding", &punk))) IUnknown_GetWindow(punk, &hWnd);
return hWnd;}
class CDummyOleWindow : public IOleWindow{protected: LONG m_cRefs; HWND m_hWnd;
public: CDummyOleWindow() : m_cRefs(1), m_hWnd(NULL) { } virtual ~CDummyOleWindow() { }
// IUnknown methods STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj) override { static const QITAB c_tab[] = { QITABENT(CDummyOleWindow, IOleWindow), { NULL } }; return ::QISearch(this, c_tab, riid, ppvObj); } STDMETHODIMP_(ULONG) AddRef() override { return ++m_cRefs; } STDMETHODIMP_(ULONG) Release() override { if (--m_cRefs == 0) { delete this; return 0; } return m_cRefs; }
// IOleWindow methods STDMETHODIMP GetWindow(HWND *phWnd) override { *phWnd = m_hWnd; if (!m_hWnd) return E_NOTIMPL; return S_OK; } STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) override { return E_NOTIMPL; }};
EXTERN_C HRESULTBindCtx_RegisterObjectParam( _In_ IBindCtx *pBindCtx, _In_ LPOLESTR pszKey, _In_opt_ IUnknown *punk, _Out_ LPBC *ppbc){ HRESULT hr = S_OK; CDummyOleWindow *pUnknown = NULL;
*ppbc = pBindCtx;
if (pBindCtx) { pBindCtx->AddRef(); } else { hr = CreateBindCtx(0, ppbc); if (FAILED(hr)) return hr; }
if (!punk) punk = pUnknown = new CDummyOleWindow();
hr = (*ppbc)->RegisterObjectParam(pszKey, punk);
if (pUnknown) pUnknown->Release();
if (FAILED(hr)) { (*ppbc)->Release(); *ppbc = NULL; }
return hr;}
/************************************************************************* * SHSetFolderPathA (SHELL32.231) * * @see https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shsetfolderpatha */EXTERN_CHRESULT WINAPISHSetFolderPathA( _In_ INT csidl, _In_ HANDLE hToken, _In_ DWORD dwFlags, _In_ LPCSTR pszPath){ TRACE("(%d, %p, 0x%X, %s)\n", csidl, hToken, dwFlags, debugstr_a(pszPath)); CStringW strPathW(pszPath); return SHSetFolderPathW(csidl, hToken, dwFlags, strPathW);}
/************************************************************************* * PathIsSlowA (SHELL32.240) * * @see https://learn.microsoft.com/en-us/windows/win32/api/shlobj/nf-shlobj-pathisslowa */EXTERN_CBOOL WINAPIPathIsSlowA( _In_ LPCSTR pszFile, _In_ DWORD dwAttr){ TRACE("(%s, 0x%X)\n", debugstr_a(pszFile), dwAttr); CStringW strFileW(pszFile); return PathIsSlowW(strFileW, dwAttr);}
/************************************************************************* * ExtractIconResInfoA (SHELL32.221) */EXTERN_CWORD WINAPIExtractIconResInfoA( _In_ HANDLE hHandle, _In_ LPCSTR lpFileName, _In_ WORD wIndex, _Out_ LPWORD lpSize, _Out_ LPHANDLE lpIcon){ TRACE("(%p, %s, %u, %p, %p)\n", hHandle, debugstr_a(lpFileName), wIndex, lpSize, lpIcon);
if (!lpFileName) return 0;
CStringW strFileNameW(lpFileName); return ExtractIconResInfoW(hHandle, strFileNameW, wIndex, lpSize, lpIcon);}
/************************************************************************* * ShortSizeFormatW (SHELL32.204) */EXTERN_CLPWSTR WINAPIShortSizeFormatW( _In_ DWORD dwNumber, _Out_writes_(0x8FFF) LPWSTR pszBuffer){ TRACE("(%lu, %p)\n", dwNumber, pszBuffer); return StrFormatByteSizeW(dwNumber, pszBuffer, 0x8FFF);}
/************************************************************************* * SHOpenEffectiveToken (SHELL32.235) */EXTERN_C BOOL WINAPI SHOpenEffectiveToken(_Out_ LPHANDLE phToken){ TRACE("%p\n", phToken); return OpenEffectiveToken(TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, phToken);}
/************************************************************************* * SHGetUserSessionId (SHELL32.248) */EXTERN_C DWORD WINAPI SHGetUserSessionId(_In_opt_ HANDLE hToken){ DWORD dwSessionId, dwLength; BOOL bOpenToken = FALSE;
TRACE("%p\n", hToken);
if (!hToken) bOpenToken = SHOpenEffectiveToken(&hToken);
if (!hToken || !GetTokenInformation(hToken, TokenSessionId, &dwSessionId, sizeof(dwSessionId), &dwLength)) { dwSessionId = 0; }
if (bOpenToken) CloseHandle(hToken);
return dwSessionId;}
/************************************************************************* * SHInvokePrivilegedFunctionW (SHELL32.246) */EXTERN_CHRESULT WINAPISHInvokePrivilegedFunctionW( _In_ LPCWSTR pszName, _In_ PRIVILEGED_FUNCTION fn, _In_opt_ LPARAM lParam){ TRACE("(%s %p %p)\n", debugstr_w(pszName), fn, lParam);
if (!pszName || !fn) return E_INVALIDARG;
HANDLE hToken = NULL; TOKEN_PRIVILEGES NewPriv, PrevPriv; BOOL bAdjusted = FALSE;
if (SHOpenEffectiveToken(&hToken) && ::LookupPrivilegeValueW(NULL, pszName, &NewPriv.Privileges[0].Luid)) { NewPriv.PrivilegeCount = 1; NewPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
DWORD dwReturnSize; bAdjusted = ::AdjustTokenPrivileges(hToken, FALSE, &NewPriv, sizeof(PrevPriv), &PrevPriv, &dwReturnSize); }
HRESULT hr = fn(lParam);
if (bAdjusted) ::AdjustTokenPrivileges(hToken, FALSE, &PrevPriv, 0, NULL, NULL);
if (hToken) ::CloseHandle(hToken);
return hr;}
/************************************************************************* * SHTestTokenPrivilegeW (SHELL32.236) * * @see http://undoc.airesoft.co.uk/shell32.dll/SHTestTokenPrivilegeW.php */EXTERN_CBOOL WINAPISHTestTokenPrivilegeW( _In_opt_ HANDLE hToken, _In_ LPCWSTR lpName){ LUID Luid; DWORD dwLength; PTOKEN_PRIVILEGES pTokenPriv; HANDLE hNewToken = NULL; BOOL ret = FALSE;
TRACE("(%p, %s)\n", hToken, debugstr_w(lpName));
if (!lpName) return FALSE;
if (!hToken) { if (!SHOpenEffectiveToken(&hNewToken)) goto Quit;
if (!hNewToken) return FALSE;
hToken = hNewToken; }
if (!LookupPrivilegeValueW(NULL, lpName, &Luid)) return FALSE;
dwLength = 0; if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwLength)) goto Quit;
pTokenPriv = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, dwLength); if (!pTokenPriv) goto Quit;
if (GetTokenInformation(hToken, TokenPrivileges, pTokenPriv, dwLength, &dwLength)) { UINT iPriv, cPrivs; cPrivs = pTokenPriv->PrivilegeCount; for (iPriv = 0; !ret && iPriv < cPrivs; ++iPriv) { ret = RtlEqualLuid(&Luid, &pTokenPriv->Privileges[iPriv].Luid); } }
LocalFree(pTokenPriv);
Quit: if (hToken == hNewToken) CloseHandle(hNewToken);
return ret;}
BOOL IsShutdownAllowed(VOID){ return SHTestTokenPrivilegeW(NULL, SE_SHUTDOWN_NAME);}
/************************************************************************* * IsSuspendAllowed (SHELL32.53) */BOOL WINAPI IsSuspendAllowed(VOID){ TRACE("()\n"); return IsShutdownAllowed() && IsPwrSuspendAllowed();}
/************************************************************************* * SHGetShellStyleHInstance (SHELL32.749) */EXTERN_C HINSTANCEWINAPISHGetShellStyleHInstance(VOID){ HINSTANCE hInst = NULL; WCHAR szPath[MAX_PATH], szColorName[100]; HRESULT hr; CStringW strShellStyle;
TRACE("SHGetShellStyleHInstance called\n");
/* First, attempt to load the shellstyle dll from the current active theme */ hr = GetCurrentThemeName(szPath, _countof(szPath), szColorName, _countof(szColorName), NULL, 0); if (FAILED(hr)) goto DoDefault;
/* Strip the theme filename */ PathRemoveFileSpecW(szPath);
strShellStyle = szPath; strShellStyle += L"\\Shell\\"; strShellStyle += szColorName; strShellStyle += L"\\ShellStyle.dll";
hInst = LoadLibraryExW(strShellStyle, NULL, LOAD_LIBRARY_AS_DATAFILE); if (hInst) return hInst;
/* Otherwise, use the version stored in the System32 directory */DoDefault: if (!ExpandEnvironmentStringsW(L"%SystemRoot%\\System32\\ShellStyle.dll", szPath, _countof(szPath))) { ERR("Expand failed\n"); return NULL; } return LoadLibraryExW(szPath, NULL, LOAD_LIBRARY_AS_DATAFILE);}
/************************************************************************* * SHCreatePropertyBag (SHELL32.715) */EXTERN_C HRESULTWINAPISHCreatePropertyBag(_In_ REFIID riid, _Out_ void **ppvObj){ return SHCreatePropertyBagOnMemory(STGM_READWRITE, riid, ppvObj);}
// The helper function for SHGetUnreadMailCountWstatic DWORDSHELL_ReadSingleUnreadMailCount( _In_ HKEY hKey, _Out_opt_ PDWORD pdwCount, _Out_opt_ PFILETIME pFileTime, _Out_writes_opt_(cchShellExecuteCommand) LPWSTR pszShellExecuteCommand, _In_ INT cchShellExecuteCommand){ DWORD dwType, dwCount, cbSize = sizeof(dwCount); DWORD error = SHQueryValueExW(hKey, L"MessageCount", 0, &dwType, &dwCount, &cbSize); if (error) return error; if (pdwCount && dwType == REG_DWORD) *pdwCount = dwCount;
FILETIME FileTime; cbSize = sizeof(FileTime); error = SHQueryValueExW(hKey, L"TimeStamp", 0, &dwType, &FileTime, &cbSize); if (error) return error; if (pFileTime && dwType == REG_BINARY) *pFileTime = FileTime;
WCHAR szName[2 * MAX_PATH]; cbSize = sizeof(szName); error = SHQueryValueExW(hKey, L"Application", 0, &dwType, szName, &cbSize); if (error) return error;
if (pszShellExecuteCommand && dwType == REG_SZ && FAILED(StringCchCopyW(pszShellExecuteCommand, cchShellExecuteCommand, szName))) { return ERROR_INSUFFICIENT_BUFFER; }
return ERROR_SUCCESS;}
/************************************************************************* * SHGetUnreadMailCountW [SHELL32.320] * * @see https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shgetunreadmailcountw */EXTERN_CHRESULT WINAPISHGetUnreadMailCountW( _In_opt_ HKEY hKeyUser, _In_opt_ PCWSTR pszMailAddress, _Out_opt_ PDWORD pdwCount, _Inout_opt_ PFILETIME pFileTime, _Out_writes_opt_(cchShellExecuteCommand) PWSTR pszShellExecuteCommand, _In_ INT cchShellExecuteCommand){ LSTATUS error; HKEY hKey;
if (!hKeyUser) hKeyUser = HKEY_CURRENT_USER;
if (pszMailAddress) { CStringW strKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail"; strKey += L'\\'; strKey += pszMailAddress;
error = RegOpenKeyExW(hKeyUser, strKey, 0, KEY_QUERY_VALUE, &hKey); if (error) return HRESULT_FROM_WIN32(error);
error = SHELL_ReadSingleUnreadMailCount(hKey, pdwCount, pFileTime, pszShellExecuteCommand, cchShellExecuteCommand); } else { if (pszShellExecuteCommand || cchShellExecuteCommand) return E_INVALIDARG;
*pdwCount = 0;
error = RegOpenKeyExW(hKeyUser, L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail", 0, KEY_ENUMERATE_SUB_KEYS, &hKey); if (error) return HRESULT_FROM_WIN32(error);
for (DWORD dwIndex = 0; !error; ++dwIndex) { WCHAR Name[2 * MAX_PATH]; DWORD cchName = _countof(Name); FILETIME LastWritten; error = RegEnumKeyExW(hKey, dwIndex, Name, &cchName, NULL, NULL, NULL, &LastWritten); if (error) break;
HKEY hSubKey; error = RegOpenKeyExW(hKey, Name, 0, KEY_QUERY_VALUE, &hSubKey); if (error) break;
FILETIME FileTime; DWORD dwCount; error = SHELL_ReadSingleUnreadMailCount(hSubKey, &dwCount, &FileTime, NULL, 0); if (!error && (!pFileTime || CompareFileTime(&FileTime, pFileTime) >= 0)) *pdwCount += dwCount;
RegCloseKey(hSubKey); }
if (error == ERROR_NO_MORE_ITEMS) error = ERROR_SUCCESS; }
RegCloseKey(hKey);
return error ? HRESULT_FROM_WIN32(error) : S_OK;}
/************************************************************************* * SHSetUnreadMailCountW [SHELL32.336] * * @see https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shsetunreadmailcountw */EXTERN_CHRESULT WINAPISHSetUnreadMailCountW( _In_ PCWSTR pszMailAddress, _In_ DWORD dwCount, _In_ PCWSTR pszShellExecuteCommand){ CString strKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail\\"; strKey += pszMailAddress;
HKEY hKey; DWORD dwDisposition; LSTATUS error = RegCreateKeyExW(HKEY_CURRENT_USER, strKey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hKey, &dwDisposition); if (error) return HRESULT_FROM_WIN32(error);
error = RegSetValueExW(hKey, L"MessageCount", 0, REG_DWORD, (PBYTE)&dwCount, sizeof(dwCount)); if (error) { RegCloseKey(hKey); return HRESULT_FROM_WIN32(error); }
FILETIME FileTime; GetSystemTimeAsFileTime(&FileTime);
error = RegSetValueExW(hKey, L"TimeStamp", 0, REG_BINARY, (PBYTE)&FileTime, sizeof(FileTime)); if (error) { RegCloseKey(hKey); return HRESULT_FROM_WIN32(error); }
WCHAR szBuff[2 * MAX_PATH]; if (!PathUnExpandEnvStringsW(pszShellExecuteCommand, szBuff, _countof(szBuff))) { HRESULT hr = StringCchCopyW(szBuff, _countof(szBuff), pszShellExecuteCommand); if (FAILED_UNEXPECTEDLY(hr)) { RegCloseKey(hKey); return hr; } }
DWORD cbValue = (lstrlenW(szBuff) + 1) * sizeof(WCHAR); error = RegSetValueExW(hKey, L"Application", 0, REG_SZ, (PBYTE)szBuff, cbValue);
RegCloseKey(hKey); return (error ? HRESULT_FROM_WIN32(error) : S_OK);}
/************************************************************************* * SheRemoveQuotesA (SHELL32.@) */EXTERN_C LPSTRWINAPISheRemoveQuotesA(LPSTR psz){ PCHAR pch;
if (*psz == '"') { for (pch = psz + 1; *pch && *pch != '"'; ++pch) { *(pch - 1) = *pch; }
if (*pch == '"') *(pch - 1) = ANSI_NULL; }
return psz;}
/************************************************************************* * SheRemoveQuotesW (SHELL32.@) * * ExtractAssociatedIconExW uses this function. */EXTERN_C LPWSTRWINAPISheRemoveQuotesW(LPWSTR psz){ PWCHAR pch;
if (*psz == L'"') { for (pch = psz + 1; *pch && *pch != L'"'; ++pch) { *(pch - 1) = *pch; }
if (*pch == L'"') *(pch - 1) = UNICODE_NULL; }
return psz;}
/************************************************************************* * SHEnumerateUnreadMailAccountsW [SHELL32.287] * * @see https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shenumerateunreadmailaccountsw */EXTERN_CHRESULT WINAPISHEnumerateUnreadMailAccountsW( _In_opt_ HKEY hKeyUser, _In_ DWORD dwIndex, _Out_writes_(cchMailAddress) PWSTR pszMailAddress, _In_ INT cchMailAddress){ if (!hKeyUser) hKeyUser = HKEY_CURRENT_USER;
HKEY hKey; LSTATUS error = RegOpenKeyExW(hKeyUser, L"Software\\Microsoft\\Windows\\CurrentVersion\\UnreadMail", 0, KEY_ENUMERATE_SUB_KEYS, &hKey); if (error) return HRESULT_FROM_WIN32(error);
FILETIME FileTime; error = RegEnumKeyExW(hKey, dwIndex, pszMailAddress, (PDWORD)&cchMailAddress, NULL, NULL, NULL, &FileTime); if (error) *pszMailAddress = UNICODE_NULL;
RegCloseKey(hKey); return error ? HRESULT_FROM_WIN32(error) : S_OK;}
/************************************************************************* * SHFindComputer [SHELL32.91] * * Invokes the shell search in My Computer. Used in SHFindFiles. * Two parameters are ignored. */EXTERN_C BOOLWINAPISHFindComputer(LPCITEMIDLIST pidlRoot, LPCITEMIDLIST pidlSavedSearch){ UNREFERENCED_PARAMETER(pidlRoot); UNREFERENCED_PARAMETER(pidlSavedSearch);
TRACE("%p %p\n", pidlRoot, pidlSavedSearch);
IContextMenu *pCM; HRESULT hr = CoCreateInstance(CLSID_ShellSearchExt, NULL, CLSCTX_INPROC_SERVER, IID_IContextMenu, (void **)&pCM); if (FAILED(hr)) { ERR("0x%08X\n", hr); return hr; }
CMINVOKECOMMANDINFO InvokeInfo = { sizeof(InvokeInfo) }; InvokeInfo.lpParameters = "{996E1EB1-B524-11D1-9120-00A0C98BA67D}"; InvokeInfo.nShow = SW_SHOWNORMAL; hr = pCM->InvokeCommand(&InvokeInfo); pCM->Release();
return SUCCEEDED(hr);}
static HRESULTInt64ToStr( _In_ LONGLONG llValue, _Out_writes_(cchValue) LPWSTR pszValue, _In_ UINT cchValue){ WCHAR szBuff[40]; UINT ich = 0, ichValue;#if (WINVER >= _WIN32_WINNT_VISTA) BOOL bMinus = (llValue < 0);
if (bMinus) llValue = -llValue;#endif
if (cchValue <= 0) return E_FAIL;
do { szBuff[ich++] = (WCHAR)(L'0' + (llValue % 10)); llValue /= 10; } while (llValue != 0 && ich < _countof(szBuff) - 1);
#if (WINVER >= _WIN32_WINNT_VISTA) if (bMinus && ich < _countof(szBuff)) szBuff[ich++] = '-';#endif
for (ichValue = 0; ich > 0 && ichValue < cchValue; ++ichValue) { --ich; pszValue[ichValue] = szBuff[ich]; }
if (ichValue >= cchValue) { pszValue[cchValue - 1] = UNICODE_NULL; return E_FAIL; }
pszValue[ichValue] = UNICODE_NULL; return S_OK;}
static VOIDInt64GetNumFormat( _Out_ NUMBERFMTW *pDest, _In_opt_ const NUMBERFMTW *pSrc, _In_ DWORD dwNumberFlags, _Out_writes_(cchDecimal) LPWSTR pszDecimal, _In_ INT cchDecimal, _Out_writes_(cchThousand) LPWSTR pszThousand, _In_ INT cchThousand){ WCHAR szBuff[20];
if (pSrc) *pDest = *pSrc; else dwNumberFlags = 0;
if (!(dwNumberFlags & FMT_USE_NUMDIGITS)) { GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, szBuff, _countof(szBuff)); pDest->NumDigits = StrToIntW(szBuff); }
if (!(dwNumberFlags & FMT_USE_LEADZERO)) { GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILZERO, szBuff, _countof(szBuff)); pDest->LeadingZero = StrToIntW(szBuff); }
if (!(dwNumberFlags & FMT_USE_GROUPING)) { GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szBuff, _countof(szBuff)); pDest->Grouping = StrToIntW(szBuff); }
if (!(dwNumberFlags & FMT_USE_DECIMAL)) { GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, pszDecimal, cchDecimal); pDest->lpDecimalSep = pszDecimal; }
if (!(dwNumberFlags & FMT_USE_THOUSAND)) { GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, pszThousand, cchThousand); pDest->lpThousandSep = pszThousand; }
if (!(dwNumberFlags & FMT_USE_NEGNUMBER)) { GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_INEGNUMBER, szBuff, _countof(szBuff)); pDest->NegativeOrder = StrToIntW(szBuff); }}
/************************************************************************* * Int64ToString [SHELL32.209] * * @see http://undoc.airesoft.co.uk/shell32.dll/Int64ToString.php */EXTERN_CINT WINAPIInt64ToString( _In_ LONGLONG llValue, _Out_writes_(cchOut) LPWSTR pszOut, _In_ UINT cchOut, _In_ BOOL bUseFormat, _In_opt_ const NUMBERFMTW *pNumberFormat, _In_ DWORD dwNumberFlags){ INT ret; NUMBERFMTW NumFormat; WCHAR szValue[80], szDecimalSep[6], szThousandSep[6];
Int64ToStr(llValue, szValue, _countof(szValue));
if (bUseFormat) { Int64GetNumFormat(&NumFormat, pNumberFormat, dwNumberFlags, szDecimalSep, _countof(szDecimalSep), szThousandSep, _countof(szThousandSep)); ret = GetNumberFormatW(LOCALE_USER_DEFAULT, 0, szValue, &NumFormat, pszOut, cchOut); if (ret) --ret; return ret; }
if (FAILED(StringCchCopyW(pszOut, cchOut, szValue))) return 0;
return lstrlenW(pszOut);}
/************************************************************************* * LargeIntegerToString [SHELL32.210] * * @see http://undoc.airesoft.co.uk/shell32.dll/LargeIntegerToString.php */EXTERN_CINT WINAPILargeIntegerToString( _In_ const LARGE_INTEGER *pLargeInt, _Out_writes_(cchOut) LPWSTR pszOut, _In_ UINT cchOut, _In_ BOOL bUseFormat, _In_opt_ const NUMBERFMTW *pNumberFormat, _In_ DWORD dwNumberFlags){ return Int64ToString(pLargeInt->QuadPart, pszOut, cchOut, bUseFormat, pNumberFormat, dwNumberFlags);}
/************************************************************************* * CopyStreamUI [SHELL32.726] * * Copy a stream to another stream with optional progress display. */EXTERN_CHRESULT WINAPICopyStreamUI( _In_ IStream *pSrc, _Out_ IStream *pDst, _Inout_opt_ IProgressDialog *pProgress, _In_opt_ DWORDLONG dwlSize){ HRESULT hr = E_FAIL; DWORD cbBuff, cbRead, dwSizeToWrite; DWORDLONG cbDone; LPVOID pBuff; CComHeapPtr<BYTE> pHeapPtr; STATSTG Stat; BYTE abBuff[1024];
TRACE("(%p, %p, %p, %I64u)\n", pSrc, pDst, pProgress, dwlSize);
if (dwlSize == 0) // Invalid size? { // Get the stream size ZeroMemory(&Stat, sizeof(Stat)); if (FAILED(pSrc->Stat(&Stat, STATFLAG_NONAME))) pProgress = NULL; // No size info. Disable progress else dwlSize = Stat.cbSize.QuadPart; }
if (!pProgress) // Progress is disabled? { ULARGE_INTEGER uliSize;
if (dwlSize > 0) uliSize.QuadPart = dwlSize; else uliSize.HighPart = uliSize.LowPart = INVALID_FILE_SIZE;
return pSrc->CopyTo(pDst, uliSize, NULL, NULL); // One punch }
// Allocate the buffer if necessary if (dwlSize > 0 && dwlSize <= sizeof(abBuff)) { cbBuff = sizeof(abBuff); pBuff = abBuff; } else {#define COPY_STREAM_DEFAULT_BUFFER_SIZE 0x4000 cbBuff = COPY_STREAM_DEFAULT_BUFFER_SIZE; if (pHeapPtr.AllocateBytes(cbBuff)) { pBuff = pHeapPtr; } else // Low memory? { cbBuff = sizeof(abBuff); pBuff = abBuff; }#undef COPY_STREAM_DEFAULT_BUFFER_SIZE }
// Start reading LARGE_INTEGER zero; zero.QuadPart = 0; pSrc->Seek(zero, 0, NULL); pDst->Seek(zero, 0, NULL); cbDone = 0; pProgress->SetProgress64(cbDone, dwlSize);
// Repeat reading and writing until goal for (;;) { hr = pSrc->Read(pBuff, cbBuff, &cbRead); if (FAILED(hr)) break;
// Calculate the size to write if (dwlSize > 0) dwSizeToWrite = (DWORD)min((DWORDLONG)(dwlSize - cbDone), (DWORDLONG)cbRead); else dwSizeToWrite = cbRead;
if (dwSizeToWrite == 0) // No need to write? { hr = S_OK; break; }
hr = pDst->Write(pBuff, dwSizeToWrite, NULL); if (hr != S_OK) break;
cbDone += dwSizeToWrite;
if (pProgress->HasUserCancelled()) // Cancelled? { hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); break; } pProgress->SetProgress64(cbDone, dwlSize);
if (dwlSize > 0 && cbDone >= dwlSize) // Reached the goal? { hr = S_OK; break; } }
return hr;}
/************************************************************************* * Activate_RunDLL [SHELL32.105] * * Unlocks the foreground window and allows the shell window to become the * foreground window. Every parameter is unused. */EXTERN_CBOOL WINAPIActivate_RunDLL( _In_ HWND hwnd, _In_ HINSTANCE hinst, _In_ LPCWSTR cmdline, _In_ INT cmdshow){ DWORD dwProcessID;
UNREFERENCED_PARAMETER(hwnd); UNREFERENCED_PARAMETER(hinst); UNREFERENCED_PARAMETER(cmdline); UNREFERENCED_PARAMETER(cmdshow);
TRACE("(%p, %p, %s, %d)\n", hwnd, hinst, debugstr_w(cmdline), cmdline);
GetWindowThreadProcessId(GetShellWindow(), &dwProcessID); return AllowSetForegroundWindow(dwProcessID);}
/************************************************************************* * SHStartNetConnectionDialogA (SHELL32.12) * * @see https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shstartnetconnectiondialoga */EXTERN_CHRESULT WINAPISHStartNetConnectionDialogA( _In_ HWND hwnd, _In_ LPCSTR pszRemoteName, _In_ DWORD dwType){ LPCWSTR pszRemoteNameW = NULL; CStringW strRemoteNameW;
TRACE("(%p, %s, %lu)\n", hwnd, debugstr_a(pszRemoteName), dwType);
if (pszRemoteName) { strRemoteNameW = pszRemoteName; pszRemoteNameW = strRemoteNameW; }
return SHStartNetConnectionDialogW(hwnd, pszRemoteNameW, dwType);}
/************************************************************************* * Helper functions for PathIsEqualOrSubFolder */
static INTDynamicPathCommonPrefixW( _In_ LPCWSTR lpszPath1, _In_ LPCWSTR lpszPath2, _Out_ CStringW& strPath){ SIZE_T cchPath1 = wcslen(lpszPath1); SIZE_T cchPath2 = wcslen(lpszPath2); LPWSTR lpszPath = strPath.GetBuffer((INT)max(cchPath1, cchPath2) + 16); INT ret = PathCommonPrefixW(lpszPath1, lpszPath2, lpszPath); strPath.ReleaseBuffer(); return ret;}
EXTERN_C HRESULT WINAPISHGetPathCchFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath, SIZE_T cchPathMax);
static HRESULTDynamicSHGetPathFromIDListW( _In_ LPCITEMIDLIST pidl, _Out_ CStringW& strPath){ HRESULT hr;
for (UINT cchPath = MAX_PATH;; cchPath *= 2) { LPWSTR lpszPath = strPath.GetBuffer(cchPath); if (!lpszPath) return E_OUTOFMEMORY;
hr = SHGetPathCchFromIDListW(pidl, lpszPath, cchPath); strPath.ReleaseBuffer();
if (hr != E_NOT_SUFFICIENT_BUFFER) break;
if (cchPath >= MAXUINT / 2) { hr = E_FAIL; break; } }
if (FAILED(hr)) strPath.Empty();
return hr;}
static HRESULTDynamicSHGetSpecialFolderPathW( _In_ HWND hwndOwner, _Out_ CStringW& strPath, _In_ INT nCSIDL, _In_ BOOL bCreate){ LPITEMIDLIST pidl; HRESULT hr = SHGetSpecialFolderLocation(hwndOwner, nCSIDL, &pidl); if (SUCCEEDED(hr)) { hr = DynamicSHGetPathFromIDListW(pidl, strPath); CoTaskMemFree(pidl); }
if (FAILED(hr)) strPath.Empty(); else if (bCreate) CreateDirectoryW(strPath, NULL);
return hr;}
static VOIDDynamicPathRemoveBackslashW( _Out_ CStringW& strPath){ INT nLength = strPath.GetLength(); if (nLength > 0 && strPath[nLength - 1] == L'\\') strPath = strPath.Left(nLength - 1);}
/************************************************************************* * PathIsEqualOrSubFolder (SHELL32.755) */EXTERN_CBOOL WINAPIPathIsEqualOrSubFolder( _In_ LPCWSTR pszPath1OrCSIDL, _In_ LPCWSTR pszPath2){ CStringW strCommon, strPath1;
TRACE("(%s %s)\n", debugstr_w(pszPath1OrCSIDL), debugstr_w(pszPath2));
if (IS_INTRESOURCE(pszPath1OrCSIDL)) { DynamicSHGetSpecialFolderPathW( NULL, strPath1, LOWORD(pszPath1OrCSIDL) | CSIDL_FLAG_DONT_VERIFY, FALSE); } else { strPath1 = pszPath1OrCSIDL; }
DynamicPathRemoveBackslashW(strPath1);
if (!DynamicPathCommonPrefixW(strPath1, pszPath2, strCommon)) return FALSE;
return strPath1.CompareNoCase(strCommon) == 0;}
/************************************************************************* * SHGetRealIDL [SHELL32.98] */EXTERN_CHRESULT WINAPISHGetRealIDL( _In_ IShellFolder *psf, _In_ PCUITEMID_CHILD pidlSimple, _Outptr_ PITEMID_CHILD *ppidlReal){ HRESULT hr; STRRET strret; WCHAR szPath[MAX_PATH]; SFGAOF attrs;
*ppidlReal = NULL;
hr = IShellFolder_GetDisplayNameOf(psf, pidlSimple, SHGDN_INFOLDER | SHGDN_FORPARSING, &strret, 0); if (FAILED_UNEXPECTEDLY(hr)) return hr;
hr = StrRetToBufW(&strret, pidlSimple, szPath, _countof(szPath)); if (FAILED_UNEXPECTEDLY(hr)) return hr;
attrs = SFGAO_FILESYSTEM; hr = psf->GetAttributesOf(1, &pidlSimple, &attrs); if (SUCCEEDED(hr) && !(attrs & SFGAO_FILESYSTEM)) return SHILClone(pidlSimple, ppidlReal);
hr = IShellFolder_ParseDisplayName(psf, NULL, NULL, szPath, NULL, ppidlReal, NULL); if (hr == E_INVALIDARG || hr == E_NOTIMPL) return SHILClone(pidlSimple, ppidlReal);
return hr;}
EXTERN_C HRESULTIUnknown_InitializeCommand( _In_ IUnknown *pUnk, _In_ PCWSTR pszCommandName, _In_opt_ IPropertyBag *pPB){ HRESULT hr; CComPtr<IInitializeCommand> pIC; if (SUCCEEDED(hr = pUnk->QueryInterface(IID_PPV_ARG(IInitializeCommand, &pIC)))) hr = pIC->Initialize(pszCommandName, pPB); return hr;}
EXTERN_C HRESULTInvokeIExecuteCommand( _In_ IExecuteCommand *pEC, _In_ PCWSTR pszCommandName, _In_opt_ IPropertyBag *pPB, _In_opt_ IShellItemArray *pSIA, _In_opt_ LPCMINVOKECOMMANDINFOEX pICI, _In_opt_ IUnknown *pSite){ if (!pEC) return E_INVALIDARG;
CScopedSetObjectWithSite site(pEC, pSite); IUnknown_InitializeCommand(pEC, pszCommandName, pPB);
CComPtr<IObjectWithSelection> pOWS; if (pSIA && SUCCEEDED(pEC->QueryInterface(IID_PPV_ARG(IObjectWithSelection, &pOWS)))) pOWS->SetSelection(pSIA);
DWORD dwKeyState = 0, fMask = pICI ? pICI->fMask : 0; pEC->SetNoShowUI((fMask & CMIC_MASK_FLAG_NO_UI) != 0); pEC->SetShowWindow(pICI ? pICI->nShow : SW_SHOW); if (fMask & CMIC_MASK_SHIFT_DOWN) dwKeyState |= MK_SHIFT; if (fMask & CMIC_MASK_CONTROL_DOWN) dwKeyState |= MK_CONTROL; pEC->SetKeyState(dwKeyState); if ((fMask & CMIC_MASK_UNICODE) && pICI->lpDirectoryW) pEC->SetDirectory(pICI->lpDirectoryW); if ((fMask & CMIC_MASK_UNICODE) && pICI->lpParametersW) pEC->SetParameters(pICI->lpParametersW); if (fMask & CMIC_MASK_PTINVOKE) pEC->SetPosition(pICI->ptInvoke);
return pEC->Execute();}
EXTERN_C HRESULTInvokeIExecuteCommandWithDataObject( _In_ IExecuteCommand *pEC, _In_ PCWSTR pszCommandName, _In_opt_ IPropertyBag *pPB, _In_ IDataObject *pDO, _In_opt_ LPCMINVOKECOMMANDINFOEX pICI, _In_opt_ IUnknown *pSite){ CComPtr<IShellItemArray> pSIA; HRESULT hr = SHCreateShellItemArrayFromDataObject(pDO, IID_PPV_ARG(IShellItemArray, &pSIA)); return SUCCEEDED(hr) ? InvokeIExecuteCommand(pEC, pszCommandName, pPB, pSIA, pICI, pSite) : hr;}
static HRESULTGetCommandStringA(_In_ IContextMenu *pCM, _In_ UINT_PTR Id, _In_ UINT GCS, _Out_writes_(cchMax) LPSTR Buf, _In_ UINT cchMax){ HRESULT hr = pCM->GetCommandString(Id, GCS & ~GCS_UNICODE, NULL, Buf, cchMax); if (FAILED(hr)) { WCHAR buf[MAX_PATH]; hr = pCM->GetCommandString(Id, GCS | GCS_UNICODE, NULL, (LPSTR)buf, _countof(buf)); if (SUCCEEDED(hr)) hr = SHUnicodeToAnsi(buf, Buf, cchMax) > 0 ? S_OK : E_FAIL; } return hr;}
UINTGetDfmCmd(_In_ IContextMenu *pCM, _In_ LPCSTR verba){ CHAR buf[MAX_PATH]; if (IS_INTRESOURCE(verba)) { if (FAILED(GetCommandStringA(pCM, LOWORD(verba), GCS_VERB, buf, _countof(buf)))) return 0; verba = buf; } return MapVerbToDfmCmd(verba); // Returns DFM_CMD_* or 0}
HRESULTSHELL_MapContextMenuVerbToCmdId(LPCMINVOKECOMMANDINFO pICI, const CMVERBMAP *pMap){ LPCSTR pVerbA = pICI->lpVerb; CHAR buf[MAX_PATH]; LPCMINVOKECOMMANDINFOEX pICIX = (LPCMINVOKECOMMANDINFOEX)pICI; if (IsUnicode(*pICIX) && !IS_INTRESOURCE(pICIX->lpVerbW)) { if (SHUnicodeToAnsi(pICIX->lpVerbW, buf, _countof(buf))) pVerbA = buf; }
if (IS_INTRESOURCE(pVerbA)) return LOWORD(pVerbA); for (SIZE_T i = 0; pMap[i].Verb; ++i) { assert(SUCCEEDED((int)(pMap[i].CmdId))); // The id must be >= 0 and ideally in the 0..0x7fff range if (!lstrcmpiA(pMap[i].Verb, pVerbA) && pVerbA[0]) return pMap[i].CmdId; } return E_FAIL;}
static const CMVERBMAP*FindVerbMapEntry(UINT_PTR CmdId, const CMVERBMAP *pMap){ for (SIZE_T i = 0; pMap[i].Verb; ++i) { if (pMap[i].CmdId == CmdId) return &pMap[i]; } return NULL;}
HRESULTSHELL_GetCommandStringImpl(SIZE_T CmdId, UINT uFlags, LPSTR Buf, UINT cchBuf, const CMVERBMAP *pMap){ const CMVERBMAP* pEntry; switch (uFlags | GCS_UNICODE) { case GCS_VALIDATEW: case GCS_VERBW: pEntry = FindVerbMapEntry(CmdId, pMap); if ((uFlags | GCS_UNICODE) == GCS_VERBW) { if (!pEntry) return E_INVALIDARG; else if (uFlags & GCS_UNICODE) return SHAnsiToUnicode(pEntry->Verb, (LPWSTR)Buf, cchBuf) ? S_OK : E_FAIL; else return StringCchCopyA(Buf, cchBuf, pEntry->Verb); } return pEntry ? S_OK : S_FALSE; // GCS_VALIDATE } return E_NOTIMPL;}
HRESULTSHELL_CreateShell32DefaultExtractIcon(int IconIndex, REFIID riid, LPVOID *ppvOut){ CComPtr<IDefaultExtractIconInit> initIcon; HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon)); if (FAILED_UNEXPECTEDLY(hr)) return hr; initIcon->SetNormalIcon(swShell32Name, IconIndex); return initIcon->QueryInterface(riid, ppvOut);}
int DCIA_AddEntry(HDCIA hDCIA, REFCLSID rClsId){ for (UINT i = 0;; ++i) { const CLSID *pClsId = DCIA_GetEntry(hDCIA, i); if (!pClsId) break; if (IsEqualGUID(*pClsId, rClsId)) return i; // Don't allow duplicates } return DSA_AppendItem((HDSA)hDCIA, const_cast<CLSID*>(&rClsId));}
void DCIA_AddShellExSubkey(HDCIA hDCIA, HKEY hProgId, PCWSTR pszSubkey){ WCHAR szKey[200]; PathCombineW(szKey, L"shellex", pszSubkey); HKEY hEnum; if (RegOpenKeyExW(hProgId, szKey, 0, KEY_READ, &hEnum) != ERROR_SUCCESS) return; for (UINT i = 0; RegEnumKeyW(hEnum, i++, szKey, _countof(szKey)) == ERROR_SUCCESS;) { CLSID clsid; if (SUCCEEDED(SHELL_GetShellExtensionRegCLSID(hEnum, szKey, &clsid))) DCIA_AddEntry(hDCIA, clsid); } RegCloseKey(hEnum);}
/************************************************************************* * SHIsBadInterfacePtr [SHELL32.84] * * Retired in 6.0 from Windows Vista and higher. */EXTERN_CBOOL WINAPISHIsBadInterfacePtr( _In_ LPCVOID pv, _In_ UINT_PTR ucb){ struct CUnknownVtbl { HRESULT (STDMETHODCALLTYPE *QueryInterface)(REFIID riid, LPVOID *ppvObj); ULONG (STDMETHODCALLTYPE *AddRef)(); ULONG (STDMETHODCALLTYPE *Release)(); }; struct CUnknown { CUnknownVtbl *lpVtbl; }; const CUnknown *punk = reinterpret_cast<const CUnknown *>(pv); return !punk || IsBadReadPtr(punk, sizeof(punk->lpVtbl)) || IsBadReadPtr(punk->lpVtbl, ucb) || IsBadCodePtr((FARPROC)punk->lpVtbl->Release);}
/************************************************************************* * SHGetUserDisplayName [SHELL32.241] * * @see https://undoc.airesoft.co.uk/shell32.dll/SHGetUserDisplayName.php */EXTERN_CHRESULT WINAPISHGetUserDisplayName( _Out_writes_to_(*puSize, *puSize) PWSTR pName, _Inout_ PULONG puSize){ if (!pName || !puSize) return E_INVALIDARG;
if (GetUserNameExW(NameDisplay, pName, puSize)) return S_OK;
LONG error = GetLastError(); // for ERROR_NONE_MAPPED HRESULT hr = HRESULT_FROM_WIN32(error);
WCHAR UserName[MAX_PATH]; DWORD cchUserName = _countof(UserName); if (!GetUserNameW(UserName, &cchUserName)) return HRESULT_FROM_WIN32(GetLastError());
// Was the user name not available in the specified format (NameDisplay)? if (error == ERROR_NONE_MAPPED) { // Try to get the user name by using Network API PUSER_INFO_2 UserInfo; DWORD NetError = NetUserGetInfo(NULL, UserName, 2, (PBYTE*)&UserInfo); if (NetError) { hr = HRESULT_FROM_WIN32(NetError); } else { if (UserInfo->usri2_full_name) { hr = StringCchCopyW(pName, *puSize, UserInfo->usri2_full_name); if (SUCCEEDED(hr)) { // Include the NUL-terminator *puSize = lstrlenW(UserInfo->usri2_full_name) + 1; } }
NetApiBufferFree(UserInfo); } }
if (FAILED(hr)) { hr = StringCchCopyW(pName, *puSize, UserName); if (SUCCEEDED(hr)) *puSize = cchUserName; }
return hr;}
// Skip leading backslashesstatic PCWSTRSHELL_SkipServerSlashes( _In_ PCWSTR pszPath){ PCWSTR pch; for (pch = pszPath; *pch == L'\\'; ++pch) ; return pch;}
// The registry key for server computer descriptions cache#define COMPUTER_DESCRIPTIONS_KEY \ L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComputerDescriptions"
// Get server computer description from cachestatic HRESULTSHELL_GetCachedComputerDescription( _Out_writes_z_(cchDescMax) PWSTR pszDesc, _In_ DWORD cchDescMax, _In_ PCWSTR pszServerName){ cchDescMax *= sizeof(WCHAR); DWORD error = SHGetValueW(HKEY_CURRENT_USER, COMPUTER_DESCRIPTIONS_KEY, SHELL_SkipServerSlashes(pszServerName), NULL, pszDesc, &cchDescMax); return HRESULT_FROM_WIN32(error);}
// Do cache a server computer descriptionstatic VOIDSHELL_CacheComputerDescription( _In_ PCWSTR pszServerName, _In_ PCWSTR pszDesc){ if (!pszDesc) return;
SIZE_T cbDesc = (wcslen(pszDesc) + 1) * sizeof(WCHAR); SHSetValueW(HKEY_CURRENT_USER, COMPUTER_DESCRIPTIONS_KEY, SHELL_SkipServerSlashes(pszServerName), REG_SZ, pszDesc, (DWORD)cbDesc);}
// Get real server computer descriptionstatic HRESULTSHELL_GetComputerDescription( _Out_writes_z_(cchDescMax) PWSTR pszDesc, _In_ SIZE_T cchDescMax, _In_ PWSTR pszServerName){ PSERVER_INFO_101 bufptr; NET_API_STATUS error = NetServerGetInfo(pszServerName, 101, (PBYTE*)&bufptr); HRESULT hr = (error > 0) ? HRESULT_FROM_WIN32(error) : error; if (FAILED_UNEXPECTEDLY(hr)) return hr;
PCWSTR comment = bufptr->sv101_comment; if (comment && comment[0]) StringCchCopyW(pszDesc, cchDescMax, comment); else hr = E_FAIL;
NetApiBufferFree(bufptr); return hr;}
// Build computer display namestatic HRESULTSHELL_BuildDisplayMachineName( _Out_writes_z_(cchNameMax) PWSTR pszName, _In_ DWORD cchNameMax, _In_ PCWSTR pszServerName, _In_ PCWSTR pszDescription){ if (!pszDescription || !*pszDescription) return E_FAIL;
PCWSTR pszFormat = (SHRestricted(REST_ALLOWCOMMENTTOGGLE) ? L"%2 (%1)" : L"%1 (%2)"); PCWSTR args[] = { pszDescription , SHELL_SkipServerSlashes(pszServerName) }; return (FormatMessageW(FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING, pszFormat, 0, 0, pszName, cchNameMax, (va_list *)args) ? S_OK : E_FAIL);}
/************************************************************************* * SHGetComputerDisplayNameW [SHELL32.752] */EXTERN_CHRESULT WINAPISHGetComputerDisplayNameW( _In_opt_ PWSTR pszServerName, _In_ DWORD dwFlags, _Out_writes_z_(cchNameMax) PWSTR pszName, _In_ DWORD cchNameMax){ WCHAR szDesc[256], szCompName[MAX_COMPUTERNAME_LENGTH + 1];
// If no server name is specified, retrieve the local computer name if (!pszServerName) { // Use computer name as server name DWORD cchCompName = _countof(szCompName); if (!GetComputerNameW(szCompName, &cchCompName)) return E_FAIL; pszServerName = szCompName;
// Don't use the cache for the local machine dwFlags |= SHGCDN_NOCACHE; }
// Get computer description from cache if necessary HRESULT hr = E_FAIL; if (!(dwFlags & SHGCDN_NOCACHE)) hr = SHELL_GetCachedComputerDescription(szDesc, _countof(szDesc), pszServerName);
// Actually retrieve the computer description if it is not in the cache if (FAILED(hr)) { hr = SHELL_GetComputerDescription(szDesc, _countof(szDesc), pszServerName); if (FAILED(hr)) szDesc[0] = UNICODE_NULL;
// Cache the description if necessary if (!(dwFlags & SHGCDN_NOCACHE)) SHELL_CacheComputerDescription(pszServerName, szDesc); }
// If getting the computer description failed, store the server name only if (FAILED(hr) || !szDesc[0]) { if (dwFlags & SHGCDN_NOSERVERNAME) return hr; // Bail out if no server name is requested
StringCchCopyW(pszName, cchNameMax, SHELL_SkipServerSlashes(pszServerName)); return S_OK; }
// If no server name is requested, store the description only if (dwFlags & SHGCDN_NOSERVERNAME) { StringCchCopyW(pszName, cchNameMax, szDesc); return S_OK; }
// Build a string like "Description (SERVERNAME)" return SHELL_BuildDisplayMachineName(pszName, cchNameMax, pszServerName, szDesc);}
typedef struct tagALIAS_MAPPING{ BYTE bFlagMask; // The combination of ALIAS_USER_FOLDER and/or ALIAS_DESKTOP BYTE bCommonDesktop; WORD nCsidlSrc; // CSIDL_... (source) WORD nCsidlDest; // CSIDL_... (destination)} ALIAS_MAPPING, *PALIAS_MAPPING;
//! PIDL alias tablestatic const ALIAS_MAPPING g_AliasTable[] ={ { ALIAS_USER_FOLDER, FALSE, CSIDL_PERSONAL | CSIDL_FLAG_NO_ALIAS, CSIDL_PERSONAL }, { ALIAS_USER_FOLDER | ALIAS_DESKTOP, FALSE, CSIDL_COMMON_DOCUMENTS | CSIDL_FLAG_NO_ALIAS, CSIDL_COMMON_DOCUMENTS }, { ALIAS_DESKTOP, FALSE, CSIDL_DESKTOPDIRECTORY, CSIDL_DESKTOP }, { ALIAS_DESKTOP, TRUE, CSIDL_COMMON_DESKTOPDIRECTORY, CSIDL_DESKTOP }};
//! Translate a PIDL to an "alias" PIDL.EXTERN_C BOOLSHELL32_ReparentAsAliasPidl( _In_opt_ HWND hwnd, _In_opt_ HANDLE hToken, _In_ LPCITEMIDLIST pidlTarget, _Out_ LPITEMIDLIST *ppidlNew, _In_ DWORD dwFlags){ if (!pidlTarget || !ppidlNew) return FALSE;
*ppidlNew = NULL;
for (SIZE_T iEntry = 0; iEntry < _countof(g_AliasTable); ++iEntry) { const ALIAS_MAPPING *pEntry = &g_AliasTable[iEntry];
if (!(dwFlags & pEntry->bFlagMask)) continue;
// Get the source root PIDL LPITEMIDLIST pidlSrcRoot = NULL; HRESULT hr = SHGetFolderLocation(hwnd, pEntry->nCsidlSrc, hToken, 0, &pidlSrcRoot); if (FAILED(hr)) continue;
// Check whether the input pidlTarget is under the source folder. // If it matches, ILFindChild returns the relative PIDL in the pidlTarget. LPCITEMIDLIST pidlRelative = ILFindChild(pidlSrcRoot, pidlTarget); if (!pidlRelative) // Not found? { ILFree(pidlSrcRoot); continue; }
// Found. Get the destination root PIDL LPITEMIDLIST pidlDestRoot = NULL; hr = SHGetFolderLocation(hwnd, pEntry->nCsidlDest, hToken, 0, &pidlDestRoot); if (SUCCEEDED(hr)) { // Create a new PIDL by combining the destination root PIDL and the relative PIDL *ppidlNew = ILCombine(pidlDestRoot, pidlRelative); if (*ppidlNew) { // Manipulate specific flags in the PIDL if necessary if (pEntry->bCommonDesktop && (*ppidlNew)->mkid.cb >= 3) { (*ppidlNew)->mkid.abID[0] |= (PT_FS | PT_FS_COMMON_FLAG); } } ILFree(pidlDestRoot); }
ILFree(pidlSrcRoot); break; // A match was found, so exit the loop }
return (*ppidlNew != NULL);}
//! Translate a PIDL to an "alias" PIDL.EXTERN_C HRESULTSHELL32_AliasTranslatePidl( _In_ LPCITEMIDLIST pidl, _Out_ LPITEMIDLIST *ppidlNew, _In_ DWORD dwFlags){ return SHELL32_ReparentAsAliasPidl(NULL, NULL, pidl, ppidlNew, dwFlags) ? S_OK : E_FAIL;}