diff --git a/rostests/apitests/browseui/ACListISF.cpp b/rostests/apitests/browseui/ACListISF.cpp new file mode 100644 index 00000000000..59607dd58ad --- /dev/null +++ b/rostests/apitests/browseui/ACListISF.cpp @@ -0,0 +1,472 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Test for ACListISF objects + * PROGRAMMER: Mark Jansen + */ + +#define _UNICODE +#define UNICODE +#include +#include +#include +#include // +#include // These 3 includes only exist here to make gcc happy about (unused) templates.. +#include // + +// Yes, gcc at it again, let's validate everything found inside unused templates! +ULONG DbgPrint(PCH Format,...); + +#include +#include +#include + +static bool g_ShowHidden; +static DWORD g_WinVersion; +#define WINVER_VISTA 0x0600 + + +#define ok_hr(status, expected) ok_hex(status, expected) + +// We do not want our results to originate from the helper functions, so have them originate from the calls to them +#define test_at_end (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_at_end_imp +#define test_ExpectDrives (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_ExpectDrives_imp +#define test_ExpectFolders (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_ExpectFolders_imp +#define winetest_ok_hr(expression, expected) \ + do { \ + int _value = (expression); \ + winetest_ok(_value == (expected), "Wrong value for '%s', expected: " #expected " (0x%x), got: 0x%x\n", \ + #expression, (int)(expected), _value); \ + } while (0) + + + + +static void test_at_end_imp(CComPtr& EnumStr) +{ + CComHeapPtr Result; + ULONG Fetched = 12345; + HRESULT hr = EnumStr->Next(1, &Result, &Fetched); + winetest_ok(hr == S_FALSE, "Expected hr to be S_FALSE, was 0x%lx\n", hr); + winetest_ok(Fetched == 0u, "Expected Fetched to be 0, was: %lu\n", Fetched); + if (Fetched == 1u) + winetest_ok(0, "Expected there not to be a result, got: %s\n", wine_dbgstr_w(Result)); +} + +static bool GetDisplayname(CComPtr& spDrives, CComHeapPtr& pidl, CComHeapPtr& DisplayName) +{ + STRRET StrRet; + HRESULT hr; + winetest_ok_hr(hr = spDrives->GetDisplayNameOf(pidl, SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR, &StrRet), S_OK); + if (!SUCCEEDED(hr)) + return false; + + winetest_ok_hr(hr = StrRetToStrW(&StrRet, NULL, &DisplayName), S_OK); + if (!SUCCEEDED(hr)) + return false; + return true; +} + +enum ExpectOptions +{ + None = 0, + IgnoreRoot = 1, + CheckLast = 2, + IgnoreHidden = 4, + IgnoreFiles = 8, +}; + +// wtf c++ +ExpectOptions operator | (const ExpectOptions& left, const ExpectOptions& right) +{ + return static_cast(static_cast(left) | static_cast(right)); +} + + +static void +test_ExpectFolders_imp(CComPtr& EnumStr, LPITEMIDLIST pidlTarget, const WCHAR* Root, ExpectOptions options) +{ + CComPtr spDesktop; + HRESULT hr = SHGetDesktopFolder(&spDesktop); + + CComPtr spTarget; + if (pidlTarget) + { + winetest_ok_hr(hr = spDesktop->BindToObject(pidlTarget, NULL, IID_PPV_ARG(IShellFolder, &spTarget)), S_OK); + if (!SUCCEEDED(hr)) + return; + } + else + { + spTarget = spDesktop; + } + + SHCONTF EnumFlags = SHCONTF_FOLDERS | SHCONTF_INIT_ON_FIRST_NEXT; + if (g_ShowHidden && !(options & IgnoreHidden)) + EnumFlags |= SHCONTF_INCLUDEHIDDEN; + if (!(options & IgnoreFiles)) + EnumFlags |= SHCONTF_NONFOLDERS; + + CComPtr spEnumIDList; + winetest_ok_hr(hr = spTarget->EnumObjects(NULL, EnumFlags, &spEnumIDList), S_OK); + if (!SUCCEEDED(hr)) + return; + + WCHAR Buffer[512]; + CComHeapPtr pidl; + INT Count = 0; + while (spEnumIDList->Next(1, &pidl, NULL) == S_OK) + { + CComHeapPtr DisplayName; + if (!GetDisplayname(spTarget, pidl, DisplayName)) + break; + + CComHeapPtr Result; + ULONG Fetched; + hr = EnumStr->Next(1, &Result, &Fetched); + winetest_ok_hr(hr, S_OK); + + + if (hr != S_OK) + break; + + + StringCchPrintfW(Buffer, _ARRAYSIZE(Buffer), L"%s%s", (options & IgnoreRoot) ? L"" : Root, (WCHAR*)DisplayName); + + winetest_ok(!wcscmp(Buffer, Result), "Expected %s, got %s\n", wine_dbgstr_w(Buffer), wine_dbgstr_w(Result)); + + pidl.Free(); + Count++; + } + if (options & CheckLast) + { + test_at_end_imp(EnumStr); + } +} + +static void +test_ExpectDrives_imp(CComPtr& EnumStr, CComHeapPtr& pidlTarget) +{ + test_ExpectFolders_imp(EnumStr, pidlTarget, NULL, IgnoreRoot | CheckLast); +} + +static void +test_ACListISF_NONE() +{ + CComPtr EnumStr; + HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); + ok_hr(hr, S_OK); + if (!SUCCEEDED(hr)) + return; + + CComPtr ACList; + ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); + if (!SUCCEEDED(hr)) + return; + + ok_hr(hr = ACList->SetOptions(ACLO_NONE), S_OK); + test_at_end(EnumStr); + + + WCHAR Buffer[MAX_PATH]; + GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer)); + Buffer[3] = '\0'; + + CComHeapPtr pidlDiskRoot; + ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK); + if (!SUCCEEDED(hr)) + return; + + ok_hr(hr = ACList->Expand(Buffer), S_OK); + test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast | IgnoreHidden); + + ok_hr(hr = EnumStr->Reset(), S_OK); + ok_hr(hr = ACList->Expand(Buffer), S_OK); + ok_hr(hr = ACList->SetOptions(ACLO_NONE), S_OK); + test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast); +} + +static void +test_ACListISF_CURRENTDIR() +{ + CComPtr EnumStr; + HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); + ok_hr(hr, S_OK); + if (!SUCCEEDED(hr)) + return; + + CComPtr ACList; + ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); + if (!SUCCEEDED(hr)) + return; + + CComPtr CurrentWorkingDir; + ok_hr(hr = EnumStr->QueryInterface(IID_ICurrentWorkingDirectory, (void**)&CurrentWorkingDir), S_OK); + if (!SUCCEEDED(hr)) + return; + + ok_hr(hr = ACList->SetOptions(ACLO_CURRENTDIR), S_OK); + test_at_end(EnumStr); + + + WCHAR Buffer[MAX_PATH] = { 1, 1, 1, 1, 1, 0 }, Buffer2[MAX_PATH]; + if (g_WinVersion < WINVER_VISTA) + ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_NOTIMPL); + else + ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_UNEXPECTED); + ok(!wcscmp(L"\x1\x1\x1\x1\x1", Buffer), "Expected %s, got %s\n", wine_dbgstr_w(L"\x1\x1\x1\x1\x1"), wine_dbgstr_w(Buffer)); + + GetSystemWindowsDirectoryW(Buffer2, _ARRAYSIZE(Buffer2)); + // Windows 2k3 does not parse it without the trailing '\\' + Buffer2[3] = '\0'; + CComHeapPtr pidlDiskRoot; + ok_hr(hr = SHParseDisplayName(Buffer2, NULL, &pidlDiskRoot, NULL, NULL), S_OK); + if (!SUCCEEDED(hr)) + return; + + ok_hr(hr = CurrentWorkingDir->SetDirectory(Buffer2), S_OK); + test_at_end(EnumStr); + + Buffer[0] = '\0'; + if (g_WinVersion < WINVER_VISTA) + { + ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_NOTIMPL); + } + else + { + ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), S_OK); + ok(!wcscmp(Buffer2, Buffer), "Expected %s, got %s\n", wine_dbgstr_w(Buffer2), wine_dbgstr_w(Buffer)); + } + + Buffer2[2] = '\0'; + ok_hr(hr = CurrentWorkingDir->SetDirectory(Buffer2), S_OK); + test_at_end(EnumStr); + + Buffer[0] = '\0'; + Buffer2[2] = '\\'; + if (g_WinVersion < WINVER_VISTA) + { + ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_NOTIMPL); + } + else + { + ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), S_OK); + ok(!wcscmp(Buffer2, Buffer), "Expected %s, got %s\n", wine_dbgstr_w(Buffer2), wine_dbgstr_w(Buffer)); + } + + ok_hr(hr = ACList->Expand(Buffer2), S_OK); + // The first set of results are absolute paths, without hidden files?! + test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer2, IgnoreHidden); + test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer2, IgnoreHidden | IgnoreRoot | CheckLast); +} + +static void +test_ACListISF_MYCOMPUTER() +{ + CComPtr ACList; + HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IACList2, &ACList)); + ok_hr(hr, S_OK); + if (!SUCCEEDED(hr)) + return; + + // Check the default + DWORD CurrentOption = 0xdeadbeef; + ok_hr(ACList->GetOptions(&CurrentOption), S_OK); + ok(CurrentOption == (ACLO_CURRENTDIR|ACLO_MYCOMPUTER), "Expected the default to be %x, was %lx\n", + (ACLO_CURRENTDIR|ACLO_MYCOMPUTER), CurrentOption); + + + CComPtr EnumStr; + ok_hr(hr = ACList->QueryInterface(IID_IEnumString, (void**)&EnumStr), S_OK); + if (!SUCCEEDED(hr)) + return; + + CComPtr PersistFolder; + ok_hr(hr = EnumStr->QueryInterface(IID_IPersistFolder, (void**)&PersistFolder), S_OK); + if (!SUCCEEDED(hr)) + return; + + CComHeapPtr pidlMyComputer; + ok_hr(hr = SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlMyComputer), S_OK); + if (!SUCCEEDED(hr)) + return; + + + hr = EnumStr->Reset(); + if (g_WinVersion < WINVER_VISTA) + ok_hr(hr, S_FALSE); + else + ok_hr(hr, S_OK); + test_ExpectDrives(EnumStr, pidlMyComputer); + + ok_hr(hr = ACList->SetOptions(ACLO_MYCOMPUTER), S_OK); + ok_hr(EnumStr->Reset(), S_OK); + test_ExpectDrives(EnumStr, pidlMyComputer); + + WCHAR Buffer[MAX_PATH]; + GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer)); + // Windows 2k3 does not parse it without the trailing '\\' + Buffer[3] = '\0'; + CComHeapPtr pidlDiskRoot; + ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK); + if (!SUCCEEDED(hr)) + return; + Buffer[2] = '\0'; + + ok_hr(hr = ACList->Expand(Buffer), S_OK); + test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, None); + test_ExpectDrives(EnumStr, pidlMyComputer); + + ok_hr(hr = ACList->Expand(Buffer), S_OK); + ok_hr(EnumStr->Reset(), S_OK); + // Pre vista does not remove the expanded data from the enumeration, it changes it to relative paths??? + if (g_WinVersion < WINVER_VISTA) + test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, IgnoreRoot); + test_ExpectDrives(EnumStr, pidlMyComputer); + + ok_hr(EnumStr->Reset(), S_OK); + ok_hr(hr = ACList->Expand(Buffer), S_OK); + test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, None); + test_ExpectDrives(EnumStr, pidlMyComputer); +} + +static void +test_ACListISF_DESKTOP() +{ + CComPtr EnumStr; + HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); + ok_hr(hr, S_OK); + if (!SUCCEEDED(hr)) + return; + + CComPtr ACList; + ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); + if (!SUCCEEDED(hr)) + return; + + ok_hr(hr = ACList->SetOptions(ACLO_DESKTOP), S_OK); + test_ExpectFolders(EnumStr, NULL, NULL, IgnoreRoot | CheckLast | IgnoreHidden); +} + +static void +test_ACListISF_FAVORITES() +{ + CComPtr EnumStr; + HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); + ok_hr(hr, S_OK); + if (!SUCCEEDED(hr)) + return; + + CComPtr ACList; + ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); + if (!SUCCEEDED(hr)) + return; + + CComHeapPtr pidlFavorites; + ok_hr(hr = SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidlFavorites), S_OK); + if (!SUCCEEDED(hr)) + return; + + ok_hr(hr = ACList->SetOptions(ACLO_FAVORITES), S_OK); + test_ExpectFolders(EnumStr, pidlFavorites, NULL, IgnoreRoot | CheckLast | IgnoreHidden); +} + +static void +test_ACListISF_FILESYSONLY() +{ + CComPtr EnumStr; + HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); + ok_hr(hr, S_OK); + if (!SUCCEEDED(hr)) + return; + + CComPtr ACList; + ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); + if (!SUCCEEDED(hr)) + return; + + WCHAR Buffer[MAX_PATH]; + GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer)); + // Windows 2k3 does not parse it without the trailing '\\' + Buffer[3] = '\0'; + CComHeapPtr pidlDiskRoot; + ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK); + if (!SUCCEEDED(hr)) + return; + + ok_hr(hr = ACList->SetOptions(ACLO_FILESYSONLY), S_OK); + test_at_end(EnumStr); + + ok_hr(hr = ACList->Expand(Buffer), S_OK); + test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast | IgnoreHidden); +} + +static void +test_ACListISF_FILESYSDIRS() +{ + CComPtr EnumStr; + HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr)); + ok_hr(hr, S_OK); + if (!SUCCEEDED(hr)) + return; + + CComPtr ACList; + ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK); + if (!SUCCEEDED(hr)) + return; + + WCHAR Buffer[MAX_PATH]; + GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer)); + // Windows 2k3 does not parse it without the trailing '\\' + Buffer[3] = '\0'; + CComHeapPtr pidlDiskRoot; + ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK); + if (!SUCCEEDED(hr)) + return; + + ok_hr(hr = ACList->SetOptions(ACLO_FILESYSDIRS), S_OK); + test_at_end(EnumStr); + + ok_hr(hr = ACList->Expand(Buffer), S_OK); + test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast | IgnoreFiles | IgnoreHidden); +} + +static void GetEnvStatus() +{ + RTL_OSVERSIONINFOEXW rtlinfo = {0}; + void (__stdcall* pRtlGetVersion)(RTL_OSVERSIONINFOEXW*); + pRtlGetVersion = (void (__stdcall*)(RTL_OSVERSIONINFOEXW*))GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion"); + + rtlinfo.dwOSVersionInfoSize = sizeof(rtlinfo); + pRtlGetVersion(&rtlinfo); + g_WinVersion = (rtlinfo.dwMajorVersion << 8) | rtlinfo.dwMinorVersion; + + SHELLFLAGSTATE sfs = {0}; + SHGetSettings(&sfs, SSF_SHOWALLOBJECTS); + g_ShowHidden = !!sfs.fShowAllObjects; + trace("Show hidden folders: %s\n", g_ShowHidden ? "yes" : "no"); +} + +struct CCoInit +{ + CCoInit() { hres = CoInitialize(NULL); } + ~CCoInit() { if (SUCCEEDED(hres)) { CoUninitialize(); } } + HRESULT hres; +}; + +START_TEST(ACListISF) +{ + GetEnvStatus(); + CCoInit init; + ok_hr(init.hres, S_OK); + if (!SUCCEEDED(init.hres)) + return; + + test_ACListISF_NONE(); + test_ACListISF_CURRENTDIR(); + test_ACListISF_MYCOMPUTER(); + test_ACListISF_DESKTOP(); + test_ACListISF_FAVORITES(); + test_ACListISF_FILESYSONLY(); + test_ACListISF_FILESYSDIRS(); +} diff --git a/rostests/apitests/browseui/CMakeLists.txt b/rostests/apitests/browseui/CMakeLists.txt index d8cb019e794..e3d9700cba2 100644 --- a/rostests/apitests/browseui/CMakeLists.txt +++ b/rostests/apitests/browseui/CMakeLists.txt @@ -1,10 +1,21 @@ +set_cpp(WITH_RTTI WITH_RUNTIME WITH_EXCEPTIONS) +if(NOT MSVC) + # HACK: this should be enabled globally! + add_compile_flags_language("-std=c++11" "CXX") +endif() + +include_directories( + ${REACTOS_SOURCE_DIR}/sdk/lib/atl + includes) + list(APPEND SOURCE + ACListISF.cpp SHExplorerParseCmdLine.c testlist.c) add_executable(browseui_apitest ${SOURCE}) -target_link_libraries(browseui_apitest wine) +target_link_libraries(browseui_apitest uuid wine) set_module_type(browseui_apitest win32cui) -add_importlibs(browseui_apitest browseui shell32 msvcrt kernel32 ntdll) +add_importlibs(browseui_apitest shell32 ole32 shlwapi msvcrt kernel32 ntdll) add_cd_file(TARGET browseui_apitest DESTINATION reactos/bin FOR all) diff --git a/rostests/apitests/browseui/SHExplorerParseCmdLine.c b/rostests/apitests/browseui/SHExplorerParseCmdLine.c index 293e833a37a..97b2ddc1f06 100644 --- a/rostests/apitests/browseui/SHExplorerParseCmdLine.c +++ b/rostests/apitests/browseui/SHExplorerParseCmdLine.c @@ -35,10 +35,7 @@ typedef struct _EXPLORER_INFO ULONG Padding[PADDING_SIZE]; } EXPLORER_INFO, *PEXPLORER_INFO; -UINT -WINAPI -SHExplorerParseCmdLine( -_Out_ PEXPLORER_INFO Info); +UINT (WINAPI *SHExplorerParseCmdLine)(_Out_ PEXPLORER_INFO Info); #define PIDL_IS_UNTOUCHED -1 #define PIDL_IS_NULL -2 @@ -346,6 +343,14 @@ START_TEST(SHExplorerParseCmdLine) UINT maxWrite = 0; FILE * ff; + HMODULE browseui = LoadLibraryA("browseui.dll"); + SHExplorerParseCmdLine = (UINT (__stdcall *)(PEXPLORER_INFO))GetProcAddress(browseui, MAKEINTRESOURCEA(107)); + if (!SHExplorerParseCmdLine) + { + skip("SHExplorerParseCmdLine not found, NT 6.0?\n"); + return; + } + CommandLine = GetCommandLineW(); StringCbCopyW(OriginalCommandLine, sizeof(OriginalCommandLine), CommandLine); diff --git a/rostests/apitests/browseui/testlist.c b/rostests/apitests/browseui/testlist.c index 9ab96c76775..0684387d42b 100644 --- a/rostests/apitests/browseui/testlist.c +++ b/rostests/apitests/browseui/testlist.c @@ -3,10 +3,12 @@ #define STANDALONE #include +extern void func_ACListISF(void); extern void func_SHExplorerParseCmdLine(void); const struct test winetest_testlist[] = { + { "ACListISF", func_ACListISF }, { "SHExplorerParseCmdLine", func_SHExplorerParseCmdLine }, { 0, 0 }