예제 #1
0
NTSTATUS
NTAPI
VTUTF8ChannelOWrite(IN PSAC_CHANNEL Channel,
                    IN PCHAR String,
                    IN ULONG Length)
{
    NTSTATUS Status;
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(String);

    /* Call the lower level function */
    Status = VTUTF8ChannelOWrite2(Channel, (PWCHAR)String, Length / sizeof(WCHAR));
    if (NT_SUCCESS(Status))
    {
        /* Is the channel enabled for output? */
        if ((ConMgrIsWriteEnabled(Channel)) && (Channel->WriteEnabled))
        {
            /* Go ahead and output it */
            Status = VTUTF8ChannelOEcho(Channel, String, Length);
        }
        else
        {
            /* Otherwise, just remember that we have new data */
            _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 1);
        }
    }

    /* We're done */
    return Status;
}
예제 #2
0
NTSTATUS
NTAPI
VTUTF8ChannelIRead(IN PSAC_CHANNEL Channel,
                   IN PCHAR Buffer,
                   IN ULONG BufferSize,
                   IN PULONG ReturnBufferSize)
{
    ULONG CopyChars, ReadLength;
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(Buffer);
    CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE);

    /* Assume failure */
    *ReturnBufferSize = 0;

    /* Check how many bytes are in the buffer */
    if (Channel->ChannelInputBufferLength(Channel) == 0)
    {
        /* Apparently nothing. Make sure the flag indicates so too */
        ASSERT(ChannelHasNewIBufferData(Channel) == FALSE);
    }
    else
    {
        /* Use the smallest number of bytes either in the buffer or requested */
        ReadLength = min(Channel->ChannelInputBufferLength(Channel) * sizeof(WCHAR),
                         BufferSize);

        /* Do some cheezy buffer alignment */
        CopyChars = ReadLength / sizeof(WCHAR);
        ReadLength = CopyChars * sizeof(WCHAR);
        ASSERT(CopyChars <= Channel->ChannelInputBufferLength(Channel));

        /* Copy them into the caller's buffer */
        RtlCopyMemory(Buffer, Channel->IBuffer, ReadLength);

        /* Update the channel's index past the copied (read) bytes */
        VTUTF8ChannelSetIBufferIndex(Channel,
            VTUTF8ChannelGetIBufferIndex(Channel) - ReadLength);

        /* Are there still bytes that haven't been read yet? */
        if (Channel->ChannelInputBufferLength(Channel))
        {
            /* Shift them up in the buffer */
            RtlMoveMemory(Channel->IBuffer,
                          &Channel->IBuffer[ReadLength],
                          Channel->ChannelInputBufferLength(Channel) *
                          sizeof(WCHAR));
        }

        /* Return the number of bytes we actually copied */
        *ReturnBufferSize = ReadLength;
    }

    /* Return success */
    return STATUS_SUCCESS;
}
예제 #3
0
파일: rawchan.c 프로젝트: GYGit/reactos
NTSTATUS
NTAPI
RawChannelORead(IN PSAC_CHANNEL Channel,
                IN PCHAR Buffer,
                IN ULONG BufferSize,
                OUT PULONG ByteCount)
{
    NTSTATUS Status;
    ULONG NextIndex;

    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(Buffer);
    CHECK_PARAMETER3(BufferSize > 0);
    CHECK_PARAMETER4(ByteCount);

    *ByteCount = 0;

    if (ChannelHasNewOBufferData(Channel))
    {
        Status = STATUS_SUCCESS;

        while (TRUE)
        {
            Buffer[(*ByteCount)++] = Channel->OBuffer[Channel->OBufferFirstGoodIndex];

            NextIndex = (Channel->OBufferFirstGoodIndex + 1) & (SAC_OBUFFER_SIZE - 1);
            Channel->OBufferFirstGoodIndex = NextIndex;

            if (NextIndex == Channel->OBufferIndex)
            {
                _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 0);
                break;
            }

            ASSERT(*ByteCount > 0);

            if (*ByteCount >= BufferSize) break;
        }
    }
    else
    {
        Status = STATUS_NO_DATA_DETECTED;
    }

    if (Channel->OBufferFirstGoodIndex == Channel->OBufferIndex)
    {
        ASSERT(ChannelHasNewOBufferData(Channel) == FALSE);
    }

    if (ChannelHasNewOBufferData(Channel) == FALSE)
    {
        ASSERT(Channel->OBufferFirstGoodIndex == Channel->OBufferIndex);
    }

    return Status;
}
예제 #4
0
파일: channel.c 프로젝트: GYGit/reactos
NTSTATUS
NTAPI
ChannelHasRedrawEvent(IN PSAC_CHANNEL Channel,
                      OUT PBOOLEAN Present)
{
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(Present);

    /* Return if the flag is set */
    *Present = Channel->Flags & SAC_CHANNEL_FLAG_REDRAW_EVENT;
    return STATUS_SUCCESS;
}
예제 #5
0
파일: rawchan.c 프로젝트: GYGit/reactos
NTSTATUS
NTAPI
RawChannelIBufferIsFull(IN PSAC_CHANNEL Channel,
                        OUT PBOOLEAN BufferStatus)
{
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(BufferStatus);

    /* If the index is beyond the length, the buffer must be full */
    *BufferStatus = RawChannelGetIBufferIndex(Channel) > SAC_RAW_IBUFFER_SIZE;
    return STATUS_SUCCESS;
}
예제 #6
0
NTSTATUS
NTAPI
VTUTF8ChannelIWrite(IN PSAC_CHANNEL Channel,
                    IN PCHAR Buffer,
                    IN ULONG BufferSize)
{
    NTSTATUS Status;
    BOOLEAN IsFull;
    ULONG Index, i;
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(Buffer);
    CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE);

    /* First, check if the input buffer still has space */
    Status = VTUTF8ChannelIBufferIsFull(Channel, &IsFull);
    if (!NT_SUCCESS(Status)) return Status;
    if (IsFull) return STATUS_UNSUCCESSFUL;

    /* Get the current buffer index */
    Index = VTUTF8ChannelGetIBufferIndex(Channel);
    if ((SAC_VTUTF8_IBUFFER_SIZE - Index) < BufferSize)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    /* Copy the new data */
    for (i = 0; i < BufferSize; i++)
    {
        /* Convert the character */
        if (SacTranslateUtf8ToUnicode(Buffer[i],
                                      IncomingUtf8ConversionBuffer,
                                      &IncomingUnicodeValue))
        {
            /* Write it into the buffer */
            *(PWCHAR)&Channel->IBuffer[VTUTF8ChannelGetIBufferIndex(Channel)] =
                IncomingUnicodeValue;

            /* Update the index */
            Index = VTUTF8ChannelGetIBufferIndex(Channel);
            VTUTF8ChannelSetIBufferIndex(Channel, Index + sizeof(WCHAR));
        }
    }

    /* Signal the event, if one was set */
    if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT)
    {
        ChannelSetEvent(Channel, HasNewDataEvent);
    }

    /* All done */
    return STATUS_SUCCESS;
}
예제 #7
0
파일: rawchan.c 프로젝트: GYGit/reactos
NTSTATUS
NTAPI
RawChannelOWrite(IN PSAC_CHANNEL Channel,
                 IN PCHAR String,
                 IN ULONG Length)
{
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(String);

    if ((ConMgrIsWriteEnabled(Channel)) && (Channel->WriteEnabled))
    {
        return RawChannelOEcho(Channel, String, Length);
    }

    return RawChannelOWrite2(Channel, String, Length);
}
예제 #8
0
파일: rawchan.c 프로젝트: GYGit/reactos
NTSTATUS
NTAPI
RawChannelOEcho(IN PSAC_CHANNEL Channel,
                IN PCHAR String,
                IN ULONG Length)
{
    NTSTATUS Status = STATUS_SUCCESS;

    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(String);

    if (Length)
    {
        Status = ConMgrWriteData(Channel, String, Length);
        if (NT_SUCCESS(Status)) ConMgrFlushData(Channel);
    }

    return Status;
}
예제 #9
0
파일: channel.c 프로젝트: GYGit/reactos
NTSTATUS
NTAPI
ChannelSetDescription(IN PSAC_CHANNEL Channel,
                      IN PWCHAR Description)
{
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(Description);

    /* Lock the attributes while we copy the name */
    ChannelLockAttributes(Channel);

    /* Copy the name and null-terminate it */
    ASSERT(((wcslen(Description) + 1) * sizeof(WCHAR)) <= ((SAC_CHANNEL_NAME_SIZE + 1) * sizeof(WCHAR)));
    wcsncpy(Channel->DescriptionBuffer, Description, RTL_NUMBER_OF(Channel->DescriptionBuffer)); // bug
    Channel->DescriptionBuffer[SAC_CHANNEL_DESCRIPTION_SIZE] = UNICODE_NULL;

    /* Release the lock and return */
    ChannelUnlockAttributes(Channel);
    return STATUS_SUCCESS;
}
예제 #10
0
파일: rawchan.c 프로젝트: GYGit/reactos
NTSTATUS
NTAPI
RawChannelIWrite(IN PSAC_CHANNEL Channel,
                 IN PCHAR Buffer,
                 IN ULONG BufferSize)
{
    NTSTATUS Status;
    BOOLEAN IsFull;
    ULONG Index;
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(Buffer);
    CHECK_PARAMETER_WITH_STATUS(BufferSize > 0, STATUS_INVALID_BUFFER_SIZE);

    /* First, check if the input buffer still has space */
    Status = RawChannelIBufferIsFull(Channel, &IsFull);
    if (!NT_SUCCESS(Status)) return Status;
    if (IsFull) return STATUS_UNSUCCESSFUL;

    /* Get the current buffer index */
    Index = RawChannelGetIBufferIndex(Channel);
    if ((SAC_RAW_IBUFFER_SIZE - Index) < BufferSize)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    /* Copy the new data */
    RtlCopyMemory(&Channel->IBuffer[Index], Buffer, BufferSize);

    /* Update the index */
    RawChannelSetIBufferIndex(Channel, BufferSize + Index);

    /* Signal the event, if one was set */
    if (Channel->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT)
    {
        ChannelSetEvent(Channel, HasNewDataEvent);
    }

    /* All done */
    return STATUS_SUCCESS;
}
예제 #11
0
파일: channel.c 프로젝트: GYGit/reactos
NTSTATUS
NTAPI
ChannelGetDescription(IN PSAC_CHANNEL Channel,
                      IN PWCHAR* Description)
{
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(Description);

    /* Allocate space to hold the description */
    *Description = SacAllocatePool(sizeof(Channel->DescriptionBuffer), GLOBAL_BLOCK_TAG);
    CHECK_ALLOCATION(*Description);

    /* Lock the attributes while we copy the name */
    ChannelLockAttributes(Channel);

    /* Copy the name and null-terminate it */
    ASSERT(((wcslen(Channel->DescriptionBuffer) + 1) * sizeof(WCHAR)) <= ((SAC_CHANNEL_DESCRIPTION_SIZE + 1) * sizeof(WCHAR)));
    wcsncpy(*Description, Channel->DescriptionBuffer, RTL_NUMBER_OF(Channel->DescriptionBuffer)); // bug
    (*Description)[SAC_CHANNEL_DESCRIPTION_SIZE] = UNICODE_NULL;

    /* Release the lock and return */
    ChannelUnlockAttributes(Channel);
    return STATUS_SUCCESS;
}
예제 #12
0
파일: rawchan.c 프로젝트: GYGit/reactos
NTSTATUS
NTAPI
RawChannelOWrite2(IN PSAC_CHANNEL Channel,
                  IN PCHAR String,
                  IN ULONG Size)
{
    BOOLEAN Overflow;
    ULONG i, NextIndex;

    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(String);

    Overflow = FALSE;

    for (i = 0; i < Size; i++)
    {
        if ((Channel->OBufferIndex == Channel->OBufferFirstGoodIndex) &&
            ((i) || (ChannelHasNewOBufferData(Channel))))
        {
            Overflow = TRUE;
        }

        ASSERT(Channel->OBufferIndex < SAC_RAW_OBUFFER_SIZE);

        Channel->OBuffer[Channel->OBufferIndex] = String[i];

        NextIndex = (Channel->OBufferIndex + 1) & (SAC_RAW_OBUFFER_SIZE - 1);
        Channel->OBufferIndex = NextIndex;

        if (Overflow) Channel->OBufferFirstGoodIndex = NextIndex;
    }

    _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 1);

    return STATUS_SUCCESS;
}
예제 #13
0
NTSTATUS
NTAPI
VTUTF8ChannelOWrite2(IN PSAC_CHANNEL Channel,
                     IN PWCHAR String,
                     IN ULONG Size)
{
    PSAC_VTUTF8_SCREEN Screen;
    ULONG i, EscapeSize, R, C;
    PWSTR pwch;
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(String);
    VTUTF8ChannelAssertCursor(Channel);

    /* Loop every character */
    Screen = (PSAC_VTUTF8_SCREEN)Channel->OBuffer;
    for (i = 0; i < Size; i++)
    {
        /* Check what the character is */
        pwch = &String[i];
        switch (*pwch)
        {
            /* It's an escape sequence... */
            case L'\x1B':

                /* Send it to the parser, see how long the sequence was */
                EscapeSize = VTUTF8ChannelConsumeEscapeSequence(Channel, pwch);
                if (EscapeSize)
                {
                    /* Consume that many characters for next time*/
                    i += EscapeSize - 1;
                }
                else
                {
                    /* Invalid escape sequence, skip just the ESC character */
                    i++;
                }

                /* Keep going*/
                break;

            /* It's a line feed */
            case L'\n':

                /* Simply reset the column to zero on the current line */
                Channel->CursorCol = 0;
                break;

            /* It's a carriage feed */
            case L'\r':

                /* Move to the next row */
                Channel->CursorRow++;

                /* Check if we hit the last row on the screen */
                if (Channel->CursorRow >= SAC_VTUTF8_ROW_HEIGHT)
                {
                    /* Go over every row before the last one */
                    for (R = 0; R < (SAC_VTUTF8_ROW_HEIGHT - 1); R++)
                    {
                        /* Sanity check, since we always copy one row below */
                        ASSERT((R + 1) < SAC_VTUTF8_ROW_HEIGHT);

                        /* Loop every character on the row */
                        for (C = 0; C < SAC_VTUTF8_COL_WIDTH; C++)
                        {
                            /* And replace it with one from the row below */
                            Screen->Cell[R][C] = Screen->Cell[R + 1][C];
                        }
                    }

                    /* Now we're left with the before-last row, zero it out */
                    ASSERT(R == (SAC_VTUTF8_ROW_HEIGHT - 1));
                    RtlZeroMemory(&Screen->Cell[R], sizeof(Screen->Cell[R]));

                    /* Reset the row back by one */
                    Channel->CursorRow--;
                    VTUTF8ChannelAssertCursor(Channel);
                }
                break;

            /* It's a TAB character */
            case L'\t':

                /* Loop the remaining characters until a multiple of 4 */
                VTUTF8ChannelAssertCursor(Channel);
                for (C = (4 - Channel->CursorCol % 4); C; C--)
                {
                    /* Fill each remaining character with a space */
                    VTUTF8ChannelAssertCursor(Channel);
                    Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellFlags = Channel->CellFlags;
                    Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellBackColor = Channel->CellBackColor;
                    Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellForeColor = Channel->CellForeColor;
                    Screen->Cell[Channel->CursorRow][Channel->CursorCol].Char = L' ';

                    /* Move to the next character position, but don't overflow */
                    Channel->CursorCol++;
                    if (Channel->CursorCol >= SAC_VTUTF8_COL_WIDTH)
                    {
                        Channel->CursorCol = SAC_VTUTF8_COL_WIDTH - 1;
                    }
                }

                /* All done, move to the next one */
                VTUTF8ChannelAssertCursor(Channel);
                break;

            /* It's a backspace or delete character */
            case L'\b':
            case L'\x7F':

                /* Move back one character, unless we had nothing typed */
                if (Channel->CursorCol) Channel->CursorCol--;
                VTUTF8ChannelAssertCursor(Channel);
                break;

            /* It's some other character */
            default:

                /* Is it non-printable? Ignore it and keep parsing */
                if (*pwch < L' ') continue;

                /* Otherwise, print it out with the current attributes */
                VTUTF8ChannelAssertCursor(Channel);
                Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellFlags = Channel->CellFlags;
                Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellBackColor = Channel->CellBackColor;
                Screen->Cell[Channel->CursorRow][Channel->CursorCol].CellForeColor = Channel->CellForeColor;
                Screen->Cell[Channel->CursorRow][Channel->CursorCol].Char = *pwch;

                /* Move forward one character, but make sure not to overflow */
                Channel->CursorCol++;
                if (Channel->CursorCol == SAC_VTUTF8_COL_WIDTH)
                {
                    Channel->CursorCol = SAC_VTUTF8_COL_WIDTH - 1;
                }

                /* All done, move to the next one */
                VTUTF8ChannelAssertCursor(Channel);
                break;
            }
    }

    /* Parsing of the input string completed -- string was written */
    VTUTF8ChannelAssertCursor(Channel);
    return STATUS_SUCCESS;
}
예제 #14
0
NTSTATUS
NTAPI
VTUTF8ChannelOEcho(IN PSAC_CHANNEL Channel,
                   IN PCHAR String,
                   IN ULONG Size)
{
    NTSTATUS Status = STATUS_SUCCESS;
    PWSTR pwch;
    ULONG i, k, TranslatedCount, UTF8TranslationSize;
    BOOLEAN Result;
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(String);

    /* Return success if there's nothing to echo */
    if (!(Size / sizeof(WCHAR))) return Status;

    /* Start with the input string */
    pwch = (PWCHAR)String;

    /* First, figure out how much is outside of the block length alignment */
    k = (Size / sizeof(WCHAR)) % MAX_UTF8_ENCODE_BLOCK_LENGTH;
    if (k)
    {
        /* Translate the misaligned portion */
        Result = SacTranslateUnicodeToUtf8(pwch,
                                           k,
                                           Utf8ConversionBuffer,
                                           Utf8ConversionBufferSize,
                                           &UTF8TranslationSize,
                                           &TranslatedCount);
        ASSERT(k == TranslatedCount);
        if (!Result)
        {
            /* If we couldn't translate, write failure to break out below */
            Status = STATUS_UNSUCCESSFUL;
        }
        else
        {
            /* Write the misaligned portion into the buffer */
            Status = ConMgrWriteData(Channel,
                                     Utf8ConversionBuffer,
                                     UTF8TranslationSize);
        }

        /* If translation or write failed, bail out */
        if (!NT_SUCCESS(Status)) goto Return;
    }

    /* Push the string to its new location (this could be a noop if aligned) */
    pwch += k;

    /* Now figure out how many aligned blocks we have, and loop each one */
    k = (Size / sizeof(WCHAR)) / MAX_UTF8_ENCODE_BLOCK_LENGTH;
    for (i = 0; i < k; i++)
    {
        /* Translate the aligned block */
        Result = SacTranslateUnicodeToUtf8(pwch,
                                           MAX_UTF8_ENCODE_BLOCK_LENGTH,
                                           Utf8ConversionBuffer,
                                           Utf8ConversionBufferSize,
                                           &UTF8TranslationSize,
                                           &TranslatedCount);
        ASSERT(MAX_UTF8_ENCODE_BLOCK_LENGTH == TranslatedCount);
        ASSERT(UTF8TranslationSize > 0);
        if (!Result)
        {
            /* Set failure here, we'll break out below */
            Status = STATUS_UNSUCCESSFUL;
        }
        else
        {
            /* Move the string location to the next aligned block */
            pwch += MAX_UTF8_ENCODE_BLOCK_LENGTH;

            /* Write the aligned block into the buffer */
            Status = ConMgrWriteData(Channel,
                                     Utf8ConversionBuffer,
                                     UTF8TranslationSize);
        }

        /* If translation or write failed, bail out */
        if (!NT_SUCCESS(Status)) break;
    }

Return:
    ASSERT(pwch == (PWSTR)(String + Size));
    if (NT_SUCCESS(Status)) Status = ConMgrFlushData(Channel);
    return Status;
}
예제 #15
0
파일: channel.c 프로젝트: GYGit/reactos
NTSTATUS
NTAPI
ChannelCreate(IN PSAC_CHANNEL Channel,
              IN PSAC_CHANNEL_ATTRIBUTES Attributes,
              IN SAC_CHANNEL_ID ChannelId)
{
    NTSTATUS Status;
    CHECK_PARAMETER1(Channel);
    CHECK_PARAMETER2(Attributes);

    /* If a close event is being passed in, it must exist, and vice-versa */
    if (Attributes->Flag & SAC_CHANNEL_FLAG_CLOSE_EVENT)
    {
        CHECK_PARAMETER(Attributes->CloseEvent != NULL);
    }
    else
    {
        CHECK_PARAMETER(Attributes->CloseEvent == NULL);
    }

    /* If a new data event is being passed in, it must exist, and vice-versa */
    if (Attributes->Flag & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT)
    {
        CHECK_PARAMETER(Attributes->HasNewDataEvent != NULL);
    }
    else
    {
        CHECK_PARAMETER(Attributes->HasNewDataEvent == NULL);
    }

    /* If a lock event is being passed in, it must exist, and vice-versa */
    if (Attributes->Flag & SAC_CHANNEL_FLAG_LOCK_EVENT)
    {
        CHECK_PARAMETER(Attributes->LockEvent != NULL);
    }
    else
    {
        CHECK_PARAMETER(Attributes->LockEvent == NULL);
    }

    /* If a redraw event is being passed in, it must exist, and vice-versa */
    if (Attributes->Flag & SAC_CHANNEL_FLAG_REDRAW_EVENT)
    {
        CHECK_PARAMETER(Attributes->RedrawEvent != NULL);
    }
    else
    {
        CHECK_PARAMETER(Attributes->RedrawEvent == NULL);
    }

    /* Initialize the channel structure */
    RtlZeroMemory(Channel, sizeof(SAC_CHANNEL));
    Channel->ChannelId = ChannelId;
    Channel->ChannelType = Attributes->ChannelType;
    Channel->Flags = Attributes->Flag;
    if (Attributes->Flag & SAC_CHANNEL_FLAG_APPLICATION)
    {
        Channel->ApplicationType = Attributes->ChannelId;
    }

    /* Initialize all the locks and events */
    SacInitializeLock(&Channel->ChannelAttributeLock);
    SacInitializeLock(&Channel->ChannelOBufferLock);
    SacInitializeLock(&Channel->ChannelIBufferLock);
    ChannelInitializeEvent(Channel, Attributes, CloseEvent);
    ChannelInitializeEvent(Channel, Attributes, HasNewDataEvent);
    ChannelInitializeEvent(Channel, Attributes, LockEvent);
    ChannelInitializeEvent(Channel, Attributes, RedrawEvent);

    /* Set the name and description */
    ChannelSetName(Channel, Attributes->NameBuffer);
    ChannelSetDescription(Channel, Attributes->DescriptionBuffer);

    /* Initialize the function table for the type of channel this is */
    Status = ChannelInitializeVTable(Channel);
    if (!NT_SUCCESS(Status))
    {
        /* This is critical */
        SAC_DBG(SAC_DBG_INIT, "SAC Create Channel :: Failed to initialize vtable\n");
        goto FailChannel;
    }

    /* Now call the channel specific type constructor */
    Status = Channel->ChannelCreate(Channel);
    if (!NT_SUCCESS(Status))
    {
        /* This is critical */
        SAC_DBG(SAC_DBG_INIT, "SAC Create Channel :: Failed channel specific initialization\n");
        goto FailChannel;
    }

    /* Finally, mark the channel as active */
    ChannelSetStatus(Channel, Active);
    return STATUS_SUCCESS;

FailChannel:
    /* Destroy the channel and return the failure code */
    Channel->ChannelDestroy(Channel);
    return Status;
}