// // 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); }