⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 class.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 *  ReactOS W32 Subsystem
 *  Copyright (C) 1998 - 2006 ReactOS Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/* $Id: class.c 27946 2007-07-28 12:22:27Z weiden $
 *
 * COPYRIGHT:        See COPYING in the top level directory
 * PROJECT:          ReactOS kernel
 * PURPOSE:          Window classes
 * FILE:             subsys/win32k/ntuser/class.c
 * PROGRAMER:        Thomas Weidenmueller <w3seek@reactos.com>
 * REVISION HISTORY:
 *       06-06-2001  CSH  Created
 */
/* INCLUDES ******************************************************************/

#include <w32k.h>

#define NDEBUG
#include <debug.h>
#define TRACE DPRINT
#define WARN DPRINT1
#define ERR DPRINT1

/* WINDOWCLASS ***************************************************************/

static VOID
IntFreeClassMenuName(IN OUT PWINDOWCLASS Class)
{
    /* free the menu name, if it was changed and allocated */
    if (Class->MenuName != NULL && Class->MenuNameIsString)
    {
        UserHeapFree(Class->MenuName);
        Class->MenuName = NULL;
        Class->AnsiMenuName = NULL;
    }
}

static VOID
IntDestroyClass(IN OUT PWINDOWCLASS Class)
{
    /* there shouldn't be any clones anymore */
    ASSERT(Class->Windows == 0);
    ASSERT(Class->Clone == NULL);

    if (Class->Base == Class)
    {
        /* destruct resources shared with clones */
        if (!Class->System && Class->CallProc != NULL)
        {
            DestroyCallProc(Class->GlobalCallProc ? NULL : Class->Desktop,
                            Class->CallProc);
        }

        if (Class->CallProc2 != NULL)
        {
            DestroyCallProc(Class->GlobalCallProc2 ? NULL : Class->Desktop,
                            Class->CallProc2);
        }

        IntFreeClassMenuName(Class);
    }

    /* free the structure */
    if (Class->Desktop != NULL)
    {
        DesktopHeapFree(Class->Desktop,
                        Class);
    }
    else
    {
        UserHeapFree(Class);
    }
}


/* clean all process classes. all process windows must cleaned first!! */
void FASTCALL DestroyProcessClasses(PW32PROCESS Process )
{
    PWINDOWCLASS Class;
    PW32PROCESSINFO pi = Process->ProcessInfo;

    if (pi != NULL)
    {
        /* free all local classes */
        Class = pi->LocalClassList;
        while (Class != NULL)
        {
            pi->LocalClassList = Class->Next;

            ASSERT(Class->Base == Class);
            IntDestroyClass(Class);

            Class = pi->LocalClassList;
        }

        /* free all global classes */
        Class = pi->GlobalClassList;
        while (Class != NULL)
        {
            pi->GlobalClassList = Class->Next;

            ASSERT(Class->Base == Class);
            IntDestroyClass(Class);

            Class = pi->GlobalClassList;
        }

        /* free all system classes */
        Class = pi->SystemClassList;
        while (Class != NULL)
        {
            pi->SystemClassList = Class->Next;

            ASSERT(Class->Base == Class);
            IntDestroyClass(Class);

            Class = pi->SystemClassList;
        }
    }
}

static BOOL
IntRegisterClassAtom(IN PUNICODE_STRING ClassName,
                     OUT RTL_ATOM *pAtom)
{
    WCHAR szBuf[65];
    PWSTR AtomName;
    NTSTATUS Status;

    if (ClassName->Length != 0)
    {
        /* FIXME - Don't limit to 64 characters! use SEH when allocating memory! */
        if (ClassName->Length / sizeof(WCHAR) >= sizeof(szBuf) / sizeof(szBuf[0]))
        {
            SetLastWin32Error(ERROR_INVALID_PARAMETER);
            return (RTL_ATOM)0;
        }

        RtlCopyMemory(szBuf,
                      ClassName->Buffer,
                      ClassName->Length);
        szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
        AtomName = szBuf;
    }
    else
        AtomName = ClassName->Buffer;

    Status = RtlAddAtomToAtomTable(gAtomTable,
                                   AtomName,
                                   pAtom);

    if (!NT_SUCCESS(Status))
    {
        SetLastNtError(Status);
        return FALSE;
    }

    return TRUE;
}

static NTSTATUS
IntDeregisterClassAtom(IN RTL_ATOM Atom)
{
    return RtlDeleteAtomFromAtomTable(gAtomTable,
                                      Atom);
}

static BOOL
IntSetClassAtom(IN OUT PWINDOWCLASS Class,
                IN PUNICODE_STRING ClassName)
{
    RTL_ATOM Atom = (RTL_ATOM)0;

    /* update the base class first */
    Class = Class->Base;

    if (!IntRegisterClassAtom(ClassName,
                              &Atom))
    {
        return FALSE;
    }

    IntDeregisterClassAtom(Class->Atom);

    Class->Atom = Atom;

    /* update the clones */
    Class = Class->Clone;
    while (Class != NULL)
    {
        Class->Atom = Atom;

        Class = Class->Next;
    }

    return TRUE;
}

