435 lines
12 KiB
C
435 lines
12 KiB
C
//
|
|
// Windows NT WOW v5
|
|
//
|
|
// fmtmsg.c -- 16-bit FormatMessage API, lifted from Win95
|
|
// \win\core\user\wn32rare.c by Dave Hart
|
|
//
|
|
//
|
|
|
|
#include "user.h"
|
|
|
|
typedef DWORD ULONG;
|
|
|
|
// from win95 user.h
|
|
#define CODESEG _based(_segname("_CODE"))
|
|
#define TESTFAR(p) SELECTOROF(p)
|
|
|
|
// from win95 dev\inc16\windows.h
|
|
#define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 /* ;Internal NT */
|
|
#define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 /* ;Internal NT */
|
|
#define FORMAT_MESSAGE_FROM_STRING 0x00000400 /* ;Internal NT */
|
|
#define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 /* ;Internal NT */
|
|
#define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 /* ;Internal NT */
|
|
//#define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x00002000 /* ;Internal */
|
|
#define FORMAT_MESSAGE_MAX_WIDTH_MASK 0x000000FF /* ;Internal NT */
|
|
#define FORMAT_MESSAGE_VALID 0x00003FFF /* ;Internal */
|
|
|
|
|
|
char CODESEG szStringFormat[] = "%s";
|
|
char CODESEG szStringFormat2[] = "%%%lu";
|
|
char CODESEG szStringFormat3[] = "%%%lu!%s!";
|
|
|
|
|
|
#if 0
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// GetSystemInstance()
|
|
//
|
|
// _loadds function to return hInstanceWin. Needed cuz FormatMessage can
|
|
// LocalAlloc a buffer for an app. We GlobalAlloc() a temp buffer to do the
|
|
// actual work in. Both local & global memory go away when the context that
|
|
// created it terminates.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
HINSTANCE NEAR _loadds FMGetSystemInstance(void)
|
|
{
|
|
return(hInstanceWin);
|
|
}
|
|
#endif
|
|
|
|
|
|
#undef LocalAlloc
|
|
#undef LocalFree
|
|
extern HLOCAL WINAPI LocalAlloc(UINT, UINT);
|
|
extern HLOCAL WINAPI LocalFree(HLOCAL);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// FormatMessage()
|
|
//
|
|
// 16-bit version of FormatMessage32().
|
|
//
|
|
// Note that this API is NOT _loadds. We might need to LocalAlloc() a buffer
|
|
// for the result. Therefore, we can't just use random static string vars.
|
|
// They _must_ be CODESEG.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
UINT _far _pascal FormatMessage(DWORD dwFlags, LPVOID lpSource, UINT idMessage,
|
|
UINT idLanguage, LPSTR lpResult, UINT cbResultMax, DWORD FAR * rglArgs)
|
|
{
|
|
LPSTR lpBuffer;
|
|
HINSTANCE hInstance;
|
|
UINT Column;
|
|
UINT MaximumWidth;
|
|
DWORD rgInserts[100];
|
|
WORD MaxInsert, CurInsert;
|
|
UINT cbNeeded, cbResult;
|
|
char szMessage[256];
|
|
LPSTR MessageFormat;
|
|
UINT cbMessage;
|
|
UINT PrintParameterCount;
|
|
DWORD PrintParameter1;
|
|
DWORD PrintParameter2;
|
|
char PrintFormatString[32];
|
|
LPSTR s, s1, s1base;
|
|
LPSTR lpAlloc;
|
|
LPSTR lpDst, lpDstBeg;
|
|
|
|
//
|
|
// Force idLanguage to be 0 for 16-bit apps, for now...
|
|
//
|
|
if (idLanguage)
|
|
{
|
|
DebugErr(DBF_ERROR, "FormatMessage: language id must be 0");
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// Prevent NULL lpResult
|
|
//
|
|
if (!TESTFAR(lpResult))
|
|
{
|
|
DebugErr(DBF_ERROR, "FormatMessage: NULL result buffer");
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// Prevent caller from using non-defined flags...
|
|
//
|
|
if (dwFlags & ~FORMAT_MESSAGE_VALID)
|
|
{
|
|
DebugErr(DBF_ERROR, "FormatMessage: invalid flags");
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// Get temporary buffer.
|
|
//
|
|
if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
|
|
cbResultMax = 0x7FFE;
|
|
|
|
lpBuffer = MAKELP(GlobalAlloc(GHND, (DWORD)cbResultMax+1), 0);
|
|
if (!SELECTOROF(lpBuffer))
|
|
{
|
|
DebugErr(DBF_ERROR, "FormatMessage: Couldn't allocate enough memory");
|
|
return(0);
|
|
}
|
|
|
|
lpAlloc = NULL;
|
|
cbResult = 0;
|
|
|
|
MaximumWidth = LOWORD(dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK);
|
|
|
|
//
|
|
// Get message string
|
|
//
|
|
if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
|
|
{
|
|
if (!TESTFAR(lpSource))
|
|
{
|
|
DebugErr(DBF_ERROR, "FormatMessage: NULL format string");
|
|
goto FailureExit;
|
|
}
|
|
|
|
MessageFormat = lpSource;
|
|
cbMessage = lstrlen(MessageFormat);
|
|
}
|
|
else
|
|
{
|
|
if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)
|
|
{
|
|
hInstance = (HINSTANCE)OFFSETOF(lpSource);
|
|
if (!hInstance)
|
|
{
|
|
DebugErr(DBF_ERROR, "FormatMessage: NULL hInstance not allowed for 16 bits");
|
|
goto FailureExit;
|
|
}
|
|
}
|
|
else if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
|
|
#if 0
|
|
// This doesn't work on WOW and it's not worth
|
|
// fixing because our user.exe doesn't have any
|
|
// FormatMessage text as string resources.
|
|
hInstance = FMGetSystemInstance();
|
|
#else
|
|
{
|
|
DebugErr(DBF_ERROR, "FormatMessage: FORMAT_MESSAGE_FROM_SYSTEM");
|
|
goto FailureExit;
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
DebugErr(DBF_ERROR, "FormatMessage: Invalid source");
|
|
goto FailureExit;
|
|
}
|
|
|
|
//
|
|
// Load the string
|
|
//
|
|
cbMessage = LoadString(hInstance, idMessage, szMessage,
|
|
sizeof(szMessage)-1);
|
|
|
|
if (!cbMessage)
|
|
{
|
|
DebugErr(DBF_ERROR, "FormatMessage: Couldn't load source string");
|
|
goto FailureExit;
|
|
}
|
|
|
|
MessageFormat = (LPSTR)szMessage;
|
|
}
|
|
|
|
lpDst = lpBuffer;
|
|
MaxInsert = 0;
|
|
Column = 0;
|
|
s = MessageFormat;
|
|
|
|
while (*s)
|
|
{
|
|
if (*s == '%')
|
|
{
|
|
s++;
|
|
|
|
lpDstBeg = lpDst;
|
|
if (*s >= '1' && *s <= '9')
|
|
{
|
|
CurInsert = *s++ - '0';
|
|
if (*s >= '0' && *s <= '9')
|
|
{
|
|
CurInsert = (CurInsert * 10) + (*s++ - '0');
|
|
}
|
|
CurInsert--;
|
|
|
|
PrintParameterCount = 0;
|
|
if (*s == '!')
|
|
{
|
|
s1 = s1base = PrintFormatString;
|
|
*s1++ = '%';
|
|
s++;
|
|
while (*s != '!')
|
|
{
|
|
if (*s != '\0')
|
|
{
|
|
if (s1 >= (s1base + sizeof(PrintFormatString) - 1))
|
|
{
|
|
goto ParamError;
|
|
}
|
|
|
|
if (*s == '*')
|
|
{
|
|
if (PrintParameterCount++ > 1)
|
|
{
|
|
goto ParamError;
|
|
}
|
|
}
|
|
|
|
*s1++ = *s++;
|
|
}
|
|
else
|
|
{
|
|
ParamError:
|
|
DebugErr(DBF_ERROR, "FormatMessage: Invalid format string");
|
|
goto FailureExit;
|
|
}
|
|
}
|
|
|
|
s++;
|
|
*s1 = '\0';
|
|
}
|
|
else
|
|
{
|
|
lstrcpy(PrintFormatString, szStringFormat);
|
|
s1 = PrintFormatString + lstrlen(PrintFormatString);
|
|
}
|
|
|
|
if (!(dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) && TESTFAR(rglArgs))
|
|
{
|
|
while (CurInsert >= MaxInsert)
|
|
{
|
|
rgInserts[MaxInsert++] = *(rglArgs++);
|
|
}
|
|
|
|
s1 = (LPSTR)rgInserts[CurInsert];
|
|
PrintParameter1 = 0;
|
|
PrintParameter2 = 0;
|
|
if (PrintParameterCount > 0)
|
|
{
|
|
PrintParameter1 = rgInserts[MaxInsert++] = *(rglArgs++);
|
|
if (PrintParameterCount > 1)
|
|
{
|
|
PrintParameter2 = rgInserts[MaxInsert++] = *(rglArgs++);
|
|
}
|
|
}
|
|
|
|
lpDst += wsprintf(lpDst, PrintFormatString, s1,
|
|
PrintParameter1, PrintParameter2);
|
|
}
|
|
else if (!lstrcmp(PrintFormatString, szStringFormat))
|
|
{
|
|
lpDst += wsprintf(lpDst, szStringFormat2, CurInsert+1);
|
|
}
|
|
else
|
|
{
|
|
lpDst += wsprintf(lpDst, szStringFormat3, CurInsert+1,
|
|
(LPSTR)&PrintFormatString[1]);
|
|
}
|
|
}
|
|
else if (*s == '0')
|
|
break;
|
|
else if (!*s)
|
|
goto FailureExit;
|
|
else if (*s == '!')
|
|
{
|
|
*lpDst++ = '!';
|
|
s++;
|
|
}
|
|
else if (*s == 't')
|
|
{
|
|
*lpDst++ = '\t';
|
|
s++;
|
|
if (Column % 8)
|
|
{
|
|
Column = (Column + 7) & ~7;
|
|
}
|
|
else
|
|
{
|
|
Column += 8;
|
|
}
|
|
}
|
|
else if (*s == 'b')
|
|
{
|
|
*lpDst++ = ' ';
|
|
s++;
|
|
}
|
|
else if (*s == 'r')
|
|
{
|
|
*lpDst++ = '\r';
|
|
s++;
|
|
lpDstBeg = NULL;
|
|
}
|
|
else if (*s == '\n')
|
|
{
|
|
*lpDst++ = '\r';
|
|
*lpDst++ = '\n';
|
|
s++;
|
|
lpDstBeg = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS)
|
|
{
|
|
*lpDst++ = '%';
|
|
}
|
|
|
|
*lpDst++ = *s++;
|
|
}
|
|
|
|
if (!TESTFAR(lpDstBeg))
|
|
{
|
|
Column = 0;
|
|
}
|
|
else
|
|
{
|
|
Column += lpDst - lpDstBeg;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char c;
|
|
|
|
c = *s++;
|
|
if (c == '\r')
|
|
{
|
|
if (*s == '\n')
|
|
{
|
|
s++;
|
|
}
|
|
|
|
if (MaximumWidth)
|
|
{
|
|
c = ' ';
|
|
}
|
|
else
|
|
{
|
|
c = '\n';
|
|
}
|
|
}
|
|
|
|
if (c == '\n' || (c == ' ' && MaximumWidth &&
|
|
MaximumWidth != FORMAT_MESSAGE_MAX_WIDTH_MASK &&
|
|
Column >= MaximumWidth))
|
|
{
|
|
|
|
*lpDst++ = '\r';
|
|
*lpDst++ = '\n';
|
|
Column = 0;
|
|
}
|
|
else
|
|
{
|
|
*lpDst++ = c;
|
|
Column++;
|
|
}
|
|
}
|
|
}
|
|
|
|
*lpDst++ = 0;
|
|
cbNeeded = lpDst - lpBuffer;
|
|
|
|
if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
|
|
{
|
|
PSTR pstr;
|
|
|
|
*(PSTR FAR *)lpResult = NULL;
|
|
|
|
pstr = (PSTR)LocalAlloc(LPTR, cbNeeded);
|
|
|
|
if (!pstr)
|
|
{
|
|
DebugErr(DBF_ERROR, "FormatMessge: couldn't LocalAlloc memory for result");
|
|
goto FailureExit;
|
|
}
|
|
|
|
lpDst = lpAlloc = (LPSTR)pstr;
|
|
}
|
|
else if (cbNeeded > cbResultMax)
|
|
{
|
|
DebugErr(DBF_ERROR, "FormatMessage: passed in buffer is too small for result");
|
|
goto FailureExit;
|
|
}
|
|
else
|
|
{
|
|
lpDst = lpResult;
|
|
}
|
|
|
|
lstrcpyn(lpDst, lpBuffer, cbNeeded);
|
|
|
|
cbResult = --cbNeeded;
|
|
|
|
FailureExit:
|
|
if (TESTFAR(lpAlloc))
|
|
{
|
|
if (cbResult)
|
|
{
|
|
*(PSTR FAR *)lpResult = (PSTR)OFFSETOF(lpAlloc);
|
|
}
|
|
else
|
|
{
|
|
LocalFree((HANDLE)OFFSETOF(lpAlloc));
|
|
}
|
|
}
|
|
|
|
if (TESTFAR(lpBuffer))
|
|
GlobalFree((HANDLE)SELECTOROF(lpBuffer));
|
|
|
|
return(cbResult);
|
|
}
|