788 lines
19 KiB
C
788 lines
19 KiB
C
#include <setupp.h>
|
|
|
|
DEFINE_GUID(
|
|
SAC_CHANNEL_GUI_MODE_DEBUG_GUID,
|
|
0x5ed3bac7, 0xa2f9, 0x4e45, 0x98, 0x75, 0xb2, 0x59, 0xea, 0x3f, 0x29, 0x1f
|
|
);
|
|
|
|
DEFINE_GUID(
|
|
SAC_CHANNEL_GUI_MODE_ERROR_LOG_GUID,
|
|
0x773d2759, 0x19b8, 0x4d6e, 0x80, 0x45, 0x26, 0xbf, 0x38, 0x40, 0x22, 0x52
|
|
);
|
|
|
|
DEFINE_GUID(
|
|
SAC_CHANNEL_GUI_MODE_ACTION_LOG_GUID,
|
|
0xd37c67ba, 0x89e7, 0x44ba, 0xae, 0x5a, 0x11, 0x2c, 0x68, 0x06, 0xb0, 0xdd
|
|
);
|
|
|
|
//
|
|
// The GUI-mode channels
|
|
//
|
|
SAC_CHANNEL_HANDLE SacChannelGuiModeDebugHandle;
|
|
BOOL SacChannelGuiModeDebugEnabled = FALSE;
|
|
SAC_CHANNEL_HANDLE SacChannelActionLogHandle;
|
|
BOOL SacChannelActionLogEnabled = FALSE;
|
|
SAC_CHANNEL_HANDLE SacChannelErrorLogHandle;
|
|
BOOL SacChannelErrorLogEnabled = FALSE;
|
|
|
|
PUCHAR Utf8ConversionBuffer = NULL;
|
|
ULONG Utf8ConversionBufferSize = 0;
|
|
|
|
//
|
|
// Define the max # of Unicode chars that can be translated with the
|
|
// given size of the utf8 translation buffer
|
|
//
|
|
#define MAX_UTF8_ENCODE_BLOCK_LENGTH ((Utf8ConversionBufferSize / 3) - 1)
|
|
|
|
VOID
|
|
SacChannelInitialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates and initializes all the GUI-mode channels
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
BOOL bSuccess;
|
|
SAC_CHANNEL_OPEN_ATTRIBUTES Attributes;
|
|
|
|
//
|
|
//
|
|
//
|
|
Utf8ConversionBufferSize = 512*3+3;
|
|
Utf8ConversionBuffer = malloc(Utf8ConversionBufferSize);
|
|
if (Utf8ConversionBuffer == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Configure the new channel
|
|
//
|
|
RtlZeroMemory(&Attributes, sizeof(SAC_CHANNEL_OPEN_ATTRIBUTES));
|
|
|
|
Attributes.Type = ChannelTypeRaw;
|
|
if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_DEBUG_NAME, Attributes.Name, ARRAYSIZE(Attributes.Name)) ) {
|
|
Attributes.Name[0] = L'\0';
|
|
}
|
|
if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_DEBUG_DESCRIPTION, Attributes.Description, ARRAYSIZE(Attributes.Description)) ) {
|
|
Attributes.Description[0] = L'\0';
|
|
}
|
|
Attributes.ApplicationType = SAC_CHANNEL_GUI_MODE_DEBUG_GUID;
|
|
|
|
//
|
|
// Create a channel for the GUI Mode Debug spew
|
|
//
|
|
bSuccess = SacChannelOpen(
|
|
&SacChannelGuiModeDebugHandle,
|
|
&Attributes
|
|
);
|
|
|
|
|
|
if (bSuccess) {
|
|
|
|
//
|
|
// We can now use this channel
|
|
//
|
|
SacChannelGuiModeDebugEnabled = TRUE;
|
|
|
|
SetupDebugPrint(L"Successfully opened GuiModeDebug channel\n");
|
|
|
|
} else {
|
|
SetupDebugPrint(L"Failed to open GuiModeDebug channel\n");
|
|
}
|
|
|
|
//
|
|
// Configure the new channel
|
|
//
|
|
RtlZeroMemory(&Attributes, sizeof(SAC_CHANNEL_OPEN_ATTRIBUTES));
|
|
|
|
Attributes.Type = ChannelTypeRaw;
|
|
if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ACTION_LOG_NAME, Attributes.Name, ARRAYSIZE(Attributes.Name)) ) {
|
|
Attributes.Name[0] = L'\0';
|
|
}
|
|
if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ACTION_LOG_DESCRIPTION, Attributes.Description, ARRAYSIZE(Attributes.Description)) ) {
|
|
Attributes.Description[0] = L'\0';
|
|
}
|
|
Attributes.ApplicationType = SAC_CHANNEL_GUI_MODE_ACTION_LOG_GUID;
|
|
|
|
//
|
|
// Create a channel for the Action Log spew
|
|
//
|
|
bSuccess = SacChannelOpen(
|
|
&SacChannelActionLogHandle,
|
|
&Attributes
|
|
);
|
|
|
|
|
|
if (bSuccess) {
|
|
|
|
//
|
|
// We can now use this channel
|
|
//
|
|
SacChannelActionLogEnabled = TRUE;
|
|
|
|
SetupDebugPrint(L"Successfully opened ActionLog channel\n");
|
|
|
|
} else {
|
|
SetupDebugPrint(L"Failed to open ActionLog channel\n");
|
|
}
|
|
|
|
|
|
//
|
|
// Configure the new channel
|
|
//
|
|
RtlZeroMemory(&Attributes, sizeof(SAC_CHANNEL_OPEN_ATTRIBUTES));
|
|
|
|
Attributes.Type = ChannelTypeRaw;
|
|
if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ERROR_LOG_NAME, Attributes.Name, ARRAYSIZE(Attributes.Name)) ) {
|
|
Attributes.Name[0] = L'\0';
|
|
}
|
|
if( !LoadString(MyModuleHandle, IDS_SAC_GUI_MODE_ERROR_LOG_DESCRIPTION, Attributes.Description, ARRAYSIZE(Attributes.Description)) ) {
|
|
Attributes.Description[0] = L'\0';
|
|
}
|
|
Attributes.ApplicationType = SAC_CHANNEL_GUI_MODE_ERROR_LOG_GUID;
|
|
|
|
//
|
|
// Create a channel for the Error Log spew
|
|
//
|
|
bSuccess = SacChannelOpen(
|
|
&SacChannelErrorLogHandle,
|
|
&Attributes
|
|
);
|
|
|
|
if (bSuccess) {
|
|
|
|
//
|
|
// We can now use this channel
|
|
//
|
|
SacChannelErrorLogEnabled = TRUE;
|
|
|
|
SetupDebugPrint(L"Successfully opened ErrorLog channel\n");
|
|
|
|
} else {
|
|
SetupDebugPrint(L"Failed to open ErrorLog channel\n");
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
SacChannelTerminate(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine closes all the GUI-mode setup channels
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// If the channel is enabled,
|
|
// then attempt to close it
|
|
//
|
|
if (SacChannelActionLogEnabled) {
|
|
|
|
//
|
|
// This channel is no longer available
|
|
//
|
|
SacChannelActionLogEnabled = FALSE;
|
|
|
|
//
|
|
// Attempt to close the channel
|
|
//
|
|
if (SacChannelClose(&SacChannelActionLogHandle)) {
|
|
SetupDebugPrint(L"Successfully closed ActionLog channel\n");
|
|
} else {
|
|
SetupDebugPrint(L"Failed to close ActionLog channel\n");
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If the channel is enabled,
|
|
// then attempt to close it
|
|
//
|
|
if (SacChannelErrorLogEnabled) {
|
|
|
|
//
|
|
// This channel is no longer available
|
|
//
|
|
SacChannelErrorLogEnabled = FALSE;
|
|
|
|
//
|
|
// Attempt to close the channel
|
|
//
|
|
if (SacChannelClose(&SacChannelErrorLogHandle)) {
|
|
SetupDebugPrint(L"Successfully closed ErrorLog channel\n");
|
|
} else {
|
|
SetupDebugPrint(L"Failed to close ErrorLog channel\n");
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If the channel is enabled,
|
|
// then attempt to close it
|
|
//
|
|
if (SacChannelGuiModeDebugEnabled) {
|
|
|
|
//
|
|
// This channel is no longer available
|
|
//
|
|
SacChannelGuiModeDebugEnabled = FALSE;
|
|
|
|
//
|
|
// Attempt to close the channel
|
|
//
|
|
if (SacChannelClose(&SacChannelGuiModeDebugHandle)) {
|
|
SetupDebugPrint(L"Successfully closed GuiModeDebug channel\n");
|
|
} else {
|
|
SetupDebugPrint(L"Failed to close GuiModeDebug channel\n");
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// free the conversion buffer if necessary
|
|
//
|
|
if (Utf8ConversionBuffer != NULL) {
|
|
free(Utf8ConversionBuffer);
|
|
Utf8ConversionBuffer = NULL;
|
|
Utf8ConversionBufferSize = 0;
|
|
}
|
|
|
|
}
|
|
|
|
#if 0
|
|
BOOL
|
|
CopyAndInsertStringAtInterval(
|
|
IN PSTR SourceStr,
|
|
IN ULONG Interval,
|
|
IN PSTR InsertStr,
|
|
OUT PSTR *pDestStr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes a source string and inserts an
|
|
"interval string" at interval characters in the new
|
|
destination string.
|
|
|
|
Note: caller is responsible for releasing DestStr if successful
|
|
|
|
ex:
|
|
|
|
src "aaabbbccc"
|
|
interval string = "XYZ"
|
|
interval = 3
|
|
|
|
==> dest string == "aaaXYZbbbXYZccc"
|
|
|
|
Arguments:
|
|
|
|
SourceStr - the source string
|
|
Interval - spanning interval
|
|
InsertStr - the insert string
|
|
DestStr - the destination string
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
ULONG SrcLength;
|
|
ULONG DestLength;
|
|
ULONG DestSize;
|
|
ULONG InsertLength;
|
|
ULONG k;
|
|
ULONG l;
|
|
ULONG i;
|
|
PSTR DestStr;
|
|
ULONG IntervalCnt;
|
|
|
|
ASSERT(SourceStr);
|
|
ASSERT(Interval > 0);
|
|
ASSERT(InsertStr);
|
|
ASSERT(pDestStr > 0);
|
|
|
|
//
|
|
// the length of the insert string
|
|
//
|
|
InsertLength = strlen(InsertStr);
|
|
|
|
//
|
|
// Compute how large the destination string needs to be,
|
|
// including the source string and the interval strings.
|
|
//
|
|
// Note: if the srclength is an integer multiple of Interval
|
|
// then we need to subtract 1 from the # of partitions
|
|
//
|
|
SrcLength = strlen(SourceStr);
|
|
IntervalCnt = SrcLength / Interval;
|
|
if (SrcLength % Interval == 0) {
|
|
IntervalCnt = IntervalCnt > 0 ? IntervalCnt - 1 : IntervalCnt;
|
|
}
|
|
DestLength = SrcLength + (IntervalCnt * strlen(InsertStr));
|
|
DestSize = (DestLength + 1) * sizeof(UCHAR);
|
|
|
|
//
|
|
// Allocate the new destination string
|
|
//
|
|
DestStr = LocalAlloc(LPTR, DestSize);
|
|
if (!DestStr) {
|
|
return FALSE;
|
|
}
|
|
RtlZeroMemory(DestStr, DestSize);
|
|
|
|
//
|
|
// Initialize the pointers into the source and destination strings
|
|
//
|
|
l = 0;
|
|
i = 0;
|
|
|
|
do {
|
|
|
|
//
|
|
// k = # of characters to copy
|
|
//
|
|
// if Interval > # of characters left to copy,
|
|
// then k = # of characters left to copy
|
|
// else k = interval
|
|
//
|
|
k = Interval > (SrcLength - i) ? (SrcLength - i) : Interval;
|
|
|
|
//
|
|
// Copy k charactars to the destination buffer
|
|
//
|
|
strncpy(
|
|
&DestStr[l],
|
|
&SourceStr[i],
|
|
k
|
|
);
|
|
|
|
//
|
|
// Account for how many characters we just copied
|
|
//
|
|
l += k;
|
|
i += k;
|
|
|
|
//
|
|
// If there are any characters left to copy,
|
|
// then we need to insert the InsertString
|
|
// That is, we are at an interval.
|
|
//
|
|
if (i < SrcLength) {
|
|
|
|
//
|
|
// Insert the specified string at the interval
|
|
//
|
|
strcpy(
|
|
&DestStr[l],
|
|
InsertStr
|
|
);
|
|
|
|
//
|
|
// Account for how many characters we just copied
|
|
//
|
|
l += InsertLength;
|
|
|
|
}
|
|
|
|
} while ( i < SrcLength);
|
|
|
|
//
|
|
//
|
|
//
|
|
ASSERT(i == SrcLength);
|
|
ASSERT(l == DestLength);
|
|
ASSERT((l + 1) * sizeof(UCHAR) == DestSize);
|
|
|
|
//
|
|
// Send back the destination string
|
|
//
|
|
*pDestStr = DestStr;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
SacChannelWrappedWrite(
|
|
IN SAC_CHANNEL_HANDLE SacChannelHandle,
|
|
IN PCBYTE Buffer,
|
|
IN ULONG BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes a string and makes it wrap at 80 cols
|
|
and then sends the new string to the specified channel.
|
|
|
|
Arguments:
|
|
|
|
SacChannelHandle - the channel reference to received the data
|
|
Buffer - the string
|
|
BufferSize - the string size
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
BOOL bSuccess;
|
|
PSTR OutStr;
|
|
|
|
UNREFERENCED_PARAMETER(BufferSize);
|
|
|
|
bSuccess = CopyAndInsertStringAtInterval(
|
|
Buffer,
|
|
80,
|
|
"\r\n",
|
|
&OutStr
|
|
);
|
|
|
|
if (bSuccess) {
|
|
|
|
bSuccess = SacChannelRawWrite(
|
|
SacChannelHandle,
|
|
OutStr,
|
|
strlen(OutStr)*sizeof(UCHAR)
|
|
);
|
|
|
|
LocalFree(OutStr);
|
|
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
#endif
|
|
|
|
BOOLEAN
|
|
SacTranslateUnicodeToUtf8(
|
|
IN PCWSTR SourceBuffer,
|
|
IN ULONG SourceBufferLength,
|
|
IN PUCHAR DestinationBuffer,
|
|
IN ULONG DestinationBufferSize,
|
|
OUT PULONG UTF8Count,
|
|
OUT PULONG ProcessedCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine translates a Unicode string into a UFT8
|
|
encoded string.
|
|
|
|
Note: if the destination buffer is not large enough to hold
|
|
the entire encoded UFT8 string, then it will contain
|
|
as much as can fit.
|
|
|
|
TODO: this routine should return some notification if
|
|
the entire Unicode string was not encoded.
|
|
|
|
Arguments:
|
|
|
|
SourceBuffer - the source Unicode string
|
|
SourceBufferLength - the # of characters the caller wants to translate
|
|
note: a NULL termination overrides this
|
|
DestinationBuffer - the destination for the UTF8 string
|
|
DestinationBufferSize - the size of the destination buffer
|
|
UTF8Count - on exit, contains the # of resulting UTF8 characters
|
|
ProcessedCount - on exit, contains the # of processed Unicode characters
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Init
|
|
//
|
|
*UTF8Count = 0;
|
|
*ProcessedCount = 0;
|
|
|
|
//
|
|
// convert into UTF8 for actual transmission
|
|
//
|
|
// UTF-8 encodes 2-byte Unicode characters as follows:
|
|
// If the first nine bits are zero (00000000 0xxxxxxx), encode it as one byte 0xxxxxxx
|
|
// If the first five bits are zero (00000yyy yyxxxxxx), encode it as two bytes 110yyyyy 10xxxxxx
|
|
// Otherwise (zzzzyyyy yyxxxxxx), encode it as three bytes 1110zzzz 10yyyyyy 10xxxxxx
|
|
//
|
|
|
|
//
|
|
// Process until one of the specified conditions is met
|
|
//
|
|
while (*SourceBuffer &&
|
|
(*UTF8Count < DestinationBufferSize) &&
|
|
(*ProcessedCount < SourceBufferLength)
|
|
) {
|
|
|
|
if( (*SourceBuffer & 0xFF80) == 0 ) {
|
|
|
|
//
|
|
// if the top 9 bits are zero, then just
|
|
// encode as 1 byte. (ASCII passes through unchanged).
|
|
//
|
|
DestinationBuffer[(*UTF8Count)++] = (UCHAR)(*SourceBuffer & 0x7F);
|
|
|
|
} else if( (*SourceBuffer & 0xF800) == 0 ) {
|
|
|
|
//
|
|
// see if we pass the end of the buffer
|
|
//
|
|
if ((*UTF8Count + 2) >= DestinationBufferSize) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// if the top 5 bits are zero, then encode as 2 bytes
|
|
//
|
|
DestinationBuffer[(*UTF8Count)++] = (UCHAR)((*SourceBuffer >> 6) & 0x1F) | 0xC0;
|
|
DestinationBuffer[(*UTF8Count)++] = (UCHAR)(*SourceBuffer & 0xBF) | 0x80;
|
|
|
|
} else {
|
|
|
|
//
|
|
// see if we pass the end of the buffer
|
|
//
|
|
if ((*UTF8Count + 3) >= DestinationBufferSize) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// encode as 3 bytes
|
|
//
|
|
DestinationBuffer[(*UTF8Count)++] = (UCHAR)((*SourceBuffer >> 12) & 0xF) | 0xE0;
|
|
DestinationBuffer[(*UTF8Count)++] = (UCHAR)((*SourceBuffer >> 6) & 0x3F) | 0x80;
|
|
DestinationBuffer[(*UTF8Count)++] = (UCHAR)(*SourceBuffer & 0xBF) | 0x80;
|
|
|
|
}
|
|
|
|
//
|
|
// Advance the # of characters processed
|
|
//
|
|
(*ProcessedCount)++;
|
|
|
|
//
|
|
// Advanced to the next character to process
|
|
//
|
|
SourceBuffer += 1;
|
|
|
|
}
|
|
|
|
//
|
|
// Sanity checks
|
|
//
|
|
ASSERT(*ProcessedCount <= SourceBufferLength);
|
|
ASSERT(*UTF8Count <= DestinationBufferSize);
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
BOOL
|
|
SacChannelUnicodeWrite(
|
|
IN SAC_CHANNEL_HANDLE SacChannelHandle,
|
|
IN PCWSTR String
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a wrapper routine for sending data to a channel. That is,
|
|
we can use this routine to modify the string before we send it off
|
|
without having to modify the callers.
|
|
|
|
This is a convenience routine to simplify
|
|
UFT8 encoding and sending a Unicode string.
|
|
|
|
Arguments:
|
|
|
|
Channel - Previously created channel.
|
|
String - Output string.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, otherwise status
|
|
|
|
--*/
|
|
{
|
|
BOOL bStatus;
|
|
ULONG Length;
|
|
ULONG i;
|
|
ULONG k;
|
|
ULONG j;
|
|
ULONG TranslatedCount;
|
|
ULONG UTF8TranslationSize;
|
|
PCWSTR pwch;
|
|
|
|
ASSERT(String);
|
|
|
|
//
|
|
// Determine the total # of WCHARs to process
|
|
//
|
|
Length = wcslen(String);
|
|
|
|
//
|
|
// Do nothing if there is nothing to do
|
|
//
|
|
if (Length == 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Point to the beginning of the string
|
|
//
|
|
pwch = (PCWSTR)String;
|
|
|
|
//
|
|
// default:
|
|
//
|
|
bStatus = TRUE;
|
|
|
|
//
|
|
// Divide the incoming buffer into blocks of length
|
|
// MAX_UTF8_ENCODE_BLOCK_LENGTH.
|
|
//
|
|
do {
|
|
|
|
//
|
|
// Determine the remainder
|
|
//
|
|
k = Length % MAX_UTF8_ENCODE_BLOCK_LENGTH;
|
|
|
|
if (k > 0) {
|
|
|
|
//
|
|
// Translate the first k characters
|
|
//
|
|
bStatus = SacTranslateUnicodeToUtf8(
|
|
pwch,
|
|
k,
|
|
Utf8ConversionBuffer,
|
|
Utf8ConversionBufferSize,
|
|
&UTF8TranslationSize,
|
|
&TranslatedCount
|
|
);
|
|
|
|
//
|
|
// If this assert hits, it is probably caused by
|
|
// a premature NULL termination in the incoming string
|
|
//
|
|
ASSERT(k == TranslatedCount);
|
|
|
|
if (!bStatus) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Send the UTF8 encoded characters
|
|
//
|
|
bStatus = SacChannelRawWrite(
|
|
SacChannelHandle,
|
|
Utf8ConversionBuffer,
|
|
UTF8TranslationSize
|
|
);
|
|
|
|
if (! bStatus) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Adjust the pwch to account for the sent length
|
|
//
|
|
pwch += k;
|
|
|
|
}
|
|
|
|
//
|
|
// Determine the # of blocks we can process
|
|
//
|
|
j = Length / MAX_UTF8_ENCODE_BLOCK_LENGTH;
|
|
|
|
//
|
|
// Translate each WCHAR to UTF8 individually. This way,
|
|
// no matter how big the String is, we don't run into
|
|
// buffer size problems (it just might take a while).
|
|
//
|
|
for (i = 0; i < j; i++) {
|
|
|
|
//
|
|
// Encode the next block
|
|
//
|
|
bStatus = SacTranslateUnicodeToUtf8(
|
|
pwch,
|
|
MAX_UTF8_ENCODE_BLOCK_LENGTH,
|
|
Utf8ConversionBuffer,
|
|
Utf8ConversionBufferSize,
|
|
&UTF8TranslationSize,
|
|
&TranslatedCount
|
|
);
|
|
|
|
//
|
|
// If this assert hits, it is probably caused by
|
|
// a premature NULL termination in the incoming string
|
|
//
|
|
ASSERT(MAX_UTF8_ENCODE_BLOCK_LENGTH == TranslatedCount);
|
|
|
|
if (! bStatus) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Adjust the pwch to account for the sent length
|
|
//
|
|
pwch += MAX_UTF8_ENCODE_BLOCK_LENGTH;
|
|
|
|
//
|
|
// Send the UTF8 encoded characters
|
|
//
|
|
bStatus = SacChannelRawWrite(
|
|
SacChannelHandle,
|
|
Utf8ConversionBuffer,
|
|
UTF8TranslationSize
|
|
);
|
|
|
|
if (! bStatus) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
//
|
|
// Validate that the pwch pointer stopped at the end of the buffer
|
|
//
|
|
ASSERT(pwch == (String + Length));
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
|