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

📄 class.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
                /* replace the base class */
                (void)InterlockedExchangePointer(ClassLink,
                                                 Class);

                /* destroy the obsolete copy on the shared heap */
                BaseClass->Base = NULL;
                BaseClass->Clone = NULL;
                IntDestroyClass(BaseClass);
            }
            else
            {
                /* link in the clone */
                Class->Clone = NULL;
                Class->Base = BaseClass;
                Class->Next = BaseClass->Clone;
                (void)InterlockedExchangePointer(&BaseClass->Clone,
                                                 Class);
            }
        }
        else
        {
            SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
        }
    }

    return Class;
}

PWINDOWCLASS
IntReferenceClass(IN OUT PWINDOWCLASS BaseClass,
                  IN OUT PWINDOWCLASS *ClassLink,
                  IN PDESKTOP Desktop)
{
    PWINDOWCLASS Class;

    ASSERT(BaseClass->Base == BaseClass);

    Class = IntGetClassForDesktop(BaseClass,
                                  ClassLink,
                                  Desktop);
    if (Class != NULL)
    {
        Class->Windows++;
    }

    return Class;
}

static VOID
IntMakeCloneBaseClass(IN OUT PWINDOWCLASS Class,
                      IN OUT PWINDOWCLASS *BaseClassLink,
                      IN OUT PWINDOWCLASS *CloneLink)
{
    PWINDOWCLASS Clone, BaseClass;
    PCALLPROC CallProc;

    ASSERT(Class->Base != Class);
    ASSERT(Class->Base->Clone != NULL);
    ASSERT(Class->Desktop != NULL);
    ASSERT(Class->Windows != 0);
    ASSERT(Class->Base->Desktop != NULL);
    ASSERT(Class->Base->Windows == 0);

    /* unlink the clone */
    *CloneLink = Class->Next;
    Class->Clone = Class->Base->Clone;

    BaseClass = Class->Base;

    if (!BaseClass->System && BaseClass->CallProc != NULL &&
        !BaseClass->GlobalCallProc)
    {
        /* we need to move the allocated call procedure */
        CallProc = BaseClass->CallProc;
        Class->CallProc = CloneCallProc(Class->Desktop,
                                        CallProc);
        DestroyCallProc(BaseClass->Desktop,
                        CallProc);
    }

    if (BaseClass->CallProc2 != NULL &&
        !BaseClass->GlobalCallProc2)
    {
        /* we need to move the allocated call procedure */
        CallProc = BaseClass->CallProc2;
        Class->CallProc2 = CloneCallProc(Class->Desktop,
                                         CallProc);
        DestroyCallProc(BaseClass->Desktop,
                        CallProc);
    }

    /* update the class information to make it a base class */
    Class->Base = Class;
    Class->Next = (*BaseClassLink)->Next;

    /* update all clones */
    Clone = Class->Clone;
    while (Clone != NULL)
    {
        ASSERT(Clone->Clone == NULL);
        Clone->Base = Class;

        if (!Class->System)
            Clone->CallProc = Class->CallProc;
        Clone->CallProc2 = Class->CallProc2;

        Clone = Clone->Next;
    }

    /* link in the new base class */
    (void)InterlockedExchangePointer(BaseClassLink,
                                     Class);
}

VOID
IntDereferenceClass(IN OUT PWINDOWCLASS Class,
                    IN PDESKTOP Desktop,
                    IN PW32PROCESSINFO pi)
{
    PWINDOWCLASS *PrevLink, BaseClass, CurrentClass;

    BaseClass = Class->Base;

    if (--Class->Windows == 0)
    {
        if (BaseClass == Class)
        {
            ASSERT(Class->Base == Class);

            /* check if there are clones of the class on other desktops,
               link the first clone in if possible. If there are no clones
               then leave the class on the desktop heap. It will get moved
               to the shared heap when the thread detaches. */
            if (BaseClass->Clone != NULL)
            {
                if (BaseClass->System)
                    PrevLink = &pi->SystemClassList;
                else if (BaseClass->Global)
                    PrevLink = &pi->GlobalClassList;
                else
                    PrevLink = &pi->LocalClassList;

                while (*PrevLink != BaseClass)
                {
                    ASSERT(*PrevLink != NULL);
                    PrevLink = &BaseClass->Next;
                }

                ASSERT(*PrevLink == BaseClass);

                /* make the first clone become the new base class */
                IntMakeCloneBaseClass(BaseClass->Clone,
                                      PrevLink,
                                      &BaseClass->Clone);

                /* destroy the class, there's still another clone of the class
                   that now serves as a base class. Make sure we don't destruct
                   resources shared by all classes (Base = NULL)! */
                BaseClass->Base = NULL;
                BaseClass->Clone = NULL;
                IntDestroyClass(BaseClass);
            }
        }
        else
        {
            /* locate the cloned class and unlink it */
            PrevLink = &BaseClass->Clone;
            CurrentClass = BaseClass->Clone;
            while (CurrentClass != Class)
            {
                ASSERT(CurrentClass != NULL);

                PrevLink = &CurrentClass->Next;
                CurrentClass = CurrentClass->Next;
            }

            ASSERT(CurrentClass == Class);

            (void)InterlockedExchangePointer(PrevLink,
                                             Class->Next);

            ASSERT(Class->Base == BaseClass);
            ASSERT(Class->Clone == NULL);

            /* the class was just a clone, we don't need it anymore */
            IntDestroyClass(Class);
        }
    }
}

