2017-12-08 23:51:56 +00:00
/*
* PROJECT : ReactOS API tests
* LICENSE : GPL - 2.0 + ( https : //spdx.org/licenses/GPL-2.0+)
* PURPOSE : Test for SHCreateFileExtractIconW
2018-03-27 17:58:43 +00:00
* COPYRIGHT : Copyright 2017 , 2018 Mark Jansen ( mark . jansen @ reactos . org )
2017-12-08 23:51:56 +00:00
*/
# include "shelltest.h"
2017-12-17 12:31:22 +00:00
2017-12-08 23:51:56 +00:00
# include <wincon.h>
# include <wingdi.h>
2019-08-25 09:17:42 +00:00
# include <stdio.h>
2017-12-17 12:31:22 +00:00
# include <shellutils.h>
2017-12-08 23:51:56 +00:00
HRESULT ( STDAPICALLTYPE * pSHCreateFileExtractIconW ) ( LPCWSTR pszFile , DWORD dwFileAttributes , REFIID riid , void * * ppv ) ;
2017-12-25 12:33:33 +00:00
struct TestData
2017-12-08 23:51:56 +00:00
{
const WCHAR * Name ;
DWORD dwFlags ;
} ;
2017-12-25 12:33:33 +00:00
static TestData IconTests [ ] =
2017-12-08 23:51:56 +00:00
{
{ L " xxx.zip " , FILE_ATTRIBUTE_NORMAL } ,
{ L " xxx.zip " , FILE_ATTRIBUTE_DIRECTORY } ,
{ L " xxx.exe " , FILE_ATTRIBUTE_NORMAL } ,
{ L " xxx.exe " , FILE_ATTRIBUTE_DIRECTORY } ,
{ L " xxx.dll " , FILE_ATTRIBUTE_NORMAL } ,
{ L " xxx.dll " , FILE_ATTRIBUTE_DIRECTORY } ,
{ L " xxx.txt " , FILE_ATTRIBUTE_NORMAL } ,
{ L " xxx.txt " , FILE_ATTRIBUTE_DIRECTORY } ,
{ NULL , FILE_ATTRIBUTE_NORMAL } ,
{ NULL , FILE_ATTRIBUTE_DIRECTORY } ,
} ;
2018-03-27 17:58:43 +00:00
struct TestIID
{
const GUID * IID ;
HRESULT ExpectedCreate ;
HRESULT ExpectedQueryInterface ;
} ;
static TestIID InterfaceTests [ ] =
{
{ & IID_IDefaultExtractIconInit , E_NOINTERFACE , E_NOINTERFACE } ,
{ & IID_IExtractIconW , S_OK , S_OK } ,
{ & IID_IExtractIconA , S_OK , S_OK } ,
{ & IID_IPersist , E_NOINTERFACE , E_NOINTERFACE } ,
{ & IID_IPersistFile , E_NOINTERFACE , E_NOINTERFACE } ,
} ;
2017-12-08 23:51:56 +00:00
static void ExtractOneBitmap ( HBITMAP hbm , CComHeapPtr < BYTE > & data , DWORD & size )
{
HDC hdc = CreateCompatibleDC ( NULL ) ;
HGDIOBJ obj = SelectObject ( hdc , hbm ) ;
CComHeapPtr < BITMAPINFO > pInfoBM ;
pInfoBM . AllocateBytes ( sizeof ( BITMAPINFOHEADER ) + 256 * sizeof ( RGBQUAD ) ) ;
memset ( pInfoBM , 0 , sizeof ( BITMAPINFOHEADER ) + 256 * sizeof ( RGBQUAD ) ) ;
pInfoBM - > bmiHeader . biSize = sizeof ( pInfoBM - > bmiHeader ) ;
if ( ! GetDIBits ( hdc , hbm , 0 , 0 , NULL , pInfoBM , DIB_RGB_COLORS ) )
return ;
size = pInfoBM - > bmiHeader . biSizeImage ;
data . Allocate ( size ) ;
GetDIBits ( hdc , hbm , 0 , pInfoBM - > bmiHeader . biHeight , data , pInfoBM , DIB_RGB_COLORS ) ;
SelectObject ( hdc , obj ) ;
DeleteDC ( hdc ) ;
}
static bool GetIconData ( HICON icon , CComHeapPtr < BYTE > & colorData , DWORD & colorSize , CComHeapPtr < BYTE > & maskData , DWORD & maskSize )
{
ICONINFO iconinfo ;
if ( ! GetIconInfo ( icon , & iconinfo ) )
return false ;
ExtractOneBitmap ( iconinfo . hbmColor , colorData , colorSize ) ;
ExtractOneBitmap ( iconinfo . hbmMask , maskData , maskSize ) ;
DeleteObject ( iconinfo . hbmColor ) ;
DeleteObject ( iconinfo . hbmMask ) ;
return true ;
}
START_TEST ( SHCreateFileExtractIconW )
{
WCHAR CurrentModule [ MAX_PATH ] ;
HMODULE shell32 = LoadLibraryA ( " shell32.dll " ) ;
HICON myIcon ;
pSHCreateFileExtractIconW = ( HRESULT ( __stdcall * ) ( LPCWSTR , DWORD , REFIID , void * * ) ) GetProcAddress ( shell32 , " SHCreateFileExtractIconW " ) ;
2018-03-27 17:58:43 +00:00
/* Show that icons returned are always the same */
UINT tryFlags [ 4 ] = { 0 , GIL_FORSHORTCUT , GIL_OPENICON } ;
2017-12-08 23:51:56 +00:00
CoInitialize ( NULL ) ;
GetModuleFileNameW ( NULL , CurrentModule , _countof ( CurrentModule ) ) ;
{
SHFILEINFOW shfi ;
ULONG_PTR firet = SHGetFileInfoW ( CurrentModule , 0 , & shfi , sizeof ( shfi ) , SHGFI_ICON ) ;
myIcon = shfi . hIcon ;
if ( ! firet )
{
skip ( " Unable to get my own icon \n " ) ;
return ;
}
}
if ( ! pSHCreateFileExtractIconW )
{
skip ( " SHCreateFileExtractIconW not available \n " ) ;
return ;
}
2018-03-27 17:58:43 +00:00
for ( size_t n = 0 ; n < _countof ( InterfaceTests ) ; + + n )
{
{
CComPtr < IUnknown > spUnknown ;
HRESULT hr = pSHCreateFileExtractIconW ( L " test.txt " , FILE_ATTRIBUTE_NORMAL , * InterfaceTests [ n ] . IID , ( void * * ) & spUnknown ) ;
ok ( hr = = InterfaceTests [ n ] . ExpectedCreate , " Expected hr to be 0x%lx, was 0x%lx for %u \n " , InterfaceTests [ n ] . ExpectedCreate , hr , n ) ;
}
{
CComPtr < IUnknown > spUnknown , spUnknown2 ;
HRESULT hr = pSHCreateFileExtractIconW ( L " test.txt " , FILE_ATTRIBUTE_NORMAL , IID_PPV_ARG ( IUnknown , & spUnknown ) ) ;
ok ( hr = = S_OK , " Expected hr to be S_OK, was 0x%lx for %u \n " , hr , n ) ;
hr = spUnknown - > QueryInterface ( * InterfaceTests [ n ] . IID , ( void * * ) & spUnknown2 ) ;
ok ( hr = = InterfaceTests [ n ] . ExpectedQueryInterface , " Expected hr to be 0x%lx, was 0x%lx for %u \n " , InterfaceTests [ n ] . ExpectedQueryInterface , hr , n ) ;
}
}
2017-12-25 12:33:33 +00:00
for ( size_t n = 0 ; n < _countof ( IconTests ) ; + + n )
2017-12-08 23:51:56 +00:00
{
2017-12-25 12:33:33 +00:00
TestData & cur = IconTests [ n ] ;
2017-12-08 23:51:56 +00:00
bool useMyIcon = false ;
if ( cur . Name = = NULL )
{
cur . Name = CurrentModule ;
useMyIcon = true ;
}
CComPtr < IExtractIconW > spExtract ;
HRESULT hr = pSHCreateFileExtractIconW ( cur . Name , cur . dwFlags , IID_PPV_ARG ( IExtractIconW , & spExtract ) ) ;
ok ( hr = = S_OK , " Expected hr to be S_OK, was 0x%lx for %S(%lx) \n " , hr , cur . Name , cur . dwFlags ) ;
if ( ! SUCCEEDED ( hr ) )
continue ;
2018-03-27 17:58:43 +00:00
/* Show that GIL_DEFAULTICON does not work. */
{
int ilIndex = - 1 ;
UINT wFlags = 0xdeaddead ;
WCHAR Buffer [ MAX_PATH ] ;
hr = spExtract - > GetIconLocation ( GIL_DEFAULTICON , Buffer , _countof ( Buffer ) , & ilIndex , & wFlags ) ;
ok ( hr = = S_FALSE , " Expected hr to be S_FALSE, was 0x%lx for %S(0x%lx) \n " , hr , cur . Name , cur . dwFlags ) ;
}
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
for ( UINT idFlags = 0 ; idFlags < _countof ( tryFlags ) ; + + idFlags )
{
int ilIndex = - 1 ;
UINT wFlags = 0xdeaddead ;
WCHAR Buffer [ MAX_PATH ] ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
hr = spExtract - > GetIconLocation ( tryFlags [ idFlags ] , Buffer , _countof ( Buffer ) , & ilIndex , & wFlags ) ;
ok ( hr = = S_OK , " Expected hr to be S_OK, was 0x%lx for %S(0x%lx,0x%x) \n " , hr , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
if ( ! SUCCEEDED ( hr ) )
continue ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
ok ( wFlags & ( GIL_NOTFILENAME | GIL_PERCLASS ) , " Expected GIL_NOTFILENAME|GIL_PERCLASS to be set for %S(0x%lx,0x%x) \n " , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
ok ( ! wcscmp ( Buffer , L " * " ) , " Expected '*', was '%S' for %S(0x%lx,0x%x) \n " , Buffer , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
HICON ico ;
hr = spExtract - > Extract ( Buffer , ilIndex , & ico , NULL , 0 ) ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
/* Visualize the icon extracted for whoever is stepping through this code. */
HWND console = GetConsoleWindow ( ) ;
SendMessage ( console , WM_SETICON , ICON_BIG , ( LPARAM ) ico ) ;
SendMessage ( console , WM_SETICON , ICON_SMALL , ( LPARAM ) ico ) ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
CComHeapPtr < BYTE > colorData , maskData ;
DWORD colorSize = 0 , maskSize = 0 ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
GetIconData ( ico , colorData , colorSize , maskData , maskSize ) ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
if ( ! colorSize | | ! maskSize )
continue ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
SHFILEINFOW shfi ;
ULONG_PTR firet = SHGetFileInfoW ( cur . Name , cur . dwFlags , & shfi , sizeof ( shfi ) , SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SYSICONINDEX ) ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
if ( ! firet )
continue ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
ok ( shfi . iIcon = = ilIndex , " Expected ilIndex to be 0%x, was 0x%x for %S(0x%lx,0x%x) \n " , shfi . iIcon , ilIndex , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
CComHeapPtr < BYTE > colorDataRef , maskDataRef ;
DWORD colorSizeRef = 0 , maskSizeRef = 0 ;
GetIconData ( shfi . hIcon , colorDataRef , colorSizeRef , maskDataRef , maskSizeRef ) ;
2017-12-08 23:51:56 +00:00
2018-03-27 17:58:43 +00:00
ok ( colorSizeRef = = colorSize , " Expected %lu, was %lu for %S(0x%lx,0x%x) \n " , colorSizeRef , colorSize , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
ok ( maskSizeRef = = maskSize , " Expected %lu, was %lu for %S(0x%lx,0x%x) \n " , maskSizeRef , maskSize , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
2017-12-08 23:51:56 +00:00
if ( colorSizeRef = = colorSize )
{
2018-03-27 17:58:43 +00:00
ok ( ! memcmp ( colorData , colorDataRef , colorSize ) , " Expected equal colorData for %S(0x%lx,0x%x) \n " , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
}
if ( maskSizeRef = = maskSize )
{
ok ( ! memcmp ( maskData , maskDataRef , maskSize ) , " Expected equal maskData for %S(0x%lx,0x%x) \n " , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
}
if ( useMyIcon )
{
colorDataRef . Free ( ) ;
maskDataRef . Free ( ) ;
colorSizeRef = maskSizeRef = 0 ;
GetIconData ( myIcon , colorDataRef , colorSizeRef , maskDataRef , maskSizeRef ) ;
ok ( colorSizeRef = = colorSize , " Expected %lu, was %lu for %S(0x%lx,0x%x) \n " , colorSizeRef , colorSize , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
ok ( maskSizeRef = = maskSize , " Expected %lu, was %lu for %S(0x%lx,0x%x) \n " , maskSizeRef , maskSize , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
if ( colorSizeRef = = colorSize )
2017-12-08 23:51:56 +00:00
{
2018-03-27 17:58:43 +00:00
/* In case requested filetype does not match, the exe icon is not used! */
if ( cur . dwFlags = = FILE_ATTRIBUTE_DIRECTORY )
{
ok ( memcmp ( colorData , colorDataRef , colorSize ) , " Expected colorData to be changed for %S(0x%lx,0x%x) \n " , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
}
else
{
ok ( ! memcmp ( colorData , colorDataRef , colorSize ) , " Expected equal colorData for %S(0x%lx,0x%x) \n " , cur . Name , cur . dwFlags , tryFlags [ idFlags ] ) ;
}
2017-12-08 23:51:56 +00:00
}
2018-03-27 17:58:43 +00:00
// Mask is not reliable for some reason
//if (maskSizeRef == maskSize)
//{
// ok(!memcmp(maskData, maskDataRef, maskSize), "Expected equal maskData for %S(0x%lx,0x%lx)\n", cur.Name, cur.dwFlags);
//}
}
2017-12-08 23:51:56 +00:00
}
}
}