1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008, 2010-2012 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "ResModule.h"
21 #include "../Utils/SysInfo.h"
26 #define RT_RIBBON MAKEINTRESOURCE(28)
30 #define MYERROR {CUtils::Error(); return FALSE;}
32 CResModule::CResModule(void)
33 : m_bTranslatedStrings(0)
34 , m_bDefaultStrings(0)
35 , m_bTranslatedDialogStrings(0)
36 , m_bDefaultDialogStrings(0)
37 , m_bTranslatedMenuStrings(0)
38 , m_bDefaultMenuStrings(0)
39 , m_bTranslatedAcceleratorStrings(0)
40 , m_bDefaultAcceleratorStrings(0)
41 , m_bTranslatedRibbonTexts(0)
42 , m_bDefaultRibbonTexts(0)
48 , m_bAdjustEOLs(false)
52 CResModule::~CResModule(void)
56 BOOL
CResModule::ExtractResources(std::vector
<std::wstring
> filelist
, LPCTSTR lpszPOFilePath
, BOOL bNoUpdate
, LPCTSTR lpszHeaderFile
)
58 for (std::vector
<std::wstring
>::iterator I
= filelist
.begin(); I
!= filelist
.end(); ++I
)
60 m_hResDll
= LoadLibraryEx(I
->c_str(), NULL
, LOAD_LIBRARY_AS_IMAGE_RESOURCE
|LOAD_LIBRARY_AS_DATAFILE
);
61 if (m_hResDll
== NULL
)
64 size_t nEntries
= m_StringEntries
.size();
65 // fill in the std::map with all translatable entries
68 _ftprintf(stdout
, _T("Extracting StringTable...."));
69 EnumResourceNames(m_hResDll
, RT_STRING
, EnumResNameCallback
, (LONG_PTR
)this);
71 _ftprintf(stdout
, _T("%4d Strings\n"), m_StringEntries
.size()-nEntries
);
72 nEntries
= m_StringEntries
.size();
75 _ftprintf(stdout
, _T("Extracting Dialogs........"));
76 EnumResourceNames(m_hResDll
, RT_DIALOG
, EnumResNameCallback
, (LONG_PTR
)this);
78 _ftprintf(stdout
, _T("%4d Strings\n"), m_StringEntries
.size()-nEntries
);
79 nEntries
= m_StringEntries
.size();
82 _ftprintf(stdout
, _T("Extracting Menus.........."));
83 EnumResourceNames(m_hResDll
, RT_MENU
, EnumResNameCallback
, (LONG_PTR
)this);
85 _ftprintf(stdout
, _T("%4d Strings\n"), m_StringEntries
.size()-nEntries
);
86 nEntries
= m_StringEntries
.size();
88 _ftprintf(stdout
, _T("Extracting Accelerators..."));
89 EnumResourceNames(m_hResDll
, RT_ACCELERATOR
, EnumResNameCallback
, (LONG_PTR
)this);
91 _ftprintf(stdout
, _T("%4d Accelerators\n"), m_StringEntries
.size()-nEntries
);
92 nEntries
= m_StringEntries
.size();
94 _ftprintf(stdout
, _T("Extracting Ribbons........"));
95 EnumResourceNames(m_hResDll
, RT_RIBBON
, EnumResNameCallback
, (LONG_PTR
)this);
97 _ftprintf(stdout
, _T("%4d Strings\n"), m_StringEntries
.size()-nEntries
);
98 nEntries
= m_StringEntries
.size();
100 // parse a probably existing file and update the translations which are
102 m_StringEntries
.ParseFile(lpszPOFilePath
, !bNoUpdate
, m_bAdjustEOLs
);
104 FreeLibrary(m_hResDll
);
107 // at last, save the new file
108 return m_StringEntries
.SaveFile(lpszPOFilePath
, lpszHeaderFile
);
111 BOOL
CResModule::ExtractResources(LPCTSTR lpszSrcLangDllPath
, LPCTSTR lpszPoFilePath
, BOOL bNoUpdate
, LPCTSTR lpszHeaderFile
)
113 m_hResDll
= LoadLibraryEx(lpszSrcLangDllPath
, NULL
, LOAD_LIBRARY_AS_IMAGE_RESOURCE
|LOAD_LIBRARY_AS_DATAFILE
);
114 if (m_hResDll
== NULL
)
118 // fill in the std::map with all translatable entries
121 _ftprintf(stdout
, _T("Extracting StringTable...."));
122 EnumResourceNames(m_hResDll
, RT_STRING
, EnumResNameCallback
, (LONG_PTR
)this);
124 _ftprintf(stdout
, _T("%4d Strings\n"), m_StringEntries
.size());
125 nEntries
= m_StringEntries
.size();
128 _ftprintf(stdout
, _T("Extracting Dialogs........"));
129 EnumResourceNames(m_hResDll
, RT_DIALOG
, EnumResNameCallback
, (LONG_PTR
)this);
131 _ftprintf(stdout
, _T("%4d Strings\n"), m_StringEntries
.size()-nEntries
);
132 nEntries
= m_StringEntries
.size();
135 _ftprintf(stdout
, _T("Extracting Menus.........."));
136 EnumResourceNames(m_hResDll
, RT_MENU
, EnumResNameCallback
, (LONG_PTR
)this);
138 _ftprintf(stdout
, _T("%4d Strings\n"), m_StringEntries
.size()-nEntries
);
139 nEntries
= m_StringEntries
.size();
142 _ftprintf(stdout
, _T("Extracting Accelerators..."));
143 EnumResourceNames(m_hResDll
, RT_ACCELERATOR
, EnumResNameCallback
, (LONG_PTR
)this);
145 _ftprintf(stdout
, _T("%4d Accelerators\n"), m_StringEntries
.size()-nEntries
);
146 nEntries
= m_StringEntries
.size();
148 // parse a probably existing file and update the translations which are
150 m_StringEntries
.ParseFile(lpszPoFilePath
, !bNoUpdate
, m_bAdjustEOLs
);
152 // at last, save the new file
153 if (!m_StringEntries
.SaveFile(lpszPoFilePath
, lpszHeaderFile
))
156 FreeLibrary(m_hResDll
);
161 FreeLibrary(m_hResDll
);
165 BOOL
CResModule::CreateTranslatedResources(LPCTSTR lpszSrcLangDllPath
, LPCTSTR lpszDestLangDllPath
, LPCTSTR lpszPOFilePath
)
167 if (!CopyFile(lpszSrcLangDllPath
, lpszDestLangDllPath
, FALSE
))
173 if (SysInfo::Instance().IsVistaOrLater())
174 m_hResDll
= LoadLibraryEx (lpszSrcLangDllPath
, NULL
, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
|LOAD_LIBRARY_AS_IMAGE_RESOURCE
|LOAD_IGNORE_CODE_AUTHZ_LEVEL
);
176 m_hResDll
= LoadLibraryEx (lpszSrcLangDllPath
, NULL
, LOAD_LIBRARY_AS_IMAGE_RESOURCE
|LOAD_IGNORE_CODE_AUTHZ_LEVEL
);
177 if (m_hResDll
== NULL
)
180 } while ((m_hResDll
== NULL
)&&(count
< 10));
182 if (m_hResDll
== NULL
)
185 sDestFile
= std::wstring(lpszDestLangDllPath
);
187 // get all translated strings
188 if (!m_StringEntries
.ParseFile(lpszPOFilePath
, FALSE
, m_bAdjustEOLs
))
190 m_bTranslatedStrings
= 0;
191 m_bDefaultStrings
= 0;
192 m_bTranslatedDialogStrings
= 0;
193 m_bDefaultDialogStrings
= 0;
194 m_bTranslatedMenuStrings
= 0;
195 m_bDefaultMenuStrings
= 0;
196 m_bTranslatedAcceleratorStrings
= 0;
197 m_bDefaultAcceleratorStrings
= 0;
203 m_hUpdateRes
= BeginUpdateResource(sDestFile
.c_str(), FALSE
);
204 if (m_hUpdateRes
== NULL
)
207 } while ((m_hUpdateRes
== NULL
)&&(count
< 10));
209 if (m_hUpdateRes
== NULL
)
214 _ftprintf(stdout
, _T("Translating StringTable..."));
215 bRes
= EnumResourceNames(m_hResDll
, RT_STRING
, EnumResNameWriteCallback
, (LONG_PTR
)this);
217 _ftprintf(stdout
, _T("%4d translated, %4d not translated\n"), m_bTranslatedStrings
, m_bDefaultStrings
);
220 _ftprintf(stdout
, _T("Translating Dialogs......."));
221 bRes
= EnumResourceNames(m_hResDll
, RT_DIALOG
, EnumResNameWriteCallback
, (LONG_PTR
)this);
223 _ftprintf(stdout
, _T("%4d translated, %4d not translated\n"), m_bTranslatedDialogStrings
, m_bDefaultDialogStrings
);
226 _ftprintf(stdout
, _T("Translating Menus........."));
227 bRes
= EnumResourceNames(m_hResDll
, RT_MENU
, EnumResNameWriteCallback
, (LONG_PTR
)this);
229 _ftprintf(stdout
, _T("%4d translated, %4d not translated\n"), m_bTranslatedMenuStrings
, m_bDefaultMenuStrings
);
232 _ftprintf(stdout
, _T("Translating Accelerators.."));
233 bRes
= EnumResourceNames(m_hResDll
, RT_ACCELERATOR
, EnumResNameWriteCallback
, (LONG_PTR
)this);
235 _ftprintf(stdout
, _T("%4d translated, %4d not translated\n"), m_bTranslatedAcceleratorStrings
, m_bDefaultAcceleratorStrings
);
238 _ftprintf(stdout
, _T("Translating Ribbons......."));
239 bRes
= EnumResourceNames(m_hResDll
, RT_RIBBON
, EnumResNameWriteCallback
, (LONG_PTR
)this);
241 _ftprintf(stdout
, _T("%4d translated, %4d not translated\n"), m_bTranslatedRibbonTexts
, m_bDefaultRibbonTexts
);
243 if (!EndUpdateResource(m_hUpdateRes
, !bRes
))
246 FreeLibrary(m_hResDll
);
250 FreeLibrary(m_hResDll
);
254 BOOL
CResModule::ExtractString(LPCTSTR lpszType
)
256 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_STRING
);
257 HGLOBAL hglStringTable
;
262 hglStringTable
= LoadResource(m_hResDll
, hrsrc
);
266 p
= (LPWSTR
)LockResource(hglStringTable
);
270 /* [Block of 16 strings. The strings are Pascal style with a WORD
271 length preceding the string. 16 strings are always written, even
272 if not all slots are full. Any slots in the block with no string
273 have a zero WORD for the length.]
276 //first check how much memory we need
278 for (int i
=0; i
<16; ++i
)
280 int len
= GET_WORD(pp
);
282 std::wstring msgid
= std::wstring(pp
, len
);
283 WCHAR
* pBuf
= new WCHAR
[MAX_STRING_LENGTH
*2];
284 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
*2*sizeof(WCHAR
));
285 wcscpy(pBuf
, msgid
.c_str());
286 CUtils::StringExtend(pBuf
);
290 std::wstring str
= std::wstring(pBuf
);
291 RESOURCEENTRY entry
= m_StringEntries
[str
];
292 entry
.resourceIDs
.insert((DWORD
)lpszType
);
293 if (wcschr(str
.c_str(), '%'))
294 entry
.flag
= _T("#, c-format");
295 m_StringEntries
[str
] = entry
;
300 UnlockResource(hglStringTable
);
301 FreeResource(hglStringTable
);
304 UnlockResource(hglStringTable
);
305 FreeResource(hglStringTable
);
309 BOOL
CResModule::ReplaceString(LPCTSTR lpszType
, WORD wLanguage
)
311 HRSRC hrsrc
= FindResourceEx(m_hResDll
, RT_STRING
, lpszType
, wLanguage
);
312 HGLOBAL hglStringTable
;
317 hglStringTable
= LoadResource(m_hResDll
, hrsrc
);
321 p
= (LPWSTR
)LockResource(hglStringTable
);
325 /* [Block of 16 strings. The strings are Pascal style with a WORD
326 length preceding the string. 16 strings are always written, even
327 if not all slots are full. Any slots in the block with no string
328 have a zero WORD for the length.]
331 //first check how much memory we need
334 for (int i
=0; i
<16; ++i
)
337 size_t len
= GET_WORD(pp
);
339 std::wstring msgid
= std::wstring(pp
, len
);
340 WCHAR
* pBuf
= new WCHAR
[MAX_STRING_LENGTH
*2];
341 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
*2*sizeof(WCHAR
));
342 wcscpy(pBuf
, msgid
.c_str());
343 CUtils::StringExtend(pBuf
);
344 msgid
= std::wstring(pBuf
);
346 RESOURCEENTRY resEntry
;
347 resEntry
= m_StringEntries
[msgid
];
348 wcscpy(pBuf
, resEntry
.msgstr
.c_str());
349 CUtils::StringCollapse(pBuf
);
350 size_t newlen
= wcslen(pBuf
);
359 WORD
* newTable
= new WORD
[nMem
+ (nMem
% 2)];
360 SecureZeroMemory(newTable
, (nMem
+ (nMem
% 2))*2);
363 for (int i
=0; i
<16; ++i
)
365 int len
= GET_WORD(p
);
367 std::wstring msgid
= std::wstring(p
, len
);
368 WCHAR
* pBuf
= new WCHAR
[MAX_STRING_LENGTH
*2];
369 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
*2*sizeof(WCHAR
));
370 wcscpy(pBuf
, msgid
.c_str());
371 CUtils::StringExtend(pBuf
);
372 msgid
= std::wstring(pBuf
);
374 RESOURCEENTRY resEntry
;
375 resEntry
= m_StringEntries
[msgid
];
376 wcscpy(pBuf
, resEntry
.msgstr
.c_str());
377 CUtils::StringCollapse(pBuf
);
378 size_t newlen
= wcslen(pBuf
);
381 newTable
[index
++] = (WORD
)newlen
;
382 wcsncpy((wchar_t *)&newTable
[index
], pBuf
, newlen
);
384 m_bTranslatedStrings
++;
388 newTable
[index
++] = (WORD
)len
;
390 wcsncpy((wchar_t *)&newTable
[index
], p
, len
);
399 if (!UpdateResource(m_hUpdateRes
, RT_STRING
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newTable
, (DWORD
)(nMem
+ (nMem
% 2))*2))
405 if ((m_wTargetLang
)&&(!UpdateResource(m_hUpdateRes
, RT_STRING
, lpszType
, wLanguage
, NULL
, 0)))
411 UnlockResource(hglStringTable
);
412 FreeResource(hglStringTable
);
415 UnlockResource(hglStringTable
);
416 FreeResource(hglStringTable
);
420 BOOL
CResModule::ExtractMenu(LPCTSTR lpszType
)
422 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_MENU
);
423 HGLOBAL hglMenuTemplate
;
424 WORD version
, offset
;
430 hglMenuTemplate
= LoadResource(m_hResDll
, hrsrc
);
432 if (!hglMenuTemplate
)
435 p
= (const WORD
*)LockResource(hglMenuTemplate
);
440 // Standard MENU resource
441 //struct MenuHeader {
442 // WORD wVersion; // Currently zero
443 // WORD cbHeaderSize; // Also zero
447 //struct MenuExHeader {
448 // WORD wVersion; // One
453 version
= GET_WORD(p
);
461 offset
= GET_WORD(p
);
464 if (!ParseMenuResource(p
))
470 offset
= GET_WORD(p
);
472 //dwHelpId = GET_DWORD(p);
473 if (!ParseMenuExResource(p0
+ offset
))
481 UnlockResource(hglMenuTemplate
);
482 FreeResource(hglMenuTemplate
);
486 UnlockResource(hglMenuTemplate
);
487 FreeResource(hglMenuTemplate
);
491 BOOL
CResModule::ReplaceMenu(LPCTSTR lpszType
, WORD wLanguage
)
493 HRSRC hrsrc
= FindResourceEx(m_hResDll
, RT_MENU
, lpszType
, wLanguage
);
494 HGLOBAL hglMenuTemplate
;
495 WORD version
, offset
;
500 MYERROR
; //just the language wasn't found
502 hglMenuTemplate
= LoadResource(m_hResDll
, hrsrc
);
504 if (!hglMenuTemplate
)
507 p
= (LPWSTR
)LockResource(hglMenuTemplate
);
512 //struct MenuHeader {
513 // WORD wVersion; // Currently zero
514 // WORD cbHeaderSize; // Also zero
518 //struct MenuExHeader {
519 // WORD wVersion; // One
524 version
= GET_WORD(p
);
532 offset
= GET_WORD(p
);
536 if (!CountMemReplaceMenuResource((WORD
*)p
, &nMem
, NULL
))
538 WORD
* newMenu
= new WORD
[nMem
+ (nMem
% 2)+2];
539 SecureZeroMemory(newMenu
, (nMem
+ (nMem
% 2)+2)*2);
540 size_t index
= 2; // MenuHeader has 2 WORDs zero
541 if (!CountMemReplaceMenuResource((WORD
*)p
, &index
, newMenu
))
547 if (!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newMenu
, (DWORD
)(nMem
+ (nMem
% 2)+2)*2))
553 if ((m_wTargetLang
)&&(!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, wLanguage
, NULL
, 0)))
563 offset
= GET_WORD(p
);
565 //dwHelpId = GET_DWORD(p);
567 if (!CountMemReplaceMenuExResource((WORD
*)(p0
+ offset
), &nMem
, NULL
))
569 WORD
* newMenu
= new WORD
[nMem
+ (nMem
% 2) + 4];
570 SecureZeroMemory(newMenu
, (nMem
+ (nMem
% 2) + 4) * 2);
571 CopyMemory(newMenu
, p0
, 2 * sizeof(WORD
) + sizeof(DWORD
));
572 size_t index
= 4; // MenuExHeader has 2 x WORD + 1 x DWORD
573 if (!CountMemReplaceMenuExResource((WORD
*)(p0
+ offset
), &index
, newMenu
))
579 if (!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newMenu
, (DWORD
)(nMem
+ (nMem
% 2) + 4) * 2))
585 if ((m_wTargetLang
)&&(!UpdateResource(m_hUpdateRes
, RT_MENU
, lpszType
, wLanguage
, NULL
, 0)))
597 UnlockResource(hglMenuTemplate
);
598 FreeResource(hglMenuTemplate
);
602 UnlockResource(hglMenuTemplate
);
603 FreeResource(hglMenuTemplate
);
607 const WORD
* CResModule::ParseMenuResource(const WORD
* res
)
613 //struct PopupMenuItem {
615 // WCHAR szItemText[];
617 //struct NormalMenuItem {
620 // WCHAR szItemText[];
625 flags
= GET_WORD(res
);
627 if (!(flags
& MF_POPUP
))
629 id
= GET_WORD(res
); //normal menu item
633 id
= (WORD
)-1; //popup menu item
636 size_t l
= wcslen(str
)+1;
639 if (flags
& MF_POPUP
)
641 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
642 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
644 CUtils::StringExtend(pBuf
);
646 std::wstring wstr
= std::wstring(pBuf
);
647 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
649 entry
.resourceIDs
.insert(id
);
651 m_StringEntries
[wstr
] = entry
;
654 if ((res
= ParseMenuResource(res
))==0)
659 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
660 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
662 CUtils::StringExtend(pBuf
);
664 std::wstring wstr
= std::wstring(pBuf
);
665 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
666 entry
.resourceIDs
.insert(id
);
668 TCHAR szTempBuf
[1024];
669 _stprintf(szTempBuf
, _T("#: MenuEntry; ID:%u"), id
);
670 MENUENTRY menu_entry
;
672 menu_entry
.reference
= szTempBuf
;
673 menu_entry
.msgstr
= wstr
;
675 m_StringEntries
[wstr
] = entry
;
676 m_MenuEntries
[id
] = menu_entry
;
679 } while (!(flags
& MF_END
));
683 const WORD
* CResModule::CountMemReplaceMenuResource(const WORD
* res
, size_t * wordcount
, WORD
* newMenu
)
688 //struct PopupMenuItem {
690 // WCHAR szItemText[];
692 //struct NormalMenuItem {
695 // WCHAR szItemText[];
700 flags
= GET_WORD(res
);
705 newMenu
[(*wordcount
)++] = flags
;
706 if (!(flags
& MF_POPUP
))
708 id
= GET_WORD(res
); //normal menu item
713 newMenu
[(*wordcount
)++] = id
;
716 id
= (WORD
)-1; //popup menu item
718 if (flags
& MF_POPUP
)
720 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
721 res
+= wcslen((LPCWSTR
)res
) + 1;
723 if ((res
= CountMemReplaceMenuResource(res
, wordcount
, newMenu
))==0)
728 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
729 res
+= wcslen((LPCWSTR
)res
) + 1;
734 wcscpy((wchar_t *)&newMenu
[(*wordcount
)], (LPCWSTR
)res
);
735 (*wordcount
) += wcslen((LPCWSTR
)res
) + 1;
736 res
+= wcslen((LPCWSTR
)res
) + 1;
738 } while (!(flags
& MF_END
));
742 const WORD
* CResModule::ParseMenuExResource(const WORD
* res
)
744 DWORD dwType
, menuId
;
748 //struct MenuExItem {
754 // DWORD dwHelpId; - Popup menu only
759 dwType
= GET_DWORD(res
);
761 //dwState = GET_DWORD(res);
763 menuId
= GET_DWORD(res
);
765 bResInfo
= GET_WORD(res
);
769 size_t l
= wcslen(str
)+1;
771 // Align to DWORD boundary
772 res
+= ((((WORD
)res
+ 3) & ~3) - (WORD
)res
)/sizeof(WORD
);
774 if (dwType
& MFT_SEPARATOR
)
779 // Popup menu - note this can also have a non-zero ID
782 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
783 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
785 CUtils::StringExtend(pBuf
);
787 std::wstring wstr
= std::wstring(pBuf
);
788 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
789 // Popup has a DWORD help entry on a DWORD boundary - skip over it
792 entry
.resourceIDs
.insert(menuId
);
793 TCHAR szTempBuf
[1024];
794 _stprintf(szTempBuf
, _T("#: MenuExPopupEntry; ID:%u"), menuId
);
795 MENUENTRY menu_entry
;
796 menu_entry
.wID
= (WORD
)menuId
;
797 menu_entry
.reference
= szTempBuf
;
798 menu_entry
.msgstr
= wstr
;
799 m_StringEntries
[wstr
] = entry
;
800 m_MenuEntries
[(WORD
)menuId
] = menu_entry
;
803 if ((res
= ParseMenuExResource(res
)) == 0)
805 } else if (menuId
!= 0)
807 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
808 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
810 CUtils::StringExtend(pBuf
);
812 std::wstring wstr
= std::wstring(pBuf
);
813 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
814 entry
.resourceIDs
.insert(menuId
);
816 TCHAR szTempBuf
[1024];
817 _stprintf(szTempBuf
, _T("#: MenuExEntry; ID:%u"), menuId
);
818 MENUENTRY menu_entry
;
819 menu_entry
.wID
= (WORD
)menuId
;
820 menu_entry
.reference
= szTempBuf
;
821 menu_entry
.msgstr
= wstr
;
822 m_StringEntries
[wstr
] = entry
;
823 m_MenuEntries
[(WORD
)menuId
] = menu_entry
;
826 } while (!(bResInfo
& 0x80));
830 const WORD
* CResModule::CountMemReplaceMenuExResource(const WORD
* res
, size_t * wordcount
, WORD
* newMenu
)
832 DWORD dwType
, menuId
;
836 //struct MenuExItem {
842 // DWORD dwHelpId; - Popup menu only
848 dwType
= GET_DWORD(res
);
850 //dwState = GET_DWORD(res);
852 menuId
= GET_DWORD(res
);
854 bResInfo
= GET_WORD(res
);
857 if (newMenu
!= NULL
) {
858 CopyMemory(&newMenu
[*wordcount
], p0
, 7 * sizeof(WORD
));
862 if (dwType
& MFT_SEPARATOR
) {
871 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
872 res
+= wcslen((LPCWSTR
)res
) + 1;
874 res
+= ((((WORD
)res
+ 3) & ~3) - (WORD
)res
)/sizeof(WORD
);
875 if ((*wordcount
) & 0x01)
879 CopyMemory(&newMenu
[*wordcount
], res
, sizeof(DWORD
)); // Copy Help ID
884 if ((res
= CountMemReplaceMenuExResource(res
, wordcount
, newMenu
)) == 0)
887 else if (menuId
!= 0)
889 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
890 res
+= wcslen((LPCWSTR
)res
) + 1;
895 wcscpy((wchar_t *)&newMenu
[(*wordcount
)], (LPCWSTR
)res
);
896 (*wordcount
) += wcslen((LPCWSTR
)res
) + 1;
897 res
+= wcslen((LPCWSTR
)res
) + 1;
900 res
+= ((((WORD
)res
+ 3) & ~3) - (WORD
)res
)/sizeof(WORD
);
901 if ((*wordcount
) & 0x01)
903 } while (!(bResInfo
& 0x80));
907 BOOL
CResModule::ExtractAccelerator(LPCTSTR lpszType
)
909 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_ACCELERATOR
);
911 WORD fFlags
, wAnsi
, wID
;
918 hglAccTable
= LoadResource(m_hResDll
, hrsrc
);
923 p
= (const WORD
*)LockResource(hglAccTable
);
929 struct ACCELTABLEENTRY
931 WORD fFlags; FVIRTKEY, FSHIFT, FCONTROL, FALT, 0x80 - Last in a table
932 WORD wAnsi; ANSI character
933 WORD wId; Keyboard accelerator passed to windows
934 WORD padding; # bytes added to ensure aligned to DWORD boundary
940 fFlags
= GET_WORD(p
);
946 p
++; // Skip over padding
948 if ((fFlags
& 0x80) == 0x80)
953 if ((wAnsi
< 0x30) ||
955 (wAnsi
>= 0x3A && wAnsi
<= 0x40))
958 std::unique_ptr
<WCHAR
[]> pBuf(new WCHAR
[1024]);
959 std::unique_ptr
<WCHAR
[]> pBuf2(new WCHAR
[1024]);
960 SecureZeroMemory(pBuf
.get(), 1024 * sizeof(WCHAR
));
961 SecureZeroMemory(pBuf2
.get(), 1024 * sizeof(WCHAR
));
963 // include the menu ID in the msgid to make sure that 'duplicate'
964 // accelerator keys are listed in the po-file.
965 // without this, we would get entries like this:
966 //#. Accelerator Entry for Menu ID:32809; '&Filter'
967 //#. Accelerator Entry for Menu ID:57636; '&Find'
968 //#: Corresponding Menu ID:32771; '&Find'
972 // Since "filter" and "find" are most likely translated to words starting
973 // with different letters, we need to have a separate accelerator entry
975 _stprintf(pBuf
.get(), _T("ID:%u:"), wID
);
977 // EXACTLY 5 characters long "ACS+X"
978 // V = Virtual key (or blank if not used)
979 // A = Alt key (or blank if not used)
980 // C = Ctrl key (or blank if not used)
981 // S = Shift key (or blank if not used)
982 // X = upper case character
983 // e.g. "V CS+Q" == Ctrl + Shift + 'Q'
984 if ((fFlags
& FVIRTKEY
) == FVIRTKEY
) // 0x01
985 _tcscat(pBuf
.get(), _T("V"));
987 _tcscat(pBuf
.get(), _T(" "));
989 if ((fFlags
& FALT
) == FALT
) // 0x10
990 _tcscat(pBuf
.get(), _T("A"));
992 _tcscat(pBuf
.get(), _T(" "));
994 if ((fFlags
& FCONTROL
) == FCONTROL
) // 0x08
995 _tcscat(pBuf
.get(), _T("C"));
997 _tcscat(pBuf
.get(), _T(" "));
999 if ((fFlags
& FSHIFT
) == FSHIFT
) // 0x04
1000 _tcscat(pBuf
.get(), _T("S"));
1002 _tcscat(pBuf
.get(), _T(" "));
1004 _stprintf(pBuf2
.get(), _T("%s+%c"), pBuf
.get(), wAnsi
);
1006 std::wstring wstr
= std::wstring(pBuf2
.get());
1007 RESOURCEENTRY AKey_entry
= m_StringEntries
[wstr
];
1009 TCHAR szTempBuf
[1024];
1010 SecureZeroMemory(szTempBuf
, sizeof (szTempBuf
));
1011 std::wstring wmenu
= _T("");
1012 pME_iter
= m_MenuEntries
.find(wID
);
1013 if (pME_iter
!= m_MenuEntries
.end())
1015 wmenu
= pME_iter
->second
.msgstr
;
1017 _stprintf(szTempBuf
, _T("#. Accelerator Entry for Menu ID:%u; '%s'"), wID
, wmenu
.c_str());
1018 AKey_entry
.automaticcomments
.push_back(std::wstring(szTempBuf
));
1020 m_StringEntries
[wstr
] = AKey_entry
;
1023 UnlockResource(hglAccTable
);
1024 FreeResource(hglAccTable
);
1028 UnlockResource(hglAccTable
);
1029 FreeResource(hglAccTable
);
1033 BOOL
CResModule::ReplaceAccelerator(LPCTSTR lpszType
, WORD wLanguage
)
1035 LPACCEL lpaccelNew
; // pointer to new accelerator table
1036 HACCEL haccelOld
; // handle to old accelerator table
1037 int cAccelerators
; // number of accelerators in table
1038 HGLOBAL hglAccTableNew
;
1042 haccelOld
= LoadAccelerators(m_hResDll
, lpszType
);
1044 if (haccelOld
== NULL
)
1047 cAccelerators
= CopyAcceleratorTable(haccelOld
, NULL
, 0);
1049 lpaccelNew
= (LPACCEL
) LocalAlloc(LPTR
, cAccelerators
* sizeof(ACCEL
));
1051 if (lpaccelNew
== NULL
)
1054 CopyAcceleratorTable(haccelOld
, lpaccelNew
, cAccelerators
);
1056 // Find the accelerator that the user modified
1057 // and change its flags and virtual-key code
1062 static const size_t BufferSize
= 1024;
1063 std::unique_ptr
<WCHAR
[]> pBuf(new WCHAR
[BufferSize
]);
1064 std::unique_ptr
<WCHAR
[]> pBuf2(new WCHAR
[BufferSize
]);
1065 for (i
= 0; i
< cAccelerators
; i
++)
1067 if ((lpaccelNew
[i
].key
< 0x30) ||
1068 (lpaccelNew
[i
].key
> 0x5A) ||
1069 (lpaccelNew
[i
].key
>= 0x3A && lpaccelNew
[i
].key
<= 0x40))
1072 SecureZeroMemory(pBuf
.get(), 1024 * sizeof(WCHAR
));
1073 SecureZeroMemory(pBuf2
.get(), 1024 * sizeof(WCHAR
));
1075 _stprintf(pBuf
.get(), _T("ID:%d:"), lpaccelNew
[i
].cmd
);
1077 // get original key combination
1078 if ((lpaccelNew
[i
].fVirt
& FVIRTKEY
) == FVIRTKEY
) // 0x01
1079 _tcscat(pBuf
.get(), _T("V"));
1081 _tcscat(pBuf
.get(), _T(" "));
1083 if ((lpaccelNew
[i
].fVirt
& FALT
) == FALT
) // 0x10
1084 _tcscat(pBuf
.get(), _T("A"));
1086 _tcscat(pBuf
.get(), _T(" "));
1088 if ((lpaccelNew
[i
].fVirt
& FCONTROL
) == FCONTROL
) // 0x08
1089 _tcscat(pBuf
.get(), _T("C"));
1091 _tcscat(pBuf
.get(), _T(" "));
1093 if ((lpaccelNew
[i
].fVirt
& FSHIFT
) == FSHIFT
) // 0x04
1094 _tcscat(pBuf
.get(), _T("S"));
1096 _tcscat(pBuf
.get(), _T(" "));
1098 _stprintf(pBuf2
.get(), _T("%s+%c"), pBuf
.get(), lpaccelNew
[i
].key
);
1101 std::map
<std::wstring
, RESOURCEENTRY
>::iterator pAK_iter
= m_StringEntries
.find(pBuf2
.get());
1102 if (pAK_iter
!= m_StringEntries
.end())
1104 m_bTranslatedAcceleratorStrings
++;
1107 std::wstring wtemp
= pAK_iter
->second
.msgstr
;
1108 wtemp
= wtemp
.substr(wtemp
.find_last_of(':')+1);
1109 if (wtemp
.size() != 6)
1111 if (wtemp
.compare(0, 1, _T("V")) == 0)
1113 else if (wtemp
.compare(0, 1, _T(" ")) != 0)
1114 continue; // not a space - user must have made a mistake when translating
1115 if (wtemp
.compare(1, 1, _T("A")) == 0)
1117 else if (wtemp
.compare(1, 1, _T(" ")) != 0)
1118 continue; // not a space - user must have made a mistake when translating
1119 if (wtemp
.compare(2, 1, _T("C")) == 0)
1121 else if (wtemp
.compare(2, 1, _T(" ")) != 0)
1122 continue; // not a space - user must have made a mistake when translating
1123 if (wtemp
.compare(3, 1, _T("S")) == 0)
1125 else if (wtemp
.compare(3, 1, _T(" ")) != 0)
1126 continue; // not a space - user must have made a mistake when translating
1127 if (wtemp
.compare(4, 1, _T("+")) == 0)
1129 _stscanf(wtemp
.substr(5, 1).c_str(), _T("%c"), &xkey
);
1130 lpaccelNew
[i
].fVirt
= xfVirt
;
1131 lpaccelNew
[i
].key
= xkey
;
1135 m_bDefaultAcceleratorStrings
++;
1139 // Create the new accelerator table
1140 hglAccTableNew
= LocalAlloc(LPTR
, cAccelerators
* 4 * sizeof(WORD
));
1141 p
= (WORD
*)hglAccTableNew
;
1142 lpaccelNew
[cAccelerators
-1].fVirt
|= 0x80;
1143 for (i
= 0; i
< cAccelerators
; i
++)
1145 memcpy((void *)p
, &lpaccelNew
[i
].fVirt
, 1);
1147 memcpy((void *)p
, &lpaccelNew
[i
].key
, sizeof(WORD
));
1149 memcpy((void *)p
, &lpaccelNew
[i
].cmd
, sizeof(WORD
));
1154 if (!UpdateResource(m_hUpdateRes
, RT_ACCELERATOR
, lpszType
,
1155 (m_wTargetLang
? m_wTargetLang
: wLanguage
), hglAccTableNew
/* haccelNew*/, cAccelerators
* 4 * sizeof(WORD
)))
1160 if ((m_wTargetLang
)&&(!UpdateResource(m_hUpdateRes
, RT_ACCELERATOR
, lpszType
, wLanguage
, NULL
, 0)))
1165 LocalFree(hglAccTableNew
);
1166 LocalFree(lpaccelNew
);
1170 LocalFree(hglAccTableNew
);
1171 LocalFree(lpaccelNew
);
1175 BOOL
CResModule::ExtractDialog(LPCTSTR lpszType
)
1178 const WORD
* lpDlgItem
;
1180 DLGITEMINFO dlgItem
;
1183 HGLOBAL hGlblDlgTemplate
;
1185 hrsrc
= FindResource(m_hResDll
, lpszType
, RT_DIALOG
);
1190 hGlblDlgTemplate
= LoadResource(m_hResDll
, hrsrc
);
1191 if (hGlblDlgTemplate
== NULL
)
1194 lpDlg
= (const WORD
*) LockResource(hGlblDlgTemplate
);
1199 lpDlgItem
= (const WORD
*) GetDialogInfo(lpDlg
, &dlg
);
1200 bNumControls
= dlg
.nbItems
;
1204 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
1205 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
1206 _tcscpy(pBuf
, dlg
.caption
);
1207 CUtils::StringExtend(pBuf
);
1209 std::wstring wstr
= std::wstring(pBuf
);
1210 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
1211 entry
.resourceIDs
.insert((DWORD
)lpszType
);
1213 m_StringEntries
[wstr
] = entry
;
1217 while (bNumControls
-- != 0)
1220 SecureZeroMemory(szTitle
, sizeof(szTitle
));
1223 lpDlgItem
= GetControlInfo((WORD
*) lpDlgItem
, &dlgItem
, dlg
.dialogEx
, &bCode
);
1226 _tcscpy(szTitle
, dlgItem
.windowName
);
1228 if (_tcslen(szTitle
) > 0)
1230 CUtils::StringExtend(szTitle
);
1232 std::wstring wstr
= std::wstring(szTitle
);
1233 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
1234 entry
.resourceIDs
.insert(dlgItem
.id
);
1236 m_StringEntries
[wstr
] = entry
;
1240 UnlockResource(hGlblDlgTemplate
);
1241 FreeResource(hGlblDlgTemplate
);
1245 BOOL
CResModule::ReplaceDialog(LPCTSTR lpszType
, WORD wLanguage
)
1249 HGLOBAL hGlblDlgTemplate
;
1251 hrsrc
= FindResourceEx(m_hResDll
, RT_DIALOG
, lpszType
, wLanguage
);
1256 hGlblDlgTemplate
= LoadResource(m_hResDll
, hrsrc
);
1258 if (hGlblDlgTemplate
== NULL
)
1261 lpDlg
= (WORD
*) LockResource(hGlblDlgTemplate
);
1267 const WORD
* p
= lpDlg
;
1268 if (!CountMemReplaceDialogResource(p
, &nMem
, NULL
))
1270 WORD
* newDialog
= new WORD
[nMem
+ (nMem
% 2)];
1271 SecureZeroMemory(newDialog
, (nMem
+ (nMem
% 2))*2);
1274 if (!CountMemReplaceDialogResource(lpDlg
, &index
, newDialog
))
1276 delete [] newDialog
;
1280 if (!UpdateResource(m_hUpdateRes
, RT_DIALOG
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newDialog
, (DWORD
)(nMem
+ (nMem
% 2))*2))
1282 delete [] newDialog
;
1286 if ((m_wTargetLang
)&&(!UpdateResource(m_hUpdateRes
, RT_DIALOG
, lpszType
, wLanguage
, NULL
, 0)))
1288 delete [] newDialog
;
1292 delete [] newDialog
;
1293 UnlockResource(hGlblDlgTemplate
);
1294 FreeResource(hGlblDlgTemplate
);
1298 UnlockResource(hGlblDlgTemplate
);
1299 FreeResource(hGlblDlgTemplate
);
1303 const WORD
* CResModule::GetDialogInfo(const WORD
* pTemplate
, LPDIALOGINFO lpDlgInfo
)
1305 const WORD
* p
= (const WORD
*)pTemplate
;
1307 lpDlgInfo
->style
= GET_DWORD(p
);
1310 if (lpDlgInfo
->style
== 0xffff0001) // DIALOGEX resource
1312 lpDlgInfo
->dialogEx
= TRUE
;
1313 lpDlgInfo
->helpId
= GET_DWORD(p
);
1315 lpDlgInfo
->exStyle
= GET_DWORD(p
);
1317 lpDlgInfo
->style
= GET_DWORD(p
);
1322 lpDlgInfo
->dialogEx
= FALSE
;
1323 lpDlgInfo
->helpId
= 0;
1324 lpDlgInfo
->exStyle
= GET_DWORD(p
);
1328 lpDlgInfo
->nbItems
= GET_WORD(p
);
1331 lpDlgInfo
->x
= GET_WORD(p
);
1334 lpDlgInfo
->y
= GET_WORD(p
);
1337 lpDlgInfo
->cx
= GET_WORD(p
);
1340 lpDlgInfo
->cy
= GET_WORD(p
);
1343 // Get the menu name
1345 switch (GET_WORD(p
))
1348 lpDlgInfo
->menuName
= NULL
;
1352 lpDlgInfo
->menuName
= (LPCTSTR
) (WORD
) GET_WORD(p
+ 1);
1356 lpDlgInfo
->menuName
= (LPCTSTR
) p
;
1357 p
+= wcslen((LPCWSTR
) p
) + 1;
1361 // Get the class name
1363 switch (GET_WORD(p
))
1366 lpDlgInfo
->className
= (LPCTSTR
)MAKEINTATOM(32770);
1370 lpDlgInfo
->className
= (LPCTSTR
) (WORD
) GET_WORD(p
+ 1);
1374 lpDlgInfo
->className
= (LPCTSTR
) p
;
1375 p
+= wcslen((LPCTSTR
)p
) + 1;
1379 // Get the window caption
1381 lpDlgInfo
->caption
= (LPCTSTR
)p
;
1382 p
+= wcslen((LPCWSTR
) p
) + 1;
1384 // Get the font name
1386 if (lpDlgInfo
->style
& DS_SETFONT
)
1388 lpDlgInfo
->pointSize
= GET_WORD(p
);
1391 if (lpDlgInfo
->dialogEx
)
1393 lpDlgInfo
->weight
= GET_WORD(p
);
1395 lpDlgInfo
->italic
= LOBYTE(GET_WORD(p
));
1400 lpDlgInfo
->weight
= FW_DONTCARE
;
1401 lpDlgInfo
->italic
= FALSE
;
1404 lpDlgInfo
->faceName
= (LPCTSTR
)p
;
1405 p
+= wcslen((LPCWSTR
) p
) + 1;
1407 // First control is on DWORD boundary
1408 p
+= ((((WORD
)p
+ 3) & ~3) - (WORD
)p
)/sizeof(WORD
);
1413 const WORD
* CResModule::GetControlInfo(const WORD
* p
, LPDLGITEMINFO lpDlgItemInfo
, BOOL dialogEx
, LPBOOL bIsID
)
1417 lpDlgItemInfo
->helpId
= GET_DWORD(p
);
1419 lpDlgItemInfo
->exStyle
= GET_DWORD(p
);
1421 lpDlgItemInfo
->style
= GET_DWORD(p
);
1426 lpDlgItemInfo
->helpId
= 0;
1427 lpDlgItemInfo
->style
= GET_DWORD(p
);
1429 lpDlgItemInfo
->exStyle
= GET_DWORD(p
);
1433 lpDlgItemInfo
->x
= GET_WORD(p
);
1436 lpDlgItemInfo
->y
= GET_WORD(p
);
1439 lpDlgItemInfo
->cx
= GET_WORD(p
);
1442 lpDlgItemInfo
->cy
= GET_WORD(p
);
1447 // ID is a DWORD for DIALOGEX
1448 lpDlgItemInfo
->id
= (WORD
) GET_DWORD(p
);
1453 lpDlgItemInfo
->id
= GET_WORD(p
);
1457 if (GET_WORD(p
) == 0xffff)
1465 lpDlgItemInfo
->className
= (LPCTSTR
) p
;
1466 p
+= wcslen((LPCWSTR
) p
) + 1;
1469 if (GET_WORD(p
) == 0xffff) // an integer ID?
1472 lpDlgItemInfo
->windowName
= (LPCTSTR
) (DWORD
) GET_WORD(p
+ 1);
1478 lpDlgItemInfo
->windowName
= (LPCTSTR
) p
;
1479 p
+= wcslen((LPCWSTR
) p
) + 1;
1484 lpDlgItemInfo
->data
= (LPVOID
) (p
+ 1);
1485 p
+= GET_WORD(p
) / sizeof(WORD
);
1488 lpDlgItemInfo
->data
= NULL
;
1491 // Next control is on DWORD boundary
1492 p
+= ((((WORD
)p
+ 3) & ~3) - (WORD
)p
)/sizeof(WORD
);
1496 const WORD
* CResModule::CountMemReplaceDialogResource(const WORD
* res
, size_t * wordcount
, WORD
* newDialog
)
1499 DWORD style
= GET_DWORD(res
);
1502 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1503 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1511 if (style
== 0xffff0001) // DIALOGEX resource
1516 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //help id
1517 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //help id
1518 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1519 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1520 style
= GET_DWORD(res
);
1521 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1522 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1527 style
= GET_DWORD(res
);
1537 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1538 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1539 //style = GET_DWORD(res);
1540 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1541 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1551 newDialog
[(*wordcount
)] = GET_WORD(res
);
1552 WORD nbItems
= GET_WORD(res
);
1557 newDialog
[(*wordcount
)] = GET_WORD(res
); //x
1562 newDialog
[(*wordcount
)] = GET_WORD(res
); //y
1567 newDialog
[(*wordcount
)] = GET_WORD(res
); //cx
1572 newDialog
[(*wordcount
)] = GET_WORD(res
); //cy
1576 // Get the menu name
1578 switch (GET_WORD(res
))
1582 newDialog
[(*wordcount
)] = GET_WORD(res
);
1589 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1590 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1601 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1603 (*wordcount
) += wcslen((LPCWSTR
) res
) + 1;
1604 res
+= wcslen((LPCWSTR
) res
) + 1;
1608 // Get the class name
1610 switch (GET_WORD(res
))
1614 newDialog
[(*wordcount
)] = GET_WORD(res
);
1621 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1622 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1633 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1635 (*wordcount
) += wcslen((LPCWSTR
) res
) + 1;
1636 res
+= wcslen((LPCWSTR
) res
) + 1;
1640 // Get the window caption
1642 ReplaceStr((LPCWSTR
)res
, newDialog
, wordcount
, &m_bTranslatedDialogStrings
, &m_bDefaultDialogStrings
);
1643 res
+= wcslen((LPCWSTR
)res
) + 1;
1645 // Get the font name
1647 if (style
& DS_SETFONT
)
1650 newDialog
[(*wordcount
)] = GET_WORD(res
);
1658 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1659 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1669 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1670 (*wordcount
) += wcslen((LPCWSTR
)res
) + 1;
1671 res
+= wcslen((LPCWSTR
)res
) + 1;
1673 // First control is on DWORD boundary
1674 while ((*wordcount
)%2)
1676 while ((ULONG
)res
% 4)
1681 res
= ReplaceControlInfo(res
, wordcount
, newDialog
, bEx
);
1686 const WORD
* CResModule::ReplaceControlInfo(const WORD
* res
, size_t * wordcount
, WORD
* newDialog
, BOOL bEx
)
1692 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //helpid
1693 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //helpid
1703 LONG
* exStyle
= (LONG
*)&newDialog
[(*wordcount
)];
1704 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1705 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1707 *exStyle
|= WS_EX_RTLREADING
;
1717 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1718 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1727 newDialog
[(*wordcount
)] = GET_WORD(res
); //x
1732 newDialog
[(*wordcount
)] = GET_WORD(res
); //y
1737 newDialog
[(*wordcount
)] = GET_WORD(res
); //cx
1742 newDialog
[(*wordcount
)] = GET_WORD(res
); //cy
1748 // ID is a DWORD for DIALOGEX
1751 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1752 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1763 newDialog
[(*wordcount
)] = GET_WORD(res
);
1768 if (GET_WORD(res
) == 0xffff) //classID
1772 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1773 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1784 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1785 (*wordcount
) += wcslen((LPCWSTR
) res
) + 1;
1786 res
+= wcslen((LPCWSTR
) res
) + 1;
1789 if (GET_WORD(res
) == 0xffff) // an integer ID?
1793 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1794 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1804 ReplaceStr((LPCWSTR
)res
, newDialog
, wordcount
, &m_bTranslatedDialogStrings
, &m_bDefaultDialogStrings
);
1805 res
+= wcslen((LPCWSTR
)res
) + 1;
1809 memcpy(&newDialog
[(*wordcount
)], res
, (GET_WORD(res
)+1)*sizeof(WORD
));
1810 (*wordcount
) += (GET_WORD(res
)+1);
1811 res
+= (GET_WORD(res
)+1);
1812 // Next control is on DWORD boundary
1813 while ((*wordcount
) % 2)
1815 res
+= ((((WORD
)res
+ 3) & ~3) - (WORD
)res
)/sizeof(WORD
);
1820 BOOL
CResModule::ExtractRibbon(LPCTSTR lpszType
)
1822 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_RIBBON
);
1823 HGLOBAL hglRibbonTemplate
;
1829 hglRibbonTemplate
= LoadResource(m_hResDll
, hrsrc
);
1831 DWORD sizeres
= SizeofResource(m_hResDll
, hrsrc
);
1833 if (!hglRibbonTemplate
)
1836 p
= (const BYTE
*)LockResource(hglRibbonTemplate
);
1841 // Resource consists of one single string
1844 // extract all <text>blah</text> elements
1846 const std::regex
regRevMatch("<TEXT>([^<]+)</TEXT>");
1847 std::string ss
= std::string((const char*)p
, sizeres
);
1848 const std::sregex_iterator end
;
1849 for (std::sregex_iterator
it(ss
.begin(), ss
.end(), regRevMatch
); it
!= end
; ++it
)
1851 std::string str
= (*it
)[1];
1852 size_t len
= str
.size();
1853 std::unique_ptr
<wchar_t[]> bufw(new wchar_t[len
*4 + 1]);
1854 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1855 MultiByteToWideChar(CP_UTF8
, 0, str
.c_str(), -1, bufw
.get(), (int)len
*4);
1856 std::wstring ret
= bufw
.get();
1857 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1858 entry
.resourceIDs
.insert((DWORD
)lpszType
);
1859 if (wcschr(ret
.c_str(), '%'))
1860 entry
.flag
= _T("#, c-format");
1861 m_StringEntries
[ret
] = entry
;
1862 m_bDefaultRibbonTexts
++;
1865 // extract all </ELEMENT_NAME><NAME>blahblah</NAME> elements
1867 const std::regex
regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
1868 for (std::sregex_iterator
it(ss
.begin(), ss
.end(), regRevMatchName
); it
!= end
; ++it
)
1870 std::string str
= (*it
)[1];
1871 size_t len
= str
.size();
1872 std::unique_ptr
<wchar_t[]> bufw(new wchar_t[len
*4 + 1]);
1873 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1874 MultiByteToWideChar(CP_UTF8
, 0, str
.c_str(), -1, bufw
.get(), (int)len
*4);
1875 std::wstring ret
= bufw
.get();
1876 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1877 entry
.resourceIDs
.insert((DWORD
)lpszType
);
1878 if (wcschr(ret
.c_str(), '%'))
1879 entry
.flag
= _T("#, c-format");
1880 m_StringEntries
[ret
] = entry
;
1881 m_bDefaultRibbonTexts
++;
1884 UnlockResource(hglRibbonTemplate
);
1885 FreeResource(hglRibbonTemplate
);
1889 BOOL
CResModule::ReplaceRibbon(LPCTSTR lpszType
, WORD wLanguage
)
1891 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_RIBBON
);
1892 HGLOBAL hglRibbonTemplate
;
1898 hglRibbonTemplate
= LoadResource(m_hResDll
, hrsrc
);
1900 DWORD sizeres
= SizeofResource(m_hResDll
, hrsrc
);
1902 if (!hglRibbonTemplate
)
1905 p
= (const BYTE
*)LockResource(hglRibbonTemplate
);
1910 std::string ss
= std::string((const char*)p
, sizeres
);
1911 size_t len
= ss
.size();
1912 std::unique_ptr
<wchar_t[]> bufw(new wchar_t[len
*4 + 1]);
1913 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1914 MultiByteToWideChar(CP_UTF8
, 0, ss
.c_str(), -1, bufw
.get(), (int)len
*4);
1915 std::wstring ssw
= bufw
.get();
1918 const std::regex
regRevMatch("<TEXT>([^<]+)</TEXT>");
1919 const std::sregex_iterator end
;
1920 for (std::sregex_iterator
it(ss
.begin(), ss
.end(), regRevMatch
); it
!= end
; ++it
)
1922 std::string str
= (*it
)[1];
1923 size_t len
= str
.size();
1924 std::unique_ptr
<wchar_t[]> bufw(new wchar_t[len
*4 + 1]);
1925 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1926 MultiByteToWideChar(CP_UTF8
, 0, str
.c_str(), -1, bufw
.get(), (int)len
*4);
1927 std::wstring ret
= bufw
.get();
1929 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1930 ret
= L
"<TEXT>" + ret
+ L
"</TEXT>";
1932 if (entry
.msgstr
.size())
1934 CUtils::SearchReplace(ssw
, ret
, L
"<TEXT>" + entry
.msgstr
+ L
"</TEXT>");
1935 m_bTranslatedRibbonTexts
++;
1938 m_bDefaultRibbonTexts
++;
1941 const std::regex
regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
1942 for (std::sregex_iterator
it(ss
.begin(), ss
.end(), regRevMatchName
); it
!= end
; ++it
)
1944 std::string str
= (*it
)[1];
1945 size_t len
= str
.size();
1946 std::unique_ptr
<wchar_t[]> bufw(new wchar_t[len
*4 + 1]);
1947 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1948 MultiByteToWideChar(CP_UTF8
, 0, str
.c_str(), -1, bufw
.get(), (int)len
*4);
1949 std::wstring ret
= bufw
.get();
1951 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1952 ret
= L
"</ELEMENT_NAME><NAME>" + ret
+ L
"</NAME>";
1954 if (entry
.msgstr
.size())
1956 CUtils::SearchReplace(ssw
, ret
, L
"</ELEMENT_NAME><NAME>" + entry
.msgstr
+ L
"</NAME>");
1957 m_bTranslatedRibbonTexts
++;
1960 m_bDefaultRibbonTexts
++;
1963 std::unique_ptr
<char[]> buf(new char[ssw
.size()*4 + 1]);
1964 int lengthIncTerminator
= WideCharToMultiByte(CP_UTF8
, 0, ssw
.c_str(), -1, buf
.get(), (int)len
*4, NULL
, NULL
);
1967 if (!UpdateResource(m_hUpdateRes
, RT_RIBBON
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), buf
.get(), lengthIncTerminator
-1))
1972 if ((m_wTargetLang
)&&(!UpdateResource(m_hUpdateRes
, RT_RIBBON
, lpszType
, wLanguage
, NULL
, 0)))
1978 UnlockResource(hglRibbonTemplate
);
1979 FreeResource(hglRibbonTemplate
);
1983 UnlockResource(hglRibbonTemplate
);
1984 FreeResource(hglRibbonTemplate
);
1988 BOOL CALLBACK
CResModule::EnumResNameCallback(HMODULE
/*hModule*/, LPCTSTR lpszType
, LPTSTR lpszName
, LONG_PTR lParam
)
1990 CResModule
* lpResModule
= (CResModule
*)lParam
;
1992 if (lpszType
== RT_STRING
)
1994 if (IS_INTRESOURCE(lpszName
))
1996 if (!lpResModule
->ExtractString(lpszName
))
2000 else if (lpszType
== RT_MENU
)
2002 if (IS_INTRESOURCE(lpszName
))
2004 if (!lpResModule
->ExtractMenu(lpszName
))
2008 else if (lpszType
== RT_DIALOG
)
2010 if (IS_INTRESOURCE(lpszName
))
2012 if (!lpResModule
->ExtractDialog(lpszName
))
2016 else if (lpszType
== RT_ACCELERATOR
)
2018 if (IS_INTRESOURCE(lpszName
))
2020 if (!lpResModule
->ExtractAccelerator(lpszName
))
2024 else if (lpszType
== RT_RIBBON
)
2026 if (IS_INTRESOURCE(lpszName
))
2028 if (!lpResModule
->ExtractRibbon(lpszName
))
2036 #pragma warning(push)
2037 #pragma warning(disable: 4189)
2038 BOOL CALLBACK
CResModule::EnumResNameWriteCallback(HMODULE hModule
, LPCTSTR lpszType
, LPTSTR lpszName
, LONG_PTR lParam
)
2040 CResModule
* lpResModule
= (CResModule
*)lParam
;
2041 return EnumResourceLanguages(hModule
, lpszType
, lpszName
, (ENUMRESLANGPROC
)&lpResModule
->EnumResWriteLangCallback
, lParam
);
2043 #pragma warning(pop)
2045 BOOL CALLBACK
CResModule::EnumResWriteLangCallback(HMODULE
/*hModule*/, LPCTSTR lpszType
, LPTSTR lpszName
, WORD wLanguage
, LONG_PTR lParam
)
2048 CResModule
* lpResModule
= (CResModule
*)lParam
;
2050 if (lpszType
== RT_STRING
)
2052 bRes
= lpResModule
->ReplaceString(lpszName
, wLanguage
);
2054 else if (lpszType
== RT_MENU
)
2056 bRes
= lpResModule
->ReplaceMenu(lpszName
, wLanguage
);
2058 else if (lpszType
== RT_DIALOG
)
2060 bRes
= lpResModule
->ReplaceDialog(lpszName
, wLanguage
);
2062 else if (lpszType
== RT_ACCELERATOR
)
2064 bRes
= lpResModule
->ReplaceAccelerator(lpszName
, wLanguage
);
2066 else if (lpszType
== RT_RIBBON
)
2068 bRes
= lpResModule
->ReplaceRibbon(lpszName
, wLanguage
);
2075 void CResModule::ReplaceStr(LPCWSTR src
, WORD
* dest
, size_t * count
, int * translated
, int * def
)
2077 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
2078 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
2080 CUtils::StringExtend(pBuf
);
2082 std::wstring wstr
= std::wstring(pBuf
);
2083 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
2084 if (!entry
.msgstr
.empty())
2086 wcscpy(pBuf
, entry
.msgstr
.c_str());
2087 CUtils::StringCollapse(pBuf
);
2089 wcscpy((wchar_t *)&dest
[(*count
)], pBuf
);
2090 (*count
) += wcslen(pBuf
)+1;
2096 wcscpy((wchar_t *)&dest
[(*count
)], src
);
2097 (*count
) += wcslen(src
) + 1;