windows-nt/Source/XPSP1/NT/shell/shell32/apdlglog.cpp
2020-09-26 16:20:57 +08:00

787 lines
19 KiB
C++

#include "shellprv.h"
#include "ids.h"
#include "hwcmmn.h"
#include "apdlglog.h"
#include "mtptl.h"
BOOL _AreHandlersDifferent(LPCWSTR pszOriginal, LPCWSTR pszNew)
{
return TRUE;
}
CHandlerDataArray::~CHandlerDataArray()
{
if (IsDPASet())
{
DestroyCallback(_ReleaseHandler, NULL);
}
}
BOOL CHandlerDataArray::_IsDemotedHandler(PCWSTR pszHandler)
{
return ((0 == StrCmpIW(pszHandler, L"MSTakeNoAction"))
|| (0 == StrCmpIW(pszHandler, L"MSOpenFolder")));
}
HRESULT CHandlerDataArray::AddHandler(CHandlerData *pdata)
{
// always insert ahead of TakeNoAction and OpenFolder
int iInsert;
if (!_IsDemotedHandler(pdata->_pszHandler))
{
int c = GetPtrCount();
for (iInsert = 0; iInsert < c; iInsert++)
{
if (_IsDemotedHandler(GetPtr(iInsert)->_pszHandler))
{
// insert here
break;
}
}
iInsert = InsertPtr(iInsert, pdata);
}
else
{
iInsert = AppendPtr(pdata);
}
return DPA_ERR != iInsert ? S_OK : E_OUTOFMEMORY;
}
BOOL CHandlerDataArray::IsDuplicateCommand(PCWSTR pszCommand)
{
WCHAR sz[MAX_PATH * 2];
BOOL fRet = FALSE;
int c = GetPtrCount();
for (int i = 0; i < c; i++)
{
CHandlerData *pdata = GetPtr(i);
if (SUCCEEDED(pdata->_GetCommand(sz, ARRAYSIZE(sz))))
{
fRet = (0 == StrCmpIW(pszCommand, sz));
if (fRet)
break;
}
}
return fRet;
}
// We are erring on the side of safety here by giving FALSE positives
// sometimes. This could be optimized to consider if we have diff handler
// just because one is missing.
void CContentTypeData::UpdateDirty()
{
BOOL fDirty = _AreHandlersDifferent(_pszHandlerDefault, _pszHandlerDefaultOriginal) ||
(HANDLERDEFAULT_DEFAULTSAREDIFFERENT & _dwHandlerDefaultFlags);
_SetDirty(fDirty);
}
#define SOFTPREFIX TEXT("[soft]")
HRESULT CContentTypeData::CommitChangesToStorage()
{
HRESULT hr = S_OK;
if (_AreHandlersDifferent(_pszHandlerDefault, _pszHandlerDefaultOriginal) ||
(HANDLERDEFAULT_DEFAULTSAREDIFFERENT & _dwHandlerDefaultFlags))
{
// Yep, changed
IAutoplayHandler* piah;
hr = _GetAutoplayHandler(_szDrive, TEXT("ContentArrival"), _szContentTypeHandler, &piah);
if (SUCCEEDED(hr))
{
if (!_fSoftCommit)
{
hr = piah->SetDefaultHandler(_pszHandlerDefault);
}
else
{
WCHAR szHandler[MAX_HANDLER + ARRAYSIZE(SOFTPREFIX)];
lstrcpyn(szHandler, SOFTPREFIX, ARRAYSIZE(szHandler));
StrCatBuff(szHandler, _pszHandlerDefault, ARRAYSIZE(szHandler));
hr = piah->SetDefaultHandler(szHandler);
}
piah->Release();
}
}
if (SUCCEEDED(hr))
{
_SetHandlerDefault(&_pszHandlerDefaultOriginal, _pszHandlerDefault);
}
return hr;
}
CContentTypeData::~CContentTypeData()
{
if (_pszHandlerDefaultOriginal)
{
CoTaskMemFree(_pszHandlerDefaultOriginal);
}
if (_pszHandlerDefault)
{
CoTaskMemFree(_pszHandlerDefault);
}
}
HRESULT _MakeActionString(LPCWSTR pszAction, LPWSTR* ppszAction2)
{
*ppszAction2 = NULL;
WCHAR szAction[250];
HRESULT hr = SHLoadIndirectString(pszAction, szAction, ARRAYSIZE(szAction), NULL);
if (SUCCEEDED(hr))
{
hr = SHStrDup(szAction, ppszAction2);
}
return hr;
}
HRESULT _MakeProviderString(LPCWSTR pszProvider, LPWSTR* ppszProvider2)
{
WCHAR szProviderNonMUI[250];
HRESULT hr = SHLoadIndirectString(pszProvider, szProviderNonMUI, ARRAYSIZE(szProviderNonMUI), NULL);
if (SUCCEEDED(hr))
{
WCHAR szUsing[50];
if (LoadString(g_hinst, IDS_AP_USING, szUsing, ARRAYSIZE(szUsing)))
{
WCHAR szProvider2[250];
wnsprintf(szProvider2, ARRAYSIZE(szProvider2), szUsing, szProviderNonMUI);
if (SUCCEEDED(SHStrDup(szProvider2, ppszProvider2)))
{
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = E_FAIL;
}
}
return hr;
}
inline void _CoTaskMemFree(void* pv)
{
if (pv)
{
CoTaskMemFree(pv);
}
}
HRESULT _CreateHandlerData( PCWSTR pszAction,
PCWSTR pszProvider,
PWSTR *ppszHandler, // IN/OUT
PWSTR *ppszIcon, // IN/OUT
CHandlerData **ppdata)
{
*ppdata = 0;
LPWSTR pszAction2 = NULL;
HRESULT hr = _MakeActionString(pszAction, &pszAction2);
if (SUCCEEDED(hr))
{
LPWSTR pszProvider2 = NULL;
// Special case this guy, we don't want to say:
// "Take no action, using Microsoft Windows"
if (lstrcmp(*ppszHandler, TEXT("MSTakeNoAction")))
{
hr = _MakeProviderString(pszProvider, &pszProvider2);
}
// else this is NULL, and ignored
if (SUCCEEDED(hr))
{
*ppdata = new CHandlerData();
if (*ppdata)
{
// give away ownership of these allocations
(*ppdata)->Init(*ppszHandler, pszAction2,
*ppszIcon, pszProvider2);
*ppszHandler = NULL;
*ppszIcon = NULL;
pszAction2 = NULL;
pszProvider2 = NULL;
}
else
{
hr = E_OUTOFMEMORY;
CoTaskMemFree(pszProvider2);
}
}
CoTaskMemFree(pszAction2);
}
return hr;
}
HRESULT CContentBase::_EnumHandlerHelper(IAutoplayHandler* piah)
{
IEnumAutoplayHandler* penum;
if (S_OK == piah->EnumHandlers(&penum))
{
LPWSTR pszHandler;
LPWSTR pszAction;
LPWSTR pszProvider;
LPWSTR pszIconLocation;
while (S_OK == penum->Next(&pszHandler, &pszAction, &pszProvider,
&pszIconLocation))
{
// Do not free the strings from EnumHandlers
// CHandlerData will free them in its destructor
CHandlerData *pdata;
HRESULT hr = _CreateHandlerData(pszAction, pszProvider, &pszHandler, &pszIconLocation, &pdata);
if (SUCCEEDED(hr))
{
hr = _dpaHandlerData.AddHandler(pdata);
if (FAILED(hr))
{
pdata->Release();
}
}
else
{
CoTaskMemFree(pszHandler);
CoTaskMemFree(pszIconLocation);
}
CoTaskMemFree(pszProvider);
CoTaskMemFree(pszAction);
}
penum->Release();
}
return S_OK;
}
HRESULT _CreateLegacyHandler(IAssociationElement *pae, PCWSTR pszAction, CHandlerData **ppdata)
{
*ppdata = 0;
PWSTR pszIcon;
HRESULT hr = pae->QueryString(AQVS_APPLICATION_PATH, NULL, &pszIcon);
if(SUCCEEDED(hr))
{
PWSTR pszFriendly;
hr = pae->QueryString(AQVS_APPLICATION_FRIENDLYNAME, NULL, &pszFriendly);
if(SUCCEEDED(hr))
{
PWSTR pszHandler;
hr = SHStrDup(TEXT("AutoplayLegacyHandler"), &pszHandler);
if (SUCCEEDED(hr))
{
hr = _CreateHandlerData(pszAction, pszFriendly, &pszHandler, &pszIcon, ppdata);
CoTaskMemFree(pszHandler);
}
CoTaskMemFree(pszFriendly);
}
CoTaskMemFree(pszIcon);
}
return hr;
}
CHandlerData* CContentBase::GetHandlerData(int i)
{
CHandlerData* phandlerdata = _dpaHandlerData.GetPtr(i);
if (phandlerdata)
{
phandlerdata->AddRef();
}
return phandlerdata;
}
HRESULT CContentBase::_AddLegacyHandler(DWORD dwContentType)
{
HRESULT hr = S_FALSE;
if (dwContentType & (CT_CDAUDIO | CT_DVDMOVIE))
{
LPCWSTR pszProgID;
LPCWSTR pszAction;
if (dwContentType & CT_CDAUDIO)
{
pszProgID = TEXT("AudioCD");
pszAction = TEXT("@%SystemRoot%\\system32\\shell32.dll,-17171");
}
else
{
ASSERT(dwContentType & CT_DVDMOVIE);
pszProgID = TEXT("DVD");
pszAction = TEXT("@%SystemRoot%\\system32\\shell32.dll,-17172");
}
IAssociationElement * pae;
hr = AssocElemCreateForClass(&CLSID_AssocProgidElement, pszProgID, &pae);
if (SUCCEEDED(hr))
{
PWSTR pszCommand;
hr = pae->QueryString(AQVS_COMMAND, NULL, &pszCommand);
if (SUCCEEDED(hr))
{
// legacy guys have a command or we dont add them
// we expect new guys to be responsible and add themselves
// to the autoplay handlers key
if (!_dpaHandlerData.IsDuplicateCommand(pszCommand))
{
LPWSTR pszPath;
hr = pae->QueryString(AQVS_APPLICATION_PATH, NULL, &pszPath);
if (SUCCEEDED(hr))
{
DWORD dwAttrib = GetFileAttributes(pszPath);
// We do not want to show legacy handler if their exe
// is hidden
if ((0xFFFFFFFF != dwAttrib) &&
!(FILE_ATTRIBUTE_HIDDEN & dwAttrib))
{
CHandlerData* pdata;
hr = _CreateLegacyHandler(pae, pszAction, &pdata);
if (SUCCEEDED(hr))
{
hr = _dpaHandlerData.AddHandler(pdata);
if (FAILED(hr))
{
pdata->Release();
}
}
}
CoTaskMemFree(pszPath);
}
}
CoTaskMemFree(pszCommand);
}
pae->Release();
}
}
return hr;
}
HRESULT CContentTypeData::Init(LPCWSTR pszDrive, DWORD dwContentType)
{
HRESULT hr;
_dwContentType = dwContentType;
hr = _GetContentTypeHandler(_dwContentType, _szContentTypeHandler,
ARRAYSIZE(_szContentTypeHandler));
if (SUCCEEDED(hr))
{
hr = _GetContentTypeInfo(_dwContentType, _szIconLabel, ARRAYSIZE(_szIconLabel),
_szIconLocation, ARRAYSIZE(_szIconLocation));
lstrcpyn(_szDrive, pszDrive, ARRAYSIZE(_szDrive));
if (SUCCEEDED(hr))
{
IAutoplayHandler* piah;
hr = _GetAutoplayHandler(_szDrive, TEXT("ContentArrival"),
_szContentTypeHandler, &piah);
if (SUCCEEDED(hr))
{
hr = piah->GetDefaultHandler(&_pszHandlerDefaultOriginal);
if (SUCCEEDED(hr))
{
if (S_FALSE != hr)
{
_dwHandlerDefaultFlags = HANDLERDEFAULT_GETFLAGS(hr);
}
// SHStrDup (we want CoTaskMemAlloc)
hr = SHStrDup(_pszHandlerDefaultOriginal, &_pszHandlerDefault);
}
if (SUCCEEDED(hr))
{
if (_dpaHandlerData.Create(4))
{
hr = _EnumHandlerHelper(piah);
if (SUCCEEDED(hr))
{
_AddLegacyHandler(dwContentType);
}
}
}
piah->Release();
}
}
}
return hr;
}
HRESULT CContentTypeLVItem::GetText(LPWSTR pszText, DWORD cchText)
{
HRESULT hr;
CContentTypeData* pdata = GetData();
if (pdata)
{
lstrcpyn(pszText, pdata->_szIconLabel, cchText);
pdata->Release();
hr = S_OK;
}
else
{
*pszText = NULL;
hr = S_FALSE;
}
return hr;
}
HRESULT CContentTypeLVItem::GetIconLocation(LPWSTR pszIconLocation,
DWORD cchIconLocation)
{
HRESULT hr;
CContentTypeData* pdata = GetData();
if (pdata)
{
lstrcpyn(pszIconLocation, pdata->_szIconLocation, cchIconLocation);
pdata->Release();
hr = S_OK;
}
else
{
*pszIconLocation = NULL;
hr = S_FALSE;
}
return hr;
}
HRESULT CContentTypeCBItem::GetText(LPWSTR pszText, DWORD cchText)
{
HRESULT hr;
CContentTypeData* pdata = GetData();
if (pdata)
{
lstrcpyn(pszText, pdata->_szIconLabel, cchText);
pdata->Release();
hr = S_OK;
}
else
{
*pszText = NULL;
hr = S_FALSE;
}
return hr;
}
HRESULT CContentTypeCBItem::GetIconLocation(LPWSTR pszIconLocation, DWORD cchIconLocation)
{
HRESULT hr;
CContentTypeData* pdata = GetData();
if (pdata)
{
lstrcpyn(pszIconLocation, pdata->_szIconLocation, cchIconLocation);
pdata->Release();
hr = S_OK;
}
else
{
*pszIconLocation = NULL;
hr = S_FALSE;
}
return hr;
}
CHandlerData::~CHandlerData()
{
if (_pszHandler)
{
CoTaskMemFree((void*)_pszHandler);
}
if (_pszHandlerFriendlyName)
{
CoTaskMemFree((void*)_pszHandlerFriendlyName);
}
if (_pszIconLocation)
{
CoTaskMemFree((void*)_pszIconLocation);
}
if (_pszTileText)
{
CoTaskMemFree(_pszTileText);
}
}
void CHandlerData::Init(PWSTR pszHandler, PWSTR pszHandlerFriendlyName,
PWSTR pszIconLocation, PWSTR pszTileText)
{
_pszHandler = pszHandler;
_pszHandlerFriendlyName = pszHandlerFriendlyName;
_pszIconLocation = pszIconLocation;
_pszTileText = pszTileText;
// WE CANT FAIL
}
void CHandlerData::UpdateDirty()
{
// nothing to do
}
HRESULT CHandlerCBItem::GetText(LPWSTR pszText, DWORD cchText)
{
HRESULT hr;
CHandlerData* pdata = GetData();
if (pdata)
{
lstrcpyn(pszText, pdata->_pszHandlerFriendlyName, cchText);
pdata->Release();
hr = S_OK;
}
else
{
*pszText = NULL;
hr = S_FALSE;
}
return hr;
}
HRESULT CHandlerLVItem::GetText(LPWSTR pszText, DWORD cchText)
{
HRESULT hr;
CHandlerData* pdata = GetData();
if (pdata)
{
lstrcpyn(pszText, pdata->_pszHandlerFriendlyName, cchText);
pdata->Release();
hr = S_OK;
}
else
{
*pszText = NULL;
hr = S_FALSE;
}
return hr;
}
HRESULT CHandlerLVItem::GetIconLocation(LPWSTR pszIconLocation, DWORD cchIconLocation)
{
HRESULT hr;
CHandlerData* pdata = GetData();
if (pdata)
{
lstrcpyn(pszIconLocation, pdata->_pszIconLocation, cchIconLocation);
pdata->Release();
hr = S_OK;
}
else
{
*pszIconLocation = NULL;
hr = S_FALSE;
}
return hr;
}
HRESULT CHandlerLVItem::GetTileText(int i, LPWSTR pszTileText, DWORD cchTileText)
{
HRESULT hr = S_FALSE;
CHandlerData* pdata = GetData();
*pszTileText = NULL;
hr = S_FALSE;
// we dont support anything but zero
ASSERT(0 == i);
if (pdata)
{
if (pdata->_pszTileText)
{
lstrcpyn(pszTileText, pdata->_pszTileText, cchTileText);
hr = S_OK;
}
pdata->Release();
}
return hr;
}
// We are erring on the side of safety here by giving FALSE positives
// sometimes. This could be optimized to consider if we have diff handler
// just because one is missing.
void CNoContentData::UpdateDirty()
{
BOOL fDirty = _AreHandlersDifferent(_pszHandlerDefault, _pszHandlerDefaultOriginal) ||
(HANDLERDEFAULT_DEFAULTSAREDIFFERENT & _dwHandlerDefaultFlags);
_SetDirty(fDirty);
}
HRESULT CNoContentData::CommitChangesToStorage()
{
HRESULT hr = S_OK;
if (_AreHandlersDifferent(_pszHandlerDefault, _pszHandlerDefaultOriginal) ||
(HANDLERDEFAULT_DEFAULTSAREDIFFERENT & _dwHandlerDefaultFlags))
{
// Yep, changed
IAutoplayHandler* piah;
hr = _GetAutoplayHandlerNoContent(_szDeviceID, TEXT("DeviceArrival"), &piah);
if (SUCCEEDED(hr))
{
if (!_fSoftCommit)
{
hr = piah->SetDefaultHandler(_pszHandlerDefault);
}
else
{
WCHAR szHandler[MAX_HANDLER + ARRAYSIZE(SOFTPREFIX)];
lstrcpyn(szHandler, SOFTPREFIX, ARRAYSIZE(szHandler));
StrCatBuff(szHandler, _pszHandlerDefault, ARRAYSIZE(szHandler));
hr = piah->SetDefaultHandler(szHandler);
}
piah->Release();
}
}
if (SUCCEEDED(hr))
{
_SetHandlerDefault(&_pszHandlerDefaultOriginal, _pszHandlerDefault);
}
return hr;
}
CNoContentData::~CNoContentData()
{
if (_pszHandlerDefaultOriginal)
{
CoTaskMemFree(_pszHandlerDefaultOriginal);
}
if (_pszHandlerDefault)
{
CoTaskMemFree(_pszHandlerDefault);
}
if (_pszIconLabel)
{
CoTaskMemFree((void*)_pszIconLabel);
}
if (_pszIconLocation)
{
CoTaskMemFree((void*)_pszIconLocation);
}
}
HRESULT _MakeDeviceLabel(LPCWSTR pszSource, LPWSTR* ppszDest)
{
WCHAR szDeviceName[250];
HRESULT hr = SHLoadIndirectString(pszSource, szDeviceName, ARRAYSIZE(szDeviceName), NULL);
if (SUCCEEDED(hr))
{
hr = SHStrDup(szDeviceName, ppszDest);
}
return hr;
}
HRESULT CNoContentData::Init(LPCWSTR pszDeviceID)
{
lstrcpyn(_szDeviceID, pszDeviceID, ARRAYSIZE(_szDeviceID));
IAutoplayHandler* piah;
HRESULT hr = _GetAutoplayHandlerNoContent(_szDeviceID, TEXT("DeviceArrival"), &piah);
if (SUCCEEDED(hr))
{
hr = piah->GetDefaultHandler(&_pszHandlerDefaultOriginal);
if (SUCCEEDED(hr))
{
if (S_FALSE != hr)
{
_dwHandlerDefaultFlags = HANDLERDEFAULT_GETFLAGS(hr);
}
// SHStrDup (we want CoTaskMemAlloc)
hr = SHStrDup(_pszHandlerDefaultOriginal, &_pszHandlerDefault);
}
if (SUCCEEDED(hr))
{
if (_dpaHandlerData.Create(4))
{
hr = _EnumHandlerHelper(piah);
}
}
piah->Release();
}
if (SUCCEEDED(hr))
{
IHWDeviceCustomProperties* pihwdevcp;
hr = GetDeviceProperties(_szDeviceID, &pihwdevcp);
if (SUCCEEDED(hr))
{
LPWSTR pszIconLabel;
hr = pihwdevcp->GetStringProperty(TEXT("Label"), &pszIconLabel);
if (SUCCEEDED(hr))
{
hr = _MakeDeviceLabel(pszIconLabel, &_pszIconLabel);
if (SUCCEEDED(hr))
{
WORD_BLOB* pblob;
hr = pihwdevcp->GetMultiStringProperty(TEXT("Icons"), TRUE, &pblob);
if (SUCCEEDED(hr))
{
hr = SHStrDup(pblob->asData, &_pszIconLocation);
CoTaskMemFree(pblob);
}
CoTaskMemFree(pszIconLabel);
}
}
pihwdevcp->Release();
}
}
return hr;
}