[PATCH 3/8] explorerframe/nstc: Add host window and create a treeview.

David Hedberg david.hedberg at gmail.com
Thu Jul 29 14:26:02 CDT 2010


---
 dlls/explorerframe/explorerframe_main.h |    3 +
 dlls/explorerframe/nstc.c               |  211 ++++++++++++++++++++++++++++++-
 dlls/explorerframe/tests/nstc.c         |   49 +++++++-
 3 files changed, 260 insertions(+), 3 deletions(-)

diff --git a/dlls/explorerframe/explorerframe_main.h b/dlls/explorerframe/explorerframe_main.h
index 1abf85a..a933675 100644
--- a/dlls/explorerframe/explorerframe_main.h
+++ b/dlls/explorerframe/explorerframe_main.h
@@ -23,6 +23,9 @@
 
 #include "shlobj.h"
 
+/* Not declared in commctrl.h ("for internal use (msdn)") */
+#define TVS_EX_NOSINGLECOLLAPSE 0x0001
+
 extern HINSTANCE explorerframe_hinstance;
 
 extern LONG EFRAME_refCount;
diff --git a/dlls/explorerframe/nstc.c b/dlls/explorerframe/nstc.c
index 8068e37..8c3b403 100644
--- a/dlls/explorerframe/nstc.c
+++ b/dlls/explorerframe/nstc.c
@@ -35,8 +35,161 @@ WINE_DEFAULT_DEBUG_CHANNEL(nstc);
 typedef struct {
     const INameSpaceTreeControl2Vtbl *lpVtbl;
     LONG ref;
+
+    HWND hwnd_main;
+    HWND hwnd_tv;
+
+    NSTCSTYLE style;
 } 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;
