diff options
Diffstat (limited to 'src/dutil/reswutil.cpp')
| -rw-r--r-- | src/dutil/reswutil.cpp | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/src/dutil/reswutil.cpp b/src/dutil/reswutil.cpp new file mode 100644 index 00000000..e534fc09 --- /dev/null +++ b/src/dutil/reswutil.cpp | |||
| @@ -0,0 +1,368 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | #include "precomp.h" | ||
| 4 | |||
| 5 | #define RES_STRINGS_PER_BLOCK 16 | ||
| 6 | |||
| 7 | // Internal data structure format for a string block in a resource table. | ||
| 8 | // Note: Strings are always stored as UNICODED. | ||
| 9 | typedef struct _RES_STRING_BLOCK | ||
| 10 | { | ||
| 11 | DWORD dwBlockId; | ||
| 12 | WORD wLangId; | ||
| 13 | LPWSTR rgwz[RES_STRINGS_PER_BLOCK]; | ||
| 14 | } RES_STRING_BLOCK; | ||
| 15 | |||
| 16 | |||
| 17 | // private functions | ||
| 18 | static HRESULT StringBlockInitialize( | ||
| 19 | __in_opt HINSTANCE hModule, | ||
| 20 | __in DWORD dwBlockId, | ||
| 21 | __in WORD wLangId, | ||
| 22 | __in RES_STRING_BLOCK* pStrBlock | ||
| 23 | ); | ||
| 24 | static void StringBlockUnitialize( | ||
| 25 | __in RES_STRING_BLOCK* pStrBlock | ||
| 26 | ); | ||
| 27 | static HRESULT StringBlockChangeString( | ||
| 28 | __in RES_STRING_BLOCK* pStrBlock, | ||
| 29 | __in DWORD dwStringId, | ||
| 30 | __in_z LPCWSTR szData | ||
| 31 | ); | ||
| 32 | static HRESULT StringBlockConvertToResourceData( | ||
| 33 | __in const RES_STRING_BLOCK* pStrBlock, | ||
| 34 | __deref_out_bcount(*pcbData) LPVOID* ppvData, | ||
| 35 | __out DWORD* pcbData | ||
| 36 | ); | ||
| 37 | static HRESULT StringBlockConvertFromResourceData( | ||
| 38 | __in RES_STRING_BLOCK* pStrBlock, | ||
| 39 | __in_bcount(cbData) LPCVOID pvData, | ||
| 40 | __in SIZE_T cbData | ||
| 41 | ); | ||
| 42 | |||
| 43 | |||
| 44 | /******************************************************************** | ||
| 45 | ResWriteString - sets the string into to the specified file's resource name | ||
| 46 | |||
| 47 | ********************************************************************/ | ||
| 48 | extern "C" HRESULT DAPI ResWriteString( | ||
| 49 | __in_z LPCWSTR wzResourceFile, | ||
| 50 | __in DWORD dwDataId, | ||
| 51 | __in_z LPCWSTR wzData, | ||
| 52 | __in WORD wLangId | ||
| 53 | ) | ||
| 54 | { | ||
| 55 | Assert(wzResourceFile); | ||
| 56 | Assert(wzData); | ||
| 57 | |||
| 58 | HRESULT hr = S_OK; | ||
| 59 | HINSTANCE hModule = NULL; | ||
| 60 | HANDLE hUpdate = NULL; | ||
| 61 | RES_STRING_BLOCK StrBlock = { }; | ||
| 62 | LPVOID pvData = NULL; | ||
| 63 | DWORD cbData = 0; | ||
| 64 | |||
| 65 | DWORD dwBlockId = (dwDataId / RES_STRINGS_PER_BLOCK) + 1; | ||
| 66 | DWORD dwStringId = (dwDataId % RES_STRINGS_PER_BLOCK); | ||
| 67 | |||
| 68 | hModule = LoadLibraryExW(wzResourceFile, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); | ||
| 69 | ExitOnNullWithLastError(hModule, hr, "Failed to load library: %ls", wzResourceFile); | ||
| 70 | |||
| 71 | hr = StringBlockInitialize(hModule, dwBlockId, wLangId, &StrBlock); | ||
| 72 | ExitOnFailure(hr, "Failed to get string block to update."); | ||
| 73 | |||
| 74 | hr = StringBlockChangeString(&StrBlock, dwStringId, wzData); | ||
| 75 | ExitOnFailure(hr, "Failed to update string block string."); | ||
| 76 | |||
| 77 | hr = StringBlockConvertToResourceData(&StrBlock, &pvData, &cbData); | ||
| 78 | ExitOnFailure(hr, "Failed to convert string block to resource data."); | ||
| 79 | |||
| 80 | ::FreeLibrary(hModule); | ||
| 81 | hModule = NULL; | ||
| 82 | |||
| 83 | hUpdate = ::BeginUpdateResourceW(wzResourceFile, FALSE); | ||
| 84 | ExitOnNullWithLastError(hUpdate, hr, "Failed to ::BeginUpdateResourcesW."); | ||
| 85 | |||
| 86 | if (!::UpdateResourceA(hUpdate, RT_STRING, MAKEINTRESOURCE(dwBlockId), wLangId, pvData, cbData)) | ||
| 87 | { | ||
| 88 | ExitWithLastError(hr, "Failed to ::UpdateResourceA."); | ||
| 89 | } | ||
| 90 | |||
| 91 | if (!::EndUpdateResource(hUpdate, FALSE)) | ||
| 92 | { | ||
| 93 | ExitWithLastError(hr, "Failed to ::EndUpdateResourceW."); | ||
| 94 | } | ||
| 95 | |||
| 96 | hUpdate = NULL; | ||
| 97 | |||
| 98 | LExit: | ||
| 99 | ReleaseMem(pvData); | ||
| 100 | |||
| 101 | StringBlockUnitialize(&StrBlock); | ||
| 102 | |||
| 103 | if (hUpdate) | ||
| 104 | { | ||
| 105 | ::EndUpdateResource(hUpdate, TRUE); | ||
| 106 | } | ||
| 107 | |||
| 108 | if (hModule) | ||
| 109 | { | ||
| 110 | ::FreeLibrary(hModule); | ||
| 111 | } | ||
| 112 | |||
| 113 | return hr; | ||
| 114 | } | ||
| 115 | |||
| 116 | |||
| 117 | /******************************************************************** | ||
| 118 | ResWriteData - sets the data into to the specified file's resource name | ||
| 119 | |||
| 120 | ********************************************************************/ | ||
| 121 | extern "C" HRESULT DAPI ResWriteData( | ||
| 122 | __in_z LPCWSTR wzResourceFile, | ||
| 123 | __in_z LPCSTR szDataName, | ||
| 124 | __in PVOID pData, | ||
| 125 | __in DWORD cbData | ||
| 126 | ) | ||
| 127 | { | ||
| 128 | Assert(wzResourceFile); | ||
| 129 | Assert(szDataName); | ||
| 130 | Assert(pData); | ||
| 131 | Assert(cbData); | ||
| 132 | |||
| 133 | HRESULT hr = S_OK; | ||
| 134 | HANDLE hUpdate = NULL; | ||
| 135 | |||
| 136 | hUpdate = ::BeginUpdateResourceW(wzResourceFile, FALSE); | ||
| 137 | ExitOnNullWithLastError(hUpdate, hr, "Failed to ::BeginUpdateResourcesW."); | ||
| 138 | |||
| 139 | if (!::UpdateResourceA(hUpdate, RT_RCDATA, szDataName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), pData, cbData)) | ||
| 140 | { | ||
| 141 | ExitWithLastError(hr, "Failed to ::UpdateResourceA."); | ||
| 142 | } | ||
| 143 | |||
| 144 | if (!::EndUpdateResource(hUpdate, FALSE)) | ||
| 145 | { | ||
| 146 | ExitWithLastError(hr, "Failed to ::EndUpdateResourceW."); | ||
| 147 | } | ||
| 148 | |||
| 149 | hUpdate = NULL; | ||
| 150 | |||
| 151 | LExit: | ||
| 152 | if (hUpdate) | ||
| 153 | { | ||
| 154 | ::EndUpdateResource(hUpdate, TRUE); | ||
| 155 | } | ||
| 156 | |||
| 157 | return hr; | ||
| 158 | } | ||
| 159 | |||
| 160 | |||
| 161 | /******************************************************************** | ||
| 162 | ResImportDataFromFile - reads a file and sets the data into to the specified file's resource name | ||
| 163 | |||
| 164 | ********************************************************************/ | ||
| 165 | extern "C" HRESULT DAPI ResImportDataFromFile( | ||
| 166 | __in_z LPCWSTR wzTargetFile, | ||
| 167 | __in_z LPCWSTR wzSourceFile, | ||
| 168 | __in_z LPCSTR szDataName | ||
| 169 | ) | ||
| 170 | { | ||
| 171 | HRESULT hr = S_OK; | ||
| 172 | HANDLE hFile = INVALID_HANDLE_VALUE; | ||
| 173 | DWORD cbFile = 0; | ||
| 174 | HANDLE hMap = NULL; | ||
| 175 | PVOID pv = NULL; | ||
| 176 | |||
| 177 | hFile = ::CreateFileW(wzSourceFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | ||
| 178 | if (INVALID_HANDLE_VALUE == hFile) | ||
| 179 | { | ||
| 180 | ExitWithLastError(hr, "Failed to CreateFileW for %ls.", wzSourceFile); | ||
| 181 | } | ||
| 182 | |||
| 183 | cbFile = ::GetFileSize(hFile, NULL); | ||
| 184 | if (!cbFile) | ||
| 185 | { | ||
| 186 | ExitWithLastError(hr, "Failed to GetFileSize for %ls.", wzSourceFile); | ||
| 187 | } | ||
| 188 | |||
| 189 | hMap = ::CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); | ||
| 190 | ExitOnNullWithLastError(hMap, hr, "Failed to CreateFileMapping for %ls.", wzSourceFile); | ||
| 191 | |||
| 192 | pv = ::MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, cbFile); | ||
| 193 | ExitOnNullWithLastError(pv, hr, "Failed to MapViewOfFile for %ls.", wzSourceFile); | ||
| 194 | |||
| 195 | hr = ResWriteData(wzTargetFile, szDataName, pv, cbFile); | ||
| 196 | ExitOnFailure(hr, "Failed to ResSetData %s on file %ls.", szDataName, wzTargetFile); | ||
| 197 | |||
| 198 | LExit: | ||
| 199 | if (pv) | ||
| 200 | { | ||
| 201 | ::UnmapViewOfFile(pv); | ||
| 202 | } | ||
| 203 | |||
| 204 | if (hMap) | ||
| 205 | { | ||
| 206 | ::CloseHandle(hMap); | ||
| 207 | } | ||
| 208 | |||
| 209 | ReleaseFile(hFile); | ||
| 210 | |||
| 211 | return hr; | ||
| 212 | } | ||
| 213 | |||
| 214 | |||
| 215 | static HRESULT StringBlockInitialize( | ||
| 216 | __in_opt HINSTANCE hModule, | ||
| 217 | __in DWORD dwBlockId, | ||
| 218 | __in WORD wLangId, | ||
| 219 | __in RES_STRING_BLOCK* pStrBlock | ||
| 220 | ) | ||
| 221 | { | ||
| 222 | HRESULT hr = S_OK; | ||
| 223 | HRSRC hRsrc = NULL; | ||
| 224 | HGLOBAL hData = NULL; | ||
| 225 | LPCVOID pvData = NULL; // does not need to be freed | ||
| 226 | DWORD cbData = 0; | ||
| 227 | |||
| 228 | hRsrc = ::FindResourceExA(hModule, RT_STRING, MAKEINTRESOURCE(dwBlockId), wLangId); | ||
| 229 | ExitOnNullWithLastError(hRsrc, hr, "Failed to ::FindResourceExW."); | ||
| 230 | |||
| 231 | hData = ::LoadResource(hModule, hRsrc); | ||
| 232 | ExitOnNullWithLastError(hData, hr, "Failed to ::LoadResource."); | ||
| 233 | |||
| 234 | cbData = ::SizeofResource(hModule, hRsrc); | ||
| 235 | if (!cbData) | ||
| 236 | { | ||
| 237 | ExitWithLastError(hr, "Failed to ::SizeofResource."); | ||
| 238 | } | ||
| 239 | |||
| 240 | pvData = ::LockResource(hData); | ||
| 241 | ExitOnNullWithLastError(pvData, hr, "Failed to lock data resource."); | ||
| 242 | |||
| 243 | pStrBlock->dwBlockId = dwBlockId; | ||
| 244 | pStrBlock->wLangId = wLangId; | ||
| 245 | |||
| 246 | hr = StringBlockConvertFromResourceData(pStrBlock, pvData, cbData); | ||
| 247 | ExitOnFailure(hr, "Failed to convert string block from resource data."); | ||
| 248 | |||
| 249 | LExit: | ||
| 250 | return hr; | ||
| 251 | } | ||
| 252 | |||
| 253 | |||
| 254 | static void StringBlockUnitialize( | ||
| 255 | __in RES_STRING_BLOCK* pStrBlock | ||
| 256 | ) | ||
| 257 | { | ||
| 258 | if (pStrBlock) | ||
| 259 | { | ||
| 260 | for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) | ||
| 261 | { | ||
| 262 | ReleaseNullMem(pStrBlock->rgwz[i]); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | |||
| 268 | static HRESULT StringBlockChangeString( | ||
| 269 | __in RES_STRING_BLOCK* pStrBlock, | ||
| 270 | __in DWORD dwStringId, | ||
| 271 | __in_z LPCWSTR szData | ||
| 272 | ) | ||
| 273 | { | ||
| 274 | HRESULT hr = S_OK; | ||
| 275 | LPWSTR pwzData = NULL; | ||
| 276 | DWORD cchData = lstrlenW(szData); | ||
| 277 | |||
| 278 | pwzData = static_cast<LPWSTR>(MemAlloc((cchData + 1) * sizeof(WCHAR), TRUE)); | ||
| 279 | ExitOnNull(pwzData, hr, E_OUTOFMEMORY, "Failed to allocate new block string."); | ||
| 280 | |||
| 281 | hr = ::StringCchCopyW(pwzData, cchData + 1, szData); | ||
| 282 | ExitOnFailure(hr, "Failed to copy new block string."); | ||
| 283 | |||
| 284 | ReleaseNullMem(pStrBlock->rgwz[dwStringId]); | ||
| 285 | |||
| 286 | pStrBlock->rgwz[dwStringId] = pwzData; | ||
| 287 | pwzData = NULL; | ||
| 288 | |||
| 289 | LExit: | ||
| 290 | ReleaseMem(pwzData); | ||
| 291 | |||
| 292 | return hr; | ||
| 293 | } | ||
| 294 | |||
| 295 | |||
| 296 | static HRESULT StringBlockConvertToResourceData( | ||
| 297 | __in const RES_STRING_BLOCK* pStrBlock, | ||
| 298 | __deref_out_bcount(*pcbData) LPVOID* ppvData, | ||
| 299 | __out DWORD* pcbData | ||
| 300 | ) | ||
| 301 | { | ||
| 302 | HRESULT hr = S_OK; | ||
| 303 | DWORD cbData = 0; | ||
| 304 | LPVOID pvData = NULL; | ||
| 305 | WCHAR* pwz = NULL; | ||
| 306 | |||
| 307 | for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) | ||
| 308 | { | ||
| 309 | cbData += (lstrlenW(pStrBlock->rgwz[i]) + 1); | ||
| 310 | } | ||
| 311 | cbData *= sizeof(WCHAR); | ||
| 312 | |||
| 313 | pvData = MemAlloc(cbData, TRUE); | ||
| 314 | ExitOnNull(pvData, hr, E_OUTOFMEMORY, "Failed to allocate buffer to convert string block."); | ||
| 315 | |||
| 316 | pwz = static_cast<LPWSTR>(pvData); | ||
| 317 | for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) | ||
| 318 | { | ||
| 319 | DWORD cch = lstrlenW(pStrBlock->rgwz[i]); | ||
| 320 | |||
| 321 | *pwz = static_cast<WCHAR>(cch); | ||
| 322 | ++pwz; | ||
| 323 | |||
| 324 | for (DWORD j = 0; j < cch; ++j) | ||
| 325 | { | ||
| 326 | *pwz = pStrBlock->rgwz[i][j]; | ||
| 327 | ++pwz; | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | *pcbData = cbData; | ||
| 332 | *ppvData = pvData; | ||
| 333 | pvData = NULL; | ||
| 334 | |||
| 335 | LExit: | ||
| 336 | ReleaseMem(pvData); | ||
| 337 | |||
| 338 | return hr; | ||
| 339 | } | ||
| 340 | |||
| 341 | |||
| 342 | static HRESULT StringBlockConvertFromResourceData( | ||
| 343 | __in RES_STRING_BLOCK* pStrBlock, | ||
| 344 | __in_bcount(cbData) LPCVOID pvData, | ||
| 345 | __in SIZE_T cbData | ||
| 346 | ) | ||
| 347 | { | ||
| 348 | UNREFERENCED_PARAMETER(cbData); | ||
| 349 | HRESULT hr = S_OK; | ||
| 350 | LPCWSTR pwzParse = static_cast<LPCWSTR>(pvData); | ||
| 351 | |||
| 352 | for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) | ||
| 353 | { | ||
| 354 | DWORD cchParse = static_cast<DWORD>(*pwzParse); | ||
| 355 | ++pwzParse; | ||
| 356 | |||
| 357 | pStrBlock->rgwz[i] = static_cast<LPWSTR>(MemAlloc((cchParse + 1) * sizeof(WCHAR), TRUE)); | ||
| 358 | ExitOnNull(pStrBlock->rgwz[i], hr, E_OUTOFMEMORY, "Failed to populate pStrBlock."); | ||
| 359 | |||
| 360 | hr = ::StringCchCopyNExW(pStrBlock->rgwz[i], cchParse + 1, pwzParse, cchParse, NULL, NULL, STRSAFE_FILL_BEHIND_NULL); | ||
| 361 | ExitOnFailure(hr, "Failed to copy parsed resource data into string block."); | ||
| 362 | |||
| 363 | pwzParse += cchParse; | ||
| 364 | } | ||
| 365 | |||
| 366 | LExit: | ||
| 367 | return hr; | ||
| 368 | } | ||