static BOOL
IntMoveClassToSharedHeap(IN OUT PWINDOWCLASS Class,
                         IN OUT PWINDOWCLASS **ClassLinkPtr)
{
    PWINDOWCLASS NewClass;
    PCALLPROC CallProc;
    SIZE_T ClassSize;

    ASSERT(Class->Base == Class);
    ASSERT(Class->Desktop != NULL);
    ASSERT(Class->Windows == 0);
    ASSERT(Class->Clone == NULL);

    ClassSize = sizeof(*Class) + (SIZE_T)Class->ClsExtra;

    /* allocate the new base class on the shared heap */
    NewClass = UserHeapAlloc(ClassSize);
    if (NewClass != NULL)
    {
        RtlCopyMemory(NewClass,
                      Class,
                      ClassSize);

        NewClass->Desktop = NULL;
        NewClass->Base = NewClass;

        if (!NewClass->System && NewClass->CallProc != NULL &&
            !NewClass->GlobalCallProc)
        {
            /* we need to move the allocated call procedure to the shared heap */
            CallProc = NewClass->CallProc;
            NewClass->CallProc = CloneCallProc(NULL,
                                               CallProc);
            DestroyCallProc(Class->Desktop,
                            CallProc);

            NewClass->GlobalCallProc = TRUE;
        }

        if (NewClass->CallProc2 != NULL &&
            !NewClass->GlobalCallProc2)
        {
            /* we need to move the allocated call procedure to the shared heap */
            CallProc = NewClass->CallProc2;
            NewClass->CallProc2 = CloneCallProc(NULL,
                                                CallProc);
            DestroyCallProc(Class->Desktop,
                            CallProc);

            NewClass->GlobalCallProc2 = TRUE;
        }

        /* replace the class in the list */
        (void)InterlockedExchangePointer(*ClassLinkPtr,
                                         NewClass);
        *ClassLinkPtr = &NewClass->Next;

        /* free the obsolete class on the desktop heap */
        Class->Base = NULL;
        IntDestroyClass(Class);
        return TRUE;
    }

    return FALSE;
}

static VOID
IntCheckDesktopClasses(IN PDESKTOP Desktop,
                       IN OUT PWINDOWCLASS *ClassList,
                       IN BOOL FreeOnFailure,
                       OUT BOOL *Ret)
{
    PWINDOWCLASS Class, NextClass, *Link;

    /* NOTE: We only need to check base classes! When classes are no longer needed
             on a desktop, the clones will be freed automatically as soon as possible.
             However, we need to move base classes to the shared heap, as soon as
             the last desktop heap where a class is allocated on is about to be destroyed.
             If we didn't move the class to the shared heap, the class would become
             inaccessible! */

    ASSERT(Desktop != NULL);

    Link = ClassList;
    Class = *Link;
    while (Class != NULL)
    {
        NextClass = Class->Next;

        ASSERT(Class->Base == Class);

        if (Class->Desktop == Desktop &&
            Class->Windows == 0)
        {
            /* there shouldn't be any clones around anymore! */
            ASSERT(Class->Clone == NULL);

            /* FIXME - If process is terminating, don't move the class but rather destroy it! */
            /* FIXME - We could move the class to another desktop heap if there's still desktops
                       mapped into the process... */

            /* move the class to the shared heap */
            if (IntMoveClassToSharedHeap(Class,
                                         &Link))
            {
                ASSERT(*Link == NextClass);
            }
            else
            {
                ASSERT(NextClass == Class->Next);

                if (FreeOnFailure)
                {
                    /* unlink the base class */
                    (void)InterlockedExchangePointer(Link,
                                                     Class->Next);

                    /* we can free the old base class now */
                    Class->Base = NULL;
                    IntDestroyClass(Class);
                }
                else
                {
                    Link = &Class->Next;
                    *Ret = FALSE;
                }
            }
        }
        else
            Link = &Class->Next;

        Class = NextClass;
    }
}