+
+/*************************************************************************
+ * NamespaceTree helper functions
+ */
+static DWORD treeview_style_from_nstcs(NSTC2Impl *This, NSTCSTYLE nstcs,
+                                       NSTCSTYLE nstcs_mask, DWORD *new_style)
+{
+    DWORD old_style, tv_mask = 0;
+    TRACE("%p, %x, %x, %p\n", This, nstcs, nstcs_mask, new_style);
+
+    if(This->hwnd_tv)
+        old_style = GetWindowLongPtrW(This->hwnd_tv, GWL_STYLE);
+    else
+        old_style = /* The default */
+            WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
+            WS_TABSTOP | TVS_NOHSCROLL | TVS_NONEVENHEIGHT | TVS_INFOTIP |
+            TVS_EDITLABELS | TVS_TRACKSELECT;
+
+    if(nstcs_mask & NSTCS_HASEXPANDOS)         tv_mask |= TVS_HASBUTTONS;
+    if(nstcs_mask & NSTCS_HASLINES)            tv_mask |= TVS_HASLINES;
+    if(nstcs_mask & NSTCS_FULLROWSELECT)       tv_mask |= TVS_FULLROWSELECT;
+    if(nstcs_mask & NSTCS_HORIZONTALSCROLL)    tv_mask |= TVS_NOHSCROLL;
+    if(nstcs_mask & NSTCS_ROOTHASEXPANDO)      tv_mask |= TVS_LINESATROOT;
+    if(nstcs_mask & NSTCS_SHOWSELECTIONALWAYS) tv_mask |= TVS_SHOWSELALWAYS;
+    if(nstcs_mask & NSTCS_NOINFOTIP)           tv_mask |= TVS_INFOTIP;
+    if(nstcs_mask & NSTCS_EVENHEIGHT)          tv_mask |= TVS_NONEVENHEIGHT;
+    if(nstcs_mask & NSTCS_DISABLEDRAGDROP)     tv_mask |= TVS_DISABLEDRAGDROP;
+    if(nstcs_mask & NSTCS_NOEDITLABELS)        tv_mask |= TVS_EDITLABELS;
+    if(nstcs_mask & NSTCS_CHECKBOXES)          tv_mask |= TVS_CHECKBOXES;
+
+    *new_style = old_style & ~tv_mask;
+
+    if(nstcs & NSTCS_HASEXPANDOS)         *new_style |= TVS_HASBUTTONS;
+    if(nstcs & NSTCS_HASLINES)            *new_style |= TVS_HASLINES;
+    if(nstcs & NSTCS_FULLROWSELECT)       *new_style |= TVS_FULLROWSELECT;
+    if(!(nstcs & NSTCS_HORIZONTALSCROLL)) *new_style |= TVS_NOHSCROLL;
+    if(nstcs & NSTCS_ROOTHASEXPANDO)      *new_style |= TVS_LINESATROOT;
+    if(nstcs & NSTCS_SHOWSELECTIONALWAYS) *new_style |= TVS_SHOWSELALWAYS;
+    if(!(nstcs & NSTCS_NOINFOTIP))        *new_style |= TVS_INFOTIP;
+    if(!(nstcs & NSTCS_EVENHEIGHT))       *new_style |= TVS_NONEVENHEIGHT;
+    if(nstcs & NSTCS_DISABLEDRAGDROP)     *new_style |= TVS_DISABLEDRAGDROP;
+    if(!(nstcs & NSTCS_NOEDITLABELS))     *new_style |= TVS_EDITLABELS;
+    if(nstcs & NSTCS_CHECKBOXES)          *new_style |= TVS_CHECKBOXES;
+
+    TRACE("old: %08x, new: %08x\n", old_style, *new_style);
+
+    return old_style^*new_style;
+}
+
+/*************************************************************************
+ * NamespaceTree Window Functions
+ */
+static LRESULT create_namespacetree(HWND hWnd, CREATESTRUCTW *crs)
+{
+    NSTC2Impl *This = crs->lpCreateParams;
+    HIMAGELIST ShellSmallIconList;
+    DWORD treeview_style, treeview_ex_style;
+
+    TRACE("%p (%p)\n", This, crs);
+    SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This);
+
+    treeview_style_from_nstcs(This, This->style, 0xFFFFFFFF, &treeview_style);
+
+    /* Create the treeview */
+    This->hwnd_tv = CreateWindowExW(0, WC_TREEVIEWW, NULL, treeview_style,
+                                    0, 0, 0, 0,
+                                    hWnd, NULL, explorerframe_hinstance, NULL);
+
+    if(!This->hwnd_tv)
+    {
+        ERR("Failed to create treeview!\n");
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    /* Some default flags */
+    treeview_ex_style = TVS_EX_DRAWIMAGEASYNC | TVS_EX_RICHTOOLTIP |
+        TVS_EX_DOUBLEBUFFER | TVS_EX_NOSINGLECOLLAPSE;
+
+    if(This->style & NSTCS_AUTOHSCROLL)
+        treeview_ex_style |= TVS_EX_AUTOHSCROLL;
+    if(This->style & NSTCS_FADEINOUTEXPANDOS)
+        treeview_ex_style |= TVS_EX_FADEINOUTEXPANDOS;
+    if(This->style & NSTCS_PARTIALCHECKBOXES)
+        treeview_ex_style |= TVS_EX_PARTIALCHECKBOXES;
+    if(This->style & NSTCS_EXCLUSIONCHECKBOXES)
+        treeview_ex_style |= TVS_EX_EXCLUSIONCHECKBOXES;
+    if(This->style & NSTCS_DIMMEDCHECKBOXES)
+        treeview_ex_style |= TVS_EX_DIMMEDCHECKBOXES;
+
+    SendMessageW(This->hwnd_tv, TVM_SETEXTENDEDSTYLE, treeview_ex_style, 0xffff);
+
+    /* Get and Set the image list */
+    if(Shell_GetImageLists(NULL, &ShellSmallIconList))
+    {
+        SendMessageW(This->hwnd_tv, TVM_SETIMAGELIST,
+                     (WPARAM)TVSIL_NORMAL, (LPARAM)ShellSmallIconList);
+    }
+    else
+    {
+        ERR("Failed to get the System Image List.\n");
+    }
+
+    /* Native is not destroyed until the window is destroyed. */
+    INameSpaceTreeControl_AddRef((INameSpaceTreeControl*)This);
+
+    return TRUE;
+}
+
+static LRESULT resize_namespacetree(NSTC2Impl *This)
+{
+    RECT rc;
+    TRACE("%p\n", This);
+
+    /* Resize the treeview to fit inside the window */
+    GetClientRect(This->hwnd_main, &rc);
+    SetWindowPos(This->hwnd_tv, HWND_TOP, rc.left, rc.top,
+                 rc.right, rc.bottom, SWP_SHOWWINDOW);
+
+    return TRUE;
+}
+
+static LRESULT destroy_namespacetree(NSTC2Impl *This)
+{
+    TRACE("%p\n", This);
+
+    INameSpaceTreeControl_Release((INameSpaceTreeControl*)This);
+    return TRUE;
+}
+
+static LRESULT CALLBACK NSTC2_WndProc(HWND hWnd, UINT uMessage,
+                                      WPARAM wParam, LPARAM lParam)
+{
+    NSTC2Impl *This = (NSTC2Impl*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+
+    switch(uMessage)
+    {
+    case WM_NCCREATE:         return create_namespacetree(hWnd, (CREATESTRUCTW*)lParam);
+    case WM_SIZE:             return resize_namespacetree(This);
+    case WM_DESTROY:          return destroy_namespacetree(This);
+    default:                  return DefWindowProcW(hWnd, uMessage, wParam, lParam);
+    }
+    return 0;
+}
+
 /**************************************************************************
  * INameSpaceTreeControl2 Implementation
  */
@@ -98,8 +251,62 @@ static HRESULT WINAPI NSTC2_fnInitialize(INameSpaceTreeControl2* iface,
                                          NSTCSTYLE nstcsFlags)
 {
     NSTC2Impl *This = (NSTC2Impl*)iface;
-    FIXME("stub, %p (%p, %p, %x)\n", This, hwndParent, prc, nstcsFlags);
-    return E_NOTIMPL;
+    WNDCLASSW wc;
+    DWORD window_style, window_ex_style;
+    static const WCHAR NSTC2_CLASS_NAME[] =
+        {'N','a','m','e','s','p','a','c','e','T','r','e','e',
+         'C','o','n','t','r','o','l',0};
+
+    TRACE("%p (%p, %p, %x)\n", This, hwndParent, prc, nstcsFlags);
+
+    if(nstcsFlags & unsupported_styles)
+        FIXME("0x%08x contains the unsupported style(s) 0x%08x\n",
+              nstcsFlags, nstcsFlags & unsupported_styles);
+
+    /* Save the flags */
+    This->style = nstcsFlags;
+
+    /* Set up the control window */
+    if(!GetClassInfoW(explorerframe_hinstance, NSTC2_CLASS_NAME, &wc))
+    {
+        wc.style            = CS_HREDRAW | CS_VREDRAW;
+        wc.lpfnWndProc      = NSTC2_WndProc;
+        wc.cbClsExtra       = 0;
+        wc.cbWndExtra       = 0;
+        wc.hInstance        = explorerframe_hinstance;
+        wc.hIcon            = 0;
+        wc.hCursor          = LoadCursorW(0, (LPWSTR)IDC_ARROW);
+        wc.hbrBackground    = (HBRUSH)(COLOR_WINDOW + 1);
+        wc.lpszMenuName     = NULL;
+        wc.lpszClassName    = NSTC2_CLASS_NAME;
+
+        if (!RegisterClassW(&wc)) return E_FAIL;
+    }
+
+    /* NSTCS_TABSTOP and NSTCS_BORDER affects the host window */
+    window_style = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
+        (nstcsFlags & NSTCS_BORDER ? WS_BORDER : 0);
+    window_ex_style = nstcsFlags & NSTCS_TABSTOP ? WS_EX_CONTROLPARENT : 0;
+
+    This->hwnd_main = CreateWindowExW(window_ex_style, NSTC2_CLASS_NAME, NULL,
+                                      window_style,
+                                      0, 0, 0, 0, hwndParent, 0,
+                                      explorerframe_hinstance, This);
+
+    if(!This->hwnd_main)
+    {
+        ERR("Failed to create the window.\n");
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    /* Native accepts a NULL prc, so should we. */
+    if(prc)
+        SetWindowPos(This->hwnd_main, HWND_TOP, prc->left, prc->top,
+                     prc->right - prc->left, prc->bottom - prc->top, SWP_SHOWWINDOW);
+
+    UpdateWindow(This->hwnd_main);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI NSTC2_fnTreeAdvise(INameSpaceTreeControl2* iface,
diff --git a/dlls/explorerframe/tests/nstc.c b/dlls/explorerframe/tests/nstc.c
index fdb9d15..0ecec68 100644
--- a/dlls/explorerframe/tests/nstc.c
+++ b/dlls/explorerframe/tests/nstc.c
@@ -33,13 +33,60 @@ static HWND hwnd;
 static void test_initialization(void)
 {
     INameSpaceTreeControl2 *pnstc;
+    IUnknown *punk;
+    LONG lres;
     HRESULT hr;
+    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);
 
-    INameSpaceTreeControl_Release(pnstc);
+    hr = INameSpaceTreeControl_Initialize(pnstc, NULL, NULL, 0);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_TLW_WITH_WSCHILD),
+       "Got (0x%08x)\n", hr);
+
+    hr = INameSpaceTreeControl_Initialize(pnstc, (HWND)0xDEADBEEF, NULL, 0);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_WINDOW_HANDLE), "Got (0x%08x)\n", hr);
+
+    ZeroMemory(&rc, sizeof(RECT));
+    hr = INameSpaceTreeControl_Initialize(pnstc, NULL, &rc, 0);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_TLW_WITH_WSCHILD),
+       "Got (0x%08x)\n", hr);
+
+    hr = INameSpaceTreeControl_Initialize(pnstc, (HWND)0xDEADBEEF, &rc, 0);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_WINDOW_HANDLE),
+       "Got (0x%08x)\n", hr);
+
+    hr = INameSpaceTreeControl_Initialize(pnstc, hwnd, NULL, 0);
+    ok(hr == S_OK, "Got (0x%08x)\n", hr);
+
+    /* Some "random" interfaces */
+    hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleInPlaceObject, (void**)&punk);
+    ok(hr == E_NOINTERFACE || hr == S_OK /* vista, w2k8 */, "Got (0x%08x)\n", hr);
+    if(SUCCEEDED(hr)) IUnknown_Release(punk);
+    hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleInPlaceActiveObject, (void**)&punk);
+    ok(hr == E_NOINTERFACE || hr == S_OK /* vista, w2k8 */, "Got (0x%08x)\n", hr);
+    if(SUCCEEDED(hr)) IUnknown_Release(punk);
+    hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleInPlaceObjectWindowless, (void**)&punk);
+    ok(hr == E_NOINTERFACE || hr == S_OK /* vista, w2k8 */, "Got (0x%08x)\n", hr);
+    if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+    hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleInPlaceUIWindow, (void**)&punk);
+    ok(hr == E_NOINTERFACE, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleInPlaceFrame, (void**)&punk);
+    ok(hr == E_NOINTERFACE, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleInPlaceSite, (void**)&punk);
+    ok(hr == E_NOINTERFACE, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleInPlaceSiteEx, (void**)&punk);
+    ok(hr == E_NOINTERFACE, "Got (0x%08x)\n", hr);
+    hr = INameSpaceTreeControl_QueryInterface(pnstc, &IID_IOleInPlaceSiteWindowless, (void**)&punk);
+    ok(hr == E_NOINTERFACE, "Got (0x%08x)\n", hr);
+
+    /* On windows, the reference count won't go to zero until the
+     * window is destroyed. */
+    lres = INameSpaceTreeControl_Release(pnstc);
+    ok(lres, "lres was %d\n", lres);
 }
 
 static BOOL have_INameSpaceTreeControl(void)
-- 
1.7.2




More information about the wine-patches mailing list