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.
 
 
 
 
 
 

569 lines
17 KiB

/****************************** Module Header ******************************\
* Module Name: classc.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* This module contains
*
* History:
* 15-Dec-1993 JohnC Pulled functions from user\server.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* These arrays are used by GetClassWord/Long.
*/
// !!! can't we get rid of this and just special case GCW_ATOM
CONST BYTE afClassDWord[] = {
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)
};
CONST BYTE aiClassOffset[] = {
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
};
/*
* INDEX_OFFSET must refer to the first entry of afClassDWord[]
*/
#define INDEX_OFFSET GCLP_HICONSM
/***************************************************************************\
* GetClassData
*
* GetClassWord and GetClassLong 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 UINT 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 _GetClassData(
PCLS pcls,
PWND pwnd, // used for transition to kernel-mode for GCL_WNDPROC
int index,
BOOL bAnsi)
{
KERNEL_ULONG_PTR dwData;
DWORD dwCPDType = 0;
index -= INDEX_OFFSET;
if (index < 0) {
RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
return 0;
}
UserAssert(index >= 0);
UserAssert(index < sizeof(afClassDWord));
UserAssert(sizeof(afClassDWord) == sizeof(aiClassOffset));
if (afClassDWord[index] == sizeof(DWORD)) {
dwData = *(KPDWORD)(((KPBYTE)pcls) + aiClassOffset[index]);
} else if (afClassDWord[index] == sizeof(KERNEL_ULONG_PTR)) {
dwData = *(KPKERNEL_ULONG_PTR)(((KPBYTE)pcls) + aiClassOffset[index]);
} else {
dwData = (DWORD)*(KPWORD)(((KPBYTE)pcls) + aiClassOffset[index]);
}
index += INDEX_OFFSET;
/*
* If we're returning an icon or cursor handle, do the reverse
* mapping here.
*/
switch(index) {
case GCLP_MENUNAME:
if (IS_PTR(pcls->lpszMenuName)) {
/*
* The Menu Name is a real string: return the client-side address.
* (If the class was registered by another app this returns an
* address in that app's addr. space, but it's the best we can do)
*/
dwData = bAnsi ?
(ULONG_PTR)pcls->lpszClientAnsiMenuName :
(ULONG_PTR)pcls->lpszClientUnicodeMenuName;
}
break;
case GCLP_HICON:
case GCLP_HCURSOR:
case GCLP_HICONSM:
/*
* We have to go to the kernel to convert the pcursor to a handle because
* cursors are allocated out of POOL, which is not accessable from the client.
*/
if (dwData) {
dwData = NtUserCallHwndParam(PtoH(pwnd), index, SFI_GETCLASSICOCUR);
}
break;
case GCLP_WNDPROC:
{
/*
* Always return the client wndproc in case this is a server
* window class.
*/
if (pcls->CSF_flags & CSF_SERVERSIDEPROC) {
dwData = MapServerToClientPfn(dwData, bAnsi);
} else {
KERNEL_ULONG_PTR dwT = dwData;
dwData = MapClientNeuterToClientPfn(pcls, dwT, bAnsi);
/*
* If the client mapping didn't change the window proc then see if
* we need a callproc handle.
*/
if (dwData == dwT) {
/*
* 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(pwnd, dwCPDType | CPD_WNDTOCLS, KERNEL_ULONG_PTR_TO_ULONG_PTR(dwData));
if (dwCPD) {
dwData = dwCPD;
} else {
RIPMSG0(RIP_WARNING, "GetClassLong unable to alloc CPD returning handle\n");
}
}
}
break;
case GCL_CBCLSEXTRA:
if ((pcls->CSF_flags & CSF_WOWCLASS) && (pcls->CSF_flags & CSF_WOWEXTRA)) {
/*
* The 16-bit app changed its Extra bytes value. Return the changed
* value. FritzS
*/
return PWCFromPCLS(pcls)->iClsExtra;
}
else
return pcls->cbclsExtra;
break;
/*
* WOW uses a pointer straight into the class structure.
*/
case GCLP_WOWWORDS:
if (pcls->CSF_flags & CSF_WOWCLASS) {
return ((ULONG_PTR)PWCFromPCLS(pcls));
} else
return 0;
case GCL_STYLE:
dwData &= CS_VALID;
break;
}
return KERNEL_ULONG_PTR_TO_ULONG_PTR(dwData);
}
/***************************************************************************\
* _GetClassLong (API)
*
* Return a class long. Positive index values return application class longs
* while negative index values return system class longs. The negative
* indices are published in WINDOWS.H.
*
* History:
* 10-16-90 darrinm Wrote.
\***************************************************************************/
ULONG_PTR _GetClassLongPtr(
PWND pwnd,
int index,
BOOL bAnsi)
{
PCLS pcls = REBASEALWAYS(pwnd, pcls);
if (index < 0) {
return _GetClassData(pcls, pwnd, index, bAnsi);
} else {
if ((UINT)index + sizeof(ULONG_PTR) > (UINT)pcls->cbclsExtra) {
RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
return 0;
} else {
ULONG_PTR UNALIGNED * KPTR_MODIFIER pudw;
pudw = (ULONG_PTR UNALIGNED * KPTR_MODIFIER)((KPBYTE)(pcls + 1) + index);
return *pudw;
}
}
}
#ifdef _WIN64
DWORD _GetClassLong(
PWND pwnd,
int index,
BOOL bAnsi)
{
PCLS pcls = REBASEALWAYS(pwnd, pcls);
if (index < 0) {
if (index < INDEX_OFFSET || afClassDWord[index - INDEX_OFFSET] > sizeof(DWORD)) {
RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "GetClassLong: invalid index %d", index);
return 0;
}
return (DWORD)_GetClassData(pcls, pwnd, index, bAnsi);
} else {
if ((UINT)index + sizeof(DWORD) > (UINT)pcls->cbclsExtra) {
RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
return 0;
} else {
DWORD UNALIGNED * KPTR_MODIFIER pudw;
pudw = (DWORD UNALIGNED * KPTR_MODIFIER)((KPBYTE)(pcls + 1) + index);
return *pudw;
}
}
}
#endif
/***************************************************************************\
* GetClassWord (API)
*
* Return a class word. Positive index values return application class words
* while negative index values return system class words. The negative
* indices are published in WINDOWS.H.
*
* History:
* 10-16-90 darrinm Wrote.
\***************************************************************************/
FUNCLOG2(LOG_GENERAL, WORD, DUMMYCALLINGTYPE, GetClassWord, HWND, hwnd, int, index)
WORD GetClassWord(
HWND hwnd,
int index)
{
PWND pwnd;
PCLS pclsClient;
pwnd = ValidateHwnd(hwnd);
if (pwnd == NULL)
return 0;
pclsClient = (PCLS)REBASEALWAYS(pwnd, pcls);
try {
if (index == GCW_ATOM) {
return (WORD)_GetClassData(pclsClient, pwnd, index, FALSE);
} else {
if ((index < 0) || ((UINT)index + sizeof(WORD) > (UINT)pclsClient->cbclsExtra)) {
RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
return 0;
} else {
WORD UNALIGNED * KPTR_MODIFIER puw;
puw = (WORD UNALIGNED * KPTR_MODIFIER)((KPBYTE)(pclsClient + 1) + index);
return *puw;
}
}
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
RIPERR1(ERROR_INVALID_WINDOW_HANDLE,
RIP_WARNING,
"Window %x no longer valid",
hwnd);
return 0;
}
}
/***************************************************************************\
* VersionRegisterClass
*
* Tries to register a versioned class by loading calling a
* predefined entry point in the DLL lpzDllName in the specified activation context.
*
* History:
* 10-16-01 msadek Wrote.
\***************************************************************************/
BOOL VersionRegisterClass(
LPWSTR lpzClassName,
LPWSTR lpzDllName,
PACTIVATION_CONTEXT lpActivationContext,
HMODULE *phModule)
{
BOOL bRet = FALSE;
HMODULE hDllMod = NULL;
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame = { sizeof(ActivationFrame),
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
RtlActivateActivationContextUnsafeFast(&ActivationFrame, lpActivationContext);
__try {
/*
* Try to register it, by loading its DLL. Notice that this DLL
* will never get unloaded unless we failed to create the window.
* but once we created a window by loading this DLL will never free it.
*/
PREGISTERCLASSNAMEW pRegisterClassNameW = NULL;
if ((hDllMod = LoadLibraryW(lpzDllName)) &&
(pRegisterClassNameW = (PREGISTERCLASSNAMEW)GetProcAddress(hDllMod, "RegisterClassNameW"))) {
if (IS_PTR(lpzClassName)) {
bRet = (*pRegisterClassNameW)(lpzClassName);
} else {
UNICODE_STRING UnicodeClassName;
WCHAR Buffer[MAX_ATOM_LEN];
UnicodeClassName.MaximumLength = (USHORT)(MAX_ATOM_LEN * sizeof(WCHAR));
UnicodeClassName.Buffer = Buffer;
if (NtUserGetAtomName((ATOM)lpzClassName, &UnicodeClassName)) {
bRet = (*pRegisterClassNameW)(Buffer);
}
}
}
} __finally {
RtlDeactivateActivationContextUnsafeFast(&ActivationFrame);
}
if (!bRet && hDllMod != NULL) {
FREE_LIBRARY_SAVE_ERROR(hDllMod);
} else if (phModule) {
*phModule = hDllMod;
}
return bRet;
}
/***************************************************************************\
* ClassNameToVersion
*
* Map class name to class name+version.
* lpClassName : Class name to be mapped, it may be ANSI, Unicode or an Atom.
* pClassVerName : Buffer to receive the class name+version.
* lpDllName : if it is not NULL it will point to the DLL owns this class
name.
* bIsANSI : True of lpClassName is ANSI, FALSE if it is Unicode.
*
* Return: If it succeed it returns lpClassName or lpClassName.
* if it failed it returns NULL.
*
* History:
* 08-01-00 MHamid Wrote.
\***************************************************************************/
LPWSTR
ClassNameToVersion(
LPCWSTR lpClassName,
LPWSTR pClassVerName,
LPWSTR *lpDllName,
PACTIVATION_CONTEXT* lppActivationContext,
BOOL bIsANSI
)
{
int cbSrc;
int cbDst;
UNICODE_STRING UnicodeClassName;
ACTIVATION_CONTEXT_SECTION_KEYED_DATA acskd;
ACTIVATION_CONTEXT_DATA_WINDOW_CLASS_REDIRECTION UNALIGNED * pRedirEntry;
LPWSTR lpClassNameRet;
LPWSTR pwstr;
ULONG strLength;
LPWSTR Buffer;
NTSTATUS Status;
acskd.ActivationContext = NULL;
if (lppActivationContext != NULL) {
*lppActivationContext = NULL;
}
/*
* Allocate local buffer.
*/
Buffer = UserLocalAlloc(0, MAX_ATOM_LEN * sizeof(WCHAR));
if (Buffer == NULL) {
return NULL;
}
/*
* Capture lpClassName into a local buffer.
*/
if (IS_PTR(lpClassName)) {
/*
* lpClassName is string.
*/
if (bIsANSI) {
/*
* it is ANSI then convert it to unicode.
*/
cbSrc = strlen((LPSTR)lpClassName) + 1;
RtlMultiByteToUnicodeN(Buffer,
MAX_ATOM_LEN * sizeof(WCHAR), &cbDst,
(LPSTR)lpClassName, cbSrc);
} else {
/*
* It is already unicode, then just copy it.
*/
cbSrc = min (wcslen(lpClassName) + 1, MAX_ATOM_LEN);
cbSrc *= sizeof(WCHAR);
RtlCopyMemory(Buffer, lpClassName, cbSrc);
}
/*
* Build the UNICODE_STRING
*/
RtlInitUnicodeString(&UnicodeClassName, Buffer);
} else {
/*
* lpClassName is an atom, get its name and build the UNICODE_STRING
*/
UnicodeClassName.MaximumLength = (USHORT)(MAX_ATOM_LEN * sizeof(WCHAR));
UnicodeClassName.Buffer = Buffer;
UnicodeClassName.Length = (USHORT)NtUserGetAtomName((ATOM)lpClassName, &UnicodeClassName) * sizeof(WCHAR);
if (!UnicodeClassName.Length) {
lpClassNameRet = NULL;
goto Free_Buffer;
}
}
/*
* Call Fusion to map the class name.
*/
RtlZeroMemory(&acskd, sizeof(acskd));
acskd.Size = sizeof(acskd);
Status = RtlFindActivationContextSectionString(
FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ACTIVATION_CONTEXT,
NULL,
ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
&UnicodeClassName,
&acskd);
/*
* If there is no Activation Section we will use the plain class name.
*/
if ((Status == STATUS_SXS_SECTION_NOT_FOUND) ||
(Status == STATUS_SXS_KEY_NOT_FOUND)) {
lpClassNameRet = (LPWSTR)lpClassName;
goto Free_Buffer;
}
/*
* Case of failure return NULL.
*/
if (!NT_SUCCESS(Status) ||
acskd.DataFormatVersion != ACTIVATION_CONTEXT_DATA_WINDOW_CLASS_REDIRECTION_FORMAT_WHISTLER) {
lpClassNameRet = NULL;
goto Free_Buffer;
}
pRedirEntry = (PACTIVATION_CONTEXT_DATA_WINDOW_CLASS_REDIRECTION) acskd.Data;
UserAssert(pRedirEntry);
pwstr = (LPWSTR)(((ULONG_PTR) pRedirEntry) + pRedirEntry->VersionSpecificClassNameOffset);
strLength = pRedirEntry->VersionSpecificClassNameLength + sizeof(WCHAR);
if (lpDllName) {
*lpDllName = (LPWSTR)(((ULONG_PTR) acskd.SectionBase) + pRedirEntry->DllNameOffset);
}
UserAssert(pwstr);
UserAssert(strLength <= MAX_ATOM_LEN * sizeof(WCHAR));
/*
* if the call is ANSI then convert the class name+version to ANSI string.
*/
if (bIsANSI) {
RtlUnicodeToMultiByteN((LPSTR)pClassVerName,
MAX_ATOM_LEN, &cbDst,
pwstr, strLength);
} else {
/*
* if it is unicode then just copy the class name+version to the caller's buffer.
*/
RtlCopyMemory(pClassVerName, pwstr, strLength);
}
/*
* And return it.
*/
lpClassNameRet = pClassVerName;
if (lppActivationContext != NULL) {
*lppActivationContext = acskd.ActivationContext;
acskd.ActivationContext = NULL;
}
Free_Buffer:
/*
* Don't forget to free the local memory.
*/
UserLocalFree(Buffer);
if (acskd.ActivationContext != NULL) {
RtlReleaseActivationContext(acskd.ActivationContext);
acskd.ActivationContext = NULL;
}
return lpClassNameRet;
}