diff --git a/dlls/shell32/ebrowser.c b/dlls/shell32/ebrowser.c index ff035ba513c..9f9308eb406 100644 --- a/dlls/shell32/ebrowser.c +++ b/dlls/shell32/ebrowser.c @@ -31,6 +31,8 @@ #include "wine/debug.h" #include "debughlp.h" +#include "shell32_main.h" + WINE_DEFAULT_DEBUG_CHANNEL(shell); typedef struct _ExplorerBrowserImpl { @@ -38,8 +40,35 @@ typedef struct _ExplorerBrowserImpl { const IShellBrowserVtbl *lpsbVtbl; LONG ref; BOOL destroyed; + + HWND hwnd_main; } ExplorerBrowserImpl; +/************************************************************************** + * Main window related functions. + */ +static LRESULT main_on_wm_create(HWND hWnd, CREATESTRUCTW *crs) +{ + ExplorerBrowserImpl *This = crs->lpCreateParams; + TRACE("%p\n", This); + + SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LPARAM)This); + This->hwnd_main = hWnd; + + return TRUE; +} + +static LRESULT CALLBACK main_wndproc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) +{ + switch(uMessage) + { + case WM_CREATE: return main_on_wm_create(hWnd, (CREATESTRUCTW*)lParam); + default: return DefWindowProcW(hWnd, uMessage, wParam, lParam); + } + + return 0; +} + /************************************************************************** * IExplorerBrowser Implementation */ @@ -103,8 +132,47 @@ static HRESULT WINAPI IExplorerBrowser_fnInitialize(IExplorerBrowser *iface, const FOLDERSETTINGS *pfs) { ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; + WNDCLASSW wc; + LONG style; + static const WCHAR EB_CLASS_NAME[] = + {'E','x','p','l','o','r','e','r','B','r','o','w','s','e','r','C','o','n','t','r','o','l',0}; + TRACE("%p (%p, %p, %p)\n", This, hwndParent, prc, pfs); + if(This->hwnd_main) + return E_UNEXPECTED; + + if(!hwndParent) + return E_INVALIDARG; + + if( !GetClassInfoW(shell32_hInstance, EB_CLASS_NAME, &wc) ) + { + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = main_wndproc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = shell32_hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszMenuName = NULL; + wc.lpszClassName = EB_CLASS_NAME; + + if (!RegisterClassW(&wc)) return E_FAIL; + } + + style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_BORDER; + This->hwnd_main = CreateWindowExW(WS_EX_CONTROLPARENT, EB_CLASS_NAME, NULL, style, + prc->left, prc->top, + prc->right - prc->left, prc->bottom - prc->top, + hwndParent, 0, shell32_hInstance, This); + + if(!This->hwnd_main) + { + ERR("Failed to create the window.\n"); + return E_FAIL; + } + return S_OK; } @@ -113,6 +181,7 @@ static HRESULT WINAPI IExplorerBrowser_fnDestroy(IExplorerBrowser *iface) ExplorerBrowserImpl *This = (ExplorerBrowserImpl*)iface; TRACE("%p\n", This); + DestroyWindow(This->hwnd_main); This->destroyed = TRUE; return S_OK; @@ -294,9 +363,13 @@ static ULONG WINAPI IShellBrowser_fnRelease(IShellBrowser *iface) static HRESULT WINAPI IShellBrowser_fnGetWindow(IShellBrowser *iface, HWND *phwnd) { ExplorerBrowserImpl *This = impl_from_IShellBrowser(iface); - FIXME("stub, %p (%p)\n", This, phwnd); + TRACE("%p (%p)\n", This, phwnd); - return E_NOTIMPL; + if(!This->hwnd_main) + return E_FAIL; + + *phwnd = This->hwnd_main; + return S_OK; } static HRESULT WINAPI IShellBrowser_fnContextSensitiveHelp(IShellBrowser *iface, diff --git a/dlls/shell32/tests/ebrowser.c b/dlls/shell32/tests/ebrowser.c index e2e4b4f33fc..e3f4e9c38ad 100644 --- a/dlls/shell32/tests/ebrowser.c +++ b/dlls/shell32/tests/ebrowser.c @@ -26,6 +26,8 @@ #include "wine/test.h" +static HWND hwnd; + /********************************************************************* * Some simple helpers */ @@ -129,6 +131,140 @@ static void test_SB_misc(void) ok(lres == 0, "Got %d\n", lres); } +static void test_initialization(void) +{ + IExplorerBrowser *peb; + IShellBrowser *psb; + HRESULT hr; + ULONG lres; + RECT rc; + + ebrowser_instantiate(&peb); + + if(0) + { + /* Crashes on Windows 7 */ + hr = IExplorerBrowser_Initialize(peb, NULL, NULL, NULL); + hr = IExplorerBrowser_Initialize(peb, hwnd, NULL, NULL); + } + + ZeroMemory(&rc, sizeof(RECT)); + + hr = IExplorerBrowser_Initialize(peb, NULL, &rc, NULL); + ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr); + + hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL); + ok(hr == S_OK, "got (0x%08x)\n", hr); + + /* Initialize twice */ + hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL); + ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr); + + hr = IExplorerBrowser_Destroy(peb); + ok(hr == S_OK, "got (0x%08x)\n", hr); + + /* Initialize again */ + hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL); + ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr); + + /* Destroy again */ + hr = IExplorerBrowser_Destroy(peb); + ok(hr == S_OK, "got (0x%08x)\n", hr); + lres = IExplorerBrowser_Release(peb); + ok(lres == 0, "Got %d\n", lres); + + /* Initialize with a few different rectangles */ + peb = NULL; + ebrowser_instantiate(&peb); + rc.left = 50; rc.top = 20; rc.right = 100; rc.bottom = 80; + hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL); + ok(hr == S_OK, "got (0x%08x)\n", hr); + hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb); + ok(hr == S_OK, "Got 0x%08x\n", hr); + if(SUCCEEDED(hr)) + { + HWND eb_hwnd; + RECT eb_rc; + char buf[1024]; + LONG style, expected_style; + static const RECT exp_rc = {0, 0, 48, 58}; + + hr = IShellBrowser_GetWindow(psb, &eb_hwnd); + ok(hr == S_OK, "Got 0x%08x\n", hr); + + GetClientRect(eb_hwnd, &eb_rc); + ok(EqualRect(&eb_rc, &exp_rc), "Got client rect (%d, %d)-(%d, %d)\n", + eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom); + + GetWindowRect(eb_hwnd, &eb_rc); + ok(eb_rc.right - eb_rc.left == 50, "Got window width %d\n", eb_rc.right - eb_rc.left); + ok(eb_rc.bottom - eb_rc.top == 60, "Got window height %d\n", eb_rc.bottom - eb_rc.top); + + buf[0] = '\0'; + GetClassNameA(eb_hwnd, buf, 1024); + ok(!lstrcmpA(buf, "ExplorerBrowserControl"), "Unexpected classname %s\n", buf); + + expected_style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER; + style = GetWindowLongPtrW(eb_hwnd, GWL_STYLE); + todo_wine ok(style == expected_style, "Got style 0x%08x, expected 0x%08x\n", style, expected_style); + + expected_style = WS_EX_CONTROLPARENT; + style = GetWindowLongPtrW(eb_hwnd, GWL_EXSTYLE); + ok(style == expected_style, "Got exstyle 0x%08x, expected 0x%08x\n", style, expected_style); + + ok(GetParent(eb_hwnd) == hwnd, "GetParent returns %p\n", GetParent(eb_hwnd)); + + /* ::Destroy() destroys the window. */ + ok(IsWindow(eb_hwnd), "eb_hwnd invalid.\n"); + IExplorerBrowser_Destroy(peb); + ok(!IsWindow(eb_hwnd), "eb_hwnd valid.\n"); + + IShellBrowser_Release(psb); + lres = IExplorerBrowser_Release(peb); + ok(lres == 0, "Got refcount %d\n", lres); + } + else + { + skip("Skipping some tests.\n"); + + IExplorerBrowser_Destroy(peb); + lres = IExplorerBrowser_Release(peb); + ok(lres == 0, "Got refcount %d\n", lres); + } + + ebrowser_instantiate(&peb); + rc.left = 0; rc.top = 0; rc.right = 0; rc.bottom = 0; + hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL); + ok(hr == S_OK, "got (0x%08x)\n", hr); + IExplorerBrowser_Destroy(peb); + lres = IExplorerBrowser_Release(peb); + ok(lres == 0, "Got refcount %d\n", lres); + + ebrowser_instantiate(&peb); + rc.left = -1; rc.top = -1; rc.right = 1; rc.bottom = 1; + hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL); + ok(hr == S_OK, "got (0x%08x)\n", hr); + IExplorerBrowser_Destroy(peb); + lres = IExplorerBrowser_Release(peb); + ok(lres == 0, "Got refcount %d\n", lres); + + ebrowser_instantiate(&peb); + rc.left = 10; rc.top = 10; rc.right = 5; rc.bottom = 5; + hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL); + ok(hr == S_OK, "got (0x%08x)\n", hr); + IExplorerBrowser_Destroy(peb); + lres = IExplorerBrowser_Release(peb); + ok(lres == 0, "Got refcount %d\n", lres); + + ebrowser_instantiate(&peb); + rc.left = 10; rc.top = 10; rc.right = 5; rc.bottom = 5; + hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL); + ok(hr == S_OK, "got (0x%08x)\n", hr); + IExplorerBrowser_Destroy(peb); + lres = IExplorerBrowser_Release(peb); + ok(lres == 0, "Got refcount %d\n", lres); +} + static BOOL test_instantiate_control(void) { IExplorerBrowser *peb; @@ -143,6 +279,21 @@ static BOOL test_instantiate_control(void) return TRUE; } +static void setup_window(void) +{ + WNDCLASSW wc; + static const WCHAR ebtestW[] = {'e','b','t','e','s','t',0}; + + ZeroMemory(&wc, sizeof(WNDCLASSW)); + wc.lpfnWndProc = DefWindowProcW; + wc.lpszClassName = ebtestW; + RegisterClassW(&wc); + hwnd = CreateWindowExW(0, ebtestW, NULL, 0, + 0, 0, 500, 500, + NULL, 0, 0, NULL); + ok(hwnd != NULL, "Failed to create window for tests.\n"); +} + START_TEST(ebrowser) { OleInitialize(NULL); @@ -154,8 +305,12 @@ START_TEST(ebrowser) return; } + setup_window(); + test_QueryInterface(); test_SB_misc(); + test_initialization(); + DestroyWindow(hwnd); OleUninitialize(); }