Merge branch 'selection-navigation'
[TortoiseGit.git] / src / ResText / ResModule.cpp
blob2b3928bdd33a4b3a77546b8ace41968e9b69d5ae
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008, 2010-2014 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 #include "stdafx.h"
19 #include "Utils.h"
20 #include "ResModule.h"
21 #include "../Utils/SysInfo.h"
22 #include <regex>
23 #include <memory>
25 #ifndef RT_RIBBON
26 #define RT_RIBBON MAKEINTRESOURCE(28)
27 #endif
30 #define MYERROR {CUtils::Error(); return FALSE;}
32 CResModule::CResModule(void)
33 : m_bTranslatedStrings(0)
34 , m_bDefaultStrings(0)
35 , m_bTranslatedDialogStrings(0)
36 , m_bDefaultDialogStrings(0)
37 , m_bTranslatedMenuStrings(0)
38 , m_bDefaultMenuStrings(0)
39 , m_bTranslatedAcceleratorStrings(0)
40 , m_bDefaultAcceleratorStrings(0)
41 , m_bTranslatedRibbonTexts(0)
42 , m_bDefaultRibbonTexts(0)
43 , m_wTargetLang(0)
44 , m_hResDll(NULL)
45 , m_hUpdateRes(NULL)
46 , m_bQuiet(false)
47 , m_bRTL(false)
48 , m_bAdjustEOLs(false)
52 CResModule::~CResModule(void)
56 BOOL CResModule::ExtractResources(std::vector<std::wstring> filelist, LPCTSTR lpszPOFilePath, BOOL bNoUpdate, LPCTSTR lpszHeaderFile)
58 for (std::vector<std::wstring>::iterator I = filelist.begin(); I != filelist.end(); ++I)
60 m_hResDll = LoadLibraryEx(I->c_str(), NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE|LOAD_LIBRARY_AS_DATAFILE);
61 if (m_hResDll == NULL)
62 MYERROR;
64 size_t nEntries = m_StringEntries.size();
65 // fill in the std::map with all translatable entries
67 if (!m_bQuiet)
68 _ftprintf(stdout, _T("Extracting StringTable...."));
69 EnumResourceNames(m_hResDll, RT_STRING, EnumResNameCallback, (LONG_PTR)this);
70 if (!m_bQuiet)
71 _ftprintf(stdout, _T("%4Iu Strings\n"), m_StringEntries.size()-nEntries);
72 nEntries = m_StringEntries.size();
74 if (!m_bQuiet)
75 _ftprintf(stdout, _T("Extracting Dialogs........"));
76 EnumResourceNames(m_hResDll, RT_DIALOG, EnumResNameCallback, (LONG_PTR)this);
77 if (!m_bQuiet)
78 _ftprintf(stdout, _T("%4Iu Strings\n"), m_StringEntries.size()-nEntries);
79 nEntries = m_StringEntries.size();
81 if (!m_bQuiet)
82 _ftprintf(stdout, _T("Extracting Menus.........."));
83 EnumResourceNames(m_hResDll, RT_MENU, EnumResNameCallback, (LONG_PTR)this);
84 if (!m_bQuiet)
85 _ftprintf(stdout, _T("%4Iu Strings\n"), m_StringEntries.size()-nEntries);
86 nEntries = m_StringEntries.size();
87 if (!m_bQuiet)
88 _ftprintf(stdout, _T("Extracting Accelerators..."));
89 EnumResourceNames(m_hResDll, RT_ACCELERATOR, EnumResNameCallback, (LONG_PTR)this);
90 if (!m_bQuiet)
91 _ftprintf(stdout, _T("%4Iu Accelerators\n"), m_StringEntries.size()-nEntries);
92 nEntries = m_StringEntries.size();
93 if (!m_bQuiet)
94 _ftprintf(stdout, _T("Extracting Ribbons........"));
95 EnumResourceNames(m_hResDll, RT_RIBBON, EnumResNameCallback, (LONG_PTR)this);
96 if (!m_bQuiet)
97 _ftprintf(stdout, _T("%4Iu Strings\n"), m_StringEntries.size()-nEntries);
98 nEntries = m_StringEntries.size();
100 // parse a probably existing file and update the translations which are
101 // already done
102 m_StringEntries.ParseFile(lpszPOFilePath, !bNoUpdate, m_bAdjustEOLs);
104 FreeLibrary(m_hResDll);
107 // at last, save the new file
108 return m_StringEntries.SaveFile(lpszPOFilePath, lpszHeaderFile);
111 BOOL CResModule::ExtractResources(LPCTSTR lpszSrcLangDllPath, LPCTSTR lpszPoFilePath, BOOL bNoUpdate, LPCTSTR lpszHeaderFile)
113 m_hResDll = LoadLibraryEx(lpszSrcLangDllPath, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE|LOAD_LIBRARY_AS_DATAFILE);
114 if (m_hResDll == NULL)
115 MYERROR;
117 size_t nEntries = 0;
118 // fill in the std::map with all translatable entries
120 if (!m_bQuiet)
121 _ftprintf(stdout, _T("Extracting StringTable...."));
122 EnumResourceNames(m_hResDll, RT_STRING, EnumResNameCallback, (LONG_PTR)this);
123 if (!m_bQuiet)
124 _ftprintf(stdout, _T("%4Iu Strings\n"), m_StringEntries.size());
125 nEntries = m_StringEntries.size();
127 if (!m_bQuiet)
128 _ftprintf(stdout, _T("Extracting Dialogs........"));
129 EnumResourceNames(m_hResDll, RT_DIALOG, EnumResNameCallback, (LONG_PTR)this);
130 if (!m_bQuiet)
131 _ftprintf(stdout, _T("%4Iu Strings\n"), m_StringEntries.size()-nEntries);
132 nEntries = m_StringEntries.size();
134 if (!m_bQuiet)
135 _ftprintf(stdout, _T("Extracting Menus.........."));
136 EnumResourceNames(m_hResDll, RT_MENU, EnumResNameCallback, (LONG_PTR)this);
137 if (!m_bQuiet)
138 _ftprintf(stdout, _T("%4Iu Strings\n"), m_StringEntries.size()-nEntries);
139 nEntries = m_StringEntries.size();
141 if (!m_bQuiet)
142 _ftprintf(stdout, _T("Extracting Accelerators..."));
143 EnumResourceNames(m_hResDll, RT_ACCELERATOR, EnumResNameCallback, (LONG_PTR)this);
144 if (!m_bQuiet)
145 _ftprintf(stdout, _T("%4Iu Accelerators\n"), m_StringEntries.size()-nEntries);
146 nEntries = m_StringEntries.size();
148 // parse a probably existing file and update the translations which are
149 // already done
150 m_StringEntries.ParseFile(lpszPoFilePath, !bNoUpdate, m_bAdjustEOLs);
152 // at last, save the new file
153 if (!m_StringEntries.SaveFile(lpszPoFilePath, lpszHeaderFile))
154 goto DONE_ERROR;
156 FreeLibrary(m_hResDll);
157 return TRUE;
159 DONE_ERROR:
160 if (m_hResDll)
161 FreeLibrary(m_hResDll);
162 return FALSE;
165 BOOL CResModule::CreateTranslatedResources(LPCTSTR lpszSrcLangDllPath, LPCTSTR lpszDestLangDllPath, LPCTSTR lpszPOFilePath)
167 if (!CopyFile(lpszSrcLangDllPath, lpszDestLangDllPath, FALSE))
168 MYERROR;
170 int count = 0;
173 if (SysInfo::Instance().IsVistaOrLater())
174 m_hResDll = LoadLibraryEx (lpszSrcLangDllPath, NULL, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE|LOAD_LIBRARY_AS_IMAGE_RESOURCE|LOAD_IGNORE_CODE_AUTHZ_LEVEL);
175 else
176 m_hResDll = LoadLibraryEx (lpszSrcLangDllPath, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE|LOAD_IGNORE_CODE_AUTHZ_LEVEL);
177 if (m_hResDll == NULL)
178 Sleep(100);
179 count++;
180 } while ((m_hResDll == NULL)&&(count < 10));
182 if (m_hResDll == NULL)
183 MYERROR;
185 sDestFile = std::wstring(lpszDestLangDllPath);
187 // get all translated strings
188 if (!m_StringEntries.ParseFile(lpszPOFilePath, FALSE, m_bAdjustEOLs))
189 goto DONE_ERROR;
190 m_bTranslatedStrings = 0;
191 m_bDefaultStrings = 0;
192 m_bTranslatedDialogStrings = 0;
193 m_bDefaultDialogStrings = 0;
194 m_bTranslatedMenuStrings = 0;
195 m_bDefaultMenuStrings = 0;
196 m_bTranslatedAcceleratorStrings = 0;
197 m_bDefaultAcceleratorStrings = 0;
199 BOOL bRes = FALSE;
200 count = 0;
203 m_hUpdateRes = BeginUpdateResource(sDestFile.c_str(), FALSE);
204 if (m_hUpdateRes == NULL)
205 Sleep(100);
206 count++;
207 } while ((m_hUpdateRes == NULL)&&(count < 10));
209 if (m_hUpdateRes == NULL)
210 MYERROR;
213 if (!m_bQuiet)
214 _ftprintf(stdout, _T("Translating StringTable..."));
215 bRes = EnumResourceNames(m_hResDll, RT_STRING, EnumResNameWriteCallback, (LONG_PTR)this);
216 if (!m_bQuiet)
217 _ftprintf(stdout, _T("%4d translated, %4d not translated\n"), m_bTranslatedStrings, m_bDefaultStrings);
219 if (!m_bQuiet)
220 _ftprintf(stdout, _T("Translating Dialogs......."));
221 bRes = EnumResourceNames(m_hResDll, RT_DIALOG, EnumResNameWriteCallback, (LONG_PTR)this);
222 if (!m_bQuiet)
223 _ftprintf(stdout, _T("%4d translated, %4d not translated\n"), m_bTranslatedDialogStrings, m_bDefaultDialogStrings);
225 if (!m_bQuiet)
226 _ftprintf(stdout, _T("Translating Menus........."));
227 bRes = EnumResourceNames(m_hResDll, RT_MENU, EnumResNameWriteCallback, (LONG_PTR)this);
228 if (!m_bQuiet)
229 _ftprintf(stdout, _T("%4d translated, %4d not translated\n"), m_bTranslatedMenuStrings, m_bDefaultMenuStrings);
231 if (!m_bQuiet)
232 _ftprintf(stdout, _T("Translating Accelerators.."));
233 bRes = EnumResourceNames(m_hResDll, RT_ACCELERATOR, EnumResNameWriteCallback, (LONG_PTR)this);
234 if (!m_bQuiet)
235 _ftprintf(stdout, _T("%4d translated, %4d not translated\n"), m_bTranslatedAcceleratorStrings, m_bDefaultAcceleratorStrings);
237 if (!m_bQuiet)
238 _ftprintf(stdout, _T("Translating Ribbons......."));
239 bRes = EnumResourceNames(m_hResDll, RT_RIBBON, EnumResNameWriteCallback, (LONG_PTR)this);
240 if (!m_bQuiet)
241 _ftprintf(stdout, _T("%4d translated, %4d not translated\n"), m_bTranslatedRibbonTexts, m_bDefaultRibbonTexts);
242 bRes = TRUE;
243 if (!EndUpdateResource(m_hUpdateRes, !bRes))
244 MYERROR;
246 FreeLibrary(m_hResDll);
247 return TRUE;
248 DONE_ERROR:
249 if (m_hResDll)
250 FreeLibrary(m_hResDll);
251 return FALSE;
254 BOOL CResModule::ExtractString(LPCTSTR lpszType)
256 HRSRC hrsrc = FindResource(m_hResDll, lpszType, RT_STRING);
257 HGLOBAL hglStringTable;
258 LPWSTR p;
260 if (!hrsrc)
261 MYERROR;
262 hglStringTable = LoadResource(m_hResDll, hrsrc);
264 if (!hglStringTable)
265 goto DONE_ERROR;
266 p = (LPWSTR)LockResource(hglStringTable);
268 if (p == NULL)
269 goto DONE_ERROR;
270 /* [Block of 16 strings. The strings are Pascal style with a WORD
271 length preceding the string. 16 strings are always written, even
272 if not all slots are full. Any slots in the block with no string
273 have a zero WORD for the length.]
276 //first check how much memory we need
277 LPWSTR pp = p;
278 for (int i=0; i<16; ++i)
280 int len = GET_WORD(pp);
281 pp++;
282 std::wstring msgid = std::wstring(pp, len);
283 WCHAR * pBuf = new WCHAR[MAX_STRING_LENGTH*2];
284 SecureZeroMemory(pBuf, MAX_STRING_LENGTH*2*sizeof(WCHAR));
285 wcscpy(pBuf, msgid.c_str());
286 CUtils::StringExtend(pBuf);
288 if (wcslen(pBuf))
290 std::wstring str = std::wstring(pBuf);
291 RESOURCEENTRY entry = m_StringEntries[str];
292 entry.resourceIDs.insert((DWORD)lpszType);
293 if (wcschr(str.c_str(), '%'))
294 entry.flag = _T("#, c-format");
295 m_StringEntries[str] = entry;
297 delete [] pBuf;
298 pp += len;
300 UnlockResource(hglStringTable);
301 FreeResource(hglStringTable);
302 return TRUE;
303 DONE_ERROR:
304 UnlockResource(hglStringTable);
305 FreeResource(hglStringTable);
306 MYERROR;
309 BOOL CResModule::ReplaceString(LPCTSTR lpszType, WORD wLanguage)
311 HRSRC hrsrc = FindResourceEx(m_hResDll, RT_STRING, lpszType, wLanguage);
312 HGLOBAL hglStringTable;
313 LPWSTR p;
315 if (!hrsrc)
316 MYERROR;
317 hglStringTable = LoadResource(m_hResDll, hrsrc);
319 if (!hglStringTable)
320 goto DONE_ERROR;
321 p = (LPWSTR)LockResource(hglStringTable);
323 if (p == NULL)
324 goto DONE_ERROR;
325 /* [Block of 16 strings. The strings are Pascal style with a WORD
326 length preceding the string. 16 strings are always written, even
327 if not all slots are full. Any slots in the block with no string
328 have a zero WORD for the length.]
331 //first check how much memory we need
332 size_t nMem = 0;
333 LPWSTR pp = p;
334 for (int i=0; i<16; ++i)
336 nMem++;
337 size_t len = GET_WORD(pp);
338 pp++;
339 std::wstring msgid = std::wstring(pp, len);
340 WCHAR * pBuf = new WCHAR[MAX_STRING_LENGTH*2];
341 SecureZeroMemory(pBuf, MAX_STRING_LENGTH*2*sizeof(WCHAR));
342 wcscpy(pBuf, msgid.c_str());
343 CUtils::StringExtend(pBuf);
344 msgid = std::wstring(pBuf);
346 RESOURCEENTRY resEntry;
347 resEntry = m_StringEntries[msgid];
348 wcscpy(pBuf, resEntry.msgstr.c_str());
349 CUtils::StringCollapse(pBuf);
350 size_t newlen = wcslen(pBuf);
351 if (newlen)
352 nMem += newlen;
353 else
354 nMem += len;
355 pp += len;
356 delete [] pBuf;
359 WORD * newTable = new WORD[nMem + (nMem % 2)];
360 SecureZeroMemory(newTable, (nMem + (nMem % 2))*2);
362 size_t index = 0;
363 for (int i=0; i<16; ++i)
365 int len = GET_WORD(p);
366 p++;
367 std::wstring msgid = std::wstring(p, len);
368 WCHAR * pBuf = new WCHAR[MAX_STRING_LENGTH*2];
369 SecureZeroMemory(pBuf, MAX_STRING_LENGTH*2*sizeof(WCHAR));
370 wcscpy(pBuf, msgid.c_str());
371 CUtils::StringExtend(pBuf);
372 msgid = std::wstring(pBuf);
374 RESOURCEENTRY resEntry;
375 resEntry = m_StringEntries[msgid];
376 wcscpy(pBuf, resEntry.msgstr.c_str());
377 CUtils::StringCollapse(pBuf);
378 size_t newlen = wcslen(pBuf);
379 if (newlen)
381 newTable[index++] = (WORD)newlen;
382 wcsncpy((wchar_t *)&newTable[index], pBuf, newlen);
383 index += newlen;
384 m_bTranslatedStrings++;
386 else
388 newTable[index++] = (WORD)len;
389 if (len)
390 wcsncpy((wchar_t *)&newTable[index], p, len);
391 index += len;
392 if (len)
393 m_bDefaultStrings++;
395 p += len;
396 delete [] pBuf;
399 if (!UpdateResource(m_hUpdateRes, RT_STRING, lpszType, (m_wTargetLang ? m_wTargetLang : wLanguage), newTable, (DWORD)(nMem + (nMem % 2))*2))
401 delete [] newTable;
402 goto DONE_ERROR;
405 if ((m_wTargetLang)&&(!UpdateResource(m_hUpdateRes, RT_STRING, lpszType, wLanguage, NULL, 0)))
407 delete [] newTable;
408 goto DONE_ERROR;
410 delete [] newTable;
411 UnlockResource(hglStringTable);
412 FreeResource(hglStringTable);
413 return TRUE;
414 DONE_ERROR:
415 UnlockResource(hglStringTable);
416 FreeResource(hglStringTable);
417 MYERROR;
420 BOOL CResModule::ExtractMenu(LPCTSTR lpszType)
422 HRSRC hrsrc = FindResource(m_hResDll, lpszType, RT_MENU);
423 HGLOBAL hglMenuTemplate;
424 WORD version, offset;
425 const WORD *p, *p0;
427 if (!hrsrc)
428 MYERROR;
430 hglMenuTemplate = LoadResource(m_hResDll, hrsrc);
432 if (!hglMenuTemplate)
433 MYERROR;
435 p = (const WORD*)LockResource(hglMenuTemplate);
437 if (p == NULL)
438 MYERROR;
440 // Standard MENU resource
441 //struct MenuHeader {
442 // WORD wVersion; // Currently zero
443 // WORD cbHeaderSize; // Also zero
444 //};
446 // MENUEX resource
447 //struct MenuExHeader {
448 // WORD wVersion; // One
449 // WORD wOffset;
450 // DWORD dwHelpId;
451 //};
452 p0 = p;
453 version = GET_WORD(p);
455 p++;
457 switch (version)
459 case 0:
461 offset = GET_WORD(p);
462 p += offset;
463 p++;
464 if (!ParseMenuResource(p))
465 goto DONE_ERROR;
467 break;
468 case 1:
470 offset = GET_WORD(p);
471 p++;
472 //dwHelpId = GET_DWORD(p);
473 if (!ParseMenuExResource(p0 + offset))
474 goto DONE_ERROR;
476 break;
477 default:
478 goto DONE_ERROR;
481 UnlockResource(hglMenuTemplate);
482 FreeResource(hglMenuTemplate);
483 return TRUE;
485 DONE_ERROR:
486 UnlockResource(hglMenuTemplate);
487 FreeResource(hglMenuTemplate);
488 MYERROR;
491 BOOL CResModule::ReplaceMenu(LPCTSTR lpszType, WORD wLanguage)
493 HRSRC hrsrc = FindResourceEx(m_hResDll, RT_MENU, lpszType, wLanguage);
494 HGLOBAL hglMenuTemplate;
495 WORD version, offset;
496 LPWSTR p;
497 WORD *p0;
499 if (!hrsrc)
500 MYERROR; //just the language wasn't found
502 hglMenuTemplate = LoadResource(m_hResDll, hrsrc);
504 if (!hglMenuTemplate)
505 MYERROR;
507 p = (LPWSTR)LockResource(hglMenuTemplate);
509 if (p == NULL)
510 MYERROR;
512 //struct MenuHeader {
513 // WORD wVersion; // Currently zero
514 // WORD cbHeaderSize; // Also zero
515 //};
517 // MENUEX resource
518 //struct MenuExHeader {
519 // WORD wVersion; // One
520 // WORD wOffset;
521 // DWORD dwHelpId;
522 //};
523 p0 = (WORD *)p;
524 version = GET_WORD(p);
526 p++;
528 switch (version)
530 case 0:
532 offset = GET_WORD(p);
533 p += offset;
534 p++;
535 size_t nMem = 0;
536 if (!CountMemReplaceMenuResource((WORD *)p, &nMem, NULL))
537 goto DONE_ERROR;
538 WORD * newMenu = new WORD[nMem + (nMem % 2)+2];
539 SecureZeroMemory(newMenu, (nMem + (nMem % 2)+2)*2);
540 size_t index = 2; // MenuHeader has 2 WORDs zero
541 if (!CountMemReplaceMenuResource((WORD *)p, &index, newMenu))
543 delete [] newMenu;
544 goto DONE_ERROR;
547 if (!UpdateResource(m_hUpdateRes, RT_MENU, lpszType, (m_wTargetLang ? m_wTargetLang : wLanguage), newMenu, (DWORD)(nMem + (nMem % 2)+2)*2))
549 delete [] newMenu;
550 goto DONE_ERROR;
553 if ((m_wTargetLang)&&(!UpdateResource(m_hUpdateRes, RT_MENU, lpszType, wLanguage, NULL, 0)))
555 delete [] newMenu;
556 goto DONE_ERROR;
558 delete [] newMenu;
560 break;
561 case 1:
563 offset = GET_WORD(p);
564 p++;
565 //dwHelpId = GET_DWORD(p);
566 size_t nMem = 0;
567 if (!CountMemReplaceMenuExResource((WORD *)(p0 + offset), &nMem, NULL))
568 goto DONE_ERROR;
569 WORD * newMenu = new WORD[nMem + (nMem % 2) + 4];
570 SecureZeroMemory(newMenu, (nMem + (nMem % 2) + 4) * 2);
571 CopyMemory(newMenu, p0, 2 * sizeof(WORD) + sizeof(DWORD));
572 size_t index = 4; // MenuExHeader has 2 x WORD + 1 x DWORD
573 if (!CountMemReplaceMenuExResource((WORD *)(p0 + offset), &index, newMenu))
575 delete [] newMenu;
576 goto DONE_ERROR;
579 if (!UpdateResource(m_hUpdateRes, RT_MENU, lpszType, (m_wTargetLang ? m_wTargetLang : wLanguage), newMenu, (DWORD)(nMem + (nMem % 2) + 4) * 2))
581 delete [] newMenu;
582 goto DONE_ERROR;
585 if ((m_wTargetLang)&&(!UpdateResource(m_hUpdateRes, RT_MENU, lpszType, wLanguage, NULL, 0)))
587 delete [] newMenu;
588 goto DONE_ERROR;
590 delete [] newMenu;
592 break;
593 default:
594 goto DONE_ERROR;
597 UnlockResource(hglMenuTemplate);
598 FreeResource(hglMenuTemplate);
599 return TRUE;
601 DONE_ERROR:
602 UnlockResource(hglMenuTemplate);
603 FreeResource(hglMenuTemplate);
604 MYERROR;
607 const WORD* CResModule::ParseMenuResource(const WORD * res)
609 WORD flags;
610 WORD id = 0;
612 //struct PopupMenuItem {
613 // WORD fItemFlags;
614 // WCHAR szItemText[];
615 //};
616 //struct NormalMenuItem {
617 // WORD fItemFlags;
618 // WORD wMenuID;
619 // WCHAR szItemText[];
620 //};
624 flags = GET_WORD(res);
625 res++;
626 if (!(flags & MF_POPUP))
628 id = GET_WORD(res); //normal menu item
629 res++;
631 else
632 id = (WORD)-1; //popup menu item
634 LPCWSTR str = (LPCWSTR)res;
635 size_t l = wcslen(str)+1;
636 res += l;
638 if (flags & MF_POPUP)
640 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
641 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
642 _tcscpy(pBuf, str);
643 CUtils::StringExtend(pBuf);
645 std::wstring wstr = std::wstring(pBuf);
646 RESOURCEENTRY entry = m_StringEntries[wstr];
647 if (id)
648 entry.resourceIDs.insert(id);
650 m_StringEntries[wstr] = entry;
651 delete [] pBuf;
653 if ((res = ParseMenuResource(res))==0)
654 return NULL;
656 else if (id != 0)
658 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
659 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
660 _tcscpy(pBuf, str);
661 CUtils::StringExtend(pBuf);
663 std::wstring wstr = std::wstring(pBuf);
664 RESOURCEENTRY entry = m_StringEntries[wstr];
665 entry.resourceIDs.insert(id);
667 TCHAR szTempBuf[1024] = { 0 };
668 _stprintf(szTempBuf, _T("#: MenuEntry; ID:%u"), id);
669 MENUENTRY menu_entry;
670 menu_entry.wID = id;
671 menu_entry.reference = szTempBuf;
672 menu_entry.msgstr = wstr;
674 m_StringEntries[wstr] = entry;
675 m_MenuEntries[id] = menu_entry;
676 delete [] pBuf;
678 } while (!(flags & MF_END));
679 return res;
682 const WORD* CResModule::CountMemReplaceMenuResource(const WORD * res, size_t * wordcount, WORD * newMenu)
684 WORD flags;
685 WORD id = 0;
687 //struct PopupMenuItem {
688 // WORD fItemFlags;
689 // WCHAR szItemText[];
690 //};
691 //struct NormalMenuItem {
692 // WORD fItemFlags;
693 // WORD wMenuID;
694 // WCHAR szItemText[];
695 //};
699 flags = GET_WORD(res);
700 res++;
701 if (newMenu == NULL)
702 (*wordcount)++;
703 else
704 newMenu[(*wordcount)++] = flags;
705 if (!(flags & MF_POPUP))
707 id = GET_WORD(res); //normal menu item
708 res++;
709 if (newMenu == NULL)
710 (*wordcount)++;
711 else
712 newMenu[(*wordcount)++] = id;
714 else
715 id = (WORD)-1; //popup menu item
717 if (flags & MF_POPUP)
719 ReplaceStr((LPCWSTR)res, newMenu, wordcount, &m_bTranslatedMenuStrings, &m_bDefaultMenuStrings);
720 res += wcslen((LPCWSTR)res) + 1;
722 if ((res = CountMemReplaceMenuResource(res, wordcount, newMenu))==0)
723 return NULL;
725 else if (id != 0)
727 ReplaceStr((LPCWSTR)res, newMenu, wordcount, &m_bTranslatedMenuStrings, &m_bDefaultMenuStrings);
728 res += wcslen((LPCWSTR)res) + 1;
730 else
732 if (newMenu)
733 wcscpy((wchar_t *)&newMenu[(*wordcount)], (LPCWSTR)res);
734 (*wordcount) += wcslen((LPCWSTR)res) + 1;
735 res += wcslen((LPCWSTR)res) + 1;
737 } while (!(flags & MF_END));
738 return res;
741 const WORD* CResModule::ParseMenuExResource(const WORD * res)
743 WORD bResInfo;
745 //struct MenuExItem {
746 // DWORD dwType;
747 // DWORD dwState;
748 // DWORD menuId;
749 // WORD bResInfo;
750 // WCHAR szText[];
751 // DWORD dwHelpId; - Popup menu only
752 //};
756 DWORD dwType = GET_DWORD(res);
757 res += 2;
758 //dwState = GET_DWORD(res);
759 res += 2;
760 DWORD menuId = GET_DWORD(res);
761 res += 2;
762 bResInfo = GET_WORD(res);
763 res++;
765 LPCWSTR str = (LPCWSTR)res;
766 size_t l = wcslen(str)+1;
767 res += l;
768 // Align to DWORD boundary
769 res += ((((WORD)res + 3) & ~3) - (WORD)res)/sizeof(WORD);
771 if (dwType & MFT_SEPARATOR)
772 continue;
774 if (bResInfo & 0x01)
776 // Popup menu - note this can also have a non-zero ID
777 if (menuId == 0)
778 menuId = (WORD)-1;
779 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
780 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
781 _tcscpy(pBuf, str);
782 CUtils::StringExtend(pBuf);
784 std::wstring wstr = std::wstring(pBuf);
785 RESOURCEENTRY entry = m_StringEntries[wstr];
786 // Popup has a DWORD help entry on a DWORD boundary - skip over it
787 res += 2;
789 entry.resourceIDs.insert(menuId);
790 TCHAR szTempBuf[1024] = { 0 };
791 _stprintf(szTempBuf, _T("#: MenuExPopupEntry; ID:%lu"), menuId);
792 MENUENTRY menu_entry;
793 menu_entry.wID = (WORD)menuId;
794 menu_entry.reference = szTempBuf;
795 menu_entry.msgstr = wstr;
796 m_StringEntries[wstr] = entry;
797 m_MenuEntries[(WORD)menuId] = menu_entry;
798 delete [] pBuf;
800 if ((res = ParseMenuExResource(res)) == 0)
801 return NULL;
802 } else if (menuId != 0)
804 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
805 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
806 _tcscpy(pBuf, str);
807 CUtils::StringExtend(pBuf);
809 std::wstring wstr = std::wstring(pBuf);
810 RESOURCEENTRY entry = m_StringEntries[wstr];
811 entry.resourceIDs.insert(menuId);
813 TCHAR szTempBuf[1024] = { 0 };
814 _stprintf(szTempBuf, _T("#: MenuExEntry; ID:%lu"), menuId);
815 MENUENTRY menu_entry;
816 menu_entry.wID = (WORD)menuId;
817 menu_entry.reference = szTempBuf;
818 menu_entry.msgstr = wstr;
819 m_StringEntries[wstr] = entry;
820 m_MenuEntries[(WORD)menuId] = menu_entry;
821 delete [] pBuf;
823 } while (!(bResInfo & 0x80));
824 return res;
827 const WORD* CResModule::CountMemReplaceMenuExResource(const WORD * res, size_t * wordcount, WORD * newMenu)
829 WORD bResInfo;
831 //struct MenuExItem {
832 // DWORD dwType;
833 // DWORD dwState;
834 // DWORD menuId;
835 // WORD bResInfo;
836 // WCHAR szText[];
837 // DWORD dwHelpId; - Popup menu only
838 //};
842 WORD * p0 = (WORD *)res;
843 DWORD dwType = GET_DWORD(res);
844 res += 2;
845 //dwState = GET_DWORD(res);
846 res += 2;
847 DWORD menuId = GET_DWORD(res);
848 res += 2;
849 bResInfo = GET_WORD(res);
850 res++;
852 if (newMenu != NULL) {
853 CopyMemory(&newMenu[*wordcount], p0, 7 * sizeof(WORD));
855 (*wordcount) += 7;
857 if (dwType & MFT_SEPARATOR) {
858 // Align to DWORD
859 (*wordcount)++;
860 res++;
861 continue;
864 if (bResInfo & 0x01)
866 ReplaceStr((LPCWSTR)res, newMenu, wordcount, &m_bTranslatedMenuStrings, &m_bDefaultMenuStrings);
867 res += wcslen((LPCWSTR)res) + 1;
868 // Align to DWORD
869 res += ((((WORD)res + 3) & ~3) - (WORD)res)/sizeof(WORD);
870 if ((*wordcount) & 0x01)
871 (*wordcount)++;
873 if (newMenu != NULL)
874 CopyMemory(&newMenu[*wordcount], res, sizeof(DWORD)); // Copy Help ID
876 res += 2;
877 (*wordcount) += 2;
879 if ((res = CountMemReplaceMenuExResource(res, wordcount, newMenu)) == 0)
880 return NULL;
882 else if (menuId != 0)
884 ReplaceStr((LPCWSTR)res, newMenu, wordcount, &m_bTranslatedMenuStrings, &m_bDefaultMenuStrings);
885 res += wcslen((LPCWSTR)res) + 1;
887 else
889 if (newMenu)
890 wcscpy((wchar_t *)&newMenu[(*wordcount)], (LPCWSTR)res);
891 (*wordcount) += wcslen((LPCWSTR)res) + 1;
892 res += wcslen((LPCWSTR)res) + 1;
894 // Align to DWORD
895 res += ((((WORD)res + 3) & ~3) - (WORD)res)/sizeof(WORD);
896 if ((*wordcount) & 0x01)
897 (*wordcount)++;
898 } while (!(bResInfo & 0x80));
899 return res;
902 BOOL CResModule::ExtractAccelerator(LPCTSTR lpszType)
904 HRSRC hrsrc = FindResource(m_hResDll, lpszType, RT_ACCELERATOR);
905 HGLOBAL hglAccTable;
906 WORD fFlags, wAnsi, wID;
907 const WORD* p;
908 bool bEnd(false);
910 if (!hrsrc)
911 MYERROR;
913 hglAccTable = LoadResource(m_hResDll, hrsrc);
915 if (!hglAccTable)
916 goto DONE_ERROR;
918 p = (const WORD*)LockResource(hglAccTable);
920 if (p == NULL)
921 MYERROR;
924 struct ACCELTABLEENTRY
926 WORD fFlags; FVIRTKEY, FSHIFT, FCONTROL, FALT, 0x80 - Last in a table
927 WORD wAnsi; ANSI character
928 WORD wId; Keyboard accelerator passed to windows
929 WORD padding; # bytes added to ensure aligned to DWORD boundary
935 fFlags = GET_WORD(p);
936 p++;
937 wAnsi = GET_WORD(p);
938 p++;
939 wID = GET_WORD(p);
940 p++;
941 p++; // Skip over padding
943 if ((fFlags & 0x80) == 0x80)
944 { // 0x80
945 bEnd = true;
948 if ((wAnsi < 0x30) ||
949 (wAnsi > 0x5A) ||
950 (wAnsi >= 0x3A && wAnsi <= 0x40))
951 continue;
953 std::unique_ptr<WCHAR[]> pBuf(new WCHAR[1024]);
954 std::unique_ptr<WCHAR[]> pBuf2(new WCHAR[1024]);
955 SecureZeroMemory(pBuf.get(), 1024 * sizeof(WCHAR));
956 SecureZeroMemory(pBuf2.get(), 1024 * sizeof(WCHAR));
958 // include the menu ID in the msgid to make sure that 'duplicate'
959 // accelerator keys are listed in the po-file.
960 // without this, we would get entries like this:
961 //#. Accelerator Entry for Menu ID:32809; '&Filter'
962 //#. Accelerator Entry for Menu ID:57636; '&Find'
963 //#: Corresponding Menu ID:32771; '&Find'
964 //msgid "V C +F"
965 //msgstr ""
967 // Since "filter" and "find" are most likely translated to words starting
968 // with different letters, we need to have a separate accelerator entry
969 // for each of those
970 _stprintf(pBuf.get(), _T("ID:%u:"), wID);
972 // EXACTLY 5 characters long "ACS+X"
973 // V = Virtual key (or blank if not used)
974 // A = Alt key (or blank if not used)
975 // C = Ctrl key (or blank if not used)
976 // S = Shift key (or blank if not used)
977 // X = upper case character
978 // e.g. "V CS+Q" == Ctrl + Shift + 'Q'
979 if ((fFlags & FVIRTKEY) == FVIRTKEY) // 0x01
980 _tcscat(pBuf.get(), _T("V"));
981 else
982 _tcscat(pBuf.get(), _T(" "));
984 if ((fFlags & FALT) == FALT) // 0x10
985 _tcscat(pBuf.get(), _T("A"));
986 else
987 _tcscat(pBuf.get(), _T(" "));
989 if ((fFlags & FCONTROL) == FCONTROL) // 0x08
990 _tcscat(pBuf.get(), _T("C"));
991 else
992 _tcscat(pBuf.get(), _T(" "));
994 if ((fFlags & FSHIFT) == FSHIFT) // 0x04
995 _tcscat(pBuf.get(), _T("S"));
996 else
997 _tcscat(pBuf.get(), _T(" "));
999 _stprintf(pBuf2.get(), _T("%s+%c"), pBuf.get(), wAnsi);
1001 std::wstring wstr = std::wstring(pBuf2.get());
1002 RESOURCEENTRY AKey_entry = m_StringEntries[wstr];
1004 TCHAR szTempBuf[1024] = { 0 };
1005 SecureZeroMemory(szTempBuf, sizeof (szTempBuf));
1006 std::wstring wmenu = _T("");
1007 pME_iter = m_MenuEntries.find(wID);
1008 if (pME_iter != m_MenuEntries.end())
1010 wmenu = pME_iter->second.msgstr;
1012 _stprintf(szTempBuf, _T("#. Accelerator Entry for Menu ID:%u; '%s'"), wID, wmenu.c_str());
1013 AKey_entry.automaticcomments.push_back(std::wstring(szTempBuf));
1015 m_StringEntries[wstr] = AKey_entry;
1016 } while (!bEnd);
1018 UnlockResource(hglAccTable);
1019 FreeResource(hglAccTable);
1020 return TRUE;
1022 DONE_ERROR:
1023 UnlockResource(hglAccTable);
1024 FreeResource(hglAccTable);
1025 MYERROR;
1028 BOOL CResModule::ReplaceAccelerator(LPCTSTR lpszType, WORD wLanguage)
1030 LPACCEL lpaccelNew; // pointer to new accelerator table
1031 HACCEL haccelOld; // handle to old accelerator table
1032 int cAccelerators; // number of accelerators in table
1033 HGLOBAL hglAccTableNew;
1034 const WORD* p;
1035 int i;
1037 haccelOld = LoadAccelerators(m_hResDll, lpszType);
1039 if (haccelOld == NULL)
1040 MYERROR;
1042 cAccelerators = CopyAcceleratorTable(haccelOld, NULL, 0);
1044 lpaccelNew = (LPACCEL) LocalAlloc(LPTR, cAccelerators * sizeof(ACCEL));
1046 if (lpaccelNew == NULL)
1047 MYERROR;
1049 CopyAcceleratorTable(haccelOld, lpaccelNew, cAccelerators);
1051 // Find the accelerator that the user modified
1052 // and change its flags and virtual-key code
1053 // as appropriate.
1055 BYTE xfVirt;
1056 WORD xkey;
1057 static const size_t BufferSize = 1024;
1058 std::unique_ptr<WCHAR[]> pBuf(new WCHAR[BufferSize]);
1059 std::unique_ptr<WCHAR[]> pBuf2(new WCHAR[BufferSize]);
1060 for (i = 0; i < cAccelerators; i++)
1062 if ((lpaccelNew[i].key < 0x30) ||
1063 (lpaccelNew[i].key > 0x5A) ||
1064 (lpaccelNew[i].key >= 0x3A && lpaccelNew[i].key <= 0x40))
1065 continue;
1067 SecureZeroMemory(pBuf.get(), 1024 * sizeof(WCHAR));
1068 SecureZeroMemory(pBuf2.get(), 1024 * sizeof(WCHAR));
1070 _stprintf(pBuf.get(), _T("ID:%d:"), lpaccelNew[i].cmd);
1072 // get original key combination
1073 if ((lpaccelNew[i].fVirt & FVIRTKEY) == FVIRTKEY) // 0x01
1074 _tcscat(pBuf.get(), _T("V"));
1075 else
1076 _tcscat(pBuf.get(), _T(" "));
1078 if ((lpaccelNew[i].fVirt & FALT) == FALT) // 0x10
1079 _tcscat(pBuf.get(), _T("A"));
1080 else
1081 _tcscat(pBuf.get(), _T(" "));
1083 if ((lpaccelNew[i].fVirt & FCONTROL) == FCONTROL) // 0x08
1084 _tcscat(pBuf.get(), _T("C"));
1085 else
1086 _tcscat(pBuf.get(), _T(" "));
1088 if ((lpaccelNew[i].fVirt & FSHIFT) == FSHIFT) // 0x04
1089 _tcscat(pBuf.get(), _T("S"));
1090 else
1091 _tcscat(pBuf.get(), _T(" "));
1093 _stprintf(pBuf2.get(), _T("%s+%c"), pBuf.get(), lpaccelNew[i].key);
1095 // Is it there?
1096 std::map<std::wstring, RESOURCEENTRY>::iterator pAK_iter = m_StringEntries.find(pBuf2.get());
1097 if (pAK_iter != m_StringEntries.end())
1099 m_bTranslatedAcceleratorStrings++;
1100 xfVirt = 0;
1101 xkey = 0;
1102 std::wstring wtemp = pAK_iter->second.msgstr;
1103 wtemp = wtemp.substr(wtemp.find_last_of(':')+1);
1104 if (wtemp.size() != 6)
1105 continue;
1106 if (wtemp.compare(0, 1, _T("V")) == 0)
1107 xfVirt |= FVIRTKEY;
1108 else if (wtemp.compare(0, 1, _T(" ")) != 0)
1109 continue; // not a space - user must have made a mistake when translating
1110 if (wtemp.compare(1, 1, _T("A")) == 0)
1111 xfVirt |= FALT;
1112 else if (wtemp.compare(1, 1, _T(" ")) != 0)
1113 continue; // not a space - user must have made a mistake when translating
1114 if (wtemp.compare(2, 1, _T("C")) == 0)
1115 xfVirt |= FCONTROL;
1116 else if (wtemp.compare(2, 1, _T(" ")) != 0)
1117 continue; // not a space - user must have made a mistake when translating
1118 if (wtemp.compare(3, 1, _T("S")) == 0)
1119 xfVirt |= FSHIFT;
1120 else if (wtemp.compare(3, 1, _T(" ")) != 0)
1121 continue; // not a space - user must have made a mistake when translating
1122 if (wtemp.compare(4, 1, _T("+")) == 0)
1124 _stscanf(wtemp.substr(5, 1).c_str(), _T("%c"), &xkey);
1125 lpaccelNew[i].fVirt = xfVirt;
1126 lpaccelNew[i].key = xkey;
1129 else
1130 m_bDefaultAcceleratorStrings++;
1134 // Create the new accelerator table
1135 hglAccTableNew = LocalAlloc(LPTR, cAccelerators * 4 * sizeof(WORD));
1136 p = (WORD *)hglAccTableNew;
1137 lpaccelNew[cAccelerators-1].fVirt |= 0x80;
1138 for (i = 0; i < cAccelerators; i++)
1140 memcpy((void *)p, &lpaccelNew[i].fVirt, 1);
1141 p++;
1142 memcpy((void *)p, &lpaccelNew[i].key, sizeof(WORD));
1143 p++;
1144 memcpy((void *)p, &lpaccelNew[i].cmd, sizeof(WORD));
1145 p++;
1146 p++;
1149 if (!UpdateResource(m_hUpdateRes, RT_ACCELERATOR, lpszType,
1150 (m_wTargetLang ? m_wTargetLang : wLanguage), hglAccTableNew /* haccelNew*/, cAccelerators * 4 * sizeof(WORD)))
1152 goto DONE_ERROR;
1155 if ((m_wTargetLang)&&(!UpdateResource(m_hUpdateRes, RT_ACCELERATOR, lpszType, wLanguage, NULL, 0)))
1157 goto DONE_ERROR;
1160 LocalFree(hglAccTableNew);
1161 LocalFree(lpaccelNew);
1162 return TRUE;
1164 DONE_ERROR:
1165 LocalFree(hglAccTableNew);
1166 LocalFree(lpaccelNew);
1167 MYERROR;
1170 BOOL CResModule::ExtractDialog(LPCTSTR lpszType)
1172 const WORD* lpDlg;
1173 const WORD* lpDlgItem;
1174 DIALOGINFO dlg;
1175 DLGITEMINFO dlgItem;
1176 WORD bNumControls;
1177 HRSRC hrsrc;
1178 HGLOBAL hGlblDlgTemplate;
1180 hrsrc = FindResource(m_hResDll, lpszType, RT_DIALOG);
1182 if (hrsrc == NULL)
1183 MYERROR;
1185 hGlblDlgTemplate = LoadResource(m_hResDll, hrsrc);
1186 if (hGlblDlgTemplate == NULL)
1187 MYERROR;
1189 lpDlg = (const WORD*) LockResource(hGlblDlgTemplate);
1191 if (lpDlg == NULL)
1192 MYERROR;
1194 lpDlgItem = (const WORD*) GetDialogInfo(lpDlg, &dlg);
1195 bNumControls = dlg.nbItems;
1197 if (dlg.caption)
1199 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
1200 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
1201 _tcscpy(pBuf, dlg.caption);
1202 CUtils::StringExtend(pBuf);
1204 std::wstring wstr = std::wstring(pBuf);
1205 RESOURCEENTRY entry = m_StringEntries[wstr];
1206 entry.resourceIDs.insert((DWORD)lpszType);
1208 m_StringEntries[wstr] = entry;
1209 delete [] pBuf;
1212 while (bNumControls-- != 0)
1214 TCHAR szTitle[500] = { 0 };
1215 SecureZeroMemory(szTitle, sizeof(szTitle));
1216 BOOL bCode;
1218 lpDlgItem = GetControlInfo((WORD *) lpDlgItem, &dlgItem, dlg.dialogEx, &bCode);
1220 if (bCode == FALSE)
1221 _tcscpy(szTitle, dlgItem.windowName);
1223 if (_tcslen(szTitle) > 0)
1225 CUtils::StringExtend(szTitle);
1227 std::wstring wstr = std::wstring(szTitle);
1228 RESOURCEENTRY entry = m_StringEntries[wstr];
1229 entry.resourceIDs.insert(dlgItem.id);
1231 m_StringEntries[wstr] = entry;
1235 UnlockResource(hGlblDlgTemplate);
1236 FreeResource(hGlblDlgTemplate);
1237 return (TRUE);
1240 BOOL CResModule::ReplaceDialog(LPCTSTR lpszType, WORD wLanguage)
1242 const WORD* lpDlg;
1243 HRSRC hrsrc;
1244 HGLOBAL hGlblDlgTemplate;
1246 hrsrc = FindResourceEx(m_hResDll, RT_DIALOG, lpszType, wLanguage);
1248 if (hrsrc == NULL)
1249 MYERROR;
1251 hGlblDlgTemplate = LoadResource(m_hResDll, hrsrc);
1253 if (hGlblDlgTemplate == NULL)
1254 MYERROR;
1256 lpDlg = (WORD *) LockResource(hGlblDlgTemplate);
1258 if (lpDlg == NULL)
1259 MYERROR;
1261 size_t nMem = 0;
1262 const WORD * p = lpDlg;
1263 if (!CountMemReplaceDialogResource(p, &nMem, NULL))
1264 goto DONE_ERROR;
1265 WORD * newDialog = new WORD[nMem + (nMem % 2)];
1266 SecureZeroMemory(newDialog, (nMem + (nMem % 2))*2);
1268 size_t index = 0;
1269 if (!CountMemReplaceDialogResource(lpDlg, &index, newDialog))
1271 delete [] newDialog;
1272 goto DONE_ERROR;
1275 if (!UpdateResource(m_hUpdateRes, RT_DIALOG, lpszType, (m_wTargetLang ? m_wTargetLang : wLanguage), newDialog, (DWORD)(nMem + (nMem % 2))*2))
1277 delete [] newDialog;
1278 goto DONE_ERROR;
1281 if ((m_wTargetLang)&&(!UpdateResource(m_hUpdateRes, RT_DIALOG, lpszType, wLanguage, NULL, 0)))
1283 delete [] newDialog;
1284 goto DONE_ERROR;
1287 delete [] newDialog;
1288 UnlockResource(hGlblDlgTemplate);
1289 FreeResource(hGlblDlgTemplate);
1290 return TRUE;
1292 DONE_ERROR:
1293 UnlockResource(hGlblDlgTemplate);
1294 FreeResource(hGlblDlgTemplate);
1295 MYERROR;
1298 const WORD* CResModule::GetDialogInfo(const WORD * pTemplate, LPDIALOGINFO lpDlgInfo) const
1300 const WORD* p = (const WORD *)pTemplate;
1302 lpDlgInfo->style = GET_DWORD(p);
1303 p += 2;
1305 if (lpDlgInfo->style == 0xffff0001) // DIALOGEX resource
1307 lpDlgInfo->dialogEx = TRUE;
1308 lpDlgInfo->helpId = GET_DWORD(p);
1309 p += 2;
1310 lpDlgInfo->exStyle = GET_DWORD(p);
1311 p += 2;
1312 lpDlgInfo->style = GET_DWORD(p);
1313 p += 2;
1315 else
1317 lpDlgInfo->dialogEx = FALSE;
1318 lpDlgInfo->helpId = 0;
1319 lpDlgInfo->exStyle = GET_DWORD(p);
1320 p += 2;
1323 lpDlgInfo->nbItems = GET_WORD(p);
1324 p++;
1326 lpDlgInfo->x = GET_WORD(p);
1327 p++;
1329 lpDlgInfo->y = GET_WORD(p);
1330 p++;
1332 lpDlgInfo->cx = GET_WORD(p);
1333 p++;
1335 lpDlgInfo->cy = GET_WORD(p);
1336 p++;
1338 // Get the menu name
1340 switch (GET_WORD(p))
1342 case 0x0000:
1343 lpDlgInfo->menuName = NULL;
1344 p++;
1345 break;
1346 case 0xffff:
1347 lpDlgInfo->menuName = (LPCTSTR) (WORD) GET_WORD(p + 1);
1348 p += 2;
1349 break;
1350 default:
1351 lpDlgInfo->menuName = (LPCTSTR) p;
1352 p += wcslen((LPCWSTR) p) + 1;
1353 break;
1356 // Get the class name
1358 switch (GET_WORD(p))
1360 case 0x0000:
1361 lpDlgInfo->className = (LPCTSTR)MAKEINTATOM(32770);
1362 p++;
1363 break;
1364 case 0xffff:
1365 lpDlgInfo->className = (LPCTSTR) (WORD) GET_WORD(p + 1);
1366 p += 2;
1367 break;
1368 default:
1369 lpDlgInfo->className = (LPCTSTR) p;
1370 p += wcslen((LPCTSTR)p) + 1;
1371 break;
1374 // Get the window caption
1376 lpDlgInfo->caption = (LPCTSTR)p;
1377 p += wcslen((LPCWSTR) p) + 1;
1379 // Get the font name
1381 if (lpDlgInfo->style & DS_SETFONT)
1383 lpDlgInfo->pointSize = GET_WORD(p);
1384 p++;
1386 if (lpDlgInfo->dialogEx)
1388 lpDlgInfo->weight = GET_WORD(p);
1389 p++;
1390 lpDlgInfo->italic = LOBYTE(GET_WORD(p));
1391 p++;
1393 else
1395 lpDlgInfo->weight = FW_DONTCARE;
1396 lpDlgInfo->italic = FALSE;
1399 lpDlgInfo->faceName = (LPCTSTR)p;
1400 p += wcslen((LPCWSTR) p) + 1;
1402 // First control is on DWORD boundary
1403 p += ((((WORD)p + 3) & ~3) - (WORD)p)/sizeof(WORD);
1405 return p;
1408 const WORD* CResModule::GetControlInfo(const WORD* p, LPDLGITEMINFO lpDlgItemInfo, BOOL dialogEx, LPBOOL bIsID) const
1410 if (dialogEx)
1412 lpDlgItemInfo->helpId = GET_DWORD(p);
1413 p += 2;
1414 lpDlgItemInfo->exStyle = GET_DWORD(p);
1415 p += 2;
1416 lpDlgItemInfo->style = GET_DWORD(p);
1417 p += 2;
1419 else
1421 lpDlgItemInfo->helpId = 0;
1422 lpDlgItemInfo->style = GET_DWORD(p);
1423 p += 2;
1424 lpDlgItemInfo->exStyle = GET_DWORD(p);
1425 p += 2;
1428 lpDlgItemInfo->x = GET_WORD(p);
1429 p++;
1431 lpDlgItemInfo->y = GET_WORD(p);
1432 p++;
1434 lpDlgItemInfo->cx = GET_WORD(p);
1435 p++;
1437 lpDlgItemInfo->cy = GET_WORD(p);
1438 p++;
1440 if (dialogEx)
1442 // ID is a DWORD for DIALOGEX
1443 lpDlgItemInfo->id = (WORD) GET_DWORD(p);
1444 p += 2;
1446 else
1448 lpDlgItemInfo->id = GET_WORD(p);
1449 p++;
1452 if (GET_WORD(p) == 0xffff)
1454 GET_WORD(p + 1);
1456 p += 2;
1458 else
1460 lpDlgItemInfo->className = (LPCTSTR) p;
1461 p += wcslen((LPCWSTR) p) + 1;
1464 if (GET_WORD(p) == 0xffff) // an integer ID?
1466 *bIsID = TRUE;
1467 lpDlgItemInfo->windowName = (LPCTSTR) (DWORD) GET_WORD(p + 1);
1468 p += 2;
1470 else
1472 *bIsID = FALSE;
1473 lpDlgItemInfo->windowName = (LPCTSTR) p;
1474 p += wcslen((LPCWSTR) p) + 1;
1477 if (GET_WORD(p))
1479 lpDlgItemInfo->data = (LPVOID) (p + 1);
1480 p += GET_WORD(p) / sizeof(WORD);
1482 else
1483 lpDlgItemInfo->data = NULL;
1485 p++;
1486 // Next control is on DWORD boundary
1487 p += ((((WORD)p + 3) & ~3) - (WORD)p)/sizeof(WORD);
1488 return p;
1491 const WORD * CResModule::CountMemReplaceDialogResource(const WORD * res, size_t * wordcount, WORD * newDialog)
1493 BOOL bEx = FALSE;
1494 DWORD style = GET_DWORD(res);
1495 if (newDialog)
1497 newDialog[(*wordcount)++] = GET_WORD(res++);
1498 newDialog[(*wordcount)++] = GET_WORD(res++);
1500 else
1502 res += 2;
1503 (*wordcount) += 2;
1506 if (style == 0xffff0001) // DIALOGEX resource
1508 bEx = TRUE;
1509 if (newDialog)
1511 newDialog[(*wordcount)++] = GET_WORD(res++); //help id
1512 newDialog[(*wordcount)++] = GET_WORD(res++); //help id
1513 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1514 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1515 style = GET_DWORD(res);
1516 newDialog[(*wordcount)++] = GET_WORD(res++); //style
1517 newDialog[(*wordcount)++] = GET_WORD(res++); //style
1519 else
1521 res += 4;
1522 style = GET_DWORD(res);
1523 res += 2;
1524 (*wordcount) += 6;
1527 else
1529 bEx = FALSE;
1530 if (newDialog)
1532 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1533 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1534 //style = GET_DWORD(res);
1535 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1536 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1538 else
1540 res += 2;
1541 (*wordcount) += 2;
1545 if (newDialog)
1546 newDialog[(*wordcount)] = GET_WORD(res);
1547 WORD nbItems = GET_WORD(res);
1548 (*wordcount)++;
1549 res++;
1551 if (newDialog)
1552 newDialog[(*wordcount)] = GET_WORD(res); //x
1553 (*wordcount)++;
1554 res++;
1556 if (newDialog)
1557 newDialog[(*wordcount)] = GET_WORD(res); //y
1558 (*wordcount)++;
1559 res++;
1561 if (newDialog)
1562 newDialog[(*wordcount)] = GET_WORD(res); //cx
1563 (*wordcount)++;
1564 res++;
1566 if (newDialog)
1567 newDialog[(*wordcount)] = GET_WORD(res); //cy
1568 (*wordcount)++;
1569 res++;
1571 // Get the menu name
1573 switch (GET_WORD(res))
1575 case 0x0000:
1576 if (newDialog)
1577 newDialog[(*wordcount)] = GET_WORD(res);
1578 (*wordcount)++;
1579 res++;
1580 break;
1581 case 0xffff:
1582 if (newDialog)
1584 newDialog[(*wordcount)++] = GET_WORD(res++);
1585 newDialog[(*wordcount)++] = GET_WORD(res++);
1587 else
1589 (*wordcount) += 2;
1590 res += 2;
1592 break;
1593 default:
1594 if (newDialog)
1596 wcscpy((LPWSTR)&newDialog[(*wordcount)], (LPCWSTR)res);
1598 (*wordcount) += wcslen((LPCWSTR) res) + 1;
1599 res += wcslen((LPCWSTR) res) + 1;
1600 break;
1603 // Get the class name
1605 switch (GET_WORD(res))
1607 case 0x0000:
1608 if (newDialog)
1609 newDialog[(*wordcount)] = GET_WORD(res);
1610 (*wordcount)++;
1611 res++;
1612 break;
1613 case 0xffff:
1614 if (newDialog)
1616 newDialog[(*wordcount)++] = GET_WORD(res++);
1617 newDialog[(*wordcount)++] = GET_WORD(res++);
1619 else
1621 (*wordcount) += 2;
1622 res += 2;
1624 break;
1625 default:
1626 if (newDialog)
1628 wcscpy((LPWSTR)&newDialog[(*wordcount)], (LPCWSTR)res);
1630 (*wordcount) += wcslen((LPCWSTR) res) + 1;
1631 res += wcslen((LPCWSTR) res) + 1;
1632 break;
1635 // Get the window caption
1637 ReplaceStr((LPCWSTR)res, newDialog, wordcount, &m_bTranslatedDialogStrings, &m_bDefaultDialogStrings);
1638 res += wcslen((LPCWSTR)res) + 1;
1640 // Get the font name
1642 if (style & DS_SETFONT)
1644 if (newDialog)
1645 newDialog[(*wordcount)] = GET_WORD(res);
1646 res++;
1647 (*wordcount)++;
1649 if (bEx)
1651 if (newDialog)
1653 newDialog[(*wordcount)++] = GET_WORD(res++);
1654 newDialog[(*wordcount)++] = GET_WORD(res++);
1656 else
1658 res += 2;
1659 (*wordcount) += 2;
1663 if (newDialog)
1664 wcscpy((LPWSTR)&newDialog[(*wordcount)], (LPCWSTR)res);
1665 (*wordcount) += wcslen((LPCWSTR)res) + 1;
1666 res += wcslen((LPCWSTR)res) + 1;
1668 // First control is on DWORD boundary
1669 while ((*wordcount)%2)
1670 (*wordcount)++;
1671 while ((ULONG)res % 4)
1672 res++;
1674 while (nbItems--)
1676 res = ReplaceControlInfo(res, wordcount, newDialog, bEx);
1678 return res;
1681 const WORD* CResModule::ReplaceControlInfo(const WORD * res, size_t * wordcount, WORD * newDialog, BOOL bEx)
1683 if (bEx)
1685 if (newDialog)
1687 newDialog[(*wordcount)++] = GET_WORD(res++); //helpid
1688 newDialog[(*wordcount)++] = GET_WORD(res++); //helpid
1690 else
1692 res += 2;
1693 (*wordcount) += 2;
1696 if (newDialog)
1698 LONG * exStyle = (LONG*)&newDialog[(*wordcount)];
1699 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1700 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1701 if (m_bRTL)
1702 *exStyle |= WS_EX_RTLREADING;
1704 else
1706 res += 2;
1707 (*wordcount) += 2;
1710 if (newDialog)
1712 newDialog[(*wordcount)++] = GET_WORD(res++); //style
1713 newDialog[(*wordcount)++] = GET_WORD(res++); //style
1715 else
1717 res += 2;
1718 (*wordcount) += 2;
1721 if (newDialog)
1722 newDialog[(*wordcount)] = GET_WORD(res); //x
1723 res++;
1724 (*wordcount)++;
1726 if (newDialog)
1727 newDialog[(*wordcount)] = GET_WORD(res); //y
1728 res++;
1729 (*wordcount)++;
1731 if (newDialog)
1732 newDialog[(*wordcount)] = GET_WORD(res); //cx
1733 res++;
1734 (*wordcount)++;
1736 if (newDialog)
1737 newDialog[(*wordcount)] = GET_WORD(res); //cy
1738 res++;
1739 (*wordcount)++;
1741 if (bEx)
1743 // ID is a DWORD for DIALOGEX
1744 if (newDialog)
1746 newDialog[(*wordcount)++] = GET_WORD(res++);
1747 newDialog[(*wordcount)++] = GET_WORD(res++);
1749 else
1751 res += 2;
1752 (*wordcount) += 2;
1755 else
1757 if (newDialog)
1758 newDialog[(*wordcount)] = GET_WORD(res);
1759 res++;
1760 (*wordcount)++;
1763 if (GET_WORD(res) == 0xffff) //classID
1765 if (newDialog)
1767 newDialog[(*wordcount)++] = GET_WORD(res++);
1768 newDialog[(*wordcount)++] = GET_WORD(res++);
1770 else
1772 res += 2;
1773 (*wordcount) += 2;
1776 else
1778 if (newDialog)
1779 wcscpy((LPWSTR)&newDialog[(*wordcount)], (LPCWSTR)res);
1780 (*wordcount) += wcslen((LPCWSTR) res) + 1;
1781 res += wcslen((LPCWSTR) res) + 1;
1784 if (GET_WORD(res) == 0xffff) // an integer ID?
1786 if (newDialog)
1788 newDialog[(*wordcount)++] = GET_WORD(res++);
1789 newDialog[(*wordcount)++] = GET_WORD(res++);
1791 else
1793 res += 2;
1794 (*wordcount) += 2;
1797 else
1799 ReplaceStr((LPCWSTR)res, newDialog, wordcount, &m_bTranslatedDialogStrings, &m_bDefaultDialogStrings);
1800 res += wcslen((LPCWSTR)res) + 1;
1803 if (newDialog)
1804 memcpy(&newDialog[(*wordcount)], res, (GET_WORD(res)+1)*sizeof(WORD));
1805 (*wordcount) += (GET_WORD(res)+1);
1806 res += (GET_WORD(res)+1);
1807 // Next control is on DWORD boundary
1808 while ((*wordcount) % 2)
1809 (*wordcount)++;
1810 res += ((((WORD)res + 3) & ~3) - (WORD)res)/sizeof(WORD);
1812 return res;
1815 BOOL CResModule::ExtractRibbon(LPCTSTR lpszType)
1817 HRSRC hrsrc = FindResource(m_hResDll, lpszType, RT_RIBBON);
1818 HGLOBAL hglRibbonTemplate;
1819 const BYTE *p;
1821 if (!hrsrc)
1822 MYERROR;
1824 hglRibbonTemplate = LoadResource(m_hResDll, hrsrc);
1826 DWORD sizeres = SizeofResource(m_hResDll, hrsrc);
1828 if (!hglRibbonTemplate)
1829 MYERROR;
1831 p = (const BYTE*)LockResource(hglRibbonTemplate);
1833 if (p == NULL)
1834 MYERROR;
1836 // Resource consists of one single string
1837 // that is XML.
1839 // extract all <text>blah</text> elements
1841 const std::regex regRevMatch("<TEXT>([^<]+)</TEXT>");
1842 std::string ss = std::string((const char*)p, sizeres);
1843 const std::sregex_iterator end;
1844 for (std::sregex_iterator it(ss.begin(), ss.end(), regRevMatch); it != end; ++it)
1846 std::string str = (*it)[1];
1847 size_t len = str.size();
1848 std::unique_ptr<wchar_t[]> bufw(new wchar_t[len*4 + 1]);
1849 SecureZeroMemory(bufw.get(), (len*4 + 1)*sizeof(wchar_t));
1850 MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, bufw.get(), (int)len*4);
1851 std::wstring ret = bufw.get();
1852 RESOURCEENTRY entry = m_StringEntries[ret];
1853 entry.resourceIDs.insert((DWORD)lpszType);
1854 if (wcschr(ret.c_str(), '%'))
1855 entry.flag = _T("#, c-format");
1856 m_StringEntries[ret] = entry;
1857 m_bDefaultRibbonTexts++;
1860 // extract all </ELEMENT_NAME><NAME>blahblah</NAME> elements
1862 const std::regex regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
1863 for (std::sregex_iterator it(ss.begin(), ss.end(), regRevMatchName); it != end; ++it)
1865 std::string str = (*it)[1];
1866 size_t len = str.size();
1867 std::unique_ptr<wchar_t[]> bufw(new wchar_t[len*4 + 1]);
1868 SecureZeroMemory(bufw.get(), (len*4 + 1)*sizeof(wchar_t));
1869 MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, bufw.get(), (int)len*4);
1870 std::wstring ret = bufw.get();
1871 RESOURCEENTRY entry = m_StringEntries[ret];
1872 entry.resourceIDs.insert((DWORD)lpszType);
1873 if (wcschr(ret.c_str(), '%'))
1874 entry.flag = _T("#, c-format");
1875 m_StringEntries[ret] = entry;
1876 m_bDefaultRibbonTexts++;
1879 UnlockResource(hglRibbonTemplate);
1880 FreeResource(hglRibbonTemplate);
1881 return TRUE;
1884 BOOL CResModule::ReplaceRibbon(LPCTSTR lpszType, WORD wLanguage)
1886 HRSRC hrsrc = FindResource(m_hResDll, lpszType, RT_RIBBON);
1887 HGLOBAL hglRibbonTemplate;
1888 const BYTE *p;
1890 if (!hrsrc)
1891 MYERROR;
1893 hglRibbonTemplate = LoadResource(m_hResDll, hrsrc);
1895 DWORD sizeres = SizeofResource(m_hResDll, hrsrc);
1897 if (!hglRibbonTemplate)
1898 MYERROR;
1900 p = (const BYTE*)LockResource(hglRibbonTemplate);
1902 if (p == NULL)
1903 MYERROR;
1905 std::string ss = std::string((const char*)p, sizeres);
1906 size_t len = ss.size();
1907 std::unique_ptr<wchar_t[]> bufw(new wchar_t[len*4 + 1]);
1908 SecureZeroMemory(bufw.get(), (len*4 + 1)*sizeof(wchar_t));
1909 MultiByteToWideChar(CP_UTF8, 0, ss.c_str(), -1, bufw.get(), (int)len*4);
1910 std::wstring ssw = bufw.get();
1913 const std::regex regRevMatch("<TEXT>([^<]+)</TEXT>");
1914 const std::sregex_iterator end;
1915 for (std::sregex_iterator it(ss.begin(), ss.end(), regRevMatch); it != end; ++it)
1917 std::string str = (*it)[1];
1918 size_t len = str.size();
1919 std::unique_ptr<wchar_t[]> bufw(new wchar_t[len*4 + 1]);
1920 SecureZeroMemory(bufw.get(), (len*4 + 1)*sizeof(wchar_t));
1921 MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, bufw.get(), (int)len*4);
1922 std::wstring ret = bufw.get();
1924 RESOURCEENTRY entry = m_StringEntries[ret];
1925 ret = L"<TEXT>" + ret + L"</TEXT>";
1927 if (entry.msgstr.size())
1929 CUtils::SearchReplace(ssw, ret, L"<TEXT>" + entry.msgstr + L"</TEXT>");
1930 m_bTranslatedRibbonTexts++;
1932 else
1933 m_bDefaultRibbonTexts++;
1936 const std::regex regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
1937 for (std::sregex_iterator it(ss.begin(), ss.end(), regRevMatchName); it != end; ++it)
1939 std::string str = (*it)[1];
1940 size_t len = str.size();
1941 std::unique_ptr<wchar_t[]> bufw(new wchar_t[len*4 + 1]);
1942 SecureZeroMemory(bufw.get(), (len*4 + 1)*sizeof(wchar_t));
1943 MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, bufw.get(), (int)len*4);
1944 std::wstring ret = bufw.get();
1946 RESOURCEENTRY entry = m_StringEntries[ret];
1947 ret = L"</ELEMENT_NAME><NAME>" + ret + L"</NAME>";
1949 if (entry.msgstr.size())
1951 CUtils::SearchReplace(ssw, ret, L"</ELEMENT_NAME><NAME>" + entry.msgstr + L"</NAME>");
1952 m_bTranslatedRibbonTexts++;
1954 else
1955 m_bDefaultRibbonTexts++;
1958 std::unique_ptr<char[]> buf(new char[ssw.size()*4 + 1]);
1959 int lengthIncTerminator = WideCharToMultiByte(CP_UTF8, 0, ssw.c_str(), -1, buf.get(), (int)len*4, NULL, NULL);
1962 if (!UpdateResource(m_hUpdateRes, RT_RIBBON, lpszType, (m_wTargetLang ? m_wTargetLang : wLanguage), buf.get(), lengthIncTerminator-1))
1964 goto DONE_ERROR;
1967 if ((m_wTargetLang)&&(!UpdateResource(m_hUpdateRes, RT_RIBBON, lpszType, wLanguage, NULL, 0)))
1969 goto DONE_ERROR;
1973 UnlockResource(hglRibbonTemplate);
1974 FreeResource(hglRibbonTemplate);
1975 return TRUE;
1977 DONE_ERROR:
1978 UnlockResource(hglRibbonTemplate);
1979 FreeResource(hglRibbonTemplate);
1980 MYERROR;
1983 BOOL CALLBACK CResModule::EnumResNameCallback(HMODULE /*hModule*/, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
1985 CResModule* lpResModule = (CResModule*)lParam;
1987 if (lpszType == RT_STRING)
1989 if (IS_INTRESOURCE(lpszName))
1991 if (!lpResModule->ExtractString(lpszName))
1992 return FALSE;
1995 else if (lpszType == RT_MENU)
1997 if (IS_INTRESOURCE(lpszName))
1999 if (!lpResModule->ExtractMenu(lpszName))
2000 return FALSE;
2003 else if (lpszType == RT_DIALOG)
2005 if (IS_INTRESOURCE(lpszName))
2007 if (!lpResModule->ExtractDialog(lpszName))
2008 return FALSE;
2011 else if (lpszType == RT_ACCELERATOR)
2013 if (IS_INTRESOURCE(lpszName))
2015 if (!lpResModule->ExtractAccelerator(lpszName))
2016 return FALSE;
2019 else if (lpszType == RT_RIBBON)
2021 if (IS_INTRESOURCE(lpszName))
2023 if (!lpResModule->ExtractRibbon(lpszName))
2024 return FALSE;
2028 return TRUE;
2031 #pragma warning(push)
2032 #pragma warning(disable: 4189)
2033 BOOL CALLBACK CResModule::EnumResNameWriteCallback(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
2035 CResModule* lpResModule = (CResModule*)lParam;
2036 return EnumResourceLanguages(hModule, lpszType, lpszName, (ENUMRESLANGPROC)&lpResModule->EnumResWriteLangCallback, lParam);
2038 #pragma warning(pop)
2040 BOOL CALLBACK CResModule::EnumResWriteLangCallback(HMODULE /*hModule*/, LPCTSTR lpszType, LPTSTR lpszName, WORD wLanguage, LONG_PTR lParam)
2042 BOOL bRes = FALSE;
2043 CResModule* lpResModule = (CResModule*)lParam;
2045 if (lpszType == RT_STRING)
2047 bRes = lpResModule->ReplaceString(lpszName, wLanguage);
2049 else if (lpszType == RT_MENU)
2051 bRes = lpResModule->ReplaceMenu(lpszName, wLanguage);
2053 else if (lpszType == RT_DIALOG)
2055 bRes = lpResModule->ReplaceDialog(lpszName, wLanguage);
2057 else if (lpszType == RT_ACCELERATOR)
2059 bRes = lpResModule->ReplaceAccelerator(lpszName, wLanguage);
2061 else if (lpszType == RT_RIBBON)
2063 bRes = lpResModule->ReplaceRibbon(lpszName, wLanguage);
2066 return bRes;
2070 void CResModule::ReplaceStr(LPCWSTR src, WORD * dest, size_t * count, int * translated, int * def)
2072 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
2073 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
2074 wcscpy(pBuf, src);
2075 CUtils::StringExtend(pBuf);
2077 std::wstring wstr = std::wstring(pBuf);
2078 RESOURCEENTRY entry = m_StringEntries[wstr];
2079 if (!entry.msgstr.empty())
2081 wcscpy(pBuf, entry.msgstr.c_str());
2082 CUtils::StringCollapse(pBuf);
2083 if (dest)
2084 wcscpy((wchar_t *)&dest[(*count)], pBuf);
2085 (*count) += wcslen(pBuf)+1;
2086 (*translated)++;
2088 else
2090 if (dest)
2091 wcscpy((wchar_t *)&dest[(*count)], src);
2092 (*count) += wcslen(src) + 1;
2093 if (wcslen(src))
2094 (*def)++;
2096 delete [] pBuf;