1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2015-2017 - TortoiseGit
4 // Copyright (C) 2003-2008, 2010-2017 - 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.
21 #include "UnicodeUtils.h"
22 #include "ResModule.h"
33 #pragma warning(disable: 4091) // 'typedef ': ignored on left of '' when no variable is declared
37 #pragma comment(lib, "Imagehlp.lib")
40 #define RT_RIBBON MAKEINTRESOURCE(28)
44 #define MYERROR {CUtils::Error(); return FALSE;}
46 static const WORD
* AlignWORD(const WORD
* pWord
)
48 const WORD
* res
= pWord
;
49 res
+= ((((UINT_PTR
)pWord
+ 3) & ~3) - (UINT_PTR
)pWord
) / sizeof(WORD
);
53 std::wstring
NumToStr(INT_PTR num
)
56 swprintf_s(buf
, L
"%Id", num
);
60 CResModule::CResModule(void)
61 : m_bTranslatedStrings(0)
62 , m_bDefaultStrings(0)
63 , m_bTranslatedDialogStrings(0)
64 , m_bDefaultDialogStrings(0)
65 , m_bTranslatedMenuStrings(0)
66 , m_bDefaultMenuStrings(0)
67 , m_bTranslatedAcceleratorStrings(0)
68 , m_bDefaultAcceleratorStrings(0)
69 , m_bTranslatedRibbonTexts(0)
70 , m_bDefaultRibbonTexts(0)
73 , m_hUpdateRes(nullptr)
76 , m_bAdjustEOLs(false)
80 CResModule::~CResModule(void)
84 BOOL
CResModule::ExtractResources(const std::vector
<std::wstring
>& filelist
, LPCTSTR lpszPOFilePath
, BOOL bNoUpdate
, LPCTSTR lpszHeaderFile
)
86 for (auto I
= filelist
.cbegin(); I
!= filelist
.cend(); ++I
)
88 std::wstring filepath
= *I
;
89 m_currentHeaderDataDialogs
.clear();
90 m_currentHeaderDataMenus
.clear();
91 m_currentHeaderDataStrings
.clear();
92 auto starpos
= I
->find('*');
93 if (starpos
!= std::wstring::npos
)
94 filepath
= I
->substr(0, starpos
);
95 while (starpos
!= std::wstring::npos
)
97 auto starposnext
= I
->find('*', starpos
+ 1);
98 std::wstring headerfile
= I
->substr(starpos
+ 1, starposnext
- starpos
- 1);
99 ScanHeaderFile(headerfile
);
100 starpos
= starposnext
;
102 m_hResDll
= LoadLibraryEx(filepath
.c_str(), nullptr, LOAD_LIBRARY_AS_IMAGE_RESOURCE
| LOAD_LIBRARY_AS_DATAFILE
);
106 size_t nEntries
= m_StringEntries
.size();
107 // fill in the std::map with all translatable entries
110 _ftprintf(stdout
, L
"Extracting StringTable....");
111 EnumResourceNames(m_hResDll
, RT_STRING
, EnumResNameCallback
, (LONG_PTR
)this);
113 _ftprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size()-nEntries
);
114 nEntries
= m_StringEntries
.size();
117 _ftprintf(stdout
, L
"Extracting Dialogs........");
118 EnumResourceNames(m_hResDll
, RT_DIALOG
, EnumResNameCallback
, (LONG_PTR
)this);
120 _ftprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size()-nEntries
);
121 nEntries
= m_StringEntries
.size();
124 _ftprintf(stdout
, L
"Extracting Menus..........");
125 EnumResourceNames(m_hResDll
, RT_MENU
, EnumResNameCallback
, (LONG_PTR
)this);
127 _ftprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size()-nEntries
);
128 nEntries
= m_StringEntries
.size();
130 _ftprintf(stdout
, L
"Extracting Accelerators...");
131 EnumResourceNames(m_hResDll
, RT_ACCELERATOR
, EnumResNameCallback
, (LONG_PTR
)this);
133 _ftprintf(stdout
, L
"%4Iu Accelerators\n", m_StringEntries
.size()-nEntries
);
134 nEntries
= m_StringEntries
.size();
136 _ftprintf(stdout
, L
"Extracting Ribbons........");
137 EnumResourceNames(m_hResDll
, RT_RIBBON
, EnumResNameCallback
, (LONG_PTR
)this);
139 _ftprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size()-nEntries
);
140 nEntries
= m_StringEntries
.size();
142 // parse a probably existing file and update the translations which are
144 m_StringEntries
.ParseFile(lpszPOFilePath
, !bNoUpdate
, m_bAdjustEOLs
);
146 FreeLibrary(m_hResDll
);
149 // at last, save the new file
150 return m_StringEntries
.SaveFile(lpszPOFilePath
, lpszHeaderFile
);
153 BOOL
CResModule::ExtractResources(LPCTSTR lpszSrcLangDllPath
, LPCTSTR lpszPoFilePath
, BOOL bNoUpdate
, LPCTSTR lpszHeaderFile
)
155 m_hResDll
= LoadLibraryEx(lpszSrcLangDllPath
, nullptr, LOAD_LIBRARY_AS_IMAGE_RESOURCE
| LOAD_LIBRARY_AS_DATAFILE
);
160 // fill in the std::map with all translatable entries
163 _ftprintf(stdout
, L
"Extracting StringTable....");
164 EnumResourceNames(m_hResDll
, RT_STRING
, EnumResNameCallback
, (LONG_PTR
)this);
166 _ftprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size());
167 nEntries
= m_StringEntries
.size();
170 _ftprintf(stdout
, L
"Extracting Dialogs........");
171 EnumResourceNames(m_hResDll
, RT_DIALOG
, EnumResNameCallback
, (LONG_PTR
)this);
173 _ftprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size()-nEntries
);
174 nEntries
= m_StringEntries
.size();
177 _ftprintf(stdout
, L
"Extracting Menus..........");
178 EnumResourceNames(m_hResDll
, RT_MENU
, EnumResNameCallback
, (LONG_PTR
)this);
180 _ftprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size()-nEntries
);
181 nEntries
= m_StringEntries
.size();
184 _ftprintf(stdout
, L
"Extracting Accelerators...");
185 EnumResourceNames(m_hResDll
, RT_ACCELERATOR
, EnumResNameCallback
, (LONG_PTR
)this);
187 _ftprintf(stdout
, L
"%4Iu Accelerators\n", m_StringEntries
.size()-nEntries
);
188 nEntries
= m_StringEntries
.size();
190 // parse a probably existing file and update the translations which are
192 m_StringEntries
.ParseFile(lpszPoFilePath
, !bNoUpdate
, m_bAdjustEOLs
);
194 // at last, save the new file
195 if (!m_StringEntries
.SaveFile(lpszPoFilePath
, lpszHeaderFile
))
198 FreeLibrary(m_hResDll
);
200 AdjustCheckSum(sDestFile
);
206 FreeLibrary(m_hResDll
);
210 void CResModule::RemoveSignatures(LPCTSTR lpszDestLangDllPath
)
212 // Remove any signatures in the file:
213 // if we don't remove it here, the signature will be invalid after
214 // we modify this file, and the signtool.exe will throw an error and refuse to sign it again.
215 auto hFile
= CreateFile(lpszDestLangDllPath
, FILE_READ_DATA
| FILE_WRITE_DATA
, 0, nullptr, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, nullptr);
216 if (hFile
== INVALID_HANDLE_VALUE
)
224 ImageEnumerateCertificates(hFile
, CERT_SECTION_TYPE_ANY
, &certcount
, indices
, _countof(indices
));
226 for (DWORD i
= 0; i
< certcount
; ++i
)
227 ImageRemoveCertificate(hFile
, i
);
232 BOOL
CResModule::CreateTranslatedResources(LPCTSTR lpszSrcLangDllPath
, LPCTSTR lpszDestLangDllPath
, LPCTSTR lpszPOFilePath
)
234 if (!CopyFile(lpszSrcLangDllPath
, lpszDestLangDllPath
, FALSE
))
237 RemoveSignatures(lpszDestLangDllPath
);
242 m_hResDll
= LoadLibraryEx(lpszSrcLangDllPath
, nullptr, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
| LOAD_LIBRARY_AS_IMAGE_RESOURCE
| LOAD_IGNORE_CODE_AUTHZ_LEVEL
);
246 } while (!m_hResDll
&& (count
< 10));
251 sDestFile
= std::wstring(lpszDestLangDllPath
);
253 // get all translated strings
254 if (!m_StringEntries
.ParseFile(lpszPOFilePath
, FALSE
, m_bAdjustEOLs
))
256 m_bTranslatedStrings
= 0;
257 m_bDefaultStrings
= 0;
258 m_bTranslatedDialogStrings
= 0;
259 m_bDefaultDialogStrings
= 0;
260 m_bTranslatedMenuStrings
= 0;
261 m_bDefaultMenuStrings
= 0;
262 m_bTranslatedAcceleratorStrings
= 0;
263 m_bDefaultAcceleratorStrings
= 0;
269 m_hUpdateRes
= BeginUpdateResource(sDestFile
.c_str(), FALSE
);
273 } while (!m_hUpdateRes
&& (count
< 10));
280 _ftprintf(stdout
, L
"Translating StringTable...");
281 bRes
= EnumResourceNames(m_hResDll
, RT_STRING
, EnumResNameWriteCallback
, (LONG_PTR
)this);
283 _ftprintf(stdout
, L
"%4d translated, %4d not translated\n", m_bTranslatedStrings
, m_bDefaultStrings
);
286 _ftprintf(stdout
, L
"Translating Dialogs.......");
287 bRes
= EnumResourceNames(m_hResDll
, RT_DIALOG
, EnumResNameWriteCallback
, (LONG_PTR
)this);
289 _ftprintf(stdout
, L
"%4d translated, %4d not translated\n", m_bTranslatedDialogStrings
, m_bDefaultDialogStrings
);
292 _ftprintf(stdout
, L
"Translating Menus.........");
293 bRes
= EnumResourceNames(m_hResDll
, RT_MENU
, EnumResNameWriteCallback
, (LONG_PTR
)this);
295 _ftprintf(stdout
, L
"%4d translated, %4d not translated\n", m_bTranslatedMenuStrings
, m_bDefaultMenuStrings
);
298 _ftprintf(stdout
, L
"Translating Accelerators..");
299 bRes
= EnumResourceNames(m_hResDll
, RT_ACCELERATOR
, EnumResNameWriteCallback
, (LONG_PTR
)this);
301 _ftprintf(stdout
, L
"%4d translated, %4d not translated\n", m_bTranslatedAcceleratorStrings
, m_bDefaultAcceleratorStrings
);
304 _ftprintf(stdout
, L
"Translating Ribbons.......");
305 bRes
= EnumResourceNames(m_hResDll
, RT_RIBBON
, EnumResNameWriteCallback
, (LONG_PTR
)this);
307 _ftprintf(stdout
, L
"%4d translated, %4d not translated\n", m_bTranslatedRibbonTexts
, m_bDefaultRibbonTexts
);
309 if (!EndUpdateResource(m_hUpdateRes
, !bRes
))
312 FreeLibrary(m_hResDll
);
316 FreeLibrary(m_hResDll
);
320 BOOL
CResModule::ExtractString(LPCTSTR lpszType
)
322 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_STRING
);
323 HGLOBAL hglStringTable
;
328 hglStringTable
= LoadResource(m_hResDll
, hrsrc
);
332 p
= (LPWSTR
)LockResource(hglStringTable
);
336 /* [Block of 16 strings. The strings are Pascal style with a WORD
337 length preceding the string. 16 strings are always written, even
338 if not all slots are full. Any slots in the block with no string
339 have a zero WORD for the length.]
342 //first check how much memory we need
344 for (int i
=0; i
<16; ++i
)
346 int len
= GET_WORD(pp
);
348 std::wstring msgid
= std::wstring(pp
, len
);
349 WCHAR
* pBuf
= new WCHAR
[MAX_STRING_LENGTH
*2];
350 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
*2*sizeof(WCHAR
));
351 wcscpy(pBuf
, msgid
.c_str());
352 CUtils::StringExtend(pBuf
);
356 std::wstring str
= std::wstring(pBuf
);
357 RESOURCEENTRY entry
= m_StringEntries
[str
];
358 InsertResourceIDs(RT_STRING
, 0, entry
, ((INT_PTR
)lpszType
- 1) * 16 + i
, L
"");
359 if (wcschr(str
.c_str(), '%'))
360 entry
.flag
= L
"#, c-format";
361 m_StringEntries
[str
] = entry
;
366 UnlockResource(hglStringTable
);
367 FreeResource(hglStringTable
);
370 UnlockResource(hglStringTable
);
371 FreeResource(hglStringTable
);
375 BOOL
CResModule::ReplaceString(LPCTSTR lpszType
, WORD wLanguage
)
377 HRSRC hrsrc
= FindResourceEx(m_hResDll
, RT_STRING
, lpszType
, wLanguage
);
378 HGLOBAL hglStringTable
;
383 hglStringTable
= LoadResource(m_hResDll
, hrsrc
);
387 p
= (LPWSTR
)LockResource(hglStringTable
);
391 /* [Block of 16 strings. The strings are Pascal style with a WORD
392 length preceding the string. 16 strings are always written, even
393 if not all slots are full. Any slots in the block with no string
394 have a zero WORD for the length.]
397 //first check how much memory we need
400 for (int i
=0; i
<16; ++i
)
403 size_t len
= GET_WORD(pp
);
405 std::wstring msgid
= std::wstring(pp
, len
);
406 WCHAR
* pBuf
= new WCHAR
[MAX_STRING_LENGTH
*2];
407 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
*2*sizeof(WCHAR
));
408 wcscpy(pBuf
, msgid
.c_str());
409 CUtils::StringExtend(pBuf
);
410 msgid
= std::wstring(pBuf
);
412 RESOURCEENTRY resEntry
;
413 resEntry
= m_StringEntries
[msgid
];
414 wcscpy(pBuf
, resEntry
.msgstr
.empty() ? msgid
.c_str() : resEntry
.msgstr
.c_str());
415 ReplaceWithRegex(pBuf
);
416 CUtils::StringCollapse(pBuf
);
417 size_t newlen
= wcslen(pBuf
);
426 WORD
* newTable
= new WORD
[nMem
+ (nMem
% 2)];
427 SecureZeroMemory(newTable
, (nMem
+ (nMem
% 2))*2);
430 for (int i
=0; i
<16; ++i
)
432 int len
= GET_WORD(p
);
434 std::wstring msgid
= std::wstring(p
, len
);
435 WCHAR
* pBuf
= new WCHAR
[MAX_STRING_LENGTH
*2];
436 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
*2*sizeof(WCHAR
));
437 wcscpy(pBuf
, msgid
.c_str());
438 CUtils::StringExtend(pBuf
);
439 msgid
= std::wstring(pBuf
);
441 RESOURCEENTRY resEntry
;
442 resEntry
= m_StringEntries
[msgid
];
443 wcscpy(pBuf
, resEntry
.msgstr
.empty() ? msgid
.c_str() : resEntry
.msgstr
.c_str());
444 ReplaceWithRegex(pBuf
);
445 CUtils::StringCollapse(pBuf
);
446 size_t newlen
= wcslen(pBuf
);
449 newTable
[index
++] = (WORD
)newlen
;
450 wcsncpy((wchar_t *)&newTable
[index
], pBuf
, newlen
);
452 m_bTranslatedStrings
++;
456 newTable
[index
++] = (WORD
)len
;
458 wcsncpy((wchar_t *)&newTable
[index
], p
, len
);
467 if (!UpdateResource(m_hUpdateRes
, RT_STRING
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newTable
, (DWORD
)(nMem
+ (nMem
% 2))*2))
473 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_STRING
, lpszType
, wLanguage
, nullptr, 0)))
479 UnlockResource(hglStringTable
);
480 FreeResource(hglStringTable
);
483 UnlockResource(hglStringTable
);
484 FreeResource(hglStringTable
);
488 BOOL
CResModule::ExtractMenu(LPCTSTR lpszType
)
490 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_MENU
);
491 HGLOBAL hglMenuTemplate
;
492 WORD version
, offset
;
498 hglMenuTemplate
= LoadResource(m_hResDll
, hrsrc
);
500 if (!hglMenuTemplate
)
503 p
= (const WORD
*)LockResource(hglMenuTemplate
);
508 // Standard MENU resource
509 //struct MenuHeader {
510 // WORD wVersion; // Currently zero
511 // WORD cbHeaderSize; // Also zero
515 //struct MenuExHeader {
516 // WORD wVersion; // One
521 version
= GET_WORD(p
);
529 offset
= GET_WORD(p
);
532 if (!ParseMenuResource(p
))
538 offset
= GET_WORD(p
);
540 //dwHelpId = GET_DWORD(p);
541 if (!ParseMenuExResource(p0
+ offset
))
549 UnlockResource(hglMenuTemplate
);
550 FreeResource(hglMenuTemplate
);
554 UnlockResource(hglMenuTemplate
);
555 FreeResource(hglMenuTemplate
);
559 BOOL
CResModule::ReplaceMenu(LPCTSTR lpszType
, WORD wLanguage
)
561 HRSRC hrsrc
= FindResourceEx(m_hResDll
, RT_MENU
, lpszType
, wLanguage
);
562 HGLOBAL hglMenuTemplate
;
563 WORD version
, offset
;
568 MYERROR
; //just the language wasn't found
570 hglMenuTemplate
= LoadResource(m_hResDll
, hrsrc
);
572 if (!hglMenuTemplate
)
575 p
= (LPWSTR
)LockResource(hglMenuTemplate
);
580 //struct MenuHeader {
581 // WORD wVersion; // Currently zero
582 // WORD cbHeaderSize; // Also zero
586 //struct MenuExHeader {
587 // WORD wVersion; // One
592 version
= GET_WORD(p
);
600 offset
= GET_WORD(p
);
604 if (!CountMemReplaceMenuResource((WORD
*)p
, &nMem
, nullptr))
606 WORD
* newMenu
= new WORD
[nMem
+ (nMem
% 2)+2];
607 SecureZeroMemory(newMenu
, (nMem
+ (nMem
% 2)+2)*2);
608 size_t index
= 2; // MenuHeader has 2 WORDs zero
609 if (!CountMemReplaceMenuResource((WORD
*)p
, &index
, newMenu
))
615 if (!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newMenu
, (DWORD
)(nMem
+ (nMem
% 2)+2)*2))
621 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, wLanguage
, nullptr, 0)))
631 offset
= GET_WORD(p
);
633 //dwHelpId = GET_DWORD(p);
635 if (!CountMemReplaceMenuExResource((WORD
*)(p0
+ offset
), &nMem
, nullptr))
637 WORD
* newMenu
= new WORD
[nMem
+ (nMem
% 2) + 4];
638 SecureZeroMemory(newMenu
, (nMem
+ (nMem
% 2) + 4) * 2);
639 CopyMemory(newMenu
, p0
, 2 * sizeof(WORD
) + sizeof(DWORD
));
640 size_t index
= 4; // MenuExHeader has 2 x WORD + 1 x DWORD
641 if (!CountMemReplaceMenuExResource((WORD
*)(p0
+ offset
), &index
, newMenu
))
647 if (!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newMenu
, (DWORD
)(nMem
+ (nMem
% 2) + 4) * 2))
653 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, wLanguage
, nullptr, 0)))
665 UnlockResource(hglMenuTemplate
);
666 FreeResource(hglMenuTemplate
);
670 UnlockResource(hglMenuTemplate
);
671 FreeResource(hglMenuTemplate
);
675 const WORD
* CResModule::ParseMenuResource(const WORD
* res
)
680 //struct PopupMenuItem {
682 // WCHAR szItemText[];
684 //struct NormalMenuItem {
687 // WCHAR szItemText[];
692 flags
= GET_WORD(res
);
694 if (!(flags
& MF_POPUP
))
696 id
= GET_WORD(res
); //normal menu item
700 id
= (WORD
)-1; //popup menu item
702 LPCWSTR str
= (LPCWSTR
)res
;
703 size_t l
= wcslen(str
)+1;
706 if (flags
& MF_POPUP
)
708 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
709 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
711 CUtils::StringExtend(pBuf
);
713 std::wstring wstr
= std::wstring(pBuf
);
714 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
716 InsertResourceIDs(RT_MENU
, 0, entry
, id
, L
" - PopupMenu");
718 m_StringEntries
[wstr
] = entry
;
721 if ((res
= ParseMenuResource(res
))==0)
726 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
727 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
729 CUtils::StringExtend(pBuf
);
731 std::wstring wstr
= std::wstring(pBuf
);
732 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
733 InsertResourceIDs(RT_MENU
, 0, entry
, id
, L
" - Menu");
735 TCHAR szTempBuf
[1024] = { 0 };
736 swprintf(szTempBuf
, L
"#: MenuEntry; ID:%u", id
);
737 MENUENTRY menu_entry
;
739 menu_entry
.reference
= szTempBuf
;
740 menu_entry
.msgstr
= wstr
;
742 m_StringEntries
[wstr
] = entry
;
743 m_MenuEntries
[id
] = menu_entry
;
746 } while (!(flags
& MF_END
));
750 const WORD
* CResModule::CountMemReplaceMenuResource(const WORD
* res
, size_t * wordcount
, WORD
* newMenu
)
755 //struct PopupMenuItem {
757 // WCHAR szItemText[];
759 //struct NormalMenuItem {
762 // WCHAR szItemText[];
767 flags
= GET_WORD(res
);
772 newMenu
[(*wordcount
)++] = flags
;
773 if (!(flags
& MF_POPUP
))
775 id
= GET_WORD(res
); //normal menu item
780 newMenu
[(*wordcount
)++] = id
;
783 id
= (WORD
)-1; //popup menu item
785 if (flags
& MF_POPUP
)
787 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
788 res
+= wcslen((LPCWSTR
)res
) + 1;
790 if ((res
= CountMemReplaceMenuResource(res
, wordcount
, newMenu
))==0)
795 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
796 res
+= wcslen((LPCWSTR
)res
) + 1;
801 wcscpy((wchar_t *)&newMenu
[(*wordcount
)], (LPCWSTR
)res
);
802 (*wordcount
) += wcslen((LPCWSTR
)res
) + 1;
803 res
+= wcslen((LPCWSTR
)res
) + 1;
805 } while (!(flags
& MF_END
));
809 const WORD
* CResModule::ParseMenuExResource(const WORD
* res
)
813 //struct MenuExItem {
819 // DWORD dwHelpId; - Popup menu only
824 DWORD dwType
= GET_DWORD(res
);
826 //dwState = GET_DWORD(res);
828 DWORD menuId
= GET_DWORD(res
);
830 bResInfo
= GET_WORD(res
);
833 LPCWSTR str
= (LPCWSTR
)res
;
834 size_t l
= wcslen(str
)+1;
836 // Align to DWORD boundary
837 res
= AlignWORD(res
);
839 if (dwType
& MFT_SEPARATOR
)
844 // Popup menu - note this can also have a non-zero ID
847 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
848 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
850 CUtils::StringExtend(pBuf
);
852 std::wstring wstr
= std::wstring(pBuf
);
853 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
854 // Popup has a DWORD help entry on a DWORD boundary - skip over it
857 InsertResourceIDs(RT_MENU
, 0, entry
, menuId
, L
" - PopupMenuEx");
858 TCHAR szTempBuf
[1024] = { 0 };
859 swprintf(szTempBuf
, L
"#: MenuExPopupEntry; ID:%lu", menuId
);
860 MENUENTRY menu_entry
;
861 menu_entry
.wID
= (WORD
)menuId
;
862 menu_entry
.reference
= szTempBuf
;
863 menu_entry
.msgstr
= wstr
;
864 m_StringEntries
[wstr
] = entry
;
865 m_MenuEntries
[(WORD
)menuId
] = menu_entry
;
868 if ((res
= ParseMenuExResource(res
)) == 0)
870 } else if (menuId
!= 0)
872 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
873 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
875 CUtils::StringExtend(pBuf
);
877 std::wstring wstr
= std::wstring(pBuf
);
878 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
879 InsertResourceIDs(RT_MENU
, 0, entry
, menuId
, L
" - MenuEx");
881 TCHAR szTempBuf
[1024] = { 0 };
882 swprintf(szTempBuf
, L
"#: MenuExEntry; ID:%lu", menuId
);
883 MENUENTRY menu_entry
;
884 menu_entry
.wID
= (WORD
)menuId
;
885 menu_entry
.reference
= szTempBuf
;
886 menu_entry
.msgstr
= wstr
;
887 m_StringEntries
[wstr
] = entry
;
888 m_MenuEntries
[(WORD
)menuId
] = menu_entry
;
891 } while (!(bResInfo
& 0x80));
895 const WORD
* CResModule::CountMemReplaceMenuExResource(const WORD
* res
, size_t * wordcount
, WORD
* newMenu
)
899 //struct MenuExItem {
905 // DWORD dwHelpId; - Popup menu only
910 WORD
* p0
= (WORD
*)res
;
911 DWORD dwType
= GET_DWORD(res
);
913 //dwState = GET_DWORD(res);
915 DWORD menuId
= GET_DWORD(res
);
917 bResInfo
= GET_WORD(res
);
921 CopyMemory(&newMenu
[*wordcount
], p0
, 7 * sizeof(WORD
));
925 if (dwType
& MFT_SEPARATOR
) {
934 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
935 res
+= wcslen((LPCWSTR
)res
) + 1;
937 res
= AlignWORD(res
);
938 if ((*wordcount
) & 0x01)
942 CopyMemory(&newMenu
[*wordcount
], res
, sizeof(DWORD
)); // Copy Help ID
947 if ((res
= CountMemReplaceMenuExResource(res
, wordcount
, newMenu
)) == 0)
950 else if (menuId
!= 0)
952 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
953 res
+= wcslen((LPCWSTR
)res
) + 1;
958 wcscpy((wchar_t *)&newMenu
[(*wordcount
)], (LPCWSTR
)res
);
959 (*wordcount
) += wcslen((LPCWSTR
)res
) + 1;
960 res
+= wcslen((LPCWSTR
)res
) + 1;
963 res
= AlignWORD(res
);
964 if ((*wordcount
) & 0x01)
966 } while (!(bResInfo
& 0x80));
970 BOOL
CResModule::ExtractAccelerator(LPCTSTR lpszType
)
972 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_ACCELERATOR
);
974 WORD fFlags
, wAnsi
, wID
;
981 hglAccTable
= LoadResource(m_hResDll
, hrsrc
);
986 p
= (const WORD
*)LockResource(hglAccTable
);
992 struct ACCELTABLEENTRY
994 WORD fFlags; FVIRTKEY, FSHIFT, FCONTROL, FALT, 0x80 - Last in a table
995 WORD wAnsi; ANSI character
996 WORD wId; Keyboard accelerator passed to windows
997 WORD padding; # bytes added to ensure aligned to DWORD boundary
1003 fFlags
= GET_WORD(p
);
1005 wAnsi
= GET_WORD(p
);
1009 p
++; // Skip over padding
1011 if ((fFlags
& 0x80) == 0x80)
1016 if ((wAnsi
< 0x30) ||
1018 (wAnsi
>= 0x3A && wAnsi
<= 0x40))
1021 auto pBuf
= std::make_unique
<WCHAR
[]>(1024);
1022 auto pBuf2
= std::make_unique
<WCHAR
[]>(1024);
1023 SecureZeroMemory(pBuf
.get(), 1024 * sizeof(WCHAR
));
1024 SecureZeroMemory(pBuf2
.get(), 1024 * sizeof(WCHAR
));
1026 // include the menu ID in the msgid to make sure that 'duplicate'
1027 // accelerator keys are listed in the po-file.
1028 // without this, we would get entries like this:
1029 //#. Accelerator Entry for Menu ID:32809; '&Filter'
1030 //#. Accelerator Entry for Menu ID:57636; '&Find'
1031 //#: Corresponding Menu ID:32771; '&Find'
1035 // Since "filter" and "find" are most likely translated to words starting
1036 // with different letters, we need to have a separate accelerator entry
1037 // for each of those
1038 swprintf(pBuf
.get(), L
"ID:%u:", wID
);
1040 // EXACTLY 5 characters long "ACS+X"
1041 // V = Virtual key (or blank if not used)
1042 // A = Alt key (or blank if not used)
1043 // C = Ctrl key (or blank if not used)
1044 // S = Shift key (or blank if not used)
1045 // X = upper case character
1046 // e.g. "V CS+Q" == Ctrl + Shift + 'Q'
1047 if ((fFlags
& FVIRTKEY
) == FVIRTKEY
) // 0x01
1048 wcscat(pBuf
.get(), L
"V");
1050 wcscat(pBuf
.get(), L
" ");
1052 if ((fFlags
& FALT
) == FALT
) // 0x10
1053 wcscat(pBuf
.get(), L
"A");
1055 wcscat(pBuf
.get(), L
" ");
1057 if ((fFlags
& FCONTROL
) == FCONTROL
) // 0x08
1058 wcscat(pBuf
.get(), L
"C");
1060 wcscat(pBuf
.get(), L
" ");
1062 if ((fFlags
& FSHIFT
) == FSHIFT
) // 0x04
1063 wcscat(pBuf
.get(), L
"S");
1065 wcscat(pBuf
.get(), L
" ");
1067 swprintf(pBuf2
.get(), L
"%s+%c", pBuf
.get(), wAnsi
);
1069 std::wstring wstr
= std::wstring(pBuf2
.get());
1070 RESOURCEENTRY AKey_entry
= m_StringEntries
[wstr
];
1072 TCHAR szTempBuf
[1024] = { 0 };
1073 SecureZeroMemory(szTempBuf
, sizeof (szTempBuf
));
1075 pME_iter
= m_MenuEntries
.find(wID
);
1076 if (pME_iter
!= m_MenuEntries
.end())
1078 wmenu
= pME_iter
->second
.msgstr
;
1080 swprintf(szTempBuf
, L
"#. Accelerator Entry for Menu ID:%u; '%s'", wID
, wmenu
.c_str());
1081 AKey_entry
.automaticcomments
.push_back(std::wstring(szTempBuf
));
1083 m_StringEntries
[wstr
] = AKey_entry
;
1086 UnlockResource(hglAccTable
);
1087 FreeResource(hglAccTable
);
1091 UnlockResource(hglAccTable
);
1092 FreeResource(hglAccTable
);
1096 BOOL
CResModule::ReplaceAccelerator(LPCTSTR lpszType
, WORD wLanguage
)
1098 LPACCEL lpaccelNew
; // pointer to new accelerator table
1099 HACCEL haccelOld
; // handle to old accelerator table
1100 int cAccelerators
; // number of accelerators in table
1101 HGLOBAL hglAccTableNew
;
1105 haccelOld
= LoadAccelerators(m_hResDll
, lpszType
);
1110 cAccelerators
= CopyAcceleratorTable(haccelOld
, nullptr, 0);
1112 lpaccelNew
= (LPACCEL
) LocalAlloc(LPTR
, cAccelerators
* sizeof(ACCEL
));
1117 CopyAcceleratorTable(haccelOld
, lpaccelNew
, cAccelerators
);
1119 // Find the accelerator that the user modified
1120 // and change its flags and virtual-key code
1125 static const size_t BufferSize
= 1024;
1126 auto pBuf
= std::make_unique
<WCHAR
[]>(BufferSize
);
1127 auto pBuf2
= std::make_unique
<WCHAR
[]>(BufferSize
);
1128 for (i
= 0; i
< cAccelerators
; i
++)
1130 if ((lpaccelNew
[i
].key
< 0x30) ||
1131 (lpaccelNew
[i
].key
> 0x5A) ||
1132 (lpaccelNew
[i
].key
>= 0x3A && lpaccelNew
[i
].key
<= 0x40))
1135 SecureZeroMemory(pBuf
.get(), 1024 * sizeof(WCHAR
));
1136 SecureZeroMemory(pBuf2
.get(), 1024 * sizeof(WCHAR
));
1138 swprintf(pBuf
.get(), L
"ID:%d:", lpaccelNew
[i
].cmd
);
1140 // get original key combination
1141 if ((lpaccelNew
[i
].fVirt
& FVIRTKEY
) == FVIRTKEY
) // 0x01
1142 wcscat(pBuf
.get(), L
"V");
1144 wcscat(pBuf
.get(), L
" ");
1146 if ((lpaccelNew
[i
].fVirt
& FALT
) == FALT
) // 0x10
1147 wcscat(pBuf
.get(), L
"A");
1149 wcscat(pBuf
.get(), L
" ");
1151 if ((lpaccelNew
[i
].fVirt
& FCONTROL
) == FCONTROL
) // 0x08
1152 wcscat(pBuf
.get(), L
"C");
1154 wcscat(pBuf
.get(), L
" ");
1156 if ((lpaccelNew
[i
].fVirt
& FSHIFT
) == FSHIFT
) // 0x04
1157 wcscat(pBuf
.get(), L
"S");
1159 wcscat(pBuf
.get(), L
" ");
1161 swprintf(pBuf2
.get(), L
"%s+%c", pBuf
.get(), lpaccelNew
[i
].key
);
1164 std::map
<std::wstring
, RESOURCEENTRY
>::iterator pAK_iter
= m_StringEntries
.find(pBuf2
.get());
1165 if (pAK_iter
!= m_StringEntries
.end())
1167 m_bTranslatedAcceleratorStrings
++;
1170 std::wstring wtemp
= pAK_iter
->second
.msgstr
;
1171 wtemp
= wtemp
.substr(wtemp
.find_last_of(':')+1);
1172 if (wtemp
.size() != 6)
1174 if (wtemp
.compare(0, 1, L
"V") == 0)
1176 else if (wtemp
.compare(0, 1, L
" ") != 0)
1177 continue; // not a space - user must have made a mistake when translating
1178 if (wtemp
.compare(1, 1, L
"A") == 0)
1180 else if (wtemp
.compare(1, 1, L
" ") != 0)
1181 continue; // not a space - user must have made a mistake when translating
1182 if (wtemp
.compare(2, 1, L
"C") == 0)
1184 else if (wtemp
.compare(2, 1, L
" ") != 0)
1185 continue; // not a space - user must have made a mistake when translating
1186 if (wtemp
.compare(3, 1, L
"S") == 0)
1188 else if (wtemp
.compare(3, 1, L
" ") != 0)
1189 continue; // not a space - user must have made a mistake when translating
1190 if (wtemp
.compare(4, 1, L
"+") == 0)
1192 swscanf(wtemp
.substr(5, 1).c_str(), L
"%c", &xkey
);
1193 lpaccelNew
[i
].fVirt
= xfVirt
;
1194 lpaccelNew
[i
].key
= (DWORD
)xkey
;
1198 m_bDefaultAcceleratorStrings
++;
1202 // Create the new accelerator table
1203 hglAccTableNew
= LocalAlloc(LPTR
, cAccelerators
* 4 * sizeof(WORD
));
1204 if (!hglAccTableNew
)
1206 p
= (WORD
*)hglAccTableNew
;
1207 lpaccelNew
[cAccelerators
-1].fVirt
|= 0x80;
1208 for (i
= 0; i
< cAccelerators
; i
++)
1210 memcpy((void *)p
, &lpaccelNew
[i
].fVirt
, 1);
1212 memcpy((void *)p
, &lpaccelNew
[i
].key
, sizeof(WORD
));
1214 memcpy((void *)p
, &lpaccelNew
[i
].cmd
, sizeof(WORD
));
1219 if (!UpdateResource(m_hUpdateRes
, RT_ACCELERATOR
, lpszType
,
1220 (m_wTargetLang
? m_wTargetLang
: wLanguage
), hglAccTableNew
/* haccelNew*/, cAccelerators
* 4 * sizeof(WORD
)))
1225 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_ACCELERATOR
, lpszType
, wLanguage
, nullptr, 0)))
1230 LocalFree(hglAccTableNew
);
1231 LocalFree(lpaccelNew
);
1235 LocalFree(hglAccTableNew
);
1236 LocalFree(lpaccelNew
);
1240 BOOL
CResModule::ExtractDialog(LPCTSTR lpszType
)
1243 const WORD
* lpDlgItem
;
1245 DLGITEMINFO dlgItem
;
1248 HGLOBAL hGlblDlgTemplate
;
1250 hrsrc
= FindResource(m_hResDll
, lpszType
, RT_DIALOG
);
1255 hGlblDlgTemplate
= LoadResource(m_hResDll
, hrsrc
);
1256 if (!hGlblDlgTemplate
)
1259 lpDlg
= (const WORD
*) LockResource(hGlblDlgTemplate
);
1264 lpDlgItem
= (const WORD
*) GetDialogInfo(lpDlg
, &dlg
);
1265 bNumControls
= dlg
.nbItems
;
1269 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
1270 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
1271 wcscpy(pBuf
, dlg
.caption
);
1272 CUtils::StringExtend(pBuf
);
1274 std::wstring wstr
= std::wstring(pBuf
);
1275 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
1276 InsertResourceIDs(RT_DIALOG
, (INT_PTR
)lpszType
, entry
, (INT_PTR
)lpszType
, L
"");
1278 m_StringEntries
[wstr
] = entry
;
1282 while (bNumControls
-- != 0)
1284 TCHAR szTitle
[500] = { 0 };
1285 SecureZeroMemory(szTitle
, sizeof(szTitle
));
1288 lpDlgItem
= GetControlInfo((WORD
*) lpDlgItem
, &dlgItem
, dlg
.dialogEx
, &bCode
);
1291 wcsncpy(szTitle
, dlgItem
.windowName
, _countof(szTitle
) - 1);
1295 CUtils::StringExtend(szTitle
);
1297 std::wstring wstr
= std::wstring(szTitle
);
1298 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
1299 InsertResourceIDs(RT_DIALOG
, (INT_PTR
)lpszType
, entry
, dlgItem
.id
, L
"");
1301 m_StringEntries
[wstr
] = entry
;
1305 UnlockResource(hGlblDlgTemplate
);
1306 FreeResource(hGlblDlgTemplate
);
1310 BOOL
CResModule::ReplaceDialog(LPCTSTR lpszType
, WORD wLanguage
)
1314 HGLOBAL hGlblDlgTemplate
;
1316 hrsrc
= FindResourceEx(m_hResDll
, RT_DIALOG
, lpszType
, wLanguage
);
1321 hGlblDlgTemplate
= LoadResource(m_hResDll
, hrsrc
);
1323 if (!hGlblDlgTemplate
)
1326 lpDlg
= (WORD
*) LockResource(hGlblDlgTemplate
);
1332 const WORD
* p
= lpDlg
;
1333 if (!CountMemReplaceDialogResource(p
, &nMem
, nullptr))
1335 WORD
* newDialog
= new WORD
[nMem
+ (nMem
% 2)];
1336 SecureZeroMemory(newDialog
, (nMem
+ (nMem
% 2))*2);
1339 if (!CountMemReplaceDialogResource(lpDlg
, &index
, newDialog
))
1341 delete [] newDialog
;
1345 if (!UpdateResource(m_hUpdateRes
, RT_DIALOG
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newDialog
, (DWORD
)(nMem
+ (nMem
% 2))*2))
1347 delete [] newDialog
;
1351 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_DIALOG
, lpszType
, wLanguage
, nullptr, 0)))
1353 delete [] newDialog
;
1357 delete [] newDialog
;
1358 UnlockResource(hGlblDlgTemplate
);
1359 FreeResource(hGlblDlgTemplate
);
1363 UnlockResource(hGlblDlgTemplate
);
1364 FreeResource(hGlblDlgTemplate
);
1368 const WORD
* CResModule::GetDialogInfo(const WORD
* pTemplate
, LPDIALOGINFO lpDlgInfo
) const
1370 const WORD
* p
= (const WORD
*)pTemplate
;
1372 lpDlgInfo
->style
= GET_DWORD(p
);
1375 if (lpDlgInfo
->style
== 0xffff0001) // DIALOGEX resource
1377 lpDlgInfo
->dialogEx
= TRUE
;
1378 lpDlgInfo
->helpId
= GET_DWORD(p
);
1380 lpDlgInfo
->exStyle
= GET_DWORD(p
);
1382 lpDlgInfo
->style
= GET_DWORD(p
);
1387 lpDlgInfo
->dialogEx
= FALSE
;
1388 lpDlgInfo
->helpId
= 0;
1389 lpDlgInfo
->exStyle
= GET_DWORD(p
);
1393 lpDlgInfo
->nbItems
= GET_WORD(p
);
1396 lpDlgInfo
->x
= GET_WORD(p
);
1399 lpDlgInfo
->y
= GET_WORD(p
);
1402 lpDlgInfo
->cx
= GET_WORD(p
);
1405 lpDlgInfo
->cy
= GET_WORD(p
);
1408 // Get the menu name
1410 switch (GET_WORD(p
))
1413 lpDlgInfo
->menuName
= nullptr;
1417 lpDlgInfo
->menuName
= (LPCTSTR
) (WORD
) GET_WORD(p
+ 1);
1421 lpDlgInfo
->menuName
= (LPCTSTR
) p
;
1422 p
+= wcslen((LPCWSTR
) p
) + 1;
1426 // Get the class name
1428 switch (GET_WORD(p
))
1431 lpDlgInfo
->className
= (LPCTSTR
)MAKEINTATOM(32770);
1435 lpDlgInfo
->className
= (LPCTSTR
) (WORD
) GET_WORD(p
+ 1);
1439 lpDlgInfo
->className
= (LPCTSTR
) p
;
1440 p
+= wcslen((LPCTSTR
)p
) + 1;
1444 // Get the window caption
1446 lpDlgInfo
->caption
= (LPCTSTR
)p
;
1447 p
+= wcslen((LPCWSTR
) p
) + 1;
1449 // Get the font name
1451 if (lpDlgInfo
->style
& DS_SETFONT
)
1453 lpDlgInfo
->pointSize
= GET_WORD(p
);
1456 if (lpDlgInfo
->dialogEx
)
1458 lpDlgInfo
->weight
= GET_WORD(p
);
1460 lpDlgInfo
->italic
= LOBYTE(GET_WORD(p
));
1465 lpDlgInfo
->weight
= FW_DONTCARE
;
1466 lpDlgInfo
->italic
= FALSE
;
1469 lpDlgInfo
->faceName
= (LPCTSTR
)p
;
1470 p
+= wcslen((LPCWSTR
) p
) + 1;
1472 // First control is on DWORD boundary
1478 const WORD
* CResModule::GetControlInfo(const WORD
* p
, LPDLGITEMINFO lpDlgItemInfo
, BOOL dialogEx
, LPBOOL bIsID
) const
1482 lpDlgItemInfo
->helpId
= GET_DWORD(p
);
1484 lpDlgItemInfo
->exStyle
= GET_DWORD(p
);
1486 lpDlgItemInfo
->style
= GET_DWORD(p
);
1491 lpDlgItemInfo
->helpId
= 0;
1492 lpDlgItemInfo
->style
= GET_DWORD(p
);
1494 lpDlgItemInfo
->exStyle
= GET_DWORD(p
);
1498 lpDlgItemInfo
->x
= GET_WORD(p
);
1501 lpDlgItemInfo
->y
= GET_WORD(p
);
1504 lpDlgItemInfo
->cx
= GET_WORD(p
);
1507 lpDlgItemInfo
->cy
= GET_WORD(p
);
1512 // ID is a DWORD for DIALOGEX
1513 lpDlgItemInfo
->id
= (WORD
) GET_DWORD(p
);
1518 lpDlgItemInfo
->id
= GET_WORD(p
);
1522 if (GET_WORD(p
) == 0xffff)
1530 lpDlgItemInfo
->className
= (LPCTSTR
) p
;
1531 p
+= wcslen((LPCWSTR
) p
) + 1;
1534 if (GET_WORD(p
) == 0xffff) // an integer ID?
1537 lpDlgItemInfo
->windowName
= (LPCTSTR
) (UINT_PTR
) GET_WORD(p
+ 1);
1543 lpDlgItemInfo
->windowName
= (LPCTSTR
) p
;
1544 p
+= wcslen((LPCWSTR
) p
) + 1;
1549 lpDlgItemInfo
->data
= (LPVOID
) (p
+ 1);
1550 p
+= GET_WORD(p
) / sizeof(WORD
);
1553 lpDlgItemInfo
->data
= nullptr;
1556 // Next control is on DWORD boundary
1561 const WORD
* CResModule::CountMemReplaceDialogResource(const WORD
* res
, size_t * wordcount
, WORD
* newDialog
)
1564 DWORD style
= GET_DWORD(res
);
1567 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1568 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1576 if (style
== 0xffff0001) // DIALOGEX resource
1581 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //help id
1582 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //help id
1583 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1584 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1585 style
= GET_DWORD(res
);
1586 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1587 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1592 style
= GET_DWORD(res
);
1602 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1603 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1604 //style = GET_DWORD(res);
1605 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1606 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1616 newDialog
[(*wordcount
)] = GET_WORD(res
);
1617 WORD nbItems
= GET_WORD(res
);
1622 newDialog
[(*wordcount
)] = GET_WORD(res
); //x
1627 newDialog
[(*wordcount
)] = GET_WORD(res
); //y
1632 newDialog
[(*wordcount
)] = GET_WORD(res
); //cx
1637 newDialog
[(*wordcount
)] = GET_WORD(res
); //cy
1641 // Get the menu name
1643 switch (GET_WORD(res
))
1647 newDialog
[(*wordcount
)] = GET_WORD(res
);
1654 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1655 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1666 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1668 (*wordcount
) += wcslen((LPCWSTR
) res
) + 1;
1669 res
+= wcslen((LPCWSTR
) res
) + 1;
1673 // Get the class name
1675 switch (GET_WORD(res
))
1679 newDialog
[(*wordcount
)] = GET_WORD(res
);
1686 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1687 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1698 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1700 (*wordcount
) += wcslen((LPCWSTR
) res
) + 1;
1701 res
+= wcslen((LPCWSTR
) res
) + 1;
1705 // Get the window caption
1707 ReplaceStr((LPCWSTR
)res
, newDialog
, wordcount
, &m_bTranslatedDialogStrings
, &m_bDefaultDialogStrings
);
1708 res
+= wcslen((LPCWSTR
)res
) + 1;
1710 // Get the font name
1712 if (style
& DS_SETFONT
)
1715 newDialog
[(*wordcount
)] = GET_WORD(res
);
1723 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1724 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1734 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1735 (*wordcount
) += wcslen((LPCWSTR
)res
) + 1;
1736 res
+= wcslen((LPCWSTR
)res
) + 1;
1738 // First control is on DWORD boundary
1739 while ((*wordcount
)%2)
1741 while ((UINT_PTR
)res
% 4)
1746 res
= ReplaceControlInfo(res
, wordcount
, newDialog
, bEx
);
1751 const WORD
* CResModule::ReplaceControlInfo(const WORD
* res
, size_t * wordcount
, WORD
* newDialog
, BOOL bEx
)
1757 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //helpid
1758 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //helpid
1768 LONG
* exStyle
= (LONG
*)&newDialog
[(*wordcount
)];
1769 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1770 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1772 *exStyle
|= WS_EX_RTLREADING
;
1782 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1783 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1792 newDialog
[(*wordcount
)] = GET_WORD(res
); //x
1797 newDialog
[(*wordcount
)] = GET_WORD(res
); //y
1802 newDialog
[(*wordcount
)] = GET_WORD(res
); //cx
1807 newDialog
[(*wordcount
)] = GET_WORD(res
); //cy
1813 // ID is a DWORD for DIALOGEX
1816 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1817 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1828 newDialog
[(*wordcount
)] = GET_WORD(res
);
1833 if (GET_WORD(res
) == 0xffff) //classID
1837 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1838 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1849 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1850 (*wordcount
) += wcslen((LPCWSTR
) res
) + 1;
1851 res
+= wcslen((LPCWSTR
) res
) + 1;
1854 if (GET_WORD(res
) == 0xffff) // an integer ID?
1858 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1859 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1869 ReplaceStr((LPCWSTR
)res
, newDialog
, wordcount
, &m_bTranslatedDialogStrings
, &m_bDefaultDialogStrings
);
1870 res
+= wcslen((LPCWSTR
)res
) + 1;
1874 memcpy(&newDialog
[(*wordcount
)], res
, (GET_WORD(res
)+1)*sizeof(WORD
));
1875 (*wordcount
) += (GET_WORD(res
)+1);
1876 res
+= (GET_WORD(res
)+1);
1877 // Next control is on DWORD boundary
1878 while ((*wordcount
) % 2)
1880 res
= AlignWORD(res
);
1885 BOOL
CResModule::ExtractRibbon(LPCTSTR lpszType
)
1887 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_RIBBON
);
1888 HGLOBAL hglRibbonTemplate
;
1894 hglRibbonTemplate
= LoadResource(m_hResDll
, hrsrc
);
1896 DWORD sizeres
= SizeofResource(m_hResDll
, hrsrc
);
1898 if (!hglRibbonTemplate
)
1901 p
= (const BYTE
*)LockResource(hglRibbonTemplate
);
1906 // Resource consists of one single string
1909 // extract all <id><name>blah1</name><value>blah2</value></id><text>blah</text> elements
1911 const std::regex
regRevMatch("<ID><NAME>([^<]+)</NAME><VALUE>([^<]+)</VALUE></ID><TEXT>([^<]+)</TEXT>");
1912 std::string ss
= std::string((const char*)p
, sizeres
);
1913 const std::sregex_iterator end
;
1914 for (std::sregex_iterator
it(ss
.cbegin(), ss
.cend(), regRevMatch
); it
!= end
; ++it
)
1918 std::string str1
= (*it
)[1];
1920 auto bufw1
= std::make_unique
<wchar_t[]>(len
* 4 + 1);
1921 SecureZeroMemory(bufw1
.get(), (len
* 4 + 1) * sizeof(wchar_t));
1922 MultiByteToWideChar(CP_UTF8
, 0, str1
.c_str(), -1, bufw1
.get(), (int)len
* 4);
1923 std::wstring strIdNameVal
= bufw1
.get();
1924 strIdNameVal
+= L
" - Ribbon name";
1926 std::string str2
= (*it
)[2];
1928 auto bufw2
= std::make_unique
<wchar_t[]>(len
* 4 + 1);
1929 SecureZeroMemory(bufw2
.get(), (len
* 4 + 1)*sizeof(wchar_t));
1930 MultiByteToWideChar(CP_UTF8
, 0, str2
.c_str(), -1, bufw2
.get(), (int)len
* 4);
1931 std::wstring strIdVal
= bufw2
.get();
1933 std::string str3
= (*it
)[3];
1935 auto bufw3
= std::make_unique
<wchar_t[]>(len
* 4 + 1);
1936 SecureZeroMemory(bufw3
.get(), (len
* 4 + 1)*sizeof(wchar_t));
1937 MultiByteToWideChar(CP_UTF8
, 0, str3
.c_str(), -1, bufw3
.get(), (int)len
* 4);
1938 std::wstring str
= bufw3
.get();
1940 RESOURCEENTRY entry
= m_StringEntries
[str
];
1941 InsertResourceIDs(RT_RIBBON
, 0, entry
, std::stoi(strIdVal
), strIdNameVal
.c_str());
1942 if (wcschr(str
.c_str(), '%'))
1943 entry
.flag
= L
"#, c-format";
1944 m_StringEntries
[str
] = entry
;
1945 m_bDefaultRibbonTexts
++;
1948 // extract all </ELEMENT_NAME><NAME>blahblah</NAME> elements
1950 const std::regex
regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
1951 for (std::sregex_iterator
it(ss
.cbegin(), ss
.cend(), regRevMatchName
); it
!= end
; ++it
)
1953 std::string str
= (*it
)[1];
1954 size_t len
= str
.size();
1955 auto bufw
= std::make_unique
<wchar_t[]>(len
* 4 + 1);
1956 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1957 MultiByteToWideChar(CP_UTF8
, 0, str
.c_str(), -1, bufw
.get(), (int)len
*4);
1958 std::wstring ret
= bufw
.get();
1959 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1960 InsertResourceIDs(RT_RIBBON
, 0, entry
, (INT_PTR
)lpszType
, L
" - Ribbon element");
1961 if (wcschr(ret
.c_str(), '%'))
1962 entry
.flag
= L
"#, c-format";
1963 m_StringEntries
[ret
] = entry
;
1964 m_bDefaultRibbonTexts
++;
1967 UnlockResource(hglRibbonTemplate
);
1968 FreeResource(hglRibbonTemplate
);
1972 BOOL
CResModule::ReplaceRibbon(LPCTSTR lpszType
, WORD wLanguage
)
1974 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_RIBBON
);
1975 HGLOBAL hglRibbonTemplate
;
1981 hglRibbonTemplate
= LoadResource(m_hResDll
, hrsrc
);
1983 DWORD sizeres
= SizeofResource(m_hResDll
, hrsrc
);
1985 if (!hglRibbonTemplate
)
1988 p
= (const BYTE
*)LockResource(hglRibbonTemplate
);
1993 std::string ss
= std::string((const char*)p
, sizeres
);
1994 size_t len
= ss
.size();
1995 auto bufw
= std::make_unique
<wchar_t[]>(len
* 4 + 1);
1996 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1997 MultiByteToWideChar(CP_UTF8
, 0, ss
.c_str(), -1, bufw
.get(), (int)len
*4);
1998 std::wstring ssw
= bufw
.get();
2001 const std::regex
regRevMatch("<TEXT>([^<]+)</TEXT>");
2002 const std::sregex_iterator end
;
2003 for (std::sregex_iterator
it(ss
.cbegin(), ss
.cend(), regRevMatch
); it
!= end
; ++it
)
2005 std::string str
= (*it
)[1];
2006 size_t slen
= str
.size();
2007 auto bufw2
= std::make_unique
<wchar_t[]>(slen
* 4 + 1);
2008 SecureZeroMemory(bufw2
.get(), (slen
*4 + 1)*sizeof(wchar_t));
2009 MultiByteToWideChar(CP_UTF8
, 0, str
.c_str(), -1, bufw2
.get(), (int)slen
*4);
2010 std::wstring ret
= bufw2
.get();
2012 RESOURCEENTRY entry
= m_StringEntries
[ret
];
2013 ret
= L
"<TEXT>" + ret
+ L
"</TEXT>";
2015 if (entry
.msgstr
.size())
2017 auto sbuf
= std::make_unique
<wchar_t[]>(entry
.msgstr
.size() + 10);
2018 wcscpy(sbuf
.get(), entry
.msgstr
.c_str());
2019 CUtils::StringCollapse(sbuf
.get());
2020 ReplaceWithRegex(sbuf
.get());
2021 std::wstring sreplace
= L
"<TEXT>";
2022 sreplace
+= sbuf
.get();
2023 sreplace
+= L
"</TEXT>";
2024 CUtils::SearchReplace(ssw
, ret
, sreplace
);
2025 m_bTranslatedRibbonTexts
++;
2028 m_bDefaultRibbonTexts
++;
2031 const std::regex
regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
2032 for (std::sregex_iterator
it(ss
.cbegin(), ss
.cend(), regRevMatchName
); it
!= end
; ++it
)
2034 std::string str
= (*it
)[1];
2035 size_t slen
= str
.size();
2036 auto bufw2
= std::make_unique
<wchar_t[]>(slen
* 4 + 1);
2037 SecureZeroMemory(bufw2
.get(), (slen
*4 + 1)*sizeof(wchar_t));
2038 MultiByteToWideChar(CP_UTF8
, 0, str
.c_str(), -1, bufw2
.get(), (int)slen
*4);
2039 std::wstring ret
= bufw2
.get();
2041 RESOURCEENTRY entry
= m_StringEntries
[ret
];
2042 ret
= L
"</ELEMENT_NAME><NAME>" + ret
+ L
"</NAME>";
2044 if (entry
.msgstr
.size())
2046 auto sbuf
= std::make_unique
<wchar_t[]>(entry
.msgstr
.size() + 10);
2047 wcscpy(sbuf
.get(), entry
.msgstr
.c_str());
2048 CUtils::StringCollapse(sbuf
.get());
2049 ReplaceWithRegex(sbuf
.get());
2050 std::wstring sreplace
= L
"</ELEMENT_NAME><NAME>";
2051 sreplace
+= sbuf
.get();
2052 sreplace
+= L
"</NAME>";
2053 CUtils::SearchReplace(ssw
, ret
, sreplace
);
2054 m_bTranslatedRibbonTexts
++;
2057 m_bDefaultRibbonTexts
++;
2060 auto buf
= std::make_unique
<char[]>(ssw
.size() * 4 + 1);
2061 int lengthIncTerminator
= WideCharToMultiByte(CP_UTF8
, 0, ssw
.c_str(), -1, buf
.get(), (int)len
* 4, nullptr, nullptr);
2064 if (!UpdateResource(m_hUpdateRes
, RT_RIBBON
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), buf
.get(), lengthIncTerminator
-1))
2069 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_RIBBON
, lpszType
, wLanguage
, nullptr, 0)))
2075 UnlockResource(hglRibbonTemplate
);
2076 FreeResource(hglRibbonTemplate
);
2080 UnlockResource(hglRibbonTemplate
);
2081 FreeResource(hglRibbonTemplate
);
2085 std::wstring
CResModule::ReplaceWithRegex(WCHAR
* pBuf
)
2087 for (const auto& t
: m_StringEntries
.m_regexes
)
2091 std::wregex
e(std::get
<0>(t
), std::regex_constants::icase
);
2092 auto replaced
= std::regex_replace(pBuf
, e
, std::get
<1>(t
));
2093 wcscpy(pBuf
, replaced
.c_str());
2095 catch (std::exception
&)
2102 std::wstring
CResModule::ReplaceWithRegex(std::wstring
& s
)
2104 for (const auto& t
: m_StringEntries
.m_regexes
)
2108 std::wregex
e(std::get
<0>(t
), std::regex_constants::icase
);
2109 auto replaced
= std::regex_replace(s
, e
, std::get
<1>(t
));
2112 catch (std::exception
&)
2119 BOOL CALLBACK
CResModule::EnumResNameCallback(HMODULE
/*hModule*/, LPCTSTR lpszType
, LPTSTR lpszName
, LONG_PTR lParam
)
2121 auto lpResModule
= reinterpret_cast<CResModule
*>(lParam
);
2123 if (lpszType
== RT_STRING
)
2125 if (IS_INTRESOURCE(lpszName
))
2127 if (!lpResModule
->ExtractString(lpszName
))
2131 else if (lpszType
== RT_MENU
)
2133 if (IS_INTRESOURCE(lpszName
))
2135 if (!lpResModule
->ExtractMenu(lpszName
))
2139 else if (lpszType
== RT_DIALOG
)
2141 if (IS_INTRESOURCE(lpszName
))
2143 if (!lpResModule
->ExtractDialog(lpszName
))
2147 else if (lpszType
== RT_ACCELERATOR
)
2149 if (IS_INTRESOURCE(lpszName
))
2151 if (!lpResModule
->ExtractAccelerator(lpszName
))
2155 else if (lpszType
== RT_RIBBON
)
2157 if (IS_INTRESOURCE(lpszName
))
2159 if (!lpResModule
->ExtractRibbon(lpszName
))
2167 #pragma warning(push)
2168 #pragma warning(disable: 4189)
2169 BOOL CALLBACK
CResModule::EnumResNameWriteCallback(HMODULE hModule
, LPCTSTR lpszType
, LPTSTR lpszName
, LONG_PTR lParam
)
2171 auto lpResModule
= reinterpret_cast<CResModule
*>(lParam
);
2172 return EnumResourceLanguages(hModule
, lpszType
, lpszName
, (ENUMRESLANGPROC
)&lpResModule
->EnumResWriteLangCallback
, lParam
);
2174 #pragma warning(pop)
2176 BOOL CALLBACK
CResModule::EnumResWriteLangCallback(HMODULE
/*hModule*/, LPCTSTR lpszType
, LPTSTR lpszName
, WORD wLanguage
, LONG_PTR lParam
)
2179 auto lpResModule
= reinterpret_cast<CResModule
*>(lParam
);
2181 if (lpszType
== RT_STRING
)
2183 bRes
= lpResModule
->ReplaceString(lpszName
, wLanguage
);
2185 else if (lpszType
== RT_MENU
)
2187 bRes
= lpResModule
->ReplaceMenu(lpszName
, wLanguage
);
2189 else if (lpszType
== RT_DIALOG
)
2191 bRes
= lpResModule
->ReplaceDialog(lpszName
, wLanguage
);
2193 else if (lpszType
== RT_ACCELERATOR
)
2195 bRes
= lpResModule
->ReplaceAccelerator(lpszName
, wLanguage
);
2197 else if (lpszType
== RT_RIBBON
)
2199 bRes
= lpResModule
->ReplaceRibbon(lpszName
, wLanguage
);
2206 void CResModule::ReplaceStr(LPCWSTR src
, WORD
* dest
, size_t * count
, int * translated
, int * def
)
2208 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
2209 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
2211 CUtils::StringExtend(pBuf
);
2213 std::wstring wstr
= std::wstring(pBuf
);
2214 ReplaceWithRegex(pBuf
);
2215 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
2216 if (!entry
.msgstr
.empty())
2218 wcscpy(pBuf
, entry
.msgstr
.c_str());
2219 ReplaceWithRegex(pBuf
);
2220 CUtils::StringCollapse(pBuf
);
2222 wcscpy((wchar_t *)&dest
[(*count
)], pBuf
);
2223 (*count
) += wcslen(pBuf
)+1;
2228 if (wcscmp(pBuf
, wstr
.c_str()))
2231 wcscpy((wchar_t*)&dest
[(*count
)], pBuf
);
2232 (*count
) += wcslen(pBuf
) + 1;
2238 wcscpy((wchar_t*)&dest
[(*count
)], src
);
2239 (*count
) += wcslen(src
) + 1;
2247 static bool StartsWith(const std::string
& heystacl
, const char* needle
)
2249 return heystacl
.compare(0, strlen(needle
), needle
) == 0;
2252 static bool StartsWith(const std::wstring
& heystacl
, const wchar_t* needle
)
2254 return heystacl
.compare(0, wcslen(needle
), needle
) == 0;
2257 size_t CResModule::ScanHeaderFile(const std::wstring
& filepath
)
2261 // open the file and read the contents
2262 DWORD reqLen
= GetFullPathName(filepath
.c_str(), 0, nullptr, nullptr);
2263 auto wcfullPath
= std::make_unique
<TCHAR
[]>(reqLen
+ 1);
2264 GetFullPathName(filepath
.c_str(), reqLen
, wcfullPath
.get(), nullptr);
2265 std::wstring fullpath
= wcfullPath
.get();
2268 // first treat the file as ASCII and try to get the defines
2270 std::ifstream
fin(fullpath
);
2271 std::string file_line
;
2272 while (std::getline(fin
, file_line
))
2274 auto defpos
= file_line
.find("#define");
2275 if (defpos
!= std::string::npos
)
2277 std::string text
= file_line
.substr(defpos
+ 7);
2279 auto spacepos
= text
.find(' ');
2280 if (spacepos
== std::string::npos
)
2281 spacepos
= text
.find('\t');
2282 if (spacepos
!= std::string::npos
)
2284 auto value
= atol(text
.substr(spacepos
).c_str());
2285 if (value
== 0 && text
.substr(spacepos
).find("0x") != std::string::npos
)
2286 value
= std::stoul(text
.substr(spacepos
), nullptr, 16);
2287 text
= text
.substr(0, spacepos
);
2289 if (StartsWith(text
, "IDS_") || StartsWith(text
, "AFX_IDS_") || StartsWith(text
, "AFX_IDP_"))
2291 m_currentHeaderDataStrings
[value
] = CUnicodeUtils::StdGetUnicode(text
);
2294 else if (StartsWith(text
, "IDD_") || StartsWith(text
, "AFX_IDD_"))
2296 m_currentHeaderDataDialogs
[value
] = CUnicodeUtils::StdGetUnicode(text
);
2299 else if (StartsWith(text
, "ID_") || StartsWith(text
, "AFX_ID_"))
2301 m_currentHeaderDataMenus
[value
] = CUnicodeUtils::StdGetUnicode(text
);
2304 else if (StartsWith(text
, "cmd"))
2306 m_currentHeaderDataStrings
[value
] = CUnicodeUtils::StdGetUnicode(text
);
2309 else if (text
.find("_RESID") != std::string::npos
)
2311 m_currentHeaderDataStrings
[value
] = CUnicodeUtils::StdGetUnicode(text
);
2320 // now try the same with the file treated as utf16
2322 // open as a byte stream
2323 std::wifstream
wfin(fullpath
, std::ios::binary
);
2324 // apply BOM-sensitive UTF-16 facet
2325 wfin
.imbue(std::locale(wfin
.getloc(), new std::codecvt_utf16
<wchar_t, 0x10ffff, std::consume_header
>));
2326 //std::wifstream wfin(fullpath);
2327 std::wstring wfile_line
;
2328 while (std::getline(wfin
, wfile_line
))
2330 auto defpos
= wfile_line
.find(L
"#define");
2331 if (defpos
!= std::wstring::npos
)
2333 std::wstring text
= wfile_line
.substr(defpos
+ 7);
2335 auto spacepos
= text
.find(' ');
2336 if (spacepos
== std::wstring::npos
)
2337 spacepos
= text
.find('\t');
2338 if (spacepos
!= std::wstring::npos
)
2340 auto value
= _wtol(text
.substr(spacepos
).c_str());
2341 if (value
== 0 && text
.substr(spacepos
).find(L
"0x") != std::wstring::npos
)
2342 value
= std::stoul(text
.substr(spacepos
), nullptr, 16);
2343 text
= text
.substr(0, spacepos
);
2345 if (StartsWith(text
, L
"IDS_") || StartsWith(text
, L
"AFX_IDS_") || StartsWith(text
, L
"AFX_IDP_"))
2347 m_currentHeaderDataStrings
[value
] = text
;
2350 else if (StartsWith(text
, L
"IDD_") || StartsWith(text
, L
"AFX_IDD_"))
2352 m_currentHeaderDataDialogs
[value
] = text
;
2355 else if (StartsWith(text
, L
"ID_") || StartsWith(text
, L
"AFX_ID_"))
2357 m_currentHeaderDataMenus
[value
] = text
;
2360 else if (StartsWith(text
, L
"cmd"))
2362 m_currentHeaderDataStrings
[value
] = text
;
2365 else if (text
.find(L
"_RESID") != std::string::npos
)
2367 m_currentHeaderDataStrings
[value
] = text
;
2378 void CResModule::InsertResourceIDs(LPCWSTR lpType
, INT_PTR mainId
, RESOURCEENTRY
& entry
, INT_PTR id
, LPCWSTR infotext
)
2380 if (lpType
== RT_DIALOG
)
2382 auto foundIt
= m_currentHeaderDataDialogs
.find(mainId
);
2383 if (foundIt
!= m_currentHeaderDataDialogs
.end())
2384 entry
.resourceIDs
.insert(L
"Dialog " + foundIt
->second
+ L
": Control id " + NumToStr(id
) + infotext
);
2386 entry
.resourceIDs
.insert(NumToStr(id
) + infotext
);
2388 else if (lpType
== RT_STRING
)
2390 auto foundIt
= m_currentHeaderDataStrings
.find(id
);
2391 if (foundIt
!= m_currentHeaderDataStrings
.end())
2392 entry
.resourceIDs
.insert(foundIt
->second
+ infotext
);
2394 entry
.resourceIDs
.insert(NumToStr(id
) + infotext
);
2396 else if (lpType
== RT_MENU
)
2398 auto foundIt
= m_currentHeaderDataMenus
.find(id
);
2399 if (foundIt
!= m_currentHeaderDataMenus
.end())
2400 entry
.resourceIDs
.insert(foundIt
->second
+ infotext
);
2402 entry
.resourceIDs
.insert(NumToStr(id
) + infotext
);
2404 else if (lpType
== RT_RIBBON
&& infotext
&& wcsstr(infotext
, L
"ID") == infotext
)
2405 entry
.resourceIDs
.insert(infotext
);
2407 entry
.resourceIDs
.insert(NumToStr(id
) + infotext
);
2410 bool CResModule::AdjustCheckSum(const std::wstring
& resFile
)
2412 HANDLE hFile
= INVALID_HANDLE_VALUE
;
2413 HANDLE hFileMapping
= nullptr;
2414 PVOID pBaseAddress
= nullptr;
2418 hFile
= CreateFile(resFile
.c_str(), FILE_READ_DATA
| FILE_WRITE_DATA
, 0, nullptr, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, nullptr);
2419 if (hFile
== INVALID_HANDLE_VALUE
)
2420 throw GetLastError();
2422 hFileMapping
= CreateFileMapping(hFile
, nullptr, PAGE_READWRITE
, 0, 0, nullptr);
2424 throw GetLastError();
2426 pBaseAddress
= MapViewOfFile(hFileMapping
, FILE_MAP_ALL_ACCESS
, 0, 0, 0);
2428 throw GetLastError();
2430 auto fileSize
= GetFileSize(hFile
, nullptr);
2431 if (fileSize
== INVALID_FILE_SIZE
)
2432 throw GetLastError();
2433 DWORD dwChecksum
= 0;
2434 DWORD dwHeaderSum
= 0;
2435 CheckSumMappedFile(pBaseAddress
, fileSize
, &dwHeaderSum
, &dwChecksum
);
2437 PIMAGE_DOS_HEADER pDOSHeader
= static_cast<PIMAGE_DOS_HEADER
>(pBaseAddress
);
2438 if (pDOSHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
2439 throw GetLastError();
2441 PIMAGE_NT_HEADERS pNTHeader
= reinterpret_cast<PIMAGE_NT_HEADERS
>((PBYTE
)pBaseAddress
+ pDOSHeader
->e_lfanew
);
2442 if (pNTHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
2443 throw GetLastError();
2445 SetLastError(ERROR_SUCCESS
);
2447 DWORD
* pChecksum
= &(pNTHeader
->OptionalHeader
.CheckSum
);
2448 *pChecksum
= dwChecksum
;
2450 UnmapViewOfFile(pBaseAddress
);
2451 CloseHandle(hFileMapping
);
2457 UnmapViewOfFile(pBaseAddress
);
2459 CloseHandle(hFileMapping
);
2460 if (hFile
!= INVALID_HANDLE_VALUE
)