BOOL
IntCheckProcessDesktopClasses(IN PDESKTOP Desktop,
                              IN BOOL FreeOnFailure)
{
    PW32PROCESSINFO pi;
    BOOL Ret = TRUE;

    pi = GetW32ProcessInfo();
    if (pi == NULL)
        return TRUE;

    /* check all local classes */
    IntCheckDesktopClasses(Desktop,
                           &pi->LocalClassList,
                           FreeOnFailure,
                           &Ret);

    /* check all global classes */
    IntCheckDesktopClasses(Desktop,
                           &pi->GlobalClassList,
                           FreeOnFailure,
                           &Ret);

    /* check all system classes */
    IntCheckDesktopClasses(Desktop,
                           &pi->SystemClassList,
                           FreeOnFailure,
                           &Ret);

    if (!Ret)
    {
        DPRINT1("Failed to move process classes from desktop 0x%p to the shared heap!\n", Desktop);
        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
    }

    return Ret;
}

static PWINDOWCLASS
IntCreateClass(IN CONST WNDCLASSEXW* lpwcx,
               IN PUNICODE_STRING ClassName,
               IN PUNICODE_STRING MenuName,
               IN WNDPROC wpExtra,
               IN DWORD dwFlags,
               IN PDESKTOP Desktop,
               IN PW32PROCESSINFO pi)
{
    SIZE_T ClassSize;
    PWINDOWCLASS Class = NULL;
    RTL_ATOM Atom;
    PWSTR pszMenuName = NULL;
    NTSTATUS Status = STATUS_SUCCESS;

    TRACE("lpwcx=%p ClassName=%wZ MenuName=%wZ wpExtra=%p dwFlags=%08x Desktop=%p pi=%p\n",
        lpwcx, ClassName, MenuName, wpExtra, dwFlags, Desktop, pi);

    if (!IntRegisterClassAtom(ClassName,
                              &Atom))
    {
        DPRINT1("Failed to register class atom!\n");
        return NULL;
    }

    ClassSize = sizeof(*Class) + lpwcx->cbClsExtra;
    if (MenuName->Length != 0)
    {
        pszMenuName = UserHeapAlloc(MenuName->Length + sizeof(UNICODE_NULL) +
                                    RtlUnicodeStringToAnsiSize(MenuName));
        if (pszMenuName == NULL)
            goto NoMem;
    }

    if (Desktop != NULL)
    {
        Class = DesktopHeapAlloc(Desktop,
                                 ClassSize);
    }
    else
    {
        /* FIXME - the class was created before being connected
                   to a desktop. It is possible for the desktop window,
                   but should it be allowed for any other case? */
        Class = UserHeapAlloc(ClassSize);
    }

    if (Class != NULL)
    {
        RtlZeroMemory(Class,
                      ClassSize);

        Class->Desktop = Desktop;
        Class->Base = Class;
        Class->Atom = Atom;

        if (dwFlags & REGISTERCLASS_SYSTEM)
        {
            dwFlags &= ~REGISTERCLASS_ANSI;
            Class->WndProcExtra = wpExtra;
            Class->System = TRUE;
        }

        _SEH_TRY
        {
            PWSTR pszMenuNameBuffer = pszMenuName;

            /* need to protect with SEH since accessing the WNDCLASSEX structure
               and string buffers might raise an exception! We don't want to
               leak memory... */
            Class->WndProc = lpwcx->lpfnWndProc;
            Class->Style = lpwcx->style;
            Class->ClsExtra = lpwcx->cbClsExtra;
            Class->WndExtra = lpwcx->cbWndExtra;
            Class->hInstance = lpwcx->hInstance;
            Class->hIcon = lpwcx->hIcon; /* FIXME */
            Class->hIconSm = lpwcx->hIconSm; /* FIXME */
            Class->hCursor = lpwcx->hCursor; /* FIXME */
            Class->hbrBackground = lpwcx->hbrBackground;

⌨️ 快捷键说明

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