aboutsummaryrefslogtreecommitdiff
path: root/src/dutil/reswutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dutil/reswutil.cpp')
-rw-r--r--src/dutil/reswutil.cpp368
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.
9typedef 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
18static HRESULT StringBlockInitialize(
19 __in_opt HINSTANCE hModule,
20 __in DWORD dwBlockId,
21 __in WORD wLangId,
22 __in RES_STRING_BLOCK* pStrBlock
23 );
24static void StringBlockUnitialize(
25 __in RES_STRING_BLOCK* pStrBlock
26 );
27static HRESULT StringBlockChangeString(
28 __in RES_STRING_BLOCK* pStrBlock,
29 __in DWORD dwStringId,
30 __in_z LPCWSTR szData
31 );
32static HRESULT StringBlockConvertToResourceData(
33 __in const RES_STRING_BLOCK* pStrBlock,
34 __deref_out_bcount(*pcbData) LPVOID* ppvData,
35 __out DWORD* pcbData
36 );
37static HRESULT StringBlockConvertFromResourceData(
38 __in RES_STRING_BLOCK* pStrBlock,
39 __in_bcount(cbData) LPCVOID pvData,
40 __in SIZE_T cbData
41 );
42
43
44/********************************************************************
45ResWriteString - sets the string into to the specified file's resource name
46
47********************************************************************/
48extern "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
98LExit:
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/********************************************************************
118ResWriteData - sets the data into to the specified file's resource name
119
120********************************************************************/
121extern "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
151LExit:
152 if (hUpdate)
153 {
154 ::EndUpdateResource(hUpdate, TRUE);
155 }
156
157 return hr;
158}
159
160
161/********************************************************************
162ResImportDataFromFile - reads a file and sets the data into to the specified file's resource name
163
164********************************************************************/
165extern "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
198LExit:
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
215static 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
249LExit:
250 return hr;
251}
252
253
254static 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
268static 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
289LExit:
290 ReleaseMem(pwzData);
291
292 return hr;
293}
294
295
296static 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
335LExit:
336 ReleaseMem(pvData);
337
338 return hr;
339}
340
341
342static 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
366LExit:
367 return hr;
368}