/******************************************************************** StrAnsiAllocFormattedArgs - allocates or reuses dynamic ANSI string memory and formats it with the passed in args NOTE: caller is responsible for freeing ppsz even if function fails ********************************************************************/ extern "C" HRESULT DAPI StrAnsiAllocFormattedArgs( __inout LPSTR* ppsz, __in LPCSTR szFormat, __in va_list args ) { Assert(ppsz && szFormat && *szFormat); HRESULT hr = S_OK; DWORD_PTR cch = *ppsz ? MemSize(*ppsz) / sizeof(CHAR) : 0; LPSTR pszOriginal = NULL; DWORD cchOriginal = 0; if (*ppsz) { cch = MemSize(*ppsz); // get the count in bytes so we can check if it failed (returns -1) if (-1 == cch) ExitOnFailure(hr = E_INVALIDARG, "failed to get size of destination string"); cch /= sizeof(CHAR); //convert the count in bytes to count in characters cchOriginal = lstrlenA(*ppsz); } if (0 == cch) // if there is no space in the string buffer { cch = 256; hr = StrAnsiAlloc(ppsz, cch); ExitOnFailure1(hr, "failed to allocate string to format: %s", szFormat); } // format the message (grow until it fits or there is a failure) do { hr = StringCchVPrintfA(*ppsz, cch, szFormat, args); if (STRSAFE_E_INSUFFICIENT_BUFFER == hr) { if (!pszOriginal) { // this allows you to pass the original string as a formatting argument and not crash // save the original string and free it after the printf is complete pszOriginal = *ppsz; *ppsz = NULL; // StringCchVPrintfW starts writing to the string... // NOTE: this hack only works with sprintf(&pwz, "%s ...", pwz, ...); pszOriginal[cchOriginal] = 0; } cch *= 2; hr = StrAnsiAlloc(ppsz, cch); ExitOnFailure1(hr, "failed to allocate string to format: %S", szFormat); hr = S_FALSE; } } while (S_FALSE == hr); ExitOnFailure(hr, "failed to format string"); LExit: ReleaseStr((void*) pszOriginal); return hr; }
/******************************************************************** ResReadStringAnsi NOTE: ppszString should be freed with StrFree() ********************************************************************/ extern "C" HRESULT DAPI ResReadStringAnsi( __in HINSTANCE hinst, __in UINT uID, __deref_out_z LPSTR* ppszString ) { Assert(hinst && ppszString); HRESULT hr = S_OK; DWORD cch = 64; // first guess DWORD cchReturned = 0; do { hr = StrAnsiAlloc(ppszString, cch); ExitOnFailureDebugTrace1(hr, "Failed to allocate string for resource id: %d", uID); #pragma prefast(push) #pragma prefast(disable:25068) cchReturned = ::LoadStringA(hinst, uID, *ppszString, cch); #pragma prefast(pop) if (0 == cchReturned) { ExitWithLastError1(hr, "Failed to load string resource id: %d", uID); } // if the returned string count is one character too small, it's likely we have // more data to read if (cchReturned + 1 == cch) { cch *= 2; hr = S_FALSE; } } while (S_FALSE == hr); ExitOnFailure1(hr, "failed to load string resource id: %d", uID); LExit: return hr; }