1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008, 2010-2014 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
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("%4Iu 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("%4Iu 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("%4Iu 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("%4Iu 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("%4Iu 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("%4Iu 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("%4Iu 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("%4Iu 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("%4Iu 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
)
612 //struct PopupMenuItem {
614 // WCHAR szItemText[];
616 //struct NormalMenuItem {
619 // WCHAR szItemText[];
624 flags
= GET_WORD(res
);
626 if (!(flags
& MF_POPUP
))
628 id
= GET_WORD(res
); //normal menu item
632 id
= (WORD
)-1; //popup menu item
634 LPCWSTR str
= (LPCWSTR
)res
;
635 size_t l
= wcslen(str
)+1;
638 if (flags
& MF_POPUP
)
640 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
641 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
643 CUtils::StringExtend(pBuf
);
645 std::wstring wstr
= std::wstring(pBuf
);
646 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
648 entry
.resourceIDs
.insert(id
);
650 m_StringEntries
[wstr
] = entry
;
653 if ((res
= ParseMenuResource(res
))==0)
658 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
659 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
661 CUtils::StringExtend(pBuf
);
663 std::wstring wstr
= std::wstring(pBuf
);
664 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
665 entry
.resourceIDs
.insert(id
);
667 TCHAR szTempBuf
[1024] = { 0 };
668 _stprintf(szTempBuf
, _T("#: MenuEntry; ID:%u"), id
);
669 MENUENTRY menu_entry
;
671 menu_entry
.reference
= szTempBuf
;
672 menu_entry
.msgstr
= wstr
;
674 m_StringEntries
[wstr
] = entry
;
675 m_MenuEntries
[id
] = menu_entry
;
678 } while (!(flags
& MF_END
));
682 const WORD
* CResModule::CountMemReplaceMenuResource(const WORD
* res
, size_t * wordcount
, WORD
* newMenu
)
687 //struct PopupMenuItem {
689 // WCHAR szItemText[];
691 //struct NormalMenuItem {
694 // WCHAR szItemText[];
699 flags
= GET_WORD(res
);
704 newMenu
[(*wordcount
)++] = flags
;
705 if (!(flags
& MF_POPUP
))
707 id
= GET_WORD(res
); //normal menu item
712 newMenu
[(*wordcount
)++] = id
;
715 id
= (WORD
)-1; //popup menu item
717 if (flags
& MF_POPUP
)
719 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
720 res
+= wcslen((LPCWSTR
)res
) + 1;
722 if ((res
= CountMemReplaceMenuResource(res
, wordcount
, newMenu
))==0)
727 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
728 res
+= wcslen((LPCWSTR
)res
) + 1;
733 wcscpy((wchar_t *)&newMenu
[(*wordcount
)], (LPCWSTR
)res
);
734 (*wordcount
) += wcslen((LPCWSTR
)res
) + 1;
735 res
+= wcslen((LPCWSTR
)res
) + 1;
737 } while (!(flags
& MF_END
));
741 const WORD
* CResModule::ParseMenuExResource(const WORD
* res
)
745 //struct MenuExItem {
751 // DWORD dwHelpId; - Popup menu only
756 DWORD dwType
= GET_DWORD(res
);
758 //dwState = GET_DWORD(res);
760 DWORD menuId
= GET_DWORD(res
);
762 bResInfo
= GET_WORD(res
);
765 LPCWSTR str
= (LPCWSTR
)res
;
766 size_t l
= wcslen(str
)+1;
768 // Align to DWORD boundary
769 res
+= ((((WORD
)res
+ 3) & ~3) - (WORD
)res
)/sizeof(WORD
);
771 if (dwType
& MFT_SEPARATOR
)
776 // Popup menu - note this can also have a non-zero ID
779 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
780 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
782 CUtils::StringExtend(pBuf
);
784 std::wstring wstr
= std::wstring(pBuf
);
785 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
786 // Popup has a DWORD help entry on a DWORD boundary - skip over it
789 entry
.resourceIDs
.insert(menuId
);
790 TCHAR szTempBuf
[1024] = { 0 };
791 _stprintf(szTempBuf
, _T("#: MenuExPopupEntry; ID:%lu"), menuId
);
792 MENUENTRY menu_entry
;
793 menu_entry
.wID
= (WORD
)menuId
;
794 menu_entry
.reference
= szTempBuf
;
795 menu_entry
.msgstr
= wstr
;
796 m_StringEntries
[wstr
] = entry
;
797 m_MenuEntries
[(WORD
)menuId
] = menu_entry
;
800 if ((res
= ParseMenuExResource(res
)) == 0)
802 } else if (menuId
!= 0)
804 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
805 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
807 CUtils::StringExtend(pBuf
);
809 std::wstring wstr
= std::wstring(pBuf
);
810 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
811 entry
.resourceIDs
.insert(menuId
);
813 TCHAR szTempBuf
[1024] = { 0 };
814 _stprintf(szTempBuf
, _T("#: MenuExEntry; ID:%lu"), menuId
);
815 MENUENTRY menu_entry
;
816 menu_entry
.wID
= (WORD
)menuId
;
817 menu_entry
.reference
= szTempBuf
;
818 menu_entry
.msgstr
= wstr
;
819 m_StringEntries
[wstr
] = entry
;
820 m_MenuEntries
[(WORD
)menuId
] = menu_entry
;
823 } while (!(bResInfo
& 0x80));
827 const WORD
* CResModule::CountMemReplaceMenuExResource(const WORD
* res
, size_t * wordcount
, WORD
* newMenu
)
831 //struct MenuExItem {
837 // DWORD dwHelpId; - Popup menu only
842 WORD
* p0
= (WORD
*)res
;
843 DWORD dwType
= GET_DWORD(res
);
845 //dwState = GET_DWORD(res);
847 DWORD menuId
= GET_DWORD(res
);
849 bResInfo
= GET_WORD(res
);
852 if (newMenu
!= NULL
) {
853 CopyMemory(&newMenu
[*wordcount
], p0
, 7 * sizeof(WORD
));
857 if (dwType
& MFT_SEPARATOR
) {
866 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
867 res
+= wcslen((LPCWSTR
)res
) + 1;
869 res
+= ((((WORD
)res
+ 3) & ~3) - (WORD
)res
)/sizeof(WORD
);
870 if ((*wordcount
) & 0x01)
874 CopyMemory(&newMenu
[*wordcount
], res
, sizeof(DWORD
)); // Copy Help ID
879 if ((res
= CountMemReplaceMenuExResource(res
, wordcount
, newMenu
)) == 0)
882 else if (menuId
!= 0)
884 ReplaceStr((LPCWSTR
)res
, newMenu
, wordcount
, &m_bTranslatedMenuStrings
, &m_bDefaultMenuStrings
);
885 res
+= wcslen((LPCWSTR
)res
) + 1;
890 wcscpy((wchar_t *)&newMenu
[(*wordcount
)], (LPCWSTR
)res
);
891 (*wordcount
) += wcslen((LPCWSTR
)res
) + 1;
892 res
+= wcslen((LPCWSTR
)res
) + 1;
895 res
+= ((((WORD
)res
+ 3) & ~3) - (WORD
)res
)/sizeof(WORD
);
896 if ((*wordcount
) & 0x01)
898 } while (!(bResInfo
& 0x80));
902 BOOL
CResModule::ExtractAccelerator(LPCTSTR lpszType
)
904 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_ACCELERATOR
);
906 WORD fFlags
, wAnsi
, wID
;
913 hglAccTable
= LoadResource(m_hResDll
, hrsrc
);
918 p
= (const WORD
*)LockResource(hglAccTable
);
924 struct ACCELTABLEENTRY
926 WORD fFlags; FVIRTKEY, FSHIFT, FCONTROL, FALT, 0x80 - Last in a table
927 WORD wAnsi; ANSI character
928 WORD wId; Keyboard accelerator passed to windows
929 WORD padding; # bytes added to ensure aligned to DWORD boundary
935 fFlags
= GET_WORD(p
);
941 p
++; // Skip over padding
943 if ((fFlags
& 0x80) == 0x80)
948 if ((wAnsi
< 0x30) ||
950 (wAnsi
>= 0x3A && wAnsi
<= 0x40))
953 std::unique_ptr
<WCHAR
[]> pBuf(new WCHAR
[1024]);
954 std::unique_ptr
<WCHAR
[]> pBuf2(new WCHAR
[1024]);
955 SecureZeroMemory(pBuf
.get(), 1024 * sizeof(WCHAR
));
956 SecureZeroMemory(pBuf2
.get(), 1024 * sizeof(WCHAR
));
958 // include the menu ID in the msgid to make sure that 'duplicate'
959 // accelerator keys are listed in the po-file.
960 // without this, we would get entries like this:
961 //#. Accelerator Entry for Menu ID:32809; '&Filter'
962 //#. Accelerator Entry for Menu ID:57636; '&Find'
963 //#: Corresponding Menu ID:32771; '&Find'
967 // Since "filter" and "find" are most likely translated to words starting
968 // with different letters, we need to have a separate accelerator entry
970 _stprintf(pBuf
.get(), _T("ID:%u:"), wID
);
972 // EXACTLY 5 characters long "ACS+X"
973 // V = Virtual key (or blank if not used)
974 // A = Alt key (or blank if not used)
975 // C = Ctrl key (or blank if not used)
976 // S = Shift key (or blank if not used)
977 // X = upper case character
978 // e.g. "V CS+Q" == Ctrl + Shift + 'Q'
979 if ((fFlags
& FVIRTKEY
) == FVIRTKEY
) // 0x01
980 _tcscat(pBuf
.get(), _T("V"));
982 _tcscat(pBuf
.get(), _T(" "));
984 if ((fFlags
& FALT
) == FALT
) // 0x10
985 _tcscat(pBuf
.get(), _T("A"));
987 _tcscat(pBuf
.get(), _T(" "));
989 if ((fFlags
& FCONTROL
) == FCONTROL
) // 0x08
990 _tcscat(pBuf
.get(), _T("C"));
992 _tcscat(pBuf
.get(), _T(" "));
994 if ((fFlags
& FSHIFT
) == FSHIFT
) // 0x04
995 _tcscat(pBuf
.get(), _T("S"));
997 _tcscat(pBuf
.get(), _T(" "));
999 _stprintf(pBuf2
.get(), _T("%s+%c"), pBuf
.get(), wAnsi
);
1001 std::wstring wstr
= std::wstring(pBuf2
.get());
1002 RESOURCEENTRY AKey_entry
= m_StringEntries
[wstr
];
1004 TCHAR szTempBuf
[1024] = { 0 };
1005 SecureZeroMemory(szTempBuf
, sizeof (szTempBuf
));
1006 std::wstring wmenu
= _T("");
1007 pME_iter
= m_MenuEntries
.find(wID
);
1008 if (pME_iter
!= m_MenuEntries
.end())
1010 wmenu
= pME_iter
->second
.msgstr
;
1012 _stprintf(szTempBuf
, _T("#. Accelerator Entry for Menu ID:%u; '%s'"), wID
, wmenu
.c_str());
1013 AKey_entry
.automaticcomments
.push_back(std::wstring(szTempBuf
));
1015 m_StringEntries
[wstr
] = AKey_entry
;
1018 UnlockResource(hglAccTable
);
1019 FreeResource(hglAccTable
);
1023 UnlockResource(hglAccTable
);
1024 FreeResource(hglAccTable
);
1028 BOOL
CResModule::ReplaceAccelerator(LPCTSTR lpszType
, WORD wLanguage
)
1030 LPACCEL lpaccelNew
; // pointer to new accelerator table
1031 HACCEL haccelOld
; // handle to old accelerator table
1032 int cAccelerators
; // number of accelerators in table
1033 HGLOBAL hglAccTableNew
;
1037 haccelOld
= LoadAccelerators(m_hResDll
, lpszType
);
1039 if (haccelOld
== NULL
)
1042 cAccelerators
= CopyAcceleratorTable(haccelOld
, NULL
, 0);
1044 lpaccelNew
= (LPACCEL
) LocalAlloc(LPTR
, cAccelerators
* sizeof(ACCEL
));
1046 if (lpaccelNew
== NULL
)
1049 CopyAcceleratorTable(haccelOld
, lpaccelNew
, cAccelerators
);
1051 // Find the accelerator that the user modified
1052 // and change its flags and virtual-key code
1057 static const size_t BufferSize
= 1024;
1058 std::unique_ptr
<WCHAR
[]> pBuf(new WCHAR
[BufferSize
]);
1059 std::unique_ptr
<WCHAR
[]> pBuf2(new WCHAR
[BufferSize
]);
1060 for (i
= 0; i
< cAccelerators
; i
++)
1062 if ((lpaccelNew
[i
].key
< 0x30) ||
1063 (lpaccelNew
[i
].key
> 0x5A) ||
1064 (lpaccelNew
[i
].key
>= 0x3A && lpaccelNew
[i
].key
<= 0x40))
1067 SecureZeroMemory(pBuf
.get(), 1024 * sizeof(WCHAR
));
1068 SecureZeroMemory(pBuf2
.get(), 1024 * sizeof(WCHAR
));
1070 _stprintf(pBuf
.get(), _T("ID:%d:"), lpaccelNew
[i
].cmd
);
1072 // get original key combination
1073 if ((lpaccelNew
[i
].fVirt
& FVIRTKEY
) == FVIRTKEY
) // 0x01
1074 _tcscat(pBuf
.get(), _T("V"));
1076 _tcscat(pBuf
.get(), _T(" "));
1078 if ((lpaccelNew
[i
].fVirt
& FALT
) == FALT
) // 0x10
1079 _tcscat(pBuf
.get(), _T("A"));
1081 _tcscat(pBuf
.get(), _T(" "));
1083 if ((lpaccelNew
[i
].fVirt
& FCONTROL
) == FCONTROL
) // 0x08
1084 _tcscat(pBuf
.get(), _T("C"));
1086 _tcscat(pBuf
.get(), _T(" "));
1088 if ((lpaccelNew
[i
].fVirt
& FSHIFT
) == FSHIFT
) // 0x04
1089 _tcscat(pBuf
.get(), _T("S"));
1091 _tcscat(pBuf
.get(), _T(" "));
1093 _stprintf(pBuf2
.get(), _T("%s+%c"), pBuf
.get(), lpaccelNew
[i
].key
);
1096 std::map
<std::wstring
, RESOURCEENTRY
>::iterator pAK_iter
= m_StringEntries
.find(pBuf2
.get());
1097 if (pAK_iter
!= m_StringEntries
.end())
1099 m_bTranslatedAcceleratorStrings
++;
1102 std::wstring wtemp
= pAK_iter
->second
.msgstr
;
1103 wtemp
= wtemp
.substr(wtemp
.find_last_of(':')+1);
1104 if (wtemp
.size() != 6)
1106 if (wtemp
.compare(0, 1, _T("V")) == 0)
1108 else if (wtemp
.compare(0, 1, _T(" ")) != 0)
1109 continue; // not a space - user must have made a mistake when translating
1110 if (wtemp
.compare(1, 1, _T("A")) == 0)
1112 else if (wtemp
.compare(1, 1, _T(" ")) != 0)
1113 continue; // not a space - user must have made a mistake when translating
1114 if (wtemp
.compare(2, 1, _T("C")) == 0)
1116 else if (wtemp
.compare(2, 1, _T(" ")) != 0)
1117 continue; // not a space - user must have made a mistake when translating
1118 if (wtemp
.compare(3, 1, _T("S")) == 0)
1120 else if (wtemp
.compare(3, 1, _T(" ")) != 0)
1121 continue; // not a space - user must have made a mistake when translating
1122 if (wtemp
.compare(4, 1, _T("+")) == 0)
1124 _stscanf(wtemp
.substr(5, 1).c_str(), _T("%c"), &xkey
);
1125 lpaccelNew
[i
].fVirt
= xfVirt
;
1126 lpaccelNew
[i
].key
= xkey
;
1130 m_bDefaultAcceleratorStrings
++;
1134 // Create the new accelerator table
1135 hglAccTableNew
= LocalAlloc(LPTR
, cAccelerators
* 4 * sizeof(WORD
));
1136 p
= (WORD
*)hglAccTableNew
;
1137 lpaccelNew
[cAccelerators
-1].fVirt
|= 0x80;
1138 for (i
= 0; i
< cAccelerators
; i
++)
1140 memcpy((void *)p
, &lpaccelNew
[i
].fVirt
, 1);
1142 memcpy((void *)p
, &lpaccelNew
[i
].key
, sizeof(WORD
));
1144 memcpy((void *)p
, &lpaccelNew
[i
].cmd
, sizeof(WORD
));
1149 if (!UpdateResource(m_hUpdateRes
, RT_ACCELERATOR
, lpszType
,
1150 (m_wTargetLang
? m_wTargetLang
: wLanguage
), hglAccTableNew
/* haccelNew*/, cAccelerators
* 4 * sizeof(WORD
)))
1155 if ((m_wTargetLang
)&&(!UpdateResource(m_hUpdateRes
, RT_ACCELERATOR
, lpszType
, wLanguage
, NULL
, 0)))
1160 LocalFree(hglAccTableNew
);
1161 LocalFree(lpaccelNew
);
1165 LocalFree(hglAccTableNew
);
1166 LocalFree(lpaccelNew
);
1170 BOOL
CResModule::ExtractDialog(LPCTSTR lpszType
)
1173 const WORD
* lpDlgItem
;
1175 DLGITEMINFO dlgItem
;
1178 HGLOBAL hGlblDlgTemplate
;
1180 hrsrc
= FindResource(m_hResDll
, lpszType
, RT_DIALOG
);
1185 hGlblDlgTemplate
= LoadResource(m_hResDll
, hrsrc
);
1186 if (hGlblDlgTemplate
== NULL
)
1189 lpDlg
= (const WORD
*) LockResource(hGlblDlgTemplate
);
1194 lpDlgItem
= (const WORD
*) GetDialogInfo(lpDlg
, &dlg
);
1195 bNumControls
= dlg
.nbItems
;
1199 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
1200 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
1201 _tcscpy(pBuf
, dlg
.caption
);
1202 CUtils::StringExtend(pBuf
);
1204 std::wstring wstr
= std::wstring(pBuf
);
1205 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
1206 entry
.resourceIDs
.insert((DWORD
)lpszType
);
1208 m_StringEntries
[wstr
] = entry
;
1212 while (bNumControls
-- != 0)
1214 TCHAR szTitle
[500] = { 0 };
1215 SecureZeroMemory(szTitle
, sizeof(szTitle
));
1218 lpDlgItem
= GetControlInfo((WORD
*) lpDlgItem
, &dlgItem
, dlg
.dialogEx
, &bCode
);
1221 _tcscpy(szTitle
, dlgItem
.windowName
);
1223 if (_tcslen(szTitle
) > 0)
1225 CUtils::StringExtend(szTitle
);
1227 std::wstring wstr
= std::wstring(szTitle
);
1228 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
1229 entry
.resourceIDs
.insert(dlgItem
.id
);
1231 m_StringEntries
[wstr
] = entry
;
1235 UnlockResource(hGlblDlgTemplate
);
1236 FreeResource(hGlblDlgTemplate
);
1240 BOOL
CResModule::ReplaceDialog(LPCTSTR lpszType
, WORD wLanguage
)
1244 HGLOBAL hGlblDlgTemplate
;
1246 hrsrc
= FindResourceEx(m_hResDll
, RT_DIALOG
, lpszType
, wLanguage
);
1251 hGlblDlgTemplate
= LoadResource(m_hResDll
, hrsrc
);
1253 if (hGlblDlgTemplate
== NULL
)
1256 lpDlg
= (WORD
*) LockResource(hGlblDlgTemplate
);
1262 const WORD
* p
= lpDlg
;
1263 if (!CountMemReplaceDialogResource(p
, &nMem
, NULL
))
1265 WORD
* newDialog
= new WORD
[nMem
+ (nMem
% 2)];
1266 SecureZeroMemory(newDialog
, (nMem
+ (nMem
% 2))*2);
1269 if (!CountMemReplaceDialogResource(lpDlg
, &index
, newDialog
))
1271 delete [] newDialog
;
1275 if (!UpdateResource(m_hUpdateRes
, RT_DIALOG
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), newDialog
, (DWORD
)(nMem
+ (nMem
% 2))*2))
1277 delete [] newDialog
;
1281 if ((m_wTargetLang
)&&(!UpdateResource(m_hUpdateRes
, RT_DIALOG
, lpszType
, wLanguage
, NULL
, 0)))
1283 delete [] newDialog
;
1287 delete [] newDialog
;
1288 UnlockResource(hGlblDlgTemplate
);
1289 FreeResource(hGlblDlgTemplate
);
1293 UnlockResource(hGlblDlgTemplate
);
1294 FreeResource(hGlblDlgTemplate
);
1298 const WORD
* CResModule::GetDialogInfo(const WORD
* pTemplate
, LPDIALOGINFO lpDlgInfo
) const
1300 const WORD
* p
= (const WORD
*)pTemplate
;
1302 lpDlgInfo
->style
= GET_DWORD(p
);
1305 if (lpDlgInfo
->style
== 0xffff0001) // DIALOGEX resource
1307 lpDlgInfo
->dialogEx
= TRUE
;
1308 lpDlgInfo
->helpId
= GET_DWORD(p
);
1310 lpDlgInfo
->exStyle
= GET_DWORD(p
);
1312 lpDlgInfo
->style
= GET_DWORD(p
);
1317 lpDlgInfo
->dialogEx
= FALSE
;
1318 lpDlgInfo
->helpId
= 0;
1319 lpDlgInfo
->exStyle
= GET_DWORD(p
);
1323 lpDlgInfo
->nbItems
= GET_WORD(p
);
1326 lpDlgInfo
->x
= GET_WORD(p
);
1329 lpDlgInfo
->y
= GET_WORD(p
);
1332 lpDlgInfo
->cx
= GET_WORD(p
);
1335 lpDlgInfo
->cy
= GET_WORD(p
);
1338 // Get the menu name
1340 switch (GET_WORD(p
))
1343 lpDlgInfo
->menuName
= NULL
;
1347 lpDlgInfo
->menuName
= (LPCTSTR
) (WORD
) GET_WORD(p
+ 1);
1351 lpDlgInfo
->menuName
= (LPCTSTR
) p
;
1352 p
+= wcslen((LPCWSTR
) p
) + 1;
1356 // Get the class name
1358 switch (GET_WORD(p
))
1361 lpDlgInfo
->className
= (LPCTSTR
)MAKEINTATOM(32770);
1365 lpDlgInfo
->className
= (LPCTSTR
) (WORD
) GET_WORD(p
+ 1);
1369 lpDlgInfo
->className
= (LPCTSTR
) p
;
1370 p
+= wcslen((LPCTSTR
)p
) + 1;
1374 // Get the window caption
1376 lpDlgInfo
->caption
= (LPCTSTR
)p
;
1377 p
+= wcslen((LPCWSTR
) p
) + 1;
1379 // Get the font name
1381 if (lpDlgInfo
->style
& DS_SETFONT
)
1383 lpDlgInfo
->pointSize
= GET_WORD(p
);
1386 if (lpDlgInfo
->dialogEx
)
1388 lpDlgInfo
->weight
= GET_WORD(p
);
1390 lpDlgInfo
->italic
= LOBYTE(GET_WORD(p
));
1395 lpDlgInfo
->weight
= FW_DONTCARE
;
1396 lpDlgInfo
->italic
= FALSE
;
1399 lpDlgInfo
->faceName
= (LPCTSTR
)p
;
1400 p
+= wcslen((LPCWSTR
) p
) + 1;
1402 // First control is on DWORD boundary
1403 p
+= ((((WORD
)p
+ 3) & ~3) - (WORD
)p
)/sizeof(WORD
);
1408 const WORD
* CResModule::GetControlInfo(const WORD
* p
, LPDLGITEMINFO lpDlgItemInfo
, BOOL dialogEx
, LPBOOL bIsID
) const
1412 lpDlgItemInfo
->helpId
= GET_DWORD(p
);
1414 lpDlgItemInfo
->exStyle
= GET_DWORD(p
);
1416 lpDlgItemInfo
->style
= GET_DWORD(p
);
1421 lpDlgItemInfo
->helpId
= 0;
1422 lpDlgItemInfo
->style
= GET_DWORD(p
);
1424 lpDlgItemInfo
->exStyle
= GET_DWORD(p
);
1428 lpDlgItemInfo
->x
= GET_WORD(p
);
1431 lpDlgItemInfo
->y
= GET_WORD(p
);
1434 lpDlgItemInfo
->cx
= GET_WORD(p
);
1437 lpDlgItemInfo
->cy
= GET_WORD(p
);
1442 // ID is a DWORD for DIALOGEX
1443 lpDlgItemInfo
->id
= (WORD
) GET_DWORD(p
);
1448 lpDlgItemInfo
->id
= GET_WORD(p
);
1452 if (GET_WORD(p
) == 0xffff)
1460 lpDlgItemInfo
->className
= (LPCTSTR
) p
;
1461 p
+= wcslen((LPCWSTR
) p
) + 1;
1464 if (GET_WORD(p
) == 0xffff) // an integer ID?
1467 lpDlgItemInfo
->windowName
= (LPCTSTR
) (DWORD
) GET_WORD(p
+ 1);
1473 lpDlgItemInfo
->windowName
= (LPCTSTR
) p
;
1474 p
+= wcslen((LPCWSTR
) p
) + 1;
1479 lpDlgItemInfo
->data
= (LPVOID
) (p
+ 1);
1480 p
+= GET_WORD(p
) / sizeof(WORD
);
1483 lpDlgItemInfo
->data
= NULL
;
1486 // Next control is on DWORD boundary
1487 p
+= ((((WORD
)p
+ 3) & ~3) - (WORD
)p
)/sizeof(WORD
);
1491 const WORD
* CResModule::CountMemReplaceDialogResource(const WORD
* res
, size_t * wordcount
, WORD
* newDialog
)
1494 DWORD style
= GET_DWORD(res
);
1497 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1498 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1506 if (style
== 0xffff0001) // DIALOGEX resource
1511 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //help id
1512 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //help id
1513 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1514 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1515 style
= GET_DWORD(res
);
1516 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1517 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1522 style
= GET_DWORD(res
);
1532 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1533 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1534 //style = GET_DWORD(res);
1535 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1536 //newDialog[(*wordcount)++] = GET_WORD(res++); //style
1546 newDialog
[(*wordcount
)] = GET_WORD(res
);
1547 WORD nbItems
= GET_WORD(res
);
1552 newDialog
[(*wordcount
)] = GET_WORD(res
); //x
1557 newDialog
[(*wordcount
)] = GET_WORD(res
); //y
1562 newDialog
[(*wordcount
)] = GET_WORD(res
); //cx
1567 newDialog
[(*wordcount
)] = GET_WORD(res
); //cy
1571 // Get the menu name
1573 switch (GET_WORD(res
))
1577 newDialog
[(*wordcount
)] = GET_WORD(res
);
1584 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1585 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1596 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1598 (*wordcount
) += wcslen((LPCWSTR
) res
) + 1;
1599 res
+= wcslen((LPCWSTR
) res
) + 1;
1603 // Get the class name
1605 switch (GET_WORD(res
))
1609 newDialog
[(*wordcount
)] = GET_WORD(res
);
1616 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1617 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1628 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1630 (*wordcount
) += wcslen((LPCWSTR
) res
) + 1;
1631 res
+= wcslen((LPCWSTR
) res
) + 1;
1635 // Get the window caption
1637 ReplaceStr((LPCWSTR
)res
, newDialog
, wordcount
, &m_bTranslatedDialogStrings
, &m_bDefaultDialogStrings
);
1638 res
+= wcslen((LPCWSTR
)res
) + 1;
1640 // Get the font name
1642 if (style
& DS_SETFONT
)
1645 newDialog
[(*wordcount
)] = GET_WORD(res
);
1653 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1654 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1664 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1665 (*wordcount
) += wcslen((LPCWSTR
)res
) + 1;
1666 res
+= wcslen((LPCWSTR
)res
) + 1;
1668 // First control is on DWORD boundary
1669 while ((*wordcount
)%2)
1671 while ((ULONG
)res
% 4)
1676 res
= ReplaceControlInfo(res
, wordcount
, newDialog
, bEx
);
1681 const WORD
* CResModule::ReplaceControlInfo(const WORD
* res
, size_t * wordcount
, WORD
* newDialog
, BOOL bEx
)
1687 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //helpid
1688 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //helpid
1698 LONG
* exStyle
= (LONG
*)&newDialog
[(*wordcount
)];
1699 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1700 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //exStyle
1702 *exStyle
|= WS_EX_RTLREADING
;
1712 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1713 newDialog
[(*wordcount
)++] = GET_WORD(res
++); //style
1722 newDialog
[(*wordcount
)] = GET_WORD(res
); //x
1727 newDialog
[(*wordcount
)] = GET_WORD(res
); //y
1732 newDialog
[(*wordcount
)] = GET_WORD(res
); //cx
1737 newDialog
[(*wordcount
)] = GET_WORD(res
); //cy
1743 // ID is a DWORD for DIALOGEX
1746 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1747 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1758 newDialog
[(*wordcount
)] = GET_WORD(res
);
1763 if (GET_WORD(res
) == 0xffff) //classID
1767 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1768 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1779 wcscpy((LPWSTR
)&newDialog
[(*wordcount
)], (LPCWSTR
)res
);
1780 (*wordcount
) += wcslen((LPCWSTR
) res
) + 1;
1781 res
+= wcslen((LPCWSTR
) res
) + 1;
1784 if (GET_WORD(res
) == 0xffff) // an integer ID?
1788 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1789 newDialog
[(*wordcount
)++] = GET_WORD(res
++);
1799 ReplaceStr((LPCWSTR
)res
, newDialog
, wordcount
, &m_bTranslatedDialogStrings
, &m_bDefaultDialogStrings
);
1800 res
+= wcslen((LPCWSTR
)res
) + 1;
1804 memcpy(&newDialog
[(*wordcount
)], res
, (GET_WORD(res
)+1)*sizeof(WORD
));
1805 (*wordcount
) += (GET_WORD(res
)+1);
1806 res
+= (GET_WORD(res
)+1);
1807 // Next control is on DWORD boundary
1808 while ((*wordcount
) % 2)
1810 res
+= ((((WORD
)res
+ 3) & ~3) - (WORD
)res
)/sizeof(WORD
);
1815 BOOL
CResModule::ExtractRibbon(LPCTSTR lpszType
)
1817 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_RIBBON
);
1818 HGLOBAL hglRibbonTemplate
;
1824 hglRibbonTemplate
= LoadResource(m_hResDll
, hrsrc
);
1826 DWORD sizeres
= SizeofResource(m_hResDll
, hrsrc
);
1828 if (!hglRibbonTemplate
)
1831 p
= (const BYTE
*)LockResource(hglRibbonTemplate
);
1836 // Resource consists of one single string
1839 // extract all <text>blah</text> elements
1841 const std::regex
regRevMatch("<TEXT>([^<]+)</TEXT>");
1842 std::string ss
= std::string((const char*)p
, sizeres
);
1843 const std::sregex_iterator end
;
1844 for (std::sregex_iterator
it(ss
.begin(), ss
.end(), regRevMatch
); it
!= end
; ++it
)
1846 std::string str
= (*it
)[1];
1847 size_t len
= str
.size();
1848 std::unique_ptr
<wchar_t[]> bufw(new wchar_t[len
*4 + 1]);
1849 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1850 MultiByteToWideChar(CP_UTF8
, 0, str
.c_str(), -1, bufw
.get(), (int)len
*4);
1851 std::wstring ret
= bufw
.get();
1852 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1853 entry
.resourceIDs
.insert((DWORD
)lpszType
);
1854 if (wcschr(ret
.c_str(), '%'))
1855 entry
.flag
= _T("#, c-format");
1856 m_StringEntries
[ret
] = entry
;
1857 m_bDefaultRibbonTexts
++;
1860 // extract all </ELEMENT_NAME><NAME>blahblah</NAME> elements
1862 const std::regex
regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
1863 for (std::sregex_iterator
it(ss
.begin(), ss
.end(), regRevMatchName
); it
!= end
; ++it
)
1865 std::string str
= (*it
)[1];
1866 size_t len
= str
.size();
1867 std::unique_ptr
<wchar_t[]> bufw(new wchar_t[len
*4 + 1]);
1868 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1869 MultiByteToWideChar(CP_UTF8
, 0, str
.c_str(), -1, bufw
.get(), (int)len
*4);
1870 std::wstring ret
= bufw
.get();
1871 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1872 entry
.resourceIDs
.insert((DWORD
)lpszType
);
1873 if (wcschr(ret
.c_str(), '%'))
1874 entry
.flag
= _T("#, c-format");
1875 m_StringEntries
[ret
] = entry
;
1876 m_bDefaultRibbonTexts
++;
1879 UnlockResource(hglRibbonTemplate
);
1880 FreeResource(hglRibbonTemplate
);
1884 BOOL
CResModule::ReplaceRibbon(LPCTSTR lpszType
, WORD wLanguage
)
1886 HRSRC hrsrc
= FindResource(m_hResDll
, lpszType
, RT_RIBBON
);
1887 HGLOBAL hglRibbonTemplate
;
1893 hglRibbonTemplate
= LoadResource(m_hResDll
, hrsrc
);
1895 DWORD sizeres
= SizeofResource(m_hResDll
, hrsrc
);
1897 if (!hglRibbonTemplate
)
1900 p
= (const BYTE
*)LockResource(hglRibbonTemplate
);
1905 std::string ss
= std::string((const char*)p
, sizeres
);
1906 size_t len
= ss
.size();
1907 std::unique_ptr
<wchar_t[]> bufw(new wchar_t[len
*4 + 1]);
1908 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1909 MultiByteToWideChar(CP_UTF8
, 0, ss
.c_str(), -1, bufw
.get(), (int)len
*4);
1910 std::wstring ssw
= bufw
.get();
1913 const std::regex
regRevMatch("<TEXT>([^<]+)</TEXT>");
1914 const std::sregex_iterator end
;
1915 for (std::sregex_iterator
it(ss
.begin(), ss
.end(), regRevMatch
); it
!= end
; ++it
)
1917 std::string str
= (*it
)[1];
1918 size_t len
= str
.size();
1919 std::unique_ptr
<wchar_t[]> bufw(new wchar_t[len
*4 + 1]);
1920 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1921 MultiByteToWideChar(CP_UTF8
, 0, str
.c_str(), -1, bufw
.get(), (int)len
*4);
1922 std::wstring ret
= bufw
.get();
1924 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1925 ret
= L
"<TEXT>" + ret
+ L
"</TEXT>";
1927 if (entry
.msgstr
.size())
1929 CUtils::SearchReplace(ssw
, ret
, L
"<TEXT>" + entry
.msgstr
+ L
"</TEXT>");
1930 m_bTranslatedRibbonTexts
++;
1933 m_bDefaultRibbonTexts
++;
1936 const std::regex
regRevMatchName("</ELEMENT_NAME><NAME>([^<]+)</NAME>");
1937 for (std::sregex_iterator
it(ss
.begin(), ss
.end(), regRevMatchName
); it
!= end
; ++it
)
1939 std::string str
= (*it
)[1];
1940 size_t len
= str
.size();
1941 std::unique_ptr
<wchar_t[]> bufw(new wchar_t[len
*4 + 1]);
1942 SecureZeroMemory(bufw
.get(), (len
*4 + 1)*sizeof(wchar_t));
1943 MultiByteToWideChar(CP_UTF8
, 0, str
.c_str(), -1, bufw
.get(), (int)len
*4);
1944 std::wstring ret
= bufw
.get();
1946 RESOURCEENTRY entry
= m_StringEntries
[ret
];
1947 ret
= L
"</ELEMENT_NAME><NAME>" + ret
+ L
"</NAME>";
1949 if (entry
.msgstr
.size())
1951 CUtils::SearchReplace(ssw
, ret
, L
"</ELEMENT_NAME><NAME>" + entry
.msgstr
+ L
"</NAME>");
1952 m_bTranslatedRibbonTexts
++;
1955 m_bDefaultRibbonTexts
++;
1958 std::unique_ptr
<char[]> buf(new char[ssw
.size()*4 + 1]);
1959 int lengthIncTerminator
= WideCharToMultiByte(CP_UTF8
, 0, ssw
.c_str(), -1, buf
.get(), (int)len
*4, NULL
, NULL
);
1962 if (!UpdateResource(m_hUpdateRes
, RT_RIBBON
, lpszType
, (m_wTargetLang
? m_wTargetLang
: wLanguage
), buf
.get(), lengthIncTerminator
-1))
1967 if ((m_wTargetLang
)&&(!UpdateResource(m_hUpdateRes
, RT_RIBBON
, lpszType
, wLanguage
, NULL
, 0)))
1973 UnlockResource(hglRibbonTemplate
);
1974 FreeResource(hglRibbonTemplate
);
1978 UnlockResource(hglRibbonTemplate
);
1979 FreeResource(hglRibbonTemplate
);
1983 BOOL CALLBACK
CResModule::EnumResNameCallback(HMODULE
/*hModule*/, LPCTSTR lpszType
, LPTSTR lpszName
, LONG_PTR lParam
)
1985 CResModule
* lpResModule
= (CResModule
*)lParam
;
1987 if (lpszType
== RT_STRING
)
1989 if (IS_INTRESOURCE(lpszName
))
1991 if (!lpResModule
->ExtractString(lpszName
))
1995 else if (lpszType
== RT_MENU
)
1997 if (IS_INTRESOURCE(lpszName
))
1999 if (!lpResModule
->ExtractMenu(lpszName
))
2003 else if (lpszType
== RT_DIALOG
)
2005 if (IS_INTRESOURCE(lpszName
))
2007 if (!lpResModule
->ExtractDialog(lpszName
))
2011 else if (lpszType
== RT_ACCELERATOR
)
2013 if (IS_INTRESOURCE(lpszName
))
2015 if (!lpResModule
->ExtractAccelerator(lpszName
))
2019 else if (lpszType
== RT_RIBBON
)
2021 if (IS_INTRESOURCE(lpszName
))
2023 if (!lpResModule
->ExtractRibbon(lpszName
))
2031 #pragma warning(push)
2032 #pragma warning(disable: 4189)
2033 BOOL CALLBACK
CResModule::EnumResNameWriteCallback(HMODULE hModule
, LPCTSTR lpszType
, LPTSTR lpszName
, LONG_PTR lParam
)
2035 CResModule
* lpResModule
= (CResModule
*)lParam
;
2036 return EnumResourceLanguages(hModule
, lpszType
, lpszName
, (ENUMRESLANGPROC
)&lpResModule
->EnumResWriteLangCallback
, lParam
);
2038 #pragma warning(pop)
2040 BOOL CALLBACK
CResModule::EnumResWriteLangCallback(HMODULE
/*hModule*/, LPCTSTR lpszType
, LPTSTR lpszName
, WORD wLanguage
, LONG_PTR lParam
)
2043 CResModule
* lpResModule
= (CResModule
*)lParam
;
2045 if (lpszType
== RT_STRING
)
2047 bRes
= lpResModule
->ReplaceString(lpszName
, wLanguage
);
2049 else if (lpszType
== RT_MENU
)
2051 bRes
= lpResModule
->ReplaceMenu(lpszName
, wLanguage
);
2053 else if (lpszType
== RT_DIALOG
)
2055 bRes
= lpResModule
->ReplaceDialog(lpszName
, wLanguage
);
2057 else if (lpszType
== RT_ACCELERATOR
)
2059 bRes
= lpResModule
->ReplaceAccelerator(lpszName
, wLanguage
);
2061 else if (lpszType
== RT_RIBBON
)
2063 bRes
= lpResModule
->ReplaceRibbon(lpszName
, wLanguage
);
2070 void CResModule::ReplaceStr(LPCWSTR src
, WORD
* dest
, size_t * count
, int * translated
, int * def
)
2072 TCHAR
* pBuf
= new TCHAR
[MAX_STRING_LENGTH
];
2073 SecureZeroMemory(pBuf
, MAX_STRING_LENGTH
* sizeof(TCHAR
));
2075 CUtils::StringExtend(pBuf
);
2077 std::wstring wstr
= std::wstring(pBuf
);
2078 RESOURCEENTRY entry
= m_StringEntries
[wstr
];
2079 if (!entry
.msgstr
.empty())
2081 wcscpy(pBuf
, entry
.msgstr
.c_str());
2082 CUtils::StringCollapse(pBuf
);
2084 wcscpy((wchar_t *)&dest
[(*count
)], pBuf
);
2085 (*count
) += wcslen(pBuf
)+1;
2091 wcscpy((wchar_t *)&dest
[(*count
)], src
);
2092 (*count
) += wcslen(src
) + 1;