|
|
/****************************** Module Header ******************************\
* Module Name: class.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains RegisterClass and the related window class management * functions. * * History: * 10-16-90 DarrinM Ported functions from Win 3.0 sources. * 02-01-91 mikeke Added Revalidation code (None) * 04-08-91 DarrinM C-S-ized and removed global/public class support. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* These arrays are used by Get/SetClassWord/Long. * * INDEX_OFFSET must refer to the first entry of afClassDWord[] */ #define INDEX_OFFSET GCLP_HICONSM
CONST BYTE afClassDWord[-INDEX_OFFSET] = { FIELD_SIZE(CLS, spicnSm), // GCL_HICONSM (-34)
0, FIELD_SIZE(CLS, atomNVClassName), // GCW_ATOM (-32)
0, 0, 0, 0, 0, FIELD_SIZE(CLS, style), // GCL_STYLE (-26)
0, FIELD_SIZE(CLS, lpfnWndProc), // GCL_WNDPROC (-24)
0, 0, 0, FIELD_SIZE(CLS, cbclsExtra), // GCL_CBCLSEXTRA (-20)
0, FIELD_SIZE(CLS, cbwndExtra), // GCL_CBWNDEXTRA (-18)
0, FIELD_SIZE(CLS, hModule), // GCL_HMODULE (-16)
0, FIELD_SIZE(CLS, spicn), // GCL_HICON (-14)
0, FIELD_SIZE(CLS, spcur), // GCL_HCURSOR (-12)
0, FIELD_SIZE(CLS, hbrBackground), // GCL_HBRBACKGROUND (-10)
0, FIELD_SIZE(CLS, lpszMenuName), // GCL_HMENUNAME (-8)
0, 0, 0, 0, 0, 0, 0 };
CONST BYTE aiClassOffset[-INDEX_OFFSET] = { FIELD_OFFSET(CLS, spicnSm), // GCL_HICONSM
0, FIELD_OFFSET(CLS, atomNVClassName), // GCW_ATOM
0, 0, 0, 0, 0, FIELD_OFFSET(CLS, style), // GCL_STYLE
0, FIELD_OFFSET(CLS, lpfnWndProc), // GCL_WNDPROC
0, 0, 0, FIELD_OFFSET(CLS, cbclsExtra), // GCL_CBCLSEXTRA
0, FIELD_OFFSET(CLS, cbwndExtra), // GCL_CBWNDEXTRA
0, FIELD_OFFSET(CLS, hModule), // GCL_HMODULE
0, FIELD_OFFSET(CLS, spicn), // GCL_HICON
0, FIELD_OFFSET(CLS, spcur), // GCL_HCURSOR
0, FIELD_OFFSET(CLS, hbrBackground), // GCL_HBRBACKGROUND
0, FIELD_OFFSET(CLS, lpszMenuName), // GCL_MENUNAME
0, 0, 0, 0, 0, 0, 0 };
/***************************************************************************\
* _RegisterClassEx (API) * * This stub calls InternalRegisterClass to do its work and then does some * additional work to save a pointer to the client-side menu name string. * The menu string is returned by _GetClassInfo so the client can fix up * a valid entry for the WNDCLASS lpszMenuName field. * * History: * 04-26-91 DarrinM Created. \***************************************************************************/ ATOM _RegisterClassEx( LPWNDCLASSVEREX cczpwc, PCLSMENUNAME pcmn, WORD fnid, DWORD dwFlags, LPDWORD pdwWOW) { PCLS pcls; PTHREADINFO ptiCurrent = PtiCurrent();
/*
* NOTE -- lpszClassName and lpszMenuName in the wndclass may be client-side * pointers. Use of those fields must be protected in try blocks. */
/*
* Convert a possible CallProc Handle into a real address. They may * have kept the CallProc Handle from some previous mixed GetClassinfo * or SetWindowLong. */ if (ISCPDTAG(cczpwc->lpfnWndProc)) { PCALLPROCDATA pCPD; if (pCPD = HMValidateHandleNoRip((HANDLE)cczpwc->lpfnWndProc, TYPE_CALLPROC)) { cczpwc->lpfnWndProc = (WNDPROC)pCPD->pfnClientPrevious; } }
pcls = InternalRegisterClassEx(cczpwc, fnid, dwFlags | ((ptiCurrent->TIF_flags & TIF_16BIT)? CSF_WOWCLASS : 0)); if (pcls != NULL) {
pcls->lpszClientUnicodeMenuName = pcmn->pwszClientUnicodeMenuName; pcls->lpszClientAnsiMenuName = pcmn->pszClientAnsiMenuName;
/*
* copy 5 WOW dwords. */ if (pdwWOW && (ptiCurrent->TIF_flags & TIF_16BIT)) { RtlCopyMemory (PWCFromPCLS(pcls), pdwWOW, sizeof(WC)); }
if ((ptiCurrent->TIF_flags & TIF_16BIT) && ptiCurrent->ptdb) { pcls->hTaskWow = ptiCurrent->ptdb->hTaskWow; } else { pcls->hTaskWow = 0; }
/*
* For some (presumably good) reason Win 3.1 changed RegisterClass * to return the classes classname atom. */ return pcls->atomNVClassName; } else { return 0; } }
/***************************************************************************\
* ClassAlloc * ClassFree * * Generic allocation routines that discriminate between desktop heap * and pool. * * History: * 08-07-95 JimA Created \***************************************************************************/
PVOID ClassAlloc( PDESKTOP pdesk, DWORD cbAlloc, ULONG tag) { PVOID pvalloc;
if (pdesk) { /*
* NTRAID#NTBUG9-411175-2001/06/06-jasonsch. */ pvalloc = DesktopAllocAlways(pdesk, cbAlloc, tag); } else { pvalloc = UserAllocPoolWithQuotaZInit(cbAlloc, TAG_CLASS); }
return pvalloc; }
VOID ClassFree( PDESKTOP pdesk, PVOID pvfree) { if (pdesk != NULL) { DesktopFree(pdesk, pvfree); } else { UserFreePool(pvfree); } }
/***************************************************************************\
* ValidateAndLockCursor * * Win95 comaptible validation * * History: * 12-19-95 GerardoB Created \***************************************************************************/ BOOL ValidateAndLockCursor( PCURSOR *ppcursor, BOOL fIs40Compat) { PCURSOR pcur;
if (*ppcursor == NULL) { return TRUE; }
pcur = HMValidateHandleNoSecure(*ppcursor, TYPE_CURSOR); if (pcur == NULL) { RIPMSGF1(RIP_WARNING, "Invalid Cursor or Icon: 0x%p", *ppcursor); if (fIs40Compat) { RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "RegisterClass: Invalid Parameter"); return FALSE; } }
*ppcursor = NULL; Lock(ppcursor, pcur); return TRUE; }
/***************************************************************************\
* InternalRegisterClass * * This API is called by applications or the system to register private or * global (public) window classes. If a class with the same name already * exists the call will fail, except in the special case where an application * registers a private class with the same name as a global class. In this * case the private class supercedes the global class for that application. * * History: * 10-15-90 DarrinM Ported from Win 3.0 sources. \***************************************************************************/ PCLS InternalRegisterClassEx( LPWNDCLASSVEREX cczlpwndcls, WORD fnid, DWORD CSF_flags) { BOOL fIs40Compat; ULONG_PTR dwT; PCLS pcls; LPWSTR pszT1; ATOM atomT; PTHREADINFO ptiCurrent; HANDLE hModule; PDESKTOP pdesk; ULONG cch; UNICODE_STRING UString; ANSI_STRING AString;
/*
* NOTE -- lpszClassName and lpszMenuName in the wndclass may be client-side * pointers. Use of those fields must be protected in try blocks. */ CheckCritIn();
ptiCurrent = PtiCurrent();
/*
* Don't allow 4.0 apps to register a class using hModuleWin * LATER GerardoB: Our client side classes use hmodUser (USER32) while * our server side classes use hWinInstance (WIN32K). We should change * CreateThreadInfo and LW_RegisterWindows so all classes use hModUser. */ hModule = cczlpwndcls->hInstance; if (!(CSF_flags & (CSF_SYSTEMCLASS | CSF_SERVERSIDEPROC)) && (hModule == hModuleWin) && (LOWORD(ptiCurrent->dwExpWinVer) >= VER40)) {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "InternalRegisterClassEx: Invalid hInstance (Cannot use system's hInstance)"); return NULL; }
/*
* As of NT 4.0 we no longer honor CS_BYTEALIGNCLIENT or CS_BYTEALIGNWINDOW */ if (cczlpwndcls->style & (CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW)) { RIPMSG0(RIP_VERBOSE, "CS_BYTEALIGNCLIENT and CS_BYTEALIGNWINDOW styles no longer honored."); }
/*
* Does this class exist as a private class? If so, fail. */ atomT = FindClassAtom(cczlpwndcls->lpszClassNameVer);
if (atomT != 0 && !(CSF_flags & CSF_SERVERSIDEPROC)) { /*
* First check private classes. If already exists, return error. */ if (_InnerGetClassPtr(atomT, &ptiCurrent->ppi->pclsPrivateList, hModule) != NULL) { RIPERR1(ERROR_CLASS_ALREADY_EXISTS, RIP_VERBOSE, "RegisterClass: Class already exists %lx", (DWORD)atomT); return NULL; }
/*
* Now only check public classes if CS_GLOBALCLASS is set. If it * isn't set, then this will allow an application to re-register * a private class to take precedence over a public class. */ if (cczlpwndcls->style & CS_GLOBALCLASS) { if (_InnerGetClassPtr(atomT, &ptiCurrent->ppi->pclsPublicList, NULL) != NULL) { RIPERR0(ERROR_CLASS_ALREADY_EXISTS, RIP_VERBOSE, "RegisterClass: Global Class already exists"); return NULL; } } }
/*
* Alloc space for the class. */ if (ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD) { pdesk = NULL; } else { pdesk = ptiCurrent->rpdesk; } pcls = (PCLS)ClassAlloc(pdesk, sizeof(CLS) + cczlpwndcls->cbClsExtra + (CSF_flags & CSF_WOWCLASS ? sizeof(WC):0), DTAG_CLASS); if (pcls == NULL) { return NULL; }
LockDesktop(&pcls->rpdeskParent, pdesk, LDL_CLS_DESKPARENT1, (ULONG_PTR)pcls); pcls->pclsBase = pcls;
/*
* Copy over the shared part of the class structure. */ UserAssert(FIELD_OFFSET(WNDCLASSEX, style) == FIELD_OFFSET(COMMON_WNDCLASS, style)); RtlCopyMemory(&pcls->style, &(cczlpwndcls->style), sizeof(COMMON_WNDCLASS) - FIELD_OFFSET(COMMON_WNDCLASS, style));
/*
* Copy CSF_SERVERSIDEPROC, CSF_ANSIPROC (etc.) flags */ pcls->CSF_flags = LOWORD(CSF_flags); pcls->fnid = fnid; if (fnid) { CBFNID(fnid) = (WORD)(pcls->cbwndExtra + sizeof(WND));
#ifndef LAZY_CLASS_INIT
if (!(pcls->CSF_flags & CSF_SERVERSIDEPROC) && ptiCurrent->pClientInfo != NULL) { /*
* Clear the bit so new threads in this process * won't bother to reregister the client-side USER classes. */ try { ptiCurrent->pClientInfo->CI_flags &= ~CI_REGISTERCLASSES; } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { goto ValidateError1; } } #endif
}
/*
* If this wndproc happens to be a client wndproc stub for a server * wndproc, then remember the server wndproc! This should be rare: why * would an application re-register a class that isn't "subclassed"? */ if (!(pcls->CSF_flags & CSF_SERVERSIDEPROC)) { dwT = MapClientToServerPfn((ULONG_PTR)pcls->lpfnWndProc); if (dwT != 0) { pcls->CSF_flags |= CSF_SERVERSIDEPROC; pcls->CSF_flags &= ~CSF_ANSIPROC; pcls->lpfnWndProc = (WNDPROC_PWND)dwT; } }
/*
* Win95 compatible validation. * * hbrBackground was validated by GDI in the client side * NULL hInstances are mapped to GetModuleHandle(NULL) in the client * side */
fIs40Compat = (CSF_flags & CSF_WIN40COMPAT) != 0;
if (!ValidateAndLockCursor(&pcls->spcur, fIs40Compat)) { goto ValidateError1; }
if (!ValidateAndLockCursor(&pcls->spicn, fIs40Compat)) { goto ValidateError2; }
if (!ValidateAndLockCursor(&pcls->spicnSm, fIs40Compat)) { goto ValidateError3; }
/*
* Add the class name to the atom table. */ if (IS_PTR(cczlpwndcls->lpszClassName)) { atomT = UserAddAtom(cczlpwndcls->lpszClassName, FALSE); } else { atomT = PTR_TO_ID(cczlpwndcls->lpszClassName); }
if (atomT == 0) { goto AtomError1; } pcls->atomNVClassName = atomT;
if (IS_PTR(cczlpwndcls->lpszClassNameVer)) { atomT = UserAddAtom(cczlpwndcls->lpszClassNameVer, FALSE); } else { atomT = PTR_TO_ID(cczlpwndcls->lpszClassNameVer); }
if (atomT == 0) { goto AtomError2; } pcls->atomClassName = atomT;
/*
* Make an ANSI version of the class name to optimize * GetClassNameA for WOW. */ if (IS_PTR(cczlpwndcls->lpszClassName)) { try { RtlInitUnicodeString(&UString, cczlpwndcls->lpszClassName); } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { goto MemError2; } #ifdef FE_SB // InternalRegisterClassEx()
cch = UString.Length + 1; #else
cch = UString.Length / sizeof(WCHAR) + 1; #endif // FE_SB
} else { cch = 7; // 1 char for '#', 5 for '65536'.
}
/*
* Allocate the ANSI name buffer and convert the unicode name * to ANSI. */ pcls->lpszAnsiClassName = (LPSTR)ClassAlloc(pdesk, cch, DTAG_TEXT); if (pcls->lpszAnsiClassName == NULL) { goto MemError2; }
/*
* Form the ANSI class name. */ if (IS_PTR(cczlpwndcls->lpszClassName)) {
/*
* Class name is a string. */ AString.Length = 0; AString.MaximumLength = (USHORT)cch; AString.Buffer = pcls->lpszAnsiClassName; try { RtlUnicodeStringToAnsiString(&AString, &UString, FALSE); } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { goto MemError3; } } else {
/*
* Class name is an integer atom. */ pcls->lpszAnsiClassName[0] = L'#'; RtlIntegerToChar(PTR_TO_ID(cczlpwndcls->lpszClassName), 10, cch - 1, &pcls->lpszAnsiClassName[1]); }
/*
* Make local copy of menu name. */ pszT1 = pcls->lpszMenuName;
if (pszT1 != NULL) { if (IS_PTR(pszT1)) { try { RtlInitUnicodeString(&UString, pszT1); } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { goto MemError3; } if (UString.Length == 0) {
/*
* app passed an empty string for the name */ pcls->lpszMenuName = NULL; } else { UNICODE_STRING strMenuName;
/*
* Alloc space for the Menu Name. */ if (!AllocateUnicodeString(&strMenuName, &UString)) { /*
* The unlock call is delayed after the free such that if this is * the last reference on the desktop, the desktop heap is not * destroyed before we free the objects. */ PDESKTOP rpdesk; MemError3: ClassFree(pdesk, pcls->lpszAnsiClassName); MemError2: UserDeleteAtom(pcls->atomClassName); AtomError2: UserDeleteAtom(pcls->atomNVClassName); AtomError1: Unlock(&pcls->spicnSm); ValidateError3: Unlock(&pcls->spicn); ValidateError2: Unlock(&pcls->spcur); ValidateError1: rpdesk = pcls->rpdeskParent; pcls->rpdeskParent = NULL; ClassFree(pdesk, pcls); /*
* NOTE: Using pobj after freeing the object is not a * problem because UnlockDesktop uses the value for * tracking and doesn't dereference the pointer. If this * ever changes we'll get a BC. */ UnlockDesktop(&rpdesk, LDU_CLS_DESKPARENT1, (ULONG_PTR)pcls); return NULL; }
pcls->lpszMenuName = strMenuName.Buffer; } } }
if ((CSF_flags & CSF_SERVERSIDEPROC) || (pcls->style & CS_GLOBALCLASS)) { if (pcls->CSF_flags & CSF_SYSTEMCLASS) { pcls->pclsNext = gpclsList; gpclsList = pcls; } else { pcls->pclsNext = ptiCurrent->ppi->pclsPublicList; ptiCurrent->ppi->pclsPublicList = pcls; } } else { pcls->pclsNext = ptiCurrent->ppi->pclsPrivateList; ptiCurrent->ppi->pclsPrivateList = pcls; }
return pcls; }
/***************************************************************************\
* _UnregisterClass (API) * * This API function is used to unregister a window class previously * registered by the Application. * * Returns: * TRUE if successful. * FALSE otherwise. * * NOTE: * 1. The class name must have been registered earlier by this client * through RegisterClass(). * 2. The class name should not be one of the predefined control classes. * 3. All windows created with this class must be destroyed before calling * this function. * * History: * 10-15-90 DarrinM Ported from Win 3.0 sources. * 03-09-94 BradG Fixed bug when ATOM was passed in \***************************************************************************/
BOOL _UnregisterClass( LPCWSTR ccxlpszClassName, HANDLE hModule, PCLSMENUNAME pcmn) { ATOM atomT; PPCLS ppcls; PTHREADINFO ptiCurrent;
CheckCritIn();
ptiCurrent = PtiCurrent();
/*
* Check whether the given ClassName is already registered by the * Application with the given handle. * Return error, if either the Class does not exist or it does not * belong to the calling process. */
/*
* bradg (3/9/95) - Must first check to see if an ATOM has been passed */ atomT = FindClassAtom(ccxlpszClassName); ppcls = _InnerGetClassPtr(atomT, &ptiCurrent->ppi->pclsPrivateList, hModule); if (ppcls == NULL) { /*
* Maybe this is a public class. */ ppcls = _InnerGetClassPtr(atomT, &ptiCurrent->ppi->pclsPublicList, NULL); if (ppcls == NULL) { RIPERR1(ERROR_CLASS_DOES_NOT_EXIST, RIP_WARNING, "UnregisterClass: Class does not exist; atom=%lX", (DWORD)atomT); return FALSE; } }
/*
* If any windows created with this class still exist return an error. */ if ((*ppcls)->cWndReferenceCount != 0) { RIPERR0(ERROR_CLASS_HAS_WINDOWS, RIP_WARNING, "UnregisterClass: Class still has window"); return FALSE; }
/*
* Return client side pointers for cleanup */ pcmn->pszClientAnsiMenuName = (*ppcls)->lpszClientAnsiMenuName; pcmn->pwszClientUnicodeMenuName = (*ppcls)->lpszClientUnicodeMenuName; pcmn->pusMenuName = NULL;
/*
* Release the Window class and related information. */ DestroyClass(ppcls);
return TRUE; }
PCLS _GetWOWClass( HANDLE hModule, LPCWSTR ccxlpszClassName) { PCLS pcls; PPCLS ppcls = NULL; ATOM atomT; PTHREADINFO ptiCurrent;
CheckCritInShared();
ptiCurrent = PtiCurrentShared();
/*
* Is this class registered as a private class? */ atomT = UserFindAtom(ccxlpszClassName); if (atomT != 0) { ppcls = GetClassPtr(atomT, ptiCurrent->ppi, hModule); }
if (ppcls == NULL) { RIPERR0(ERROR_CLASS_DOES_NOT_EXIST, RIP_VERBOSE, ""); return NULL; }
pcls = *ppcls;
if (ptiCurrent->rpdesk != pcls->rpdeskParent) { pcls = pcls->pclsClone; while (pcls != NULL) { if (ptiCurrent->rpdesk == pcls->rpdeskParent) { goto Done; } pcls = pcls->pclsNext; } RIPERR0(ERROR_CLASS_DOES_NOT_EXIST, RIP_VERBOSE, ""); return NULL; } Done: return pcls; }
/***************************************************************************\
* GetClassInfo (API) * * This function checks if the given class name is registered already. If the * class is not found, it returns 0; If the class is found, then all the * relevant information from the CLS structure is copied into the WNDCLASS * structure pointed to by the lpWndCls argument. If successful, it returns * the class name atom * * NOTE: hmod was used to distinguish between different task's public classes. * Now that public classes are gone, hmod isn't used anymore. We just search * the applications private class for a match and if none is found we search * the system classes. * * History: * 10-15-90 DarrinM Ported from Win 3.0 sources. * 04-08-91 DarrinM Removed public classes. * 04-26-91 DarrinM Streamlined to work with the client-side API. * 03-09-95 BradG Fixed bug when ATOM was passed in. \***************************************************************************/ ATOM _GetClassInfoEx( HANDLE hModule, LPCWSTR ccxlpszClassName, LPWNDCLASSEX pwc, LPWSTR *ppszMenuName, BOOL bAnsi) { PCLS pcls; PPCLS ppcls; ATOM atomT; PTHREADINFO ptiCurrent; DWORD dwCPDType = 0;
CheckCritIn();
ptiCurrent = PtiCurrent();
/*
* These are done first so if we don't find the class, and therefore * fail, the return thank won't try to copy back these (nonexistant) * strings. */ pwc->lpszMenuName = NULL; pwc->lpszClassName = NULL;
/*
* Must first check to see if an ATOM has been passed. */ atomT = FindClassAtom(ccxlpszClassName);
/*
* Windows 3.1 does not perform the class search with * a null hModule. If an application supplies a NULL * hModule, they search on hModuleWin instead. */
if (hModule == NULL) { hModule = hModClient; }
ppcls = GetClassPtr(atomT, ptiCurrent->ppi, hModule);
if (ppcls == NULL) { RIPERR0(ERROR_CLASS_DOES_NOT_EXIST, RIP_VERBOSE, "GetClassInfo: Class does not exist"); return 0; }
pcls = *ppcls;
/*
* Copy all the fields common to CLS and WNDCLASS structures except * the lpszMenuName and lpszClassName which will be filled in by the * client-side piece of GetClassInfo. */
/*
* Return public bits only. */ pwc->style = pcls->style & CS_VALID;
/*
* Corel Depth 6.0 calls GetClassInfo (COMBOBOX) and registers a class * using the same name and style bits. This works OK on Win95 because * their "system" (combo, edit, etc) classes are not CS_GLOBALCLASS. * So we've got to mask this bit out for our classes. */
/*
* Bug 17998. If the app is 32bit and WinVer is less than 4.0 don't mask * out the CS_GLOBALCLASS bit. */
if ((pcls->fnid != 0) && ((LOWORD(ptiCurrent->dwExpWinVer) >= VER40) || (ptiCurrent->TIF_flags & TIF_16BIT)) ) { pwc->style &= ~CS_GLOBALCLASS; }
pwc->cbClsExtra = pcls->cbclsExtra; pwc->cbWndExtra = pcls->cbwndExtra;
/*
* Stop 32-bit apps from inadvertantly using hModuleWin as their hInstance * when they register a window class. */ if (LOWORD(ptiCurrent->dwExpWinVer) >= VER40) { /*
* This is actually, Win95 behavior -- the USER.EXE hModule gets thunked * to NULL on the way out of the 16->32 bit thunk. Note -- if we ever * need to support 16-bit 4.0 apps (shudder), this may need to change. */ if (hModule == hModClient) { pwc->hInstance = NULL; } else { pwc->hInstance = hModule; } } else { /*
* Win NT 3.1/3.51 returned the hInstance from the class. Note that this * is incompatible with Win 3.1. WoW has hacks for 16-bit apps. */
if ((pcls->hModule == hModuleWin) || (pcls->hModule == hModClient)) { pwc->hInstance = hModClient; } else { pwc->hInstance = pcls->hModule; } }
pwc->hIcon = PtoH(pcls->spicn); pwc->hCursor = PtoH(pcls->spcur); pwc->hbrBackground = pcls->hbrBackground;
/*
* Need to hide the small icon if it's USER created. */ if (pcls->spicnSm && (pcls->spicnSm->CURSORF_flags & CURSORF_SECRET)) { pwc->hIconSm = NULL; } else { pwc->hIconSm = PtoH(pcls->spicnSm); }
/*
* If its a server proc then map it to a client proc. If not we may have * to create a CPD. */ if (pcls->CSF_flags & CSF_SERVERSIDEPROC) { pwc->lpfnWndProc = (WNDPROC)MapServerToClientPfn((ULONG_PTR)pcls->lpfnWndProc, bAnsi); } else { pwc->lpfnWndProc = (WNDPROC)MapClientNeuterToClientPfn(pcls, 0, bAnsi);
/*
* If the client mapping didn't change the window proc then see if * we need a callproc handle. */ if (pwc->lpfnWndProc == (WNDPROC)pcls->lpfnWndProc) { /*
* Need to return a CallProc handle if there is an Ansi/Unicode mismatch */ if (bAnsi != !!(pcls->CSF_flags & CSF_ANSIPROC)) { dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI; } } }
if (dwCPDType) { ULONG_PTR dwCPD;
dwCPD = GetCPD(pcls, dwCPDType | CPD_CLASS, (ULONG_PTR)pwc->lpfnWndProc);
if (dwCPD) { pwc->lpfnWndProc = (WNDPROC)dwCPD; } else { RIPMSG0(RIP_WARNING, "GetClassInfo unable to alloc CPD returning handle"); } }
/*
* Return the stashed pointer to the client-side menu name string. */ if (bAnsi) { *ppszMenuName = (LPWSTR)pcls->lpszClientAnsiMenuName; } else { *ppszMenuName = pcls->lpszClientUnicodeMenuName; } return pcls->atomNVClassName; }
/***************************************************************************\
* _SetClassWord (API) * * Set a class word. Positive index values set application class words * while negative index values set system class words. The negative * indices are published in WINDOWS.H. * * History: * 10-16-90 darrinm Wrote. \***************************************************************************/ WORD _SetClassWord( PWND pwnd, int index, WORD value) { WORD wOld; WORD UNALIGNED *pw; PCLS pcls;
CheckCritIn();
if (GETPTI(pwnd)->ppi != PpiCurrent()) { RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING, "SetClassWord: different process: index 0x%lx", index); return 0; }
pcls = pwnd->pcls->pclsBase; if ((index < 0) || ((UINT)index + sizeof(WORD) > (UINT)pcls->cbclsExtra)) { RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "SetClassWord: invalid index 0x%x", index); return 0; } else { pw = (WORD UNALIGNED *)((BYTE *)(pcls + 1) + index); wOld = *pw; *pw = value; pcls = pcls->pclsClone; while (pcls != NULL) { pw = (WORD UNALIGNED *)((BYTE *)(pcls + 1) + index); *pw = value; pcls = pcls->pclsNext; } return wOld; } }
/***************************************************************************\
* xxxSetClassLong (API) * * Set a class long. Positive index values set application class longs * while negative index values set system class longs. The negative * indices are published in WINDOWS.H. * * History: * 10-16-90 darrinm Wrote. \***************************************************************************/ ULONG_PTR xxxSetClassLongPtr( PWND pwnd, int index, ULONG_PTR value, BOOL bAnsi) { ULONG_PTR dwOld; PCLS pcls;
CheckLock(pwnd); CheckCritIn();
if (GETPTI(pwnd)->ppi != PpiCurrent()) { RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING, "SetClassLongPtr: different process: index 0x%lx", index); return 0; }
if (index < 0) { return xxxSetClassData(pwnd, index, value, bAnsi); } else { pcls = pwnd->pcls->pclsBase; if ((UINT)index + sizeof(ULONG_PTR) > (UINT)pcls->cbclsExtra) { RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "SetClassLongPtr: invalid index 0x%x", index); return 0; } else { ULONG_PTR UNALIGNED *pudw; pudw = (ULONG_PTR UNALIGNED *)((BYTE *)(pcls + 1) + index); dwOld = *pudw; *pudw = value; pcls = pcls->pclsClone; while (pcls != NULL) { pudw = (ULONG_PTR UNALIGNED *)((BYTE *)(pcls + 1) + index); *pudw = value; pcls = pcls->pclsNext; } return dwOld; } } }
#ifdef _WIN64
DWORD xxxSetClassLong( PWND pwnd, int index, DWORD value, BOOL bAnsi) { DWORD dwOld; PCLS pcls;
CheckLock(pwnd); CheckCritIn();
if (GETPTI(pwnd)->ppi != PpiCurrent()) { RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING, "SetClassLong: different process: index 0x%lx", index); return 0; }
if (index < 0) { if (index < INDEX_OFFSET || afClassDWord[index - INDEX_OFFSET] > sizeof(DWORD)) { RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "SetClassLong: invalid index 0x%x", index); return 0; } return (DWORD)xxxSetClassData(pwnd, index, value, bAnsi); } else { pcls = pwnd->pcls->pclsBase; if ((UINT)index + sizeof(DWORD) > (UINT)pcls->cbclsExtra) { RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "SetClassLong: invalid index 0x%x", index); return 0; } else { DWORD UNALIGNED *pudw; pudw = (DWORD UNALIGNED *)((BYTE *)(pcls + 1) + index); dwOld = *pudw; *pudw = value; pcls = pcls->pclsClone; while (pcls != NULL) { pudw = (DWORD UNALIGNED *)((BYTE *)(pcls + 1) + index); *pudw = value; pcls = pcls->pclsNext; } return dwOld; } } } #endif
PPCLS _InnerGetClassPtr( ATOM atom, PPCLS ppcls, HANDLE hModule) { if (atom == 0) return NULL;
while (*ppcls != NULL) { if ((*ppcls)->atomClassName == atom && (hModule == NULL || HIWORD((ULONG_PTR)(*ppcls)->hModule) == HIWORD((ULONG_PTR)hModule)) && !((*ppcls)->CSF_flags & CSF_WOWDEFERDESTROY)) { return ppcls; }
ppcls = (PPCLS)*ppcls; }
return NULL; }
/***************************************************************************\
* GetClassPtr * * Note: This returns a "pointer-to-PCLS" and not "PCLS". * * Scan the passed-in class list for the specified class. Return NULL if * the class isn't in the list. * * History: * 10-16-90 darrinm Ported this puppy. * 04-08-91 DarrinM Rewrote to remove global classes. * 08-14-92 FritzS Changed check to HIWORD only to allow Wow apps to * share window classes between instances of an app. (For Wow apps, HiWord of hInstance is 16-bit module, and LoWord is 16-bit hInstance \***************************************************************************/
PPCLS GetClassPtr( ATOM atom, PPROCESSINFO ppi, HANDLE hModule) { PPCLS ppcls;
/*
* First search public then private then usersrv registered classes */ ppcls = _InnerGetClassPtr(atom, &ppi->pclsPrivateList, hModule); if (ppcls) return ppcls;
ppcls = _InnerGetClassPtr(atom, &ppi->pclsPublicList, NULL); if (ppcls) return ppcls;
/*
* Next seach public and private classes and override hmodule; * some apps (bunny) do a GetClassInfo(dialog) and RegisterClass * and only change the wndproc which set the hmodule to be just * like usersrv created it even though it is in the app's public * or private class list */
/*
* Later -- since we are no longer returning hModuleWin to any app, * we may only need to check for hModClient. Check this out. * FritzS */
ppcls = _InnerGetClassPtr(atom, &ppi->pclsPrivateList, hModClient); if (ppcls) return ppcls;
ppcls = _InnerGetClassPtr(atom, &ppi->pclsPublicList, hModClient); if (ppcls) return ppcls;
/*
* Search the system class list */ ppcls = _InnerGetClassPtr(atom, &gpclsList, NULL); return ppcls; }
/***************************************************************************\
* UnlockAndFreeCPDs - * * Safe way to unlock and free a linked list of CPDs. Need to do it this * way in case the Thread's objects have already been marked for destruction. * * History 2/10/95 SanfordS Created \***************************************************************************/
VOID UnlockAndFreeCPDs( PCALLPROCDATA *ppCPD) { PCALLPROCDATA pCPD;
while ((pCPD = *ppCPD) != NULL) { /*
* Unlink the CPD from the list. */ *ppCPD = pCPD->spcpdNext; pCPD->spcpdNext = NULL;
/*
* Mark it for destruction. */ if (!HMIsMarkDestroy(pCPD)) { HMMarkObjectDestroy(pCPD); }
/*
* Unlock it and it will be destroyed. */ Unlock(&pCPD); } }
/***************************************************************************\
* DestroyClassBrush * * Destroy the brush of the class if it's a brush, it's not a system * brush and no other class is using it * * History: * 4-10-96 CLupu Created \***************************************************************************/
void DestroyClassBrush( PCLS pcls) { PPROCESSINFO ppi = PpiCurrent(); PCLS pclsWalk; int nInd; BOOL bRet; /*
* Return if it's not a real brush */ if (pcls->hbrBackground <= (HBRUSH)(COLOR_MAX)) return;
/*
* Don't delete the system brushes */ for (nInd = 0; nInd < COLOR_MAX; nInd++) { if (pcls->hbrBackground == SYSHBRUSH(nInd)) return; }
/*
* Walk the process public public list */ pclsWalk = ppi->pclsPublicList;
while (pclsWalk) { if (pclsWalk != pcls && pclsWalk->hbrBackground == pcls->hbrBackground) return;
pclsWalk = pclsWalk->pclsNext; }
/*
* Walk the process private class list */ pclsWalk = ppi->pclsPrivateList;
while (pclsWalk) { if (pclsWalk != pcls && pclsWalk->hbrBackground == pcls->hbrBackground) return;
pclsWalk = pclsWalk->pclsNext; }
/*
* Finaly walk the system class list */ pclsWalk = gpclsList;
while (pclsWalk) { if (pclsWalk != pcls && pclsWalk->hbrBackground == pcls->hbrBackground) return;
pclsWalk = pclsWalk->pclsNext; }
bRet = GreDeleteObject(pcls->hbrBackground);
#if DBG
if (!bRet) RIPERR1(ERROR_INVALID_HANDLE, RIP_WARNING, "DestroyClassBrush: failed to destroy brush %#p", pcls->hbrBackground); #endif
}
/***************************************************************************\
* DestroyClass * * Delete the window class. First, destroy any DCs that are attached to the * class. Then delete classname atom. Then free the other stuff that was * allocated when the class was registered and unlink the class from the * master class list. * * History: * 10-16-90 darrinm Ported this puppy. \***************************************************************************/ VOID DestroyClass( PPCLS ppcls) { PPCLS ppclsClone; PCLS pcls; PDESKTOP rpdesk;
pcls = *ppcls;
UserAssert(pcls->cWndReferenceCount == 0);
/*
* If this is a base class, destroy all clones before deleting * stuff. */ if (pcls == pcls->pclsBase) { ppclsClone = &pcls->pclsClone; while (*ppclsClone != NULL) { DestroyClass(ppclsClone); }
UserDeleteAtom(pcls->atomClassName); UserDeleteAtom(pcls->atomNVClassName);
/*
* No freeing if it's an integer resource. */ if (IS_PTR(pcls->lpszMenuName)) { UserFreePool(pcls->lpszMenuName); }
/*
* Free up the class dc if there is one. */ if (pcls->pdce != NULL) DestroyCacheDC(NULL, pcls->pdce->hdc);
/*
* Delete the hBrBackground brush if nobody else is * using it. */ DestroyClassBrush(pcls); }
/*
* If we created the small icon delete it */ DestroyClassSmIcon(pcls);
/*
* Unlock cursor and icon */ Unlock(&pcls->spicn); Unlock(&pcls->spicnSm); Unlock(&pcls->spcur);
/*
* Free any CallProcData objects associated with this class */ if (pcls->spcpdFirst) { UnlockAndFreeCPDs(&pcls->spcpdFirst); }
/*
* Point the previous guy at the guy we currently point to. */ *ppcls = pcls->pclsNext;
/*
* The unlock call is delayed after the free such that if this is * the last reference on the desktop, the desktop heap is not * destroyed before we free the objects. */ rpdesk = pcls->rpdeskParent; pcls->rpdeskParent = NULL;
ClassFree(rpdesk, pcls->lpszAnsiClassName); ClassFree(rpdesk, pcls);
/*
* NOTE: Using pobj after freeing the object is not a problem because * UnlockDesktop uses the value for tracking and doesn't dereference * the pointer. If this ever changes we'll get a BC. */ UnlockDesktop(&rpdesk, LDU_CLS_DESKPARENT2, (ULONG_PTR)pcls); }
/***************************************************************************\
* GetClassIcoCur * * Returns the pwnd's class icon/cursor. This is called by _GetClassData * from the client side because PCURSORs are allocated from POOL (so the * client cannot do PtoH on them). NtUserCallHwndParam does the PtoH translation * * History: * 11-19-90 darrinm Wrote. \***************************************************************************/ PCURSOR GetClassIcoCur( PWND pwnd, int index) { PCLS pcls = pwnd->pcls; PCURSOR pcur;
switch (index) { case GCLP_HICON: pcur = pcls->spicn; break;
case GCLP_HCURSOR: pcur = pcls->spcur; break;
case GCLP_HICONSM: pcur = pcls->spicnSm; break;
default: RIPMSG2(RIP_WARNING, "GetWndIcoCur: Invalid index: 0x%x pwnd: 0x%p", index, pwnd); pcur = NULL; }
return pcur; }
/***************************************************************************\
* xxxSetClassCursor * * History: \***************************************************************************/ ULONG_PTR xxxSetClassCursor( PWND pwnd, PCLS pcls, DWORD index, ULONG_PTR dwData) { ULONG_PTR dwOld;
CheckLock(pwnd);
if ((HANDLE)dwData != NULL) { dwData = (ULONG_PTR)HMValidateHandle((HANDLE)dwData, TYPE_CURSOR); if ((PVOID)dwData == NULL) { if (index == GCLP_HICON || index == GCLP_HICONSM) { RIPERR0(ERROR_INVALID_ICON_HANDLE, RIP_WARNING, "SetClassData: invalid icon"); } else { RIPERR0(ERROR_INVALID_CURSOR_HANDLE, RIP_WARNING, "SetClassData: invalid cursor"); } } }
/*
* Handle the locking issue. */ pcls = pcls->pclsBase; switch (index) { case GCLP_HICON: case GCLP_HICONSM: dwOld = (ULONG_PTR)xxxSetClassIcon(pwnd, pcls, (PCURSOR)dwData, index); break;
case GCLP_HCURSOR: dwOld = (ULONG_PTR)Lock(&pcls->spcur, dwData); break; }
/*
* Now set it for each clone class. */ pcls = pcls->pclsClone; while (pcls != NULL) { switch(index) { case GCLP_HICON: case GCLP_HICONSM: xxxSetClassIcon(pwnd, pcls, (PCURSOR)dwData, index); break;
case GCLP_HCURSOR: Lock(&pcls->spcur, dwData); break; } pcls = pcls->pclsNext; }
return (ULONG_PTR)PtoH((PVOID)dwOld); }
/***************************************************************************\
* SetClassData * * SetClassWord and SetClassLong are now identical routines because they both * can return DWORDs. This single routine performs the work for them both * by using two arrays; afClassDWord to determine whether the result should be * a WORD or a DWORD, and aiClassOffset to find the correct offset into the * CLS structure for a given GCL_ or GCL_ index. * * History: * 11-19-90 darrinm Wrote. \***************************************************************************/ ULONG_PTR xxxSetClassData( PWND pwnd, int index, ULONG_PTR dwData, BOOL bAnsi) { PCLS pcls = pwnd->pcls; BYTE *pb; ULONG_PTR dwT; ULONG_PTR dwOld; DWORD dwCPDType = 0; PCLSMENUNAME pcmn; UNICODE_STRING strMenuName, UString;
CheckLock(pwnd);
switch(index) { case GCLP_WNDPROC:
/*
* If the application (client) subclasses a class that has a server - * side window proc we must return a client side proc stub that it * can call. */ if (pcls->CSF_flags & CSF_SERVERSIDEPROC) { dwOld = MapServerToClientPfn((ULONG_PTR)pcls->lpfnWndProc, bAnsi); pcls->CSF_flags &= ~CSF_SERVERSIDEPROC;
UserAssert(!(pcls->CSF_flags & CSF_ANSIPROC)); if (bAnsi) { pcls->CSF_flags |= CSF_ANSIPROC; } } else { dwOld = MapClientNeuterToClientPfn(pcls, 0, bAnsi);
/*
* If the client mapping didn't change the window proc then see if * we need a callproc handle. */ if (dwOld == (ULONG_PTR)pcls->lpfnWndProc) { /*
* Need to return a CallProc handle if there is an Ansi/Unicode mismatch */ if (bAnsi != !!(pcls->CSF_flags & CSF_ANSIPROC)) { dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI; } } }
if (dwCPDType) { ULONG_PTR dwCPD;
dwCPD = GetCPD(pcls, dwCPDType | CPD_CLASS, dwOld);
if (dwCPD) { dwOld = dwCPD; } else { RIPMSG0(RIP_WARNING, "GetClassLong unable to alloc CPD returning handle"); } }
/*
* Convert a possible CallProc Handle into a real address. They may * have kept the CallProc Handle from some previous mixed GetClassinfo * or SetWindowLong. */ if (ISCPDTAG(dwData)) { PCALLPROCDATA pCPD; if (pCPD = HMValidateHandleNoRip((HANDLE)dwData, TYPE_CALLPROC)) { dwData = pCPD->pfnClientPrevious; } }
/*
* If an app 'unsubclasses' a server-side window proc we need to * restore everything so SendMessage and friends know that it's * a server-side proc again. Need to check against client side * stub addresses. */ pcls->lpfnWndProc = (WNDPROC_PWND)dwData; if ((dwT = MapClientToServerPfn(dwData)) != 0) { pcls->lpfnWndProc = (WNDPROC_PWND)dwT; pcls->CSF_flags |= CSF_SERVERSIDEPROC; pcls->CSF_flags &= ~CSF_ANSIPROC; } else { if (bAnsi) { pcls->CSF_flags |= CSF_ANSIPROC; } else { pcls->CSF_flags &= ~CSF_ANSIPROC; } } if (pcls->CSF_flags & CSF_WOWCLASS) { PWC pwc = PWCFromPCLS(pcls); pwc->hMod16 = (pcls->CSF_flags & CSF_SERVERSIDEPROC) ? 0 : xxxClientWOWGetProcModule(pcls->lpfnWndProc); }
return dwOld; break;
case GCLP_HICON: case GCLP_HICONSM: case GCLP_HCURSOR: return xxxSetClassCursor(pwnd, pcls, index, dwData); break;
case GCL_WOWMENUNAME: if (pcls->CSF_flags & CSF_WOWCLASS) { PWCFromPCLS(pcls)->vpszMenu = (DWORD)dwData; } else { UserAssert(FALSE); } break;
case GCL_CBCLSEXTRA: if (pcls->CSF_flags & CSF_WOWCLASS) { /*
* yes -- we can do this for WOW classes only. */ if (pcls->CSF_flags & CSF_WOWEXTRA) { dwOld = PWCFromPCLS(pcls)->iClsExtra; PWCFromPCLS(pcls)->iClsExtra = LOWORD(dwData); return dwOld; } else { PWCFromPCLS(pcls)->iClsExtra = LOWORD(dwData); pcls->CSF_flags |= CSF_WOWEXTRA; return pcls->cbclsExtra; } } RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Attempt to change cbClsExtra"); break;
case GCLP_MENUNAME: pcmn = (PCLSMENUNAME) dwData;
/*
* pcmn->pusMenuName->Buffer is a client-side address. */
dwOld = (ULONG_PTR) pcls->lpszMenuName; /* Is it a string? */ if (IS_PTR(pcmn->pusMenuName->Buffer)) { try { RtlInitUnicodeString(&UString, pcmn->pusMenuName->Buffer); } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { break; } /* Empty String? */ if (UString.Length == 0) { pcls->lpszMenuName = NULL; } else { /* Make a copy of the string */ if (!AllocateUnicodeString(&strMenuName, &UString)) { RIPMSG0(RIP_WARNING, "xxxSetClassData: GCL_MENUNAME AllocateUnicodeString failed"); break; }
pcls->lpszMenuName = strMenuName.Buffer; } } else { /* Just copy the id */ pcls->lpszMenuName = pcmn->pusMenuName->Buffer; } /* Don't return the kernel side pointer */ pcmn->pusMenuName = NULL;
/* Free old string, if any */ if (IS_PTR(dwOld)) { UserFreePool((PVOID)dwOld); }
/* Return client side pointers */ dwOld = (ULONG_PTR) pcls->lpszClientAnsiMenuName; pcls->lpszClientAnsiMenuName = pcmn->pszClientAnsiMenuName; pcmn->pszClientAnsiMenuName = (LPSTR)dwOld;
dwOld = (ULONG_PTR) pcls->lpszClientUnicodeMenuName; pcls->lpszClientUnicodeMenuName = pcmn->pwszClientUnicodeMenuName; pcmn->pwszClientUnicodeMenuName = (LPWSTR)dwOld;
return (bAnsi ? (ULONG_PTR) pcmn->pszClientAnsiMenuName : (ULONG_PTR) pcmn->pwszClientUnicodeMenuName);
default: /*
* All other indexes go here... */ index -= INDEX_OFFSET;
/*
* Only let valid indices go through; if aiClassOffset is zero * then we have no mapping for this negative index so it must * be a bogus index. */ if ((index < 0) || (aiClassOffset[index] == 0)) { RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "SetClassLong: invalid index 0x%x", index); return 0; }
pcls = pcls->pclsBase; pb = ((BYTE *)pcls) + aiClassOffset[index];
if (afClassDWord[index] == sizeof(DWORD)) { dwOld = *(DWORD *)pb; *(DWORD *)pb = (DWORD)dwData; } else if (afClassDWord[index] == sizeof(ULONG_PTR)) { dwOld = *(ULONG_PTR *)pb; *(ULONG_PTR *)pb = dwData; } else { dwOld = (DWORD)*(WORD *)pb; *(WORD *)pb = (WORD)dwData; }
pcls = pcls->pclsClone; while (pcls != NULL) { pb = ((BYTE *)pcls) + aiClassOffset[index];
if (afClassDWord[index] == sizeof(DWORD)) { dwOld = *(DWORD *)pb; *(DWORD *)pb = (DWORD)dwData; } else if (afClassDWord[index] == sizeof(ULONG_PTR)) { dwOld = *(ULONG_PTR *)pb; *(ULONG_PTR *)pb = dwData; } else { dwOld = (DWORD)*(WORD *)pb; *(WORD *)pb = (WORD)dwData; } pcls = pcls->pclsNext; }
return dwOld; }
return 0; }
/***************************************************************************\
* ReferenceClass * * Clones the class if it is a different desktop than the new window and * increments the class window count(s). * * History: * 12-11-93 JimA Created. \***************************************************************************/
BOOL ReferenceClass( PCLS pcls, PWND pwnd) { DWORD cbName; PCLS pclsClone; PDESKTOP pdesk;
/*
* If the window is on the same desktop as the base class, just * increment the window count. */ if (pcls->rpdeskParent == pwnd->head.rpdesk) { pcls->cWndReferenceCount++; return TRUE; }
/*
* The window is not on the base desktop. Try to find a cloned * class. */ for (pclsClone = pcls->pclsClone; pclsClone != NULL; pclsClone = pclsClone->pclsNext) { if (pclsClone->rpdeskParent == pwnd->head.rpdesk) { break; } }
/*
* If we can't find one, clone the base class. */ if (pclsClone == NULL) { pdesk = pwnd->head.rpdesk; pclsClone = ClassAlloc(pdesk, sizeof(CLS) + pcls->cbclsExtra + (pcls->CSF_flags & CSF_WOWCLASS ?sizeof(WC):0), DTAG_CLASS); if (pclsClone == NULL) { RIPMSG0(RIP_WARNING, "ReferenceClass: Failed Clone-Class Allocation"); return FALSE; }
RtlCopyMemory(pclsClone, pcls, sizeof(CLS) + pcls->cbclsExtra + (pcls->CSF_flags & CSF_WOWCLASS?sizeof(WC):0));
cbName = strlen(pcls->lpszAnsiClassName) + 1; pclsClone->lpszAnsiClassName = ClassAlloc(pdesk, cbName, DTAG_TEXT); if (pclsClone->lpszAnsiClassName == NULL) { ClassFree(pdesk, pclsClone); RIPMSG0(RIP_WARNING, "ReferenceClass: No Clone Class Name"); return FALSE; }
/*
* Everything has been allocated, now lock everything down. * NULL pointers in clone to prevent Lock() from incorrectly * decrementing object reference count */ pclsClone->rpdeskParent = NULL; LockDesktop(&pclsClone->rpdeskParent, pdesk, LDL_CLS_DESKPARENT2, (ULONG_PTR)pclsClone); pclsClone->pclsNext = pcls->pclsClone; pclsClone->pclsClone = NULL; pcls->pclsClone = pclsClone; RtlCopyMemory(pclsClone->lpszAnsiClassName, pcls->lpszAnsiClassName, cbName);
pclsClone->spicn = pclsClone->spicnSm = pclsClone->spcur = NULL;
Lock(&pclsClone->spicn, pcls->spicn); Lock(&pclsClone->spicnSm, pcls->spicnSm); Lock(&pclsClone->spcur, pcls->spcur); pclsClone->spcpdFirst = NULL; pclsClone->cWndReferenceCount = 0; }
/*
* Increment reference counts. */ pcls->cWndReferenceCount++; pclsClone->cWndReferenceCount++; pwnd->pcls = pclsClone;
return TRUE; }
/***************************************************************************\
* DereferenceClass * * Decrements the class window count in the base class. If it's the * last window of a clone class, destroy the clone. * * History: * 12-11-93 JimA Created. \***************************************************************************/
VOID DereferenceClass( PWND pwnd) { PCLS pcls = pwnd->pcls; PPCLS ppcls;
UserAssert(pcls->cWndReferenceCount >= 1);
pwnd->pcls = NULL;
pcls->cWndReferenceCount--; if (pcls != pcls->pclsBase) {
UserAssert(pcls->pclsBase->cWndReferenceCount >= 1);
pcls->pclsBase->cWndReferenceCount--;
if (pcls->cWndReferenceCount == 0) { ppcls = &pcls->pclsBase->pclsClone; while ((*ppcls) != pcls) ppcls = &(*ppcls)->pclsNext; UserAssert(ppcls); DestroyClass(ppcls); } } }
/***************************************************************************\
* DestroyProcessesClasses * * History: * 04-07-91 DarrinM Created. \***************************************************************************/
VOID DestroyProcessesClasses( PPROCESSINFO ppi) { PPCLS ppcls;
/*
* Destroy the private classes first */ ppcls = &(ppi->pclsPrivateList); while (*ppcls != NULL) { DestroyClass(ppcls); }
/*
* Then the cloned public classes */ ppcls = &(ppi->pclsPublicList); while (*ppcls != NULL) { DestroyClass(ppcls); } }
|