mirror of https://github.com/lianthony/NT4.0
760 lines
21 KiB
760 lines
21 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
spdsputl.c
|
|
|
|
Abstract:
|
|
|
|
Text setup high-level display utility routines.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 30-July-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "spprecmp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// Indicate that if resources are not unicode, they should
|
|
// be interpreted as OEM characters.
|
|
//
|
|
#define OEM_RESOURCES
|
|
|
|
//
|
|
// This will be filled in at init time with the base address of the image
|
|
// containing the message resources.
|
|
// This implementation assumes that we are always executing in the context
|
|
// of that image!
|
|
//
|
|
|
|
PVOID ResourceImageBase;
|
|
|
|
|
|
PIMAGE_RESOURCE_DIRECTORY
|
|
pSpFindDirectoryEntry(
|
|
IN PIMAGE_RESOURCE_DIRECTORY Directory,
|
|
IN ULONG Id,
|
|
IN PIMAGE_RESOURCE_DIRECTORY SectionStart
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches through a resource directory for the given ID. Ignores entries
|
|
with actual names, only searches for ID. If the given ID is -1, the
|
|
first entry is returned.
|
|
|
|
Arguments:
|
|
|
|
Directory - Supplies the resource directory to search.
|
|
|
|
Id - Supplies the ID to search for. -1 means return the first ID found.
|
|
|
|
SectionStart - Supplies a pointer to the start of the resource section.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the found resource directory.
|
|
|
|
NULL for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY FoundDirectory;
|
|
|
|
FoundDirectory = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(Directory+1);
|
|
|
|
//
|
|
// Skip entries with names.
|
|
//
|
|
for (i=0;i<Directory->NumberOfNamedEntries;i++) {
|
|
++FoundDirectory;
|
|
}
|
|
|
|
//
|
|
// Search for matching ID.
|
|
//
|
|
for (i=0;i<Directory->NumberOfIdEntries;i++) {
|
|
if ((FoundDirectory->Name == Id) || (Id == (ULONG)-1)) {
|
|
//
|
|
// Found a match.
|
|
//
|
|
return((PIMAGE_RESOURCE_DIRECTORY)((PUCHAR)SectionStart +
|
|
(FoundDirectory->OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY)));
|
|
|
|
}
|
|
++FoundDirectory;
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpFindMessage(
|
|
IN ULONG MessageId,
|
|
OUT PMESSAGE_RESOURCE_ENTRY *MessageEntry
|
|
)
|
|
{
|
|
PIMAGE_SECTION_HEADER SectionHeader;
|
|
ULONG NumberOfSections;
|
|
ULONG ResourceOffset;
|
|
PIMAGE_RESOURCE_DIRECTORY ResourceDirectory;
|
|
PIMAGE_RESOURCE_DIRECTORY NextDirectory;
|
|
PMESSAGE_RESOURCE_DATA MessageData;
|
|
PMESSAGE_RESOURCE_BLOCK MessageBlock;
|
|
PMESSAGE_RESOURCE_ENTRY messageEntry;
|
|
PIMAGE_RESOURCE_DATA_ENTRY DataEntry;
|
|
ULONG NumberOfBlocks;
|
|
ULONG Index;
|
|
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
|
|
//
|
|
// First, locate the resource (.rsrc) section.
|
|
//
|
|
NtHeaders = RtlImageNtHeader(ResourceImageBase);
|
|
NumberOfSections = NtHeaders->FileHeader.NumberOfSections;
|
|
SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
|
|
ResourceDirectory = NULL;
|
|
|
|
while(NumberOfSections) {
|
|
if(!_stricmp(SectionHeader->Name, ".rsrc")) {
|
|
ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)SectionHeader->VirtualAddress;
|
|
ResourceOffset = SectionHeader->VirtualAddress;
|
|
break;
|
|
}
|
|
++SectionHeader;
|
|
--NumberOfSections;
|
|
}
|
|
|
|
if(!ResourceDirectory) {
|
|
return(FALSE);
|
|
}
|
|
|
|
ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResourceDirectory + (ULONG)ResourceImageBase);
|
|
|
|
//
|
|
// Search the directory. We are looking for the type RT_MESSAGETABLE (11)
|
|
//
|
|
NextDirectory = pSpFindDirectoryEntry(ResourceDirectory,(ULONG)RT_MESSAGETABLE,ResourceDirectory);
|
|
if(!NextDirectory) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Find the next directory. Should only be one entry here (nameid == 1)
|
|
//
|
|
NextDirectory = pSpFindDirectoryEntry(NextDirectory,1,ResourceDirectory);
|
|
if(!NextDirectory) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Find the language. We always assume there is only one language messagetable,
|
|
// so just return the first one.
|
|
//
|
|
DataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)pSpFindDirectoryEntry(NextDirectory,(ULONG)(-1),ResourceDirectory);
|
|
|
|
if(!DataEntry) {
|
|
return(FALSE);
|
|
}
|
|
|
|
MessageData = (PMESSAGE_RESOURCE_DATA)((PUCHAR)ResourceDirectory+DataEntry->OffsetToData-ResourceOffset);
|
|
|
|
NumberOfBlocks = MessageData->NumberOfBlocks;
|
|
MessageBlock = MessageData->Blocks;
|
|
while (NumberOfBlocks--) {
|
|
if((MessageId >= MessageBlock->LowId) && (MessageId <= MessageBlock->HighId)) {
|
|
|
|
//
|
|
// The requested ID is within this block, scan forward until
|
|
// we find it.
|
|
//
|
|
messageEntry = (PMESSAGE_RESOURCE_ENTRY)((PCHAR)MessageData + MessageBlock->OffsetToEntries);
|
|
Index = MessageId - MessageBlock->LowId;
|
|
while (Index--) {
|
|
messageEntry = (PMESSAGE_RESOURCE_ENTRY)((PUCHAR)messageEntry + messageEntry->Length);
|
|
}
|
|
*MessageEntry = messageEntry;
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Check the next block for this ID.
|
|
//
|
|
MessageBlock++;
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpRtlFormatMessage(
|
|
IN PWSTR MessageFormat,
|
|
IN ULONG MaximumWidth OPTIONAL,
|
|
IN BOOLEAN IgnoreInserts,
|
|
IN BOOLEAN ArgumentsAreAnsi,
|
|
IN BOOLEAN ArgumentsAreAnArray,
|
|
IN va_list *Arguments,
|
|
OUT PWSTR Buffer,
|
|
IN ULONG Length,
|
|
OUT PULONG ReturnLength OPTIONAL
|
|
)
|
|
{
|
|
ULONG Column;
|
|
int cchRemaining, cchWritten;
|
|
PULONG ArgumentsArray = (PULONG)Arguments;
|
|
ULONG rgInserts[ 100 ], cSpaces;
|
|
ULONG MaxInsert, CurInsert;
|
|
ULONG PrintParameterCount;
|
|
ULONG PrintParameter1;
|
|
ULONG PrintParameter2;
|
|
WCHAR PrintFormatString[ 32 ];
|
|
WCHAR c;
|
|
PWSTR s, s1;
|
|
PWSTR lpDst, lpDstBeg, lpDstLastSpace;
|
|
|
|
cchRemaining = Length / sizeof( WCHAR );
|
|
lpDst = Buffer;
|
|
MaxInsert = 0;
|
|
lpDstLastSpace = NULL;
|
|
Column = 0;
|
|
s = MessageFormat;
|
|
while (*s != UNICODE_NULL) {
|
|
if (*s == L'%') {
|
|
s++;
|
|
lpDstBeg = lpDst;
|
|
if (*s >= L'1' && *s <= L'9') {
|
|
CurInsert = *s++ - L'0';
|
|
if (*s >= L'0' && *s <= L'9') {
|
|
CurInsert = (CurInsert * 10) + (*s++ - L'0');
|
|
}
|
|
CurInsert -= 1;
|
|
|
|
PrintParameterCount = 0;
|
|
if (*s == L'!') {
|
|
s1 = PrintFormatString;
|
|
*s1++ = L'%';
|
|
s++;
|
|
while (*s != L'!') {
|
|
if (*s != UNICODE_NULL) {
|
|
if (s1 >= &PrintFormatString[ 31 ]) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
if (*s == L'*') {
|
|
if (PrintParameterCount++ > 1) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
*s1++ = *s++;
|
|
}
|
|
else {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
|
|
s++;
|
|
*s1 = UNICODE_NULL;
|
|
}
|
|
else {
|
|
wcscpy( PrintFormatString, L"%s" );
|
|
s1 = PrintFormatString + wcslen( PrintFormatString );
|
|
}
|
|
|
|
if (!IgnoreInserts && ARGUMENT_PRESENT( Arguments )) {
|
|
|
|
if (ArgumentsAreAnsi) {
|
|
if (s1[ -1 ] == L'c' && s1[ -2 ] != L'h'
|
|
&& s1[ -2 ] != L'w' && s1[ -2 ] != L'l') {
|
|
wcscpy( &s1[ -1 ], L"hc" );
|
|
}
|
|
else
|
|
if (s1[ -1 ] == L's' && s1[ -2 ] != L'h'
|
|
&& s1[ -2 ] != L'w' && s1[ -2 ] != L'l') {
|
|
wcscpy( &s1[ -1 ], L"hs" );
|
|
}
|
|
else if (s1[ -1 ] == L'S') {
|
|
s1[ -1 ] = L's';
|
|
}
|
|
else if (s1[ -1 ] == L'C') {
|
|
s1[ -1 ] = L'c';
|
|
}
|
|
}
|
|
|
|
while (CurInsert >= MaxInsert) {
|
|
if (ArgumentsAreAnArray) {
|
|
rgInserts[ MaxInsert++ ] = *((PULONG)Arguments)++;
|
|
}
|
|
else {
|
|
rgInserts[ MaxInsert++ ] = va_arg(*Arguments, ULONG);
|
|
}
|
|
}
|
|
|
|
s1 = (PWSTR)rgInserts[ CurInsert ];
|
|
PrintParameter1 = 0;
|
|
PrintParameter2 = 0;
|
|
if (PrintParameterCount > 0) {
|
|
if (ArgumentsAreAnArray) {
|
|
PrintParameter1 = rgInserts[ MaxInsert++ ] = *((PULONG)Arguments)++;
|
|
}
|
|
else {
|
|
PrintParameter1 = rgInserts[ MaxInsert++ ] = va_arg( *Arguments, ULONG );
|
|
}
|
|
|
|
if (PrintParameterCount > 1) {
|
|
if (ArgumentsAreAnArray) {
|
|
PrintParameter2 = rgInserts[ MaxInsert++ ] = *((PULONG)Arguments)++;
|
|
}
|
|
else {
|
|
PrintParameter2 = rgInserts[ MaxInsert++ ] = va_arg( *Arguments, ULONG );
|
|
}
|
|
}
|
|
}
|
|
|
|
cchWritten = _snwprintf( lpDst,
|
|
cchRemaining,
|
|
PrintFormatString,
|
|
s1,
|
|
PrintParameter1,
|
|
PrintParameter2
|
|
);
|
|
}
|
|
else
|
|
if (!wcscmp( PrintFormatString, L"%s" )) {
|
|
cchWritten = _snwprintf( lpDst,
|
|
cchRemaining,
|
|
L"%%%u",
|
|
CurInsert+1
|
|
);
|
|
}
|
|
else {
|
|
cchWritten = _snwprintf( lpDst,
|
|
cchRemaining,
|
|
L"%%%u!%s!",
|
|
CurInsert+1,
|
|
&PrintFormatString[ 1 ]
|
|
);
|
|
}
|
|
|
|
if ((cchRemaining -= cchWritten) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
lpDst += cchWritten;
|
|
}
|
|
else
|
|
if (*s == L'0') {
|
|
break;
|
|
}
|
|
else
|
|
if (!*s) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
else
|
|
if (*s == L'!') {
|
|
if ((cchRemaining -= 1) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
*lpDst++ = L'!';
|
|
s++;
|
|
}
|
|
else
|
|
if (*s == L't') {
|
|
if ((cchRemaining -= 1) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
if (Column % 8) {
|
|
Column = (Column + 7) & ~7;
|
|
}
|
|
else {
|
|
Column += 8;
|
|
}
|
|
|
|
lpDstLastSpace = lpDst;
|
|
*lpDst++ = L'\t';
|
|
s++;
|
|
}
|
|
else
|
|
if (*s == L'b') {
|
|
if ((cchRemaining -= 1) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
lpDstLastSpace = lpDst;
|
|
*lpDst++ = L' ';
|
|
s++;
|
|
}
|
|
else
|
|
if (*s == L'r') {
|
|
if ((cchRemaining -= 1) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
*lpDst++ = L'\r';
|
|
s++;
|
|
lpDstBeg = NULL;
|
|
}
|
|
else
|
|
if (*s == L'n') {
|
|
if ((cchRemaining -= 2) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
*lpDst++ = L'\r';
|
|
*lpDst++ = L'\n';
|
|
s++;
|
|
lpDstBeg = NULL;
|
|
}
|
|
else {
|
|
if ((cchRemaining -= 1) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
if (IgnoreInserts) {
|
|
if ((cchRemaining -= 1) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
*lpDst++ = L'%';
|
|
}
|
|
|
|
*lpDst++ = *s++;
|
|
}
|
|
|
|
if (lpDstBeg == NULL) {
|
|
lpDstLastSpace = NULL;
|
|
Column = 0;
|
|
}
|
|
else {
|
|
Column += lpDst - lpDstBeg;
|
|
}
|
|
}
|
|
else {
|
|
c = *s++;
|
|
if (c == L'\r' || c == L'\n') {
|
|
if (c == L'\r' && *s == L'\n') {
|
|
s++;
|
|
}
|
|
|
|
if (MaximumWidth != 0) {
|
|
lpDstLastSpace = lpDst;
|
|
c = L' ';
|
|
}
|
|
else {
|
|
c = L'\n';
|
|
}
|
|
}
|
|
|
|
|
|
if (c == L'\n') {
|
|
if ((cchRemaining -= 2) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
*lpDst++ = L'\r';
|
|
*lpDst++ = L'\n';
|
|
lpDstLastSpace = NULL;
|
|
Column = 0;
|
|
}
|
|
else {
|
|
if ((cchRemaining -= 1) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
if (c == L' ') {
|
|
lpDstLastSpace = lpDst;
|
|
}
|
|
|
|
*lpDst++ = c;
|
|
Column += 1;
|
|
}
|
|
}
|
|
|
|
if (MaximumWidth != 0 &&
|
|
MaximumWidth != 0xFFFFFFFF &&
|
|
Column >= MaximumWidth
|
|
) {
|
|
if (lpDstLastSpace != NULL) {
|
|
lpDstBeg = lpDstLastSpace;
|
|
while (*lpDstBeg == L' ' || *lpDstBeg == L'\t') {
|
|
lpDstBeg += 1;
|
|
if (lpDstBeg == lpDst) {
|
|
break;
|
|
}
|
|
}
|
|
while (lpDstLastSpace > Buffer) {
|
|
if (lpDstLastSpace[ -1 ] == L' ' || lpDstLastSpace[ -1 ] == L'\t') {
|
|
lpDstLastSpace -= 1;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
cSpaces = lpDstBeg - lpDstLastSpace;
|
|
if (cSpaces == 1) {
|
|
if ((cchRemaining -= 1) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
else
|
|
if (cSpaces > 2) {
|
|
cchRemaining += (cSpaces - 2);
|
|
}
|
|
|
|
memmove( lpDstLastSpace + 2,
|
|
lpDstBeg,
|
|
(lpDst - lpDstBeg) * sizeof( WCHAR )
|
|
);
|
|
*lpDstLastSpace++ = L'\r';
|
|
*lpDstLastSpace++ = L'\n';
|
|
Column = lpDst - lpDstBeg;
|
|
lpDst = lpDstLastSpace + Column;
|
|
lpDstLastSpace = NULL;
|
|
}
|
|
else {
|
|
if ((cchRemaining -= 2) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
*lpDst++ = L'\r';
|
|
*lpDst++ = L'\n';
|
|
lpDstLastSpace = NULL;
|
|
Column = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((cchRemaining -= 1) <= 0) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
*lpDst++ = '\0';
|
|
if ( ARGUMENT_PRESENT(ReturnLength) ) {
|
|
*ReturnLength = (lpDst - Buffer) * sizeof( WCHAR );
|
|
}
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
PWCHAR
|
|
SpRetreiveMessageText(
|
|
IN ULONG MessageId,
|
|
IN OUT PWCHAR MessageText, OPTIONAL
|
|
IN ULONG MessageTextBufferSize OPTIONAL
|
|
)
|
|
{
|
|
ULONG LenBytes;
|
|
PMESSAGE_RESOURCE_ENTRY MessageEntry;
|
|
BOOLEAN IsUnicode;
|
|
#ifdef OEM_RESOURCES
|
|
OEM_STRING OemString;
|
|
#else
|
|
ANSI_STRING AnsiString;
|
|
#endif
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
if(!SpFindMessage(MessageId,&MessageEntry)) {
|
|
KdPrint(("SETUP: Can't find message 0x%lx\n",MessageId));
|
|
return(NULL);
|
|
}
|
|
|
|
IsUnicode = (BOOLEAN)((MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE) != 0);
|
|
|
|
//
|
|
// Get the size in bytes of a buffer large enough to hold the
|
|
// message and its terminating nul wchar. If the message is
|
|
// unicode, then this value is equal to the size of the message.
|
|
// If the message is not unicode, then we have to calculate this value.
|
|
//
|
|
if(IsUnicode) {
|
|
|
|
LenBytes = (wcslen((PWSTR)MessageEntry->Text) + 1) * sizeof(WCHAR);
|
|
|
|
} else {
|
|
|
|
#ifdef OEM_RESOURCES
|
|
//
|
|
// RtlOemStringToUnicodeSize includes an implied wide-nul terminator
|
|
// in the count it returns.
|
|
//
|
|
|
|
OemString.Buffer = MessageEntry->Text;
|
|
OemString.Length = (USHORT)strlen(MessageEntry->Text);
|
|
OemString.MaximumLength = OemString.Length;
|
|
|
|
LenBytes = RtlOemStringToUnicodeSize(&OemString);
|
|
#else
|
|
//
|
|
// RtlAnsiStringToUnicodeSize includes an implied wide-nul terminator
|
|
// in the count it returns.
|
|
//
|
|
|
|
AnsiString.Buffer = MessageEntry->Text;
|
|
AnsiString.Length = (USHORT)strlen(MessageEntry->Text);
|
|
AnsiString.MaximumLength = AnsiString.Length;
|
|
|
|
LenBytes = RtlAnsiStringToUnicodeSize(&AnsiString);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// If the caller gave a buffer, check its size.
|
|
// Otherwise, allocate a buffer.
|
|
//
|
|
if(MessageText) {
|
|
if(MessageTextBufferSize < LenBytes) {
|
|
KdPrint(("SETUP: SpRetreiveMessageText: buffer is too small (%u bytes, need %u)\n",MessageTextBufferSize,LenBytes));
|
|
return(NULL);
|
|
}
|
|
} else {
|
|
MessageText = SpMemAlloc(LenBytes);
|
|
if(MessageText == NULL) {
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
if(IsUnicode) {
|
|
|
|
//
|
|
// Message is already unicode; just copy it into the buffer.
|
|
//
|
|
wcscpy(MessageText,(PWSTR)MessageEntry->Text);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Message is not unicode; convert in into the buffer.
|
|
//
|
|
UnicodeString.Buffer = MessageText;
|
|
UnicodeString.Length = 0;
|
|
UnicodeString.MaximumLength = (USHORT)LenBytes;
|
|
|
|
#ifdef OEM_RESOURCES
|
|
RtlOemStringToUnicodeString(
|
|
&UnicodeString,
|
|
&OemString,
|
|
FALSE
|
|
);
|
|
#else
|
|
RtlAnsiStringToUnicodeString(
|
|
&UnicodeString,
|
|
&AnsiString,
|
|
FALSE
|
|
);
|
|
#endif
|
|
}
|
|
|
|
return(MessageText);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
vSpFormatMessageText(
|
|
OUT PVOID LargeBuffer,
|
|
IN ULONG BufferSize,
|
|
IN PWSTR MessageText,
|
|
OUT PULONG ReturnLength, OPTIONAL
|
|
IN va_list arglist
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = SpRtlFormatMessage(
|
|
MessageText,
|
|
0, // don't bother with maximum width
|
|
FALSE, // don't ignore inserts
|
|
FALSE, // args are unicode
|
|
FALSE, // args are not an array
|
|
&arglist,
|
|
LargeBuffer,
|
|
BufferSize,
|
|
ReturnLength
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SpFormatMessageText(
|
|
OUT PVOID LargeBuffer,
|
|
IN ULONG BufferSize,
|
|
IN PWSTR MessageText,
|
|
...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
|
|
va_start(arglist,MessageText);
|
|
|
|
vSpFormatMessageText(LargeBuffer,BufferSize,MessageText,NULL,arglist);
|
|
|
|
va_end(arglist);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
vSpFormatMessage(
|
|
OUT PVOID LargeBuffer,
|
|
IN ULONG BufferSize,
|
|
IN ULONG MessageId,
|
|
OUT PULONG ReturnLength, OPTIONAL
|
|
IN va_list arglist
|
|
)
|
|
{
|
|
PWCHAR MessageText;
|
|
|
|
//
|
|
// Get the message text.
|
|
//
|
|
MessageText = SpRetreiveMessageText(MessageId,NULL,0);
|
|
ASSERT(MessageText);
|
|
if(MessageText == NULL) {
|
|
KdPrint(("SETUP: vSpFormatMessage: SpRetreiveMessageText %u returned NULL\n",MessageId));
|
|
return;
|
|
}
|
|
|
|
vSpFormatMessageText(LargeBuffer,BufferSize,MessageText,ReturnLength,arglist);
|
|
|
|
SpMemFree(MessageText);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SpFormatMessage(
|
|
OUT PVOID LargeBuffer,
|
|
IN ULONG BufferSize,
|
|
IN ULONG MessageId,
|
|
...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
|
|
va_start(arglist,MessageId);
|
|
|
|
vSpFormatMessage(LargeBuffer,BufferSize,MessageId,NULL,arglist);
|
|
|
|
va_end(arglist);
|
|
}
|