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