--- /dev/null
- #define USE_CUSTOM_MENUBAND 1
+/*
+ * ReactOS Explorer
+ *
+ * Copyright 2009 Andrew Hill <ash77 at domain reactos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+Implements a class that knows how to hold and manage the menu band, brand band,
+toolbar, and address band for an explorer window
+*/
+
+#include "precomp.h"
+
+/* FIXME, I can't include windowsx because it conflicts with some #defines */
+#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
+#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
+
++#define USE_CUSTOM_MENUBAND 0
+
+// navigation controls and menubar just send a message to parent window
+/*
+TODO:
+****Implement BandProxy methods
+****Add QueryStatus handler for built-in bands
+****Enable/Disable up, search, and folders commands appropriately
+ **Why are explorer toolbar separators a nonstandard width?
+ **Remove "(Empty)" item from Favorites menu. Probably something missing in CMenuCallback::CallbackSM
+ **Chevron menu on menuband doesn't work
+ **Fix CInternetToolbar::QueryBand to be generic
+
+****Fix context menu to strip divider when menu shown for menu band
+****Fix context menu to have items checked appropriately
+****Implement -1 command id update
+****When bands are rearranged, resize the internet toolbar and fix height of brand band
+****Right clicking on the browse back and forward toolbar buttons displays the same as pulldown menus
+ Implement show/hide of bands
+ Why is the background color of my toolbars different from explorer?
+ Internet Toolbar command handler should get the target for the command and call Exec on the target.
+ For commands built in to the Internet Toolbar, its Exec handles the command
+ When window width is changed, brand band flashes badly
+ Add all bands with correct ids (system bands now add with correct ids)
+ Implement IBandSite
+ Implement remaining IExplorerToolbar methods
+ Fix toolbar buttons to enable/disable correctly
+ After toolbar is customized, it may be necessary to patch the widths of separators
+ Add theme support
+ Check sizes and spacing of toolbars against Explorer
+ Implement resizing of the dock bar
+ Add missing icons for toolbar items
+ Draw History item in forward/back dropdown menus with icon
+ Fix toolbar customize dialog to not include separators as possible selections
+ Implement save/restore of toolbar state
+ Refactor drop down menu code to use a common function since code is so similar
+*/
+
+extern HRESULT WINAPI SHBindToFolder(LPCITEMIDLIST path, IShellFolder **newFolder);
+extern HRESULT CreateToolsBar(REFIID riid, void **ppv);
+extern HRESULT CreateBrandBand(REFIID riid, void **ppv);
+extern HRESULT CreateBandProxy(REFIID riid, void **ppv);
+extern HRESULT CreateAddressBand(REFIID riid, void **ppv);
+
+typedef HRESULT(*PMENUBAND_CONSTRUCTOR)(REFIID riid, void **ppv);
+
+class CInternetToolbar;
+
+class CDockSite :
+ public CComObjectRootEx<CComMultiThreadModelNoCS>,
+ public IDockingWindowSite,
+ public IInputObjectSite,
+ public IOleCommandTarget,
+ public IServiceProvider
+{
+public:
+ enum {
+ ITF_NOGRIPPER = 1,
+ ITF_NOTITLE = 2,
+ ITF_NEWBANDALWAYS = 4,
+ ITF_GRIPPERALWAYS = 8,
+ ITF_FIXEDSIZE = 16
+ };
+private:
+ CComPtr<IUnknown> fContainedBand; // the band inside us
+ CInternetToolbar *fToolbar; // our browser
+ HWND fRebarWindow;
+ HWND fChildWindow;
+ int fBandID;
+public:
+ int fFlags;
+private:
+ bool fInitialized;
+ // fields of DESKBANDINFO must be preserved between calls to GetBandInfo
+ DESKBANDINFO fDeskBandInfo;
+public:
+ CDockSite();
+ ~CDockSite();
+ HRESULT Initialize(IUnknown *containedBand, CInternetToolbar *browser, HWND hwnd, int bandID, int flags);
+ HRESULT GetRBBandInfo(REBARBANDINFOW &bandInfo);
+private:
+
+ // *** IOleWindow methods ***
+ virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
+ virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
+
+ // *** IDockingWindow methods ***
+ virtual HRESULT STDMETHODCALLTYPE GetBorderDW(IUnknown* punkObj, LPRECT prcBorder);
+ virtual HRESULT STDMETHODCALLTYPE RequestBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw);
+ virtual HRESULT STDMETHODCALLTYPE SetBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw);
+
+ // *** IInputObjectSite specific methods ***
+ virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus);
+
+ // *** IOleCommandTarget specific methods ***
+ virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
+ OLECMD prgCmds[ ], OLECMDTEXT *pCmdText);
+ virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
+ DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
+
+ // *** IServiceProvider methods ***
+ virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
+
+BEGIN_COM_MAP(CDockSite)
+ COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
+ COM_INTERFACE_ENTRY_IID(IID_IDockingWindowSite, IDockingWindowSite)
+ COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite)
+ COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
+ COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
+END_COM_MAP()
+};
+
+CDockSite::CDockSite()
+{
+ fToolbar = NULL;
+ fRebarWindow = NULL;
+ fChildWindow = NULL;
+ fBandID = 0;
+ fFlags = 0;
+ fInitialized = false;
+ memset(&fDeskBandInfo, 0, sizeof(fDeskBandInfo));
+}
+
+CDockSite::~CDockSite()
+{
+}
+
+HRESULT CDockSite::Initialize(IUnknown *containedBand, CInternetToolbar *browser, HWND hwnd, int bandID, int flags)
+{
+ CComPtr<IObjectWithSite> child;
+ CComPtr<IOleWindow> oleWindow;
+ CComPtr<IDeskBand> deskBand;
+ TCHAR textBuffer[40];
+ REBARBANDINFOW bandInfo;
+ HRESULT hResult;
+
+ hResult = containedBand->QueryInterface(IID_PPV_ARG(IObjectWithSite, &child));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = containedBand->QueryInterface(IID_PPV_ARG(IOleWindow, &oleWindow));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = containedBand->QueryInterface(IID_PPV_ARG(IDeskBand, &deskBand));
+ if (FAILED(hResult))
+ return hResult;
+ fContainedBand = containedBand;
+ fToolbar = browser;
+ fRebarWindow = hwnd;
+ fBandID = bandID;
+ fFlags = flags;
+ hResult = child->SetSite(static_cast<IOleWindow *>(this));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = oleWindow->GetWindow(&fChildWindow);
+ if (FAILED(hResult))
+ return hResult;
+
+ memset(&bandInfo, 0, sizeof(bandInfo));
+ bandInfo.cbSize = sizeof(bandInfo);
+ bandInfo.lpText = textBuffer;
+ bandInfo.cch = sizeof(textBuffer) / sizeof(TCHAR);
+ hResult = GetRBBandInfo(bandInfo);
+
+ SendMessage(fRebarWindow, RB_GETBANDCOUNT, 0, 0);
+ SendMessage(fRebarWindow, RB_INSERTBANDW, -1, (LPARAM)&bandInfo);
+ fInitialized = true;
+ return S_OK;
+}
+
+HRESULT CDockSite::GetRBBandInfo(REBARBANDINFOW &bandInfo)
+{
+ CComPtr<IDeskBand> deskBand;
+ HRESULT hResult;
+
+ hResult = fContainedBand->QueryInterface(IID_PPV_ARG(IDeskBand, &deskBand));
+ if (FAILED(hResult))
+ return hResult;
+
+ fDeskBandInfo.dwMask = DBIM_BKCOLOR | DBIM_MODEFLAGS | DBIM_TITLE | DBIM_ACTUAL |
+ DBIM_INTEGRAL | DBIM_MAXSIZE | DBIM_MINSIZE;
+ hResult = deskBand->GetBandInfo(fBandID, 0, &fDeskBandInfo);
+ // result of call is ignored
+
+ bandInfo.fMask = RBBIM_LPARAM | RBBIM_IDEALSIZE | RBBIM_ID | RBBIM_CHILDSIZE | RBBIM_CHILD |
+ RBBIM_TEXT | RBBIM_STYLE;
+
+ bandInfo.fStyle = RBBS_FIXEDBMP;
+ if (fDeskBandInfo.dwModeFlags & DBIMF_VARIABLEHEIGHT)
+ bandInfo.fStyle |= RBBS_VARIABLEHEIGHT;
+ if (fDeskBandInfo.dwModeFlags & DBIMF_USECHEVRON)
+ bandInfo.fStyle |= RBBS_USECHEVRON;
+ if (fDeskBandInfo.dwModeFlags & DBIMF_BREAK)
+ bandInfo.fStyle |= RBBS_BREAK;
+ if (fDeskBandInfo.dwModeFlags & DBIMF_TOPALIGN)
+ bandInfo.fStyle |= RBBS_TOPALIGN;
+ if (fFlags & ITF_NOGRIPPER || fToolbar->fLocked)
+ bandInfo.fStyle |= RBBS_NOGRIPPER;
+ if (fFlags & ITF_NOTITLE)
+ bandInfo.fStyle |= RBBS_HIDETITLE;
+ if (fFlags & ITF_GRIPPERALWAYS && !fToolbar->fLocked)
+ bandInfo.fStyle |= RBBS_GRIPPERALWAYS;
+ if (fFlags & ITF_FIXEDSIZE)
+ bandInfo.fStyle |= RBBS_FIXEDSIZE;
+
+ if (fDeskBandInfo.dwModeFlags & DBIMF_BKCOLOR)
+ {
+ bandInfo.fMask |= RBBIM_COLORS;
+ bandInfo.clrFore = CLR_DEFAULT;
+ bandInfo.clrBack = fDeskBandInfo.crBkgnd;
+ }
+ wcsncpy(bandInfo.lpText, fDeskBandInfo.wszTitle, bandInfo.cch);
+ bandInfo.hwndChild = fChildWindow;
+ bandInfo.cxMinChild = fDeskBandInfo.ptMinSize.x;
+ bandInfo.cyMinChild = fDeskBandInfo.ptMinSize.y;
+ bandInfo.wID = fBandID;
+ bandInfo.cyChild = fDeskBandInfo.ptActual.y;
+ bandInfo.cyMaxChild = fDeskBandInfo.ptMaxSize.y;
+ bandInfo.cyIntegral = fDeskBandInfo.ptIntegral.y;
+ bandInfo.cxIdeal = fDeskBandInfo.ptActual.x;
+ bandInfo.lParam = reinterpret_cast<LPARAM>(this);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CDockSite::GetWindow(HWND *lphwnd)
+{
+ if (lphwnd == NULL)
+ return E_POINTER;
+ *lphwnd = fRebarWindow;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CDockSite::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CDockSite::GetBorderDW(IUnknown* punkObj, LPRECT prcBorder)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CDockSite::RequestBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CDockSite::SetBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CDockSite::OnFocusChangeIS (IUnknown *punkObj, BOOL fSetFocus)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CDockSite::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
+ OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CDockSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
+ VARIANT *pvaIn, VARIANT *pvaOut)
+{
+ TCHAR textBuffer[40];
+ REBARBANDINFOW bandInfo;
+ int index;
+ HRESULT hResult;
+
+ if (IsEqualIID(*pguidCmdGroup, CGID_DeskBand))
+ {
+ switch (nCmdID)
+ {
+ case DBID_BANDINFOCHANGED:
+ if (fInitialized == false)
+ return S_OK;
+ if (V_VT(pvaIn) != VT_I4)
+ return E_INVALIDARG;
+ if (V_I4(pvaIn) != fBandID)
+ return E_FAIL;
+ // deskband information changed
+ // call GetBandInfo and refresh information in rebar
+ memset(&bandInfo, 0, sizeof(bandInfo));
+ bandInfo.cbSize = sizeof(bandInfo);
+ bandInfo.lpText = textBuffer;
+ bandInfo.cch = sizeof(textBuffer) / sizeof(TCHAR);
+ hResult = GetRBBandInfo(bandInfo);
+ if (FAILED(hResult))
+ return hResult;
+ index = (int)SendMessage(fRebarWindow, RB_IDTOINDEX, fBandID, 0);
+ SendMessage(fRebarWindow, RB_SETBANDINFOW, index, (LPARAM)&bandInfo);
+ return S_OK;
+ }
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE CDockSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
+{
+ if (IsEqualIID(guidService, SID_SMenuBandParent))
+ return this->QueryInterface(riid, ppvObject);
+
+ return fToolbar->QueryService(guidService, riid, ppvObject);
+}
+
+CMenuCallback::CMenuCallback()
+{
+}
+
+CMenuCallback::~CMenuCallback()
+{
+}
+
+HRESULT STDMETHODCALLTYPE CMenuCallback::GetObject(LPSMDATA psmd, REFIID riid, void **ppvObject)
+{
+ CComPtr<IShellMenu> parentMenu;
+ CComPtr<IShellMenu> newMenu;
+ CComPtr<IShellFolder> favoritesFolder;
+ LPITEMIDLIST favoritesPIDL;
+ HWND ownerWindow;
+ HMENU parentHMenu;
+ HMENU favoritesHMenu;
+ HKEY orderRegKey;
+ DWORD disposition;
+ HRESULT hResult;
+ static const TCHAR szFavoritesKey[] =
+ _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MenuOrder\\Favorites");
+
+ if (!IsEqualIID(riid, IID_IShellMenu))
+ return E_FAIL;
+ if (psmd->uId != FCIDM_MENU_FAVORITES)
+ return E_FAIL;
+
+ if (fFavoritesMenu.p == NULL)
+ {
+ // create favorites menu
+ hResult = psmd->punk->QueryInterface(IID_PPV_ARG(IShellMenu, &parentMenu));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = parentMenu->GetMenu(&parentHMenu, &ownerWindow, NULL);
+ if (FAILED(hResult))
+ return hResult;
+ favoritesHMenu = GetSubMenu(parentHMenu, 3);
+ if (favoritesHMenu == NULL)
+ return E_FAIL;
+#if USE_CUSTOM_MENUBAND
+ HMODULE hrs = LoadLibrary(L"rshell.dll");
+
+ PMENUBAND_CONSTRUCTOR func = (PMENUBAND_CONSTRUCTOR) GetProcAddress(hrs, "CMenuBand_Constructor");
+ if (func)
+ {
+ hResult = func(IID_PPV_ARG(IShellMenu, &newMenu));
+ }
+ else
+ {
+ hResult = CoCreateInstance(CLSID_MenuBand, NULL, CLSCTX_INPROC_SERVER,
+ IID_PPV_ARG(IShellMenu, &newMenu));
+ }
+#else
+ hResult = CoCreateInstance(CLSID_MenuBand, NULL, CLSCTX_INPROC_SERVER,
+ IID_PPV_ARG(IShellMenu, &newMenu));
+#endif
+ if (FAILED(hResult))
+ return hResult;
+ hResult = newMenu->Initialize(this, FCIDM_MENU_FAVORITES, -1, SMINIT_VERTICAL | SMINIT_CACHED);
+ if (FAILED(hResult))
+ return hResult;
+ hResult = newMenu->SetMenu(favoritesHMenu, ownerWindow, SMSET_TOP | SMSET_DONTOWN);
+ if (FAILED(hResult))
+ return hResult;
+ hResult = SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &favoritesPIDL);
+ if (FAILED(hResult))
+ return hResult;
+ hResult = SHBindToFolder(favoritesPIDL, &favoritesFolder);
+ if (FAILED(hResult))
+ return hResult;
+ RegCreateKeyEx(HKEY_CURRENT_USER, szFavoritesKey,
+ 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &orderRegKey, &disposition);
+ hResult = newMenu->SetShellFolder(favoritesFolder, favoritesPIDL, orderRegKey, SMSET_BOTTOM | 0x18);
+ ILFree(favoritesPIDL);
+ if (SUCCEEDED(hResult))
+ fFavoritesMenu.Attach(newMenu.Detach());
+ }
+ if (fFavoritesMenu.p == NULL)
+ return E_FAIL;
+ return fFavoritesMenu->QueryInterface(riid, ppvObject);
+}
+
+HRESULT STDMETHODCALLTYPE CMenuCallback::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case SMC_INITMENU:
+ break;
+ case SMC_CREATE:
+ break;
+ case SMC_EXITMENU:
+ break;
+ case SMC_GETINFO:
+ {
+ SMINFO *infoPtr = reinterpret_cast<SMINFO *>(lParam);
+ if ((infoPtr->dwMask & SMIM_FLAGS) != 0)
+ {
+ if (psmd->uId == FCIDM_MENU_FAVORITES)
+ {
+ infoPtr->dwFlags |= SMIF_DROPCASCADE;
+ }
+ else
+ {
+ infoPtr->dwFlags |= SMIF_TRACKPOPUP;
+ }
+ }
+ if ((infoPtr->dwMask & SMIM_ICON) != 0)
+ infoPtr->iIcon = -1;
+ return S_OK;
+ }
+ case SMC_GETSFINFO:
+ break;
+ case SMC_GETOBJECT:
+ return GetObject(psmd, *reinterpret_cast<IID *>(wParam), reinterpret_cast<void **>(lParam));
+ case SMC_GETSFOBJECT:
+ break;
+ case SMC_SFEXEC:
+ break;
+ case SMC_SFSELECTITEM:
+ break;
+ case 13:
+ // return tooltip
+ break;
+ case SMC_REFRESH:
+ break;
+ case SMC_DEMOTE:
+ break;
+ case SMC_PROMOTE:
+ break;
+ case 0x13:
+ break;
+ case SMC_DEFAULTICON:
+ break;
+ case SMC_NEWITEM:
+ break;
+ case SMC_CHEVRONEXPAND:
+ break;
+ case SMC_DISPLAYCHEVRONTIP:
+ break;
+ case SMC_SETSFOBJECT:
+ break;
+ case SMC_SHCHANGENOTIFY:
+ break;
+ case SMC_CHEVRONGETTIP:
+ break;
+ case SMC_SFDDRESTRICTED:
+ break;
+ case 0x35:
+ break;
+ case 49:
+ break;
+ case 0x10000000:
+ break;
+ }
+ return S_FALSE;
+}
+
+CInternetToolbar::CInternetToolbar()
+{
+ fMainReBar = NULL;
+ fLocked = false;
+ fMenuBandWindow = NULL;
+ fNavigationWindow = NULL;
+ fMenuCallback.AddRef();
+ fToolbarWindow = NULL;
+ fAdviseCookie = 0;
+}
+
+CInternetToolbar::~CInternetToolbar()
+{
+ fMenuCallback.Release();
+}
+
+void CInternetToolbar::AddDockItem(IUnknown *newItem, int bandID, int flags)
+{
+ CDockSite *newSite;
+
+ newSite = new CComObject<CDockSite>;
+ newSite->AddRef();
+ newSite->Initialize(newItem, this, fMainReBar, bandID, flags);
+}
+
+HRESULT CInternetToolbar::ReserveBorderSpace(LONG maxHeight)
+{
+ CComPtr<IDockingWindowSite> dockingWindowSite;
+ RECT availableBorderSpace;
+
+ HRESULT hResult = fSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &dockingWindowSite));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = dockingWindowSite->GetBorderDW(static_cast<IDockingWindow *>(this), &availableBorderSpace);
+ if (FAILED(hResult))
+ return hResult;
+
+ if (availableBorderSpace.top > maxHeight)
+ {
+ availableBorderSpace.top = maxHeight;
+ }
+
+ return ResizeBorderDW(&availableBorderSpace, fSite, FALSE);
+}
+
+HRESULT CInternetToolbar::CreateMenuBar(IShellMenu **menuBar)
+{
+ CComPtr<IOleCommandTarget> siteCommandTarget;
+ CComPtr<IOleWindow> oleWindow;
+ CComPtr<IOleCommandTarget> commandTarget;
+ CComPtr<IShellMenuCallback> callback;
+ VARIANT menuOut;
+ HWND ownerWindow;
+ HRESULT hResult;
+
+#if USE_CUSTOM_MENUBAND
+ HMODULE hrs = LoadLibraryW(L"rshell.dll");
+
+ if (!hrs)
+ {
+ DbgPrint("Failed: %d\n", GetLastError());
+ return E_FAIL;
+ }
+
+ PMENUBAND_CONSTRUCTOR func = (PMENUBAND_CONSTRUCTOR) GetProcAddress(hrs, "CMenuBand_Constructor");
+ if (func)
+ {
+ hResult = func(IID_PPV_ARG(IShellMenu, menuBar));
+ }
+ else
+ {
+ DbgPrint("Failed: %d\n", GetLastError());
+ hResult = E_FAIL;
+ }
+
+ if (FAILED(hResult))
+ {
+ hResult = CoCreateInstance(CLSID_MenuBand, NULL, CLSCTX_INPROC_SERVER,
+ IID_PPV_ARG(IShellMenu, menuBar));
+ }
+#else
+ hResult = CoCreateInstance(CLSID_MenuBand, NULL, CLSCTX_INPROC_SERVER,
+ IID_PPV_ARG(IShellMenu, menuBar));
+#endif
+ if (FAILED(hResult))
+ return hResult;
+ hResult = fMenuCallback.QueryInterface(IID_PPV_ARG(IShellMenuCallback, &callback));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = (*menuBar)->Initialize(callback, -1, ANCESTORDEFAULT, SMINIT_HORIZONTAL | SMINIT_TOPLEVEL);
+ if (FAILED(hResult))
+ return hResult;
+ hResult = fSite->QueryInterface(IID_PPV_ARG(IOleWindow, &oleWindow));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = oleWindow->GetWindow(&ownerWindow);
+ if (FAILED(hResult))
+ return hResult;
+ hResult = fSite->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &siteCommandTarget));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = siteCommandTarget->Exec(&CGID_Explorer, 0x35, 0, NULL, &menuOut);
+ if (FAILED(hResult))
+ return hResult;
+ if (V_VT(&menuOut) != VT_INT_PTR || V_INTREF(&menuOut) == NULL)
+ return E_FAIL;
+ hResult = (*menuBar)->SetMenu((HMENU)V_INTREF(&menuOut), ownerWindow, SMSET_DONTOWN);
+ if (FAILED(hResult))
+ return hResult;
+ hResult = (*menuBar)->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &commandTarget));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = commandTarget->Exec(&CGID_MenuBand, 3, 1, NULL, NULL);
+ if (FAILED(hResult))
+ return hResult;
+ return S_OK;
+}
+
+HRESULT CInternetToolbar::CreateBrandBand(IUnknown **logoBar)
+{
+ CComPtr<IUnknown> tempBand;
+ HRESULT hResult;
+
+#if 1
+ hResult = ::CreateBrandBand(IID_PPV_ARG(IUnknown, logoBar));
+#else
+ hResult = CoCreateInstance(CLSID_BrandBand, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUnknown, logoBar));
+#endif
+ if (FAILED(hResult))
+ return hResult;
+ return S_OK;
+}
+
+HRESULT CInternetToolbar::CreateToolsBar(IUnknown **toolsBar)
+{
+ HRESULT hResult;
+
+ hResult = ::CreateToolsBar(IID_PPV_ARG(IUnknown, toolsBar));
+ if (FAILED(hResult))
+ return hResult;
+ return S_OK;
+}
+
+HRESULT CInternetToolbar::CreateAddressBand(IUnknown **toolsBar)
+{
+ CComPtr<IAddressBand> addressBand;
+ HRESULT hResult;
+
+#if 1
+ hResult = ::CreateAddressBand(IID_PPV_ARG(IUnknown, toolsBar));
+#else
+ hResult = CoCreateInstance(CLSID_SH_AddressBand, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUnknown, toolsBar));
+#endif
+ if (FAILED(hResult))
+ return hResult;
+ hResult = (*toolsBar)->QueryInterface(IID_PPV_ARG(IAddressBand, &addressBand));
+ return S_OK;
+}
+
+HRESULT CInternetToolbar::LockUnlockToolbars(bool locked)
+{
+ REBARBANDINFOW rebarBandInfo;
+ int bandCount;
+ CDockSite *dockSite;
+ HRESULT hResult;
+
+ if (locked != fLocked)
+ {
+ fLocked = locked;
+ rebarBandInfo.cbSize = sizeof(rebarBandInfo);
+ rebarBandInfo.fMask = RBBIM_STYLE | RBBIM_LPARAM;
+ bandCount = (int)SendMessage(fMainReBar, RB_GETBANDCOUNT, 0, 0);
+ for (INT x = 0; x < bandCount; x++)
+ {
+ SendMessage(fMainReBar, RB_GETBANDINFOW, x, (LPARAM)&rebarBandInfo);
+ dockSite = reinterpret_cast<CDockSite *>(rebarBandInfo.lParam);
+ if (dockSite != NULL)
+ {
+ rebarBandInfo.fStyle &= ~(RBBS_NOGRIPPER | RBBS_GRIPPERALWAYS);
+ if (dockSite->fFlags & CDockSite::ITF_NOGRIPPER || fLocked)
+ rebarBandInfo.fStyle |= RBBS_NOGRIPPER;
+ if (dockSite->fFlags & CDockSite::ITF_GRIPPERALWAYS && !fLocked)
+ rebarBandInfo.fStyle |= RBBS_GRIPPERALWAYS;
+ SendMessage(fMainReBar, RB_SETBANDINFOW, x, (LPARAM)&rebarBandInfo);
+ }
+ }
+ hResult = ReserveBorderSpace();
+
+ // TODO: refresh view menu?
+ }
+ return S_OK;
+}
+
+HRESULT CInternetToolbar::CommandStateChanged(bool newValue, int commandID)
+{
+ HRESULT hResult;
+
+ hResult = S_OK;
+ switch (commandID)
+ {
+ case -1:
+ // loop through buttons
+ //for buttons in CLSID_CommonButtons
+ // if up, QueryStatus for up state and update it
+ //
+ //for buttons in fCommandCategory, update with QueryStatus of fCommandTarget
+ break;
+ case 1:
+ // forward
+ hResult = SetState(&CLSID_CommonButtons, IDM_GOTO_FORWARD, newValue ? TBSTATE_ENABLED : 0);
+ break;
+ case 2:
+ // back
+ hResult = SetState(&CLSID_CommonButtons, IDM_GOTO_BACK, newValue ? TBSTATE_ENABLED : 0);
+ break;
+ }
+ return hResult;
+}
+
+HRESULT CInternetToolbar::CreateAndInitBandProxy()
+{
+ CComPtr<IServiceProvider> serviceProvider;
+ HRESULT hResult;
+
+ hResult = fSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &serviceProvider));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = serviceProvider->QueryService(SID_IBandProxy, IID_PPV_ARG(IBandProxy, &fBandProxy));
+ if (FAILED(hResult))
+ {
+ hResult = CreateBandProxy(IID_PPV_ARG(IBandProxy, &fBandProxy));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = fBandProxy->SetSite(fSite);
+ if (FAILED(hResult))
+ return hResult;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::HasFocusIO()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::TranslateAcceleratorIO(LPMSG lpMsg)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetWindow(HWND *lphwnd)
+{
+ if (lphwnd == NULL)
+ return E_POINTER;
+ *lphwnd = m_hWnd;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::ShowDW(BOOL fShow)
+{
+ CComPtr<IDockingWindow> dockingWindow;
+ HRESULT hResult;
+
+ // show the bar here
+ hResult = ReserveBorderSpace();
+ hResult = fMenuBar->QueryInterface(IID_PPV_ARG(IDockingWindow, &dockingWindow));
+ hResult = dockingWindow->ShowDW(fShow);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::CloseDW(DWORD dwReserved)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::ResizeBorderDW(LPCRECT prcBorder,
+ IUnknown *punkToolbarSite, BOOL fReserved)
+{
+ RECT neededBorderSpace;
+ RECT availableBorderSpace = *prcBorder;
+
+ SendMessage(fMainReBar, RB_SIZETORECT, RBSTR_CHANGERECT, reinterpret_cast<LPARAM>(&availableBorderSpace));
+
+ // RBSTR_CHANGERECT does not seem to set the proper size in the rect.
+ // Let's make sure we fetch the actual size properly.
+ GetWindowRect(fMainReBar, &availableBorderSpace);
+ neededBorderSpace.left = 0;
+ neededBorderSpace.top = availableBorderSpace.bottom - availableBorderSpace.top;
+ if (!fLocked)
+ neededBorderSpace.top += 3;
+ neededBorderSpace.right = 0;
+ neededBorderSpace.bottom = 0;
+
+ CComPtr<IDockingWindowSite> dockingWindowSite;
+
+ HRESULT hResult = fSite->QueryInterface(IID_PPV_ARG(IDockingWindowSite, &dockingWindowSite));
+ if (FAILED(hResult))
+ return hResult;
+
+ hResult = dockingWindowSite->RequestBorderSpaceDW(static_cast<IDockingWindow *>(this), &neededBorderSpace);
+ if (FAILED(hResult))
+ return hResult;
+
+ hResult = dockingWindowSite->SetBorderSpaceDW(static_cast<IDockingWindow *>(this), &neededBorderSpace);
+ if (FAILED(hResult))
+ return hResult;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetClassID(CLSID *pClassID)
+{
+ if (pClassID == NULL)
+ return E_POINTER;
+ *pClassID = CLSID_InternetToolbar;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::IsDirty()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::Load(IStream *pStm)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::Save(IStream *pStm, BOOL fClearDirty)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetSizeMax(ULARGE_INTEGER *pcbSize)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::InitNew()
+{
+ CComPtr<IShellMenu> menuBar;
+ CComPtr<IUnknown> logoBar;
+ CComPtr<IUnknown> toolsBar;
+ CComPtr<IUnknown> navigationBar;
+ CComPtr<IOleWindow> menuOleWindow;
+ CComPtr<IOleWindow> toolbarOleWindow;
+ CComPtr<IOleWindow> navigationOleWindow;
+ HRESULT hResult;
+
+ /* Create and attach the menubar to the rebar */
+ hResult = CreateMenuBar(&menuBar);
+ if (FAILED(hResult))
+ return hResult;
+ AddDockItem(menuBar, ITBBID_MENUBAND, CDockSite::ITF_NOTITLE | CDockSite::ITF_NEWBANDALWAYS | CDockSite::ITF_GRIPPERALWAYS);
+
+ hResult = menuBar->QueryInterface(IID_PPV_ARG(IOleWindow, &menuOleWindow));
+ hResult = menuOleWindow->GetWindow(&fMenuBandWindow);
+ fMenuBar.Attach(menuBar.Detach()); // transfer the ref count
+
+ // FIXME: The ros Rebar does not properly support fixed-size items such as the brandband,
+ // and it will put them in their own row, sized to take up the whole row.
+#if 0
+ /* Create and attach the brand/logo to the rebar */
+ hResult = CreateBrandBand(&logoBar);
+ if (FAILED(hResult))
+ return hResult;
+ AddDockItem(logoBar, ITBBID_BRANDBAND, CDockSite::ITF_NOGRIPPER | CDockSite::ITF_NOTITLE | CDockSite::ITF_FIXEDSIZE);
+ fLogoBar.Attach(logoBar.Detach()); // transfer the ref count
+#endif
+
+ /* Create and attach the standard toolbar to the rebar */
+ hResult = CreateToolsBar(&toolsBar);
+ if (FAILED(hResult))
+ return hResult;
+ AddDockItem(toolsBar, ITBBID_TOOLSBAND, CDockSite::ITF_NOTITLE | CDockSite::ITF_NEWBANDALWAYS | CDockSite::ITF_GRIPPERALWAYS);
+ fControlsBar.Attach(toolsBar.Detach()); // transfer the ref count
+ hResult = fControlsBar->QueryInterface(IID_PPV_ARG(IOleWindow, &toolbarOleWindow));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = toolbarOleWindow->GetWindow(&fToolbarWindow);
+ if (FAILED(hResult))
+ return hResult;
+
+ /* Create and attach the address/navigation toolbar to the rebar */
+ hResult = CreateAddressBand(&navigationBar);
+ if (FAILED(hResult))
+ return hResult;
+ AddDockItem(navigationBar, ITBBID_ADDRESSBAND, CDockSite::ITF_NEWBANDALWAYS | CDockSite::ITF_GRIPPERALWAYS);
+ hResult = navigationBar->QueryInterface(IID_PPV_ARG(IOleWindow, &navigationOleWindow));
+ hResult = navigationOleWindow->GetWindow(&fNavigationWindow);
+ fNavigationBar.Attach(navigationBar.Detach());
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::QueryStatus(const GUID *pguidCmdGroup,
+ ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
+{
+ if (IsEqualIID(*pguidCmdGroup, CGID_PrivCITCommands))
+ {
+ while (cCmds != 0)
+ {
+ switch (prgCmds->cmdID)
+ {
+ case ITID_TEXTLABELS: // Text Labels state
+ prgCmds->cmdf = OLECMDF_SUPPORTED;
+ break;
+ case ITID_TOOLBARBANDSHOWN: // toolbar visibility
+ prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
+ break;
+ case ITID_ADDRESSBANDSHOWN: // address bar visibility
+ prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
+ break;
+ case ITID_LINKSBANDSHOWN: // links bar visibility
+ prgCmds->cmdf = 0;
+ break;
+ case ITID_MENUBANDSHOWN: // Menubar band visibility
+ prgCmds->cmdf = 0;
+ break;
+ case ITID_AUTOHIDEENABLED: // Auto hide enabled/disabled
+ prgCmds->cmdf = 0;
+ break;
+ case ITID_CUSTOMIZEENABLED: // customize enabled
+ prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
+ break;
+ case ITID_TOOLBARLOCKED: // lock toolbars
+ prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
+ if (fLocked)
+ prgCmds->cmdf |= OLECMDF_LATCHED;
+ break;
+ default:
+ prgCmds->cmdf = 0;
+ break;
+ }
+ prgCmds++;
+ cCmds--;
+ }
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
+ DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
+{
+ if (IsEqualIID(*pguidCmdGroup, CGID_PrivCITCommands))
+ {
+ switch (nCmdID)
+ {
+ case 1:
+ // what do I do here?
+ return S_OK;
+ case ITID_TEXTLABELS:
+ // toggle text labels
+ return S_OK;
+ case ITID_TOOLBARBANDSHOWN:
+ // toggle toolbar band visibility
+ return S_OK;
+ case ITID_ADDRESSBANDSHOWN:
+ // toggle address band visibility
+ return S_OK;
+ case ITID_LINKSBANDSHOWN:
+ // toggle links band visibility
+ return S_OK;
+ case ITID_CUSTOMIZEENABLED:
+ // run customize
+ return S_OK;
+ case ITID_TOOLBARLOCKED:
+ return LockUnlockToolbars(!fLocked);
+ }
+ }
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetTypeInfoCount(UINT *pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
+ LCID lcid, DISPID *rgDispId)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
+ WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+ HRESULT hResult;
+
+ switch(dispIdMember)
+ {
+ case DISPID_BEFORENAVIGATE:
+ hResult = S_OK;
+ break;
+ case DISPID_DOWNLOADCOMPLETE:
+ hResult = S_OK;
+ break;
+ case DISPID_COMMANDSTATECHANGE:
+ if (pDispParams->cArgs != 2)
+ return E_INVALIDARG;
+ if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL || V_VT(&pDispParams->rgvarg[1]) != VT_I4)
+ return E_INVALIDARG;
+ return CommandStateChanged(V_BOOL(&pDispParams->rgvarg[0]) != VARIANT_FALSE,
+ V_I4(&pDispParams->rgvarg[1]));
+ case DISPID_DOWNLOADBEGIN:
+ hResult = S_OK;
+ break;
+ case DISPID_NAVIGATECOMPLETE2:
+ hResult = S_OK;
+ break;
+ case DISPID_DOCUMENTCOMPLETE:
+ hResult = S_OK;
+ break;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::SetCommandTarget(IUnknown *theTarget, GUID *category, long param14)
+{
+ HRESULT hResult;
+
+ fCommandTarget.Release();
+ hResult = theTarget->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &fCommandTarget));
+ if (FAILED(hResult))
+ return hResult;
+ fCommandCategory = *category;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::Unknown1()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::AddButtons(const GUID *pguidCmdGroup, long buttonCount, TBBUTTON *buttons)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::AddString(const GUID *pguidCmdGroup,
+ HINSTANCE param10, LPCTSTR param14, long *param18)
+{
+ long result;
+
+ result = (long)::SendMessage(fToolbarWindow, TB_ADDSTRINGW,
+ reinterpret_cast<WPARAM>(param10), reinterpret_cast<LPARAM>(param14));
+ *param18 = result;
+ if (result == -1)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetButton(const GUID *pguidCmdGroup, long param10, long param14)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetState(const GUID *pguidCmdGroup, long commandID, long *theState)
+{
+ if (theState == NULL)
+ return E_POINTER;
+ // map the command id
+ *theState = (long)::SendMessage(fToolbarWindow, TB_GETSTATE, commandID, 0);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::SetState(const GUID *pguidCmdGroup, long commandID, long theState)
+{
+ // map the command id
+ ::SendMessage(fToolbarWindow, TB_SETSTATE, commandID, MAKELONG(theState, 0));
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::AddBitmap(const GUID *pguidCmdGroup, long param10, long buttonCount,
+ TBADDBITMAP *lParam, long *newIndex, COLORREF param20)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetBitmapSize(long *paramC)
+{
+ if (paramC == NULL)
+ return E_POINTER;
+ *paramC = MAKELONG(24, 24);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::SendToolbarMsg(const GUID *pguidCmdGroup, UINT uMsg,
+ WPARAM wParam, LPARAM lParam, LRESULT *result)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::SetImageList(const GUID *pguidCmdGroup, HIMAGELIST param10,
+ HIMAGELIST param14, HIMAGELIST param18)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::ModifyButton(const GUID *pguidCmdGroup, long param10, long param14)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::OnChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::SetSite(IUnknown *pUnkSite)
+{
+ CComPtr<IBrowserService> browserService;
+ CComPtr<IServiceProvider> serviceProvider;
+ CComPtr<IOleWindow> oleWindow;
+ HWND ownerWindow;
+ HWND dockContainer;
+ HRESULT hResult;
+
+ if (pUnkSite == NULL)
+ {
+ hResult = AtlUnadvise(fSite, DIID_DWebBrowserEvents, fAdviseCookie);
+ ::DestroyWindow(fMainReBar);
+ DestroyWindow();
+ fSite.Release();
+ }
+ else
+ {
+ // get window handle of owner
+ hResult = pUnkSite->QueryInterface(IID_PPV_ARG(IOleWindow, &oleWindow));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = oleWindow->GetWindow(&ownerWindow);
+ if (FAILED(hResult))
+ return hResult;
+ if (ownerWindow == NULL)
+ return E_FAIL;
+
+ // create dock container
+ fSite = pUnkSite;
+ dockContainer = SHCreateWorkerWindowW(0, ownerWindow, 0,
+ WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, NULL, 0);
+ if (dockContainer == NULL)
+ return E_FAIL;
+ SubclassWindow(dockContainer);
+
+ // create rebar in dock container
+ DWORD style = WS_VISIBLE | WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
+ RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_REGISTERDROP | RBS_AUTOSIZE | RBS_DBLCLKTOGGLE |
+ CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_TOP;
+ DWORD exStyle = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_TOOLWINDOW;
+ fMainReBar = CreateWindowEx(exStyle, REBARCLASSNAMEW, NULL, style,
+ 0, 0, 700, 60, dockContainer, NULL, _AtlBaseModule.GetModuleInstance(), NULL);
+ if (fMainReBar == NULL)
+ return E_FAIL;
+
+ // take advice to watch events
+ hResult = pUnkSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &serviceProvider));
+ hResult = serviceProvider->QueryService(
+ SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
+ hResult = AtlAdvise(browserService, static_cast<IDispatch *>(this), DIID_DWebBrowserEvents, &fAdviseCookie);
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetSite(REFIID riid, void **ppvSite)
+{
+ if (ppvSite == NULL)
+ return E_POINTER;
+ if (fSite.p != NULL)
+ return fSite->QueryInterface(riid, ppvSite);
+ *ppvSite = NULL;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
+{
+ CComPtr<IServiceProvider> serviceProvider;
+ HRESULT hResult;
+
+ if (IsEqualIID(guidService, IID_IBandSite))
+ return this->QueryInterface(riid, ppvObject);
+ if (IsEqualIID(guidService, SID_IBandProxy))
+ {
+ if (fBandProxy.p == NULL)
+ {
+ hResult = CreateAndInitBandProxy();
+ if (FAILED(hResult))
+ return hResult;
+ }
+ return fBandProxy->QueryInterface(riid, ppvObject);
+ }
+ return IUnknown_QueryService(fSite, guidService, riid, ppvObject);
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::OnWinEvent(
+ HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
+{
+ CComPtr<IWinEventHandler> menuWinEventHandler;
+ HRESULT hResult;
+
+ if (fMenuBar)
+ {
+ hResult = fMenuBar->QueryInterface(IID_PPV_ARG(IWinEventHandler, &menuWinEventHandler));
+ if (menuWinEventHandler->IsWindowOwner(hWnd) == S_OK)
+ {
+ return menuWinEventHandler->OnWinEvent(fMenuBandWindow, uMsg, wParam, lParam, theResult);
+ }
+ }
+
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::IsWindowOwner(HWND hWnd)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::AddBand(IUnknown *punk)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::EnumBands(UINT uBand, DWORD *pdwBandID)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::QueryBand(DWORD dwBandID,
+ IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName)
+{
+ if (ppstb == NULL)
+ return E_POINTER;
+ if (dwBandID == ITBBID_MENUBAND && fMenuBar.p != NULL)
+ return fMenuBar->QueryInterface(IID_PPV_ARG(IDeskBand, ppstb));
+ //if (dwBandID == ITBBID_BRANDBAND && fLogoBar.p != NULL)
+ // return fLogoBar->QueryInterface(IID_PPV_ARG(IDeskBand, ppstb));
+ *ppstb = NULL;
+ return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::RemoveBand(DWORD dwBandID)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetBandObject(DWORD dwBandID, REFIID riid, void **ppv)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::SetBandSiteInfo(const BANDSITEINFO *pbsinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CInternetToolbar::GetBandSiteInfo(BANDSITEINFO *pbsinfo)
+{
+ return E_NOTIMPL;
+}
+
+LRESULT CInternetToolbar::OnTravelBack(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ CComPtr<IServiceProvider> serviceProvider;
+ CComPtr<IWebBrowser> webBrowser;
+ HRESULT hResult;
+
+ hResult = fSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &serviceProvider));
+ if (FAILED(hResult))
+ return 0;
+ hResult = serviceProvider->QueryService(SID_SShellBrowser,
+ IID_PPV_ARG(IWebBrowser, &webBrowser));
+ if (FAILED(hResult))
+ return 0;
+ hResult = webBrowser->GoBack();
+ return 1;
+}
+
+LRESULT CInternetToolbar::OnTravelForward(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ CComPtr<IServiceProvider> serviceProvider;
+ CComPtr<IWebBrowser> webBrowser;
+ HRESULT hResult;
+
+ hResult = fSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &serviceProvider));
+ if (FAILED(hResult))
+ return 0;
+ hResult = serviceProvider->QueryService(
+ SID_SShellBrowser, IID_PPV_ARG(IWebBrowser, &webBrowser));
+ if (FAILED(hResult))
+ return 0;
+ hResult = webBrowser->GoForward();
+ return 1;
+}
+
+LRESULT CInternetToolbar::OnUpLevel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ CComPtr<IOleCommandTarget> oleCommandTarget;
+ HRESULT hResult;
+
+ hResult = fSite->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &oleCommandTarget));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = oleCommandTarget->Exec(&CGID_ShellBrowser, IDM_GOTO_UPONELEVEL, 0, NULL, NULL);
+ return 1;
+}
+
+LRESULT CInternetToolbar::OnSearch(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ CComPtr<IObjectWithSite> objectWithSite;
+ CComPtr<IContextMenu> contextMenu;
+ CMINVOKECOMMANDINFO commandInfo;
+ const char *searchGUID = "{169A0691-8DF9-11d1-A1C4-00C04FD75D13}";
+ HRESULT hResult;
+
+ // TODO: Query shell if this command is enabled first
+
+ memset(&commandInfo, 0, sizeof(commandInfo));
+ commandInfo.cbSize = sizeof(commandInfo);
+ commandInfo.hwnd = m_hWnd;
+ commandInfo.lpParameters = searchGUID;
+ commandInfo.nShow = SW_SHOWNORMAL;
+
+ hResult = CoCreateInstance(CLSID_ShellSearchExt, NULL, CLSCTX_INPROC_SERVER,
+ IID_PPV_ARG(IContextMenu, &contextMenu));
+ if (FAILED(hResult))
+ return 0;
+ hResult = contextMenu->QueryInterface(IID_PPV_ARG(IObjectWithSite, &objectWithSite));
+ if (FAILED(hResult))
+ return 0;
+ hResult = objectWithSite->SetSite(fSite);
+ if (FAILED(hResult))
+ return 0;
+ hResult = contextMenu->InvokeCommand(&commandInfo);
+ hResult = objectWithSite->SetSite(NULL);
+ return 0;
+}
+
+LRESULT CInternetToolbar::OnFolders(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ CComPtr<IOleCommandTarget> oleCommandTarget;
+ HRESULT hResult;
+
+ hResult = fSite->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &oleCommandTarget));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = oleCommandTarget->Exec(&CGID_Explorer, 0x23, 0, NULL, NULL);
+ return 1;
+}
+
+LRESULT CInternetToolbar::OnForwardToCommandTarget(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ HRESULT hResult;
+
+ if (fCommandTarget.p != NULL)
+ {
+ hResult = fCommandTarget->Exec(&fCommandCategory, wID, 0, NULL, NULL);
+ }
+ return 1;
+}
+
+LRESULT CInternetToolbar::OnMenuDropDown(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
+{
+ CComPtr<IServiceProvider> serviceProvider;
+ CComPtr<IBrowserService> browserService;
+ CComPtr<IOleCommandTarget> commandTarget;
+ CComPtr<ITravelLog> travelLog;
+ NMTOOLBARW *notifyInfo;
+ RECT bounds;
+ HMENU newMenu;
+ TPMPARAMS params;
+ int selectedItem;
+ VARIANT parmIn;
+ OLECMD commandInfo;
+ HRESULT hResult;
+
+ notifyInfo = (NMTOOLBARW *)pNMHDR;
+ if (notifyInfo->hdr.hwndFrom != fToolbarWindow)
+ {
+ // not from the toolbar, keep looking for a message handler
+ bHandled = FALSE;
+ return 0;
+ }
+ SendMessage(fToolbarWindow, TB_GETRECT, notifyInfo->iItem, reinterpret_cast<LPARAM>(&bounds));
+ ::MapWindowPoints(fToolbarWindow, NULL, reinterpret_cast<POINT *>(&bounds), 2);
+ switch (notifyInfo->iItem)
+ {
+ case IDM_GOTO_BACK:
+ newMenu = CreatePopupMenu();
+ hResult = fSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &serviceProvider));
+ hResult = serviceProvider->QueryService(
+ SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
+ hResult = browserService->GetTravelLog(&travelLog);
+ hResult = travelLog->InsertMenuEntries(browserService, newMenu, 0, 1, 9, TLMENUF_BACK);
+ hResult = browserService->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &commandTarget));
+ commandInfo.cmdID = 0x1d;
+ hResult = commandTarget->QueryStatus(&CGID_Explorer, 1, &commandInfo, NULL);
+ if ((commandInfo.cmdf & (OLECMDF_ENABLED | OLECMDF_LATCHED)) == OLECMDF_ENABLED &&
+ travelLog->CountEntries(browserService) > 1)
+ {
+ AppendMenu(newMenu, MF_SEPARATOR, -1, L"");
+ AppendMenu(newMenu, MF_STRING /* | MF_OWNERDRAW */, IDM_EXPLORERBAR_HISTORY, L"&History\tCtrl+H");
+ }
+ params.cbSize = sizeof (params);
+ params.rcExclude = bounds;
+ selectedItem = TrackPopupMenuEx(newMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
+ bounds.left, bounds.bottom, m_hWnd, ¶ms);
+ if (selectedItem == IDM_EXPLORERBAR_HISTORY)
+ {
+ V_VT(&parmIn) = VT_I4;
+ V_I4(&parmIn) = 1;
+ Exec(&CGID_Explorer, 0x1d, 2, &parmIn, NULL);
+ }
+ else if (selectedItem != 0)
+ hResult = travelLog->Travel(browserService, -selectedItem);
+ DestroyMenu(newMenu);
+ break;
+ case IDM_GOTO_FORWARD:
+ newMenu = CreatePopupMenu();
+ hResult = fSite->QueryInterface(IID_PPV_ARG(IServiceProvider, &serviceProvider));
+ hResult = serviceProvider->QueryService(SID_SShellBrowser, IID_PPV_ARG(IBrowserService, &browserService));
+ hResult = browserService->GetTravelLog(&travelLog);
+ hResult = travelLog->InsertMenuEntries(browserService, newMenu, 0, 1, 9, TLMENUF_FORE);
+ hResult = browserService->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &commandTarget));
+ commandInfo.cmdID = 0x1d;
+ hResult = commandTarget->QueryStatus(&CGID_Explorer, 1, &commandInfo, NULL);
+ if ((commandInfo.cmdf & (OLECMDF_ENABLED | OLECMDF_LATCHED)) == OLECMDF_ENABLED &&
+ travelLog->CountEntries(browserService) > 1)
+ {
+ AppendMenu(newMenu, MF_SEPARATOR, -1, L"");
+ AppendMenu(newMenu, MF_STRING /* | MF_OWNERDRAW */, IDM_EXPLORERBAR_HISTORY, L"&History\tCtrl+H");
+ }
+ params.cbSize = sizeof (params);
+ params.rcExclude = bounds;
+ selectedItem = TrackPopupMenuEx(newMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD,
+ bounds.left, bounds.bottom, m_hWnd, ¶ms);
+ if (selectedItem == IDM_EXPLORERBAR_HISTORY)
+ {
+ V_VT(&parmIn) = VT_I4;
+ V_I4(&parmIn) = 1;
+ Exec(&CGID_Explorer, 0x1d, 2, &parmIn, NULL);
+ }
+ else if (selectedItem != 0)
+ hResult = travelLog->Travel(browserService, -selectedItem);
+ DestroyMenu(newMenu);
+ break;
+ case gViewsCommandID:
+ VARIANT inValue;
+ CComVariant outValue;
+ HRESULT hResult;
+
+ V_VT(&inValue) = VT_INT_PTR;
+ V_INTREF(&inValue) = reinterpret_cast<INT *>(&bounds);
+
+ if (fCommandTarget.p != NULL)
+ hResult = fCommandTarget->Exec(&fCommandCategory, 0x7031, 1, &inValue, &outValue);
+ // pvaOut is VT_I4 with value 0x403
+ break;
+ }
+ return TBDDRET_DEFAULT;
+}
+
+LRESULT CInternetToolbar::OnQueryInsert(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
+{
+ return 1;
+}
+
+LRESULT CInternetToolbar::OnQueryDelete(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
+{
+ return 1;
+}
+
+LRESULT CInternetToolbar::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ HMENU contextMenuBar;
+ HMENU contextMenu;
+ POINT clickLocation;
+ int command;
+ RBHITTESTINFO hitTestInfo;
+ REBARBANDINFOW rebarBandInfo;
+ int bandID;
+
+ clickLocation.x = LOWORD(lParam);
+ clickLocation.y = HIWORD(lParam);
+ hitTestInfo.pt = clickLocation;
+ ScreenToClient(&hitTestInfo.pt);
+ SendMessage(fMainReBar, RB_HITTEST, 0, (LPARAM)&hitTestInfo);
+ if (hitTestInfo.iBand == -1)
+ return 0;
+ rebarBandInfo.cbSize = sizeof(rebarBandInfo);
+ rebarBandInfo.fMask = RBBIM_ID;
+ SendMessage(fMainReBar, RB_GETBANDINFOW, hitTestInfo.iBand, (LPARAM)&rebarBandInfo);
+ bandID = rebarBandInfo.wID;
+ contextMenuBar = LoadMenu(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(IDM_CABINET_CONTEXTMENU));
+ contextMenu = GetSubMenu(contextMenuBar, 0);
+ switch (bandID)
+ {
+ case ITBBID_MENUBAND: // menu band
+ DeleteMenu(contextMenu, IDM_TOOLBARS_CUSTOMIZE, MF_BYCOMMAND);
+ DeleteMenu(contextMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
+ DeleteMenu(contextMenu, IDM_TOOLBARS_GOBUTTON, MF_BYCOMMAND);
+ break;
+ case ITBBID_BRANDBAND: // brand band
+ DeleteMenu(contextMenu, IDM_TOOLBARS_CUSTOMIZE, MF_BYCOMMAND);
+ DeleteMenu(contextMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
+ DeleteMenu(contextMenu, IDM_TOOLBARS_GOBUTTON, MF_BYCOMMAND);
+ break;
+ case ITBBID_TOOLSBAND: // tools band
+ DeleteMenu(contextMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
+ DeleteMenu(contextMenu, IDM_TOOLBARS_GOBUTTON, MF_BYCOMMAND);
+ break;
+ case ITBBID_ADDRESSBAND: // navigation band
+ DeleteMenu(contextMenu, IDM_TOOLBARS_CUSTOMIZE, MF_BYCOMMAND);
+ DeleteMenu(contextMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
+ break;
+ default:
+ break;
+ }
+
+ MENUITEMINFO mii;
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STATE;
+ mii.fState = fLocked ? MFS_CHECKED : MFS_UNCHECKED;
+ command = SetMenuItemInfo(contextMenu, IDM_TOOLBARS_LOCKTOOLBARS, FALSE, &mii);
+
+ // TODO: use GetSystemMetrics(SM_MENUDROPALIGNMENT) to determine menu alignment
+ command = TrackPopupMenu(contextMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
+ clickLocation.x, clickLocation.y, 0, m_hWnd, NULL);
+ switch (command)
+ {
+ case IDM_TOOLBARS_STANDARDBUTTONS: // standard buttons
+ break;
+ case IDM_TOOLBARS_ADDRESSBAR: // address bar
+ break;
+ case IDM_TOOLBARS_LINKSBAR: // links
+ break;
+ case IDM_TOOLBARS_LOCKTOOLBARS: // lock the toolbars
+ LockUnlockToolbars(!fLocked);
+ break;
+ case IDM_TOOLBARS_CUSTOMIZE: // customize
+ SendMessage(fToolbarWindow, TB_CUSTOMIZE, 0, 0);
+ break;
+ }
+ return 1;
+}
+
+LRESULT CInternetToolbar::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ if (wParam != SIZE_MINIMIZED)
+ {
+ ::SetWindowPos(fMainReBar, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam),
+ SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
+ }
+ return 1;
+}
+
+LRESULT CInternetToolbar::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ if ((short)lParam != HTCLIENT || (HWND)wParam != m_hWnd)
+ {
+ bHandled = FALSE;
+ return 0;
+ }
+ SetCursor(LoadCursor(NULL, IDC_SIZENS));
+ return 1;
+}
+
+LRESULT CInternetToolbar::OnTipText(UINT idControl, NMHDR *pNMHDR, BOOL &bHandled)
+{
+ CComPtr<IBrowserService> browserService;
+ CComPtr<ITravelLog> travelLog;
+ TOOLTIPTEXTW *pTTTW;
+ UINT nID;
+ wchar_t tempString[300];
+ HRESULT hResult;
+
+ pTTTW = reinterpret_cast<TOOLTIPTEXTW *>(pNMHDR);
+ if ((pTTTW->uFlags & TTF_IDISHWND) != 0)
+ nID = ::GetDlgCtrlID((HWND)pNMHDR->idFrom);
+ else
+ nID = (UINT)pNMHDR->idFrom;
+
+ if (nID != 0)
+ {
+ if (nID == (UINT)IDM_GOTO_BACK || nID == (UINT)IDM_GOTO_FORWARD)
+ {
+ // TODO: Should this call QueryService?
+ hResult = fSite->QueryInterface(IID_PPV_ARG(IBrowserService, &browserService));
+ hResult = browserService->GetTravelLog(&travelLog);
+ hResult = travelLog->GetToolTipText(browserService,
+ (nID == (UINT)IDM_GOTO_BACK) ? TLOG_BACK : TLOG_FORE,
+ 0, tempString, 299);
+ if (FAILED(hResult))
+ {
+ bHandled = FALSE;
+ return 0;
+ }
+ }
+ else
+ tempString[0] = 0;
+ wcsncpy (pTTTW->szText, tempString, sizeof (pTTTW->szText) / sizeof (wchar_t));
+ ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
+ SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+ return 0;
+ }
+ return 0;
+}
+
+LRESULT CInternetToolbar::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ LRESULT theResult;
+ HRESULT hResult;
+ HWND target = (HWND) lParam;
+
+ if (fMenuBar)
+ {
+ CComPtr<IWinEventHandler> menuWinEventHandler;
+ hResult = fMenuBar->QueryInterface(IID_PPV_ARG(IWinEventHandler, &menuWinEventHandler));
+ if (SUCCEEDED(hResult))
+ {
+ if (menuWinEventHandler->IsWindowOwner(target) == S_OK)
+ {
+ hResult = menuWinEventHandler->OnWinEvent(target, uMsg, wParam, lParam, &theResult);
+ return FAILED(hResult) ? 0 : theResult;
+ }
+ }
+ }
+
+ if (fNavigationBar)
+ {
+ CComPtr<IWinEventHandler> menuWinEventHandler;
+ hResult = fNavigationBar->QueryInterface(IID_PPV_ARG(IWinEventHandler, &menuWinEventHandler));
+ if (SUCCEEDED(hResult))
+ {
+ if (menuWinEventHandler->IsWindowOwner(target) == S_OK)
+ {
+ hResult = menuWinEventHandler->OnWinEvent(target, uMsg, wParam, lParam, &theResult);
+ return FAILED(hResult) ? 0 : theResult;
+ }
+ }
+ }
+
+ return 0;
+}
+LRESULT CInternetToolbar::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ NMHDR *notifyHeader;
+ LRESULT theResult;
+ HRESULT hResult;
+
+ notifyHeader = (NMHDR *) lParam;
+
+ if (fMenuBar)
+ {
+ CComPtr<IWinEventHandler> menuWinEventHandler;
+ hResult = fMenuBar->QueryInterface(IID_PPV_ARG(IWinEventHandler, &menuWinEventHandler));
+ if (SUCCEEDED(hResult))
+ {
+ if (menuWinEventHandler->IsWindowOwner(notifyHeader->hwndFrom) == S_OK)
+ {
+ hResult = menuWinEventHandler->OnWinEvent(notifyHeader->hwndFrom, uMsg, wParam, lParam, &theResult);
+ return FAILED(hResult) ? 0 : theResult;
+ }
+ }
+ }
+
+ if (fNavigationBar)
+ {
+ CComPtr<IWinEventHandler> menuWinEventHandler;
+ hResult = fNavigationBar->QueryInterface(IID_PPV_ARG(IWinEventHandler, &menuWinEventHandler));
+ if (SUCCEEDED(hResult))
+ {
+ if (menuWinEventHandler->IsWindowOwner(notifyHeader->hwndFrom) == S_OK)
+ {
+ hResult = menuWinEventHandler->OnWinEvent(notifyHeader->hwndFrom, uMsg, wParam, lParam, &theResult);
+ return FAILED(hResult) ? 0 : theResult;
+ }
+ }
+ }
+
+ return 0;
+}
+
+LRESULT CInternetToolbar::OnLDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ bHandled = FALSE;
+ if (fLocked)
+ return 0;
+
+ if (wParam & MK_CONTROL)
+ return 0;
+
+ fSizing = TRUE;
+
+ DWORD msgp = GetMessagePos();
+
+ fStartPosition.x = GET_X_LPARAM(msgp);
+ fStartPosition.y = GET_Y_LPARAM(msgp);
+
+ RECT rc;
+ GetWindowRect(m_hWnd, &rc);
+
+ fStartHeight = rc.bottom - rc.top;
+
+ SetCapture();
+
+ bHandled = TRUE;
+ return 0;
+}
+
+LRESULT CInternetToolbar::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ bHandled = FALSE;
+ if (!fSizing)
+ return 0;
+
+ DWORD msgp = GetMessagePos();
+
+ POINT pt;
+ pt.x = GET_X_LPARAM(msgp);
+ pt.y = GET_Y_LPARAM(msgp);
+
+ ReserveBorderSpace(fStartHeight - fStartPosition.y + pt.y);
+
+ bHandled = TRUE;
+ return 0;
+}
+
+LRESULT CInternetToolbar::OnLUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ bHandled = FALSE;
+ if (!fSizing)
+ return 0;
+
+ OnMouseMove(uMsg, wParam, lParam, bHandled);
+
+ fSizing = FALSE;
+
+ ReleaseCapture();
+
+ return 0;
+}
+
+HRESULT CreateInternetToolbar(REFIID riid, void **ppv)
+{
+ CComObject<CInternetToolbar> *theToolbar;
+ HRESULT hResult;
+
+ if (ppv == NULL)
+ return E_POINTER;
+ *ppv = NULL;
+ ATLTRY (theToolbar = new CComObject<CInternetToolbar>);
+ if (theToolbar == NULL)
+ return E_OUTOFMEMORY;
+ hResult = theToolbar->QueryInterface (riid, reinterpret_cast<void **>(ppv));
+ if (FAILED(hResult))
+ {
+ delete theToolbar;
+ return hResult;
+ }
+ return S_OK;
+}
--- /dev/null
+/*
+ * ReactOS Explorer
+ *
+ * Copyright 2009 Andrew Hill <ash77 at domain reactos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "precomp.h"
+
+#include <shellapi.h>
+#include <htiframe.h>
+
+extern "C"
+BOOL WINAPI Shell_GetImageLists(
+ _Out_ HIMAGELIST *phiml,
+ _Out_ HIMAGELIST *phimlSmall
+ );
+
+#include "newatlinterfaces.h"
+
+/*
+TODO:
+ **Provide implementation of new and delete that use LocalAlloc
+ **Persist history for shell view isn't working correctly, possibly because of the mismatch between traveling and updating the travel log. The
+ view doesn't restore the selection correctly.
+ **Build explorer.exe, browseui.dll, comctl32.dll, shdocvw.dll, shell32.dll, shlwapi.dll into a directory and run them for testing...
+ **Add brand band bitmaps to shell32.dll
+ **If Go button on address bar is clicked, each time a new duplicate entry is added to travel log
+****The current entry is updated in travel log before doing the travel, which means when traveling back the update of the
+ current state overwrites the wrong entry's contents. This needs to be changed.
+****Fix close of browser window to release all objects
+****Given only a GUID in ShowBrowserBar, what is the correct way to determine if the bar is vertical or horizontal?
+ **When a new bar is added to base bar site, how is base bar told so it can resize?
+ **Does the base bar site have a classid?
+ **What should refresh command send to views to make them refresh?
+ **When new bar is created, what status notifications need to be fired?
+ **How does keyboard filtering dispatch?
+ **For deferred persist history load, how does the view connect up and get the state?
+ How does context menu send open, cut, rename commands to its site (the shell view)?
+ **Fix browser to implement IProfferService and hold onto brand band correctly - this will allow animations.
+
+ **Route View->Toolbars commands to internet toolbar
+ **Handle travel log items in View->Go
+ **Fix ShowBrowserBar to pass correct size on when bar is shown
+****Fix SetBorderSpaceDW to cascade resize to subsequent bars
+****Make ShowToolbar check if bar is already created before creating it again
+****Shell should fill in the list of explorer bars in the View submenus
+ **Add folder menu in the file menu
+ **Fix CShellBrowser::GetBorderDW to compute available size correctly
+ **When a new bar is shown, re-fire the navigate event. This makes the explorer band select the correct folder
+ **Implement support for refresh. Forward refresh to explorer bar (refresh on toolbar and in menu is dispatched different)
+ Make folders toolbar item update state appropriately
+ Read list of bands from registry on launch
+ Read list of bars from registry on launch
+ If the folders or search bars don't exist, disable the toolbar buttons
+ If the favorites or history bars don't exist, disable the toolbar butons
+ Fix Apply to all Folders in Folder Options
+ Implement close command
+ Add explorer band context menu to file menu
+ Add code to allow restore of internet toolbar from registry
+ Fix code that calls FireNavigateComplete to pass the correct new path
+
+ What are the other command ids for QueryStatus/FireCommandStateChange?
+
+ Add handler for cabinet settings change
+ Add handler for system metrics change (renegotiate border space?)
+ Add handler for theme change and forward to contained windows
+
+ When folders are shown, the status bar text should change
+ Add code to save/restore shell view settings
+ Implement tabbing between frames
+ Fix handling of focus everywhere
+ Most keyboard shortcuts don't work, such as F2 for rename, F5 for refresh (see list in "explorer keyboard shortcuts")
+
+ The status bar doesn't show help text for items owned by frame during menu tracking
+ Stub out frame command handlers
+ "Arrange icons by" group is not checked properly
+
+ When folders are hidden, icon is the same as the current shell object being displayed. When folders are shown,
+ the icon is always an open folder with magnifying glass
+ Fix bars to calculate height correctly
+ Hookup policies for everything...
+ Investigate toolbar message WM_USER+93
+ Investigate toolbar message WM_USER+100 (Adds extra padding between parts of buttons with BTNS_DROPDOWN | BTNS_SHOWTEXT style
+
+ Vertical Explorer Bar CATID_InfoBand
+ Horizontal Explorer Bar CATID_CommBand
+ Desk Band CATID_DeskBand
+
+ cache of bars
+ HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Discardable\PostSetup\Component Categories\{00021493-0000-0000-C000-000000000046}\Enum
+ HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Discardable\PostSetup\Component Categories\{00021494-0000-0000-C000-000000000046}\Enum
+
+ create key here with CLSID of bar to register tool band
+ HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Toolbar
+
+*/
+
+#ifndef __GNUC__
+#pragma comment(linker, \
+ "\"/manifestdependency:type='Win32' "\
+ "name='Microsoft.Windows.Common-Controls' "\
+ "version='6.0.0.0' "\
+ "processorArchitecture='*' "\
+ "publicKeyToken='6595b64144ccf1df' "\
+ "language='*'\"")
+#endif // __GNUC__
+
+struct categoryCacheHeader
+{
+ long dwSize; // size of header only
+ long version; // currently 1
+ SYSTEMTIME writeTime; // time we were written to registry
+ long classCount; // number of classes following
+};
+
+static const unsigned int folderOptionsPageCountMax = 20;
+static const long BTP_UPDATE_CUR_HISTORY = 1;
+static const long BTP_UPDATE_NEXT_HISTORY = 2;
+
+BOOL createNewStuff = false;
+
+
+// this class is private to browseui.dll and is not registered externally?
+//DEFINE_GUID(CLSID_ShellFldSetExt, 0x6D5313C0, 0x8C62, 0x11D1, 0xB2, 0xCD, 0x00, 0x60, 0x97, 0xDF, 0x8C, 0x11);
+
+
+extern HRESULT CreateTravelLog(REFIID riid, void **ppv);
+extern HRESULT CreateBaseBar(REFIID riid, void **ppv);
+extern HRESULT CreateBaseBarSite(REFIID riid, void **ppv);
+
+// temporary
+extern HRESULT CreateInternetToolbar(REFIID riid, void **ppv);
+
+
+HMENU SHGetMenuFromID(HMENU topMenu, int theID)
+{
+ MENUITEMINFO menuItemInfo;
+
+ menuItemInfo.cbSize = sizeof(menuItemInfo);
+ menuItemInfo.fMask = MIIM_SUBMENU;
+ if (!GetMenuItemInfo(topMenu, theID, FALSE, &menuItemInfo))
+ return NULL;
+ return menuItemInfo.hSubMenu;
+}
+
+void SHCheckMenuItem(HMENU theMenu, int theID, BOOL checked)
+{
+ MENUITEMINFO menuItemInfo;
+
+ menuItemInfo.cbSize = sizeof(menuItemInfo);
+ menuItemInfo.fMask = MIIM_STATE;
+ if (GetMenuItemInfo(theMenu, theID, FALSE, &menuItemInfo))
+ {
+ if (checked)
+ menuItemInfo.fState |= MF_CHECKED;
+ else
+ menuItemInfo.fState &= ~MF_CHECKED;
+ SetMenuItemInfo(theMenu, theID, FALSE, &menuItemInfo);
+ }
+}
+
+void DeleteMenuItems(HMENU theMenu, unsigned int firstIDToDelete, unsigned int lastIDToDelete)
+{
+ MENUITEMINFO menuItemInfo;
+ int menuItemCount;
+ int curIndex;
+
+ menuItemCount = GetMenuItemCount(theMenu);
+ curIndex = 0;
+ while (curIndex < menuItemCount)
+ {
+ menuItemInfo.cbSize = sizeof(menuItemInfo);
+ menuItemInfo.fMask = MIIM_ID;
+ if (GetMenuItemInfo(theMenu, curIndex, TRUE, &menuItemInfo) &&
+ menuItemInfo.wID >= firstIDToDelete && menuItemInfo.wID <= lastIDToDelete)
+ {
+ DeleteMenu(theMenu, curIndex, MF_BYPOSITION);
+ menuItemCount--;
+ }
+ else
+ curIndex++;
+ }
+}
+
+HRESULT WINAPI SHBindToFolder(LPCITEMIDLIST path, IShellFolder **newFolder)
+{
+ CComPtr<IShellFolder> desktop;
+
+ HRESULT hr = ::SHGetDesktopFolder(&desktop);
+ if (FAILED(hr))
+ return E_FAIL;
+ if (path == NULL || path->mkid.cb == 0)
+ {
+ *newFolder = desktop;
+ desktop.p->AddRef ();
+ return S_OK;
+ }
+ return desktop->BindToObject (path, NULL, IID_PPV_ARG(IShellFolder, newFolder));
+}
+
+static const TCHAR szCabinetWndClass[] = TEXT("CabinetWClassX");
+static const TCHAR szExploreWndClass[] = TEXT("ExploreWClassX");
+
+class CDockManager;
+class CShellBrowser;
+
+class CToolbarProxy :
+ public CWindowImpl<CToolbarProxy, CWindow, CControlWinTraits>
+{
+private:
+ CComPtr<IExplorerToolbar> fExplorerToolbar;
+public:
+ void Initialize(HWND parent, IUnknown *explorerToolbar);
+
+private:
+
+ // message handlers
+ LRESULT OnAddBitmap(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ LRESULT OnForwardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+
+ BEGIN_MSG_MAP(CToolbarProxy)
+ MESSAGE_HANDLER(TB_ADDBITMAP, OnAddBitmap)
+ MESSAGE_RANGE_HANDLER(WM_USER, 0x7fff, OnForwardMessage)
+ END_MSG_MAP()
+};
+
+void CToolbarProxy::Initialize(HWND parent, IUnknown *explorerToolbar)
+{
+ HWND myWindow;
+ HRESULT hResult;
+
+ myWindow = SHCreateWorkerWindowW(0, parent, 0, WS_CHILD, NULL, 0);
+ if (myWindow != NULL)
+ {
+ SubclassWindow(myWindow);
+ SetWindowPos(NULL, -32000, -32000, 0, 0, SWP_NOOWNERZORDER | SWP_NOZORDER);
+ hResult = explorerToolbar->QueryInterface(
+ IID_PPV_ARG(IExplorerToolbar, &fExplorerToolbar));
+ }
+}
+
+LRESULT CToolbarProxy::OnAddBitmap(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ long int result;
+ HRESULT hResult;
+
+ result = 0;
+ if (fExplorerToolbar.p != NULL)
+ {
+ hResult = fExplorerToolbar->AddBitmap(&CGID_ShellBrowser, 1, (long)wParam,
+ reinterpret_cast<TBADDBITMAP *>(lParam), &result, RGB(192, 192, 192));
+ hResult = fExplorerToolbar->AddBitmap(&CGID_ShellBrowser, 2, (long)wParam,
+ reinterpret_cast<TBADDBITMAP *>(lParam), &result, RGB(192, 192, 192));
+ }
+ return result;
+}
+
+LRESULT CToolbarProxy::OnForwardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ LRESULT result;
+ HRESULT hResult;
+
+ result = 0;
+ if (fExplorerToolbar.p != NULL)
+ hResult = fExplorerToolbar->SendToolbarMsg(&CGID_ShellBrowser, uMsg, wParam, lParam, &result);
+ return result;
+}
+
+/*
+Switch to a new bar when it receives an Exec(CGID_IDeskBand, 1, 1, vaIn, NULL);
+ where vaIn will be a VT_UNKNOWN with the new bar. It also sends a RB_SHOWBAND to the
+ rebar
+*/
+
+class CShellBrowser :
+ public CWindowImpl<CShellBrowser, CWindow, CFrameWinTraits>,
+ public CComObjectRootEx<CComMultiThreadModelNoCS>,
+ public IShellBrowser,
+ public IDropTarget,
+ public IServiceProvider,
+ public IProfferServiceImpl<CShellBrowser>,
+ public IShellBrowserService,
+ public IWebBrowser2,
+ public ITravelLogClient,
+ public IPersistHistory,
+ public IDockingWindowSite,
+ public IOleCommandTarget,
+ public IBrowserService2,
+ public IConnectionPointContainerImpl<CShellBrowser>,
+ public MyIConnectionPointImpl<CShellBrowser, &DIID_DWebBrowserEvents2>,
+ public MyIConnectionPointImpl<CShellBrowser, &DIID_DWebBrowserEvents>
+{
+private:
+ class barInfo
+ {
+ public:
+ RECT borderSpace;
+ CComPtr<IUnknown> clientBar;
+ HWND hwnd;
+ };
+ static const int BIInternetToolbar = 0;
+ static const int BIVerticalBaseBar = 1;
+ static const int BIHorizontalBaseBar = 2;
+
+ HWND fCurrentShellViewWindow; // our currently hosted shell view window
+ CComPtr<IShellFolder> fCurrentShellFolder; //
+ CComPtr<IShellView> fCurrentShellView; //
+ LPITEMIDLIST fCurrentDirectoryPIDL; //
+ HWND fStatusBar;
+ bool fStatusBarVisible;
+ CToolbarProxy fToolbarProxy;
+ barInfo fClientBars[3];
+ CComPtr<ITravelLog> fTravelLog;
+ HMENU fCurrentMenuBar;
+ CABINETSTATE fCabinetState;
+ // The next three fields support persisted history for shell views.
+ // They do not need to be reference counted.
+ IOleObject *fHistoryObject;
+ IStream *fHistoryStream;
+ IBindCtx *fHistoryBindContext;
+ HACCEL m_hAccel;
+public:
+#if 0
+ ULONG InternalAddRef()
+ {
+ OutputDebugString(_T("AddRef\n"));
+ return CComObjectRootEx<CComMultiThreadModelNoCS>::InternalAddRef();
+ }
+ ULONG InternalRelease()
+ {
+ OutputDebugString(_T("Release\n"));
+ return CComObjectRootEx<CComMultiThreadModelNoCS>::InternalRelease();
+ }
+#endif
+
+ CShellBrowser();
+ ~CShellBrowser();
+ HRESULT Initialize(LPITEMIDLIST pidl, long b, long c, long d);
+public:
+ HRESULT BrowseToPIDL(LPCITEMIDLIST pidl, long flags);
+ HRESULT BrowseToPath(IShellFolder *newShellFolder, LPCITEMIDLIST absolutePIDL,
+ FOLDERSETTINGS *folderSettings, long flags);
+ HRESULT GetMenuBand(REFIID riid, void **shellMenu);
+ HRESULT GetBaseBar(bool vertical, IUnknown **theBaseBar);
+ HRESULT ShowBand(const CLSID &classID, bool vertical);
+ HRESULT NavigateToParent();
+ HRESULT DoFolderOptions();
+ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void RepositionBars();
+ virtual WNDPROC GetWindowProc()
+ {
+ return WindowProc;
+ }
+ HRESULT FireEvent(DISPID dispIdMember, int argCount, VARIANT *arguments);
+ HRESULT FireNavigateComplete(const wchar_t *newDirectory);
+ HRESULT FireCommandStateChange(bool newState, int commandID);
+ HRESULT FireCommandStateChangeAll();
+ HRESULT UpdateForwardBackState();
+ void UpdateGotoMenu(HMENU theMenu);
+ void UpdateViewMenu(HMENU theMenu);
+
+/* // *** IDockingWindowFrame methods ***
+ virtual HRESULT STDMETHODCALLTYPE AddToolbar(IUnknown *punkSrc, LPCWSTR pwszItem, DWORD dwAddFlags);
+ virtual HRESULT STDMETHODCALLTYPE RemoveToolbar(IUnknown *punkSrc, DWORD dwRemoveFlags);
+ virtual HRESULT STDMETHODCALLTYPE FindToolbar(LPCWSTR pwszItem, REFIID riid, void **ppv);
+ */
+
+ // *** IDockingWindowSite methods ***
+ virtual HRESULT STDMETHODCALLTYPE GetBorderDW(IUnknown* punkObj, LPRECT prcBorder);
+ virtual HRESULT STDMETHODCALLTYPE RequestBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw);
+ virtual HRESULT STDMETHODCALLTYPE SetBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw);
+
+ // *** IOleCommandTarget methods ***
+ virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
+ OLECMD prgCmds[ ], OLECMDTEXT *pCmdText);
+ virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
+ DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
+
+ // *** IOleWindow methods ***
+ virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
+ virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
+
+ // *** IShellBrowser methods ***
+ virtual HRESULT STDMETHODCALLTYPE InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
+ virtual HRESULT STDMETHODCALLTYPE SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject);
+ virtual HRESULT STDMETHODCALLTYPE RemoveMenusSB(HMENU hmenuShared);
+ virtual HRESULT STDMETHODCALLTYPE SetStatusTextSB(LPCOLESTR pszStatusText);
+ virtual HRESULT STDMETHODCALLTYPE EnableModelessSB(BOOL fEnable);
+ virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorSB(MSG *pmsg, WORD wID);
+ virtual HRESULT STDMETHODCALLTYPE BrowseObject(LPCITEMIDLIST pidl, UINT wFlags);
+ virtual HRESULT STDMETHODCALLTYPE GetViewStateStream(DWORD grfMode, IStream **ppStrm);
+ virtual HRESULT STDMETHODCALLTYPE GetControlWindow(UINT id, HWND *lphwnd);
+ virtual HRESULT STDMETHODCALLTYPE SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret);
+ virtual HRESULT STDMETHODCALLTYPE QueryActiveShellView(IShellView **ppshv);
+ virtual HRESULT STDMETHODCALLTYPE OnViewWindowActive(IShellView *ppshv);
+ virtual HRESULT STDMETHODCALLTYPE SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags);
+
+ // *** IDropTarget methods ***
+ virtual HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
+ virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
+ virtual HRESULT STDMETHODCALLTYPE DragLeave();
+ virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
+
+ // *** IServiceProvider methods ***
+ virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
+
+ // *** IShellBowserService methods ***
+ virtual HRESULT STDMETHODCALLTYPE GetPropertyBag(long flags, REFIID riid, void **ppvObject);
+
+ // *** IDispatch methods ***
+ virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
+ virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
+ virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(
+ REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
+ virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
+ DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
+
+ // *** IBrowserService methods ***
+ virtual HRESULT STDMETHODCALLTYPE GetParentSite(IOleInPlaceSite **ppipsite);
+ virtual HRESULT STDMETHODCALLTYPE SetTitle(IShellView *psv, LPCWSTR pszName);
+ virtual HRESULT STDMETHODCALLTYPE GetTitle(IShellView *psv, LPWSTR pszName, DWORD cchName);
+ virtual HRESULT STDMETHODCALLTYPE GetOleObject(IOleObject **ppobjv);
+ virtual HRESULT STDMETHODCALLTYPE GetTravelLog(ITravelLog **pptl);
+ virtual HRESULT STDMETHODCALLTYPE ShowControlWindow(UINT id, BOOL fShow);
+ virtual HRESULT STDMETHODCALLTYPE IsControlWindowShown(UINT id, BOOL *pfShown);
+ virtual HRESULT STDMETHODCALLTYPE IEGetDisplayName(LPCITEMIDLIST pidl, LPWSTR pwszName, UINT uFlags);
+ virtual HRESULT STDMETHODCALLTYPE IEParseDisplayName(UINT uiCP, LPCWSTR pwszPath, LPITEMIDLIST *ppidlOut);
+ virtual HRESULT STDMETHODCALLTYPE DisplayParseError(HRESULT hres, LPCWSTR pwszPath);
+ virtual HRESULT STDMETHODCALLTYPE NavigateToPidl(LPCITEMIDLIST pidl, DWORD grfHLNF);
+ virtual HRESULT STDMETHODCALLTYPE SetNavigateState(BNSTATE bnstate);
+ virtual HRESULT STDMETHODCALLTYPE GetNavigateState(BNSTATE *pbnstate);
+ virtual HRESULT STDMETHODCALLTYPE NotifyRedirect(IShellView *psv, LPCITEMIDLIST pidl, BOOL *pfDidBrowse);
+ virtual HRESULT STDMETHODCALLTYPE UpdateWindowList();
+ virtual HRESULT STDMETHODCALLTYPE UpdateBackForwardState();
+ virtual HRESULT STDMETHODCALLTYPE SetFlags(DWORD dwFlags, DWORD dwFlagMask);
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(DWORD *pdwFlags);
+ virtual HRESULT STDMETHODCALLTYPE CanNavigateNow( void);
+ virtual HRESULT STDMETHODCALLTYPE GetPidl(LPITEMIDLIST *ppidl);
+ virtual HRESULT STDMETHODCALLTYPE SetReferrer(LPCITEMIDLIST pidl);
+ virtual DWORD STDMETHODCALLTYPE GetBrowserIndex();
+ virtual HRESULT STDMETHODCALLTYPE GetBrowserByIndex(DWORD dwID, IUnknown **ppunk);
+ virtual HRESULT STDMETHODCALLTYPE GetHistoryObject(IOleObject **ppole, IStream **pstm, IBindCtx **ppbc);
+ virtual HRESULT STDMETHODCALLTYPE SetHistoryObject(IOleObject *pole, BOOL fIsLocalAnchor);
+ virtual HRESULT STDMETHODCALLTYPE CacheOLEServer(IOleObject *pole);
+ virtual HRESULT STDMETHODCALLTYPE GetSetCodePage(VARIANT *pvarIn, VARIANT *pvarOut);
+ virtual HRESULT STDMETHODCALLTYPE OnHttpEquiv(IShellView *psv, BOOL fDone, VARIANT *pvarargIn, VARIANT *pvarargOut);
+ virtual HRESULT STDMETHODCALLTYPE GetPalette(HPALETTE *hpal);
+ virtual HRESULT STDMETHODCALLTYPE RegisterWindow(BOOL fForceRegister, int swc);
+
+ // *** IBrowserService2 methods ***
+ virtual LRESULT STDMETHODCALLTYPE WndProcBS(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ virtual HRESULT STDMETHODCALLTYPE SetAsDefFolderSettings();
+ virtual HRESULT STDMETHODCALLTYPE GetViewRect(RECT *prc);
+ virtual HRESULT STDMETHODCALLTYPE OnSize(WPARAM wParam);
+ virtual HRESULT STDMETHODCALLTYPE OnCreate(struct tagCREATESTRUCTW *pcs);
+ virtual LRESULT STDMETHODCALLTYPE OnCommand(WPARAM wParam, LPARAM lParam);
+ virtual HRESULT STDMETHODCALLTYPE OnDestroy();
+ virtual LRESULT STDMETHODCALLTYPE OnNotify(struct tagNMHDR *pnm);
+ virtual HRESULT STDMETHODCALLTYPE OnSetFocus();
+ virtual HRESULT STDMETHODCALLTYPE OnFrameWindowActivateBS(BOOL fActive);
+ virtual HRESULT STDMETHODCALLTYPE ReleaseShellView();
+ virtual HRESULT STDMETHODCALLTYPE ActivatePendingView();
+ virtual HRESULT STDMETHODCALLTYPE CreateViewWindow(IShellView *psvNew, IShellView *psvOld, LPRECT prcView, HWND *phwnd);
+ virtual HRESULT STDMETHODCALLTYPE CreateBrowserPropSheetExt(REFIID riid, void **ppv);
+ virtual HRESULT STDMETHODCALLTYPE GetViewWindow(HWND *phwndView);
+ virtual HRESULT STDMETHODCALLTYPE GetBaseBrowserData(LPCBASEBROWSERDATA *pbbd);
+ virtual LPBASEBROWSERDATA STDMETHODCALLTYPE PutBaseBrowserData( void);
+ virtual HRESULT STDMETHODCALLTYPE InitializeTravelLog(ITravelLog *ptl, DWORD dw);
+ virtual HRESULT STDMETHODCALLTYPE SetTopBrowser();
+ virtual HRESULT STDMETHODCALLTYPE Offline(int iCmd);
+ virtual HRESULT STDMETHODCALLTYPE AllowViewResize(BOOL f);
+ virtual HRESULT STDMETHODCALLTYPE SetActivateState(UINT u);
+ virtual HRESULT STDMETHODCALLTYPE UpdateSecureLockIcon(int eSecureLock);
+ virtual HRESULT STDMETHODCALLTYPE InitializeDownloadManager();
+ virtual HRESULT STDMETHODCALLTYPE InitializeTransitionSite();
+ virtual HRESULT STDMETHODCALLTYPE _Initialize(HWND hwnd, IUnknown *pauto);
+ virtual HRESULT STDMETHODCALLTYPE _CancelPendingNavigationAsync( void);
+ virtual HRESULT STDMETHODCALLTYPE _CancelPendingView();
+ virtual HRESULT STDMETHODCALLTYPE _MaySaveChanges();
+ virtual HRESULT STDMETHODCALLTYPE _PauseOrResumeView(BOOL fPaused);
+ virtual HRESULT STDMETHODCALLTYPE _DisableModeless();
+ virtual HRESULT STDMETHODCALLTYPE _NavigateToPidl(LPCITEMIDLIST pidl, DWORD grfHLNF, DWORD dwFlags);
+ virtual HRESULT STDMETHODCALLTYPE _TryShell2Rename(IShellView *psv, LPCITEMIDLIST pidlNew);
+ virtual HRESULT STDMETHODCALLTYPE _SwitchActivationNow();
+ virtual HRESULT STDMETHODCALLTYPE _ExecChildren(IUnknown *punkBar, BOOL fBroadcast, const GUID *pguidCmdGroup,
+ DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut);
+ virtual HRESULT STDMETHODCALLTYPE _SendChildren(
+ HWND hwndBar, BOOL fBroadcast, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ virtual HRESULT STDMETHODCALLTYPE GetFolderSetData(struct tagFolderSetData *pfsd);
+ virtual HRESULT STDMETHODCALLTYPE _OnFocusChange(UINT itb);
+ virtual HRESULT STDMETHODCALLTYPE v_ShowHideChildWindows(BOOL fChildOnly);
+ virtual UINT STDMETHODCALLTYPE _get_itbLastFocus();
+ virtual HRESULT STDMETHODCALLTYPE _put_itbLastFocus(UINT itbLastFocus);
+ virtual HRESULT STDMETHODCALLTYPE _UIActivateView(UINT uState);
+ virtual HRESULT STDMETHODCALLTYPE _GetViewBorderRect(RECT *prc);
+ virtual HRESULT STDMETHODCALLTYPE _UpdateViewRectSize();
+ virtual HRESULT STDMETHODCALLTYPE _ResizeNextBorder(UINT itb);
+ virtual HRESULT STDMETHODCALLTYPE _ResizeView();
+ virtual HRESULT STDMETHODCALLTYPE _GetEffectiveClientArea(LPRECT lprectBorder, HMONITOR hmon);
+ virtual IStream *STDMETHODCALLTYPE v_GetViewStream(LPCITEMIDLIST pidl, DWORD grfMode, LPCWSTR pwszName);
+ virtual LRESULT STDMETHODCALLTYPE ForwardViewMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
+ virtual HRESULT STDMETHODCALLTYPE SetAcceleratorMenu(HACCEL hacc);
+ virtual int STDMETHODCALLTYPE _GetToolbarCount();
+ virtual LPTOOLBARITEM STDMETHODCALLTYPE _GetToolbarItem(int itb);
+ virtual HRESULT STDMETHODCALLTYPE _SaveToolbars(IStream *pstm);
+ virtual HRESULT STDMETHODCALLTYPE _LoadToolbars(IStream *pstm);
+ virtual HRESULT STDMETHODCALLTYPE _CloseAndReleaseToolbars(BOOL fClose);
+ virtual HRESULT STDMETHODCALLTYPE v_MayGetNextToolbarFocus(LPMSG lpMsg, UINT itbNext,
+ int citb, LPTOOLBARITEM *pptbi, HWND *phwnd);
+ virtual HRESULT STDMETHODCALLTYPE _ResizeNextBorderHelper(UINT itb, BOOL bUseHmonitor);
+ virtual UINT STDMETHODCALLTYPE _FindTBar(IUnknown *punkSrc);
+ virtual HRESULT STDMETHODCALLTYPE _SetFocus(LPTOOLBARITEM ptbi, HWND hwnd, LPMSG lpMsg);
+ virtual HRESULT STDMETHODCALLTYPE v_MayTranslateAccelerator(MSG *pmsg);
+ virtual HRESULT STDMETHODCALLTYPE _GetBorderDWHelper(IUnknown *punkSrc, LPRECT lprectBorder, BOOL bUseHmonitor);
+ virtual HRESULT STDMETHODCALLTYPE v_CheckZoneCrossing(LPCITEMIDLIST pidl);
+
+ // *** IWebBrowser methods ***
+ virtual HRESULT STDMETHODCALLTYPE GoBack();
+ virtual HRESULT STDMETHODCALLTYPE GoForward();
+ virtual HRESULT STDMETHODCALLTYPE GoHome();
+ virtual HRESULT STDMETHODCALLTYPE GoSearch();
+ virtual HRESULT STDMETHODCALLTYPE Navigate(BSTR URL, VARIANT *Flags, VARIANT *TargetFrameName,
+ VARIANT *PostData, VARIANT *Headers);
+ virtual HRESULT STDMETHODCALLTYPE Refresh();
+ virtual HRESULT STDMETHODCALLTYPE Refresh2(VARIANT *Level);
+ virtual HRESULT STDMETHODCALLTYPE Stop();
+ virtual HRESULT STDMETHODCALLTYPE get_Application(IDispatch **ppDisp);
+ virtual HRESULT STDMETHODCALLTYPE get_Parent(IDispatch **ppDisp);
+ virtual HRESULT STDMETHODCALLTYPE get_Container(IDispatch **ppDisp);
+ virtual HRESULT STDMETHODCALLTYPE get_Document(IDispatch **ppDisp);
+ virtual HRESULT STDMETHODCALLTYPE get_TopLevelContainer(VARIANT_BOOL *pBool);
+ virtual HRESULT STDMETHODCALLTYPE get_Type(BSTR *Type);
+ virtual HRESULT STDMETHODCALLTYPE get_Left(long *pl);
+ virtual HRESULT STDMETHODCALLTYPE put_Left(long Left);
+ virtual HRESULT STDMETHODCALLTYPE get_Top(long *pl);
+ virtual HRESULT STDMETHODCALLTYPE put_Top(long Top);
+ virtual HRESULT STDMETHODCALLTYPE get_Width(long *pl);
+ virtual HRESULT STDMETHODCALLTYPE put_Width(long Width);
+ virtual HRESULT STDMETHODCALLTYPE get_Height(long *pl);
+ virtual HRESULT STDMETHODCALLTYPE put_Height(long Height);
+ virtual HRESULT STDMETHODCALLTYPE get_LocationName(BSTR *LocationName);
+ virtual HRESULT STDMETHODCALLTYPE get_LocationURL(BSTR *LocationURL);
+ virtual HRESULT STDMETHODCALLTYPE get_Busy(VARIANT_BOOL *pBool);
+
+ // *** IWebBrowserApp methods ***
+ virtual HRESULT STDMETHODCALLTYPE Quit();
+ virtual HRESULT STDMETHODCALLTYPE ClientToWindow(int *pcx, int *pcy);
+ virtual HRESULT STDMETHODCALLTYPE PutProperty(BSTR Property, VARIANT vtValue);
+ virtual HRESULT STDMETHODCALLTYPE GetProperty(BSTR Property, VARIANT *pvtValue);
+ virtual HRESULT STDMETHODCALLTYPE get_Name(BSTR *Name);
+ virtual HRESULT STDMETHODCALLTYPE get_HWND(SHANDLE_PTR *pHWND);
+ virtual HRESULT STDMETHODCALLTYPE get_FullName(BSTR *FullName);
+ virtual HRESULT STDMETHODCALLTYPE get_Path(BSTR *Path);
+ virtual HRESULT STDMETHODCALLTYPE get_Visible(VARIANT_BOOL *pBool);
+ virtual HRESULT STDMETHODCALLTYPE put_Visible(VARIANT_BOOL Value);
+ virtual HRESULT STDMETHODCALLTYPE get_StatusBar(VARIANT_BOOL *pBool);
+ virtual HRESULT STDMETHODCALLTYPE put_StatusBar(VARIANT_BOOL Value);
+ virtual HRESULT STDMETHODCALLTYPE get_StatusText(BSTR *StatusText);
+ virtual HRESULT STDMETHODCALLTYPE put_StatusText(BSTR StatusText);
+ virtual HRESULT STDMETHODCALLTYPE get_ToolBar(int *Value);
+ virtual HRESULT STDMETHODCALLTYPE put_ToolBar(int Value);
+ virtual HRESULT STDMETHODCALLTYPE get_MenuBar(VARIANT_BOOL *Value);
+ virtual HRESULT STDMETHODCALLTYPE put_MenuBar(VARIANT_BOOL Value);
+ virtual HRESULT STDMETHODCALLTYPE get_FullScreen(VARIANT_BOOL *pbFullScreen);
+ virtual HRESULT STDMETHODCALLTYPE put_FullScreen(VARIANT_BOOL bFullScreen);
+
+ // *** IWebBrowser2 methods ***
+ virtual HRESULT STDMETHODCALLTYPE Navigate2(VARIANT *URL, VARIANT *Flags, VARIANT *TargetFrameName,
+ VARIANT *PostData, VARIANT *Headers);
+ virtual HRESULT STDMETHODCALLTYPE QueryStatusWB(OLECMDID cmdID, OLECMDF *pcmdf);
+ virtual HRESULT STDMETHODCALLTYPE ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt,
+ VARIANT *pvaIn, VARIANT *pvaOut);
+ virtual HRESULT STDMETHODCALLTYPE ShowBrowserBar(VARIANT *pvaClsid, VARIANT *pvarShow, VARIANT *pvarSize);
+ virtual HRESULT STDMETHODCALLTYPE get_ReadyState(READYSTATE *plReadyState);
+ virtual HRESULT STDMETHODCALLTYPE get_Offline(VARIANT_BOOL *pbOffline);
+ virtual HRESULT STDMETHODCALLTYPE put_Offline(VARIANT_BOOL bOffline);
+ virtual HRESULT STDMETHODCALLTYPE get_Silent(VARIANT_BOOL *pbSilent);
+ virtual HRESULT STDMETHODCALLTYPE put_Silent(VARIANT_BOOL bSilent);
+ virtual HRESULT STDMETHODCALLTYPE get_RegisterAsBrowser(VARIANT_BOOL *pbRegister);
+ virtual HRESULT STDMETHODCALLTYPE put_RegisterAsBrowser(VARIANT_BOOL bRegister);
+ virtual HRESULT STDMETHODCALLTYPE get_RegisterAsDropTarget(VARIANT_BOOL *pbRegister);
+ virtual HRESULT STDMETHODCALLTYPE put_RegisterAsDropTarget(VARIANT_BOOL bRegister);
+ virtual HRESULT STDMETHODCALLTYPE get_TheaterMode(VARIANT_BOOL *pbRegister);
+ virtual HRESULT STDMETHODCALLTYPE put_TheaterMode(VARIANT_BOOL bRegister);
+ virtual HRESULT STDMETHODCALLTYPE get_AddressBar(VARIANT_BOOL *Value);
+ virtual HRESULT STDMETHODCALLTYPE put_AddressBar(VARIANT_BOOL Value);
+ virtual HRESULT STDMETHODCALLTYPE get_Resizable(VARIANT_BOOL *Value);
+ virtual HRESULT STDMETHODCALLTYPE put_Resizable(VARIANT_BOOL Value);
+
+ // *** ITravelLogClient methods ***
+ virtual HRESULT STDMETHODCALLTYPE FindWindowByIndex(DWORD dwID, IUnknown **ppunk);
+ virtual HRESULT STDMETHODCALLTYPE GetWindowData(IStream *pStream, LPWINDOWDATA pWinData);
+ virtual HRESULT STDMETHODCALLTYPE LoadHistoryPosition(LPWSTR pszUrlLocation, DWORD dwPosition);
+
+ // *** IPersist methods ***
+ virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
+
+ // *** IPersistHistory methods ***
+ virtual HRESULT STDMETHODCALLTYPE LoadHistory(IStream *pStream, IBindCtx *pbc);
+ virtual HRESULT STDMETHODCALLTYPE SaveHistory(IStream *pStream);
+ virtual HRESULT STDMETHODCALLTYPE SetPositionCookie(DWORD dwPositioncookie);
+ virtual HRESULT STDMETHODCALLTYPE GetPositionCookie(DWORD *pdwPositioncookie);
+
+ // message handlers
+ LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ LRESULT RelayMsgToShellView(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+ LRESULT OnClose(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnFolderOptions(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnMapNetworkDrive(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnDisconnectNetworkDrive(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnAboutReactOS(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnGoBack(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnGoForward(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnGoUpLevel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnBackspace(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnGoHome(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnIsThisLegal(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnToggleStatusBarVisible(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnToggleToolbarLock(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnToggleToolbarBandVisible(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnToggleAddressBandVisible(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnToggleLinksBandVisible(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnToggleTextLabels(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnToolbarCustomize(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT OnGoTravel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled);
+ LRESULT RelayCommands(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
+
+ static ATL::CWndClassInfo& GetWndClassInfo()
+ {
+ static ATL::CWndClassInfo wc =
+ {
+ { sizeof(WNDCLASSEX), CS_DBLCLKS, StartWindowProc,
+ 0, 0, NULL, LoadIcon(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(IDI_CABINET)),
+ LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, szCabinetWndClass, NULL },
+ NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
+ };
+ return wc;
+ }
+
+ BEGIN_MSG_MAP(CShellBrowser)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+ MESSAGE_HANDLER(WM_SIZE, OnSize)
+ MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
+ MESSAGE_HANDLER(WM_MEASUREITEM, RelayMsgToShellView)
+ MESSAGE_HANDLER(WM_DRAWITEM, RelayMsgToShellView)
+ MESSAGE_HANDLER(WM_MENUSELECT, RelayMsgToShellView)
+ COMMAND_ID_HANDLER(IDM_FILE_CLOSE, OnClose)
+ COMMAND_ID_HANDLER(IDM_TOOLS_FOLDEROPTIONS, OnFolderOptions)
+ COMMAND_ID_HANDLER(IDM_TOOLS_MAPNETWORKDRIVE, OnMapNetworkDrive)
+ COMMAND_ID_HANDLER(IDM_TOOLS_DISCONNECTNETWORKDRIVE, OnDisconnectNetworkDrive)
+ COMMAND_ID_HANDLER(IDM_HELP_ABOUT, OnAboutReactOS)
+ COMMAND_ID_HANDLER(IDM_GOTO_BACK, OnGoBack)
+ COMMAND_ID_HANDLER(IDM_GOTO_FORWARD, OnGoForward)
+ COMMAND_ID_HANDLER(IDM_GOTO_UPONELEVEL, OnGoUpLevel)
+ COMMAND_ID_HANDLER(IDM_GOTO_HOMEPAGE, OnGoHome)
+ COMMAND_ID_HANDLER(IDM_HELP_ISTHISCOPYLEGAL, OnIsThisLegal)
+ COMMAND_ID_HANDLER(IDM_VIEW_STATUSBAR, OnToggleStatusBarVisible)
+ COMMAND_ID_HANDLER(IDM_TOOLBARS_LOCKTOOLBARS, OnToggleToolbarLock)
+ COMMAND_ID_HANDLER(IDM_TOOLBARS_STANDARDBUTTONS, OnToggleToolbarBandVisible)
+ COMMAND_ID_HANDLER(IDM_TOOLBARS_ADDRESSBAR, OnToggleAddressBandVisible)
+ COMMAND_ID_HANDLER(IDM_TOOLBARS_LINKSBAR, OnToggleLinksBandVisible)
+ COMMAND_ID_HANDLER(IDM_TOOLBARS_TEXTLABELS, OnToggleTextLabels)
+ COMMAND_ID_HANDLER(IDM_TOOLBARS_CUSTOMIZE, OnToolbarCustomize)
+ COMMAND_ID_HANDLER(IDM_BACKSPACE, OnBackspace)
+ COMMAND_RANGE_HANDLER(IDM_GOTO_TRAVEL_FIRSTTARGET, IDM_GOTO_TRAVEL_LASTTARGET, OnGoTravel)
+ MESSAGE_HANDLER(WM_COMMAND, RelayCommands)
+ END_MSG_MAP()
+
+ BEGIN_CONNECTION_POINT_MAP(CShellBrowser)
+ CONNECTION_POINT_ENTRY(DIID_DWebBrowserEvents2)
+ CONNECTION_POINT_ENTRY(DIID_DWebBrowserEvents)
+ END_CONNECTION_POINT_MAP()
+
+ BEGIN_COM_MAP(CShellBrowser)
+ COM_INTERFACE_ENTRY_IID(IID_IDockingWindowSite, IDockingWindowSite)
+ COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
+ COM_INTERFACE_ENTRY2_IID(IID_IOleWindow, IOleWindow, IDockingWindowSite)
+ COM_INTERFACE_ENTRY_IID(IID_IShellBrowser, IShellBrowser)
+ COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
+ COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
+ COM_INTERFACE_ENTRY_IID(IID_IProfferService, IProfferService)
+ COM_INTERFACE_ENTRY_IID(IID_IShellBrowserService, IShellBrowserService)
+ COM_INTERFACE_ENTRY_IID(IID_IDispatch, IDispatch)
+ COM_INTERFACE_ENTRY_IID(IID_IConnectionPointContainer, IConnectionPointContainer)
+ COM_INTERFACE_ENTRY_IID(IID_IWebBrowser, IWebBrowser)
+ COM_INTERFACE_ENTRY_IID(IID_IWebBrowserApp, IWebBrowserApp)
+ COM_INTERFACE_ENTRY_IID(IID_IWebBrowser2, IWebBrowser2)
+ COM_INTERFACE_ENTRY_IID(IID_ITravelLogClient, ITravelLogClient)
+ COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
+ COM_INTERFACE_ENTRY_IID(IID_IPersistHistory, IPersistHistory)
+ COM_INTERFACE_ENTRY_IID(IID_IBrowserService, IBrowserService)
+ COM_INTERFACE_ENTRY_IID(IID_IBrowserService2, IBrowserService2)
+ END_COM_MAP()
+};
+
+extern HRESULT CreateProgressDialog(REFIID riid, void **ppv);
+
+CShellBrowser::CShellBrowser()
+{
+ fCurrentShellViewWindow = NULL;
+ fCurrentDirectoryPIDL = NULL;
+ fStatusBar = NULL;
+ fStatusBarVisible = true;
+ memset(fClientBars, 0, sizeof(fClientBars));
+ fCurrentMenuBar = NULL;
+ fHistoryObject = NULL;
+ fHistoryStream = NULL;
+ fHistoryBindContext = NULL;
+}
+
+CShellBrowser::~CShellBrowser()
+{
+}
+
+HRESULT CShellBrowser::Initialize(LPITEMIDLIST pidl, long b, long c, long d)
+{
+ CComPtr<IDockingWindow> dockingWindow;
+ CComPtr<IStream> settingsStream;
+ CComPtr<IPersistStreamInit> persistStreamInit;
+ CComPtr<IOleCommandTarget> commandTarget;
+ CComPtr<IObjectWithSite> objectSite;
+ HRESULT hResult;
+
+ _AtlInitialConstruct();
+
+ fCabinetState.cLength = sizeof(fCabinetState);
+ if (ReadCabinetState(&fCabinetState, sizeof(fCabinetState)) == FALSE)
+ {
+ }
+
+ // create window
+ Create(HWND_DESKTOP);
+ if (m_hWnd == NULL)
+ return E_FAIL;
+
+#if 0
+ hResult = CoCreateInstance(CLSID_InternetToolbar, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUnknown, &fClientBars[BIInternetToolbar].clientBar));
+ if (FAILED(hResult))
+ return hResult;
+#else
+ hResult = CreateInternetToolbar(IID_PPV_ARG(IUnknown, &fClientBars[BIInternetToolbar].clientBar));
+ if (FAILED(hResult))
+ return hResult;
+#endif
+
+ // create interfaces
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IDockingWindow, &dockingWindow));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IPersistStreamInit, &persistStreamInit));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IOleCommandTarget, &commandTarget));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IObjectWithSite, &objectSite));
+ if (FAILED(hResult))
+ return hResult;
+
+ hResult = objectSite->SetSite(static_cast<IShellBrowser *>(this));
+ if (FAILED(hResult))
+ return hResult;
+
+ hResult = commandTarget->Exec(&CGID_PrivCITCommands, 1, 1 /* or 0 */, NULL, NULL);
+ if (FAILED(hResult))
+ return hResult;
+
+ // TODO: create settingsStream from registry entry
+ if (settingsStream.p == NULL)
+ {
+ hResult = persistStreamInit->InitNew();
+ if (FAILED(hResult))
+ return hResult;
+ }
+ else
+ {
+ hResult = persistStreamInit->Load(settingsStream);
+ if (FAILED(hResult))
+ return hResult;
+ }
+ hResult = dockingWindow->ShowDW(TRUE);
+ if (FAILED(hResult))
+ return hResult;
+
+ fToolbarProxy.Initialize(m_hWnd, fClientBars[BIInternetToolbar].clientBar);
+
+ // create status bar
+ fStatusBar = CreateWindow(STATUSCLASSNAMEW, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
+ SBT_NOBORDERS | SBT_TOOLTIPS, 0, 0, 500, 20, m_hWnd, (HMENU)0xa001,
+ _AtlBaseModule.GetModuleInstance(), 0);
+ fStatusBarVisible = true;
+
+ // browse
+ hResult = BrowseToPIDL(pidl, BTP_UPDATE_NEXT_HISTORY);
+ if (FAILED(hResult))
+ return hResult;
+
+ ShowWindow(SW_SHOWNORMAL);
+
+ return S_OK;
+}
+
+HRESULT CShellBrowser::BrowseToPIDL(LPCITEMIDLIST pidl, long flags)
+{
+ CComPtr<IShellFolder> newFolder;
+ FOLDERSETTINGS newFolderSettings;
+ HRESULT hResult;
+
+ // called by shell view to browse to new folder
+ // also called by explorer band to navigate to new folder
+ hResult = SHBindToFolder(pidl, &newFolder);
+ if (FAILED(hResult))
+ return hResult;
+
+ newFolderSettings.ViewMode = FVM_ICON;
+ newFolderSettings.fFlags = 0;
+ hResult = BrowseToPath(newFolder, pidl, &newFolderSettings, flags);
+ if (FAILED(hResult))
+ return hResult;
+ return S_OK;
+}
+
+BOOL WINAPI _ILIsDesktop(LPCITEMIDLIST pidl)
+{
+ return (pidl == NULL || pidl->mkid.cb == 0);
+}
+
+BOOL WINAPI _ILIsPidlSimple(LPCITEMIDLIST pidl)
+{
+ LPCITEMIDLIST pidlnext;
+ WORD length;
+ BOOL ret;
+
+ ret = TRUE;
+ if (! _ILIsDesktop(pidl))
+ {
+ length = pidl->mkid.cb;
+ pidlnext =
+ reinterpret_cast<LPCITEMIDLIST>(
+ reinterpret_cast<const BYTE *>(pidl) + length);
+ if (pidlnext->mkid.cb != 0)
+ ret = FALSE;
+ }
+ return ret;
+}
+
+HRESULT WINAPI SHBindToFolderIDListParent(IShellFolder *unused, LPCITEMIDLIST pidl,
+ const IID *riid, LPVOID *ppv, LPITEMIDLIST *ppidlLast)
+{
+ CComPtr<IShellFolder> psf;
+ LPITEMIDLIST pidlChild;
+ LPITEMIDLIST pidlParent;
+ HRESULT hResult;
+
+ hResult = E_FAIL;
+ if (ppv == NULL)
+ return E_POINTER;
+ *ppv = NULL;
+ if (ppidlLast != NULL)
+ *ppidlLast = NULL;
+ if (_ILIsPidlSimple(pidl))
+ {
+ if (ppidlLast != NULL)
+ *ppidlLast = ILClone(pidl);
+ hResult = SHGetDesktopFolder((IShellFolder **)ppv);
+ }
+ else
+ {
+ pidlChild = ILClone(ILFindLastID(pidl));
+ pidlParent = ILClone(pidl);
+ ILRemoveLastID(pidlParent);
+ hResult = SHGetDesktopFolder(&psf);
+ if (SUCCEEDED(hResult))
+ hResult = psf->BindToObject(pidlParent, NULL, *riid, ppv);
+ if (SUCCEEDED(hResult) && ppidlLast != NULL)
+ *ppidlLast = pidlChild;
+ else
+ ILFree(pidlChild);
+ ILFree(pidlParent);
+ }
+ return hResult;
+}
+
+HRESULT IEGetNameAndFlagsEx(LPITEMIDLIST pidl, SHGDNF uFlags, long param10,
+ LPWSTR pszBuf, UINT cchBuf, SFGAOF *rgfInOut)
+{
+ CComPtr<IShellFolder> parentFolder;
+ LPITEMIDLIST childPIDL;
+ STRRET L108;
+ HRESULT hResult;
+
+ hResult = SHBindToFolderIDListParent(NULL, pidl, &IID_PPV_ARG(IShellFolder, &parentFolder), &childPIDL);
+ hResult = parentFolder->GetDisplayNameOf(childPIDL, uFlags, &L108);
+ StrRetToBufW(&L108, childPIDL, pszBuf, cchBuf);
+ if (rgfInOut)
+ hResult = parentFolder->GetAttributesOf(1, const_cast<LPCITEMIDLIST *>(&childPIDL), rgfInOut);
+ ILFree(childPIDL);
+ return S_OK;
+}
+
+long IEGetNameAndFlags(LPITEMIDLIST pidl, SHGDNF uFlags, LPWSTR pszBuf, UINT cchBuf, SFGAOF *rgfInOut)
+{
+ return IEGetNameAndFlagsEx(pidl, uFlags, 0, pszBuf, cchBuf, rgfInOut);
+}
+
+HRESULT CShellBrowser::BrowseToPath(IShellFolder *newShellFolder,
+ LPCITEMIDLIST absolutePIDL, FOLDERSETTINGS *folderSettings, long flags)
+{
+ CComPtr<IObjectWithSite> objectWithSite;
+ CComPtr<IShellFolder> saveCurrentShellFolder;
+ CComPtr<IShellView> saveCurrentShellView;
+ CComPtr<IShellView> newShellView;
+ CComPtr<ITravelLog> travelLog;
+ HWND newShellViewWindow;
+ BOOL windowUpdateIsLocked;
+ RECT shellViewWindowBounds;
+ HWND previousView;
+ HCURSOR saveCursor;
+ wchar_t newTitle[MAX_PATH];
+ SHGDNF nameFlags;
+ HRESULT hResult;
+
+ if (newShellFolder == NULL)
+ return E_INVALIDARG;
+
+ hResult = GetTravelLog(&travelLog);
+ if (FAILED(hResult))
+ return hResult;
+
+ // update history
+ if (flags & BTP_UPDATE_CUR_HISTORY)
+ {
+ if (travelLog->CountEntries(static_cast<IDropTarget *>(this)) > 0)
+ hResult = travelLog->UpdateEntry(static_cast<IDropTarget *>(this), FALSE);
+ // what to do with error? Do we want to halt browse because state save failed?
+ }
+
++ if (fCurrentShellView)
++ {
++ fCurrentShellView->UIActivate(SVUIA_DEACTIVATE);
++ }
++
+ // create view object
+ hResult = newShellFolder->CreateViewObject(m_hWnd, IID_PPV_ARG(IShellView, &newShellView));
+ if (FAILED(hResult))
+ return hResult;
+ previousView = fCurrentShellViewWindow;
+
+ // enter updating section
+ saveCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
+ windowUpdateIsLocked = LockWindowUpdate(TRUE);
+ if (fCurrentShellView != NULL)
+ ::SendMessage(fCurrentShellViewWindow, WM_SETREDRAW, 0, 0);
+
+ // set site
+ hResult = newShellView->QueryInterface(IID_PPV_ARG(IObjectWithSite, &objectWithSite));
+ if (SUCCEEDED(hResult) && objectWithSite.p != NULL)
+ hResult = objectWithSite->SetSite(static_cast<IDropTarget *>(this));
+
+ // update folder and view
+ saveCurrentShellFolder = fCurrentShellFolder;
+ saveCurrentShellView = fCurrentShellView;
+ fCurrentShellFolder = newShellFolder;
+ fCurrentShellView = newShellView;
+
+ // get boundary
+ if (previousView != NULL)
+ ::GetWindowRect(previousView, &shellViewWindowBounds);
+ else
+ ZeroMemory(&shellViewWindowBounds, sizeof(shellViewWindowBounds));
+ ::MapWindowPoints(0, m_hWnd, reinterpret_cast<POINT *>(&shellViewWindowBounds), 2);
+
+ // create view window
+ hResult = newShellView->CreateViewWindow(saveCurrentShellView, folderSettings,
+ this, &shellViewWindowBounds, &newShellViewWindow);
+ if (FAILED(hResult) || newShellViewWindow == NULL)
+ {
+ fCurrentShellView = saveCurrentShellView;
+ fCurrentShellFolder = saveCurrentShellFolder;
+ ::SendMessage(fCurrentShellViewWindow, WM_SETREDRAW, 1, 0);
+ if (windowUpdateIsLocked)
+ LockWindowUpdate(FALSE);
+ SetCursor(saveCursor);
+ return hResult;
+ }
+
+ if (objectWithSite.p != NULL)
+ hResult = objectWithSite->SetSite(NULL);
+
+ // update current pidl
+ ILFree(fCurrentDirectoryPIDL);
+ fCurrentDirectoryPIDL = ILClone(absolutePIDL);
+
+ // update view window
+ if (saveCurrentShellView != NULL)
+ saveCurrentShellView->DestroyViewWindow();
+ fCurrentShellViewWindow = newShellViewWindow;
+
+ // no use
+ saveCurrentShellView.Release();
+ saveCurrentShellFolder.Release();
+
+ hResult = newShellView->UIActivate(SVUIA_ACTIVATE_FOCUS);
+
+ // leave updating section
+ if (windowUpdateIsLocked)
+ LockWindowUpdate(FALSE);
+ SetCursor(saveCursor);
+
+ // update history
+ if (flags & BTP_UPDATE_NEXT_HISTORY)
+ {
+ hResult = travelLog->AddEntry(static_cast<IDropTarget *>(this), FALSE);
+ hResult = travelLog->UpdateEntry(static_cast<IDropTarget *>(this), FALSE);
+ }
+
+ // completed
+ nameFlags = SHGDN_FORADDRESSBAR | SHGDN_FORPARSING;
+ hResult = IEGetNameAndFlags(fCurrentDirectoryPIDL, nameFlags, newTitle,
+ sizeof(newTitle) / sizeof(wchar_t), NULL);
+ if (SUCCEEDED(hResult))
+ {
+ FireNavigateComplete(newTitle);
+ }
+ else
+ {
+ FireNavigateComplete(L"ERROR");
+ }
+
+ if (fCabinetState.fFullPathTitle)
+ nameFlags = SHGDN_FORADDRESSBAR | SHGDN_FORPARSING;
+ else
+ nameFlags = SHGDN_FORADDRESSBAR;
+ hResult = IEGetNameAndFlags(fCurrentDirectoryPIDL, nameFlags, newTitle,
+ sizeof(newTitle) / sizeof(wchar_t), NULL);
+ if (SUCCEEDED(hResult))
+ {
+ SetWindowText(newTitle);
+
+ LPCITEMIDLIST pidlChild;
+ INT index, indexOpen;
+ HIMAGELIST himlSmall, himlLarge;
+
+ CComPtr<IShellFolder> sf;
+ SHBindToParent(absolutePIDL, IID_PPV_ARG(IShellFolder, &sf), &pidlChild);
+
+ index = SHMapPIDLToSystemImageListIndex(sf, pidlChild, &indexOpen);
+
+ Shell_GetImageLists(&himlLarge, &himlSmall);
+
+ HICON icSmall = ImageList_GetIcon(himlSmall, indexOpen, 0);
+ HICON icLarge = ImageList_GetIcon(himlLarge, indexOpen, 0);
+
+ SendMessage(WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(icSmall));
+ SendMessage(WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(icLarge));
+ }
+
+ // TODO: Update the window icon
+
+ FireCommandStateChangeAll();
+ hResult = UpdateForwardBackState();
+ return S_OK;
+}
+
+HRESULT CShellBrowser::GetMenuBand(REFIID riid, void **shellMenu)
+{
+ CComPtr<IServiceProvider> serviceProvider;
+ CComPtr<IBandSite> bandSite;
+ CComPtr<IDeskBand> deskBand;
+ HRESULT hResult;
+
+ if (fClientBars[BIInternetToolbar].clientBar.p == NULL)
+ return E_FAIL;
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IServiceProvider, &serviceProvider));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = serviceProvider->QueryService(SID_IBandSite, IID_PPV_ARG(IBandSite, &bandSite));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = bandSite->QueryBand(1, &deskBand, NULL, NULL, 0);
+ if (FAILED(hResult))
+ return hResult;
+ return deskBand->QueryInterface(riid, shellMenu);
+}
+
+HRESULT CShellBrowser::GetBaseBar(bool vertical, IUnknown **theBaseBar)
+{
+ CComPtr<IUnknown> newBaseBar;
+ CComPtr<IDeskBar> deskBar;
+ CComPtr<IUnknown> newBaseBarSite;
+ CComPtr<IObjectWithSite> objectWithSite;
+ CComPtr<IDeskBarClient> deskBarClient;
+ IUnknown **cache;
+ HRESULT hResult;
+
+ if (vertical)
+ cache = &fClientBars[BIVerticalBaseBar].clientBar.p;
+ else
+ cache = &fClientBars[BIHorizontalBaseBar].clientBar.p;
+ if (*cache == NULL)
+ {
+ hResult = CreateBaseBar(IID_PPV_ARG(IUnknown, &newBaseBar));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = CreateBaseBarSite(IID_PPV_ARG(IUnknown, &newBaseBarSite));
+ if (FAILED(hResult))
+ return hResult;
+
+ // tell the new base bar about the shell browser
+ hResult = newBaseBar->QueryInterface(IID_PPV_ARG(IObjectWithSite, &objectWithSite));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = objectWithSite->SetSite(static_cast<IDropTarget *>(this));
+ if (FAILED(hResult))
+ return hResult;
+
+ // tell the new base bar about the new base bar site
+ hResult = newBaseBar->QueryInterface(IID_PPV_ARG(IDeskBar, &deskBar));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = deskBar->SetClient(newBaseBarSite);
+ if (FAILED(hResult))
+ return hResult;
+
+ // tell the new base bar site about the new base bar
+ hResult = newBaseBarSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &deskBarClient));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = deskBarClient->SetDeskBarSite(newBaseBar);
+ if (FAILED(hResult))
+ return hResult;
+
+ *cache = newBaseBar.Detach();
+ }
+ return (*cache)->QueryInterface(IID_PPV_ARG(IUnknown, theBaseBar));
+}
+
+HRESULT CShellBrowser::ShowBand(const CLSID &classID, bool vertical)
+{
+ CComPtr<IDockingWindow> dockingWindow;
+ CComPtr<IOleCommandTarget> oleCommandTarget;
+ CComPtr<IUnknown> baseBarSite;
+ CComPtr<IUnknown> newBand;
+ CComPtr<IUnknown> theBaseBar;
+ CComPtr<IDeskBar> deskBar;
+ VARIANT vaIn;
+ HRESULT hResult;
+
+ __debugbreak();
+
+ hResult = GetBaseBar(vertical, (IUnknown **)&theBaseBar);
+ if (FAILED(hResult))
+ return hResult;
+ hResult = CoCreateInstance(classID, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUnknown, &newBand));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = theBaseBar->QueryInterface(IID_PPV_ARG(IDeskBar, &deskBar));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = deskBar->GetClient(&baseBarSite);
+ if (FAILED(hResult))
+ return hResult;
+ hResult = theBaseBar->QueryInterface(IID_PPV_ARG(IDockingWindow, &dockingWindow));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = baseBarSite->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &oleCommandTarget));
+ if (FAILED(hResult))
+ return hResult;
+ V_VT(&vaIn) = VT_UNKNOWN;
+ V_UNKNOWN(&vaIn) = newBand.p;
+ hResult = oleCommandTarget->Exec(&CGID_IDeskBand, 1, 1, &vaIn, NULL);
+ if (FAILED(hResult))
+ return hResult;
+ hResult = dockingWindow->ShowDW(TRUE);
+ if (FAILED(hResult))
+ return hResult;
+ return S_OK;
+}
+
+HRESULT CShellBrowser::NavigateToParent()
+{
+ LPITEMIDLIST newDirectory;
+ HRESULT hResult;
+
+ newDirectory = ILClone(fCurrentDirectoryPIDL);
+ if (newDirectory == NULL)
+ return E_OUTOFMEMORY;
+ ILRemoveLastID(newDirectory);
+ hResult = BrowseToPIDL(newDirectory, BTP_UPDATE_CUR_HISTORY | BTP_UPDATE_NEXT_HISTORY);
+ ILFree(newDirectory);
+ if (FAILED(hResult))
+ return hResult;
+ return S_OK;
+}
+
+BOOL CALLBACK AddFolderOptionsPage(HPROPSHEETPAGE thePage, LPARAM lParam)
+{
+ PROPSHEETHEADER *sheetInfo;
+
+ sheetInfo = (PROPSHEETHEADER *)lParam;
+ if (sheetInfo->nPages >= folderOptionsPageCountMax)
+ return FALSE;
+ sheetInfo->phpage[sheetInfo->nPages] = thePage;
+ sheetInfo->nPages++;
+ return TRUE;
+}
+
+HRESULT CShellBrowser::DoFolderOptions()
+{
+ CComPtr<IShellPropSheetExt> folderOptionsSheet;
+ CComPtr<IObjectWithSite> objectWithSite;
+ PROPSHEETHEADER m_PropSheet;
+ HPROPSHEETPAGE m_psp[folderOptionsPageCountMax];
+// CComPtr<IGlobalFolderSettings> globalSettings;
+// SHELLSTATE2 shellState;
+ HRESULT hResult;
+
+ memset(m_psp, 0, sizeof(m_psp));
+ memset(&m_PropSheet, 0, sizeof(m_PropSheet));
+
+ // create sheet object
+ hResult = CoCreateInstance(CLSID_ShellFldSetExt, NULL, CLSCTX_INPROC_SERVER,
+ IID_PPV_ARG(IShellPropSheetExt, &folderOptionsSheet));
+ if (FAILED(hResult))
+ return E_FAIL;
+
+ // must set site in order for Apply to all Folders on Advanced page to be enabled
+ hResult = folderOptionsSheet->QueryInterface(IID_PPV_ARG(IObjectWithSite, &objectWithSite));
+ if (SUCCEEDED(hResult) && objectWithSite.p != NULL)
+ hResult = objectWithSite->SetSite(static_cast<IDispatch *>(this));
+ m_PropSheet.phpage = m_psp;
+
+#if 0
+ hResult = CoCreateInstance(CLSID_GlobalFolderSettings, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IGlobalFolderSettings, &globalSettings));
+ if (FAILED(hResult))
+ return E_FAIL;
+ hResult = globalSettings->Get(&shellState, sizeof(shellState));
+ if (FAILED(hResult))
+ return E_FAIL;
+#endif
+
+ // add pages
+ hResult = folderOptionsSheet->AddPages(AddFolderOptionsPage, reinterpret_cast<LPARAM>(&m_PropSheet));
+ if (FAILED(hResult))
+ return E_FAIL;
+
+ if (fCurrentShellView != NULL)
+ {
+ hResult = fCurrentShellView->AddPropertySheetPages(
+ 0, AddFolderOptionsPage, reinterpret_cast<LPARAM>(&m_PropSheet));
+ if (FAILED(hResult))
+ return E_FAIL;
+ }
+
+ // show sheet
+ m_PropSheet.dwSize = sizeof(PROPSHEETHEADER);
+ m_PropSheet.dwFlags = 0;
+ m_PropSheet.hwndParent = m_hWnd;
+ m_PropSheet.hInstance = _AtlBaseModule.GetResourceInstance();
+ m_PropSheet.pszCaption = _T("Folder Options");
+ m_PropSheet.nStartPage = 0;
+ PropertySheet(&m_PropSheet);
+ return S_OK;
+}
+
+LRESULT CALLBACK CShellBrowser::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ CShellBrowser *pThis = reinterpret_cast<CShellBrowser *>(hWnd);
+ _ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
+ LRESULT lResult;
+ CComPtr<IMenuBand> menuBand;
+ const _ATL_MSG *previousMessage;
+ BOOL handled;
+ WNDPROC saveWindowProc;
+ HRESULT hResult;
+
+ hWnd = pThis->m_hWnd;
+ previousMessage = pThis->m_pCurrentMsg;
+ pThis->m_pCurrentMsg = &msg;
+
+ hResult = pThis->GetMenuBand(IID_PPV_ARG(IMenuBand, &menuBand));
+ if (SUCCEEDED(hResult) && menuBand.p != NULL)
+ {
+ hResult = menuBand->TranslateMenuMessage(&msg, &lResult);
+ if (hResult == S_OK)
+ return lResult;
+ uMsg = msg.message;
+ wParam = msg.wParam;
+ lParam = msg.lParam;
+ }
+
+ handled = pThis->ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, 0);
+ ATLASSERT(pThis->m_pCurrentMsg == &msg);
+ if (handled == FALSE)
+ {
+ if (uMsg == WM_NCDESTROY)
+ {
+ saveWindowProc = reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWL_WNDPROC));
+ lResult = pThis->DefWindowProc(uMsg, wParam, lParam);
+ if (saveWindowProc == reinterpret_cast<WNDPROC>(GetWindowLongPtr(hWnd, GWL_WNDPROC)))
+ SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);
+ pThis->m_dwState |= WINSTATE_DESTROYED;
+ }
+ else
+ lResult = pThis->DefWindowProc(uMsg, wParam, lParam);
+ }
+ pThis->m_pCurrentMsg = previousMessage;
+ if (previousMessage == NULL && (pThis->m_dwState & WINSTATE_DESTROYED) != 0)
+ {
+ pThis->m_dwState &= ~WINSTATE_DESTROYED;
+ pThis->m_hWnd = NULL;
+ pThis->OnFinalMessage(hWnd);
+ }
+ return lResult;
+}
+
+void CShellBrowser::RepositionBars()
+{
+ RECT clientRect;
+ RECT statusRect;
+ int x;
+
+ GetClientRect(&clientRect);
+
+ if (fStatusBarVisible && fStatusBar)
+ {
+ ::GetWindowRect(fStatusBar, &statusRect);
+ ::SetWindowPos(fStatusBar, NULL, clientRect.left, clientRect.bottom - (statusRect.bottom - statusRect.top),
+ clientRect.right - clientRect.left,
+ statusRect.bottom - statusRect.top, SWP_NOOWNERZORDER | SWP_NOZORDER);
+ clientRect.bottom -= statusRect.bottom - statusRect.top;
+ }
+
+ for (x = 0; x < 3; x++)
+ {
+ HWND hwnd = fClientBars[x].hwnd;
+ RECT borderSpace = fClientBars[x].borderSpace;
+ if (hwnd == NULL && fClientBars[x].clientBar != NULL)
+ {
+ IUnknown_GetWindow(fClientBars[x].clientBar, &hwnd);
+ fClientBars[x].hwnd = hwnd;
+ }
+ if (hwnd != NULL)
+ {
+ RECT toolbarRect = clientRect;
+ if (borderSpace.top != 0)
+ {
+ toolbarRect.bottom = toolbarRect.top + borderSpace.top;
+ }
+ else if (borderSpace.bottom != 0)
+ {
+ toolbarRect.top = toolbarRect.bottom - borderSpace.bottom;
+ }
+ else if (borderSpace.left != 0)
+ {
+ toolbarRect.right = toolbarRect.left + borderSpace.left;
+ }
+ else if (borderSpace.right != 0)
+ {
+ toolbarRect.left = toolbarRect.right - borderSpace.right;
+ }
+
+ ::SetWindowPos(hwnd, NULL,
+ toolbarRect.left,
+ toolbarRect.top,
+ toolbarRect.right - toolbarRect.left,
+ toolbarRect.bottom - toolbarRect.top,
+ SWP_NOOWNERZORDER | SWP_NOZORDER);
+
+ if (borderSpace.top != 0)
+ {
+ clientRect.top = toolbarRect.bottom;
+ }
+ else if (borderSpace.bottom != 0)
+ {
+ clientRect.bottom = toolbarRect.top;
+ }
+ else if (borderSpace.left != 0)
+ {
+ clientRect.left = toolbarRect.right;
+ }
+ else if (borderSpace.right != 0)
+ {
+ clientRect.right = toolbarRect.left;
+ }
+ }
+ }
+ ::SetWindowPos(fCurrentShellViewWindow, NULL, clientRect.left, clientRect.top,
+ clientRect.right - clientRect.left,
+ clientRect.bottom - clientRect.top, SWP_NOOWNERZORDER | SWP_NOZORDER);
+}
+
+HRESULT CShellBrowser::FireEvent(DISPID dispIdMember, int argCount, VARIANT *arguments)
+{
+ DISPPARAMS params;
+ CComDynamicUnkArray &vec = IConnectionPointImpl<CShellBrowser, &DIID_DWebBrowserEvents2>::m_vec;
+ CComDynamicUnkArray &vec2 = IConnectionPointImpl<CShellBrowser, &DIID_DWebBrowserEvents>::m_vec;
+ HRESULT hResult;
+
+ params.rgvarg = arguments;
+ params.rgdispidNamedArgs = NULL;
+ params.cArgs = argCount;
+ params.cNamedArgs = 0;
+ IUnknown** pp = vec.begin();
+ while (pp < vec.end())
+ {
+ if (*pp != NULL)
+ {
+ CComPtr<IDispatch> theDispatch;
+
+ hResult = (*pp)->QueryInterface(IID_PPV_ARG(IDispatch, &theDispatch));
+ hResult = theDispatch->Invoke(dispIdMember, GUID_NULL, 0, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL);
+ }
+ pp++;
+ }
+ pp = vec2.begin();
+ while (pp < vec2.end())
+ {
+ if (*pp != NULL)
+ {
+ CComPtr<IDispatch> theDispatch;
+
+ hResult = (*pp)->QueryInterface(IID_PPV_ARG(IDispatch, &theDispatch));
+ hResult = theDispatch->Invoke(dispIdMember, GUID_NULL, 0, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL);
+ }
+ pp++;
+ }
+ return S_OK;
+}
+
+HRESULT CShellBrowser::FireNavigateComplete(const wchar_t *newDirectory)
+{
+ // these two variants intentionally to do use CComVariant because it would double free/release
+ // or does not need to dispose at all
+ VARIANT varArg[2];
+ VARIANT varArgs;
+ CComBSTR tempString(newDirectory);
+
+ V_VT(&varArgs) = VT_BSTR;
+ V_BSTR(&varArgs) = tempString.m_str;
+
+ V_VT(&varArg[0]) = VT_VARIANT | VT_BYREF;
+ V_VARIANTREF(&varArg[0]) = &varArgs;
+ V_VT(&varArg[1]) = VT_DISPATCH;
+ V_DISPATCH(&varArg[1]) = (IDispatch *)this;
+
+ return FireEvent(DISPID_NAVIGATECOMPLETE2, 2, varArg);
+}
+
+HRESULT CShellBrowser::FireCommandStateChange(bool newState, int commandID)
+{
+ VARIANT varArg[2];
+
+ V_VT(&varArg[0]) = VT_BOOL;
+ V_BOOL(&varArg[0]) = newState ? VARIANT_TRUE : VARIANT_FALSE;
+ V_VT(&varArg[1]) = VT_I4;
+ V_I4(&varArg[1]) = commandID;
+
+ return FireEvent(DISPID_COMMANDSTATECHANGE, 2, varArg);
+}
+
+HRESULT CShellBrowser::FireCommandStateChangeAll()
+{
+ return FireCommandStateChange(false, -1);
+}
+
+HRESULT CShellBrowser::UpdateForwardBackState()
+{
+ CComPtr<ITravelLog> travelLog;
+ CComPtr<ITravelEntry> unusedEntry;
+ bool canGoBack;
+ bool canGoForward;
+ HRESULT hResult;
+
+ canGoBack = false;
+ canGoForward = false;
+ hResult = GetTravelLog(&travelLog);
+ if (FAILED(hResult))
+ return hResult;
+ hResult = travelLog->GetTravelEntry(static_cast<IDropTarget *>(this), TLOG_BACK, &unusedEntry);
+ if (SUCCEEDED(hResult))
+ {
+ canGoBack = true;
+ unusedEntry.Release();
+ }
+ hResult = travelLog->GetTravelEntry(static_cast<IDropTarget *>(this), TLOG_FORE, &unusedEntry);
+ if (SUCCEEDED(hResult))
+ {
+ canGoForward = true;
+ unusedEntry.Release();
+ }
+ hResult = FireCommandStateChange(canGoBack, 2);
+ hResult = FireCommandStateChange(canGoForward, 1);
+ return S_OK;
+}
+
+void CShellBrowser::UpdateGotoMenu(HMENU theMenu)
+{
+ CComPtr<ITravelLog> travelLog;
+ int position;
+ MENUITEMINFO menuItemInfo;
+ HRESULT hResult;
+
+ DeleteMenuItems(theMenu, IDM_GOTO_TRAVEL_FIRST, IDM_GOTO_TRAVEL_LAST);
+
+ position = GetMenuItemCount(theMenu);
+ hResult = GetTravelLog(&travelLog);
+ if (FAILED(hResult))
+ return;
+ hResult = travelLog->InsertMenuEntries(static_cast<IDropTarget *>(this), theMenu, position,
+ IDM_GOTO_TRAVEL_FIRSTTARGET, IDM_GOTO_TRAVEL_LASTTARGET, TLMENUF_BACKANDFORTH | TLMENUF_CHECKCURRENT);
+ if (SUCCEEDED(hResult))
+ {
+ menuItemInfo.cbSize = sizeof(menuItemInfo);
+ menuItemInfo.fMask = MIIM_TYPE | MIIM_ID;
+ menuItemInfo.fType = MF_SEPARATOR;
+ menuItemInfo.wID = IDM_GOTO_TRAVEL_SEP;
+ InsertMenuItem(theMenu, position, TRUE, &menuItemInfo);
+ }
+}
+
+void CShellBrowser::UpdateViewMenu(HMENU theMenu)
+{
+ CComPtr<IOleCommandTarget> oleCommandTarget;
+ CComPtr<ITravelLog> travelLog;
+ HMENU gotoMenu;
+ OLECMD commandList[5];
+ HMENU toolbarMenuBar;
+ HMENU toolbarMenu;
+ MENUITEMINFO menuItemInfo;
+ HRESULT hResult;
+
+ gotoMenu = SHGetMenuFromID(theMenu, FCIDM_MENU_EXPLORE);
+ if (gotoMenu != NULL)
+ UpdateGotoMenu(gotoMenu);
+
+ commandList[0].cmdID = ITID_TOOLBARBANDSHOWN;
+ commandList[1].cmdID = ITID_ADDRESSBANDSHOWN;
+ commandList[2].cmdID = ITID_LINKSBANDSHOWN;
+ commandList[3].cmdID = ITID_TOOLBARLOCKED;
+ commandList[4].cmdID = ITID_CUSTOMIZEENABLED;
+
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IOleCommandTarget, &oleCommandTarget));
+ if (SUCCEEDED(hResult))
+ hResult = oleCommandTarget->QueryStatus(&CGID_PrivCITCommands, 5, commandList, NULL);
+ if (FAILED(hResult))
+ DeleteMenu(theMenu, IDM_VIEW_TOOLBARS, MF_BYCOMMAND);
+ else
+ {
+ toolbarMenuBar = LoadMenu(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(IDM_CABINET_CONTEXTMENU));
+ toolbarMenu = GetSubMenu(toolbarMenuBar, 0);
+
+ SHCheckMenuItem(toolbarMenu, IDM_TOOLBARS_STANDARDBUTTONS, commandList[0].cmdf);
+ SHCheckMenuItem(toolbarMenu, IDM_TOOLBARS_ADDRESSBAR, commandList[1].cmdf & OLECMDF_ENABLED);
+ SHCheckMenuItem(toolbarMenu, IDM_TOOLBARS_LINKSBAR, commandList[2].cmdf & OLECMDF_ENABLED);
+ SHCheckMenuItem(toolbarMenu, IDM_TOOLBARS_LOCKTOOLBARS, commandList[3].cmdf & OLECMDF_ENABLED);
+ if ((commandList[4].cmdf & OLECMDF_ENABLED) == 0)
+ DeleteMenu(toolbarMenu, IDM_TOOLBARS_CUSTOMIZE, MF_BYCOMMAND);
+ DeleteMenu(toolbarMenu, IDM_TOOLBARS_TEXTLABELS, MF_BYCOMMAND);
+ DeleteMenu(toolbarMenu, IDM_TOOLBARS_GOBUTTON, MF_BYCOMMAND);
+
+ menuItemInfo.cbSize = sizeof(menuItemInfo);
+ menuItemInfo.fMask = MIIM_SUBMENU;
+ menuItemInfo.hSubMenu = toolbarMenu;
+ SetMenuItemInfo(theMenu, IDM_VIEW_TOOLBARS, FALSE, &menuItemInfo);
+ }
+ SHCheckMenuItem(theMenu, IDM_VIEW_STATUSBAR, fStatusBarVisible ? TRUE : FALSE);
+}
+
+bool IUnknownIsEqual(IUnknown *int1, IUnknown *int2)
+{
+ CComPtr<IUnknown> int1Retry;
+ CComPtr<IUnknown> int2Retry;
+ HRESULT hResult;
+
+ if (int1 == int2)
+ return true;
+ if (int1 == NULL || int2 == NULL)
+ return false;
+ hResult = int1->QueryInterface(IID_PPV_ARG(IUnknown, &int1Retry));
+ if (FAILED(hResult))
+ return false;
+ hResult = int2->QueryInterface(IID_PPV_ARG(IUnknown, &int2Retry));
+ if (FAILED(hResult))
+ return false;
+ if (int1Retry == int2Retry)
+ return true;
+ return false;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetBorderDW(IUnknown *punkObj, LPRECT prcBorder)
+{
+ static const INT excludeItems[] = { 1, 1, 1, 0xa001, 0, 0 };
+
+ RECT availableBounds;
+
+ GetEffectiveClientRect(m_hWnd, &availableBounds, excludeItems);
+ for (INT x = 0; x < 3; x++)
+ {
+ if (fClientBars[x].clientBar.p != NULL && !IUnknownIsEqual(fClientBars[x].clientBar, punkObj))
+ {
+ availableBounds.top += fClientBars[x].borderSpace.top;
+ availableBounds.left += fClientBars[x].borderSpace.left;
+ availableBounds.bottom -= fClientBars[x].borderSpace.bottom;
+ availableBounds.right -= fClientBars[x].borderSpace.right;
+ }
+ }
+ *prcBorder = availableBounds;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::RequestBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw)
+{
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetBorderSpaceDW(IUnknown* punkObj, LPCBORDERWIDTHS pbw)
+{
+ for (INT x = 0; x < 3; x++)
+ {
+ if (IUnknownIsEqual(fClientBars[x].clientBar, punkObj))
+ {
+ fClientBars[x].borderSpace = *pbw;
+ // if this bar changed size, it cascades and forces all subsequent bars to resize
+ RepositionBars();
+ return S_OK;
+ }
+ }
+ return E_INVALIDARG;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::QueryStatus(const GUID *pguidCmdGroup,
+ ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText)
+{
+ CComPtr<IOleCommandTarget> commandTarget;
+ HRESULT hResult;
+
+ if (prgCmds == NULL)
+ return E_INVALIDARG;
+ if (pguidCmdGroup == NULL)
+ {
+ if (fCurrentShellView.p != NULL)
+ {
+ hResult = fCurrentShellView->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &commandTarget));
+ if (SUCCEEDED(hResult) && commandTarget.p != NULL)
+ return commandTarget->QueryStatus(NULL, 1, prgCmds, pCmdText);
+ }
+ while (cCmds != 0)
+ {
+ prgCmds->cmdf = 0;
+ prgCmds++;
+ cCmds--;
+ }
+ }
+ else if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
+ {
+ while (cCmds != 0)
+ {
+ switch (prgCmds->cmdID)
+ {
+ case 0x1c: // search
+ prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
+ break;
+ case 0x1d: // history
+ prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
+ break;
+ case 0x1e: // favorites
+ prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
+ break;
+ case 0x23: // folders
+ prgCmds->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_LATCHED;
+ break;
+ default:
+ prgCmds->cmdf = 0;
+ break;
+ }
+ prgCmds++;
+ cCmds--;
+ }
+ }
+ else if (IsEqualIID(*pguidCmdGroup, CGID_ShellBrowser))
+ {
+ while (cCmds != 0)
+ {
+ switch (prgCmds->cmdID)
+ {
+ case 0xa022: // up level
+ prgCmds->cmdf = OLECMDF_SUPPORTED;
+ if (fCurrentDirectoryPIDL->mkid.cb != 0)
+ prgCmds->cmdf |= OLECMDF_ENABLED;
+ break;
+ }
+ prgCmds++;
+ cCmds--;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
+ DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
+{
+ HRESULT hResult;
+
+ if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
+ {
+ switch (nCmdID)
+ {
+ case 0x23:
+ hResult = ShowBand(CLSID_ExplorerBand, true);
+ return S_OK;
+ case 0x27:
+ if (nCmdexecopt == 1)
+ {
+ // pvaIn is a VT_UNKNOWN with a band that is being hidden
+ }
+ else
+ {
+ // update zones part of the status bar
+ }
+ return S_OK;
+ case 0x35: // don't do this, and the internet toolbar doesn't create a menu band
+ V_VT(pvaOut) = VT_INT_PTR;
+ V_INTREF(pvaOut) = reinterpret_cast<INT *>(
+ LoadMenu(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(IDM_CABINET_MAINMENU)));
+ return S_OK;
+ case 0x38:
+ // indicate if this cabinet was opened as a browser
+ return S_FALSE;
+ default:
+ return E_NOTIMPL;
+ }
+ }
+ else if (IsEqualIID(*pguidCmdGroup, CGID_InternetButtons))
+ {
+ switch (nCmdID)
+ {
+ case 0x23:
+ // placeholder
+ return S_OK;
+ }
+ }
+ else if (IsEqualIID(*pguidCmdGroup, CGID_Theater))
+ {
+ switch (nCmdID)
+ {
+ case 6:
+ // what is theater mode and why do we receive this?
+ return E_NOTIMPL;
+ }
+ }
+ else if (IsEqualIID(*pguidCmdGroup, CGID_MenuBand))
+ {
+ switch (nCmdID)
+ {
+ case 14:
+ // initialize favorites menu
+ return S_OK;
+ }
+ }
+ else if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView))
+ {
+ switch (nCmdID)
+ {
+ case 0x12:
+ // refresh on toolbar clicked
+ return S_OK;
+ case 0x4d:
+ // tell the view if it should hide the task pane or not
+ return (fClientBars[BIVerticalBaseBar].clientBar.p == NULL) ? S_FALSE : S_OK;
+ }
+ }
+ else if (IsEqualIID(*pguidCmdGroup, CGID_ShellBrowser))
+ {
+ switch (nCmdID)
+ {
+ case 40994:
+ return NavigateToParent();
+ }
+ }
+ else if (IsEqualIID(*pguidCmdGroup, CGID_IExplorerToolbar))
+ {
+ switch (nCmdID)
+ {
+ case 0x7063:
+ return DoFolderOptions();
+ }
+ }
+ else if (IsEqualIID(*pguidCmdGroup, CGID_DefView))
+ {
+ switch (nCmdID)
+ {
+ case 1:
+ // Reset All Folders option in Folder Options
+ break;
+ }
+ }
+ else
+ {
+ return E_NOTIMPL;
+ }
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetWindow(HWND *lphwnd)
+{
+ if (lphwnd == NULL)
+ return E_POINTER;
+ *lphwnd = m_hWnd;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::ContextSensitiveHelp(BOOL fEnterMode)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
+{
+ HMENU mainMenu = LoadMenu(_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(IDM_CABINET_MAINMENU));
+ Shell_MergeMenus(hmenuShared, mainMenu, 0, 0, FCIDM_BROWSERLAST, MM_SUBMENUSHAVEIDS);
+
+ int GCCU(itemCount3) = GetMenuItemCount(hmenuShared);
+ Unused(itemCount3);
+
+ lpMenuWidths->width[0] = 2;
+ lpMenuWidths->width[2] = 3;
+ lpMenuWidths->width[4] = 1;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject)
+{
+ CComPtr<IShellMenu> shellMenu;
+ HRESULT hResult;
+
+ if (IsMenu(hmenuShared) == FALSE)
+ return E_FAIL;
+ hResult = GetMenuBand(IID_PPV_ARG(IShellMenu, &shellMenu));
+ if (FAILED(hResult))
+ return hResult;
+ hResult = shellMenu->SetMenu(hmenuShared, NULL, SMSET_DONTOWN);
+ if (FAILED(hResult))
+ return hResult;
+ fCurrentMenuBar = hmenuShared;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::RemoveMenusSB(HMENU hmenuShared)
+{
+ if (hmenuShared == fCurrentMenuBar)
+ fCurrentMenuBar = NULL;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetStatusTextSB(LPCOLESTR pszStatusText)
+{
+ //
+ if (pszStatusText)
+ {
+ ::SetWindowText(fStatusBar, pszStatusText);
+ }
+ else
+ {
+
+ }
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::EnableModelessSB(BOOL fEnable)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::TranslateAcceleratorSB(MSG *pmsg, WORD wID)
+{
+ if (!::TranslateAcceleratorW(m_hWnd, m_hAccel, pmsg))
+ return S_FALSE;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::BrowseObject(LPCITEMIDLIST pidl, UINT wFlags)
+{
+ return BrowseToPIDL(pidl, BTP_UPDATE_CUR_HISTORY | BTP_UPDATE_NEXT_HISTORY);
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetViewStateStream(DWORD grfMode, IStream **ppStrm)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetControlWindow(UINT id, HWND *lphwnd)
+{
+ if (lphwnd == NULL)
+ return E_POINTER;
+ *lphwnd = NULL;
+ switch(id)
+ {
+ case FCW_TOOLBAR:
+ *lphwnd = fToolbarProxy.m_hWnd;
+ return S_OK;
+ case FCW_STATUS:
+ *lphwnd = fStatusBar;
+ return S_OK;
+ case FCW_TREE:
+ // find the directory browser and return it
+ // this should be used only to determine if a tree is present
+ return S_OK;
+ case FCW_PROGRESS:
+ // is this a progress dialog?
+ return S_OK;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SendControlMsg(
+ UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret)
+{
+ LPARAM result;
+
+ if (pret != NULL)
+ *pret = 0;
+ switch(id)
+ {
+ case FCW_TOOLBAR:
+ result = fToolbarProxy.SendMessage(uMsg, wParam, lParam);
+ if (pret != NULL)
+ *pret = result;
+ break;
+ case FCW_STATUS:
+ result = SendMessage(fStatusBar, uMsg, wParam, lParam);
+ if (pret != NULL)
+ *pret = result;
+ break;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::QueryActiveShellView(IShellView **ppshv)
+{
+ if (ppshv == NULL)
+ return E_POINTER;
+ *ppshv = fCurrentShellView;
+ if (fCurrentShellView.p != NULL)
+ fCurrentShellView.p->AddRef();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::OnViewWindowActive(IShellView *ppshv)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::DragEnter(
+ IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::DragLeave()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::Drop(
+ IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
+{
+ // view does a query for SID_STopLevelBrowser, IID_IShellBrowserService
+ // the returned interface has a method GetPropertyBag on it
+ if (IsEqualIID(guidService, SID_STopLevelBrowser))
+ return this->QueryInterface(riid, ppvObject);
+ if (IsEqualIID(guidService, SID_SShellBrowser))
+ return this->QueryInterface(riid, ppvObject);
+ if (IsEqualIID(guidService, SID_ITargetFrame2))
+ return this->QueryInterface(riid, ppvObject);
+ if (IsEqualIID(guidService, SID_IWebBrowserApp)) // without this, the internet toolbar won't reflect notifications
+ return this->QueryInterface(riid, ppvObject);
+ if (IsEqualIID(guidService, SID_SProxyBrowser))
+ return this->QueryInterface(riid, ppvObject);
+ if (IsEqualIID(guidService, SID_IExplorerToolbar))
+ return fClientBars[BIInternetToolbar].clientBar->QueryInterface(riid, ppvObject);
+ if (IsEqualIID(riid, IID_IShellBrowser))
+ return this->QueryInterface(riid, ppvObject);
+ return E_NOINTERFACE;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetPropertyBag(long flags, REFIID riid, void **ppvObject)
+{
+ if (ppvObject == NULL)
+ return E_POINTER;
+ *ppvObject = NULL;
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetTypeInfoCount(UINT *pctinfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames,
+ UINT cNames, LCID lcid, DISPID *rgDispId)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
+ WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetParentSite(IOleInPlaceSite **ppipsite)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetTitle(IShellView *psv, LPCWSTR pszName)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetTitle(IShellView *psv, LPWSTR pszName, DWORD cchName)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetOleObject(IOleObject **ppobjv)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetTravelLog(ITravelLog **pptl)
+{
+ HRESULT hResult;
+
+ // called by toolbar when displaying tooltips
+ if (pptl == NULL)
+ return E_FAIL;
+
+ *pptl = NULL;
+ if (fTravelLog.p == NULL)
+ {
+ hResult = CreateTravelLog(IID_PPV_ARG(ITravelLog, &fTravelLog));
+ if (FAILED(hResult))
+ return hResult;
+ }
+ *pptl = fTravelLog.p;
+ fTravelLog.p->AddRef();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::ShowControlWindow(UINT id, BOOL fShow)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::IsControlWindowShown(UINT id, BOOL *pfShown)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::IEGetDisplayName(LPCITEMIDLIST pidl, LPWSTR pwszName, UINT uFlags)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::IEParseDisplayName(UINT uiCP, LPCWSTR pwszPath, LPITEMIDLIST *ppidlOut)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::DisplayParseError(HRESULT hres, LPCWSTR pwszPath)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::NavigateToPidl(LPCITEMIDLIST pidl, DWORD grfHLNF)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetNavigateState(BNSTATE bnstate)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetNavigateState(BNSTATE *pbnstate)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::NotifyRedirect(IShellView *psv, LPCITEMIDLIST pidl, BOOL *pfDidBrowse)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::UpdateWindowList()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::UpdateBackForwardState()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetFlags(DWORD dwFlags, DWORD dwFlagMask)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetFlags(DWORD *pdwFlags)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::CanNavigateNow()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetPidl(LPITEMIDLIST *ppidl)
+{
+ // called by explorer bar to get current pidl
+ if (ppidl == NULL)
+ return E_POINTER;
+ *ppidl = ILClone(fCurrentDirectoryPIDL);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetReferrer(LPCITEMIDLIST pidl)
+{
+ return E_NOTIMPL;
+}
+
+DWORD STDMETHODCALLTYPE CShellBrowser::GetBrowserIndex()
+{
+ return -1;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetBrowserByIndex(DWORD dwID, IUnknown **ppunk)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetHistoryObject(IOleObject **ppole, IStream **pstm, IBindCtx **ppbc)
+{
+ if (ppole == NULL || pstm == NULL || ppbc == NULL)
+ return E_INVALIDARG;
+ *ppole = fHistoryObject;
+ if (fHistoryObject != NULL)
+ fHistoryObject->AddRef();
+ *pstm = fHistoryStream;
+ if (fHistoryStream != NULL)
+ fHistoryStream->AddRef();
+ *ppbc = fHistoryBindContext;
+ if (fHistoryBindContext != NULL)
+ fHistoryBindContext->AddRef();
+ fHistoryObject = NULL;
+ fHistoryStream = NULL;
+ fHistoryBindContext = NULL;
+ if (*ppole == NULL)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetHistoryObject(IOleObject *pole, BOOL fIsLocalAnchor)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::CacheOLEServer(IOleObject *pole)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetSetCodePage(VARIANT *pvarIn, VARIANT *pvarOut)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::OnHttpEquiv(
+ IShellView *psv, BOOL fDone, VARIANT *pvarargIn, VARIANT *pvarargOut)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetPalette(HPALETTE *hpal)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::RegisterWindow(BOOL fForceRegister, int swc)
+{
+ return E_NOTIMPL;
+}
+
+LRESULT STDMETHODCALLTYPE CShellBrowser::WndProcBS(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetAsDefFolderSettings()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetViewRect(RECT *prc)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::OnSize(WPARAM wParam)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::OnCreate(struct tagCREATESTRUCTW *pcs)
+{
+ m_hAccel = LoadAcceleratorsW(GetModuleHandle(L"browseui.dll"), MAKEINTRESOURCEW(256));
+ return S_OK;
+}
+
+LRESULT STDMETHODCALLTYPE CShellBrowser::OnCommand(WPARAM wParam, LPARAM lParam)
+{
+ return 0;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::OnDestroy()
+{
+ return E_NOTIMPL;
+}
+
+LRESULT STDMETHODCALLTYPE CShellBrowser::OnNotify(struct tagNMHDR *pnm)
+{
+ return 0;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::OnSetFocus()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::OnFrameWindowActivateBS(BOOL fActive)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::ReleaseShellView()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::ActivatePendingView()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::CreateViewWindow(
+ IShellView *psvNew, IShellView *psvOld, LPRECT prcView, HWND *phwnd)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::CreateBrowserPropSheetExt(REFIID riid, void **ppv)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetViewWindow(HWND *phwndView)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetBaseBrowserData(LPCBASEBROWSERDATA *pbbd)
+{
+ return E_NOTIMPL;
+}
+
+LPBASEBROWSERDATA STDMETHODCALLTYPE CShellBrowser::PutBaseBrowserData()
+{
+ return NULL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::InitializeTravelLog(ITravelLog *ptl, DWORD dw)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetTopBrowser()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::Offline(int iCmd)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::AllowViewResize(BOOL f)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetActivateState(UINT u)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::UpdateSecureLockIcon(int eSecureLock)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::InitializeDownloadManager()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::InitializeTransitionSite()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_Initialize(HWND hwnd, IUnknown *pauto)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_CancelPendingNavigationAsync()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_CancelPendingView()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_MaySaveChanges()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_PauseOrResumeView(BOOL fPaused)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_DisableModeless()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_NavigateToPidl(LPCITEMIDLIST pidl, DWORD grfHLNF, DWORD dwFlags)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_TryShell2Rename(IShellView *psv, LPCITEMIDLIST pidlNew)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_SwitchActivationNow()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_ExecChildren(IUnknown *punkBar, BOOL fBroadcast,
+ const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_SendChildren(
+ HWND hwndBar, BOOL fBroadcast, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetFolderSetData(struct tagFolderSetData *pfsd)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_OnFocusChange(UINT itb)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::v_ShowHideChildWindows(BOOL fChildOnly)
+{
+ return E_NOTIMPL;
+}
+
+UINT STDMETHODCALLTYPE CShellBrowser::_get_itbLastFocus()
+{
+ return 0;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_put_itbLastFocus(UINT itbLastFocus)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_UIActivateView(UINT uState)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_GetViewBorderRect(RECT *prc)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_UpdateViewRectSize()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_ResizeNextBorder(UINT itb)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_ResizeView()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_GetEffectiveClientArea(LPRECT lprectBorder, HMONITOR hmon)
+{
+ return E_NOTIMPL;
+}
+
+IStream *STDMETHODCALLTYPE CShellBrowser::v_GetViewStream(LPCITEMIDLIST pidl, DWORD grfMode, LPCWSTR pwszName)
+{
+ return NULL;
+}
+
+LRESULT STDMETHODCALLTYPE CShellBrowser::ForwardViewMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ return 0;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetAcceleratorMenu(HACCEL hacc)
+{
+ return E_NOTIMPL;
+}
+
+int STDMETHODCALLTYPE CShellBrowser::_GetToolbarCount()
+{
+ return 0;
+}
+
+LPTOOLBARITEM STDMETHODCALLTYPE CShellBrowser::_GetToolbarItem(int itb)
+{
+ return NULL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_SaveToolbars(IStream *pstm)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_LoadToolbars(IStream *pstm)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_CloseAndReleaseToolbars(BOOL fClose)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::v_MayGetNextToolbarFocus(
+ LPMSG lpMsg, UINT itbNext, int citb, LPTOOLBARITEM *pptbi, HWND *phwnd)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_ResizeNextBorderHelper(UINT itb, BOOL bUseHmonitor)
+{
+ return E_NOTIMPL;
+}
+
+UINT STDMETHODCALLTYPE CShellBrowser::_FindTBar(IUnknown *punkSrc)
+{
+ return 0;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_SetFocus(LPTOOLBARITEM ptbi, HWND hwnd, LPMSG lpMsg)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::v_MayTranslateAccelerator(MSG *pmsg)
+{
+ if (fCurrentShellView->TranslateAcceleratorW(pmsg) != S_OK)
+ {
+ if (TranslateAcceleratorSB(pmsg, 0) != S_OK)
+ return S_FALSE;
+ return S_OK;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::_GetBorderDWHelper(IUnknown *punkSrc, LPRECT lprectBorder, BOOL bUseHmonitor)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::v_CheckZoneCrossing(LPCITEMIDLIST pidl)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GoBack()
+{
+ CComPtr<ITravelLog> travelLog;
+ HRESULT hResult;
+
+ hResult = GetTravelLog(&travelLog);
+ if (FAILED(hResult))
+ return hResult;
+ return travelLog->Travel(static_cast<IDropTarget *>(this), TLOG_BACK);
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GoForward()
+{
+ CComPtr<ITravelLog> travelLog;
+ HRESULT hResult;
+
+ hResult = GetTravelLog(&travelLog);
+ if (FAILED(hResult))
+ return hResult;
+ return travelLog->Travel(static_cast<IDropTarget *>(this), TLOG_FORE);
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GoHome()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GoSearch()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::Navigate(BSTR URL, VARIANT *Flags,
+ VARIANT *TargetFrameName, VARIANT *PostData, VARIANT *Headers)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::Refresh()
+{
+ VARIANT level;
+
+ V_VT(&level) = VT_I4;
+ V_I4(&level) = 4;
+ return Refresh2(&level);
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::Refresh2(VARIANT *Level)
+{
+ CComPtr<IOleCommandTarget> oleCommandTarget;
+ HRESULT hResult;
+
+ hResult = fCurrentShellView->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &oleCommandTarget));
+ if (FAILED(hResult))
+ return hResult;
+ return oleCommandTarget->Exec(NULL, 22, 1, Level, NULL);
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::Stop()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Application(IDispatch **ppDisp)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Parent(IDispatch **ppDisp)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Container(IDispatch **ppDisp)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Document(IDispatch **ppDisp)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_TopLevelContainer(VARIANT_BOOL *pBool)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Type(BSTR *Type)
+{
+ return E_NOTIMPL;
+}
+#ifdef __exdisp_h__
+#define long LONG
+#endif
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Left(long *pl)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_Left(long Left)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Top(long *pl)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_Top(long Top)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Width(long *pl)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_Width(long Width)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Height(long *pl)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_Height(long Height)
+{
+ return E_NOTIMPL;
+}
+#ifdef __exdisp_h__
+#undef long
+#endif
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_LocationName(BSTR *LocationName)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_LocationURL(BSTR *LocationURL)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Busy(VARIANT_BOOL *pBool)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::Quit()
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::ClientToWindow(int *pcx, int *pcy)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::PutProperty(BSTR Property, VARIANT vtValue)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetProperty(BSTR Property, VARIANT *pvtValue)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Name(BSTR *Name)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_HWND(SHANDLE_PTR *pHWND)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_FullName(BSTR *FullName)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Path(BSTR *Path)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Visible(VARIANT_BOOL *pBool)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_Visible(VARIANT_BOOL Value)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_StatusBar(VARIANT_BOOL *pBool)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_StatusBar(VARIANT_BOOL Value)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_StatusText(BSTR *StatusText)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_StatusText(BSTR StatusText)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_ToolBar(int *Value)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_ToolBar(int Value)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_MenuBar(VARIANT_BOOL *Value)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_MenuBar(VARIANT_BOOL Value)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_FullScreen(VARIANT_BOOL *pbFullScreen)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_FullScreen(VARIANT_BOOL bFullScreen)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::Navigate2(VARIANT *URL, VARIANT *Flags,
+ VARIANT *TargetFrameName, VARIANT *PostData, VARIANT *Headers)
+{
+ LPITEMIDLIST pidl;
+ HRESULT hResult;
+
+ // called from drive combo box to navigate to a directory
+ if (V_VT(URL) != (VT_ARRAY | VT_UI1))
+ return E_INVALIDARG;
+ if (V_ARRAY(URL)->cDims != 1 || V_ARRAY(URL)->cbElements != 1)
+ return E_INVALIDARG;
+ pidl = (LPITEMIDLIST)V_ARRAY(URL)->pvData;
+ hResult = BrowseToPIDL((LPITEMIDLIST)pidl, BTP_UPDATE_CUR_HISTORY | BTP_UPDATE_NEXT_HISTORY);
+ if (FAILED(hResult))
+ return hResult;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::QueryStatusWB(OLECMDID cmdID, OLECMDF *pcmdf)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt,
+ VARIANT *pvaIn, VARIANT *pvaOut)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::ShowBrowserBar(VARIANT *pvaClsid, VARIANT *pvarShow, VARIANT *pvarSize)
+{
+ CLSID classID;
+ bool vertical;
+
+ // called to show search bar
+ if (V_VT(pvaClsid) != VT_BSTR)
+ return E_INVALIDARG;
+ CLSIDFromString(V_BSTR(pvaClsid), &classID);
+ // TODO: properly compute the value of vertical
+ vertical = true;
+ return ShowBand(classID, vertical);
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_ReadyState(READYSTATE *plReadyState)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Offline(VARIANT_BOOL *pbOffline)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_Offline(VARIANT_BOOL bOffline)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Silent(VARIANT_BOOL *pbSilent)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_Silent(VARIANT_BOOL bSilent)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_RegisterAsBrowser(VARIANT_BOOL *pbRegister)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_RegisterAsBrowser(VARIANT_BOOL bRegister)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_RegisterAsDropTarget(VARIANT_BOOL *pbRegister)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_RegisterAsDropTarget(VARIANT_BOOL bRegister)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_TheaterMode(VARIANT_BOOL *pbRegister)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_TheaterMode(VARIANT_BOOL bRegister)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_AddressBar(VARIANT_BOOL *Value)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_AddressBar(VARIANT_BOOL Value)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::get_Resizable(VARIANT_BOOL *Value)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::put_Resizable(VARIANT_BOOL Value)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::FindWindowByIndex(DWORD dwID, IUnknown **ppunk)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetWindowData(IStream *pStream, LPWINDOWDATA pWinData)
+{
+ if (pWinData == NULL)
+ return E_POINTER;
+
+ pWinData->dwWindowID = -1;
+ pWinData->uiCP = 0;
+ pWinData->pidl = ILClone(fCurrentDirectoryPIDL);
+ pWinData->lpszUrl = NULL;
+ pWinData->lpszUrlLocation = NULL;
+ pWinData->lpszTitle = NULL;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::LoadHistoryPosition(LPWSTR pszUrlLocation, DWORD dwPosition)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetClassID(CLSID *pClassID)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::LoadHistory(IStream *pStream, IBindCtx *pbc)
+{
+ CComPtr<IPersistHistory> viewPersistHistory;
+ CComPtr<IOleObject> viewHistoryObject;
+ persistState oldState;
+ ULONG numRead;
+ LPITEMIDLIST pidl;
+ HRESULT hResult;
+
+ hResult = pStream->Read(&oldState, sizeof(oldState), &numRead);
+ if (FAILED(hResult))
+ return hResult;
+ if (numRead != sizeof(oldState) || oldState.dwSize != sizeof(oldState))
+ return E_FAIL;
+ if (oldState.browseType != 2)
+ return E_FAIL;
+ pidl = static_cast<LPITEMIDLIST>(CoTaskMemAlloc(oldState.pidlSize));
+ if (pidl == NULL)
+ return E_OUTOFMEMORY;
+ hResult = pStream->Read(pidl, oldState.pidlSize, &numRead);
+ if (FAILED(hResult))
+ {
+ ILFree(pidl);
+ return hResult;
+ }
+ if (numRead != oldState.pidlSize)
+ {
+ ILFree(pidl);
+ return E_FAIL;
+ }
+ hResult = CoCreateInstance(oldState.persistClass, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER,
+ IID_PPV_ARG(IOleObject, &viewHistoryObject));
+ fHistoryObject = viewHistoryObject;
+ fHistoryStream = pStream;
+ fHistoryBindContext = pbc;
+ hResult = BrowseToPIDL(pidl, BTP_UPDATE_CUR_HISTORY);
+ fHistoryObject = NULL;
+ fHistoryStream = NULL;
+ fHistoryBindContext = NULL;
+ ILFree(pidl);
+ if (FAILED(hResult))
+ return hResult;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SaveHistory(IStream *pStream)
+{
+ CComPtr<IPersistHistory> viewPersistHistory;
+ persistState newState;
+ HRESULT hResult;
+
+ hResult = fCurrentShellView->GetItemObject(
+ SVGIO_BACKGROUND, IID_PPV_ARG(IPersistHistory, &viewPersistHistory));
+ memset(&newState, 0, sizeof(newState));
+ newState.dwSize = sizeof(newState);
+ newState.browseType = 2;
+ newState.browserIndex = GetBrowserIndex();
+ if (viewPersistHistory.p != NULL)
+ {
+ hResult = viewPersistHistory->GetClassID(&newState.persistClass);
+ if (FAILED(hResult))
+ return hResult;
+ }
+ newState.pidlSize = ILGetSize(fCurrentDirectoryPIDL);
+ hResult = pStream->Write(&newState, sizeof(newState), NULL);
+ if (FAILED(hResult))
+ return hResult;
+ hResult = pStream->Write(fCurrentDirectoryPIDL, newState.pidlSize, NULL);
+ if (FAILED(hResult))
+ return hResult;
+ if (viewPersistHistory.p != NULL)
+ {
+ hResult = viewPersistHistory->SaveHistory(pStream);
+ if (FAILED(hResult))
+ return hResult;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::SetPositionCookie(DWORD dwPositioncookie)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CShellBrowser::GetPositionCookie(DWORD *pdwPositioncookie)
+{
+ return E_NOTIMPL;
+}
+
+LRESULT CShellBrowser::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ OnCreate(reinterpret_cast<LPCREATESTRUCT> (lParam));
+ return 0;
+}
+
+LRESULT CShellBrowser::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ // TODO: rip down everything
+ PostQuitMessage(0);
+ return 0;
+}
+
+LRESULT CShellBrowser::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ CComPtr<IDockingWindow> dockingWindow;
+ RECT availableBounds;
+ static const INT excludeItems[] = {1, 1, 1, 0xa001, 0, 0};
+ HRESULT hResult;
+
+ if (wParam != SIZE_MINIMIZED)
+ {
+ GetEffectiveClientRect(m_hWnd, &availableBounds, excludeItems);
+ for (INT x = 0; x < 3; x++)
+ {
+ if (fClientBars[x].clientBar != NULL)
+ {
+ hResult = fClientBars[x].clientBar->QueryInterface(
+ IID_PPV_ARG(IDockingWindow, &dockingWindow));
+ if (SUCCEEDED(hResult) && dockingWindow != NULL)
+ {
+ hResult = dockingWindow->ResizeBorderDW(
+ &availableBounds, static_cast<IDropTarget *>(this), TRUE);
+ break;
+ }
+ }
+ }
+ RepositionBars();
+ }
+ return 1;
+}
+
+LRESULT CShellBrowser::OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ HMENU theMenu;
+
+ theMenu = reinterpret_cast<HMENU>(wParam);
+ if (theMenu == SHGetMenuFromID(fCurrentMenuBar, FCIDM_MENU_VIEW))
+ UpdateViewMenu(theMenu);
+ return RelayMsgToShellView(uMsg, wParam, lParam, bHandled);
+}
+
+LRESULT CShellBrowser::RelayMsgToShellView(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ if (fCurrentShellViewWindow != NULL)
+ return SendMessage(fCurrentShellViewWindow, uMsg, wParam, lParam);
+ return 0;
+}
+
+LRESULT CShellBrowser::OnClose(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ return 0;
+}
+
+LRESULT CShellBrowser::OnFolderOptions(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ HRESULT hResult;
+
+ hResult = DoFolderOptions();
+ return 0;
+}
+
+LRESULT CShellBrowser::OnMapNetworkDrive(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+#ifndef __REACTOS__
+ WNetConnectionDialog(m_hWnd, RESOURCETYPE_DISK);
+#endif /* __REACTOS__ */
+ return 0;
+}
+
+LRESULT CShellBrowser::OnDisconnectNetworkDrive(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+#ifndef __REACTOS__
+ WNetDisconnectDialog(m_hWnd, RESOURCETYPE_DISK);
+#endif /* __REACTOS__ */
+ return 0;
+}
+
+LRESULT CShellBrowser::OnAboutReactOS(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ ShellAbout(m_hWnd, _T("ReactOS"), _T(""), NULL);
+ return 0;
+}
+
+LRESULT CShellBrowser::OnGoBack(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ HRESULT hResult;
+
+ hResult = GoBack();
+ return 0;
+}
+
+LRESULT CShellBrowser::OnGoForward(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ HRESULT hResult;
+
+ hResult = GoForward();
+ return 0;
+}
+
+LRESULT CShellBrowser::OnGoUpLevel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ HRESULT hResult;
+
+ hResult = NavigateToParent();
+ return 0;
+}
+
+LRESULT CShellBrowser::OnGoHome(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ HRESULT hResult;
+
+ hResult = GoHome();
+ return 0;
+}
+
+LRESULT CShellBrowser::OnBackspace(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ HRESULT hResult;
+
+ // FIXME: This does not appear to be what windows does.
+ hResult = NavigateToParent();
+ return 0;
+}
+
+LRESULT CShellBrowser::OnIsThisLegal(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ HRESULT hResult;
+
+ typedef HRESULT (WINAPI *PSHOpenNewFrame)(LPITEMIDLIST pidl, IUnknown *b, long c, long d);
+ PSHOpenNewFrame Func = NULL;
+ HMODULE Module = GetModuleHandle(TEXT("browseui.dll"));
+ if (Module != NULL)
+ Func = reinterpret_cast<PSHOpenNewFrame>(GetProcAddress(Module, (LPCSTR) 103));
+ if (Func != NULL)
+ {
+ LPITEMIDLIST desktopPIDL;
+
+ hResult = SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, 0, &desktopPIDL);
+ if (SUCCEEDED(hResult))
+ {
+ hResult = Func(desktopPIDL, NULL, -1, 1);
+ }
+ }
+ return 0;
+}
+
+LRESULT CShellBrowser::OnToggleStatusBarVisible(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ fStatusBarVisible = !fStatusBarVisible;
+ // TODO: trigger a relayout of contained items
+ return 0;
+}
+
+LRESULT CShellBrowser::OnToggleToolbarLock(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ CComPtr<IOleCommandTarget> commandTarget;
+ HRESULT hResult;
+
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IOleCommandTarget, &commandTarget));
+ if (FAILED(hResult))
+ return 0;
+ hResult = commandTarget->Exec(&CGID_PrivCITCommands, ITID_TOOLBARLOCKED, 0, NULL, NULL);
+ return 0;
+}
+
+LRESULT CShellBrowser::OnToggleToolbarBandVisible(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ CComPtr<IOleCommandTarget> commandTarget;
+ HRESULT hResult;
+
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IOleCommandTarget, &commandTarget));
+ if (FAILED(hResult))
+ return 0;
+ hResult = commandTarget->Exec(&CGID_PrivCITCommands, ITID_TOOLBARBANDSHOWN, 0, NULL, NULL);
+ return 0;
+}
+
+LRESULT CShellBrowser::OnToggleAddressBandVisible(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ CComPtr<IOleCommandTarget> commandTarget;
+ HRESULT hResult;
+
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IOleCommandTarget, &commandTarget));
+ if (FAILED(hResult))
+ return 0;
+ hResult = commandTarget->Exec(&CGID_PrivCITCommands, ITID_ADDRESSBANDSHOWN, 0, NULL, NULL);
+ return 0;
+}
+
+LRESULT CShellBrowser::OnToggleLinksBandVisible(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ CComPtr<IOleCommandTarget> commandTarget;
+ HRESULT hResult;
+
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IOleCommandTarget, &commandTarget));
+ if (FAILED(hResult))
+ return 0;
+ hResult = commandTarget->Exec(&CGID_PrivCITCommands, ITID_LINKSBANDSHOWN, 0, NULL, NULL);
+ return 0;
+}
+
+LRESULT CShellBrowser::OnToggleTextLabels(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ CComPtr<IOleCommandTarget> commandTarget;
+ HRESULT hResult;
+
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IOleCommandTarget, &commandTarget));
+ if (FAILED(hResult))
+ return 0;
+ hResult = commandTarget->Exec(&CGID_PrivCITCommands, ITID_TEXTLABELS, 0, NULL, NULL);
+ return 0;
+}
+
+LRESULT CShellBrowser::OnToolbarCustomize(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ CComPtr<IOleCommandTarget> commandTarget;
+ HRESULT hResult;
+
+ hResult = fClientBars[BIInternetToolbar].clientBar->QueryInterface(
+ IID_PPV_ARG(IOleCommandTarget, &commandTarget));
+ if (FAILED(hResult))
+ return 0;
+ hResult = commandTarget->Exec(&CGID_PrivCITCommands, ITID_CUSTOMIZEENABLED, 0, NULL, NULL);
+ return 0;
+}
+
+LRESULT CShellBrowser::OnGoTravel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled)
+{
+ return 0;
+}
+
+LRESULT CShellBrowser::RelayCommands(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
+{
+ if (HIWORD(wParam) == 0 && LOWORD(wParam) < FCIDM_SHVIEWLAST && fCurrentShellViewWindow != NULL)
+ return SendMessage(fCurrentShellViewWindow, uMsg, wParam, lParam);
+ return 0;
+}
+
+static HRESULT ExplorerMessageLoop(IEThreadParamBlock * parameters)
+{
+ CComPtr<IShellBrowser> shellBrowser;
+ CComObject<CShellBrowser> *theCabinet;
+ HRESULT hResult;
+ MSG Msg;
+ BOOL Ret;
+
+ OleInitialize(NULL);
+
+ ATLTRY(theCabinet = new CComObject<CShellBrowser>);
+ if (theCabinet == NULL)
+ {
+ hResult = E_OUTOFMEMORY;
+ goto uninitialize;
+ }
+
+ hResult = theCabinet->QueryInterface(IID_PPV_ARG(IShellBrowser, &shellBrowser));
+ if (FAILED(hResult))
+ {
+ delete theCabinet;
+ goto uninitialize;
+ }
+
+ hResult = theCabinet->Initialize(parameters->directoryPIDL, 0, 0, 0);
+ if (FAILED(hResult))
+ goto uninitialize;
+
+ while ((Ret = GetMessage(&Msg, NULL, 0, 0)) != 0)
+ {
+ if (Ret == -1)
+ {
+ // Error: continue or exit?
+ break;
+ }
+
+ if (theCabinet->v_MayTranslateAccelerator(&Msg) != S_OK)
+ {
+ TranslateMessage(&Msg);
+ DispatchMessage(&Msg);
+ }
+
+ if (Msg.message == WM_QUIT)
+ break;
+ }
+
+uninitialize:
+ OleUninitialize();
+ return hResult;
+}
+
+DWORD WINAPI BrowserThreadProc(LPVOID lpThreadParameter)
+{
+ IEThreadParamBlock * parameters = (IEThreadParamBlock *) lpThreadParameter;
+ return ExplorerMessageLoop(parameters);
+}
--- /dev/null
- PMENU FASTCALL
- IntGetSystemMenu(PWND Window, BOOL bRevert, BOOL RetMenu)
- {
- PMENU Menu, NewMenu = NULL, SysMenu = NULL, ret = NULL;
- PTHREADINFO W32Thread;
- HMENU hNewMenu, hSysMenu;
- ROSMENUITEMINFO ItemInfoSet = {0};
- ROSMENUITEMINFO ItemInfo = {0};
- UNICODE_STRING MenuName;
-
- if(bRevert)
- {
- W32Thread = PsGetCurrentThreadWin32Thread();
-
- if(!W32Thread->rpdesk)
- return NULL;
-
- if(Window->SystemMenu)
- {
- Menu = UserGetMenuObject(Window->SystemMenu);
- if(Menu)
- {
- IntDestroyMenuObject(Menu, TRUE, TRUE);
- Window->SystemMenu = (HMENU)0;
- }
- }
-
- if(W32Thread->rpdesk->rpwinstaParent->SystemMenuTemplate)
- {
- /* Clone system menu */
- Menu = UserGetMenuObject(W32Thread->rpdesk->rpwinstaParent->SystemMenuTemplate);
- if(!Menu)
- return NULL;
-
- NewMenu = IntCloneMenu(Menu);
- if(NewMenu)
- { // Use spmenuSys
- Window->SystemMenu = NewMenu->head.h;
- NewMenu->fFlags |= MNF_SYSDESKMN;
- NewMenu->hWnd = Window->head.h;
- ret = NewMenu;
- //IntReleaseMenuObject(NewMenu);
- }
- }
- else
- {
- hSysMenu = UserCreateMenu(FALSE);
- if (NULL == hSysMenu)
- {
- return NULL;
- }
- SysMenu = IntGetMenuObject(hSysMenu);
- if (NULL == SysMenu)
- {
- UserDestroyMenu(hSysMenu);
- return NULL;
- }
- SysMenu->fFlags |= MNF_SYSDESKMN;
- SysMenu->hWnd = Window->head.h;
- //hNewMenu = co_IntLoadSysMenuTemplate();
- //if ( Window->ExStyle & WS_EX_MDICHILD )
- //{
- // RtlInitUnicodeString( &MenuName, L"SYSMENUMDI");
- // hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
- //}
- //else
- {
- RtlInitUnicodeString( &MenuName, L"SYSMENU");
- hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
- //ERR("%wZ\n",&MenuName);
- }
- if(!hNewMenu)
- {
- ERR("No Menu!!\n");
- IntReleaseMenuObject(SysMenu);
- UserDestroyMenu(hSysMenu);
- return NULL;
- }
- Menu = IntGetMenuObject(hNewMenu);
- if(!Menu)
- {
- IntReleaseMenuObject(SysMenu);
- UserDestroyMenu(hSysMenu);
- return NULL;
- }
-
- // Do the rest in here.
-
- Menu->fFlags |= MNS_CHECKORBMP | MNF_SYSDESKMN | MNF_POPUP;
-
- ItemInfoSet.cbSize = sizeof( MENUITEMINFOW);
- ItemInfoSet.fMask = MIIM_BITMAP;
- ItemInfoSet.hbmpItem = HBMMENU_POPUP_CLOSE;
- IntMenuItemInfo(Menu, SC_CLOSE, FALSE, &ItemInfoSet, TRUE, NULL);
- ItemInfoSet.hbmpItem = HBMMENU_POPUP_RESTORE;
- IntMenuItemInfo(Menu, SC_RESTORE, FALSE, &ItemInfoSet, TRUE, NULL);
- ItemInfoSet.hbmpItem = HBMMENU_POPUP_MAXIMIZE;
- IntMenuItemInfo(Menu, SC_MAXIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
- ItemInfoSet.hbmpItem = HBMMENU_POPUP_MINIMIZE;
- IntMenuItemInfo(Menu, SC_MINIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
-
- NewMenu = IntCloneMenu(Menu);
- if(NewMenu)
- {
- NewMenu->fFlags |= MNF_SYSDESKMN | MNF_POPUP;
- // Do not set MNS_CHECKORBMP it breaks menus, also original code destroyed the style anyway.
- IntReleaseMenuObject(NewMenu);
- UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
-
- if (Window->pcls->style & CS_NOCLOSE)
- IntRemoveMenuItem(NewMenu, SC_CLOSE, MF_BYCOMMAND, TRUE);
-
- ItemInfo.cbSize = sizeof(MENUITEMINFOW);
- ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
- ItemInfo.fType = 0;
- ItemInfo.fState = MFS_ENABLED;
- ItemInfo.dwTypeData = NULL;
- ItemInfo.cch = 0;
- ItemInfo.hSubMenu = NewMenu->head.h;
- IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo, NULL);
-
- Window->SystemMenu = SysMenu->head.h;
-
- ret = SysMenu;
- }
- IntDestroyMenuObject(Menu, FALSE, TRUE);
- }
- if(RetMenu)
- return ret;
- else
- return NULL;
- }
- else
- {
- if(Window->SystemMenu)
- return IntGetMenuObject((HMENU)Window->SystemMenu);
- else
- return NULL;
- }
- }
-
-
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Win32k subsystem
+ * PURPOSE: Windows
+ * FILE: subsystems/win32/win32k/ntuser/window.c
+ * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ */
+
+#include <win32k.h>
+DBG_DEFAULT_CHANNEL(UserWnd);
+
+INT gNestedWindowLimit = 50;
+
+/* HELPER FUNCTIONS ***********************************************************/
+
+BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
+{
+ WORD Action = LOWORD(wParam);
+ WORD Flags = HIWORD(wParam);
+
+ if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ switch (Action)
+ {
+ case UIS_INITIALIZE:
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+
+ case UIS_SET:
+ if (Flags & UISF_HIDEFOCUS)
+ Wnd->HideFocus = TRUE;
+ if (Flags & UISF_HIDEACCEL)
+ Wnd->HideAccel = TRUE;
+ break;
+
+ case UIS_CLEAR:
+ if (Flags & UISF_HIDEFOCUS)
+ Wnd->HideFocus = FALSE;
+ if (Flags & UISF_HIDEACCEL)
+ Wnd->HideAccel = FALSE;
+ break;
+ }
+
+ return TRUE;
+}
+
+PWND FASTCALL IntGetWindowObject(HWND hWnd)
+{
+ PWND Window;
+
+ if (!hWnd) return NULL;
+
+ Window = UserGetWindowObject(hWnd);
+ if (Window)
+ Window->head.cLockObj++;
+
+ return Window;
+}
+
+PWND FASTCALL VerifyWnd(PWND pWnd)
+{
+ HWND hWnd;
+ UINT State, State2;
+
+ if (!pWnd) return NULL;
+
+ _SEH2_TRY
+ {
+ hWnd = UserHMGetHandle(pWnd);
+ State = pWnd->state;
+ State2 = pWnd->state2;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(return NULL);
+ }
+ _SEH2_END
+
+ if ( UserObjectInDestroy(hWnd) ||
+ State & WNDS_DESTROYED ||
+ State2 & WNDS2_INDESTROY )
+ return NULL;
+
+ return pWnd;
+}
+
+PWND FASTCALL ValidateHwndNoErr(HWND hWnd)
+{
+ if (hWnd) return (PWND)UserGetObjectNoErr(gHandleTable, hWnd, TYPE_WINDOW);
+ return NULL;
+}
+
+/* Temp HACK */
+PWND FASTCALL UserGetWindowObject(HWND hWnd)
+{
+ PWND Window;
+
+ if (!hWnd)
+ {
+ EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
+ return NULL;
+ }
+
+ Window = (PWND)UserGetObject(gHandleTable, hWnd, TYPE_WINDOW);
+ if (!Window || 0 != (Window->state & WNDS_DESTROYED))
+ {
+ EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
+ return NULL;
+ }
+
+ return Window;
+}
+
+ULONG FASTCALL
+IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits )
+{
+ ULONG styleOld, styleNew;
+ styleOld = pwnd->style;
+ styleNew = (pwnd->style | set_bits) & ~clear_bits;
+ if (styleNew == styleOld) return styleNew;
+ pwnd->style = styleNew;
+ if ((styleOld ^ styleNew) & WS_VISIBLE) // State Change.
+ {
+ if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--;
+ if (styleNew & WS_VISIBLE) pwnd->head.pti->cVisWindows++;
+ DceResetActiveDCEs( pwnd );
+ }
+ return styleOld;
+}
+
+/*
+ * IntIsWindow
+ *
+ * The function determines whether the specified window handle identifies
+ * an existing window.
+ *
+ * Parameters
+ * hWnd
+ * Handle to the window to test.
+ *
+ * Return Value
+ * If the window handle identifies an existing window, the return value
+ * is TRUE. If the window handle does not identify an existing window,
+ * the return value is FALSE.
+ */
+
+BOOL FASTCALL
+IntIsWindow(HWND hWnd)
+{
+ PWND Window;
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL FASTCALL
+IntIsWindowVisible(PWND Wnd)
+{
+ PWND Temp = Wnd;
+ for (;;)
+ {
+ if (!Temp) return TRUE;
+ if (!(Temp->style & WS_VISIBLE)) break;
+ if (Temp->style & WS_MINIMIZE && Temp != Wnd) break;
+ if (Temp->fnid == FNID_DESKTOP) return TRUE;
+ Temp = Temp->spwndParent;
+ }
+ return FALSE;
+}
+
+PWND FASTCALL
+IntGetParent(PWND Wnd)
+{
+ if (Wnd->style & WS_POPUP)
+ {
+ return Wnd->spwndOwner;
+ }
+ else if (Wnd->style & WS_CHILD)
+ {
+ return Wnd->spwndParent;
+ }
+
+ return NULL;
+}
+
+BOOL
+FASTCALL
+IntEnableWindow( HWND hWnd, BOOL bEnable )
+{
+ BOOL Update;
+ PWND pWnd;
+ UINT bIsDisabled;
+
+ if(!(pWnd = UserGetWindowObject(hWnd)))
+ {
+ return FALSE;
+ }
+
+ /* check if updating is needed */
+ bIsDisabled = !!(pWnd->style & WS_DISABLED);
+ Update = bIsDisabled;
+
+ if (bEnable)
+ {
+ IntSetStyle( pWnd, 0, WS_DISABLED );
+ }
+ else
+ {
+ Update = !bIsDisabled;
+
+ co_IntSendMessage( hWnd, WM_CANCELMODE, 0, 0);
+
+ /* Remove keyboard focus from that window if it had focus */
+ if (hWnd == IntGetThreadFocusWindow())
+ {
+ TRACE("IntEnableWindow SF NULL\n");
+ co_UserSetFocus(NULL);
+ }
+ IntSetStyle( pWnd, WS_DISABLED, 0 );
+ }
+
+ if (Update)
+ {
+ IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
+ co_IntSendMessage(hWnd, WM_ENABLE, (LPARAM)bEnable, 0);
+ }
+ // Return nonzero if it was disabled, or zero if it wasn't:
+ return bIsDisabled;
+}
+
+/*
+ * IntWinListChildren
+ *
+ * Compile a list of all child window handles from given window.
+ *
+ * Remarks
+ * This function is similar to Wine WIN_ListChildren. The caller
+ * must free the returned list with ExFreePool.
+ */
+
+HWND* FASTCALL
+IntWinListChildren(PWND Window)
+{
+ PWND Child;
+ HWND *List;
+ UINT Index, NumChildren = 0;
+
+ if (!Window) return NULL;
+
+ for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
+ ++NumChildren;
+
+ List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
+ if(!List)
+ {
+ ERR("Failed to allocate memory for children array\n");
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
+ }
+ for (Child = Window->spwndChild, Index = 0;
+ Child != NULL;
+ Child = Child->spwndNext, ++Index)
+ List[Index] = Child->head.h;
+ List[Index] = NULL;
+
+ return List;
+}
+
+PWND FASTCALL
+IntGetNonChildAncestor(PWND pWnd)
+{
+ while(pWnd && (pWnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
+ pWnd = pWnd->spwndParent;
+ return pWnd;
+}
+
+BOOL FASTCALL
+IntIsTopLevelWindow(PWND pWnd)
+{
+ if ( pWnd->spwndParent &&
+ pWnd->spwndParent == co_GetDesktopWindow(pWnd) ) return TRUE;
+ return FALSE;
+}
+
+BOOL FASTCALL
+IntValidateOwnerDepth(PWND Wnd, PWND Owner)
+{
+ INT Depth = 1;
+ for (;;)
+ {
+ if ( !Owner ) return gNestedWindowLimit >= Depth;
+ if (Owner == Wnd) break;
+ Owner = Owner->spwndOwner;
+ Depth++;
+ }
+ return FALSE;
+}
+
+HWND FASTCALL
+IntGetWindow(HWND hWnd,
+ UINT uCmd)
+{
+ PWND Wnd, FoundWnd;
+ HWND Ret = NULL;
+
+ Wnd = ValidateHwndNoErr(hWnd);
+ if (!Wnd)
+ return NULL;
+
+ FoundWnd = NULL;
+ switch (uCmd)
+ {
+ case GW_OWNER:
+ if (Wnd->spwndOwner != NULL)
+ FoundWnd = Wnd->spwndOwner;
+ break;
+
+ case GW_HWNDFIRST:
+ if(Wnd->spwndParent != NULL)
+ {
+ FoundWnd = Wnd->spwndParent;
+ if (FoundWnd->spwndChild != NULL)
+ FoundWnd = FoundWnd->spwndChild;
+ }
+ break;
+ case GW_HWNDNEXT:
+ if (Wnd->spwndNext != NULL)
+ FoundWnd = Wnd->spwndNext;
+ break;
+
+ case GW_HWNDPREV:
+ if (Wnd->spwndPrev != NULL)
+ FoundWnd = Wnd->spwndPrev;
+ break;
+
+ case GW_CHILD:
+ if (Wnd->spwndChild != NULL)
+ FoundWnd = Wnd->spwndChild;
+ break;
+
+ case GW_HWNDLAST:
+ FoundWnd = Wnd;
+ while ( FoundWnd->spwndNext != NULL)
+ FoundWnd = FoundWnd->spwndNext;
+ break;
+
+ default:
+ Wnd = NULL;
+ break;
+ }
+
+ if (FoundWnd != NULL)
+ Ret = UserHMGetHandle(FoundWnd);
+ return Ret;
+}
+
+/***********************************************************************
+ * IntSendDestroyMsg
+ */
+static void IntSendDestroyMsg(HWND hWnd)
+{
+
+ PWND Window;
+#if 0 /* FIXME */
+
+ GUITHREADINFO info;
+
+ if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
+ {
+ if (hWnd == info.hwndCaret)
+ {
+ DestroyCaret();
+ }
+ }
+#endif
+
+ Window = UserGetWindowObject(hWnd);
+ if (Window)
+ {
+// USER_REFERENCE_ENTRY Ref;
+// UserRefObjectCo(Window, &Ref);
+
+ if (!Window->spwndOwner && !IntGetParent(Window))
+ {
+ co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
+ }
+
+// UserDerefObjectCo(Window);
+ }
+
+ /* The window could already be destroyed here */
+
+ /*
+ * Send the WM_DESTROY to the window.
+ */
+
+ co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
+
+ /*
+ * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
+ * make sure that the window still exists when we come back.
+ */
+#if 0 /* FIXME */
+
+ if (IsWindow(Wnd))
+ {
+ HWND* pWndArray;
+ int i;
+
+ if (!(pWndArray = WIN_ListChildren( hwnd )))
+ return;
+
+ /* start from the end (FIXME: is this needed?) */
+ for (i = 0; pWndArray[i]; i++)
+ ;
+
+ while (--i >= 0)
+ {
+ if (IsWindow( pWndArray[i] ))
+ WIN_SendDestroyMsg( pWndArray[i] );
+ }
+ HeapFree(GetProcessHeap(), 0, pWndArray);
+ }
+ else
+ {
+ TRACE("destroyed itself while in WM_DESTROY!\n");
+ }
+#endif
+}
+
+static VOID
+UserFreeWindowInfo(PTHREADINFO ti, PWND Wnd)
+{
+ PCLIENTINFO ClientInfo = GetWin32ClientInfo();
+
+ if (!Wnd) return;
+
+ if (ClientInfo->CallbackWnd.pWnd == DesktopHeapAddressToUser(Wnd))
+ {
+ ClientInfo->CallbackWnd.hWnd = NULL;
+ ClientInfo->CallbackWnd.pWnd = NULL;
+ }
+
+ if (Wnd->strName.Buffer != NULL)
+ {
+ Wnd->strName.Length = 0;
+ Wnd->strName.MaximumLength = 0;
+ DesktopHeapFree(Wnd->head.rpdesk,
+ Wnd->strName.Buffer);
+ Wnd->strName.Buffer = NULL;
+ }
+
+// DesktopHeapFree(Wnd->head.rpdesk, Wnd);
+// WindowObject->hWnd = NULL;
+}
+
+/***********************************************************************
+ * IntDestroyWindow
+ *
+ * Destroy storage associated to a window. "Internals" p.358
+ *
+ * This is the "functional" DestroyWindows function ei. all stuff
+ * done in CreateWindow is undone here and not in DestroyWindow:-P
+
+ */
+static LRESULT co_UserFreeWindow(PWND Window,
+ PPROCESSINFO ProcessData,
+ PTHREADINFO ThreadData,
+ BOOLEAN SendMessages)
+{
+ HWND *Children;
+ HWND *ChildHandle;
+ PWND Child;
+ PMENU Menu;
+ BOOLEAN BelongsToThreadData;
+
+ ASSERT(Window);
+
+ if(Window->state2 & WNDS2_INDESTROY)
+ {
+ TRACE("Tried to call IntDestroyWindow() twice\n");
+ return 0;
+ }
+ Window->state2 |= WNDS2_INDESTROY;
+ Window->style &= ~WS_VISIBLE;
+ Window->head.pti->cVisWindows--;
+
+ IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
+
+ /* remove the window already at this point from the thread window list so we
+ don't get into trouble when destroying the thread windows while we're still
+ in IntDestroyWindow() */
+ RemoveEntryList(&Window->ThreadListEntry);
+
+ BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
+
+ IntDeRegisterShellHookWindow(Window->head.h);
+
+ if(SendMessages)
+ {
+ /* Send destroy messages */
+ IntSendDestroyMsg(Window->head.h);
+ }
+
+ /* free child windows */
+ Children = IntWinListChildren(Window);
+ if (Children)
+ {
+ for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
+ {
+ if ((Child = IntGetWindowObject(*ChildHandle)))
+ {
+ if(!IntWndBelongsToThread(Child, ThreadData))
+ {
+ /* send WM_DESTROY messages to windows not belonging to the same thread */
+ IntSendDestroyMsg(Child->head.h);
+ }
+ else
+ co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
+
+ UserDereferenceObject(Child);
+ }
+ }
+ ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
+ }
+
+ if(SendMessages)
+ {
+ /*
+ * Clear the update region to make sure no WM_PAINT messages will be
+ * generated for this window while processing the WM_NCDESTROY.
+ */
+ co_UserRedrawWindow(Window, NULL, 0,
+ RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
+ RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
+ if(BelongsToThreadData)
+ co_IntSendMessage(Window->head.h, WM_NCDESTROY, 0, 0);
+ }
+
+ DestroyTimersForWindow(ThreadData, Window);
+
+ /* Unregister hot keys */
+ UnregisterWindowHotKeys (Window);
+
+ /* flush the message queue */
+ MsqRemoveWindowMessagesFromQueue(Window);
+
+ /* from now on no messages can be sent to this window anymore */
+ Window->state |= WNDS_DESTROYED;
+ Window->fnid |= FNID_FREED;
+
+ /* don't remove the WINDOWSTATUS_DESTROYING bit */
+
+ /* reset shell window handles */
+ if(ThreadData->rpdesk)
+ {
+ if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
+ ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
+
+ if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellListView)
+ ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
+ }
+
+ /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
+
+#if 0 /* FIXME */
+
+ WinPosCheckInternalPos(Window->head.h);
+ if (Window->head.h == GetCapture())
+ {
+ ReleaseCapture();
+ }
+
+ /* free resources associated with the window */
+ TIMER_RemoveWindowTimers(Window->head.h);
+#endif
+
+ if ( ((Window->style & (WS_CHILD|WS_POPUP)) != WS_CHILD) &&
+ Window->IDMenu &&
+ (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
+ {
+ IntDestroyMenuObject(Menu, TRUE, TRUE);
+ Window->IDMenu = 0;
+ }
+
+ if(Window->SystemMenu
+ && (Menu = UserGetMenuObject(Window->SystemMenu)))
+ {
+ IntDestroyMenuObject(Menu, TRUE, TRUE);
+ Window->SystemMenu = (HMENU)0;
+ }
+
+ DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
+#if 0 /* FIXME */
+
+ WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
+ CLASS_RemoveWindow(Window->Class);
+#endif
+
+ IntUnlinkWindow(Window);
+
+ if (Window->PropListItems)
+ {
+ IntRemoveWindowProp(Window);
+ TRACE("Window->PropListItems %d\n",Window->PropListItems);
+ ASSERT(Window->PropListItems==0);
+ }
+
+ UserReferenceObject(Window);
+ UserDeleteObject(Window->head.h, TYPE_WINDOW);
+
+ IntDestroyScrollBars(Window);
+
+ /* dereference the class */
+ IntDereferenceClass(Window->pcls,
+ Window->head.pti->pDeskInfo,
+ Window->head.pti->ppi);
+ Window->pcls = NULL;
+
+ if(Window->hrgnClip)
+ {
+ IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(Window->hrgnClip);
+ Window->hrgnClip = NULL;
+ }
+ Window->head.pti->cWindows--;
+
+// ASSERT(Window != NULL);
+ UserFreeWindowInfo(Window->head.pti, Window);
+
+ UserDereferenceObject(Window);
+
+ UserClipboardFreeWindow(Window);
+
+ return 0;
+}
+
+//
+// Same as User32:IntGetWndProc.
+//
+WNDPROC FASTCALL
+IntGetWindowProc(PWND pWnd,
+ BOOL Ansi)
+{
+ INT i;
+ PCLS Class;
+ WNDPROC gcpd, Ret = 0;
+
+ ASSERT(UserIsEnteredExclusive() == TRUE);
+
+ Class = pWnd->pcls;
+
+ if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
+ {
+ for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
+ {
+ if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
+ {
+ if (Ansi)
+ Ret = GETPFNCLIENTA(i);
+ else
+ Ret = GETPFNCLIENTW(i);
+ }
+ }
+ return Ret;
+ }
+
+ if (Class->fnid == FNID_EDIT)
+ Ret = pWnd->lpfnWndProc;
+ else
+ {
+ Ret = pWnd->lpfnWndProc;
+
+ if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
+ {
+ if (Ansi)
+ {
+ if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
+ Ret = GETPFNCLIENTA(Class->fnid);
+ }
+ else
+ {
+ if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
+ Ret = GETPFNCLIENTW(Class->fnid);
+ }
+ }
+ if ( Ret != pWnd->lpfnWndProc)
+ return Ret;
+ }
+ if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
+ return Ret;
+
+ gcpd = (WNDPROC)UserGetCPD(
+ pWnd,
+ (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
+ (ULONG_PTR)Ret);
+
+ return (gcpd ? gcpd : Ret);
+}
+
+static WNDPROC
+IntSetWindowProc(PWND pWnd,
+ WNDPROC NewWndProc,
+ BOOL Ansi)
+{
+ INT i;
+ PCALLPROCDATA CallProc;
+ PCLS Class;
+ WNDPROC Ret, chWndProc = NULL;
+
+ // Retrieve previous window proc.
+ Ret = IntGetWindowProc(pWnd, Ansi);
+
+ Class = pWnd->pcls;
+
+ if (IsCallProcHandle(NewWndProc))
+ {
+ CallProc = UserGetObject(gHandleTable, NewWndProc, TYPE_CALLPROC);
+ if (CallProc)
+ { // Reset new WndProc.
+ NewWndProc = CallProc->pfnClientPrevious;
+ // Reset Ansi from CallProc handle. This is expected with wine "deftest".
+ Ansi = !!(CallProc->wType & UserGetCPDU2A);
+ }
+ }
+ // Switch from Client Side call to Server Side call if match. Ref: "deftest".
+ for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
+ {
+ if (GETPFNCLIENTW(i) == NewWndProc)
+ {
+ chWndProc = GETPFNSERVER(i);
+ break;
+ }
+ if (GETPFNCLIENTA(i) == NewWndProc)
+ {
+ chWndProc = GETPFNSERVER(i);
+ break;
+ }
+ }
+ // If match, set/reset to Server Side and clear ansi.
+ if (chWndProc)
+ {
+ pWnd->lpfnWndProc = chWndProc;
+ pWnd->Unicode = TRUE;
+ pWnd->state &= ~WNDS_ANSIWINDOWPROC;
+ pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
+ }
+ else
+ {
+ pWnd->Unicode = !Ansi;
+ // Handle the state change in here.
+ if (Ansi)
+ pWnd->state |= WNDS_ANSIWINDOWPROC;
+ else
+ pWnd->state &= ~WNDS_ANSIWINDOWPROC;
+
+ if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
+ pWnd->state &= ~WNDS_SERVERSIDEWINDOWPROC;
+
+ if (!NewWndProc) NewWndProc = pWnd->lpfnWndProc;
+
+ if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
+ {
+ if (Ansi)
+ {
+ if (GETPFNCLIENTW(Class->fnid) == NewWndProc)
+ chWndProc = GETPFNCLIENTA(Class->fnid);
+ }
+ else
+ {
+ if (GETPFNCLIENTA(Class->fnid) == NewWndProc)
+ chWndProc = GETPFNCLIENTW(Class->fnid);
+ }
+ }
+ // Now set the new window proc.
+ pWnd->lpfnWndProc = (chWndProc ? chWndProc : NewWndProc);
+ }
+ return Ret;
+}
+
+static BOOL FASTCALL
+IntSetMenu(
+ PWND Wnd,
+ HMENU Menu,
+ BOOL *Changed)
+{
+ PMENU OldMenu, NewMenu = NULL;
+
+ if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
+ {
+ ERR("SetMenu: Invalid handle 0x%p!\n",UserHMGetHandle(Wnd));
+ EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
+ return FALSE;
+ }
+
+ *Changed = (Wnd->IDMenu != (UINT) Menu);
+ if (! *Changed)
+ {
+ return TRUE;
+ }
+
+ if (Wnd->IDMenu)
+ {
+ OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
+ ASSERT(NULL == OldMenu || OldMenu->hWnd == Wnd->head.h);
+ }
+ else
+ {
+ OldMenu = NULL;
+ }
+
+ if (NULL != Menu)
+ {
+ NewMenu = IntGetMenuObject(Menu);
+ if (NULL == NewMenu)
+ {
+ if (NULL != OldMenu)
+ {
+ IntReleaseMenuObject(OldMenu);
+ }
+ EngSetLastError(ERROR_INVALID_MENU_HANDLE);
+ return FALSE;
+ }
+ if (NULL != NewMenu->hWnd)
+ {
+ /* Can't use the same menu for two windows */
+ if (NULL != OldMenu)
+ {
+ IntReleaseMenuObject(OldMenu);
+ }
+ EngSetLastError(ERROR_INVALID_MENU_HANDLE);
+ return FALSE;
+ }
+
+ }
+
+ Wnd->IDMenu = (UINT) Menu;
+ if (NULL != NewMenu)
+ {
+ NewMenu->hWnd = Wnd->head.h;
+ IntReleaseMenuObject(NewMenu);
+ }
+ if (NULL != OldMenu)
+ {
+ OldMenu->hWnd = NULL;
+ IntReleaseMenuObject(OldMenu);
+ }
+
+ return TRUE;
+}
+
+
+/* INTERNAL ******************************************************************/
+
+
+VOID FASTCALL
+co_DestroyThreadWindows(struct _ETHREAD *Thread)
+{
+ PTHREADINFO WThread;
+ PLIST_ENTRY Current;
+ PWND Wnd;
+ USER_REFERENCE_ENTRY Ref;
+ WThread = (PTHREADINFO)Thread->Tcb.Win32Thread;
+
+ while (!IsListEmpty(&WThread->WindowListHead))
+ {
+ Current = WThread->WindowListHead.Flink;
+ Wnd = CONTAINING_RECORD(Current, WND, ThreadListEntry);
+
+ TRACE("thread cleanup: while destroy wnds, wnd=%p\n", Wnd);
+
+ /* Window removes itself from the list */
+
+ /*
+ * FIXME: It is critical that the window removes itself! If now, we will loop
+ * here forever...
+ */
+
+ //ASSERT(co_UserDestroyWindow(Wnd));
+
+ UserRefObjectCo(Wnd, &Ref); // FIXME: Temp HACK??
+ if (!co_UserDestroyWindow(Wnd))
+ {
+ ERR("Unable to destroy window %p at thread cleanup... This is _VERY_ bad!\n", Wnd);
+ }
+ UserDerefObjectCo(Wnd); // FIXME: Temp HACK??
+ }
+}
+
- BOOL FASTCALL
- IntSetSystemMenu(PWND Window, PMENU Menu)
- {
- PMENU OldMenu;
- if(Window->SystemMenu)
- {
- OldMenu = IntGetMenuObject(Window->SystemMenu);
- if(OldMenu)
- {
- OldMenu->fFlags &= ~ MNF_SYSDESKMN;
- IntReleaseMenuObject(OldMenu);
- }
- }
-
- if(Menu)
- {
- /* FIXME: Check window style, propably return FALSE? */
- Window->SystemMenu = Menu->head.h;
- Menu->fFlags |= MNF_SYSDESKMN;
- }
- else // Use spmenuSys too!
- Window->SystemMenu = (HMENU)0;
-
- return TRUE;
- }
-
+BOOL FASTCALL
+IntIsChildWindow(PWND Parent, PWND BaseWindow)
+{
+ PWND Window;
+
+ Window = BaseWindow;
+ while (Window && ((Window->style & (WS_POPUP|WS_CHILD)) == WS_CHILD))
+ {
+ if (Window == Parent)
+ {
+ return(TRUE);
+ }
+
+ Window = Window->spwndParent;
+ }
+
+ return(FALSE);
+}
+
+/*
+ Link the window into siblings list
+ children and parent are kept in place.
+*/
+VOID FASTCALL
+IntLinkWindow(
+ PWND Wnd,
+ PWND WndInsertAfter /* set to NULL if top sibling */
+)
+{
+ if ((Wnd->spwndPrev = WndInsertAfter))
+ {
+ /* link after WndInsertAfter */
+ if ((Wnd->spwndNext = WndInsertAfter->spwndNext))
+ Wnd->spwndNext->spwndPrev = Wnd;
+
+ Wnd->spwndPrev->spwndNext = Wnd;
+ }
+ else
+ {
+ /* link at top */
+ if ((Wnd->spwndNext = Wnd->spwndParent->spwndChild))
+ Wnd->spwndNext->spwndPrev = Wnd;
+
+ Wnd->spwndParent->spwndChild = Wnd;
+ }
+}
+
+/*
+ Note: Wnd->spwndParent can be null if it is the desktop.
+*/
+VOID FASTCALL IntLinkHwnd(PWND Wnd, HWND hWndPrev)
+{
+ if (hWndPrev == HWND_NOTOPMOST)
+ {
+ if (!(Wnd->ExStyle & WS_EX_TOPMOST) &&
+ (Wnd->ExStyle2 & WS_EX2_LINKED)) return; /* nothing to do */
+ Wnd->ExStyle &= ~WS_EX_TOPMOST;
+ hWndPrev = HWND_TOP; /* fallback to the HWND_TOP case */
+ }
+
+ IntUnlinkWindow(Wnd); /* unlink it from the previous location */
+
+ if (hWndPrev == HWND_BOTTOM)
+ {
+ /* Link in the bottom of the list */
+ PWND WndInsertAfter;
+
+ WndInsertAfter = Wnd->spwndParent->spwndChild;
+ while( WndInsertAfter && WndInsertAfter->spwndNext)
+ WndInsertAfter = WndInsertAfter->spwndNext;
+
+ IntLinkWindow(Wnd, WndInsertAfter);
+ Wnd->ExStyle &= ~WS_EX_TOPMOST;
+ }
+ else if (hWndPrev == HWND_TOPMOST)
+ {
+ /* Link in the top of the list */
+ IntLinkWindow(Wnd, NULL);
+
+ Wnd->ExStyle |= WS_EX_TOPMOST;
+ }
+ else if (hWndPrev == HWND_TOP)
+ {
+ /* Link it after the last topmost window */
+ PWND WndInsertBefore;
+
+ WndInsertBefore = Wnd->spwndParent->spwndChild;
+
+ if (!(Wnd->ExStyle & WS_EX_TOPMOST)) /* put it above the first non-topmost window */
+ {
+ while (WndInsertBefore != NULL && WndInsertBefore->spwndNext != NULL)
+ {
+ if (!(WndInsertBefore->ExStyle & WS_EX_TOPMOST)) break;
+ if (WndInsertBefore == Wnd->spwndOwner) /* keep it above owner */
+ {
+ Wnd->ExStyle |= WS_EX_TOPMOST;
+ break;
+ }
+ WndInsertBefore = WndInsertBefore->spwndNext;
+ }
+ }
+
+ IntLinkWindow(Wnd, WndInsertBefore ? WndInsertBefore->spwndPrev : NULL);
+ }
+ else
+ {
+ /* Link it after hWndPrev */
+ PWND WndInsertAfter;
+
+ WndInsertAfter = UserGetWindowObject(hWndPrev);
+ /* Are we called with an erroneous handle */
+ if(WndInsertAfter == NULL)
+ {
+ /* Link in a default position */
+ IntLinkHwnd(Wnd, HWND_TOP);
+ return;
+ }
+
+ IntLinkWindow(Wnd, WndInsertAfter);
+
+ /* Fix the WS_EX_TOPMOST flag */
+ if (!(WndInsertAfter->ExStyle & WS_EX_TOPMOST))
+ {
+ Wnd->ExStyle &= ~WS_EX_TOPMOST;
+ }
+ else
+ {
+ if(WndInsertAfter->spwndNext &&
+ WndInsertAfter->spwndNext->ExStyle & WS_EX_TOPMOST)
+ {
+ Wnd->ExStyle |= WS_EX_TOPMOST;
+ }
+ }
+ }
+ Wnd->ExStyle2 |= WS_EX2_LINKED;
+}
+
+VOID FASTCALL
+IntProcessOwnerSwap(PWND Wnd, PWND WndNewOwner, PWND WndOldOwner)
+{
+ if (WndOldOwner)
+ {
+ if (Wnd->head.pti != WndOldOwner->head.pti)
+ {
+ if (!WndNewOwner ||
+ Wnd->head.pti == WndNewOwner->head.pti ||
+ WndOldOwner->head.pti != WndNewOwner->head.pti )
+ {
+ //ERR("ProcessOwnerSwap Old out.\n");
+ UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
+ }
+ }
+ }
+ if (WndNewOwner)
+ {
+ if (Wnd->head.pti != WndNewOwner->head.pti)
+ {
+ if (!WndOldOwner ||
+ WndOldOwner->head.pti != WndNewOwner->head.pti )
+ {
+ //ERR("ProcessOwnerSwap New in.\n");
+ UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
+ }
+ }
+ }
+ // FIXME: System Tray checks.
+}
+
+HWND FASTCALL
+IntSetOwner(HWND hWnd, HWND hWndNewOwner)
+{
+ PWND Wnd, WndOldOwner, WndNewOwner;
+ HWND ret;
+
+ Wnd = IntGetWindowObject(hWnd);
+ if(!Wnd)
+ return NULL;
+
+ WndOldOwner = Wnd->spwndOwner;
+
+ ret = WndOldOwner ? UserHMGetHandle(WndOldOwner) : 0;
+ WndNewOwner = UserGetWindowObject(hWndNewOwner);
+
+ if (!WndNewOwner && hWndNewOwner)
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ ret = NULL;
+ goto Error;
+ }
+
+ /* if parent belongs to a different thread and the window isn't */
+ /* top-level, attach the two threads */
+ IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
+
+ if (IntValidateOwnerDepth(Wnd, WndNewOwner))
+ {
+ if (WndNewOwner)
+ {
+ Wnd->spwndOwner= WndNewOwner;
+ }
+ else
+ {
+ Wnd->spwndOwner = NULL;
+ }
+ }
+ else
+ {
+ IntProcessOwnerSwap(Wnd, WndOldOwner, WndNewOwner);
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ ret = NULL;
+ }
+Error:
+ UserDereferenceObject(Wnd);
+ return ret;
+}
+
+PWND FASTCALL
+co_IntSetParent(PWND Wnd, PWND WndNewParent)
+{
+ PWND WndOldParent, pWndExam;
+ BOOL WasVisible;
+ POINT pt;
+ int swFlags = SWP_NOSIZE|SWP_NOZORDER;
+
+ ASSERT(Wnd);
+ ASSERT(WndNewParent);
+ ASSERT_REFS_CO(Wnd);
+ ASSERT_REFS_CO(WndNewParent);
+
+ if (Wnd == Wnd->head.rpdesk->spwndMessage)
+ {
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ return( NULL);
+ }
+
+ /* Some applications try to set a child as a parent */
+ if (IntIsChildWindow(Wnd, WndNewParent))
+ {
+ TRACE("IntSetParent try to set a child as a parent.\n");
+ EngSetLastError( ERROR_INVALID_PARAMETER );
+ return NULL;
+ }
+
+ pWndExam = WndNewParent; // Load parent Window to examine.
+ // Now test for set parent to parent hit.
+ while (pWndExam)
+ {
+ if (Wnd == pWndExam)
+ {
+ TRACE("IntSetParent Failed Test for set parent to parent!\n");
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+ pWndExam = pWndExam->spwndParent;
+ }
+
+ /*
+ * Windows hides the window first, then shows it again
+ * including the WM_SHOWWINDOW messages and all
+ */
+ WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
+
+ /* Window must belong to current process */
+ if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
+ {
+ ERR("IntSetParent Window must belong to current process!\n");
+ return NULL;
+ }
+
+ WndOldParent = Wnd->spwndParent;
+
+ if ( WndOldParent &&
+ WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
+ pt.x = Wnd->rcWindow.right;
+ else
+ pt.x = Wnd->rcWindow.left;
+ pt.y = Wnd->rcWindow.top;
+
+ IntScreenToClient(WndOldParent, &pt);
+
+ if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
+
+ if (WndNewParent != WndOldParent)
+ {
+ /* Unlink the window from the siblings list */
+ IntUnlinkWindow(Wnd);
+ Wnd->ExStyle2 &= ~WS_EX2_LINKED;
+
+ /* Set the new parent */
+ Wnd->spwndParent = WndNewParent;
+
+ if ( Wnd->style & WS_CHILD &&
+ Wnd->spwndOwner &&
+ Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
+ {
+ ERR("SetParent Top Most from Pop up!\n");
+ Wnd->ExStyle |= WS_EX_TOPMOST;
+ }
+
+ /* Link the window with its new siblings */
+ IntLinkHwnd( Wnd,
+ ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
+ WndNewParent == UserGetDesktopWindow() ) ? HWND_TOP : HWND_TOPMOST ) );
+
+ }
+
+ if ( WndNewParent == co_GetDesktopWindow(Wnd) &&
+ !(Wnd->style & WS_CLIPSIBLINGS) )
+ {
+ Wnd->style |= WS_CLIPSIBLINGS;
+ DceResetActiveDCEs(Wnd);
+ }
+
+ /* if parent belongs to a different thread and the window isn't */
+ /* top-level, attach the two threads */
+ if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
+ {
+ if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
+ {
+ if (Wnd->head.pti != WndOldParent->head.pti)
+ {
+ //ERR("SetParent Old out.\n");
+ UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
+ }
+ }
+ if ( WndNewParent != co_GetDesktopWindow(Wnd))
+ {
+ if (Wnd->head.pti != WndNewParent->head.pti)
+ {
+ //ERR("SetParent New in.\n");
+ UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
+ }
+ }
+ }
+
+ if (WndOldParent == UserGetMessageWindow() || WndNewParent == UserGetMessageWindow())
+ swFlags |= SWP_NOACTIVATE;
+
+ IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
+ /*
+ * SetParent additionally needs to make hwnd the top window
+ * in the z-order and send the expected WM_WINDOWPOSCHANGING and
+ * WM_WINDOWPOSCHANGED notification messages.
+ */
+ //ERR("IntSetParent SetWindowPos 1\n");
+ co_WinPosSetWindowPos( Wnd,
+ (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
+ pt.x, pt.y, 0, 0, swFlags);
+ //ERR("IntSetParent SetWindowPos 2 X %d Y %d\n",pt.x, pt.y);
+ if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
+
+ return WndOldParent;
+}
+
+HWND FASTCALL
+co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
+{
+ PWND Wnd = NULL, WndParent = NULL, WndOldParent;
+ HWND hWndOldParent = NULL;
+ USER_REFERENCE_ENTRY Ref, ParentRef;
+
+ if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return( NULL);
+ }
+
+ if (hWndChild == IntGetDesktopWindow())
+ {
+ ERR("UserSetParent Access Denied!\n");
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ return( NULL);
+ }
+
+ if (hWndNewParent)
+ {
+ if (!(WndParent = UserGetWindowObject(hWndNewParent)))
+ {
+ ERR("UserSetParent Bad New Parent!\n");
+ return( NULL);
+ }
+ }
+ else
+ {
+ if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
+ {
+ return( NULL);
+ }
+ }
+
+ if (!(Wnd = UserGetWindowObject(hWndChild)))
+ {
+ ERR("UserSetParent Bad Child!\n");
+ return( NULL);
+ }
+
+ UserRefObjectCo(Wnd, &Ref);
+ UserRefObjectCo(WndParent, &ParentRef);
+ //ERR("Enter co_IntSetParent\n");
+ WndOldParent = co_IntSetParent(Wnd, WndParent);
+ //ERR("Leave co_IntSetParent\n");
+ UserDerefObjectCo(WndParent);
+ UserDerefObjectCo(Wnd);
+
+ if (WndOldParent)
+ {
+ hWndOldParent = WndOldParent->head.h;
+ UserDereferenceObject(WndOldParent);
+ }
+
+ return( hWndOldParent);
+}
+
- PMENU SystemMenu;
+/* Unlink the window from siblings. children and parent are kept in place. */
+VOID FASTCALL
+IntUnlinkWindow(PWND Wnd)
+{
+ if (Wnd->spwndNext)
+ Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
+
+ if (Wnd->spwndPrev)
+ Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
+
+ if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
+ Wnd->spwndParent->spwndChild = Wnd->spwndNext;
+
+ Wnd->spwndPrev = Wnd->spwndNext = NULL;
+}
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * As best as I can figure, this function is used by EnumWindows,
+ * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
+ *
+ * It's supposed to build a list of HWNDs to return to the caller.
+ * We can figure out what kind of list by what parameters are
+ * passed to us.
+ */
+/*
+ * @implemented
+ */
+NTSTATUS
+APIENTRY
+NtUserBuildHwndList(
+ HDESK hDesktop,
+ HWND hwndParent,
+ BOOLEAN bChildren,
+ ULONG dwThreadId,
+ ULONG lParam,
+ HWND* pWnd,
+ ULONG* pBufSize)
+{
+ NTSTATUS Status;
+ ULONG dwCount = 0;
+
+ if (pBufSize == 0)
+ return ERROR_INVALID_PARAMETER;
+
+ if (hwndParent || !dwThreadId)
+ {
+ PDESKTOP Desktop;
+ PWND Parent, Window;
+
+ if(!hwndParent)
+ {
+ if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
+ {
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if(hDesktop)
+ {
+ Status = IntValidateDesktopHandle(hDesktop,
+ UserMode,
+ 0,
+ &Desktop);
+ if(!NT_SUCCESS(Status))
+ {
+ return ERROR_INVALID_HANDLE;
+ }
+ }
+ hwndParent = Desktop->DesktopWindow;
+ }
+ else
+ {
+ hDesktop = 0;
+ }
+
+ if((Parent = UserGetWindowObject(hwndParent)) &&
+ (Window = Parent->spwndChild))
+ {
+ BOOL bGoDown = TRUE;
+
+ Status = STATUS_SUCCESS;
+ while(TRUE)
+ {
+ if (bGoDown)
+ {
+ if(dwCount++ < *pBufSize && pWnd)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite(pWnd, sizeof(HWND), 1);
+ *pWnd = Window->head.h;
+ pWnd++;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ break;
+ }
+ }
+ if (Window->spwndChild && bChildren)
+ {
+ Window = Window->spwndChild;
+ continue;
+ }
+ bGoDown = FALSE;
+ }
+ if (Window->spwndNext)
+ {
+ Window = Window->spwndNext;
+ bGoDown = TRUE;
+ continue;
+ }
+ Window = Window->spwndParent;
+ if (Window == Parent)
+ {
+ break;
+ }
+ }
+ }
+
+ if(hDesktop)
+ {
+ ObDereferenceObject(Desktop);
+ }
+ }
+ else // Build EnumThreadWindows list!
+ {
+ PETHREAD Thread;
+ PTHREADINFO W32Thread;
+ PLIST_ENTRY Current;
+ PWND Window;
+
+ Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("Thread Id is not valid!\n");
+ return ERROR_INVALID_PARAMETER;
+ }
+ if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
+ {
+ ObDereferenceObject(Thread);
+ ERR("Thread is not initialized!\n");
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ Current = W32Thread->WindowListHead.Flink;
+ while (Current != &(W32Thread->WindowListHead))
+ {
+ Window = CONTAINING_RECORD(Current, WND, ThreadListEntry);
+ ASSERT(Window);
+
+ if (dwCount < *pBufSize && pWnd)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite(pWnd, sizeof(HWND), 1);
+ *pWnd = Window->head.h;
+ pWnd++;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("Failure to build window list!\n");
+ SetLastNtError(Status);
+ break;
+ }
+ }
+ dwCount++;
+ Current = Window->ThreadListEntry.Flink;
+ }
+
+ ObDereferenceObject(Thread);
+ }
+
+ *pBufSize = dwCount;
+ return STATUS_SUCCESS;
+}
+
+static void IntSendParentNotify( PWND pWindow, UINT msg )
+{
+ if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
+ !(pWindow->style & WS_EX_NOPARENTNOTIFY))
+ {
+ if (pWindow->spwndParent && pWindow->spwndParent != UserGetDesktopWindow())
+ {
+ USER_REFERENCE_ENTRY Ref;
+ UserRefObjectCo(pWindow->spwndParent, &Ref);
+ co_IntSendMessage( pWindow->spwndParent->head.h,
+ WM_PARENTNOTIFY,
+ MAKEWPARAM( msg, pWindow->IDMenu),
+ (LPARAM)pWindow->head.h );
+ UserDerefObjectCo(pWindow->spwndParent);
+ }
+ }
+}
+
+void FASTCALL
+IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
+{
+#define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
+
+ /* default positioning for overlapped windows */
+ if(!(Cs->style & (WS_POPUP | WS_CHILD)))
+ {
+ PMONITOR pMonitor;
+ PRTL_USER_PROCESS_PARAMETERS ProcessParams;
+
+ pMonitor = UserGetPrimaryMonitor();
+
+ /* Check if we don't have a monitor attached yet */
+ if(pMonitor == NULL)
+ {
+ Cs->x = Cs->y = 0;
+ Cs->cx = 800;
+ Cs->cy = 600;
+ return;
+ }
+
+ ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
+
+ if (IS_DEFAULT(Cs->x))
+ {
+ if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
+
+ if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
+ {
+ Cs->x = ProcessParams->StartingX;
+ Cs->y = ProcessParams->StartingY;
+ }
+ else
+ {
+ Cs->x = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
+ Cs->y = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
+ if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
+ Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
+ {
+ /* reset counter and position */
+ Cs->x = 0;
+ Cs->y = 0;
+ pMonitor->cWndStack = 0;
+ }
+ pMonitor->cWndStack++;
+ }
+ }
+
+ if (IS_DEFAULT(Cs->cx))
+ {
+ if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
+ {
+ Cs->cx = ProcessParams->CountX;
+ Cs->cy = ProcessParams->CountY;
+ }
+ else
+ {
+ Cs->cx = (pMonitor->rcWork.right - pMonitor->rcWork.left) * 3 / 4;
+ Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
+ }
+ }
+ /* neither x nor cx are default. Check the y values .
+ * In the trace we see Outlook and Outlook Express using
+ * cy set to CW_USEDEFAULT when opening the address book.
+ */
+ else if (IS_DEFAULT(Cs->cy))
+ {
+ TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
+ Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
+ }
+ }
+ else
+ {
+ /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
+ if(IS_DEFAULT(Cs->x))
+ {
+ Cs->x = 0;
+ Cs->y = 0;
+ }
+ if(IS_DEFAULT(Cs->cx))
+ {
+ Cs->cx = 0;
+ Cs->cy = 0;
+ }
+ }
+
+#undef IS_DEFAULT
+}
+
+/* Allocates and initializes a window */
+PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
+ PLARGE_STRING WindowName,
+ PCLS Class,
+ PWND ParentWindow,
+ PWND OwnerWindow,
+ PVOID acbiBuffer,
+ PDESKTOP pdeskCreated)
+{
+ PWND pWnd = NULL;
+ HWND hWnd;
+ PTHREADINFO pti = NULL;
- /* Create system menu */
- if ((Cs->style & WS_SYSMENU)) // && (dwStyle & WS_CAPTION) == WS_CAPTION)
- {
- SystemMenu = IntGetSystemMenu(pWnd, TRUE, TRUE);
- if(SystemMenu)
- { // spmenuSys
- pWnd->SystemMenu = SystemMenu->head.h;
- IntReleaseMenuObject(SystemMenu);
- }
- }
-
+ BOOL MenuChanged;
+ BOOL bUnicodeWindow;
+
+ pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
+
+ if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
+ { // Need both here for wine win.c test_CreateWindow.
+ //if (Cs->hwndParent && ParentWindow)
+ if (ParentWindow) // It breaks more tests..... WIP.
+ {
+ if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
+ ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
+ !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
+ Cs->dwExStyle |= WS_EX_LAYOUTRTL;
+ }
+ else
+ { /*
+ * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
+ *
+ * Dialog boxes and message boxes do not inherit layout, so you must
+ * set the layout explicitly.
+ */
+ if ( Class->fnid != FNID_DIALOG )
+ {
+ if (pti->ppi->dwLayout & LAYOUT_RTL)
+ {
+ Cs->dwExStyle |= WS_EX_LAYOUTRTL;
+ }
+ }
+ }
+ }
+
+ /* Automatically add WS_EX_WINDOWEDGE */
+ if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
+ ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
+ (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
+ Cs->dwExStyle |= WS_EX_WINDOWEDGE;
+ else
+ Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
+
+ /* Is it a unicode window? */
+ bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
+ Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
+
+ /* Allocate the new window */
+ pWnd = (PWND) UserCreateObject( gHandleTable,
+ pdeskCreated ? pdeskCreated : pti->rpdesk,
+ pti,
+ (PHANDLE)&hWnd,
+ TYPE_WINDOW,
+ sizeof(WND) + Class->cbwndExtra);
+
+ if (!pWnd)
+ {
+ goto AllocError;
+ }
+
+ TRACE("Created window object with handle %p\n", hWnd);
+
+ if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
+ { /* HACK: Helper for win32csr/desktopbg.c */
+ /* If there is no desktop window yet, we must be creating it */
+ TRACE("CreateWindow setting desktop.\n");
+ pdeskCreated->DesktopWindow = hWnd;
+ pdeskCreated->pDeskInfo->spwnd = pWnd;
+ }
+
+ /*
+ * Fill out the structure describing it.
+ */
+ /* Remember, pWnd->head is setup in object.c ... */
+ pWnd->spwndParent = ParentWindow;
+ pWnd->spwndOwner = OwnerWindow;
+ pWnd->fnid = 0;
+ pWnd->spwndLastActive = pWnd;
+ pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
+ pWnd->pcls = Class;
+ pWnd->hModule = Cs->hInstance;
+ pWnd->style = Cs->style & ~WS_VISIBLE;
+ pWnd->ExStyle = Cs->dwExStyle;
+ pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
+ pWnd->pActCtx = acbiBuffer;
+ pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
+ pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
+
+ if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
+ {
+ pWnd->HideFocus = pWnd->spwndParent->HideFocus;
+ pWnd->HideAccel = pWnd->spwndParent->HideAccel;
+ }
+
+ pWnd->head.pti->cWindows++;
+
+ if (Class->hIcon && !Class->hIconSm)
+ {
+ Class->hIconSmIntern = co_IntCopyImage( Class->hIcon, IMAGE_ICON,
+ UserGetSystemMetrics( SM_CXSMICON ),
+ UserGetSystemMetrics( SM_CYSMICON ), 0 );
+ TRACE("IntCreateWindow hIconSmIntern %p\n",Class->hIconSmIntern);
+ Class->CSF_flags |= CSF_CACHEDSMICON;
+ }
+
+ if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
+ pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
+
+ /* BugBoy Comments: Comment below say that System classes are always created
+ as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
+ sets the window to ansi as verified by testing with IsUnicodeWindow API.
+
+ No where can I see in code or through testing does the window change back
+ to ANSI after being created as UNICODE in ROS. I didnt do more testing to
+ see what problems this would cause. */
+
+ // Set WndProc from Class.
+ pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
+
+ // GetWindowProc, test for non server side default classes and set WndProc.
+ if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
+ {
+ if (bUnicodeWindow)
+ {
+ if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
+ pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
+ }
+ else
+ {
+ if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
+ pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
+ }
+ }
+
+ // If not an Unicode caller, set Ansi creator bit.
+ if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
+
+ // Clone Class Ansi/Unicode proc type.
+ if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
+ {
+ pWnd->state |= WNDS_ANSIWINDOWPROC;
+ pWnd->Unicode = FALSE;
+ }
+ else
+ { /*
+ * It seems there can be both an Ansi creator and Unicode Class Window
+ * WndProc, unless the following overriding conditions occur:
+ */
+ if ( !bUnicodeWindow &&
+ ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
+ Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
+ Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
+ Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
+ Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
+ Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
+ Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
+ Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
+ Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
+ { // Override Class and set the window Ansi WndProc.
+ pWnd->state |= WNDS_ANSIWINDOWPROC;
+ pWnd->Unicode = FALSE;
+ }
+ else
+ { // Set the window Unicode WndProc.
+ pWnd->state &= ~WNDS_ANSIWINDOWPROC;
+ pWnd->Unicode = TRUE;
+ }
+ }
+
+ /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
+ then my testing shows that windows (2k and XP) creates a CallProc for it immediately
+ Dont understand why it does this. */
+ if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
+ {
+ PCALLPROCDATA CallProc;
+ CallProc = CreateCallProc(NULL, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
+
+ if (!CallProc)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
+ }
+ else
+ {
+ UserAddCallProcToClass(pWnd->pcls, CallProc);
+ }
+ }
+
+ InitializeListHead(&pWnd->PropListHead);
+
+ if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
+ {
+ pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
+ WindowName->Length + sizeof(UNICODE_NULL));
+ if (pWnd->strName.Buffer == NULL)
+ {
+ goto AllocError;
+ }
+
+ RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
+ pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
+ pWnd->strName.Length = WindowName->Length;
+ pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
+ }
+
+ /* Correct the window style. */
+ if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
+ {
+ pWnd->style |= WS_CLIPSIBLINGS;
+ if (!(pWnd->style & WS_POPUP))
+ {
+ pWnd->style |= WS_CAPTION;
+ }
+ }
+
+ /* WS_EX_WINDOWEDGE depends on some other styles */
+ if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
+ pWnd->ExStyle |= WS_EX_WINDOWEDGE;
+ else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
+ {
+ if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
+ (pWnd->style & (WS_CHILD | WS_POPUP))))
+ pWnd->ExStyle |= WS_EX_WINDOWEDGE;
+ }
+ else
+ pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
+
+ if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
+ pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
+
- if (Cs->hMenu)
+ /* Set the window menu */
+ if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
+ {
- /*
++ if (Cs->hMenu)
++ {
+ IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
++ }
+ else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
+ {
+ UNICODE_STRING MenuName;
+ HMENU hMenu;
+
+ if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
+ {
+ MenuName.Length = 0;
+ MenuName.MaximumLength = 0;
+ MenuName.Buffer = pWnd->pcls->lpszMenuName;
+ }
+ else
+ {
+ RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
+ }
+ hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
+ if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
+ }
+ }
+ else // Not a child
+ pWnd->IDMenu = (UINT) Cs->hMenu;
+
+
+ if ( ParentWindow &&
+ ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
+ ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
+ {
+ PWND Owner = IntGetNonChildAncestor(ParentWindow);
+
+ if (!IntValidateOwnerDepth(pWnd, Owner))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ goto Error;
+ }
+ if ( pWnd->spwndOwner &&
+ pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
+ {
+ pWnd->ExStyle |= WS_EX_TOPMOST;
+ }
+ if ( pWnd->spwndOwner &&
+ Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
+ pti != pWnd->spwndOwner->head.pti)
+ {
+ //ERR("CreateWindow Owner in.\n");
+ UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
+ }
+ }
+
+ /* Insert the window into the thread's window list. */
+ InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
+
+ /* Handle "CS_CLASSDC", it is tested first. */
+ if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
+ { /* One DCE per class to have CLASS. */
+ pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
+ }
+ else if ( pWnd->pcls->style & CS_OWNDC)
+ { /* Allocate a DCE for this window. */
+ DceAllocDCE(pWnd, DCE_WINDOW_DC);
+ }
+
+ return pWnd;
+
+AllocError:
+ ERR("IntCreateWindow Allocation Error.\n");
+ SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
+Error:
+ if(pWnd)
+ UserDereferenceObject(pWnd);
+ return NULL;
+}
+
+/*
+ * @implemented
+ */
+PWND FASTCALL
+co_UserCreateWindowEx(CREATESTRUCTW* Cs,
+ PUNICODE_STRING ClassName,
+ PLARGE_STRING WindowName,
+ PVOID acbiBuffer)
+{
+ ULONG style;
+ PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
+ HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
+ PWINSTATION_OBJECT WinSta;
+ PCLS Class = NULL;
+ SIZE Size;
+ POINT MaxSize, MaxPos, MinTrack, MaxTrack;
+ CBT_CREATEWNDW * pCbtCreate;
+ LRESULT Result;
+ USER_REFERENCE_ENTRY ParentRef, Ref;
+ PTHREADINFO pti;
+ DWORD dwShowMode = SW_SHOW;
+ CREATESTRUCTW *pCsw = NULL;
+ PVOID pszClass = NULL, pszName = NULL;
+ PWND ret = NULL;
+
+ /* Get the current window station and reference it */
+ pti = GetW32ThreadInfo();
+ if (pti == NULL || pti->rpdesk == NULL)
+ {
+ ERR("Thread is not attached to a desktop! Cannot create window!\n");
+ return NULL; // There is nothing to cleanup.
+ }
+ WinSta = pti->rpdesk->rpwinstaParent;
+ ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
+
+ pCsw = NULL;
+ pCbtCreate = NULL;
+
+ /* Get the class and reference it */
+ Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
+ if(!Class)
+ {
+ ERR("Failed to find class %wZ\n", ClassName);
+ goto cleanup;
+ }
+
+ /* Now find the parent and the owner window */
+ hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
+ hWndOwner = NULL;
+
+ if (Cs->hwndParent == HWND_MESSAGE)
+ {
+ Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
+ }
+ else if (Cs->hwndParent)
+ {
+ if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
+ hWndOwner = Cs->hwndParent;
+ else
+ hWndParent = Cs->hwndParent;
+ }
+ else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
+ {
+ ERR("Cannot create a child window without a parrent!\n");
+ EngSetLastError(ERROR_TLW_WITH_WSCHILD);
+ goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
+ }
+
+ ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
+ OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
+
+ /* FIXME: Is this correct? */
+ if(OwnerWindow)
+ OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
+
+ /* Fix the position and the size of the window */
+ if (ParentWindow)
+ {
+ UserRefObjectCo(ParentWindow, &ParentRef);
+ IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
+ }
+
+ /* Allocate and initialize the new window */
+ Window = IntCreateWindow(Cs,
+ WindowName,
+ Class,
+ ParentWindow,
+ OwnerWindow,
+ acbiBuffer,
+ NULL);
+ if(!Window)
+ {
+ ERR("IntCreateWindow failed!\n");
+ goto cleanup;
+ }
+
+ hWnd = UserHMGetHandle(Window);
+ hwndInsertAfter = HWND_TOP;
+
+ UserRefObjectCo(Window, &Ref);
+ UserDereferenceObject(Window);
+ ObDereferenceObject(WinSta);
+
+ //// Check for a hook to eliminate overhead. ////
+ if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
+ {
+ // Allocate the calling structures Justin Case this goes Global.
+ pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
+ pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
+ if (!pCsw || !pCbtCreate)
+ {
+ ERR("UserHeapAlloc() failed!\n");
+ goto cleanup;
+ }
+
+ /* Fill the new CREATESTRUCTW */
+ RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
+ pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
+
+ // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
+ if (!IS_ATOM(ClassName->Buffer))
+ {
+ if (Window->state & WNDS_ANSICREATOR)
+ {
+ ANSI_STRING AnsiString;
+ AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
+ pszClass = UserHeapAlloc(AnsiString.MaximumLength);
+ if (!pszClass)
+ {
+ ERR("UserHeapAlloc() failed!\n");
+ goto cleanup;
+ }
+ RtlZeroMemory(pszClass, AnsiString.MaximumLength);
+ AnsiString.Buffer = (PCHAR)pszClass;
+ RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
+ }
+ else
+ {
+ UNICODE_STRING UnicodeString;
+ UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
+ pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
+ if (!pszClass)
+ {
+ ERR("UserHeapAlloc() failed!\n");
+ goto cleanup;
+ }
+ RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
+ UnicodeString.Buffer = (PWSTR)pszClass;
+ RtlCopyUnicodeString(&UnicodeString, ClassName);
+ }
+ pCsw->lpszClass = UserHeapAddressToUser(pszClass);
+ }
+ if (WindowName->Length)
+ {
+ UNICODE_STRING Name;
+ Name.Buffer = WindowName->Buffer;
+ Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
+ Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
+
+ if (Window->state & WNDS_ANSICREATOR)
+ {
+ ANSI_STRING AnsiString;
+ AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
+ pszName = UserHeapAlloc(AnsiString.MaximumLength);
+ if (!pszName)
+ {
+ ERR("UserHeapAlloc() failed!\n");
+ goto cleanup;
+ }
+ RtlZeroMemory(pszName, AnsiString.MaximumLength);
+ AnsiString.Buffer = (PCHAR)pszName;
+ RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
+ }
+ else
+ {
+ UNICODE_STRING UnicodeString;
+ UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
+ pszName = UserHeapAlloc(UnicodeString.MaximumLength);
+ if (!pszName)
+ {
+ ERR("UserHeapAlloc() failed!\n");
+ goto cleanup;
+ }
+ RtlZeroMemory(pszName, UnicodeString.MaximumLength);
+ UnicodeString.Buffer = (PWSTR)pszName;
+ RtlCopyUnicodeString(&UnicodeString, &Name);
+ }
+ pCsw->lpszName = UserHeapAddressToUser(pszName);
+ }
+
+ pCbtCreate->lpcs = pCsw;
+ pCbtCreate->hwndInsertAfter = hwndInsertAfter;
+
+ //// Call the WH_CBT hook ////
+ Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
+ if (Result != 0)
+ {
+ ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
+ goto cleanup;
+ }
+ // Write back changes.
+ Cs->cx = pCsw->cx;
+ Cs->cy = pCsw->cy;
+ Cs->x = pCsw->x;
+ Cs->y = pCsw->y;
+ hwndInsertAfter = pCbtCreate->hwndInsertAfter;
+ }
+
+ /* NCCREATE and WM_NCCALCSIZE need the original values */
+ Cs->lpszName = (LPCWSTR) WindowName;
+ Cs->lpszClass = (LPCWSTR) ClassName;
+
+ if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
+ {
+ if (ParentWindow != co_GetDesktopWindow(Window))
+ {
+ Cs->x += ParentWindow->rcClient.left;
+ Cs->y += ParentWindow->rcClient.top;
+ }
+ }
+
+ /* Send the WM_GETMINMAXINFO message */
+ Size.cx = Cs->cx;
+ Size.cy = Cs->cy;
+
+ if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
+ {
+ co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
+ if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
+ if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
+ if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
+ if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
+ }
+
+ Window->rcWindow.left = Cs->x;
+ Window->rcWindow.top = Cs->y;
+ Window->rcWindow.right = Cs->x + Size.cx;
+ Window->rcWindow.bottom = Cs->y + Size.cy;
- // ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
++ /*
+ if (0 != (Window->style & WS_CHILD) && ParentWindow)
+ {
- */
++ ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
+ RECTL_vOffsetRect(&Window->rcWindow,
+ ParentWindow->rcClient.left,
+ ParentWindow->rcClient.top);
+ }
- /*
- * NtUserGetSystemMenu
- *
- * The NtUserGetSystemMenu function allows the application to access the
- * window menu (also known as the system menu or the control menu) for
- * copying and modifying.
- *
- * Parameters
- * hWnd
- * Handle to the window that will own a copy of the window menu.
- * bRevert
- * Specifies the action to be taken. If this parameter is FALSE,
- * NtUserGetSystemMenu returns a handle to the copy of the window menu
- * currently in use. The copy is initially identical to the window menu
- * but it can be modified.
- * If this parameter is TRUE, GetSystemMenu resets the window menu back
- * to the default state. The previous window menu, if any, is destroyed.
- *
- * Return Value
- * If the bRevert parameter is FALSE, the return value is a handle to a
- * copy of the window menu. If the bRevert parameter is TRUE, the return
- * value is NULL.
- *
- * Status
- * @implemented
- */
-
- HMENU APIENTRY
- NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
- {
- PWND Window;
- PMENU Menu;
- DECLARE_RETURN(HMENU);
-
- TRACE("Enter NtUserGetSystemMenu\n");
- UserEnterShared();
-
- if (!(Window = UserGetWindowObject(hWnd)))
- {
- RETURN(NULL);
- }
-
- if (!(Menu = IntGetSystemMenu(Window, bRevert, FALSE)))
- {
- RETURN(NULL);
- }
-
- RETURN(Menu->head.h);
-
- CLEANUP:
- TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_);
- UserLeave();
- END_CLEANUP;
- }
-
- /*
- * NtUserSetSystemMenu
- *
- * Status
- * @implemented
- */
-
- BOOL APIENTRY
- NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
- {
- BOOL Result = FALSE;
- PWND Window;
- PMENU Menu;
- DECLARE_RETURN(BOOL);
-
- TRACE("Enter NtUserSetSystemMenu\n");
- UserEnterExclusive();
-
- if (!(Window = UserGetWindowObject(hWnd)))
- {
- RETURN( FALSE);
- }
-
- if (hMenu)
- {
- /*
- * Assign new menu handle.
- */
- if (!(Menu = UserGetMenuObject(hMenu)))
- {
- RETURN( FALSE);
- }
-
- Result = IntSetSystemMenu(Window, Menu);
- }
-
- RETURN( Result);
-
- CLEANUP:
- TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
- UserLeave();
- END_CLEANUP;
- }
-
++ */
+ /* correct child window coordinates if mirroring on parent is enabled */
+ if (ParentWindow != NULL)
+ {
+ if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
+ ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
+ {
+ Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
+ Window->rcWindow.left = Window->rcWindow.right - Size.cx;
+ }
+ }
+
+ Window->rcClient = Window->rcWindow;
+
+ /* Link the window */
+ if (NULL != ParentWindow)
+ {
+ /* Link the window into the siblings list */
+ if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
+ IntLinkHwnd(Window, HWND_BOTTOM);
+ else
+ IntLinkHwnd(Window, hwndInsertAfter);
+ }
+
+ if (!(Window->state2 & WNDS2_WIN31COMPAT))
+ {
+ if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
+ Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
+ }
+
+ if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
+ {
+ if ( !IntIsTopLevelWindow(Window) )
+ {
+ if (pti != Window->spwndParent->head.pti)
+ {
+ //ERR("CreateWindow Parent in.\n");
+ UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
+ }
+ }
+ }
+
+ /* Send the NCCREATE message */
+ Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
+ if (!Result)
+ {
+ ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
+ goto cleanup;
+ }
+
+ /* Send the WM_NCCALCSIZE message */
+ {
+ // RECT rc;
+ MaxPos.x = Window->rcWindow.left;
+ MaxPos.y = Window->rcWindow.top;
+
+ Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
+ //rc = Window->rcWindow;
+ //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
+ //Window->rcClient = rc;
+
+ RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
+ MaxPos.y - Window->rcWindow.top);
+ }
+
+ /* Send the WM_CREATE message. */
+ Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
+ if (Result == (LRESULT)-1)
+ {
+ ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
+ goto cleanup;
+ }
+
+ /* Send the EVENT_OBJECT_CREATE event */
+ IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
+
+ /* By setting the flag below it can be examined to determine if the window
+ was created successfully and a valid pwnd was passed back to caller since
+ from here the function has to succeed. */
+ Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
+
+ /* Send the WM_SIZE and WM_MOVE messages. */
+ if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
+ {
+ co_WinPosSendSizeMove(Window);
+ }
+
+ /* Show or maybe minimize or maximize the window. */
+
+ style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
+ if (style & (WS_MINIMIZE | WS_MAXIMIZE))
+ {
+ RECTL NewPos;
+ UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
+
+ SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
+ SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
+ if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
+ co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
+ NewPos.right, NewPos.bottom, SwFlag);
+ }
+
+ /* Send the WM_PARENTNOTIFY message */
+ IntSendParentNotify(Window, WM_CREATE);
+
+ /* Notify the shell that a new window was created */
+ if (Window->spwndParent == UserGetDesktopWindow() &&
+ Window->spwndOwner == NULL &&
+ (Window->style & WS_VISIBLE) &&
+ (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
+ (Window->ExStyle & WS_EX_APPWINDOW)))
+ {
+ co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
+ }
+
+ /* Initialize and show the window's scrollbars */
+ if (Window->style & WS_VSCROLL)
+ {
+ co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
+ }
+ if (Window->style & WS_HSCROLL)
+ {
+ co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
+ }
+
+ /* Show the new window */
+ if (Cs->style & WS_VISIBLE)
+ {
+ if (Window->style & WS_MAXIMIZE)
+ dwShowMode = SW_SHOW;
+ else if (Window->style & WS_MINIMIZE)
+ dwShowMode = SW_SHOWMINIMIZED;
+
+ co_WinPosShowWindow(Window, dwShowMode);
+
+ if (Window->ExStyle & WS_EX_MDICHILD)
+ {
+ ASSERT(ParentWindow);
+ if(!ParentWindow)
+ goto cleanup;
+ co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
+ /* ShowWindow won't activate child windows */
+ co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
+ }
+ }
+
+ TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
+ ret = Window;
+
+cleanup:
+ if (!ret)
+ {
+ TRACE("co_UserCreateWindowEx(): Error Created window!\n");
+ /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
+ if (Window)
+ co_UserDestroyWindow(Window);
+ else if (Class)
+ IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
+ }
+
+ if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
+ if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
+ if (pszName) UserHeapFree(pszName);
+ if (pszClass) UserHeapFree(pszClass);
+
+ if (Window)
+ {
+ UserDerefObjectCo(Window);
+ }
+ if (ParentWindow) UserDerefObjectCo(ParentWindow);
+
+ return ret;
+}
+
+NTSTATUS
+NTAPI
+ProbeAndCaptureLargeString(
+ OUT PLARGE_STRING plstrSafe,
+ IN PLARGE_STRING plstrUnsafe)
+{
+ LARGE_STRING lstrTemp;
+ PVOID pvBuffer = NULL;
+
+ _SEH2_TRY
+ {
+ /* Probe and copy the string */
+ ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
+ lstrTemp = *plstrUnsafe;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Fail */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode();)
+ }
+ _SEH2_END
+
+ if (lstrTemp.Length != 0)
+ {
+ /* Allocate a buffer from paged pool */
+ pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
+ if (!pvBuffer)
+ {
+ return STATUS_NO_MEMORY;
+ }
+
+ _SEH2_TRY
+ {
+ /* Probe and copy the buffer */
+ ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
+ RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Cleanup and fail */
+ ExFreePoolWithTag(pvBuffer, TAG_STRING);
+ _SEH2_YIELD(return _SEH2_GetExceptionCode();)
+ }
+ _SEH2_END
+ }
+
+ /* Set the output string */
+ plstrSafe->Buffer = pvBuffer;
+ plstrSafe->Length = lstrTemp.Length;
+ plstrSafe->MaximumLength = lstrTemp.Length;
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * \todo Allow passing plstrClassName as ANSI.
+ */
+HWND
+NTAPI
+NtUserCreateWindowEx(
+ DWORD dwExStyle,
+ PLARGE_STRING plstrClassName,
+ PLARGE_STRING plstrClsVersion,
+ PLARGE_STRING plstrWindowName,
+ DWORD dwStyle,
+ int x,
+ int y,
+ int nWidth,
+ int nHeight,
+ HWND hWndParent,
+ HMENU hMenu,
+ HINSTANCE hInstance,
+ LPVOID lpParam,
+ DWORD dwFlags,
+ PVOID acbiBuffer)
+{
+ NTSTATUS Status;
+ LARGE_STRING lstrWindowName;
+ LARGE_STRING lstrClassName;
+ UNICODE_STRING ustrClassName;
+ CREATESTRUCTW Cs;
+ HWND hwnd = NULL;
+ PWND pwnd;
+
+ lstrWindowName.Buffer = NULL;
+ lstrClassName.Buffer = NULL;
+
+ ASSERT(plstrWindowName);
+
+ if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
+ {
+ /* check hMenu is valid handle */
+ if (hMenu && !ValidateHandle(hMenu, TYPE_MENU))
+ {
+ /* error is set in ValidateHandle */
+ return NULL;
+ }
+ }
+
+ /* Copy the window name to kernel mode */
+ Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
+ SetLastNtError(Status);
+ return NULL;
+ }
+
+ plstrWindowName = &lstrWindowName;
+
+ /* Check if the class is an atom */
+ if (IS_ATOM(plstrClassName))
+ {
+ /* It is, pass the atom in the UNICODE_STRING */
+ ustrClassName.Buffer = (PVOID)plstrClassName;
+ ustrClassName.Length = 0;
+ ustrClassName.MaximumLength = 0;
+ }
+ else
+ {
+ /* It's not, capture the class name */
+ Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
+ /* Set last error, cleanup and return */
+ SetLastNtError(Status);
+ goto cleanup;
+ }
+
+ /* We pass it on as a UNICODE_STRING */
+ ustrClassName.Buffer = lstrClassName.Buffer;
+ ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
+ ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
+ }
+
+ /* Fill the CREATESTRUCTW */
+ /* we will keep here the original parameters */
+ Cs.style = dwStyle;
+ Cs.lpCreateParams = lpParam;
+ Cs.hInstance = hInstance;
+ Cs.hMenu = hMenu;
+ Cs.hwndParent = hWndParent;
+ Cs.cx = nWidth;
+ Cs.cy = nHeight;
+ Cs.x = x;
+ Cs.y = y;
+ Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
+ if (IS_ATOM(plstrClassName))
+ Cs.lpszClass = (LPCWSTR) plstrClassName;
+ else
+ Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
+ Cs.dwExStyle = dwExStyle;
+
+ UserEnterExclusive();
+
+ /* Call the internal function */
+ pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
+
+ if(!pwnd)
+ {
+ ERR("co_UserCreateWindowEx failed!\n");
+ }
+ hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
+
+ UserLeave();
+
+cleanup:
+ if (lstrWindowName.Buffer)
+ {
+ ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
+ }
+ if (lstrClassName.Buffer)
+ {
+ ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
+ }
+
+ return hwnd;
+}
+
+
+BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
+{
+ HWND hWnd;
+ PWND pwndTemp;
+ PTHREADINFO ti;
+ MSG msg;
+
+ ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
+
+ hWnd = Window->head.h;
+ ti = PsGetCurrentThreadWin32Thread();
+
+ TRACE("co_UserDestroyWindow \n");
+
+ /* Check for owner thread */
+ if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
+ {
+ /* Check if we are destroying the desktop window */
+ if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
+ {
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ return FALSE;
+ }
+ }
+
+ /* If window was created successfully and it is hooked */
+ if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
+ {
+ if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
+ {
+ ERR("Destroy Window WH_CBT Call Hook return!\n");
+ return FALSE;
+ }
+ }
+
+ if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
+ {
+ if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
+ {
+ if (Window->spwndOwner)
+ {
+ //ERR("DestroyWindow Owner out.\n");
+ UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
+ }
+ }
+ }
+
+ /* Inform the parent */
+ if (Window->style & WS_CHILD)
+ {
+ IntSendParentNotify(Window, WM_DESTROY);
+ }
+
+ /* Look whether the focus is within the tree of windows we will
+ * be destroying.
+ */
+ if (!co_WinPosShowWindow(Window, SW_HIDE))
+ { // Rule #1.
+ if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
+ {
+ co_WinPosActivateOtherWindow(Window);
+ }
+ }
+
+ // Adjust last active.
+ if ((pwndTemp = Window->spwndOwner))
+ {
+ while (pwndTemp->spwndOwner)
+ pwndTemp = pwndTemp->spwndOwner;
+
+ if (pwndTemp->spwndLastActive == Window)
+ pwndTemp->spwndLastActive = Window->spwndOwner;
+ }
+
+ if (Window->spwndParent && IntIsWindow(Window->head.h))
+ {
+ if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
+ {
+ if (!IntIsTopLevelWindow(Window))
+ {
+ //ERR("DestroyWindow Parent out.\n");
+ UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
+ }
+ }
+ }
+
+ if (Window->head.pti->MessageQueue->spwndActive == Window)
+ Window->head.pti->MessageQueue->spwndActive = NULL;
+ if (Window->head.pti->MessageQueue->spwndFocus == Window)
+ Window->head.pti->MessageQueue->spwndFocus = NULL;
+ if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
+ Window->head.pti->MessageQueue->spwndActivePrev = NULL;
+ if (Window->head.pti->MessageQueue->spwndCapture == Window)
+ Window->head.pti->MessageQueue->spwndCapture = NULL;
+
+ /*
+ * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
+ */
+
+ if ((ti != NULL) && (ti->pDeskInfo != NULL))
+ {
+ if (ti->pDeskInfo->hShellWindow == hWnd)
+ {
+ ERR("Destroying the ShellWindow!\n");
+ ti->pDeskInfo->hShellWindow = NULL;
+ }
+ }
+
+ IntEngWindowChanged(Window, WOC_DELETE);
+
+ if (!IntIsWindow(Window->head.h))
+ {
+ return TRUE;
+ }
+
+ /* Recursively destroy owned windows */
+
+ if (! (Window->style & WS_CHILD))
+ {
+ for (;;)
+ {
+ BOOL GotOne = FALSE;
+ HWND *Children;
+ HWND *ChildHandle;
+ PWND Child, Desktop;
+
+ Desktop = IntIsDesktopWindow(Window) ? Window :
+ UserGetWindowObject(IntGetDesktopWindow());
+ Children = IntWinListChildren(Desktop);
+
+ if (Children)
+ {
+ for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
+ {
+ Child = UserGetWindowObject(*ChildHandle);
+ if (Child == NULL)
+ continue;
+ if (Child->spwndOwner != Window)
+ {
+ continue;
+ }
+
+ if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
+ {
+ USER_REFERENCE_ENTRY ChildRef;
+ UserRefObjectCo(Child, &ChildRef); // Temp HACK?
+ co_UserDestroyWindow(Child);
+ UserDerefObjectCo(Child); // Temp HACK?
+
+ GotOne = TRUE;
+ continue;
+ }
+
+ if (Child->spwndOwner != NULL)
+ {
+ Child->spwndOwner = NULL;
+ }
+
+ }
+ ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
+ }
+ if (! GotOne)
+ {
+ break;
+ }
+ }
+ }
+
+ /* Generate mouse move message for the next window */
+ msg.message = WM_MOUSEMOVE;
+ msg.wParam = UserGetMouseButtonsState();
+ msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
+ msg.pt = gpsi->ptCursor;
+ co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
+
+ if (!IntIsWindow(Window->head.h))
+ {
+ return TRUE;
+ }
+
+ /* Destroy the window storage */
+ co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
+
+ return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+BOOLEAN APIENTRY
+NtUserDestroyWindow(HWND Wnd)
+{
+ PWND Window;
+ DECLARE_RETURN(BOOLEAN);
+ BOOLEAN ret;
+ USER_REFERENCE_ENTRY Ref;
+
+ TRACE("Enter NtUserDestroyWindow\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(Wnd)))
+ {
+ RETURN(FALSE);
+ }
+
+ UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
+ ret = co_UserDestroyWindow(Window);
+ UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
+
+ RETURN(ret);
+
+CLEANUP:
+ TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+static HWND FASTCALL
+IntFindWindow(PWND Parent,
+ PWND ChildAfter,
+ RTL_ATOM ClassAtom,
+ PUNICODE_STRING WindowName)
+{
+ BOOL CheckWindowName;
+ HWND *List, *phWnd;
+ HWND Ret = NULL;
+ UNICODE_STRING CurrentWindowName;
+
+ ASSERT(Parent);
+
+ CheckWindowName = WindowName->Buffer != 0;
+
+ if((List = IntWinListChildren(Parent)))
+ {
+ phWnd = List;
+ if(ChildAfter)
+ {
+ /* skip handles before and including ChildAfter */
+ while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
+ ;
+ }
+
+ /* search children */
+ while(*phWnd)
+ {
+ PWND Child;
+ if(!(Child = UserGetWindowObject(*(phWnd++))))
+ {
+ continue;
+ }
+
+ /* Do not send WM_GETTEXT messages in the kernel mode version!
+ The user mode version however calls GetWindowText() which will
+ send WM_GETTEXT messages to windows belonging to its processes */
+ if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
+ {
+ // FIXME: LARGE_STRING truncated
+ CurrentWindowName.Buffer = Child->strName.Buffer;
+ CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
+ CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
+ if(!CheckWindowName ||
+ (Child->strName.Length < 0xFFFF &&
+ !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
+ {
+ Ret = Child->head.h;
+ break;
+ }
+ }
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+
+ return Ret;
+}
+
+/*
+ * FUNCTION:
+ * Searches a window's children for a window with the specified
+ * class and name
+ * ARGUMENTS:
+ * hwndParent = The window whose childs are to be searched.
+ * NULL = desktop
+ * HWND_MESSAGE = message-only windows
+ *
+ * hwndChildAfter = Search starts after this child window.
+ * NULL = start from beginning
+ *
+ * ucClassName = Class name to search for
+ * Reguired parameter.
+ *
+ * ucWindowName = Window name
+ * ->Buffer == NULL = don't care
+ *
+ * RETURNS:
+ * The HWND of the window if it was found, otherwise NULL
+ */
+/*
+ * @implemented
+ */
+HWND APIENTRY
+NtUserFindWindowEx(HWND hwndParent,
+ HWND hwndChildAfter,
+ PUNICODE_STRING ucClassName,
+ PUNICODE_STRING ucWindowName,
+ DWORD dwUnknown)
+{
+ PWND Parent, ChildAfter;
+ UNICODE_STRING ClassName = {0}, WindowName = {0};
+ HWND Desktop, Ret = NULL;
+ BOOL DoMessageWnd = FALSE;
+ RTL_ATOM ClassAtom = (RTL_ATOM)0;
+ DECLARE_RETURN(HWND);
+
+ TRACE("Enter NtUserFindWindowEx\n");
+ UserEnterShared();
+
+ if (ucClassName != NULL || ucWindowName != NULL)
+ {
+ _SEH2_TRY
+ {
+ if (ucClassName != NULL)
+ {
+ ClassName = ProbeForReadUnicodeString(ucClassName);
+ if (ClassName.Length != 0)
+ {
+ ProbeForRead(ClassName.Buffer,
+ ClassName.Length,
+ sizeof(WCHAR));
+ }
+ else if (!IS_ATOM(ClassName.Buffer))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ _SEH2_LEAVE;
+ }
+
+ if (!IntGetAtomFromStringOrAtom(&ClassName,
+ &ClassAtom))
+ {
+ _SEH2_LEAVE;
+ }
+ }
+
+ if (ucWindowName != NULL)
+ {
+ WindowName = ProbeForReadUnicodeString(ucWindowName);
+ if (WindowName.Length != 0)
+ {
+ ProbeForRead(WindowName.Buffer,
+ WindowName.Length,
+ sizeof(WCHAR));
+ }
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(RETURN(NULL));
+ }
+ _SEH2_END;
+
+ if (ucClassName != NULL)
+ {
+ if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
+ !IS_ATOM(ClassName.Buffer))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ RETURN(NULL);
+ }
+ else if (ClassAtom == (RTL_ATOM)0)
+ {
+ /* LastError code was set by IntGetAtomFromStringOrAtom */
+ RETURN(NULL);
+ }
+ }
+ }
+
+ Desktop = IntGetCurrentThreadDesktopWindow();
+
+ if(hwndParent == NULL)
+ {
+ hwndParent = Desktop;
+ DoMessageWnd = TRUE;
+ }
+ else if(hwndParent == HWND_MESSAGE)
+ {
+ hwndParent = IntGetMessageWindow();
+ }
+
+ if(!(Parent = UserGetWindowObject(hwndParent)))
+ {
+ RETURN( NULL);
+ }
+
+ ChildAfter = NULL;
+ if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
+ {
+ RETURN( NULL);
+ }
+
+ _SEH2_TRY
+ {
+ if(Parent->head.h == Desktop)
+ {
+ HWND *List, *phWnd;
+ PWND TopLevelWindow;
+ BOOLEAN CheckWindowName;
+ BOOLEAN WindowMatches;
+ BOOLEAN ClassMatches;
+
+ /* windows searches through all top-level windows if the parent is the desktop
+ window */
+
+ if((List = IntWinListChildren(Parent)))
+ {
+ phWnd = List;
+
+ if(ChildAfter)
+ {
+ /* skip handles before and including ChildAfter */
+ while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
+ ;
+ }
+
+ CheckWindowName = WindowName.Buffer != 0;
+
+ /* search children */
+ while(*phWnd)
+ {
+ UNICODE_STRING ustr;
+
+ if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
+ {
+ continue;
+ }
+
+ /* Do not send WM_GETTEXT messages in the kernel mode version!
+ The user mode version however calls GetWindowText() which will
+ send WM_GETTEXT messages to windows belonging to its processes */
+ ustr.Buffer = TopLevelWindow->strName.Buffer;
+ ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
+ ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
+ WindowMatches = !CheckWindowName ||
+ (TopLevelWindow->strName.Length < 0xFFFF &&
+ !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
+ ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
+ ClassAtom == TopLevelWindow->pcls->atomClassName;
+
+ if (WindowMatches && ClassMatches)
+ {
+ Ret = TopLevelWindow->head.h;
+ break;
+ }
+
+ if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
+ {
+ /* window returns the handle of the top-level window, in case it found
+ the child window */
+ Ret = TopLevelWindow->head.h;
+ break;
+ }
+
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+ }
+ else
+ {
+ ERR("FindWindowEx: Not Desktop Parent!\n");
+ Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
+ }
+
+ if (Ret == NULL && DoMessageWnd)
+ {
+ PWND MsgWindows;
+
+ if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
+ {
+ Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
+ }
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ Ret = NULL;
+ }
+ _SEH2_END;
+
+ RETURN( Ret);
+
+CLEANUP:
+ TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+/*
+ * @implemented
+ */
+PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
+{
+ PWND WndAncestor, Parent;
+
+ if (Wnd->head.h == IntGetDesktopWindow())
+ {
+ return NULL;
+ }
+
+ switch (Type)
+ {
+ case GA_PARENT:
+ {
+ WndAncestor = Wnd->spwndParent;
+ break;
+ }
+
+ case GA_ROOT:
+ {
+ WndAncestor = Wnd;
+ Parent = NULL;
+
+ for(;;)
+ {
+ if(!(Parent = WndAncestor->spwndParent))
+ {
+ break;
+ }
+ if(IntIsDesktopWindow(Parent))
+ {
+ break;
+ }
+
+ WndAncestor = Parent;
+ }
+ break;
+ }
+
+ case GA_ROOTOWNER:
+ {
+ WndAncestor = Wnd;
+
+ for (;;)
+ {
+ Parent = IntGetParent(WndAncestor);
+
+ if (!Parent)
+ {
+ break;
+ }
+
+ WndAncestor = Parent;
+ }
+ break;
+ }
+
+ default:
+ {
+ return NULL;
+ }
+ }
+
+ return WndAncestor;
+}
+
+/*
+ * @implemented
+ */
+HWND APIENTRY
+NtUserGetAncestor(HWND hWnd, UINT Type)
+{
+ PWND Window, Ancestor;
+ DECLARE_RETURN(HWND);
+
+ TRACE("Enter NtUserGetAncestor\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN(NULL);
+ }
+
+ Ancestor = UserGetAncestor(Window, Type);
+ /* faxme: can UserGetAncestor ever return NULL for a valid window? */
+
+ RETURN(Ancestor ? Ancestor->head.h : NULL);
+
+CLEANUP:
+ TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+////
+//// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
+////
+/* combo state struct */
+typedef struct
+{
+ HWND self;
+ HWND owner;
+ UINT dwStyle;
+ HWND hWndEdit;
+ HWND hWndLBox;
+ UINT wState;
+ HFONT hFont;
+ RECT textRect;
+ RECT buttonRect;
+ RECT droppedRect;
+ INT droppedIndex;
+ INT fixedOwnerDrawHeight;
+ INT droppedWidth; /* last two are not used unless set */
+ INT editHeight; /* explicitly */
+ LONG UIState;
+} HEADCOMBO,*LPHEADCOMBO;
+
+// Window Extra data container.
+typedef struct _WND2CBOX
+{
+ WND;
+ LPHEADCOMBO pCBox;
+} WND2CBOX, *PWND2CBOX;
+
+#define CBF_BUTTONDOWN 0x0002
+////
+////
+////
+BOOL
+APIENTRY
+NtUserGetComboBoxInfo(
+ HWND hWnd,
+ PCOMBOBOXINFO pcbi)
+{
+ PWND Wnd;
+ PPROCESSINFO ppi;
+ BOOL NotSameppi = FALSE;
+ BOOL Ret = TRUE;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserGetComboBoxInfo\n");
+ UserEnterShared();
+
+ if (!(Wnd = UserGetWindowObject(hWnd)))
+ {
+ RETURN( FALSE );
+ }
+ _SEH2_TRY
+ {
+ if(pcbi)
+ {
+ ProbeForWrite(pcbi,
+ sizeof(COMBOBOXINFO),
+ 1);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(RETURN(FALSE));
+ }
+ _SEH2_END;
+
+ if (pcbi->cbSize < sizeof(COMBOBOXINFO))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ RETURN(FALSE);
+ }
+
+ // Pass the user pointer, it was already probed.
+ if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
+ {
+ RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
+ }
+
+ ppi = PsGetCurrentProcessWin32Process();
+ NotSameppi = ppi != Wnd->head.pti->ppi;
+ if (NotSameppi)
+ {
+ KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
+ }
+
+ _SEH2_TRY
+ {
+ LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
+ pcbi->rcItem = lphc->textRect;
+ pcbi->rcButton = lphc->buttonRect;
+ pcbi->stateButton = 0;
+ if (lphc->wState & CBF_BUTTONDOWN)
+ pcbi->stateButton |= STATE_SYSTEM_PRESSED;
+ if (RECTL_bIsEmptyRect(&lphc->buttonRect))
+ pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
+ pcbi->hwndCombo = lphc->self;
+ pcbi->hwndItem = lphc->hWndEdit;
+ pcbi->hwndList = lphc->hWndLBox;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = FALSE;
+ SetLastNtError(_SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ RETURN( Ret);
+
+CLEANUP:
+ if (NotSameppi) KeDetachProcess();
+ TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+////
+//// ReactOS work around! Keep it the sames as in Listbox.c
+////
+/* Listbox structure */
+typedef struct
+{
+ HWND self; /* Our own window handle */
+ HWND owner; /* Owner window to send notifications to */
+ UINT style; /* Window style */
+ INT width; /* Window width */
+ INT height; /* Window height */
+ VOID *items; /* Array of items */
+ INT nb_items; /* Number of items */
+ INT top_item; /* Top visible item */
+ INT selected_item; /* Selected item */
+ INT focus_item; /* Item that has the focus */
+ INT anchor_item; /* Anchor item for extended selection */
+ INT item_height; /* Default item height */
+ INT page_size; /* Items per listbox page */
+ INT column_width; /* Column width for multi-column listboxes */
+} LB_DESCR;
+
+// Window Extra data container.
+typedef struct _WND2LB
+{
+ WND;
+ LB_DESCR * pLBiv;
+} WND2LB, *PWND2LB;
+////
+////
+////
+DWORD
+APIENTRY
+NtUserGetListBoxInfo(
+ HWND hWnd)
+{
+ PWND Wnd;
+ PPROCESSINFO ppi;
+ BOOL NotSameppi = FALSE;
+ DWORD Ret = 0;
+ DECLARE_RETURN(DWORD);
+
+ TRACE("Enter NtUserGetListBoxInfo\n");
+ UserEnterShared();
+
+ if (!(Wnd = UserGetWindowObject(hWnd)))
+ {
+ RETURN( 0 );
+ }
+
+ if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
+ {
+ RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
+ }
+
+ // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
+ ppi = PsGetCurrentProcessWin32Process();
+ NotSameppi = ppi != Wnd->head.pti->ppi;
+ if (NotSameppi)
+ {
+ KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
+ }
+
+ _SEH2_TRY
+ {
+ LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
+ // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
+ if (descr->style & LBS_MULTICOLUMN) //// ReactOS
+ Ret = descr->page_size * descr->column_width;
+ else
+ Ret = descr->page_size;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = 0;
+ SetLastNtError(_SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ RETURN( Ret);
+
+CLEANUP:
+ if (NotSameppi) KeDetachProcess();
+ TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * NtUserSetParent
+ *
+ * The NtUserSetParent function changes the parent window of the specified
+ * child window.
+ *
+ * Remarks
+ * The new parent window and the child window must belong to the same
+ * application. If the window identified by the hWndChild parameter is
+ * visible, the system performs the appropriate redrawing and repainting.
+ * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
+ * or WS_POPUP window styles of the window whose parent is being changed.
+ *
+ * Status
+ * @implemented
+ */
+
+HWND APIENTRY
+NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
+{
+ DECLARE_RETURN(HWND);
+
+ TRACE("Enter NtUserSetParent\n");
+ UserEnterExclusive();
+
+ /*
+ Check Parent first from user space, set it here.
+ */
+ if (!hWndNewParent)
+ {
+ hWndNewParent = IntGetDesktopWindow();
+ }
+ else if (hWndNewParent == HWND_MESSAGE)
+ {
+ hWndNewParent = IntGetMessageWindow();
+ }
+
+ RETURN( co_UserSetParent(hWndChild, hWndNewParent));
+
+CLEANUP:
+ TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * UserGetShellWindow
+ *
+ * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
+ *
+ * Status
+ * @implemented
+ */
+HWND FASTCALL UserGetShellWindow(VOID)
+{
+ PWINSTATION_OBJECT WinStaObject;
+ HWND Ret;
+
+ NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
+ KernelMode,
+ 0,
+ &WinStaObject);
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ return( (HWND)0);
+ }
+
+ Ret = (HWND)WinStaObject->ShellWindow;
+
+ ObDereferenceObject(WinStaObject);
+ return( Ret);
+}
+
+/*
+ * NtUserSetShellWindowEx
+ *
+ * This is undocumented function to set global shell window. The global
+ * shell window has special handling of window position.
+ *
+ * Status
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
+{
+ PWINSTATION_OBJECT WinStaObject;
+ PWND WndShell, WndListView;
+ DECLARE_RETURN(BOOL);
+ USER_REFERENCE_ENTRY Ref;
+ NTSTATUS Status;
+ PTHREADINFO ti;
+
+ TRACE("Enter NtUserSetShellWindowEx\n");
+ UserEnterExclusive();
+
+ if (!(WndShell = UserGetWindowObject(hwndShell)))
+ {
+ RETURN(FALSE);
+ }
+
+ if(!(WndListView = UserGetWindowObject(hwndListView)))
+ {
+ RETURN(FALSE);
+ }
+
+ Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
+ KernelMode,
+ 0,
+ &WinStaObject);
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( FALSE);
+ }
+
+ /*
+ * Test if we are permitted to change the shell window.
+ */
+ if (WinStaObject->ShellWindow)
+ {
+ ObDereferenceObject(WinStaObject);
+ RETURN( FALSE);
+ }
+
+ /*
+ * Move shell window into background.
+ */
+ if (hwndListView && hwndListView != hwndShell)
+ {
+ /*
+ * Disabled for now to get Explorer working.
+ * -- Filip, 01/nov/2003
+ */
+#if 0
+ co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
+#endif
+
+ if (WndListView->ExStyle & WS_EX_TOPMOST)
+ {
+ ObDereferenceObject(WinStaObject);
+ RETURN( FALSE);
+ }
+ }
+
+ if (WndShell->ExStyle & WS_EX_TOPMOST)
+ {
+ ObDereferenceObject(WinStaObject);
+ RETURN( FALSE);
+ }
+
+ UserRefObjectCo(WndShell, &Ref);
+ WndShell->state2 |= WNDS2_BOTTOMMOST;
+ co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
+
+ WinStaObject->ShellWindow = hwndShell;
+ WinStaObject->ShellListView = hwndListView;
+
+ ti = GetW32ThreadInfo();
+ if (ti->pDeskInfo)
+ {
+ ti->pDeskInfo->hShellWindow = hwndShell;
+ ti->pDeskInfo->spwndShell = WndShell;
+ ti->pDeskInfo->ppiShellProcess = ti->ppi;
+ }
+
+ UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE);
+
+ UserDerefObjectCo(WndShell);
+
+ ObDereferenceObject(WinStaObject);
+ RETURN( TRUE);
+
+CLEANUP:
+ TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+// Fixes wine Win test_window_styles and todo tests...
+static BOOL FASTCALL
+IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
+{
+ if (ExStyle & WS_EX_DLGMODALFRAME)
+ return TRUE;
+ else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+LONG FASTCALL
+co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
+{
+ PWND Window, Parent;
+ PWINSTATION_OBJECT WindowStation;
+ LONG OldValue;
+ STYLESTRUCT Style;
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ return( 0);
+ }
+
+ if ((INT)Index >= 0)
+ {
+ if ((Index + sizeof(LONG)) > Window->cbwndExtra)
+ {
+ EngSetLastError(ERROR_INVALID_INDEX);
+ return( 0);
+ }
+
+ OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
+/*
+ if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
+ {
+ OldValue = (LONG)IntSetWindowProc( Wnd,
+ (WNDPROC)NewValue,
+ Ansi);
+ if (!OldValue) return 0;
+ }
+*/
+ *((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
+ }
+ else
+ {
+ switch (Index)
+ {
+ case GWL_EXSTYLE:
+ OldValue = (LONG) Window->ExStyle;
+ Style.styleOld = OldValue;
+ Style.styleNew = NewValue;
+
+ co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
+
+ /*
+ * Remove extended window style bit WS_EX_TOPMOST for shell windows.
+ */
+ WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
+ if(WindowStation)
+ {
+ if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
+ Style.styleNew &= ~WS_EX_TOPMOST;
+ }
+ /* WS_EX_WINDOWEDGE depends on some other styles */
+ if (IntCheckFrameEdge(Window->style, NewValue))
+ Style.styleNew |= WS_EX_WINDOWEDGE;
+ else
+ Style.styleNew &= ~WS_EX_WINDOWEDGE;
+
+ Window->ExStyle = (DWORD)Style.styleNew;
+ co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
+ break;
+
+ case GWL_STYLE:
+ OldValue = (LONG) Window->style;
+ Style.styleOld = OldValue;
+ Style.styleNew = NewValue;
+ co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
+
+ /* WS_CLIPSIBLINGS can't be reset on top-level windows */
+ if (Window->spwndParent == UserGetDesktopWindow()) Style.styleNew |= WS_CLIPSIBLINGS;
+ /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
+ if (IntCheckFrameEdge(NewValue, Window->ExStyle))
+ Window->ExStyle |= WS_EX_WINDOWEDGE;
+ else
+ Window->ExStyle &= ~WS_EX_WINDOWEDGE;
+
+ if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
+ {
+ if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
+ if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
+ DceResetActiveDCEs( Window );
+ }
+ Window->style = (DWORD)Style.styleNew;
+ co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
+ break;
+
+ case GWL_WNDPROC:
+ {
+ if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
+ Window->fnid & FNID_FREED)
+ {
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ return( 0);
+ }
+ OldValue = (LONG)IntSetWindowProc(Window,
+ (WNDPROC)NewValue,
+ Ansi);
+ break;
+ }
+
+ case GWL_HINSTANCE:
+ OldValue = (LONG) Window->hModule;
+ Window->hModule = (HINSTANCE) NewValue;
+ break;
+
+ case GWL_HWNDPARENT:
+ Parent = Window->spwndParent;
+ if (Parent && (Parent->head.h == IntGetDesktopWindow()))
+ OldValue = (LONG) IntSetOwner(Window->head.h, (HWND) NewValue);
+ else
+ OldValue = (LONG) co_UserSetParent(Window->head.h, (HWND) NewValue);
+ break;
+
+ case GWL_ID:
+ OldValue = (LONG) Window->IDMenu;
+ Window->IDMenu = (UINT) NewValue;
+ break;
+
+ case GWL_USERDATA:
+ OldValue = Window->dwUserData;
+ Window->dwUserData = NewValue;
+ break;
+
+ default:
+ ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
+ EngSetLastError(ERROR_INVALID_INDEX);
+ OldValue = 0;
+ break;
+ }
+ }
+
+ return( OldValue);
+}
+
+/*
+ * NtUserSetWindowLong
+ *
+ * The NtUserSetWindowLong function changes an attribute of the specified
+ * window. The function also sets the 32-bit (long) value at the specified
+ * offset into the extra window memory.
+ *
+ * Status
+ * @implemented
+ */
+
+LONG APIENTRY
+NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
+{
+ DECLARE_RETURN(LONG);
+
+ TRACE("Enter NtUserSetWindowLong\n");
+ UserEnterExclusive();
+
+ if (hWnd == IntGetDesktopWindow())
+ {
+ EngSetLastError(STATUS_ACCESS_DENIED);
+ RETURN( 0);
+ }
+
+ RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
+
+CLEANUP:
+ TRACE("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * NtUserSetWindowWord
+ *
+ * Legacy function similar to NtUserSetWindowLong.
+ *
+ * Status
+ * @implemented
+ */
+
+WORD APIENTRY
+NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
+{
+ PWND Window;
+ WORD OldValue;
+ DECLARE_RETURN(WORD);
+
+ TRACE("Enter NtUserSetWindowWord\n");
+ UserEnterExclusive();
+
+ if (hWnd == IntGetDesktopWindow())
+ {
+ EngSetLastError(STATUS_ACCESS_DENIED);
+ RETURN( 0);
+ }
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN( 0);
+ }
+
+ switch (Index)
+ {
+ case GWL_ID:
+ case GWL_HINSTANCE:
+ case GWL_HWNDPARENT:
+ RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
+ default:
+ if (Index < 0)
+ {
+ EngSetLastError(ERROR_INVALID_INDEX);
+ RETURN( 0);
+ }
+ }
+
+ if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ RETURN( 0);
+ }
+
+ OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
+ *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
+
+ RETURN( OldValue);
+
+CLEANUP:
+ TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ QueryWindow based on KJK::Hyperion and James Tabor.
+
+ 0 = QWUniqueProcessId
+ 1 = QWUniqueThreadId
+ 2 = QWActiveWindow
+ 3 = QWFocusWindow
+ 4 = QWIsHung Implements IsHungAppWindow found
+ by KJK::Hyperion.
+
+ 9 = QWKillWindow When I called this with hWnd ==
+ DesktopWindow, it shutdown the system
+ and rebooted.
+*/
+/*
+ * @implemented
+ */
+DWORD APIENTRY
+NtUserQueryWindow(HWND hWnd, DWORD Index)
+{
+/* Console Leader Process CID Window offsets */
+#define GWLP_CONSOLE_LEADER_PID 0
+#define GWLP_CONSOLE_LEADER_TID 4
+
+ PWND pWnd;
+ DWORD Result;
+ DECLARE_RETURN(UINT);
+
+ TRACE("Enter NtUserQueryWindow\n");
+ UserEnterShared();
+
+ if (!(pWnd = UserGetWindowObject(hWnd)))
+ {
+ RETURN( 0);
+ }
+
+ switch(Index)
+ {
+ case QUERY_WINDOW_UNIQUE_PROCESS_ID:
+ {
+ if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
+ (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
+ {
+ // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
+ Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
+ }
+ else
+ {
+ Result = (DWORD)IntGetWndProcessId(pWnd);
+ }
+ break;
+ }
+
+ case QUERY_WINDOW_UNIQUE_THREAD_ID:
+ {
+ if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
+ (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
+ {
+ // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
+ Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
+ }
+ else
+ {
+ Result = (DWORD)IntGetWndThreadId(pWnd);
+ }
+ break;
+ }
+
+ case QUERY_WINDOW_ACTIVE:
+ Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
+ break;
+
+ case QUERY_WINDOW_FOCUS:
+ Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
+ break;
+
+ case QUERY_WINDOW_ISHUNG:
+ Result = (DWORD)MsqIsHung(pWnd->head.pti);
+ break;
+
+ case QUERY_WINDOW_REAL_ID:
+ Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
+ break;
+
+ case QUERY_WINDOW_FOREGROUND:
+ Result = (pWnd->head.pti->MessageQueue == gpqForeground);
+ break;
+
+ default:
+ Result = (DWORD)NULL;
+ break;
+ }
+
+ RETURN( Result);
+
+CLEANUP:
+ TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+/*
+ * @implemented
+ */
+UINT APIENTRY
+NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
+{
+ UNICODE_STRING SafeMessageName;
+ NTSTATUS Status;
+ UINT Ret;
+ DECLARE_RETURN(UINT);
+
+ TRACE("Enter NtUserRegisterWindowMessage\n");
+ UserEnterExclusive();
+
+ if(MessageNameUnsafe == NULL)
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ RETURN( 0);
+ }
+
+ Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( 0);
+ }
+
+ Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
+ if (SafeMessageName.Buffer)
+ ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
+ RETURN( Ret);
+
+CLEANUP:
+ TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserSetMenu(
+ HWND hWnd,
+ HMENU Menu,
+ BOOL Repaint)
+{
+ PWND Window;
+ BOOL Changed;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserSetMenu\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ RETURN( FALSE);
+ }
+
+ if (! IntSetMenu(Window, Menu, &Changed))
+ {
+ RETURN( FALSE);
+ }
+
+ if (Changed && Repaint)
+ {
+ USER_REFERENCE_ENTRY Ref;
+
+ UserRefObjectCo(Window, &Ref);
+ co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
+
+ UserDerefObjectCo(Window);
+ }
+
+ RETURN( TRUE);
+
+CLEANUP:
+ TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserSetWindowFNID(HWND hWnd,
+ WORD fnID)
+{
+ PWND Wnd;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserSetWindowFNID\n");
+ UserEnterExclusive();
+
+ if (!(Wnd = UserGetWindowObject(hWnd)))
+ {
+ RETURN( FALSE);
+ }
+
+ if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
+ {
+ EngSetLastError(ERROR_ACCESS_DENIED);
+ RETURN( FALSE);
+ }
+
+ // From user land we only set these.
+ if (fnID != FNID_DESTROY)
+ { // Hacked so we can mark desktop~!
+ if ( (/*(fnID < FNID_BUTTON)*/ (fnID < FNID_FIRST) && (fnID > FNID_GHOST)) ||
+ Wnd->fnid != 0 )
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ RETURN( FALSE);
+ }
+ }
+
+ Wnd->fnid |= fnID;
+ RETURN( TRUE);
+
+CLEANUP:
+ TRACE("Leave NtUserSetWindowFNID\n");
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * NtUserDefSetText
+ *
+ * Undocumented function that is called from DefWindowProc to set
+ * window text.
+ *
+ * Status
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
+{
+ PWND Wnd;
+ LARGE_STRING SafeText;
+ UNICODE_STRING UnicodeString;
+ BOOL Ret = TRUE;
+
+ TRACE("Enter NtUserDefSetText\n");
+
+ if (WindowText != NULL)
+ {
+ _SEH2_TRY
+ {
+ SafeText = ProbeForReadLargeString(WindowText);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = FALSE;
+ SetLastNtError(_SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ if (!Ret)
+ return FALSE;
+ }
+ else
+ return TRUE;
+
+ UserEnterExclusive();
+
+ if(!(Wnd = UserGetWindowObject(hWnd)))
+ {
+ UserLeave();
+ return FALSE;
+ }
+
+ // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
+ // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
+ // Now we know what the bAnsi is for.
+ RtlInitUnicodeString(&UnicodeString, NULL);
+ if (SafeText.Buffer)
+ {
+ _SEH2_TRY
+ {
+ if (SafeText.bAnsi)
+ ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
+ else
+ ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
+ Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Ret = FALSE;
+ SetLastNtError(_SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+ if (!Ret) goto Exit;
+ }
+
+ if (UnicodeString.Length != 0)
+ {
+ if (Wnd->strName.MaximumLength > 0 &&
+ UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
+ {
+ ASSERT(Wnd->strName.Buffer != NULL);
+
+ Wnd->strName.Length = UnicodeString.Length;
+ Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
+ RtlCopyMemory(Wnd->strName.Buffer,
+ UnicodeString.Buffer,
+ UnicodeString.Length);
+ }
+ else
+ {
+ PWCHAR buf;
+ Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
+ buf = Wnd->strName.Buffer;
+ Wnd->strName.Buffer = NULL;
+ if (buf != NULL)
+ {
+ DesktopHeapFree(Wnd->head.rpdesk, buf);
+ }
+
+ Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
+ UnicodeString.Length + sizeof(UNICODE_NULL));
+ if (Wnd->strName.Buffer != NULL)
+ {
+ Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
+ RtlCopyMemory(Wnd->strName.Buffer,
+ UnicodeString.Buffer,
+ UnicodeString.Length);
+ Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
+ Wnd->strName.Length = UnicodeString.Length;
+ }
+ else
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ Ret = FALSE;
+ goto Exit;
+ }
+ }
+ }
+ else
+ {
+ Wnd->strName.Length = 0;
+ if (Wnd->strName.Buffer != NULL)
+ Wnd->strName.Buffer[0] = L'\0';
+ }
+
+ // FIXME: HAX! Windows does not do this in here!
+ // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
+ // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
+ /* Send shell notifications */
+ if (!Wnd->spwndOwner && !IntGetParent(Wnd))
+ {
+ co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
+ }
+
+ Ret = TRUE;
+Exit:
+ if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
+ TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
+ UserLeave();
+ return Ret;
+}
+
+/*
+ * NtUserInternalGetWindowText
+ *
+ * Status
+ * @implemented
+ */
+
+INT APIENTRY
+NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
+{
+ PWND Wnd;
+ NTSTATUS Status;
+ INT Result;
+ DECLARE_RETURN(INT);
+
+ TRACE("Enter NtUserInternalGetWindowText\n");
+ UserEnterShared();
+
+ if(lpString && (nMaxCount <= 1))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ RETURN( 0);
+ }
+
+ if(!(Wnd = UserGetWindowObject(hWnd)))
+ {
+ RETURN( 0);
+ }
+
+ Result = Wnd->strName.Length / sizeof(WCHAR);
+ if(lpString)
+ {
+ const WCHAR Terminator = L'\0';
+ INT Copy;
+ WCHAR *Buffer = (WCHAR*)lpString;
+
+ Copy = min(nMaxCount - 1, Result);
+ if(Copy > 0)
+ {
+ Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( 0);
+ }
+ Buffer += Copy;
+ }
+
+ Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( 0);
+ }
+
+ Result = Copy;
+ }
+
+ RETURN( Result);
+
+CLEANUP:
+ TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ API Call
+*/
+BOOL
+FASTCALL
+IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
+{
+ int count = 0;
+ PWND pWnd;
+ HWND *win_array;
+
+// ASSERT(OwnerWnd);
+
+ TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
+ win_array = IntWinListChildren(OwnerWnd);
+
+ if (!win_array)
+ return TRUE;
+
+ while (win_array[count])
+ count++;
+ while (--count >= 0)
+ {
+ if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
+ continue;
+ if (pWnd->spwndOwner != OwnerWnd)
+ continue;
+
+ if (fShow)
+ {
+ if (pWnd->state & WNDS_HIDDENPOPUP)
+ {
+ /* In Windows, ShowOwnedPopups(TRUE) generates
+ * WM_SHOWWINDOW messages with SW_PARENTOPENING,
+ * regardless of the state of the owner
+ */
+ co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
+ continue;
+ }
+ }
+ else
+ {
+ if (pWnd->style & WS_VISIBLE)
+ {
+ /* In Windows, ShowOwnedPopups(FALSE) generates
+ * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
+ * regardless of the state of the owner
+ */
+ co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
+ continue;
+ }
+ }
+
+ }
+ ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST);
+ TRACE("Leave ShowOwnedPopups\n");
+ return TRUE;
+}
+
+/* EOF */
--- /dev/null
- // This helps with bug 6751 forcing modal dialog active when another app is minimized or closed.
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS kernel
+ * PURPOSE: Windows
+ * FILE: subsystems/win32/win32k/ntuser/window.c
+ * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ */
+
+#include <win32k.h>
+DBG_DEFAULT_CHANNEL(UserWinpos);
+
+/* GLOBALS *******************************************************************/
+
+#define MINMAX_NOSWP (0x00010000)
+
+#define SWP_EX_NOCOPY 0x0001
+#define SWP_EX_PAINTSELF 0x0002
+
+#define SWP_AGG_NOGEOMETRYCHANGE \
+ (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
+#define SWP_AGG_NOPOSCHANGE \
+ (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
+#define SWP_AGG_STATUSFLAGS \
+ (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
+
+#define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1)
+#define PLACE_MIN 0x0001
+#define PLACE_MAX 0x0002
+#define PLACE_RECT 0x0004
+
+VOID FASTCALL IntLinkWindow(PWND Wnd,PWND WndInsertAfter);
+
+/* FUNCTIONS *****************************************************************/
+
+BOOL FASTCALL
+IntGetClientOrigin(PWND Window OPTIONAL, LPPOINT Point)
+{
+ Window = Window ? Window : UserGetDesktopWindow();
+ if (Window == NULL)
+ {
+ Point->x = Point->y = 0;
+ return FALSE;
+ }
+ Point->x = Window->rcClient.left;
+ Point->y = Window->rcClient.top;
+
+ return TRUE;
+}
+
+/*!
+ * Internal function.
+ * Returns client window rectangle relative to the upper-left corner of client area.
+ *
+ * \note Does not check the validity of the parameters
+*/
+VOID FASTCALL
+IntGetClientRect(PWND Wnd, RECTL *Rect)
+{
+ ASSERT( Wnd );
+ ASSERT( Rect );
+ if (Wnd->style & WS_MINIMIZED)
+ {
+ Rect->left = Rect->top = 0;
+ Rect->right = UserGetSystemMetrics(SM_CXMINIMIZED);
+ Rect->bottom = UserGetSystemMetrics(SM_CYMINIMIZED);
+ return;
+ }
+ if ( Wnd != UserGetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP )
+ {
+ *Rect = Wnd->rcClient;
+ RECTL_vOffsetRect(Rect, -Wnd->rcClient.left, -Wnd->rcClient.top);
+ }
+ else
+ {
+ Rect->left = Rect->top = 0;
+ Rect->right = Wnd->rcClient.right;
+ Rect->bottom = Wnd->rcClient.bottom;
+ /* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
+ Rect->right = UserGetSystemMetrics(SM_CXSCREEN);
+ Rect->bottom = UserGetSystemMetrics(SM_CYSCREEN);
+ */
+ }
+}
+
+INT FASTCALL
+IntMapWindowPoints(PWND FromWnd, PWND ToWnd, LPPOINT lpPoints, UINT cPoints)
+{
+ BOOL mirror_from, mirror_to;
+ POINT Delta;
+ UINT i;
+ int Change = 1;
+
+ /* Note: Desktop Top and Left is always 0! */
+ Delta.x = Delta.y = 0;
+ mirror_from = mirror_to = FALSE;
+
+ if (FromWnd && FromWnd != UserGetDesktopWindow()) // FromWnd->fnid != FNID_DESKTOP)
+ {
+ if (FromWnd->ExStyle & WS_EX_LAYOUTRTL)
+ {
+ mirror_from = TRUE;
+ Change = -Change;
+ Delta.x = -FromWnd->rcClient.right;
+ }
+ else
+ Delta.x = FromWnd->rcClient.left;
+ Delta.y = FromWnd->rcClient.top;
+ }
+
+ if (ToWnd && ToWnd != UserGetDesktopWindow()) // ToWnd->fnid != FNID_DESKTOP)
+ {
+ if (ToWnd->ExStyle & WS_EX_LAYOUTRTL)
+ {
+ mirror_to = TRUE;
+ Change = -Change;
+ Delta.x += Change * ToWnd->rcClient.right;
+ }
+ else
+ Delta.x -= Change * ToWnd->rcClient.left;
+ Delta.y -= ToWnd->rcClient.top;
+ }
+
+ for (i = 0; i != cPoints; i++)
+ {
+ lpPoints[i].x += Delta.x;
+ lpPoints[i].x *= Change;
+ lpPoints[i].y += Delta.y;
+ }
+
+ if ((mirror_from || mirror_to) && cPoints == 2) /* special case for rectangle */
+ {
+ int tmp = min(lpPoints[0].x, lpPoints[1].x);
+ lpPoints[1].x = max(lpPoints[0].x, lpPoints[1].x);
+ lpPoints[0].x = tmp;
+ }
+
+ return MAKELONG(LOWORD(Delta.x), LOWORD(Delta.y));
+}
+
+BOOL FASTCALL
+IntClientToScreen(PWND Wnd, LPPOINT lpPoint)
+{
+ if (Wnd && Wnd->fnid != FNID_DESKTOP )
+ {
+ if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
+ lpPoint->x = Wnd->rcClient.right - lpPoint->x;
+ else
+ lpPoint->x += Wnd->rcClient.left;
+ lpPoint->y += Wnd->rcClient.top;
+ }
+ return TRUE;
+}
+
+BOOL FASTCALL
+IntScreenToClient(PWND Wnd, LPPOINT lpPoint)
+{
+ if (Wnd && Wnd->fnid != FNID_DESKTOP )
+ {
+ if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
+ lpPoint->x = Wnd->rcClient.right - lpPoint->x;
+ else
+ lpPoint->x -= Wnd->rcClient.left;
+ lpPoint->y -= Wnd->rcClient.top;
+ }
+ return TRUE;
+}
+
+BOOL FASTCALL IsChildVisible(PWND pWnd)
+{
+ do
+ {
+ if ( (pWnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD ||
+ !(pWnd = pWnd->spwndParent) )
+ return TRUE;
+ }
+ while (pWnd->style & WS_VISIBLE);
+ return FALSE;
+}
+
+PWND FASTCALL IntGetLastTopMostWindow(VOID)
+{
+ PWND pWnd;
+ PDESKTOP rpdesk = gptiCurrent->rpdesk;
+
+ if ( rpdesk &&
+ (pWnd = rpdesk->pDeskInfo->spwnd->spwndChild) &&
+ pWnd->ExStyle & WS_EX_TOPMOST)
+ {
+ for (;;)
+ {
+ if (!pWnd->spwndNext) break;
+ if (!(pWnd->spwndNext->ExStyle & WS_EX_TOPMOST)) break;
+ pWnd = pWnd->spwndNext;
+ }
+ return pWnd;
+ }
+ return NULL;
+}
+
+//
- UINT
- FASTCALL
- co_WinPosArrangeIconicWindows(PWND parent)
- {
- RECTL rectParent;
- INT i, x, y, xspacing, yspacing, sx, sy;
- HWND *List = IntWinListChildren(parent);
-
- ASSERT_REFS_CO(parent);
-
- /* Check if we found any children */
- if(List == NULL)
- {
- return 0;
- }
-
- IntGetClientRect( parent, &rectParent );
- // FIXME: Support gspv.mm.iArrange.
- x = rectParent.left;
- y = rectParent.bottom;
-
- xspacing = (UserGetSystemMetrics(SM_CXMINSPACING)/2)+UserGetSystemMetrics(SM_CXBORDER);
- yspacing = (UserGetSystemMetrics(SM_CYMINSPACING)/2)+UserGetSystemMetrics(SM_CYBORDER);
-
- //ERR("X:%d Y:%d XS:%d YS:%d\n",x,y,xspacing,yspacing);
-
- for(i = 0; List[i]; i++)
- {
- PWND Child;
-
- if (!(Child = ValidateHwndNoErr(List[i])))
- continue;
-
- if((Child->style & WS_MINIMIZE) != 0 )
- {
- USER_REFERENCE_ENTRY Ref;
- UserRefObjectCo(Child, &Ref);
-
- sx = x + UserGetSystemMetrics(SM_CXBORDER);
- sy = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
-
- co_WinPosSetWindowPos( Child, 0, sx, sy, 0, 0,
- SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
-
- Child->InternalPos.IconPos.x = sx;
- Child->InternalPos.IconPos.y = sy;
- Child->InternalPos.flags |= WPF_MININIT;
- Child->InternalPos.flags &= ~WPF_SETMINPOSITION;
-
- UserDerefObjectCo(Child);
-
- if (x <= (rectParent.right - UserGetSystemMetrics(SM_CXMINSPACING)))
- x += xspacing;
- else
- {
- x = rectParent.left;
- y -= yspacing;
- }
- //ERR("X:%d Y:%d\n",x,y);
- }
- }
- ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
- return yspacing;
- }
-
- static VOID FASTCALL
- WinPosFindIconPos(PWND Window, POINT *Pos)
- {
- RECT rectParent;
- PWND pwndChild, pwndParent;
- int x, y, xspacing, yspacing;
-
- pwndParent = Window->spwndParent;
- if (pwndParent == UserGetDesktopWindow())
- {
- //ERR("Parent is Desktop, Min off screen!\n");
- /* ReactOS doesn't support iconic minimize to desktop */
- Pos->x = Pos->y = -32000;
- Window->InternalPos.flags |= WPF_MININIT;
- Window->InternalPos.IconPos.x = Pos->x;
- Window->InternalPos.IconPos.y = Pos->y;
- return;
- }
-
- IntGetClientRect( pwndParent, &rectParent );
- // FIXME: Support gspv.mm.iArrange.
- x = rectParent.left;
- y = rectParent.bottom;
-
- xspacing = (UserGetSystemMetrics(SM_CXMINSPACING)/2)+UserGetSystemMetrics(SM_CXBORDER);
- yspacing = (UserGetSystemMetrics(SM_CYMINSPACING)/2)+UserGetSystemMetrics(SM_CYBORDER);
-
- //ERR("X:%d Y:%d XS:%d YS:%d\n",Pos->x,Pos->y,xspacing,yspacing);
-
- // Set to default position when minimized.
- Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
- Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
-
- for (pwndChild = pwndParent->spwndChild; pwndChild; pwndChild = pwndChild->spwndNext)
- {
- if (pwndChild == Window) continue;
-
- if (pwndChild->style & WS_VISIBLE)
- {
- //ERR("Loop!\n");
- continue;
- }
- //ERR("Pos Child X %d Y %d!\n", pwndChild->InternalPos.IconPos.x, pwndChild->InternalPos.IconPos.y);
- if ( pwndChild->InternalPos.IconPos.x == Pos->x &&
- pwndChild->InternalPos.IconPos.y == Pos->y )
- {
- if (x <= rectParent.right - UserGetSystemMetrics(SM_CXMINSPACING))
- x += xspacing;
- else
- {
- x = rectParent.left;
- y -= yspacing;
- }
- Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
- Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
- }
- }
- Window->InternalPos.IconPos.x = Pos->x;
- Window->InternalPos.IconPos.y = Pos->y;
- Window->InternalPos.flags |= WPF_MININIT;
- //ERR("Position is set! X:%d Y:%d\n",Pos->x,Pos->y);
- return;
- }
-
++// This helps with CORE-6129 forcing modal dialog active when another app is minimized or closed.
+//
+BOOL FASTCALL ActivateOtherWindowMin(PWND Wnd)
+{
+ BOOL ActivePrev, FindTopWnd;
+ PWND pWndTopMost, pWndChild, pWndSetActive, pWndTemp, pWndDesk;
+ USER_REFERENCE_ENTRY Ref;
+ PTHREADINFO pti = gptiCurrent;
+
+ //ERR("AOWM 1\n");
+ ActivePrev = (pti->MessageQueue->spwndActivePrev != NULL);
+ FindTopWnd = TRUE;
+
+ if ((pWndTopMost = IntGetLastTopMostWindow()))
+ pWndChild = pWndTopMost->spwndNext;
+ else
+ pWndChild = Wnd->spwndParent->spwndChild;
+
+ for (;;)
+ {
+ if ( ActivePrev )
+ pWndSetActive = pti->MessageQueue->spwndActivePrev;
+ else
+ pWndSetActive = pWndChild;
+
+ pWndTemp = NULL;
+
+ while(pWndSetActive)
+ {
+ if ( VerifyWnd(pWndSetActive) &&
+ !(pWndSetActive->ExStyle & WS_EX_NOACTIVATE) &&
+ (pWndSetActive->style & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE &&
+ (!(pWndSetActive->style & WS_ICONIC) /* FIXME MinMax pos? */ ) )
+ {
+ if (!(pWndSetActive->ExStyle & WS_EX_TOOLWINDOW) )
+ {
+ UserRefObjectCo(pWndSetActive, &Ref);
+ //ERR("ActivateOtherWindowMin Set FG 1\n");
+ co_IntSetForegroundWindow(pWndSetActive);
+ UserDerefObjectCo(pWndSetActive);
+ //ERR("AOWM 2 Exit Good\n");
+ return TRUE;
+ }
+ if (!pWndTemp ) pWndTemp = pWndSetActive;
+ }
+ if ( ActivePrev )
+ {
+ ActivePrev = FALSE;
+ pWndSetActive = pWndChild;
+ }
+ else
+ pWndSetActive = pWndSetActive->spwndNext;
+ }
+
+ if ( !FindTopWnd ) break;
+ FindTopWnd = FALSE;
+
+ if ( pWndChild )
+ {
+ pWndChild = pWndChild->spwndParent->spwndChild;
+ continue;
+ }
+
+ if (!(pWndDesk = IntGetThreadDesktopWindow(pti)))
+ {
+ pWndChild = NULL;
+ continue;
+ }
+ pWndChild = pWndDesk->spwndChild;
+ }
+
+ if ((pWndSetActive = pWndTemp))
+ {
+ UserRefObjectCo(pWndSetActive, &Ref);
+ //ERR("ActivateOtherWindowMin Set FG 2\n");
+ co_IntSetForegroundWindow(pWndSetActive);
+ UserDerefObjectCo(pWndSetActive);
+ //ERR("AOWM 3 Exit Good\n");
+ return TRUE;
+ }
+ //ERR("AOWM 4 Bad\n");
+ return FALSE;
+}
+
+/*******************************************************************
+ * can_activate_window
+ *
+ * Check if we can activate the specified window.
+ */
+static
+BOOL FASTCALL can_activate_window( PWND Wnd OPTIONAL)
+{
+ LONG style;
+
+ if (!Wnd) return FALSE;
+
+ style = Wnd->style;
+ if (!(style & WS_VISIBLE)) return FALSE;
+ if (style & WS_MINIMIZE) return FALSE;
+ if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
+ return TRUE;
+ /* FIXME: This window could be disable because the child that closed
+ was a popup. */
+ //return !(style & WS_DISABLED);
+}
+
+
+/*******************************************************************
+ * WinPosActivateOtherWindow
+ *
+ * Activates window other than pWnd.
+ */
+VOID FASTCALL
+co_WinPosActivateOtherWindow(PWND Wnd)
+{
+ PWND WndTo = NULL;
+ USER_REFERENCE_ENTRY Ref;
+
+ ASSERT_REFS_CO(Wnd);
+
+ if (IntIsDesktopWindow(Wnd))
+ {
+ IntSetFocusMessageQueue(NULL);
+ return;
+ }
+
+ /* If this is popup window, try to activate the owner first. */
+ if ((Wnd->style & WS_POPUP) && (WndTo = Wnd->spwndOwner))
+ {
+ WndTo = UserGetAncestor( WndTo, GA_ROOT );
+ if (can_activate_window(WndTo)) goto done;
+ }
+
+ /* Pick a next top-level window. */
+ /* FIXME: Search for non-tooltip windows first. */
+ WndTo = Wnd;
+ for (;;)
+ {
+ if (!(WndTo = WndTo->spwndNext)) break;
+ if (can_activate_window( WndTo )) break;
+ }
+
+done:
+
+ if (WndTo) UserRefObjectCo(WndTo, &Ref);
+
+ if (!gpqForeground || Wnd == gpqForeground->spwndActive)
+ {
+ /* ReactOS can pass WndTo = NULL to co_IntSetForegroundWindow and returns FALSE. */
+ //ERR("WinPosActivateOtherWindow Set FG 0x%p\n",WndTo);
+ if (co_IntSetForegroundWindow(WndTo))
+ {
+ if (WndTo) UserDerefObjectCo(WndTo);
+ return;
+ }
+ }
+ //ERR("WinPosActivateOtherWindow Set Active 0x%p\n",WndTo);
+ if (!co_IntSetActiveWindow(WndTo,FALSE,TRUE,FALSE)) /* Ok for WndTo to be NULL here */
+ {
+ co_IntSetActiveWindow(NULL,FALSE,TRUE,FALSE);
+ }
+ if (WndTo) UserDerefObjectCo(WndTo);
+}
+
- co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE |
- RDW_NOINTERNALPAINT);
+VOID FASTCALL
+WinPosInitInternalPos(PWND Wnd, RECTL *RestoreRect)
+{
+ POINT Size;
+ RECTL Rect = *RestoreRect;
+
+ if (Wnd->spwndParent != UserGetDesktopWindow())
+ {
+ RECTL_vOffsetRect(&Rect,
+ -Wnd->spwndParent->rcClient.left,
+ -Wnd->spwndParent->rcClient.top);
+ }
+
+ Size.x = Rect.left;
+ Size.y = Rect.top;
+
+ if (!Wnd->InternalPosInitialized)
+ {
+ // FIXME: Use check point Atom..
+ Wnd->InternalPos.flags = 0;
+ Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1;
+ Wnd->InternalPos.IconPos.x = Wnd->InternalPos.IconPos.y = -1;
+ Wnd->InternalPos.NormalRect = Rect;
+ Wnd->InternalPosInitialized = TRUE;
+ }
+
+ if (Wnd->style & WS_MINIMIZE)
+ {
+ Wnd->InternalPos.IconPos = Size;
+ Wnd->InternalPos.flags |= WPF_MININIT;
+ }
+ else if (Wnd->style & WS_MAXIMIZE)
+ {
+ Wnd->InternalPos.flags |= WPF_MAXINIT;
+
+ if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd )
+ {
+ if (Wnd->state & WNDS_MAXIMIZESTOMONITOR)
+ {
+ Wnd->InternalPos.flags &= ~WPF_MAXINIT;
+ Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1;
+ }
+ else
+ {
+ RECTL WorkArea;
+ PMONITOR pmonitor = UserMonitorFromRect(&Rect, MONITOR_DEFAULTTOPRIMARY );
+ // FIXME: support DPI aware, rcWorkDPI/Real etc..
+ WorkArea = pmonitor->rcMonitor;
+
+ if (Wnd->style & WS_MAXIMIZEBOX)
+ { // Support (Wnd->state & WNDS_HASCAPTION) || pmonitor->cFullScreen too.
+ if ((Wnd->style & WS_CAPTION) == WS_CAPTION || !(Wnd->style & (WS_CHILD | WS_POPUP)))
+ {
+ WorkArea = pmonitor->rcWork;
+ //ERR("rcWork\n");
+ }
+ }
+
+ Wnd->InternalPos.MaxPos.x = Rect.left - WorkArea.left;
+ Wnd->InternalPos.MaxPos.y = Rect.top - WorkArea.top;
+
+ /*ERR("WinPosIP 2 X %d = R.l %d - W.l %d | Y %d = R.t %d - W.t %d\n",
+ Wnd->InternalPos.MaxPos.x,
+ Rect.left, WorkArea.left,
+ Wnd->InternalPos.MaxPos.y,
+ Rect.top, WorkArea.top);*/
+ }
+ }
+ else
+ Wnd->InternalPos.MaxPos = Size;
+ }
+ else
+ {
+ Wnd->InternalPos.NormalRect = Rect;
+ }
+}
+
+BOOL
+FASTCALL
+IntGetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *lpwndpl)
+{
+ if (!Wnd) return FALSE;
+
+ if(lpwndpl->length != sizeof(WINDOWPLACEMENT))
+ {
+ return FALSE;
+ }
+
+ lpwndpl->flags = 0;
+
+ WinPosInitInternalPos(Wnd, &Wnd->rcWindow);
+
+ lpwndpl->showCmd = SW_HIDE;
+
+ if ( Wnd->style & WS_MINIMIZE )
+ lpwndpl->showCmd = SW_SHOWMINIMIZED;
+ else
+ lpwndpl->showCmd = ( Wnd->style & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
+
+ lpwndpl->rcNormalPosition = Wnd->InternalPos.NormalRect;
+
+ if (Wnd->InternalPos.flags & WPF_MININIT) // Return if it was set!
+ {
+ lpwndpl->ptMinPosition.x = Wnd->InternalPos.IconPos.x;
+ lpwndpl->ptMinPosition.y = Wnd->InternalPos.IconPos.y;
+ }
+ else
+ lpwndpl->ptMinPosition.x = lpwndpl->ptMinPosition.y = -1;
+
+ if ( Wnd->InternalPos.flags & WPF_MAXINIT && // Return if set and not maximized to monitor!
+ !(Wnd->state & WNDS_MAXIMIZESTOMONITOR))
+ {
+ lpwndpl->ptMaxPosition.x = Wnd->InternalPos.MaxPos.x;
+ lpwndpl->ptMaxPosition.y = Wnd->InternalPos.MaxPos.y;
+ }
+ else
+ lpwndpl->ptMaxPosition.x = lpwndpl->ptMaxPosition.y = -1;
+
+ if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd &&
+ !(Wnd->ExStyle & WS_EX_TOOLWINDOW))
+ {
+ PMONITOR pmonitor = UserMonitorFromRect(&lpwndpl->rcNormalPosition, MONITOR_DEFAULTTOPRIMARY );
+
+ // FIXME: support DPI aware, rcWorkDPI/Real etc..
+ if (Wnd->InternalPos.flags & WPF_MININIT)
+ {
+ lpwndpl->ptMinPosition.x -= (pmonitor->rcWork.left - pmonitor->rcMonitor.left);
+ lpwndpl->ptMinPosition.y -= (pmonitor->rcWork.top - pmonitor->rcMonitor.top);
+ }
+ RECTL_vOffsetRect(&lpwndpl->rcNormalPosition,
+ pmonitor->rcMonitor.left - pmonitor->rcWork.left,
+ pmonitor->rcMonitor.top - pmonitor->rcWork.top);
+ }
+
+ if ( Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED || Wnd->style & WS_MAXIMIZE )
+ lpwndpl->flags |= WPF_RESTORETOMAXIMIZED;
+
+ if ( ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD) && Wnd->InternalPos.flags & WPF_SETMINPOSITION)
+ lpwndpl->flags |= WPF_SETMINPOSITION;
+
+ return TRUE;
+}
+
+/* make sure the specified rect is visible on screen */
+static void make_rect_onscreen( RECT *rect )
+{
+ PMONITOR pmonitor = UserMonitorFromRect( rect, MONITOR_DEFAULTTONEAREST ); // Wine uses this.
+
+ // FIXME: support DPI aware, rcWorkDPI/Real etc..
+ if (!pmonitor) return;
+ /* FIXME: map coordinates from rcWork to rcMonitor */
+ if (rect->right <= pmonitor->rcWork.left)
+ {
+ rect->right += pmonitor->rcWork.left - rect->left;
+ rect->left = pmonitor->rcWork.left;
+ }
+ else if (rect->left >= pmonitor->rcWork.right)
+ {
+ rect->left += pmonitor->rcWork.right - rect->right;
+ rect->right = pmonitor->rcWork.right;
+ }
+ if (rect->bottom <= pmonitor->rcWork.top)
+ {
+ rect->bottom += pmonitor->rcWork.top - rect->top;
+ rect->top = pmonitor->rcWork.top;
+ }
+ else if (rect->top >= pmonitor->rcWork.bottom)
+ {
+ rect->top += pmonitor->rcWork.bottom - rect->bottom;
+ rect->bottom = pmonitor->rcWork.bottom;
+ }
+}
+
+/* make sure the specified point is visible on screen */
+static void make_point_onscreen( POINT *pt )
+{
+ RECT rect;
+
+ RECTL_vSetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 );
+ make_rect_onscreen( &rect );
+ pt->x = rect.left;
+ pt->y = rect.top;
+}
+
+BOOL FASTCALL
+IntSetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *wpl, UINT Flags)
+{
+ BOOL sAsync;
+ UINT SWP_Flags;
+
+ if ( Flags & PLACE_MIN) make_point_onscreen( &wpl->ptMinPosition );
+ if ( Flags & PLACE_MAX) make_point_onscreen( &wpl->ptMaxPosition );
+ if ( Flags & PLACE_RECT) make_rect_onscreen( &wpl->rcNormalPosition );
+
+ if (!Wnd || Wnd == Wnd->head.rpdesk->pDeskInfo->spwnd) return FALSE;
+
+ if ( Flags & PLACE_MIN ) Wnd->InternalPos.IconPos = wpl->ptMinPosition;
+ if ( Flags & PLACE_MAX ) Wnd->InternalPos.MaxPos = wpl->ptMaxPosition;
+ if ( Flags & PLACE_RECT) Wnd->InternalPos.NormalRect = wpl->rcNormalPosition;
+
+ SWP_Flags = SWP_NOZORDER | SWP_NOACTIVATE | ((wpl->flags & WPF_ASYNCWINDOWPLACEMENT) ? SWP_ASYNCWINDOWPOS : 0);
+
+ if (Wnd->style & WS_MINIMIZE )
+ {
+ if (Flags & PLACE_MIN || Wnd->InternalPos.flags & WPF_SETMINPOSITION)
+ {
+ co_WinPosSetWindowPos(Wnd, HWND_TOP,
+ wpl->ptMinPosition.x, wpl->ptMinPosition.y, 0, 0,
+ SWP_NOSIZE | SWP_Flags);
+ Wnd->InternalPos.flags |= WPF_MININIT;
+ }
+ }
+ else if (Wnd->style & WS_MAXIMIZE )
+ {
+ if (Flags & PLACE_MAX)
+ {
+ co_WinPosSetWindowPos(Wnd, HWND_TOP,
+ wpl->ptMaxPosition.x, wpl->ptMaxPosition.y, 0, 0,
+ SWP_NOSIZE | SWP_Flags);
+ Wnd->InternalPos.flags |= WPF_MAXINIT;
+ }
+ }
+ else if (Flags & PLACE_RECT)
+ {
+ co_WinPosSetWindowPos(Wnd, HWND_TOP,
+ wpl->rcNormalPosition.left, wpl->rcNormalPosition.top,
+ wpl->rcNormalPosition.right - wpl->rcNormalPosition.left,
+ wpl->rcNormalPosition.bottom - wpl->rcNormalPosition.top,
+ SWP_Flags);
+ }
+
+ sAsync = (Wnd->head.pti->MessageQueue != gptiCurrent->MessageQueue && wpl->flags & WPF_ASYNCWINDOWPLACEMENT);
+
+ if ( sAsync )
+ co_IntSendMessageNoWait( UserHMGetHandle(Wnd), WM_ASYNC_SHOWWINDOW, wpl->showCmd, 0 );
+ else
+ co_WinPosShowWindow(Wnd, wpl->showCmd);
+
+ if ( Wnd->style & WS_MINIMIZE && !sAsync )
+ {
+ if ( wpl->flags & WPF_SETMINPOSITION )
+ Wnd->InternalPos.flags |= WPF_SETMINPOSITION;
+
+ if ( wpl->flags & WPF_RESTORETOMAXIMIZED )
+ Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
+ }
+ return TRUE;
+}
+
++UINT
++FASTCALL
++co_WinPosArrangeIconicWindows(PWND parent)
++{
++ RECTL rectParent;
++ PWND Child;
++ INT x, y, xspacing, yspacing, sx, sy;
++
++ ASSERT_REFS_CO(parent);
++
++ IntGetClientRect( parent, &rectParent );
++ // FIXME: Support Minimize Metrics gspv.mm.iArrange.
++ // Default: ARW_BOTTOMLEFT
++ x = rectParent.left;
++ y = rectParent.bottom;
++
++ xspacing = UserGetSystemMetrics(SM_CXMINIMIZED);
++ yspacing = UserGetSystemMetrics(SM_CYMINIMIZED);
++
++ Child = parent->spwndChild;
++ while(Child)
++ {
++ if((Child->style & WS_MINIMIZE) != 0 )
++ {
++ USER_REFERENCE_ENTRY Ref;
++ UserRefObjectCo(Child, &Ref);
++
++ sx = x + UserGetSystemMetrics(SM_CXBORDER);
++ sy = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
++
++ Child->InternalPos.IconPos.x = sx;
++ Child->InternalPos.IconPos.y = sy;
++ Child->InternalPos.flags |= WPF_MININIT;
++
++ co_WinPosSetWindowPos( Child, 0, sx, sy, xspacing, yspacing, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_ASYNCWINDOWPOS);
++
++ UserDerefObjectCo(Child);
++
++ if (x <= rectParent.right - xspacing)
++ x += xspacing;
++ else
++ {
++ x = rectParent.left;
++ y -= yspacing;
++ }
++ }
++ Child = Child->spwndNext;
++ }
++ return yspacing;
++}
++
++static VOID FASTCALL
++WinPosFindIconPos(PWND Window, POINT *Pos)
++{
++ RECT rectParent;
++ PWND pwndChild, pwndParent;
++ int x, y, xspacing, yspacing;
++
++ pwndParent = Window->spwndParent;
++ if (pwndParent == UserGetDesktopWindow())
++ {
++ //ERR("Parent is Desktop, Min off screen!\n");
++ /* ReactOS doesn't support iconic minimize to desktop */
++ Pos->x = Pos->y = -32000;
++ Window->InternalPos.flags |= WPF_MININIT;
++ Window->InternalPos.IconPos.x = Pos->x;
++ Window->InternalPos.IconPos.y = Pos->y;
++ return;
++ }
++
++ IntGetClientRect( pwndParent, &rectParent );
++ // FIXME: Support Minimize Metrics gspv.mm.iArrange.
++ // Default: ARW_BOTTOMLEFT
++ x = rectParent.left;
++ y = rectParent.bottom;
++
++ xspacing = UserGetSystemMetrics(SM_CXMINIMIZED);
++ yspacing = UserGetSystemMetrics(SM_CYMINIMIZED);
++
++ // Set to default position when minimized.
++ Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
++ Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
++
++ for (pwndChild = pwndParent->spwndChild; pwndChild; pwndChild = pwndChild->spwndNext)
++ {
++ if (pwndChild == Window) continue;
++
++ if ((pwndChild->style & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE) )
++ {
++ continue;
++ }
++
++ if ( pwndChild->InternalPos.IconPos.x != Pos->x && pwndChild->InternalPos.IconPos.y != Pos->y )
++ {
++ break;
++ }
++ if (x <= rectParent.right - xspacing)
++ x += xspacing;
++ else
++ {
++ x = rectParent.left;
++ y -= yspacing;
++ }
++ Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
++ Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
++ }
++
++ Window->InternalPos.IconPos.x = Pos->x;
++ Window->InternalPos.IconPos.y = Pos->y;
++ Window->InternalPos.flags |= WPF_MININIT;
++ TRACE("Position is set! X:%d Y:%d\n",Pos->x,Pos->y);
++ return;
++}
++
+UINT FASTCALL
+co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
+{
+ POINT Size;
+ WINDOWPLACEMENT wpl;
+ LONG old_style;
+ UINT SwpFlags = 0;
+
+ ASSERT_REFS_CO(Wnd);
+
+ wpl.length = sizeof(wpl);
+ IntGetWindowPlacement( Wnd, &wpl );
+
+ if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
+ {
+ ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
+ return SWP_NOSIZE | SWP_NOMOVE;
+ }
+ if (Wnd->style & WS_MINIMIZE)
+ {
+ switch (ShowFlag)
+ {
+ case SW_SHOWMINNOACTIVE:
+ case SW_SHOWMINIMIZED:
+ case SW_FORCEMINIMIZE:
+ case SW_MINIMIZE:
+ return SWP_NOSIZE | SWP_NOMOVE;
+ }
+ if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
+ {
+ return(SWP_NOSIZE | SWP_NOMOVE);
+ }
+ SwpFlags |= SWP_NOCOPYBITS;
+ }
+ switch (ShowFlag)
+ {
+ case SW_SHOWMINNOACTIVE:
+ case SW_SHOWMINIMIZED:
+ case SW_FORCEMINIMIZE:
+ case SW_MINIMIZE:
+ {
+ //ERR("MinMaximize Minimize\n");
+ if (Wnd->style & WS_MAXIMIZE)
+ {
+ Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
+ }
+ else
+ {
+ Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
+ }
+
+ old_style = IntSetStyle( Wnd, WS_MINIMIZE, WS_MAXIMIZE );
+
- /*ERR("Minimize: %d,%d %dx%d\n",
- wpl.ptMinPosition.x, wpl.ptMinPosition.y, UserGetSystemMetrics(SM_CXMINIMIZED),
- UserGetSystemMetrics(SM_CYMINIMIZED));
- */
++ co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOINTERNALPAINT);
+
+ if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION))
+ Wnd->InternalPos.flags &= ~WPF_MININIT;
+
+ WinPosFindIconPos(Wnd, &wpl.ptMinPosition);
+
+ if (!(old_style & WS_MINIMIZE)) SwpFlags |= SWP_STATECHANGED;
+
- // wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
- // wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
- UserGetSystemMetrics(SM_CXMINIMIZED),
- UserGetSystemMetrics(SM_CYMINIMIZED));
+ RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
- // wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
++ wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
++ wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
+ SwpFlags |= SWP_NOCOPYBITS;
+ break;
+ }
+
+ case SW_MAXIMIZE:
+ {
+ //ERR("MinMaximize Maximize\n");
+ if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE))
+ {
+ SwpFlags = SWP_NOSIZE | SWP_NOMOVE;
+ break;
+ }
+ co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
+
+ /*ERR("Maximize: %d,%d %dx%d\n",
+ wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
+ */
+ old_style = IntSetStyle( Wnd, WS_MAXIMIZE, WS_MINIMIZE );
+
+ if (!(old_style & WS_MAXIMIZE)) SwpFlags |= SWP_STATECHANGED;
+ RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
- /*ERR("Restore to Max: %d,%d %dx%d\n",
- wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
- */
++ //wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
+ Size.x, Size.y);
+ break;
+ }
+
+ case SW_SHOWNOACTIVATE:
+ Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
+ /* fall through */
+ case SW_SHOWNORMAL:
+ case SW_RESTORE:
+ case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
+ {
+ //ERR("MinMaximize Restore\n");
+ old_style = IntSetStyle( Wnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
+ if (old_style & WS_MINIMIZE)
+ {
+ if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED)
+ {
+ co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
+ IntSetStyle( Wnd, WS_MAXIMIZE, 0 );
+ SwpFlags |= SWP_STATECHANGED;
- // wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
- Size.x, Size.y);
+ RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
- /*ERR("Restore Max: %d,%d %dx%d\n",
- NewPos->left, NewPos->top, NewPos->right - NewPos->left, NewPos->bottom - NewPos->top);
- */
++ wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
+ break;
+ }
+ else
+ {
+ *NewPos = wpl.rcNormalPosition;
- /*ERR("Restore Min: %d,%d %dx%d\n",
- NewPos->left, NewPos->top, NewPos->right - NewPos->left, NewPos->bottom - NewPos->top);
- */
+ NewPos->right -= NewPos->left;
+ NewPos->bottom -= NewPos->top;
+ break;
+ }
+ }
+ else
+ {
+ if (!(old_style & WS_MAXIMIZE))
+ {
+ break;
+ }
+ SwpFlags |= SWP_STATECHANGED;
+ Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
+ *NewPos = wpl.rcNormalPosition;
- RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left,
- - Parent->rcClient.top);
- RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left,
- - Parent->rcClient.top);
- RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left,
- - Parent->rcClient.top);
+ NewPos->right -= NewPos->left;
+ NewPos->bottom -= NewPos->top;
+ break;
+ }
+ }
+ }
+ return SwpFlags;
+}
+
+BOOL
+UserHasWindowEdge(DWORD Style, DWORD ExStyle)
+{
+ if (Style & WS_MINIMIZE)
+ return TRUE;
+ if (ExStyle & WS_EX_DLGMODALFRAME)
+ return TRUE;
+ if (ExStyle & WS_EX_STATICEDGE)
+ return FALSE;
+ if (Style & WS_THICKFRAME)
+ return TRUE;
+ Style &= WS_CAPTION;
+ if (Style == WS_DLGFRAME || Style == WS_CAPTION)
+ return TRUE;
+ return FALSE;
+}
+
+VOID FASTCALL
+IntGetWindowBorderMeasures(PWND Wnd, UINT *cx, UINT *cy)
+{
+ if(HAS_DLGFRAME(Wnd->style, Wnd->ExStyle) && !(Wnd->style & WS_MINIMIZE))
+ {
+ *cx = UserGetSystemMetrics(SM_CXDLGFRAME);
+ *cy = UserGetSystemMetrics(SM_CYDLGFRAME);
+ }
+ else
+ {
+ if(HAS_THICKFRAME(Wnd->style, Wnd->ExStyle)&& !(Wnd->style & WS_MINIMIZE))
+ {
+ *cx = UserGetSystemMetrics(SM_CXFRAME);
+ *cy = UserGetSystemMetrics(SM_CYFRAME);
+ }
+ else if(HAS_THINFRAME(Wnd->style, Wnd->ExStyle))
+ {
+ *cx = UserGetSystemMetrics(SM_CXBORDER);
+ *cy = UserGetSystemMetrics(SM_CYBORDER);
+ }
+ else
+ {
+ *cx = *cy = 0;
+ }
+ }
+}
+
+VOID
+UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
+{
+ DWORD Border = 0;
+
+ if (UserHasWindowEdge(Style, ExStyle))
+ Border += 2;
+ else if (ExStyle & WS_EX_STATICEDGE)
+ Border += 1;
+ if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
+ Border += 2;
+ if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
+ Border ++;
+ Size->cx = Size->cy = Border;
+ if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
+ {
+ Size->cx += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME);
+ Size->cy += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME);
+ }
+ Size->cx *= UserGetSystemMetrics(SM_CXBORDER);
+ Size->cy *= UserGetSystemMetrics(SM_CYBORDER);
+}
+
+BOOL WINAPI
+UserAdjustWindowRectEx(LPRECT lpRect,
+ DWORD dwStyle,
+ BOOL bMenu,
+ DWORD dwExStyle)
+{
+ SIZE BorderSize;
+
+ if (bMenu)
+ {
+ lpRect->top -= UserGetSystemMetrics(SM_CYMENU);
+ }
+ if ((dwStyle & WS_CAPTION) == WS_CAPTION)
+ {
+ if (dwExStyle & WS_EX_TOOLWINDOW)
+ lpRect->top -= UserGetSystemMetrics(SM_CYSMCAPTION);
+ else
+ lpRect->top -= UserGetSystemMetrics(SM_CYCAPTION);
+ }
+ UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
+ RECTL_vInflateRect(
+ lpRect,
+ BorderSize.cx,
+ BorderSize.cy);
+
+ return TRUE;
+}
+
+UINT FASTCALL
+co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
+ POINT* MinTrack, POINT* MaxTrack)
+{
+ MINMAXINFO MinMax;
+ PMONITOR monitor;
+ INT xinc, yinc;
+ LONG style = Window->style;
+ LONG adjustedStyle;
+ LONG exstyle = Window->ExStyle;
+ RECT rc;
+
+ ASSERT_REFS_CO(Window);
+
+ /* Compute default values */
+
+ rc = Window->rcWindow;
+ MinMax.ptReserved.x = rc.left;
+ MinMax.ptReserved.y = rc.top;
+
+ if ((style & WS_CAPTION) == WS_CAPTION)
+ adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
+ else
+ adjustedStyle = style;
+
+ if(Window->spwndParent)
+ IntGetClientRect(Window->spwndParent, &rc);
+ UserAdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && Window->IDMenu), exstyle);
+
+ xinc = -rc.left;
+ yinc = -rc.top;
+
+ MinMax.ptMaxSize.x = rc.right - rc.left;
+ MinMax.ptMaxSize.y = rc.bottom - rc.top;
+ if (style & (WS_DLGFRAME | WS_BORDER))
+ {
+ MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
+ MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
+ }
+ else
+ {
+ MinMax.ptMinTrackSize.x = 2 * xinc;
+ MinMax.ptMinTrackSize.y = 2 * yinc;
+ }
+ MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK);
+ MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK);
+ MinMax.ptMaxPosition.x = -xinc;
+ MinMax.ptMaxPosition.y = -yinc;
+
+ if (!EMPTYPOINT(Window->InternalPos.MaxPos)) MinMax.ptMaxPosition = Window->InternalPos.MaxPos;
+
+ co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
+
+ /* if the app didn't change the values, adapt them for the current monitor */
+ if ((monitor = UserGetPrimaryMonitor()))
+ {
+ RECT rc_work;
+
+ rc_work = monitor->rcMonitor;
+
+ if (style & WS_MAXIMIZEBOX)
+ {
+ if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
+ rc_work = monitor->rcWork;
+ }
+
+ if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
+ MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
+ {
+ MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
+ MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
+ }
+ if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
+ {
+ MinMax.ptMaxPosition.x = rc_work.left - xinc;
+ MinMax.ptMaxPosition.y = rc_work.top - yinc;
+ }
+ if (MinMax.ptMaxSize.x >= (monitor->rcMonitor.right - monitor->rcMonitor.left) &&
+ MinMax.ptMaxSize.y >= (monitor->rcMonitor.bottom - monitor->rcMonitor.top) )
+ Window->state |= WNDS_MAXIMIZESTOMONITOR;
+ else
+ Window->state &= ~WNDS_MAXIMIZESTOMONITOR;
+ }
+
+
+ MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
+ MinMax.ptMinTrackSize.x);
+ MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
+ MinMax.ptMinTrackSize.y);
+
+ if (MaxSize)
+ *MaxSize = MinMax.ptMaxSize;
+ if (MaxPos)
+ *MaxPos = MinMax.ptMaxPosition;
+ if (MinTrack)
+ *MinTrack = MinMax.ptMinTrackSize;
+ if (MaxTrack)
+ *MaxTrack = MinMax.ptMaxTrackSize;
+
+ return 0; // FIXME: What does it return?
+}
+
+static
+VOID FASTCALL
+FixClientRect(PRECTL ClientRect, PRECTL WindowRect)
+{
+ if (ClientRect->left < WindowRect->left)
+ {
+ ClientRect->left = WindowRect->left;
+ }
+ else if (WindowRect->right < ClientRect->left)
+ {
+ ClientRect->left = WindowRect->right;
+ }
+ if (ClientRect->right < WindowRect->left)
+ {
+ ClientRect->right = WindowRect->left;
+ }
+ else if (WindowRect->right < ClientRect->right)
+ {
+ ClientRect->right = WindowRect->right;
+ }
+ if (ClientRect->top < WindowRect->top)
+ {
+ ClientRect->top = WindowRect->top;
+ }
+ else if (WindowRect->bottom < ClientRect->top)
+ {
+ ClientRect->top = WindowRect->bottom;
+ }
+ if (ClientRect->bottom < WindowRect->top)
+ {
+ ClientRect->bottom = WindowRect->top;
+ }
+ else if (WindowRect->bottom < ClientRect->bottom)
+ {
+ ClientRect->bottom = WindowRect->bottom;
+ }
+}
+/***********************************************************************
+ * get_valid_rects
+ *
+ * Compute the valid rects from the old and new client rect and WVR_* flags.
+ * Helper for WM_NCCALCSIZE handling.
+ */
+static
+VOID FASTCALL
+get_valid_rects( RECTL *old_client, RECTL *new_client, UINT flags, RECTL *valid )
+{
+ int cx, cy;
+
+ if (flags & WVR_REDRAW)
+ {
+ RECTL_vSetEmptyRect( &valid[0] );
+ RECTL_vSetEmptyRect( &valid[1] );
+ return;
+ }
+
+ if (flags & WVR_VALIDRECTS)
+ {
+ if (!RECTL_bIntersectRect( &valid[0], &valid[0], new_client ) ||
+ !RECTL_bIntersectRect( &valid[1], &valid[1], old_client ))
+ {
+ RECTL_vSetEmptyRect( &valid[0] );
+ RECTL_vSetEmptyRect( &valid[1] );
+ return;
+ }
+ flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
+ }
+ else
+ {
+ valid[0] = *new_client;
+ valid[1] = *old_client;
+ }
+
+ /* make sure the rectangles have the same size */
+ cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
+ cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
+
+ if (flags & WVR_ALIGNBOTTOM)
+ {
+ valid[0].top = valid[0].bottom - cy;
+ valid[1].top = valid[1].bottom - cy;
+ }
+ else
+ {
+ valid[0].bottom = valid[0].top + cy;
+ valid[1].bottom = valid[1].top + cy;
+ }
+ if (flags & WVR_ALIGNRIGHT)
+ {
+ valid[0].left = valid[0].right - cx;
+ valid[1].left = valid[1].right - cx;
+ }
+ else
+ {
+ valid[0].right = valid[0].left + cx;
+ valid[1].right = valid[1].left + cx;
+ }
+}
+
+static
+LONG FASTCALL
+co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos, RECTL* WindowRect, RECTL* ClientRect, RECTL* validRects)
+{
+ PWND Parent;
+ UINT wvrFlags = 0;
+
+ ASSERT_REFS_CO(Window);
+
+ /* Send WM_NCCALCSIZE message to get new client area */
+ if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
+ {
+ NCCALCSIZE_PARAMS params;
+ WINDOWPOS winposCopy;
+
+ params.rgrc[0] = *WindowRect; // new coordinates of a window that has been moved or resized
+ params.rgrc[1] = Window->rcWindow; // window before it was moved or resized
+ params.rgrc[2] = Window->rcClient; // client area before the window was moved or resized
+
+ Parent = Window->spwndParent;
+ if (0 != (Window->style & WS_CHILD) && Parent)
+ {
- RECTL_vOffsetRect(ClientRect, Parent->rcClient.left,
- Parent->rcClient.top);
++ RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left, - Parent->rcClient.top);
++ RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left, - Parent->rcClient.top);
++ RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left, - Parent->rcClient.top);
+ }
+
+ params.lppos = &winposCopy;
+ winposCopy = *WinPos;
+
+ wvrFlags = co_IntSendMessage(Window->head.h, WM_NCCALCSIZE, TRUE, (LPARAM) ¶ms);
+
+ /* If the application send back garbage, ignore it */
+ if (params.rgrc[0].left <= params.rgrc[0].right &&
+ params.rgrc[0].top <= params.rgrc[0].bottom)
+ {
+ *ClientRect = params.rgrc[0]; // First rectangle contains the coordinates of the new client rectangle resulting from the move or resize
+ if ((Window->style & WS_CHILD) && Parent)
+ {
- if (ClientRect->right - ClientRect->left !=
- Window->rcClient.right - Window->rcClient.left)
++ RECTL_vOffsetRect(ClientRect, Parent->rcClient.left, Parent->rcClient.top);
+ }
+ FixClientRect(ClientRect, WindowRect);
+ }
+
+ if (ClientRect->left != Window->rcClient.left ||
+ ClientRect->top != Window->rcClient.top)
+ {
+ WinPos->flags &= ~SWP_NOCLIENTMOVE;
+ }
+
- if (ClientRect->bottom - ClientRect->top !=
- Window->rcClient.bottom - Window->rcClient.top)
++ if (ClientRect->right - ClientRect->left != Window->rcClient.right - Window->rcClient.left)
+ {
+ WinPos->flags &= ~SWP_NOCLIENTSIZE;
+ }
+ else
+ wvrFlags &= ~WVR_HREDRAW;
+
- WindowRect->right = WindowRect->left + UserGetSystemMetrics(SM_CXICON);
- WindowRect->bottom = WindowRect->top + UserGetSystemMetrics(SM_CYICON);
++ if (ClientRect->bottom - ClientRect->top != Window->rcClient.bottom - Window->rcClient.top)
+ {
+ WinPos->flags &= ~SWP_NOCLIENTSIZE;
+ }
+ else
+ wvrFlags &= ~WVR_VREDRAW;
+
+ validRects[0] = params.rgrc[1]; // second rectangle contains the valid destination rectangle
+ validRects[1] = params.rgrc[2]; // third rectangle contains the valid source rectangle
+ }
+ else
+ {
+ if (!(WinPos->flags & SWP_NOMOVE) &&
+ (ClientRect->left != Window->rcClient.left ||
+ ClientRect->top != Window->rcClient.top))
+ {
+ WinPos->flags &= ~SWP_NOCLIENTMOVE;
+ }
+ }
+
+ if (WinPos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
+ {
+ RECTL_vSetEmptyRect( &validRects[0] );
+ RECTL_vSetEmptyRect( &validRects[1] );
+ }
+ else get_valid_rects( &Window->rcClient, ClientRect, wvrFlags, validRects );
+
+ return wvrFlags;
+}
+
+static
+BOOL FASTCALL
+co_WinPosDoWinPosChanging(PWND Window,
+ PWINDOWPOS WinPos,
+ PRECTL WindowRect,
+ PRECTL ClientRect)
+{
+ ASSERT_REFS_CO(Window);
+
+ /* Send WM_WINDOWPOSCHANGING message */
+
+ if (!(WinPos->flags & SWP_NOSENDCHANGING))
+ {
+ co_IntSendMessageNoWait(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
+ }
+
+ /* Calculate new position and size */
+
+ *WindowRect = Window->rcWindow;
+ *ClientRect = (Window->style & WS_MINIMIZE) ? Window->rcWindow : Window->rcClient;
+
+ if (!(WinPos->flags & SWP_NOSIZE))
+ {
+ if (Window->style & WS_MINIMIZE)
+ {
- #if 0
- if (!(WinPos->flags & SWP_NOMOVE))
- {
- WindowRect->left = WinPos->x;
- WindowRect->top = WinPos->y;
- WindowRect->right += WinPos->x - Window->rcWindow.left;
- WindowRect->bottom += WinPos->y - Window->rcWindow.top;
- RECTL_vOffsetRect(ClientRect,
- WinPos->x - Window->rcWindow.left,
- WinPos->y - Window->rcWindow.top);
++ WindowRect->right = WindowRect->left + UserGetSystemMetrics(SM_CXMINIMIZED);
++ WindowRect->bottom = WindowRect->top + UserGetSystemMetrics(SM_CYMINIMIZED);
+ }
+ else
+ {
+ WindowRect->right = WindowRect->left + WinPos->cx;
+ WindowRect->bottom = WindowRect->top + WinPos->cy;
+ }
+ }
- }
-
- *WindowRect = Window->rcWindow;
- *ClientRect = Window->rcClient;
-
- if (!(WinPos->flags & SWP_NOSIZE))
- {
- WindowRect->right = WindowRect->left + WinPos->cx;
- WindowRect->bottom = WindowRect->top + WinPos->cy;
- }
- #endif
+
- //ERR("Not SWP_NOMOVE\n");
+ if (!(WinPos->flags & SWP_NOMOVE))
+ {
+ INT X, Y;
+ PWND Parent;
+ X = WinPos->x;
+ Y = WinPos->y;
- //ERR("Not SWP_NOMOVE 1 Parent client offset X %d Y %d\n",X,Y);
++
+ Parent = Window->spwndParent;
++
+ if (((Window->style & WS_CHILD) != 0) &&
+ Parent &&
+ Parent != Window->head.rpdesk->pDeskInfo->spwnd)
+ {
- //ERR("Not SWP_NOMOVE 2 Parent client offset X %d Y %d\n",X,Y);
++ TRACE("Not SWP_NOMOVE 1 Parent client offset X %d Y %d\n",X,Y);
+ X += Parent->rcClient.left;
+ Y += Parent->rcClient.top;
-
++ TRACE("Not SWP_NOMOVE 2 Parent client offset X %d Y %d\n",X,Y);
+ }
+
+ WindowRect->left = X;
+ WindowRect->top = Y;
+ WindowRect->right += X - Window->rcWindow.left;
+ WindowRect->bottom += Y - Window->rcWindow.top;
+
+ RECTL_vOffsetRect(ClientRect, X - Window->rcWindow.left,
+ Y - Window->rcWindow.top);
+ }
- //ERR("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y);
+ WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
+
+ TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
+ WinPos->hwnd, WinPos->hwndInsertAfter, WinPos->x, WinPos->y,
+ WinPos->cx, WinPos->cy, WinPos->flags );
++ TRACE("WindowRect: %d %d %d %d\n", WindowRect->left,WindowRect->top,WindowRect->right,WindowRect->bottom);
++ TRACE("ClientRect: %d %d %d %d\n", ClientRect->left,ClientRect->top,ClientRect->right,ClientRect->bottom);
+
+ return TRUE;
+}
+
+/*
+ * Fix Z order taking into account owned popups -
+ * basically we need to maintain them above the window that owns them
+ *
+ * FIXME: hide/show owned popups when owner visibility changes.
+ *
+ * ReactOS: See bug CORE-6129 and CORE-6554.
+ *
+ */
+ ////
+ // Pass all the win:test_children/popup_zorder tests except "move hwnd_F and its popups down" which is if'ed out.
+ // Side effect, breaks more of the DeferWindowPos api tests, but wine breaks more!!!!
+static
+HWND FASTCALL
+WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter)
+{
+ HWND *List = NULL;
+ HWND Owner;
+ LONG Style;
+ PWND DesktopWindow, ChildObject;
+ int i;
+
+ TRACE("(%p) hInsertAfter = %p\n", Window, hWndInsertAfter );
+
+ Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
+ Style = Window->style;
+
+ if (Style & WS_CHILD)
+ {
+ TRACE("Window is child\n");
+ return hWndInsertAfter;
+ }
+
+ if (Owner)
+ {
+ /* Make sure this popup stays above the owner */
+
+ if (hWndInsertAfter != HWND_TOPMOST)
+ {
+ DesktopWindow = UserGetDesktopWindow();
+ List = IntWinListChildren(DesktopWindow);
+
+ if (List != NULL)
+ {
+ for (i = 0; List[i]; i++)
+ {
+ BOOL topmost = FALSE;
+
+ ChildObject = ValidateHwndNoErr(List[i]);
+ if (ChildObject)
+ {
+ topmost = (ChildObject->ExStyle & WS_EX_TOPMOST) != 0;
+ }
+
+ if (List[i] == Owner)
+ {
+ if (i > 0) hWndInsertAfter = List[i-1];
+ else hWndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
+ break;
+ }
+
+ if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
+ {
+ if (!topmost) break;
+ }
+ else if (List[i] == hWndInsertAfter) break;
+ }
+ }
+ else
+ return hWndInsertAfter;
+ }
+ }
+
+ if (hWndInsertAfter == HWND_BOTTOM)
+ {
+ ERR("Window is HWND_BOTTOM\n");
+ if (List) ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ goto done;
+ }
+
+ if (!List)
+ {
+ DesktopWindow = UserGetDesktopWindow();
+ List = IntWinListChildren(DesktopWindow);
+ }
+
+ if (List != NULL)
+ {
+ i = 0;
+
+ if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
+ {
+ if (hWndInsertAfter == HWND_NOTOPMOST || !(Window->ExStyle & WS_EX_TOPMOST))
+ {
+ TRACE("skip all the topmost windows\n");
+ /* skip all the topmost windows */
+ while (List[i] &&
+ (ChildObject = ValidateHwndNoErr(List[i])) &&
+ (ChildObject->ExStyle & WS_EX_TOPMOST)) i++;
+ }
+ }
+ else if (hWndInsertAfter != HWND_TOPMOST)
+ {
+ /* skip windows that are already placed correctly */
+ for (i = 0; List[i]; i++)
+ {
+ if (List[i] == hWndInsertAfter) break;
+ if (List[i] == UserHMGetHandle(Window))
+ {
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ goto done; /* nothing to do if window is moving backwards in z-order */
+ }
+ }
+ }
+
+ for (; List[i]; i++)
+ {
+ PWND Wnd;
+ USER_REFERENCE_ENTRY Ref;
+
+ if (List[i] == UserHMGetHandle(Window))
+ break;
+
+ if (!(Wnd = ValidateHwndNoErr(List[i])))
+ continue;
+
+ Owner = Wnd->spwndOwner ? Wnd->spwndOwner->head.h : NULL;
+
+ if (Owner != UserHMGetHandle(Window)) continue;
+
+ UserRefObjectCo(Wnd, &Ref);
+ TRACE( "moving %p owned by %p after %p\n", List[i], UserHMGetHandle(Window), hWndInsertAfter );
+ co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING| SWP_DEFERERASE);
+
+ UserDerefObjectCo(Wnd);
+ hWndInsertAfter = List[i];
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+done:
+ return hWndInsertAfter;
+}
+////
+
+/***********************************************************************
+ * WinPosInternalMoveWindow
+ *
+ * Update WindowRect and ClientRect of Window and all of its children
+ * We keep both WindowRect and ClientRect in screen coordinates internally
+ */
+static
+VOID FASTCALL
+WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
+{
+ PWND Child;
+
+ ASSERT(Window != Window->spwndChild);
++ TRACE("InternalMoveWin X %d Y %d\n", MoveX, MoveY);
+
+ Window->rcWindow.left += MoveX;
+ Window->rcWindow.right += MoveX;
+ Window->rcWindow.top += MoveY;
+ Window->rcWindow.bottom += MoveY;
+
+ Window->rcClient.left += MoveX;
+ Window->rcClient.right += MoveX;
+ Window->rcClient.top += MoveY;
+ Window->rcClient.bottom += MoveY;
+
+ for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
+ {
+ WinPosInternalMoveWindow(Child, MoveX, MoveY);
+ }
+}
+
+/*
+ * WinPosFixupSWPFlags
+ *
+ * Fix redundant flags and values in the WINDOWPOS structure.
+ */
+static
+BOOL FASTCALL
+WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
+{
+ PWND Parent;
+ POINT pt;
+
+ /* Finally make sure that all coordinates are valid */
+ if (WinPos->x < -32768) WinPos->x = -32768;
+ else if (WinPos->x > 32767) WinPos->x = 32767;
+ if (WinPos->y < -32768) WinPos->y = -32768;
+ else if (WinPos->y > 32767) WinPos->y = 32767;
+
+ WinPos->cx = max(WinPos->cx, 0);
+ WinPos->cy = max(WinPos->cy, 0);
+
+ Parent = UserGetAncestor( Wnd, GA_PARENT );
+ if (!IntIsWindowVisible( Parent )) WinPos->flags |= SWP_NOREDRAW;
+
+ if (Wnd->style & WS_VISIBLE) WinPos->flags &= ~SWP_SHOWWINDOW;
+ else
+ {
+ WinPos->flags &= ~SWP_HIDEWINDOW;
+ if (!(WinPos->flags & SWP_SHOWWINDOW)) WinPos->flags |= SWP_NOREDRAW;
+ }
+
+ /* Check for right size */
+ if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
+ Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
+ {
+ WinPos->flags |= SWP_NOSIZE;
+ }
+
+ pt.x = WinPos->x;
+ pt.y = WinPos->y;
+ IntClientToScreen( Parent, &pt );
- //ERR("SetWindowPos OldWindowRect: %d %d %d %d\n", OldWindowRect.left,OldWindowRect.top,OldWindowRect.right,OldWindowRect.bottom);
- //ERR("SetWindowPos OldClientRect: %d %d %d %d\n", OldClientRect.left,OldClientRect.top,OldClientRect.right,OldClientRect.bottom);
++ TRACE("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y);
+ /* Check for right position */
+ if (Wnd->rcWindow.left == pt.x && Wnd->rcWindow.top == pt.y)
+ {
+ //ERR("In right pos\n");
+ WinPos->flags |= SWP_NOMOVE;
+ }
+
+ if (WinPos->hwnd == UserGetForegroundWindow())
+ {
+ WinPos->flags |= SWP_NOACTIVATE; /* Already active */
+ }
+ else
+ if ((Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
+ {
+ /* Bring to the top when activating */
+ if (!(WinPos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) &&
+ (WinPos->flags & SWP_NOZORDER ||
+ (WinPos->hwndInsertAfter != HWND_TOPMOST && WinPos->hwndInsertAfter != HWND_NOTOPMOST)))
+ {
+ WinPos->flags &= ~SWP_NOZORDER;
+ WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP);
+ }
+ }
+
+ /* Check hwndInsertAfter */
+ if (!(WinPos->flags & SWP_NOZORDER))
+ {
+ /* Fix sign extension */
+ if (WinPos->hwndInsertAfter == (HWND)0xffff)
+ {
+ WinPos->hwndInsertAfter = HWND_TOPMOST;
+ }
+ else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
+ {
+ WinPos->hwndInsertAfter = HWND_NOTOPMOST;
+ }
+
+ if (WinPos->hwndInsertAfter == HWND_TOP)
+ {
+ /* Keep it topmost when it's already topmost */
+ if ((Wnd->ExStyle & WS_EX_TOPMOST) != 0)
+ WinPos->hwndInsertAfter = HWND_TOPMOST;
+
+ if (IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
+ WinPos->flags |= SWP_NOZORDER;
+ }
+ else if (WinPos->hwndInsertAfter == HWND_BOTTOM)
+ {
+ if (!(Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDLAST) == WinPos->hwnd)
+ WinPos->flags |= SWP_NOZORDER;
+ }
+ else if (WinPos->hwndInsertAfter == HWND_TOPMOST)
+ {
+ if ((Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
+ WinPos->flags |= SWP_NOZORDER;
+ }
+ else if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
+ {
+ if (!(Wnd->ExStyle & WS_EX_TOPMOST))
+ WinPos->flags |= SWP_NOZORDER;
+ }
+ else /* hwndInsertAfter must be a sibling of the window */
+ {
+ PWND InsAfterWnd;
+
+ InsAfterWnd = ValidateHwndNoErr(WinPos->hwndInsertAfter);
+ if(!InsAfterWnd)
+ {
+ return TRUE;
+ }
+
+ if (InsAfterWnd->spwndParent != Wnd->spwndParent)
+ {
+ /* Note from wine User32 Win test_SetWindowPos:
+ "Returns TRUE also for windows that are not siblings"
+ "Does not seem to do anything even without passing flags, still returns TRUE"
+ "Same thing the other way around."
+ ".. and with these windows."
+ */
+ return FALSE;
+ }
+ else
+ {
+ /*
+ * We don't need to change the Z order of hwnd if it's already
+ * inserted after hwndInsertAfter or when inserting hwnd after
+ * itself.
+ */
+ if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
+ ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
+ {
+ WinPos->flags |= SWP_NOZORDER;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/* x and y are always screen relative */
+BOOLEAN FASTCALL
+co_WinPosSetWindowPos(
+ PWND Window,
+ HWND WndInsertAfter,
+ INT x,
+ INT y,
+ INT cx,
+ INT cy,
+ UINT flags
+ )
+{
+ WINDOWPOS WinPos;
+ RECTL NewWindowRect;
+ RECTL NewClientRect;
+ RECTL valid_rects[2];
+ PROSRGNDATA VisRgn;
+ HRGN VisBefore = NULL;
+ HRGN VisBeforeJustClient = NULL;
+ HRGN VisAfter = NULL;
+ HRGN DirtyRgn = NULL;
+ HRGN ExposedRgn = NULL;
+ HRGN CopyRgn = NULL;
+ ULONG WvrFlags = 0;
+ RECTL OldWindowRect, OldClientRect;
+ int RgnType;
+ HDC Dc;
+ RECTL CopyRect;
+ PWND Ancestor;
+ BOOL bPointerInWindow;
+
+ ASSERT_REFS_CO(Window);
+
+ /* FIXME: Get current active window from active queue. Why? since r2915. */
+
+ bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
+
+ WinPos.hwnd = Window->head.h;
+ WinPos.hwndInsertAfter = WndInsertAfter;
+ WinPos.x = x;
+ WinPos.y = y;
+ WinPos.cx = cx;
+ WinPos.cy = cy;
+ WinPos.flags = flags;
+
+ if ( flags & SWP_ASYNCWINDOWPOS )
+ {
+ LRESULT lRes;
+ PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
+ if ( ppos )
+ {
+ WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag.
+ *ppos = WinPos;
+ /* Yes it's a pointer inside Win32k! */
+ lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
+ /* We handle this the same way as Event Hooks and Hooks. */
+ if ( !lRes )
+ {
+ ExFreePoolWithTag(ppos, USERTAG_SWP);
+ return FALSE;
+ }
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
+
+ /* Does the window still exist? */
+ if (!IntIsWindow(WinPos.hwnd))
+ {
+ TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd);
+ EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
+ return FALSE;
+ }
+
+ /* Fix up the flags. */
+ if (!WinPosFixupFlags(&WinPos, Window))
+ {
+ // See Note.
+ return TRUE;
+ }
+
+ Ancestor = UserGetAncestor(Window, GA_PARENT);
+ if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER &&
+ Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
+ {
+ WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
+ }
+
+ if (!(WinPos.flags & SWP_NOREDRAW))
+ {
+ /* Compute the visible region before the window position is changed */
+ if (!(WinPos.flags & SWP_SHOWWINDOW) &&
+ (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
+ SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
+ (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
+ {
+ VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
+ (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
+ VisRgn = NULL;
+
+ if ( VisBefore != NULL &&
+ (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisBefore, NULL)) &&
+ REGION_Complexity(VisRgn) == NULLREGION )
+ {
+ RGNOBJAPI_Unlock(VisRgn);
+ GreDeleteObject(VisBefore);
+ VisBefore = NULL;
+ }
+ else if(VisRgn)
+ {
+ RGNOBJAPI_Unlock(VisRgn);
+ NtGdiOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
+ }
+
+ /* Calculate the non client area for resizes, as this is used in the copy region */
+ if (!(WinPos.flags & SWP_NOSIZE))
+ {
+ VisBeforeJustClient = VIS_ComputeVisibleRegion(Window, TRUE, FALSE,
+ (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
+ VisRgn = NULL;
+
+ if ( VisBeforeJustClient != NULL &&
+ (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisBeforeJustClient, NULL)) &&
+ REGION_Complexity(VisRgn) == NULLREGION )
+ {
+ RGNOBJAPI_Unlock(VisRgn);
+ GreDeleteObject(VisBeforeJustClient);
+ VisBeforeJustClient = NULL;
+ }
+ else if(VisRgn)
+ {
+ RGNOBJAPI_Unlock(VisRgn);
+ NtGdiOffsetRgn(VisBeforeJustClient, -Window->rcWindow.left, -Window->rcWindow.top);
+ }
+ }
+ }
+ }
+
+ WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects);
+
+// ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags,
+// valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom,
+// valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom);
+
+ /* Validate link windows. (also take into account shell window in hwndShellWindow) */
+ if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
+ {
+ IntLinkHwnd(Window, WinPos.hwndInsertAfter);
+ }
+
+ OldWindowRect = Window->rcWindow;
+ OldClientRect = Window->rcClient;
- //ERR("SetWindowPos NewWindowRect: %d %d %d %d\n", NewWindowRect.left,NewWindowRect.top,NewWindowRect.right,NewWindowRect.bottom);
- //ERR("SetWindowPos NewClientRect: %d %d %d %d\n", NewClientRect.left,NewClientRect.top,NewClientRect.right,NewClientRect.bottom);
-
+
+ if (NewClientRect.left != OldClientRect.left ||
+ NewClientRect.top != OldClientRect.top)
+ {
++ // Move child window if their parent is moved. Keep Child window relative to Parent...
+ WinPosInternalMoveWindow(Window,
+ NewClientRect.left - OldClientRect.left,
+ NewClientRect.top - OldClientRect.top);
+ }
+
+ Window->rcWindow = NewWindowRect;
+ Window->rcClient = NewClientRect;
+
- // HRGN VisibleRgn;
- //ERR("co_WinPosShowWindow START\n");
+ /* erase parent when hiding or resizing child */
+ if (WinPos.flags & SWP_HIDEWINDOW)
+ {
+ /* Clear the update region */
+ co_UserRedrawWindow( Window,
+ NULL,
+ 0,
+ RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
+
+ if (Window->spwndParent == UserGetDesktopWindow())
+ co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)Window->head.h, 0);
+
+ Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE );
+ Window->head.pti->cVisWindows--;
+ IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
+ }
+ else if (WinPos.flags & SWP_SHOWWINDOW)
+ {
+ if (Window->spwndParent == UserGetDesktopWindow() &&
+ Window->spwndOwner == NULL &&
+ (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
+ (Window->ExStyle & WS_EX_APPWINDOW)))
+ co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
+
+ Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
+ Window->head.pti->cVisWindows++;
+ IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
+ }
+
+ if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
+ {
+ NtGdiOffsetRgn(Window->hrgnUpdate,
+ NewWindowRect.left - OldWindowRect.left,
+ NewWindowRect.top - OldWindowRect.top);
+ }
+
+ DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
+
+ if (!(WinPos.flags & SWP_NOREDRAW))
+ {
+ /* Determine the new visible region */
+ VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
+ (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
+ VisRgn = NULL;
+
+ if ( VisAfter != NULL &&
+ (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisAfter, NULL)) &&
+ REGION_Complexity(VisRgn) == NULLREGION )
+ {
+ RGNOBJAPI_Unlock(VisRgn);
+ GreDeleteObject(VisAfter);
+ VisAfter = NULL;
+ }
+ else if(VisRgn)
+ {
+ RGNOBJAPI_Unlock(VisRgn);
+ NtGdiOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
+ }
+
+ /*
+ * Determine which pixels can be copied from the old window position
+ * to the new. Those pixels must be visible in both the old and new
+ * position. Also, check the class style to see if the windows of this
+ * class need to be completely repainted on (horizontal/vertical) size
+ * change.
+ */
+ if ( VisBefore != NULL &&
+ VisAfter != NULL &&
+ !(WinPos.flags & SWP_NOCOPYBITS) &&
+ ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
+ !(Window->ExStyle & WS_EX_TRANSPARENT) )
+ {
+
+ /*
+ * If this is (also) a window resize, the whole nonclient area
+ * needs to be repainted. So we limit the copy to the client area,
+ * 'cause there is no use in copying it (would possibly cause
+ * "flashing" too). However, if the copy region is already empty,
+ * we don't have to crop (can't take anything away from an empty
+ * region...)
+ */
+
+ CopyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
+ if (WinPos.flags & SWP_NOSIZE)
+ RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
+ else if (VisBeforeJustClient != NULL)
+ {
+ RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND);
+ GreDeleteObject(VisBeforeJustClient);
+ }
+
+ /* No use in copying bits which are in the update region. */
+ if (Window->hrgnUpdate != NULL)
+ {
+ NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
+ NtGdiCombineRgn(CopyRgn, CopyRgn, Window->hrgnUpdate, RGN_DIFF);
+ NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
+ }
+
+ /*
+ * Now, get the bounding box of the copy region. If it's empty
+ * there's nothing to copy. Also, it's no use copying bits onto
+ * themselves.
+ */
+ if ( (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(CopyRgn, NULL)) &&
+ REGION_GetRgnBox(VisRgn, &CopyRect) == NULLREGION)
+ {
+ /* Nothing to copy, clean up */
+ RGNOBJAPI_Unlock(VisRgn);
+ GreDeleteObject(CopyRgn);
+ CopyRgn = NULL;
+ }
+ else if (OldWindowRect.left != NewWindowRect.left ||
+ OldWindowRect.top != NewWindowRect.top)
+ {
+ if(VisRgn)
+ {
+ RGNOBJAPI_Unlock(VisRgn);
+ }
+
+ /*
+ * Small trick here: there is no function to bitblt a region. So
+ * we set the region as the clipping region, take the bounding box
+ * of the region and bitblt that. Since nothing outside the clipping
+ * region is copied, this has the effect of bitblt'ing the region.
+ *
+ * Since NtUserGetDCEx takes ownership of the clip region, we need
+ * to create a copy of CopyRgn and pass that. We need CopyRgn later
+ */
+ NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
+ Dc = UserGetDCEx( Window,
+ CopyRgn,
+ DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
+ NtGdiBitBlt( Dc,
+ CopyRect.left, CopyRect.top,
+ CopyRect.right - CopyRect.left,
+ CopyRect.bottom - CopyRect.top,
+ Dc,
+ CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
+ CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
+ SRCCOPY,
+ 0,
+ 0);
+
+ UserReleaseDC(Window, Dc, FALSE);
+ IntValidateParent(Window, CopyRgn, FALSE);
+ NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
+ }
+ else if(VisRgn)
+ {
+ RGNOBJAPI_Unlock(VisRgn);
+ }
+ }
+ else
+ {
+ CopyRgn = NULL;
+ }
+
+ /* We need to redraw what wasn't visible before */
+ if (VisAfter != NULL)
+ {
+ DirtyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
+ if (CopyRgn != NULL)
+ {
+ RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
+ }
+ else
+ {
+ RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
+ }
+ if (RgnType != ERROR && RgnType != NULLREGION)
+ {
+ /* old code
+ NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
+ IntInvalidateWindows( Window,
+ DirtyRgn,
+ RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
+ }
+ GreDeleteObject(DirtyRgn);
+ */
+
+ PWND Parent = Window->spwndParent;
+
+ NtGdiOffsetRgn( DirtyRgn,
+ Window->rcWindow.left,
+ Window->rcWindow.top);
+ if ( (Window->style & WS_CHILD) &&
+ (Parent) &&
+ !(Parent->style & WS_CLIPCHILDREN))
+ {
+ IntInvalidateWindows( Parent,
+ DirtyRgn,
+ RDW_ERASE | RDW_INVALIDATE);
+ co_IntPaintWindows(Parent, RDW_ERASENOW, FALSE);
+ }
+ else
+ {
+ IntInvalidateWindows( Window,
+ DirtyRgn,
+ RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
+ }
+ }
+ GreDeleteObject(DirtyRgn);
+ }
+
+ if (CopyRgn != NULL)
+ {
+ GreDeleteObject(CopyRgn);
+ }
+
+ /* Expose what was covered before but not covered anymore */
+ if (VisBefore != NULL)
+ {
+ ExposedRgn = IntSysCreateRectRgn(0, 0, 0, 0);
+ RgnType = NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
+ NtGdiOffsetRgn( ExposedRgn,
+ OldWindowRect.left - NewWindowRect.left,
+ OldWindowRect.top - NewWindowRect.top);
+
+ if (VisAfter != NULL)
+ RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
+
+ if (RgnType != ERROR && RgnType != NULLREGION)
+ {
+ co_VIS_WindowLayoutChanged(Window, ExposedRgn);
+ }
+ GreDeleteObject(ExposedRgn);
+ GreDeleteObject(VisBefore);
+ }
+
+ if (VisAfter != NULL)
+ {
+ GreDeleteObject(VisAfter);
+ }
+ }
+
+ if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
+ {
+ if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
+ {
+ co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
+ }
+ else
+ {
+ //ERR("SetWindowPos Set FG Window!\n");
+ if (Window->state & WNDS_BEINGACTIVATED) // Inside SAW?
+ co_IntSetActiveWindow(Window, FALSE, TRUE, FALSE); // Fixes Api AttachThreadInput tests.
+ else
+ co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
+ }
+ }
+
+ /* And last, send the WM_WINDOWPOSCHANGED message */
+
+ TRACE("\tstatus flags = %04x\n", WinPos.flags & SWP_AGG_STATUSFLAGS);
+
+ if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
+ {
+ /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
+ and always contains final window position.
+ */
+ WinPos.x = NewWindowRect.left;
+ WinPos.y = NewWindowRect.top;
+ WinPos.cx = NewWindowRect.right - NewWindowRect.left;
+ WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
+ co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
+ }
+
+ if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
+ !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
+ {
+ PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
+ if (pWnd)
+ IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
+ }
+
+ if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
+ {
+ /* Generate mouse move message */
+ MSG msg;
+ msg.message = WM_MOUSEMOVE;
+ msg.wParam = UserGetMouseButtonsState();
+ msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
+ msg.pt = gpsi->ptCursor;
+ co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
+ }
+
+ return TRUE;
+}
+
+LRESULT FASTCALL
+co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
+{
+ LRESULT Result;
+
+ ASSERT_REFS_CO(Window);
+
+ *ClientRect = *WindowRect;
+ Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
+
+ FixClientRect(ClientRect, WindowRect);
+
+ return Result;
+}
+
+void FASTCALL
+co_WinPosSendSizeMove(PWND Wnd)
+{
+ RECTL Rect;
+ LPARAM lParam;
+ WPARAM wParam = SIZE_RESTORED;
+
+ IntGetClientRect(Wnd, &Rect);
+ lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
+
+ Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
+
+ if (Wnd->style & WS_MAXIMIZE)
+ {
+ wParam = SIZE_MAXIMIZED;
+ }
+ else if (Wnd->style & WS_MINIMIZE)
+ {
+ wParam = SIZE_MINIMIZED;
+ lParam = 0;
+ }
+
+ co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
+
+ if (Wnd->spwndParent == UserGetDesktopWindow()) // Wnd->spwndParent->fnid == FNID_DESKTOP )
+ lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
+ else
+ lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
+
+ co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
+
+ IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
+}
+
+BOOLEAN FASTCALL
+co_WinPosShowWindow(PWND Wnd, INT Cmd)
+{
+ BOOLEAN WasVisible;
+ UINT Swp = 0, EventMsg = 0;
+ RECTL NewPos = {0, 0, 0, 0};
+ BOOLEAN ShowFlag;
+ LONG style;
+ PWND Parent;
+ PTHREADINFO pti;
- #if 0 // Explorer issues with common controls. Someone does not know how CS_SAVEBITS works.
++ //HRGN VisibleRgn;
+ BOOL ShowOwned = FALSE;
+ ASSERT_REFS_CO(Wnd);
++ //ERR("co_WinPosShowWindow START\n");
+
+ pti = PsGetCurrentThreadWin32Thread();
+ WasVisible = (Wnd->style & WS_VISIBLE) != 0;
+ style = Wnd->style;
+
+ switch (Cmd)
+ {
+ case SW_HIDE:
+ {
+ if (!WasVisible)
+ {
+ //ERR("co_WinPosShowWindow Exit Bad\n");
+ return(FALSE);
+ }
+ Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
+ if (Wnd != pti->MessageQueue->spwndActive)
+ Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+ break;
+ }
+
+ case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
+ case SW_SHOWMINNOACTIVE:
+ Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+ /* Fall through. */
+ case SW_SHOWMINIMIZED:
+ Swp |= SWP_SHOWWINDOW;
+ /* Fall through. */
+ case SW_MINIMIZE:
+ {
+ Swp |= SWP_NOACTIVATE;
+ if (!(style & WS_MINIMIZE))
+ {
+ IntShowOwnedPopups(Wnd, FALSE );
+
+ // Fix wine Win test_SetFocus todo #1 & #2,
+ if (Cmd == SW_SHOWMINIMIZED)
+ {
+ //ERR("co_WinPosShowWindow Set focus 1\n");
+ if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
+ co_UserSetFocus(Wnd->spwndParent);
+ else
+ co_UserSetFocus(0);
+ }
+
+ Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos) |
+ SWP_FRAMECHANGED;
+
+ EventMsg = EVENT_SYSTEM_MINIMIZESTART;
+ }
+ else
+ {
+ if (!WasVisible)
+ {
+ Swp |= SWP_FRAMECHANGED;
+ }
+ else ////
+ {
+ //ERR("co_WinPosShowWindow Exit Good\n");
+ return TRUE;
+ }
+ Swp |= SWP_NOSIZE | SWP_NOMOVE;
+ }
+ break;
+ }
+
+ case SW_SHOWMAXIMIZED:
+ {
+ Swp |= SWP_SHOWWINDOW;
+ if (!(style & WS_MAXIMIZE))
+ {
+ ShowOwned = TRUE;
+
+ Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos) |
+ SWP_FRAMECHANGED;
+
+ EventMsg = EVENT_SYSTEM_MINIMIZEEND;
+ }
+ else
+ {
+ if (!WasVisible)
+ {
+ Swp |= SWP_FRAMECHANGED;
+ }
+ else ////
+ {
+ //ERR("co_WinPosShowWindow Exit Good 1\n");
+ return TRUE;
+ }
+ Swp |= SWP_NOSIZE | SWP_NOMOVE;
+ }
+ break;
+ }
+
+ case SW_SHOWNA:
+ Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
+ if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
+ break;
+ case SW_SHOW:
+ if (WasVisible) return(TRUE); // Nothing to do!
+ Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
+ /* Don't activate the topmost window. */
+ if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+ break;
+
+ case SW_SHOWNOACTIVATE:
+ Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+ /* Fall through. */
+ case SW_SHOWNORMAL:
+ case SW_SHOWDEFAULT:
+ case SW_RESTORE:
+ if (!WasVisible) Swp |= SWP_SHOWWINDOW;
+ if (style & (WS_MINIMIZE | WS_MAXIMIZE))
+ {
+ Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos) |
+ SWP_FRAMECHANGED;
+
+ if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
+ }
+ else
+ {
+ if (!WasVisible)
+ {
+ Swp |= SWP_FRAMECHANGED;
+ }
+ else ////
+ {
+ //ERR("co_WinPosShowWindow Exit Good 3\n");
+ return TRUE;
+ }
+ Swp |= SWP_NOSIZE | SWP_NOMOVE;
+ }
+ if ( style & WS_CHILD &&
+ !(Wnd->ExStyle & WS_EX_MDICHILD) &&
+ !(Swp & SWP_STATECHANGED))
+ Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+ break;
+
+ default:
+ //ERR("co_WinPosShowWindow Exit Good 4\n");
+ return WasVisible;
+ }
+
+ ShowFlag = (Cmd != SW_HIDE);
+
+ if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
+ {
+ co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
+ if (!(Wnd->state2 & WNDS2_WIN31COMPAT))
+ co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
+ if (!VerifyWnd(Wnd)) return WasVisible;
+ }
+
+ /* We can't activate a child window */
+ if ((Wnd->style & WS_CHILD) &&
+ !(Wnd->ExStyle & WS_EX_MDICHILD) &&
+ Cmd != SW_SHOWNA)
+ {
+ //ERR("SWP Child No active and ZOrder\n");
+ Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+ }
+
++#if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works.
++ // Breaks startup and shutdown active window...
+ if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
+ Wnd->pcls->style & CS_SAVEBITS &&
+ ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
+ {
+ ERR("WinPosShowWindow Set active\n");
+ UserSetActiveWindow(Wnd);
+ Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
+ }
+#endif
+
+ if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
+ {
+ TRACE("Child is Vis %s or State changed %s. ShowFlag %s\n",
+ (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
+ (ShowFlag ? "TRUE" : "FALSE"));
+ co_WinPosSetWindowPos( Wnd,
+ 0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
+ NewPos.left,
+ NewPos.top,
+ NewPos.right, //NewPos.right - NewPos.left,
+ NewPos.bottom, //NewPos.bottom - NewPos.top,
+ LOWORD(Swp));
+ }
+ else
+ {
+ TRACE("Parent Vis?\n");
+ /* if parent is not visible simply toggle WS_VISIBLE and return */
+ if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
+ else IntSetStyle( Wnd, 0, WS_VISIBLE );
+ }
+
+ if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
+
+ if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
+
+ if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
+ {
+ if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue() )
+ {
+ if ( Wnd->spwndParent == UserGetDesktopWindow())
+ {
+ if(!ActivateOtherWindowMin(Wnd))
+ co_WinPosActivateOtherWindow(Wnd);
+ }
+ else
+ co_WinPosActivateOtherWindow(Wnd);
+ }
+
+ /* Revert focus to parent */
+ if (Wnd == pti->MessageQueue->spwndFocus)
+ {
+ Parent = Wnd->spwndParent;
+ if (Wnd->spwndParent == UserGetDesktopWindow()) Parent = 0;
+ co_UserSetFocus(Parent);
+ }
+ }
+
+ /* FIXME: Check for window destruction. */
+
+ if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
+ !(Wnd->state2 & WNDS2_INDESTROY))
+ {
+ co_WinPosSendSizeMove(Wnd);
+ }
+
+ /* if previous state was minimized Windows sets focus to the window */
+ if (style & WS_MINIMIZE)
+ {
+ co_UserSetFocus(Wnd);
+ // Fix wine Win test_SetFocus todo #3,
+ if (!(style & WS_CHILD)) co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
+ }
+ //ERR("co_WinPosShowWindow EXIT\n");
+ return(WasVisible);
+}
+
+static
+PWND FASTCALL
+co_WinPosSearchChildren(
+ PWND ScopeWin,
+ POINT *Point,
+ USHORT *HitTest,
+ BOOL Ignore
+ )
+{
+ PWND pwndChild;
+ HWND *List, *phWnd;
+
+ if (!(ScopeWin->style & WS_VISIBLE))
+ {
+ return NULL;
+ }
+
+ if (!Ignore && (ScopeWin->style & WS_DISABLED))
+ {
+ return NULL;
+ }
+
+ if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
+ {
+ return NULL;
+ }
+
+ UserReferenceObject(ScopeWin);
+
+ if ( RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
+ {
+ List = IntWinListChildren(ScopeWin);
+ if(List)
+ {
+ for (phWnd = List; *phWnd; ++phWnd)
+ {
+ if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
+ {
+ continue;
+ }
+
+ pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
+
+ if(pwndChild != NULL)
+ {
+ /* We found a window. Don't send any more WM_NCHITTEST messages */
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ UserDereferenceObject(ScopeWin);
+ return pwndChild;
+ }
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+ }
+
+ if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
+ {
+ *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0,
+ MAKELONG(Point->x, Point->y));
+ if ((*HitTest) == (USHORT)HTTRANSPARENT)
+ {
+ UserDereferenceObject(ScopeWin);
+ return NULL;
+ }
+ }
+ else
+ *HitTest = HTCLIENT;
+
+ return ScopeWin;
+}
+
+PWND FASTCALL
+co_WinPosWindowFromPoint(PWND ScopeWin, POINT *WinPoint, USHORT* HitTest, BOOL Ignore)
+{
+ PWND Window;
+ POINT Point = *WinPoint;
+ USER_REFERENCE_ENTRY Ref;
+
+ if( ScopeWin == NULL )
+ {
+ ScopeWin = UserGetDesktopWindow();
+ if(ScopeWin == NULL)
+ return NULL;
+ }
+
+ *HitTest = HTNOWHERE;
+
+ ASSERT_REFS_CO(ScopeWin);
+ UserRefObjectCo(ScopeWin, &Ref);
+
+ Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
+
+ UserDerefObjectCo(ScopeWin);
+ if (Window)
+ ASSERT_REFS_CO(Window);
+ ASSERT_REFS_CO(ScopeWin);
+
+ return Window;
+}
+
+PWND FASTCALL
+IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
+{
+ POINTL Pt;
+ HWND *List, *phWnd;
+ PWND pwndHit = NULL;
+
+ Pt.x = x;
+ Pt.y = y;
+
+ if (Parent != UserGetDesktopWindow())
+ {
+ Pt.x += Parent->rcClient.left;
+ Pt.y += Parent->rcClient.top;
+ }
+
+ if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
+
+ if ((List = IntWinListChildren(Parent)))
+ {
+ for (phWnd = List; *phWnd; phWnd++)
+ {
+ PWND Child;
+ if ((Child = ValidateHwndNoErr(*phWnd)))
+ {
+ if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
+ {
+ if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
+ (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
+ {
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ return Child;
+ }
+ pwndHit = Child;
+ }
+ }
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+ return pwndHit ? pwndHit : Parent;
+}
+
+PWND APIENTRY
+IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
+{
+ POINTL Pt;
+ HWND *List, *phWnd;
+ PWND pwndHit = NULL;
+
+ Pt.x = x;
+ Pt.y = y;
+
+ if (Parent != UserGetDesktopWindow())
+ {
+ if (Parent->ExStyle & WS_EX_LAYOUTRTL)
+ Pt.x = Parent->rcClient.right - Pt.x;
+ else
+ Pt.x += Parent->rcClient.left;
+ Pt.y += Parent->rcClient.top;
+ }
+
+ if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
+
+ if ((List = IntWinListChildren(Parent)))
+ {
+ for (phWnd = List; *phWnd; phWnd++)
+ {
+ PWND Child;
+ if ((Child = ValidateHwndNoErr(*phWnd)))
+ {
+ if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
+ {
+ if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
+ if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
+ }
+
+ if (uiFlags & CWP_SKIPTRANSPARENT)
+ {
+ if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
+ }
+
+ if (IntPtInWindow(Child, Pt.x, Pt.y))
+ {
+ pwndHit = Child;
+ break;
+ }
+ }
+ }
+ ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
+ }
+ return pwndHit ? pwndHit : Parent;
+}
+
+HDWP
+FASTCALL
+IntDeferWindowPos( HDWP hdwp,
+ HWND hwnd,
+ HWND hwndAfter,
+ INT x,
+ INT y,
+ INT cx,
+ INT cy,
+ UINT flags )
+{
+ PSMWP pDWP;
+ int i;
+ HDWP retvalue = hdwp;
+
+ TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
+ hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
+
+ if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
+ SWP_NOZORDER | SWP_NOREDRAW |
+ SWP_NOACTIVATE | SWP_NOCOPYBITS |
+ SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
+ SWP_HIDEWINDOW | SWP_FRAMECHANGED))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
+ {
+ EngSetLastError(ERROR_INVALID_DWP_HANDLE);
+ return NULL;
+ }
+
+ for (i = 0; i < pDWP->ccvr; i++)
+ {
+ if (pDWP->acvr[i].pos.hwnd == hwnd)
+ {
+ /* Merge with the other changes */
+ if (!(flags & SWP_NOZORDER))
+ {
+ pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
+ }
+ if (!(flags & SWP_NOMOVE))
+ {
+ pDWP->acvr[i].pos.x = x;
+ pDWP->acvr[i].pos.y = y;
+ }
+ if (!(flags & SWP_NOSIZE))
+ {
+ pDWP->acvr[i].pos.cx = cx;
+ pDWP->acvr[i].pos.cy = cy;
+ }
+ pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
+ SWP_NOZORDER | SWP_NOREDRAW |
+ SWP_NOACTIVATE | SWP_NOCOPYBITS|
+ SWP_NOOWNERZORDER);
+ pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
+ SWP_FRAMECHANGED);
+ goto END;
+ }
+ }
+ if (pDWP->ccvr >= pDWP->ccvrAlloc)
+ {
+ PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
+ if (!newpos)
+ {
+ retvalue = NULL;
+ goto END;
+ }
+ RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
+ RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
+ ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
+ pDWP->ccvrAlloc *= 2;
+ pDWP->acvr = newpos;
+ }
+ pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
+ pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
+ pDWP->acvr[pDWP->ccvr].pos.x = x;
+ pDWP->acvr[pDWP->ccvr].pos.y = y;
+ pDWP->acvr[pDWP->ccvr].pos.cx = cx;
+ pDWP->acvr[pDWP->ccvr].pos.cy = cy;
+ pDWP->acvr[pDWP->ccvr].pos.flags = flags;
+ pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
+ pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
+ pDWP->ccvr++;
+END:
+ return retvalue;
+}
+
+BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
+{
+ PSMWP pDWP;
+ PCVR winpos;
+ BOOL res = TRUE;
+ int i;
+
+ TRACE("%p\n", hdwp);
+
+ if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
+ {
+ EngSetLastError(ERROR_INVALID_DWP_HANDLE);
+ return FALSE;
+ }
+
+ for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
+ {
+ PWND pwnd;
+ USER_REFERENCE_ENTRY Ref;
+
+ TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
+ winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
+ winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
+
+ pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
+ if (!pwnd)
+ continue;
+
+ UserRefObjectCo(pwnd, &Ref);
+
+ if ( sAsync )
+ {
+ LRESULT lRes;
+ PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
+ if ( ppos )
+ {
+ *ppos = winpos->pos;
+ /* Yes it's a pointer inside Win32k! */
+ lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
+ /* We handle this the same way as Event Hooks and Hooks. */
+ if ( !lRes )
+ {
+ ExFreePoolWithTag(ppos, USERTAG_SWP);
+ }
+ }
+ }
+ else
+ res = co_WinPosSetWindowPos( pwnd,
+ winpos->pos.hwndInsertAfter,
+ winpos->pos.x,
+ winpos->pos.y,
+ winpos->pos.cx,
+ winpos->pos.cy,
+ winpos->pos.flags);
+
+ // Hack to pass tests.... Must have some work to do so clear the error.
+ if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
+ EngSetLastError(ERROR_SUCCESS);
+
+ UserDerefObjectCo(pwnd);
+ }
+ ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
+ UserDereferenceObject(pDWP);
+ UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
+ return res;
+}
+
+/*
+ * @implemented
+ */
+HWND APIENTRY
+NtUserChildWindowFromPointEx(HWND hwndParent,
+ LONG x,
+ LONG y,
+ UINT uiFlags)
+{
+ PWND pwndParent;
+ TRACE("Enter NtUserChildWindowFromPointEx\n");
+ UserEnterExclusive();
+ if ((pwndParent = UserGetWindowObject(hwndParent)))
+ {
+ pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
+ }
+ UserLeave();
+ TRACE("Leave NtUserChildWindowFromPointEx\n");
+ return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
+}
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
+ DWORD Unknown1)
+{
+ BOOL Ret;
+ TRACE("Enter NtUserEndDeferWindowPosEx\n");
+ UserEnterExclusive();
+ Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
+ TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
+ UserLeave();
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+HDWP APIENTRY
+NtUserDeferWindowPos(HDWP WinPosInfo,
+ HWND Wnd,
+ HWND WndInsertAfter,
+ int x,
+ int y,
+ int cx,
+ int cy,
+ UINT Flags)
+{
+ PWND pWnd, pWndIA;
+ HDWP Ret = NULL;
+ UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
+ SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
+ SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
+
+ TRACE("Enter NtUserDeferWindowPos\n");
+ UserEnterExclusive();
+
+ if ( Flags & Tmp )
+ {
+ EngSetLastError(ERROR_INVALID_FLAGS);
+ goto Exit;
+ }
+
+ pWnd = UserGetWindowObject(Wnd);
+ if ( !pWnd || // FIXME:
+ pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
+ pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
+ {
+ goto Exit;
+ }
+
+ if ( WndInsertAfter &&
+ WndInsertAfter != HWND_BOTTOM &&
+ WndInsertAfter != HWND_TOPMOST &&
+ WndInsertAfter != HWND_NOTOPMOST )
+ {
+ pWndIA = UserGetWindowObject(WndInsertAfter);
+ if ( !pWndIA ||
+ pWndIA == UserGetDesktopWindow() ||
+ pWndIA == UserGetMessageWindow() )
+ {
+ goto Exit;
+ }
+ }
+
+ Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
+
+Exit:
+ TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
+ UserLeave();
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+DWORD APIENTRY
+NtUserGetInternalWindowPos( HWND hWnd,
+ LPRECT rectWnd,
+ LPPOINT ptIcon)
+{
+ PWND Window;
+ DWORD Ret = 0;
+ BOOL Hit = FALSE;
+ WINDOWPLACEMENT wndpl;
+
+ UserEnterShared();
+
+ if (!(Window = UserGetWindowObject(hWnd)))
+ {
+ Hit = FALSE;
+ goto Exit;
+ }
+
+ _SEH2_TRY
+ {
+ if(rectWnd)
+ {
+ ProbeForWrite(rectWnd,
+ sizeof(RECT),
+ 1);
+ }
+ if(ptIcon)
+ {
+ ProbeForWrite(ptIcon,
+ sizeof(POINT),
+ 1);
+ }
+
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ Hit = TRUE;
+ }
+ _SEH2_END;
+
+ wndpl.length = sizeof(WINDOWPLACEMENT);
+
+ if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
+ {
+ _SEH2_TRY
+ {
+ if (rectWnd)
+ {
+ RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
+ }
+ if (ptIcon)
+ {
+ RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
+ }
+
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ Hit = TRUE;
+ }
+ _SEH2_END;
+
+ if (!Hit) Ret = wndpl.showCmd;
+ }
+Exit:
+ UserLeave();
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserGetWindowPlacement(HWND hWnd,
+ WINDOWPLACEMENT *lpwndpl)
+{
+ PWND Wnd;
+ WINDOWPLACEMENT Safepl;
+ NTSTATUS Status;
+ DECLARE_RETURN(BOOL);
+
+ TRACE("Enter NtUserGetWindowPlacement\n");
+ UserEnterShared();
+
+ if (!(Wnd = UserGetWindowObject(hWnd)))
+ {
+ RETURN( FALSE);
+ }
+
+ Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( FALSE);
+ }
+ if(Safepl.length != sizeof(WINDOWPLACEMENT))
+ {
+ RETURN( FALSE);
+ }
+
+ IntGetWindowPlacement(Wnd, &Safepl);
+
+ Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
+ if(!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ RETURN( FALSE);
+ }
+
+ RETURN( TRUE);
+
+CLEANUP:
+ TRACE("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+DWORD
+APIENTRY
+NtUserMinMaximize(
+ HWND hWnd,
+ UINT cmd, // Wine SW_ commands
+ BOOL Hide)
+{
+ PWND pWnd;
+
+ TRACE("Enter NtUserMinMaximize\n");
+ UserEnterExclusive();
+
+ pWnd = UserGetWindowObject(hWnd);
+ if ( !pWnd || // FIXME:
+ pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
+ pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
+ {
+ goto Exit;
+ }
+
+ if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ goto Exit;
+ }
+
+ cmd |= Hide ? SW_HIDE : 0;
+
+ co_WinPosShowWindow(pWnd, cmd);
+
+Exit:
+ TRACE("Leave NtUserMinMaximize\n");
+ UserLeave();
+ return 0; // Always NULL?
+}
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserMoveWindow(
+ HWND hWnd,
+ int X,
+ int Y,
+ int nWidth,
+ int nHeight,
+ BOOL bRepaint)
+{
+ return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
+ (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
+}
+
+/*
+ * @implemented
+ */
+HWND APIENTRY
+NtUserRealChildWindowFromPoint(HWND Parent,
+ LONG x,
+ LONG y)
+{
+ PWND pwndParent;
+ TRACE("Enter NtUserRealChildWindowFromPoint\n");
+ UserEnterShared();
+ if ((pwndParent = UserGetWindowObject(Parent)))
+ {
+ pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y);
+ }
+ UserLeave();
+ TRACE("Leave NtUserRealChildWindowFromPoint\n");
+ return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
+}
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserSetWindowPos(
+ HWND hWnd,
+ HWND hWndInsertAfter,
+ int X,
+ int Y,
+ int cx,
+ int cy,
+ UINT uFlags)
+{
+ DECLARE_RETURN(BOOL);
+ PWND Window, pWndIA;
+ BOOL ret;
+ USER_REFERENCE_ENTRY Ref;
+
+ TRACE("Enter NtUserSetWindowPos\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
+ Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
+ Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
+ {
+ ERR("NtUserSetWindowPos bad window handle!\n");
+ RETURN(FALSE);
+ }
+
+ if ( hWndInsertAfter &&
+ hWndInsertAfter != HWND_BOTTOM &&
+ hWndInsertAfter != HWND_TOPMOST &&
+ hWndInsertAfter != HWND_NOTOPMOST )
+ {
+ if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) ||
+ pWndIA == UserGetDesktopWindow() ||
+ pWndIA == UserGetMessageWindow() )
+ {
+ ERR("NtUserSetWindowPos bad insert window handle!\n");
+ RETURN(FALSE);
+ }
+ }
+
+ /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
+ if (!(uFlags & SWP_NOMOVE))
+ {
+ if (X < -32768) X = -32768;
+ else if (X > 32767) X = 32767;
+ if (Y < -32768) Y = -32768;
+ else if (Y > 32767) Y = 32767;
+ }
+ if (!(uFlags & SWP_NOSIZE))
+ {
+ if (cx < 0) cx = 0;
+ else if (cx > 32767) cx = 32767;
+ if (cy < 0) cy = 0;
+ else if (cy > 32767) cy = 32767;
+ }
+
+ UserRefObjectCo(Window, &Ref);
+ ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
+ UserDerefObjectCo(Window);
+
+ RETURN(ret);
+
+CLEANUP:
+ TRACE("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * @implemented
+ */
+INT APIENTRY
+NtUserSetWindowRgn(
+ HWND hWnd,
+ HRGN hRgn,
+ BOOL bRedraw)
+{
+ HRGN hrgnCopy;
+ PWND Window;
+ INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
+ BOOLEAN Ret = FALSE;
+ DECLARE_RETURN(INT);
+
+ TRACE("Enter NtUserSetWindowRgn\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
+ Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
+ Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
+ {
+ RETURN( 0);
+ }
+
+ if (hRgn) // The region will be deleted in user32.
+ {
+ if (GreIsHandleValid(hRgn))
+ {
+ hrgnCopy = IntSysCreateRectRgn(0, 0, 0, 0);
+ /* The coordinates of a window's window region are relative to the
+ upper-left corner of the window, not the client area of the window. */
+ NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY);
+ }
+ else
+ RETURN( 0);
+ }
+ else
+ {
+ hrgnCopy = NULL;
+ }
+
+ if (Window->hrgnClip)
+ {
+ /* Delete no longer needed region handle */
+ IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
+ GreDeleteObject(Window->hrgnClip);
+ }
+
+ if (hrgnCopy)
+ {
+ /* Set public ownership */
+ IntGdiSetRegionOwner(hrgnCopy, GDI_OBJ_HMGR_PUBLIC);
+ }
+ Window->hrgnClip = hrgnCopy;
+
+ Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) );
+
+ RETURN( (INT)Ret);
+
+CLEANUP:
+ TRACE("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * @implemented
+ */
+DWORD APIENTRY
+NtUserSetInternalWindowPos(
+ HWND hwnd,
+ UINT showCmd,
+ LPRECT lprect,
+ LPPOINT lppt)
+{
+ WINDOWPLACEMENT wndpl;
+ UINT flags;
+ PWND Wnd;
+ RECT rect;
+ POINT pt = {0};
+ DECLARE_RETURN(BOOL);
+ USER_REFERENCE_ENTRY Ref;
+
+ TRACE("Enter NtUserSetWindowPlacement\n");
+ UserEnterExclusive();
+
+ if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME:
+ Wnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
+ Wnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
+ {
+ RETURN( FALSE);
+ }
+
+ _SEH2_TRY
+ {
+ if (lppt)
+ {
+ ProbeForRead(lppt, sizeof(POINT), 1);
+ RtlCopyMemory(&pt, lppt, sizeof(POINT));
+ }
+ if (lprect)
+ {
+ ProbeForRead(lprect, sizeof(RECT), 1);
+ RtlCopyMemory(&rect, lprect, sizeof(RECT));
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(RETURN( FALSE));
+ }
+ _SEH2_END
+
+ wndpl.length = sizeof(wndpl);
+ wndpl.showCmd = showCmd;
+ wndpl.flags = flags = 0;
+
+ if ( lppt )
+ {
+ flags |= PLACE_MIN;
+ wndpl.flags |= WPF_SETMINPOSITION;
+ wndpl.ptMinPosition = pt;
+ }
+ if ( lprect )
+ {
+ flags |= PLACE_RECT;
+ wndpl.rcNormalPosition = rect;
+ }
+
+ UserRefObjectCo(Wnd, &Ref);
+ IntSetWindowPlacement(Wnd, &wndpl, flags);
+ UserDerefObjectCo(Wnd);
+ RETURN(TRUE);
+
+CLEANUP:
+ TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserSetWindowPlacement(HWND hWnd,
+ WINDOWPLACEMENT *lpwndpl)
+{
+ PWND Wnd;
+ WINDOWPLACEMENT Safepl;
+ UINT Flags;
+ DECLARE_RETURN(BOOL);
+ USER_REFERENCE_ENTRY Ref;
+
+ TRACE("Enter NtUserSetWindowPlacement\n");
+ UserEnterExclusive();
+
+ if (!(Wnd = UserGetWindowObject(hWnd)) || // FIXME:
+ Wnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
+ Wnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
+ {
+ RETURN( FALSE);
+ }
+
+ _SEH2_TRY
+ {
+ ProbeForRead(lpwndpl, sizeof(WINDOWPLACEMENT), 1);
+ RtlCopyMemory(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastNtError(_SEH2_GetExceptionCode());
+ _SEH2_YIELD(RETURN( FALSE));
+ }
+ _SEH2_END
+
+ if(Safepl.length != sizeof(WINDOWPLACEMENT))
+ {
+ RETURN( FALSE);
+ }
+
+ Flags = PLACE_MAX | PLACE_RECT;
+ if (Safepl.flags & WPF_SETMINPOSITION) Flags |= PLACE_MIN;
+ UserRefObjectCo(Wnd, &Ref);
+ IntSetWindowPlacement(Wnd, &Safepl, Flags);
+ UserDerefObjectCo(Wnd);
+ RETURN(TRUE);
+
+CLEANUP:
+ TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
+{
+ PWND Window;
+ BOOL ret;
+ DECLARE_RETURN(BOOL);
+ USER_REFERENCE_ENTRY Ref;
+
+ TRACE("Enter NtUserShowWindowAsync\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
+ Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
+ Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
+ {
+ RETURN(FALSE);
+ }
+
+ if ( nCmdShow > SW_MAX )
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ RETURN(FALSE);
+ }
+
+ UserRefObjectCo(Window, &Ref);
+ ret = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 );
+ UserDerefObjectCo(Window);
+ if (-1 == (int) ret || !ret) ret = FALSE;
+
+ RETURN(ret);
+
+CLEANUP:
+ TRACE("Leave NtUserShowWindowAsync, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/*
+ * @implemented
+ */
+BOOL APIENTRY
+NtUserShowWindow(HWND hWnd, LONG nCmdShow)
+{
+ PWND Window;
+ BOOL ret;
+ DECLARE_RETURN(BOOL);
+ USER_REFERENCE_ENTRY Ref;
+
+ TRACE("Enter NtUserShowWindow\n");
+ UserEnterExclusive();
+
+ if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
+ Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
+ Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
+ {
+ RETURN(FALSE);
+ }
+
+ if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ RETURN(FALSE);
+ }
+
+ UserRefObjectCo(Window, &Ref);
+ ret = co_WinPosShowWindow(Window, nCmdShow);
+ UserDerefObjectCo(Window);
+
+ RETURN(ret);
+
+CLEANUP:
+ TRACE("Leave NtUserShowWindow, ret=%i\n",_ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+
+/*
+ * @implemented
+ */
+HWND APIENTRY
+NtUserWindowFromPoint(LONG X, LONG Y)
+{
+ POINT pt;
+ HWND Ret;
+ PWND DesktopWindow = NULL, Window = NULL;
+ USHORT hittest;
+ DECLARE_RETURN(HWND);
+ USER_REFERENCE_ENTRY Ref;
+
+ TRACE("Enter NtUserWindowFromPoint\n");
+ UserEnterExclusive();
+
+ if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
+ {
+ //PTHREADINFO pti;
+
+ pt.x = X;
+ pt.y = Y;
+
+ // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window.
+ // It is possible this referencing is useless, though it should not hurt...
+ UserRefObjectCo(DesktopWindow, &Ref);
+
+ //pti = PsGetCurrentThreadWin32Thread();
+ Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest, FALSE);
+
+ if (Window)
+ {
+ Ret = UserHMGetHandle(Window);
+
+ RETURN( Ret);
+ }
+ }
+
+ RETURN( NULL);
+
+CLEANUP:
+ if (Window) UserDereferenceObject(Window);
+ if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
+
+ TRACE("Leave NtUserWindowFromPoint, ret=%p\n", _ret_);
+ UserLeave();
+ END_CLEANUP;
+}
+
+/* EOF */
--- /dev/null
- (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS user32.dll
+ * FILE: user32/windows/menu.c
+ * PURPOSE: Menus
+ *
+ * PROGRAMMERS: Casper S. Hornstrup
+ * James Tabor
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <user32.h>
+#include <wine/debug.h>
+
+LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active);
+BOOL WINAPI GdiValidateHandle(HGDIOBJ hobj);
+LRESULT DefWndNCHitTest(HWND hWnd, POINT Point);
+void FASTCALL NcGetSysPopupPos(HWND Wnd, RECT *Rect);
+
+WINE_DEFAULT_DEBUG_CHANNEL(menu);
+
+/* internal popup menu window messages */
+
+#define MM_SETMENUHANDLE (WM_USER + 0)
+#define MM_GETMENUHANDLE (WM_USER + 1)
+
+/* internal flags for menu tracking */
+
+#define TF_ENDMENU 0x10000
+#define TF_SUSPENDPOPUP 0x20000
+#define TF_SKIPREMOVE 0x40000
+
+#define ITEM_PREV -1
+#define ITEM_NEXT 1
+
+/* Internal MenuTrackMenu() flags */
+#define TPM_INTERNAL 0xF0000000
+#define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
+#define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
+
+ /* Space between 2 columns */
+#define MENU_COL_SPACE 4
+
+/* top and bottom margins for popup menus */
+#define MENU_TOP_MARGIN 3
+#define MENU_BOTTOM_MARGIN 2
+
+#define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
+
+#define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
+
+#define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
+
+#define MENUITEMINFO_TYPE_MASK \
+ (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
+ MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
+ MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
+
+#define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
+
+#define STATE_MASK (~TYPE_MASK)
+
+#define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
+
+#define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
+
+/* macro to test that flags do not indicate bitmap, ownerdraw or separator */
+#define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
+#define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
+
+#define IS_SYSTEM_MENU(MenuInfo) \
- (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
++ (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
+
+#define IS_SYSTEM_POPUP(MenuInfo) \
- Flags |= menu->fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0;
++ (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
+
+#define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
+
+/* Use global popup window because there's no way 2 menus can
+ * be tracked at the same time. */
+static HWND top_popup;
+static HMENU top_popup_hmenu;
+
+/* Flag set by EndMenu() to force an exit from menu tracking */
+static BOOL fEndMenu = FALSE;
+
+#define MENU_ITEM_HBMP_SPACE (5)
+#define MENU_BAR_ITEMS_SPACE (12)
+#define SEPARATOR_HEIGHT (5)
+#define MENU_TAB_SPACE (8)
+
+typedef struct
+{
+ UINT TrackFlags;
+ HMENU CurrentMenu; /* current submenu (can be equal to hTopMenu)*/
+ HMENU TopMenu; /* initial menu */
+ HWND OwnerWnd; /* where notifications are sent */
+ POINT Pt;
+} MTRACKER;
+
+
+/*********************************************************************
+ * PopupMenu class descriptor
+ */
+const struct builtin_class_descr POPUPMENU_builtin_class =
+{
+ WC_MENU, /* name */
+ CS_SAVEBITS | CS_DBLCLKS, /* style */
+ (WNDPROC) NULL, /* FIXME - procA */
+ (WNDPROC) PopupMenuWndProcW, /* FIXME - procW */
+ sizeof(MENUINFO *), /* extra */
+ (LPCWSTR) IDC_ARROW, /* cursor */
+ (HBRUSH)(COLOR_MENU + 1) /* brush */
+};
+
+#ifndef GET_WORD
+#define GET_WORD(ptr) (*(WORD *)(ptr))
+#endif
+#ifndef GET_DWORD
+#define GET_DWORD(ptr) (*(DWORD *)(ptr))
+#endif
+
+HFONT hMenuFont = NULL;
+HFONT hMenuFontBold = NULL;
+
+/* Dimension of the menu bitmaps */
+static HBITMAP BmpSysMenu = NULL;
+
+static SIZE MenuCharSize;
+
+
+/***********************************************************************
+ * MENU_GetMenu
+ *
+ * Validate the given menu handle and returns the menu structure pointer.
+ */
+FORCEINLINE PMENU MENU_GetMenu(HMENU hMenu)
+{
+ return ValidateHandleNoErr(hMenu, TYPE_MENU);
+}
+
+/***********************************************************************
+ * get_win_sys_menu
+ *
+ * Get the system menu of a window
+ */
+static HMENU get_win_sys_menu( HWND hwnd )
+{
+ HMENU ret = 0;
+ WND *win = ValidateHwnd( hwnd );
+ if (win)
+ {
+ ret = win->SystemMenu;
+ }
+ return ret;
+}
+
+/***********************************************************************
+ * MENU_FindItem
+ *
+ * Find a menu item. Return a pointer on the item, and modifies *hmenu
+ * in case the item was in a sub-menu.
+ */
+ITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
+{
+ MENU *menu;
+ ITEM *fallback = NULL;
+ UINT fallback_pos = 0;
+ UINT i;
+ PITEM pItem;
+
+ if ((*hmenu == (HMENU)0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
+ if (wFlags & MF_BYPOSITION)
+ {
+ if (*nPos >= menu->cItems) return NULL;
+ pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
+ if (pItem) pItem = &pItem[*nPos];
+ return pItem;
+ }
+ else
+ {
+ PITEM item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
+ for (i = 0; item, i < menu->cItems; i++, item++)
+ {
+ if (item->spSubMenu)
+ {
+ PMENU pSubMenu = DesktopPtrToUser(item->spSubMenu);
+ HMENU hsubmenu = UserHMGetHandle(pSubMenu);
+ ITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
+ if (subitem)
+ {
+ *hmenu = hsubmenu;
+ return subitem;
+ }
+ else if (item->wID == *nPos)
+ {
+ /* fallback to this item if nothing else found */
+ fallback_pos = i;
+ fallback = item;
+ }
+ }
+ else if (item->wID == *nPos)
+ {
+ *nPos = i;
+ return item;
+ }
+ }
+ }
+
+ if (fallback)
+ *nPos = fallback_pos;
+
+ return fallback;
+}
+
+#define MAX_GOINTOSUBMENU (0x10)
+UINT FASTCALL
+IntGetMenuDefaultItem(PMENU Menu, BOOL fByPos, UINT gmdiFlags, DWORD *gismc)
+{
+ UINT i = 0;
+ PITEM Item = Menu->rgItems ? DesktopPtrToUser(Menu->rgItems) : NULL;
+
+ /* empty menu */
+ if (!Item) return -1;
+
+ while ( !( Item->fState & MFS_DEFAULT ) )
+ {
+ i++; Item++;
+ if (i >= Menu->cItems ) return -1;
+ }
+
+ /* default: don't return disabled items */
+ if ( (!(GMDI_USEDISABLED & gmdiFlags)) && (Item->fState & MFS_DISABLED )) return -1;
+
+ /* search rekursiv when needed */
+ if ( (Item->fType & MF_POPUP) && (gmdiFlags & GMDI_GOINTOPOPUPS) && Item->spSubMenu)
+ {
+ UINT ret;
+ (*gismc)++;
+ ret = IntGetMenuDefaultItem( DesktopPtrToUser(Item->spSubMenu), fByPos, gmdiFlags, gismc );
+ (*gismc)--;
+ if ( -1 != ret ) return ret;
+
+ /* when item not found in submenu, return the popup item */
+ }
+ return ( fByPos ) ? i : Item->wID;
+}
+
+static BOOL GetMenuItemInfo_common ( HMENU hmenu,
+ UINT item,
+ BOOL bypos,
+ LPMENUITEMINFOW lpmii,
+ BOOL unicode)
+{
+ ITEM *pItem = MENU_FindItem (&hmenu, &item, bypos ? MF_BYPOSITION : 0);
+
+ //debug_print_menuitem("GetMenuItemInfo_common: ", pItem, "");
+
+ if (!pItem)
+ {
+ SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
+ return FALSE;
+ }
+
+ if( lpmii->fMask & MIIM_TYPE)
+ {
+ if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP))
+ {
+ ERR("invalid combination of fMask bits used\n");
+ /* this does not happen on Win9x/ME */
+ SetLastError( ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
+ if( pItem->hbmp) lpmii->fType |= MFT_BITMAP;
+ lpmii->hbmpItem = pItem->hbmp; /* not on Win9x/ME */
+ if( lpmii->fType & MFT_BITMAP)
+ {
+ lpmii->dwTypeData = (LPWSTR) pItem->hbmp;
+ lpmii->cch = 0;
+ }
+ else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR))
+ {
+ /* this does not happen on Win9x/ME */
+ lpmii->dwTypeData = 0;
+ lpmii->cch = 0;
+ }
+ }
+
+ /* copy the text string */
+ if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)))
+ {
+ if( !pItem->Xlpstr )
+ { // Very strange this fixes a wine test with a crash.
+ if(lpmii->dwTypeData && lpmii->cch && !(GdiValidateHandle((HGDIOBJ)lpmii->dwTypeData)) )
+ {
+ lpmii->cch = 0;
+ if( unicode)
+ *((WCHAR *)lpmii->dwTypeData) = 0;
+ else
+ *((CHAR *)lpmii->dwTypeData) = 0;
+ }
+ }
+ else
+ {
+ int len;
+ LPWSTR text = DesktopPtrToUser(pItem->Xlpstr);
+ if (unicode)
+ {
+ len = strlenW(text);
+ if(lpmii->dwTypeData && lpmii->cch)
+ lstrcpynW(lpmii->dwTypeData, text, lpmii->cch);
+ }
+ else
+ {
+ len = WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL ) - 1;
+ if(lpmii->dwTypeData && lpmii->cch)
+ if (!WideCharToMultiByte( CP_ACP, 0, text, -1,
+ (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
+ ((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0;
+ }
+ /* if we've copied a substring we return its length */
+ if(lpmii->dwTypeData && lpmii->cch)
+ if (lpmii->cch <= len + 1)
+ lpmii->cch--;
+ else
+ lpmii->cch = len;
+ else
+ {
+ /* return length of string */
+ /* not on Win9x/ME if fType & MFT_BITMAP */
+ lpmii->cch = len;
+ }
+ }
+ }
+
+ if (lpmii->fMask & MIIM_FTYPE)
+ lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
+
+ if (lpmii->fMask & MIIM_BITMAP)
+ lpmii->hbmpItem = pItem->hbmp;
+
+ if (lpmii->fMask & MIIM_STATE)
+ lpmii->fState = pItem->fState & MENUITEMINFO_STATE_MASK;
+
+ if (lpmii->fMask & MIIM_ID)
+ lpmii->wID = pItem->wID;
+
+ if (lpmii->fMask & MIIM_SUBMENU && pItem->spSubMenu )
+ {
+ PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
+ HMENU hSubMenu = UserHMGetHandle(pSubMenu);
+ lpmii->hSubMenu = hSubMenu;
+ }
+ else
+ {
+ /* hSubMenu is always cleared
+ * (not on Win9x/ME ) */
+ lpmii->hSubMenu = 0;
+ }
+
+ if (lpmii->fMask & MIIM_CHECKMARKS)
+ {
+ lpmii->hbmpChecked = pItem->hbmpChecked;
+ lpmii->hbmpUnchecked = pItem->hbmpUnchecked;
+ }
+ if (lpmii->fMask & MIIM_DATA)
+ lpmii->dwItemData = pItem->dwItemData;
+
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuGetRosMenuInfo
+ *
+ * Get full information about menu
+ */
+static BOOL FASTCALL
+MenuGetRosMenuInfo(PROSMENUINFO MenuInfo, HMENU Menu)
+{
+ PMENU pMenu;
+ if (!(pMenu = ValidateHandleNoErr(Menu, TYPE_MENU))) return FALSE;
+
+ MenuInfo->hbrBack = pMenu->hbrBack;
+ MenuInfo->dwContextHelpID = pMenu->dwContextHelpId;
+ MenuInfo->cyMax = pMenu->cyMax;
+ MenuInfo->dwMenuData = pMenu->dwMenuData;
+ MenuInfo->dwStyle = pMenu->fFlags & MNS_STYLE_MASK;
+
+ MenuInfo->cItems = pMenu->cItems;
+
+ MenuInfo->iItem = pMenu->iItem;
+ MenuInfo->cxMenu = pMenu->cxMenu;
+ MenuInfo->cyMenu = pMenu->cyMenu;
+ MenuInfo->spwndNotify = pMenu->spwndNotify;
+ MenuInfo->cxTextAlign = pMenu->cxTextAlign;
+ MenuInfo->iTop = pMenu->iMaxTop;
+ MenuInfo->iMaxTop = pMenu->iMaxTop;
+ MenuInfo->dwArrowsOn = pMenu->dwArrowsOn;
+
+ MenuInfo->fFlags = pMenu->fFlags;
+ MenuInfo->Self = pMenu->head.h;
+ MenuInfo->TimeToHide = pMenu->TimeToHide;
+ MenuInfo->Wnd = pMenu->hWnd;
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuSetRosMenuInfo
+ *
+ * Set full information about menu
+ */
+static BOOL FASTCALL
+MenuSetRosMenuInfo(PROSMENUINFO MenuInfo)
+{
+ MenuInfo->cbSize = sizeof(ROSMENUINFO);
+ MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE;
+
+ return NtUserThunkedMenuInfo(MenuInfo->Self, (LPCMENUINFO)MenuInfo);
+}
+
+/***********************************************************************
+ * MenuInitRosMenuItemInfo
+ *
+ * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
+ */
+static VOID FASTCALL
+MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
+{
+ ZeroMemory(ItemInfo, sizeof(ROSMENUITEMINFO));
+ ItemInfo->cbSize = sizeof(ROSMENUITEMINFO);
+}
+
+/***********************************************************************
+ * MenuGetRosMenuItemInfo
+ *
+ * Get full information about a menu item
+ */
+static BOOL FASTCALL
+MenuGetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
+{
+ PITEM pItem;
+ UINT Save_Mask = ItemInfo->fMask; /* Save the org mask bits. */
+
+ if (ItemInfo->dwTypeData != NULL)
+ {
+ HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
+ }
+
+ ItemInfo->dwTypeData = NULL;
+
+ if (!(pItem = MENU_FindItem(&Menu, &Index, MF_BYPOSITION)))
+ {
+ ItemInfo->fType = 0;
+ return FALSE;
+ }
+
+ ItemInfo->fType = pItem->fType;
+ ItemInfo->hbmpItem = pItem->hbmp;
+ ItemInfo->hbmpChecked = pItem->hbmpChecked;
+ ItemInfo->hbmpUnchecked = pItem->hbmpUnchecked;
+ ItemInfo->dwItemData = pItem->dwItemData;
+ ItemInfo->wID = pItem->wID;
+ ItemInfo->fState = pItem->fState;
+
+ if (pItem->spSubMenu)
+ {
+ PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
+ HMENU hSubMenu = UserHMGetHandle(pSubMenu);
+ ItemInfo->hSubMenu = hSubMenu;
+ }
+ else
+ ItemInfo->hSubMenu = NULL;
+
+ if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING)
+ {
+ LPWSTR lpstr = pItem->lpstr.Buffer ? DesktopPtrToUser(pItem->lpstr.Buffer) : NULL;
+ if (lpstr)
+ {
+ ItemInfo->cch = pItem->lpstr.Length / sizeof(WCHAR);
+ ItemInfo->cch++;
+ ItemInfo->dwTypeData = HeapAlloc(GetProcessHeap(), 0, ItemInfo->cch * sizeof(WCHAR));
+ if (ItemInfo->dwTypeData == NULL)
+ {
+ return FALSE;
+ }
+ RtlCopyMemory(ItemInfo->dwTypeData, lpstr, min(ItemInfo->cch * sizeof(WCHAR), pItem->lpstr.MaximumLength));
+ }
+ else
+ {
+ ItemInfo->cch = 0;
+ }
+ }
+
+ ItemInfo->Rect.left = pItem->xItem;
+ ItemInfo->Rect.top = pItem->yItem;
+ ItemInfo->Rect.right = pItem->cxItem; // Do this for now......
+ ItemInfo->Rect.bottom = pItem->cyItem;
+ ItemInfo->dxTab = pItem->dxTab;
+ ItemInfo->lpstr = pItem->lpstr.Buffer ? DesktopPtrToUser(pItem->lpstr.Buffer) : NULL;
+ ItemInfo->maxBmpSize.cx = pItem->cxBmp;
+ ItemInfo->maxBmpSize.cy = pItem->cyBmp;
+
+ ItemInfo->fMask = Save_Mask;
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuSetRosMenuItemInfo
+ *
+ * Set selected information about a menu item, need to set the mask bits.
+ */
+static BOOL FASTCALL
+MenuSetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
+{
+ BOOL Ret;
+
+ if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING &&
+ ItemInfo->dwTypeData != NULL)
+ {
+ ItemInfo->cch = strlenW(ItemInfo->dwTypeData);
+ }
+ if (ItemInfo->hSubMenu)
+ {
+ if (!IsMenu(ItemInfo->hSubMenu)) ItemInfo->hSubMenu = NULL;
+ }
+ Ret = NtUserThunkedMenuItemInfo(Menu, Index, TRUE, FALSE, (LPMENUITEMINFOW)ItemInfo, NULL);
+ return Ret;
+}
+
+/***********************************************************************
+ * MenuCleanupRosMenuItemInfo
+ *
+ * Cleanup after use of MenuGet/SetRosMenuItemInfo
+ */
+static VOID FASTCALL
+MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
+{
+ if (ItemInfo->dwTypeData != NULL)
+ {
+ HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
+ ItemInfo->dwTypeData = NULL;
+ }
+}
+
+/***********************************************************************
+ * MenuInitSysMenuPopup
+ *
+ * Grey the appropriate items in System menu.
+ */
+void FASTCALL MenuInitSysMenuPopup(HMENU hmenu, DWORD style, DWORD clsStyle, LONG HitTest )
+{
+ BOOL gray;
+ UINT DefItem;
+ #if 0
+ MENUITEMINFOW mii;
+ #endif
+
+ gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
+ EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+ gray = ((style & WS_MAXIMIZE) != 0);
+ EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
+ gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
+ EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+ gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
+ EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
+ gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
+ EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
+ gray = (clsStyle & CS_NOCLOSE) != 0;
+
+ /* The menu item must keep its state if it's disabled */
+ if(gray)
+ EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
+
+ /* Set default menu item */
+ if(style & WS_MINIMIZE) DefItem = SC_RESTORE;
+ else if(HitTest == HTCAPTION) DefItem = ((style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE);
+ else DefItem = SC_CLOSE;
+#if 0
+ mii.cbSize = sizeof(MENUITEMINFOW);
+ mii.fMask |= MIIM_STATE;
+ if((DefItem != SC_CLOSE) && GetMenuItemInfoW(hmenu, DefItem, FALSE, &mii) &&
+ (mii.fState & (MFS_GRAYED | MFS_DISABLED))) DefItem = SC_CLOSE;
+#endif
+ SetMenuDefaultItem(hmenu, DefItem, MF_BYCOMMAND);
+}
+
+/******************************************************************************
+ *
+ * UINT MenuGetStartOfNextColumn(
+ * PROSMENUINFO MenuInfo)
+ *
+ *****************************************************************************/
+
+static UINT MENU_GetStartOfNextColumn(
+ HMENU hMenu )
+{
+ MENU *menu = MENU_GetMenu(hMenu);
+ PITEM pItem;
+ UINT i;
+
+ if(!menu)
+ return NO_SELECTED_ITEM;
+
+ i = menu->iItem + 1;
+ if( i == NO_SELECTED_ITEM )
+ return i;
+
+ pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
+ if (!pItem) return NO_SELECTED_ITEM;
+ for( ; i < menu->cItems; ++i ) {
+ if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
+ return i;
+ }
+
+ return NO_SELECTED_ITEM;
+}
+
+/******************************************************************************
+ *
+ * UINT MenuGetStartOfPrevColumn(
+ * PROSMENUINFO MenuInfo)
+ *
+ *****************************************************************************/
+static UINT MENU_GetStartOfPrevColumn(
+ HMENU hMenu )
+{
+ MENU *menu = MENU_GetMenu(hMenu);
+ UINT i;
+ PITEM pItem;
+
+ if( !menu )
+ return NO_SELECTED_ITEM;
+
+ if( menu->iItem == 0 || menu->iItem == NO_SELECTED_ITEM )
+ return NO_SELECTED_ITEM;
+
+ pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
+ if (!pItem) return NO_SELECTED_ITEM;
+
+ /* Find the start of the column */
+
+ for(i = menu->iItem; i != 0 &&
+ !(pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK));
+ --i); /* empty */
+
+ if(i == 0)
+ return NO_SELECTED_ITEM;
+
+ for(--i; i != 0; --i) {
+ if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
+ break;
+ }
+
+ TRACE("ret %d.\n", i );
+
+ return i;
+}
+
+/***********************************************************************
+ * MenuLoadBitmaps
+ *
+ * Load the arrow bitmap. We can't do this from MenuInit since user32
+ * can also be used (and thus initialized) from text-mode.
+ */
+static void FASTCALL
+MenuLoadBitmaps(VOID)
+{
+ /* Load system buttons bitmaps */
+ if (NULL == BmpSysMenu)
+ {
+ BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
+ }
+}
+/////////// Make gpsi OBMI via callback //////////////
+/***********************************************************************
+ * get_arrow_bitmap
+ */
+HBITMAP get_arrow_bitmap(void)
+{
+ static HBITMAP arrow_bitmap;
+
+ if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW));
+ return arrow_bitmap;
+}
+
+/***********************************************************************
+ * get_down_arrow_bitmap DFCS_MENUARROWDOWN
+ */
+HBITMAP get_down_arrow_bitmap(void)
+{
+ static HBITMAP arrow_bitmap;
+
+ if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW));
+ return arrow_bitmap;
+}
+
+/***********************************************************************
+ * get_down_arrow_inactive_bitmap DFCS_MENUARROWDOWN | DFCS_INACTIVE
+ */
+HBITMAP get_down_arrow_inactive_bitmap(void)
+{
+ static HBITMAP arrow_bitmap;
+
+ if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI));
+ return arrow_bitmap;
+}
+
+/***********************************************************************
+ * get_up_arrow_bitmap DFCS_MENUARROWUP
+ */
+HBITMAP get_up_arrow_bitmap(void)
+{
+ static HBITMAP arrow_bitmap;
+
+ if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW));
+ return arrow_bitmap;
+}
+
+/***********************************************************************
+ * get_up_arrow_inactive_bitmap DFCS_MENUARROWUP | DFCS_INACTIVE
+ */
+static HBITMAP get_up_arrow_inactive_bitmap(void)
+{
+ static HBITMAP arrow_bitmap;
+
+ if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI));
+ return arrow_bitmap;
+}
+////////////////
+/***********************************************************************
+ * MenuFindSubMenu
+ *
+ * Find a Sub menu. Return the position of the submenu, and modifies
+ * *hmenu in case it is found in another sub-menu.
+ * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
+ */
+static UINT FASTCALL MenuFindSubMenu(HMENU *hmenu, HMENU hSubTarget )
+{
+ PMENU menu, pSubMenu;
+ HMENU hSubMenu;
+ UINT i;
+ PITEM item;
+
+ if (((*hmenu)==(HMENU)0xffff) ||(!(menu = MENU_GetMenu(*hmenu))))
+ return NO_SELECTED_ITEM;
+
+ item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
+ for (i = 0; i < menu->cItems; i++, item++)
+ {
+ if (!item->spSubMenu)
+ continue;
+ else
+ {
+ pSubMenu = DesktopPtrToUser(item->spSubMenu);
+ hSubMenu = UserHMGetHandle(pSubMenu);
+ if (hSubMenu == hSubTarget)
+ {
+ return i;
+ }
+ else
+ {
+ HMENU hsubmenu = hSubMenu;
+ UINT pos = MenuFindSubMenu( &hsubmenu, hSubTarget );
+ if (pos != NO_SELECTED_ITEM)
+ {
+ *hmenu = hsubmenu;
+ return pos;
+ }
+ }
+ }
+ }
+ return NO_SELECTED_ITEM;
+}
+
+/***********************************************************************
+ * MENU_AdjustMenuItemRect
+ *
+ * Adjust menu item rectangle according to scrolling state.
+ */
+static void
+MENU_AdjustMenuItemRect(PROSMENUINFO menu, LPRECT rect)
+{
+ if (menu->dwArrowsOn)
+ {
+ UINT arrow_bitmap_height;
+ BITMAP bmp;
+
+ GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
+ arrow_bitmap_height = bmp.bmHeight;
+ rect->top += arrow_bitmap_height - menu->iTop;
+ rect->bottom += arrow_bitmap_height - menu->iTop;
+ }
+}
+
+/***********************************************************************
+ * MenuDrawPopupGlyph
+ *
+ * Draws popup magic glyphs (can be found in system menu).
+ */
+static void FASTCALL
+MenuDrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hilite)
+{
+ LOGFONTW lf;
+ HFONT hFont, hOldFont;
+ COLORREF clrsave;
+ INT bkmode;
+ TCHAR symbol;
+ switch (popupMagic)
+ {
+ case (INT_PTR) HBMMENU_POPUP_RESTORE:
+ symbol = '2';
+ break;
+ case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+ symbol = '0';
+ break;
+ case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+ symbol = '1';
+ break;
+ case (INT_PTR) HBMMENU_POPUP_CLOSE:
+ symbol = 'r';
+ break;
+ default:
+ ERR("Invalid popup magic bitmap %d\n", (int)popupMagic);
+ return;
+ }
+ ZeroMemory(&lf, sizeof(LOGFONTW));
+ InflateRect(r, -2, -2);
+ lf.lfHeight = r->bottom - r->top;
+ lf.lfWidth = 0;
+ lf.lfWeight = FW_NORMAL;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lstrcpy(lf.lfFaceName, TEXT("Marlett"));
+ hFont = CreateFontIndirect(&lf);
+ /* save font and text color */
+ hOldFont = SelectObject(dc, hFont);
+ clrsave = GetTextColor(dc);
+ bkmode = GetBkMode(dc);
+ /* set color and drawing mode */
+ SetBkMode(dc, TRANSPARENT);
+ if (inactive)
+ {
+ /* draw shadow */
+ if (!hilite)
+ {
+ SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ TextOut(dc, r->left + 1, r->top + 1, &symbol, 1);
+ }
+ }
+ SetTextColor(dc, GetSysColor(inactive ? COLOR_GRAYTEXT : (hilite ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)));
+ /* draw selected symbol */
+ TextOut(dc, r->left, r->top, &symbol, 1);
+ /* restore previous settings */
+ SetTextColor(dc, clrsave);
+ SelectObject(dc, hOldFont);
+ SetBkMode(dc, bkmode);
+ DeleteObject(hFont);
+}
+
+/***********************************************************************
+ * MenuFindItemByKey
+ *
+ * Find the menu item selected by a key press.
+ * Return item id, -1 if none, -2 if we should close the menu.
+ */
+static UINT FASTCALL MENU_FindItemByKey(HWND WndOwner, HMENU hmenu,
+ WCHAR Key, BOOL ForceMenuChar)
+{
+ LRESULT MenuChar;
+ WORD Flags = 0;
+
+ TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key, Key, hmenu );
+
+ if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(WndOwner), 0);
+ if (hmenu)
+ {
+ MENU *menu = MENU_GetMenu( hmenu );
+ ITEM *item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
+
+ if ( !ForceMenuChar )
+ {
+ UINT i;
+ BOOL cjk = GetSystemMetrics( SM_DBCSENABLED );
+
+ for (i = 0; i < menu->cItems; i++, item++)
+ {
+ LPWSTR text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
+ if( text)
+ {
+ const WCHAR *p = text - 2;
+ do
+ {
+ const WCHAR *q = p + 2;
+ p = strchrW (q, '&');
+ if (!p && cjk) p = strchrW (q, '\036'); /* Japanese Win16 */
+ }
+ while (p != NULL && p [1] == '&');
+ if (p && (toupperW(p[1]) == toupperW(Key))) return i;
+ }
+ }
+ }
+
+ Flags |= menu->fFlags & MNF_POPUP ? MF_POPUP : 0;
- register int i = 0;
++ Flags |= menu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0;
+
+ MenuChar = SendMessageW( WndOwner, WM_MENUCHAR,
+ MAKEWPARAM(Key, Flags), (LPARAM) hmenu);
+ if (HIWORD(MenuChar) == MNC_EXECUTE) return LOWORD(MenuChar);
+ if (HIWORD(MenuChar) == MNC_CLOSE) return (UINT)(-2);
+ }
+ return (UINT)(-1);
+}
+
+/***********************************************************************
+ * MenuGetBitmapItemSize
+ *
+ * Get the size of a bitmap item.
+ */
+static void FASTCALL MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *size, HWND WndOwner)
+{
+ BITMAP bm;
+ HBITMAP bmp = lpitem->hbmpItem;
+
+ size->cx = size->cy = 0;
+
+ /* check if there is a magic menu item associated with this item */
+ if (IS_MAGIC_BITMAP(bmp))
+ {
+ switch((INT_PTR) bmp)
+ {
+ case (INT_PTR)HBMMENU_CALLBACK:
+ {
+ MEASUREITEMSTRUCT measItem;
+ measItem.CtlType = ODT_MENU;
+ measItem.CtlID = 0;
+ measItem.itemID = lpitem->wID;
+ measItem.itemWidth = lpitem->Rect.right - lpitem->Rect.left;
+ measItem.itemHeight = lpitem->Rect.bottom - lpitem->Rect.top;
+ measItem.itemData = lpitem->dwItemData;
+ SendMessageW( WndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem);
+ size->cx = measItem.itemWidth;
+ size->cy = measItem.itemHeight;
+ return;
+ }
+ break;
+
+ case (INT_PTR) HBMMENU_SYSTEM:
+ if (0 != lpitem->dwItemData)
+ {
+ bmp = (HBITMAP) lpitem->dwItemData;
+ break;
+ }
+ /* fall through */
+ case (INT_PTR) HBMMENU_MBAR_RESTORE:
+ case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
+ case (INT_PTR) HBMMENU_MBAR_CLOSE:
+ case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
+ case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
+ case (INT_PTR) HBMMENU_POPUP_CLOSE:
+ case (INT_PTR) HBMMENU_POPUP_RESTORE:
+ case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+ case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+ /* FIXME: Why we need to subtract these magic values? */
+ /* to make them smaller than the menu bar? */
+ size->cx = GetSystemMetrics(SM_CXSIZE) - 2;
+ size->cy = GetSystemMetrics(SM_CYSIZE) - 4;
+ return;
+ }
+ }
+
+ if (GetObjectW(bmp, sizeof(BITMAP), &bm))
+ {
+ size->cx = bm.bmWidth;
+ size->cy = bm.bmHeight;
+ }
+}
+
+/***********************************************************************
+ * MenuDrawBitmapItem
+ *
+ * Draw a bitmap item.
+ */
+static void FASTCALL MenuDrawBitmapItem(HDC hdc, PROSMENUITEMINFO lpitem, const RECT *rect,
+ PROSMENUINFO MenuInfo, HWND WndOwner, UINT odaction, BOOL MenuBar)
+{
+ BITMAP bm;
+ DWORD rop;
+ HDC hdcMem;
+ HBITMAP bmp;
+ int w = rect->right - rect->left;
+ int h = rect->bottom - rect->top;
+ int bmp_xoffset = 0;
+ int left, top;
+ HBITMAP hbmToDraw = lpitem->hbmpItem;
+ bmp = hbmToDraw;
+
+ /* Check if there is a magic menu item associated with this item */
+ if (IS_MAGIC_BITMAP(hbmToDraw))
+ {
+ UINT flags = 0;
+ RECT r;
+
+ r = *rect;
+ switch ((INT_PTR)hbmToDraw)
+ {
+ case (INT_PTR)HBMMENU_SYSTEM:
+ if (lpitem->dwTypeData)
+ {
+ bmp = (HBITMAP)lpitem->dwTypeData;
+ if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
+ }
+ else
+ {
+ if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
+ bmp = BmpSysMenu;
+ if (! GetObjectW(bmp, sizeof(bm), &bm)) return;
+ /* only use right half of the bitmap */
+ bmp_xoffset = bm.bmWidth / 2;
+ bm.bmWidth -= bmp_xoffset;
+ }
+ goto got_bitmap;
+ case (INT_PTR)HBMMENU_MBAR_RESTORE:
+ flags = DFCS_CAPTIONRESTORE;
+ break;
+ case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
+ r.right += 1;
+ flags = DFCS_CAPTIONMIN;
+ break;
+ case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
+ r.right += 1;
+ flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
+ break;
+ case (INT_PTR)HBMMENU_MBAR_CLOSE:
+ flags = DFCS_CAPTIONCLOSE;
+ break;
+ case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
+ flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
+ break;
+ case (INT_PTR)HBMMENU_CALLBACK:
+ {
+ DRAWITEMSTRUCT drawItem;
+ POINT origorg;
+ drawItem.CtlType = ODT_MENU;
+ drawItem.CtlID = 0;
+ drawItem.itemID = lpitem->wID;
+ drawItem.itemAction = odaction;
+ drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0;
+ drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0;
+ drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0;
+ drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0;
+ drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0;
+ //drawItem.itemState |= (!(MenuInfo->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0;
+ //drawItem.itemState |= (MenuInfo->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0;
+ drawItem.hwndItem = (HWND)MenuInfo->Self;
+ drawItem.hDC = hdc;
+ drawItem.rcItem = *rect;
+ drawItem.itemData = lpitem->dwItemData;
+ /* some applications make this assumption on the DC's origin */
+ SetViewportOrgEx( hdc, lpitem->Rect.left, lpitem->Rect.top, &origorg);
+ OffsetRect( &drawItem.rcItem, - lpitem->Rect.left, - lpitem->Rect.top);
+ SendMessageW( WndOwner, WM_DRAWITEM, 0, (LPARAM)&drawItem);
+ SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
+ return;
+ }
+ break;
+
+ case (INT_PTR) HBMMENU_POPUP_CLOSE:
+ case (INT_PTR) HBMMENU_POPUP_RESTORE:
+ case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+ case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+ MenuDrawPopupGlyph(hdc, &r, (INT_PTR)hbmToDraw, lpitem->fState & MF_GRAYED, lpitem->fState & MF_HILITE);
+ return;
+ }
+ InflateRect(&r, -1, -1);
+ if (0 != (lpitem->fState & MF_HILITE))
+ {
+ flags |= DFCS_PUSHED;
+ }
+ DrawFrameControl(hdc, &r, DFC_CAPTION, flags);
+ return;
+ }
+
+ if (!bmp || !GetObjectW( bmp, sizeof(bm), &bm )) return;
+
+ got_bitmap:
+ hdcMem = CreateCompatibleDC( hdc );
+ SelectObject( hdcMem, bmp );
+
+ /* handle fontsize > bitmap_height */
+ top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
+ left=rect->left;
+ rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
+ if ((lpitem->fState & MF_HILITE) && lpitem->hbmpItem)
+ SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
+ BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
+ DeleteDC( hdcMem );
+}
+
+/***********************************************************************
+ * MenuCalcItemSize
+ *
+ * Calculate the size of the menu item and store it in lpitem->rect.
+ */
+static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMENUINFO MenuInfo, HWND hwndOwner,
+ INT orgX, INT orgY, BOOL menuBar, BOOL textandbmp)
+{
+ WCHAR *p;
+ UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
+ UINT arrow_bitmap_width;
+ BITMAP bm;
+ INT itemheight = 0;
+
+ TRACE("dc=%x owner=%x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
+
+ GetObjectW( get_arrow_bitmap(), sizeof(bm), &bm );
+ arrow_bitmap_width = bm.bmWidth;
+
+ MenuCharSize.cx = GdiGetCharDimensions( hdc, NULL, &MenuCharSize.cy );
+
+ SetRect( &lpitem->Rect, orgX, orgY, orgX, orgY );
+
+ if (lpitem->fType & MF_OWNERDRAW)
+ {
+ MEASUREITEMSTRUCT mis;
+ mis.CtlType = ODT_MENU;
+ mis.CtlID = 0;
+ mis.itemID = lpitem->wID;
+ mis.itemData = lpitem->dwItemData;
+ mis.itemHeight = HIWORD( GetDialogBaseUnits());
+ mis.itemWidth = 0;
+ SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
+ /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
+ * width of a menufont character to the width of an owner-drawn menu.
+ */
+ lpitem->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx;
+ if (menuBar) {
+ /* under at least win95 you seem to be given a standard
+ height for the menu and the height value is ignored */
+ lpitem->Rect.bottom += GetSystemMetrics(SM_CYMENUSIZE);
+ } else
+ lpitem->Rect.bottom += mis.itemHeight;
+ // Or this,
+ //Item->cxBmp = mis.itemWidth;
+ //Item->cyBmp = mis.itemHeight;
+ TRACE("id=%04lx size=%dx%d\n",
+ lpitem->wID, lpitem->Rect.right-lpitem->Rect.left,
+ lpitem->Rect.bottom-lpitem->Rect.top);
+ return;
+ }
+
+ if (lpitem->fType & MF_SEPARATOR)
+ {
+ lpitem->Rect.bottom += GetSystemMetrics( SM_CYMENUSIZE)/2;//SEPARATOR_HEIGHT;
+ if( !menuBar)
+ lpitem->Rect.right += arrow_bitmap_width/*check_bitmap_width*/ + MenuCharSize.cx;
+ return;
+ }
+
+ lpitem->dxTab = 0;
+
+ if (lpitem->hbmpItem)
+ {
+ SIZE size;
+
+ if (!menuBar) {
+ MenuGetBitmapItemSize(lpitem, &size, hwndOwner );
+ /* Keep the size of the bitmap in callback mode to be able
+ * to draw it correctly */
+ lpitem->maxBmpSize = size;
+ MenuInfo->cxTextAlign = max(MenuInfo->cxTextAlign, size.cx);
+ MenuSetRosMenuInfo(MenuInfo);
+ lpitem->Rect.right += size.cx + 2;
+ itemheight = size.cy + 2;
+
+ if( !(MenuInfo->dwStyle & MNS_NOCHECK))
+ lpitem->Rect.right += 2 * check_bitmap_width;
+ lpitem->Rect.right += 4 + MenuCharSize.cx;
+ lpitem->dxTab = lpitem->Rect.right;
+ lpitem->Rect.right += arrow_bitmap_width;//check_bitmap_width;
+ } else /* hbmpItem & MenuBar */ {
+ MenuGetBitmapItemSize(lpitem, &size, hwndOwner );
+ lpitem->Rect.right += size.cx;
+ if( lpitem->lpstr) lpitem->Rect.right += 2;
+ itemheight = size.cy;
+
+ /* Special case: Minimize button doesn't have a space behind it. */
+ if (lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE ||
+ lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D)
+ lpitem->Rect.right -= 1;
+ }
+ }
+ else if (!menuBar) {
+ if( !(MenuInfo->dwStyle & MNS_NOCHECK))
+ lpitem->Rect.right += check_bitmap_width;
+ lpitem->Rect.right += 4 + MenuCharSize.cx;
+ lpitem->dxTab = lpitem->Rect.right;
+ lpitem->Rect.right += check_bitmap_width;
+ }
+
+ /* it must be a text item - unless it's the system menu */
+ if (!(lpitem->fType & MF_SYSMENU) && lpitem->lpstr) {
+ HFONT hfontOld = NULL;
+ RECT rc = lpitem->Rect;
+ LONG txtheight, txtwidth;
+
+ if ( lpitem->fState & MFS_DEFAULT ) {
+ hfontOld = SelectObject( hdc, hMenuFontBold );
+ }
+ if (menuBar) {
+ txtheight = DrawTextW( hdc, lpitem->lpstr, -1, &rc,
+ DT_SINGLELINE|DT_CALCRECT);
+ lpitem->Rect.right += rc.right - rc.left;
+ itemheight = max( max( itemheight, txtheight),
+ GetSystemMetrics( SM_CYMENU) - 1);
+ lpitem->Rect.right += 2 * MenuCharSize.cx;
+ } else {
+ if ((p = strchrW( lpitem->lpstr, '\t' )) != NULL) {
+ RECT tmprc = rc;
+ LONG tmpheight;
+ int n = (int)( p - lpitem->lpstr);
+ /* Item contains a tab (only meaningful in popup menus) */
+ /* get text size before the tab */
+ txtheight = DrawTextW( hdc, lpitem->lpstr, n, &rc,
+ DT_SINGLELINE|DT_CALCRECT);
+ txtwidth = rc.right - rc.left;
+ p += 1; /* advance past the Tab */
+ /* get text size after the tab */
+ tmpheight = DrawTextW( hdc, p, -1, &tmprc,
+ DT_SINGLELINE|DT_CALCRECT);
+ lpitem->dxTab += txtwidth;
+ txtheight = max( txtheight, tmpheight);
+ txtwidth += MenuCharSize.cx + /* space for the tab */
+ tmprc.right - tmprc.left; /* space for the short cut */
+ } else {
+ txtheight = DrawTextW( hdc, lpitem->lpstr, -1, &rc,
+ DT_SINGLELINE|DT_CALCRECT);
+ txtwidth = rc.right - rc.left;
+ lpitem->dxTab += txtwidth;
+ }
+ lpitem->Rect.right += 2 + txtwidth;
+ itemheight = max( itemheight,
+ max( txtheight + 2, MenuCharSize.cy + 4));
+ }
+ if (hfontOld) SelectObject (hdc, hfontOld);
+ } else if( menuBar) {
+ itemheight = max( itemheight, GetSystemMetrics(SM_CYMENU)-1);
+ }
+ lpitem->Rect.bottom += itemheight;
+ TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->Rect.left, lpitem->Rect.top, lpitem->Rect.right, lpitem->Rect.bottom);
+}
+
+/***********************************************************************
+ * MENU_GetMaxPopupHeight
+ */
+static UINT
+MENU_GetMaxPopupHeight(PROSMENUINFO lppop)
+{
+ if (lppop->cyMax)
++ {
++ //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
+ return lppop->cyMax;
++ }
++ //ERR("MGMaxPH SyMax %d\n",GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYBORDER));
+ return GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYBORDER);
+}
+
+/***********************************************************************
+ * MenuPopupMenuCalcSize
+ *
+ * Calculate the size of a popup menu.
+ */
+static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner)
+{
+ ROSMENUITEMINFO lpitem;
+ HDC hdc;
+ int start, i;
+ int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight;
+ BOOL textandbmp = FALSE;
+
+ MenuInfo->cxMenu = MenuInfo->cyMenu = 0;
+ if (MenuInfo->cItems == 0)
+ {
+ MenuSetRosMenuInfo(MenuInfo);
+ return;
+ }
+
+ hdc = GetDC(NULL);
+ SelectObject( hdc, hMenuFont );
+
+ start = 0;
+ maxX = 2 + 1;
+
+ MenuInfo->cxTextAlign = 0;
+
+ MenuInitRosMenuItemInfo(&lpitem);
+ //MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
+ while (start < MenuInfo->cItems)
+ {
+ //lpitem = &lppop->items[start];
+ orgX = maxX;
+ //if( lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))
+ // orgX += MENU_COL_SPACE;
+ orgY = 2;//MENU_TOP_MARGIN;
+
+ maxTab = maxTabWidth = 0;
+ /* Parse items until column break or end of menu */
+ for (i = start; i < MenuInfo->cItems; i++)//, lpitem++)
+ {
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i, &lpitem))
+ {
+ MenuCleanupRosMenuItemInfo(&lpitem);
+ MenuSetRosMenuInfo(MenuInfo);
+ return;
+ }
+ if (i != start &&
+ (lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
+
+
+ MenuCalcItemSize(hdc, &lpitem, MenuInfo, WndOwner, orgX, orgY, FALSE, textandbmp);
+ if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &lpitem))
+ {
+ MenuCleanupRosMenuItemInfo(&lpitem);
+ MenuSetRosMenuInfo(MenuInfo);
+ return;
+ }
+
+ maxX = max(maxX, lpitem.Rect.right);
+ orgY = lpitem.Rect.bottom;
+ if (IS_STRING_ITEM(lpitem.fType) && lpitem.dxTab )
+ {
+ maxTab = max( maxTab, lpitem.dxTab );
+ maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.dxTab);
+ }
+ if( lpitem.lpstr && lpitem.hbmpItem) textandbmp = TRUE;
+ }
+
+ /* Finish the column (set all items to the largest width found) */
+ maxX = max( maxX, maxTab + maxTabWidth );
+ while (start < i)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem))
+ {
+ lpitem.Rect.right = maxX;
+ if (IS_STRING_ITEM(lpitem.fType) && lpitem.dxTab)
+ {
+ lpitem.dxTab = maxTab;
+ }
+ MenuSetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
+ }
+ start++;
+ }
+ MenuInfo->cyMenu = max(MenuInfo->cyMenu, orgY);
+ }
+
+ MenuInfo->cxMenu = maxX;
+ /* if none of the items have both text and bitmap then
+ * the text and bitmaps are all aligned on the left. If there is at
+ * least one item with both text and bitmap then bitmaps are
+ * on the left and texts left aligned with the right hand side
+ * of the bitmaps */
+ if( !textandbmp) MenuInfo->cxTextAlign = 0;
+
+ /* space for 3d border */
+ MenuInfo->cyMenu += MENU_BOTTOM_MARGIN;
+ MenuInfo->cxMenu += 2;
+
+ /* Adjust popup height if it exceeds maximum */
+ maxHeight = MENU_GetMaxPopupHeight(MenuInfo);
+ MenuInfo->iMaxTop = MenuInfo->cyMenu - MENU_TOP_MARGIN;
+ if (MenuInfo->cyMenu >= maxHeight)
+ {
+ MenuInfo->cyMenu = maxHeight;
+ MenuInfo->dwArrowsOn = 1;
+ }
+ else
+ {
+ MenuInfo->dwArrowsOn = 0;
+ }
+
+ MenuCleanupRosMenuItemInfo(&lpitem);
+ MenuSetRosMenuInfo(MenuInfo);
+ ReleaseDC( 0, hdc );
+}
+
+/***********************************************************************
+ * MenuMenuBarCalcSize
+ *
+ * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
+ * height is off by 1 pixel which causes lengthy window relocations when
+ * active document window is maximized/restored.
+ *
+ * Calculate the size of the menu bar.
+ */
+static void FASTCALL MenuMenuBarCalcSize( HDC hdc, LPRECT lprect,
+ PROSMENUINFO MenuInfo, HWND hwndOwner )
+{
+ ROSMENUITEMINFO ItemInfo;
+ int start, i, orgX, orgY, maxY, helpPos;
+
+ if ((lprect == NULL) || (MenuInfo == NULL)) return;
+ if (MenuInfo->cItems == 0) return;
+ TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
+ MenuInfo->cxMenu = lprect->right - lprect->left;
+ MenuInfo->cyMenu = 0;
+ maxY = lprect->top + 1;
+ start = 0;
+ helpPos = -1;
+
+ MenuInfo->cxTextAlign = 0;
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ while (start < MenuInfo->cItems)
+ {
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ orgX = lprect->left;
+ orgY = maxY;
+
+ /* Parse items until line break or end of menu */
+ for (i = start; i < MenuInfo->cItems; i++)
+ {
+ if ((helpPos == -1) && (ItemInfo.fType & MF_RIGHTJUSTIFY)) helpPos = i;
+ if ((i != start) &&
+ (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
+
+ TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY);
+ MenuCalcItemSize(hdc, &ItemInfo, MenuInfo, hwndOwner, orgX, orgY, TRUE, FALSE);
+ if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+
+ if (ItemInfo.Rect.right > lprect->right)
+ {
+ if (i != start) break;
+ else ItemInfo.Rect.right = lprect->right;
+ }
+ maxY = max( maxY, ItemInfo.Rect.bottom );
+ orgX = ItemInfo.Rect.right;
+ if (i + 1 < MenuInfo->cItems)
+ {
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i + 1, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ }
+ }
+
+/* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
+ HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
+#if 0
+ /* Finish the line (set all items to the largest height found) */
+ while (start < i)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo))
+ {
+ ItemInfo.Rect.bottom = maxY;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo);
+ }
+ start++;
+ }
+#else
+ start = i; /* This works! */
+#endif
+ }
+
+ lprect->bottom = maxY;
+ MenuInfo->cyMenu = lprect->bottom - lprect->top;
+ MenuSetRosMenuInfo(MenuInfo);
+
+ if (helpPos != -1)
+ {
+ /* Flush right all items between the MF_RIGHTJUSTIFY and */
+ /* the last item (if several lines, only move the last line) */
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->cItems - 1, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ orgY = ItemInfo.Rect.top;
+ orgX = lprect->right;
+ for (i = MenuInfo->cItems - 1; helpPos <= i; i--)
+ {
+ if (i < helpPos) break; /* done */
+ if (ItemInfo.Rect.top != orgY) break; /* Other line */
+ if (orgX <= ItemInfo.Rect.right) break; /* Too far right already */
+ ItemInfo.Rect.left += orgX - ItemInfo.Rect.right;
+ ItemInfo.Rect.right = orgX;
+ orgX = ItemInfo.Rect.left;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo);
+ if (helpPos + 1 <= i &&
+ ! MenuGetRosMenuItemInfo(MenuInfo->Self, i - 1, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ }
+ }
+
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+}
+
+/***********************************************************************
+ * MENU_DrawScrollArrows
+ *
+ * Draw scroll arrows.
+ */
+static void
+MENU_DrawScrollArrows(PROSMENUINFO lppop, HDC hdc)
+{
+ HDC hdcMem = CreateCompatibleDC(hdc);
+ HBITMAP hOrigBitmap;
+ UINT arrow_bitmap_width, arrow_bitmap_height;
+ BITMAP bmp;
+ RECT rect;
+
+ GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
+ arrow_bitmap_width = bmp.bmWidth;
+ arrow_bitmap_height = bmp.bmHeight;
+
+ if (lppop->iTop)
+ hOrigBitmap = SelectObject(hdcMem, get_up_arrow_bitmap());
+ else
+ hOrigBitmap = SelectObject(hdcMem, get_up_arrow_inactive_bitmap());
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = lppop->cxMenu;
+ rect.bottom = arrow_bitmap_height;
+ FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
+ BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2, 0,
+ arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
+ rect.top = lppop->cyMenu - arrow_bitmap_height;
+ rect.bottom = lppop->cyMenu;
+ FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
+ if (lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height))
+ SelectObject(hdcMem, get_down_arrow_bitmap());
+ else
+ SelectObject(hdcMem, get_down_arrow_inactive_bitmap());
+ BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2,
+ lppop->cyMenu - arrow_bitmap_height,
+ arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hOrigBitmap);
+ DeleteDC(hdcMem);
+}
+
+/***********************************************************************
+ * draw_popup_arrow
+ *
+ * Draws the popup-menu arrow.
+ */
+static void draw_popup_arrow( HDC hdc, RECT rect, UINT arrow_bitmap_width,
+ UINT arrow_bitmap_height)
+{
+ HDC hdcMem = CreateCompatibleDC( hdc );
+ HBITMAP hOrigBitmap;
+
+ hOrigBitmap = SelectObject( hdcMem, get_arrow_bitmap() );
+ BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
+ (rect.top + rect.bottom - arrow_bitmap_height) / 2,
+ arrow_bitmap_width, arrow_bitmap_height,
+ hdcMem, 0, 0, SRCCOPY );
+ SelectObject( hdcMem, hOrigBitmap );
+ DeleteDC( hdcMem );
+}
+
+/***********************************************************************
+ * MenuDrawMenuItem
+ *
+ * Draw a single menu item.
+ */
+static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC hdc,
+ PROSMENUITEMINFO lpitem, UINT Height, BOOL menuBar, UINT odaction)
+{
+ RECT rect;
+ PWCHAR Text;
+ BOOL flat_menu = FALSE;
+ int bkgnd;
+ UINT arrow_bitmap_width = 0, arrow_bitmap_height = 0;
+ PWND Wnd = ValidateHwndNoErr(hWnd);
+
+ if (!Wnd)
+ return;
+
+ if (!menuBar) {
+ BITMAP bmp;
+ GetObjectW( get_arrow_bitmap(), sizeof(bmp), &bmp );
+ arrow_bitmap_width = bmp.bmWidth;
+ arrow_bitmap_height = bmp.bmHeight;
+ }
+
+ if (lpitem->fType & MF_SYSMENU)
+ {
+ if ( (Wnd->style & WS_MINIMIZE))
+ {
+ UserGetInsideRectNC(Wnd, &rect);
+ UserDrawSysMenuButton(hWnd, hdc, &rect, lpitem->fState & (MF_HILITE | MF_MOUSESELECT));
+ }
+ return;
+ }
+
+ SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
+ bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
+
+ /* Setup colors */
+
+ if (lpitem->fState & MF_HILITE)
+ {
+ if(menuBar && !flat_menu) {
+ SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
+ SetBkColor(hdc, GetSysColor(COLOR_MENU));
+ } else {
+ if (lpitem->fState & MF_GRAYED)
+ SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
+ else
+ SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
+ }
+ }
+ else
+ {
+ if (lpitem->fState & MF_GRAYED)
+ SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
+ else
+ SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
+ SetBkColor( hdc, GetSysColor( bkgnd ) );
+ }
+
+ TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
+ rect = lpitem->Rect;
+ MENU_AdjustMenuItemRect(MenuInfo, &rect);
+
+ if (lpitem->fType & MF_OWNERDRAW)
+ {
+ /*
+ ** Experimentation under Windows reveals that an owner-drawn
+ ** menu is given the rectangle which includes the space it requested
+ ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
+ ** and a popup-menu arrow. This is the value of lpitem->rect.
+ ** Windows will leave all drawing to the application except for
+ ** the popup-menu arrow. Windows always draws that itself, after
+ ** the menu owner has finished drawing.
+ */
+ DRAWITEMSTRUCT dis;
+
+ dis.CtlType = ODT_MENU;
+ dis.CtlID = 0;
+ dis.itemID = lpitem->wID;
+ dis.itemData = (DWORD)lpitem->dwItemData;
+ dis.itemState = 0;
+ if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
+ if (lpitem->fState & MF_DEFAULT) dis.itemState |= ODS_DEFAULT;
+ if (lpitem->fState & MF_DISABLED) dis.itemState |= ODS_DISABLED;
+ if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED | ODS_DISABLED;
+ if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
+ //if (!(MenuInfo->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
+ //if (MenuInfo->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
+ dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
+ dis.hwndItem = (HWND) MenuInfo->Self;
+ dis.hDC = hdc;
+ dis.rcItem = rect;
+ TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
+ "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd,
+ dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
+ dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
+ dis.rcItem.bottom);
+ SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis);
+ /* Draw the popup-menu arrow */
+ if (lpitem->hSubMenu)
+ {
+ /* RECT rectTemp;
+ CopyRect(&rectTemp, &rect);
+ rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
+ DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
+ */
+ draw_popup_arrow( hdc, rect, arrow_bitmap_width, arrow_bitmap_height);
+ }
+ return;
+ }
+
+ if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
+
+ if (lpitem->fState & MF_HILITE)
+ {
+ if (flat_menu)
+ {
+ InflateRect (&rect, -1, -1);
+ FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENUHILIGHT));
+ InflateRect (&rect, 1, 1);
+ FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
+ }
+ else
+ {
+ if(menuBar)
+ DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
+ else
+ FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
+ }
+ }
+ else
+ FillRect( hdc, &rect, GetSysColorBrush(bkgnd) );
+
+ SetBkMode( hdc, TRANSPARENT );
+
+ /* vertical separator */
+ if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
+ {
+ HPEN oldPen;
+ RECT rc = rect;
+
+ rc.left -= 3;//MENU_COL_SPACE / 2 + 1;
+ rc.top = 3;
+ rc.bottom = Height - 3;
+ if (flat_menu)
+ {
+ oldPen = SelectObject( hdc, GetStockObject(DC_PEN) );
+ SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
+ MoveToEx( hdc, rc.left, rc.top, NULL );
+ LineTo( hdc, rc.left, rc.bottom );
+ SelectObject( hdc, oldPen );
+ }
+ else
+ DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
+ }
+
+ /* horizontal separator */
+ if (lpitem->fType & MF_SEPARATOR)
+ {
+ HPEN oldPen;
+ RECT rc = rect;
+
+ rc.left++;
+ rc.right--;
+ rc.top += SEPARATOR_HEIGHT / 2;
+ if (flat_menu)
+ {
+ oldPen = SelectObject( hdc, GetStockObject(DC_PEN) );
+ SetDCPenColor( hdc, GetSysColor(COLOR_BTNSHADOW));
+ MoveToEx( hdc, rc.left, rc.top, NULL );
+ LineTo( hdc, rc.right, rc.top );
+ SelectObject( hdc, oldPen );
+ }
+ else
+ DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
+ return;
+ }
+
+#if 0
+ /* helper lines for debugging */
+ /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
+ FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
+ SelectObject(hdc, GetStockObject(DC_PEN));
+ SetDCPenColor(hdc, GetSysColor(COLOR_WINDOWFRAME));
+ MoveToEx(hdc, rect.left, (rect.top + rect.bottom) / 2, NULL);
+ LineTo(hdc, rect.right, (rect.top + rect.bottom) / 2);
+#endif
+
+ if (!menuBar)
+ {
+ HBITMAP bm;
+ INT y = rect.top + rect.bottom;
+ RECT rc = rect;
+ BOOL checked = FALSE;
+ UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
+ UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
+ /* Draw the check mark
+ *
+ * FIXME:
+ * Custom checkmark bitmaps are monochrome but not always 1bpp.
+ */
+ if( !(MenuInfo->dwStyle & MNS_NOCHECK)) {
+ bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked :
+ lpitem->hbmpUnchecked;
+ if (bm) /* we have a custom bitmap */
+ {
+ HDC hdcMem = CreateCompatibleDC( hdc );
+
+ SelectObject( hdcMem, bm );
+ BitBlt( hdc, rc.left, (y - check_bitmap_height) / 2,
+ check_bitmap_width, check_bitmap_height,
+ hdcMem, 0, 0, SRCCOPY );
+ DeleteDC( hdcMem );
+ checked = TRUE;
+ }
+ else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
+ {
+ RECT r;
+ //HBITMAP bm = CreateBitmap( check_bitmap_width, check_bitmap_height, 1, 1, NULL );
+ //HDC hdcMem = CreateCompatibleDC( hdc );
+ //SelectObject( hdcMem, bm );
+ //SetRect( &r, 0, 0, check_bitmap_width, check_bitmap_height);
+ CopyRect(&r, &rect);
+ r.right = r.left + GetSystemMetrics(SM_CXMENUCHECK);
+ DrawFrameControl( hdc, &r, DFC_MENU,
+ (lpitem->fType & MFT_RADIOCHECK) ?
+ DFCS_MENUBULLET : DFCS_MENUCHECK);
+ //BitBlt( hdc, rc.left, (y - r.bottom) / 2, r.right, r.bottom, hdcMem, 0, 0, SRCCOPY );
+ //DeleteDC( hdcMem );
+ //DeleteObject( bm );
+ checked = TRUE;
+ }
+ }
+ if ( lpitem->hbmpItem )//&& !( checked && (MenuInfo->dwStyle & MNS_CHECKORBMP)))
+ {
+ RECT bmpRect;
+ CopyRect(&bmpRect, &rect);
+ if (!(MenuInfo->dwStyle & MNS_CHECKORBMP) && !(MenuInfo->dwStyle & MNS_NOCHECK))
+ bmpRect.left += check_bitmap_width + 2;
+ if (!(checked && (MenuInfo->dwStyle & MNS_CHECKORBMP)))
+ {
+ //POINT origorg;
+ bmpRect.right = bmpRect.left + lpitem->maxBmpSize.cx;
+ /* some applications make this assumption on the DC's origin */
+ //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
+ MenuDrawBitmapItem(hdc, lpitem, &bmpRect, MenuInfo, WndOwner, odaction, menuBar);
+ //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
+ }
+ }
+ /* Draw the popup-menu arrow */
+ if (lpitem->hSubMenu)
+ {
+ /* RECT rectTemp;
+ CopyRect(&rectTemp, &rect);
+ rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
+ DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
+ */
+ draw_popup_arrow( hdc, rect, arrow_bitmap_width, arrow_bitmap_height);
+ }
+ rect.left += 4;
+ if( !(MenuInfo->dwStyle & MNS_NOCHECK))
+ rect.left += check_bitmap_width;
+ rect.right -= arrow_bitmap_width;//check_bitmap_width;
+ }
+ else if( lpitem->hbmpItem)
+ { /* Draw the bitmap */
+ //POINT origorg;
+
+ //SetViewportOrgEx( hdc, rect.left, rect.top, &origorg);
+ MenuDrawBitmapItem(hdc, lpitem, &rect, MenuInfo, WndOwner, odaction, menuBar);
+ //SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
+ }
+
+ /* process text if present */
+ if (lpitem->lpstr)
+ {
- if((MenuInfo->dwStyle & MNS_CHECKORBMP))
++ int i = 0;
+ HFONT hfontOld = 0;
++
+ UINT uFormat = menuBar ?
+ DT_CENTER | DT_VCENTER | DT_SINGLELINE :
+ DT_LEFT | DT_VCENTER | DT_SINGLELINE;
+
- rect.left += MENU_BAR_ITEMS_SPACE / 2;
- rect.right -= MENU_BAR_ITEMS_SPACE / 2;
++ if ((MenuInfo->dwStyle & MNS_CHECKORBMP))
+ rect.left += max(0, (int)(MenuInfo->cxTextAlign - GetSystemMetrics(SM_CXMENUCHECK)));
+ else
+ rect.left += MenuInfo->cxTextAlign;
+
+ if ( lpitem->fState & MFS_DEFAULT )
+ {
+ hfontOld = SelectObject(hdc, hMenuFontBold);
+ }
+
+ if (menuBar) {
- }
- DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
++ if( lpitem->hbmpItem)
++ rect.left += lpitem->maxBmpSize.cx;
++ if( !(lpitem->hbmpItem == HBMMENU_CALLBACK))
++ rect.left += MenuCharSize.cx;
++ rect.right -= MenuCharSize.cx;
++ //rect.left += MENU_BAR_ITEMS_SPACE / 2;
++ //rect.right -= MENU_BAR_ITEMS_SPACE / 2;
+ }
+
+ Text = lpitem->lpstr;
+ if(Text)
+ {
+ for (i = 0; L'\0' != Text[i]; i++)
+ if (Text[i] == L'\t' || Text[i] == L'\b')
+ break;
+ }
+
+ if(lpitem->fState & MF_GRAYED)
+ {
+ if (!(lpitem->fState & MF_HILITE) )
+ {
+ ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
+ SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
+ DrawTextW( hdc, Text, i, &rect, uFormat );
+ --rect.left; --rect.top; --rect.right; --rect.bottom;
+ }
+ SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
+ }
+
+ DrawTextW( hdc, Text, i, &rect, uFormat);
+
+ /* paint the shortcut text */
+ if (!menuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */
+ {
+ if (L'\t' == Text[i])
+ {
+ rect.left = lpitem->dxTab;
+ uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
+ }
+ else
+ {
+ rect.right = lpitem->dxTab;
+ uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
+ }
+
+ if (lpitem->fState & MF_GRAYED)
+ {
+ if (!(lpitem->fState & MF_HILITE) )
+ {
+ ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
+ SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
+ DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat);
+ --rect.left; --rect.top; --rect.right; --rect.bottom;
+ }
+ SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
- else
++ }
++ DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
+ }
+
+ if (hfontOld)
+ SelectObject (hdc, hfontOld);
+ }
+}
+
+/***********************************************************************
+ * MenuDrawPopupMenu
+ *
+ * Paint a popup menu.
+ */
+static void FASTCALL MenuDrawPopupMenu(HWND hwnd, HDC hdc, HMENU hmenu )
+{
+ HBRUSH hPrevBrush = 0;
+ RECT rect;
+
+ TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu);
+
+ GetClientRect( hwnd, &rect );
+
+ if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
+ && (SelectObject( hdc, hMenuFont)))
+ {
+ HPEN hPrevPen;
+
+ Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
+
+ hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
+ if ( hPrevPen )
+ {
+ BOOL flat_menu = FALSE;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+
+ SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
+ if (flat_menu)
+ FrameRect(hdc, &rect, GetSysColorBrush(COLOR_BTNSHADOW));
+ else
+ DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
+
+ //TRACE("hmenu %p Style %08x\n", hmenu, menu->dwStyle);
+ /* draw menu items */
+ if (MenuGetRosMenuInfo(&MenuInfo, hmenu) && MenuInfo.cItems)
+ {
+ UINT u;
+ MenuInitRosMenuItemInfo(&ItemInfo);
+
++ //for (u = MenuInfo.cItems; u > 0; u--, item++)
+ for (u = 0; u < MenuInfo.cItems; u++)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo))
+ {
+ HWND WndOwner = MenuInfo.spwndNotify ? MenuInfo.spwndNotify->head.h : NULL;
+ MenuDrawMenuItem(hwnd, &MenuInfo, WndOwner, hdc, &ItemInfo,
+ MenuInfo.cyMenu, FALSE, ODA_DRAWENTIRE);
+ }
+ }
+ /* draw scroll arrows */
+ if (MenuInfo.dwArrowsOn)
++ {
+ MENU_DrawScrollArrows(&MenuInfo, hdc);
++ }
+
+ MenuSetRosMenuInfo(&MenuInfo);
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ }
+ } else
+ {
+ SelectObject( hdc, hPrevBrush );
+ }
+ }
+}
+
+/***********************************************************************
+ * MenuDrawMenuBar
+ *
+ * Paint a menu bar. Returns the height of the menu bar.
+ * called from [windows/nonclient.c]
+ */
+UINT MenuDrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
+ BOOL suppress_draw)
+{
+ ROSMENUINFO lppop;
+ HFONT hfontOld = 0;
+ HMENU hMenu = GetMenu(hwnd);
+
+ if (! MenuGetRosMenuInfo(&lppop, hMenu) || lprect == NULL)
+ {
+ return GetSystemMetrics(SM_CYMENU);
+ }
+
+ if (suppress_draw)
+ {
+ hfontOld = SelectObject(hDC, hMenuFont);
+
+ MenuMenuBarCalcSize(hDC, lprect, &lppop, hwnd);
+
+ lprect->bottom = lprect->top + lppop.cyMenu;
+
+ if (hfontOld) SelectObject( hDC, hfontOld);
+ return lppop.cyMenu;
+ }
- (hmenu->fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0 ) );
++ else
+ return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL);
+}
+
+/***********************************************************************
+ * MENU_InitPopup
+ *
+ * Popup menu initialization before WM_ENTERMENULOOP.
+ */
+static BOOL MENU_InitPopup( HWND hwndOwner, HMENU hmenu, UINT flags )
+{
+ MENU *menu;
+ DWORD ex_style = WS_EX_TOOLWINDOW;
+ ROSMENUINFO MenuInfo;
+
+ TRACE("owner=%p hmenu=%p\n", hwndOwner, hmenu);
+
+ if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
+
+ /* store the owner for DrawItem */
+ if (!IsWindow( hwndOwner ))
+ {
+ SetLastError( ERROR_INVALID_WINDOW_HANDLE );
+ return FALSE;
+ }
+ MenuGetRosMenuInfo(&MenuInfo, menu->head.h);
+ //menu->hwndOwner = hwndOwner;
+ MenuInfo.spwndNotify = ValidateHwndNoErr( hwndOwner );
+
+ if (flags & TPM_LAYOUTRTL)
+ ex_style = WS_EX_LAYOUTRTL;
+
+ /* NOTE: In Windows, top menu popup is not owned. */
+ //menu->hWnd = CreateWindowExW( ex_style, WC_MENU, NULL,
+ MenuInfo.Wnd = CreateWindowExW( ex_style, WC_MENU, NULL,
+ WS_POPUP, 0, 0, 0, 0,
+ hwndOwner, 0, (HINSTANCE)GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
+ (LPVOID)hmenu );
+ MenuSetRosMenuInfo(&MenuInfo);
+ if( !menu->hWnd ) return FALSE;
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuShowPopup
+ *
+ * Display a popup menu.
+ */
+static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT flags,
+ INT x, INT y, INT xanchor, INT yanchor )
+{
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+ UINT width, height;
+ POINT pt;
+ HMONITOR monitor;
+ MONITORINFO info;
+
+ TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
+ hwndOwner, hmenu, id, x, y, xanchor, yanchor);
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, hmenu)) return FALSE;
+ if (MenuInfo.iItem != NO_SELECTED_ITEM)
+ {
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo))
+ {
+ ItemInfo.fMask |= MIIM_STATE;
+ ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
+ MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo);
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ MenuInfo.iItem = NO_SELECTED_ITEM;
+ }
+
+ //menu->dwArrowsOn = 0;
+ MenuInfo.dwArrowsOn = 0;
+ MenuSetRosMenuInfo(&MenuInfo);
+ MenuPopupMenuCalcSize(&MenuInfo, hwndOwner);
+
+ /* adjust popup menu pos so that it fits within the desktop */
+
+ width = MenuInfo.cxMenu + GetSystemMetrics(SM_CXBORDER);
+ height = MenuInfo.cyMenu + GetSystemMetrics(SM_CYBORDER);
+
+ /* FIXME: should use item rect */
+ pt.x = x;
+ pt.y = y;
+ monitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
+ info.cbSize = sizeof(info);
+ GetMonitorInfoW( monitor, &info );
+
+ if (flags & TPM_LAYOUTRTL)
+ flags ^= TPM_RIGHTALIGN;
+
+ if( flags & TPM_RIGHTALIGN ) x -= width;
+ if( flags & TPM_CENTERALIGN ) x -= width / 2;
+
+ if( flags & TPM_BOTTOMALIGN ) y -= height;
+ if( flags & TPM_VCENTERALIGN ) y -= height / 2;
+
+ if( x + width > info.rcMonitor.right)
+ {
+ if( xanchor && x >= width - xanchor )
+ x -= width - xanchor;
+
+ if( x + width > info.rcMonitor.right)
+ x = info.rcMonitor.right - width;
+ }
+ if( x < info.rcMonitor.left ) x = info.rcMonitor.left;
+
+ if( y + height > info.rcMonitor.bottom)
+ {
+ if( yanchor && y >= height + yanchor )
+ y -= height + yanchor;
+
+ if( y + height > info.rcMonitor.bottom)
+ y = info.rcMonitor.bottom - height;
+ }
+ if( y < info.rcMonitor.top ) y = info.rcMonitor.top;
+
+ if (!top_popup) {
+ top_popup = MenuInfo.Wnd;
+ top_popup_hmenu = hmenu;
+ }
+ /* Display the window */
+
+ SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, x, y, width, height,
+ SWP_SHOWWINDOW | SWP_NOACTIVATE);
+ UpdateWindow( MenuInfo.Wnd );
+
+ IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
+
+ return TRUE;
+}
+
+/***********************************************************************
+ * MENU_EnsureMenuItemVisible
+ */
+void
+MENU_EnsureMenuItemVisible(PROSMENUINFO lppop, PROSMENUITEMINFO item, HDC hdc)
+{
+ if (lppop->dwArrowsOn)
+ {
+ //ITEM *item = &lppop->items[wIndex];
+ UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
+ UINT nOldPos = lppop->iTop;
+ RECT rc;
+ UINT arrow_bitmap_height;
+ BITMAP bmp;
+
+ GetClientRect(lppop->Wnd, &rc);
+
+ GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
+ arrow_bitmap_height = bmp.bmHeight;
+
+ rc.top += arrow_bitmap_height;
+ rc.bottom -= arrow_bitmap_height + MENU_BOTTOM_MARGIN;
+
+ nMaxHeight -= GetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height;
+ if (item->Rect.bottom > lppop->iTop + nMaxHeight)
+ {
+ lppop->iTop = item->Rect.bottom - nMaxHeight;
+ ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc);
+ MENU_DrawScrollArrows(lppop, hdc);
+ }
+ else if (item->Rect.top - MENU_TOP_MARGIN < lppop->iTop)
+ {
+ lppop->iTop = item->Rect.top - MENU_TOP_MARGIN;
+ ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc);
+ MENU_DrawScrollArrows(lppop, hdc);
+ }
++ MenuSetRosMenuInfo(lppop);
+ }
+}
+
+/***********************************************************************
+ * MenuSelectItem
+ */
+static void FASTCALL MenuSelectItem(HWND hwndOwner, PROSMENUINFO hmenu, UINT wIndex,
+ BOOL sendMenuSelect, HMENU topmenu)
+{
+ ROSMENUITEMINFO ItemInfo;
+ ROSMENUINFO TopMenuInfo;
+ HDC hdc;
+
+ TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
+
+ if (!hmenu || !hmenu->cItems || !hmenu->Wnd) return;
+ if (hmenu->iItem == wIndex) return;
+ if (hmenu->fFlags & MNF_POPUP) hdc = GetDC(hmenu->Wnd);
+ else hdc = GetDCEx(hmenu->Wnd, 0, DCX_CACHE | DCX_WINDOW);
+ if (!top_popup) {
+ top_popup = hmenu->Wnd;
+ top_popup_hmenu = hmenu->Self;
+ }
+
+ SelectObject( hdc, hMenuFont );
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+
+ /* Clear previous highlighted item */
+ if (hmenu->iItem != NO_SELECTED_ITEM)
+ {
+ if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo))
+ {
+ ItemInfo.fMask |= MIIM_STATE;
+ ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
+ MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo);
+ }
+ MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc, &ItemInfo,
+ hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP),
+ ODA_SELECT);
+ }
+
+ /* Highlight new item (if any) */
+ hmenu->iItem = wIndex;
+ MenuSetRosMenuInfo(hmenu);
+ if (hmenu->iItem != NO_SELECTED_ITEM)
+ {
+ if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo))
+ {
+ if (!(ItemInfo.fType & MF_SEPARATOR))
+ {
+ ItemInfo.fMask |= MIIM_STATE;
+ ItemInfo.fState |= MF_HILITE;
+ MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo);
+ MENU_EnsureMenuItemVisible(hmenu, &ItemInfo, hdc);
+ MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc,
+ &ItemInfo, hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP), ODA_SELECT);
+ }
+ if (sendMenuSelect)
+ {
+ WPARAM wParam = MAKEWPARAM( ItemInfo.hSubMenu ? wIndex : ItemInfo.wID,
+ ItemInfo.fType | ItemInfo.fState |
+ (ItemInfo.hSubMenu ? MF_POPUP : 0) |
- (TopMenuInfo.fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0 ) );
++ (hmenu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
+
+ SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) hmenu->Self);
+ }
+ }
+ }
+ else if (sendMenuSelect)
+ {
+ if(topmenu)
+ {
+ int pos;
+ pos = MenuFindSubMenu(&topmenu, hmenu->Self);
+ if (pos != NO_SELECTED_ITEM)
+ {
+ if (MenuGetRosMenuInfo(&TopMenuInfo, topmenu)
+ && MenuGetRosMenuItemInfo(topmenu, pos, &ItemInfo))
+ {
+ WPARAM wParam = MAKEWPARAM( Pos, ItemInfo.fType | ItemInfo.fState |
+ (ItemInfo.hSubMenu ? MF_POPUP : 0) |
- if (0 != (MenuInfo->fFlags & MNF_SYSDESKMN))
++ (TopMenuInfo.fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
+
+ SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) topmenu);
+ }
+ }
+ }
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ ReleaseDC(hmenu->Wnd, hdc);
+}
+
+/***********************************************************************
+ * MenuMoveSelection
+ *
+ * Moves currently selected item according to the Offset parameter.
+ * If there is no selection then it should select the last item if
+ * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
+ */
+static void FASTCALL
+MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset)
+{
+ INT i;
+ ROSMENUITEMINFO ItemInfo;
+ INT OrigPos;
+
+ TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset);
+
+ /* Prevent looping */
+ if (0 == MenuInfo->cItems || 0 == Offset)
+ return;
+ else if (Offset < -1)
+ Offset = -1;
+ else if (Offset > 1)
+ Offset = 1;
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+
+ OrigPos = MenuInfo->iItem;
+ if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */
+ {
+ OrigPos = 0;
+ i = -1;
+ }
+ else
+ {
+ i = MenuInfo->iItem;
+ }
+
+ do
+ {
+ /* Step */
+ i += Offset;
+ /* Clip and wrap around */
+ if (i < 0)
+ {
+ i = MenuInfo->cItems - 1;
+ }
+ else if (i >= MenuInfo->cItems)
+ {
+ i = 0;
+ }
+ /* If this is a good candidate; */
+ if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) &&
+ 0 == (ItemInfo.fType & MF_SEPARATOR))
+ {
+ MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL);
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ } while (i != OrigPos);
+
+ /* Not found */
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+}
+
+#if 0
+LRESULT WINAPI
+PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+#ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
+ PWND pWnd;
+ PPOPUPMENU pPopupMenu;
+
+ pWnd = ValidateHwndNoErr(Wnd);
+ if (pWnd)
+ {
+ if (!pWnd->fnid)
+ {
+ if (Message != WM_NCCREATE)
+ {
+ return DefWindowProcW(Wnd, Message, wParam, lParam);
+ }
+ NtUserSetWindowFNID(Wnd, FNID_MENU);
+ pPopupMenu = HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU) );
+ pPopupMenu->spwndPopupMenu = pWnd;
+ SetWindowLongPtrW(Wnd, 0, (LONG_PTR)pPopupMenu);
+ }
+ else
+ {
+ if (pWnd->fnid != FNID_MENU)
+ {
+ ERR("Wrong window class for Menu!\n");
+ return 0;
+ }
+ pPopupMenu = ((PMENUWND)pWnd)->ppopupmenu;
+ }
+ }
+#endif
+
+ TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+
+ switch(Message)
+ {
+ case WM_CREATE:
+ {
+ CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
+ pPopupMenu->spmenu = ValidateHandle(cs->lpCreateParams, TYPE_MENU);
+ return 0;
+ }
+
+ case WM_MOUSEACTIVATE: /* We don't want to be activated */
+ return MA_NOACTIVATE;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ BeginPaint(Wnd, &ps);
+ MenuDrawPopupMenu(Wnd, ps.hdc, pPopupMenu->spmenu->head.h);
+ EndPaint(Wnd, &ps);
+ return 0;
+ }
+
+ case WM_PRINTCLIENT:
+ {
+ MenuDrawPopupMenu( Wnd, (HDC)wParam, pPopupMenu->spmenu->head.h);
+ return 0;
+ }
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_DESTROY:
+ /* zero out global pointer in case resident popup window was destroyed. */
+ if (Wnd == top_popup)
+ {
+ top_popup = NULL;
+ top_popup_hmenu = NULL;
+ }
+ break;
+
+ case WM_NCDESTROY:
+ {
+ HeapFree( GetProcessHeap(), 0, pPopupMenu );
+ SetWindowLongPtrW(Wnd, 0, 0);
+ NtUserSetWindowFNID(Wnd, FNID_DESTROY);
+ break;
+ }
+
+ case WM_SHOWWINDOW:
+ if (0 != wParam)
+ {
+ if (!pPopupMenu || !pPopupMenu->spmenu)
+ {
+ OutputDebugStringA("no menu to display\n");
+ }
+ }
+ /*else
+ {
+ pPopupMenu->spmenu = NULL; ///// WTF?
+ }*/
+ break;
+
+ case MM_SETMENUHANDLE:
+ {
+ PMENU pmenu = ValidateHandle((HMENU)wParam, TYPE_MENU);
+ if (!pmenu)
+ {
+ ERR("Bad Menu Handle\n");
+ break;
+ }
+ pPopupMenu->spmenu = pmenu;
+ break;
+ }
+
+ case MM_GETMENUHANDLE:
+ case MN_GETHMENU:
+ return (LRESULT)(pPopupMenu ? (pPopupMenu->spmenu ? pPopupMenu->spmenu->head.h : NULL) : NULL);
+
+ default:
+ return DefWindowProcW(Wnd, Message, wParam, lParam);
+ }
+
+ return 0;
+}
+#endif
+
+LRESULT WINAPI
+PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+#ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
+ PWND pWnd;
+
+ pWnd = ValidateHwnd(Wnd);
+ if (pWnd)
+ {
+ if (!pWnd->fnid)
+ {
+ if (Message != WM_NCCREATE)
+ {
+ return DefWindowProcW(Wnd, Message, wParam, lParam);
+ }
+ NtUserSetWindowFNID(Wnd, FNID_MENU);
+ }
+ else
+ {
+ if (pWnd->fnid != FNID_MENU)
+ {
+ ERR("Wrong window class for Menu!\n");
+ return 0;
+ }
+ }
+ }
+#endif
+
+ TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+
+ switch(Message)
+ {
+ case WM_CREATE:
+ {
+ CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
+ SetWindowLongPtrW(Wnd, 0, (LONG_PTR)cs->lpCreateParams);
+ return 0;
+ }
+
+ case WM_MOUSEACTIVATE: /* We don't want to be activated */
+ return MA_NOACTIVATE;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ BeginPaint(Wnd, &ps);
+ MenuDrawPopupMenu(Wnd, ps.hdc, (HMENU)GetWindowLongPtrW(Wnd, 0));
+ EndPaint(Wnd, &ps);
+ return 0;
+ }
+
+ case WM_PRINTCLIENT:
+ {
+ MenuDrawPopupMenu( Wnd, (HDC)wParam,
+ (HMENU)GetWindowLongPtrW( Wnd, 0 ) );
+ return 0;
+ }
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_DESTROY:
+ /* zero out global pointer in case resident popup window was destroyed. */
+ if (Wnd == top_popup)
+ {
+ top_popup = NULL;
+ top_popup_hmenu = NULL;
+ }
+ break;
+
+#ifdef __REACTOS__
+ case WM_NCDESTROY:
+ NtUserSetWindowFNID(Wnd, FNID_DESTROY);
+ break;
+#endif
+
+ case WM_SHOWWINDOW:
+ if (0 != wParam)
+ {
+ if (0 == GetWindowLongPtrW(Wnd, 0))
+ {
+ OutputDebugStringA("no menu to display\n");
+ }
+ }
+ else
+ {
+ SetWindowLongPtrW(Wnd, 0, 0);
+ }
+ break;
+
+ case MM_SETMENUHANDLE:
+ SetWindowLongPtrW(Wnd, 0, wParam);
+ break;
+
+ case MM_GETMENUHANDLE:
+ case MN_GETHMENU:
+ return GetWindowLongPtrW(Wnd, 0);
+
+ default:
+ return DefWindowProcW(Wnd, Message, wParam, lParam);
+ }
+
+ return 0;
+}
+
+//
+// This breaks some test results. Should handle A2U if called!
+//
+LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
+{
+ PWND pWnd;
+
+ pWnd = ValidateHwnd(Wnd);
+ if (pWnd && !pWnd->fnid && Message != WM_NCCREATE)
+ {
+ return DefWindowProcA(Wnd, Message, wParam, lParam);
+ }
+ TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+
+ switch(Message)
+ {
+ case WM_NCCREATE:
+ case WM_CREATE:
+ case WM_MOUSEACTIVATE:
+ case WM_PAINT:
+ case WM_PRINTCLIENT:
+ case WM_ERASEBKGND:
+ case WM_DESTROY:
+ case WM_NCDESTROY:
+ case WM_SHOWWINDOW:
+ case MM_SETMENUHANDLE:
+ case MM_GETMENUHANDLE:
+ case MN_GETHMENU:
+ return PopupMenuWndProcW(Wnd, Message, wParam, lParam);
+
+ default:
+ return DefWindowProcA(Wnd, Message, wParam, lParam);
+ }
+ return 0;
+}
+
+/**********************************************************************
+ * MENU_ParseResource
+ *
+ * Parse a standard menu resource and add items to the menu.
+ * Return a pointer to the end of the resource.
+ *
+ * NOTE: flags is equivalent to the mtOption field
+ */
+static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu)
+{
+ WORD flags, id = 0;
+ HMENU hSubMenu;
+ LPCWSTR str;
+ BOOL end = FALSE;
+
+ do
+ {
+ flags = GET_WORD(res);
+
+ /* remove MF_END flag before passing it to AppendMenu()! */
+ end = (flags & MF_END);
+ if(end) flags ^= MF_END;
+
+ res += sizeof(WORD);
+ if(!(flags & MF_POPUP))
+ {
+ id = GET_WORD(res);
+ res += sizeof(WORD);
+ }
+ str = (LPCWSTR)res;
+ res += (strlenW(str) + 1) * sizeof(WCHAR);
+
+ if (flags & MF_POPUP)
+ {
+ hSubMenu = CreatePopupMenu();
+ if(!hSubMenu) return NULL;
+ if(!(res = MENU_ParseResource(res, hSubMenu))) return NULL;
+ AppendMenuW(hMenu, flags, (UINT_PTR)hSubMenu, (LPCWSTR)str);
+ }
+ else /* Not a popup */
+ {
+ AppendMenuW(hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL);
+ }
+ } while(!end);
+ return res;
+}
+
+/**********************************************************************
+ * MENUEX_ParseResource
+ *
+ * Parse an extended menu resource and add items to the menu.
+ * Return a pointer to the end of the resource.
+ */
+static LPCSTR MENUEX_ParseResource(LPCSTR res, HMENU hMenu)
+{
+ WORD resinfo;
+ do
+ {
+ MENUITEMINFOW mii;
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
+ mii.fType = GET_DWORD(res);
+ res += sizeof(DWORD);
+ mii.fState = GET_DWORD(res);
+ res += sizeof(DWORD);
+ mii.wID = GET_DWORD(res);
+ res += sizeof(DWORD);
+ resinfo = GET_WORD(res);
+ res += sizeof(WORD);
+ /* Align the text on a word boundary. */
+ res += (~((UINT_PTR)res - 1)) & 1;
+ mii.dwTypeData = (LPWSTR)res;
+ mii.cch = strlenW(mii.dwTypeData);
+ res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
+ /* Align the following fields on a dword boundary. */
+ res += (~((UINT_PTR)res - 1)) & 3;
+
+ TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
+ mii.fType, mii.fState, mii.wID, resinfo, mii.dwTypeData);
+
+ if (resinfo & 1) /* Pop-up? */
+ {
+ /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
+ res += sizeof(DWORD);
+ mii.hSubMenu = CreatePopupMenu();
+ if (!mii.hSubMenu)
+ {
+ ERR("CreatePopupMenu failed\n");
+ return NULL;
+ }
+
+ if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
+ {
+ ERR("MENUEX_ParseResource failed\n");
+ DestroyMenu(mii.hSubMenu);
+ return NULL;
+ }
+ mii.fMask |= MIIM_SUBMENU;
+ }
+ else if (!mii.dwTypeData[0] && !(mii.fType & MF_SEPARATOR))
+ {
+ WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
+ mii.wID, mii.fType);
+ mii.fType |= MF_SEPARATOR;
+ }
+ InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
+ } while (!(resinfo & MF_END));
+ return res;
+}
+
+
+/***********************************************************************
+ * DrawMenuBarTemp (USER32.@)
+ *
+ * UNDOCUMENTED !!
+ *
+ * called by W98SE desk.cpl Control Panel Applet
+ *
+ * Not 100% sure about the param names, but close.
+ *
+ * @implemented
+ */
+DWORD WINAPI
+DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font)
+{
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+ UINT i;
+ HFONT FontOld = NULL;
+ BOOL flat_menu = FALSE;
+
+ SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
+
+ if (NULL == Menu)
+ {
+ Menu = GetMenu(Wnd);
+ }
+
+ if (NULL == Font)
+ {
+ Font = hMenuFont;
+ }
+
+ if (NULL == Rect || ! MenuGetRosMenuInfo(&MenuInfo, Menu))
+ {
+ return GetSystemMetrics(SM_CYMENU);
+ }
+
+ TRACE("(%x, %x, %p, %x, %x)\n", Wnd, DC, Rect, Menu, Font);
+
+ FontOld = SelectObject(DC, Font);
+
+ if (0 == MenuInfo.cyMenu)
+ {
+ MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd);
+ }
+
+ Rect->bottom = Rect->top + MenuInfo.cyMenu;
+
+ FillRect(DC, Rect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU));
+
+ SelectObject(DC, GetStockObject(DC_PEN));
+ SetDCPenColor(DC, GetSysColor(COLOR_3DFACE));
+ MoveToEx(DC, Rect->left, Rect->bottom - 1, NULL);
+ LineTo(DC, Rect->right, Rect->bottom - 1);
+
+ if (0 == MenuInfo.cItems)
+ {
+ SelectObject(DC, FontOld);
+ return GetSystemMetrics(SM_CYMENU);
+ }
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ for (i = 0; i < MenuInfo.cItems; i++)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, i, &ItemInfo))
+ {
+ MenuDrawMenuItem(Wnd, &MenuInfo, Wnd, DC, &ItemInfo,
+ MenuInfo.cyMenu, TRUE, ODA_DRAWENTIRE);
+ }
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+
+ SelectObject(DC, FontOld);
+
+ return MenuInfo.cyMenu;
+}
+
+
+/***********************************************************************
+ * MenuShowSubPopup
+ *
+ * Display the sub-menu of the selected item of this menu.
+ * Return the handle of the submenu, or menu if no submenu to display.
+ */
+static HMENU FASTCALL
+MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Flags)
+{
+ RECT Rect;
+ ROSMENUITEMINFO ItemInfo;
+ ROSMENUINFO SubMenuInfo;
+ HDC Dc;
+ HMENU Ret;
+
+ TRACE("owner=%x menu=%p 0x%04x\n", WndOwner, MenuInfo, SelectFirst);
+
+ if (MenuInfo->iItem == NO_SELECTED_ITEM) return MenuInfo->Self;
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return MenuInfo->Self;
+ }
+
+ //item = &menu->rgItems[menu->iItem];
+ if (!(ItemInfo.hSubMenu) || (ItemInfo.fState & (MF_GRAYED | MF_DISABLED)))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return MenuInfo->Self;
+ }
+
+ /* message must be sent before using item,
+ because nearly everything may be changed by the application ! */
+
+ /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
+ if (!(Flags & TPM_NONOTIFY))
+ {
+ SendMessageW(WndOwner, WM_INITMENUPOPUP, (WPARAM) ItemInfo.hSubMenu,
+ MAKELPARAM(MenuInfo->iItem, IS_SYSTEM_MENU(MenuInfo)));
+ }
+
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return MenuInfo->Self;
+ }
+
+ //item = &menu->rgItems[menu->iItem];
+ Rect = ItemInfo.Rect;
+
+ /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
+ if (!(ItemInfo.fState & MF_HILITE))
+ {
+ if (MenuInfo->fFlags & MNF_POPUP) Dc = GetDC(MenuInfo->Wnd);
+ else Dc = GetDCEx(MenuInfo->Wnd, 0, DCX_CACHE | DCX_WINDOW);
+
+ SelectObject(Dc, hMenuFont);
+ ItemInfo.fMask |= MIIM_STATE;
+ ItemInfo.fState |= MF_HILITE;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
+ MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo, MenuInfo->cyMenu,
+ !(MenuInfo->fFlags & MNF_POPUP), ODA_DRAWENTIRE);
+ ReleaseDC(MenuInfo->Wnd, Dc);
+ }
+
+ if (!ItemInfo.Rect.top && !ItemInfo.Rect.left && !ItemInfo.Rect.bottom && !ItemInfo.Rect.right)
+ ItemInfo.Rect = Rect;
+
+ ItemInfo.fMask |= MIIM_STATE;
+ ItemInfo.fState |= MF_MOUSESELECT;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
+
+ if (IS_SYSTEM_MENU(MenuInfo))
+ {
+ MenuInitSysMenuPopup(ItemInfo.hSubMenu,
+ GetWindowLongPtrW(MenuInfo->Wnd, GWL_STYLE),
+ GetClassLongPtrW(MenuInfo->Wnd, GCL_STYLE), HTSYSMENU);
+
+ NcGetSysPopupPos(MenuInfo->Wnd, &Rect);
+ if (Flags & TPM_LAYOUTRTL) Rect.left = Rect.right;
+ Rect.top = Rect.bottom;
+ Rect.right = GetSystemMetrics(SM_CXSIZE);
+ Rect.bottom = GetSystemMetrics(SM_CYSIZE);
+ }
+ else
+ {
+ GetWindowRect(MenuInfo->Wnd, &Rect);
+ if (MenuInfo->fFlags & MNF_POPUP)
+ {
+ RECT rc = ItemInfo.Rect;
+
+ MENU_AdjustMenuItemRect(MenuInfo, &rc);
+
+ /* The first item in the popup menu has to be at the
+ same y position as the focused menu item */
+ if(Flags & TPM_LAYOUTRTL)
+ Rect.left += GetSystemMetrics(SM_CXBORDER);
+ else
+ Rect.left += rc.right /*ItemInfo.Rect.right*/ - GetSystemMetrics(SM_CXBORDER);
+ Rect.top += rc.top - MENU_TOP_MARGIN;//3;
+ Rect.right = rc.left - rc.right + GetSystemMetrics(SM_CXBORDER);
+ Rect.bottom = rc.top - rc.bottom - MENU_TOP_MARGIN - MENU_BOTTOM_MARGIN/*2*/
+ - GetSystemMetrics(SM_CYBORDER);
+ }
+ else
+ {
+ if(Flags & TPM_LAYOUTRTL)
+ Rect.left += Rect.right - ItemInfo.Rect.left;
+ else
+ Rect.left += ItemInfo.Rect.left;
+ Rect.top += ItemInfo.Rect.bottom;
+ Rect.right = ItemInfo.Rect.right - ItemInfo.Rect.left;
+ Rect.bottom = ItemInfo.Rect.bottom - ItemInfo.Rect.top;
+ }
+ }
+
+ /* use default alignment for submenus */
+ Flags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN);
+
+ MENU_InitPopup( WndOwner, ItemInfo.hSubMenu, Flags );
+
+ MenuShowPopup(WndOwner, ItemInfo.hSubMenu, MenuInfo->iItem, Flags,
+ Rect.left, Rect.top, Rect.right, Rect.bottom );
+ if (SelectFirst && MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
+ {
+ MenuMoveSelection(WndOwner, &SubMenuInfo, ITEM_NEXT);
+ }
+
+ Ret = ItemInfo.hSubMenu;
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+
+ return Ret;
+}
+
+/**********************************************************************
+ * MENU_EndMenu
+ *
+ * Calls EndMenu() if the hwnd parameter belongs to the menu owner
+ *
+ * Does the (menu stuff) of the default window handling of WM_CANCELMODE
+ */
+void MENU_EndMenu( HWND hwnd )
+{
+ MENU *menu;
+ menu = top_popup_hmenu ? MENU_GetMenu( top_popup_hmenu ) : NULL;
+ if (menu && ( hwnd == menu->hWnd || hwnd == (menu->spwndNotify ? menu->spwndNotify->head.h : NULL)) )
+ EndMenu();
+}
+
+/***********************************************************************
+ * MenuHideSubPopups
+ *
+ * Hide the sub-popup menus of this menu.
+ */
+static void FASTCALL
+MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo,
+ BOOL SendMenuSelect, UINT wFlags)
+{
+ ROSMENUINFO SubMenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+
+ TRACE("owner=%x menu=%x 0x%04x\n", WndOwner, MenuInfo, SendMenuSelect);
+
+ if (MenuInfo && top_popup && NO_SELECTED_ITEM != MenuInfo->iItem)
+ {
+ //item = &menu->rgItems[menu->iItem];
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ ItemInfo.fMask |= MIIM_FTYPE | MIIM_STATE;
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo)
+ || !(ItemInfo.hSubMenu)
+ || !(ItemInfo.fState & MF_MOUSESELECT))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ ItemInfo.fState &= ~MF_MOUSESELECT;
+ ItemInfo.fMask |= MIIM_STATE;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
+ if (MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
+ {
+ MenuHideSubPopups(WndOwner, &SubMenuInfo, FALSE, wFlags);
+ MenuSelectItem(WndOwner, &SubMenuInfo, NO_SELECTED_ITEM, SendMenuSelect, NULL);
+
+ DestroyWindow(SubMenuInfo.Wnd);
+ /* Native returns handle to destroyed window */
+ if (!(wFlags & TPM_NONOTIFY))
+ SendMessageW( WndOwner, WM_UNINITMENUPOPUP, (WPARAM)ItemInfo.hSubMenu,
+ MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo)) );
+ ////
+ // Call WM_UNINITMENUPOPUP FIRST before destroy!!
+ // Fixes todo_wine User32 test menu.c line 2233 GetMenuBarInfo callback....
+ //
+ SubMenuInfo.Wnd = NULL;
+ MenuSetRosMenuInfo(&SubMenuInfo);
+ ////
+ }
+ }
+}
+
+/***********************************************************************
+ * MenuSwitchTracking
+ *
+ * Helper function for menu navigation routines.
+ */
+static void FASTCALL
+MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index, UINT wFlags)
+{
+ ROSMENUINFO TopMenuInfo;
+
+ TRACE("%x menu=%x 0x%04x\n", Mt, PtMenuInfo->Self, Index);
+
+ if ( MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu) &&
+ Mt->TopMenu != PtMenuInfo->Self &&
+ !((PtMenuInfo->fFlags | TopMenuInfo.fFlags) & MNF_POPUP) )
+ {
+ /* both are top level menus (system and menu-bar) */
+ MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags);
+ MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, NO_SELECTED_ITEM, FALSE, NULL);
+ Mt->TopMenu = PtMenuInfo->Self;
+ }
+ else
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, PtMenuInfo, FALSE, wFlags);
+ }
+
+ MenuSelectItem(Mt->OwnerWnd, PtMenuInfo, Index, TRUE, NULL);
+}
+
+/***********************************************************************
+ * MenuExecFocusedItem
+ *
+ * Execute a menu item (for instance when user pressed Enter).
+ * Return the wID of the executed item. Otherwise, -1 indicating
+ * that no menu item was executed, -2 if a popup is shown;
+ * Have to receive the flags for the TrackPopupMenu options to avoid
+ * sending unwanted message.
+ *
+ */
+static INT FASTCALL
+MenuExecFocusedItem(MTRACKER *Mt, PROSMENUINFO MenuInfo, UINT Flags)
+{
+ ROSMENUITEMINFO ItemInfo;
+ UINT wID;
+
+ TRACE("%p menu=%p\n", Mt, MenuInfo);
+
+ if (0 == MenuInfo->cItems || NO_SELECTED_ITEM == MenuInfo->iItem)
+ {
+ return -1;
+ }
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return -1;
+ }
+
+ TRACE("%p %08x %p\n", MenuInfo, ItemInfo.wID, ItemInfo.hSubMenu);
+
+ if (0 == (ItemInfo.hSubMenu))
+ {
+ if (0 == (ItemInfo.fState & (MF_GRAYED | MF_DISABLED))
+ && 0 == (ItemInfo.fType & MF_SEPARATOR))
+ {
+ /* If TPM_RETURNCMD is set you return the id, but
+ do not send a message to the owner */
+ if (0 == (Flags & TPM_RETURNCMD))
+ {
- ret = NtUserGetSystemMenu(menu->hWnd, FALSE);
++ if (0 != (MenuInfo->fFlags & MNF_SYSMENU))
+ {
+ PostMessageW(Mt->OwnerWnd, WM_SYSCOMMAND, ItemInfo.wID,
+ MAKELPARAM((SHORT) Mt->Pt.x, (SHORT) Mt->Pt.y));
+ }
+ else
+ {
+ ROSMENUINFO topmenuI;
+ BOOL ret = MenuGetRosMenuInfo(&topmenuI, Mt->TopMenu);
+ DWORD dwStyle = MenuInfo->dwStyle | (ret ? topmenuI.dwStyle : 0);
+
+ if (dwStyle & MNS_NOTIFYBYPOS)
+ PostMessageW(Mt->OwnerWnd, WM_MENUCOMMAND, MenuInfo->iItem, (LPARAM)MenuInfo->Self);
+ else
+ PostMessageW(Mt->OwnerWnd, WM_COMMAND, ItemInfo.wID, 0);
+ }
+ }
+ wID = ItemInfo.wID;
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return wID;
+ }
+ }
+ else
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, MenuInfo, TRUE, Flags);
+ return -2;
+ }
+
+ return -1;
+}
+
+/***********************************************************************
+ * MenuButtonDown
+ *
+ * Return TRUE if we can go on with menu tracking.
+ */
+static BOOL FASTCALL
+MENU_ButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags)
+{
+ int Index;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO Item;
+
+ TRACE("%x PtMenu=%p\n", Mt, PtMenu);
+
+ if (NULL != PtMenu)
+ {
+ if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
+ {
+ return FALSE;
+ }
+ if (IS_SYSTEM_MENU(&MenuInfo))
+ {
+ Index = 0;
+ }
+ else
+ {
+ Index = NtUserMenuItemFromPoint(Mt->OwnerWnd, PtMenu, Mt->Pt.x, Mt->Pt.y);
+ }
+ MenuInitRosMenuItemInfo(&Item);
+ if (NO_SELECTED_ITEM == Index || ! MenuGetRosMenuItemInfo(PtMenu, Index, &Item))
+ {
+ MenuCleanupRosMenuItemInfo(&Item);
+ return FALSE;
+ }
+
+ if (!(Item.fType & MF_SEPARATOR) &&
+ !(Item.fState & (MFS_DISABLED | MFS_GRAYED)) )
+ {
+ if (MenuInfo.iItem != Index)
+ {
+ MenuSwitchTracking(Mt, &MenuInfo, Index, Flags);
+ }
+
+ /* If the popup menu is not already "popped" */
+ if (0 == (Item.fState & MF_MOUSESELECT))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
+ }
+ }
+
+ MenuCleanupRosMenuItemInfo(&Item);
+
+ return TRUE;
+ }
+
+ /* else the click was on the menu bar, finish the tracking */
+
+ return FALSE;
+}
+
+/***********************************************************************
+ * MenuButtonUp
+ *
+ * Return the value of MenuExecFocusedItem if
+ * the selected item was not a popup. Else open the popup.
+ * A -1 return value indicates that we go on with menu tracking.
+ *
+ */
+static INT FASTCALL
+MENU_ButtonUp(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
+{
+ INT Id;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+
+ TRACE("%p hmenu=%x\n", Mt, PtMenu);
+
+ if (NULL != PtMenu)
+ {
+ Id = 0;
+ if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
+ {
+ return -1;
+ }
+
+ if (! IS_SYSTEM_MENU(&MenuInfo))
+ {
+ Id = NtUserMenuItemFromPoint(Mt->OwnerWnd, MenuInfo.Self, Mt->Pt.x, Mt->Pt.y);
+ }
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (0 <= Id && MenuGetRosMenuItemInfo(MenuInfo.Self, Id, &ItemInfo) &&
+ MenuInfo.iItem == Id)
+ {
+ if (0 == (ItemInfo.hSubMenu))
+ {
+ INT ExecutedMenuId = MenuExecFocusedItem(Mt, &MenuInfo, Flags);
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return (ExecutedMenuId < 0) ? -1 : ExecutedMenuId;
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+
+ /* If we are dealing with the top-level menu */
+ /* and this is a click on an already "popped" item: */
+ /* Stop the menu tracking and close the opened submenus */
+ if (Mt->TopMenu == MenuInfo.Self && MenuInfo.TimeToHide)
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return 0;
+ }
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ MenuInfo.TimeToHide = TRUE;
+ MenuSetRosMenuInfo(&MenuInfo);
+ }
+
+ return -1;
+}
+
+/***********************************************************************
+ * MenuPtMenu
+ *
+ * Walks menu chain trying to find a menu pt maps to.
+ */
+static HMENU FASTCALL
+MENU_PtMenu(HMENU hMenu, POINT pt)
+{
+ MENU *menu;
+ PITEM pItem;
+ HMENU ret = NULL;
+
+ menu = MENU_GetMenu( hMenu );
+ if (!menu) return NULL;
+
+ /* try subpopup first (if any) */
+ if (menu->iItem != NO_SELECTED_ITEM)
+ {
+ pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
+ if ( pItem ) pItem = &pItem[menu->iItem];
+ if ( pItem && pItem->spSubMenu && pItem->fState & MF_MOUSESELECT)
+ {
+ PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
+ ret = MENU_PtMenu( UserHMGetHandle(pSubMenu), pt);
+ }
+ }
+
+ /* check the current window (avoiding WM_HITTEST) */
+ if (!ret)
+ {
+ INT ht = DefWndNCHitTest(menu->hWnd, pt);
+ if ( menu->fFlags & MNF_POPUP )
+ {
+ if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu;
+ }
+ else if (ht == HTSYSMENU)
- NewMenu = NtUserGetSystemMenu(NewWnd, FALSE);
++ ret = get_win_sys_menu(menu->hWnd);
+ else if (ht == HTMENU)
+ ret = GetMenu( menu->hWnd );
+ }
+ return ret;
+}
+
+/***********************************************************************
+ * MenuMouseMove
+ *
+ * Return TRUE if we can go on with menu tracking.
+ */
+static BOOL FASTCALL
+MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
+{
+ INT Index;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+
+ if (NULL != PtMenu)
+ {
+ if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
+ {
+ return TRUE;
+ }
+ if (IS_SYSTEM_MENU(&MenuInfo))
+ {
+ Index = 0;
+ }
+ else
+ {
+ Index = NtUserMenuItemFromPoint(Mt->OwnerWnd, PtMenu, Mt->Pt.x, Mt->Pt.y);
+ }
+ }
+ else
+ {
+ Index = NO_SELECTED_ITEM;
+ }
+
+ if (NO_SELECTED_ITEM == Index)
+ {
+ if (Mt->CurrentMenu == MenuInfo.Self ||
+ MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &MenuInfo, NO_SELECTED_ITEM,
+ TRUE, Mt->TopMenu);
+ }
+ }
+ else if (MenuInfo.iItem != Index)
+ {
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, Index, &ItemInfo) &&
+ !(ItemInfo.fType & MF_SEPARATOR))
+ {
+ MenuSwitchTracking(Mt, &MenuInfo, Index, Flags);
+ if (!(ItemInfo.fState & (MFS_DISABLED | MFS_GRAYED)))
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ }
+
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuGetSubPopup
+ *
+ * Return the handle of the selected sub-popup menu (if any).
+ */
+static
+HMENU MENU_GetSubPopup( HMENU hmenu )
+{
+ MENU *menu;
+ ITEM *item;
+
+ menu = MENU_GetMenu( hmenu );
+
+ if ((!menu) || (menu->iItem == NO_SELECTED_ITEM)) return 0;
+
+ //item = &menu->rgItems[menu->iItem];
+ item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
+ if (item) item = &item[menu->iItem];
+ if (item && (item->spSubMenu) && (item->fState & MF_MOUSESELECT))
+ {
+ PMENU pSubMenu = DesktopPtrToUser(item->spSubMenu);
+ return UserHMGetHandle(pSubMenu);
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * MenuDoNextMenu
+ *
+ * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
+ */
+static LRESULT FASTCALL
+MenuDoNextMenu(MTRACKER* Mt, UINT Vk, UINT wFlags)
+{
+ ROSMENUINFO TopMenuInfo;
+ ROSMENUINFO MenuInfo;
+
+ if (! MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ return (LRESULT) FALSE;
+ }
+
+ if ((VK_LEFT == Vk && 0 == TopMenuInfo.iItem)
+ || (VK_RIGHT == Vk && TopMenuInfo.iItem == TopMenuInfo.cItems - 1))
+ {
+ MDINEXTMENU NextMenu;
+ HMENU NewMenu;
+ HWND NewWnd;
+ UINT Id = 0;
+
+ NextMenu.hmenuIn = (IS_SYSTEM_MENU(&TopMenuInfo)) ? GetSubMenu(Mt->TopMenu, 0) : Mt->TopMenu;
+ NextMenu.hmenuNext = NULL;
+ NextMenu.hwndNext = NULL;
+ SendMessageW(Mt->OwnerWnd, WM_NEXTMENU, Vk, (LPARAM) &NextMenu);
+
+ TRACE("%p [%p] -> %p [%p]\n",
+ Mt->CurrentMenu, Mt->OwnerWnd, NextMenu.hmenuNext, NextMenu.hwndNext );
+
+ if (NULL == NextMenu.hmenuNext || NULL == NextMenu.hwndNext)
+ {
+ DWORD Style = GetWindowLongPtrW(Mt->OwnerWnd, GWL_STYLE);
+ NewWnd = Mt->OwnerWnd;
+ if (IS_SYSTEM_MENU(&TopMenuInfo))
+ {
+ /* switch to the menu bar */
+
+ if (0 != (Style & WS_CHILD)
+ || NULL == (NewMenu = GetMenu(NewWnd)))
+ {
+ return FALSE;
+ }
+
+ if (VK_LEFT == Vk)
+ {
+ if (! MenuGetRosMenuInfo(&MenuInfo, NewMenu))
+ {
+ return FALSE;
+ }
+ Id = MenuInfo.cItems - 1;
+ }
+ }
+ else if (0 != (Style & WS_SYSMENU))
+ {
+ /* switch to the system menu */
- && GetSystemMenu(NewWnd, FALSE) == NewMenu)
++ NewMenu = get_win_sys_menu(NewWnd);
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ else /* application returned a new menu to switch to */
+ {
+ NewMenu = NextMenu.hmenuNext;
+ NewWnd = NextMenu.hwndNext;
+
+ if (IsMenu(NewMenu) && IsWindow(NewWnd))
+ {
+ DWORD Style = GetWindowLongPtrW(NewWnd, GWL_STYLE);
+
+ if (0 != (Style & WS_SYSMENU)
- NewMenu = NtUserGetSystemMenu(NewWnd, FALSE);
++ && get_win_sys_menu(NewWnd) == NewMenu)
+ {
+ /* get the real system menu */
- MenuInfo.fFlags & MNF_SYSDESKMN ? OBJID_SYSMENU : OBJID_MENU,
++ NewMenu = get_win_sys_menu(NewWnd);
+ }
+ else if (0 != (Style & WS_CHILD) || GetMenu(NewWnd) != NewMenu)
+ {
+ /* FIXME: Not sure what to do here;
+ * perhaps try to track NewMenu as a popup? */
+
+ WARN(" -- got confused.\n");
+ return FALSE;
+ }
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ if (NewMenu != Mt->TopMenu)
+ {
+ MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, NO_SELECTED_ITEM,
+ FALSE, 0 );
+ if (Mt->CurrentMenu != Mt->TopMenu)
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags);
+ }
+ }
+
+ if (NewWnd != Mt->OwnerWnd)
+ {
+ Mt->OwnerWnd = NewWnd;
+ NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER, Mt->OwnerWnd); // 1
+ SetCapture(Mt->OwnerWnd); // 2
+ }
+
+ Mt->TopMenu = Mt->CurrentMenu = NewMenu; /* all subpopups are hidden */
+ if (MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, Id, TRUE, 0);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/***********************************************************************
+ * MenuSuspendPopup
+ *
+ * The idea is not to show the popup if the next input message is
+ * going to hide it anyway.
+ */
+static BOOL FASTCALL
+MenuSuspendPopup(MTRACKER* Mt, UINT uMsg)
+{
+ MSG msg;
+
+ msg.hwnd = Mt->OwnerWnd;
+
+ PeekMessageW( &msg, 0, uMsg, uMsg, PM_NOYIELD | PM_REMOVE); // ported incorrectly since 8317 GvG
+ //Mt->TrackFlags |= TF_SKIPREMOVE; // This sends TrackMenu into a loop with arrow keys!!!!
+
+ switch( uMsg )
+ {
+ case WM_KEYDOWN:
+ PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
+ if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
+ {
+ PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
+ PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
+ if( msg.message == WM_KEYDOWN &&
+ (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
+ {
+ Mt->TrackFlags |= TF_SUSPENDPOPUP;
+ return TRUE;
+ }
+ }
+ break;
+ }
+ /* failures go through this */
+ Mt->TrackFlags &= ~TF_SUSPENDPOPUP;
+ return FALSE;
+}
+
+/***********************************************************************
+ * MenuKeyEscape
+ *
+ * Handle a VK_ESCAPE key event in a menu.
+ */
+static BOOL FASTCALL
+MenuKeyEscape(MTRACKER *Mt, UINT Flags)
+{
+ BOOL EndMenu = TRUE;
+ ROSMENUINFO MenuInfo;
+ HMENU MenuTmp, MenuPrev;
+
+ if (Mt->CurrentMenu != Mt->TopMenu)
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu)
+ && 0 != (MenuInfo.fFlags & MNF_POPUP))
+ {
+ MenuPrev = MenuTmp = Mt->TopMenu;
+
+ /* close topmost popup */
+ while (MenuTmp != Mt->CurrentMenu)
+ {
+ MenuPrev = MenuTmp;
+ MenuTmp = MENU_GetSubPopup(MenuPrev);
+ }
+
+ if (MenuGetRosMenuInfo(&MenuInfo, MenuPrev))
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, TRUE, Flags);
+ }
+ Mt->CurrentMenu = MenuPrev;
+ EndMenu = FALSE;
+ }
+ }
+
+ return EndMenu;
+}
+
+/***********************************************************************
+ * MenuKeyLeft
+ *
+ * Handle a VK_LEFT key event in a menu.
+ */
+static void FASTCALL
+MenuKeyLeft(MTRACKER* Mt, UINT Flags)
+{
+ ROSMENUINFO MenuInfo;
+ ROSMENUINFO TopMenuInfo;
+ ROSMENUINFO PrevMenuInfo;
+ HMENU MenuTmp, MenuPrev;
+ UINT PrevCol;
+
+ MenuPrev = MenuTmp = Mt->TopMenu;
+
+ /* Try to move 1 column left (if possible) */
+ if ( (PrevCol = MENU_GetStartOfPrevColumn(Mt->CurrentMenu)) != NO_SELECTED_ITEM)
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &MenuInfo, PrevCol, TRUE, 0);
+ }
+ return;
+ }
+
+ /* close topmost popup */
+ while (MenuTmp != Mt->CurrentMenu)
+ {
+ MenuPrev = MenuTmp;
+ MenuTmp = MENU_GetSubPopup(MenuPrev);
+ }
+
+ if (! MenuGetRosMenuInfo(&PrevMenuInfo, MenuPrev))
+ {
+ return;
+ }
+ MenuHideSubPopups(Mt->OwnerWnd, &PrevMenuInfo, TRUE, Flags);
+ Mt->CurrentMenu = MenuPrev;
+
+ if (! MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ return;
+ }
+ if ((MenuPrev == Mt->TopMenu) && !(TopMenuInfo.fFlags & MNF_POPUP))
+ {
+ /* move menu bar selection if no more popups are left */
+
+ if (!MenuDoNextMenu(Mt, VK_LEFT, Flags))
+ {
+ MenuMoveSelection(Mt->OwnerWnd, &TopMenuInfo, ITEM_PREV);
+ }
+
+ if (MenuPrev != MenuTmp || Mt->TrackFlags & TF_SUSPENDPOPUP)
+ {
+ /* A sublevel menu was displayed - display the next one
+ * unless there is another displacement coming up */
+
+ if (! MenuSuspendPopup(Mt, WM_KEYDOWN)
+ && MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &TopMenuInfo,
+ TRUE, Flags);
+ }
+ }
+ }
+}
+
+/***********************************************************************
+ * MenuKeyRight
+ *
+ * Handle a VK_RIGHT key event in a menu.
+ */
+static void FASTCALL MenuKeyRight(MTRACKER *Mt, UINT Flags)
+{
+ HMENU hmenutmp;
+ ROSMENUINFO MenuInfo;
+ ROSMENUINFO CurrentMenuInfo;
+ UINT NextCol;
+
+ TRACE("MenuKeyRight called, cur %p, top %p.\n",
+ Mt->CurrentMenu, Mt->TopMenu);
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu)) return;
+ if ((MenuInfo.fFlags & MNF_POPUP) || (Mt->CurrentMenu != Mt->TopMenu))
+ {
+ /* If already displaying a popup, try to display sub-popup */
+
+ hmenutmp = Mt->CurrentMenu;
+ if (MenuGetRosMenuInfo(&CurrentMenuInfo, Mt->CurrentMenu))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &CurrentMenuInfo, TRUE, Flags);
+ }
+
+ /* if subpopup was displayed then we are done */
+ if (hmenutmp != Mt->CurrentMenu) return;
+ }
+
+ /* Check to see if there's another column */
+ if ( (NextCol = MENU_GetStartOfNextColumn(Mt->CurrentMenu)) != NO_SELECTED_ITEM)
+ {
+ TRACE("Going to %d.\n", NextCol);
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &MenuInfo, NextCol, TRUE, 0);
+ }
+ return;
+ }
+
+ if (!(MenuInfo.fFlags & MNF_POPUP)) /* menu bar tracking */
+ {
+ if (Mt->CurrentMenu != Mt->TopMenu)
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
+ hmenutmp = Mt->CurrentMenu = Mt->TopMenu;
+ }
+ else
+ {
+ hmenutmp = NULL;
+ }
+
+ /* try to move to the next item */
+ if ( !MenuDoNextMenu(Mt, VK_RIGHT, Flags))
+ MenuMoveSelection(Mt->OwnerWnd, &MenuInfo, ITEM_NEXT);
+
+ if ( hmenutmp || Mt->TrackFlags & TF_SUSPENDPOPUP )
+ {
+ if (! MenuSuspendPopup(Mt, WM_KEYDOWN)
+ && MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo,
+ TRUE, Flags);
+ }
+ }
+ }
+}
+
+/***********************************************************************
+ * MenuTrackMenu
+ *
+ * Menu tracking code.
+ */
+static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y,
+ HWND hwnd, const RECT *lprect )
+{
+ MSG msg;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+ PMENU menu;
+ BOOL fRemove;
+ INT executedMenuId = -1;
+ MTRACKER mt;
+ HWND capture_win;
+ BOOL enterIdleSent = FALSE;
+
+ mt.TrackFlags = 0;
+ mt.CurrentMenu = hmenu;
+ mt.TopMenu = hmenu;
+ mt.OwnerWnd = hwnd;
+ mt.Pt.x = x;
+ mt.Pt.y = y;
+
+ TRACE("hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
+ hmenu, wFlags, x, y, hwnd, lprect ? lprect->left : 0, lprect ? lprect->top : 0,
+ lprect ? lprect->right : 0, lprect ? lprect->bottom : 0);
+
+ if (!IsMenu(hmenu))
+ {
+ WARN("Invalid menu handle %p\n", hmenu); // Error already set in IsMenu.
+ return FALSE;
+ }
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, hmenu))
+ {
+ return FALSE;
+ }
+
+ if (wFlags & TPM_BUTTONDOWN)
+ {
+ /* Get the result in order to start the tracking or not */
+ fRemove = MENU_ButtonDown( &mt, hmenu, wFlags );
+ fEndMenu = !fRemove;
+ }
+
+ if (wFlags & TF_ENDMENU) fEndMenu = TRUE;
+
+ /* owner may not be visible when tracking a popup, so use the menu itself */
+ capture_win = (wFlags & TPM_POPUPMENU) ? MenuInfo.Wnd : mt.OwnerWnd;
+ NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER, capture_win); // 1
+ SetCapture(capture_win); // 2
+
+ while (!fEndMenu)
+ {
+ BOOL ErrorExit = FALSE;
+ menu = MENU_GetMenu( mt.CurrentMenu );
+ if (!menu) /* sometimes happens if I do a window manager close */
+ break;
+
+ /* we have to keep the message in the queue until it's
+ * clear that menu loop is not over yet. */
+
+ for (;;)
+ {
+ if (PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ))
+ {
+ if (!CallMsgFilterW( &msg, MSGF_MENU )) break;
+ /* remove the message from the queue */
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+ }
+ else
+ {
+ /* ReactOS Check */
+ if (!ValidateHwndNoErr(mt.OwnerWnd) || !ValidateHwndNoErr(MenuInfo.Wnd))
+ {
+ ErrorExit = TRUE; // Do not wait on dead windows, now test_capture_4 works.
+ break;
+ }
+ if (!enterIdleSent)
+ {
+ HWND win = MenuInfo.fFlags & MNF_POPUP ? MenuInfo.Wnd : NULL;
+ enterIdleSent = TRUE;
+ SendMessageW( mt.OwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM) win);
+ }
+ WaitMessage();
+ }
+ }
+
+ if (ErrorExit) break; // Gracefully dropout.
+
+ /* check if EndMenu() tried to cancel us, by posting this message */
+ if (msg.message == WM_CANCELMODE)
+ {
+ /* we are now out of the loop */
+ fEndMenu = TRUE;
+
+ /* remove the message from the queue */
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+
+ /* break out of internal loop, ala ESCAPE */
+ break;
+ }
+
+ TranslateMessage( &msg );
+ mt.Pt = msg.pt;
+
+ if ( (msg.hwnd == MenuInfo.Wnd) || (msg.message!=WM_TIMER) )
+ enterIdleSent=FALSE;
+
+ fRemove = FALSE;
+ if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
+ {
+ /*
+ * Use the mouse coordinates in lParam instead of those in the MSG
+ * struct to properly handle synthetic messages. They are already
+ * in screen coordinates.
+ */
+ mt.Pt.x = (short)LOWORD(msg.lParam);
+ mt.Pt.y = (short)HIWORD(msg.lParam);
+
+ /* Find a menu for this mouse event */
+ hmenu = MENU_PtMenu(mt.TopMenu, mt.Pt);
+
+ switch(msg.message)
+ {
+ /* no WM_NC... messages in captured state */
+
+ case WM_RBUTTONDBLCLK:
+ case WM_RBUTTONDOWN:
+ if (!(wFlags & TPM_RIGHTBUTTON)) break;
+ /* fall through */
+ case WM_LBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ /* If the message belongs to the menu, removes it from the queue */
+ /* Else, end menu tracking */
+ fRemove = MENU_ButtonDown(&mt, hmenu, wFlags);
+ fEndMenu = !fRemove;
+ break;
+
+ case WM_RBUTTONUP:
+ if (!(wFlags & TPM_RIGHTBUTTON)) break;
+ /* fall through */
+ case WM_LBUTTONUP:
+ /* Check if a menu was selected by the mouse */
+ if (hmenu)
+ {
+ executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags);
+ TRACE("executedMenuId %d\n", executedMenuId);
+
+ /* End the loop if executedMenuId is an item ID */
+ /* or if the job was done (executedMenuId = 0). */
+ fEndMenu = fRemove = (executedMenuId != -1);
+ }
+ /* No menu was selected by the mouse */
+ /* if the function was called by TrackPopupMenu, continue
+ with the menu tracking. If not, stop it */
+ else
+ fEndMenu = ((wFlags & TPM_POPUPMENU) ? FALSE : TRUE);
+
+ break;
+
+ case WM_MOUSEMOVE:
+ /* the selected menu item must be changed every time */
+ /* the mouse moves. */
+
+ if (hmenu)
+ fEndMenu |= !MenuMouseMove( &mt, hmenu, wFlags );
+
+ } /* switch(msg.message) - mouse */
+ }
+ else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
+ {
+ fRemove = TRUE; /* Keyboard messages are always removed */
+ switch(msg.message)
+ {
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ switch(msg.wParam)
+ {
+ case VK_MENU:
+ case VK_F10:
+ fEndMenu = TRUE;
+ break;
+
+ case VK_HOME:
+ case VK_END:
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu))
+ {
+ MenuSelectItem(mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, 0 );
+ MenuMoveSelection(mt.OwnerWnd, &MenuInfo, VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV);
+ }
+ break;
+
+ case VK_UP:
+ case VK_DOWN: /* If on menu bar, pull-down the menu */
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu))
+ {
+ if (!(MenuInfo.fFlags & MNF_POPUP))
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu))
+ mt.CurrentMenu = MenuShowSubPopup(mt.OwnerWnd, &MenuInfo, TRUE, wFlags);
+ }
+ else /* otherwise try to move selection */
+ MenuMoveSelection(mt.OwnerWnd, &MenuInfo, (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT );
+ }
+ break;
+
+ case VK_LEFT:
+ MenuKeyLeft( &mt, wFlags );
+ break;
+
+ case VK_RIGHT:
+ MenuKeyRight( &mt, wFlags );
+ break;
+
+ case VK_ESCAPE:
+ fEndMenu = MenuKeyEscape(&mt, wFlags);
+ break;
+
+ case VK_F1:
+ {
+ HELPINFO hi;
+ hi.cbSize = sizeof(HELPINFO);
+ hi.iContextType = HELPINFO_MENUITEM;
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu))
+ {
+ if (MenuInfo.iItem == NO_SELECTED_ITEM)
+ hi.iCtrlId = 0;
+ else
+ {
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self,
+ MenuInfo.iItem,
+ &ItemInfo))
+ {
+ hi.iCtrlId = ItemInfo.wID;
+ }
+ else
+ {
+ hi.iCtrlId = 0;
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ }
+ }
+ hi.hItemHandle = hmenu;
+ hi.dwContextId = MenuInfo.dwContextHelpID;
+ hi.MousePos = msg.pt;
+ SendMessageW(hwnd, WM_HELP, 0, (LPARAM)&hi);
+ break;
+ }
+
+ default:
+ break;
+ }
+ break; /* WM_KEYDOWN */
+
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ {
+ UINT pos;
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) break;
+ if (msg.wParam == L'\r' || msg.wParam == L' ')
+ {
+ executedMenuId = MenuExecFocusedItem(&mt, &MenuInfo, wFlags);
+ fEndMenu = (executedMenuId != -2);
+ break;
+ }
+
+ /* Hack to avoid control chars. */
+ /* We will find a better way real soon... */
+ if (msg.wParam < 32) break;
+
+ pos = MENU_FindItemByKey(mt.OwnerWnd, mt.CurrentMenu, LOWORD(msg.wParam), FALSE);
+ if (pos == (UINT)-2) fEndMenu = TRUE;
+ else if (pos == (UINT)-1) MessageBeep(0);
+ else
+ {
+ MenuSelectItem(mt.OwnerWnd, &MenuInfo, pos, TRUE, 0);
+ executedMenuId = MenuExecFocusedItem(&mt, &MenuInfo, wFlags);
+ fEndMenu = (executedMenuId != -2);
+ }
+ }
+ break;
+ } /* switch(msg.message) - kbd */
+ }
+ else
+ {
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+ DispatchMessageW( &msg );
+ continue;
+ }
+
+ if (!fEndMenu) fRemove = TRUE;
+
+ /* finally remove message from the queue */
+
+ if (fRemove && !(mt.TrackFlags & TF_SKIPREMOVE) )
+ PeekMessageW( &msg, 0, msg.message, msg.message, PM_REMOVE );
+ else mt.TrackFlags &= ~TF_SKIPREMOVE;
+ }
+
+ NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL);
+ SetCapture(NULL); /* release the capture */
+
+ /* If dropdown is still painted and the close box is clicked on
+ then the menu will be destroyed as part of the DispatchMessage above.
+ This will then invalidate the menu handle in mt.hTopMenu. We should
+ check for this first. */
+ if( IsMenu( mt.TopMenu ) )
+ {
+ if (IsWindow(mt.OwnerWnd))
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu))
+ {
+ MenuHideSubPopups(mt.OwnerWnd, &MenuInfo, FALSE, wFlags);
+
+ if (MenuInfo.fFlags & MNF_POPUP)
+ {
+ IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
+ DestroyWindow(MenuInfo.Wnd);
+ MenuInfo.Wnd = NULL;
+ MenuSetRosMenuInfo(&MenuInfo);
+
+ if (!(wFlags & TPM_NONOTIFY))
+ SendMessageW( mt.OwnerWnd, WM_UNINITMENUPOPUP, (WPARAM)mt.TopMenu,
+ MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo)) );
+ }
+ MenuSelectItem( mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, 0 );
+ }
+
+ SendMessageW( mt.OwnerWnd, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0 );
+ }
+
+ /* Reset the variable for hiding menu */
+ if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu))
+ {
+ MenuInfo.TimeToHide = FALSE;
+ MenuSetRosMenuInfo(&MenuInfo);
+ }
+ }
+
+ /* The return value is only used by TrackPopupMenu */
+ if (!(wFlags & TPM_RETURNCMD)) return TRUE;
+ if (executedMenuId == -1) executedMenuId = 0;
+ return executedMenuId;
+}
+
+/***********************************************************************
+ * MenuInitTracking
+ */
+static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
+{
+ ROSMENUINFO MenuInfo;
+
+ TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu);
+
+ HideCaret(0);
+
+ /* This makes the menus of applications built with Delphi work.
+ * It also enables menus to be displayed in more than one window,
+ * but there are some bugs left that need to be fixed in this case.
+ */
+ if (!bPopup && (MenuGetRosMenuInfo(&MenuInfo, hMenu)))
+ {
+ MenuInfo.Wnd = hWnd;
+ MenuSetRosMenuInfo(&MenuInfo);
+ }
+ //if (!bPopup) menu->hWnd = hWnd;
+ if (!top_popup)
+ {
+ top_popup = MenuInfo.Wnd;//menu->hWnd;
+ top_popup_hmenu = hMenu;
+ }
+
+ fEndMenu = FALSE;
+
+ /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
+ if (!(wFlags & TPM_NONOTIFY))
+ SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
+
+ SendMessageW( hWnd, WM_SETCURSOR, (WPARAM)hWnd, HTCAPTION );
+
+ if (!(wFlags & TPM_NONOTIFY))
+ {
+ SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 );
+ /* If an app changed/recreated menu bar entries in WM_INITMENU
+ * menu sizes will be recalculated once the menu created/shown.
+ */
+
+ if (!MenuInfo.cyMenu)
+ {
+ /* app changed/recreated menu bar entries in WM_INITMENU
+ Recalculate menu sizes else clicks will not work */
+ SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
+
+ }
+ }
+
+ IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART,
+ hWnd,
- HMENU hMenu = (ht == HTSYSMENU) ? NtUserGetSystemMenu( hWnd, FALSE) : GetMenu(hWnd);
++ MenuInfo.fFlags & MNF_SYSMENU ? OBJID_SYSMENU : OBJID_MENU,
+ CHILDID_SELF, 0);
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuExitTracking
+ */
+static BOOL FASTCALL MenuExitTracking(HWND hWnd, BOOL bPopup)
+{
+ TRACE("hwnd=%p\n", hWnd);
+
+ IntNotifyWinEvent( EVENT_SYSTEM_MENUEND, hWnd, OBJID_WINDOW, CHILDID_SELF, 0);
+ SendMessageW( hWnd, WM_EXITMENULOOP, bPopup, 0 );
+ ShowCaret(0);
+ top_popup = 0;
+ top_popup_hmenu = NULL;
+ return TRUE;
+}
+
+/***********************************************************************
+ * MenuTrackMouseMenuBar
+ *
+ * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
+ */
+VOID MenuTrackMouseMenuBar( HWND hWnd, ULONG ht, POINT pt)
+{
- hTrackMenu = NtUserGetSystemMenu(hwnd, FALSE);
++ HMENU hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu(hWnd);
+ UINT wFlags = TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
+
+ TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
+
+ if (GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) wFlags |= TPM_LAYOUTRTL;
+ if (IsMenu(hMenu))
+ {
+ /* map point to parent client coordinates */
+ HWND Parent = GetAncestor(hWnd, GA_PARENT );
+ if (Parent != GetDesktopWindow())
+ {
+ ScreenToClient(Parent, &pt);
+ }
+
+ MenuInitTracking(hWnd, hMenu, FALSE, wFlags);
++ /* fetch the window menu again, it may have changed */
++ hMenu = (ht == HTSYSMENU) ? get_win_sys_menu( hWnd ) : GetMenu( hWnd );
+ MenuTrackMenu(hMenu, wFlags, pt.x, pt.y, hWnd, NULL);
+ MenuExitTracking(hWnd, FALSE);
+ }
+}
+
+/***********************************************************************
+ * MenuTrackKbdMenuBar
+ *
+ * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
+ */
+VOID MenuTrackKbdMenuBar(HWND hwnd, UINT wParam, WCHAR wChar)
+{
+ UINT uItem = NO_SELECTED_ITEM;
+ HMENU hTrackMenu;
+ ROSMENUINFO MenuInfo;
+ UINT wFlags = TPM_LEFTALIGN | TPM_LEFTBUTTON;
+
+ TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd, wParam, wChar);
+
+ /* find window that has a menu */
+
+ while (!((GetWindowLongPtrW( hwnd, GWL_STYLE ) &
+ (WS_CHILD | WS_POPUP)) != WS_CHILD))
+ if (!(hwnd = GetAncestor( hwnd, GA_PARENT ))) return;
+
+ /* check if we have to track a system menu */
+
+ hTrackMenu = GetMenu( hwnd );
+ if (!hTrackMenu || IsIconic(hwnd) || wChar == ' ' )
+ {
+ if (!(GetWindowLongPtrW( hwnd, GWL_STYLE ) & WS_SYSMENU)) return;
- HMENU TopMenu;
-
- TopMenu = NtUserGetSystemMenu(hWnd, bRevert);
-
- return NULL == TopMenu ? NULL : GetSubMenu(TopMenu, 0);
++ hTrackMenu = get_win_sys_menu(hwnd);
+ uItem = 0;
+ wParam |= HTSYSMENU; /* prevent item lookup */
+ }
+
+ if (!IsMenu( hTrackMenu )) return;
+
+ MenuInitTracking( hwnd, hTrackMenu, FALSE, wFlags );
+
+ /* fetch the window menu again, it may have changed */
+ hTrackMenu = (wParam & HTSYSMENU) ? get_win_sys_menu( hwnd ) : GetMenu( hwnd );
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, hTrackMenu))
+ {
+ goto track_menu;
+ }
+
+ if( wChar && wChar != ' ' )
+ {
+ uItem = MENU_FindItemByKey( hwnd, hTrackMenu, wChar, (wParam & HTSYSMENU) );
+ if ( uItem >= (UINT)(-2) )
+ {
+ if( uItem == (UINT)(-1) ) MessageBeep(0);
+ /* schedule end of menu tracking */
+ wFlags |= TF_ENDMENU;
+ goto track_menu;
+ }
+ }
+
+ MenuSelectItem( hwnd, &MenuInfo, uItem, TRUE, 0 );
+
+ if (!(wParam & HTSYSMENU) || wChar == ' ')
+ {
+ if( uItem == NO_SELECTED_ITEM )
+ MenuMoveSelection( hwnd, &MenuInfo, ITEM_NEXT );
+ else
+ PostMessageW( hwnd, WM_KEYDOWN, VK_RETURN, 0 );
+ }
+
+track_menu:
+ MenuTrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
+ MenuExitTracking( hwnd, FALSE );
+}
+
+/**********************************************************************
+ * TrackPopupMenuEx (USER32.@)
+ */
+BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, int x, int y,
+ HWND hWnd, LPTPMPARAMS lpTpm)
+{
+ BOOL ret = FALSE;
+ MENU *menu;
+
+ TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p rect %s\n",
+ hMenu, wFlags, x, y, hWnd, lpTpm,
+ lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
+
+ /* Parameter check */
+ /* FIXME: this check is performed several times, here and in the called
+ functions. That could be optimized */
+ if (!(menu = MENU_GetMenu( hMenu )))
+ {
+ SetLastError( ERROR_INVALID_MENU_HANDLE );
+ return FALSE;
+ }
+
+ if (IsWindow(menu->hWnd))
+ {
+ SetLastError( ERROR_POPUP_ALREADY_ACTIVE );
+ return FALSE;
+ }
+
+ if (MENU_InitPopup( hWnd, hMenu, wFlags ))
+ {
+ MenuInitTracking(hWnd, hMenu, TRUE, wFlags);
+
+ /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
+ if (!(wFlags & TPM_NONOTIFY))
+ SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM) hMenu, 0);
+
+ if (MenuShowPopup(hWnd, hMenu, 0, wFlags, x, y, 0, 0 ))
+ ret = MenuTrackMenu(hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd,
+ lpTpm ? &lpTpm->rcExclude : NULL);
+ MenuExitTracking(hWnd, TRUE);
+
+ if (menu->hWnd)
+ {
+ ROSMENUINFO MenuInfo;
+ if (IsWindow( menu->hWnd )) // wine hack around this with their destroy function.
+ DestroyWindow( menu->hWnd ); // Fix wrong error return.
+ //menu->hWnd = 0;
+ MenuGetRosMenuInfo(&MenuInfo, menu->head.h);
+ MenuInfo.Wnd = 0;
+ MenuSetRosMenuInfo(&MenuInfo);
+
+ if (!(wFlags & TPM_NONOTIFY))
+ SendMessageW( hWnd, WM_UNINITMENUPOPUP, (WPARAM)hMenu,
+ MAKELPARAM(0, IS_SYSTEM_MENU(menu)) );
+ }
+ }
+ return ret;
+}
+
+/**********************************************************************
+ * TrackPopupMenu (USER32.@)
+ */
+BOOL WINAPI TrackPopupMenu( HMENU Menu, UINT Flags, int x, int y,
+ int Reserved, HWND Wnd, CONST RECT *Rect)
+{
+ return TrackPopupMenuEx( Menu, Flags, x, y, Wnd, NULL);
+}
+
+/**********************************************************************
+ * MENU_mnu2mnuii
+ *
+ * Uses flags, id and text ptr, passed by InsertMenu() and
+ * ModifyMenu() to setup a MenuItemInfo structure.
+ */
+static void MENU_mnu2mnuii( UINT flags, UINT_PTR id, LPCWSTR str, LPMENUITEMINFOW pmii, BOOL Unicode)
+{
+ RtlZeroMemory( pmii, sizeof( MENUITEMINFOW));
+ pmii->cbSize = sizeof( MENUITEMINFOW);
+ pmii->fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE;
+ /* setting bitmap clears text and vice versa */
+ if( IS_STRING_ITEM(flags)) {
+ pmii->fMask |= MIIM_STRING | MIIM_BITMAP;
+ if( !str)
+ flags |= MF_SEPARATOR;
+ /* Item beginning with a backspace is a help item */
+ /* FIXME: wrong place, this is only true in win16 */
+ else
+ {
+ if (Unicode)
+ {
+ if (*str == '\b')
+ {
+ flags |= MF_HELP;
+ str++;
+ }
+ }
+ else
+ {
+ LPCSTR NewItemA = (LPCSTR) str;
+ if (*NewItemA == '\b')
+ {
+ flags |= MF_HELP;
+ NewItemA++;
+ str = (LPCWSTR) NewItemA;
+ }
+ TRACE("A cch %d\n",strlen(NewItemA));
+ }
+ }
+ pmii->dwTypeData = (LPWSTR)str;
+ } else if( flags & MFT_BITMAP){
+ pmii->fMask |= MIIM_BITMAP | MIIM_STRING;
+ pmii->hbmpItem = (HBITMAP)str;
+ }
+ if( flags & MF_OWNERDRAW){
+ pmii->fMask |= MIIM_DATA;
+ pmii->dwItemData = (ULONG_PTR) str;
+ }
+ if( flags & MF_POPUP && MENU_GetMenu((HMENU)id)) {
+ pmii->fMask |= MIIM_SUBMENU;
+ pmii->hSubMenu = (HMENU)id;
+ }
+ if( flags & MF_SEPARATOR) flags |= MF_GRAYED | MF_DISABLED;
+ pmii->fState = flags & MENUITEMINFO_STATE_MASK & ~MFS_DEFAULT;
+ pmii->fType = flags & MENUITEMINFO_TYPE_MASK;
+ pmii->wID = (UINT)id;
+}
+
+/**********************************************************************
+ * MENU_NormalizeMenuItemInfoStruct
+ *
+ * Helper for SetMenuItemInfo and InsertMenuItemInfo:
+ * check, copy and extend the MENUITEMINFO struct from the version that the application
+ * supplied to the version used by wine source. */
+static BOOL MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW *pmii_in,
+ MENUITEMINFOW *pmii_out )
+{
+ /* do we recognize the size? */
+ if( !pmii_in || (pmii_in->cbSize != sizeof( MENUITEMINFOW) &&
+ pmii_in->cbSize != sizeof( MENUITEMINFOW) - sizeof( pmii_in->hbmpItem)) ) {
+ SetLastError( ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ /* copy the fields that we have */
+ memcpy( pmii_out, pmii_in, pmii_in->cbSize);
+ /* if the hbmpItem member is missing then extend */
+ if( pmii_in->cbSize != sizeof( MENUITEMINFOW)) {
+ pmii_out->cbSize = sizeof( MENUITEMINFOW);
+ pmii_out->hbmpItem = NULL;
+ }
+ /* test for invalid bit combinations */
+ if( (pmii_out->fMask & MIIM_TYPE &&
+ pmii_out->fMask & (MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) ||
+ (pmii_out->fMask & MIIM_FTYPE && pmii_out->fType & MFT_BITMAP)) {
+ ERR("invalid combination of fMask bits used\n");
+ /* this does not happen on Win9x/ME */
+ SetLastError( ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ /* convert old style (MIIM_TYPE) to the new and keep the old one too */
+ if( pmii_out->fMask & MIIM_TYPE){
+ pmii_out->fMask |= MIIM_FTYPE;
+ if( IS_STRING_ITEM(pmii_out->fType)){
+ pmii_out->fMask |= MIIM_STRING;
+ } else if( (pmii_out->fType) & MFT_BITMAP){
+ pmii_out->fMask |= MIIM_BITMAP;
+ pmii_out->hbmpItem = UlongToHandle(LOWORD(pmii_out->dwTypeData));
+ }
+ }
+ if (pmii_out->fMask & MIIM_FTYPE )
+ {
+ pmii_out->fType &= ~MENUITEMINFO_TYPE_MASK;
+ pmii_out->fType |= pmii_in->fType & MENUITEMINFO_TYPE_MASK;
+ }
+ if (pmii_out->fMask & MIIM_STATE)
+ /* Other menu items having MFS_DEFAULT are not converted
+ to normal items */
+ pmii_out->fState = pmii_in->fState & MENUITEMINFO_STATE_MASK;
+
+ return TRUE;
+}
+
+BOOL
+MenuInit(VOID)
+{
+ NONCLIENTMETRICSW ncm;
+
+ /* get the menu font */
+ if(!hMenuFont || !hMenuFontBold)
+ {
+ ncm.cbSize = sizeof(ncm);
+ if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
+ {
+ ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
+ return FALSE;
+ }
+
+ hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont);
+ if(hMenuFont == NULL)
+ {
+ ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
+ return FALSE;
+ }
+
+ ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
+ hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont);
+ if(hMenuFontBold == NULL)
+ {
+ ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
+ DeleteObject(hMenuFont);
+ hMenuFont = NULL;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+VOID
+MenuCleanup(VOID)
+{
+ if (hMenuFont)
+ {
+ DeleteObject(hMenuFont);
+ hMenuFont = NULL;
+ }
+
+ if (hMenuFontBold)
+ {
+ DeleteObject(hMenuFontBold);
+ hMenuFontBold = NULL;
+ }
+}
+
++HMENU FASTCALL MENU_LoadSystemMenu(BOOL mdi)
++{
++ HMENU hmenu = LoadMenuW(User32Instance, L"SYSMENU");
++
++ if (hmenu)
++ {
++ MENUINFO menuinfo = {0};
++ MENUITEMINFOW info = {0};
++ //WCHAR buf[128];
++
++ // removing space for checkboxes from menu
++ menuinfo.cbSize = sizeof(menuinfo);
++ menuinfo.fMask = MIM_STYLE;
++ GetMenuInfo(hmenu, &menuinfo);
++ menuinfo.dwStyle |= MNS_CHECKORBMP;
++ SetMenuInfo(hmenu, &menuinfo);
++
++ // adding bitmaps to menu items
++ info.cbSize = sizeof(info);
++ info.fMask |= MIIM_BITMAP;
++ info.hbmpItem = HBMMENU_POPUP_MINIMIZE;
++ SetMenuItemInfoW(hmenu, SC_MINIMIZE, FALSE, &info);
++ info.hbmpItem = HBMMENU_POPUP_RESTORE;
++ SetMenuItemInfoW(hmenu, SC_RESTORE, FALSE, &info);
++ info.hbmpItem = HBMMENU_POPUP_MAXIMIZE;
++ SetMenuItemInfoW(hmenu, SC_MAXIMIZE, FALSE, &info);
++ info.hbmpItem = HBMMENU_POPUP_CLOSE;
++ SetMenuItemInfoW(hmenu, SC_CLOSE, FALSE, &info);
++ if (mdi)
++ {
++ AppendMenuW(hmenu, MF_SEPARATOR, 0, NULL);
++ //LoadStringW(User32Instance, IDS_MDI_NEXT, buf, sizeof(buf)/sizeof(WCHAR));
++ //AppendMenuW(hmenu, MF_STRING, SC_NEXTWINDOW, buf);
++ }
++ }
++ return hmenu;
++}
++
+NTSTATUS WINAPI
+User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength)
+{
+ LRESULT Result = 0;
+
+ // Will be converted to load bitmaps for OBMI!
+
+ return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
+}
+
+NTSTATUS WINAPI
+User32CallLoadMenuFromKernel(PVOID Arguments, ULONG ArgumentLength)
+{
+ PLOADMENU_CALLBACK_ARGUMENTS Common;
+ LRESULT Result;
+
+ Common = (PLOADMENU_CALLBACK_ARGUMENTS) Arguments;
+
+ Result = (LRESULT)LoadMenuW( Common->hModule, Common->InterSource ? MAKEINTRESOURCE(Common->InterSource) : (LPCWSTR)&Common->MenuName);
+
+ return ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS);
+}
+
+
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+AppendMenuA(HMENU hMenu,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCSTR lpNewItem)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING UnicodeString;
+ BOOL res;
+
+ RtlInitUnicodeString(&UnicodeString, 0);
+
+ MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
+
+ /* copy the text string, it will be one or the other */
+ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
+ {
+ SetLastError (ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ mii.dwTypeData = UnicodeString.Buffer;
+ mii.cch = UnicodeString.Length / sizeof(WCHAR);
+ }
+ else
+ {
+ TRACE("AMA Handle bitmaps\n");
+ }
+ ////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append?
+ res = NtUserThunkedMenuItemInfo(hMenu, -1, TRUE, TRUE, &mii, &UnicodeString);
+ if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
+ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+AppendMenuW(HMENU hMenu,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCWSTR lpNewItem)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING MenuText;
+ BOOL res;
+
+ RtlInitUnicodeString(&MenuText, 0);
+
+ MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
+
+ /* copy the text string, it will be one or the other */
+ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
+ {
+ RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
+ mii.dwTypeData = MenuText.Buffer;
+ mii.cch = MenuText.Length / sizeof(WCHAR);
+ }
+ res = NtUserThunkedMenuItemInfo(hMenu, -1, TRUE, TRUE, &mii, &MenuText);
+ return res;
+}
+
+/*
+ * @implemented
+ */
+DWORD WINAPI
+CheckMenuItem(HMENU hmenu,
+ UINT uIDCheckItem,
+ UINT uCheck)
+{
+ PMENU pMenu;
+ PITEM item;
+ DWORD Ret;
+
+ if (!(pMenu = ValidateHandle(hmenu, TYPE_MENU)))
+ return -1;
+
+ if (!(item = MENU_FindItem( &hmenu, &uIDCheckItem, uCheck ))) return -1;
+
+ Ret = item->fState & MFS_CHECKED;
+ if ( Ret == (uCheck & MFS_CHECKED)) return Ret; // Already Checked...
+
+ return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck);
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+CheckMenuRadioItem(HMENU hMenu,
+ UINT first,
+ UINT last,
+ UINT check,
+ UINT bypos)
+{
+ BOOL done = FALSE;
+ UINT i;
+ PITEM mi_first = NULL, mi_check;
+ HMENU m_first, m_check;
+ MENUITEMINFOW mii;
+ mii.cbSize = sizeof( mii);
+
+ for (i = first; i <= last; i++)
+ {
+ UINT pos = i;
+
+ if (!mi_first)
+ {
+ m_first = hMenu;
+ mi_first = MENU_FindItem(&m_first, &pos, bypos);
+ if (!mi_first) continue;
+ mi_check = mi_first;
+ m_check = m_first;
+ }
+ else
+ {
+ m_check = hMenu;
+ mi_check = MENU_FindItem(&m_check, &pos, bypos);
+ if (!mi_check) continue;
+ }
+
+ if (m_first != m_check) continue;
+ if (mi_check->fType == MFT_SEPARATOR) continue;
+
+ if (i == check)
+ {
+ if (!(mi_check->fType & MFT_RADIOCHECK) || !(mi_check->fState & MFS_CHECKED))
+ {
+ mii.fMask = MIIM_FTYPE | MIIM_STATE;
+ mii.fType = (mi_check->fType & MENUITEMINFO_TYPE_MASK) | MFT_RADIOCHECK;
+ mii.fState = (mi_check->fState & MII_STATE_MASK) | MFS_CHECKED;
+ NtUserThunkedMenuItemInfo(m_check, i, bypos, FALSE, &mii, NULL);
+ }
+ done = TRUE;
+ }
+ else
+ {
+ /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
+ if (mi_check->fState & MFS_CHECKED)
+ {
+ mii.fMask = MIIM_STATE;
+ mii.fState = (mi_check->fState & MII_STATE_MASK) & ~MFS_CHECKED;
+ NtUserThunkedMenuItemInfo(m_check, i, bypos, FALSE, &mii, NULL);
+ }
+ }
+ }
+ return done;
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+CreateMenu(VOID)
+{
+ MenuLoadBitmaps();
+ return NtUserxCreateMenu();
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+CreatePopupMenu(VOID)
+{
+ MenuLoadBitmaps();
+ return NtUserxCreatePopupMenu();
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+DrawMenuBar(HWND hWnd)
+{
+ return NtUserxDrawMenuBar(hWnd);
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+EnableMenuItem(HMENU hMenu,
+ UINT uIDEnableItem,
+ UINT uEnable)
+{
+ return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable);
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+EndMenu(VOID)
+{
+ GUITHREADINFO guii;
+ guii.cbSize = sizeof(GUITHREADINFO);
+ if(GetGUIThreadInfo(GetCurrentThreadId(), &guii) && guii.hwndMenuOwner)
+ {
+ if (!fEndMenu &&
+ top_popup &&
+ guii.hwndMenuOwner != top_popup )
+ {
+ ERR("Capture GUI pti hWnd does not match top_popup!\n");
+ }
+ }
+
+ /* if we are in the menu code, and it is active */
+ if (!fEndMenu && top_popup)
+ {
+ /* terminate the menu handling code */
+ fEndMenu = TRUE;
+
+ /* needs to be posted to wakeup the internal menu handler */
+ /* which will now terminate the menu, in the event that */
+ /* the main window was minimized, or lost focus, so we */
+ /* don't end up with an orphaned menu */
+ PostMessageW( top_popup, WM_CANCELMODE, 0, 0);
+ }
+ return fEndMenu;
+}
+
+BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID,
+ UINT wHilite )
+{
+ ROSMENUINFO MenuInfo;
+ TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite);
+ // Force bits to be set call server side....
+ // This alone works and passes all the menu test_menu_hilitemenuitem tests.
+ if (!NtUserHiliteMenuItem(hWnd, hMenu, wItemID, wHilite)) return FALSE;
+ // Without the above call we fail 3 out of the wine failed todo tests, see CORE-7967
+ // Now redraw menu.
+ if (MenuGetRosMenuInfo(&MenuInfo, hMenu))
+ {
+ if (MenuInfo.iItem == wItemID) return TRUE;
+ MenuHideSubPopups( hWnd, &MenuInfo, FALSE, 0 );
+ MenuSelectItem( hWnd, &MenuInfo, wItemID, TRUE, 0 );
+ }
+ return TRUE; // Always returns TRUE!
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+GetMenu(HWND hWnd)
+{
+ PWND Wnd = ValidateHwnd(hWnd);
+
+ if (!Wnd)
+ return NULL;
+
+ return UlongToHandle(Wnd->IDMenu);
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI GetMenuBarInfo( HWND hwnd, LONG idObject, LONG idItem, PMENUBARINFO pmbi )
+{
+ BOOL Ret;
+ Ret = NtUserGetMenuBarInfo( hwnd, idObject, idItem, pmbi);
+ // Reason to move to server side!!!!!
+ if (!Ret) return Ret;
+ // EL HAXZO!!!
+ pmbi->fBarFocused = top_popup_hmenu == pmbi->hMenu;
+ if (!idItem)
+ {
+ pmbi->fFocused = pmbi->fBarFocused;
+ }
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+LONG WINAPI
+GetMenuCheckMarkDimensions(VOID)
+{
+ return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
+ GetSystemMetrics(SM_CYMENUCHECK)));
+}
+
+/*
+ * @implemented
+ */
+DWORD
+WINAPI
+GetMenuContextHelpId(HMENU hmenu)
+{
+ PMENU pMenu;
+ if ((pMenu = ValidateHandle(hmenu, TYPE_MENU)))
+ return pMenu->dwContextHelpId;
+ return 0;
+}
+
+/*
+ * @implemented
+ */
+UINT WINAPI
+GetMenuDefaultItem(HMENU hMenu,
+ UINT fByPos,
+ UINT gmdiFlags)
+{
+ PMENU pMenu;
+ DWORD gismc = 0;
+ if (!(pMenu = ValidateHandle(hMenu, TYPE_MENU)))
+ return (UINT)-1;
+
+ return IntGetMenuDefaultItem( pMenu, (BOOL)fByPos, gmdiFlags, &gismc);
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+GetMenuInfo(HMENU hmenu,
+ LPMENUINFO lpcmi)
+{
+ PMENU pMenu;
+
+ if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if (!(pMenu = ValidateHandle(hmenu, TYPE_MENU)))
+ return FALSE;
+
+ if (lpcmi->fMask & MIM_BACKGROUND)
+ lpcmi->hbrBack = pMenu->hbrBack;
+
+ if (lpcmi->fMask & MIM_HELPID)
+ lpcmi->dwContextHelpID = pMenu->dwContextHelpId;
+
+ if (lpcmi->fMask & MIM_MAXHEIGHT)
+ lpcmi->cyMax = pMenu->cyMax;
+
+ if (lpcmi->fMask & MIM_MENUDATA)
+ lpcmi->dwMenuData = pMenu->dwMenuData;
+
+ if (lpcmi->fMask & MIM_STYLE)
+ lpcmi->dwStyle = pMenu->fFlags & MNS_STYLE_MASK;
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+int WINAPI
+GetMenuItemCount(HMENU hmenu)
+{
+ PMENU pMenu;
+ if ((pMenu = ValidateHandle(hmenu, TYPE_MENU)))
+ return pMenu->cItems;
+ return -1;
+}
+
+/*
+ * @implemented
+ */
+UINT WINAPI
+GetMenuItemID(HMENU hMenu,
+ int nPos)
+{
+ ITEM * lpmi;
+ if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return -1;
+ if (lpmi->spSubMenu) return -1;
+ return lpmi->wID;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+GetMenuItemInfoA(
+ HMENU hmenu,
+ UINT item,
+ BOOL bypos,
+ LPMENUITEMINFOA lpmii)
+{
+ BOOL ret;
+ MENUITEMINFOA mii;
+
+ if( lpmii->cbSize != sizeof( mii) &&
+ lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ memcpy( &mii, lpmii, lpmii->cbSize);
+ mii.cbSize = sizeof( mii);
+ ret = GetMenuItemInfo_common (hmenu,
+ item,
+ bypos,
+ (LPMENUITEMINFOW)&mii,
+ FALSE);
+ mii.cbSize = lpmii->cbSize;
+ memcpy( lpmii, &mii, mii.cbSize);
+ return ret;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+GetMenuItemInfoW(
+ HMENU hMenu,
+ UINT Item,
+ BOOL bypos,
+ LPMENUITEMINFOW lpmii)
+{
+ BOOL ret;
+ MENUITEMINFOW mii;
+ if( lpmii->cbSize != sizeof( mii) && lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ memcpy( &mii, lpmii, lpmii->cbSize);
+ mii.cbSize = sizeof( mii);
+ ret = GetMenuItemInfo_common (hMenu, Item, bypos, &mii, TRUE);
+ mii.cbSize = lpmii->cbSize;
+ memcpy( lpmii, &mii, mii.cbSize);
+ return ret;
+}
+
+/*
+ * @implemented
+ */
+UINT
+WINAPI
+GetMenuState(
+ HMENU hMenu,
+ UINT uId,
+ UINT uFlags)
+{
+ PITEM pItem;
+ UINT Type = 0;
+ TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, uId, uFlags);
+ if (!(pItem = MENU_FindItem( &hMenu, &uId, uFlags ))) return -1;
+
+ if (!pItem->Xlpstr && pItem->hbmp) Type = MFT_BITMAP;
+
+ if (pItem->spSubMenu)
+ {
+ PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
+ HMENU hsubmenu = UserHMGetHandle(pSubMenu);
+ if (!IsMenu(hsubmenu)) return (UINT)-1;
+ else return (pSubMenu->cItems << 8) | ((pItem->fState|pItem->fType|Type) & 0xff);
+ }
+ else
+ return (pItem->fType | pItem->fState | Type);
+}
+
+/*
+ * @implemented
+ */
+int
+WINAPI
+GetMenuStringA(
+ HMENU hMenu,
+ UINT uIDItem,
+ LPSTR lpString,
+ int nMaxCount,
+ UINT uFlag)
+{
+ ITEM *item;
+ LPWSTR text;
+ ////// wine Code, seems to be faster.
+ TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag );
+
+ if (lpString && nMaxCount) lpString[0] = '\0';
+
+ if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag )))
+ {
+ SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
+ return 0;
+ }
+
+ text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
+
+ if (!text) return 0;
+ if (!lpString || !nMaxCount) return WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL );
+ if (!WideCharToMultiByte( CP_ACP, 0, text, -1, lpString, nMaxCount, NULL, NULL ))
+ lpString[nMaxCount-1] = 0;
+ TRACE("A returning %s\n", lpString);
+ return strlen(lpString);
+}
+
+/*
+ * @implemented
+ */
+int
+WINAPI
+GetMenuStringW(
+ HMENU hMenu,
+ UINT uIDItem,
+ LPWSTR lpString,
+ int nMaxCount,
+ UINT uFlag)
+{
+ ITEM *item;
+ LPWSTR text;
+
+ TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag );
+
+ if (lpString && nMaxCount) lpString[0] = '\0';
+
+ if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag )))
+ {
+ SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
+ return 0;
+ }
+
+ text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
+
+ if (!lpString || !nMaxCount) return text ? strlenW(text) : 0;
+ if( !(text))
+ {
+ lpString[0] = 0;
+ return 0;
+ }
+ lstrcpynW( lpString, text, nMaxCount );
+ TRACE("W returning %S\n", lpString);
+ return strlenW(lpString);
+}
+
+/*
+ * @implemented
+ */
+HMENU
+WINAPI
+GetSubMenu(
+ HMENU hMenu,
+ int nPos)
+{
+ PITEM pItem;
+ if (!(pItem = MENU_FindItem( &hMenu, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
+
+ if (pItem->spSubMenu)
+ {
+ PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
+ HMENU hsubmenu = UserHMGetHandle(pSubMenu);
+ if (IsMenu(hsubmenu)) return hsubmenu;
+ }
+ return NULL;
+}
+
+/*
+ * @implemented
+ */
+HMENU
+WINAPI
+GetSystemMenu(
+ HWND hWnd,
+ BOOL bRevert)
+{
++ return NtUserGetSystemMenu(hWnd, bRevert);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+InsertMenuA(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCSTR lpNewItem)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING UnicodeString;
+ BOOL res;
+
+ RtlInitUnicodeString(&UnicodeString, 0);
+
+ MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
+
+ /* copy the text string, it will be one or the other */
+ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
+ {
+ SetLastError (ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ mii.dwTypeData = UnicodeString.Buffer;
+ mii.cch = UnicodeString.Length / sizeof(WCHAR);
+ }
+ else
+ {
+ TRACE("Handle bitmaps\n");
+ }
+ res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &UnicodeString);
+ if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
+ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+InsertMenuItemA(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ LPCMENUITEMINFOA lpmii)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING UnicodeString;
+ BOOL res;
+
+ TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
+
+ RtlInitUnicodeString(&UnicodeString, 0);
+
+ if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
+
+ /* copy the text string */
+ if (((mii.fMask & MIIM_STRING) ||
+ ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
+ && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
+ {
+ SetLastError (ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ mii.dwTypeData = UnicodeString.Buffer;
+ mii.cch = UnicodeString.Length / sizeof(WCHAR);
+ }
+ else
+ {
+ TRACE("Handle bitmaps\n");
+ }
+ res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &UnicodeString);
+ if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
+ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+InsertMenuItemW(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ LPCMENUITEMINFOW lpmii)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING MenuText;
+ BOOL res = FALSE;
+
+ /* while we could just pass 'lpmii' to win32k, we make a copy so that
+ if a bad user passes bad data, we crash his process instead of the
+ entire kernel */
+
+ TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
+
+ RtlInitUnicodeString(&MenuText, 0);
+
+ if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
+
+ /* copy the text string */
+ if (((mii.fMask & MIIM_STRING) ||
+ ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
+ && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
+ {
+ RtlInitUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData);
+ mii.dwTypeData = MenuText.Buffer;
+ mii.cch = MenuText.Length / sizeof(WCHAR);
+ }
+ res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &MenuText);
+ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+InsertMenuW(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCWSTR lpNewItem)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING MenuText;
+ BOOL res;
+
+ RtlInitUnicodeString(&MenuText, 0);
+
+ MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
+
+ /* copy the text string, it will be one or the other */
+ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
+ {
+ RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
+ mii.dwTypeData = MenuText.Buffer;
+ mii.cch = MenuText.Length / sizeof(WCHAR);
+ }
+ res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &MenuText);
+ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+IsMenu(
+ HMENU Menu)
+{
+ if (ValidateHandle(Menu, TYPE_MENU)) return TRUE;
+ return FALSE;
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+LoadMenuA(HINSTANCE hInstance,
+ LPCSTR lpMenuName)
+{
+ HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
+ if (Resource == NULL)
+ {
+ return(NULL);
+ }
+ return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
+{
+ return(LoadMenuIndirectW(lpMenuTemplate));
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate)
+{
+ HMENU hMenu;
+ WORD version, offset;
+ LPCSTR p = (LPCSTR)lpMenuTemplate;
+
+ version = GET_WORD(p);
+ p += sizeof(WORD);
+
+ switch (version)
+ {
+ case 0: /* standard format is version of 0 */
+ offset = GET_WORD(p);
+ p += sizeof(WORD) + offset;
+ if (!(hMenu = CreateMenu())) return 0;
+ if (!MENU_ParseResource(p, hMenu))
+ {
+ DestroyMenu(hMenu);
+ return 0;
+ }
+ return hMenu;
+ case 1: /* extended format is version of 1 */
+ offset = GET_WORD(p);
+ p += sizeof(WORD) + offset;
+ if (!(hMenu = CreateMenu())) return 0;
+ if (!MENUEX_ParseResource(p, hMenu))
+ {
+ DestroyMenu( hMenu );
+ return 0;
+ }
+ return hMenu;
+ default:
+ ERR("Menu template version %d not supported.\n", version);
+ return 0;
+ }
+}
+
+/*
+ * @implemented
+ */
+HMENU WINAPI
+LoadMenuW(HINSTANCE hInstance,
+ LPCWSTR lpMenuName)
+{
+ HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
+ if (Resource == NULL)
+ {
+ return(NULL);
+ }
+ return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
+}
+
+/*
+ * @implemented
+ */
+int
+WINAPI
+MenuItemFromPoint(
+ HWND hWnd,
+ HMENU hMenu,
+ POINT ptScreen)
+{
+ return NtUserMenuItemFromPoint(hWnd, hMenu, ptScreen.x, ptScreen.y);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+ModifyMenuA(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCSTR lpNewItem)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING UnicodeString;
+ BOOL res;
+
+ RtlInitUnicodeString(&UnicodeString, 0);
+
+ MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
+
+ /* copy the text string, it will be one or the other */
+ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
+ {
+ if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
+ {
+ SetLastError (ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ mii.dwTypeData = UnicodeString.Buffer;
+ mii.cch = UnicodeString.Length / sizeof(WCHAR);
+ }
+ else
+ {
+ TRACE("Handle bitmaps\n");
+ }
+ res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &UnicodeString);
+ if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
+ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+ModifyMenuW(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCWSTR lpNewItem)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING MenuText;
+ BOOL res;
+
+ RtlInitUnicodeString(&MenuText, 0);
+
+ MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
+
+ /* copy the text string, it will be one or the other */
+ if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
+ {
+ RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
+ mii.dwTypeData = MenuText.Buffer;
+ mii.cch = MenuText.Length / sizeof(WCHAR);
+ }
+ else
+ {
+ TRACE("Handle bitmaps\n");
+ }
+ res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &MenuText);
+ return res;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+SetMenu(HWND hWnd,
+ HMENU hMenu)
+{
+ return NtUserSetMenu(hWnd, hMenu, TRUE);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetMenuInfo(
+ HMENU hmenu,
+ LPCMENUINFO lpcmi)
+{
+ ROSMENUINFO mi;
+ BOOL res = FALSE;
+
+ if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return res;
+ }
+
+ memcpy(&mi, lpcmi, sizeof(MENUINFO));
+ return NtUserThunkedMenuInfo(hmenu, (LPCMENUINFO)&mi);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetMenuItemBitmaps(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ HBITMAP hBitmapUnchecked,
+ HBITMAP hBitmapChecked)
+{
+ MENUITEMINFOW uItem;
+ memset ( &uItem, 0, sizeof(uItem) );
+ uItem.cbSize = sizeof(MENUITEMINFOW);
+ uItem.fMask = MIIM_CHECKMARKS;
+ uItem.hbmpUnchecked = hBitmapUnchecked;
+ uItem.hbmpChecked = hBitmapChecked;
+ return SetMenuItemInfoW(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), &uItem);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetMenuItemInfoA(
+ HMENU hmenu,
+ UINT item,
+ BOOL bypos,
+ LPCMENUITEMINFOA lpmii)
+{
+ MENUITEMINFOW mii;
+ UNICODE_STRING UnicodeString;
+ BOOL Ret;
+
+ TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii);
+
+ RtlInitUnicodeString(&UnicodeString, 0);
+
+ if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
+/*
+ * MIIM_STRING == good
+ * MIIM_TYPE & MFT_STRING == good
+ * MIIM_STRING & MFT_STRING == good
+ * MIIM_STRING & MFT_OWNERDRAW == good
+ */
+ if (((mii.fMask & MIIM_STRING) ||
+ ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
+ && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
+ {
+ /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
+ if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
+ {
+ SetLastError (ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ mii.dwTypeData = UnicodeString.Buffer;
+ mii.cch = UnicodeString.Length / sizeof(WCHAR);
+ }
+ else
+ {
+ UnicodeString.Buffer = NULL;
+ }
+ Ret = NtUserThunkedMenuItemInfo(hmenu, item, bypos, FALSE, &mii, &UnicodeString);
+ if (UnicodeString.Buffer != NULL) RtlFreeUnicodeString(&UnicodeString);
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetMenuItemInfoW(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ LPCMENUITEMINFOW lpmii)
+{
+ MENUITEMINFOW MenuItemInfoW;
+ UNICODE_STRING UnicodeString;
+ BOOL Ret;
+
+ TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
+
+ RtlInitUnicodeString(&UnicodeString, 0);
+
+ if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &MenuItemInfoW )) return FALSE;
+
+ if (((MenuItemInfoW.fMask & MIIM_STRING) ||
+ ((MenuItemInfoW.fMask & MIIM_TYPE) &&
+ (MENU_ITEM_TYPE(MenuItemInfoW.fType) == MF_STRING)))
+ && MenuItemInfoW.dwTypeData && !(GdiValidateHandle((HGDIOBJ)MenuItemInfoW.dwTypeData)) )
+ {
+ RtlInitUnicodeString(&UnicodeString, (PCWSTR)MenuItemInfoW.dwTypeData);
+ MenuItemInfoW.cch = strlenW(MenuItemInfoW.dwTypeData);
+ }
+ Ret = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, FALSE, &MenuItemInfoW, &UnicodeString);
+
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+SetSystemMenu (
+ HWND hwnd,
+ HMENU hMenu)
+{
+ if(!hwnd)
+ {
+ SetLastError(ERROR_INVALID_WINDOW_HANDLE);
+ return FALSE;
+ }
+ if(!hMenu)
+ {
+ SetLastError(ERROR_INVALID_MENU_HANDLE);
+ return FALSE;
+ }
+ return NtUserSetSystemMenu(hwnd, hMenu);
+}
+
+//
+// Example for the Win32/User32 rewrite.
+// Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
+//
+//
+BOOL
+WINAPI
+NEWTrackPopupMenu(
+ HMENU Menu,
+ UINT Flags,
+ int x,
+ int y,
+ int Reserved,
+ HWND Wnd,
+ CONST RECT *Rect)
+{
+ return NtUserTrackPopupMenuEx( Menu,
+ Flags,
+ x,
+ y,
+ Wnd,
+ NULL); // LPTPMPARAMS is null
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+MenuWindowProcA(
+ HWND hWnd,
+ ULONG_PTR Result,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ if ( Msg < WM_USER)
+ {
+ LRESULT lResult;
+ lResult = PopupMenuWndProcA(hWnd, Msg, wParam, lParam );
+ if (Result)
+ {
+ Result = (ULONG_PTR)lResult;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, TRUE);
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+MenuWindowProcW(
+ HWND hWnd,
+ ULONG_PTR Result,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ if ( Msg < WM_USER)
+ {
+ LRESULT lResult;
+ lResult = PopupMenuWndProcW(hWnd, Msg, wParam, lParam );
+ if (Result)
+ {
+ Result = (ULONG_PTR)lResult;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, FALSE);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+ChangeMenuW(
+ HMENU hMenu,
+ UINT cmd,
+ LPCWSTR lpszNewItem,
+ UINT cmdInsert,
+ UINT flags)
+{
+ /*
+ FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
+ for MF_DELETE. We should check the parameters for all others
+ MF_* actions also (anybody got a doc on ChangeMenu?).
+ */
+
+ switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
+ {
+ case MF_APPEND :
+ return AppendMenuW(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
+
+ case MF_DELETE :
+ return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
+
+ case MF_CHANGE :
+ return ModifyMenuW(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
+
+ case MF_REMOVE :
+ return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
+ flags &~ MF_REMOVE);
+
+ default : /* MF_INSERT */
+ return InsertMenuW(hMenu, cmd, flags, cmdInsert, lpszNewItem);
+ };
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+ChangeMenuA(
+ HMENU hMenu,
+ UINT cmd,
+ LPCSTR lpszNewItem,
+ UINT cmdInsert,
+ UINT flags)
+{
+ /*
+ FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
+ for MF_DELETE. We should check the parameters for all others
+ MF_* actions also (anybody got a doc on ChangeMenu?).
+ */
+
+ switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
+ {
+ case MF_APPEND :
+ return AppendMenuA(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
+
+ case MF_DELETE :
+ return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
+
+ case MF_CHANGE :
+ return ModifyMenuA(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
+
+ case MF_REMOVE :
+ return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
+ flags &~ MF_REMOVE);
+
+ default : /* MF_INSERT */
+ return InsertMenuA(hMenu, cmd, flags, cmdInsert, lpszNewItem);
+ };
+}
+