class.c

来自「一个类似windows」· C语言 代码 · 共 2,236 行 · 第 1/5 页

C
2,236
字号
                RtlCopyMemory(Class->MenuName,
                              MenuName->Buffer,
                              MenuName->Length);

                strBuf += (MenuName->Length / sizeof(WCHAR)) + 1;
            }
            else
                Class->MenuName = MenuName->Buffer;

            /* save an ansi copy of the string */
            strBufA = (PSTR)strBuf;
            if (MenuName->Length != 0)
            {
                Class->AnsiMenuName = strBufA;
                AnsiString.MaximumLength = RtlUnicodeStringToAnsiSize(MenuName);
                AnsiString.Buffer = strBufA;
                Status = RtlUnicodeStringToAnsiString(&AnsiString,
                                                      MenuName,
                                                      FALSE);
                if (!NT_SUCCESS(Status))
                {
                    DPRINT1("Failed to convert unicode menu name to ansi!\n");

                    /* life would've been much prettier if ntoskrnl exported RtlRaiseStatus()... */
                    _SEH_LEAVE;
                }

                strBufA += AnsiString.Length + 1;
            }
            else
                Class->AnsiMenuName = (PSTR)MenuName->Buffer;

            /* calculate the offset of the extra data */
            Class->ClassExtraDataOffset = (ULONG_PTR)strBufA - (ULONG_PTR)Class;

            if (!(dwFlags & REGISTERCLASS_ANSI))
                Class->Unicode = TRUE;

            if (Class->Style & CS_GLOBALCLASS)
                Class->Global = TRUE;
        }
        _SEH_HANDLE
        {
            Status = _SEH_GetExceptionCode();
        }
        _SEH_END;

        if (!NT_SUCCESS(Status))
        {
            DPRINT1("Failed creating the class: 0x%x\n", Status);

            SetLastNtError(Status);

            DesktopHeapFree(Desktop,
                            Class);
            Class = NULL;

            IntDeregisterClassAtom(Atom);
        }
    }
    else
    {
        DPRINT1("Failed to allocate class on Desktop 0x%p\n", Desktop);

        IntDeregisterClassAtom(Atom);

        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
    }

    return Class;
}

static PWINDOWCLASS
IntFindClass(IN RTL_ATOM Atom,
             IN HINSTANCE hInstance,
             IN PWINDOWCLASS *ClassList,
             OUT PWINDOWCLASS **Link  OPTIONAL)
{
    PWINDOWCLASS Class, *PrevLink = ClassList;

    Class = *PrevLink;
    while (Class != NULL)
    {
        if (Class->Atom == Atom &&
            (hInstance == NULL || Class->hInstance == hInstance) &&
            !Class->Destroying)
        {
            ASSERT(Class->Base == Class);

            if (Link != NULL)
                *Link = PrevLink;
            break;
        }

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

    return Class;
}

BOOL
IntGetAtomFromStringOrAtom(IN PUNICODE_STRING ClassName,
                           OUT RTL_ATOM *Atom)
{
    BOOL Ret = FALSE;

    if (ClassName->Length != 0)
    {
        WCHAR szBuf[65];
        PWSTR AtomName;
        NTSTATUS Status;

        /* NOTE: Caller has to protect the call with SEH! */

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

            /* We need to make a local copy of the class name! The caller could
               modify the buffer and we could overflow in RtlLookupAtomInAtomTable.
               We're protected by SEH, but the ranges that might be accessed were
               not probed... */
            RtlCopyMemory(szBuf,
                          ClassName->Buffer,
                          ClassName->Length);
            szBuf[ClassName->Length / sizeof(WCHAR)] = UNICODE_NULL;
            AtomName = szBuf;
        }
        else
            AtomName = ClassName->Buffer;

        /* lookup the atom */
        Status = RtlLookupAtomInAtomTable(gAtomTable,
                                          AtomName,
                                          Atom);
        if (NT_SUCCESS(Status))
        {
            Ret = TRUE;
        }
        else
        {
            if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
            {
                SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS);
            }
            else
            {
                SetLastNtError(Status);
            }
        }
    }
    else
    {
        ASSERT(IS_ATOM(ClassName->Buffer));
        *Atom = (RTL_ATOM)((ULONG_PTR)ClassName->Buffer);
        Ret = TRUE;
    }

    return Ret;
}

