From a5cb7652defc20959d446659a2a2eaa1ad8c5d54 Mon Sep 17 00:00:00 2001 From: David Hedberg Date: Tue, 3 Aug 2010 03:43:09 +0200 Subject: [PATCH] explorerframe: Implement Set/GetControlStyle(2). --- dlls/explorerframe/nstc.c | 81 +++++++++- dlls/explorerframe/tests/nstc.c | 255 +++++++++++++++++++++++++++++++- 2 files changed, 327 insertions(+), 9 deletions(-) diff --git a/dlls/explorerframe/nstc.c b/dlls/explorerframe/nstc.c index e9c8346c5f7..041ffd05b5f 100644 --- a/dlls/explorerframe/nstc.c +++ b/dlls/explorerframe/nstc.c @@ -43,12 +43,16 @@ typedef struct { HWND hwnd_tv; NSTCSTYLE style; + NSTCSTYLE2 style2; } NSTC2Impl; static const DWORD unsupported_styles = NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM | NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS | NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON | NSTCS_SPRINGEXPAND | NSTCS_RICHTOOLTIP | NSTCS_NOINDENTCHECKS; +static const DWORD unsupported_styles2 = + NSTCS2_INTERRUPTNOTIFICATIONS | NSTCS2_SHOWNULLSPACEMENU | NSTCS2_DISPLAYPADDING | + NSTCS2_DISPLAYPINNEDONLY | NTSCS2_NOSINGLETONAUTOEXPAND | NTSCS2_NEVERINSERTNONENUMERATED; /************************************************************************* * NamespaceTree helper functions @@ -476,8 +480,54 @@ static HRESULT WINAPI NSTC2_fnSetControlStyle(INameSpaceTreeControl2* iface, NSTCSTYLE nstcsStyle) { NSTC2Impl *This = (NSTC2Impl*)iface; - FIXME("stub, %p (%x, %x)\n", This, nstcsMask, nstcsStyle); - return E_NOTIMPL; + static const DWORD tv_style_flags = + NSTCS_HASEXPANDOS | NSTCS_HASLINES | NSTCS_FULLROWSELECT | + NSTCS_HORIZONTALSCROLL | NSTCS_ROOTHASEXPANDO | + NSTCS_SHOWSELECTIONALWAYS | NSTCS_NOINFOTIP | NSTCS_EVENHEIGHT | + NSTCS_DISABLEDRAGDROP | NSTCS_NOEDITLABELS | NSTCS_CHECKBOXES; + static const DWORD host_style_flags = NSTCS_TABSTOP | NSTCS_BORDER; + static const DWORD nstc_flags = + NSTCS_SINGLECLICKEXPAND | NSTCS_NOREPLACEOPEN | NSTCS_NOORDERSTREAM | + NSTCS_FAVORITESMODE | NSTCS_EMPTYTEXT | NSTCS_ALLOWJUNCTIONS | + NSTCS_SHOWTABSBUTTON | NSTCS_SHOWDELETEBUTTON | NSTCS_SHOWREFRESHBUTTON; + TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle); + + /* Fail if there is an attempt to set an unknown style. */ + if(nstcsMask & ~(tv_style_flags | host_style_flags | nstc_flags)) + return E_FAIL; + + if(nstcsMask & tv_style_flags) + { + DWORD new_style; + treeview_style_from_nstcs(This, nstcsStyle, nstcsMask, &new_style); + SetWindowLongPtrW(This->hwnd_tv, GWL_STYLE, new_style); + } + + /* Flags affecting the host window */ + if(nstcsMask & NSTCS_BORDER) + { + DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_STYLE); + new_style &= ~WS_BORDER; + new_style |= nstcsStyle & NSTCS_BORDER ? WS_BORDER : 0; + SetWindowLongPtrW(This->hwnd_main, GWL_STYLE, new_style); + } + if(nstcsMask & NSTCS_TABSTOP) + { + DWORD new_style = GetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE); + new_style &= ~WS_EX_CONTROLPARENT; + new_style |= nstcsStyle & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0; + SetWindowLongPtrW(This->hwnd_main, GWL_EXSTYLE, new_style); + } + + if((nstcsStyle & nstcsMask) & unsupported_styles) + FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n", + (nstcsStyle & nstcsMask), + (nstcsStyle & nstcsMask) & unsupported_styles); + + This->style &= ~nstcsMask; + This->style |= (nstcsStyle & nstcsMask); + + return S_OK; } static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface, @@ -485,8 +535,11 @@ static HRESULT WINAPI NSTC2_fnGetControlStyle(INameSpaceTreeControl2* iface, NSTCSTYLE *pnstcsStyle) { NSTC2Impl *This = (NSTC2Impl*)iface; - FIXME("stub, %p (%x, %p)\n", This, nstcsMask, pnstcsStyle); - return E_NOTIMPL; + TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle); + + *pnstcsStyle = (This->style & nstcsMask); + + return S_OK; } static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface, @@ -494,8 +547,17 @@ static HRESULT WINAPI NSTC2_fnSetControlStyle2(INameSpaceTreeControl2* iface, NSTCSTYLE2 nstcsStyle) { NSTC2Impl *This = (NSTC2Impl*)iface; - FIXME("stub, %p (%x, %x)\n", This, nstcsMask, nstcsStyle); - return E_NOTIMPL; + TRACE("%p (%x, %x)\n", This, nstcsMask, nstcsStyle); + + if((nstcsStyle & nstcsMask) & unsupported_styles2) + FIXME("mask & style (0x%08x) contains unsupported style(s): 0x%08x\n", + (nstcsStyle & nstcsMask), + (nstcsStyle & nstcsMask) & unsupported_styles2); + + This->style2 &= ~nstcsMask; + This->style2 |= (nstcsStyle & nstcsMask); + + return S_OK; } static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface, @@ -503,8 +565,11 @@ static HRESULT WINAPI NSTC2_fnGetControlStyle2(INameSpaceTreeControl2* iface, NSTCSTYLE2 *pnstcsStyle) { NSTC2Impl *This = (NSTC2Impl*)iface; - FIXME("stub, %p (%x, %p)\n", This, nstcsMask, pnstcsStyle); - return E_NOTIMPL; + TRACE("%p (%x, %p)\n", This, nstcsMask, pnstcsStyle); + + *pnstcsStyle = (This->style2 & nstcsMask); + + return S_OK; } static const INameSpaceTreeControl2Vtbl vt_INameSpaceTreeControl2 = { diff --git a/dlls/explorerframe/tests/nstc.c b/dlls/explorerframe/tests/nstc.c index 6a72eb349ce..dc8f8f38b42 100644 --- a/dlls/explorerframe/tests/nstc.c +++ b/dlls/explorerframe/tests/nstc.c @@ -181,6 +181,252 @@ static BOOL test_initialization(void) return TRUE; } +static void test_basics(void) +{ + INameSpaceTreeControl *pnstc; + INameSpaceTreeControl2 *pnstc2; + IOleWindow *pow; + HRESULT hr; + UINT i, res; + RECT rc; + + hr = CoCreateInstance(&CLSID_NamespaceTreeControl, NULL, CLSCTX_INPROC_SERVER, + &IID_INameSpaceTreeControl, (void**)&pnstc); + ok(hr == S_OK, "Failed to initialize control (0x%08x)\n", hr); + + /* Initialize the control */ + rc.top = rc.left = 0; rc.right = rc.bottom = 200; + hr = INameSpaceTreeControl_Initialize(pnstc, hwnd, &rc, 0); + ok(hr == S_OK, "Got (0x%08x)\n", hr); + + + /* Set/GetControlStyle(2) */ + hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_INameSpaceTreeControl2, (void**)&pnstc2); + ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Got 0x%08x\n", hr); + if(SUCCEEDED(hr)) + { + DWORD tmp; + NSTCSTYLE style; + NSTCSTYLE2 style2; + static const NSTCSTYLE2 styles2[] = + { NSTCS2_INTERRUPTNOTIFICATIONS,NSTCS2_SHOWNULLSPACEMENU, + NSTCS2_DISPLAYPADDING,NSTCS2_DISPLAYPINNEDONLY, + NTSCS2_NOSINGLETONAUTOEXPAND,NTSCS2_NEVERINSERTNONENUMERATED, 0}; + + + /* We can use this to differentiate between two versions of + * this interface. Windows 7 returns hr == S_OK. */ + hr = INameSpaceTreeControl2_SetControlStyle(pnstc2, 0, 0); + ok(hr == S_OK || broken(hr == E_FAIL), "Got 0x%08x\n", hr); + if(hr == S_OK) + { + static const NSTCSTYLE styles_setable[] = + { NSTCS_HASEXPANDOS,NSTCS_HASLINES,NSTCS_SINGLECLICKEXPAND, + NSTCS_FULLROWSELECT,NSTCS_HORIZONTALSCROLL, + NSTCS_ROOTHASEXPANDO,NSTCS_SHOWSELECTIONALWAYS,NSTCS_NOINFOTIP, + NSTCS_EVENHEIGHT,NSTCS_NOREPLACEOPEN,NSTCS_DISABLEDRAGDROP, + NSTCS_NOORDERSTREAM,NSTCS_BORDER,NSTCS_NOEDITLABELS, + NSTCS_TABSTOP,NSTCS_FAVORITESMODE,NSTCS_EMPTYTEXT,NSTCS_CHECKBOXES, + NSTCS_ALLOWJUNCTIONS,NSTCS_SHOWTABSBUTTON,NSTCS_SHOWDELETEBUTTON, + NSTCS_SHOWREFRESHBUTTON, 0}; + static const NSTCSTYLE styles_nonsetable[] = + { NSTCS_SPRINGEXPAND, NSTCS_RICHTOOLTIP, NSTCS_AUTOHSCROLL, + NSTCS_FADEINOUTEXPANDOS, + NSTCS_PARTIALCHECKBOXES, NSTCS_EXCLUSIONCHECKBOXES, + NSTCS_DIMMEDCHECKBOXES, NSTCS_NOINDENTCHECKS,0}; + + /* Set/GetControlStyle */ + style = style2 = 0xdeadbeef; + hr = INameSpaceTreeControl2_GetControlStyle(pnstc2, 0xFFFFFFFF, &style); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style == 0, "Got style %x\n", style); + + hr = INameSpaceTreeControl2_SetControlStyle(pnstc2, 0, 0xFFFFFFF); + ok(hr == S_OK, "Got 0x%08x\n", hr); + + hr = INameSpaceTreeControl2_SetControlStyle(pnstc2, 0xFFFFFFFF, 0); + ok(hr == E_FAIL, "Got 0x%08x\n", hr); + hr = INameSpaceTreeControl2_SetControlStyle(pnstc2, 0xFFFFFFFF, 0xFFFFFFFF); + ok(hr == E_FAIL, "Got 0x%08x\n", hr); + + tmp = 0; + for(i = 0; styles_setable[i] != 0; i++) + { + hr = INameSpaceTreeControl2_SetControlStyle(pnstc2, styles_setable[i], styles_setable[i]); + ok(hr == S_OK, "Got 0x%08x (%x)\n", hr, styles_setable[i]); + if(SUCCEEDED(hr)) tmp |= styles_setable[i]; + } + for(i = 0; styles_nonsetable[i] != 0; i++) + { + hr = INameSpaceTreeControl2_SetControlStyle(pnstc2, styles_nonsetable[i], styles_nonsetable[i]); + ok(hr == E_FAIL, "Got 0x%08x (%x)\n", hr, styles_nonsetable[i]); + } + + hr = INameSpaceTreeControl2_GetControlStyle(pnstc2, 0xFFFFFFFF, &style); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style == tmp, "Got style %x (expected %x)\n", style, tmp); + if(SUCCEEDED(hr)) + { + DWORD tmp2; + for(i = 0; styles_setable[i] != 0; i++) + { + hr = INameSpaceTreeControl2_GetControlStyle(pnstc2, styles_setable[i], &tmp2); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(tmp2 == (style & styles_setable[i]), "Got %x\n", tmp2); + } + } + + for(i = 0; styles_setable[i] != 0; i++) + { + hr = INameSpaceTreeControl2_SetControlStyle(pnstc2, styles_setable[i], 0); + ok(hr == S_OK, "Got 0x%08x (%x)\n", hr, styles_setable[i]); + } + for(i = 0; styles_nonsetable[i] != 0; i++) + { + hr = INameSpaceTreeControl2_SetControlStyle(pnstc2, styles_nonsetable[i], 0); + ok(hr == E_FAIL, "Got 0x%08x (%x)\n", hr, styles_nonsetable[i]); + } + hr = INameSpaceTreeControl2_GetControlStyle(pnstc2, 0xFFFFFFFF, &style); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style == 0, "Got style %x\n", style); + + /* Set/GetControlStyle2 */ + hr = INameSpaceTreeControl2_GetControlStyle2(pnstc2, 0xFFFFFFFF, &style2); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style2 == 0, "Got style %x\n", style2); + + hr = INameSpaceTreeControl2_SetControlStyle2(pnstc2, 0, 0); + ok(hr == S_OK, "Got 0x%08x\n", hr); + hr = INameSpaceTreeControl2_SetControlStyle2(pnstc2, 0, 0xFFFFFFFF); + ok(hr == S_OK, "Got 0x%08x\n", hr); + + hr = INameSpaceTreeControl2_SetControlStyle2(pnstc2, 0xFFFFFFFF, 0); + ok(hr == S_OK, "Got 0x%08x\n", hr); + hr = INameSpaceTreeControl2_SetControlStyle2(pnstc2, 0xFFFFFFFF, 0xFFFFFFFF); + ok(hr == S_OK, "Got 0x%08x\n", hr); + + hr = INameSpaceTreeControl2_SetControlStyle2(pnstc2, 0xFFFFFFFF, 0); + ok(hr == S_OK, "Got 0x%08x\n", hr); + hr = INameSpaceTreeControl2_GetControlStyle2(pnstc2, 0xFFFFFFFF, &style2); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style2 == 0x00000000, "Got style %x\n", style2); + + hr = INameSpaceTreeControl2_GetControlStyle2(pnstc2, 0xFFFF, &style2); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style2 == 0, "Got style %x\n", style2); + + tmp = 0; + for(i = 0; styles2[i] != 0; i++) + { + hr = INameSpaceTreeControl2_SetControlStyle2(pnstc2, styles2[i], styles2[i]); + ok(hr == S_OK, "Got 0x%08x (%x)\n", hr, styles2[i]); + if(SUCCEEDED(hr)) tmp |= styles2[i]; + } + + hr = INameSpaceTreeControl2_GetControlStyle2(pnstc2, 0xFFFF, &style2); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style2 == tmp, "Got style %x (expected %x)\n", style2, tmp); + if(SUCCEEDED(hr)) + { + DWORD tmp2; + for(i = 0; styles2[i] != 0; i++) + { + hr = INameSpaceTreeControl2_GetControlStyle2(pnstc2, styles2[i], &tmp2); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(tmp2 == (style2 & styles2[i]), "Got %x\n", tmp2); + } + } + + for(i = 0; styles2[i] != 0; i++) + { + hr = INameSpaceTreeControl2_SetControlStyle2(pnstc2, styles2[i], 0); + ok(hr == S_OK, "Got 0x%08x (%x)\n", hr, styles2[i]); + } + hr = INameSpaceTreeControl2_GetControlStyle2(pnstc2, 0xFFFF, &style2); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style2 == 0, "Got style %x (expected 0)\n", style2); + } + else + { + /* 64-bit Windows Vista (others?) seems to have a somewhat + * different idea of how the methods of this interface + * should behave. */ + + static const NSTCSTYLE styles[] = + { NSTCS_HASEXPANDOS,NSTCS_HASLINES,NSTCS_SINGLECLICKEXPAND, + NSTCS_FULLROWSELECT,NSTCS_SPRINGEXPAND,NSTCS_HORIZONTALSCROLL, + NSTCS_RICHTOOLTIP, NSTCS_AUTOHSCROLL, + NSTCS_FADEINOUTEXPANDOS, + NSTCS_PARTIALCHECKBOXES,NSTCS_EXCLUSIONCHECKBOXES, + NSTCS_DIMMEDCHECKBOXES, NSTCS_NOINDENTCHECKS, + NSTCS_ROOTHASEXPANDO,NSTCS_SHOWSELECTIONALWAYS,NSTCS_NOINFOTIP, + NSTCS_EVENHEIGHT,NSTCS_NOREPLACEOPEN,NSTCS_DISABLEDRAGDROP, + NSTCS_NOORDERSTREAM,NSTCS_BORDER,NSTCS_NOEDITLABELS, + NSTCS_TABSTOP,NSTCS_FAVORITESMODE,NSTCS_EMPTYTEXT,NSTCS_CHECKBOXES, + NSTCS_ALLOWJUNCTIONS,NSTCS_SHOWTABSBUTTON,NSTCS_SHOWDELETEBUTTON, + NSTCS_SHOWREFRESHBUTTON, 0}; + trace("Detected broken INameSpaceTreeControl2.\n"); + + style = 0xdeadbeef; + hr = INameSpaceTreeControl2_GetControlStyle(pnstc2, 0xFFFFFFFF, &style); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style == 0xdeadbeef, "Got style %x\n", style); + + hr = INameSpaceTreeControl2_GetControlStyle2(pnstc2, 0xFFFFFFFF, &style2); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style2 == 0, "Got style %x\n", style2); + + tmp = 0; + for(i = 0; styles[i] != 0; i++) + { + hr = INameSpaceTreeControl2_SetControlStyle(pnstc2, styles[i], styles[i]); + ok(hr == E_FAIL || ((styles[i] & NSTCS_SPRINGEXPAND) && hr == S_OK), + "Got 0x%08x (%x)\n", hr, styles[i]); + if(SUCCEEDED(hr)) tmp |= styles[i]; + } + + style = 0xdeadbeef; + hr = INameSpaceTreeControl2_GetControlStyle(pnstc2, tmp, &style); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style == 0xdeadbeef, "Got style %x\n", style); + + tmp = 0; + for(i = 0; styles2[i] != 0; i++) + { + hr = INameSpaceTreeControl2_SetControlStyle2(pnstc2, styles2[i], styles2[i]); + ok(hr == S_OK, "Got 0x%08x (%x)\n", hr, styles2[i]); + if(SUCCEEDED(hr)) tmp |= styles2[i]; + } + + style2 = 0xdeadbeef; + hr = INameSpaceTreeControl2_GetControlStyle2(pnstc2, 0xFFFFFFFF, &style2); + ok(hr == S_OK, "Got 0x%08x\n", hr); + ok(style2 == tmp, "Got style %x\n", style2); + + } + + INameSpaceTreeControl2_Release(pnstc2); + } + else + { + skip("INameSpaceTreeControl2 missing.\n"); + } + + hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleWindow, (void**)&pow); + ok(hr == S_OK, "Got 0x%08x\n", hr); + if(SUCCEEDED(hr)) + { + HWND hwnd_nstc; + hr = IOleWindow_GetWindow(pow, &hwnd_nstc); + ok(hr == S_OK, "Got 0x%08x\n", hr); + DestroyWindow(hwnd_nstc); + IOleWindow_Release(pow); + } + + res = INameSpaceTreeControl_Release(pnstc); + ok(!res, "res was %d!\n", res); +} + static void setup_window(void) { WNDCLASSA wc; @@ -206,7 +452,14 @@ START_TEST(nstc) OleInitialize(NULL); setup_window(); - test_initialization(); + if(test_initialization()) + { + test_basics(); + } + else + { + win_skip("No NamespaceTreeControl (or instantiation failed).\n"); + } destroy_window(); OleUninitialize();