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