--- /dev/null
+/*
+ * Fonts folder
+ *
+ * Copyright 2008 Johannes Anderwald <johannes.anderwald@reactos.org>
+ * Copyright 2009 Andrew Hill
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <precomp.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL (shell);
+
+/*
+This folder should not exist. It is just a file system folder... The \windows\fonts
+directory contains a hidden desktop.ini with a UIHandler entry that specifies a class
+that lives in fontext.dll. The UI handler creates a custom view for the folder, which
+is what we normally see. However, the folder is a perfectly normal CFSFolder.
+*/
+
+/***********************************************************************
+* IShellFolder implementation
+*/
+
+class CDesktopFolderEnumZ: public IEnumIDListImpl
+{
+ public:
+ CDesktopFolderEnumZ();
+ ~CDesktopFolderEnumZ();
+ HRESULT WINAPI Initialize(DWORD dwFlags);
+ BOOL CreateFontsEnumList(DWORD dwFlags);
+
+ BEGIN_COM_MAP(CDesktopFolderEnumZ)
+ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+ END_COM_MAP()
+};
+
+static shvheader FontsSFHeader[] = {
+ {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN_FONTTYPE , SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN12, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}
+};
+
+#define COLUMN_NAME 0
+#define COLUMN_TYPE 1
+#define COLUMN_SIZE 2
+#define COLUMN_FILENAME 3
+
+#define FontsSHELLVIEWCOLUMNS (4)
+
+CDesktopFolderEnumZ::CDesktopFolderEnumZ()
+{
+}
+
+CDesktopFolderEnumZ::~CDesktopFolderEnumZ()
+{
+}
+
+HRESULT WINAPI CDesktopFolderEnumZ::Initialize(DWORD dwFlags)
+{
+ if (CreateFontsEnumList(dwFlags) == FALSE)
+ return E_FAIL;
+ return S_OK;
+}
+
+static LPITEMIDLIST _ILCreateFontItem(LPWSTR pszFont, LPWSTR pszFile)
+{
+ PIDLDATA tmp;
+ LPITEMIDLIST pidl;
+ PIDLFontStruct * p;
+ int size0 = (char*)&tmp.u.cfont.szName - (char*)&tmp.u.cfont;
+ int size = size0;
+
+ tmp.type = 0x00;
+ tmp.u.cfont.dummy = 0xFF;
+ tmp.u.cfont.offsFile = wcslen(pszFont) + 1;
+
+ size += (tmp.u.cfont.offsFile + wcslen(pszFile) + 1) * sizeof(WCHAR);
+
+ pidl = (LPITEMIDLIST)SHAlloc(size + 4);
+ if (!pidl)
+ return pidl;
+
+ pidl->mkid.cb = size + 2;
+ memcpy(pidl->mkid.abID, &tmp, 2 + size0);
+
+ p = &((PIDLDATA*)pidl->mkid.abID)->u.cfont;
+ wcscpy(p->szName, pszFont);
+ wcscpy(p->szName + tmp.u.cfont.offsFile, pszFile);
+
+ *(WORD*)((char*)pidl + (size + 2)) = 0;
+ return pidl;
+}
+
+static PIDLFontStruct * _ILGetFontStruct(LPCITEMIDLIST pidl)
+{
+ LPPIDLDATA pdata = _ILGetDataPointer(pidl);
+
+ if (pdata && pdata->type == 0x00)
+ return (PIDLFontStruct*) & (pdata->u.cfont);
+
+ return NULL;
+}
+
+/**************************************************************************
+ * CDesktopFolderEnumZ::CreateFontsEnumList()
+ */
+BOOL CDesktopFolderEnumZ::CreateFontsEnumList(DWORD dwFlags)
+{
+ WCHAR szPath[MAX_PATH];
+ WCHAR szName[LF_FACESIZE+20];
+ WCHAR szFile[MAX_PATH];
+ LPWSTR pszPath;
+ UINT Length;
+ LONG ret;
+ DWORD dwType, dwName, dwFile, dwIndex;
+ LPITEMIDLIST pidl;
+ HKEY hKey;
+
+ if (dwFlags & SHCONTF_NONFOLDERS)
+ {
+ if (!SHGetSpecialFolderPathW(NULL, szPath, CSIDL_FONTS, FALSE))
+ return FALSE;
+
+ pszPath = PathAddBackslashW(szPath);
+ if (!pszPath)
+ return FALSE;
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
+ return FALSE;
+
+ Length = pszPath - szPath;
+ dwIndex = 0;
+ do
+ {
+ dwName = sizeof(szName) / sizeof(WCHAR);
+ dwFile = sizeof(szFile) / sizeof(WCHAR);
+ ret = RegEnumValueW(hKey, dwIndex++, szName, &dwName, NULL, &dwType, (LPBYTE)szFile, &dwFile);
+ if (ret == ERROR_SUCCESS)
+ {
+ szFile[(sizeof(szFile)/sizeof(WCHAR))-1] = L'\0';
+ if (dwType == REG_SZ && wcslen(szFile) + Length + 1 < (sizeof(szPath) / sizeof(WCHAR)))
+ {
+ wcscpy(&szPath[Length], szFile);
+ pidl = _ILCreateFontItem(szName, szPath);
+ TRACE("pidl %p name %s path %s\n", pidl, debugstr_w(szName), debugstr_w(szPath));
+ if (pidl)
+ {
+ if (!AddToEnumList(pidl))
+ SHFree(pidl);
+ }
+ }
+ }
+ } while(ret != ERROR_NO_MORE_ITEMS);
+ RegCloseKey(hKey);
+
+ }
+ return TRUE;
+}
+
+CFontsFolder::CFontsFolder()
+{
+ pidlRoot = NULL;
+ apidl = NULL;
+}
+
+CFontsFolder::~CFontsFolder()
+{
+ TRACE("-- destroying IShellFolder(%p)\n", this);
+ SHFree(pidlRoot);
+}
+
+HRESULT WINAPI CFontsFolder::FinalConstruct()
+{
+ pidlRoot = _ILCreateFont(); /* my qualified pidl */
+ if (pidlRoot == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+/**************************************************************************
+* CFontsFolder::ParseDisplayName
+*/
+HRESULT WINAPI CFontsFolder::ParseDisplayName(
+ HWND hwndOwner,
+ LPBC pbcReserved,
+ LPOLESTR lpszDisplayName,
+ DWORD *pchEaten,
+ LPITEMIDLIST *ppidl,
+ DWORD * pdwAttributes)
+{
+ HRESULT hr = E_UNEXPECTED;
+
+ TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
+ hwndOwner, pbcReserved, lpszDisplayName, debugstr_w (lpszDisplayName),
+ pchEaten, ppidl, pdwAttributes);
+
+ *ppidl = 0;
+ if (pchEaten)
+ *pchEaten = 0; /* strange but like the original */
+
+ TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
+
+ return hr;
+}
+
+/**************************************************************************
+* CFontsFolder::EnumObjects
+*/
+HRESULT WINAPI CFontsFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
+{
+ CComObject<CDesktopFolderEnumZ> *theEnumerator;
+ CComPtr<IEnumIDList> result;
+ HRESULT hResult;
+
+ TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
+
+ if (ppEnumIDList == NULL)
+ return E_POINTER;
+ *ppEnumIDList = NULL;
+ ATLTRY (theEnumerator = new CComObject<CDesktopFolderEnumZ>);
+ if (theEnumerator == NULL)
+ return E_OUTOFMEMORY;
+ hResult = theEnumerator->QueryInterface(IID_PPV_ARG(IEnumIDList, &result));
+ if (FAILED (hResult))
+ {
+ delete theEnumerator;
+ return hResult;
+ }
+ hResult = theEnumerator->Initialize (dwFlags);
+ if (FAILED (hResult))
+ return hResult;
+ *ppEnumIDList = result.Detach ();
+
+ TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
+
+ return S_OK;
+}
+
+/**************************************************************************
+* CFontsFolder::BindToObject
+*/
+HRESULT WINAPI CFontsFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
+{
+ TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", this,
+ pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
+
+ return SHELL32_BindToChild (pidlRoot, NULL, pidl, riid, ppvOut);
+}
+
+/**************************************************************************
+* CFontsFolder::BindToStorage
+*/
+HRESULT WINAPI CFontsFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
+{
+ FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
+ pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
+
+ *ppvOut = NULL;
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+* CFontsFolder::CompareIDs
+*/
+
+HRESULT WINAPI CFontsFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
+{
+ int nReturn;
+
+ TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
+ nReturn = SHELL32_CompareIDs (this, lParam, pidl1, pidl2);
+ TRACE ("-- %i\n", nReturn);
+ return nReturn;
+}
+
+/**************************************************************************
+* CFontsFolder::CreateViewObject
+*/
+HRESULT WINAPI CFontsFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
+{
+ CComPtr<IShellView> pShellView;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this,
+ hwndOwner, shdebugstr_guid (&riid), ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IDropTarget))
+ {
+ WARN ("IDropTarget not implemented\n");
+ hr = E_NOTIMPL;
+ }
+ else if (IsEqualIID (riid, IID_IContextMenu))
+ {
+ WARN ("IContextMenu not implemented\n");
+ hr = E_NOTIMPL;
+ }
+ else if (IsEqualIID (riid, IID_IShellView))
+ {
+ hr = IShellView_Constructor (this, &pShellView);
+ if (pShellView)
+ hr = pShellView->QueryInterface(riid, ppvOut);
+ }
+ TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
+ return hr;
+}
+
+/**************************************************************************
+* CFontsFolder::GetAttributesOf
+*/
+HRESULT WINAPI CFontsFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut)
+{
+ HRESULT hr = S_OK;
+
+ TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this,
+ cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
+
+ if (!rgfInOut)
+ return E_INVALIDARG;
+ if (cidl && !apidl)
+ return E_INVALIDARG;
+
+ if (*rgfInOut == 0)
+ *rgfInOut = ~0;
+
+ if (cidl == 0)
+ {
+ CComPtr<IShellFolder> psfParent;
+ LPCITEMIDLIST rpidl = NULL;
+
+ hr = SHBindToParent(pidlRoot, IID_PPV_ARG(IShellFolder, &psfParent), (LPCITEMIDLIST *)&rpidl);
+ if (SUCCEEDED(hr))
+ SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
+ }
+ else
+ {
+ while (cidl > 0 && *apidl)
+ {
+ pdump (*apidl);
+ SHELL32_GetItemAttributes (this, *apidl, rgfInOut);
+ apidl++;
+ cidl--;
+ }
+ }
+
+ /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
+ *rgfInOut &= ~SFGAO_VALIDATE;
+
+ TRACE ("-- result=0x%08x\n", *rgfInOut);
+ return hr;
+}
+
+/**************************************************************************
+* CFontsFolder::GetUIObjectOf
+*
+* PARAMETERS
+* hwndOwner [in] Parent window for any output
+* cidl [in] array size
+* apidl [in] simple pidl array
+* riid [in] Requested Interface
+* prgfInOut [ ] reserved
+* ppvObject [out] Resulting Interface
+*
+*/
+HRESULT WINAPI CFontsFolder::GetUIObjectOf(
+ HWND hwndOwner,
+ UINT cidl, LPCITEMIDLIST *apidl,
+ REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
+{
+ LPITEMIDLIST pidl;
+ CComPtr<IUnknown> pObj;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
+ hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
+ {
+ pObj = (IContextMenu *)this;
+ this->apidl = apidl[0];
+ hr = S_OK;
+ }
+ else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
+ {
+ hr = IDataObject_Constructor (hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
+ }
+ else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
+ {
+ pidl = ILCombine (pidlRoot, apidl[0]);
+ pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
+ SHFree (pidl);
+ hr = S_OK;
+ }
+ else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
+ {
+ pidl = ILCombine (pidlRoot, apidl[0]);
+ pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
+ SHFree (pidl);
+ hr = S_OK;
+ }
+ else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
+ {
+ IDropTarget * pDt = NULL;
+ hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
+ pObj = pDt;
+ }
+ else
+ hr = E_NOINTERFACE;
+
+ if (SUCCEEDED(hr) && !pObj)
+ hr = E_OUTOFMEMORY;
+
+ *ppvOut = pObj.Detach();
+ TRACE ("(%p)->hr=0x%08x\n", this, hr);
+ return hr;
+}
+
+/**************************************************************************
+* CFontsFolder::GetDisplayNameOf
+*
+*/
+HRESULT WINAPI CFontsFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
+{
+ PIDLFontStruct *pFont;
+
+ TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
+ pdump (pidl);
+
+ if (!strRet)
+ return E_INVALIDARG;
+
+ pFont = _ILGetFontStruct(pidl);
+ if (pFont)
+ {
+ strRet->pOleStr = (LPWSTR)CoTaskMemAlloc((wcslen(pFont->szName) + 1) * sizeof(WCHAR));
+ if (!strRet->pOleStr)
+ return E_OUTOFMEMORY;
+
+ wcscpy(strRet->pOleStr, pFont->szName);
+ strRet->uType = STRRET_WSTR;
+ }
+ else if (!pidl->mkid.cb)
+ {
+ WCHAR wszPath[MAX_PATH];
+
+ if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
+ (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
+ {
+ if (!SHGetSpecialFolderPathW(NULL, wszPath, CSIDL_FONTS, FALSE))
+ return E_FAIL;
+ }
+ else if (!HCR_GetClassNameW(CLSID_FontsFolderShortcut, wszPath, MAX_PATH))
+ return E_FAIL;
+
+ strRet->pOleStr = (LPWSTR)CoTaskMemAlloc((wcslen(wszPath) + 1) * sizeof(WCHAR));
+ if (!strRet->pOleStr)
+ return E_OUTOFMEMORY;
+
+ wcscpy(strRet->pOleStr, wszPath);
+ strRet->uType = STRRET_WSTR;
+ }
+ else
+ return E_INVALIDARG;
+
+ return S_OK;
+}
+
+/**************************************************************************
+* CFontsFolder::SetNameOf
+* Changes the name of a file object or subfolder, possibly changing its item
+* identifier in the process.
+*
+* PARAMETERS
+* hwndOwner [in] Owner window for output
+* pidl [in] simple pidl of item to change
+* lpszName [in] the items new display name
+* dwFlags [in] SHGNO formatting flags
+* ppidlOut [out] simple pidl returned
+*/
+HRESULT WINAPI CFontsFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /*simple pidl */
+ LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
+{
+ FIXME ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
+ hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
+ return E_FAIL;
+}
+
+HRESULT WINAPI CFontsFolder::GetDefaultSearchGUID(GUID *pguid)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CFontsFolder::EnumSearches(IEnumExtraSearch **ppenum)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CFontsFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
+{
+ TRACE ("(%p)\n", this);
+
+ if (pSort)
+ *pSort = 0;
+ if (pDisplay)
+ *pDisplay = 0;
+
+ return S_OK;
+}
+
+HRESULT WINAPI CFontsFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
+{
+ TRACE ("(%p)\n", this);
+
+ if (!pcsFlags || iColumn >= FontsSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+ *pcsFlags = FontsSFHeader[iColumn].pcsFlags;
+ return S_OK;
+}
+
+HRESULT WINAPI CFontsFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CFontsFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
+{
+ WCHAR buffer[MAX_PATH] = {0};
+ HRESULT hr = E_FAIL;
+ PIDLFontStruct * pfont;
+ HANDLE hFile;
+ LARGE_INTEGER FileSize;
+ SHFILEINFOW fi;
+
+ TRACE("(%p, %p, %d, %p)\n", this, pidl, iColumn, psd);
+
+ if (iColumn >= FontsSHELLVIEWCOLUMNS)
+ return E_FAIL;
+
+ psd->fmt = FontsSFHeader[iColumn].fmt;
+ psd->cxChar = FontsSFHeader[iColumn].cxChar;
+ if (pidl == NULL)
+ {
+ psd->str.uType = STRRET_WSTR;
+ if (LoadStringW(shell32_hInstance, FontsSFHeader[iColumn].colnameid, buffer, MAX_PATH))
+ hr = SHStrDupW(buffer, &psd->str.pOleStr);
+
+ return hr;
+ }
+
+ if (iColumn == COLUMN_NAME)
+ {
+ psd->str.uType = STRRET_WSTR;
+ return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str);
+ }
+
+ psd->str.uType = STRRET_CSTR;
+ psd->str.cStr[0] = '\0';
+
+ switch(iColumn)
+ {
+ case COLUMN_TYPE:
+ pfont = _ILGetFontStruct(pidl);
+ if (pfont)
+ {
+ if (SHGetFileInfoW(pfont->szName + pfont->offsFile, 0, &fi, sizeof(fi), SHGFI_TYPENAME))
+ {
+ psd->str.pOleStr = (LPWSTR)CoTaskMemAlloc((wcslen(fi.szTypeName) + 1) * sizeof(WCHAR));
+ if (!psd->str.pOleStr)
+ return E_OUTOFMEMORY;
+ wcscpy(psd->str.pOleStr, fi.szTypeName);
+ psd->str.uType = STRRET_WSTR;
+ return S_OK;
+ }
+ }
+ break;
+ case COLUMN_SIZE:
+ pfont = _ILGetFontStruct(pidl);
+ if (pfont)
+ {
+ hFile = CreateFileW(pfont->szName + pfont->offsFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ if (GetFileSizeEx(hFile, &FileSize))
+ {
+ if (StrFormatByteSizeW(FileSize.QuadPart, buffer, sizeof(buffer) / sizeof(WCHAR)))
+ {
+ psd->str.pOleStr = (LPWSTR)CoTaskMemAlloc(wcslen(buffer) + 1);
+ if (!psd->str.pOleStr)
++ {
++ CloseHandle(hFile);
+ return E_OUTOFMEMORY;
++ }
+ wcscpy(psd->str.pOleStr, buffer);
+ psd->str.uType = STRRET_WSTR;
+ CloseHandle(hFile);
+ return S_OK;
+ }
+ }
+ CloseHandle(hFile);
+ }
+ }
+ break;
+ case COLUMN_FILENAME:
+ pfont = _ILGetFontStruct(pidl);
+ if (pfont)
+ {
+ psd->str.pOleStr = (LPWSTR)CoTaskMemAlloc((wcslen(pfont->szName + pfont->offsFile) + 1) * sizeof(WCHAR));
+ if (psd->str.pOleStr)
+ {
+ psd->str.uType = STRRET_WSTR;
+ wcscpy(psd->str.pOleStr, pfont->szName + pfont->offsFile);
+ return S_OK;
+ }
+ else
+ return E_OUTOFMEMORY;
+ }
+ break;
+ }
+
+ return E_FAIL;
+}
+
+HRESULT WINAPI CFontsFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
+{
+ FIXME ("(%p)\n", this);
+
+ return E_NOTIMPL;
+}
+
+/************************************************************************
+ * CFontsFolder::GetClassID
+ */
+HRESULT WINAPI CFontsFolder::GetClassID(CLSID *lpClassId)
+{
+ TRACE ("(%p)\n", this);
+
+ if (!lpClassId)
+ return E_POINTER;
+
+ *lpClassId = CLSID_FontsFolderShortcut;
+
+ return S_OK;
+}
+
+/************************************************************************
+ * CFontsFolder::Initialize
+ *
+ * NOTES: it makes no sense to change the pidl
+ */
+HRESULT WINAPI CFontsFolder::Initialize(LPCITEMIDLIST pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+ * CFontsFolder::GetCurFolder
+ */
+HRESULT WINAPI CFontsFolder::GetCurFolder(LPITEMIDLIST *pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ if (!pidl)
+ return E_POINTER;
+
+ *pidl = ILClone(pidlRoot);
+
+ return S_OK;
+}
+
+/**************************************************************************
+* IContextMenu2 Implementation
+*/
+
+/**************************************************************************
+* CFontsFolder::QueryContextMenu()
+*/
+HRESULT WINAPI CFontsFolder::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
+{
+ WCHAR szBuffer[30] = {0};
+ ULONG Count = 1;
+
+ TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
+ this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
+
+ if (LoadStringW(shell32_hInstance, IDS_OPEN, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_DEFAULT);
+ Count++;
+ }
+
+ if (LoadStringW(shell32_hInstance, IDS_PRINT_VERB, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED);
+ }
+
+ if (LoadStringW(shell32_hInstance, IDS_COPY, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED);
+ }
+
+ if (LoadStringW(shell32_hInstance, IDS_DELETE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED);
+ }
+
+ if (LoadStringW(shell32_hInstance, IDS_PROPERTIES, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED);
+ }
+
+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count);
+}
+
+/**************************************************************************
+* CFontsFolder::InvokeCommand()
+*/
+HRESULT WINAPI CFontsFolder::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
+{
+ SHELLEXECUTEINFOW sei;
+ PIDLFontStruct * pfont;
+ SHFILEOPSTRUCTW op;
+
+ TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
+
+ if (lpcmi->lpVerb == MAKEINTRESOURCEA(1) || lpcmi->lpVerb == MAKEINTRESOURCEA(2) || lpcmi->lpVerb == MAKEINTRESOURCEA(7))
+ {
+ ZeroMemory(&sei, sizeof(sei));
+ sei.cbSize = sizeof(sei);
+ sei.hwnd = lpcmi->hwnd;
+ sei.nShow = SW_SHOWNORMAL;
+ if (lpcmi->lpVerb == MAKEINTRESOURCEA(1))
+ sei.lpVerb = L"open";
+ else if (lpcmi->lpVerb == MAKEINTRESOURCEA(2))
+ sei.lpVerb = L"print";
+ else if (lpcmi->lpVerb == MAKEINTRESOURCEA(7))
+ sei.lpVerb = L"properties";
+
+ pfont = _ILGetFontStruct(apidl);
+ sei.lpFile = pfont->szName + pfont->offsFile;
+
+ if (ShellExecuteExW(&sei) == FALSE)
+ return E_FAIL;
+ }
+ else if (lpcmi->lpVerb == MAKEINTRESOURCEA(4))
+ {
+ FIXME("implement font copying\n");
+ return E_NOTIMPL;
+ }
+ else if (lpcmi->lpVerb == MAKEINTRESOURCEA(6))
+ {
+ ZeroMemory(&op, sizeof(op));
+ op.hwnd = lpcmi->hwnd;
+ op.wFunc = FO_DELETE;
+ op.fFlags = FOF_ALLOWUNDO;
+ pfont = _ILGetFontStruct(apidl);
+ op.pFrom = pfont->szName + pfont->offsFile;
+ SHFileOperationW(&op);
+ }
+
+ return S_OK;
+}
+
+/**************************************************************************
+ * CFontsFolder::GetCommandString()
+ *
+ */
+HRESULT WINAPI CFontsFolder::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen)
+{
+ TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
+
+ return E_FAIL;
+}
+
+/**************************************************************************
+* CFontsFolder::HandleMenuMsg()
+*/
+HRESULT WINAPI CFontsFolder::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ TRACE("(%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg, wParam, lParam);
+
+ return E_NOTIMPL;
+}
--- /dev/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
+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);
+}
+
+/* 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++;
+ }
+