aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/locutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/locutil.cpp')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/locutil.cpp628
1 files changed, 628 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/locutil.cpp b/src/libs/dutil/WixToolset.DUtil/locutil.cpp
new file mode 100644
index 00000000..c4567c03
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/locutil.cpp
@@ -0,0 +1,628 @@
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
6// Exit macros
7#define LocExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__)
8#define LocExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__)
9#define LocExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__)
10#define LocExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__)
11#define LocExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__)
12#define LocExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__)
13#define LocExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_LOCUTIL, p, x, e, s, __VA_ARGS__)
14#define LocExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_LOCUTIL, p, x, s, __VA_ARGS__)
15#define LocExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_LOCUTIL, p, x, e, s, __VA_ARGS__)
16#define LocExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_LOCUTIL, p, x, s, __VA_ARGS__)
17#define LocExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_LOCUTIL, e, x, s, __VA_ARGS__)
18#define LocExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_LOCUTIL, g, x, s, __VA_ARGS__)
19
20// prototypes
21static HRESULT ParseWxl(
22 __in IXMLDOMDocument* pixd,
23 __out WIX_LOCALIZATION** ppWixLoc
24 );
25static HRESULT ParseWxlStrings(
26 __in IXMLDOMElement* pElement,
27 __in WIX_LOCALIZATION* pWixLoc
28 );
29static HRESULT ParseWxlControls(
30 __in IXMLDOMElement* pElement,
31 __in WIX_LOCALIZATION* pWixLoc
32 );
33static HRESULT ParseWxlString(
34 __in IXMLDOMNode* pixn,
35 __in DWORD dwIdx,
36 __in WIX_LOCALIZATION* pWixLoc
37 );
38static HRESULT ParseWxlControl(
39 __in IXMLDOMNode* pixn,
40 __in DWORD dwIdx,
41 __in WIX_LOCALIZATION* pWixLoc
42 );
43
44// from Winnls.h
45#ifndef MUI_LANGUAGE_ID
46#define MUI_LANGUAGE_ID 0x4 // Use traditional language ID convention
47#endif
48#ifndef MUI_MERGE_USER_FALLBACK
49#define MUI_MERGE_USER_FALLBACK 0x20 // GetThreadPreferredUILanguages merges in user preferred languages
50#endif
51#ifndef MUI_MERGE_SYSTEM_FALLBACK
52#define MUI_MERGE_SYSTEM_FALLBACK 0x10 // GetThreadPreferredUILanguages merges in parent and base languages
53#endif
54typedef WINBASEAPI BOOL (WINAPI *GET_THREAD_PREFERRED_UI_LANGUAGES) (
55 __in DWORD dwFlags,
56 __out PULONG pulNumLanguages,
57 __out_ecount_opt(*pcchLanguagesBuffer) PZZWSTR pwszLanguagesBuffer,
58 __inout PULONG pcchLanguagesBuffer
59);
60
61extern "C" HRESULT DAPI LocProbeForFile(
62 __in_z LPCWSTR wzBasePath,
63 __in_z LPCWSTR wzLocFileName,
64 __in_z_opt LPCWSTR wzLanguage,
65 __inout LPWSTR* psczPath
66 )
67{
68 HRESULT hr = S_OK;
69 LPWSTR sczProbePath = NULL;
70 LANGID langid = 0;
71 LPWSTR sczLangIdFile = NULL;
72 LPWSTR sczLangsBuff = NULL;
73 GET_THREAD_PREFERRED_UI_LANGUAGES pvfnGetThreadPreferredUILanguages =
74 reinterpret_cast<GET_THREAD_PREFERRED_UI_LANGUAGES>(
75 GetProcAddress(GetModuleHandle("Kernel32.dll"), "GetThreadPreferredUILanguages"));
76
77 // If a language was specified, look for a loc file in that as a directory.
78 if (wzLanguage && *wzLanguage)
79 {
80 hr = PathConcat(wzBasePath, wzLanguage, &sczProbePath);
81 LocExitOnFailure(hr, "Failed to concat base path to language.");
82
83 hr = PathConcat(sczProbePath, wzLocFileName, &sczProbePath);
84 LocExitOnFailure(hr, "Failed to concat loc file name to probe path.");
85
86 if (FileExistsEx(sczProbePath, NULL))
87 {
88 ExitFunction();
89 }
90 }
91
92 if (pvfnGetThreadPreferredUILanguages)
93 {
94 ULONG nLangs;
95 ULONG cchLangs = 0;
96 DWORD dwFlags = MUI_LANGUAGE_ID | MUI_MERGE_USER_FALLBACK | MUI_MERGE_SYSTEM_FALLBACK;
97 if (!(*pvfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, NULL, &cchLangs))
98 {
99 LocExitWithLastError(hr, "GetThreadPreferredUILanguages failed to return buffer size.");
100 }
101
102 hr = StrAlloc(&sczLangsBuff, cchLangs);
103 LocExitOnFailure(hr, "Failed to allocate buffer for languages");
104
105 nLangs = 0;
106 if (!(*pvfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, sczLangsBuff, &cchLangs))
107 {
108 LocExitWithLastError(hr, "GetThreadPreferredUILanguages failed to return language list.");
109 }
110
111 LPWSTR szLangs = sczLangsBuff;
112 for (ULONG i = 0; i < nLangs; ++i, szLangs += 5)
113 {
114 // StrHexDecode assumes low byte is first. We'll need to swap the bytes once we parse out the value.
115 hr = StrHexDecode(szLangs, reinterpret_cast<BYTE*>(&langid), sizeof(langid));
116 LocExitOnFailure(hr, "Failed to parse langId.");
117
118 langid = MAKEWORD(HIBYTE(langid), LOBYTE(langid));
119 hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName);
120 LocExitOnFailure(hr, "Failed to format user preferred langid.");
121
122 hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath);
123 LocExitOnFailure(hr, "Failed to concat user preferred langid file name to base path.");
124
125 if (FileExistsEx(sczProbePath, NULL))
126 {
127 ExitFunction();
128 }
129 }
130 }
131
132 langid = ::GetUserDefaultUILanguage();
133
134 hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName);
135 LocExitOnFailure(hr, "Failed to format user langid.");
136
137 hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath);
138 LocExitOnFailure(hr, "Failed to concat user langid file name to base path.");
139
140 if (FileExistsEx(sczProbePath, NULL))
141 {
142 ExitFunction();
143 }
144
145 if (MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT) != langid)
146 {
147 langid = MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT);
148
149 hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName);
150 LocExitOnFailure(hr, "Failed to format user langid (default sublang).");
151
152 hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath);
153 LocExitOnFailure(hr, "Failed to concat user langid file name to base path (default sublang).");
154
155 if (FileExistsEx(sczProbePath, NULL))
156 {
157 ExitFunction();
158 }
159 }
160
161 langid = ::GetSystemDefaultUILanguage();
162
163 hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName);
164 LocExitOnFailure(hr, "Failed to format system langid.");
165
166 hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath);
167 LocExitOnFailure(hr, "Failed to concat system langid file name to base path.");
168
169 if (FileExistsEx(sczProbePath, NULL))
170 {
171 ExitFunction();
172 }
173
174 if (MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT) != langid)
175 {
176 langid = MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT);
177
178 hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName);
179 LocExitOnFailure(hr, "Failed to format user langid (default sublang).");
180
181 hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath);
182 LocExitOnFailure(hr, "Failed to concat user langid file name to base path (default sublang).");
183
184 if (FileExistsEx(sczProbePath, NULL))
185 {
186 ExitFunction();
187 }
188 }
189
190 // Finally, look for the loc file in the base path.
191 hr = PathConcat(wzBasePath, wzLocFileName, &sczProbePath);
192 LocExitOnFailure(hr, "Failed to concat loc file name to base path.");
193
194 if (!FileExistsEx(sczProbePath, NULL))
195 {
196 hr = E_FILENOTFOUND;
197 }
198
199LExit:
200 if (SUCCEEDED(hr))
201 {
202 hr = StrAllocString(psczPath, sczProbePath, 0);
203 }
204
205 ReleaseStr(sczLangIdFile);
206 ReleaseStr(sczProbePath);
207 ReleaseStr(sczLangsBuff);
208
209 return hr;
210}
211
212extern "C" HRESULT DAPI LocLoadFromFile(
213 __in_z LPCWSTR wzWxlFile,
214 __out WIX_LOCALIZATION** ppWixLoc
215 )
216{
217 HRESULT hr = S_OK;
218 IXMLDOMDocument* pixd = NULL;
219
220 hr = XmlLoadDocumentFromFile(wzWxlFile, &pixd);
221 LocExitOnFailure(hr, "Failed to load WXL file as XML document.");
222
223 hr = ParseWxl(pixd, ppWixLoc);
224 LocExitOnFailure(hr, "Failed to parse WXL.");
225
226LExit:
227 ReleaseObject(pixd);
228
229 return hr;
230}
231
232extern "C" HRESULT DAPI LocLoadFromResource(
233 __in HMODULE hModule,
234 __in_z LPCSTR szResource,
235 __out WIX_LOCALIZATION** ppWixLoc
236 )
237{
238 HRESULT hr = S_OK;
239 LPVOID pvResource = NULL;
240 DWORD cbResource = 0;
241 LPWSTR sczXml = NULL;
242 IXMLDOMDocument* pixd = NULL;
243
244 hr = ResReadData(hModule, szResource, &pvResource, &cbResource);
245 LocExitOnFailure(hr, "Failed to read theme from resource.");
246
247 hr = StrAllocStringAnsi(&sczXml, reinterpret_cast<LPCSTR>(pvResource), cbResource, CP_UTF8);
248 LocExitOnFailure(hr, "Failed to convert XML document data from UTF-8 to unicode string.");
249
250 hr = XmlLoadDocument(sczXml, &pixd);
251 LocExitOnFailure(hr, "Failed to load theme resource as XML document.");
252
253 hr = ParseWxl(pixd, ppWixLoc);
254 LocExitOnFailure(hr, "Failed to parse WXL.");
255
256LExit:
257 ReleaseObject(pixd);
258 ReleaseStr(sczXml);
259
260 return hr;
261}
262
263extern "C" void DAPI LocFree(
264 __in_opt WIX_LOCALIZATION* pWixLoc
265 )
266{
267 if (pWixLoc)
268 {
269 for (DWORD idx = 0; idx < pWixLoc->cLocStrings; ++idx)
270 {
271 ReleaseStr(pWixLoc->rgLocStrings[idx].wzId);
272 ReleaseStr(pWixLoc->rgLocStrings[idx].wzText);
273 }
274
275 for (DWORD idx = 0; idx < pWixLoc->cLocControls; ++idx)
276 {
277 ReleaseStr(pWixLoc->rgLocControls[idx].wzControl);
278 ReleaseStr(pWixLoc->rgLocControls[idx].wzText);
279 }
280
281 ReleaseMem(pWixLoc->rgLocStrings);
282 ReleaseMem(pWixLoc->rgLocControls);
283 ReleaseMem(pWixLoc);
284 }
285}
286
287extern "C" HRESULT DAPI LocLocalizeString(
288 __in const WIX_LOCALIZATION* pWixLoc,
289 __inout LPWSTR* ppsczInput
290 )
291{
292 Assert(ppsczInput && pWixLoc);
293 HRESULT hr = S_OK;
294
295 for (DWORD i = 0; i < pWixLoc->cLocStrings; ++i)
296 {
297 hr = StrReplaceStringAll(ppsczInput, pWixLoc->rgLocStrings[i].wzId, pWixLoc->rgLocStrings[i].wzText);
298 LocExitOnFailure(hr, "Localizing string failed.");
299 }
300
301LExit:
302 return hr;
303}
304
305extern "C" HRESULT DAPI LocGetControl(
306 __in const WIX_LOCALIZATION* pWixLoc,
307 __in_z LPCWSTR wzId,
308 __out LOC_CONTROL** ppLocControl
309 )
310{
311 HRESULT hr = S_OK;
312 LOC_CONTROL* pLocControl = NULL;
313
314 for (DWORD i = 0; i < pWixLoc->cLocControls; ++i)
315 {
316 pLocControl = &pWixLoc->rgLocControls[i];
317
318 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pLocControl->wzControl, -1, wzId, -1))
319 {
320 *ppLocControl = pLocControl;
321 ExitFunction1(hr = S_OK);
322 }
323 }
324
325 hr = E_NOTFOUND;
326
327LExit:
328 return hr;
329}
330
331extern "C" HRESULT DAPI LocGetString(
332 __in const WIX_LOCALIZATION* pWixLoc,
333 __in_z LPCWSTR wzId,
334 __out LOC_STRING** ppLocString
335 )
336{
337 HRESULT hr = E_NOTFOUND;
338 LOC_STRING* pLocString = NULL;
339
340 for (DWORD i = 0; i < pWixLoc->cLocStrings; ++i)
341 {
342 pLocString = pWixLoc->rgLocStrings + i;
343
344 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pLocString->wzId, -1, wzId, -1))
345 {
346 *ppLocString = pLocString;
347 hr = S_OK;
348 break;
349 }
350 }
351
352 return hr;
353}
354
355extern "C" HRESULT DAPI LocAddString(
356 __in WIX_LOCALIZATION* pWixLoc,
357 __in_z LPCWSTR wzId,
358 __in_z LPCWSTR wzLocString,
359 __in BOOL bOverridable
360 )
361{
362 HRESULT hr = S_OK;
363
364 ++pWixLoc->cLocStrings;
365 pWixLoc->rgLocStrings = static_cast<LOC_STRING*>(MemReAlloc(pWixLoc->rgLocStrings, sizeof(LOC_STRING) * pWixLoc->cLocStrings, TRUE));
366 LocExitOnNull(pWixLoc->rgLocStrings, hr, E_OUTOFMEMORY, "Failed to reallocate memory for localization strings.");
367
368 LOC_STRING* pLocString = pWixLoc->rgLocStrings + (pWixLoc->cLocStrings - 1);
369
370 hr = StrAllocFormatted(&pLocString->wzId, L"#(loc.%s)", wzId);
371 LocExitOnFailure(hr, "Failed to set localization string Id.");
372
373 hr = StrAllocString(&pLocString->wzText, wzLocString, 0);
374 LocExitOnFailure(hr, "Failed to set localization string Text.");
375
376 pLocString->bOverridable = bOverridable;
377
378LExit:
379 return hr;
380}
381
382// helper functions
383
384static HRESULT ParseWxl(
385 __in IXMLDOMDocument* pixd,
386 __out WIX_LOCALIZATION** ppWixLoc
387 )
388{
389 HRESULT hr = S_OK;
390 IXMLDOMElement *pWxlElement = NULL;
391 WIX_LOCALIZATION* pWixLoc = NULL;
392
393 pWixLoc = static_cast<WIX_LOCALIZATION*>(MemAlloc(sizeof(WIX_LOCALIZATION), TRUE));
394 LocExitOnNull(pWixLoc, hr, E_OUTOFMEMORY, "Failed to allocate memory for Wxl file.");
395
396 // read the WixLocalization tag
397 hr = pixd->get_documentElement(&pWxlElement);
398 LocExitOnFailure(hr, "Failed to get localization element.");
399
400 // get the Language attribute if present
401 pWixLoc->dwLangId = WIX_LOCALIZATION_LANGUAGE_NOT_SET;
402 hr = XmlGetAttributeNumber(pWxlElement, L"Language", &pWixLoc->dwLangId);
403 if (S_FALSE == hr)
404 {
405 hr = S_OK;
406 }
407 LocExitOnFailure(hr, "Failed to get Language value.");
408
409 // store the strings and controls in a node list
410 hr = ParseWxlStrings(pWxlElement, pWixLoc);
411 LocExitOnFailure(hr, "Parsing localization strings failed.");
412
413 hr = ParseWxlControls(pWxlElement, pWixLoc);
414 LocExitOnFailure(hr, "Parsing localization controls failed.");
415
416 *ppWixLoc = pWixLoc;
417 pWixLoc = NULL;
418
419LExit:
420 ReleaseObject(pWxlElement);
421 ReleaseMem(pWixLoc);
422
423 return hr;
424}
425
426
427static HRESULT ParseWxlStrings(
428 __in IXMLDOMElement* pElement,
429 __in WIX_LOCALIZATION* pWixLoc
430 )
431{
432 HRESULT hr = S_OK;
433 IXMLDOMNode* pixn = NULL;
434 IXMLDOMNodeList* pixnl = NULL;
435 DWORD dwIdx = 0;
436
437 hr = XmlSelectNodes(pElement, L"String", &pixnl);
438 LocExitOnLastError(hr, "Failed to get String child nodes of Wxl File.");
439
440 hr = pixnl->get_length(reinterpret_cast<long*>(&pWixLoc->cLocStrings));
441 LocExitOnLastError(hr, "Failed to get number of String child nodes in Wxl File.");
442
443 if (0 < pWixLoc->cLocStrings)
444 {
445 pWixLoc->rgLocStrings = static_cast<LOC_STRING*>(MemAlloc(sizeof(LOC_STRING) * pWixLoc->cLocStrings, TRUE));
446 LocExitOnNull(pWixLoc->rgLocStrings, hr, E_OUTOFMEMORY, "Failed to allocate memory for localization strings.");
447
448 while (S_OK == (hr = XmlNextElement(pixnl, &pixn, NULL)))
449 {
450 hr = ParseWxlString(pixn, dwIdx, pWixLoc);
451 LocExitOnFailure(hr, "Failed to parse localization string.");
452
453 ++dwIdx;
454 ReleaseNullObject(pixn);
455 }
456
457 hr = S_OK;
458 LocExitOnFailure(hr, "Failed to enumerate all localization strings.");
459 }
460
461LExit:
462 if (FAILED(hr) && pWixLoc->rgLocStrings)
463 {
464 for (DWORD idx = 0; idx < pWixLoc->cLocStrings; ++idx)
465 {
466 ReleaseStr(pWixLoc->rgLocStrings[idx].wzId);
467 ReleaseStr(pWixLoc->rgLocStrings[idx].wzText);
468 }
469
470 ReleaseMem(pWixLoc->rgLocStrings);
471 }
472
473 ReleaseObject(pixn);
474 ReleaseObject(pixnl);
475
476 return hr;
477}
478
479static HRESULT ParseWxlControls(
480 __in IXMLDOMElement* pElement,
481 __in WIX_LOCALIZATION* pWixLoc
482 )
483{
484 HRESULT hr = S_OK;
485 IXMLDOMNode* pixn = NULL;
486 IXMLDOMNodeList* pixnl = NULL;
487 DWORD dwIdx = 0;
488
489 hr = XmlSelectNodes(pElement, L"UI|Control", &pixnl);
490 LocExitOnLastError(hr, "Failed to get UI child nodes of Wxl File.");
491
492 hr = pixnl->get_length(reinterpret_cast<long*>(&pWixLoc->cLocControls));
493 LocExitOnLastError(hr, "Failed to get number of UI child nodes in Wxl File.");
494
495 if (0 < pWixLoc->cLocControls)
496 {
497 pWixLoc->rgLocControls = static_cast<LOC_CONTROL*>(MemAlloc(sizeof(LOC_CONTROL) * pWixLoc->cLocControls, TRUE));
498 LocExitOnNull(pWixLoc->rgLocControls, hr, E_OUTOFMEMORY, "Failed to allocate memory for localized controls.");
499
500 while (S_OK == (hr = XmlNextElement(pixnl, &pixn, NULL)))
501 {
502 hr = ParseWxlControl(pixn, dwIdx, pWixLoc);
503 LocExitOnFailure(hr, "Failed to parse localized control.");
504
505 ++dwIdx;
506 ReleaseNullObject(pixn);
507 }
508
509 hr = S_OK;
510 LocExitOnFailure(hr, "Failed to enumerate all localized controls.");
511 }
512
513LExit:
514 if (FAILED(hr) && pWixLoc->rgLocControls)
515 {
516 for (DWORD idx = 0; idx < pWixLoc->cLocControls; ++idx)
517 {
518 ReleaseStr(pWixLoc->rgLocControls[idx].wzControl);
519 ReleaseStr(pWixLoc->rgLocControls[idx].wzText);
520 }
521
522 ReleaseMem(pWixLoc->rgLocControls);
523 }
524
525 ReleaseObject(pixn);
526 ReleaseObject(pixnl);
527
528 return hr;
529}
530
531static HRESULT ParseWxlString(
532 __in IXMLDOMNode* pixn,
533 __in DWORD dwIdx,
534 __in WIX_LOCALIZATION* pWixLoc
535 )
536{
537 HRESULT hr = S_OK;
538 LOC_STRING* pLocString = NULL;
539 BSTR bstrText = NULL;
540
541 pLocString = pWixLoc->rgLocStrings + dwIdx;
542
543 // Id
544 hr = XmlGetAttribute(pixn, L"Id", &bstrText);
545 LocExitOnFailure(hr, "Failed to get Xml attribute Id in Wxl file.");
546
547 hr = StrAllocFormatted(&pLocString->wzId, L"#(loc.%s)", bstrText);
548 LocExitOnFailure(hr, "Failed to duplicate Xml attribute Id in Wxl file.");
549
550 ReleaseNullBSTR(bstrText);
551
552 // Overrideable
553 hr = XmlGetAttribute(pixn, L"Overridable", &bstrText);
554 LocExitOnFailure(hr, "Failed to get Xml attribute Overridable.");
555
556 if (S_OK == hr)
557 {
558 pLocString->bOverridable = CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrText, -1, L"yes", -1);
559 }
560
561 ReleaseNullBSTR(bstrText);
562
563 // Text
564 hr = XmlGetText(pixn, &bstrText);
565 LocExitOnFailure(hr, "Failed to get Xml text in Wxl file.");
566
567 hr = StrAllocString(&pLocString->wzText, bstrText, 0);
568 LocExitOnFailure(hr, "Failed to duplicate Xml text in Wxl file.");
569
570LExit:
571 ReleaseBSTR(bstrText);
572
573 return hr;
574}
575
576static HRESULT ParseWxlControl(
577 __in IXMLDOMNode* pixn,
578 __in DWORD dwIdx,
579 __in WIX_LOCALIZATION* pWixLoc
580 )
581{
582 HRESULT hr = S_OK;
583 LOC_CONTROL* pLocControl = NULL;
584 BSTR bstrText = NULL;
585
586 pLocControl = pWixLoc->rgLocControls + dwIdx;
587
588 // Id
589 hr = XmlGetAttribute(pixn, L"Control", &bstrText);
590 LocExitOnFailure(hr, "Failed to get Xml attribute Control in Wxl file.");
591
592 hr = StrAllocString(&pLocControl->wzControl, bstrText, 0);
593 LocExitOnFailure(hr, "Failed to duplicate Xml attribute Control in Wxl file.");
594
595 ReleaseNullBSTR(bstrText);
596
597 // X
598 pLocControl->nX = LOC_CONTROL_NOT_SET;
599 hr = XmlGetAttributeNumber(pixn, L"X", reinterpret_cast<DWORD*>(&pLocControl->nX));
600 LocExitOnFailure(hr, "Failed to get control X attribute.");
601
602 // Y
603 pLocControl->nY = LOC_CONTROL_NOT_SET;
604 hr = XmlGetAttributeNumber(pixn, L"Y", reinterpret_cast<DWORD*>(&pLocControl->nY));
605 LocExitOnFailure(hr, "Failed to get control Y attribute.");
606
607 // Width
608 pLocControl->nWidth = LOC_CONTROL_NOT_SET;
609 hr = XmlGetAttributeNumber(pixn, L"Width", reinterpret_cast<DWORD*>(&pLocControl->nWidth));
610 LocExitOnFailure(hr, "Failed to get control width attribute.");
611
612 // Height
613 pLocControl->nHeight = LOC_CONTROL_NOT_SET;
614 hr = XmlGetAttributeNumber(pixn, L"Height", reinterpret_cast<DWORD*>(&pLocControl->nHeight));
615 LocExitOnFailure(hr, "Failed to get control height attribute.");
616
617 // Text
618 hr = XmlGetText(pixn, &bstrText);
619 LocExitOnFailure(hr, "Failed to get control text in Wxl file.");
620
621 hr = StrAllocString(&pLocControl->wzText, bstrText, 0);
622 LocExitOnFailure(hr, "Failed to duplicate control text in Wxl file.");
623
624LExit:
625 ReleaseBSTR(bstrText);
626
627 return hr;
628}