Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / WINNT / talocale / tal_main.cpp
1
2 extern "C" {
3 #include <afs/param.h>
4 #include <afs/stds.h>
5 }
6
7 #include <WINNT/TaLocale.h>
8
9
10 /*
11  * DEFINITIONS ________________________________________________________________
12  *
13  */
14
15 typedef struct
16    {
17    WORD wPriority;      // unused if MODULE_PRIORITY_REMOVED
18    HINSTANCE hInstance; // module handle
19    } MODULE, *LPMODULE;
20
21 #define cREALLOC_MODULES  4
22
23
24 /*
25  * VARIABLES __________________________________________________________________
26  *
27  */
28
29 static LANGID l_lang = LANG_USER_DEFAULT;
30 static CRITICAL_SECTION l_csModules;
31 static MODULE *l_aModules = NULL;
32 static size_t l_cModules = 0;
33
34
35 /*
36  * PROTOTYPES _________________________________________________________________
37  *
38  */
39
40 BOOL IsValidStringTemplate (LPCSTRINGTEMPLATE pTable);
41
42
43 /*
44  * ROUTINES ___________________________________________________________________
45  *
46  */
47
48 void TaLocale_Initialize (void)
49 {
50    static BOOL fInitialized = FALSE;
51    if (!fInitialized)
52       {
53       fInitialized = TRUE;
54
55       InitCommonControls();
56       InitializeCriticalSection (&l_csModules);
57       TaLocale_SpecifyModule (GetModuleHandle(NULL));
58
59       LCID lcidUser = GetUserDefaultLCID();
60       TaLocale_SetLanguage (LANGIDFROMLCID (lcidUser));
61
62       LANGID LangOverride;
63       if ((LangOverride = TaLocale_GetLanguageOverride()) != (LANGID)0)
64          TaLocale_SetLanguage (LangOverride);
65       }
66 }
67
68
69 BOOL TaLocaleReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
70 {
71    LPVOID pNew;
72    size_t cNew;
73
74    if (cReq <= *pcTarget)
75       return TRUE;
76
77    if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
78       return FALSE;
79
80    if ((pNew = Allocate (cbElement * cNew)) == NULL)
81       return FALSE;
82    memset (pNew, 0x00, cbElement * cNew);
83
84    if (*pcTarget != 0)
85       {
86       memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
87       Free (*ppTarget);
88       }
89
90    *ppTarget = pNew;
91    *pcTarget = cNew;
92    return TRUE;
93 }
94
95
96 /*
97  *** TaLocale_GuessBestLangID
98  *
99  * This routine picks the most common language/sublanguage pair based on
100  * the current language and sublanguage. These values are based on the
101  * most likely targets for our localization teams--e.g., we usually put
102  * out a Simplified Chinese translation, so if we run under a Singapore
103  * locale it's a good bet that we should load the Simplified Chinese
104  * translation instead of just failing for lack of a Singapore binary.
105  *
106  */
107
108 LANGID TaLocale_GuessBestLangID (LANGID lang)
109 {
110    switch (PRIMARYLANGID(lang))
111       {
112       case LANG_KOREAN:
113          return MAKELANGID(LANG_KOREAN,SUBLANG_KOREAN);
114
115       case LANG_JAPANESE:
116          return MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT);
117
118       case LANG_ENGLISH:
119          return MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US);
120
121       case LANG_CHINESE:
122          if (SUBLANGID(lang) != SUBLANG_CHINESE_TRADITIONAL)
123             return MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED);
124
125       case LANG_GERMAN:
126          return MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN);
127
128       case LANG_SPANISH:
129          return MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH);
130
131       case LANG_PORTUGUESE:
132          return MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE_BRAZILIAN);
133       }
134
135    return lang;
136 }
137
138
139 /*
140  *** TaLocale_SpecifyModule
141  *
142  * Adds the given module handle to TaLocale's known list of possible sources
143  * for localized resource data. By default, the list is initialized with
144  * the current executable's module handle; if resources are to be extracted
145  * from other .DLLs using the functions in the TaLocale library, this routine
146  * should be called first to notify TaLocale about each .DLL.
147  *
148  */
149
150 void TaLocale_SpecifyModule (HINSTANCE hInstance, WORD wSearchPriority)
151 {
152    TaLocale_Initialize();
153    EnterCriticalSection (&l_csModules);
154
155    // First see if the specified module handle already exists; if
156    // so, remove it (its priority may be changing, or we may actually
157    // have been asked to remove it).
158    //
159    for (size_t iModule = 0; iModule < l_cModules; ++iModule)
160       {
161       if (l_aModules[ iModule ].wPriority == 0)  // end of list?
162          break;
163       if (l_aModules[ iModule ].hInstance == hInstance)  // found module?
164          break;
165       }
166    if (iModule < l_cModules)
167       {
168       for ( ; iModule < l_cModules-1; ++iModule)
169          memcpy (&l_aModules[ iModule ], &l_aModules[ iModule+1 ], sizeof(MODULE));
170       memset (&l_aModules[ iModule ], 0x00, sizeof(MODULE));
171       }
172
173    // Next, if we have been asked to add this module, find a good place for it.
174    // We want to leave {iModule} pointing to the slot where this module
175    // should be inserted--anything currently at or after {iModule} will have
176    // to be moved outward.
177    //
178    if (wSearchPriority != MODULE_PRIORITY_REMOVE)
179       {
180       for (iModule = 0; iModule < l_cModules; ++iModule)
181          {
182          if (l_aModules[ iModule ].wPriority == 0)  // end of list?
183             break;
184          if (l_aModules[ iModule ].wPriority > wSearchPriority)  // good place?
185             break;
186          }
187
188       for (size_t iTarget = iModule; iTarget < l_cModules; ++iTarget)
189          {
190          if (l_aModules[ iTarget ].wPriority == 0)  // end of list?
191             break;
192          }
193
194       if (REALLOC (l_aModules, l_cModules, 1+iTarget, cREALLOC_MODULES))
195          {
196          for (size_t iSource = iTarget -1; (LONG)iSource >= (LONG)iModule; --iSource, --iTarget)
197             memcpy (&l_aModules[ iTarget ], &l_aModules[ iSource ], sizeof(MODULE));
198
199          l_aModules[ iModule ].wPriority = wSearchPriority;
200          l_aModules[ iModule ].hInstance = hInstance;
201          }
202       }
203
204    LeaveCriticalSection (&l_csModules);
205 }
206
207
208 /*
209  *** FindAfsCommonPath
210  *
211  * Because our localized files are often placed in a single Common directory
212  * for the AFS product, we need to know how to find that directory. This
213  * routine, and its helper FindAfsCommonPathByComponent(), do that search.
214  *
215  */
216
217 BOOL FindAfsCommonPathByComponent (LPTSTR pszCommonPath, LPTSTR pszComponent)
218 {
219    *pszCommonPath = 0;
220
221    TCHAR szRegPath[ MAX_PATH ];
222    wsprintf (szRegPath, TEXT("Software\\TransarcCorporation\\%s\\CurrentVersion"), pszComponent);
223
224    HKEY hk;
225    if (RegOpenKey (HKEY_LOCAL_MACHINE, szRegPath, &hk) == 0)
226       {
227       DWORD dwType = REG_SZ;
228       DWORD dwSize = MAX_PATH;
229
230       if (RegQueryValueEx (hk, TEXT("PathName"), NULL, &dwType, (PBYTE)pszCommonPath, &dwSize) == 0)
231          {
232          *(LPTSTR)FindBaseFileName (pszCommonPath) = TEXT('\0');
233
234          if (pszCommonPath[0] && (pszCommonPath[ lstrlen(pszCommonPath)-1 ] == TEXT('\\')))
235             pszCommonPath[ lstrlen(pszCommonPath)-1 ] = TEXT('\0');
236
237          if (pszCommonPath[0])
238             lstrcat (pszCommonPath, TEXT("\\Common"));
239          }
240
241       RegCloseKey (hk);
242       }
243
244    return !!*pszCommonPath;
245 }
246
247
248 BOOL FindAfsCommonPath (LPTSTR pszCommonPath)
249 {
250    if (FindAfsCommonPathByComponent (pszCommonPath, TEXT("AFS Client")))
251       return TRUE;
252    if (FindAfsCommonPathByComponent (pszCommonPath, TEXT("AFS Control Center")))
253       return TRUE;
254    if (FindAfsCommonPathByComponent (pszCommonPath, TEXT("AFS Server")))
255       return TRUE;
256    if (FindAfsCommonPathByComponent (pszCommonPath, TEXT("AFS Supplemental Documentation")))
257       return TRUE;
258    return FALSE;
259 }
260
261
262 /*
263  *** TaLocale_LoadCorrespondingModule
264  *
265  * This routine looks for a .DLL named after the specified module, but
266  * with a suffix reflecting the current locale--it loads that library
267  * and calls TaLocale_SpecifyModule for the library.
268  *
269  */
270
271 HINSTANCE TaLocale_LoadCorrespondingModule (HINSTANCE hInstance, WORD wSearchPriority)
272 {
273    // If the caller was sloppy and didn't supply an instance handle,
274    // assume we should find the module corresponding with the current .EXE.
275    //
276    if (hInstance == NULL)
277       hInstance = GetModuleHandle(NULL);
278
279    TCHAR szFilename[ MAX_PATH ] = TEXT("");
280    GetModuleFileName (hInstance, szFilename, MAX_PATH);
281
282    return TaLocale_LoadCorrespondingModuleByName (hInstance, szFilename, wSearchPriority);
283 }
284
285 HINSTANCE TaLocale_LoadCorrespondingModuleByName (HINSTANCE hInstance, LPTSTR pszFilename, WORD wSearchPriority)
286 {
287    HINSTANCE hDLL = NULL;
288
289    TCHAR szFilename[ MAX_PATH ];
290    if (lstrchr (pszFilename, TEXT('\\')) != NULL)
291       lstrcpy (szFilename, pszFilename);
292    else
293       {
294       GetModuleFileName (hInstance, szFilename, MAX_PATH);
295       lstrcpy ((LPTSTR)FindBaseFileName (szFilename), pszFilename);
296       }
297
298
299    // If the caller was sloppy and didn't supply an instance handle,
300    // assume we should find the module corresponding with the current .EXE.
301    //
302    if (hInstance == NULL)
303       hInstance = GetModuleHandle(NULL);
304
305    LPTSTR pchExtension;
306    if ((pchExtension = (LPTSTR)FindExtension (szFilename)) != NULL)
307       {
308
309       // Find the filename associated with the specified module, remove its
310       // extension, and append "_409.dll" (where the 409 is, naturally, the
311       // current LANGID). Then try to load that library.
312       //
313       wsprintf (pchExtension, TEXT("_%lu.dll"), TaLocale_GetLanguage());
314       if ((hDLL = LoadLibrary (szFilename)) == NULL)
315          hDLL = LoadLibrary (FindBaseFileName (szFilename));
316
317       // If we couldn't find the thing under that name, it's possible we
318       // have a .DLL made for the proper language but not for the user's
319       // specific sublanguage (say, a US English .DLL but we're running
320       // in a Canadian English locale). Make an intelligent guess about
321       // what the valid ID would be.
322       //
323       if (hDLL == NULL)
324          {
325          wsprintf (pchExtension, TEXT("_%lu.dll"), TaLocale_GuessBestLangID (TaLocale_GetLanguage()));
326          if ((hDLL = LoadLibrary (szFilename)) == NULL)
327             hDLL = LoadLibrary (FindBaseFileName (szFilename));
328          }
329
330       // If we STILL couldn't find a corresponding resource library,
331       // we'll take anything we can find; this should cover the case
332       // where a Setup program asked the user what language to use,
333       // and just installed that matching library. Look in the
334       // appropriate directory for any .DLL that fits the naming convention.
335       //
336       if (hDLL == NULL)
337          {
338          wsprintf (pchExtension, TEXT("_*.dll"));
339
340          WIN32_FIND_DATA wfd;
341          memset (&wfd, 0x00, sizeof(wfd));
342
343          HANDLE hFind;
344          if ((hFind = FindFirstFile (szFilename, &wfd)) != NULL)
345             {
346             if (wfd.cFileName[0])
347                {
348                wsprintf ((LPTSTR)FindBaseFileName (szFilename), wfd.cFileName);
349                hDLL = LoadLibrary (szFilename);
350                }
351             FindClose (hFind);
352             }
353          }
354
355       // If we EVEN NOW couldn't find a corresponding resource library,
356       // we may have done our wildcard search in the wrong directory.
357       // Try to find the Common subdirectory of our AFS installation,
358       // and look for any matching DLL there.
359       //
360       if (hDLL == NULL)
361          {
362          wsprintf (pchExtension, TEXT("_*.dll"));
363
364          TCHAR szCommonPath[ MAX_PATH ];
365          if (FindAfsCommonPath (szCommonPath))
366             {
367             lstrcat (szCommonPath, TEXT("\\"));
368             lstrcat (szCommonPath, FindBaseFileName (szFilename));
369
370             WIN32_FIND_DATA wfd;
371             memset (&wfd, 0x00, sizeof(wfd));
372
373             HANDLE hFind;
374             if ((hFind = FindFirstFile (szCommonPath, &wfd)) != NULL)
375                {
376                if (wfd.cFileName[0])
377                   {
378                   wsprintf ((LPTSTR)FindBaseFileName (szCommonPath), wfd.cFileName);
379                   hDLL = LoadLibrary (szCommonPath);
380                   }
381                FindClose (hFind);
382                }
383             }
384          }
385
386       // If all else fails, we'll try to find the English library
387       // somewhere on our path.
388       //
389       if (hDLL == NULL)
390          {
391          wsprintf (pchExtension, TEXT("_%lu.dll"), MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US));
392          if ((hDLL = LoadLibrary (szFilename)) == NULL)
393             hDLL = LoadLibrary (FindBaseFileName (szFilename));
394          }
395
396       // If we were successful in loading the resource library, add it
397       // to our chain of modules-to-search
398       //
399       if (hDLL != NULL)
400          {
401          TaLocale_SpecifyModule (hDLL, wSearchPriority);
402          }
403       }
404
405    return hDLL;
406 }
407
408
409 /*
410  *** TaLocale_EnumModule
411  *
412  * Enables enumeration of each of the product modules which will be seached
413  * by TaLocale for resources. Use TaLocale_SpecifyModule to modify this list.
414  * Modules will be returned in priority order, with the highest-priority
415  * modules being searched first.
416  *
417  */
418
419 BOOL TaLocale_EnumModule (size_t iModule, HINSTANCE *phInstance, WORD *pwSearchPriority)
420 {
421    BOOL rc = FALSE;
422    TaLocale_Initialize();
423    EnterCriticalSection (&l_csModules);
424
425    if ( (iModule < l_cModules) && (l_aModules[ iModule ].wPriority != 0) )
426       {
427       rc = TRUE;
428       if (phInstance)
429          *phInstance = l_aModules[ iModule ].hInstance;
430       if (pwSearchPriority)
431          *pwSearchPriority = l_aModules[ iModule ].wPriority;
432       }
433
434    LeaveCriticalSection (&l_csModules);
435    return rc;
436 }
437
438
439 /*
440  *** TaLocale_GetLanguage
441  *** TaLocale_SetLanguage
442  *
443  * Allows specification of a default language for resources extracted by
444  * the functions exported by tal_string.h and tal_dialog.h. When a particular
445  * string or dialog resource is required, the resource which matches this
446  * specified language will be retrieved--if no localized resource is available,
447  * the default resource will instead be used.
448  *
449  */
450
451 LANGID TaLocale_GetLanguage (void)
452 {
453    TaLocale_Initialize();
454    return l_lang;
455 }
456
457
458 void TaLocale_SetLanguage (LANGID lang)
459 {
460    TaLocale_Initialize();
461    l_lang = lang;
462 }
463
464
465 /*
466  *** TaLocale_GetLanguageOverride
467  *** TaLocale_SetLanguageOverride
468  *
469  * Allows specification of a persistent default language for resources
470  * extracted by the functions exported by tal_string.h and tal_dialog.h.
471  * If a language override (which is really just a registry entry) exists,
472  * all TaLocale-based applications will default to that locale when first
473  * run.
474  *
475  */
476
477 static HKEY REGSTR_BASE_OVERRIDE = HKEY_LOCAL_MACHINE;
478 static TCHAR REGSTR_PATH_OVERRIDE[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Nls");
479 static TCHAR REGSTR_VAL_OVERRIDE[] = TEXT("Default Language");
480
481 LANGID TaLocale_GetLanguageOverride (void)
482 {
483    DWORD dwLang = 0;
484
485    HKEY hk;
486    if (RegOpenKey (REGSTR_BASE_OVERRIDE, REGSTR_PATH_OVERRIDE, &hk) == 0)
487       {
488       DWORD dwType = REG_DWORD;
489       DWORD dwSize = sizeof(DWORD);
490       if (RegQueryValueEx (hk, REGSTR_VAL_OVERRIDE, 0, &dwType, (PBYTE)&dwLang, &dwSize) != 0)
491          dwLang = 0;
492       RegCloseKey (hk);
493       }
494
495    return (LANGID)dwLang;
496 }
497
498
499 void TaLocale_SetLanguageOverride (LANGID lang)
500 {
501    HKEY hk;
502    if (RegCreateKey (REGSTR_BASE_OVERRIDE, REGSTR_PATH_OVERRIDE, &hk) == 0)
503       {
504       DWORD dwLang = (DWORD)lang;
505       RegSetValueEx (hk, REGSTR_VAL_OVERRIDE, 0, REG_DWORD, (PBYTE)&dwLang, sizeof(DWORD));
506       RegCloseKey (hk);
507       }
508 }
509
510
511 void TaLocale_RemoveLanguageOverride (void)
512 {
513    HKEY hk;
514    if (RegOpenKey (REGSTR_BASE_OVERRIDE, REGSTR_PATH_OVERRIDE, &hk) == 0)
515       {
516       RegDeleteValue (hk, REGSTR_VAL_OVERRIDE);
517       RegCloseKey (hk);
518       }
519 }
520
521
522 /*
523  *** TaLocale_GetResource
524  *
525  * Returns a pointer an in-memory image of a language-specific resource.
526  * The resource is found by searching all specified module handles
527  * (as determined automatically, or as specified by previous calls to
528  * TaLocale_SpecifyModule()) for an equivalent resource identifier matching
529  * the requested resource type and localized into the requested language.
530  * In the event that a matching localized resource cannot be found, the
531  * search is repeated using LANG_USER_DEFAULT.
532  *
533  * The pointer returned should be treated as read-only, and should not be freed.
534  *
535  */
536
537 LPCVOID TaLocale_GetResourceEx (LPCTSTR pszType, LPCTSTR pszRes, LANGID lang, HINSTANCE *phInstFound, BOOL fSearchDefaultLanguageToo)
538 {
539    PVOID pr = NULL;
540
541    HINSTANCE hInstance;
542    for (size_t iModule = 0; TaLocale_EnumModule (iModule, &hInstance); ++iModule)
543       {
544       HRSRC hr;
545       if ((hr = FindResourceEx (hInstance, pszType, pszRes, lang)) == NULL)
546          {
547          // Our translation teams don't usually change the language
548          // constants within .RC files, so we should look for English
549          // language translations too.
550          //
551          if ((hr = FindResourceEx (hInstance, pszType, pszRes, MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US))) == NULL)
552             {
553             // If we still can't find it, we'll take anything...
554             //
555             if ((hr = FindResource (hInstance, pszType, pszRes)) == NULL)
556                continue;
557             }
558          }
559
560       // Once we get here, we'll only fail for weird out-of-memory problems.
561       //
562       HGLOBAL hg;
563       if ((hg = LoadResource (hInstance, hr)) != NULL)
564          {
565          if ((pr = (PVOID)LockResource (hg)) != NULL)
566             {
567             if (phInstFound)
568                *phInstFound = hInstance;
569             break;
570             }
571          }
572       }
573
574    return pr;
575 }
576
577
578 LPCVOID TaLocale_GetResource (LPCTSTR pszType, LPCTSTR pszRes, LANGID lang, HINSTANCE *phInstFound)
579 {
580    return TaLocale_GetResourceEx (pszType, pszRes, lang, phInstFound, TRUE);
581 }
582
583
584
585 /*
586  *** TaLocale_GetStringResource
587  *** TaLocale_GetDialogResource
588  *
589  * Convenience wrappers around TaLocale_GetResource for obtaining resources
590  * of a particular type by numeric identifier; these routines specify the
591  * default language (from TaLocale_SetLanguage()) when calling
592  * TaLocale_GetResource().
593  *
594  */
595
596 LPCDLGTEMPLATE TaLocale_GetDialogResource (int idd, HINSTANCE *phInstFound)
597 {
598    return (LPCDLGTEMPLATE)TaLocale_GetResource (RT_DIALOG, MAKEINTRESOURCE( idd ), TaLocale_GetLanguage(), phInstFound);
599 }
600
601
602 LPCSTRINGTEMPLATE TaLocale_GetStringResource (int ids, HINSTANCE *phInstFound)
603 {
604    // Strings are organized into heaps of String Tables, each table
605    // holding 16 strings (regardless of their length). The first table's
606    // first string index is for string #1. When searching for a string,
607    // the string's table is the index given to FindResource.
608    //
609    LPCSTRINGTEMPLATE pst = NULL;
610    LANGID lang = TaLocale_GetLanguage();
611
612    int iTable = (ids / 16) + 1;           // 1 = first string table
613    int iIndex = ids - ((iTable-1) * 16);  // 0 = first string in the table
614
615    HINSTANCE hInstance;
616    for (size_t iModule = 0; !pst && TaLocale_EnumModule (iModule, &hInstance); ++iModule)
617       {
618       HRSRC hr;
619       if ((hr = FindResourceEx (hInstance, RT_STRING, MAKEINTRESOURCE( iTable ), lang)) == NULL)
620          {
621          // Our translation teams don't usually change the language
622          // constants within .RC files, so we should look for English
623          // language translations too.
624          //
625          if ((hr = FindResourceEx (hInstance, RT_STRING, MAKEINTRESOURCE( iTable ), MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US))) == NULL)
626             {
627             // If we still can't find it, we'll take anything...
628             //
629             if ((hr = FindResource (hInstance, RT_STRING, MAKEINTRESOURCE( iTable ))) == NULL)
630                continue;
631             }
632          }
633
634       HGLOBAL hg;
635       if ((hg = LoadResource (hInstance, hr)) != NULL)
636          {
637          const WORD *pTable;
638          if ((pTable = (WORD*)LockResource (hg)) != NULL)
639             {
640             try {
641                // Skip words in the string table until we reach the string
642                // index we're looking for.
643                //
644                for (int iIndexWalk = iIndex; iIndexWalk; --iIndexWalk)
645                   pTable += 1 + ((LPCSTRINGTEMPLATE)pTable)->cchString;
646
647                if (IsValidStringTemplate ((LPCSTRINGTEMPLATE)pTable))
648                   {
649                   pst = (LPCSTRINGTEMPLATE)pTable;
650                   if (phInstFound)
651                      *phInstFound = hInstance;
652                   }
653                }
654             catch(...)
655                {
656                // If we walked off the end of the table, then the
657                // string we want just wasn't there.
658                }
659             }
660          }
661       }
662
663    return pst;
664 }
665
666
667 BOOL IsValidStringTemplate (LPCSTRINGTEMPLATE pTable)
668 {
669    if (!pTable->cchString)
670       return FALSE;
671
672    for (size_t ii = 0; ii < pTable->cchString; ++ii)
673       {
674       if (!pTable->achString[ii])
675          return FALSE;
676       }
677
678    return TRUE;
679 }
680
681
682 /*
683  *** TaLocale_LoadMenu
684  *** TaLocale_LoadImage
685  *
686  * Replacements for Win32 functions. By using these functions instead, the
687  * caller can load the appropriate resources regardless of the module in
688  * which they reside, or the language which is required.
689  *
690  */
691
692 HMENU TaLocale_LoadMenu (int idm)
693 {
694    const MENUTEMPLATE *pTemplate;
695    if ((pTemplate = (const MENUTEMPLATE *)TaLocale_GetResource (RT_MENU, MAKEINTRESOURCE( idm ), TaLocale_GetLanguage())) == NULL)
696       return NULL;
697    return LoadMenuIndirect (pTemplate);
698 }
699
700
701 HANDLE TaLocale_LoadImage (int idi, UINT imageType, int cx, int cy, UINT imageFlags)
702 {
703    HINSTANCE hInstance;
704    for (size_t iModule = 0; TaLocale_EnumModule (iModule, &hInstance); ++iModule)
705       {
706       HANDLE hImage;
707       if (imageType == IMAGE_ICON)
708          hImage = (HANDLE)LoadIcon (hInstance, MAKEINTRESOURCE(idi));
709       else
710          hImage = LoadImage (hInstance, MAKEINTRESOURCE(idi), imageType, cx, cy, imageFlags);
711
712       if (hImage != NULL)
713          return hImage;
714       }
715
716    return NULL;
717 }
718
719
720 HICON TaLocale_LoadIcon (int idi)
721 {
722    return (HICON)TaLocale_LoadImage (idi, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
723 }
724
725
726 HACCEL TaLocale_LoadAccelerators (int ida)
727 {
728    HINSTANCE hInstance;
729    for (size_t iModule = 0; TaLocale_EnumModule (iModule, &hInstance); ++iModule)
730       {
731       HACCEL hAccel;
732       if ((hAccel = LoadAccelerators (hInstance, MAKEINTRESOURCE(ida))) != NULL)
733          return hAccel;
734       }
735
736    return NULL;
737 }
738
739
740