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 | } | ||