Reduce C style casts
[TortoiseGit.git] / src / ResText / ResModule.cpp
blob149dc06403d6f7a15548d43206013fd450951c0f
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2015-2016 - TortoiseGit
4 // Copyright (C) 2003-2008, 2010-2016 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
20 #include "Utils.h"
21 #include "UnicodeUtils.h"
22 #include "ResModule.h"
23 #include <regex>
24 #include <memory>
25 #include <fstream>
26 #include <string>
27 #include <algorithm>
28 #include <functional>
29 #include <locale>
30 #include <codecvt>
31 #ifndef RT_RIBBON
32 #define RT_RIBBON MAKEINTRESOURCE(28)
33 #endif
36 #define MYERROR {CUtils::Error(); return FALSE;}
38 static const WORD * AlignWORD(const WORD * pWord)
40 const WORD * res = pWord;
41 res += ((((UINT_PTR)pWord + 3) & ~3) - (UINT_PTR)pWord) / sizeof(WORD);
42 return res;
45 std::wstring NumToStr(INT_PTR num)
47 wchar_t buf[100];
48 swprintf_s(buf, L"%Id", num);
49 return buf;
52 CResModule::CResModule(void)
53 : m_bTranslatedStrings(0)
54 , m_bDefaultStrings(0)
55 , m_bTranslatedDialogStrings(0)
56 , m_bDefaultDialogStrings(0)
57 , m_bTranslatedMenuStrings(0)
58 , m_bDefaultMenuStrings(0)
59 , m_bTranslatedAcceleratorStrings(0)
60 , m_bDefaultAcceleratorStrings(0)
61 , m_bTranslatedRibbonTexts(0)
62 , m_bDefaultRibbonTexts(0)
63 , m_wTargetLang(0)
64 , m_hResDll(nullptr)
65 , m_hUpdateRes(nullptr)
66 , m_bQuiet(false)
67 , m_bRTL(false)
68 , m_bAdjustEOLs(false)
72 CResModule::~CResModule(void)
76 BOOL CResModule::ExtractResources(std::vector<std::wstring> filelist, LPCTSTR lpszPOFilePath, BOOL bNoUpdate, LPCTSTR lpszHeaderFile)
78 for (auto I = filelist.cbegin(); I != filelist.cend(); ++I)
80 std::wstring filepath = *I;
81 m_currentHeaderDataDialogs.clear();
82 m_currentHeaderDataMenus.clear();
83 m_currentHeaderDataStrings.clear();
84 auto starpos = I->find('*');
85 if (starpos != std::wstring::npos)
86 filepath = I->substr(0, starpos);
87 while (starpos != std::wstring::npos)
89 auto starposnext = I->find('*', starpos + 1);
90 std::wstring headerfile = I->substr(starpos + 1, starposnext - starpos - 1);
91 ScanHeaderFile(headerfile);
92 starpos = starposnext;
94 m_hResDll = LoadLibraryEx(filepath.c_str(), nullptr, LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE);
95 if (!m_hResDll)
96 MYERROR;
98 size_t nEntries = m_StringEntries.size();
99 // fill in the std::map with all translatable entries
101 if (!m_bQuiet)
102 _ftprintf(stdout, L"Extracting StringTable....");
103 EnumResourceNames(m_hResDll, RT_STRING, EnumResNameCallback, (LONG_PTR)this);
104 if (!m_bQuiet)
105 _ftprintf(stdout, L"%4Iu Strings\n", m_StringEntries.size()-nEntries);
106 nEntries = m_StringEntries.size();
108 if (!m_bQuiet)
109 _ftprintf(stdout, L"Extracting Dialogs........");
110 EnumResourceNames(m_hResDll, RT_DIALOG, EnumResNameCallback, (LONG_PTR)this);
111 if (!m_bQuiet)
112 _ftprintf(stdout, L"%4Iu Strings\n", m_StringEntries.size()-nEntries);
113 nEntries = m_StringEntries.size();
115 if (!m_bQuiet)
116 _ftprintf(stdout, L"Extracting Menus..........");
117 EnumResourceNames(m_hResDll, RT_MENU, EnumResNameCallback, (LONG_PTR)this);
118 if (!m_bQuiet)
119 _ftprintf(stdout, L"%4Iu Strings\n", m_StringEntries.size()-nEntries);
120 nEntries = m_StringEntries.size();
121 if (!m_bQuiet)
122 _ftprintf(stdout, L"Extracting Accelerators...");
123 EnumResourceNames(m_hResDll, RT_ACCELERATOR, EnumResNameCallback, (LONG_PTR)this);
124 if (!m_bQuiet)
125 _ftprintf(stdout, L"%4Iu Accelerators\n", m_StringEntries.size()-nEntries);
126 nEntries = m_StringEntries.size();
127 if (!m_bQuiet)
128 _ftprintf(stdout, L"Extracting Ribbons........");
129 EnumResourceNames(m_hResDll, RT_RIBBON, EnumResNameCallback, (LONG_PTR)this);
130 if (!m_bQuiet)
131 _ftprintf(stdout, L"%4Iu Strings\n", m_StringEntries.size()-nEntries);
132 nEntries = m_StringEntries.size();
134 // parse a probably existing file and update the translations which are
135 // already done
136 m_StringEntries.ParseFile(lpszPOFilePath, !bNoUpdate, m_bAdjustEOLs);
138 FreeLibrary(m_hResDll);
141 // at last, save the new file
142 return m_StringEntries.SaveFile(lpszPOFilePath, lpszHeaderFile);
145 BOOL CResModule::ExtractResources(LPCTSTR lpszSrcLangDllPath, LPCTSTR lpszPoFilePath, BOOL bNoUpdate, LPCTSTR lpszHeaderFile)
147 m_hResDll = LoadLibraryEx(lpszSrcLangDllPath, nullptr, LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE);
148 if (!m_hResDll)
149 MYERROR;
151 size_t nEntries = 0;
152 // fill in the std::map with all translatable entries
154 if (!m_bQuiet)
155 _ftprintf(stdout, L"Extracting StringTable....");
156 EnumResourceNames(m_hResDll, RT_STRING, EnumResNameCallback, (LONG_PTR)this);
157 if (!m_bQuiet)
158 _ftprintf(stdout, L"%4Iu Strings\n", m_StringEntries.size());
159 nEntries = m_StringEntries.size();
161 if (!m_bQuiet)
162 _ftprintf(stdout, L"Extracting Dialogs........");
163 EnumResourceNames(m_hResDll, RT_DIALOG, EnumResNameCallback, (LONG_PTR)this);
164 if (!m_bQuiet)
165 _ftprintf(stdout, L"%4Iu Strings\n", m_StringEntries.size()-nEntries);
166 nEntries = m_StringEntries.size();
168 if (!m_bQuiet)
169 _ftprintf(stdout, L"Extracting Menus..........");
170 EnumResourceNames(m_hResDll, RT_MENU, EnumResNameCallback, (LONG_PTR)this);
171 if (!m_bQuiet)
172 _ftprintf(stdout, L"%4Iu Strings\n", m_StringEntries.size()-nEntries);
173 nEntries = m_StringEntries.size();
175 if (!m_bQuiet)
176 _ftprintf(stdout, L"Extracting Accelerators...");
177 EnumResourceNames(m_hResDll, RT_ACCELERATOR, EnumResNameCallback, (LONG_PTR)this);
178 if (!m_bQuiet)
179 _ftprintf(stdout, L"%4Iu Accelerators\n", m_StringEntries.size()-nEntries);
180 nEntries = m_StringEntries.size();
182 // parse a probably existing file and update the translations which are
183 // already done
184 m_StringEntries.ParseFile(lpszPoFilePath, !bNoUpdate, m_bAdjustEOLs);
186 // at last, save the new file
187 if (!m_StringEntries.SaveFile(lpszPoFilePath, lpszHeaderFile))
188 goto DONE_ERROR;
190 FreeLibrary(m_hResDll);
191 return TRUE;
193 DONE_ERROR:
194 if (m_hResDll)
195 FreeLibrary(m_hResDll);
196 return FALSE;
199 BOOL CResModule::CreateTranslatedResources(LPCTSTR lpszSrcLangDllPath, LPCTSTR lpszDestLangDllPath, LPCTSTR lpszPOFilePath)
201 if (!CopyFile(lpszSrcLangDllPath, lpszDestLangDllPath, FALSE))
202 MYERROR;
204 int count = 0;
207 m_hResDll = LoadLibraryEx(lpszSrcLangDllPath, nullptr, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_IGNORE_CODE_AUTHZ_LEVEL);
208 if (!m_hResDll)
209 Sleep(100);
210 count++;
211 } while (!m_hResDll && (count < 10));
213 if (!m_hResDll)
214 MYERROR;
216 sDestFile = std::wstring(lpszDestLangDllPath);
218 // get all translated strings
219 if (!m_StringEntries.ParseFile(lpszPOFilePath, FALSE, m_bAdjustEOLs))
220 goto DONE_ERROR;
221 m_bTranslatedStrings = 0;
222 m_bDefaultStrings = 0;
223 m_bTranslatedDialogStrings = 0;
224 m_bDefaultDialogStrings = 0;
225 m_bTranslatedMenuStrings = 0;
226 m_bDefaultMenuStrings = 0;
227 m_bTranslatedAcceleratorStrings = 0;
228 m_bDefaultAcceleratorStrings = 0;
230 BOOL bRes = FALSE;
231 count = 0;
234 m_hUpdateRes = BeginUpdateResource(sDestFile.c_str(), FALSE);
235 if (!m_hUpdateRes)
236 Sleep(100);
237 count++;
238 } while (!m_hUpdateRes && (count < 10));
240 if (!m_hUpdateRes)
241 MYERROR;
244 if (!m_bQuiet)
245 _ftprintf(stdout, L"Translating StringTable...");
246 bRes = EnumResourceNames(m_hResDll, RT_STRING, EnumResNameWriteCallback, (LONG_PTR)this);
247 if (!m_bQuiet)
248 _ftprintf(stdout, L"%4d translated, %4d not translated\n", m_bTranslatedStrings, m_bDefaultStrings);
250 if (!m_bQuiet)
251 _ftprintf(stdout, L"Translating Dialogs.......");
252 bRes = EnumResourceNames(m_hResDll, RT_DIALOG, EnumResNameWriteCallback, (LONG_PTR)this);
253 if (!m_bQuiet)
254 _ftprintf(stdout, L"%4d translated, %4d not translated\n", m_bTranslatedDialogStrings, m_bDefaultDialogStrings);
256 if (!m_bQuiet)
257 _ftprintf(stdout, L"Translating Menus.........");
258 bRes = EnumResourceNames(m_hResDll, RT_MENU, EnumResNameWriteCallback, (LONG_PTR)this);
259 if (!m_bQuiet)
260 _ftprintf(stdout, L"%4d translated, %4d not translated\n", m_bTranslatedMenuStrings, m_bDefaultMenuStrings);
262 if (!m_bQuiet)
263 _ftprintf(stdout, L"Translating Accelerators..");
264 bRes = EnumResourceNames(m_hResDll, RT_ACCELERATOR, EnumResNameWriteCallback, (LONG_PTR)this);
265 if (!m_bQuiet)
266 _ftprintf(stdout, L"%4d translated, %4d not translated\n", m_bTranslatedAcceleratorStrings, m_bDefaultAcceleratorStrings);
268 if (!m_bQuiet)
269 _ftprintf(stdout, L"Translating Ribbons.......");
270 bRes = EnumResourceNames(m_hResDll, RT_RIBBON, EnumResNameWriteCallback, (LONG_PTR)this);
271 if (!m_bQuiet)
272 _ftprintf(stdout, L"%4d translated, %4d not translated\n", m_bTranslatedRibbonTexts, m_bDefaultRibbonTexts);
273 bRes = TRUE;
274 if (!EndUpdateResource(m_hUpdateRes, !bRes))
275 MYERROR;
277 FreeLibrary(m_hResDll);
278 return TRUE;
279 DONE_ERROR:
280 if (m_hResDll)
281 FreeLibrary(m_hResDll);
282 return FALSE;
285 BOOL CResModule::ExtractString(LPCTSTR lpszType)
287 HRSRC hrsrc = FindResource(m_hResDll, lpszType, RT_STRING);
288 HGLOBAL hglStringTable;
289 LPWSTR p;
291 if (!hrsrc)
292 MYERROR;
293 hglStringTable = LoadResource(m_hResDll, hrsrc);
295 if (!hglStringTable)
296 goto DONE_ERROR;
297 p = (LPWSTR)LockResource(hglStringTable);
299 if (!p)
300 goto DONE_ERROR;
301 /* [Block of 16 strings. The strings are Pascal style with a WORD
302 length preceding the string. 16 strings are always written, even
303 if not all slots are full. Any slots in the block with no string
304 have a zero WORD for the length.]
307 //first check how much memory we need
308 LPWSTR pp = p;
309 for (int i=0; i<16; ++i)
311 int len = GET_WORD(pp);
312 pp++;
313 std::wstring msgid = std::wstring(pp, len);
314 WCHAR * pBuf = new WCHAR[MAX_STRING_LENGTH*2];
315 SecureZeroMemory(pBuf, MAX_STRING_LENGTH*2*sizeof(WCHAR));
316 wcscpy(pBuf, msgid.c_str());
317 CUtils::StringExtend(pBuf);
319 if (wcslen(pBuf))
321 std::wstring str = std::wstring(pBuf);
322 RESOURCEENTRY entry = m_StringEntries[str];
323 InsertResourceIDs(RT_STRING, 0, entry, ((INT_PTR)lpszType - 1) * 16 + i, L"");
324 if (wcschr(str.c_str(), '%'))
325 entry.flag = L"#, c-format";
326 m_StringEntries[str] = entry;
328 delete [] pBuf;
329 pp += len;
331 UnlockResource(hglStringTable);
332 FreeResource(hglStringTable);
333 return TRUE;
334 DONE_ERROR:
335 UnlockResource(hglStringTable);
336 FreeResource(hglStringTable);
337 MYERROR;
340 BOOL CResModule::ReplaceString(LPCTSTR lpszType, WORD wLanguage)
342 HRSRC hrsrc = FindResourceEx(m_hResDll, RT_STRING, lpszType, wLanguage);
343 HGLOBAL hglStringTable;
344 LPWSTR p;
346 if (!hrsrc)
347 MYERROR;
348 hglStringTable = LoadResource(m_hResDll, hrsrc);
350 if (!hglStringTable)
351 goto DONE_ERROR;
352 p = (LPWSTR)LockResource(hglStringTable);
354 if (!p)
355 goto DONE_ERROR;
356 /* [Block of 16 strings. The strings are Pascal style with a WORD
357 length preceding the string. 16 strings are always written, even
358 if not all slots are full. Any slots in the block with no string
359 have a zero WORD for the length.]
362 //first check how much memory we need
363 size_t nMem = 0;
364 LPWSTR pp = p;
365 for (int i=0; i<16; ++i)
367 nMem++;
368 size_t len = GET_WORD(pp);
369 pp++;
370 std::wstring msgid = std::wstring(pp, len);
371 WCHAR * pBuf = new WCHAR[MAX_STRING_LENGTH*2];
372 SecureZeroMemory(pBuf, MAX_STRING_LENGTH*2*sizeof(WCHAR));
373 wcscpy(pBuf, msgid.c_str());
374 CUtils::StringExtend(pBuf);
375 msgid = std::wstring(pBuf);
377 RESOURCEENTRY resEntry;
378 resEntry = m_StringEntries[msgid];
379 wcscpy(pBuf, resEntry.msgstr.c_str());
380 CUtils::StringCollapse(pBuf);
381 size_t newlen = wcslen(pBuf);
382 if (newlen)
383 nMem += newlen;
384 else
385 nMem += len;
386 pp += len;
387 delete [] pBuf;
390 WORD * newTable = new WORD[nMem + (nMem % 2)];
391 SecureZeroMemory(newTable, (nMem + (nMem % 2))*2);
393 size_t index = 0;
394 for (int i=0; i<16; ++i)
396 int len = GET_WORD(p);
397 p++;
398 std::wstring msgid = std::wstring(p, len);
399 WCHAR * pBuf = new WCHAR[MAX_STRING_LENGTH*2];
400 SecureZeroMemory(pBuf, MAX_STRING_LENGTH*2*sizeof(WCHAR));
401 wcscpy(pBuf, msgid.c_str());
402 CUtils::StringExtend(pBuf);
403 msgid = std::wstring(pBuf);
405 RESOURCEENTRY resEntry;
406 resEntry = m_StringEntries[msgid];
407 wcscpy(pBuf, resEntry.msgstr.c_str());
408 CUtils::StringCollapse(pBuf);
409 size_t newlen = wcslen(pBuf);
410 if (newlen)
412 newTable[index++] = (WORD)newlen;
413 wcsncpy((wchar_t *)&newTable[index], pBuf, newlen);
414 index += newlen;
415 m_bTranslatedStrings++;
417 else
419 newTable[index++] = (WORD)len;
420 if (len)
421 wcsncpy((wchar_t *)&newTable[index], p, len);
422 index += len;
423 if (len)
424 m_bDefaultStrings++;
426 p += len;
427 delete [] pBuf;
430 if (!UpdateResource(m_hUpdateRes, RT_STRING, lpszType, (m_wTargetLang ? m_wTargetLang : wLanguage), newTable, (DWORD)(nMem + (nMem % 2))*2))
432 delete [] newTable;
433 goto DONE_ERROR;
436 if (m_wTargetLang && (!UpdateResource(m_hUpdateRes, RT_STRING, lpszType, wLanguage, nullptr, 0)))
438 delete [] newTable;
439 goto DONE_ERROR;
441 delete [] newTable;
442 UnlockResource(hglStringTable);
443 FreeResource(hglStringTable);
444 return TRUE;
445 DONE_ERROR:
446 UnlockResource(hglStringTable);
447 FreeResource(hglStringTable);
448 MYERROR;
451 BOOL CResModule::ExtractMenu(LPCTSTR lpszType)
453 HRSRC hrsrc = FindResource(m_hResDll, lpszType, RT_MENU);
454 HGLOBAL hglMenuTemplate;
455 WORD version, offset;
456 const WORD *p, *p0;
458 if (!hrsrc)
459 MYERROR;
461 hglMenuTemplate = LoadResource(m_hResDll, hrsrc);
463 if (!hglMenuTemplate)
464 MYERROR;
466 p = (const WORD*)LockResource(hglMenuTemplate);
468 if (!p)
469 MYERROR;
471 // Standard MENU resource
472 //struct MenuHeader {
473 // WORD wVersion; // Currently zero
474 // WORD cbHeaderSize; // Also zero
475 //};
477 // MENUEX resource
478 //struct MenuExHeader {
479 // WORD wVersion; // One
480 // WORD wOffset;
481 // DWORD dwHelpId;
482 //};
483 p0 = p;
484 version = GET_WORD(p);
486 p++;
488 switch (version)
490 case 0:
492 offset = GET_WORD(p);
493 p += offset;
494 p++;
495 if (!ParseMenuResource(p))
496 goto DONE_ERROR;
498 break;
499 case 1:
501 offset = GET_WORD(p);
502 p++;
503 //dwHelpId = GET_DWORD(p);
504 if (!ParseMenuExResource(p0 + offset))
505 goto DONE_ERROR;
507 break;
508 default:
509 goto DONE_ERROR;
512 UnlockResource(hglMenuTemplate);
513 FreeResource(hglMenuTemplate);
514 return TRUE;
516 DONE_ERROR:
517 UnlockResource(hglMenuTemplate);
518 FreeResource(hglMenuTemplate);
519 MYERROR;
522 BOOL CResModule::ReplaceMenu(LPCTSTR lpszType, WORD wLanguage)
524 HRSRC hrsrc = FindResourceEx(m_hResDll, RT_MENU, lpszType, wLanguage);
525 HGLOBAL hglMenuTemplate;
526 WORD version, offset;
527 LPWSTR p;
528 WORD *p0;
530 if (!hrsrc)
531 MYERROR; //just the language wasn't found
533 hglMenuTemplate = LoadResource(m_hResDll, hrsrc);
535 if (!hglMenuTemplate)
536 MYERROR;
538 p = (LPWSTR)LockResource(hglMenuTemplate);
540 if (!p)
541 MYERROR;
543 //struct MenuHeader {
544 // WORD wVersion; // Currently zero
545 // WORD cbHeaderSize; // Also zero
546 //};
548 // MENUEX resource
549 //struct MenuExHeader {
550 // WORD wVersion; // One
551 // WORD wOffset;
552 // DWORD dwHelpId;
553 //};
554 p0 = (WORD *)p;
555 version = GET_WORD(p);
557 p++;
559 switch (version)
561 case 0:
563 offset = GET_WORD(p);
564 p += offset;
565 p++;
566 size_t nMem = 0;
567 if (!CountMemReplaceMenuResource((WORD*)p, &nMem, nullptr))
568 goto DONE_ERROR;
569 WORD * newMenu = new WORD[nMem + (nMem % 2)+2];
570 SecureZeroMemory(newMenu, (nMem + (nMem % 2)+2)*2);
571 size_t index = 2; // MenuHeader has 2 WORDs zero
572 if (!CountMemReplaceMenuResource((WORD *)p, &index, newMenu))
574 delete [] newMenu;
575 goto DONE_ERROR;
578 if (!UpdateResource(m_hUpdateRes, RT_MENU, lpszType, (m_wTargetLang ? m_wTargetLang : wLanguage), newMenu, (DWORD)(nMem + (nMem % 2)+2)*2))
580 delete [] newMenu;
581 goto DONE_ERROR;
584 if (m_wTargetLang && (!UpdateResource(m_hUpdateRes, RT_MENU, lpszType, wLanguage, nullptr, 0)))
586 delete [] newMenu;
587 goto DONE_ERROR;
589 delete [] newMenu;
591 break;
592 case 1:
594 offset = GET_WORD(p);
595 p++;
596 //dwHelpId = GET_DWORD(p);
597 size_t nMem = 0;
598 if (!CountMemReplaceMenuExResource((WORD*)(p0 + offset), &nMem, nullptr))
599 goto DONE_ERROR;
600 WORD * newMenu = new WORD[nMem + (nMem % 2) + 4];
601 SecureZeroMemory(newMenu, (nMem + (nMem % 2) + 4) * 2);
602 CopyMemory(newMenu, p0, 2 * sizeof(WORD) + sizeof(DWORD));
603 size_t index = 4; // MenuExHeader has 2 x WORD + 1 x DWORD
604 if (!CountMemReplaceMenuExResource((WORD *)(p0 + offset), &index, newMenu))
606 delete [] newMenu;
607 goto DONE_ERROR;
610 if (!UpdateResource(m_hUpdateRes, RT_MENU, lpszType, (m_wTargetLang ? m_wTargetLang : wLanguage), newMenu, (DWORD)(nMem + (nMem % 2) + 4) * 2))
612 delete [] newMenu;
613 goto DONE_ERROR;
616 if (m_wTargetLang && (!UpdateResource(m_hUpdateRes, RT_MENU, lpszType, wLanguage, nullptr, 0)))
618 delete [] newMenu;
619 goto DONE_ERROR;
621 delete [] newMenu;
623 break;
624 default:
625 goto DONE_ERROR;
628 UnlockResource(hglMenuTemplate);
629 FreeResource(hglMenuTemplate);
630 return TRUE;
632 DONE_ERROR:
633 UnlockResource(hglMenuTemplate);
634 FreeResource(hglMenuTemplate);
635 MYERROR;
638 const WORD* CResModule::ParseMenuResource(const WORD * res)
640 WORD flags;
641 WORD id = 0;
643 //struct PopupMenuItem {
644 // WORD fItemFlags;
645 // WCHAR szItemText[];
646 //};
647 //struct NormalMenuItem {
648 // WORD fItemFlags;
649 // WORD wMenuID;
650 // WCHAR szItemText[];
651 //};
655 flags = GET_WORD(res);
656 res++;
657 if (!(flags & MF_POPUP))
659 id = GET_WORD(res); //normal menu item
660 res++;
662 else
663 id = (WORD)-1; //popup menu item
665 LPCWSTR str = (LPCWSTR)res;
666 size_t l = wcslen(str)+1;
667 res += l;
669 if (flags & MF_POPUP)
671 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
672 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
673 wcscpy(pBuf, str);
674 CUtils::StringExtend(pBuf);
676 std::wstring wstr = std::wstring(pBuf);
677 RESOURCEENTRY entry = m_StringEntries[wstr];
678 if (id)
679 InsertResourceIDs(RT_MENU, 0, entry, id, L" - PopupMenu");
681 m_StringEntries[wstr] = entry;
682 delete [] pBuf;
684 if ((res = ParseMenuResource(res))==0)
685 return nullptr;
687 else if (id != 0)
689 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
690 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
691 wcscpy(pBuf, str);
692 CUtils::StringExtend(pBuf);
694 std::wstring wstr = std::wstring(pBuf);
695 RESOURCEENTRY entry = m_StringEntries[wstr];
696 InsertResourceIDs(RT_MENU, 0, entry, id, L" - Menu");
698 TCHAR szTempBuf[1024] = { 0 };
699 swprintf(szTempBuf, L"#: MenuEntry; ID:%u", id);
700 MENUENTRY menu_entry;
701 menu_entry.wID = id;
702 menu_entry.reference = szTempBuf;
703 menu_entry.msgstr = wstr;
705 m_StringEntries[wstr] = entry;
706 m_MenuEntries[id] = menu_entry;
707 delete [] pBuf;
709 } while (!(flags & MF_END));
710 return res;
713 const WORD* CResModule::CountMemReplaceMenuResource(const WORD * res, size_t * wordcount, WORD * newMenu)
715 WORD flags;
716 WORD id = 0;
718 //struct PopupMenuItem {
719 // WORD fItemFlags;
720 // WCHAR szItemText[];
721 //};
722 //struct NormalMenuItem {
723 // WORD fItemFlags;
724 // WORD wMenuID;
725 // WCHAR szItemText[];
726 //};
730 flags = GET_WORD(res);
731 res++;
732 if (!newMenu)
733 (*wordcount)++;
734 else
735 newMenu[(*wordcount)++] = flags;
736 if (!(flags & MF_POPUP))
738 id = GET_WORD(res); //normal menu item
739 res++;
740 if (!newMenu)
741 (*wordcount)++;
742 else
743 newMenu[(*wordcount)++] = id;
745 else
746 id = (WORD)-1; //popup menu item
748 if (flags & MF_POPUP)
750 ReplaceStr((LPCWSTR)res, newMenu, wordcount, &m_bTranslatedMenuStrings, &m_bDefaultMenuStrings);
751 res += wcslen((LPCWSTR)res) + 1;
753 if ((res = CountMemReplaceMenuResource(res, wordcount, newMenu))==0)
754 return nullptr;
756 else if (id != 0)
758 ReplaceStr((LPCWSTR)res, newMenu, wordcount, &m_bTranslatedMenuStrings, &m_bDefaultMenuStrings);
759 res += wcslen((LPCWSTR)res) + 1;
761 else
763 if (newMenu)
764 wcscpy((wchar_t *)&newMenu[(*wordcount)], (LPCWSTR)res);
765 (*wordcount) += wcslen((LPCWSTR)res) + 1;
766 res += wcslen((LPCWSTR)res) + 1;
768 } while (!(flags & MF_END));
769 return res;
772 const WORD* CResModule::ParseMenuExResource(const WORD * res)
774 WORD bResInfo;
776 //struct MenuExItem {
777 // DWORD dwType;
778 // DWORD dwState;
779 // DWORD menuId;
780 // WORD bResInfo;
781 // WCHAR szText[];
782 // DWORD dwHelpId; - Popup menu only
783 //};
787 DWORD dwType = GET_DWORD(res);
788 res += 2;
789 //dwState = GET_DWORD(res);
790 res += 2;
791 DWORD menuId = GET_DWORD(res);
792 res += 2;
793 bResInfo = GET_WORD(res);
794 res++;
796 LPCWSTR str = (LPCWSTR)res;
797 size_t l = wcslen(str)+1;
798 res += l;
799 // Align to DWORD boundary
800 res = AlignWORD(res);
802 if (dwType & MFT_SEPARATOR)
803 continue;
805 if (bResInfo & 0x01)
807 // Popup menu - note this can also have a non-zero ID
808 if (menuId == 0)
809 menuId = (WORD)-1;
810 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
811 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
812 wcscpy(pBuf, str);
813 CUtils::StringExtend(pBuf);
815 std::wstring wstr = std::wstring(pBuf);
816 RESOURCEENTRY entry = m_StringEntries[wstr];
817 // Popup has a DWORD help entry on a DWORD boundary - skip over it
818 res += 2;
820 InsertResourceIDs(RT_MENU, 0, entry, menuId, L" - PopupMenuEx");
821 TCHAR szTempBuf[1024] = { 0 };
822 swprintf(szTempBuf, L"#: MenuExPopupEntry; ID:%lu", menuId);
823 MENUENTRY menu_entry;
824 menu_entry.wID = (WORD)menuId;
825 menu_entry.reference = szTempBuf;
826 menu_entry.msgstr = wstr;
827 m_StringEntries[wstr] = entry;
828 m_MenuEntries[(WORD)menuId] = menu_entry;
829 delete [] pBuf;
831 if ((res = ParseMenuExResource(res)) == 0)
832 return nullptr;
833 } else if (menuId != 0)
835 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
836 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
837 wcscpy(pBuf, str);
838 CUtils::StringExtend(pBuf);
840 std::wstring wstr = std::wstring(pBuf);
841 RESOURCEENTRY entry = m_StringEntries[wstr];
842 InsertResourceIDs(RT_MENU, 0, entry, menuId, L" - MenuEx");
844 TCHAR szTempBuf[1024] = { 0 };
845 swprintf(szTempBuf, L"#: MenuExEntry; ID:%lu", menuId);
846 MENUENTRY menu_entry;
847 menu_entry.wID = (WORD)menuId;
848 menu_entry.reference = szTempBuf;
849 menu_entry.msgstr = wstr;
850 m_StringEntries[wstr] = entry;
851 m_MenuEntries[(WORD)menuId] = menu_entry;
852 delete [] pBuf;
854 } while (!(bResInfo & 0x80));
855 return res;
858 const WORD* CResModule::CountMemReplaceMenuExResource(const WORD * res, size_t * wordcount, WORD * newMenu)
860 WORD bResInfo;
862 //struct MenuExItem {
863 // DWORD dwType;
864 // DWORD dwState;
865 // DWORD menuId;
866 // WORD bResInfo;
867 // WCHAR szText[];
868 // DWORD dwHelpId; - Popup menu only
869 //};
873 WORD * p0 = (WORD *)res;
874 DWORD dwType = GET_DWORD(res);
875 res += 2;
876 //dwState = GET_DWORD(res);
877 res += 2;
878 DWORD menuId = GET_DWORD(res);
879 res += 2;
880 bResInfo = GET_WORD(res);
881 res++;
883 if (newMenu)
884 CopyMemory(&newMenu[*wordcount], p0, 7 * sizeof(WORD));
886 (*wordcount) += 7;
888 if (dwType & MFT_SEPARATOR) {
889 // Align to DWORD
890 (*wordcount)++;
891 res++;
892 continue;
895 if (bResInfo & 0x01)
897 ReplaceStr((LPCWSTR)res, newMenu, wordcount, &m_bTranslatedMenuStrings, &m_bDefaultMenuStrings);
898 res += wcslen((LPCWSTR)res) + 1;
899 // Align to DWORD
900 res = AlignWORD(res);
901 if ((*wordcount) & 0x01)
902 (*wordcount)++;
904 if (newMenu)
905 CopyMemory(&newMenu[*wordcount], res, sizeof(DWORD)); // Copy Help ID
907 res += 2;
908 (*wordcount) += 2;
910 if ((res = CountMemReplaceMenuExResource(res, wordcount, newMenu)) == 0)
911 return nullptr;
913 else if (menuId != 0)
915 ReplaceStr((LPCWSTR)res, newMenu, wordcount, &m_bTranslatedMenuStrings, &m_bDefaultMenuStrings);
916 res += wcslen((LPCWSTR)res) + 1;
918 else
920 if (newMenu)
921 wcscpy((wchar_t *)&newMenu[(*wordcount)], (LPCWSTR)res);
922 (*wordcount) += wcslen((LPCWSTR)res) + 1;
923 res += wcslen((LPCWSTR)res) + 1;
925 // Align to DWORD
926 res = AlignWORD(res);
927 if ((*wordcount) & 0x01)
928 (*wordcount)++;
929 } while (!(bResInfo & 0x80));
930 return res;
933 BOOL CResModule::ExtractAccelerator(LPCTSTR lpszType)
935 HRSRC hrsrc = FindResource(m_hResDll, lpszType, RT_ACCELERATOR);
936 HGLOBAL hglAccTable;
937 WORD fFlags, wAnsi, wID;
938 const WORD* p;
939 bool bEnd(false);
941 if (!hrsrc)
942 MYERROR;
944 hglAccTable = LoadResource(m_hResDll, hrsrc);
946 if (!hglAccTable)
947 goto DONE_ERROR;
949 p = (const WORD*)LockResource(hglAccTable);
951 if (!p)
952 MYERROR;
955 struct ACCELTABLEENTRY
957 WORD fFlags; FVIRTKEY, FSHIFT, FCONTROL, FALT, 0x80 - Last in a table
958 WORD wAnsi; ANSI character
959 WORD wId; Keyboard accelerator passed to windows
960 WORD padding; # bytes added to ensure aligned to DWORD boundary
966 fFlags = GET_WORD(p);
967 p++;
968 wAnsi = GET_WORD(p);
969 p++;
970 wID = GET_WORD(p);
971 p++;
972 p++; // Skip over padding
974 if ((fFlags & 0x80) == 0x80)
975 { // 0x80
976 bEnd = true;
979 if ((wAnsi < 0x30) ||
980 (wAnsi > 0x5A) ||
981 (wAnsi >= 0x3A && wAnsi <= 0x40))
982 continue;
984 auto pBuf = std::make_unique<WCHAR[]>(1024);
985 auto pBuf2 = std::make_unique<WCHAR[]>(1024);
986 SecureZeroMemory(pBuf.get(), 1024 * sizeof(WCHAR));
987 SecureZeroMemory(pBuf2.get(), 1024 * sizeof(WCHAR));
989 // include the menu ID in the msgid to make sure that 'duplicate'
990 // accelerator keys are listed in the po-file.
991 // without this, we would get entries like this:
992 //#. Accelerator Entry for Menu ID:32809; '&Filter'
993 //#. Accelerator Entry for Menu ID:57636; '&Find'
994 //#: Corresponding Menu ID:32771; '&Find'
995 //msgid "V C +F"
996 //msgstr ""
998 // Since "filter" and "find" are most likely translated to words starting
999 // with different letters, we need to have a separate accelerator entry
1000 // for each of those
1001 swprintf(pBuf.get(), L"ID:%u:", wID);
1003 // EXACTLY 5 characters long "ACS+X"
1004 // V = Virtual key (or blank if not used)
1005 // A = Alt key (or blank if not used)
1006 // C = Ctrl key (or blank if not used)
1007 // S = Shift key (or blank if not used)
1008 // X = upper case character
1009 // e.g. "V CS+Q" == Ctrl + Shift + 'Q'
1010 if ((fFlags & FVIRTKEY) == FVIRTKEY) // 0x01
1011 wcscat(pBuf.get(), L"V");
1012 else
1013 wcscat(pBuf.get(), L" ");
1015 if ((fFlags & FALT) == FALT) // 0x10
1016 wcscat(pBuf.get(), L"A");
1017 else
1018 wcscat(pBuf.get(), L" ");
1020 if ((fFlags & FCONTROL) == FCONTROL) // 0x08
1021 wcscat(pBuf.get(), L"C");
1022 else
1023 wcscat(pBuf.get(), L" ");
1025 if ((fFlags & FSHIFT) == FSHIFT) // 0x04
1026 wcscat(pBuf.get(), L"S");
1027 else
1028 wcscat(pBuf.get(), L" ");
1030 swprintf(pBuf2.get(), L"%s+%c", pBuf.get(), wAnsi);
1032 std::wstring wstr = std::wstring(pBuf2.get());
1033 RESOURCEENTRY AKey_entry = m_StringEntries[wstr];
1035 TCHAR szTempBuf[1024] = { 0 };
1036 SecureZeroMemory(szTempBuf, sizeof (szTempBuf));
1037 std::wstring wmenu = L"";
1038 pME_iter = m_MenuEntries.find(wID);
1039 if (pME_iter != m_MenuEntries.end())
1041 wmenu = pME_iter->second.msgstr;
1043 swprintf(szTempBuf, L"#. Accelerator Entry for Menu ID:%u; '%s'", wID, wmenu.c_str());
1044 AKey_entry.automaticcomments.push_back(std::wstring(szTempBuf));
1046 m_StringEntries[wstr] = AKey_entry;
1047 } while (!bEnd);
1049 UnlockResource(hglAccTable);
1050 FreeResource(hglAccTable);
1051 return TRUE;
1053 DONE_ERROR:
1054 UnlockResource(hglAccTable);
1055 FreeResource(hglAccTable);
1056 MYERROR;
1059 BOOL CResModule::ReplaceAccelerator(LPCTSTR lpszType, WORD wLanguage)
1061 LPACCEL lpaccelNew; // pointer to new accelerator table
1062 HACCEL haccelOld; // handle to old accelerator table
1063 int cAccelerators; // number of accelerators in table
1064 HGLOBAL hglAccTableNew;
1065 const WORD* p;
1066 int i;
1068 haccelOld = LoadAccelerators(m_hResDll, lpszType);
1070 if (!haccelOld)
1071 MYERROR;
1073 cAccelerators = CopyAcceleratorTable(haccelOld, nullptr, 0);
1075 lpaccelNew = (LPACCEL) LocalAlloc(LPTR, cAccelerators * sizeof(ACCEL));
1077 if (!lpaccelNew)
1078 MYERROR;
1080 CopyAcceleratorTable(haccelOld, lpaccelNew, cAccelerators);
1082 // Find the accelerator that the user modified
1083 // and change its flags and virtual-key code
1084 // as appropriate.
1086 BYTE xfVirt;
1087 wchar_t xkey;
1088 static const size_t BufferSize = 1024;
1089 auto pBuf = std::make_unique<WCHAR[]>(BufferSize);
1090 auto pBuf2 = std::make_unique<WCHAR[]>(BufferSize);
1091 for (i = 0; i < cAccelerators; i++)
1093 if ((lpaccelNew[i].key < 0x30) ||
1094 (lpaccelNew[i].key > 0x5A) ||
1095 (lpaccelNew[i].key >= 0x3A && lpaccelNew[i].key <= 0x40))
1096 continue;
1098 SecureZeroMemory(pBuf.get(), 1024 * sizeof(WCHAR));
1099 SecureZeroMemory(pBuf2.get(), 1024 * sizeof(WCHAR));
1101 swprintf(pBuf.get(), L"ID:%d:", lpaccelNew[i].cmd);
1103 // get original key combination
1104 if ((lpaccelNew[i].fVirt & FVIRTKEY) == FVIRTKEY) // 0x01
1105 wcscat(pBuf.get(), L"V");
1106 else
1107 wcscat(pBuf.get(), L" ");
1109 if ((lpaccelNew[i].fVirt & FALT) == FALT) // 0x10
1110 wcscat(pBuf.get(), L"A");
1111 else
1112 wcscat(pBuf.get(), L" ");
1114 if ((lpaccelNew[i].fVirt & FCONTROL) == FCONTROL) // 0x08
1115 wcscat(pBuf.get(), L"C");
1116 else
1117 wcscat(pBuf.get(), L" ");
1119 if ((lpaccelNew[i].fVirt & FSHIFT) == FSHIFT) // 0x04
1120 wcscat(pBuf.get(), L"S");
1121 else
1122 wcscat(pBuf.get(), L" ");
1124 swprintf(pBuf2.get(), L"%s+%c", pBuf.get(), lpaccelNew[i].key);
1126 // Is it there?
1127 std::map<std::wstring, RESOURCEENTRY>::iterator pAK_iter = m_StringEntries.find(pBuf2.get());
1128 if (pAK_iter != m_StringEntries.end())
1130 m_bTranslatedAcceleratorStrings++;
1131 xfVirt = 0;
1132 xkey = 0;
1133 std::wstring wtemp = pAK_iter->second.msgstr;
1134 wtemp = wtemp.substr(wtemp.find_last_of(':')+1);
1135 if (wtemp.size() != 6)
1136 continue;
1137 if (wtemp.compare(0, 1, L"V") == 0)
1138 xfVirt |= FVIRTKEY;
1139 else if (wtemp.compare(0, 1, L" ") != 0)
1140 continue; // not a space - user must have made a mistake when translating
1141 if (wtemp.compare(1, 1, L"A") == 0)
1142 xfVirt |= FALT;
1143 else if (wtemp.compare(1, 1, L" ") != 0)
1144 continue; // not a space - user must have made a mistake when translating
1145 if (wtemp.compare(2, 1, L"C") == 0)
1146 xfVirt |= FCONTROL;
1147 else if (wtemp.compare(2, 1, L" ") != 0)
1148 continue; // not a space - user must have made a mistake when translating
1149 if (wtemp.compare(3, 1, L"S") == 0)
1150 xfVirt |= FSHIFT;
1151 else if (wtemp.compare(3, 1, L" ") != 0)
1152 continue; // not a space - user must have made a mistake when translating
1153 if (wtemp.compare(4, 1, L"+") == 0)
1155 _stscanf(wtemp.substr(5, 1).c_str(), L"%c", &xkey);
1156 lpaccelNew[i].fVirt = xfVirt;
1157 lpaccelNew[i].key = (DWORD)xkey;
1160 else
1161 m_bDefaultAcceleratorStrings++;
1165 // Create the new accelerator table
1166 hglAccTableNew = LocalAlloc(LPTR, cAccelerators * 4 * sizeof(WORD));
1167 if (!hglAccTableNew)
1168 goto DONE_ERROR;
1169 p = (WORD *)hglAccTableNew;
1170 lpaccelNew[cAccelerators-1].fVirt |= 0x80;
1171 for (i = 0; i < cAccelerators; i++)
1173 memcpy((void *)p, &lpaccelNew[i].fVirt, 1);
1174 p++;
1175 memcpy((void *)p, &lpaccelNew[i].key, sizeof(WORD));
1176 p++;
1177 memcpy((void *)p, &lpaccelNew[i].cmd, sizeof(WORD));
1178 p++;
1179 p++;
1182 if (!UpdateResource(m_hUpdateRes, RT_ACCELERATOR, lpszType,
1183 (m_wTargetLang ? m_wTargetLang : wLanguage), hglAccTableNew /* haccelNew*/, cAccelerators * 4 * sizeof(WORD)))
1185 goto DONE_ERROR;
1188 if (m_wTargetLang && (!UpdateResource(m_hUpdateRes, RT_ACCELERATOR, lpszType, wLanguage, nullptr, 0)))
1190 goto DONE_ERROR;
1193 LocalFree(hglAccTableNew);
1194 LocalFree(lpaccelNew);
1195 return TRUE;
1197 DONE_ERROR:
1198 LocalFree(hglAccTableNew);
1199 LocalFree(lpaccelNew);
1200 MYERROR;
1203 BOOL CResModule::ExtractDialog(LPCTSTR lpszType)
1205 const WORD* lpDlg;
1206 const WORD* lpDlgItem;
1207 DIALOGINFO dlg;
1208 DLGITEMINFO dlgItem;
1209 WORD bNumControls;
1210 HRSRC hrsrc;
1211 HGLOBAL hGlblDlgTemplate;
1213 hrsrc = FindResource(m_hResDll, lpszType, RT_DIALOG);
1215 if (!hrsrc)
1216 MYERROR;
1218 hGlblDlgTemplate = LoadResource(m_hResDll, hrsrc);
1219 if (!hGlblDlgTemplate)
1220 MYERROR;
1222 lpDlg = (const WORD*) LockResource(hGlblDlgTemplate);
1224 if (!lpDlg)
1225 MYERROR;
1227 lpDlgItem = (const WORD*) GetDialogInfo(lpDlg, &dlg);
1228 bNumControls = dlg.nbItems;
1230 if (dlg.caption)
1232 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
1233 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
1234 wcscpy(pBuf, dlg.caption);
1235 CUtils::StringExtend(pBuf);
1237 std::wstring wstr = std::wstring(pBuf);
1238 RESOURCEENTRY entry = m_StringEntries[wstr];
1239 InsertResourceIDs(RT_DIALOG, (INT_PTR)lpszType, entry, (INT_PTR)lpszType, L"");
1241 m_StringEntries[wstr] = entry;
1242 delete [] pBuf;
1245 while (bNumControls-- != 0)
1247 TCHAR szTitle[500] = { 0 };
1248 SecureZeroMemory(szTitle, sizeof(szTitle));
1249 BOOL bCode;
1251 lpDlgItem = GetControlInfo((WORD *) lpDlgItem, &dlgItem, dlg.dialogEx, &bCode);
1253 if (bCode == FALSE)
1254 wcsncpy(szTitle, dlgItem.windowName, _countof(szTitle) - 1);
1256 if (wcslen(szTitle) > 0)
1258 CUtils::StringExtend(szTitle);
1260 std::wstring wstr = std::wstring(szTitle);
1261 RESOURCEENTRY entry = m_StringEntries[wstr];
1262 InsertResourceIDs(RT_DIALOG, (INT_PTR)lpszType, entry, dlgItem.id, L"");
1264 m_StringEntries[wstr] = entry;
1268 UnlockResource(hGlblDlgTemplate);
1269 FreeResource(hGlblDlgTemplate);
1270 return (TRUE);
1273 BOOL CResModule::ReplaceDialog(LPCTSTR lpszType, WORD wLanguage)
1275 const WORD* lpDlg;
1276 HRSRC hrsrc;
1277 HGLOBAL hGlblDlgTemplate;
1279 hrsrc = FindResourceEx(m_hResDll, RT_DIALOG, lpszType, wLanguage);
1281 if (!hrsrc)
1282 MYERROR;
1284 hGlblDlgTemplate = LoadResource(m_hResDll, hrsrc);
1286 if (!hGlblDlgTemplate)
1287 MYERROR;
1289 lpDlg = (WORD *) LockResource(hGlblDlgTemplate);
1291 if (!lpDlg)
1292 MYERROR;
1294 size_t nMem = 0;
1295 const WORD * p = lpDlg;
1296 if (!CountMemReplaceDialogResource(p, &nMem, nullptr))
1297 goto DONE_ERROR;
1298 WORD * newDialog = new WORD[nMem + (nMem % 2)];
1299 SecureZeroMemory(newDialog, (nMem + (nMem % 2))*2);
1301 size_t index = 0;
1302 if (!CountMemReplaceDialogResource(lpDlg, &index, newDialog))
1304 delete [] newDialog;
1305 goto DONE_ERROR;
1308 if (!UpdateResource(m_hUpdateRes, RT_DIALOG, lpszType, (m_wTargetLang ? m_wTargetLang : wLanguage), newDialog, (DWORD)(nMem + (nMem % 2))*2))
1310 delete [] newDialog;
1311 goto DONE_ERROR;
1314 if (m_wTargetLang && (!UpdateResource(m_hUpdateRes, RT_DIALOG, lpszType, wLanguage, nullptr, 0)))
1316 delete [] newDialog;
1317 goto DONE_ERROR;
1320 delete [] newDialog;
1321 UnlockResource(hGlblDlgTemplate);
1322 FreeResource(hGlblDlgTemplate);
1323 return TRUE;
1325 DONE_ERROR:
1326 UnlockResource(hGlblDlgTemplate);
1327 FreeResource(hGlblDlgTemplate);
1328 MYERROR;
1331 const WORD* CResModule::GetDialogInfo(const WORD * pTemplate, LPDIALOGINFO lpDlgInfo) const
1333 const WORD* p = (const WORD *)pTemplate;
1335 lpDlgInfo->style = GET_DWORD(p);
1336 p += 2;
1338 if (lpDlgInfo->style == 0xffff0001) // DIALOGEX resource
1340 lpDlgInfo->dialogEx = TRUE;
1341 lpDlgInfo->helpId = GET_DWORD(p);
1342 p += 2;
1343 lpDlgInfo->exStyle = GET_DWORD(p);
1344 p += 2;
1345 lpDlgInfo->style = GET_DWORD(p);
1346 p += 2;
1348 else
1350 lpDlgInfo->dialogEx = FALSE;
1351 lpDlgInfo->helpId = 0;
1352 lpDlgInfo->exStyle = GET_DWORD(p);
1353 p += 2;
1356 lpDlgInfo->nbItems = GET_WORD(p);
1357 p++;
1359 lpDlgInfo->x = GET_WORD(p);
1360 p++;
1362 lpDlgInfo->y = GET_WORD(p);
1363 p++;
1365 lpDlgInfo->cx = GET_WORD(p);
1366 p++;
1368 lpDlgInfo->cy = GET_WORD(p);
1369 p++;
1371 // Get the menu name
1373 switch (GET_WORD(p))
1375 case 0x0000:
1376 lpDlgInfo->menuName = nullptr;
1377 p++;
1378 break;
1379 case 0xffff:
1380 lpDlgInfo->menuName = (LPCTSTR) (WORD) GET_WORD(p + 1);
1381 p += 2;
1382 break;
1383 default:
1384 lpDlgInfo->menuName = (LPCTSTR) p;
1385 p += wcslen((LPCWSTR) p) + 1;
1386 break;
1389 // Get the class name
1391 switch (GET_WORD(p))
1393 case 0x0000:
1394 lpDlgInfo->className = (LPCTSTR)MAKEINTATOM(32770);
1395 p++;
1396 break;
1397 case 0xffff:
1398 lpDlgInfo->className = (LPCTSTR) (WORD) GET_WORD(p + 1);
1399 p += 2;
1400 break;
1401 default:
1402 lpDlgInfo->className = (LPCTSTR) p;
1403 p += wcslen((LPCTSTR)p) + 1;
1404 break;
1407 // Get the window caption
1409 lpDlgInfo->caption = (LPCTSTR)p;
1410 p += wcslen((LPCWSTR) p) + 1;
1412 // Get the font name
1414 if (lpDlgInfo->style & DS_SETFONT)
1416 lpDlgInfo->pointSize = GET_WORD(p);
1417 p++;
1419 if (lpDlgInfo->dialogEx)
1421 lpDlgInfo->weight = GET_WORD(p);
1422 p++;
1423 lpDlgInfo->italic = LOBYTE(GET_WORD(p));
1424 p++;
1426 else
1428 lpDlgInfo->weight = FW_DONTCARE;
1429 lpDlgInfo->italic = FALSE;
1432 lpDlgInfo->faceName = (LPCTSTR)p;
1433 p += wcslen((LPCWSTR) p) + 1;
1435 // First control is on DWORD boundary
1436 p = AlignWORD(p);
1438 return p;
1441 const WORD* CResModule::GetControlInfo(const WORD* p, LPDLGITEMINFO lpDlgItemInfo, BOOL dialogEx, LPBOOL bIsID) const
1443 if (dialogEx)
1445 lpDlgItemInfo->helpId = GET_DWORD(p);
1446 p += 2;
1447 lpDlgItemInfo->exStyle = GET_DWORD(p);
1448 p += 2;
1449 lpDlgItemInfo->style = GET_DWORD(p);
1450 p += 2;
1452 else
1454 lpDlgItemInfo->helpId = 0;
1455 lpDlgItemInfo->style = GET_DWORD(p);
1456 p += 2;
1457 lpDlgItemInfo->exStyle = GET_DWORD(p);
1458 p += 2;
1461 lpDlgItemInfo->x = GET_WORD(p);
1462 p++;
1464 lpDlgItemInfo->y = GET_WORD(p);
1465 p++;
1467 lpDlgItemInfo->cx = GET_WORD(p);
1468 p++;
1470 lpDlgItemInfo->cy = GET_WORD(p);
1471 p++;
1473 if (dialogEx)
1475 // ID is a DWORD for DIALOGEX
1476 lpDlgItemInfo->id = (WORD) GET_DWORD(p);
1477 p += 2;
1479 else
1481 lpDlgItemInfo->id = GET_WORD(p);
1482 p++;
1485 if (GET_WORD(p) == 0xffff)
1487 GET_WORD(p + 1);
1489 p += 2;
1491 else
1493 lpDlgItemInfo->className = (LPCTSTR) p;
1494 p += wcslen((LPCWSTR) p) + 1;
1497 if (GET_WORD(p) == 0xffff) // an integer ID?
1499 *bIsID = TRUE;
1500 lpDlgItemInfo->windowName = (LPCTSTR) (UINT_PTR) GET_WORD(p + 1);
1501 p += 2;
1503 else
1505 *bIsID = FALSE;
1506 lpDlgItemInfo->windowName = (LPCTSTR) p;
1507 p += wcslen((LPCWSTR) p) + 1;
1510 if (GET_WORD(p))
1512 lpDlgItemInfo->data = (LPVOID) (p + 1);
1513 p += GET_WORD(p) / sizeof(WORD);
1515 else
1516 lpDlgItemInfo->data = nullptr;
1518 p++;
1519 // Next control is on DWORD boundary
1520 p = AlignWORD(p);
1521 return p;
1524 const WORD * CResModule::CountMemReplaceDialogResource(const WORD * res, size_t * wordcount, WORD * newDialog)
1526 BOOL bEx = FALSE;
1527 DWORD style = GET_DWORD(res);
1528 if (newDialog)
1530 newDialog[(*wordcount)++] = GET_WORD(res++);
1531 newDialog[(*wordcount)++] = GET_WORD(res++);
1533 else
1535 res += 2;
1536 (*wordcount) += 2;
1539 if (style == 0xffff0001) // DIALOGEX resource
1541 bEx = TRUE;
1542 if (newDialog)
1544 newDialog[(*wordcount)++] = GET_WORD(res++); //help id
1545 newDialog[(*wordcount)++] = GET_WORD(res++); //help id
1546 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1547 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1548 style = GET_DWORD(res);
1549 newDialog[(*wordcount)++] = GET_WORD(res++); //style
1550 newDialog[(*wordcount)++] = GET_WORD(res++); //style
1552 else
1554 res += 4;
1555 style = GET_DWORD(res);
1556 res += 2;
1557 (*wordcount) += 6;
1560 else
1562 bEx = FALSE;
1563 if (newDialog)
1565 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1566 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1567 //style = GET_DWORD(res);
1568 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1569 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1571 else
1573 res += 2;
1574 (*wordcount) += 2;
1578 if (newDialog)
1579 newDialog[(*wordcount)] = GET_WORD(res);
1580 WORD nbItems = GET_WORD(res);
1581 (*wordcount)++;
1582 res++;
1584 if (newDialog)
1585 newDialog[(*wordcount)] = GET_WORD(res); //x
1586 (*wordcount)++;
1587 res++;
1589 if (newDialog)
1590 newDialog[(*wordcount)] = GET_WORD(res); //y
1591 (*wordcount)++;
1592 res++;
1594 if (newDialog)
1595 newDialog[(*wordcount)] = GET_WORD(res); //cx
1596 (*wordcount)++;
1597 res++;
1599 if (newDialog)
1600 newDialog[(*wordcount)] = GET_WORD(res); //cy
1601 (*wordcount)++;
1602 res++;
1604 // Get the menu name
1606 switch (GET_WORD(res))
1608 case 0x0000:
1609 if (newDialog)
1610 newDialog[(*wordcount)] = GET_WORD(res);
1611 (*wordcount)++;
1612 res++;
1613 break;
1614 case 0xffff:
1615 if (newDialog)
1617 newDialog[(*wordcount)++] = GET_WORD(res++);
1618 newDialog[(*wordcount)++] = GET_WORD(res++);
1620 else
1622 (*wordcount) += 2;
1623 res += 2;
1625 break;
1626 default:
1627 if (newDialog)
1629 wcscpy((LPWSTR)&newDialog[(*wordcount)], (LPCWSTR)res);
1631 (*wordcount) += wcslen((LPCWSTR) res) + 1;
1632 res += wcslen((LPCWSTR) res) + 1;
1633 break;
1636 // Get the class name
1638 switch (GET_WORD(res))
1640 case 0x0000:
1641 if (newDialog)
1642 newDialog[(*wordcount)] = GET_WORD(res);
1643 (*wordcount)++;
1644 res++;
1645 break;
1646 case 0xffff:
1647 if (newDialog)
1649 newDialog[(*wordcount)++] = GET_WORD(res++);
1650 newDialog[(*wordcount)++] = GET_WORD(res++);
1652 else
1654 (*wordcount) += 2;
1655 res += 2;
1657 break;
1658 default:
1659 if (newDialog)
1661 wcscpy((LPWSTR)&newDialog[(*wordcount)], (LPCWSTR)res);
1663 (*wordcount) += wcslen((LPCWSTR) res) + 1;
1664 res += wcslen((LPCWSTR) res) + 1;
1665 break;
1668 // Get the window caption
1670 ReplaceStr((LPCWSTR)res, newDialog, wordcount, &m_bTranslatedDialogStrings, &m_bDefaultDialogStrings);
1671 res += wcslen((LPCWSTR)res) + 1;
1673 // Get the font name
1675 if (style & DS_SETFONT)
1677 if (newDialog)
1678 newDialog[(*wordcount)] = GET_WORD(res);
1679 res++;
1680 (*wordcount)++;
1682 if (bEx)
1684 if (newDialog)
1686 newDialog[(*wordcount)++] = GET_WORD(res++);
1687 newDialog[(*wordcount)++] = GET_WORD(res++);
1689 else
1691 res += 2;
1692 (*wordcount) += 2;
1696 if (newDialog)
1697 wcscpy((LPWSTR)&newDialog[(*wordcount)], (LPCWSTR)res);
1698 (*wordcount) += wcslen((LPCWSTR)res) + 1;
1699 res += wcslen((LPCWSTR)res) + 1;
1701 // First control is on DWORD boundary
1702 while ((*wordcount)%2)
1703 (*wordcount)++;
1704 while ((UINT_PTR)res % 4)
1705 res++;
1707 while (nbItems--)
1709 res = ReplaceControlInfo(res, wordcount, newDialog, bEx);
1711 return res;
1714 const WORD* CResModule::ReplaceControlInfo(const WORD * res, size_t * wordcount, WORD * newDialog, BOOL bEx)
1716 if (bEx)
1718 if (newDialog)
1720 newDialog[(*wordcount)++] = GET_WORD(res++); //helpid
1721 newDialog[(*wordcount)++] = GET_WORD(res++); //helpid
1723 else
1725 res += 2;
1726 (*wordcount) += 2;
1729 if (newDialog)
1731 LONG * exStyle = (LONG*)&newDialog[(*wordcount)];
1732 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1733 newDialog[(*wordcount)++] = GET_WORD(res++); //exStyle
1734 if (m_bRTL)
1735 *exStyle |= WS_EX_RTLREADING;
1737 else
1739 res += 2;
1740 (*wordcount) += 2;
1743 if (newDialog)
1745 newDialog[(*wordcount)++] = GET_WORD(res++); //style
1746 newDialog[(*wordcount)++] = GET_WORD(res++); //style
1748 else
1750 res += 2;
1751 (*wordcount) += 2;
1754 if (newDialog)
1755 newDialog[(*wordcount)] = GET_WORD(res); //x
1756 res++;
1757 (*wordcount)++;
1759 if (newDialog)
1760 newDialog[(*wordcount)] = GET_WORD(res); //y
1761 res++;
1762 (*wordcount)++;
1764 if (newDialog)
1765 newDialog[(*wordcount)] = GET_WORD(res); //cx
1766 res++;
1767 (*wordcount)++;
1769 if (newDialog)
1770 newDialog[(*wordcount)] = GET_WORD(res); //cy
1771 res++;
1772 (*wordcount)++;
1774 if (bEx)
1776 // ID is a DWORD for DIALOGEX
1777 if (newDialog)
1779 newDialog[(*wordcount)++] = GET_WORD(res++);
1780 newDialog[(*wordcount)++] = GET_WORD(res++);
1782 else
1784 res += 2;
1785 (*wordcount) += 2;
1788 else
1790 if (newDialog)
1791 newDialog[(*wordcount)] = GET_WORD(res);
1792 res++;
1793 (*wordcount)++;
1796 if (GET_WORD(res) == 0xffff) //classID
1798 if (newDialog)
1800 newDialog[(*wordcount)++] = GET_WORD(res++);
1801 newDialog[(*wordcount)++] = GET_WORD(res++);
1803 else
1805 res += 2;
1806 (*wordcount) += 2;
1809 else
1811 if (newDialog)
1812 wcscpy((LPWSTR)&newDialog[(*wordcount)], (LPCWSTR)res);
1813 (*wordcount) += wcslen((LPCWSTR) res) + 1;
1814 res += wcslen((LPCWSTR) res) + 1;
1817 if (GET_WORD(res) == 0xffff) // an integer ID?
1819 if (newDialog)
1821 newDialog[(*wordcount)++] = GET_WORD(res++);
1822 newDialog[(*wordcount)++] = GET_WORD(res++);
1824 else
1826 res += 2;
1827 (*wordcount) += 2;
1830 else
1832 ReplaceStr((LPCWSTR)res, newDialog, wordcount, &m_bTranslatedDialogStrings, &m_bDefaultDialogStrings);
1833 res += wcslen((LPCWSTR)res) + 1;
1836 if (newDialog)
1837 memcpy(&newDialog[(*wordcount)], res, (GET_WORD(res)+1)*sizeof(WORD));
1838 (*wordcount) += (GET_WORD(res)+1);
1839 res += (GET_WORD(res)+1);
1840 // Next control is on DWORD boundary
1841 while ((*wordcount) % 2)
1842 (*wordcount)++;
1843 res = AlignWORD(res);
1845 return res;
1848 BOOL CResModule::ExtractRibbon(LPCTSTR lpszType)
1850 HRSRC hrsrc = FindResource(m_hResDll, lpszType, RT_RIBBON);
1851 HGLOBAL hglRibbonTemplate;
1852 const BYTE *p;
1854 if (!hrsrc)
1855 MYERROR;
1857 hglRibbonTemplate = LoadResource(m_hResDll, hrsrc);
1859 DWORD sizeres = SizeofResource(m_hResDll, hrsrc);
1861 if (!hglRibbonTemplate)
1862 MYERROR;
1864 p = (const BYTE*)LockResource(hglRibbonTemplate);
1866 if (!p)
1867 MYERROR;
1869 // Resource consists of one single string
1870 // that is XML.
1872 // extract all <id><name>blah1</name><value>blah2</value></id><text>blah</text> elements
1874 const std::regex regRevMatch("<ID><NAME>([^<]+)</NAME><VALUE>([^<]+)</VALUE></ID><TEXT>([^<]+)</TEXT>");
1875 std::string ss = std::string((const char*)p, sizeres);
1876 const std::sregex_iterator end;
1877 for (std::sregex_iterator it(ss.cbegin(), ss.cend(), regRevMatch); it != end; ++it)
1879 size_t len;
1881 std::string str1 = (*it)[1];
1882 len = str1.size();
1883 auto bufw1 = std::make_unique<wchar_t[]>(len * 4 + 1);
1884 SecureZeroMemory(bufw1.get(), (len * 4 + 1) * sizeof(wchar_t));
1885 MultiByteToWideChar(CP_UTF8, 0, str1.c_str(), -1, bufw1.get(), (int)len * 4);
1886 std::wstring strIdNameVal = bufw1.get();
1887 strIdNameVal += L" - Ribbon name";
1889 std::string str2 = (*it)[2];
1890 len = str2.size();
1891 auto bufw2 = std::make_unique<wchar_t[]>(len * 4 + 1);
1892 SecureZeroMemory(bufw2.get(), (len * 4 + 1)*sizeof(wchar_t));
1893 MultiByteToWideChar(CP_UTF8, 0, str2.c_str(), -1, bufw2.get(), (int)len * 4);
1894 std::wstring strIdVal = bufw2.get();
1896 std::string str3 = (*it)[3];
1897 len = str3.size();
1898 auto bufw3 = std::make_unique<wchar_t[]>(len * 4 + 1);
1899 SecureZeroMemory(bufw3.get(), (len * 4 + 1)*sizeof(wchar_t));
1900 MultiByteToWideChar(CP_UTF8, 0, str3.c_str(), -1, bufw3.get(), (int)len * 4);
1901 std::wstring str = bufw3.get();
1903 RESOURCEENTRY entry = m_StringEntries[str];
1904 InsertResourceIDs(RT_RIBBON, 0, entry, std::stoi(strIdVal), strIdNameVal.c_str());
1905 if (wcschr(str.c_str(), '%'))
1906 entry.flag = L"#, c-format";
1907 m_StringEntries[str] = entry;
1908 m_bDefaultRibbonTexts++;
1911 // extract all </ELEMENT_NAME><NAME>blahblah</NAME> elements
1913 const std::regex regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
1914 for (std::sregex_iterator it(ss.cbegin(), ss.cend(), regRevMatchName); it != end; ++it)
1916 std::string str = (*it)[1];
1917 size_t len = str.size();
1918 auto bufw = std::make_unique<wchar_t[]>(len * 4 + 1);
1919 SecureZeroMemory(bufw.get(), (len*4 + 1)*sizeof(wchar_t));
1920 MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, bufw.get(), (int)len*4);
1921 std::wstring ret = bufw.get();
1922 RESOURCEENTRY entry = m_StringEntries[ret];
1923 InsertResourceIDs(RT_RIBBON, 0, entry, (INT_PTR)lpszType, L" - Ribbon element");
1924 if (wcschr(ret.c_str(), '%'))
1925 entry.flag = L"#, c-format";
1926 m_StringEntries[ret] = entry;
1927 m_bDefaultRibbonTexts++;
1930 UnlockResource(hglRibbonTemplate);
1931 FreeResource(hglRibbonTemplate);
1932 return TRUE;
1935 BOOL CResModule::ReplaceRibbon(LPCTSTR lpszType, WORD wLanguage)
1937 HRSRC hrsrc = FindResource(m_hResDll, lpszType, RT_RIBBON);
1938 HGLOBAL hglRibbonTemplate;
1939 const BYTE *p;
1941 if (!hrsrc)
1942 MYERROR;
1944 hglRibbonTemplate = LoadResource(m_hResDll, hrsrc);
1946 DWORD sizeres = SizeofResource(m_hResDll, hrsrc);
1948 if (!hglRibbonTemplate)
1949 MYERROR;
1951 p = (const BYTE*)LockResource(hglRibbonTemplate);
1953 if (!p)
1954 MYERROR;
1956 std::string ss = std::string((const char*)p, sizeres);
1957 size_t len = ss.size();
1958 auto bufw = std::make_unique<wchar_t[]>(len * 4 + 1);
1959 SecureZeroMemory(bufw.get(), (len*4 + 1)*sizeof(wchar_t));
1960 MultiByteToWideChar(CP_UTF8, 0, ss.c_str(), -1, bufw.get(), (int)len*4);
1961 std::wstring ssw = bufw.get();
1964 const std::regex regRevMatch("<TEXT>([^<]+)</TEXT>");
1965 const std::sregex_iterator end;
1966 for (std::sregex_iterator it(ss.cbegin(), ss.cend(), regRevMatch); it != end; ++it)
1968 std::string str = (*it)[1];
1969 size_t slen = str.size();
1970 auto bufw2 = std::make_unique<wchar_t[]>(slen * 4 + 1);
1971 SecureZeroMemory(bufw2.get(), (slen*4 + 1)*sizeof(wchar_t));
1972 MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, bufw2.get(), (int)slen*4);
1973 std::wstring ret = bufw2.get();
1975 RESOURCEENTRY entry = m_StringEntries[ret];
1976 ret = L"<TEXT>" + ret + L"</TEXT>";
1978 if (entry.msgstr.size())
1980 auto sbuf = std::make_unique<wchar_t[]>(entry.msgstr.size() + 10);
1981 wcscpy(sbuf.get(), entry.msgstr.c_str());
1982 CUtils::StringCollapse(sbuf.get());
1983 std::wstring sreplace = L"<TEXT>";
1984 sreplace += sbuf.get();
1985 sreplace += L"</TEXT>";
1986 CUtils::SearchReplace(ssw, ret, sreplace);
1987 m_bTranslatedRibbonTexts++;
1989 else
1990 m_bDefaultRibbonTexts++;
1993 const std::regex regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
1994 for (std::sregex_iterator it(ss.cbegin(), ss.cend(), regRevMatchName); it != end; ++it)
1996 std::string str = (*it)[1];
1997 size_t slen = str.size();
1998 auto bufw2 = std::make_unique<wchar_t[]>(slen * 4 + 1);
1999 SecureZeroMemory(bufw2.get(), (slen*4 + 1)*sizeof(wchar_t));
2000 MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, bufw2.get(), (int)slen*4);
2001 std::wstring ret = bufw2.get();
2003 RESOURCEENTRY entry = m_StringEntries[ret];
2004 ret = L"</ELEMENT_NAME><NAME>" + ret + L"</NAME>";
2006 if (entry.msgstr.size())
2008 auto sbuf = std::make_unique<wchar_t[]>(entry.msgstr.size() + 10);
2009 wcscpy(sbuf.get(), entry.msgstr.c_str());
2010 CUtils::StringCollapse(sbuf.get());
2011 std::wstring sreplace = L"</ELEMENT_NAME><NAME>";
2012 sreplace += sbuf.get();
2013 sreplace += L"</NAME>";
2014 CUtils::SearchReplace(ssw, ret, sreplace);
2015 m_bTranslatedRibbonTexts++;
2017 else
2018 m_bDefaultRibbonTexts++;
2021 auto buf = std::make_unique<char[]>(ssw.size() * 4 + 1);
2022 int lengthIncTerminator = WideCharToMultiByte(CP_UTF8, 0, ssw.c_str(), -1, buf.get(), (int)len * 4, nullptr, nullptr);
2025 if (!UpdateResource(m_hUpdateRes, RT_RIBBON, lpszType, (m_wTargetLang ? m_wTargetLang : wLanguage), buf.get(), lengthIncTerminator-1))
2027 goto DONE_ERROR;
2030 if (m_wTargetLang && (!UpdateResource(m_hUpdateRes, RT_RIBBON, lpszType, wLanguage, nullptr, 0)))
2032 goto DONE_ERROR;
2036 UnlockResource(hglRibbonTemplate);
2037 FreeResource(hglRibbonTemplate);
2038 return TRUE;
2040 DONE_ERROR:
2041 UnlockResource(hglRibbonTemplate);
2042 FreeResource(hglRibbonTemplate);
2043 MYERROR;
2046 BOOL CALLBACK CResModule::EnumResNameCallback(HMODULE /*hModule*/, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
2048 auto lpResModule = reinterpret_cast<CResModule*>(lParam);
2050 if (lpszType == RT_STRING)
2052 if (IS_INTRESOURCE(lpszName))
2054 if (!lpResModule->ExtractString(lpszName))
2055 return FALSE;
2058 else if (lpszType == RT_MENU)
2060 if (IS_INTRESOURCE(lpszName))
2062 if (!lpResModule->ExtractMenu(lpszName))
2063 return FALSE;
2066 else if (lpszType == RT_DIALOG)
2068 if (IS_INTRESOURCE(lpszName))
2070 if (!lpResModule->ExtractDialog(lpszName))
2071 return FALSE;
2074 else if (lpszType == RT_ACCELERATOR)
2076 if (IS_INTRESOURCE(lpszName))
2078 if (!lpResModule->ExtractAccelerator(lpszName))
2079 return FALSE;
2082 else if (lpszType == RT_RIBBON)
2084 if (IS_INTRESOURCE(lpszName))
2086 if (!lpResModule->ExtractRibbon(lpszName))
2087 return FALSE;
2091 return TRUE;
2094 #pragma warning(push)
2095 #pragma warning(disable: 4189)
2096 BOOL CALLBACK CResModule::EnumResNameWriteCallback(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
2098 auto lpResModule = reinterpret_cast<CResModule*>(lParam);
2099 return EnumResourceLanguages(hModule, lpszType, lpszName, (ENUMRESLANGPROC)&lpResModule->EnumResWriteLangCallback, lParam);
2101 #pragma warning(pop)
2103 BOOL CALLBACK CResModule::EnumResWriteLangCallback(HMODULE /*hModule*/, LPCTSTR lpszType, LPTSTR lpszName, WORD wLanguage, LONG_PTR lParam)
2105 BOOL bRes = FALSE;
2106 auto lpResModule = reinterpret_cast<CResModule*>(lParam);
2108 if (lpszType == RT_STRING)
2110 bRes = lpResModule->ReplaceString(lpszName, wLanguage);
2112 else if (lpszType == RT_MENU)
2114 bRes = lpResModule->ReplaceMenu(lpszName, wLanguage);
2116 else if (lpszType == RT_DIALOG)
2118 bRes = lpResModule->ReplaceDialog(lpszName, wLanguage);
2120 else if (lpszType == RT_ACCELERATOR)
2122 bRes = lpResModule->ReplaceAccelerator(lpszName, wLanguage);
2124 else if (lpszType == RT_RIBBON)
2126 bRes = lpResModule->ReplaceRibbon(lpszName, wLanguage);
2129 return bRes;
2133 void CResModule::ReplaceStr(LPCWSTR src, WORD * dest, size_t * count, int * translated, int * def)
2135 TCHAR * pBuf = new TCHAR[MAX_STRING_LENGTH];
2136 SecureZeroMemory(pBuf, MAX_STRING_LENGTH * sizeof(TCHAR));
2137 wcscpy(pBuf, src);
2138 CUtils::StringExtend(pBuf);
2140 std::wstring wstr = std::wstring(pBuf);
2141 RESOURCEENTRY entry = m_StringEntries[wstr];
2142 if (!entry.msgstr.empty())
2144 wcscpy(pBuf, entry.msgstr.c_str());
2145 CUtils::StringCollapse(pBuf);
2146 if (dest)
2147 wcscpy((wchar_t *)&dest[(*count)], pBuf);
2148 (*count) += wcslen(pBuf)+1;
2149 (*translated)++;
2151 else
2153 if (dest)
2154 wcscpy((wchar_t *)&dest[(*count)], src);
2155 (*count) += wcslen(src) + 1;
2156 if (wcslen(src))
2157 (*def)++;
2159 delete [] pBuf;
2162 size_t CResModule::ScanHeaderFile(const std::wstring & filepath)
2164 size_t count = 0;
2166 // open the file and read the contents
2167 DWORD reqLen = GetFullPathName(filepath.c_str(), 0, nullptr, nullptr);
2168 auto wcfullPath = std::make_unique<TCHAR[]>(reqLen + 1);
2169 GetFullPathName(filepath.c_str(), reqLen, wcfullPath.get(), nullptr);
2170 std::wstring fullpath = wcfullPath.get();
2173 // first treat the file as ASCII and try to get the defines
2175 std::ifstream fin(fullpath);
2176 std::string file_line;
2177 while (std::getline(fin, file_line))
2179 auto defpos = file_line.find("#define");
2180 if (defpos != std::string::npos)
2182 std::string text = file_line.substr(defpos + 7);
2183 trim(text);
2184 auto spacepos = text.find(' ');
2185 if (spacepos == std::string::npos)
2186 spacepos = text.find('\t');
2187 if (spacepos != std::string::npos)
2189 auto value = atol(text.substr(spacepos).c_str());
2190 if (value == 0 && text.substr(spacepos).find("0x") != std::string::npos)
2191 value = std::stoul(text.substr(spacepos), nullptr, 16);
2192 text = text.substr(0, spacepos);
2193 trim(text);
2194 if (text.compare(0, 4, "IDS_") == 0)
2196 m_currentHeaderDataStrings[value] = CUnicodeUtils::StdGetUnicode(text);
2197 ++count;
2199 else if (text.compare(0, 4, "IDD_") == 0)
2201 m_currentHeaderDataDialogs[value] = CUnicodeUtils::StdGetUnicode(text);
2202 ++count;
2204 else if (text.compare(0, 3, "ID_") == 0)
2206 m_currentHeaderDataMenus[value] = CUnicodeUtils::StdGetUnicode(text);
2207 ++count;
2215 // now try the same with the file treated as utf16
2217 // open as a byte stream
2218 std::wifstream wfin(fullpath, std::ios::binary);
2219 // apply BOM-sensitive UTF-16 facet
2220 wfin.imbue(std::locale(wfin.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));
2221 //std::wifstream wfin(fullpath);
2222 std::wstring wfile_line;
2223 while (std::getline(wfin, wfile_line))
2225 auto defpos = wfile_line.find(L"#define");
2226 if (defpos != std::wstring::npos)
2228 std::wstring text = wfile_line.substr(defpos + 7);
2229 trim(text);
2230 auto spacepos = text.find(' ');
2231 if (spacepos == std::wstring::npos)
2232 spacepos = text.find('\t');
2233 if (spacepos != std::wstring::npos)
2235 auto value = _wtol(text.substr(spacepos).c_str());
2236 if (value == 0 && text.substr(spacepos).find(L"0x") != std::wstring::npos)
2237 value = std::stoul(text.substr(spacepos), nullptr, 16);
2238 text = text.substr(0, spacepos);
2239 trim(text);
2240 if (text.compare(0, 4, L"IDS_") == 0)
2242 m_currentHeaderDataStrings[value] = text;
2243 ++count;
2245 else if (text.compare(0, 4, L"IDD_") == 0)
2247 m_currentHeaderDataDialogs[value] = text;
2248 ++count;
2250 else if (text.compare(0, 3, L"ID_") == 0)
2252 m_currentHeaderDataMenus[value] = text;
2253 ++count;
2260 return count;
2263 void CResModule::InsertResourceIDs(LPCWSTR lpType, INT_PTR mainId, RESOURCEENTRY& entry, INT_PTR id, LPCWSTR infotext)
2265 if (lpType == RT_DIALOG)
2267 auto foundIt = m_currentHeaderDataDialogs.find(mainId);
2268 if (foundIt != m_currentHeaderDataDialogs.end())
2269 entry.resourceIDs.insert(L"Dialog " + foundIt->second + L": Control id " + NumToStr(id) + infotext);
2270 else
2271 entry.resourceIDs.insert(NumToStr(id) + infotext);
2273 else if (lpType == RT_STRING)
2275 auto foundIt = m_currentHeaderDataStrings.find(id);
2276 if (foundIt != m_currentHeaderDataStrings.end())
2277 entry.resourceIDs.insert(foundIt->second + infotext);
2278 else
2279 entry.resourceIDs.insert(NumToStr(id) + infotext);
2281 else if (lpType == RT_MENU)
2283 auto foundIt = m_currentHeaderDataMenus.find(id);
2284 if (foundIt != m_currentHeaderDataMenus.end())
2285 entry.resourceIDs.insert(foundIt->second + infotext);
2286 else
2287 entry.resourceIDs.insert(NumToStr(id) + infotext);
2289 else if (lpType == RT_RIBBON && infotext && wcsstr(infotext, L"ID") == infotext)
2290 entry.resourceIDs.insert(infotext);
2291 else
2292 entry.resourceIDs.insert(NumToStr(id) + infotext);