windows-nt/Source/XPSP1/NT/ds/netapi/netcmd/common/message.c

581 lines
14 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
message.c
Abstract:
This module provides support routines to map DosxxxMessage APIs to
the FormatMessage syntax and semantics.
Author:
Dan Hinsley (DanHi) 24-Sept-1991
Environment:
Contains NT specific code.
Revision History:
--*/
#define ERROR_MR_MSG_TOO_LONG 316
#define ERROR_MR_UN_ACC_MSGF 318
#define ERROR_MR_INV_IVCOUNT 320
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <limits.h>
#include <lmcons.h>
#include <lmerr.h>
#include <tstring.h>
#include "netascii.h"
#include "netcmds.h"
//
// Local function declarations
//
BOOL
FileIsConsole(
HANDLE fp
);
VOID
MyWriteConsole(
HANDLE fp,
LPWSTR lpBuffer,
DWORD cchBuffer
);
//
// 100 is plenty since FormatMessage only takes 99 & old DosGetMessage 9.
//
#define MAX_INSERT_STRINGS (100)
DWORD
DosGetMessageW(
IN LPTSTR *InsertionStrings,
IN DWORD NumberofStrings,
OUT LPTSTR Buffer,
IN DWORD BufferLength,
IN DWORD MessageId,
IN LPTSTR FileName,
OUT PDWORD pMessageLength
)
/*++
Routine Description:
This maps the OS/2 DosGetMessage API to the NT FormatMessage API.
Arguments:
InsertionStrings - Pointer to an array of strings that will be used
to replace the %n's in the message.
NumberofStrings - The number of insertion strings.
Buffer - The buffer to put the message into.
BufferLength - The length of the supplied buffer in characters.
MessageId - The message number to retrieve.
FileName - The name of the message file to get the message from.
pMessageLength - A pointer to return the length of the returned message.
Return Value:
NERR_Success
ERROR_MR_MSG_TOO_LONG
ERROR_MR_INV_IVCOUNT
ERROR_MR_UN_ACC_MSGF
ERROR_MR_MID_NOT_FOUND
ERROR_INVALID_PARAMETER
--*/
{
DWORD dwFlags = FORMAT_MESSAGE_ARGUMENT_ARRAY;
DWORD Status ;
TCHAR NumberString [18];
static HANDLE lpSource = NULL ;
static TCHAR CurrentMsgFile[MAX_PATH] = {0,} ;
//
// init clear the output string
//
Status = NERR_Success;
if (BufferLength)
Buffer[0] = NULLC ;
//
// make sure we are not over loaded & allocate
// memory for the Unicode buffer
//
if (NumberofStrings > MAX_INSERT_STRINGS)
return ERROR_INVALID_PARAMETER ;
//
// See if they want to get the message from the system message file.
//
if (! STRCMP(FileName, OS2MSG_FILENAME)) {
dwFlags |= FORMAT_MESSAGE_FROM_SYSTEM;
}
else
{
//
// They want it from a separate message file. Get a handle to DLL
// If its for the same file as before, dont reload.
//
if (!(lpSource && !STRCMP(CurrentMsgFile, FileName)))
{
if (lpSource)
{
FreeLibrary(lpSource) ;
}
STRCPY(CurrentMsgFile, FileName) ;
lpSource = LoadLibrary(FileName);
if (!lpSource)
{
return ERROR_MR_UN_ACC_MSGF;
}
}
dwFlags |= FORMAT_MESSAGE_FROM_HMODULE;
}
//
// If they just want to get the message back for later formatting,
// ignore the insert strings.
//
if (NumberofStrings == 0)
{
dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS;
}
//
// call the Unicode version
//
*pMessageLength = FormatMessageW(dwFlags,
lpSource,
MessageId,
0, // LanguageId defaulted
Buffer,
BufferLength,
(va_list *) InsertionStrings);
//
// If it failed get the return code and map it to an OS/2 equivalent
//
if (*pMessageLength == 0)
{
Buffer[0] = 0 ;
Status = GetLastError();
if (Status == ERROR_MR_MID_NOT_FOUND)
{
//
// get the message number in Unicode
//
ultow(MessageId, NumberString, 16);
//
// re-setup to get it from the system. use the not found message
//
dwFlags = FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_FROM_SYSTEM;
MessageId = ERROR_MR_MID_NOT_FOUND ;
//
// setup insert strings
//
InsertionStrings[0] = NumberString ;
InsertionStrings[1] = FileName ;
//
// recall the API
//
*pMessageLength = FormatMessageW(dwFlags,
lpSource,
MessageId,
0, // LanguageId defaulted
Buffer,
BufferLength,
(va_list *) InsertionStrings);
InsertionStrings[1] = NULL ;
//
// revert to original error
//
Status = ERROR_MR_MID_NOT_FOUND ;
}
}
//
// note: NumberString don't need to be freed
// since if used, they would be in the InsertionStrings which is whacked
//
return Status;
}
DWORD
DosInsMessageW(
IN LPTSTR *InsertionStrings,
IN DWORD NumberofStrings,
IN OUT LPTSTR InputMessage,
IN DWORD InputMessageLength,
OUT LPTSTR Buffer,
IN DWORD BufferLength,
OUT PDWORD pMessageLength
)
/*++
Routine Description:
This maps the OS/2 DosInsMessage API to the NT FormatMessage API.
Arguments:
InsertionStrings - Pointer to an array of strings that will be used
to replace the %n's in the message.
NumberofStrings - The number of insertion strings.
InputMessage - A message with %n's to replace
InputMessageLength - The length in bytes of the input message.
Buffer - The buffer to put the message into.
BufferLength - The length of the supplied buffer in characters.
pMessageLength - A pointer to return the length of the returned message.
Return Value:
NERR_Success
ERROR_MR_INV_IVCOUNT
ERROR_MR_MSG_TOO_LONG
--*/
{
DWORD Status ;
DWORD dwFlags = FORMAT_MESSAGE_ARGUMENT_ARRAY;
UNREFERENCED_PARAMETER(InputMessageLength);
//
// init clear the output string
//
Status = NERR_Success;
if (BufferLength)
Buffer[0] = NULLC ;
//
// make sure we are not over loaded & allocate
// memory for the Unicode buffer
//
if (NumberofStrings > MAX_INSERT_STRINGS)
return ERROR_INVALID_PARAMETER ;
//
// This api always supplies the string to format
//
dwFlags |= FORMAT_MESSAGE_FROM_STRING;
//
// I don't know why they would call this api if they didn't have strings
// to insert, but it is valid syntax.
//
if (NumberofStrings == 0) {
dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS;
}
*pMessageLength = (WORD) FormatMessageW(dwFlags,
InputMessage,
0, // ignored
0, // LanguageId defaulted
Buffer,
BufferLength,
(va_list *)InsertionStrings);
//
// If it failed get the return code and map it to an OS/2 equivalent
//
if (*pMessageLength == 0)
{
Status = GetLastError();
goto ExitPoint ;
}
ExitPoint:
return Status;
}
VOID
DosPutMessageW(
HANDLE fp,
LPWSTR pch,
BOOL fPrintNL
)
{
MyWriteConsole(fp,
pch,
wcslen(pch));
//
// If there's a newline at the end of the string,
// print another one for formatting.
//
if (fPrintNL)
{
while (*pch && *pch != NEWLINE)
{
pch++;
}
if (*pch == NEWLINE)
{
MyWriteConsole(fp,
L"\r\n",
2);
}
}
}
/***
* PrintDependingOnLength()
*
* Prints out a string given to it padded to be as long as iLength. checks
* the positions of the cursor in the console window. if printing the string
* would go past the end of the window buffer, outputs a newline and tabs
* first unless the cursor is at the start of a line.
*
* Args:
* iLength - size of the string to be outputted. string will be padded
* if necessary
*
* OutputString - string to output
*
* Returns:
* returns the same value as iLength on success, -1 on failure
*/
int
PrintDependingOnLength(
IN int iLength,
IN LPTSTR OutputString
)
{
CONSOLE_SCREEN_BUFFER_INFO ThisConsole;
HANDLE hStdOut;
//
// save off iLength
//
int iReturn = iLength;
//
// Get the dimensions of the current window
//
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdOut != INVALID_HANDLE_VALUE)
{
//
//init this to INT_MAX - if we aren't able to get the console screen buffer
//info, then we are probably being piped to a text file (or somewhere else)
//and can assume that there is no "SpaceLeft" constraint
//
int iSpaceLeft = INT_MAX;
if (GetConsoleScreenBufferInfo(hStdOut, &ThisConsole))
{
//
//see how much space is left in the console buffer, if we were able to
//get the console info
//
iSpaceLeft = ThisConsole.dwSize.X - ThisConsole.dwCursorPosition.X;
}
//
// Print out string. if we will have to handle a wrapping
// column and we aren't at the beginning of a line, print a newline
// and tabs first for formatting.
//
if ((iLength > iSpaceLeft) && (ThisConsole.dwCursorPosition.X))
{
WriteToCon(TEXT("\n\t\t"));
}
WriteToCon(TEXT("%Fws"), PaddedString(iLength, OutputString, NULL));
}
else
{
iReturn = -1;
}
return iReturn;
}
/***
* FindColumnWidthAndPrintHeader()
*
* figures out what the correct width should be given a longest
* string and a ID for a fixed header string. result will always
* be whichever is longer. Once that width is figured, the function
* will output the header specified by HEADER_ID
*
* Args:
* iStringLength - integer which specifies the longest string length found
* in a set of strings that is going to be outputted to the console in a column
* (think the "share name" column when you do a net view <machinename>.
* since the arrays of strings used by net.exe tend to vary in type, this function
* assumes that you have alredy gone through and figured out which string is longest
*
* HEADER_ID - ID of the fixed string that will be the column header for
* that set of strings. We will figure out whichever one is longest and return
* that value (+ an optional TAB_DISTANCE)
*
* TAB_DISTANCE - distance that should the function should pad the string by
* when it outputs the header (Usually 2 for it to look decent)
*
* Returns:
* 0 or greater - success
*
* -1 - failure - dwHeaderID was 0, or the ID lookup failed
*/
int
FindColumnWidthAndPrintHeader(
int iStringLength,
const DWORD HEADER_ID,
const int TAB_DISTANCE
)
{
DWORD dwErr;
WCHAR MsgBuffer[LITTLE_BUF_SIZE];
DWORD dwMsgLen = sizeof(MsgBuffer) / sizeof(WCHAR);
int iResultLength = -1;
//
// First, we need the the string specified by HEADER_ID and its length
//
dwErr = DosGetMessageW(IStrings,
0,
MsgBuffer,
LITTLE_BUF_SIZE,
HEADER_ID,
MESSAGE_FILENAME,
&dwMsgLen);
if (!dwErr)
{
//
// Figure out which is longer - the string to
// display, or the column header
//
iResultLength = max((int) SizeOfHalfWidthString(MsgBuffer), iStringLength);
//
// Add the tab length we were given
//
iResultLength += TAB_DISTANCE;
iResultLength = PrintDependingOnLength(
iResultLength,
MsgBuffer
);
}
return iResultLength;
}
BOOL
FileIsConsole(
HANDLE fp
)
{
unsigned htype;
htype = GetFileType(fp);
htype &= ~FILE_TYPE_REMOTE;
return htype == FILE_TYPE_CHAR;
}
VOID
MyWriteConsole(
HANDLE fp,
LPWSTR lpBuffer,
DWORD cchBuffer
)
{
//
// Jump through hoops for output because:
//
// 1. printf() family chokes on international output (stops
// printing when it hits an unrecognized character)
//
// 2. WriteConsole() works great on international output but
// fails if the handle has been redirected (i.e., when the
// output is piped to a file)
//
// 3. WriteFile() works great when output is piped to a file
// but only knows about bytes, so Unicode characters are
// printed as two Ansi characters.
//
if (FileIsConsole(fp))
{
WriteConsole(fp, lpBuffer, cchBuffer, &cchBuffer, NULL);
}
else
{
LPSTR lpAnsiBuffer = (LPSTR) LocalAlloc(LMEM_FIXED, cchBuffer * sizeof(WCHAR));
if (lpAnsiBuffer != NULL)
{
cchBuffer = WideCharToMultiByte(CP_OEMCP,
0,
lpBuffer,
cchBuffer,
lpAnsiBuffer,
cchBuffer * sizeof(WCHAR),
NULL,
NULL);
if (cchBuffer != 0)
{
WriteFile(fp, lpAnsiBuffer, cchBuffer, &cchBuffer, NULL);
}
LocalFree(lpAnsiBuffer);
}
}
}