Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2789 lines
69 KiB

/*++
Copyright (c) 1994-1995, Microsoft Corporation All rights reserved.
Module Name:
internat.c
Abstract:
This module contains the application that displays an indicator in
the Notification area of the Tray.
Revision History:
--*/
//
// Include Files.
//
#include "internat.h"
//
// Global Variables.
//
HKL hklCurrent;
BOOL bInternatActive = FALSE;
HIMAGELIST himIndicators = NULL;
HDPA hdpaInfoList = NULL;
HWND hwndTray = NULL;
HWND hwndNotify = NULL;
HINSTANCE hinst = NULL;
HINSTANCE hInstLib = NULL;
UINT cxSmIcon = 0;
UINT cySmIcon = 0;
#ifdef WINDOWS_ME
int meEto = 0;
#define NLS_RESOURCE_LOCALE_KEY TEXT("Control Panel\\desktop\\ResourceLocale")
#endif
#ifdef FE_IME
int iImeCurStat;
#endif
typedef int (CALLBACK* REGHOOKPROC)(LPVOID, LPARAM);
REGHOOKPROC fpRegHookWindow = NULL;
PROC fpStartShell = NULL;
PROC fpStopShell = NULL;
#ifdef FE_IME
typedef int (CALLBACK* FPGETIMESTAT)(VOID);
typedef HKL (CALLBACK* FPGETLAYOUT)(void);
FPGETIMESTAT fpGetIMEStat = NULL;
FPGETLAYOUT fpGetLayout = NULL;
#endif
#if defined(WINDOWS_PE) || defined(FE_IME)
typedef void (CALLBACK* FPSETNOTIFYWND)(HWND);
typedef HWND (CALLBACK* FPGETLASTACTIVE)(void);
typedef HWND (CALLBACK* FPGETLASTFOCUS)(void);
FPSETNOTIFYWND fpSetNotifyWnd = NULL;
FPGETLASTACTIVE fpGetLastActive = NULL;
FPGETLASTFOCUS fpGetLastFocus = NULL;
#endif
BOOL bInLangMenu = FALSE;
#ifndef USECBT
HWND hwndForLang = NULL;
#endif
DWORD fsShell;
TCHAR szAppName[] = TEXT("Indicator");
TCHAR szHelpFile[] = TEXT("windows.hlp");
#ifdef FE_IME
TCHAR szPropHwnd[] = TEXT("hwndIMC");
TCHAR szPropImeStat[] = TEXT("ImeStat");
BOOL g_bIMEIndicator = FALSE;
int nIMEIconIndex[8]; // eight states for now
#endif
//
// For Keyboard Layout info.
//
typedef struct
{
DWORD dwID; // numeric id
ATOM atmLayoutText; // layout text
UINT iSpecialID; // i.e. 0xf001 for dvorak etc
} LAYOUT, *LPLAYOUT;
static HANDLE hLayout;
static UINT nLayoutBuffSize;
static UINT iLayoutBuff = 0;
static LPLAYOUT lpLayout;
static TCHAR szLayoutPath[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts");
static TCHAR szLayoutText[] = TEXT("layout text");
static TCHAR szLayoutID[] = TEXT("layout id");
////////////////////////////////////////////////////////////////////////////
//
// MainWndProc
//
// Main window for processing messages.
//
////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK MainWndProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
#define hwndShell (HWND)wParam
switch (uMsg)
{
#ifdef FE_IME
//
// Discard any of the notifications to the IME because
// we don't want to see the IME UI on indicator.
//
case ( WM_IME_NOTIFY ) :
{
return (0L);
}
#endif
case ( WM_SETTINGCHANGE ) :
{
onSettingChange(hwnd);
break;
}
case ( WM_INPUTLANGCHANGEREQUEST ) :
{
return (0L);
}
case ( WM_QUERYENDSESSION ) :
{
DestroyWindow(hwnd);
return (TRUE);
}
case ( WM_CREATE ) :
{
if (OnCreate(hwnd, wParam, lParam))
{
PostMessage(hwnd, WM_COMMAND, IDM_EXIT, 0L);
return ((LRESULT)-1);
}
else
{
break;
}
}
case ( WM_MYLANGUAGECHANGE ) :
{
#ifdef WINDOWS_PE
//
// Don't handle LANGUAGE change for internat itself.
//
if (hwndShell == hwnd)
{
break;
}
else
#endif
{
return (HandleLanguageMsg(hwnd, (HKL)lParam));
}
}
#ifndef USECBT
case ( WM_MYWINDOWACTIVATED ) :
{
if (!bInLangMenu)
{
hwndForLang = hwndShell ? hwndShell : hwndTray;
}
break;
}
case ( WM_MYWINDOWCREATED ) :
{
if (!bInLangMenu)
{
hwndForLang = hwndShell;
}
break;
}
#endif
case ( WM_DESTROY ) :
{
InternatDestroy(hwnd);
break;
}
case ( WM_MEASUREITEM ) :
{
HandleLangMenuMeasure(hwnd, (LPMEASUREITEMSTRUCT)lParam);
break;
}
case ( WM_DRAWITEM ) :
{
HandleLangMenuDraw(hwnd, (LPDRAWITEMSTRUCT)lParam);
break;
}
case ( WM_LANGUAGE_INDICATOR ) :
{
#ifdef WINDOWS_PE
//
// If the current focus window has gone already, there's
// nothing we can do other than to get an active window
// which comes with HSHELL_WINDOWACTIVATED.
//
#ifndef USECBT // won't use global hwndForLang.
if (!IsWindow(hwndForLang))
{
if (fpGetLastActive)
{
hwndForLang = (fpGetLastActive)();
}
}
#endif
#endif
if (lParam == WM_LBUTTONDOWN)
{
lParam = GetMessagePos();
CreateLanguageMenu(hwnd, lParam);
PostMessage(hwndNotify, WM_LBUTTONUP, wParam, lParam);
}
else if (lParam == WM_RBUTTONDOWN)
{
lParam = GetMessagePos();
CreateOtherIndicatorMenu(hwnd, lParam);
}
break;
}
#ifdef FE_IME
case ( WM_IME_INDICATOR ) :
{
if (lParam == WM_LBUTTONDOWN)
{
CreateImeMenu(hwnd);
}
else if (lParam == WM_RBUTTONDOWN)
{
CreateRightImeMenu(hwnd);
}
else if (lParam == WM_LBUTTONDBLCLK)
{
HWND hwndImc;
HKL dwhkl;
DWORD dwThreadId;
int istat = GetIMEStatus(&hwndImc);
dwThreadId = GetWindowThreadProcessId(hwndImc, 0);
dwhkl = GetKeyboardLayout(dwThreadId);
if (istat != IMESTAT_DISABLED &&
((DWORD)dwhkl & 0xf000ffffL) != 0xe0000412L)
{
SetIMEOpenStatus(hwnd, istat == IMESTAT_CLOSE, hwndImc);
SetForegroundWindow(GetTopLevelWindow(hwndImc));
}
}
break;
}
case ( WM_MYSETOPENSTATUS ) :
{
if (IsWindow((HWND)lParam))
{
DWORD dwPI;
HWND hwndToSend = (HWND)lParam;
GetWindowThreadProcessId((HWND)lParam, &dwPI);
if (GetProcessVersion(dwPI) < 0x040000L)
{
hwndToSend = ImmGetDefaultIMEWnd((HWND)lParam);
}
SendMessage( hwndToSend,
WM_IME_SYSTEM,
IMS_SETOPENCLOSE,
(LPARAM)wParam );
}
break;
}
case ( WM_MYLANGUAGECHECK ) :
{
HKL hklLastFocus;
HWND hwndFocus;
hklLastFocus = GetLayout();
if ((hklLastFocus == hklCurrent) &&
(iImeCurStat == GetIMEStatus(&hwndFocus)))
{
break;
}
SetTimer(hwnd, TIMER_MYLANGUAGECHECK, 500, NULL);
break;
}
case ( WM_TIMER ) :
{
if (wParam == TIMER_MYLANGUAGECHECK)
{
HKL hklLastFocus;
HWND hwndFocus;
KillTimer(hwnd, TIMER_MYLANGUAGECHECK);
hklLastFocus = GetLayout();
if ((hklLastFocus == hklCurrent) &&
(iImeCurStat == GetIMEStatus(&hwndFocus)))
{
break;
}
SendMessage(hwnd, WM_MYLANGUAGECHANGE, 0, (LPARAM)hklLastFocus);
}
}
#endif
case ( WM_COMMAND ) :
{
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case ( IDM_NEWSHELL ) :
{
//
// Refresh, message comes straight from cpanel.
//
return (HandleLanguageMsg(hwnd, (HKL)lParam));
}
case ( IDM_EXIT ) :
{
DestroyWindow(hwnd);
break;
}
}
break;
}
case ( WM_SYSCOMMAND ) :
{
if (wParam == SC_CLOSE)
{
break;
}
// fall thru...
}
default :
{
return (DefWindowProc(hwnd, uMsg, wParam, lParam));
}
}
return (0L);
#undef hwndShell
}
////////////////////////////////////////////////////////////////////////////
//
// InitApplication
//
////////////////////////////////////////////////////////////////////////////
BOOL InitApplication(
HINSTANCE hInstance)
{
WNDCLASSEX wc;
TCHAR sz[100];
TCHAR szRcAppName[100];
LoadString( hInstance,
IDS_APPNAME,
szRcAppName,
sizeof(szRcAppName) / sizeof(TCHAR) );
if (FindWindow(szAppName, NULL))
{
if (LoadString(hInstance, IDS_PREVIOUS, sz, 100))
{
MessageBox(NULL, sz, szRcAppName, MB_ICONINFORMATION | MB_OK);
}
return (FALSE);
}
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_INTERNAT));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szAppName;
wc.hIconSm = NULL;
return (RegisterClassEx(&wc));
}
////////////////////////////////////////////////////////////////////////////
//
// InitInstance
//
////////////////////////////////////////////////////////////////////////////
BOOL InitInstance(
HINSTANCE hInstance,
int nCmdShow)
{
HWND hwnd;
hinst = hInstance;
hwnd = CreateWindowEx( WS_EX_TOOLWINDOW,
szAppName,
NULL,
WS_DISABLED | WS_POPUP,
0, 0, 0, 0,
NULL,
NULL,
hInstance,
NULL );
if (!hwnd)
{
return (FALSE);
}
//
// We don't want to get activated.
//
ShowWindow(hwnd, SW_SHOWNOACTIVATE);
//
// Return success.
//
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// WinMain
//
// Applications main entry point. Gets the whole show up and running.
//
////////////////////////////////////////////////////////////////////////////
int APIENTRY WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpAnsiCmdLine,
int nCmdShow)
{
MSG msg;
if (!InitApplication(hInstance))
{
return (FALSE);
}
if (!InitInstance(hInstance, nCmdShow))
{
return (FALSE);
}
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (msg.wParam);
lpAnsiCmdLine;
}
////////////////////////////////////////////////////////////////////////////
//
// TransNum
//
// Converts a number string to a dword value.
//
////////////////////////////////////////////////////////////////////////////
DWORD TransNum(
LPTSTR lpsz)
{
DWORD dw = 0L;
TCHAR c;
while (*lpsz)
{
c = *lpsz++;
if (c >= TEXT('A') && c <= TEXT('F'))
{
c -= TEXT('A') - 0xa;
}
else if (c >= TEXT('0') && c <= TEXT('9'))
{
c -= TEXT('0');
}
else if (c >= TEXT('a') && c <= TEXT('f'))
{
c -= TEXT('a') - 0xa;
}
else
{
break;
}
dw *= 0x10;
dw += c;
}
return (dw);
}
////////////////////////////////////////////////////////////////////////////
//
// LoadKeyboardLayouts
//
// Loads the layouts from the registry.
//
////////////////////////////////////////////////////////////////////////////
#define ALLOCBLOCK 3 // # items added to block for alloc/realloc
BOOL LoadKeyboardLayouts()
{
HKEY hKey;
HKEY hkey1;
DWORD cb;
DWORD dwIndex;
LONG dwRetVal;
TCHAR szValue[MAX_PATH]; // language id (number)
TCHAR szData[MAX_PATH]; // language name
//
// Now read all the locales from the registry.
//
if (RegOpenKey(HKEY_LOCAL_MACHINE, szLayoutPath, &hKey) != ERROR_SUCCESS)
{
return (FALSE);
}
dwIndex = 0;
dwRetVal = RegEnumKey( hKey,
dwIndex,
szValue,
sizeof(szValue) / sizeof(TCHAR) );
if (dwRetVal != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return (FALSE);
}
hLayout = GlobalAlloc(GHND, ALLOCBLOCK * sizeof(LAYOUT));
nLayoutBuffSize = ALLOCBLOCK;
iLayoutBuff = 0;
lpLayout = GlobalLock(hLayout);
if (!hLayout)
{
RegCloseKey(hKey);
return (FALSE);
}
do
{
//
// New language - get the language name and the language id.
//
if (iLayoutBuff + 1 == nLayoutBuffSize)
{
HANDLE hTemp;
GlobalUnlock(hLayout);
nLayoutBuffSize += ALLOCBLOCK;
hTemp = GlobalReAlloc( hLayout,
nLayoutBuffSize * sizeof(LAYOUT),
GHND );
if (hTemp == NULL)
{
break;
}
hLayout = hTemp;
lpLayout = GlobalLock(hLayout);
}
lpLayout[iLayoutBuff].dwID = TransNum(szValue);
lstrcpy(szData, szLayoutPath);
lstrcat(szData, TEXT("\\"));
lstrcat(szData, szValue);
if (RegOpenKey(HKEY_LOCAL_MACHINE, szData, &hkey1) == ERROR_SUCCESS)
{
//
// Get the layout name.
//
szValue[0] = TEXT('\0');
cb = sizeof(szValue);
if ((RegQueryValueEx( hkey1,
szLayoutText,
NULL,
NULL,
(LPBYTE)szValue,
&cb ) == ERROR_SUCCESS) &&
(cb > sizeof(TCHAR)))
{
lpLayout[iLayoutBuff].atmLayoutText = AddAtom(szValue);
szValue[0] = TEXT('\0');
cb = sizeof(szValue);
lpLayout[iLayoutBuff].iSpecialID = 0;
if (RegQueryValueEx( hkey1,
szLayoutID,
NULL,
NULL,
(LPBYTE)szValue,
&cb ) == ERROR_SUCCESS)
{
//
// This may not exist!
//
lpLayout[iLayoutBuff].iSpecialID = (UINT)TransNum(szValue);
}
iLayoutBuff++;
}
RegCloseKey(hkey1);
}
dwIndex++;
szValue[0] = TEXT('\0');
dwRetVal = RegEnumKey( hKey,
dwIndex,
szValue,
sizeof(szValue) / sizeof(TCHAR) );
} while (dwRetVal == ERROR_SUCCESS);
RegCloseKey(hKey);
return (iLayoutBuff);
}
////////////////////////////////////////////////////////////////////////////
//
// GetKbdLayoutName
//
// Gets the name of the given layout.
//
////////////////////////////////////////////////////////////////////////////
void GetKbdLayoutName(
WORD wLayout,
LPTSTR pBuffer,
int nBufSize)
{
UINT ctr, id;
//
// Find the layout in the global structure.
//
if ((wLayout & 0xf000) == 0xf000)
{
//
// Layout is special, need to search for the ID
// number.
//
id = wLayout & 0x0fff;
for (ctr = 0; ctr < iLayoutBuff; ctr++)
{
if (id == lpLayout[ctr].iSpecialID)
{
break;
}
}
}
else
{
for (ctr = 0; ctr < iLayoutBuff; ctr++)
{
if (wLayout == LOWORD(lpLayout[ctr].dwID))
{
break;
}
}
}
//
// Make sure there is a match. If not, then simply return without
// copying anything.
//
if (ctr < iLayoutBuff)
{
//
// Separate the Input Locale name and the Layout name with " - ".
//
pBuffer[0] = TEXT(' ');
pBuffer[1] = TEXT('-');
pBuffer[2] = TEXT(' ');
GetAtomName(lpLayout[ctr].atmLayoutText, pBuffer + 3, nBufSize - 3);
}
}
////////////////////////////////////////////////////////////////////////////
//
// InternatDestroy
//
////////////////////////////////////////////////////////////////////////////
void InternatDestroy(
HWND hwnd)
{
UINT ctr;
#ifdef FE_IME
KillTimer(hwnd, TIMER_MYLANGUAGECHECK);
#endif
ManageMlngInfo(hwnd, DESTROY_MLNGINFO);
for (ctr = 0; ctr < iLayoutBuff; ctr++)
{
if (lpLayout[ctr].atmLayoutText)
{
DeleteAtom(lpLayout[ctr].atmLayoutText);
}
}
iLayoutBuff = 0;
GlobalUnlock(hLayout);
GlobalFree(hLayout);
if (fpStopShell)
{
fpStopShell();
}
FreeLibrary(hInstLib);
PostQuitMessage(0);
}
////////////////////////////////////////////////////////////////////////////
//
// onSettingChange
//
////////////////////////////////////////////////////////////////////////////
void onSettingChange(
HWND hwnd)
{
UINT cx, cy;
cx = GetSystemMetrics(SM_CXSMICON);
cy = GetSystemMetrics(SM_CYSMICON);
if ((cxSmIcon != cx) || (cy != cySmIcon))
{
cxSmIcon = cx;
cySmIcon = cy;
ManageMlngInfo(hwnd, UPDATE_MLNGINFO);
}
}
////////////////////////////////////////////////////////////////////////////
//
// EnumChildWndProc
//
// Look at the class names using GetClassName to see if we can find the
// Tray notification Window.
//
////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumChildWndProc(
HWND hwnd,
LPARAM lParam)
{
TCHAR szString[50];
GetClassName(hwnd, szString, sizeof(szString) / sizeof(TCHAR));
if (lstrcmp(szString, szNotifyWindow) == 0)
{
hwndNotify = hwnd;
return (FALSE);
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// OnCreate
//
// Let's put all the Create stuff in a neat function of its own.
//
// We find the Tray Window and enumarate its windows to locate the
// Notify Window.
//
// Get all the Multilingual information about the system and then load the
// dll and start the shell Hook proc.
//
////////////////////////////////////////////////////////////////////////////
int OnCreate(
HWND hwnd,
WPARAM wParam,
LPARAM lParam)
{
HDC hdc;
CHARSETINFO cs;
#ifdef WINDOWS_ME
if (GetSystemMetrics(SM_MIDEASTENABLED))
{
TCHAR sz[10];
long cb = sizeof(sz);
//
// As we are releasing an enabled version, we need to check the
// resource locale as well.
//
sz[0] = TEXT('\0');
if (RegQueryValue( HKEY_CURRENT_USER,
NLS_RESOURCE_LOCALE_KEY,
sz,
&cb ) == ERROR_SUCCESS)
{
if ( (cb == 9) &&
(sz[6] == TEXT('0')) &&
((sz[7] == TEXT('1')) || (sz[7] == TEXT('d')) ||
(sz[7] == TEXT('D'))) )
{
meEto = ETO_RTLREADING;
}
}
}
#endif
hwndTray = FindWindow(TEXT(WNDCLASS_TRAYNOTIFY), NULL);
if (!hwndTray)
{
return (-1);
}
EnumChildWindows(hwndTray, (WNDENUMPROC)EnumChildWndProc, lParam);
if (!hwndNotify)
{
return (-1);
}
hInstLib = LoadLibrary(szDllName);
fpRegHookWindow = (REGHOOKPROC)GetProcAddress(hInstLib,
MAKEINTRESOURCEA(ORD_REGISTERHOOK));
fpStartShell = (PROC)GetProcAddress(hInstLib,
MAKEINTRESOURCEA(ORD_STARTSHELL));
fpStopShell = (PROC)GetProcAddress(hInstLib,
MAKEINTRESOURCEA(ORD_STOPSHELL));
#ifdef FE_IME
fpGetIMEStat = (FPGETIMESTAT)GetProcAddress(hInstLib,
MAKEINTRESOURCE(ORD_GETIMESTAT));
fpGetLayout = (FPGETLAYOUT)GetProcAddress(hInstLib,
MAKEINTRESOURCE(ORD_GETLAYOUT));
if (!fpGetLastFocus || !fpGetLastActive || !fpGetIMEStat ||
!fpRegHookWindow || !fpStartShell || !fpStopShell)
#else
#ifdef WINDOWS_PE
if (!fpGetLastFocus || !fpGetLastActive ||
!fpRegHookWindow || !fpStartShell || !fpStopShell)
#else
if (!fpRegHookWindow || !fpStartShell || !fpStopShell)
#endif
#endif
{
FreeLibrary(hInstLib);
fpRegHookWindow = NULL;
fpStartShell = NULL;
fpStopShell = NULL;
return (-1);
}
hdc = GetDC(hwnd);
TranslateCharsetInfo( (LPVOID)(LONG)GetTextCharsetInfo(hdc, NULL, 0),
&cs,
TCI_SRCCHARSET );
fsShell = cs.fs.fsCsb[0];
ReleaseDC(hwnd, hdc);
cxSmIcon = GetSystemMetrics(SM_CXSMICON);
cySmIcon = GetSystemMetrics(SM_CYSMICON);
if (!AttachThreadInput( GetWindowThreadProcessId(hwnd, NULL),
GetWindowThreadProcessId(hwndTray, NULL),
TRUE ))
{
MessageBeep(MB_OK);
}
LoadKeyboardLayouts();
ManageMlngInfo(hwnd, CREATE_MLNGINFO);
if (!(fpRegHookWindow)(hwnd, TRUE))
{
return (-1);
}
fpStartShell();
#if defined(FE_IME) || defined(WINDOWS_PE)
//
// Send the notify window to the hook. This is to skip status update
// when the notify window is getting the focus.
//
if (fpSetNotifyWnd)
{
(fpSetNotifyWnd)(hwndNotify);
}
#endif
#ifdef FE_IME
PostMessage( HWND_BROADCAST,
WM_IME_SYSTEM,
(WPARAM)IMS_SETOPENSTATUS,
(LPARAM)0 );
#endif
return (0);
}
////////////////////////////////////////////////////////////////////////////
//
// SendLangIndicatorMsg
//
// Using an image list to store the icons g_hIconImageList,
// we can get the icons by index calling ImageList_ExtractIcon.
//
////////////////////////////////////////////////////////////////////////////
void SendLangIndicatorMsg(
HWND hwnd,
HKL dwHkl,
DWORD dwMessage)
{
NOTIFYICONDATA tnd;
PMLNGINFO pMlngInfo;
BOOL bFound = FALSE;
int nIndex, nCount;
if (dwHkl == hklCurrent)
{
return;
}
tnd.uCallbackMessage = WM_LANGUAGE_INDICATOR;
tnd.cbSize = sizeof(NOTIFYICONDATA);
tnd.hWnd = hwnd;
tnd.uID = LANG_INDICATOR_ID;
tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
//
// Deleting is a special case.
//
if ((dwHkl == 0) && (dwMessage == NIM_DELETE))
{
tnd.hIcon = NULL;
tnd.szTip[0] = TEXT('\0');
Shell_NotifyIcon(dwMessage, &tnd);
hklCurrent--; // make it bogus
return;
}
nCount = DPA_GetPtrCount(hdpaInfoList);
for (nIndex = 0; nIndex < nCount; nIndex++)
{
pMlngInfo = DPA_GetPtr(hdpaInfoList, nIndex);
if (pMlngInfo->dwHkl == dwHkl)
{
bFound = TRUE;
break;
}
}
//
// If we can't find it, take the first one in the list.
//
if (!bFound)
{
pMlngInfo = DPA_GetPtr(hdpaInfoList, 0);
}
if (!pMlngInfo)
{
return;
}
tnd.hIcon = ImageList_ExtractIcon( hinst,
himIndicators,
pMlngInfo->nIconIndex );
lstrcpyn(tnd.szTip, pMlngInfo->szTip, sizeof(tnd.szTip) / sizeof(TCHAR));
hklCurrent = pMlngInfo->dwHkl; // update current hkl
Shell_NotifyIcon(dwMessage, &tnd);
DestroyIcon(tnd.hIcon);
}
////////////////////////////////////////////////////////////////////////////
//
// LanguageIndicator
//
// Only allows you to delete the indicator if it's present and
// add the indicator if it's not present. Also does indicator start up.
//
////////////////////////////////////////////////////////////////////////////
void LanguageIndicator(
HWND hwnd,
DWORD dwFlag)
{
HKL dwHkl = 0;
if (bInternatActive)
{
if (dwFlag == NIM_DELETE)
{
SendLangIndicatorMsg(hwnd, dwHkl, dwFlag);
bInternatActive = FALSE;
return;
}
else
{
return;
}
}
else
{
if (dwFlag == NIM_ADD)
{
dwHkl = GetKeyboardLayout((DWORD)NULL);
hklCurrent = dwHkl - 1;
SendLangIndicatorMsg(hwnd, dwHkl, dwFlag);
bInternatActive = TRUE;
return;
}
else
{
return;
}
}
}
#ifdef FE_IME
////////////////////////////////////////////////////////////////////////////
//
// GetIconFromFile
//
// Extracts an Icon from a file if possible.
//
////////////////////////////////////////////////////////////////////////////
HICON GetIconFromFile(
HIMAGELIST himIndicators,
LPTSTR lpszFileName,
UINT uIconIndex)
{
int cx, cy;
HICON hicon;
ImageList_GetIconSize(himIndicators, &cx, &cy);
if (cx > GetSystemMetrics(SM_CXSMICON))
{
ExtractIconEx(lpszFileName, uIconIndex, &hicon, NULL, 1);
}
else
{
ExtractIconEx(lpszFileName, uIconIndex, NULL, &hicon, 1);
}
return (hicon);
}
#endif
////////////////////////////////////////////////////////////////////////////
//
// Internat_CreateIcon
//
////////////////////////////////////////////////////////////////////////////
HICON Internat_CreateIcon(
HWND hwnd,
WORD langID)
{
HBITMAP hbmColour;
HBITMAP hbmMono;
HBITMAP hbmOld;
HICON hicon = NULL;
ICONINFO ii;
RECT rc;
DWORD rgbText;
DWORD rgbBk = 0;
UINT i;
HDC hdc;
HDC hdcScreen;
HBRUSH hbr;
LOGFONT lf;
HFONT hfont;
HFONT hfontOld;
TCHAR szData[20];
//
// Get the indicator by using the first 2 characters of the
// abbreviated language name.
//
if (GetLocaleInfo( MAKELCID(langID, SORT_DEFAULT),
LOCALE_SABBREVLANGNAME | LOCALE_NOUSEROVERRIDE,
szData,
sizeof(szData) / sizeof(TCHAR) ))
{
//
// Only use the first two characters.
//
szData[2] = TEXT('\0');
}
else
{
//
// Id wasn't found. Use question marks.
//
szData[0] = TEXT('?');
szData[1] = TEXT('?');
szData[2] = TEXT('\0');
}
if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0))
{
if ((hfont = CreateFontIndirect(&lf)))
{
hdcScreen = GetDC(NULL);
hdc = CreateCompatibleDC(hdcScreen);
hbmColour = CreateCompatibleBitmap(hdcScreen, cxSmIcon, cySmIcon);
ReleaseDC(NULL, hdcScreen);
if (hbmColour && hdc)
{
hbmMono = CreateBitmap(cxSmIcon, cySmIcon, 1, 1, NULL);
if (hbmMono)
{
hbmOld = SelectObject(hdc, hbmColour);
rc.left = 0;
rc.top = 0;
rc.right = cxSmIcon;
rc.bottom = cySmIcon;
rgbBk = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
rgbText = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
ExtTextOut( hdc,
rc.left,
rc.top,
ETO_OPAQUE,
&rc,
TEXT(""),
0,
NULL );
SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
hfontOld = SelectObject(hdc, hfont);
DrawText( hdc,
szData,
2,
&rc,
DT_CENTER | DT_VCENTER | DT_SINGLELINE );
SelectObject(hdc, hbmMono);
PatBlt(hdc, 0, 0, cxSmIcon, cySmIcon, BLACKNESS);
SelectObject(hdc, hbmOld);
ii.fIcon = TRUE;
ii.xHotspot = 0;
ii.yHotspot = 0;
ii.hbmColor = hbmColour;
ii.hbmMask = hbmMono;
hicon = CreateIconIndirect(&ii);
DeleteObject(hbmMono);
SelectObject(hdc, hfontOld);
}
}
DeleteObject(hbmColour);
DeleteDC(hdc);
DeleteObject(hfont);
}
}
return (hicon);
}
////////////////////////////////////////////////////////////////////////////
//
// ManageMlngInfo
//
// Manages Shell Multilingual Info. Creates and maintains "database"
// of Multilingual components in the system.
// The Information is initially taken from the registry.
//
// The "database" is a DPA of the languages in System and IMAGELIST of the
// indicator Icons.
//
// Function is called at different times for different functionality:
// 1. When application is started
// 2. When changes are made to registry information.
// This is done through the HSHELL_LANGUAGE shell hook.
// 3. When Application closes.
//
// wFlag is one of the following:
//
// DESTROY_MLNGINFO
// We're finished, so clean it all up.
//
// CREATE_MLNGINFO
// We've just started, interrogate the system and get the info we need.
//
// UPDATE_MLNGINFO
// Multilingual information has just changed, so rebuild it.
// Update involves destroying the old DPA and ImageList stuff and
// recreating it again.
//
// NOTE: Even if the system has only one language we create the DPA
// and image list. When adding extra languages to the system,
// an UPDATE will just have to be done.
//
////////////////////////////////////////////////////////////////////////////
void ManageMlngInfo(
HWND hwnd,
WORD wFlag)
{
HKL *pLanguages;
DWORD dwRegValue;
long cb;
UINT uCount;
UINT uLangs;
WORD wIndex;
int i;
HICON hIcon;
HKEY hkey;
TCHAR szRegText[256];
LPTSTR pszRT;
PMLNGINFO pMlngInfo;
PMLNGINFO *ppMlngInfo;
#ifdef FE_IME
BOOL fNeedInd = FALSE;
#endif
uLangs = GetKeyboardLayoutList(0, NULL);
//
// Make sure data structures are present.
//
if (((!hdpaInfoList) || (!himIndicators)) && (wFlag != CREATE_MLNGINFO))
{
return;
}
if (wFlag != CREATE_MLNGINFO)
{
if (wFlag == DESTROY_MLNGINFO)
{
#ifdef FE_IME
if (g_bIMEIndicator)
{
SendIMEIndicatorMsg(hwnd, 0, NIM_DELETE);
g_bIMEIndicator = FALSE;
}
#endif
LanguageIndicator(hwnd, NIM_DELETE);
}
ppMlngInfo = (PMLNGINFO *)DPA_GetPtrPtr(hdpaInfoList);
if (!ppMlngInfo)
{
return;
}
for (i = DPA_GetPtrCount(hdpaInfoList); i > 0; --i, ++ppMlngInfo)
{
LocalFree(*ppMlngInfo);
ImageList_Remove(himIndicators, 0);
}
DPA_Destroy(hdpaInfoList);
ImageList_Destroy(himIndicators);
}
if (wFlag != DESTROY_MLNGINFO)
{
if (!(hdpaInfoList = DPA_Create(0)))
{
return;
}
himIndicators = ImageList_Create( GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
TRUE,
0,
0 );
if (!himIndicators)
{
DPA_Destroy(hdpaInfoList);
hdpaInfoList = NULL;
himIndicators = NULL;
return;
}
pLanguages = (HKL *)LocalAlloc(LPTR, uLangs * sizeof(HKL));
GetKeyboardLayoutList(uLangs, (HKL *)pLanguages);
//
// pLanguages contains all the HKLs in the system.
// Put everything together in the DPA and Image List.
//
for (uCount = 0; uCount < uLangs; uCount++)
{
#ifdef FE_IME
DWORD dwIMEDesc = 0;
if ((HIWORD(pLanguages[uCount]) & 0xf000) == 0xe000)
{
dwIMEDesc = ImmGetDescription(pLanguages[uCount], NULL, 0L);
}
#endif
//
// Get the Input Locale name.
//
dwRegValue = ((DWORD)(LOWORD(pLanguages[uCount])));
if (!GetLocaleInfo( dwRegValue,
LOCALE_SLANGUAGE,
szRegText,
sizeof(szRegText) / sizeof(TCHAR) ))
{
LoadString( hinst,
IDS_UNKNOWN,
szRegText,
sizeof(szRegText) / sizeof(TCHAR) );
}
//
// Attach the Layout name if it's not the default.
//
if (HIWORD(pLanguages[uCount]) != LOWORD(pLanguages[uCount]))
{
pszRT = szRegText + lstrlen(szRegText);
GetKbdLayoutName( HIWORD(pLanguages[uCount]),
pszRT,
(sizeof(szRegText) / sizeof(TCHAR)) -
(pszRT - szRegText) );
}
#ifdef FE_IME
if (dwIMEDesc)
{
cb = (long)dwIMEDesc + 1;
}
else
#endif
cb = (lstrlen(szRegText) + 1) * sizeof(TCHAR);
if (!(pMlngInfo = LocalAlloc(LPTR, sizeof(MLNGINFO) + cb)))
{
goto MError1;
}
#ifdef FE_IME
if (dwIMEDesc)
{
ImmGetDescription(pLanguages[uCount], pMlngInfo->szTip, cb);
}
else
#endif
lstrcpy(pMlngInfo->szTip, szRegText);
pMlngInfo->dwHkl = pLanguages[uCount];
#ifdef FE_IME
if ((HIWORD(pMlngInfo->dwHkl) & 0xf000) == 0xe000)
{
TCHAR szIMEFile[32]; // assume long filename up to 32 byte
if (LOWORD(pMlngInfo->dwHkl) == 0x0404 ||
LOWORD(pMlngInfo->dwHkl) == 0x0411 ||
LOWORD(pMlngInfo->dwHkl) == 0x0412 ||
LOWORD(pMlngInfo->dwHkl) == 0x0804)
{
fNeedInd = TRUE;
pMlngInfo->bIME = TRUE;
}
if (ImmGetIMEFileName( pMlngInfo->dwHkl,
szIMEFile,
sizeof(szIMEFile) ))
{
//
// First one of the file.
//
hIcon = GetIconFromFile(himIndicators, szIMEFile, 0);
}
else
{
goto GetLangIcon;
}
}
else // for non-ime layout
GetLangIcon:
#endif
hIcon = Internat_CreateIcon(hwnd, LOWORD(pLanguages[uCount]));
pMlngInfo->nIconIndex = ImageList_AddIcon(himIndicators, hIcon);
DestroyIcon(hIcon);
if ((i = DPA_InsertPtr(hdpaInfoList, 0x7fff, pMlngInfo)) == -1)
{
MError1:
//
// Cover our tracks.
//
LocalFree((HLOCAL)pLanguages);
ppMlngInfo = (PMLNGINFO *)DPA_GetPtrPtr(hdpaInfoList);
if (!ppMlngInfo)
{
return;
}
for (i = DPA_GetPtrCount(hdpaInfoList) - 1;
i > 0;
--i, ++ppMlngInfo)
{
LocalFree(*ppMlngInfo);
ImageList_Remove(himIndicators, 0);
}
//
// Destroy everything.
//
DPA_Destroy(hdpaInfoList);
ImageList_Destroy(himIndicators);
//
// We are DEAD. Something major has gone wrong, so
// remove any form of the language indication.
//
hdpaInfoList = NULL;
himIndicators = NULL;
//
// No indicator.
//
LanguageIndicator(hwnd, NIM_DELETE);
return;
}
}
#ifdef FE_IME
if (fNeedInd)
{
LoadIMEIndicatorIcon(hInstLib, nIMEIconIndex);
}
if (pLanguages && (0xf000 & HIWORD(pLanguages[0])) == 0xe000)
{
if (!g_bIMEIndicator)
{
SendIMEIndicatorMsg(hwnd, pLanguages[0], NIM_ADD);
g_bIMEIndicator = TRUE;
}
}
#endif
//
// Clean up, and add the Indicator.
//
LocalFree((HLOCAL)pLanguages);
#ifdef FE_IME
//
// If uLang == 1 and the only layout is the IME, then we just put
// the IME indicator.
//
if (uLangs < 2)
{
LanguageIndicator(hwnd, NIM_DELETE);
}
else
#endif
LanguageIndicator(hwnd, NIM_ADD);
}
}
////////////////////////////////////////////////////////////////////////////
//
// HandleLanguageMsg
//
// Tell the indicator if there has been a language switch in the system.
//
////////////////////////////////////////////////////////////////////////////
int HandleLanguageMsg(
HWND hwnd,
HKL dwHkl)
{
//
// If dwHkl == 0, then reread registry information.
// Otherwise, change indicator to this language.
//
if (dwHkl == 0)
{
ManageMlngInfo(hwnd, UPDATE_MLNGINFO);
}
else
{
SendLangIndicatorMsg(hwnd, dwHkl, NIM_MODIFY);
}
#ifdef FE_IME
if (!dwHkl)
{
return (0);
}
if ((HIWORD(dwHkl) & 0xf000) == 0xe000)
{
if (!g_bIMEIndicator)
{
SendIMEIndicatorMsg(hwnd, dwHkl, NIM_ADD);
g_bIMEIndicator = TRUE;
}
else
{
SendIMEIndicatorMsg(hwnd, dwHkl, NIM_MODIFY);
}
}
else if (g_bIMEIndicator)
{
SendIMEIndicatorMsg(hwnd, 0, NIM_DELETE);
g_bIMEIndicator = FALSE;
}
#endif
return (0);
}
////////////////////////////////////////////////////////////////////////////
//
// HandleLangMenuMeasure
//
// Does the calculation for the language owner drawn menu item.
//
////////////////////////////////////////////////////////////////////////////
BOOL HandleLangMenuMeasure(
HWND hwnd,
LPMEASUREITEMSTRUCT lpmi)
{
NONCLIENTMETRICS ncm;
SIZE size;
PMLNGINFO pMlng = NULL;
HFONT hMenuFont, hOldFont;
HDC hDC;
UINT uCount = 0;
if (lpmi->CtlID != 0)
{
return (FALSE);
}
uCount = GetKeyboardLayoutList(0, NULL);
pMlng = DPA_GetPtr(hdpaInfoList, lpmi->itemID - IDM_LANG_MENU_START);
if (!pMlng)
{
return (FALSE);
}
//
// Get the Menu font.
//
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE);
hMenuFont = CreateFontIndirect(&ncm.lfMenuFont);
if (!hMenuFont)
{
return (FALSE);
}
hDC = GetWindowDC(hwnd);
hOldFont = SelectObject(hDC, hMenuFont);
//
// Get the length of our string as it would appear in the menu.
//
GetTextExtentPoint(hDC, pMlng->szTip, lstrlen(pMlng->szTip), &size);
//
// Total width is Icon width + 3 check marks + the text width.
//
lpmi->itemWidth = 3 * GetSystemMetrics(SM_CXMENUCHECK) +
GetSystemMetrics(SM_CYSMICON) + size.cx;
SelectObject(hDC, hOldFont);
ReleaseDC(hwnd, hDC);
DeleteObject(hMenuFont);
//
// Height is fairly straight forward, the larger of the two,
// text or Icon.
//
lpmi->itemHeight = ((size.cy > GetSystemMetrics(SM_CYSMICON))
? size.cy
: GetSystemMetrics(SM_CYSMICON)) + 2;
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// HandleLangMenuDraw
//
// Draws the owner drawn menu item.
//
////////////////////////////////////////////////////////////////////////////
BOOL HandleLangMenuDraw(
HWND hwnd,
LPDRAWITEMSTRUCT lpdi)
{
DWORD dwRop;
int checkMarkSize;
int nIndex, x, y;
PMLNGINFO pMlng = NULL;
if (lpdi->CtlID != 0)
{
return (FALSE);
}
nIndex = (int)(lpdi->itemID - IDM_LANG_MENU_START);
pMlng = DPA_GetPtr(hdpaInfoList, nIndex);
if (!pMlng)
{
return (FALSE);
}
checkMarkSize = GetSystemMetrics(SM_CXMENUCHECK);
if (lpdi->itemState & ODS_SELECTED)
{
SetTextColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
SetBkColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHT));
dwRop = SRCSTENCIL;
}
else
{
SetTextColor(lpdi->hDC, GetSysColor(COLOR_MENUTEXT));
SetBkColor(lpdi->hDC, GetSysColor(COLOR_MENU));
dwRop = SRCAND;
}
//
// Write out the text.
//
#ifdef WINDOWS_ME
ExtTextOut( lpdi->hDC,
lpdi->rcItem.left + (2 * checkMarkSize) +
GetSystemMetrics(SM_CXSMICON),
lpdi->rcItem.top + 3,
ETO_OPAQUE | meEto,
&lpdi->rcItem,
(LPTSTR)pMlng->szTip,
lstrlen((LPTSTR)pMlng->szTip),
NULL );
#else
ExtTextOut( lpdi->hDC,
lpdi->rcItem.left + (2 * checkMarkSize) +
GetSystemMetrics(SM_CXSMICON),
lpdi->rcItem.top + 3,
ETO_OPAQUE,
&lpdi->rcItem,
(LPTSTR)pMlng->szTip,
lstrlen((LPTSTR)pMlng->szTip),
NULL );
#endif
//
// Draw the Icon.
//
ImageList_Draw( himIndicators,
nIndex,
lpdi->hDC,
lpdi->rcItem.left + (checkMarkSize),
lpdi->rcItem.top + 1,
ILD_TRANSPARENT );
if (lpdi->itemState & ODS_CHECKED)
{
//
// Can't use DrawFrameControl, DFC doesn't allow colour changing.
//
HBITMAP hBmp, hBmpSave;
BITMAP bm;
HDC hDCBmp;
DWORD textColorSave;
DWORD bkColorSave;
hDCBmp = CreateCompatibleDC(lpdi->hDC);
if (hDCBmp)
{
hBmp = LoadBitmap(NULL, MAKEINTRESOURCE(OBM_MNARROW));
GetObject(hBmp, sizeof(bm), &bm);
hBmpSave = SelectObject(hDCBmp, hBmp);
x = lpdi->rcItem.left; // + checkMarkSize;
y = (lpdi->rcItem.bottom + lpdi->rcItem.top - bm.bmHeight) / 2;
textColorSave = SetTextColor(lpdi->hDC, 0x00000000L);
bkColorSave = SetBkColor(lpdi->hDC, 0x00ffffffL);
BitBlt( lpdi->hDC,
x,
y,
bm.bmWidth,
bm.bmHeight,
hDCBmp,
0,
0,
dwRop );
SetTextColor(lpdi->hDC, textColorSave);
SetBkColor(lpdi->hDC, bkColorSave);
SelectObject(hDCBmp, hBmpSave);
DeleteObject(hBmp);
DeleteDC(hDCBmp);
}
}
if (lpdi->itemState & ODS_FOCUS)
{
DrawFocusRect(lpdi->hDC, &lpdi->rcItem);
}
}
////////////////////////////////////////////////////////////////////////////
//
// CreateLanguageMenu
//
// This is the real Menu brought up by clicking on the language indicator
// with the left mouse button. This will be owner drawn later. For now it
// will allow you to select a language for your last active captioned app.
//
////////////////////////////////////////////////////////////////////////////
void CreateLanguageMenu(
HWND hwnd,
LPARAM lParam)
{
HMENU hLangMenu;
BOOL bCheckIt = FALSE;
UINT uMenuId = IDM_LANG_MENU_START;
int nIndex;
int cmd;
TCHAR szMenuOption[MENUSTRLEN];
PMLNGINFO pMlngInfo;
TPMPARAMS tpm;
LOCALESIGNATURE ls;
HWND hwndT, hwndP;
DWORD dwThread, dwThreadLang;
BOOL bFontSig = 0;
#ifdef WINDOWS_PE
HWND hwndForActivate;
#endif
#ifdef USECBT
HWND hwndForLang;
#endif
bInLangMenu = TRUE;
hLangMenu = CreatePopupMenu();
cmd = DPA_GetPtrCount(hdpaInfoList);
if (cmd == -1)
{
bInLangMenu = FALSE;
return;
}
for (nIndex = 0; nIndex < cmd; nIndex++)
{
pMlngInfo = DPA_FastGetPtr(hdpaInfoList, nIndex);
lstrcpyn( szMenuOption,
pMlngInfo->szTip,
sizeof(szMenuOption) / sizeof(TCHAR) );
if (pMlngInfo->dwHkl == hklCurrent)
{
bCheckIt = TRUE;
}
InsertMenu( hLangMenu,
(UINT)-1,
MF_BYPOSITION | MF_OWNERDRAW,
uMenuId,
(LPCTSTR)szMenuOption );
if (bCheckIt)
{
CheckMenuItem(hLangMenu, uMenuId, MF_CHECKED);
bCheckIt = FALSE;
}
uMenuId++;
}
SetForegroundWindow(hwnd);
GetClientRect(hwndNotify, &tpm.rcExclude);
MapWindowPoints(hwndNotify, NULL, (LPPOINT)&tpm.rcExclude, 2);
cmd = TrackPopupMenuEx( hLangMenu,
TPM_VERTICAL | TPM_BOTTOMALIGN | TPM_RETURNCMD,
tpm.rcExclude.left,
tpm.rcExclude.top,
hwnd,
NULL );
bInLangMenu = FALSE;
#ifdef WINDOWS_PE
hwndForLang = GetCurrentFocusWnd();
#endif
if (cmd && (cmd != -1))
{
cmd -= IDM_LANG_MENU_START;
pMlngInfo = DPA_FastGetPtr(hdpaInfoList, cmd);
if (hwndForLang == NULL)
{
MessageBeep(MB_ICONEXCLAMATION);
return;
}
//
// Send a WM_INPUTLANGCHANGEREQUEST msg to change the apps language.
// This also generates the HSHELL_LANGUAGE Hook that we
// monitor to provide the correct indicator.
//
#ifndef WINDOWS_PE
hwndP = hwndForLang; // could be focus
for (hwndT = GetParent(hwndForLang); hwndT; hwndT = GetParent(hwndT))
{
hwndP = hwndT;
}
//
// If it's a dialog, use it.
//
hwndP = GetLastActivePopup(hwndP);
if (hwndP)
{
hwndForLang = hwndP;
}
#else
hwndForActivate = hwndForLang; // could be focus
for (hwndT = GetParent(hwndForLang); hwndT; hwndT = GetParent(hwndT))
{
hwndForActivate = hwndT;
}
//
// If it's a dialog, use it.
//
hwndForActivate = GetLastActivePopup(hwndForActivate);
#endif
if (GetLocaleInfo( (DWORD)(LOWORD(pMlngInfo->dwHkl)),
LOCALE_FONTSIGNATURE,
(LPTSTR)&ls,
34 ))
{
if (fsShell & ls.lsCsbSupported[0])
{
bFontSig = 1;
}
}
dwThread = GetWindowThreadProcessId(hwnd, NULL);
#ifdef WINDOWS_PE
dwThreadLang = GetWindowThreadProcessId(hwndForActivate, NULL);
#else
dwThreadLang = GetWindowThreadProcessId(hwndForLang, NULL);
#endif
if (dwThread != dwThreadLang)
{
if (!AttachThreadInput(dwThread, dwThreadLang, TRUE))
{
MessageBeep(MB_OK);
}
}
#ifdef WINDOWS_PE
SetForegroundWindow(hwndForActivate);
#else
SetForegroundWindow(hwndForLang);
#endif
PostMessage( hwndForLang,
WM_INPUTLANGCHANGEREQUEST,
(WPARAM)bFontSig,
(LPARAM)pMlngInfo->dwHkl );
if (!AttachThreadInput( GetWindowThreadProcessId(hwnd, NULL),
GetWindowThreadProcessId(hwndTray, NULL),
TRUE ))
{
MessageBeep(MB_OK);
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// CreateOtherIndicatorMenu
//
// Right Mouse button click menu on indicator.
// Strings need to go into cabinet if necessary.
//
////////////////////////////////////////////////////////////////////////////
void CreateOtherIndicatorMenu(
HWND hwnd,
LPARAM lParam)
{
HMENU hMenu;
int cmd;
TPMPARAMS tpm;
TCHAR szTextString[MENUSTRLEN];
hMenu = CreatePopupMenu();
LoadString( hinst,
IDS_WHATSTHIS,
szTextString,
sizeof(szTextString) / sizeof(TCHAR) );
InsertMenu( hMenu,
(UINT)-1,
MF_STRING | MF_BYPOSITION,
IDM_RMENU_WHATSTHIS,
(LPCTSTR)szTextString );
InsertMenu( hMenu,
(UINT)-1,
MF_BYPOSITION | MF_SEPARATOR,
0,
(LPCTSTR)NULL );
LoadString( hinst,
IDS_PROPERTIES,
szTextString,
sizeof(szTextString) / sizeof(TCHAR) );
InsertMenu( hMenu,
(UINT)-1,
MF_STRING | MF_BYPOSITION,
IDM_RMENU_PROPERTIES,
(LPCTSTR)szTextString );
GetClientRect(hwndNotify, &tpm.rcExclude);
MapWindowPoints(hwndNotify, NULL, (LPPOINT)&tpm.rcExclude, 2);
tpm.cbSize = sizeof(tpm);
//
// The following line is necessary for FE to keep consistency.
// Without this, the icon can be messed up when no focus window
// exists.
//
bInLangMenu = TRUE;
SetActiveWindow(hwnd);
cmd = TrackPopupMenuEx( hMenu,
TPM_VERTICAL | TPM_BOTTOMALIGN | TPM_RETURNCMD,
tpm.rcExclude.left,
tpm.rcExclude.top,
hwnd,
&tpm );
bInLangMenu = FALSE;
if (cmd && (cmd != -1))
{
switch (cmd)
{
case ( IDM_RMENU_PROPERTIES ) :
{
LoadStringA( hinst,
IDS_CPL_KEYBOARD,
(LPSTR)szTextString,
MENUSTRLEN );
WinExec((LPSTR)szTextString, SW_SHOWNORMAL);
break;
}
case ( IDM_EXIT ) :
{
DestroyWindow(hwnd);
break;
}
case ( IDM_RMENU_WHATSTHIS ) :
{
WinHelp( hwnd,
szHelpFile,
HELP_CONTEXTPOPUP,
IDH_KEYB_INDICATOR_ON_TASKBAR );
break;
}
}
}
}
#ifdef WINDOWS_PE
////////////////////////////////////////////////////////////////////////////
//
// GetCurrentFocusWnd
//
////////////////////////////////////////////////////////////////////////////
HWND GetCurrentFocusWnd(void)
{
HWND hwndFocus = (fpGetLastFocus());
if (!IsWindow(hwndFocus))
{
hwndFocus = (fpGetLastActive());
}
return (hwndFocus);
}
#endif
#ifdef FE_IME
////////////////////////////////////////////////////////////////////////////
//
// LoadIMEIndicatorIcon
//
////////////////////////////////////////////////////////////////////////////
void LoadIMEIndicatorIcon(
HINSTANCE hInstLib,
int *ImeIcon)
{
HICON hIcon;
hIcon = LoadIcon(hInstLib, MAKEINTRESOURCE(10));
ImeIcon[0] = ImageList_AddIcon(himIndicators, hIcon);
DestroyIcon(hIcon);
hIcon = LoadIcon(hInstLib, MAKEINTRESOURCE(11));
ImeIcon[1] = ImageList_AddIcon(himIndicators, hIcon);
DestroyIcon(hIcon);
hIcon = LoadIcon(hInstLib, MAKEINTRESOURCE(12));
ImeIcon[2] = ImageList_AddIcon(himIndicators, hIcon);
DestroyIcon(hIcon);
hIcon = LoadIcon(hInstLib, MAKEINTRESOURCE(13));
ImeIcon[3] = ImageList_AddIcon(himIndicators, hIcon);
DestroyIcon(hIcon);
hIcon = LoadIcon(hInstLib, MAKEINTRESOURCE(14));
ImeIcon[4] = ImageList_AddIcon(himIndicators, hIcon);
DestroyIcon(hIcon);
hIcon = LoadIcon(hInstLib, MAKEINTRESOURCE(15));
ImeIcon[5] = ImageList_AddIcon(himIndicators, hIcon);
DestroyIcon(hIcon);
hIcon = LoadIcon(hInstLib, MAKEINTRESOURCE(16));
ImeIcon[6] = ImageList_AddIcon(himIndicators, hIcon);
DestroyIcon(hIcon);
}
////////////////////////////////////////////////////////////////////////////
//
// SendIMEIndicatorMsg
//
////////////////////////////////////////////////////////////////////////////
void SendIMEIndicatorMsg(
HWND hwnd,
HKL dwHkl,
DWORD dwMessage)
{
NOTIFYICONDATA tnd;
PMLNGINFO pMlngInfo;
BOOL bFound = FALSE;
int nIndex, nCount;
int iStat;
HWND hwndImc;
tnd.uCallbackMessage = WM_IME_INDICATOR;
tnd.cbSize = sizeof(NOTIFYICONDATA);
tnd.hWnd = hwnd;
tnd.uID = IME_INDICATOR_ID;
tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
if ((dwHkl == 0) && (dwMessage == NIM_DELETE))
{
tnd.hIcon = NULL;
tnd.szTip[0] = TEXT('\0');
Shell_NotifyIcon(dwMessage, &tnd);
return;
}
nCount = DPA_GetPtrCount(hdpaInfoList);
for (nIndex = 0; nIndex < nCount; nIndex++)
{
pMlngInfo = DPA_GetPtr(hdpaInfoList, nIndex);
if (pMlngInfo->dwHkl == dwHkl)
{
bFound = TRUE;
break;
}
}
//
// If we can't find it, take the first one in the list.
//
if (!bFound)
{
pMlngInfo = DPA_GetPtr(hdpaInfoList, 0);
}
else if (!pMlngInfo->bIME)
{
return;
}
else
{
int nIcon;
BOOL fLngIndicator = bInternatActive;
//
// Delete LANG ICON first when adding the IME indicator.
//
if (dwMessage == NIM_ADD && fLngIndicator)
{
LanguageIndicator(hwnd, NIM_DELETE);
}
//
// Check IME status here.
//
iStat = GetIMEStatus(&hwndImc);
if (((DWORD)dwHkl & 0xf000ffffL) == 0xe0000412L)
{
if (iStat == IMESTAT_DISABLED)
{
nIcon = 2;
}
else if (iStat & IMESTAT_CLOSE)
{
nIcon = 3;
}
else
{
nIcon = (iStat & IMESTAT_NATIVE) ? 5 : 3;
if (iStat & IMESTAT_FULLSHAPE)
{
nIcon++;
}
}
}
else
{
switch (iStat)
{
case ( IMESTAT_DISABLED ) :
default :
{
//
// Disable.
//
nIcon = 2;
break;
}
case ( IMESTAT_OPEN ) :
{
//
// Open.
//
nIcon = 0;
break;
}
case ( IMESTAT_CLOSE ) :
{
//
// Close.
//
nIcon = 1;
break;
}
}
}
tnd.hIcon = ImageList_ExtractIcon( hinst,
himIndicators,
nIMEIconIndex[nIcon]);
lstrcpyn(tnd.szTip, pMlngInfo->szTip, sizeof(tnd.szTip) / sizeof(TCHAR));
Shell_NotifyIcon(dwMessage, &tnd);
DestroyIcon(tnd.hIcon);
//
// Put LANG ICON again if already deleted it.
//
if (dwMessage == NIM_ADD && fLngIndicator)
{
SendLangIndicatorMsg(hwnd, pMlngInfo->dwHkl, NIM_ADD);
bInternatActive = TRUE;
}
}
iImeCurStat = iStat;
}
////////////////////////////////////////////////////////////////////////////
//
// CreateRightImeMenu
//
////////////////////////////////////////////////////////////////////////////
void CreateRightImeMenu(
HWND hwnd)
{
HMENU hMenu;
int cmd;
TPMPARAMS tpm;
TCHAR szTextString[MENUSTRLEN];
HKL dwhkl;
DWORD dwThreadId;
HWND hwndIMC;
if (GetIMEStatus(&hwndIMC) == IMESTAT_DISABLED)
{
return;
}
hMenu = CreatePopupMenu();
LoadString( hinst,
IDS_WHATSTHIS,
szTextString,
sizeof(szTextString) / sizeof(TCHAR) );
InsertMenu( hMenu,
(UINT)-1,
MF_STRING | MF_BYPOSITION | MF_GRAYED,
IDM_RMENU_WHATSTHIS,
(LPCTSTR)szTextString );
InsertMenu( hMenu,
(UINT)-1,
MF_BYPOSITION | MF_SEPARATOR,
0,
(LPCTSTR)NULL );
LoadString( hinst,
IDS_CONFIGUREIME,
szTextString,
sizeof(szTextString) / sizeof(TCHAR) );
InsertMenu( hMenu,
(UINT)-1,
MF_STRING | MF_BYPOSITION,
IDM_RMENU_PROPERTIES,
(LPCTSTR)szTextString );
GetClientRect(hwndNotify, &tpm.rcExclude);
MapWindowPoints(hwndNotify, NULL, (LPPOINT)&tpm.rcExclude, 2);
tpm.cbSize = sizeof(tpm);
bInLangMenu = TRUE;
SetActiveWindow(hwnd);
cmd = TrackPopupMenuEx( hMenu,
TPM_VERTICAL | TPM_BOTTOMALIGN | TPM_RETURNCMD,
tpm.rcExclude.left,
tpm.rcExclude.top,
hwnd,
&tpm );
DestroyMenu(hMenu);
bInLangMenu = FALSE;
if (cmd && (cmd != -1))
{
switch (cmd)
{
case ( IDM_RMENU_PROPERTIES ) :
{
if (hwndIMC)
{
dwThreadId = GetWindowThreadProcessId(hwndIMC, 0);
}
dwhkl = GetKeyboardLayout(dwThreadId);
if ((HIWORD(dwhkl) & 0xf000) == 0xe000)
{
CallConfigureIME(hwndIMC, dwhkl);
}
break;
}
case ( IDM_RMENU_WHATSTHIS ) :
case ( IDM_RMENU_HELPFINDER ) :
default :
{
break;
}
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// CreateImeMenu
//
////////////////////////////////////////////////////////////////////////////
void CreateImeMenu(
HWND hwnd)
{
int nIds, nIdsSoftKbd;
int cmd;
HMENU hMenu;
TCHAR szText[32];
TPMPARAMS tpm;
BOOL fShow;
int istat;
HWND hwndIMC;
HKL dwhkl;
DWORD dwThreadId;
if ((istat = GetIMEStatus(&hwndIMC)) == IMESTAT_DISABLED)
{
return;
}
bInLangMenu = TRUE;
SetForegroundWindow(hwnd);
hMenu = CreatePopupMenu();
dwThreadId = GetWindowThreadProcessId(hwndIMC, 0);
dwhkl = GetKeyboardLayout(dwThreadId);
//
// In Korean case, don't show OPEN/CLOSE menu.
//
nIds = 0;
if (((DWORD)dwhkl & 0xf000ffffL) != 0xe0000412L)
{
nIds = ((istat == IMESTAT_OPEN) ? IDS_IMECLOSE : IDS_IMEOPEN);
LoadString(hinst, nIds, szText, sizeof(szText) / sizeof(TCHAR));
InsertMenu( hMenu,
(UINT)-1,
MF_BYPOSITION,
IDM_IME_OPENCLOSE,
(LPCTSTR)szText );
}
//
// Open or close the soft keyboard.
//
nIdsSoftKbd = 0;
if (ImmGetProperty(dwhkl, IGP_CONVERSION) & IME_CMODE_SOFTKBD)
{
DWORD fdwConversion;
fdwConversion = SendMessage( hwndIMC,
WM_IME_SYSTEM,
IMS_GETCONVERSIONMODE,
0 );
nIdsSoftKbd = ((fdwConversion & IME_CMODE_SOFTKBD)
? IDS_SOFTKBDOFF
: IDS_SOFTKBDON);
LoadString(hinst, nIdsSoftKbd, szText, sizeof(szText) / sizeof(TCHAR));
InsertMenu( hMenu,
(UINT)-1,
MF_BYPOSITION,
IDM_IME_SOFTKBDONOFF,
(LPTCSTR)szText );
}
if (nIds || nIdsSoftKbd)
{
InsertMenu(hMenu, (UINT)-1, MF_SEPARATOR, 0, 0);
}
LoadString(hinst, IDS_IMESHOWSTATUS, szText, sizeof(szText) / sizeof(TCHAR));
InsertMenu( hMenu,
(UINT)-1,
MF_BYPOSITION,
IDM_IME_SHOWSTATUS,
(LPCTSTR)szText );
if ((fShow = GetIMEShowStatus()) == TRUE)
{
CheckMenuItem(hMenu, IDM_IME_SHOWSTATUS, MF_CHECKED);
}
GetClientRect(hwndNotify, &tpm.rcExclude);
MapWindowPoints(hwndNotify, NULL, (LPPOINT)&tpm.rcExclude, 2);
tpm.cbSize = sizeof(tpm);
cmd = TrackPopupMenuEx( hMenu,
TPM_VERTICAL | TPM_BOTTOMALIGN | TPM_RETURNCMD,
tpm.rcExclude.left,
tpm.rcExclude.top,
hwnd,
&tpm );
//
// Don't want to activate an app in case of canceling.
//
if (cmd && cmd != -1)
{
DWORD dwThread, dwThreadIMC;
HWND hwndForActivate;
dwThread = GetWindowThreadProcessId(hwnd, NULL);
dwThreadIMC = GetWindowThreadProcessId(hwndIMC, NULL);
if (dwThread != dwThreadIMC)
{
if (!AttachThreadInput(dwThread, dwThreadIMC, TRUE))
{
MessageBeep(MB_OK);
}
}
//
// If a dialog, use it.
//
hwndForActivate = GetLastActivePopup(GetTopLevelWindow(hwndIMC));
SetForegroundWindow(hwndForActivate);
if (!AttachThreadInput( GetWindowThreadProcessId(hwnd, NULL),
GetWindowThreadProcessId(hwndTray, NULL),
TRUE ))
{
MessageBeep(MB_OK);
}
}
switch (cmd)
{
case ( IDM_IME_OPENCLOSE ) :
{
//
// I assume IMC_SETOPENSTATUS will not be hooked by an app.
//
if (hwndIMC)
{
BOOL fopen = (nIds == IDS_IMECLOSE) ? FALSE : TRUE;
SetIMEOpenStatus(hwnd, fopen, hwndIMC);
}
break;
}
case ( IDM_IME_SOFTKBDONOFF ) :
{
if (hwndIMC)
{
BOOL fFlag = (nIdsSoftKbd == IDS_SOFTKBDOFF) ? FALSE: TRUE;
HWND hDefIMEWnd = ImmGetDefaultIMEWnd(hwndIMC);
if (!hDefIMEWnd)
{
break;
}
else if (hDefIMEWnd == (HWND)-1)
{
break;
}
SendMessage( hDefIMEWnd,
WM_IME_SYSTEM,
IMS_SETSOFTKBDONOFF,
(LPARAM)fFlag );
}
break;
}
case ( IDM_IME_SHOWSTATUS ) :
{
SetIMEShowStatus(hwndIMC, !fShow);
break;
}
}
//
// Don't move following two lines from here.
//
// SetForegroundWindow(GetTopLevelWindow(hwndIMC));
bInLangMenu = FALSE;
}
////////////////////////////////////////////////////////////////////////////
//
// GetIMEShowStatus
//
////////////////////////////////////////////////////////////////////////////
BOOL GetIMEShowStatus(void)
{
static TCHAR szInputMethod[] = TEXT("Control Panel\\Input Method");
static TCHAR szValueName[] = TEXT("show status");
TCHAR szValueText[16];
int cb;
HKEY hkey;
if (RegOpenKey(HKEY_CURRENT_USER, szInputMethod, &hkey) == ERROR_SUCCESS)
{
cb = sizeof(szValueText);
if (RegQueryValueEx( hkey,
szValueName,
NULL,
NULL,
szValueText,
&cb ) != ERROR_SUCCESS)
{
szValueText[0] = TEXT('\0');
}
RegCloseKey(hkey);
if ((szValueText[0] == TEXT('1')) && (szValueText[1] == 0))
{
return (TRUE);
}
}
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// SetIMEShowStatus
//
////////////////////////////////////////////////////////////////////////////
BOOL SetIMEShowStatus(
HWND hwnd,
BOOL fShow)
{
static TCHAR szInputMethod[] = TEXT("Control Panel\\Input Method");
static TCHAR szValueName[] = TEXT("show status");
TCHAR szValueText[16];
int cb;
HKEY hkey;
if (fShow)
{
szValueText[0] = TEXT('1');
}
else
{
szValueText[0] = TEXT('0');
}
szValueText[1] = 0;
if (RegOpenKey(HKEY_CURRENT_USER, szInputMethod, &hkey) == ERROR_SUCCESS)
{
cb = (lstrlen(szValueText) + 1) * sizeof(TCHAR);
if (RegSetValueEx( hkey,
szValueName,
0L,
REG_SZ,
szValueText,
cb ) == ERROR_SUCCESS)
{
SendMessage( hwnd,
WM_IME_SYSTEM,
IMS_CHANGE_SHOWSTAT,
(LPARAM)(DWORD)fShow );
}
RegCloseKey(hkey);
return (TRUE);
}
return (FALSE);
}
////////////////////////////////////////////////////////////////////////////
//
// GetIMEStatus
//
////////////////////////////////////////////////////////////////////////////
int GetIMEStatus(
HWND *phwndFocus)
{
HWND hwnd = (fpGetLastFocus());
if (!IsWindow(hwnd))
{
hwnd = (fpGetLastActive());
}
*phwndFocus = hwnd;
return (fpGetIMEStat)();
}
////////////////////////////////////////////////////////////////////////////
//
// GetLayout
//
////////////////////////////////////////////////////////////////////////////
HKL GetLayout(void)
{
if (!fpGetLayout)
{
return (hklCurrent);
}
return (fpGetLayout)();
}
////////////////////////////////////////////////////////////////////////////
//
// InternatTimerProc
//
////////////////////////////////////////////////////////////////////////////
void CALLBACK InternatTimerProc(
HWND hwnd,
UINT uMsg,
UINT idEvent,
DWORD dwTime)
{
HWND hwndIMC = (HWND)GetProp(hwnd, szPropHwnd);
BOOL fopen = (BOOL)GetProp(hwnd, szPropImeStat);
KillTimer(hwnd, 1);
PostMessage(hwnd, WM_MYSETOPENSTATUS, (WPARAM)fopen, (LPARAM)hwndIMC);
RemoveProp(hwnd, szPropHwnd);
RemoveProp(hwnd, szPropImeStat);
}
////////////////////////////////////////////////////////////////////////////
//
// SetIMEOpenStatus
//
////////////////////////////////////////////////////////////////////////////
void SetIMEOpenStatus(
HWND hwnd,
BOOL fopen,
HWND hwndIMC)
{
SetProp(hwnd, szPropHwnd, hwndIMC);
SetProp(hwnd, szPropImeStat, (HANDLE)fopen);
SetTimer(hwnd, 1, 100, InternatTimerProc);
}
////////////////////////////////////////////////////////////////////////////
//
// CallConfigureIME
//
////////////////////////////////////////////////////////////////////////////
void CallConfigureIME(
HWND hwnd,
HKL dwhkl)
{
if (hwnd)
{
SendMessage(hwnd, WM_IME_SYSTEM, IMS_CONFIGUREIME, (LPARAM)dwhkl);
}
}
////////////////////////////////////////////////////////////////////////////
//
// GetTopLevelWindow
//
////////////////////////////////////////////////////////////////////////////
HWND GetTopLevelWindow(
HWND hwnd)
{
HWND hwndT, hwndRet;
HWND hwndDsktop = GetDesktopWindow();
hwndT = hwndRet = hwnd;
while (hwndT && hwndT != hwndDsktop)
{
hwndRet = hwndT;
hwndT = GetParent(hwndT);
}
return (hwndRet);
}
#endif // FE_IME
////////////////////////////////////////////////////////////////////////////
//
// ModuleEntry
//
////////////////////////////////////////////////////////////////////////////
int _stdcall ModuleEntry(void)
{
int i;
STARTUPINFO si;
si.dwFlags = 0;
GetStartupInfo(&si);
i = WinMain( GetModuleHandle(NULL),
NULL,
NULL,
si.dwFlags & STARTF_USESHOWWINDOW
? si.wShowWindow
: SW_SHOWDEFAULT );
ExitProcess(i);
return (i);
}