733 lines
21 KiB
C
733 lines
21 KiB
C
|
/***************************************************************************
|
||
|
* msctls.c
|
||
|
*
|
||
|
* Utils library initialization code
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
#include "ctlspriv.h"
|
||
|
|
||
|
HINSTANCE g_hinst = 0;
|
||
|
|
||
|
#ifndef UNIX
|
||
|
CRITICAL_SECTION g_csDll = {{0},0, 0, NULL, NULL, 0 };
|
||
|
#else
|
||
|
/* IEUNIX: MainWin uses DllMain as an entry point (Ref: mwdip) */
|
||
|
#define LibMain DllMain
|
||
|
#include "mwversion.h"
|
||
|
#if defined(MW_STRUCTINIT_SUPPORTED)
|
||
|
CRITICAL_SECTION g_csDll = {{0},0, 0, NULL, NULL, 0 };
|
||
|
#else
|
||
|
CRITICAL_SECTION g_csDll;
|
||
|
#endif
|
||
|
#endif /* UNIX */
|
||
|
|
||
|
ATOM g_aCC32Subclass = 0;
|
||
|
|
||
|
#ifdef WINNT
|
||
|
BOOL g_bRunOnNT5 = FALSE;
|
||
|
BOOL g_bRemoteSession = FALSE;
|
||
|
#else
|
||
|
BOOL g_bRunOnMemphis = FALSE;
|
||
|
BOOL g_bRunOnBiDiWin95Loc = FALSE;
|
||
|
int g_cProcesses = 0;
|
||
|
#endif
|
||
|
|
||
|
UINT g_uiACP = CP_ACP;
|
||
|
|
||
|
// Is Mirroring enabled
|
||
|
BOOL g_bMirroredOS = FALSE;
|
||
|
|
||
|
|
||
|
#define PAGER //For Test Purposes
|
||
|
|
||
|
//
|
||
|
// Global DCs used during mirroring an Icon.
|
||
|
//
|
||
|
HDC g_hdc=NULL, g_hdcMask=NULL;
|
||
|
|
||
|
// per process mem to store PlugUI information
|
||
|
#ifdef WINNT
|
||
|
LANGID g_PUILangId = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
||
|
#else
|
||
|
HDPA g_hdpaPUI = NULL;
|
||
|
void InitPUI();
|
||
|
void DeInitPUI(int cProcesses);
|
||
|
#endif
|
||
|
|
||
|
BOOL PASCAL InitAnimateClass(HINSTANCE hInstance);
|
||
|
BOOL ListView_Init(HINSTANCE hinst);
|
||
|
BOOL TV_Init(HINSTANCE hinst);
|
||
|
BOOL InitComboExClass(HINSTANCE hinst);
|
||
|
BOOL PASCAL Header_Init(HINSTANCE hinst);
|
||
|
BOOL PASCAL Tab_Init(HINSTANCE hinst);
|
||
|
int InitIPAddr(HANDLE hInstance);
|
||
|
|
||
|
#if !defined(WINNT) && defined(FONT_LINK)
|
||
|
void InitMLANG();
|
||
|
void DeinitMLANG(int cProcesses);
|
||
|
#endif
|
||
|
|
||
|
#ifdef PAGER
|
||
|
BOOL InitPager(HINSTANCE hinst);
|
||
|
#endif
|
||
|
BOOL InitNativeFontCtl(HINSTANCE hinst);
|
||
|
void UnregisterClasses();
|
||
|
void Mem_Terminate();
|
||
|
|
||
|
#define DECLARE_DELAYED_FUNC(_ret, _fn, _args, _nargs) \
|
||
|
_ret (__stdcall * g_pfn##_fn) _args = NULL; \
|
||
|
_ret __stdcall _fn _args \
|
||
|
{ \
|
||
|
if (!g_pfn##_fn) { \
|
||
|
AssertMsg(g_pfn##_fn != NULL, TEXT("GetProcAddress failed")); \
|
||
|
return 0; \
|
||
|
} \
|
||
|
return g_pfn##_fn _nargs; \
|
||
|
}
|
||
|
|
||
|
#define LOAD_DELAYED_FUNC(_ret, _fn, _args) \
|
||
|
(*(FARPROC*)&(g_pfn##_fn) = GetProcAddress(hinst, #_fn))
|
||
|
|
||
|
|
||
|
DECLARE_DELAYED_FUNC(BOOL, ImmNotifyIME, (HIMC himc, DWORD dw1, DWORD dw2, DWORD dw3), (himc, dw1, dw2, dw3));
|
||
|
DECLARE_DELAYED_FUNC(HIMC, ImmAssociateContext, (HWND hwnd, HIMC himc), (hwnd, himc));
|
||
|
DECLARE_DELAYED_FUNC(BOOL, ImmReleaseContext, (HWND hwnd, HIMC himc), (hwnd, himc));
|
||
|
DECLARE_DELAYED_FUNC(HIMC, ImmGetContext, (HWND hwnd), (hwnd));
|
||
|
DECLARE_DELAYED_FUNC(LONG, ImmGetCompositionStringA, (HIMC himc, DWORD dw1, LPVOID p1, DWORD dw2), (himc, dw1, p1, dw2) );
|
||
|
DECLARE_DELAYED_FUNC(BOOL, ImmSetCompositionStringA, (HIMC himc, DWORD dw1, LPCVOID p1, DWORD dw2, LPCVOID p2, DWORD dw3), (himc, dw1, p1, dw2, p2, dw3));
|
||
|
#ifndef UNICODE_WIN9x
|
||
|
DECLARE_DELAYED_FUNC(LONG, ImmGetCompositionStringW, (HIMC himc, DWORD dw1, LPVOID p1, DWORD dw2), (himc, dw1, p1, dw2) );
|
||
|
DECLARE_DELAYED_FUNC(BOOL, ImmSetCompositionStringW, (HIMC himc, DWORD dw1, LPCVOID p1, DWORD dw2, LPCVOID p2, DWORD dw3), (himc, dw1, p1, dw2, p2, dw3));
|
||
|
#endif
|
||
|
DECLARE_DELAYED_FUNC(BOOL, ImmSetCandidateWindow, (HIMC himc, LPCANDIDATEFORM pcf), (himc, pcf));
|
||
|
DECLARE_DELAYED_FUNC(HIMC, ImmCreateContext, (void), ());
|
||
|
DECLARE_DELAYED_FUNC(BOOL, ImmDestroyContext, (HIMC himc), (himc));
|
||
|
|
||
|
|
||
|
BOOL g_fDBCSEnabled = FALSE;
|
||
|
BOOL g_fMEEnabled = FALSE;
|
||
|
BOOL g_fDBCSInputEnabled = FALSE;
|
||
|
#ifdef FONT_LINK
|
||
|
BOOL g_bComplexPlatform = FALSE;
|
||
|
#endif
|
||
|
|
||
|
#if defined(FE_IME) || !defined(WINNT)
|
||
|
void InitIme()
|
||
|
{
|
||
|
g_fMEEnabled = GetSystemMetrics(SM_MIDEASTENABLED);
|
||
|
|
||
|
g_fDBCSEnabled = g_fDBCSInputEnabled = GetSystemMetrics(SM_DBCSENABLED);
|
||
|
|
||
|
if (!g_fDBCSInputEnabled && g_bRunOnNT5)
|
||
|
g_fDBCSInputEnabled = GetSystemMetrics(SM_IMMENABLED);
|
||
|
|
||
|
// We load imm32.dll per process, but initialize proc pointers just once.
|
||
|
// this is to solve two different problems.
|
||
|
// 1) Debugging process on win95 would get our shared table trashed
|
||
|
// if we rewrite proc address each time we get loaded.
|
||
|
// 2) Some lotus application rely upon us to load imm32. They do not
|
||
|
// load/link to imm yet they use imm(!)
|
||
|
//
|
||
|
if (g_fDBCSInputEnabled) {
|
||
|
HANDLE hinst = LoadLibrary(TEXT("imm32.dll"));
|
||
|
if (! g_pfnImmSetCandidateWindow &&
|
||
|
(! hinst ||
|
||
|
! LOAD_DELAYED_FUNC(HIMC, ImmCreateContext, (void)) ||
|
||
|
! LOAD_DELAYED_FUNC(HIMC, ImmDestroyContext, (HIMC)) ||
|
||
|
! LOAD_DELAYED_FUNC(BOOL, ImmNotifyIME, (HIMC, DWORD, DWORD, DWORD)) ||
|
||
|
! LOAD_DELAYED_FUNC(HIMC, ImmAssociateContext, (HWND, HIMC)) ||
|
||
|
! LOAD_DELAYED_FUNC(BOOL, ImmReleaseContext, (HWND, HIMC)) ||
|
||
|
! LOAD_DELAYED_FUNC(HIMC, ImmGetContext, (HWND)) ||
|
||
|
! LOAD_DELAYED_FUNC(LONG, ImmGetCompositionStringA, (HIMC, DWORD, LPVOID, DWORD)) ||
|
||
|
! LOAD_DELAYED_FUNC(BOOL, ImmSetCompositionStringA, (HIMC, DWORD, LPCVOID, DWORD, LPCVOID, DWORD)) ||
|
||
|
#ifndef UNICODE_WIN9x
|
||
|
! LOAD_DELAYED_FUNC(LONG, ImmGetCompositionStringW, (HIMC, DWORD, LPVOID, DWORD)) ||
|
||
|
! LOAD_DELAYED_FUNC(BOOL, ImmSetCompositionStringW, (HIMC, DWORD, LPCVOID, DWORD, LPCVOID, DWORD)) ||
|
||
|
#endif
|
||
|
! LOAD_DELAYED_FUNC(BOOL, ImmSetCandidateWindow, (HIMC, LPCANDIDATEFORM)))) {
|
||
|
|
||
|
// if we were unable to load then bail on using IME.
|
||
|
g_fDBCSEnabled = FALSE;
|
||
|
g_fDBCSInputEnabled = FALSE;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
#define InitIme() 0
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
|
||
|
// Verify that the localizers didn't accidentally change
|
||
|
// DLG_PROPSHEET from a DIALOG to a DIALOGEX. _RealPropertySheet
|
||
|
// relies on this (as well as any apps which parse the dialog template
|
||
|
// in their PSCB_PRECREATE handler).
|
||
|
|
||
|
BOOL IsSimpleDialog(LPCTSTR ptszDialog)
|
||
|
{
|
||
|
HRSRC hrsrc;
|
||
|
LPDLGTEMPLATE pdlg;
|
||
|
BOOL fSimple = FALSE;
|
||
|
|
||
|
if ( (hrsrc = FindResource(HINST_THISDLL, ptszDialog, RT_DIALOG)) &&
|
||
|
(pdlg = LoadResource(HINST_THISDLL, hrsrc)))
|
||
|
{
|
||
|
fSimple = HIWORD(pdlg->style) != 0xFFFF;
|
||
|
}
|
||
|
return fSimple;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// For sublanguages to work, every language in our resources must contain
|
||
|
// a SUBLANG_NEUTRAL variation so that (for example) Austria gets
|
||
|
// German dialog boxes instead of English ones.
|
||
|
//
|
||
|
// The DPA is really a DSA of WORDs, but DPA's are easier to deal with.
|
||
|
// We just collect all the languages into the DPA, and study them afterwards.
|
||
|
//
|
||
|
BOOL CALLBACK CheckLangProc(HINSTANCE hinst, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIdLang, LPARAM lparam)
|
||
|
{
|
||
|
HDPA hdpa = (HDPA)lparam;
|
||
|
DPA_AppendPtr(hdpa, (LPVOID)(UINT_PTR)wIdLang);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void CheckResourceLanguages(void)
|
||
|
{
|
||
|
HDPA hdpa = DPA_Create(8);
|
||
|
if (hdpa) {
|
||
|
int i, j;
|
||
|
EnumResourceLanguages(HINST_THISDLL, RT_DIALOG,
|
||
|
MAKEINTRESOURCE(DLG_PROPSHEET), CheckLangProc,
|
||
|
(LPARAM)hdpa);
|
||
|
|
||
|
// Walk the language list. For each language we find, make sure
|
||
|
// there is a SUBLANG_NEUTRAL version of it somewhere else
|
||
|
// in the list. We use an O(n^2) algorithm because this is debug
|
||
|
// only code and happens only at DLL load.
|
||
|
|
||
|
for (i = 0; i < DPA_GetPtrCount(hdpa); i++) {
|
||
|
UINT_PTR uLangI = (UINT_PTR)DPA_FastGetPtr(hdpa, i);
|
||
|
BOOL fFound = FALSE;
|
||
|
|
||
|
//
|
||
|
// It is okay to have English (American) with no
|
||
|
// English (Neutral) because Kernel32 uses English (American)
|
||
|
// as its fallback, so we fall back to the correct language
|
||
|
// after all.
|
||
|
//
|
||
|
if (uLangI == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US))
|
||
|
continue;
|
||
|
|
||
|
//
|
||
|
// If this language is already the Neutral one, then there's
|
||
|
// no point looking for it - here it is!
|
||
|
//
|
||
|
if (SUBLANGID(uLangI) == SUBLANG_NEUTRAL)
|
||
|
continue;
|
||
|
|
||
|
//
|
||
|
// Otherwise, this language is a dialect. See if there is
|
||
|
// a Neutral version elsewhere in the table.
|
||
|
//
|
||
|
for (j = 0; j < DPA_GetPtrCount(hdpa); j++) {
|
||
|
UINT_PTR uLangJ = (UINT_PTR)DPA_FastGetPtr(hdpa, j);
|
||
|
if (PRIMARYLANGID(uLangI) == PRIMARYLANGID(uLangJ) &&
|
||
|
SUBLANGID(uLangJ) == SUBLANG_NEUTRAL) {
|
||
|
fFound = TRUE; break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If this assertion fires, it means that the localization team
|
||
|
// added support for a new language but chose to specify the
|
||
|
// language as a dialect instead of the Neutral version. E.g.,
|
||
|
// specifying Romanian (Romanian) instead of Romanian (Neutral).
|
||
|
// This means that people who live in Moldavia will see English
|
||
|
// strings, even though Romanian (Romanian) would almost
|
||
|
// certainly have been acceptable.
|
||
|
//
|
||
|
// If you want to support multiple dialects of a language
|
||
|
// (e.g., Chinese), you should nominate one of the dialects
|
||
|
// as the Neutral one. For example, we currently support
|
||
|
// both Chinese (PRC) and Chinese (Taiwan), but the Taiwanese
|
||
|
// version is marked as Chinese (Neutral), so people who live in
|
||
|
// Singapore get Chinese instead of English. Sure, it's
|
||
|
// Taiwanese Chinese, but at least it's Chinese.
|
||
|
//
|
||
|
AssertMsg(fFound, TEXT("Localization bug: No SUBLANG_NEUTRAL for language %04x"), uLangI);
|
||
|
}
|
||
|
|
||
|
DPA_Destroy(hdpa);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
int _ProcessAttach(HANDLE hInstance)
|
||
|
{
|
||
|
INITCOMMONCONTROLSEX icce;
|
||
|
|
||
|
g_hinst = hInstance;
|
||
|
|
||
|
g_uiACP = GetACP();
|
||
|
|
||
|
#if defined(MAINWIN)
|
||
|
MwSet3dLook(TRUE);
|
||
|
#endif
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
CcshellGetDebugFlags();
|
||
|
|
||
|
g_dwBreakFlags = 0; // We do not want to break in comctl32 version 5 at ALL. Too many bad callers.
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#ifdef WINNT
|
||
|
InitializeCriticalSection(&g_csDll);
|
||
|
|
||
|
g_bRunOnNT5 = staticIsOS(OS_WIN2000ORGREATER);
|
||
|
#ifdef FONT_LINK
|
||
|
g_bComplexPlatform = BOOLFROMPTR(GetModuleHandle(TEXT("LPK.DLL")));
|
||
|
#endif
|
||
|
#else
|
||
|
ReinitializeCriticalSection(&g_csDll);
|
||
|
|
||
|
#ifdef FONT_LINK
|
||
|
g_bComplexPlatform = ((g_uiACP == CP_ARABIC) || (g_uiACP == CP_HEBREW) || (g_uiACP == CP_THAI));
|
||
|
#endif
|
||
|
g_bRunOnMemphis = staticIsOS(OS_WIN98ORGREATER);
|
||
|
g_bRunOnBiDiWin95Loc = IsBiDiLocalizedWin95(FALSE);
|
||
|
|
||
|
g_cProcesses++;
|
||
|
{
|
||
|
// HACK: we are intentionally incrementing the refcount on this atom
|
||
|
// WE DO NOT WANT IT TO GO BACK DOWN so we will not delete it in process
|
||
|
// detach (see comments for g_aCC32Subclass in subclass.c for more info)
|
||
|
|
||
|
// on Win95 doe this as early as possible to avoid getting
|
||
|
// a trashed atom.
|
||
|
|
||
|
ATOM a = GlobalAddAtom(c_szCC32Subclass);
|
||
|
if (a != 0)
|
||
|
g_aCC32Subclass = a; // in case the old atom got nuked
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Check if the mirroring APIs exist on the current
|
||
|
// platform.
|
||
|
//
|
||
|
g_bMirroredOS = IS_MIRRORING_ENABLED();
|
||
|
|
||
|
#ifdef WINNT
|
||
|
//
|
||
|
// Must detect Terminal Server before initializing global metrics
|
||
|
// because we need to force some features off if running Terminal Server.
|
||
|
//
|
||
|
{
|
||
|
typedef BOOL (__stdcall * PFNPROCESSIDTOSESSIONID)(DWORD, PDWORD);
|
||
|
PFNPROCESSIDTOSESSIONID ProcessIdToSessionId =
|
||
|
(PFNPROCESSIDTOSESSIONID)
|
||
|
GetProcAddress(GetModuleHandle(TEXT("KERNEL32")),
|
||
|
"ProcessIdToSessionId");
|
||
|
DWORD dwSessionId;
|
||
|
g_bRemoteSession = ProcessIdToSessionId &&
|
||
|
ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId) &&
|
||
|
dwSessionId != 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
InitGlobalMetrics(0);
|
||
|
InitGlobalColors();
|
||
|
|
||
|
InitIme();
|
||
|
|
||
|
#ifndef WINNT
|
||
|
#ifdef FONT_LINK
|
||
|
InitMLANG();
|
||
|
#endif
|
||
|
InitPUI();
|
||
|
#endif
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
ASSERT(IsSimpleDialog(MAKEINTRESOURCE(DLG_WIZARD)));
|
||
|
ASSERT(IsSimpleDialog(MAKEINTRESOURCE(DLG_PROPSHEET)));
|
||
|
CheckResourceLanguages();
|
||
|
#endif
|
||
|
|
||
|
// BUGBUG: only do this for GetProcessVersion apps <= 0x40000
|
||
|
// Newer apps MUST use InitCommonControlsEx.
|
||
|
icce.dwSize = sizeof(icce);
|
||
|
icce.dwICC = ICC_ALL_CLASSES;
|
||
|
|
||
|
|
||
|
return InitCommonControlsEx(&icce);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void _ProcessDetach(HANDLE hInstance)
|
||
|
{
|
||
|
//
|
||
|
// Cleanup cached DCs. No need to synchronize the following section of
|
||
|
// code since it is only called in DLL_PROCESS_DETACH which is
|
||
|
// synchronized by the OS Loader.
|
||
|
//
|
||
|
#ifdef WINNT
|
||
|
if (g_hdc)
|
||
|
DeleteDC(g_hdc);
|
||
|
|
||
|
if (g_hdcMask)
|
||
|
DeleteDC(g_hdcMask);
|
||
|
|
||
|
g_hdc = g_hdcMask = NULL;
|
||
|
#endif
|
||
|
|
||
|
#ifdef WINNT
|
||
|
UnregisterClasses();
|
||
|
DeleteCriticalSection(&g_csDll);
|
||
|
#else
|
||
|
ENTERCRITICAL;
|
||
|
#ifdef FONT_LINK
|
||
|
DeinitMLANG(g_cProcesses);
|
||
|
#endif
|
||
|
DeInitPUI(g_cProcesses);
|
||
|
if (--g_cProcesses == 0)
|
||
|
{
|
||
|
if (g_hdc)
|
||
|
DeleteDC(g_hdc);
|
||
|
|
||
|
if (g_hdcMask)
|
||
|
DeleteDC(g_hdcMask);
|
||
|
|
||
|
g_hdc = g_hdcMask = NULL;
|
||
|
|
||
|
Mem_Terminate(); // shared heap cleanup... all calls after this will die!
|
||
|
}
|
||
|
LEAVECRITICAL;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
STDAPI_(BOOL) LibMain(HANDLE hDll, DWORD dwReason, LPVOID pv)
|
||
|
{
|
||
|
#ifndef WINNT
|
||
|
STDAPI_(BOOL) Cctl1632_ThunkConnect32(LPCSTR pszDll16,LPCSTR pszDll32,HANDLE hIinst,DWORD dwReason);
|
||
|
|
||
|
if (!Cctl1632_ThunkConnect32("commctrl.dll", "comctl32.dll", hDll, dwReason))
|
||
|
return FALSE;
|
||
|
#endif
|
||
|
|
||
|
switch(dwReason) {
|
||
|
case DLL_PROCESS_ATTACH:
|
||
|
DisableThreadLibraryCalls(hDll);
|
||
|
return _ProcessAttach(hDll);
|
||
|
|
||
|
case DLL_PROCESS_DETACH:
|
||
|
_ProcessDetach(hDll);
|
||
|
break;
|
||
|
|
||
|
case DLL_THREAD_ATTACH:
|
||
|
case DLL_THREAD_DETACH:
|
||
|
default:
|
||
|
break;
|
||
|
|
||
|
} // end switch()
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
} // end DllEntryPoint()
|
||
|
|
||
|
|
||
|
/* Stub function to call if all you want to do is make sure this DLL is loaded
|
||
|
*/
|
||
|
void WINAPI InitCommonControls(void)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
#ifdef WINNT
|
||
|
BOOL InitForWinlogon(HINSTANCE hInstance)
|
||
|
{
|
||
|
// Some people like to use comctl32 from inside winlogon, and
|
||
|
// for C2 security reasons, all global atoms are nuked from the
|
||
|
// window station when you log off.
|
||
|
//
|
||
|
// So the rule is that all winlogon clients of comctl32 must
|
||
|
// call InitCommonControlsEx(ICC_WINLOGON_REINIT) immediately
|
||
|
// before doing any common control things (creating windows
|
||
|
// or property sheets/wizards) from winlogon.
|
||
|
|
||
|
ATOM a = GlobalAddAtom(c_szCC32Subclass);
|
||
|
if (a)
|
||
|
g_aCC32Subclass = a;
|
||
|
|
||
|
InitGlobalMetrics(0);
|
||
|
InitGlobalColors();
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* InitCommonControlsEx creates the classes. Only those classes requested are created!
|
||
|
** The process attach figures out if it's an old app and supplies ICC_WIN95_CLASSES.
|
||
|
*/
|
||
|
typedef BOOL (PASCAL *PFNINIT)(HINSTANCE);
|
||
|
typedef struct {
|
||
|
PFNINIT pfnInit;
|
||
|
#ifdef WINNT
|
||
|
LPCTSTR pszName;
|
||
|
#endif
|
||
|
DWORD dw;
|
||
|
} INITCOMMONCONTROLSINFO;
|
||
|
|
||
|
#ifdef WINNT
|
||
|
#define MAKEICC(pfnInit, pszClass, dwFlags) { pfnInit, pszClass, dwFlags }
|
||
|
#else
|
||
|
#define MAKEICC(pfnInit, pszClass, dwFlags) { pfnInit, dwFlags }
|
||
|
#endif
|
||
|
|
||
|
const INITCOMMONCONTROLSINFO icc[] =
|
||
|
{
|
||
|
// Init function Class name Requested class sets which use this class
|
||
|
MAKEICC(InitToolbarClass, TOOLBARCLASSNAME, ICC_BAR_CLASSES),
|
||
|
MAKEICC(InitReBarClass, REBARCLASSNAME, ICC_COOL_CLASSES),
|
||
|
MAKEICC(InitToolTipsClass, TOOLTIPS_CLASS, ICC_TREEVIEW_CLASSES|ICC_BAR_CLASSES|ICC_TAB_CLASSES),
|
||
|
MAKEICC(InitStatusClass, STATUSCLASSNAME, ICC_BAR_CLASSES),
|
||
|
MAKEICC(ListView_Init, WC_LISTVIEW, ICC_LISTVIEW_CLASSES),
|
||
|
MAKEICC(Header_Init, WC_HEADER, ICC_LISTVIEW_CLASSES),
|
||
|
MAKEICC(Tab_Init, WC_TABCONTROL, ICC_TAB_CLASSES),
|
||
|
MAKEICC(TV_Init, WC_TREEVIEW, ICC_TREEVIEW_CLASSES),
|
||
|
MAKEICC(InitTrackBar, TRACKBAR_CLASS, ICC_BAR_CLASSES),
|
||
|
MAKEICC(InitUpDownClass, UPDOWN_CLASS, ICC_UPDOWN_CLASS),
|
||
|
MAKEICC(InitProgressClass, PROGRESS_CLASS, ICC_PROGRESS_CLASS),
|
||
|
MAKEICC(InitHotKeyClass, HOTKEY_CLASS, ICC_HOTKEY_CLASS),
|
||
|
MAKEICC(InitAnimateClass, ANIMATE_CLASS, ICC_ANIMATE_CLASS),
|
||
|
MAKEICC(InitDateClasses, DATETIMEPICK_CLASS,ICC_DATE_CLASSES),
|
||
|
MAKEICC(InitComboExClass, WC_COMBOBOXEX, ICC_USEREX_CLASSES),
|
||
|
MAKEICC(InitIPAddr, WC_IPADDRESS, ICC_INTERNET_CLASSES),
|
||
|
#ifdef PAGER
|
||
|
MAKEICC(InitPager, WC_PAGESCROLLER, ICC_PAGESCROLLER_CLASS),
|
||
|
#endif
|
||
|
MAKEICC(InitNativeFontCtl, WC_NATIVEFONTCTL, ICC_NATIVEFNTCTL_CLASS),
|
||
|
|
||
|
//
|
||
|
// These aren't really classes. They're just goofy flags.
|
||
|
//
|
||
|
#ifdef WINNT
|
||
|
MAKEICC(InitForWinlogon, NULL, ICC_WINLOGON_REINIT),
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
BOOL WINAPI InitCommonControlsEx(LPINITCOMMONCONTROLSEX picce)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
#ifdef UNIX
|
||
|
if (MwIsInitLite())
|
||
|
return (TRUE);
|
||
|
#endif
|
||
|
|
||
|
if (!picce ||
|
||
|
(picce->dwSize != sizeof(INITCOMMONCONTROLSEX)) ||
|
||
|
(picce->dwICC & ~ICC_ALL_VALID))
|
||
|
{
|
||
|
DebugMsg(DM_WARNING, TEXT("comctl32 - picce is bad"));
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
for (i=0 ; i < ARRAYSIZE(icc) ; i++)
|
||
|
if (picce->dwICC & icc[i].dw)
|
||
|
if (!icc[i].pfnInit(HINST_THISDLL))
|
||
|
return(FALSE);
|
||
|
|
||
|
return(TRUE);
|
||
|
}
|
||
|
//
|
||
|
// InitMUILanguage / GetMUILanguage implementation
|
||
|
//
|
||
|
// we have a per process PUI language setting. For NT it's just a global
|
||
|
// initialized with LANG_NEUTRAL and SUBLANG_NEUTRAL
|
||
|
// For Win95 it's DPA slot for the current process.
|
||
|
// InitMUILanguage sets callers preferred language id for common control
|
||
|
// GetMUILangauge returns what the caller has set to us
|
||
|
//
|
||
|
#ifdef WINNT
|
||
|
LANGID PUIGetLangId(void)
|
||
|
{
|
||
|
return g_PUILangId;
|
||
|
}
|
||
|
#else // WIN95
|
||
|
typedef struct tagPUIPROCSLOT
|
||
|
{
|
||
|
DWORD dwPID;
|
||
|
LANGID wLangId;
|
||
|
} PUIPROCSLOT, *PPUIPROCSLOT;
|
||
|
|
||
|
PPUIPROCSLOT PUICreateProcSlot(void)
|
||
|
{
|
||
|
PPUIPROCSLOT pSlot = (PPUIPROCSLOT)Alloc(sizeof(PUIPROCSLOT));
|
||
|
|
||
|
if (pSlot)
|
||
|
{
|
||
|
pSlot->dwPID = GetCurrentProcessId();
|
||
|
pSlot->wLangId = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
||
|
}
|
||
|
return pSlot;
|
||
|
}
|
||
|
|
||
|
int PUIGetProcIdx(DWORD dwProcessId)
|
||
|
{
|
||
|
int i, cSlot = 0;
|
||
|
|
||
|
ASSERTCRITICAL;
|
||
|
|
||
|
if (g_hdpaPUI)
|
||
|
cSlot = DPA_GetPtrCount(g_hdpaPUI);
|
||
|
|
||
|
for (i = 0; i < cSlot; i++)
|
||
|
{
|
||
|
PPUIPROCSLOT pSlot = (PPUIPROCSLOT)DPA_FastGetPtr(g_hdpaPUI, i);
|
||
|
|
||
|
if (pSlot && pSlot->dwPID == dwProcessId)
|
||
|
return i;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
void InitPUI(void)
|
||
|
{
|
||
|
if (NULL == g_hdpaPUI)
|
||
|
{
|
||
|
ENTERCRITICAL;
|
||
|
if (NULL == g_hdpaPUI)
|
||
|
g_hdpaPUI= DPA_Create(4);
|
||
|
LEAVECRITICAL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void DeInitPUI(int cProcesses)
|
||
|
{
|
||
|
int i = PUIGetProcIdx(GetCurrentProcessId());
|
||
|
|
||
|
ASSERTCRITICAL;
|
||
|
|
||
|
if (0 <= i)
|
||
|
{
|
||
|
Free((PPUIPROCSLOT)DPA_FastGetPtr(g_hdpaPUI, i));
|
||
|
DPA_DeletePtr(g_hdpaPUI, i);
|
||
|
}
|
||
|
|
||
|
if (g_hdpaPUI&& 1 == cProcesses) // This is last process detach
|
||
|
{
|
||
|
DPA_Destroy(g_hdpaPUI);
|
||
|
g_hdpaPUI= NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PPUIPROCSLOT PUIGetProcSlot(void)
|
||
|
{
|
||
|
PPUIPROCSLOT pSlot = NULL;
|
||
|
int i;
|
||
|
|
||
|
ENTERCRITICAL;
|
||
|
i = PUIGetProcIdx(GetCurrentProcessId());
|
||
|
|
||
|
if (0 <= i)
|
||
|
{
|
||
|
pSlot = (PPUIPROCSLOT)DPA_FastGetPtr(g_hdpaPUI, i);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pSlot = PUICreateProcSlot();
|
||
|
if (pSlot)
|
||
|
DPA_AppendPtr(g_hdpaPUI, pSlot);
|
||
|
}
|
||
|
|
||
|
LEAVECRITICAL;
|
||
|
|
||
|
return pSlot;
|
||
|
}
|
||
|
|
||
|
LANGID PUIGetLangId(void)
|
||
|
{
|
||
|
PPUIPROCSLOT pSlot = PUIGetProcSlot();
|
||
|
LANGID wLang;
|
||
|
if (pSlot)
|
||
|
wLang = pSlot->wLangId;
|
||
|
else
|
||
|
wLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
||
|
|
||
|
return wLang;
|
||
|
}
|
||
|
#endif // !WINNT
|
||
|
|
||
|
void WINAPI
|
||
|
InitMUILanguage(LANGID wLang)
|
||
|
{
|
||
|
#ifdef WINNT
|
||
|
ENTERCRITICAL;
|
||
|
g_PUILangId = wLang;
|
||
|
LEAVECRITICAL;
|
||
|
#else
|
||
|
PPUIPROCSLOT pSlot = PUIGetProcSlot();
|
||
|
if(pSlot)
|
||
|
pSlot->wLangId = wLang;
|
||
|
#endif
|
||
|
}
|
||
|
LANGID WINAPI
|
||
|
GetMUILanguage(void)
|
||
|
{
|
||
|
#ifdef WINNT
|
||
|
return g_PUILangId;
|
||
|
#else
|
||
|
return PUIGetLangId();
|
||
|
#endif
|
||
|
}
|
||
|
// end MUI functions
|
||
|
|
||
|
#ifdef WINNT
|
||
|
//
|
||
|
// Unlike Win9x, WinNT does not automatically unregister classes
|
||
|
// when a DLL unloads. We have to do it manually. Leaving the
|
||
|
// class lying around means that if an app loads our DLL, then
|
||
|
// unloads it, then reloads it at a different address, all our
|
||
|
// leftover RegisterClass()es will point the WndProc at the wrong
|
||
|
// place and we fault at the next CreateWindow().
|
||
|
//
|
||
|
// This is not purely theoretical - NT4/FE hit this bug.
|
||
|
//
|
||
|
void UnregisterClasses()
|
||
|
{
|
||
|
WNDCLASS wc;
|
||
|
int i;
|
||
|
|
||
|
for (i=0 ; i < ARRAYSIZE(icc) ; i++)
|
||
|
{
|
||
|
if (icc[i].pszName &&
|
||
|
GetClassInfo(HINST_THISDLL, icc[i].pszName, &wc))
|
||
|
{
|
||
|
UnregisterClass(icc[i].pszName, HINST_THISDLL);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if defined(DEBUG)
|
||
|
LRESULT WINAPI SendMessageD(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
ASSERTNONCRITICAL;
|
||
|
#ifdef UNICODE
|
||
|
return SendMessageW(hWnd, Msg, wParam, lParam);
|
||
|
#else
|
||
|
return SendMessageA(hWnd, Msg, wParam, lParam);
|
||
|
#endif
|
||
|
}
|
||
|
#endif // defined(DEBUG)
|
||
|
|
||
|
#define COMPILE_MULTIMON_STUBS
|
||
|
#include "multimon.h"
|