VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Setup/Resource.h
blob: b5b7d466d54da09ee704d231787211c5a93f7bbb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by Setup.rc
//
#define IDR_COMREG                      10
#define IDR_LANG_AR                     20
#define IDR_LANG_CS                     21
#define IDR_LANG_DE                     22
#define IDR_LANG_ES                     23
#define IDR_LANG_FR                     24
#define IDR_LANG_IT                     25
#define IDR_LANG_JA                     26
#define IDR_LANG_NL                     27
#define IDR_LANG_PL                     28
#define IDR_LANG_RO                     29
#define IDR_LANG_RU                     30
#define IDR_LANG_VI                     31
#define IDR_LANG_ZHCN                   32
#define IDR_LANG_ZHHK                   33
#define IDR_LANG_BE                     34
#define IDR_LANG_BG                     35
#define IDR_LANG_CA                     36
#define IDR_LANG_CO                     37
#define IDR_LANG_DA                     38
#define IDR_LANG_EL                     39
#define IDR_LANG_ET                     40
#define IDR_LANG_EU                     41
#define IDR_LANG_FA                     42
#define IDR_LANG_FI                     43
#define IDR_LANG_HE                     44
#define IDR_LANG_HU                     45
#define IDR_LANG_ID                     46
#define IDR_LANG_KA                     47
#define IDR_LANG_KO                     48
#define IDR_LANG_LV                     49
#define IDR_LANG_NN                     50
#define IDR_LANG_PTBR                   51
#define IDR_LANG_SK                     52
#define IDR_LANG_SL                     53
#define IDR_LANG_SV                     54
#define IDR_LANG_TH                     55
#define IDR_LANG_TR                     56
#define IDR_LANG_UK                     57
#define IDR_LANG_UZ                     58
#define IDR_LANG_ZHTW                   59
#define IDD_INSTALL                     101
#define IDD_INSTALL_OPTIONS_PAGE_DLG    102
#define IDD_UNINSTALL                   103
#define IDI_SETUP                       104
#define IDR_SETUP_RSRC_HEADER           105
#define IDD_EXTRACTION_OPTIONS_PAGE_DLG 106
#define IDB_SETUP_WIZARD                107
#define IDD_INTRO_PAGE_DLG              108
#define IDB_SETUP_WIZARD_BKG            109
#define IDD_INFO_PAGE_DLG               110
#define IDD_INSTL_DLG                   111
#define IDD_WIZARD_MODE_PAGE_DLG        112
#define IDD_PROGRESS_PAGE_DLG           113
#define IDD_DONATIONS_PAGE_DLG          114
#define IDD_INSTALL_LANGUAGE            115
#define IDC_DESTINATION                 1000
#define IDC_BOX_TITLE                   1001
#define IDC_BROWSE                      1002
#define IDC_BOX_INFO                    1003
#define IDC_LICENSE                     1004
#define IDC_BOX_HELP                    1005
#define IDC_LICENSE_TEXT                1006
#define IDC_BOX_HELP2                   1007
#define IDC_FILE_TYPE                   1008
#define IDT_UNINSTALL_DIR               1009
#define IDC_PROG_GROUP                  1010
#define IDC_SYSTEM_RESTORE              1011
#define IDC_DESKTOP_ICON                1012
#define IDC_ALL_USERS                   1013
#define IDT_INSTALL_DESTINATION         1014
#define IDC_UNINSTALL                   1015
#define IDC_PROGRESS_BAR                1016
#define IDC_LOG_WINDOW                  1017
#define IDC_SETUP_WIZARD_BKG            1018
#define IDC_SETUP_WIZARD_GFX_AREA       1019
#define IDC_HR                          1020
#define IDC_OPEN_CONTAINING_FOLDER      1021
#define IDC_AGREE                       1022
#define IDC_HR_BOTTOM                   1023
#define IDC_WIZARD_MODE_INSTALL         1024
#define IDC_WIZARD_MODE_EXTRACT_ONLY    1025
#define IDC_NEXT                        1026
#define IDC_PREV                        1027
#define IDT_EXTRACT_DESTINATION         1028
#define IDC_POS_BOX                     1029
#define IDC_BITMAP_SETUP_WIZARD         1030
#define IDC_MAIN_CONTENT_CANVAS         1031
#define IDC_DONATE                      1032
#define IDC_LANGUAGES_LIST              1033
#define IDC_SELECT_LANGUAGE_LABEL       1034

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC                     1
#define _APS_NEXT_RESOURCE_VALUE        116
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1035
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif
460'>460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
/*
 Derived from source code of TrueCrypt 7.1a, which is
 Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
 by the TrueCrypt License 3.0.

 Modifications and additions to the original source code (contained in this file)
 and all other portions of this file are Copyright (c) 2013-2017 IDRIX
 and are governed by the Apache License 2.0 the full text of which is
 contained in the file License.txt included in VeraCrypt binary and source
 code distribution packages.
*/