static WNDPROC
IntGetClassWndProc(IN PWINDOWCLASS Class,
                   IN PW32PROCESSINFO pi,
                   IN BOOL Ansi,
                   IN BOOL UseCallProc2)
{
    ASSERT(UserIsEnteredExclusive() == TRUE);
    
    if (Class->System)
    {
        return (Ansi ? Class->WndProcExtra : Class->WndProc);
    }
    else
    {
        if (!Ansi == Class->Unicode)
        {
            return Class->WndProc;
        }
        else
        {
            PCALLPROC *CallProcPtr;
            PWINDOWCLASS BaseClass;

            /* make sure the call procedures are located on the desktop
               of the base class! */
            BaseClass = Class->Base;
            Class = BaseClass;

            CallProcPtr = (UseCallProc2 ? &Class->CallProc2 : &Class->CallProc);

            if (*CallProcPtr != NULL)
            {
                return GetCallProcHandle(*CallProcPtr);
            }
            else
            {
                PCALLPROC NewCallProc;

                if (pi == NULL)
                    return NULL;

                NewCallProc = CreateCallProc(Class->Desktop,
                                             Class->WndProc,
                                             Class->Unicode,
                                             pi);
                if (NewCallProc == NULL)
                {
                    SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
                    return NULL;
                }

                *CallProcPtr = NewCallProc;

                if (Class->Desktop == NULL)
                {
                    if (UseCallProc2)
                        Class->GlobalCallProc2 = TRUE;
                    else
                        Class->GlobalCallProc = TRUE;
                }

                /* update the clones */
                Class = Class->Clone;
                while (Class != NULL)
                {
                    if (UseCallProc2)
                    {
                        Class->CallProc2 = NewCallProc;
                        Class->GlobalCallProc2 = BaseClass->GlobalCallProc2;
                    }
                    else
                    {
                        Class->CallProc = NewCallProc;
                        Class->GlobalCallProc = BaseClass->GlobalCallProc;
                    }

                    Class = Class->Next;
                }

                return GetCallProcHandle(NewCallProc);
            }
        }
    }
}

static WNDPROC
IntSetClassWndProc(IN OUT PWINDOWCLASS Class,
                   IN WNDPROC WndProc,
                   IN BOOL Ansi)
{
    WNDPROC Ret;

    if (Class->System)
    {
        DPRINT1("Attempted to change window procedure of system window class 0x%p!\n", Class->Atom);
        SetLastWin32Error(ERROR_ACCESS_DENIED);
        return NULL;
    }

    /* update the base class first */
    Class = Class->Base;

    /* resolve any callproc handle if possible */
    if (IsCallProcHandle(WndProc))
    {
        WNDPROC_INFO wpInfo;

        if (UserGetCallProcInfo((HANDLE)WndProc,
                                &wpInfo))
        {
            WndProc = wpInfo.WindowProc;
            /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
        }
    }

    Ret = IntGetClassWndProc(Class,
                             GetW32ProcessInfo(),
                             Ansi,
                             TRUE);
    if (Ret == NULL)
    {
        return NULL;
    }

    /* update the class info */
    Class->Unicode = !Ansi;
    Class->WndProc = WndProc;
    if (Class->CallProc != NULL)
    {
        Class->CallProc->WndProc = WndProc;
        Class->CallProc->Unicode = !Ansi;
    }

    /* update the clones */
    Class = Class->Clone;
    while (Class != NULL)
    {
        Class->Unicode = !Ansi;
        Class->WndProc = WndProc;

        Class = Class->Next;
    }

    return Ret;
}

static PWINDOWCLASS
IntGetClassForDesktop(IN OUT PWINDOWCLASS BaseClass,
                      IN OUT PWINDOWCLASS *ClassLink,
                      IN PDESKTOP Desktop)
{
    SIZE_T ClassSize;
    PWINDOWCLASS Class;

    ASSERT(Desktop != NULL);
    ASSERT(BaseClass->Base == BaseClass);

    if (BaseClass->Desktop == Desktop)
    {
        /* it is most likely that a window is created on the same
           desktop as the window class. */

        return BaseClass;
    }

    if (BaseClass->Desktop == NULL)
    {
        ASSERT(BaseClass->Windows == 0);
        ASSERT(BaseClass->Clone == NULL);

        /* Classes are also located in the shared heap when the class
           was created before the thread attached to a desktop. As soon
           as a window is created for such a class located on the shared
           heap, the class is cloned into the desktop heap on which the
           window is created. */
        Class = NULL;
    }
    else
    {
        /* The user is asking for a class object on a different desktop,
           try to find one! */
        Class = BaseClass->Clone;
        while (Class != NULL)
        {
            if (Class->Desktop == Desktop)
            {
                ASSERT(Class->Base == BaseClass);
                ASSERT(Class->Clone == NULL);
                break;
            }

            Class = Class->Next;
        }
    }

    if (Class == NULL)
    {
        /* The window is created on a different desktop, we need to
           clone the class object to the desktop heap of the window! */
        ClassSize = sizeof(*BaseClass) + (SIZE_T)BaseClass->ClsExtra;

        Class = DesktopHeapAlloc(Desktop,
                                 ClassSize);
        if (Class != NULL)
        {
            /* simply clone the class */
            RtlCopyMemory(Class,
                          BaseClass,
                          ClassSize);

            /* update some pointers and link the class */
            Class->Desktop = Desktop;
            Class->Windows = 0;

            if (BaseClass->Desktop == NULL)
            {
                /* we don't really need the base class on the shared
                   heap anymore, delete it so the only class left is
                   the clone we just created, which now serves as the
                   new base class */
                ASSERT(BaseClass->Clone == NULL);
                ASSERT(Class->Clone == NULL);
                Class->Base = Class;
                Class->Next = BaseClass->Next;

                if (!BaseClass->System && BaseClass->CallProc != NULL)
                    Class->GlobalCallProc = TRUE;
                if (BaseClass->CallProc2 != NULL)
                    Class->GlobalCallProc2 = TRUE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -