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

212 lines
6.7 KiB
C++

#include "precomp.h"
#include "shutil.h"
HRESULT SHStringFromCLSIDA( LPSTR szCLSID, DWORD cSize, REFCLSID rCLSID )
{
if ( cSize < 39 )
{
return E_INVALIDARG;
}
WCHAR szWCLSID[40];
HRESULT hr = StringFromGUID2( rCLSID, szWCLSID, 40 );
if ( FAILED( hr ))
{
return hr;
}
WideCharToMultiByte( CP_ACP, 0, szWCLSID, -1, szCLSID, cSize, 0, 0);
return hr;
}
HRESULT GetFileInfoByHandle(LPCTSTR pszFile, BY_HANDLE_FILE_INFORMATION *pInfo)
{
HRESULT hr;
HANDLE hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE != hFile)
{
if (GetFileInformationByHandle(hFile, pInfo))
{
hr = S_OK;
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
CloseHandle(hFile);
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
return hr;
}
// S_OK -> YES, S_FALSE -> NO, FAILED(hr) otherwise
STDAPI IsSameFile(LPCTSTR pszFile1, LPCTSTR pszFile2)
{
HRESULT hr;
// use CRT str cmp semantics as localized strcmp should not be used for the file system
if (0 == StrCmpIC(pszFile1, pszFile2))
{
hr = S_OK; // test the names
}
else
{
// very clever here... we can test for alias names that map to the same
// file. for example the short name vs long name of the same file
// the UNC name vs drive letter version of the name
BY_HANDLE_FILE_INFORMATION hfi1;
hr = GetFileInfoByHandle(pszFile1, &hfi1);
if (SUCCEEDED(hr))
{
BY_HANDLE_FILE_INFORMATION hfi2;
hr = GetFileInfoByHandle(pszFile2, &hfi2);
if (SUCCEEDED(hr))
{
if (hfi1.dwVolumeSerialNumber == hfi2.dwVolumeSerialNumber &&
hfi1.nFileIndexHigh == hfi2.nFileIndexHigh &&
hfi1.nFileIndexLow == hfi2.nFileIndexLow)
{
hr = S_OK; // same!
}
else
{
hr = S_FALSE; // different
}
}
}
}
return hr;
}
UINT FindInDecoderList(ImageCodecInfo *pici, UINT cDecoders, LPCTSTR pszFile)
{
LPCTSTR pszExt = PathFindExtension(pszFile); // speed up PathMatchSpec calls
// look at the list of decoders to see if this format is there
for (UINT i = 0; i < cDecoders; i++)
{
if (PathMatchSpec(pszExt, pici[i].FilenameExtension))
return i;
}
return (UINT)-1; // not found!
}
HRESULT GetUIObjectFromPath(LPCTSTR pszFile, REFIID riid, void **ppv)
{
*ppv = NULL;
LPITEMIDLIST pidl;
HRESULT hr = SHILCreateFromPath(pszFile, &pidl, NULL);
if (SUCCEEDED(hr))
{
hr = SHGetUIObjectFromFullPIDL(pidl, NULL, riid, ppv);
ILFree(pidl);
}
return hr;
}
BOOL FmtSupportsMultiPage(IShellImageData *pData, GUID *pguidFmt)
{
BOOL bRet = FALSE;
EncoderParameters *pencParams;
if (SUCCEEDED(pData->GetEncoderParams(pguidFmt, &pencParams)))
{
for (UINT i=0;!bRet && i<pencParams->Count;i++)
{
if (EncoderSaveFlag == pencParams->Parameter[i].Guid)
{
if (EncoderValueMultiFrame == *((ULONG*)pencParams->Parameter[i].Value))
{
bRet = TRUE;
}
}
}
CoTaskMemFree(pencParams);
}
return bRet;
}
HRESULT SetWallpaperHelper(LPCWSTR pszPath)
{
IActiveDesktop* pad;
HRESULT hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC, IID_PPV_ARG(IActiveDesktop, &pad));
if (SUCCEEDED(hr))
{
IShellImageDataFactory* pidf;
hr = CoCreateInstance(CLSID_ShellImageDataFactory, NULL, CLSCTX_INPROC, IID_PPV_ARG(IShellImageDataFactory, &pidf));
if (SUCCEEDED(hr))
{
IShellImageData* pid;
hr = pidf->CreateImageFromFile(pszPath, &pid);
if (SUCCEEDED(hr))
{
hr = pid->Decode(SHIMGDEC_DEFAULT, 0,0);
if (SUCCEEDED(hr))
{
// we are basing this on a best fit to the primary screen
ULONG cxScreen = GetSystemMetrics(SM_CXSCREEN);
ULONG cyScreen = GetSystemMetrics(SM_CYSCREEN);
SIZE szImg;
pid->GetSize(&szImg);
hr = pad->SetWallpaper(pszPath, 0);
if (SUCCEEDED(hr))
{
WALLPAPEROPT wpo;
wpo.dwSize = sizeof(wpo);
wpo.dwStyle = WPSTYLE_CENTER;
// if the image is small on either axis then tile
if (((ULONG)szImg.cx*2 < cxScreen) || ((ULONG)szImg.cy*2 < cyScreen))
{
wpo.dwStyle = WPSTYLE_TILE;
}
// if the image is larger than the screen then stretch
else if ((ULONG)szImg.cx > cxScreen && (ULONG)szImg.cy > cyScreen)
{
wpo.dwStyle = WPSTYLE_STRETCH;
}
else
{
// If the aspect ratio matches the screen then stretch.
// I'm checking is the aspect ratios are *close* to matching.
// Here's the logic behind this:
//
// a / b == c / d
// a * d == c * b
// (a * d) / (c * b) == 1
// 0.75 <= (a * d) / (c * b) < 1.25 <-- our *close* factor
// 3 <= 4 * (a * d) / (c * b) < 5
//
// We do an integer division which will floor the result meaning
// that if the result is 3 or 4 we are inside the rang we want.
DWORD dwRes = (4 * (ULONG)szImg.cx * cyScreen) / (cxScreen * (ULONG)szImg.cy);
if (dwRes == 4 || dwRes == 3)
wpo.dwStyle = WPSTYLE_STRETCH;
}
hr = pad->SetWallpaperOptions(&wpo, 0);
if (SUCCEEDED(hr))
{
hr = pad->ApplyChanges(AD_APPLY_ALL | AD_APPLY_DYNAMICREFRESH);
}
}
}
pid->Release();
}
pidf->Release();
}
pad->Release();
}
return hr;
}