#include "Language.h"
#include "Dlgcode.h"
#include "Dictionary.h"
#include "Tcdefs.h"
#include "Xml.h"

#include "../Common/Resource.h"

#ifdef TCMOUNT
#include "../Mount/Resource.h"
#endif

#ifdef VOLFORMAT
#include "../Format/Resource.h"
#endif

#ifdef SETUP
#include "../Setup/Resource.h"
#endif

#include <Strsafe.h>

BOOL LocalizationActive;
int LocalizationSerialNo;

wchar_t UnknownString[1024]  = {0};
static char *LanguageFileBuffer = NULL;
static HANDLE LanguageFileFindHandle = INVALID_HANDLE_VALUE;
static char PreferredLangId[6] = {0};
static char *LanguageResource = NULL;
static DWORD LanguageResourceSize = 0;
static char *HeaderResource[2] = {NULL, NULL};
static DWORD HeaderResourceSize[2] = {0, 0};
static char ActiveLangPackVersion[6] = {0};
static int LanguageResourceId = 0;

static char *MapFirstLanguageFile ()
{
	if (LanguageFileFindHandle != INVALID_HANDLE_VALUE)
	{
		FindClose (LanguageFileFindHandle);
		LanguageFileFindHandle = INVALID_HANDLE_VALUE;
	}

	if (LanguageFileBuffer != NULL)
	{
		free (LanguageFileBuffer);
		LanguageFileBuffer = NULL;
	}

	LanguageResourceId = 0;

	if (LanguageResource == NULL)
	{
		DWORD size;
		LanguageResource = MapResource (L"Xml", IDR_LANGUAGE, &size);
		if (LanguageResource)
			LanguageResourceSize = size;
	}

	if (LanguageResource)
	{
		LanguageFileBuffer = malloc(LanguageResourceSize + 1);
		if (LanguageFileBuffer)
		{
			memcpy (LanguageFileBuffer, LanguageResource, LanguageResourceSize);
			LanguageFileBuffer[LanguageResourceSize] = 0;
		}
	}

	return LanguageFileBuffer;
}


static char *MapNextLanguageFile (int resourceid)
{
	wchar_t f[TC_MAX_PATH*2], *t;
	WIN32_FIND_DATAW find;
	HANDLE file;
	DWORD read;
	BOOL bStatus;

	/* free memory here to avoid leaks */
	if (LanguageFileBuffer != NULL)
	{
		free (LanguageFileBuffer);
		LanguageFileBuffer = NULL;
	}

	if (resourceid == 0)
	{
		if (LanguageFileFindHandle == INVALID_HANDLE_VALUE)
		{
			GetModuleFileNameW (NULL, f, sizeof (f) / sizeof (f[0]));
			t = wcsrchr (f, L'\\');
			if (t == NULL) return NULL;

			*t = 0;
			StringCbCatW (f, sizeof(f), L"\\Languages\\Language*.xml");

			LanguageFileFindHandle = FindFirstFileW (f, &find);
		}
		else if (!FindNextFileW (LanguageFileFindHandle, &find))
		{
			FindClose (LanguageFileFindHandle);
			LanguageFileFindHandle = INVALID_HANDLE_VALUE;
			return NULL;
		}

		if (LanguageFileFindHandle == INVALID_HANDLE_VALUE) return NULL;
		if (find.nFileSizeHigh != 0) return NULL;

		LanguageFileBuffer = malloc(find.nFileSizeLow + 1);
		if (LanguageFileBuffer == NULL) return NULL;

		GetModuleFileNameW (NULL, f, sizeof (f) / sizeof(f[0]));
		t = wcsrchr (f, L'\\');
		if (t == NULL)
		{
			free(LanguageFileBuffer);
			LanguageFileBuffer = NULL;
			return NULL;
		}

		t[1] = 0;
		StringCbCatW (f, sizeof(f), L"Languages\\");
		StringCbCatW (f, sizeof(f),find.cFileName);

		file = CreateFileW (f, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (file == INVALID_HANDLE_VALUE)
		{
			free(LanguageFileBuffer);
			LanguageFileBuffer = NULL;
			return NULL;
		}

		bStatus = ReadFile (file, LanguageFileBuffer, find.nFileSizeLow, &read, NULL);
		CloseHandle (file);
		if (!bStatus || (read != find.nFileSizeLow))
		{
			free(LanguageFileBuffer);
			LanguageFileBuffer = NULL;
			return NULL;
		}

		LanguageFileBuffer [find.nFileSizeLow] = 0; // we have allocated (find.nFileSizeLow + 1) bytes
	}
	else if (LanguageResourceId != resourceid)
	{
		DWORD size;

		LanguageResourceId = resourceid;

		LanguageResource = MapResource (L"Languages", LanguageResourceId, &size);
		if (LanguageResource)
			LanguageResourceSize = size;

		if (LanguageResource)
		{
			LanguageFileBuffer = malloc(LanguageResourceSize + 1);
			if (LanguageFileBuffer)
			{
				memcpy (LanguageFileBuffer, LanguageResource, LanguageResourceSize);
				LanguageFileBuffer[LanguageResourceSize] = 0;
			}
		}
	}

	return LanguageFileBuffer;
}


static BOOL LoadLanguageData (int resourceid, BOOL bForceSetPreferredLanguage, BOOL bForceSilent)
{
	DWORD size;
	BYTE *res;
	char *xml, *header, *headerPtr;
	char langId[6] = "en", attr[32768], key[128];
	BOOL defaultLangParsed = FALSE, langFound = FALSE;
	WCHAR wattr[32768];
	int i, intKey, len;

	char *xmlElements[] = {"entry", 0};

#ifdef TCMOUNT
	int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_MOUNT_RSRC_HEADER, 0 };
#endif

#ifdef VOLFORMAT
	int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_FORMAT_RSRC_HEADER, 0 };
#endif

#ifdef SETUP
	int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_SETUP_RSRC_HEADER, 0 };
#endif

	LocalizationActive = FALSE;
	ActiveLangPackVersion[0] = 0;
	ClearDictionaryPool ();

	if ((resourceid == 0) && (PreferredLangId[0] != 0))
		StringCbCopyA (langId, sizeof(langId), PreferredLangId);

	// Parse all available language files until preferred language is found
	for (res = MapFirstLanguageFile (); res != NULL; res = MapNextLanguageFile (resourceid))
	{
		xml = (char *) res;
		xml = XmlFindElement (xml, "localization");
		if (!xml)
			continue;

		// Required TrueCrypt version
		XmlGetAttributeText (xml, "prog-version", attr, sizeof (attr));

		// Check version of external language file
		if (defaultLangParsed && strcmp (attr, VERSION_STRING VERSION_STRING_SUFFIX) && strcmp (attr, "DEBUG"))
		{
			wchar_t m[2048];
			StringCbPrintfW (m, sizeof(m), L"The installed language pack is incompatible with this version of VeraCrypt (the language pack is for VeraCrypt %hs). A newer version may be available at www.idrix.fr.\n\nTo prevent this message from being displayed, do any of the following:\n\n- Select 'Settings' > 'Language'; then select 'English' and click 'OK'.\n\n- Remove or replace the language pack with a compatible version (the language pack may reside e.g. in 'C:\\Program Files\\VeraCrypt' or '%%LOCALAPPDATA%%\\VirtualStore\\Program Files\\VeraCrypt', etc.)", attr);
			if (!bForceSilent)
				MessageBoxW (NULL, m, L"VeraCrypt", MB_ICONERROR);
			continue;
		}

		// Search language id in language file
		if (defaultLangParsed)
		{
			while (xml = XmlFindElement (xml, "language"))
			{
				XmlGetAttributeText (xml, "langid", attr, sizeof (attr));
				if (resourceid == 0)
				{
					if (strcmp (attr, langId) == 0)
					{
						XmlGetAttributeText (xml++, "version", ActiveLangPackVersion, sizeof (ActiveLangPackVersion));
						langFound = TRUE;
						break;
					}
					xml++;
				}
				else
				{
					StringCbCopyA (langId, sizeof (langId), attr);
					XmlGetAttributeText (xml++, "version", ActiveLangPackVersion, sizeof (ActiveLangPackVersion));
					langFound = TRUE;
					break;
				}
			}

			if (!langFound) continue;
		}

		// Create font dictionary
		xml = (char *) res;
		while (xml = XmlFindElement (xml, "font"))
		{
			XmlGetAttributeText (xml, "lang", attr, sizeof (attr));
			if (!defaultLangParsed
				|| strcmp (attr, langId) == 0)
			{
				Font font;
				memset (&font, 0, sizeof (font));

				XmlGetAttributeText (xml, "face", attr, sizeof (attr));

				len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr) / sizeof(wattr[0]));
				font.FaceName = AddPoolData ((void *) wattr, len * 2);

				XmlGetAttributeText (xml, "size", attr, sizeof (attr));
				sscanf (attr, "%d", &font.Size);

				StringCbCopyA (attr, sizeof(attr), "font_");
				XmlGetAttributeText (xml, "class", attr + 5, sizeof (attr) - 5);
				AddDictionaryEntry (
					AddPoolData ((void *) attr, strlen (attr) + 1), 0,
					AddPoolData ((void *) &font, sizeof(font)));
			}

			xml++;
		}

		// Create string and control dictionaries
		for (i = 0; xmlElements[i] != 0; i++)
		{
			xml = (char *) res;
			while (xml = XmlFindElement (xml, xmlElements[i]))
			{
				void *key;
				void *text;

				XmlGetAttributeText (xml, "lang", attr, sizeof (attr));
				if (!defaultLangParsed
					|| strcmp (attr, langId) == 0)
				{
					if (XmlGetAttributeText (xml, "key", attr, sizeof (attr)))
					{
						key = AddPoolData (attr, strlen (attr) + 1);
						if (key == NULL) return FALSE;

						XmlGetNodeText (xml, attr, sizeof (attr));

						// Parse \ escape sequences
						{
							char *in = attr, *out = attr;
							while (*in)
							{
								if (*in == '\\')
								{
									in++;
									switch (*in++)
									{
									case '\\': *out++ = '\\'; break;
									case 't': *out++ = '\t'; break;
									case 'n': *out++ = 13; *out++ = 10; break;
									default:
										if (!bForceSilent)
											MessageBoxA (0, key, "VeraCrypt: Unknown '\\' escape sequence in string", MB_ICONERROR);
										return FALSE;
									}
								}
								else
									*out++ = *in++;
							}
							*out = 0;
						}

						// UTF8 => wide char
						len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr) / sizeof(wattr[0]));
						if (len == 0)
						{
							if (!bForceSilent)
								MessageBoxA (0, key, "VeraCrypt: Error while decoding UTF-8 string", MB_ICONERROR);
							return FALSE;
						}

						// Add to dictionary
						text = AddPoolData ((void *) wattr, len * 2);
						if (text == NULL) return FALSE;

						AddDictionaryEntry ((char *) key, 0, text);
					}
				}

				xml++;
			}
		}

		if (langFound)
			break;

		if (!defaultLangParsed)
		{
			defaultLangParsed = TRUE;
			if ((resourceid == 0) && (langId[0] == 0 || strcmp (langId, "en") == 0))
				break;
		}
	}

	LocalizationActive = langFound && strcmp (langId, "en") != 0;
	LocalizationSerialNo++;

	if (bForceSetPreferredLanguage)
		StringCbCopyA (PreferredLangId, sizeof (PreferredLangId), langId);

	// Create control ID dictionary

	// Default controls
	AddDictionaryEntry (NULL, 1, GetString ("IDOK"));
	AddDictionaryEntry (NULL, 2, GetString ("IDCANCEL"));
	AddDictionaryEntry (NULL, 8, GetString ("IDCLOSE"));
	AddDictionaryEntry (NULL, 9, GetString ("IDHELP"));

	for (i = 0; headers[i] != 0; i++)
	{
		if (HeaderResource[i] == NULL)
		{
			HeaderResource[i] = MapResource (L"Header", headers[i], &size);
			if (HeaderResource[i])
				HeaderResourceSize[i] = size;
		}

		headerPtr = NULL;
		if (HeaderResource[i])
		{
			headerPtr = (char*) malloc (HeaderResourceSize[i] + 1);
			if (headerPtr)
			{
				memcpy (headerPtr, HeaderResource[i], HeaderResourceSize[i]);
				headerPtr [HeaderResourceSize[i]] = 0;
			}
		}

		header = headerPtr;
		if (header == NULL) return FALSE;
		header--;

		do
		{
			header++;
			if (sscanf (header, "#define %127s %d", key, &intKey) == 2)
			{
				WCHAR *str = GetString (key);

				if (str != UnknownString)
					AddDictionaryEntry (NULL, intKey, str);
			}

		} while ((header = strchr (header, '\n')) != NULL);

		free (headerPtr);
	}

	return TRUE;
}

BOOL LoadLanguageFile ()
{
	return LoadLanguageData (0, FALSE, FALSE);
}

BOOL LoadLanguageFromResource (int resourceid, BOOL bSetPreferredLanguage, BOOL bForceSilent)
{
	return LoadLanguageData (resourceid, bSetPreferredLanguage, bForceSilent);
}

// lParam = 1: auto mode
BOOL CALLBACK LanguageDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	WORD lw = LOWORD (wParam);
	WORD hw = HIWORD (wParam);

	switch (msg)
	{
	case WM_INITDIALOG:
		{
			char *xml;
			char attr[2048], lastLangId[10];
			WCHAR wattr[2048];
			int len;
			int langCount = 0;
			BOOL defaultLangFound = FALSE;

			LocalizeDialog (hwndDlg, "IDD_LANGUAGE");
			ToHyperlink (hwndDlg, IDC_GET_LANG_PACKS);

			for (xml = MapFirstLanguageFile (); xml != NULL; xml = MapNextLanguageFile (0))
			{
				while (xml = XmlFindElement (xml, "language"))
				{
					XmlGetAttributeText (xml, "name", attr, sizeof (attr));
					len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr) / sizeof(wattr[0]));

					if (len != 0
						&& (!defaultLangFound || wcscmp (wattr, L"English") != 0))
					{
						int i = (int) SendDlgItemMessageW (hwndDlg, IDC_LANGLIST, LB_ADDSTRING, 0, (LPARAM)wattr);
						if (i >= 0)
						{
							int id;

							// Encode language id in LPARAM
							XmlGetAttributeText (xml, "langid", attr, sizeof (attr));
							switch (strlen (attr))
							{
							case 2: id = attr[0] | attr[1] << 8; break;
							case 5: id = attr[0] | attr[1] << 8 | attr[3] << 16 | attr[4] << 24; break;
							default: continue;
							}

							if (!defaultLangFound)
								defaultLangFound = TRUE;

							SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_SETITEMDATA, i, (LPARAM) id);

							if (strcmp (attr, PreferredLangId) == 0)
							{
								char credits [10000];
								WCHAR wcredits [10000];
								WCHAR wversion [20];
								wchar_t szVers [200];
								int nLen;

								SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_SETCURSEL, i, 0);

								// Language pack version
								if (!ActiveLangPackVersion[0] || memcmp (ActiveLangPackVersion, "0.0.0", 5) == 0)
								{
									StringCbPrintfW (szVers, sizeof(szVers), GetString("LANG_PACK_VERSION"), L"--");
								}
								else
								{
									nLen = MultiByteToWideChar (CP_UTF8, 0, ActiveLangPackVersion, -1, wversion, sizeof (wversion) / sizeof(wversion[0]));
									if (nLen != 0)
										StringCbPrintfW (szVers, sizeof(szVers),GetString("LANG_PACK_VERSION"), wversion);
								}
								SetWindowTextW (GetDlgItem (hwndDlg, IDC_LANGPACK_VERSION), szVers);

								// Translator credits
								XmlGetAttributeText (xml, "translators", credits, sizeof (credits));
								nLen = MultiByteToWideChar (CP_UTF8, 0, credits, -1, wcredits, sizeof (wcredits) / sizeof(wcredits[0]));
								if (nLen != 0)
								{
									SetWindowTextW (GetDlgItem (hwndDlg, IDC_LANGPACK_CREDITS), wcredits);
								}
							}

							StringCbCopyA (lastLangId, sizeof(lastLangId),attr);
							langCount++;
						}
					}

					xml++;
				}
			}

			if (lParam == 1)
			{
				// Auto mode
				if (langCount < 2)
					EndDialog (hwndDlg, IDCANCEL);

				if (langCount == 2)
					StringCbCopyA (PreferredLangId, sizeof(PreferredLangId), lastLangId);

				EndDialog (hwndDlg, IDOK);
			}

			return 1;
		}

	case WM_COMMAND:

		if (lw == IDOK || hw == LBN_DBLCLK)
		{
			int i = (int) SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETCURSEL, 0, 0);

			if (i >= 0)
			{
				int id = (int) SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETITEMDATA, i, 0);

				if (id != LB_ERR)
				{
					char l[6];

					// Decode language id from LPARAM
					l[0] = (char) id;
					l[1] = (char) (id >> 8);
					l[2] = 0;

					if ((id & 0xffff0000) != 0)
					{
						l[2] = '-';
						l[3] = (char) (id >> 16);
						l[4] = id >> 24;
						l[5] = 0;
					}

					if (SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETCOUNT, 0, 0) > 1)
						StringCbCopyA (PreferredLangId, sizeof(PreferredLangId), l);
				}
			}

			EndDialog (hwndDlg, IDOK);
			return 1;
		}

		if (lw == IDCANCEL)
		{
			EndDialog (hwndDlg, lw);
			return 1;
		}

		if (lw == IDC_GET_LANG_PACKS)
		{
			char tmpstr [256];

			if (strlen (ActiveLangPackVersion) > 0 && strlen (GetPreferredLangId()) > 0)
				StringCbPrintfA (tmpstr, sizeof(tmpstr), "&langpackversion=%s&lang=%s", ActiveLangPackVersion, GetPreferredLangId());
			else
				tmpstr[0] = 0;

			Applink ("localizations");

			return 1;
		}
		return 0;
	}

	return 0;
}


char *GetPreferredLangId ()
{
	return PreferredLangId;
}


void SetPreferredLangId (char *langId)
{
	StringCbCopyA (PreferredLangId, sizeof(PreferredLangId), langId);
}


char *GetActiveLangPackVersion ()
{
	return ActiveLangPackVersion;
}


wchar_t *GetString (const char *stringId)
{
	WCHAR *str = (WCHAR *) GetDictionaryValue (stringId);
	if (str != NULL) return str;

	StringCbPrintfW (UnknownString, sizeof(UnknownString), UNKNOWN_STRING_ID L"%hs" UNKNOWN_STRING_ID, stringId);
	return UnknownString;
}


Font *GetFont (char *fontType)
{
	return (Font *) GetDictionaryValue (fontType);

}