Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1844 lines
54 KiB

/****************************** 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);
}
}