|
|
/*++
Copyright (c) 1999-2000 Microsoft Corporation
Module Name:
channel.c
Abstract:
Routines for managing channels in the sac.
Author:
Brian Guarraci (briangu) March, 2001. Sean Selitrennikoff (v-seans) Sept, 2000.
Revision History:
--*/
#include "sac.h"
BOOLEAN ChannelIsValidType( SAC_CHANNEL_TYPE ChannelType ) /*++
Routine Description:
This is a convenience routine to determine if a the given type is a valid Channel type Arguments:
ChannelType - the type to be investigated
Return Value:
TRUE - if type is valid otherwise, FALSE
--*/ { BOOLEAN isValid;
switch(ChannelType) { case ChannelTypeVTUTF8: case ChannelTypeRaw: case ChannelTypeCmd: isValid = TRUE; break; default: isValid = FALSE; break; }
return isValid;
} BOOLEAN ChannelIsActive( IN PSAC_CHANNEL Channel ) /*++
Routine Description:
Determine if a channel is active. Arguments:
Channel - Channel to see if has new data Return Value:
TRUE - if the channel is active otherwise, FALSE
--*/ { SAC_CHANNEL_STATUS Status;
ChannelGetStatus( Channel, &Status );
return (BOOLEAN)(Status == ChannelStatusActive); }
BOOLEAN ChannelIsEqual( IN PSAC_CHANNEL Channel, IN PSAC_CHANNEL_HANDLE Handle ) /*++
Routine Description:
Determine if a channel is the same as the one in question
Note: this is to encapsulate the GUID implementation of channel handles Arguments:
Channel - Channel to see if has new data ChannelHandle - The channel handle in question Return Value:
TRUE - if the channel is active otherwise, FALSE
--*/ {
return (BOOLEAN)IsEqualGUID( &(ChannelGetHandle(Channel).ChannelHandle), &(Handle->ChannelHandle) );
}
BOOLEAN ChannelIsClosed( IN PSAC_CHANNEL Channel ) /*++
Routine Description:
Determine if a channel is available for reuse. The criterion for reuse are: 1. The channel must be inactive 2. If the preserve bit is FALSE, then HasNewData must == FALSE Arguments:
Channel - Channel to see if has new data Return Value:
TRUE - if the channel has unsent data otherwise, FALSE
--*/ { SAC_CHANNEL_STATUS Status;
ChannelGetStatus( Channel, &Status );
return (BOOLEAN)( (Status == ChannelStatusInactive) && (ChannelHasNewOBufferData(Channel) == FALSE) );
}
NTSTATUS ChannelInitializeVTable( IN PSAC_CHANNEL Channel ) /*++
Routine Description:
This routine assigns channel type specific functions. Arguments:
Channel - The channel to assign the functions to. Return Value:
STATUS_SUCCESS if successful, else the appropriate error code.
--*/ { //
// Fill out the channel's vtable according to channel type
//
switch(ChannelGetType(Channel)){ case ChannelTypeVTUTF8: Channel->Create = VTUTF8ChannelCreate; Channel->Destroy = VTUTF8ChannelDestroy; Channel->OFlush = VTUTF8ChannelOFlush; Channel->OEcho = VTUTF8ChannelOEcho; Channel->OWrite = VTUTF8ChannelOWrite; Channel->ORead = VTUTF8ChannelORead; Channel->IWrite = VTUTF8ChannelIWrite; Channel->IRead = VTUTF8ChannelIRead; Channel->IReadLast = VTUTF8ChannelIReadLast; Channel->IBufferIsFull = VTUTF8ChannelIBufferIsFull; Channel->IBufferLength = VTUTF8ChannelIBufferLength;
break; case ChannelTypeRaw: Channel->Create = RawChannelCreate; Channel->Destroy = RawChannelDestroy; Channel->OFlush = RawChannelOFlush; Channel->OEcho = RawChannelOEcho; Channel->OWrite = RawChannelOWrite; Channel->ORead = RawChannelORead; Channel->IWrite = RawChannelIWrite; Channel->IRead = RawChannelIRead; Channel->IReadLast = RawChannelIReadLast; Channel->IBufferIsFull = RawChannelIBufferIsFull; Channel->IBufferLength = RawChannelIBufferLength; break; case ChannelTypeCmd:
Channel->Create = CmdChannelCreate; Channel->Destroy = CmdChannelDestroy; Channel->OFlush = CmdChannelOFlush; Channel->OEcho = VTUTF8ChannelOEcho; Channel->OWrite = CmdChannelOWrite; Channel->ORead = CmdChannelORead; Channel->IWrite = VTUTF8ChannelIWrite; Channel->IRead = VTUTF8ChannelIRead; Channel->IReadLast = VTUTF8ChannelIReadLast; Channel->IBufferIsFull = VTUTF8ChannelIBufferIsFull; Channel->IBufferLength = VTUTF8ChannelIBufferLength; break; default:
return STATUS_INVALID_PARAMETER;
break; }
return STATUS_SUCCESS;
}
NTSTATUS ChannelCreate( OUT PSAC_CHANNEL Channel, IN PSAC_CHANNEL_OPEN_ATTRIBUTES Attributes, IN SAC_CHANNEL_HANDLE Handle ) /*++
Routine Description:
This routine allocates a channel and returns a pointer to it. Arguments:
Channel - The resulting channel. Attributes - All the parameters for the new channel Handle - The new channel's handle Return Value:
STATUS_SUCCESS if successful, else the appropriate error code.
--*/ { NTSTATUS Status; BOOLEAN b; PVOID EventObjectBody; PVOID EventWaitObjectBody;
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1); ASSERT_STATUS(Attributes, STATUS_INVALID_PARAMETER_2);
//
// Verify that if the user wants to use the CLOSE_EVENT, we received on to use
//
if (Attributes->Flags & SAC_CHANNEL_FLAG_CLOSE_EVENT) { ASSERT_STATUS(Attributes->CloseEvent != NULL, STATUS_INVALID_PARAMETER); } else { ASSERT_STATUS(Attributes->CloseEvent == NULL, STATUS_INVALID_PARAMETER); } //
// Verify that if the user wants to use the HAS_NEW_DATA_EVENT, we received one to use
//
if (Attributes->Flags & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT) { ASSERT_STATUS(Attributes->HasNewDataEvent != NULL, STATUS_INVALID_PARAMETER); } else { ASSERT_STATUS(Attributes->HasNewDataEvent == NULL, STATUS_INVALID_PARAMETER); }
#if ENABLE_CHANNEL_LOCKING
//
// Verify that if the user wants to use the LOCK_EVENT, we received one to use
//
if (Attributes->Flags & SAC_CHANNEL_FLAG_LOCK_EVENT) { ASSERT_STATUS(Attributes->LockEvent != NULL, STATUS_INVALID_PARAMETER); } else { ASSERT_STATUS(Attributes->LockEvent == NULL, STATUS_INVALID_PARAMETER); } #endif
//
// Verify that if the user wants to use the LOCK_EVENT, we received one to use
//
if (Attributes->Flags & SAC_CHANNEL_FLAG_REDRAW_EVENT) { ASSERT_STATUS(Attributes->RedrawEvent != NULL, STATUS_INVALID_PARAMETER); } else { ASSERT_STATUS(Attributes->RedrawEvent == NULL, STATUS_INVALID_PARAMETER); } //
// Initialize the channel structure
//
do {
//
// Initialize the channel structure
//
RtlZeroMemory(Channel, sizeof(SAC_CHANNEL));
//
// Initialize the channel access locks
//
INIT_CHANNEL_LOCKS(Channel);
//
// copy the name and force NULL termination at the end of the buffer
//
ChannelSetName( Channel, Attributes->Name );
//
// copy the description and force NULL termination at the end of the buffer
//
ChannelSetDescription( Channel, Attributes->Description );
//
// Attempt to get the wait object from the event
//
if (Attributes->CloseEvent) { b = VerifyEventWaitable( Attributes->CloseEvent, &EventObjectBody, &EventWaitObjectBody );
if(!b) { Status = STATUS_INVALID_HANDLE; break; }
//
// We successfully got the wait object, so keep it.
//
Channel->CloseEvent = Attributes->CloseEvent; Channel->CloseEventObjectBody = EventObjectBody; Channel->CloseEventWaitObjectBody = EventWaitObjectBody;
} //
// Attempt to get the wait object from the event
//
if (Attributes->HasNewDataEvent) {
b = VerifyEventWaitable( Attributes->HasNewDataEvent, &EventObjectBody, &EventWaitObjectBody );
if(!b) { Status = STATUS_INVALID_HANDLE; break; }
//
// We successfully got the wait object, so keep it.
//
Channel->HasNewDataEvent = Attributes->HasNewDataEvent; Channel->HasNewDataEventObjectBody = EventObjectBody; Channel->HasNewDataEventWaitObjectBody = EventWaitObjectBody;
} #if ENABLE_CHANNEL_LOCKING
//
// Attempt to get the wait object from the event
//
if (Attributes->LockEvent) { b = VerifyEventWaitable( Attributes->LockEvent, &EventObjectBody, &EventWaitObjectBody );
if(!b) { Status = STATUS_INVALID_HANDLE; break; }
//
// We successfully got the wait object, so keep it.
//
Channel->LockEvent = Attributes->LockEvent; Channel->LockEventObjectBody = EventObjectBody; Channel->LockEventWaitObjectBody = EventWaitObjectBody;
} #endif
//
// Attempt to get the wait object from the event
//
if (Attributes->RedrawEvent) { b = VerifyEventWaitable( Attributes->RedrawEvent, &EventObjectBody, &EventWaitObjectBody );
if(!b) { Status = STATUS_INVALID_HANDLE; break; }
//
// We successfully got the wait object, so keep it.
//
Channel->RedrawEvent = Attributes->RedrawEvent; Channel->RedrawEventObjectBody = EventObjectBody; Channel->RedrawEventWaitObjectBody = EventWaitObjectBody;
} //
// Copy the remaining attributes
//
// Note: use the channel handle sent to use by the channel manager
//
Channel->Handle = Handle; Channel->Type = Attributes->Type; Channel->Flags = Attributes->Flags; //
// If we have the ApplicationType,
// then save it
//
if (Attributes->Flags & SAC_CHANNEL_FLAG_APPLICATION_TYPE) { Channel->ApplicationType = Attributes->ApplicationType; }
//
// Assign the appropriate channel functions base on type
//
Status = ChannelInitializeVTable(Channel); if (! NT_SUCCESS(Status)) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(("SAC Create Channel :: Failed to initialize vtable\n")) ); break; }
//
// Do Channel type specific initialization
//
Status = Channel->Create(Channel); if (! NT_SUCCESS(Status)) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(("SAC Create Channel :: Failed channel specific initialization\n")) ); break; }
//
// The channel is now Active
//
ChannelSetStatus(Channel, ChannelStatusActive); } while (FALSE);
//
// If the creation failed, destroy the channel object
//
if (! NT_SUCCESS(Status)) { Channel->Destroy(Channel); }
return Status; }
NTSTATUS ChannelDereferenceHandles( PSAC_CHANNEL Channel ) /*++
Routine Description:
This routine dereferences and NULLs the channel's event handles, if appropriate.
Note: caller must hold channel mutex Arguments:
Channel - the channel to close
Return Value:
STATUS_SUCCESS - if the mapping was successful otherwise, error status
--*/ { ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
//
// Release the has new data event if we have it
//
if (Channel->HasNewDataEvent) { //
// validate that the channel's attributes for this event
// are properly set
//
ASSERT(ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT); ASSERT(Channel->HasNewDataEventObjectBody); ASSERT(Channel->HasNewDataEventWaitObjectBody);
if (Channel->HasNewDataEventObjectBody) { ObDereferenceObject(Channel->HasNewDataEventObjectBody);
//
// NULL the event pointers
//
ChannelSetFlags( Channel, ChannelGetFlags(Channel) & ~SAC_CHANNEL_FLAG_HAS_NEW_DATA_EVENT ); Channel->HasNewDataEvent = NULL; Channel->HasNewDataEventObjectBody = NULL; Channel->HasNewDataEventWaitObjectBody = NULL; }
}
//
// do we have the Close Channel Event?
//
if (Channel->CloseEvent) {
//
// validate that the channel's attributes for this event
// are properly set
//
ASSERT(ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_CLOSE_EVENT); ASSERT(Channel->CloseEventObjectBody); ASSERT(Channel->CloseEventWaitObjectBody);
if (Channel->CloseEventObjectBody) { //
// release the events
//
ObDereferenceObject(Channel->CloseEventObjectBody);
//
// NULL the event pointers
//
ChannelSetFlags( Channel, ChannelGetFlags(Channel) & ~SAC_CHANNEL_FLAG_CLOSE_EVENT ); Channel->CloseEvent = NULL; Channel->CloseEventObjectBody = NULL; Channel->CloseEventWaitObjectBody = NULL; } } #if ENABLE_CHANNEL_LOCKING
//
// do we have the Lock Channel Event?
//
if (Channel->LockEvent) {
//
// validate that the channel's attributes for this event
// are properly set
//
ASSERT(ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_LOCK_EVENT); ASSERT(Channel->LockEventObjectBody); ASSERT(Channel->LockEventWaitObjectBody);
if (Channel->LockEventObjectBody) { //
// release the events
//
ObDereferenceObject(Channel->LockEventObjectBody);
//
// NULL the event pointers
//
ChannelSetFlags( Channel, ChannelGetFlags(Channel) & ~SAC_CHANNEL_FLAG_LOCK_EVENT ); Channel->LockEvent = NULL; Channel->LockEventObjectBody = NULL; Channel->LockEventWaitObjectBody = NULL; } } #endif
//
// do we have the Redraw Channel Event?
//
if (Channel->RedrawEvent) {
//
// validate that the channel's attributes for this event
// are properly set
//
ASSERT(ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_REDRAW_EVENT); ASSERT(Channel->RedrawEventObjectBody); ASSERT(Channel->RedrawEventWaitObjectBody);
if (Channel->RedrawEventObjectBody) { //
// release the events
//
ObDereferenceObject(Channel->RedrawEventObjectBody);
//
// NULL the event pointers
//
ChannelSetFlags( Channel, ChannelGetFlags(Channel) & ~SAC_CHANNEL_FLAG_REDRAW_EVENT ); Channel->RedrawEvent = NULL; Channel->RedrawEventObjectBody = NULL; Channel->RedrawEventWaitObjectBody = NULL; } } return STATUS_SUCCESS; }
NTSTATUS ChannelClose( PSAC_CHANNEL Channel ) /*++
Routine Description:
This routine closes the given channel and fires the CloseEvent if specified
Note: caller must hold channel mutex Arguments:
Channel - the channel to close
Return Value:
STATUS_SUCCESS - if the mapping was successful otherwise, error status
--*/ { NTSTATUS Status;
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
//
// Set the channel's state to inactive
//
ChannelSetStatus(Channel, ChannelStatusInactive); //
// do we need to fire the Close Channel Event?
//
if (ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_CLOSE_EVENT) {
ASSERT(Channel->CloseEvent); ASSERT(Channel->CloseEventObjectBody); ASSERT(Channel->CloseEventWaitObjectBody);
if (Channel->CloseEventWaitObjectBody) { //
// Yes, fire the event
//
KeSetEvent( Channel->CloseEventWaitObjectBody, EVENT_INCREMENT, FALSE ); }
} //
// Let go of any handles this channel may own
//
Status = ChannelDereferenceHandles(Channel); return Status; }
NTSTATUS ChannelDestroy( IN PSAC_CHANNEL Channel ) /*++
Routine Description:
This routine does the final steps of channel destruction. Arguments:
Channel - The channel to be closed Return Value:
STATUS_SUCCESS if successful, else the appropriate error code.
--*/ { NTSTATUS Status;
ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
//
// Let go of any handles this channel may own
//
Status = ChannelDereferenceHandles(Channel);
return Status; }
NTSTATUS ChannelOWrite( IN PSAC_CHANNEL Channel, IN PCUCHAR Buffer, IN ULONG BufferSize ) /*++
Routine Description:
This is the common entry point for all channel owrite methods. The purpose of this entry point is to provide a uniform locking scheme for the obuffer. Channel apps should not call the owrite method directly, but should use this instead. Arguments:
Channel - Previously created channel. Buffer - The buffer to write BufferSize - The size of the buffer to write Return Value:
Status
--*/ { NTSTATUS Status;
//
// Make sure the caller isn't sending an unacceptably
// large sized buffer. This prevents an app from blocking
// the console manager from being blocked while a channel
// dumps it's buffer.
//
ASSERT_STATUS( BufferSize < CHANNEL_MAX_OWRITE_BUFFER_SIZE, STATUS_INVALID_PARAMETER_3 );
LOCK_CHANNEL_OBUFFER(Channel); Status = Channel->OWrite( Channel, Buffer, BufferSize ); UNLOCK_CHANNEL_OBUFFER(Channel);
return Status; }
NTSTATUS ChannelOFlush( IN PSAC_CHANNEL Channel ) /*++
Routine Description:
This is the common entry point for all channel OFlush methods. The purpose of this entry point is to provide a uniform locking scheme for the obuffer. Channel apps should not call the OFlush method directly, but should use this instead. Arguments:
Channel - Previously created channel. Return Value:
Status
--*/ { NTSTATUS Status;
LOCK_CHANNEL_OBUFFER(Channel); Status = Channel->OFlush(Channel); UNLOCK_CHANNEL_OBUFFER(Channel);
return Status; }
NTSTATUS ChannelOEcho( IN PSAC_CHANNEL Channel, IN PCUCHAR Buffer, IN ULONG BufferSize ) /*++
Routine Description:
This is the common entry point for all channel OEcho methods. The purpose of this entry point is to provide a uniform locking scheme for the obuffer. Channel apps should not call the OEcho method directly, but should use this instead. Arguments:
Channel - Previously created channel. Buffer - The buffer to write BufferSize - The size of the buffer to write Return Value:
Status
--*/ { NTSTATUS Status;
LOCK_CHANNEL_OBUFFER(Channel); Status = Channel->OEcho( Channel, Buffer, BufferSize ); UNLOCK_CHANNEL_OBUFFER(Channel);
return Status; }
NTSTATUS ChannelORead( IN PSAC_CHANNEL Channel, IN PUCHAR Buffer, IN ULONG BufferSize, OUT PULONG ByteCount ) /*++
Routine Description:
This is the common entry point for all channel ORead methods. The purpose of this entry point is to provide a uniform locking scheme for the obuffer. Channel apps should not call the ORead method directly, but should use this instead. Arguments:
Channel - Previously created channel. Buffer - The buffer to write BufferSize - The size of the buffer to write ByteCount - The number bytes read Return Value:
Status
--*/ { NTSTATUS Status;
LOCK_CHANNEL_OBUFFER(Channel); Status = Channel->ORead( Channel, Buffer, BufferSize, ByteCount ); UNLOCK_CHANNEL_OBUFFER(Channel);
return Status; }
NTSTATUS ChannelIWrite( IN PSAC_CHANNEL Channel, IN PCUCHAR Buffer, IN ULONG BufferSize ) /*++
Routine Description:
This is the common entry point for all channel iwrite methods. The purpose of this entry point is to provide a uniform locking scheme for the ibuffer. Channel apps should not call the iwrite method directly, but should use this instead. Arguments:
Channel - Previously created channel. Buffer - The buffer to write BufferSize - The size of the buffer to write Return Value:
Status
--*/ { NTSTATUS Status;
LOCK_CHANNEL_IBUFFER(Channel); Status = Channel->IWrite( Channel, Buffer, BufferSize ); UNLOCK_CHANNEL_IBUFFER(Channel);
return Status; }
NTSTATUS ChannelIRead( IN PSAC_CHANNEL Channel, IN PUCHAR Buffer, IN ULONG BufferSize, OUT PULONG ByteCount ) /*++
Routine Description:
This is the common entry point for all channel iread methods. The purpose of this entry point is to provide a uniform locking scheme for the ibuffer. Channel apps should not call the iread method directly, but should use this instead. Arguments:
Channel - Previously created channel. Buffer - The buffer to read into BufferSize - The size of the buffer ByteCount - The # of bytes read Return Value:
Status
--*/ { NTSTATUS Status;
LOCK_CHANNEL_IBUFFER(Channel); Status = Channel->IRead( Channel, Buffer, BufferSize, ByteCount ); UNLOCK_CHANNEL_IBUFFER(Channel);
return Status; }
WCHAR ChannelIReadLast( IN PSAC_CHANNEL Channel ) /*++
Routine Description:
This is the common entry point for all channel ireadlast methods. The purpose of this entry point is to provide a uniform locking scheme for the ibuffer. Channel apps should not call the ireadlast method directly, but should use this instead. Arguments:
Channel - Previously created channel. Return Value:
The last character, otherwise UNICODE_NULL
--*/ { WCHAR wch;
LOCK_CHANNEL_IBUFFER(Channel); wch = Channel->IReadLast(Channel); UNLOCK_CHANNEL_IBUFFER(Channel);
return wch; }
NTSTATUS ChannelIBufferIsFull( IN PSAC_CHANNEL Channel, OUT BOOLEAN* BufferStatus ) /*++
Routine Description:
This is the common entry point for all channel IBufferIsFull methods. The purpose of this entry point is to provide a uniform locking scheme for the ibuffer. Channel apps should not call the IBufferIsFull method directly, but should use this instead. Arguments:
Channel - Previously created channel. BufferStatus - The query result Return Value:
Status
--*/ { NTSTATUS Status;
LOCK_CHANNEL_IBUFFER(Channel); Status = Channel->IBufferIsFull( Channel, BufferStatus ); UNLOCK_CHANNEL_IBUFFER(Channel);
return Status; }
ULONG ChannelIBufferLength( IN PSAC_CHANNEL Channel ) /*++
Routine Description:
This is the common entry point for all channel IBufferLength methods. The purpose of this entry point is to provide a uniform locking scheme for the ibuffer. Channel apps should not call the IBufferLength method directly, but should use this instead. Arguments:
Channel - Previously created channel. Return Value:
The last character, otherwise UNICODE_NULL
--*/ { ULONG Length;
LOCK_CHANNEL_IBUFFER(Channel); Length = Channel->IBufferLength(Channel); UNLOCK_CHANNEL_IBUFFER(Channel);
return Length; }
NTSTATUS ChannelGetName( IN PSAC_CHANNEL Channel, OUT PWSTR* Name ) /*++
Routine Description:
This routine retrieves the channel's description and stores it in a newly allocated buffer
Note: the caller is responsible for releasing the memory holding the description Arguments:
Channel - Previously created channel. Name - the retrieved name Return Value:
Status
--*/ { ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1); ASSERT_STATUS(Name, STATUS_INVALID_PARAMETER_2);
*Name = ALLOCATE_POOL(SAC_MAX_CHANNEL_NAME_SIZE, GENERAL_POOL_TAG); ASSERT_STATUS(*Name, STATUS_NO_MEMORY);
LOCK_CHANNEL_ATTRIBUTES(Channel);
SAFE_WCSCPY( SAC_MAX_CHANNEL_NAME_SIZE, *Name, Channel->Name );
UNLOCK_CHANNEL_ATTRIBUTES(Channel); return STATUS_SUCCESS; }
NTSTATUS ChannelSetName( IN PSAC_CHANNEL Channel, IN PCWSTR Name ) /*++
Routine Description:
This routine sets the channel's name. Arguments:
Channel - Previously created channel. Name - The new channel name Note: this routine does not check to see if the name is unique Return Value:
Status
--*/ { ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1); ASSERT_STATUS(Name, STATUS_INVALID_PARAMETER_2);
LOCK_CHANNEL_ATTRIBUTES(Channel); SAFE_WCSCPY( SAC_MAX_CHANNEL_NAME_SIZE, Channel->Name, Name ); Channel->Name[SAC_MAX_CHANNEL_NAME_LENGTH] = UNICODE_NULL;
UNLOCK_CHANNEL_ATTRIBUTES(Channel);
return STATUS_SUCCESS; }
NTSTATUS ChannelGetDescription( IN PSAC_CHANNEL Channel, OUT PWSTR* Description ) /*++
Routine Description:
This routine retrieves the channel's description and stores it in a newly allocated buffer
Note: the caller is responsible for releasing the memory holding the description Arguments:
Channel - Previously created channel. Description - the retrieved description Return Value:
Status
--*/ { ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1); ASSERT_STATUS(Description, STATUS_INVALID_PARAMETER_2);
*Description = ALLOCATE_POOL(SAC_MAX_CHANNEL_DESCRIPTION_SIZE, GENERAL_POOL_TAG); ASSERT_STATUS(*Description, STATUS_NO_MEMORY);
LOCK_CHANNEL_ATTRIBUTES(Channel); SAFE_WCSCPY( SAC_MAX_CHANNEL_DESCRIPTION_SIZE, *Description, Channel->Description ); UNLOCK_CHANNEL_ATTRIBUTES(Channel);
return STATUS_SUCCESS; }
NTSTATUS ChannelSetDescription( IN PSAC_CHANNEL Channel, IN PCWSTR Description ) /*++
Routine Description:
This routine sets the channels description. Arguments:
Channel - Previously created channel. Description - The new description Return Value:
Status
--*/ { ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
LOCK_CHANNEL_ATTRIBUTES(Channel); if (Description != NULL) { SAFE_WCSCPY( SAC_MAX_CHANNEL_DESCRIPTION_SIZE, Channel->Description, Description );
//
// Force a null termination at the end of the description
//
Channel->Description[SAC_MAX_CHANNEL_DESCRIPTION_LENGTH] = UNICODE_NULL; } else { //
// make the description 0 length
//
Channel->Description[0] = UNICODE_NULL; }
UNLOCK_CHANNEL_ATTRIBUTES(Channel); return STATUS_SUCCESS; }
NTSTATUS ChannelSetStatus( IN PSAC_CHANNEL Channel, IN SAC_CHANNEL_STATUS Status ) /*++
Routine Description:
This routine sets the channels status. Arguments:
Channel - Previously created channel. Status - The channel's new status Return Value:
NTStatus
--*/ { ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
LOCK_CHANNEL_ATTRIBUTES(Channel); Channel->Status = Status;
UNLOCK_CHANNEL_ATTRIBUTES(Channel); return STATUS_SUCCESS; }
NTSTATUS ChannelGetStatus( IN PSAC_CHANNEL Channel, OUT SAC_CHANNEL_STATUS* Status ) /*++
Routine Description:
This routine Gets the channels status. Arguments:
Channel - Previously created channel. Status - The channel's new status Return Value:
NTStatus
--*/ { ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
LOCK_CHANNEL_ATTRIBUTES(Channel); *Status = Channel->Status;
UNLOCK_CHANNEL_ATTRIBUTES(Channel); return STATUS_SUCCESS; }
NTSTATUS ChannelSetApplicationType( IN PSAC_CHANNEL Channel, IN GUID ApplicationType ) /*++
Routine Description:
This routine sets the channel's application type. Arguments:
Channel - Previously created channel. ApplicationType - Application type Return Value:
NTStatus
--*/ { ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
LOCK_CHANNEL_ATTRIBUTES(Channel); Channel->ApplicationType = ApplicationType;
UNLOCK_CHANNEL_ATTRIBUTES(Channel); return STATUS_SUCCESS; }
NTSTATUS ChannelGetApplicationType( IN PSAC_CHANNEL Channel, OUT GUID* ApplicationType ) /*++
Routine Description:
This routine gets the channel's application type. Arguments:
Channel - Previously created channel. ApplicationType - Application type Return Value:
NTStatus
--*/ { ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
LOCK_CHANNEL_ATTRIBUTES(Channel); *ApplicationType = Channel->ApplicationType;
UNLOCK_CHANNEL_ATTRIBUTES(Channel); return STATUS_SUCCESS; }
#if ENABLE_CHANNEL_LOCKING
NTSTATUS ChannelSetLockEvent( IN PSAC_CHANNEL Channel ) /*++
Routine Description:
Set the channel lock event Arguments:
Channel - The channel to fire the event for Return Value:
NTStatus
--*/ {
ASSERT_STATUS(Channel->LockEvent, STATUS_UNSUCCESSFUL); ASSERT_STATUS(Channel->LockEventObjectBody, STATUS_UNSUCCESSFUL); ASSERT_STATUS(Channel->LockEventWaitObjectBody, STATUS_UNSUCCESSFUL);
if (Channel->LockEventWaitObjectBody) { //
// fire the event
//
KeSetEvent( Channel->LockEventWaitObjectBody, EVENT_INCREMENT, FALSE ); }
return STATUS_SUCCESS;
}
#endif
NTSTATUS ChannelSetRedrawEvent( IN PSAC_CHANNEL Channel ) /*++
Routine Description:
Set the channel redraw event Arguments:
Channel - The channel to fire the event for Return Value:
NTStatus
--*/ {
ASSERT_STATUS(Channel->RedrawEvent, STATUS_UNSUCCESSFUL); ASSERT_STATUS(Channel->RedrawEventObjectBody, STATUS_UNSUCCESSFUL); ASSERT_STATUS(Channel->RedrawEventWaitObjectBody, STATUS_UNSUCCESSFUL);
if (Channel->RedrawEventWaitObjectBody) { //
// fire the event
//
KeSetEvent( Channel->RedrawEventWaitObjectBody, EVENT_INCREMENT, FALSE ); }
return STATUS_SUCCESS;
}
NTSTATUS ChannelClearRedrawEvent( IN PSAC_CHANNEL Channel ) /*++
Routine Description:
Clear the channel redraw event Arguments:
Channel - The channel to fire the event for Return Value:
NTStatus
--*/ {
ASSERT_STATUS(Channel->RedrawEvent, STATUS_UNSUCCESSFUL); ASSERT_STATUS(Channel->RedrawEventObjectBody, STATUS_UNSUCCESSFUL); ASSERT_STATUS(Channel->RedrawEventWaitObjectBody, STATUS_UNSUCCESSFUL);
if (Channel->RedrawEventWaitObjectBody) { //
// clear the event
//
KeClearEvent( Channel->RedrawEventWaitObjectBody ); }
return STATUS_SUCCESS;
}
NTSTATUS ChannelHasRedrawEvent( IN PSAC_CHANNEL Channel, OUT PBOOLEAN Present ) /*++
Routine Description:
This routine determines if the channel has the Redraw event present.
Arguments:
Channel - the channel to query Return Value:
TRUE - the channel has the event FALSE - Otherwise
--*/ { ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1); ASSERT_STATUS(Present, STATUS_INVALID_PARAMETER_2);
*Present = (ChannelGetFlags(Channel) & SAC_CHANNEL_FLAG_REDRAW_EVENT) ? TRUE : FALSE;
return STATUS_SUCCESS; }
|