#include "stdafx.h" #define STRSAFE_NO_DEPRECATE #include #define CurAlloc Reserved[0] BOOL MultiString_Init(MultiString *ms, DWORD dwInitLen) { HANDLE hHeap = GetProcessHeap(); if (!ms) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (dwInitLen) { ms->CurAlloc = dwInitLen; ms->Values = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(LPTSTR) * dwInitLen); if (!ms->Values) return FALSE; ms->Count = 0; } else { // Otherwise, this amounts to a zero-out ZeroMemory(ms, sizeof(MultiString)); } return TRUE; } __inline static LPTSTR CreateStrCopy(LPCTSTR szStr) { HRESULT hrRes; LPTSTR szNewCopy; // dwLen needs to include the NULL terminator size_t dwLen = _tcslen(szStr) + 1; HANDLE hHeap = GetProcessHeap(); // Allocate the new string szNewCopy = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(TCHAR) * dwLen); if (!szNewCopy) return NULL; // Copy the actual data over hrRes = StringCchCopy(szNewCopy, dwLen, szStr); if (FAILED(hrRes)) { HeapFree(hHeap, 0, szNewCopy); return NULL; } return szNewCopy; } BOOL MultiString_Append(MultiString *ms, LPCTSTR szNew) { LPTSTR szNewCopy = NULL; DWORD dwNewLen; HANDLE hHeap = GetProcessHeap(); if (!ms || !szNew) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } dwNewLen = (DWORD)_tcslen(szNew) + 1; // Do we need to allocate more room for pointers? if (ms->Values == NULL) { // Oops, we have nothing! Let's allocate a couple if (!MultiString_Init(ms, 3)) { return FALSE; } } else if (ms->CurAlloc == ms->Count) { DWORD dwNewAlloc = ms->CurAlloc + 3; LPTSTR *pszNew = HeapReAlloc(hHeap, 0, ms->Values, sizeof(LPTSTR) * dwNewAlloc); if (!pszNew) { // ReAlloc failed :< return FALSE; } ms->CurAlloc = dwNewAlloc; ms->Values = pszNew; } szNewCopy = CreateStrCopy(szNew); if (!szNewCopy) return FALSE; // All set, append to the end and increment Count ms->Values[ms->Count++] = szNewCopy; ms->TotalLength += dwNewLen; return TRUE; } BOOL MultiString_Remove(MultiString *ms, DWORD dwIdx) { DWORD dwLen = 0; HANDLE hHeap = GetProcessHeap(); if (!ms) return FALSE; if (dwIdx >= ms->Count) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } else if (ms->Values[dwIdx] != NULL) { dwLen = (DWORD)_tcslen(ms->Values[dwIdx]) + 1; HeapFree(hHeap, 0, ms->Values[dwIdx]); } // Shift down the remaining strings if (dwIdx < ms->Count - 1) { size_t i; for (i = dwIdx; i < ms->Count - 1; i++) { ms->Values[i] = ms->Values[i + 1]; } } ms->Count--; ms->TotalLength -= dwLen; return TRUE; } BOOL MultiString_Replace(MultiString *ms, DWORD dwIdx, LPCTSTR szNew) { DWORD dwOldLen = 0, dwNewLen = 0; LPTSTR szTmp; HANDLE hHeap = GetProcessHeap(); if (!ms || !szNew) return FALSE; if (dwIdx >= ms->Count) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } dwNewLen = (DWORD)_tcslen(szNew) + 1; // Create the copied new string szTmp = CreateStrCopy(szNew); if (!szTmp) return FALSE; // Perform the switcheroo if (ms->Values[dwIdx] != NULL) { dwOldLen = (DWORD)_tcslen(ms->Values[dwIdx]) + 1; HeapFree(hHeap, 0, ms->Values[dwIdx]); } ms->Values[dwIdx] = szTmp; ms->TotalLength = ms->TotalLength + dwNewLen - dwOldLen; return TRUE; } void MultiString_Dispose(MultiString *ms) { HANDLE hHeap = GetProcessHeap(); DWORD i; if (!ms) return; if (ms->Values != NULL) { for (i = 0; i < ms->Count; i++) { HeapFree(hHeap, 0, ms->Values[i]); } HeapFree(hHeap, 0, ms->Values); ms->Values = NULL; } ms->Count = 0; ms->CurAlloc = 0; return; }