1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2015-2022 - TortoiseGit
4 // Copyright (C) 2003-2008, 2010-2017, 2019 - 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.
20 #include "scope_exit_noexcept.h"
22 #include "UnicodeUtils.h"
23 #include "ResModule.h"
35 #pragma comment(lib, "Imagehlp.lib")
38 #define RT_RIBBON MAKEINTRESOURCE(28)
42 #define MYERROR {CUtils::Error(); return FALSE;}
44 static const WORD
* AlignWORD(const WORD
* pWord
)
46 const WORD
* res
= pWord
;
47 res
+= (((reinterpret_cast<UINT_PTR
>(pWord
) + 3) & ~3) - reinterpret_cast<UINT_PTR
>(pWord
)) / sizeof(WORD
);
51 std::wstring
NumToStr(INT_PTR num
)
54 swprintf_s(buf
, L
"%Id", num
);
58 CResModule::CResModule()
59 : m_bTranslatedStrings(0)
60 , m_bDefaultStrings(0)
61 , m_bTranslatedDialogStrings(0)
62 , m_bDefaultDialogStrings(0)
63 , m_bTranslatedMenuStrings(0)
64 , m_bDefaultMenuStrings(0)
65 , m_bTranslatedAcceleratorStrings(0)
66 , m_bDefaultAcceleratorStrings(0)
67 , m_bTranslatedRibbonTexts(0)
68 , m_bDefaultRibbonTexts(0)
71 , m_hUpdateRes(nullptr)
74 , m_bAdjustEOLs(false)
78 CResModule::~CResModule()
82 BOOL
CResModule::ExtractResources(const std::vector
<std::wstring
>& filelist
, LPCWSTR lpszPOFilePath
, BOOL bNoUpdate
, LPCWSTR lpszHeaderFile
)
84 for (auto I
= filelist
.cbegin(); I
!= filelist
.cend(); ++I
)
86 std::wstring filepath
= *I
;
87 m_currentHeaderDataDialogs
.clear();
88 m_currentHeaderDataMenus
.clear();
89 m_currentHeaderDataStrings
.clear();
90 auto starpos
= I
->find('*');
91 if (starpos
!= std::wstring::npos
)
92 filepath
= I
->substr(0, starpos
);
93 while (starpos
!= std::wstring::npos
)
95 auto starposnext
= I
->find('*', starpos
+ 1);
96 std::wstring headerfile
= I
->substr(starpos
+ 1, starposnext
- starpos
- 1);
97 ScanHeaderFile(headerfile
);
98 starpos
= starposnext
;
100 m_hResDll
= LoadLibraryEx(filepath
.c_str(), nullptr, LOAD_LIBRARY_AS_IMAGE_RESOURCE
| LOAD_LIBRARY_AS_DATAFILE
);
106 FreeLibrary(m_hResDll
);
109 size_t nEntries
= m_StringEntries
.size();
110 // fill in the std::map with all translatable entries
113 fwprintf(stdout
, L
"Extracting StringTable....");
114 EnumResourceNames(m_hResDll
, RT_STRING
, EnumResNameCallback
, reinterpret_cast<LONG_PTR
>(this));
116 fwprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size() - nEntries
);
117 nEntries
= m_StringEntries
.size();
120 fwprintf(stdout
, L
"Extracting Dialogs........");
121 EnumResourceNames(m_hResDll
, RT_DIALOG
, EnumResNameCallback
, reinterpret_cast<LONG_PTR
>(this));
123 fwprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size() - nEntries
);
124 nEntries
= m_StringEntries
.size();
127 fwprintf(stdout
, L
"Extracting Menus..........");
128 EnumResourceNames(m_hResDll
, RT_MENU
, EnumResNameCallback
, reinterpret_cast<LONG_PTR
>(this));
130 fwprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size() - nEntries
);
131 nEntries
= m_StringEntries
.size();
133 fwprintf(stdout
, L
"Extracting Accelerators...");
134 EnumResourceNames(m_hResDll
, RT_ACCELERATOR
, EnumResNameCallback
, reinterpret_cast<LONG_PTR
>(this));
136 fwprintf(stdout
, L
"%4Iu Accelerators\n", m_StringEntries
.size() - nEntries
);
137 nEntries
= m_StringEntries
.size();
139 fwprintf(stdout
, L
"Extracting Ribbons........");
140 EnumResourceNames(m_hResDll
, RT_RIBBON
, EnumResNameCallback
, reinterpret_cast<LONG_PTR
>(this));
142 fwprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size() - nEntries
);
143 nEntries
= m_StringEntries
.size();
145 // parse a probably existing file and update the translations which are
147 m_StringEntries
.ParseFile(lpszPOFilePath
, !bNoUpdate
, m_bAdjustEOLs
);
150 // at last, save the new file
151 return m_StringEntries
.SaveFile(lpszPOFilePath
, lpszHeaderFile
);
154 BOOL
CResModule::ExtractResources(LPCWSTR lpszSrcLangDllPath
, LPCWSTR lpszPoFilePath
, BOOL bNoUpdate
, LPCWSTR lpszHeaderFile
)
156 m_hResDll
= LoadLibraryEx(lpszSrcLangDllPath
, nullptr, LOAD_LIBRARY_AS_IMAGE_RESOURCE
| LOAD_LIBRARY_AS_DATAFILE
);
162 FreeLibrary(m_hResDll
);
166 // fill in the std::map with all translatable entries
169 fwprintf(stdout
, L
"Extracting StringTable....");
170 EnumResourceNames(m_hResDll
, RT_STRING
, EnumResNameCallback
, reinterpret_cast<LONG_PTR
>(this));
172 fwprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size());
173 nEntries
= m_StringEntries
.size();
176 fwprintf(stdout
, L
"Extracting Dialogs........");
177 EnumResourceNames(m_hResDll
, RT_DIALOG
, EnumResNameCallback
, reinterpret_cast<LONG_PTR
>(this));
179 fwprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size() - nEntries
);
180 nEntries
= m_StringEntries
.size();
183 fwprintf(stdout
, L
"Extracting Menus..........");
184 EnumResourceNames(m_hResDll
, RT_MENU
, EnumResNameCallback
, reinterpret_cast<LONG_PTR
>(this));
186 fwprintf(stdout
, L
"%4Iu Strings\n", m_StringEntries
.size()-nEntries
);
187 nEntries
= m_StringEntries
.size();
190 fwprintf(stdout
, L
"Extracting Accelerators...");
191 EnumResourceNames(m_hResDll
, RT_ACCELERATOR
, EnumResNameCallback
, reinterpret_cast<LONG_PTR
>(this));
193 fwprintf(stdout
, L
"%4Iu Accelerators\n", m_StringEntries
.size()-nEntries
);
194 nEntries
= m_StringEntries
.size();
196 // parse a probably existing file and update the translations which are
198 m_StringEntries
.ParseFile(lpszPoFilePath
, !bNoUpdate
, m_bAdjustEOLs
);
200 // at last, save the new file
201 if (!m_StringEntries
.SaveFile(lpszPoFilePath
, lpszHeaderFile
))
207 void CResModule::RemoveSignatures(LPCWSTR lpszDestLangDllPath
)
209 // Remove any signatures in the file:
210 // if we don't remove it here, the signature will be invalid after
211 // we modify this file, and the signtool.exe will throw an error and refuse to sign it again.
212 auto hFile
= CreateFile(lpszDestLangDllPath
, FILE_READ_DATA
| FILE_WRITE_DATA
, 0, nullptr, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, nullptr);
213 if (hFile
== INVALID_HANDLE_VALUE
)
221 ImageEnumerateCertificates(hFile
, CERT_SECTION_TYPE_ANY
, &certcount
, indices
, _countof(indices
));
223 for (DWORD i
= 0; i
< certcount
; ++i
)
224 ImageRemoveCertificate(hFile
, i
);
229 BOOL
CResModule::CreateTranslatedResources(LPCWSTR lpszSrcLangDllPath
, LPCWSTR lpszDestLangDllPath
, LPCWSTR lpszPOFilePath
)
231 if (!CopyFile(lpszSrcLangDllPath
, lpszDestLangDllPath
, FALSE
))
234 RemoveSignatures(lpszDestLangDllPath
);
239 m_hResDll
= LoadLibraryEx(lpszSrcLangDllPath
, nullptr, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
| LOAD_LIBRARY_AS_IMAGE_RESOURCE
| LOAD_IGNORE_CODE_AUTHZ_LEVEL
);
243 } while (!m_hResDll
&& (count
< 10));
250 FreeLibrary(m_hResDll
);
253 sDestFile
= std::wstring(lpszDestLangDllPath
);
255 // get all translated strings
256 if (!m_StringEntries
.ParseFile(lpszPOFilePath
, FALSE
, m_bAdjustEOLs
))
258 m_bTranslatedStrings
= 0;
259 m_bDefaultStrings
= 0;
260 m_bTranslatedDialogStrings
= 0;
261 m_bDefaultDialogStrings
= 0;
262 m_bTranslatedMenuStrings
= 0;
263 m_bDefaultMenuStrings
= 0;
264 m_bTranslatedAcceleratorStrings
= 0;
265 m_bDefaultAcceleratorStrings
= 0;
270 m_hUpdateRes
= BeginUpdateResource(sDestFile
.c_str(), FALSE
);
274 } while (!m_hUpdateRes
&& (count
< 10));
280 fwprintf(stdout
, L
"Translating StringTable...");
281 EnumResourceNames(m_hResDll
, RT_STRING
, EnumResNameWriteCallback
, reinterpret_cast<LONG_PTR
>(this));
283 fwprintf(stdout
, L
"%4d translated, %4d not translated\n", m_bTranslatedStrings
, m_bDefaultStrings
);
286 fwprintf(stdout
, L
"Translating Dialogs.......");
287 EnumResourceNames(m_hResDll
, RT_DIALOG
, EnumResNameWriteCallback
, reinterpret_cast<LONG_PTR
>(this));
289 fwprintf(stdout
, L
"%4d translated, %4d not translated\n", m_bTranslatedDialogStrings
, m_bDefaultDialogStrings
);
292 fwprintf(stdout
, L
"Translating Menus.........");
293 EnumResourceNames(m_hResDll
, RT_MENU
, EnumResNameWriteCallback
, reinterpret_cast<LONG_PTR
>(this));
295 fwprintf(stdout
, L
"%4d translated, %4d not translated\n", m_bTranslatedMenuStrings
, m_bDefaultMenuStrings
);
298 fwprintf(stdout
, L
"Translating Accelerators..");
299 EnumResourceNames(m_hResDll
, RT_ACCELERATOR
, EnumResNameWriteCallback
, reinterpret_cast<LONG_PTR
>(this));
301 fwprintf(stdout
, L
"%4d translated, %4d not translated\n", m_bTranslatedAcceleratorStrings
, m_bDefaultAcceleratorStrings
);
304 fwprintf(stdout
, L
"Translating Ribbons.......");
305 EnumResourceNames(m_hResDll
, RT_RIBBON
, EnumResNameWriteCallback
, reinterpret_cast<LONG_PTR
>(this));
307 fwprintf(stdout
, L
"%4d translated, %4d not translated\n", m_bTranslatedRibbonTexts
, m_bDefaultRibbonTexts
);
309 if (!EndUpdateResource(m_hUpdateRes
, !bRes
))
312 AdjustCheckSum(sDestFile
);
317 BOOL
CResModule::ExtractString(LPCWSTR lpszType
)
319 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_STRING
);
320 HGLOBAL hglStringTable
;
325 hglStringTable
= LoadResource(m_hResDll
, hrsrc
);
329 SCOPE_EXIT
{ FreeResource(hglStringTable
); };
330 p
= static_cast<LPWSTR
>(LockResource(hglStringTable
));
334 SCOPE_EXIT
{ UnlockResource(hglStringTable
); };
335 /* [Block of 16 strings. The strings are Pascal style with a WORD
336 length preceding the string. 16 strings are always written, even
337 if not all slots are full. Any slots in the block with no string
338 have a zero WORD for the length.]
341 //first check how much memory we need
343 for (int i
=0; i
<16; ++i
)
345 int len
= GET_WORD(pp
);
347 std::wstring msgid
= std::wstring(pp
, len
);
348 wchar_t buf
[MAX_STRING_LENGTH
* 2] = { 0 };
349 wcscpy_s(buf
, msgid
.c_str());
350 CUtils::StringExtend(buf
);
354 std::wstring str
= std::wstring(buf
);
355 RESOURCEENTRY entry
= m_StringEntries
[str
];
356 InsertResourceIDs(RT_STRING
, 0, entry
, (reinterpret_cast<INT_PTR
>(lpszType
) - 1) * 16 + i
, L
"");
357 if (wcschr(str
.c_str(), '%'))
358 entry
.flag
= L
"#, c-format";
359 m_StringEntries
[str
] = entry
;
366 BOOL
CResModule::ReplaceString(LPCWSTR lpszType
, WORD wLanguage
)
368 HRSRC hrsrc
= FindResourceEx(m_hResDll
, RT_STRING
, lpszType
, wLanguage
);
369 HGLOBAL hglStringTable
;
374 hglStringTable
= LoadResource(m_hResDll
, hrsrc
);
378 SCOPE_EXIT
{ FreeResource(hglStringTable
); };
379 p
= static_cast<LPWSTR
>(LockResource(hglStringTable
));
383 SCOPE_EXIT
{ UnlockResource(hglStringTable
); };
384 /* [Block of 16 strings. The strings are Pascal style with a WORD
385 length preceding the string. 16 strings are always written, even
386 if not all slots are full. Any slots in the block with no string
387 have a zero WORD for the length.]
390 //first check how much memory we need
393 for (int i
=0; i
<16; ++i
)
396 size_t len
= GET_WORD(pp
);
398 std::wstring msgid
= std::wstring(pp
, len
);
399 wchar_t buf
[MAX_STRING_LENGTH
* 2] = { 0 };
400 wcscpy_s(buf
, msgid
.c_str());
401 CUtils::StringExtend(buf
);
402 msgid
= std::wstring(buf
);
404 RESOURCEENTRY resEntry
;
405 resEntry
= m_StringEntries
[msgid
];
406 wcscpy_s(buf
, resEntry
.msgstr
.empty() ? msgid
.c_str() : resEntry
.msgstr
.c_str());
407 ReplaceWithRegex(buf
);
408 CUtils::StringCollapse(buf
);
409 size_t newlen
= wcslen(buf
);
417 auto newTable
= std::make_unique
<WORD
[]>(nMem
+ (nMem
% 2));
420 for (int i
=0; i
<16; ++i
)
422 int len
= GET_WORD(p
);
424 std::wstring msgid
= std::wstring(p
, len
);
425 wchar_t buf
[MAX_STRING_LENGTH
* 2] = { 0 };
426 wcscpy_s(buf
, msgid
.c_str());
427 CUtils::StringExtend(buf
);
428 msgid
= std::wstring(buf
);
430 RESOURCEENTRY resEntry
;
431 resEntry
= m_StringEntries
[msgid
];
432 wcscpy_s(buf
, resEntry
.msgstr
.empty() ? msgid
.c_str() : resEntry
.msgstr
.c_str());
433 ReplaceWithRegex(buf
);
434 CUtils::StringCollapse(buf
);
435 size_t newlen
= wcslen(buf
);
438 newTable
.get()[index
++] = static_cast<WORD
>(newlen
);
439 wcsncpy(reinterpret_cast<wchar_t*>(&newTable
.get()[index
]), buf
, newlen
);
441 m_bTranslatedStrings
++;
445 newTable
.get()[index
++] = static_cast<WORD
>(len
);
447 wcsncpy(reinterpret_cast<wchar_t*>(&newTable
.get()[index
]), p
, len
);
455 if (!UpdateResource(m_hUpdateRes
, RT_STRING
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newTable
.get(), static_cast<DWORD
>(nMem
+ (nMem
% 2)) * sizeof(WORD
)))
458 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_STRING
, lpszType
, wLanguage
, nullptr, 0)))
464 BOOL
CResModule::ExtractMenu(LPCWSTR lpszType
)
466 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_MENU
);
467 HGLOBAL hglMenuTemplate
;
468 WORD version
, offset
;
474 hglMenuTemplate
= LoadResource(m_hResDll
, hrsrc
);
476 if (!hglMenuTemplate
)
478 SCOPE_EXIT
{ FreeResource(hglMenuTemplate
); };
480 p
= static_cast<const WORD
*>(LockResource(hglMenuTemplate
));
484 SCOPE_EXIT
{ UnlockResource(hglMenuTemplate
); };
485 // Standard MENU resource
486 //struct MenuHeader {
487 // WORD wVersion; // Currently zero
488 // WORD cbHeaderSize; // Also zero
492 //struct MenuExHeader {
493 // WORD wVersion; // One
498 version
= GET_WORD(p
);
506 offset
= GET_WORD(p
);
509 if (!ParseMenuResource(p
))
515 offset
= GET_WORD(p
);
517 //dwHelpId = GET_DWORD(p);
518 if (!ParseMenuExResource(p0
+ offset
))
529 BOOL
CResModule::ReplaceMenu(LPCWSTR lpszType
, WORD wLanguage
)
531 HRSRC hrsrc
= FindResourceEx(m_hResDll
, RT_MENU
, lpszType
, wLanguage
);
532 HGLOBAL hglMenuTemplate
;
533 WORD version
, offset
;
538 MYERROR
; //just the language wasn't found
540 hglMenuTemplate
= LoadResource(m_hResDll
, hrsrc
);
542 if (!hglMenuTemplate
)
544 SCOPE_EXIT
{ FreeResource(hglMenuTemplate
); };
546 p
= static_cast<LPWSTR
>(LockResource(hglMenuTemplate
));
550 SCOPE_EXIT
{ UnlockResource(hglMenuTemplate
); };
551 //struct MenuHeader {
552 // WORD wVersion; // Currently zero
553 // WORD cbHeaderSize; // Also zero
557 //struct MenuExHeader {
558 // WORD wVersion; // One
562 p0
= reinterpret_cast<WORD
*>(p
);
563 version
= GET_WORD(p
);
571 offset
= GET_WORD(p
);
575 if (!CountMemReplaceMenuResource(reinterpret_cast<WORD
*>(p
), &nMem
, nullptr))
577 auto newMenu
= std::make_unique
<WORD
[]>(nMem
+ (nMem
% 2) + 2);
578 size_t index
= 2; // MenuHeader has 2 WORDs zero
579 if (!CountMemReplaceMenuResource(reinterpret_cast<WORD
*>(p
), &index
, newMenu
.get()))
582 if (!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newMenu
.get(), static_cast<DWORD
>(nMem
+ (nMem
% 2) + 2) * sizeof(WORD
)))
585 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, wLanguage
, nullptr, 0)))
591 offset
= GET_WORD(p
);
593 //dwHelpId = GET_DWORD(p);
595 if (!CountMemReplaceMenuExResource(reinterpret_cast<WORD
*>(p0
+ offset
), &nMem
, nullptr))
597 auto newMenu
= std::make_unique
<WORD
[]>(nMem
+ (nMem
% 2) + 4);
598 CopyMemory(newMenu
.get(), p0
, 2 * sizeof(WORD
) + sizeof(DWORD
));
599 size_t index
= 4; // MenuExHeader has 2 x WORD + 1 x DWORD
600 if (!CountMemReplaceMenuExResource(reinterpret_cast<WORD
*>(p0
+ offset
), &index
, newMenu
.get()))
603 if (!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newMenu
.get(), static_cast<DWORD
>(nMem
+ (nMem
% 2) + 4) * sizeof(DWORD
)))
606 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, wLanguage
, nullptr, 0)))
617 const WORD
* CResModule::ParseMenuResource(const WORD
* res
)
622 //struct PopupMenuItem {
624 // WCHAR szItemText[];
626 //struct NormalMenuItem {
629 // WCHAR szItemText[];
634 flags
= GET_WORD(res
);
636 if (!(flags
& MF_POPUP
))
638 id
= GET_WORD(res
); //normal menu item
642 id
= static_cast<WORD
>(-1); //popup menu item
644 auto str
= reinterpret_cast<LPCWSTR
>(res
);
645 size_t l
= wcslen(str
)+1;
648 if (flags
& MF_POPUP
)
650 wchar_t buf
[MAX_STRING_LENGTH
] = { 0 };
652 CUtils::StringExtend(buf
);
654 std::wstring wstr
= std::wstring(buf
);
655 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
657 InsertResourceIDs(RT_MENU
, 0, entry
, id
, L
" - PopupMenu");
659 m_StringEntries
[wstr
] = entry
;
661 if ((res
= ParseMenuResource(res
))==0)
666 wchar_t buf
[MAX_STRING_LENGTH
] = { 0 };
668 CUtils::StringExtend(buf
);
670 std::wstring wstr
= std::wstring(buf
);
671 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
672 InsertResourceIDs(RT_MENU
, 0, entry
, id
, L
" - Menu");
674 wchar_t szTempBuf
[1024] = { 0 };
675 swprintf_s(szTempBuf
, L
"#: MenuEntry; ID:%u", id
);
676 MENUENTRY menu_entry
;
678 menu_entry
.reference
= szTempBuf
;
679 menu_entry
.msgstr
= wstr
;
681 m_StringEntries
[wstr
] = entry
;
682 m_MenuEntries
[id
] = menu_entry
;
684 } while (!(flags
& MF_END
));
688 const WORD
* CResModule::CountMemReplaceMenuResource(const WORD
* res
, size_t * wordcount
, WORD
* newMenu
)
693 //struct PopupMenuItem {
695 // WCHAR szItemText[];
697 //struct NormalMenuItem {
700 // WCHAR szItemText[];
705 flags
= GET_WORD(res
);
710 newMenu
[(*wordcount
)++] = flags
;
711 if (!(flags
& MF_POPUP
))
713 id
= GET_WORD(res
); //normal menu item
718 newMenu
[(*wordcount
)++] = id
;
721 id
= static_cast<WORD
>(-1); //popup menu item
723 if (flags
& MF_POPUP
)
725 ReplaceStr(reinterpret_cast<LPCWSTR
>(res
), newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
726 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
728 if ((res
= CountMemReplaceMenuResource(res
, wordcount
, newMenu
))==0)
733 ReplaceStr(reinterpret_cast<LPCWSTR
>(res
), newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
734 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
739 wcscpy(reinterpret_cast<wchar_t*>(&newMenu
[(*wordcount
)]), reinterpret_cast<LPCWSTR
>(res
));
740 (*wordcount
) += wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
741 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
743 } while (!(flags
& MF_END
));
747 const WORD
* CResModule::ParseMenuExResource(const WORD
* res
)
751 //struct MenuExItem {
757 // DWORD dwHelpId; - Popup menu only
762 DWORD dwType
= GET_DWORD(res
);
764 //dwState = GET_DWORD(res);
766 DWORD menuId
= GET_DWORD(res
);
768 bResInfo
= GET_WORD(res
);
771 auto str
= reinterpret_cast<LPCWSTR
>(res
);
772 size_t l
= wcslen(str
)+1;
774 // Align to DWORD boundary
775 res
= AlignWORD(res
);
777 if (dwType
& MFT_SEPARATOR
)
782 // Popup menu - note this can also have a non-zero ID
784 menuId
= static_cast<WORD
>(-1);
785 wchar_t buf
[MAX_STRING_LENGTH
] = { 0 };
787 CUtils::StringExtend(buf
);
789 std::wstring wstr
= std::wstring(buf
);
790 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
791 // Popup has a DWORD help entry on a DWORD boundary - skip over it
794 InsertResourceIDs(RT_MENU
, 0, entry
, menuId
, L
" - PopupMenuEx");
795 wchar_t szTempBuf
[1024] = { 0 };
796 swprintf_s(szTempBuf
, L
"#: MenuExPopupEntry; ID:%lu", menuId
);
797 MENUENTRY menu_entry
;
798 menu_entry
.wID
= static_cast<WORD
>(menuId
);
799 menu_entry
.reference
= szTempBuf
;
800 menu_entry
.msgstr
= wstr
;
801 m_StringEntries
[wstr
] = entry
;
802 m_MenuEntries
[static_cast<WORD
>(menuId
)] = menu_entry
;
804 if ((res
= ParseMenuExResource(res
)) == 0)
806 } else if (menuId
!= 0)
808 wchar_t buf
[MAX_STRING_LENGTH
] = { 0 };
810 CUtils::StringExtend(buf
);
812 std::wstring wstr
= std::wstring(buf
);
813 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
814 InsertResourceIDs(RT_MENU
, 0, entry
, menuId
, L
" - MenuEx");
816 wchar_t szTempBuf
[1024] = { 0 };
817 swprintf_s(szTempBuf
, L
"#: MenuExEntry; ID:%lu", menuId
);
818 MENUENTRY menu_entry
;
819 menu_entry
.wID
= static_cast<WORD
>(menuId
);
820 menu_entry
.reference
= szTempBuf
;
821 menu_entry
.msgstr
= wstr
;
822 m_StringEntries
[wstr
] = entry
;
823 m_MenuEntries
[static_cast<WORD
>(menuId
)] = menu_entry
;
825 } while (!(bResInfo
& 0x80));
829 const WORD
* CResModule::CountMemReplaceMenuExResource(const WORD
* res
, size_t * wordcount
, WORD
* newMenu
)
833 //struct MenuExItem {
839 // DWORD dwHelpId; - Popup menu only
844 auto p0
= const_cast<WORD
*>(res
);
845 DWORD dwType
= GET_DWORD(res
);
847 //dwState = GET_DWORD(res);
849 DWORD menuId
= GET_DWORD(res
);
851 bResInfo
= GET_WORD(res
);
855 CopyMemory(&newMenu
[*wordcount
], p0
, 7 * sizeof(WORD
));
859 if (dwType
& MFT_SEPARATOR
) {
868 ReplaceStr(reinterpret_cast<LPCWSTR
>(res
), newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
869 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
871 res
= AlignWORD(res
);
872 if ((*wordcount
) & 0x01)
876 CopyMemory(&newMenu
[*wordcount
], res
, sizeof(DWORD
)); // Copy Help ID
881 if ((res
= CountMemReplaceMenuExResource(res
, wordcount
, newMenu
)) == 0)
884 else if (menuId
!= 0)
886 ReplaceStr(reinterpret_cast<LPCWSTR
>(res
), newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
887 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
892 wcscpy(reinterpret_cast<wchar_t*>(&newMenu
[(*wordcount
)]), reinterpret_cast<LPCWSTR
>(res
));
893 (*wordcount
) += wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
894 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
897 res
= AlignWORD(res
);
898 if ((*wordcount
) & 0x01)
900 } while (!(bResInfo
& 0x80));
904 BOOL
CResModule::ExtractAccelerator(LPCWSTR lpszType
)
906 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_ACCELERATOR
);
908 WORD fFlags
, wAnsi
, wID
;
915 hglAccTable
= LoadResource(m_hResDll
, hrsrc
);
919 SCOPE_EXIT
{ FreeResource(hglAccTable
); };
921 p
= static_cast<const WORD
*>(LockResource(hglAccTable
));
925 SCOPE_EXIT
{ UnlockResource(hglAccTable
); };
927 struct ACCELTABLEENTRY
929 WORD fFlags; FVIRTKEY, FSHIFT, FCONTROL, FALT, 0x80 - Last in a table
930 WORD wAnsi; ANSI character
931 WORD wId; Keyboard accelerator passed to windows
932 WORD padding; # bytes added to ensure aligned to DWORD boundary
938 fFlags
= GET_WORD(p
);
944 p
++; // Skip over padding
946 if ((fFlags
& 0x80) == 0x80)
951 if ((wAnsi
< 0x30) ||
953 (wAnsi
>= 0x3A && wAnsi
<= 0x40))
956 wchar_t buf
[1024] = { 0 };
957 wchar_t buf2
[1024] = { 0 };
959 // include the menu ID in the msgid to make sure that 'duplicate'
960 // accelerator keys are listed in the po-file.
961 // without this, we would get entries like this:
962 //#. Accelerator Entry for Menu ID:32809; '&Filter'
963 //#. Accelerator Entry for Menu ID:57636; '&Find'
964 //#: Corresponding Menu ID:32771; '&Find'
968 // Since "filter" and "find" are most likely translated to words starting
969 // with different letters, we need to have a separate accelerator entry
971 swprintf_s(buf
, L
"ID:%u:", wID
);
973 // EXACTLY 5 characters long "ACS+X"
974 // V = Virtual key (or blank if not used)
975 // A = Alt key (or blank if not used)
976 // C = Ctrl key (or blank if not used)
977 // S = Shift key (or blank if not used)
978 // X = upper case character
979 // e.g. "V CS+Q" == Ctrl + Shift + 'Q'
980 if ((fFlags
& FVIRTKEY
) == FVIRTKEY
) // 0x01
985 if ((fFlags
& FALT
) == FALT
) // 0x10
990 if ((fFlags
& FCONTROL
) == FCONTROL
) // 0x08
995 if ((fFlags
& FSHIFT
) == FSHIFT
) // 0x04
1000 swprintf_s(buf2
, L
"%s+%c", buf
, wAnsi
);
1002 std::wstring wstr
= std::wstring(buf2
);
1003 RESOURCEENTRY AKey_entry
= m_StringEntries
[wstr
];
1005 wchar_t szTempBuf
[1024] = { 0 };
1007 pME_iter
= m_MenuEntries
.find(wID
);
1008 if (pME_iter
!= m_MenuEntries
.end())
1010 wmenu
= pME_iter
->second
.msgstr
;
1012 swprintf_s(szTempBuf
, L
"#. Accelerator Entry for Menu ID:%u; '%s'", wID
, wmenu
.c_str());
1013 AKey_entry
.automaticcomments
.push_back(std::wstring(szTempBuf
));
1015 m_StringEntries
[wstr
] = AKey_entry
;
1021 BOOL
CResModule::ReplaceAccelerator(LPCWSTR lpszType
, WORD wLanguage
)
1023 LPACCEL lpaccelNew
; // pointer to new accelerator table
1024 HACCEL haccelOld
; // handle to old accelerator table
1025 int cAccelerators
; // number of accelerators in table
1026 HGLOBAL hglAccTableNew
;
1030 haccelOld
= LoadAccelerators(m_hResDll
, lpszType
);
1035 cAccelerators
= CopyAcceleratorTable(haccelOld
, nullptr, 0);
1037 lpaccelNew
= static_cast<LPACCEL
>(LocalAlloc(LPTR
, cAccelerators
* sizeof(ACCEL
)));
1041 SCOPE_EXIT
{ LocalFree(lpaccelNew
); };
1043 CopyAcceleratorTable(haccelOld
, lpaccelNew
, cAccelerators
);
1045 // Find the accelerator that the user modified
1046 // and change its flags and virtual-key code
1049 for (i
= 0; i
< cAccelerators
; i
++)
1051 if ((lpaccelNew
[i
].key
< 0x30) ||
1052 (lpaccelNew
[i
].key
> 0x5A) ||
1053 (lpaccelNew
[i
].key
>= 0x3A && lpaccelNew
[i
].key
<= 0x40))
1057 wchar_t xkey
= { 0 };
1058 wchar_t buf
[1024] = { 0 };
1059 wchar_t buf2
[1024] = { 0 };
1061 swprintf_s(buf
, L
"ID:%d:", lpaccelNew
[i
].cmd
);
1063 // get original key combination
1064 if ((lpaccelNew
[i
].fVirt
& FVIRTKEY
) == FVIRTKEY
) // 0x01
1065 wcscat_s(buf
, L
"V");
1067 wcscat_s(buf
, L
" ");
1069 if ((lpaccelNew
[i
].fVirt
& FALT
) == FALT
) // 0x10
1070 wcscat_s(buf
, L
"A");
1072 wcscat_s(buf
, L
" ");
1074 if ((lpaccelNew
[i
].fVirt
& FCONTROL
) == FCONTROL
) // 0x08
1075 wcscat_s(buf
, L
"C");
1077 wcscat_s(buf
, L
" ");
1079 if ((lpaccelNew
[i
].fVirt
& FSHIFT
) == FSHIFT
) // 0x04
1080 wcscat_s(buf
, L
"S");
1082 wcscat_s(buf
, L
" ");
1084 swprintf_s(buf2
, L
"%s+%c", buf
, lpaccelNew
[i
].key
);
1087 std::map
<std::wstring
, RESOURCEENTRY
>::iterator pAK_iter
= m_StringEntries
.find(buf2
);
1088 if (pAK_iter
!= m_StringEntries
.end())
1090 m_bTranslatedAcceleratorStrings
++;
1093 std::wstring wtemp
= pAK_iter
->second
.msgstr
;
1094 wtemp
= wtemp
.substr(wtemp
.find_last_of(':')+1);
1095 if (wtemp
.size() != 6)
1097 if (wtemp
.compare(0, 1, L
"V") == 0)
1099 else if (wtemp
.compare(0, 1, L
" ") != 0)
1100 continue; // not a space - user must have made a mistake when translating
1101 if (wtemp
.compare(1, 1, L
"A") == 0)
1103 else if (wtemp
.compare(1, 1, L
" ") != 0)
1104 continue; // not a space - user must have made a mistake when translating
1105 if (wtemp
.compare(2, 1, L
"C") == 0)
1107 else if (wtemp
.compare(2, 1, L
" ") != 0)
1108 continue; // not a space - user must have made a mistake when translating
1109 if (wtemp
.compare(3, 1, L
"S") == 0)
1111 else if (wtemp
.compare(3, 1, L
" ") != 0)
1112 continue; // not a space - user must have made a mistake when translating
1113 if (wtemp
.compare(4, 1, L
"+") == 0)
1115 swscanf_s(wtemp
.substr(5, 1).c_str(), L
"%c", &xkey
, 1);
1116 lpaccelNew
[i
].fVirt
= xfVirt
;
1117 lpaccelNew
[i
].key
= static_cast<DWORD
>(xkey
);
1121 m_bDefaultAcceleratorStrings
++;
1125 // Create the new accelerator table
1126 hglAccTableNew
= LocalAlloc(LPTR
, cAccelerators
* 4 * sizeof(WORD
));
1127 if (!hglAccTableNew
)
1129 SCOPE_EXIT
{ LocalFree(hglAccTableNew
); };
1130 p
= static_cast<WORD
*>(hglAccTableNew
);
1131 lpaccelNew
[cAccelerators
-1].fVirt
|= 0x80;
1132 for (i
= 0; i
< cAccelerators
; i
++)
1134 memcpy(reinterpret_cast<void*>(const_cast<WORD
*>(p
)), &lpaccelNew
[i
].fVirt
, 1);
1136 memcpy(reinterpret_cast<void*>(const_cast<WORD
*>(p
)), &lpaccelNew
[i
].key
, sizeof(WORD
));
1138 memcpy(reinterpret_cast<void*>(const_cast<WORD
*>(p
)), &lpaccelNew
[i
].cmd
, sizeof(WORD
));
1143 if (!UpdateResource(m_hUpdateRes
, RT_ACCELERATOR
, lpszType
,
1144 (m_wTargetLang
? m_wTargetLang
: wLanguage
), hglAccTableNew
/* haccelNew*/, cAccelerators
* 4 * sizeof(WORD
)))
1149 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_ACCELERATOR
, lpszType
, wLanguage
, nullptr, 0)))
1157 BOOL
CResModule::ExtractDialog(LPCWSTR lpszType
)
1160 const WORD
* lpDlgItem
;
1162 DLGITEMINFO dlgItem
;
1165 HGLOBAL hGlblDlgTemplate
;
1167 hrsrc
= FindResource(m_hResDll
, lpszType
, RT_DIALOG
);
1172 hGlblDlgTemplate
= LoadResource(m_hResDll
, hrsrc
);
1173 if (!hGlblDlgTemplate
)
1175 SCOPE_EXIT
{ FreeResource(hGlblDlgTemplate
); };
1176 lpDlg
= static_cast<const WORD
*>(LockResource(hGlblDlgTemplate
));
1180 SCOPE_EXIT
{ UnlockResource(hGlblDlgTemplate
); };
1182 lpDlgItem
= GetDialogInfo(lpDlg
, &dlg
);
1183 bNumControls
= dlg
.nbItems
;
1187 wchar_t buf
[MAX_STRING_LENGTH
] = { 0 };
1188 wcscpy_s(buf
, dlg
.caption
);
1189 CUtils::StringExtend(buf
);
1191 std::wstring wstr
= std::wstring(buf
);
1192 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
1193 InsertResourceIDs(RT_DIALOG
, reinterpret_cast<INT_PTR
>(lpszType
), entry
, reinterpret_cast<INT_PTR
>(lpszType
), L
"");
1195 m_StringEntries
[wstr
] = entry
;
1198 while (bNumControls
-- != 0)
1200 wchar_t szTitle
[500] = { 0 };
1203 lpDlgItem
= GetControlInfo(lpDlgItem
, &dlgItem
, dlg
.dialogEx
, &bCode
);
1206 wcsncpy_s(szTitle
, dlgItem
.windowName
, _countof(szTitle
) - 1);
1210 CUtils::StringExtend(szTitle
);
1212 std::wstring wstr
= std::wstring(szTitle
);
1213 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
1214 InsertResourceIDs(RT_DIALOG
, reinterpret_cast<INT_PTR
>(lpszType
), entry
, dlgItem
.id
, L
"");
1216 m_StringEntries
[wstr
] = entry
;
1223 BOOL
CResModule::ReplaceDialog(LPCWSTR lpszType
, WORD wLanguage
)
1227 HGLOBAL hGlblDlgTemplate
;
1229 hrsrc
= FindResourceEx(m_hResDll
, RT_DIALOG
, lpszType
, wLanguage
);
1234 hGlblDlgTemplate
= LoadResource(m_hResDll
, hrsrc
);
1236 if (!hGlblDlgTemplate
)
1238 SCOPE_EXIT
{ FreeResource(hGlblDlgTemplate
); };
1240 lpDlg
= static_cast<WORD
*>(LockResource(hGlblDlgTemplate
));
1244 SCOPE_EXIT
{ UnlockResource(hGlblDlgTemplate
); };
1247 const WORD
* p
= lpDlg
;
1248 if (!CountMemReplaceDialogResource(p
, &nMem
, nullptr))
1250 auto newDialog
= std::make_unique
<WORD
[]>(nMem
+ (nMem
% 2));
1253 if (!CountMemReplaceDialogResource(lpDlg
, &index
, newDialog
.get()))
1256 if (!UpdateResource(m_hUpdateRes
, RT_DIALOG
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newDialog
.get(), static_cast<DWORD
>(nMem
+ (nMem
% 2)) * sizeof(WORD
)))
1259 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_DIALOG
, lpszType
, wLanguage
, nullptr, 0)))
1265 const WORD
* CResModule::GetDialogInfo(const WORD
* pTemplate
, LPDIALOGINFO lpDlgInfo
) const
1267 const WORD
* p
= pTemplate
;
1269 lpDlgInfo
->style
= GET_DWORD(p
);
1272 if (lpDlgInfo
->style
== 0xffff0001) // DIALOGEX resource
1274 lpDlgInfo
->dialogEx
= TRUE
;
1275 lpDlgInfo
->helpId
= GET_DWORD(p
);
1277 lpDlgInfo
->exStyle
= GET_DWORD(p
);
1279 lpDlgInfo
->style
= GET_DWORD(p
);
1284 lpDlgInfo
->dialogEx
= FALSE
;
1285 lpDlgInfo
->helpId
= 0;
1286 lpDlgInfo
->exStyle
= GET_DWORD(p
);
1290 lpDlgInfo
->nbItems
= GET_WORD(p
);
1293 lpDlgInfo
->x
= GET_WORD(p
);
1296 lpDlgInfo
->y
= GET_WORD(p
);
1299 lpDlgInfo
->cx
= GET_WORD(p
);
1302 lpDlgInfo
->cy
= GET_WORD(p
);
1305 // Get the menu name
1307 switch (GET_WORD(p
))
1310 lpDlgInfo
->menuName
= nullptr;
1314 lpDlgInfo
->menuName
= reinterpret_cast<LPCWSTR
>(static_cast<WORD
>(GET_WORD(p
+ 1)));
1318 lpDlgInfo
->menuName
= reinterpret_cast<LPCWSTR
>(p
);
1319 p
+= wcslen(reinterpret_cast<LPCWSTR
>(p
)) + 1;
1323 // Get the class name
1325 switch (GET_WORD(p
))
1328 lpDlgInfo
->className
= static_cast<LPCWSTR
>(MAKEINTATOM(32770));
1332 lpDlgInfo
->className
= reinterpret_cast<LPCWSTR
>(static_cast<WORD
>(GET_WORD(p
+ 1)));
1336 lpDlgInfo
->className
= reinterpret_cast<LPCWSTR
>(p
);
1337 p
+= wcslen(reinterpret_cast<LPCWSTR
>(p
)) + 1;
1341 // Get the window caption
1343 lpDlgInfo
->caption
= reinterpret_cast<LPCWSTR
>(p
);
1344 p
+= wcslen(reinterpret_cast<LPCWSTR
>(p
)) + 1;
1346 // Get the font name
1348 if (lpDlgInfo
->style
& DS_SETFONT
)
1350 lpDlgInfo
->pointSize
= GET_WORD(p
);
1353 if (lpDlgInfo
->dialogEx
)
1355 lpDlgInfo
->weight
= GET_WORD(p
);
1357 lpDlgInfo
->italic
= LOBYTE(GET_WORD(p
));
1362 lpDlgInfo
->weight
= FW_DONTCARE
;
1363 lpDlgInfo
->italic
= FALSE
;
1366 lpDlgInfo
->faceName
= reinterpret_cast<LPCWSTR
>(p
);
1367 p
+= wcslen(reinterpret_cast<LPCWSTR
>(p
)) + 1;
1369 // First control is on DWORD boundary
1375 const WORD
* CResModule::GetControlInfo(const WORD
* p
, LPDLGITEMINFO lpDlgItemInfo
, BOOL dialogEx
, LPBOOL bIsID
) const
1379 lpDlgItemInfo
->helpId
= GET_DWORD(p
);
1381 lpDlgItemInfo
->exStyle
= GET_DWORD(p
);
1383 lpDlgItemInfo
->style
= GET_DWORD(p
);
1388 lpDlgItemInfo
->helpId
= 0;
1389 lpDlgItemInfo
->style
= GET_DWORD(p
);
1391 lpDlgItemInfo
->exStyle
= GET_DWORD(p
);
1395 lpDlgItemInfo
->x
= GET_WORD(p
);
1398 lpDlgItemInfo
->y
= GET_WORD(p
);
1401 lpDlgItemInfo
->cx
= GET_WORD(p
);
1404 lpDlgItemInfo
->cy
= GET_WORD(p
);
1409 // ID is a DWORD for DIALOGEX
1410 lpDlgItemInfo
->id
= static_cast<WORD
>(GET_DWORD(p
));
1415 lpDlgItemInfo
->id
= GET_WORD(p
);
1419 if (GET_WORD(p
) == 0xffff)
1427 lpDlgItemInfo
->className
= reinterpret_cast<LPCWSTR
>(p
);
1428 p
+= wcslen(reinterpret_cast<LPCWSTR
>(p
)) + 1;
1431 if (GET_WORD(p
) == 0xffff) // an integer ID?
1434 lpDlgItemInfo
->windowName
= reinterpret_cast<LPCWSTR
>(GET_WORD(p
+ 1));
1440 lpDlgItemInfo
->windowName
= reinterpret_cast<LPCWSTR
>(p
);
1441 p
+= wcslen(reinterpret_cast<LPCWSTR
>(p
)) + 1;
1446 lpDlgItemInfo
->data
= const_cast<WORD
*>(p
+ 1);
1447 p
+= GET_WORD(p
) / sizeof(WORD
);
1450 lpDlgItemInfo
->data
= nullptr;
1453 // Next control is on DWORD boundary
1458 const WORD
* CResModule::CountMemReplaceDialogResource(const WORD
* res
, size_t * wordcount
, WORD
* newDialog
)
1461 DWORD style
= GET_DWORD(res
);
1464 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1465 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1473 if (style
== 0xffff0001) // DIALOGEX resource
1478 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //help id
1479 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //help id
1480 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1481 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1482 style
= GET_DWORD(res
);
1483 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1484 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1489 style
= GET_DWORD(res
);
1499 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1500 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1501 //style = GET_DWORD(res);
1502 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1503 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1513 newDialog
[(*wordcount
)] = GET_WORD(res
);
1514 WORD nbItems
= GET_WORD(res
);
1519 newDialog
[(*wordcount
)] = GET_WORD(res
); //x
1524 newDialog
[(*wordcount
)] = GET_WORD(res
); //y
1529 newDialog
[(*wordcount
)] = GET_WORD(res
); //cx
1534 newDialog
[(*wordcount
)] = GET_WORD(res
); //cy
1538 // Get the menu name
1540 switch (GET_WORD(res
))
1544 newDialog
[(*wordcount
)] = GET_WORD(res
);
1551 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1552 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1563 wcscpy(reinterpret_cast<LPWSTR
>(&newDialog
[(*wordcount
)]), reinterpret_cast<LPCWSTR
>(res
));
1565 (*wordcount
) += wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
1566 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
1570 // Get the class name
1572 switch (GET_WORD(res
))
1576 newDialog
[(*wordcount
)] = GET_WORD(res
);
1583 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1584 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1595 wcscpy(reinterpret_cast<LPWSTR
>(&newDialog
[(*wordcount
)]), reinterpret_cast<LPCWSTR
>(res
));
1597 (*wordcount
) += wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
1598 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
1602 // Get the window caption
1604 ReplaceStr(reinterpret_cast<LPCWSTR
>(res
), newDialog
, wordcount
, &m_bTranslatedDialogStrings
, &m_bDefaultDialogStrings
);
1605 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
1607 // Get the font name
1609 if (style
& DS_SETFONT
)
1612 newDialog
[(*wordcount
)] = GET_WORD(res
);
1620 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1621 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1631 wcscpy(reinterpret_cast<LPWSTR
>(&newDialog
[(*wordcount
)]), reinterpret_cast<LPCWSTR
>(res
));
1632 (*wordcount
) += wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
1633 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
1635 // First control is on DWORD boundary
1636 while ((*wordcount
)%2)
1638 while (reinterpret_cast<UINT_PTR
>(res
) % 4)
1643 res
= ReplaceControlInfo(res
, wordcount
, newDialog
, bEx
);
1648 const WORD
* CResModule::ReplaceControlInfo(const WORD
* res
, size_t * wordcount
, WORD
* newDialog
, BOOL bEx
)
1654 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //helpid
1655 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //helpid
1665 auto exStyle
= reinterpret_cast<LONG
*>(&newDialog
[(*wordcount
)]);
1666 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1667 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1669 *exStyle
|= WS_EX_RTLREADING
;
1679 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1680 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1689 newDialog
[(*wordcount
)] = GET_WORD(res
); //x
1694 newDialog
[(*wordcount
)] = GET_WORD(res
); //y
1699 newDialog
[(*wordcount
)] = GET_WORD(res
); //cx
1704 newDialog
[(*wordcount
)] = GET_WORD(res
); //cy
1710 // ID is a DWORD for DIALOGEX
1713 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1714 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1725 newDialog
[(*wordcount
)] = GET_WORD(res
);
1730 if (GET_WORD(res
) == 0xffff) //classID
1734 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1735 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1746 wcscpy(reinterpret_cast<LPWSTR
>(&newDialog
[(*wordcount
)]), reinterpret_cast<LPCWSTR
>(res
));
1747 (*wordcount
) += wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
1748 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
1751 if (GET_WORD(res
) == 0xffff) // an integer ID?
1755 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1756 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1766 ReplaceStr(reinterpret_cast<LPCWSTR
>(res
), newDialog
, wordcount
, &m_bTranslatedDialogStrings
, &m_bDefaultDialogStrings
);
1767 res
+= wcslen(reinterpret_cast<LPCWSTR
>(res
)) + 1;
1771 memcpy(&newDialog
[(*wordcount
)], res
, (GET_WORD(res
)+1)*sizeof(WORD
));
1772 (*wordcount
) += (GET_WORD(res
)+1);
1773 res
+= (GET_WORD(res
)+1);
1774 // Next control is on DWORD boundary
1775 while ((*wordcount
) % 2)
1777 res
= AlignWORD(res
);
1782 BOOL
CResModule::ExtractRibbon(LPCWSTR lpszType
)
1784 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_RIBBON
);
1785 HGLOBAL hglRibbonTemplate
;
1791 hglRibbonTemplate
= LoadResource(m_hResDll
, hrsrc
);
1792 if (!hglRibbonTemplate
)
1794 SCOPE_EXIT
{ FreeResource(hglRibbonTemplate
); };
1796 DWORD sizeres
= SizeofResource(m_hResDll
, hrsrc
);
1798 p
= static_cast<const BYTE
*>(LockResource(hglRibbonTemplate
));
1802 SCOPE_EXIT
{ UnlockResource(hglRibbonTemplate
); };
1804 // Resource consists of one single string
1807 // extract all <id><name>blah1</name><value>blah2</value></id><text>blah</text> elements
1809 const std::regex
regRevMatch("<ID><NAME>([^<]+)</NAME><VALUE>([^<]+)</VALUE></ID><TEXT>([^<]+)</TEXT>");
1810 std::string ss
= std::string(reinterpret_cast<const char*>(p
), sizeres
);
1811 const std::sregex_iterator end
;
1812 for (std::sregex_iterator
it(ss
.cbegin(), ss
.cend(), regRevMatch
); it
!= end
; ++it
)
1814 std::wstring strIdNameVal
= CUnicodeUtils::StdGetUnicode((*it
)[1].str());
1815 strIdNameVal
+= L
" - Ribbon name";
1817 std::wstring strIdVal
= CUnicodeUtils::StdGetUnicode((*it
)[2].str());
1819 std::wstring str
= CUnicodeUtils::StdGetUnicode((*it
)[3].str());
1821 RESOURCEENTRY entry
= m_StringEntries
[str
];
1822 InsertResourceIDs(RT_RIBBON
, 0, entry
, std::stoi(strIdVal
), strIdNameVal
.c_str());
1823 if (wcschr(str
.c_str(), '%'))
1824 entry
.flag
= L
"#, c-format";
1825 m_StringEntries
[str
] = entry
;
1826 m_bDefaultRibbonTexts
++;
1829 // extract all </ELEMENT_NAME><NAME>blahblah</NAME> elements
1831 const std::regex
regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
1832 for (std::sregex_iterator
it(ss
.cbegin(), ss
.cend(), regRevMatchName
); it
!= end
; ++it
)
1834 std::wstring ret
= CUnicodeUtils::StdGetUnicode((*it
)[1].str());
1835 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1836 InsertResourceIDs(RT_RIBBON
, 0, entry
, reinterpret_cast<INT_PTR
>(lpszType
), L
" - Ribbon element");
1837 if (wcschr(ret
.c_str(), '%'))
1838 entry
.flag
= L
"#, c-format";
1839 m_StringEntries
[ret
] = entry
;
1840 m_bDefaultRibbonTexts
++;
1846 BOOL
CResModule::ReplaceRibbon(LPCWSTR lpszType
, WORD wLanguage
)
1848 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_RIBBON
);
1849 HGLOBAL hglRibbonTemplate
;
1855 hglRibbonTemplate
= LoadResource(m_hResDll
, hrsrc
);
1857 if (!hglRibbonTemplate
)
1859 SCOPE_EXIT
{ FreeResource(hglRibbonTemplate
); };
1861 DWORD sizeres
= SizeofResource(m_hResDll
, hrsrc
);
1863 p
= static_cast<const BYTE
*>(LockResource(hglRibbonTemplate
));
1867 SCOPE_EXIT
{ UnlockResource(hglRibbonTemplate
); };
1869 std::string ss
= std::string(reinterpret_cast<const char*>(p
), sizeres
);
1870 std::wstring ssw
= CUnicodeUtils::StdGetUnicode(ss
);
1872 const std::regex
regRevMatch("<TEXT>([^<]+)</TEXT>");
1873 const std::sregex_iterator end
;
1874 for (std::sregex_iterator
it(ss
.cbegin(), ss
.cend(), regRevMatch
); it
!= end
; ++it
)
1876 std::wstring ret
= CUnicodeUtils::StdGetUnicode((*it
)[1].str());
1878 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1879 ret
= L
"<TEXT>" + ret
+ L
"</TEXT>";
1881 if (entry
.msgstr
.size())
1883 size_t buflen
= entry
.msgstr
.size() + 10;
1884 auto sbuf
= std::make_unique
<wchar_t[]>(buflen
);
1885 wcscpy_s(sbuf
.get(), buflen
, entry
.msgstr
.c_str());
1886 CUtils::StringCollapse(sbuf
.get());
1887 ReplaceWithRegex(sbuf
.get(), buflen
);
1888 std::wstring sreplace
= L
"<TEXT>";
1889 sreplace
+= sbuf
.get();
1890 sreplace
+= L
"</TEXT>";
1891 CUtils::SearchReplace(ssw
, ret
, sreplace
);
1892 m_bTranslatedRibbonTexts
++;
1895 m_bDefaultRibbonTexts
++;
1898 const std::regex
regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
1899 for (std::sregex_iterator
it(ss
.cbegin(), ss
.cend(), regRevMatchName
); it
!= end
; ++it
)
1901 std::wstring ret
= CUnicodeUtils::StdGetUnicode((*it
)[1].str());
1903 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1904 ret
= L
"</ELEMENT_NAME><NAME>" + ret
+ L
"</NAME>";
1906 if (entry
.msgstr
.size())
1908 size_t buflen
= entry
.msgstr
.size() + 10;
1909 auto sbuf
= std::make_unique
<wchar_t[]>(buflen
);
1910 wcscpy_s(sbuf
.get(), buflen
, entry
.msgstr
.c_str());
1911 CUtils::StringCollapse(sbuf
.get());
1912 ReplaceWithRegex(sbuf
.get(), buflen
);
1913 std::wstring sreplace
= L
"</ELEMENT_NAME><NAME>";
1914 sreplace
+= sbuf
.get();
1915 sreplace
+= L
"</NAME>";
1916 CUtils::SearchReplace(ssw
, ret
, sreplace
);
1917 m_bTranslatedRibbonTexts
++;
1920 m_bDefaultRibbonTexts
++;
1923 auto buf
= std::make_unique
<char[]>(ssw
.size() * 4 + 1);
1924 int lengthIncTerminator
= WideCharToMultiByte(CP_UTF8
, 0, ssw
.c_str(), -1, buf
.get(), static_cast<int>(ssw
.size()) * 4, nullptr, nullptr);
1927 if (!UpdateResource(m_hUpdateRes
, RT_RIBBON
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), buf
.get(), lengthIncTerminator
-1))
1930 if (m_wTargetLang
&& (!UpdateResource(m_hUpdateRes
, RT_RIBBON
, lpszType
, wLanguage
, nullptr, 0)))
1936 std::wstring
CResModule::ReplaceWithRegex(WCHAR
* pBuf
, size_t bufferSize
)
1938 for (const auto& t
: m_StringEntries
.m_regexes
)
1942 std::wregex
e(std::get
<0>(t
), std::regex_constants::icase
);
1943 auto replaced
= std::regex_replace(pBuf
, e
, std::get
<1>(t
));
1944 wcscpy_s(pBuf
, bufferSize
, replaced
.c_str());
1946 catch (std::exception
&)
1953 std::wstring
CResModule::ReplaceWithRegex(std::wstring
& s
)
1955 for (const auto& t
: m_StringEntries
.m_regexes
)
1959 std::wregex
e(std::get
<0>(t
), std::regex_constants::icase
);
1960 auto replaced
= std::regex_replace(s
, e
, std::get
<1>(t
));
1963 catch (std::exception
&)
1970 BOOL CALLBACK
CResModule::EnumResNameCallback(HMODULE
/*hModule*/, LPCWSTR lpszType
, LPWSTR lpszName
, LONG_PTR lParam
)
1972 auto lpResModule
= reinterpret_cast<CResModule
*>(lParam
);
1974 if (lpszType
== RT_STRING
)
1976 if (IS_INTRESOURCE(lpszName
))
1978 if (!lpResModule
->ExtractString(lpszName
))
1982 else if (lpszType
== RT_MENU
)
1984 if (IS_INTRESOURCE(lpszName
))
1986 if (!lpResModule
->ExtractMenu(lpszName
))
1990 else if (lpszType
== RT_DIALOG
)
1992 if (IS_INTRESOURCE(lpszName
))
1994 if (!lpResModule
->ExtractDialog(lpszName
))
1998 else if (lpszType
== RT_ACCELERATOR
)
2000 if (IS_INTRESOURCE(lpszName
))
2002 if (!lpResModule
->ExtractAccelerator(lpszName
))
2006 else if (lpszType
== RT_RIBBON
)
2008 if (IS_INTRESOURCE(lpszName
))
2010 if (!lpResModule
->ExtractRibbon(lpszName
))
2018 BOOL CALLBACK
CResModule::EnumResNameWriteCallback(HMODULE hModule
, LPCWSTR lpszType
, LPWSTR lpszName
, LONG_PTR lParam
)
2020 auto lpResModule
= reinterpret_cast<CResModule
*>(lParam
);
2021 return EnumResourceLanguages(hModule
, lpszType
, lpszName
, reinterpret_cast<ENUMRESLANGPROC
>(&lpResModule
->EnumResWriteLangCallback
), lParam
);
2024 BOOL CALLBACK
CResModule::EnumResWriteLangCallback(HMODULE
/*hModule*/, LPCWSTR lpszType
, LPWSTR lpszName
, WORD wLanguage
, LONG_PTR lParam
)
2027 auto lpResModule
= reinterpret_cast<CResModule
*>(lParam
);
2029 if (lpszType
== RT_STRING
)
2031 bRes
= lpResModule
->ReplaceString(lpszName
, wLanguage
);
2033 else if (lpszType
== RT_MENU
)
2035 bRes
= lpResModule
->ReplaceMenu(lpszName
, wLanguage
);
2037 else if (lpszType
== RT_DIALOG
)
2039 bRes
= lpResModule
->ReplaceDialog(lpszName
, wLanguage
);
2041 else if (lpszType
== RT_ACCELERATOR
)
2043 bRes
= lpResModule
->ReplaceAccelerator(lpszName
, wLanguage
);
2045 else if (lpszType
== RT_RIBBON
)
2047 bRes
= lpResModule
->ReplaceRibbon(lpszName
, wLanguage
);
2054 void CResModule::ReplaceStr(LPCWSTR src
, WORD
* dest
, size_t * count
, int * translated
, int * def
)
2056 wchar_t buf
[MAX_STRING_LENGTH
] = { 0 };
2058 CUtils::StringExtend(buf
);
2060 std::wstring wstr
= std::wstring(buf
);
2061 ReplaceWithRegex(buf
);
2062 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
2063 if (!entry
.msgstr
.empty())
2065 wcscpy_s(buf
, entry
.msgstr
.c_str());
2066 ReplaceWithRegex(buf
);
2067 CUtils::StringCollapse(buf
);
2069 wcscpy(reinterpret_cast<wchar_t*>(&dest
[(*count
)]), buf
);
2070 (*count
) += wcslen(buf
) + 1;
2075 if (wcscmp(buf
, wstr
.c_str()))
2078 wcscpy(reinterpret_cast<wchar_t*>(&dest
[(*count
)]), buf
);
2079 (*count
) += wcslen(buf
) + 1;
2085 wcscpy(reinterpret_cast<wchar_t*>(&dest
[(*count
)]), src
);
2086 (*count
) += wcslen(src
) + 1;
2093 static bool StartsWith(const std::string
& heystacl
, const char* needle
)
2095 return heystacl
.compare(0, strlen(needle
), needle
) == 0;
2098 static bool StartsWith(const std::wstring
& heystacl
, const wchar_t* needle
)
2100 return heystacl
.compare(0, wcslen(needle
), needle
) == 0;
2103 size_t CResModule::ScanHeaderFile(const std::wstring
& filepath
)
2107 // open the file and read the contents
2108 DWORD reqLen
= GetFullPathName(filepath
.c_str(), 0, nullptr, nullptr);
2109 auto wcfullPath
= std::make_unique
<wchar_t[]>(reqLen
+ 1);
2110 GetFullPathName(filepath
.c_str(), reqLen
, wcfullPath
.get(), nullptr);
2111 std::wstring fullpath
= wcfullPath
.get();
2114 // first treat the file as ASCII and try to get the defines
2116 std::ifstream
fin(fullpath
);
2117 std::string file_line
;
2118 while (std::getline(fin
, file_line
))
2120 auto defpos
= file_line
.find("#define");
2121 if (defpos
!= std::string::npos
)
2123 std::string text
= file_line
.substr(defpos
+ 7);
2125 auto spacepos
= text
.find(' ');
2126 if (spacepos
== std::string::npos
)
2127 spacepos
= text
.find('\t');
2128 if (spacepos
!= std::string::npos
)
2130 auto value
= atol(text
.substr(spacepos
).c_str());
2131 if (value
== 0 && text
.substr(spacepos
).find("0x") != std::string::npos
)
2132 value
= std::stoul(text
.substr(spacepos
), nullptr, 16);
2133 text
= text
.substr(0, spacepos
);
2135 if (StartsWith(text
, "IDS_") || StartsWith(text
, "AFX_IDS_") || StartsWith(text
, "AFX_IDP_"))
2137 m_currentHeaderDataStrings
[value
] = CUnicodeUtils::StdGetUnicode(text
);
2140 else if (StartsWith(text
, "IDD_") || StartsWith(text
, "AFX_IDD_"))
2142 m_currentHeaderDataDialogs
[value
] = CUnicodeUtils::StdGetUnicode(text
);
2145 else if (StartsWith(text
, "ID_") || StartsWith(text
, "AFX_ID_"))
2147 m_currentHeaderDataMenus
[value
] = CUnicodeUtils::StdGetUnicode(text
);
2150 else if (StartsWith(text
, "cmd"))
2152 m_currentHeaderDataStrings
[value
] = CUnicodeUtils::StdGetUnicode(text
);
2155 else if (text
.find("_RESID") != std::string::npos
)
2157 m_currentHeaderDataStrings
[value
] = CUnicodeUtils::StdGetUnicode(text
);
2166 // now try the same with the file treated as utf16
2168 // open as a byte stream
2169 std::ifstream
wfin(fullpath
, std::ios::binary
);
2170 // apply BOM-sensitive UTF-16 facet
2171 //std::wifstream wfin(fullpath);
2172 std::string file_line
;
2173 while (std::getline(wfin
, file_line
))
2175 auto defpos
= file_line
.find("#define");
2176 if (defpos
!= std::wstring::npos
)
2178 std::wstring text
= CUnicodeUtils::StdGetUnicode(file_line
.substr(defpos
+ 7));
2180 auto spacepos
= text
.find(' ');
2181 if (spacepos
== std::wstring::npos
)
2182 spacepos
= text
.find('\t');
2183 if (spacepos
!= std::wstring::npos
)
2185 auto value
= _wtol(text
.substr(spacepos
).c_str());
2186 if (value
== 0 && text
.substr(spacepos
).find(L
"0x") != std::wstring::npos
)
2187 value
= std::stoul(text
.substr(spacepos
), nullptr, 16);
2188 text
= text
.substr(0, spacepos
);
2190 if (StartsWith(text
, L
"IDS_") || StartsWith(text
, L
"AFX_IDS_") || StartsWith(text
, L
"AFX_IDP_"))
2192 m_currentHeaderDataStrings
[value
] = text
;
2195 else if (StartsWith(text
, L
"IDD_") || StartsWith(text
, L
"AFX_IDD_"))
2197 m_currentHeaderDataDialogs
[value
] = text
;
2200 else if (StartsWith(text
, L
"ID_") || StartsWith(text
, L
"AFX_ID_"))
2202 m_currentHeaderDataMenus
[value
] = text
;
2205 else if (StartsWith(text
, L
"cmd"))
2207 m_currentHeaderDataStrings
[value
] = text
;
2210 else if (text
.find(L
"_RESID") != std::string::npos
)
2212 m_currentHeaderDataStrings
[value
] = text
;
2223 void CResModule::InsertResourceIDs(LPCWSTR lpType
, INT_PTR mainId
, RESOURCEENTRY
& entry
, INT_PTR id
, LPCWSTR infotext
)
2225 if (lpType
== RT_DIALOG
)
2227 auto foundIt
= m_currentHeaderDataDialogs
.find(mainId
);
2228 if (foundIt
!= m_currentHeaderDataDialogs
.end())
2229 entry
.resourceIDs
.insert(L
"Dialog " + foundIt
->second
+ L
": Control id " + NumToStr(id
) + infotext
);
2231 entry
.resourceIDs
.insert(NumToStr(id
) + infotext
);
2233 else if (lpType
== RT_STRING
)
2235 auto foundIt
= m_currentHeaderDataStrings
.find(id
);
2236 if (foundIt
!= m_currentHeaderDataStrings
.end())
2237 entry
.resourceIDs
.insert(foundIt
->second
+ infotext
);
2239 entry
.resourceIDs
.insert(NumToStr(id
) + infotext
);
2241 else if (lpType
== RT_MENU
)
2243 auto foundIt
= m_currentHeaderDataMenus
.find(id
);
2244 if (foundIt
!= m_currentHeaderDataMenus
.end())
2245 entry
.resourceIDs
.insert(foundIt
->second
+ infotext
);
2247 entry
.resourceIDs
.insert(NumToStr(id
) + infotext
);
2249 else if (lpType
== RT_RIBBON
&& infotext
&& wcsstr(infotext
, L
"ID") == infotext
)
2250 entry
.resourceIDs
.insert(infotext
);
2252 entry
.resourceIDs
.insert(NumToStr(id
) + infotext
);
2255 bool CResModule::AdjustCheckSum(const std::wstring
& resFile
)
2257 HANDLE hFile
= INVALID_HANDLE_VALUE
;
2258 HANDLE hFileMapping
= nullptr;
2259 PVOID pBaseAddress
= nullptr;
2263 hFile
= CreateFile(resFile
.c_str(), FILE_READ_DATA
| FILE_WRITE_DATA
, 0, nullptr, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, nullptr);
2264 if (hFile
== INVALID_HANDLE_VALUE
)
2265 throw GetLastError();
2267 hFileMapping
= CreateFileMapping(hFile
, nullptr, PAGE_READWRITE
, 0, 0, nullptr);
2269 throw GetLastError();
2271 pBaseAddress
= MapViewOfFile(hFileMapping
, FILE_MAP_ALL_ACCESS
, 0, 0, 0);
2273 throw GetLastError();
2275 auto fileSize
= GetFileSize(hFile
, nullptr);
2276 if (fileSize
== INVALID_FILE_SIZE
)
2277 throw GetLastError();
2278 DWORD dwChecksum
= 0;
2279 DWORD dwHeaderSum
= 0;
2280 CheckSumMappedFile(pBaseAddress
, fileSize
, &dwHeaderSum
, &dwChecksum
);
2282 PIMAGE_DOS_HEADER pDOSHeader
= static_cast<PIMAGE_DOS_HEADER
>(pBaseAddress
);
2283 if (pDOSHeader
->e_magic
!= IMAGE_DOS_SIGNATURE
)
2284 throw GetLastError();
2286 PIMAGE_NT_HEADERS pNTHeader
= reinterpret_cast<PIMAGE_NT_HEADERS
>(static_cast<PBYTE
>(pBaseAddress
) + pDOSHeader
->e_lfanew
);
2287 if (pNTHeader
->Signature
!= IMAGE_NT_SIGNATURE
)
2288 throw GetLastError();
2290 SetLastError(ERROR_SUCCESS
);
2292 DWORD
* pChecksum
= &(pNTHeader
->OptionalHeader
.CheckSum
);
2293 *pChecksum
= dwChecksum
;
2295 UnmapViewOfFile(pBaseAddress
);
2296 CloseHandle(hFileMapping
);
2302 UnmapViewOfFile(pBaseAddress
);
2304 CloseHandle(hFileMapping
);
2305 if (hFile
!= INVALID_HANDLE_VALUE
)