RTL_ATOM
IntGetClassAtom(IN PUNICODE_STRING ClassName,
                IN HINSTANCE hInstance  OPTIONAL,
                IN PW32PROCESSINFO pi  OPTIONAL,
                OUT PWINDOWCLASS *BaseClass  OPTIONAL,
                OUT PWINDOWCLASS **Link  OPTIONAL)
{
    RTL_ATOM Atom = (RTL_ATOM)0;

    if (IntGetAtomFromStringOrAtom(ClassName,
                                   &Atom) &&
        BaseClass != NULL && Atom != (RTL_ATOM)0)
    {
        PWINDOWCLASS Class;

        /* attempt to locate the class object */

        ASSERT(pi != NULL);

        /* Step 1: try to find an exact match of locally registered classes */
        Class = IntFindClass(Atom,
                             hInstance,
                             &pi->LocalClassList,
                             Link);
        if (Class != NULL)
        {
            goto FoundClass;
        }

        /* Step 2: try to find any globally registered class. The hInstance
                   is not relevant for global classes */
        Class = IntFindClass(Atom,
                             NULL,
                             &pi->GlobalClassList,
                             Link);
        if (Class != NULL)
        {
            goto FoundClass;
        }

        /* Step 3: try to find a system class */
        Class = IntFindClass(Atom,
                             NULL,
                             &pi->SystemClassList,
                             Link);

        if (Class == NULL)
        {
            SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
            return (RTL_ATOM)0;
        }

FoundClass:
        *BaseClass = Class;
    }

    return Atom;
}

RTL_ATOM
UserRegisterClass(IN CONST WNDCLASSEXW* lpwcx,
                  IN PUNICODE_STRING ClassName,
                  IN PUNICODE_STRING MenuName,
                  IN HANDLE hMenu, /* FIXME */
                  IN WNDPROC wpExtra,
                  IN DWORD dwFlags)
{
    PW32THREADINFO ti;
    PW32PROCESSINFO pi;
    PWINDOWCLASS Class;
    RTL_ATOM ClassAtom;
    RTL_ATOM Ret = (RTL_ATOM)0;

    /* NOTE: Accessing the buffers in ClassName and MenuName may raise exceptions! */

    ti = GetW32ThreadInfo();
    if (ti == NULL)
    {
        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
        return (RTL_ATOM)0;
    }

    pi = ti->kpi;

    /* try to find a previously registered class */
    ClassAtom = IntGetClassAtom(ClassName,
                                NULL,
                                NULL,
                                NULL,
                                NULL);
    if (ClassAtom != (RTL_ATOM)0)
    {
        Class = IntFindClass(ClassAtom,
                             lpwcx->hInstance,
                             &pi->LocalClassList,
                             NULL);
        if (Class != NULL)
        {
            goto ClassAlreadyExists;
        }

        /* if CS_GLOBALCLASS is set, try to find a previously registered global class.
           Re-registering system classes as global classes seems to be allowed,
           so we don't fail */
        if (lpwcx->style & CS_GLOBALCLASS)
        {
            Class = IntFindClass(ClassAtom,
                                 NULL,
                                 ((dwFlags & REGISTERCLASS_SYSTEM) ?
                                     &pi->SystemClassList : &pi->GlobalClassList),
                                 NULL);
            if (Class != NULL)
            {
ClassAlreadyExists:
                DPRINT1("Class 0x%p does already exist!\n", ClassAtom);
                SetLastWin32Error(ERROR_CLASS_ALREADY_EXISTS);
                return (RTL_ATOM)0;
            }
        }
    }

    Class = IntCreateClass(lpwcx,
                           ClassName,
                           MenuName,
                           wpExtra,
                           dwFlags,
                           ti->Desktop,
                           pi);

    if (Class != NULL)
    {
        PWINDOWCLASS *List;

        /* FIXME - pass the PMENU pointer to IntCreateClass instead! */
        Class->hMenu = hMenu;

        /* Register the class */
        if (Class->System)
            List = &pi->SystemClassList;
        else if (Class->Global)
            List = &pi->GlobalClassList;
        else
            List = &pi->LocalClassList;

        Class->Next = *List;
        (void)InterlockedExchangePointer(List,
                                         Class);

        Ret = Class->Atom;
    }

    return Ret;
}

