Sorry for the long post, but here's my solution (there is a companion wide string set of functions as well.) The DT... is my library prefix.
There are similar looking functions in Microsoft safe string library, but I was able to cause every one of them to throw exceptions in common scenarios. This set of code had to run in a DLL which logged errors so it simple couldn't throw exceptions (though I suppose it could in very fringe cases.)
<br />#include <stdarg.h><br /><br />inline<br />char* DTSafeStrCopyLen(LPSTR pDst, LPCSTR pSrc, int len)<br />{<br /> if (pDst)<br /> {<br /> if (pSrc && len > 0)<br /> {<br /> while (len && *pSrc)<br /> {<br /> *pDst++ = *pSrc++;<br /> len--;<br /> }<br /> }<br /> *pDst = 0;<br /> }<br /> return pDst;<br />}<br /><br />inline<br />int DTSafeStrCopyLen2(LPSTR pDst, LPCSTR pSrc, int len)<br />{<br /> return DTSafeStrCopyLen(pDst, pSrc, len) - pDst;<br />}<br /><br />#pragma warning(disable:4702) // unreachable code<br /><br />int DTSafeFormatStringV(LPSTR pBuffer, int bufferLen, LPCSTR pFormat, va_list args)<br />{<br /> if (!pBuffer || bufferLen <= 0)<br /> return -1;<br /><br /> int returnLen = 0;<br /><br /> if (pFormat && *pFormat)<br /> {<br />#if _MSC_VER >= 8<br /> __try<br />#else<br /> try<br />#endif<br /> {<br /> returnLen = _vsnprintf(pBuffer, bufferLen, pFormat, args);<br /> if (returnLen < 0)<br /> {<br /> pBuffer[bufferLen - 1] = 0;<br /> returnLen = bufferLen - 1;<br /> }<br /> }<br />#if _MSC_VER >= 8<br /> __except (EXCEPTION_EXECUTE_HANDLER)<br />#else<br /> catch (...)<br />#endif<br /> {<br /> returnLen = DTSafeStrCopyLen2(pBuffer, "!exception thrown during formatting: \"", bufferLen);<br /> returnLen += DTSafeStrCopyLen2(&pBuffer[returnLen], pFormat, bufferLen - returnLen); <br /><br /> if (returnLen < bufferLen - 1)<br /> {<br /> pBuffer[returnLen++] = '"';<br /> pBuffer[returnLen] = 0;<br /> }<br /> }<br /> }<br /> else<br /> {<br /> pBuffer[0] = 0;<br /> }<br /><br /> return returnLen;<br />}<br /><br />int DTSafeFormatString(LPSTR pBuffer, int bufferLen, LPCSTR pFormat, ...)<br />{<br /> if (!pBuffer || bufferLen <= 0)<br /> return -1;<br /><br /> int returnLen = 0;<br /><br /> if (pFormat && *pFormat)<br /> {<br /> va_list args;<br /> va_start (args, pFormat);<br /> returnLen = DTSafeFormatStringV(pBuffer, bufferLen, pFormat, args);<br /> va_end (args);<br /> }<br /> else<br /> {<br /> pBuffer[0] = 0;<br /> }<br /><br /> return returnLen;<br />}<br />