OSDN Git Service

Rewrite CProfile::LevelUp.
[xkeymacs/xkeymacs.git] / xkeymacs / dotxkeymacs.cpp
1 // DotXkeymacs.cpp: implementation of the CDotXkeymacs class.\r
2 //\r
3 //////////////////////////////////////////////////////////////////////\r
4 \r
5 #include "stdafx.h"\r
6 #include <direct.h>\r
7 #include <Shlwapi.h>\r
8 #include "DotXkeymacs.h"\r
9 \r
10 #ifdef _DEBUG\r
11 #undef THIS_FILE\r
12 static char THIS_FILE[]=__FILE__;\r
13 #define new DEBUG_NEW\r
14 #endif\r
15 \r
16 struct Language\r
17 {\r
18         WORD wLanguage;\r
19         LPCTSTR szLanguage;\r
20 };\r
21 \r
22 static const Language Languages[] = {\r
23         { 0x0001, _T("Arabic") },\r
24         { 0x0004, _T("Chinese") },\r
25         { 0x0009, _T("English") },\r
26         { 0x0401, _T("Arabic (Saudi Arabia)") },\r
27         { 0x0402, _T("Bulgarian") },\r
28         { 0x0403, _T("Catalan") },\r
29         { 0x0404, _T("Chinese (Taiwan)") },\r
30         { 0x0405, _T("Czech") },\r
31         { 0x0406, _T("Danish") },\r
32         { 0x0407, _T("German (Germany)") },\r
33         { 0x0408, _T("Greek") },\r
34         { 0x0409, _T("English (United States)") },\r
35         { 0x040A, _T("Spanish (Traditional Sort)") },\r
36         { 0x040B, _T("Finnish") },\r
37         { 0x040C, _T("French (France)") },\r
38         { 0x040D, _T("Hebrew") },\r
39         { 0x040E, _T("Hungarian") },\r
40         { 0x040F, _T("Icelandic") },\r
41         { 0x0410, _T("Italian (Italy)") },\r
42         { 0x0411, _T("Japanese") },\r
43         { 0x0412, _T("Korean") },\r
44         { 0x0413, _T("Dutch (Netherlands)") },\r
45         { 0x0414, _T("Norwegian (Bokmal)") },\r
46         { 0x0415, _T("Polish") },\r
47         { 0x0416, _T("Portuguese (Brazil)") },\r
48         { 0x0417, _T("Rhaeto-Romanic") },\r
49         { 0x0418, _T("Romanian") },\r
50         { 0x0419, _T("Russian") },\r
51         { 0x041A, _T("Croatian") },\r
52         { 0x041B, _T("Slovak") },\r
53         { 0x041C, _T("Albanian") },\r
54         { 0x041D, _T("Swedish") },\r
55         { 0x041E, _T("Thai") },\r
56         { 0x041F, _T("Turkish") },\r
57         { 0x0420, _T("Urdu") },\r
58         { 0x0421, _T("Indonesian") },\r
59         { 0x0422, _T("Ukrainian") },\r
60         { 0x0423, _T("Belarusian") },\r
61         { 0x0424, _T("Slovenian") },\r
62         { 0x0425, _T("Estonian") },\r
63         { 0x0426, _T("Latvian") },\r
64         { 0x0427, _T("Lithuanian") },\r
65         { 0x0428, _T("Tajik") },\r
66         { 0x0429, _T("Farsi") },\r
67         { 0x042A, _T("Vietnamese") },\r
68         { 0x042B, _T("Armenian") },\r
69         { 0x042C, _T("Azeri (Latin)") },\r
70         { 0x042D, _T("Basque") },\r
71         { 0x042E, _T("Sorbian") },\r
72         { 0x042F, _T("Macedonian (FYROM)") },\r
73         { 0x0430, _T("Sutu") },\r
74         { 0x0431, _T("Tsonga") },\r
75         { 0x0432, _T("Tswana") },\r
76         { 0x0434, _T("Xhosa") },\r
77         { 0x0435, _T("Zulu") },\r
78         { 0x0436, _T("Afrikaans") },\r
79         { 0x0437, _T("Georgian") },\r
80         { 0x0438, _T("Faeroese") },\r
81         { 0x0439, _T("Hindi") },\r
82         { 0x043A, _T("Maltese") },\r
83         { 0x043C, _T("Gaelic") },\r
84         { 0x043D, _T("Yiddish") },\r
85         { 0x043E, _T("Malay (Malaysia)") },\r
86         { 0x043F, _T("Kazakh") },\r
87         { 0x0440, _T("Kyrgyz") },\r
88         { 0x0441, _T("Swahili") },\r
89         { 0x0442, _T("Turkmen") },\r
90         { 0x0443, _T("Uzbek (Latin)") },\r
91         { 0x0444, _T("Tatar") },\r
92         { 0x0445, _T("Bengali") },\r
93         { 0x0446, _T("Punjabi") },\r
94         { 0x0447, _T("Gujarati") },\r
95         { 0x0448, _T("Oriya") },\r
96         { 0x0449, _T("Tamil") },\r
97         { 0x044A, _T("Telugu") },\r
98         { 0x044B, _T("Kannada") },\r
99         { 0x044C, _T("Malayalam") },\r
100         { 0x044D, _T("Assamese") },\r
101         { 0x044E, _T("Marathi") },\r
102         { 0x044F, _T("Sanskrit") },\r
103         { 0x0450, _T("Mongolian") },\r
104         { 0x0456, _T("Galician") },\r
105         { 0x0457, _T("Konkani") },\r
106         { 0x0458, _T("Manipuri") },\r
107         { 0x0459, _T("Sindhi") },\r
108         { 0x045A, _T("Syriac") },\r
109         { 0x045B, _T("Sinhalese") },\r
110         { 0x045C, _T("Cherokee") },\r
111         { 0x045D, _T("Inuktitut") },\r
112         { 0x045E, _T("Amharic") },\r
113         { 0x045F, _T("Tamazight (Berber/Arabic)") },\r
114         { 0x0460, _T("Kashmiri (Arabic)") },\r
115         { 0x0461, _T("Nepali") },\r
116         { 0x0462, _T("Frisian") },\r
117         { 0x0463, _T("Pashto") },\r
118         { 0x0464, _T("Filipino") },\r
119         { 0x0465, _T("Dhivehi") },\r
120         { 0x0466, _T("Edo") },\r
121         { 0x0467, _T("Fulfulde") },\r
122         { 0x0468, _T("Hausa") },\r
123         { 0x0469, _T("Ibibio") },\r
124         { 0x046A, _T("Yoruba") },\r
125         { 0x0470, _T("Igbo") },\r
126         { 0x0471, _T("Kanuri") },\r
127         { 0x0472, _T("Oromo") },\r
128         { 0x0473, _T("Tigrigna (Ethiopia)") },\r
129         { 0x0475, _T("Hawaiian") },\r
130         { 0x0476, _T("Latin") },\r
131         { 0x0477, _T("Somali") },\r
132         { 0x0478, _T("Yi") },\r
133         { 0x0801, _T("Arabic (Iraq)") },\r
134         { 0x0804, _T("Chinese (PRC)") },\r
135         { 0x0807, _T("German (Switzerland)") },\r
136         { 0x0809, _T("English (United Kingdom)") },\r
137         { 0x080A, _T("Spanish (Mexico)") },\r
138         { 0x080C, _T("French (Belgium)") },\r
139         { 0x0810, _T("Italian (Switzerland)") },\r
140         { 0x0813, _T("Dutch (Belgium)") },\r
141         { 0x0814, _T("Norwegian (Nynorsk)") },\r
142         { 0x0816, _T("Portuguese (Portugal)") },\r
143         { 0x0818, _T("Romanian (Moldova)") },\r
144         { 0x0819, _T("Russian (Moldova)") },\r
145         { 0x081A, _T("Serbian (Latin)") },\r
146         { 0x081D, _T("Swedish (Finland)") },\r
147         { 0x082C, _T("Azeri (Cyrillic)") },\r
148         { 0x0843, _T("Uzbek (Cyrillic)") },\r
149         { 0x085F, _T("Tamazight (Latin)") },\r
150         { 0x0873, _T("Tigrigna (Eritrea)") },\r
151         { 0x0C01, _T("Arabic (Egypt)") },\r
152         { 0x0C04, _T("Chinese (Hong Kong SAR)") },\r
153         { 0x0C07, _T("German (Austria)") },\r
154         { 0x0C09, _T("English (Australia)") },\r
155         { 0x0C0A, _T("Spanish (International Sort)") },\r
156         { 0x0C0C, _T("French (Canada)") },\r
157         { 0x0C1A, _T("Serbian (Cyrillic)") },\r
158         { 0x1001, _T("Arabic (Libya)") },\r
159         { 0x1004, _T("Chinese (Singapore)") },\r
160         { 0x1007, _T("German (Luxembourg)") },\r
161         { 0x1009, _T("English (Canada)") },\r
162         { 0x100A, _T("Spanish (Guatemala)") },\r
163         { 0x100C, _T("French (Switzerland)") },\r
164         { 0x1401, _T("Arabic (Algeria)") },\r
165         { 0x1407, _T("German (Liechtenstein)") },\r
166         { 0x1409, _T("English (New Zealand)") },\r
167         { 0x140A, _T("Spanish (Costa Rica)") },\r
168         { 0x140C, _T("French (Luxembourg)") },\r
169         { 0x1801, _T("Arabic (Morocco)") },\r
170         { 0x1809, _T("English (Ireland)") },\r
171         { 0x180A, _T("Spanish (Panama)") },\r
172         { 0x1C01, _T("Arabic (Tunisia)") },\r
173         { 0x1C09, _T("English (South Africa)") },\r
174         { 0x1C0A, _T("Spanish (Dominican Republic)") },\r
175         { 0x2001, _T("Arabic (Oman)") },\r
176         { 0x2009, _T("English (Jamaica)") },\r
177         { 0x200A, _T("Spanish (Venezuela)") },\r
178         { 0x2401, _T("Arabic (Yemen)") },\r
179         { 0x240A, _T("Spanish (Colombia)") },\r
180         { 0x2801, _T("Arabic (Syria)") },\r
181         { 0x2809, _T("English (Belize)") },\r
182         { 0x280A, _T("Spanish (Peru)") },\r
183         { 0x2C01, _T("Arabic (Jordan)") },\r
184         { 0x2C09, _T("English (Trinidad)") },\r
185         { 0x2C0A, _T("Spanish (Argentina)") },\r
186         { 0x3001, _T("Arabic (Lebanon)") },\r
187         { 0x300A, _T("Spanish (Ecuador)") },\r
188         { 0x3401, _T("Arabic (Kuwait)") },\r
189         { 0x340A, _T("Spanish (Chile)") },\r
190         { 0x3801, _T("Arabic (U.A.E.)") },\r
191         { 0x380A, _T("Spanish (Uruguay)") },\r
192         { 0x3C01, _T("Arabic (Bahrain)") },\r
193         { 0x3C0A, _T("Spanish (Paraguay)") },\r
194         { 0x4001, _T("Arabic (Qatar)") },\r
195         { 0x400A, _T("Spanish (Bolivia)") },\r
196         { 0x440A, _T("Spanish (El Salvador)") },\r
197         { 0x480A, _T("Spanish (Honduras)") },\r
198         { 0x4C0A, _T("Spanish (Nicaragua)") },\r
199         { 0x500A, _T("Spanish (Puerto Rico)") },\r
200 };\r
201         \r
202 CObList         CDotXkeymacs::m_oFunctionDefinition;\r
203 int                     CDotXkeymacs::m_nIndex[MAX_APP][MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
204 const TCHAR     CDotXkeymacs::m_szExt[] = _T("xkeymacs");\r
205 \r
206 void CDotXkeymacs::Load(LPCTSTR lpszFileName)\r
207 {\r
208         CStdioFile oDotXkeymacs;\r
209         if (oDotXkeymacs.Open(lpszFileName, CFile::modeRead | CFile::shareDenyWrite | CFile::typeText)) {\r
210                 CString szRead;\r
211                 while (oDotXkeymacs.ReadString(szRead)) {\r
212                         if (IsFunctionDefinition(szRead)) {\r
213                                 CFunctionDefinition *pFunctionDefinition = new CFunctionDefinition(GetSymbol(szRead), GetDefinition(szRead));\r
214 \r
215                                 // Delete a listed definition which has the same symbol as a new one.\r
216                                 for (POSITION currentPos, pos = m_oFunctionDefinition.GetHeadPosition(); (currentPos = pos) != NULL; ) {\r
217                                         CFunctionDefinition *pCurrentDefinition = (CFunctionDefinition *)m_oFunctionDefinition.GetNext(pos);\r
218 \r
219                                         if (pCurrentDefinition->GetSymbol() == pFunctionDefinition->GetSymbol()) {\r
220                                                 CFunctionDefinition *pOverwritten = (CFunctionDefinition *)m_oFunctionDefinition.GetAt(currentPos);\r
221                                                 m_oFunctionDefinition.RemoveAt(currentPos);\r
222                                                 delete pOverwritten;\r
223                                         }\r
224                                 }\r
225 \r
226                                 m_oFunctionDefinition.AddTail((CObject *)pFunctionDefinition);\r
227                         }\r
228                 }\r
229         }\r
230 }\r
231 \r
232 void CDotXkeymacs::LoadMainData(LPCTSTR lpszFileName)\r
233 {\r
234         TCHAR szModuleFileName[MAX_PATH] = {'\0'};\r
235         TCHAR szDrive[_MAX_DRIVE] = {'\0'};\r
236         TCHAR szDir[_MAX_DIR] = {'\0'};\r
237 \r
238         if (GetModuleFileName(NULL, szModuleFileName, sizeof(szModuleFileName))) {\r
239                 _tsplitpath_s(szModuleFileName, szDrive, _MAX_DRIVE, szDir, _MAX_DIR, NULL, 0, NULL, 0);\r
240         }\r
241 \r
242         TCHAR szOldPath[MAX_PATH] = {'\0'};     // This path is used by XKeymacs 3.22 and earlier\r
243         _tmakepath_s(szOldPath, szDrive, szDir, lpszFileName, m_szExt);\r
244 \r
245         PathAppend(szDir, _T("etc"));\r
246         TCHAR szPath[MAX_PATH] = {'\0'};\r
247         _tmakepath_s(szPath, szDrive, szDir, lpszFileName, m_szExt);\r
248 \r
249         if (_trename(szOldPath, szPath)) {                      // try to move old file as backup when rename returns an error because files exist in both directorys\r
250                 TCHAR szBackupPath[MAX_PATH] = {'\0'};\r
251                 TCHAR szBackupFlag[_MAX_FNAME] = _T("~");\r
252                 _tcscat_s(szBackupFlag, lpszFileName);\r
253                 _tmakepath_s(szBackupPath, szDrive, szDir, szBackupFlag, m_szExt);\r
254                 (void)_trename(szOldPath, szBackupPath);        // do nothing when a backup file has existed already\r
255         }\r
256 \r
257         Load(szPath);\r
258 }\r
259 \r
260 void CDotXkeymacs::LoadUserData(LPCTSTR lpszFileName)\r
261 {\r
262         TCHAR szPath[MAX_PATH] = {'\0'};\r
263         if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_APPDATA, TRUE)) {\r
264                 _tmakepath_s(szPath, NULL, szPath, lpszFileName, m_szExt);\r
265                 Load(szPath);\r
266         }\r
267 }\r
268 \r
269 void CDotXkeymacs::Load()\r
270 {\r
271         static LPCTSTR szFileName = _T("dot");\r
272 \r
273         ClearFunctionDefinition();\r
274         LoadMainData(GetLanguage());    // just for localization\r
275         LoadMainData(szFileName);\r
276         LoadUserData(szFileName);       // overwrite main data\r
277 }\r
278 \r
279 BOOL CDotXkeymacs::IsFunctionDefinition(CString szFunctionDefinition)\r
280 {\r
281         return !_tcsncmp(szFunctionDefinition, CString(MAKEINTRESOURCE(IDS_FSET)), _tcslen(CString(MAKEINTRESOURCE(IDS_FSET))));\r
282 }\r
283 \r
284 CString CDotXkeymacs::GetSymbol(CString szFunctionDefinition)\r
285 {\r
286         const int nFirst = _tcslen(CString(MAKEINTRESOURCE(IDS_FSET))) + _tcslen(_T("'"));\r
287         return szFunctionDefinition.Mid(nFirst, szFunctionDefinition.Find(_T(' '), nFirst) - nFirst);\r
288 }\r
289 \r
290 CString CDotXkeymacs::GetDefinition(CString szFunctionDefinition)\r
291 {\r
292         const int nFirst = szFunctionDefinition.Find(_T(' '), _tcslen(CString(MAKEINTRESOURCE(IDS_FSET)))) + _tcslen(_T("'"));\r
293         return szFunctionDefinition.Mid(nFirst, szFunctionDefinition.GetLength() - nFirst - _tcslen(_T(")")));\r
294 }\r
295 \r
296 void CDotXkeymacs::ClearFunctionDefinition()\r
297 {\r
298         while (!m_oFunctionDefinition.IsEmpty()) {\r
299                 CFunctionDefinition *pFunctionDefinition = (CFunctionDefinition *)m_oFunctionDefinition.GetHead();\r
300                 delete pFunctionDefinition;\r
301                 pFunctionDefinition = NULL;\r
302                 m_oFunctionDefinition.RemoveHead();\r
303         }\r
304         memset(m_nIndex, -1, sizeof(m_nIndex));\r
305 }\r
306 \r
307 int CDotXkeymacs::GetFunctionNumber()\r
308 {\r
309         return m_oFunctionDefinition.GetCount();\r
310 }\r
311 \r
312 CString CDotXkeymacs::GetFunctionSymbol(int nIndex)\r
313 {\r
314         if (nIndex < 0 || m_oFunctionDefinition.GetCount() <= nIndex) {\r
315                 return CString();\r
316         }\r
317 \r
318         if (CFunctionDefinition *pFunctionDefinition = (CFunctionDefinition *)m_oFunctionDefinition.GetAt(m_oFunctionDefinition.FindIndex(nIndex))) {\r
319                 return pFunctionDefinition->GetSymbol();\r
320         }\r
321         return CString();\r
322 }\r
323 \r
324 CString CDotXkeymacs::GetFunctionDefinition(int nIndex)\r
325 {\r
326         if (nIndex < 0 || m_oFunctionDefinition.GetCount() <= nIndex) {\r
327                 return CString();\r
328         }\r
329 \r
330         if (CFunctionDefinition *pFunctionDefinition = (CFunctionDefinition *)m_oFunctionDefinition.GetAt(m_oFunctionDefinition.FindIndex(nIndex))) {\r
331                 return pFunctionDefinition->GetDefinition();\r
332         }\r
333         return CString();\r
334 }\r
335 \r
336 CString CDotXkeymacs::GetFunctionDefinition(CString szSymbol)\r
337 {\r
338         for (POSITION pos = m_oFunctionDefinition.GetHeadPosition(); pos;) {\r
339                 CFunctionDefinition *pFunctionDefinition = (CFunctionDefinition *)m_oFunctionDefinition.GetNext(pos);\r
340                 if (!pFunctionDefinition->GetSymbol().Compare(szSymbol)) {\r
341                         return pFunctionDefinition->GetDefinition();\r
342                 }\r
343         }\r
344 \r
345         return CString(_T("Undefined Command"));\r
346 }\r
347 \r
348 void CDotXkeymacs::ClearKey(int nIndex, int nAppID)\r
349 {\r
350         if (nIndex < 0 || m_oFunctionDefinition.GetCount() <= nIndex) {\r
351                 return;\r
352         }\r
353 \r
354         if (CFunctionDefinition *pFunctionDefinition = (CFunctionDefinition *)m_oFunctionDefinition.GetAt(m_oFunctionDefinition.FindIndex(nIndex))) {\r
355                 pFunctionDefinition->ClearKey(nAppID);\r
356         }\r
357 \r
358         for (int nType = 0; nType < MAX_COMMAND_TYPE; ++nType) {\r
359                 for (int nKey = 0; nKey < MAX_KEY; ++nKey) {\r
360                         if (m_nIndex[nAppID][nType][nKey] == nIndex) {\r
361                                 m_nIndex[nAppID][nType][nKey] = -1;\r
362                         }\r
363                 }\r
364         }\r
365 }\r
366 \r
367 void CDotXkeymacs::SetKey(int nIndex, int nAppID, int nType, int nKey)\r
368 {\r
369         if (nIndex < 0 || m_oFunctionDefinition.GetCount() <= nIndex) {\r
370                 return;\r
371         }\r
372 \r
373         if (CFunctionDefinition *pFunctionDefinition = (CFunctionDefinition *)m_oFunctionDefinition.GetAt(m_oFunctionDefinition.FindIndex(nIndex))) {\r
374                 pFunctionDefinition->SetKey(nAppID, nType, nKey);\r
375                 m_nIndex[nAppID][nType][nKey] = nIndex;\r
376         }\r
377 }\r
378 \r
379 int CDotXkeymacs::GetIndex(CString szSymbol)\r
380 {\r
381         int nIndex = 0;\r
382         for (nIndex = 0; nIndex < m_oFunctionDefinition.GetCount(); ++nIndex) {\r
383                 CFunctionDefinition *pFunctionDefinition = (CFunctionDefinition *)m_oFunctionDefinition.GetAt(m_oFunctionDefinition.FindIndex(nIndex));\r
384                 if (!pFunctionDefinition->GetSymbol().Compare(szSymbol)) {\r
385                         return nIndex;\r
386                 }\r
387         }\r
388         return -1;\r
389 }\r
390 \r
391 int CDotXkeymacs::GetKeyNumber(int nIndex, int nAppID)\r
392 {\r
393         if (nIndex < 0 || m_oFunctionDefinition.GetCount() <= nIndex) {\r
394                 return 0;\r
395         }\r
396 \r
397         CFunctionDefinition *pFunctionDefinition = (CFunctionDefinition *)m_oFunctionDefinition.GetAt(m_oFunctionDefinition.FindIndex(nIndex));\r
398         return pFunctionDefinition->GetKeyNumber(nAppID);\r
399 }\r
400 \r
401 void CDotXkeymacs::GetKey(int nIndex, int nAppID, int nKeyID, int *pCommandType, int *pKey)\r
402 {\r
403         if (nIndex < 0 || m_oFunctionDefinition.GetCount() <= nIndex) {\r
404                 return;\r
405         }\r
406 \r
407         CFunctionDefinition *pFunctionDefinition = (CFunctionDefinition *)m_oFunctionDefinition.GetAt(m_oFunctionDefinition.FindIndex(nIndex));\r
408         pFunctionDefinition->GetKey(nAppID, nKeyID, pCommandType, pKey);\r
409 }\r
410 \r
411 int CDotXkeymacs::GetIndex(int nAppID, int nType, int nKey)\r
412 {\r
413         return m_nIndex[nAppID][nType][nKey];\r
414 }\r
415 \r
416 void CDotXkeymacs::RemoveKey(const int nIndex, const int nAppID, const int nType, const int nKey)\r
417 {\r
418         if (nIndex < 0 || m_oFunctionDefinition.GetCount() <= nIndex) {\r
419                 return;\r
420         }\r
421 \r
422         CFunctionDefinition *pFunctionDefinition = (CFunctionDefinition *)m_oFunctionDefinition.GetAt(m_oFunctionDefinition.FindIndex(nIndex));\r
423         if (pFunctionDefinition) {\r
424                 pFunctionDefinition->RemoveKey(nAppID, nType, nKey);\r
425         }\r
426 }\r
427 \r
428 void CDotXkeymacs::RemoveKey(const int nAppID, const int nType, const int nKey)\r
429 {\r
430         for (int nIndex = 0; nIndex < m_oFunctionDefinition.GetCount(); ++nIndex) {\r
431                 RemoveKey(nIndex, nAppID, nType, nKey);\r
432         }\r
433 }\r
434 \r
435 LPCTSTR CDotXkeymacs::GetLanguage()\r
436 {\r
437         LPCTSTR szLanguage = _T("unknown");\r
438 \r
439         TCHAR lptstrFilename[MAX_PATH] = {'\0'};\r
440         TCHAR windir[MAX_PATH] = "";\r
441         size_t len;\r
442         _tgetenv_s(&len, windir, _T("windir"));\r
443         _tmakepath_s(lptstrFilename, NULL, windir, _T("explorer"), _T("exe"));\r
444         DWORD dwLen = GetFileVersionInfoSize(lptstrFilename, NULL);\r
445 \r
446         if (dwLen) {\r
447                 LPVOID lpData = malloc(dwLen);\r
448 \r
449                 if (lpData && GetFileVersionInfo(lptstrFilename, NULL, dwLen, lpData)) {\r
450                         struct Translate {\r
451                                 WORD wLanguage;\r
452                                 WORD wCodePage;\r
453                         } *lpTranslate;\r
454                         UINT cbTranslate = 0;\r
455 \r
456                         if (VerQueryValue(lpData, _T("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate) && sizeof(Translate) <= cbTranslate) {\r
457                                 for (int i = 0; i < _countof(Languages); ++i) {\r
458                                         if (Languages[i].wLanguage == lpTranslate->wLanguage) {\r
459                                                 szLanguage = Languages[i].szLanguage;\r
460                                                 break;\r
461                                         }\r
462                                 }\r
463                         }\r
464                 }\r
465 \r
466                 free(lpData);\r
467         }\r
468 \r
469         return szLanguage;\r
470 }\r