BOOL
UserUnregisterClass(IN PUNICODE_STRING ClassName,
                    IN HINSTANCE hInstance)
{
    PWINDOWCLASS *Link;
    PW32PROCESSINFO pi;
    RTL_ATOM ClassAtom;
    PWINDOWCLASS Class;

    pi = GetW32ProcessInfo();
    if (pi == NULL)
    {
        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
        return FALSE;
    }

    /* NOTE: Accessing the buffer in ClassName may raise an exception! */
    ClassAtom = IntGetClassAtom(ClassName,
                                hInstance,
                                pi,
                                &Class,
                                &Link);
    if (ClassAtom == (RTL_ATOM)0)
    {
        return FALSE;
    }

    ASSERT(Class != NULL);

    if (Class->System)
    {
        DPRINT1("Attempted to unregister system class 0x%p!\n", ClassAtom);
        SetLastWin32Error(ERROR_ACCESS_DENIED);
        return FALSE;
    }

    if (Class->Windows != 0 ||
        Class->Clone != NULL)
    {
        SetLastWin32Error(ERROR_CLASS_HAS_WINDOWS);
        return FALSE;
    }

    /* must be a base class! */
    ASSERT(Class->Base == Class);

    /* unlink the class */
    *Link = Class->Next;

    IntDeregisterClassAtom(Class->Atom);

    /* finally free the resources */
    IntDestroyClass(Class);
    return TRUE;
}

INT
UserGetClassName(IN PWINDOWCLASS Class,
                 IN OUT PUNICODE_STRING ClassName,
                 IN BOOL Ansi)
{
    NTSTATUS Status = STATUS_SUCCESS;
    WCHAR szStaticTemp[32];
    PWSTR szTemp = NULL;
    ULONG BufLen = sizeof(szStaticTemp);
    INT Ret = 0;

    /* Note: Accessing the buffer in ClassName may raise an exception! */

    _SEH_TRY
    {
        if (Ansi)
        {
            PANSI_STRING AnsiClassName = (PANSI_STRING)ClassName;
            UNICODE_STRING UnicodeClassName;

            /* limit the size of the static buffer on the stack to the
               size of the buffer provided by the caller */
            if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
            {
                BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
            }

            /* find out how big the buffer needs to be */
            Status = RtlQueryAtomInAtomTable(gAtomTable,
                                             Class->Atom,
                                             NULL,
                                             NULL,
                                             szStaticTemp,
                                             &BufLen);
            if (Status == STATUS_BUFFER_TOO_SMALL)
            {
                if (BufLen / sizeof(WCHAR) > AnsiClassName->MaximumLength)
                {
                    /* the buffer required exceeds the ansi buffer provided,
                       pretend like we're using the ansi buffer and limit the
                       size to the buffer size provided */
                    BufLen = AnsiClassName->MaximumLength * sizeof(WCHAR);
                }

                /* allocate a temporary buffer that can hold the unicode class name */
                szTemp = ExAllocatePool(PagedPool,
                                        BufLen);
                if (szTemp == NULL)
                {
                    SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
                    _SEH_LEAVE;
                }

                /* query the class name */
                Status = RtlQueryAtomInAtomTable(gAtomTable,
                                                 Class->Atom,
                                                 NULL,
                                                 NULL,
                                                 szTemp,
                                                 &BufLen);
            }
            else
                szTemp = szStaticTemp;

            if (NT_SUCCESS(Status))
            {
                /* convert the atom name to ansi */

                RtlInitUnicodeString(&UnicodeClassName,
                                     szTemp);

⌨️ 快捷键说明

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