2 * PROJECT: ReactOS Drivers
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/sac/driver/conmgr.c
5 * PURPOSE: Driver for the Server Administration Console (SAC) for EMS
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 DEFINE_GUID(PRIMARY_SAC_CHANNEL_APPLICATION_GUID
,
21 0xBC, 0xCF, 0x80, 0x6D, 0x61, 0x72, 0x69, 0x6F);
23 LONG CurrentChannelRefCount
;
24 KMUTEX CurrentChannelLock
;
26 PSAC_CHANNEL CurrentChannel
;
27 PSAC_CHANNEL SacChannel
;
29 ULONG ExecutePostConsumerCommand
;
30 PSAC_CHANNEL ExecutePostConsumerCommandData
;
32 BOOLEAN InputInEscape
, InputInEscTab
, ConMgrLastCharWasCR
;
35 BOOLEAN GlobalPagingNeeded
, GlobalDoThreads
;
37 /* FUNCTIONS ******************************************************************/
41 SacPutString(IN PWCHAR String
)
45 /* Write the string on the main SAC channel */
46 Status
= ChannelOWrite(SacChannel
,
48 wcslen(String
) * sizeof(WCHAR
));
49 if (!NT_SUCCESS(Status
))
51 SAC_DBG(SAC_DBG_INIT
, "SAC XmlMgrSacPutString: OWrite failed\n");
57 SacPutSimpleMessage(IN ULONG MessageIndex
)
63 MessageBuffer
= GetMessage(MessageIndex
);
67 SacPutString(MessageBuffer
);
81 ConMgrDisplayCurrentChannel(VOID
)
86 /* Make sure the lock is held */
87 SacAssertMutexLockHeld();
89 /* Check if we can redraw */
90 Status
= ChannelHasRedrawEvent(CurrentChannel
, &HasRedraw
);
91 if (NT_SUCCESS(Status
))
94 _InterlockedExchange(&CurrentChannel
->WriteEnabled
, 1);
97 /* If we can redraw, set the event */
98 ChannelSetRedrawEvent(CurrentChannel
);
101 /* Flush the output */
102 Status
= ChannelOFlush(CurrentChannel
);
105 /* All done, return the status */
111 ConMgrWriteData(IN PSAC_CHANNEL Channel
,
113 IN ULONG BufferLength
)
117 LARGE_INTEGER Interval
;
119 /* Loop up to 32 times */
120 for (i
= 0; i
< 32; i
++)
122 /* Attempt sending the data */
123 Status
= HeadlessDispatch(HeadlessCmdPutData
, Buffer
, BufferLength
, NULL
, NULL
);
124 if (Status
!= STATUS_UNSUCCESSFUL
) break;
126 /* Sending the data on the port failed, wait a second... */
127 Interval
.HighPart
= -1;
128 Interval
.LowPart
= -100000;
129 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
132 /* After 32 attempts it should really have worked... */
133 ASSERT(NT_SUCCESS(Status
));
139 ConMgrFlushData(IN PSAC_CHANNEL Channel
)
142 return STATUS_SUCCESS
;
147 ConMgrIsSacChannel(IN PSAC_CHANNEL Channel
)
149 /* Check which channel is active */
150 return Channel
== SacChannel
;
155 ConMgrIsWriteEnabled(IN PSAC_CHANNEL Channel
)
157 /* If the current channel is active, allow writes */
158 return ChannelIsEqual(Channel
, &CurrentChannel
->ChannelId
);
163 ConMgrInitialize(VOID
)
166 PSAC_CHANNEL FoundChannel
;
167 SAC_CHANNEL_ATTRIBUTES SacChannelAttributes
;
170 /* Initialize the connection manager lock */
171 SacInitializeMutexLock();
172 SacAcquireMutexLock();
174 /* Setup the attributes for the raw SAC channel */
175 RtlZeroMemory(&SacChannelAttributes
, sizeof(SacChannelAttributes
));
176 SacChannelAttributes
.ChannelType
= VtUtf8
;
178 /* Get the right name for it */
179 pcwch
= GetMessage(SAC_CHANNEL_NAME
);
181 wcsncpy(SacChannelAttributes
.NameBuffer
, pcwch
, SAC_CHANNEL_NAME_SIZE
);
182 SacChannelAttributes
.NameBuffer
[SAC_CHANNEL_NAME_SIZE
] = ANSI_NULL
;
184 /* Get the right description for it */
185 pcwch
= GetMessage(SAC_CHANNEL_DESCRIPTION
);
187 wcsncpy(SacChannelAttributes
.DescriptionBuffer
, pcwch
, SAC_CHANNEL_DESCRIPTION_SIZE
);
188 SacChannelAttributes
.DescriptionBuffer
[SAC_CHANNEL_DESCRIPTION_SIZE
] = ANSI_NULL
;
190 /* Set all the right flags */
191 SacChannelAttributes
.Flag
= SAC_CHANNEL_FLAG_APPLICATION
| SAC_CHANNEL_FLAG_INTERNAL
;
192 SacChannelAttributes
.CloseEvent
= NULL
;
193 SacChannelAttributes
.HasNewDataEvent
= NULL
;
194 SacChannelAttributes
.LockEvent
= NULL
;
195 SacChannelAttributes
.RedrawEvent
= NULL
;
196 SacChannelAttributes
.ChannelId
= PRIMARY_SAC_CHANNEL_APPLICATION_GUID
;
199 Status
= ChanMgrCreateChannel(&SacChannel
, &SacChannelAttributes
);
200 if (NT_SUCCESS(Status
))
202 /* Try to get it back */
203 Status
= ChanMgrGetByHandle(SacChannel
->ChannelId
, &FoundChannel
);
204 if (NT_SUCCESS(Status
))
206 /* Set it as the current and SAC channel */
207 SacChannel
= CurrentChannel
= FoundChannel
;
209 /* Disable writes for now and clear the display */
210 _InterlockedExchange(&FoundChannel
->WriteEnabled
, FALSE
);
211 Status
= HeadlessDispatch(HeadlessCmdClearDisplay
, NULL
, 0, NULL
, NULL
);
212 if (!NT_SUCCESS(Status
))
214 SAC_DBG(SAC_DBG_INIT
, "SAC ConMgrInitialize: Failed dispatch\n");
217 /* Display the initial prompt */
218 SacPutSimpleMessage(SAC_NEWLINE
);
219 SacPutSimpleMessage(SAC_INIT_STATUS
);
220 SacPutSimpleMessage(SAC_NEWLINE
);
221 SacPutSimpleMessage(SAC_PROMPT
);
223 /* Display the current channel */
224 ConMgrDisplayCurrentChannel();
228 /* Release the channel lock */
229 SacReleaseMutexLock();
230 return STATUS_SUCCESS
;
235 ConMgrEventMessage(IN PWCHAR EventMessage
,
238 /* Acquire the current channel lock if needed */
239 if (!LockHeld
) SacAcquireMutexLock();
241 /* Send out the event message */
242 SacPutSimpleMessage(2);
243 SacPutString(EventMessage
);
244 SacPutSimpleMessage(3);
246 /* Release the current channel lock if needed */
247 if (!LockHeld
) SacReleaseMutexLock();
252 ConMgrSimpleEventMessage(IN ULONG MessageIndex
,
255 PWCHAR MessageBuffer
;
258 /* Get the message to send out */
259 MessageBuffer
= GetMessage(MessageIndex
);
263 ConMgrEventMessage(MessageBuffer
, LockHeld
);
268 /* It doesn't exist, fail */
272 /* Return if the message was sent or not */
278 ConMgrDisplayFastChannelSwitchingInterface(IN PSAC_CHANNEL Channel
)
282 return STATUS_NOT_IMPLEMENTED
;
287 ConMgrSetCurrentChannel(IN PSAC_CHANNEL Channel
)
290 BOOLEAN HasRedrawEvent
;
292 /* Make sure the lock is held */
293 SacAssertMutexLockHeld();
295 /* Check if we have a redraw event */
296 Status
= ChannelHasRedrawEvent(CurrentChannel
, &HasRedrawEvent
);
297 if (!NT_SUCCESS(Status
)) return Status
;
300 if (HasRedrawEvent
) ChannelClearRedrawEvent(CurrentChannel
);
302 /* Disable writes on the current channel */
303 _InterlockedExchange(&CurrentChannel
->WriteEnabled
, 0);
305 /* Release the current channel */
306 Status
= ChanMgrReleaseChannel(CurrentChannel
);
307 if (!NT_SUCCESS(Status
)) return Status
;
309 /* Set the new channel and also disable writes on it */
310 CurrentChannel
= Channel
;
311 _InterlockedExchange(&Channel
->WriteEnabled
, 0);
312 return STATUS_SUCCESS
;
317 ConMgrResetCurrentChannel(IN BOOLEAN KeepChannel
)
320 PSAC_CHANNEL Channel
;
322 /* Make sure the lock is held */
323 SacAssertMutexLockHeld();
325 /* Get the current SAC channel */
326 Status
= ChanMgrGetByHandle(SacChannel
->ChannelId
, &Channel
);
327 if (NT_SUCCESS(Status
))
329 /* Set this as the current SAC channel*/
330 SacChannel
= Channel
;
331 Status
= ConMgrSetCurrentChannel(Channel
);
332 if (NT_SUCCESS(Status
))
334 /* Check if the caller wants to switch or not */
337 /* Nope, keep the same channel */
338 Status
= ConMgrDisplayCurrentChannel();
342 /* Yep, show the switching interface */
343 Status
= ConMgrDisplayFastChannelSwitchingInterface(CurrentChannel
);
354 ConMgrChannelClose(IN PSAC_CHANNEL Channel
)
356 NTSTATUS Status
= STATUS_SUCCESS
;
358 /* Check if we're in the right channel */
359 if (ConMgrIsWriteEnabled(Channel
))
362 Status
= ConMgrResetCurrentChannel(FALSE
);
363 ASSERT(NT_SUCCESS(Status
));
376 /* Check if we have a SAC channel */
380 Status
= ChannelClose(SacChannel
);
381 if (!NT_SUCCESS(Status
))
383 SAC_DBG(SAC_DBG_INIT
, "SAC ConMgrShutdown: failed closing SAC channel.\n");
386 /* No longer have one */
390 /* Check if we have a current channel */
394 Status
= ChanMgrReleaseChannel(CurrentChannel
);
395 if (!NT_SUCCESS(Status
))
397 SAC_DBG(SAC_DBG_INIT
, "SAC ConMgrShutdown: failed releasing current channel\n");
400 /* No longer have one */
401 CurrentChannel
= NULL
;
405 return STATUS_SUCCESS
;
410 ConMgrAdvanceCurrentChannel(VOID
)
414 PSAC_CHANNEL Channel
;
416 /* Should always be called with the lock held */
417 SacAssertMutexLockHeld();
419 /* Get the next active channel */
420 Status
= ChanMgrGetNextActiveChannel(CurrentChannel
, &Index
, &Channel
);
421 if (NT_SUCCESS(Status
))
423 /* Set it as the new channel */
424 Status
= ConMgrSetCurrentChannel(Channel
);
425 if (NT_SUCCESS(Status
))
427 /* Let the user switch to it */
428 Status
= ConMgrDisplayFastChannelSwitchingInterface(Channel
);
438 ConMgrChannelOWrite(IN PSAC_CHANNEL Channel
,
439 IN PVOID WriteBuffer
)
443 /* Do the write with the lock held */
444 SacAcquireMutexLock();
446 Status
= STATUS_NOT_IMPLEMENTED
;// ChannelOWrite(Channel, WriteBuffer + 24, *(WriteBuffer + 20));
447 SacReleaseMutexLock();
449 /* Return back to the caller */
450 ASSERT(NT_SUCCESS(Status
) || Status
== STATUS_NOT_FOUND
);
456 ConMgrProcessInputLine(VOID
)
458 BOOLEAN EnablePaging
;
461 SAC_DBG(SAC_DBG_INIT
, "SAC Input Test: %s\n", InputBuffer
);
463 if (!strncmp(InputBuffer
, "t", 1))
467 else if (!strncmp(InputBuffer
, "?", 1))
471 else if (!strncmp(InputBuffer
, "help", 4))
475 else if (!strncmp(InputBuffer
, "f", 1))
479 else if (!strncmp(InputBuffer
, "p", 1))
483 else if (!strncmp(InputBuffer
, "id", 2))
485 DoMachineInformationCommand();
487 else if (!strncmp(InputBuffer
, "crashdump", 9))
491 else if (!strncmp(InputBuffer
, "lock", 4))
495 else if (!strncmp(InputBuffer
, "shutdown", 8))
497 ExecutePostConsumerCommand
= Shutdown
;
499 else if (!strncmp(InputBuffer
, "restart", 7))
501 ExecutePostConsumerCommand
= Restart
;
503 else if (!strncmp(InputBuffer
, "d", 1))
505 EnablePaging
= GlobalPagingNeeded
;
506 Status
= HeadlessDispatch(HeadlessCmdDisplayLog
,
508 sizeof(EnablePaging
),
511 if (!NT_SUCCESS(Status
)) SAC_DBG(SAC_DBG_INIT
, "SAC Display Log failed.\n");
513 else if (!strncmp(InputBuffer
, "cmd", 3))
515 if (CommandConsoleLaunchingEnabled
)
517 DoCmdCommand(InputBuffer
);
521 SacPutSimpleMessage(148);
524 else if (!(strncmp(InputBuffer
, "ch", 2)) &&
525 (((strlen(InputBuffer
) > 1) && (InputBuffer
[2] == ' ')) ||
526 (strlen(InputBuffer
) == 2)))
528 DoChannelCommand(InputBuffer
);
530 else if (!(strncmp(InputBuffer
, "k", 1)) &&
531 (((strlen(InputBuffer
) > 1) && (InputBuffer
[1] == ' ')) ||
532 (strlen(InputBuffer
) == 1)))
534 DoKillCommand(InputBuffer
);
536 else if (!(strncmp(InputBuffer
, "l", 1)) &&
537 (((strlen(InputBuffer
) > 1) && (InputBuffer
[1] == ' ')) ||
538 (strlen(InputBuffer
) == 1)))
540 DoLowerPriorityCommand(InputBuffer
);
542 else if (!(strncmp(InputBuffer
, "r", 1)) &&
543 (((strlen(InputBuffer
) > 1) && (InputBuffer
[1] == ' ')) ||
544 (strlen(InputBuffer
) == 1)))
546 DoRaisePriorityCommand(InputBuffer
);
548 else if (!(strncmp(InputBuffer
, "m", 1)) &&
549 (((strlen(InputBuffer
) > 1) && (InputBuffer
[1] == ' ')) ||
550 (strlen(InputBuffer
) == 1)))
552 DoLimitMemoryCommand(InputBuffer
);
554 else if (!(strncmp(InputBuffer
, "s", 1)) &&
555 (((strlen(InputBuffer
) > 1) && (InputBuffer
[1] == ' ')) ||
556 (strlen(InputBuffer
) == 1)))
558 DoSetTimeCommand(InputBuffer
);
560 else if (!(strncmp(InputBuffer
, "i", 1)) &&
561 (((strlen(InputBuffer
) > 1) && (InputBuffer
[1] == ' ')) ||
562 (strlen(InputBuffer
) == 1)))
564 DoSetIpAddressCommand(InputBuffer
);
566 else if ((InputBuffer
[0] != '\n') && (InputBuffer
[0] != ANSI_NULL
))
568 SacPutSimpleMessage(SAC_UNKNOWN_COMMAND
);
574 ConMgrSerialPortConsumer(VOID
)
580 ULONG ReadBufferSize
, i
;
581 WCHAR StringBuffer
[2];
582 SAC_DBG(SAC_DBG_MACHINE
, "SAC TimerDpcRoutine: Entering.\n"); //bug
584 /* Acquire the manager lock and make sure a channel is selected */
585 SacAcquireMutexLock();
586 ASSERT(CurrentChannel
);
588 /* Read whatever came off the serial port */
589 for (Status
= SerialBufferGetChar(&Char
);
591 Status
= SerialBufferGetChar(&Char
))
593 /* If nothing came through, bail out */
594 if (Status
== STATUS_NO_DATA_DETECTED
) break;
596 /* Check if ESC was pressed */
599 /* Was it already pressed? */
602 /* First time ESC is pressed! Remember and reset TAB state */
603 InputInEscTab
= FALSE
;
604 InputInEscape
= TRUE
;
608 else if (Char
== '\t')
610 /* TAB was pressed, is it following ESC (VT-100 sequence)? */
613 /* Yes! This must be the only ESC-TAB we see in once moment */
614 ASSERT(InputInEscTab
== FALSE
);
616 /* No longer treat us as being in ESC */
617 InputInEscape
= FALSE
;
619 /* ESC-TAB is the sequence for changing channels */
620 Status
= ConMgrAdvanceCurrentChannel();
621 if (!NT_SUCCESS(Status
)) break;
623 /* Remember ESC-TAB was pressed */
624 InputInEscTab
= TRUE
;
628 else if ((Char
== '0') && (InputInEscTab
))
630 /* It this ESC-TAB-0? */
631 ASSERT(InputInEscape
== FALSE
);
632 InputInEscTab
= FALSE
;
634 /* If writes are already enabled, don't do this */
635 if (!CurrentChannel
->WriteEnabled
)
637 /* Reset the channel, this is our special sequence */
638 Status
= ConMgrResetCurrentChannel(FALSE
);
639 if (!NT_SUCCESS(Status
)) break;
646 /* This is ESC-TAB-something else */
647 InputInEscTab
= FALSE
;
649 /* If writes are already enabled, don't do this */
650 if (!CurrentChannel
->WriteEnabled
)
652 /* Display the current channel */
653 InputInEscape
= FALSE
;
654 Status
= ConMgrDisplayCurrentChannel();
655 if (!NT_SUCCESS(Status
)) break;
660 /* Check if an ESC-sequence was being typed into a command channel */
661 if ((InputInEscape
) && (CurrentChannel
!= SacChannel
))
663 /* Store the ESC in the current channel buffer */
664 ReadBuffer
[0] = '\x1B';
665 ChannelIWrite(CurrentChannel
, ReadBuffer
, sizeof(CHAR
));
668 /* Check if we are no longer pressing ESC and exit the mode if so */
669 if (Char
!= '\x1B') InputInEscape
= FALSE
;
671 /* Whatever was typed in, save it int eh current channel */
672 ChannelIWrite(CurrentChannel
, &Char
, sizeof(Char
));
674 /* If this is a command channel, we're done, nothing to process */
675 if (CurrentChannel
!= SacChannel
) continue;
677 /* Check for line feed right after a carriage return */
678 if ((ConMgrLastCharWasCR
) && (Char
== '\n'))
680 /* Ignore the line feed, but clear the carriage return */
681 ChannelIReadLast(CurrentChannel
);
682 ConMgrLastCharWasCR
= 0;
686 /* Check if the user did a carriage return */
687 ConMgrLastCharWasCR
= (Char
== '\n');
689 /* If the user did an "ENTER", we need to run the command */
690 if ((Char
== '\n') || (Char
== '\r'))
692 /* Echo back to the terminal */
693 SacPutString(L
"\r\n");
696 /* Inhibit the character (either CR or LF) */
697 ChannelIReadLast(CurrentChannel
);
699 /* NULL-terminate the channel's input buffer */
700 ReadBuffer
[0] = ANSI_NULL
;
701 ChannelIWrite(CurrentChannel
, ReadBuffer
, sizeof(CHAR
));
703 /* Loop over every last character */
706 /* Read every character in the channel, and strip whitespace */
707 LastChar
= ChannelIReadLast(CurrentChannel
);
708 ReadBuffer
[0] = (CHAR
) LastChar
;
709 } while ((!(LastChar
) ||
710 (LastChar
== L
' ') ||
711 (LastChar
== L
'\t')) &&
712 (ChannelIBufferLength(CurrentChannel
)));
714 /* Write back into the channel the last character */
715 ChannelIWrite(CurrentChannel
, ReadBuffer
, sizeof(CHAR
));
717 /* NULL-terminate the input buffer */
718 ReadBuffer
[0] = ANSI_NULL
;
719 ChannelIWrite(CurrentChannel
, ReadBuffer
, sizeof(CHAR
));
721 /* Now loop over every first character */
724 /* Read every character in the channel, and strip whitespace */
725 ChannelIRead(CurrentChannel
,
729 } while ((ReadBufferSize
) &&
730 ((ReadBuffer
[0] == ' ') || (ReadBuffer
[0] == '\t')));
732 /* We read one more than we should, so treat that as our first one */
733 InputBuffer
[0] = ReadBuffer
[0];
736 /* And now loop reading all the others */
739 /* Read each character -- there should be max 80 */
740 ChannelIRead(CurrentChannel
,
744 ASSERT(i
< SAC_VTUTF8_COL_WIDTH
);
745 InputBuffer
[i
++] = ReadBuffer
[0];
746 } while (ReadBufferSize
);
748 /* Now go over the entire input stream */
749 for (i
= 0; InputBuffer
[i
]; i
++)
751 /* Again it should be less than 80 characters */
752 ASSERT(i
< SAC_VTUTF8_COL_WIDTH
);
754 /* And downbase each character */
755 Char
= InputBuffer
[i
];
756 if ((Char
>= 'A') && (Char
<= 'Z')) InputBuffer
[i
] = Char
+ ' ';
759 /* Ok, at this point, no pending command should exist */
760 ASSERT(ExecutePostConsumerCommand
== Nothing
);
762 /* Go and process the input, then show the prompt again */
763 ConMgrProcessInputLine();
764 SacPutSimpleMessage(SAC_PROMPT
);
766 /* If the user typed a valid command, get out of here */
767 if (ExecutePostConsumerCommand
!= Nothing
) break;
773 /* Check if the user typed backspace or delete */
774 if ((Char
== '\b') || (Char
== '\x7F'))
776 /* Omit the last character, which should be the DEL/BS itself */
777 if (ChannelIBufferLength(CurrentChannel
))
779 ChannelIReadLast(CurrentChannel
);
782 /* Omit the before-last character, which is the one to delete */
783 if (ChannelIBufferLength(CurrentChannel
))
785 /* Also send two backspaces back to the console */
786 SacPutString(L
"\b \b");
787 ChannelIReadLast(CurrentChannel
);
794 /* If the user pressed CTRL-C at this point, treat it like ENTER */
795 if (Char
== '\x03') goto DoLineParsing
;
797 /* Check if the user pressed TAB */
800 /* Omit it, send a BELL, and keep going. We ignore TABs */
801 ChannelIReadLast(CurrentChannel
);
806 /* Check if the user is getting close to the end of the screen */
807 if (ChannelIBufferLength(CurrentChannel
) == (SAC_VTUTF8_COL_WIDTH
- 2))
809 /* Delete the last character, replacing it with this one instead */
810 swprintf(StringBuffer
, L
"\b%c", Char
);
811 SacPutString(StringBuffer
);
813 /* Omit the last two characters from the buffer */
814 ChannelIReadLast(CurrentChannel
);
815 ChannelIReadLast(CurrentChannel
);
817 /* Write the last character that was just typed in */
818 ReadBuffer
[0] = Char
;
819 ChannelIWrite(CurrentChannel
, ReadBuffer
, sizeof(CHAR
));
823 /* Nothing of interest happened, just write the character back */
824 swprintf(StringBuffer
, L
"%c", Char
);
825 SacPutString(StringBuffer
);
828 /* We're done, release the lock */
829 SacReleaseMutexLock();
830 SAC_DBG(SAC_DBG_MACHINE
, "SAC TimerDpcRoutine: Exiting.\n"); //bug
835 ConMgrWorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension
)
837 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC WorkerProcessEvents: Entering.\n");
839 /* Enter the main loop */
842 /* Wait for something to do */
843 KeWaitForSingleObject(&DeviceExtension
->Event
,
849 /* Consume data off the serial port */
850 ConMgrSerialPortConsumer();
851 switch (ExecutePostConsumerCommand
)
854 /* A reboot was sent, do it */
855 DoRebootCommand(FALSE
);
859 /* A close was sent, do it */
860 ChanMgrCloseChannel(ExecutePostConsumerCommandData
);
861 ChanMgrReleaseChannel(ExecutePostConsumerCommandData
);
865 /* A shutdown was sent, do it */
866 DoRebootCommand(TRUE
);
870 /* Clear the serial port consumer state */
871 ExecutePostConsumerCommand
= Nothing
;
872 ExecutePostConsumerCommandData
= NULL
;
878 ConMgrGetChannelCloseMessage(IN PSAC_CHANNEL Channel
,
879 IN NTSTATUS CloseStatus
,
880 OUT PWCHAR OutputBuffer
)
883 return STATUS_NOT_IMPLEMENTED
;
888 ConMgrHandleEvent(IN ULONG EventCode
,
889 IN PSAC_CHANNEL Channel
,
893 return STATUS_NOT_IMPLEMENTED
;