windows-nt/Source/XPSP1/NT/windows/richedit/re30/w32win32.cpp
2020-09-26 16:20:57 +08:00

4788 lines
127 KiB
C++

/*
* Unicode <--> MultiByte conversions, OLE, and other system functions
*
* Copyright (c) 1995-1998, Microsoft Corporation. All rights reserved.
*/
#include <objbase.h> // CoCreateInstance define
#include "aimm.h" // AIMM i/f
#include "aimm_i.c" // AIMM CLSID etc
#include "_font.h"
#include "_uspi.h"
#define MAX_HKLS 256 // It will be a while before we have more KBs
static HINSTANCE g_hOleAut32 = NULL;
static HINSTANCE g_hOle32 = NULL;
#ifndef NOACCESSIBILITY
static HINSTANCE g_hAcc = NULL;
static HINSTANCE g_hUser32 = NULL;
#endif
class CIMM32_PROC
{
public:
void *ImmGetCompositionStringA;
void *ImmGetCompositionStringW;
void *ImmGetContext;
void *ImmSetCompositionFontA;
void *ImmSetCompositionWindow;
void *ImmReleaseContext;
void *ImmGetProperty;
void *ImmGetCandidateWindow;
void *ImmSetCandidateWindow;
void *ImmNotifyIME;
void *ImmAssociateContext;
void *ImmGetVirtualKey;
void *ImmEscapeA;
void *ImmEscapeW;
void *ImmGetOpenStatus;
void *ImmSetOpenStatus;
void *ImmGetConversionStatus;
void *ImmSetConversionStatus;
void *ImmGetDefaultIMEWnd;
void *ImmSetCompositionStringW;
};
static CIMM32_PROC g_IMM32Proc;
class CIMESHARE_PROC
{
public:
void *FSupportSty;
void *PIMEStyleFromAttr;
void *PColorStyleTextFromIMEStyle;
void *PColorStyleBackFromIMEStyle;
void *FBoldIMEStyle;
void *FItalicIMEStyle;
void *FUlIMEStyle;
void *IdUlIMEStyle;
void *RGBFromIMEColorStyle;
};
static CIMESHARE_PROC g_IMEShareProc;
class COLEAUT32_PROC
{
public:
void *LoadRegTypeLib;
void *LoadTypeLib;
void *LoadTypeLibEx;
void *SysAllocString;
void *SysAllocStringLen;
void *SysFreeString;
void *SysStringLen;
void *VariantInit;
};
static COLEAUT32_PROC g_OleAut32Proc;
class COLE32_PROC
{
public:
void *OleCreateFromData;
void *CoTaskMemFree;
void *CreateBindCtx;
void *OleDuplicateData;
void *CoTreatAsClass;
void *ProgIDFromCLSID;
void *OleConvertIStorageToOLESTREAM;
void *OleConvertIStorageToOLESTREAMEx;
void *OleSave;
void *StgCreateDocfileOnILockBytes;
void *CreateILockBytesOnHGlobal;
void *OleCreateLinkToFile;
void *CoTaskMemAlloc;
void *CoTaskMemRealloc;
void *OleInitialize;
void *OleUninitialize;
void *OleSetClipboard;
void *OleFlushClipboard;
void *OleIsCurrentClipboard;
void *DoDragDrop;
void *OleGetClipboard;
void *RegisterDragDrop;
void *OleCreateLinkFromData;
void *OleCreateStaticFromData;
void *OleDraw;
void *OleSetContainedObject;
void *CoDisconnectObject;
void *WriteFmtUserTypeStg;
void *WriteClassStg;
void *SetConvertStg;
void *ReadFmtUserTypeStg;
void *ReadClassStg;
void *OleRun;
void *RevokeDragDrop;
void *CreateStreamOnHGlobal;
void *GetHGlobalFromStream;
void *OleCreateDefaultHandler;
void *CLSIDFromProgID;
void *OleConvertOLESTREAMToIStorage;
void *OleLoad;
void *ReleaseStgMedium;
void *CoCreateInstance;
};
static COLE32_PROC g_Ole32Proc;
class CConvertStr
{
public:
operator char *();
protected:
CConvertStr();
~CConvertStr();
void Free();
LPSTR _pstr;
char _ach[MAX_PATH * 2];
};
inline CConvertStr::operator char *()
{
return _pstr;
}
inline CConvertStr::CConvertStr()
{
_pstr = NULL;
}
inline CConvertStr::~CConvertStr()
{
Free();
}
class CStrIn : public CConvertStr
{
public:
CStrIn(LPCWSTR pwstr, UINT CodePage = CP_ACP);
CStrIn(LPCWSTR pwstr, int cwch, UINT CodePage = CP_ACP);
int strlen();
protected:
CStrIn();
void Init(LPCWSTR pwstr, int cwch, UINT CodePage = CP_ACP);
int _cchLen;
};
inline CStrIn::CStrIn()
{
}
inline int CStrIn::strlen()
{
return _cchLen;
}
class CStrOut : public CConvertStr
{
public:
CStrOut(LPWSTR pwstr, int cwchBuf);
~CStrOut();
int BufSize();
int Convert();
private:
LPWSTR _pwstr;
int _cwchBuf;
};
inline int CStrOut::BufSize()
{
return _cwchBuf * 2;
}
//
// Multi-Byte ---> Unicode conversion
//
class CStrOutW : public CConvertStrW
{
public:
CStrOutW(LPSTR pstr, int cchBuf, UINT uiCodePage);
~CStrOutW();
int BufSize();
int Convert();
private:
LPSTR _pstr;
int _cchBuf;
UINT _uiCodePage;
};
inline int CStrOutW::BufSize()
{
return _cchBuf;
}
DWORD CW32System::AddRef()
{
return ++_cRefs;
}
DWORD CW32System::Release()
{
DWORD culRefs = --_cRefs;
if(culRefs == 0)
{
FreeIME();
if (g_hOle32)
{
EnterCriticalSection(&g_CriticalSection);
OleUninitialize();
FreeLibrary(g_hOle32);
g_hOle32 = NULL;
memset(&g_Ole32Proc, 0, sizeof(g_Ole32Proc));
LeaveCriticalSection(&g_CriticalSection);
}
}
return culRefs;
}
ATOM WINAPI CW32System::RegisterREClass(
const WNDCLASSW *lpWndClass,
const char *szAnsiClassName,
WNDPROC AnsiWndProc
)
{
WNDCLASSA wc;
ATOM atom;
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "RegisterREClass");
// First register the normal window class.
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
{
atom = ::RegisterClass(lpWndClass);
if (!atom && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
atom = FindAtom(lpWndClass->lpszClassName);
}
else
{
// On WIndows 95 we need to convert the window class name.
CStrIn strMenuName(lpWndClass->lpszMenuName);
CStrIn strClassName(lpWndClass->lpszClassName);
Assert(sizeof(wc) == sizeof(*lpWndClass));
memcpy(&wc, lpWndClass, sizeof(wc));
wc.lpszMenuName = strMenuName;
wc.lpszClassName = strClassName;
atom = ::RegisterClassA(&wc);
if (!atom && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
atom = FindAtomA(wc.lpszClassName);
}
if (!atom || !szAnsiClassName)
return atom;
// Now REgister the ANSI window class name i.e. RICHEDIT20A
wc.style = lpWndClass->style;
wc.cbClsExtra = lpWndClass->cbClsExtra;
wc.cbWndExtra = lpWndClass->cbWndExtra;
wc.hInstance = lpWndClass->hInstance;
wc.hIcon = lpWndClass->hIcon;
wc.hCursor = lpWndClass->hIcon;
wc.hbrBackground = lpWndClass->hbrBackground;
wc.lpszMenuName = NULL;
wc.lpfnWndProc = AnsiWndProc;
wc.lpszClassName = szAnsiClassName;
atom = ::RegisterClassA(&wc);
if (!atom && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
atom = FindAtomA(szAnsiClassName);
return atom;
}
LONG ValidateTextRange(TEXTRANGE *pstrg);
LRESULT CW32System::ANSIWndProc(
HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam,
BOOL fIs10Mode)
{
TRACEBEGIN(TRCSUBSYSHOST, TRCSCOPEINTERN, "RichEditANSIWndProc");
#ifdef DEBUG
Tracef(TRCSEVINFO, "hwnd %lx, msg %lx, wparam %lx, lparam %lx", hwnd, msg, wparam, lparam);
#endif // DEBUG
LRESULT lres;
switch( msg )
{
case EM_REPLACESEL:
case WM_SETTEXT:
{
SETTEXTEX st = {ST_CHECKPROTECTION, 0};
if(msg == EM_REPLACESEL)
{
st.flags = wparam ? ST_CHECKPROTECTION | ST_SELECTION | ST_KEEPUNDO | ST_10REPLACESEL
: ST_CHECKPROTECTION | ST_SELECTION | ST_10REPLACESEL;
}
else if (fIs10Mode)
st.flags |= ST_10WM_SETTEXT; // 1.0 Mode WM_SETTEXT
return RichEditWndProc(hwnd, EM_SETTEXTEX, (WPARAM)&st, lparam);
}
case EM_FINDTEXT:
case EM_FINDTEXTEX:
{
// We cheat a little here because FINDTEXT and FINDTEXTEX overlap
// with the exception of the extra out param chrgText in FINDTEXTEX
FINDTEXTEXW ftexw;
FINDTEXTA *pfta = (FINDTEXTA *)lparam;
CStrInW strinw(pfta->lpstrText, W32->GetKeyboardCodePage());
ftexw.chrg = pfta->chrg;
ftexw.lpstrText = (WCHAR *)strinw;
lres = RichEditWndProc(hwnd, msg, wparam, (LPARAM)&ftexw);
if(msg == EM_FINDTEXTEX)
{
// In the FINDTEXTEX case, the extra field in the
// FINDTEXTEX data structure is an out parameter indicating
// the range where the text was found. Update the 'real'
// [in, out] parameter accordingly.
((FINDTEXTEXA *)lparam)->chrgText = ftexw.chrgText;
}
return lres;
}
break;
case EM_GETSELTEXT:
{
GETTEXTEX gt;
const char chDefault = ' ';
gt.cb = (unsigned)-1; // Client claims to have enuf room
gt.flags = GT_SELECTION; // Get selected text
gt.codepage = (unsigned)-1; // Use default CCharFormat codepage
gt.lpDefaultChar = &chDefault; // Translate other chars into blanks
gt.lpUsedDefChar = NULL;
return RichEditWndProc(hwnd, EM_GETTEXTEX, (WPARAM)&gt, lparam);
}
break;
// case WM_GETTEXT: Handled by Ansi filter
// case WM_GETTEXTLENGTH: Handled by Ansi filter
case EM_GETTEXTRANGE:
{
TEXTRANGEA *ptrg = (TEXTRANGEA *)lparam;
LONG clInBuffer = ValidateTextRange((TEXTRANGEW *) ptrg);
// If size is -1, this means that the size required is the total
// size of the the text.
if(-1 == clInBuffer)
{
// We can get this length either by digging the data out of the
// various structures below us or we can take advantage of the
// WM_GETTEXTLENGTH message. The first might be slightly
// faster but the second definitely save code size. So we
// will go with the second.
clInBuffer = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
}
if(0 == clInBuffer)
{
// The buffer was invalid for some reason or there was not data
// to copy. In any case, we are done.
return 0;
}
// Verify that the output buffer is big enough.
if(IsBadWritePtr(ptrg->lpstrText, clInBuffer + 1))
{
// Not enough space so don't copy any
return 0;
}
// For EM_GETTEXTRANGE case, we again don't know how big the
// incoming buffer is, only that it should be *at least* as
// great as cpMax - cpMin in the text range structure. We also
// know that anything *bigger* than (cpMax - cpMin)*2 bytes is
// uncessary. So we'll just assume that it's "big enough"
// and let WideCharToMultiByte scribble as much as it needs.
// Memory shortages are the caller's responsibility (courtesy
// of the RichEdit 1.0 design).
CStrOutW stroutw(ptrg->lpstrText, (clInBuffer + 1) * sizeof(WCHAR),
RichEditWndProc(hwnd, EM_GETCODEPAGE, 0, 0));
TEXTRANGEW trgw;
trgw.chrg = ptrg->chrg;
trgw.lpstrText = (WCHAR *)stroutw;
RichEditWndProc(hwnd, EM_GETTEXTRANGE, wparam, (LPARAM)&trgw);
return stroutw.Convert(); // Return count of BYTEs converted
}
case EM_GETLINE:
{
// The size is indicated by the first word of the memory pointed
// to by lparam
WORD size = *(WORD *)lparam;
CStrOutW stroutw((char *)lparam, (DWORD)size,
RichEditWndProc(hwnd, EM_GETCODEPAGE, 0, 0));
WCHAR *pwsz = (WCHAR *)stroutw;
*(WORD *)pwsz = size;
lres = RichEditWndProc(hwnd, msg, wparam, (LPARAM)pwsz);
if (lres < size)
*(pwsz+lres) = L'\0'; // EM_GETLINE does not return NULL-terminated string.
LONG cach = stroutw.Convert();
// Note: should probably return cach for 3.0 too, i.e.,
// just like EM_GETTEXTRANGE above
return fIs10Mode ? cach : lres; // If 1.0, return count of BYTEs converted
}
#ifdef DEBUG
case WM_NCCREATE:
case WM_CREATE:
// These messages should be handled higher up so let everyone
// know we got to the wrong place!
AssertSz(FALSE, "CW32System::ANSIWndProc got WM_CREATE or WM_NCCREATE");
break;
#endif // DEBUG
}
return RichEditWndProc(hwnd, msg, wparam, lparam);
}
// Note that AnsiFilter could be refined so that we could get rid
// of the ANSI window proc.
void CW32System::AnsiFilter(
UINT & msg,
WPARAM &wparam,
LPARAM lparam,
void *pvoid,
BOOL f10Mode
)
{
GETTEXTEX *pgt;
GETTEXTLENGTHEX *pgtl;
WM_CHAR_INFO *pwmci;
bool fAltNumPad = (GetKeyboardFlags() & ALTNUMPAD) != 0;
UINT cpg = GetKeyboardCodePage(0xFFFFFFFF);
switch (msg)
{
case WM_CHAR:
pwmci = (WM_CHAR_INFO *) pvoid;
pwmci->_fTrailByte = false;
pwmci->_fLeadByte = false;
pwmci->_fIMEChar = false;
if (pwmci->_fAccumulate) {
// We could do some validation here.
pwmci->_fTrailByte = true;
return;
}
// WM_CHAR > 256 on Win95; assumed to be Unicode
if(fAltNumPad)
{
DWORD Number = GetKeyPadNumber();
if(Number >= 256 || GetKeyboardFlags() & ALT0)
{
wparam = Number;
if(!IN_RANGE(1250, cpg, 1258)) // Use 1252 for DBCS
cpg = 1252; // codepages
}
}
if(IN_RANGE(128, wparam, 255))
{
bool fShift = (GetKeyboardFlags() & SHIFT) != 0;
bool fCtrl = (GetKeyboardFlags() & CTRL) != 0;
// If fAltNumPad is set, wparam is HiAnsi
// If Shift + Alt + Ctrl, it is repeat event from Win3.1 IME
if ((!fAltNumPad || (fShift && fCtrl)) && GetTrailBytesCount((BYTE) wparam, cpg))
{
pwmci->_fLeadByte = true;
return;
}
WPARAM wparamNew = 0;
switch ( cpg )
{
case CP_JAPAN:
// for Japanese codepage, need to translate SBC if KANA mode is on
if ((GetKeyState(VK_KANA) & 1) || f10Mode)
break;
// If not in KANA mode, then fall thru to use 1252 codepage...
case CP_KOREAN:
case CP_CHINESE_TRAD:
case CP_CHINESE_SIM:
// use English codepage since there is no HiAnsi conversion for
// FE systems
cpg = 1252;
break;
}
if (cpg == 1252 && !IN_RANGE(0x80, wparam, 0x9f))
return;
// Convert single byte WM_CHAR messages to Unicode
if(UnicodeFromMbcs((LPWSTR)&wparamNew, 1, (char *)&wparam, 1,
cpg) == 1 )
{
wparam = wparamNew;
if (fAltNumPad)
SetKeyPadNumber(wparam);
}
}
else if(lparam == 1 && _dwPlatformId == VER_PLATFORM_WIN32_NT &&
wparam > 256 && !fAltNumPad)
{
// On WinNT s/w generated WM_CHAR, this should be WM_IME_CHAR message
// for some Chinese Level 2 IME.
if ( cpg == CP_CHINESE_SIM || cpg == CP_CHINESE_TRAD )
{
BYTE bTrailByte = wparam >> 8;
BYTE bLeadByte = wparam;
wparam = (bLeadByte << 8) | bTrailByte;
pwmci->_fIMEChar = true;
}
}
return;
case WM_GETTEXT:
// EVIL HACK ALERT: on Win95, WM_GETTEXT should always be treated
// as an ANSI message.
pgt = (GETTEXTEX *) pvoid;
pgt->cb = wparam;
pgt->flags = GT_USECRLF;
pgt->codepage = 0;
pgt->lpDefaultChar = NULL;
pgt->lpUsedDefChar = NULL;
msg = EM_GETTEXTEX;
wparam = (WPARAM) pgt;
return;
case WM_GETTEXTLENGTH:
// EVIL HACK ALERT: on Win95, WM_GETEXTLENGTH should always
// be treated an ANSI message because some old apps will send
// this message to arbitrary windows (e.g., accessibility aps)
pgtl = (GETTEXTLENGTHEX *) pvoid;
pgtl->flags = GTL_NUMBYTES | GTL_PRECISE | GTL_USECRLF;
pgtl->codepage = 0;
msg = EM_GETTEXTLENGTHEX;
wparam = (WPARAM) pgtl;
return;
}
}
HGLOBAL WINAPI CW32System::GlobalAlloc( UINT uFlags, DWORD dwBytes )
{
return ::GlobalAlloc( uFlags, dwBytes );
}
HGLOBAL WINAPI CW32System::GlobalFree( HGLOBAL hMem )
{
return hMem ? ::GlobalFree( hMem ) : NULL;
}
UINT WINAPI CW32System::GlobalFlags( HGLOBAL hMem )
{
return ::GlobalFlags( hMem );
}
HGLOBAL WINAPI CW32System::GlobalReAlloc( HGLOBAL hMem, DWORD dwBytes, UINT uFlags )
{
return ::GlobalReAlloc( hMem, dwBytes, uFlags );
}
DWORD WINAPI CW32System::GlobalSize( HGLOBAL hMem )
{
return ::GlobalSize( hMem );
}
LPVOID WINAPI CW32System::GlobalLock( HGLOBAL hMem )
{
return ::GlobalLock( hMem );
}
HGLOBAL WINAPI CW32System::GlobalHandle( LPCVOID pMem )
{
return ::GlobalHandle( pMem );
}
BOOL WINAPI CW32System::GlobalUnlock( HGLOBAL hMem )
{
return ::GlobalUnlock( hMem );
}
/*
* CW32System::CheckChangeKeyboardLayout (bCharSet)
*
* @mfunc
* Change keyboard for new charset, or charset at new character position.
*
* @rdesc
* Keyboard hkl selected. 0 if failed to find keyboard
*
* @comm
* Using only the currently loaded KBs, locate one that will support
* bCharSet. This is called anytime a character format change occurs,
* or the caret position changes.
*
* @devnote
* The current KB is preferred. If a previous association was made,
* see if the KB is still loaded in the system and if so use it.
* Otherwise, locate a suitable KB, preferring KB's that have
* the same charset ID as their default, preferred charset. If no
* match can be found, nothing changes.
*/
HKL CW32System::CheckChangeKeyboardLayout(
BYTE bCharSet)
{
return ActivateKeyboard(ScriptIndexFromCharSet(bCharSet));
}
HKL CW32System::GetKeyboardLayout (
DWORD dwThreadID)
{
if(dwThreadID == 0x0FFFFFFFF)
RefreshKeyboardLayout();
return _hklCurrent;
}
/*
* CW32System::RefreshKeyboardLayout ()
*
* @mfunc
* Update _hklCurrent with current keyboard layout and update
* entry for corresponding script.
*/
void CW32System::RefreshKeyboardLayout ()
{
INT iScript;
_hklCurrent = ::GetKeyboardLayout(0);
GetCharSet(ConvertLanguageIDtoCodePage(PRIMARYLANGID(_hklCurrent)), &iScript);
SetPreferredKbd(iScript, _hklCurrent);
}
/*
* CW32System::ActivateKeyboard (iScript)
*
* @mfunc
* Change keyboard to that for iScript
*
* @rdesc
* Keyboard hkl selected. 0 if no keyboard assigned to iScript
*/
HKL CW32System::ActivateKeyboard(
LONG iScript)
{
HKL hkl = 0;
if((unsigned)iScript < NCHARSETS)
{
hkl = GetPreferredKbd(iScript);
if(hkl && hkl != _hklCurrent && ActivateKeyboardLayout(hkl, 0))
_hklCurrent = hkl;
}
return hkl;
}
/*
* CW32System::FindDirectionalKeyboard (fRTL)
*
* @mfunc
* Find first keyboard with direction given by fRTL
*
* @rdesc
* HKL of keyboard selected. 0 if no keyboard for direction given by fRTL
*/
HKL CW32System::FindDirectionalKeyboard(
BOOL fRTL)
{
Assert(ARABIC_INDEX == (HEBREW_INDEX | 1));
int iKB;
if(fRTL)
{
GetCharSet(GetACP(), &iKB);
if(!IN_RANGE(HEBREW_INDEX, iKB, ARABIC_INDEX))
iKB = _hkl[HEBREW_INDEX] ? HEBREW_INDEX :
_hkl[ARABIC_INDEX] ? ARABIC_INDEX : -1;
}
else
for(iKB = 0;
iKB < NCHARSETS && (!_hkl[iKB] || IN_RANGE(HEBREW_INDEX, iKB, ARABIC_INDEX));
iKB++)
;
return ActivateKeyboard(iKB);
}
enum DLL_ENUM{
DLL_OLEAUT32,
DLL_OLE32,
#ifndef NOACCESSIBILITY
DLL_ACC,
DLL_USER32
#endif
};
static void SetProcAddr(
void * & pfunc,
DLL_ENUM which,
char * fname )
{
HINSTANCE hdll = NULL;
EnterCriticalSection(&g_CriticalSection);
if (pfunc == NULL)
{
switch (which)
{
case DLL_OLEAUT32:
if (g_hOleAut32 == NULL)
g_hOleAut32 = W32->LoadLibrary(L"oleaut32.dll" );
hdll = g_hOleAut32;
break;
case DLL_OLE32:
if (g_hOle32 == NULL)
{
g_hOle32 = W32->LoadLibrary(L"ole32.dll");
CW32System::OleInitialize(NULL);
}
hdll = g_hOle32;
break;
#ifndef NOACCESSIBILITY
case DLL_ACC:
if (g_hAcc == NULL)
g_hAcc = W32->LoadLibrary(L"oleacc.dll");
hdll = g_hAcc;
break;
case DLL_USER32:
if (g_hUser32 == NULL)
g_hUser32 = W32->LoadLibrary(L"user32.dll");
hdll = g_hUser32;
break;
#endif
}
Assert(hdll != NULL || which == DLL_USER32);
pfunc = GetProcAddress( hdll, fname );
}
AssertSz(pfunc != NULL || which == DLL_USER32, fname);
LeaveCriticalSection(&g_CriticalSection);
}
void CW32System::FreeOle()
{
if (g_hOleAut32 || g_hOle32) {
EnterCriticalSection(&g_CriticalSection);
if (g_hOleAut32 != NULL && FreeLibrary(g_hOleAut32)) {
g_hOleAut32 = NULL;
memset(&g_OleAut32Proc, 0, sizeof(g_OleAut32Proc));
}
if (g_hOle32 != NULL && FreeLibrary(g_hOle32)) {
g_hOle32 = NULL;
memset(&g_Ole32Proc, 0, sizeof(g_Ole32Proc));
}
LeaveCriticalSection(&g_CriticalSection);
}
}
enum IME_DLL_ENUM{
DLL_IMM32,
DLL_IMESHARE
};
static HINSTANCE hIMM32 = NULL;
static HINSTANCE hIMEShare = NULL;
static void SetIMEProcAddr( void * &pfunc, IME_DLL_ENUM which, char * fname )
{
HINSTANCE hdll = NULL;
EnterCriticalSection(&g_CriticalSection);
if (pfunc == NULL)
{
switch (which) {
case DLL_IMM32 :
if (hIMM32 == NULL)
hIMM32 = W32->LoadLibrary(L"imm32.dll" );
Assert( hIMM32 != NULL );
hdll = hIMM32;
break;
case DLL_IMESHARE :
if (hIMEShare == NULL)
hIMEShare = W32->LoadLibrary(L"imeshare.dll" );
else if (hIMEShare == (HINSTANCE)INVALID_HANDLE_VALUE)
goto Exit;
hdll = hIMEShare;
// set to invalid handle if we have tried loading it.
// this is to avoid loading it again and again in case
// imeshare.dll is not in the system.
if (hIMEShare == NULL)
hIMEShare = (HINSTANCE)INVALID_HANDLE_VALUE;
break;
}
if (hdll)
{
pfunc = GetProcAddress( hdll, fname );
Assert(pfunc != NULL );
}
}
Exit:
LeaveCriticalSection(&g_CriticalSection);
}
static IActiveIMMApp *pAIMM = (IActiveIMMApp *) NULL;
typedef IMESHAREAPI void (IMECDECL*FEND_CAST)(void);
void CW32System::FreeIME()
{
if (hIMM32 || hIMEShare || pAIMM) {
EnterCriticalSection(&g_CriticalSection);
if (hIMM32 != NULL && FreeLibrary(hIMM32)) {
hIMM32 = NULL;
memset(&g_IMM32Proc, 0, sizeof(g_IMM32Proc));
}
if (hIMEShare != NULL && hIMEShare != (HINSTANCE)INVALID_HANDLE_VALUE) {
// clean up IMMShare before leaving
if ( _pIMEShare )
{
_pIMEShare->FDeleteIMEShare();
_pIMEShare = NULL;
}
else
{
// This is old IMEShare, end it the old way
void *pEndIMEShareFunc;
pEndIMEShareFunc = GetProcAddress( hIMEShare, "EndIMEShare" );
if (pEndIMEShareFunc)
{
( (FEND_CAST)pEndIMEShareFunc)();
}
}
FreeLibrary(hIMEShare);
hIMEShare = NULL;
memset(&g_IMEShareProc, 0, sizeof(g_IMEShareProc));
}
if (pAIMM != (IActiveIMMApp *)NULL && pAIMM != (IActiveIMMApp *)INVALID_HANDLE_VALUE)
{
pAIMM->Release();
pAIMM = (IActiveIMMApp *)NULL;
}
_fHaveAIMM = FALSE;
_fHaveIMMEShare = FALSE;
_fHaveIMMProcs = FALSE;
LeaveCriticalSection(&g_CriticalSection);
}
}
// return TRUE if we load AIMM
BOOL CW32System::LoadAIMM()
{
HRESULT hResult;
// return if AIMM has been loaded
if (_fHaveAIMM)
return TRUE;
if (pAIMM == (IActiveIMMApp *)INVALID_HANDLE_VALUE)
return FALSE;
EnterCriticalSection(&g_CriticalSection);
// load if it has not been loaded
// Try with new W2K/COM+ CLSCTX_NO_CODE_DOWNLOAD flag
hResult = CW32System::CoCreateInstance(CLSID_CActiveIMM,
NULL, CLSCTX_INPROC_SERVER | CLSCTX_NO_CODE_DOWNLOAD, IID_IActiveIMMApp, (LPVOID *)&pAIMM);
if (hResult == E_INVALIDARG) // Try again if CLSCTX_NO_CODE_DOWNLOAD not support
hResult = CW32System::CoCreateInstance(CLSID_CActiveIMM,
NULL, CLSCTX_INPROC_SERVER, IID_IActiveIMMApp, (LPVOID *)&pAIMM);
_fHaveAIMM = TRUE;
if (FAILED(hResult))
{
_fHaveAIMM = FALSE;
pAIMM = (IActiveIMMApp *)INVALID_HANDLE_VALUE;
}
LeaveCriticalSection(&g_CriticalSection);
return _fHaveAIMM;
}
// Return the Aimm object and AddRef()
BOOL CW32System::GetAimmObject(IUnknown **ppAimm)
{
*ppAimm = NULL;
if (pAIMM != NULL && pAIMM != (IActiveIMMApp *)INVALID_HANDLE_VALUE)
{
pAIMM->AddRef();
*ppAimm = pAIMM;
return TRUE;
}
return FALSE;
}
// return TRUE if we have IMEShare in system
// else return FALSE
typedef IMESHAREAPI BOOL (IMECDECL*FINIT_CAST)(void);
typedef IMESHAREAPI CIMEShare * (IMECDECL*FPIME_CAST)(void);
BOOL CW32System::HaveIMEShare()
{
// return if IMEShare has been loaded
if (_fHaveIMMEShare)
return TRUE;
if (hIMEShare == (HINSTANCE)INVALID_HANDLE_VALUE)
return FALSE;
EnterCriticalSection(&g_CriticalSection);
// load if it has not been loaded
hIMEShare = W32->LoadLibrary(L"imeshare.dll");
_fHaveIMMEShare = TRUE;
// load fail, setup INVALID_HANDLE_VALUE
if (hIMEShare == NULL)
{
hIMEShare = (HINSTANCE)INVALID_HANDLE_VALUE;
_fHaveIMMEShare = FALSE;
}
else
{
// get the new IMEshare object and init the DLL
void *pPIMEShareCreate;
pPIMEShareCreate = GetProcAddress( hIMEShare, "PIMEShareCreate" );
if (pPIMEShareCreate)
{
_pIMEShare = ( (FPIME_CAST)pPIMEShareCreate) ();
if ( _pIMEShare == NULL )
_fHaveIMMEShare = FALSE;
else
{
// Setup underline styles that RE supports
for (int i = IMESTY_UL_MIN; i <= IMESTY_UL_MAX; i++)
{
if (i == 2004 || i == 2007 || i == 2008 ||
i == 2009 || i == 2010) // Obsolete styles
continue;
_pIMEShare->FSupportSty(i, i);
}
}
}
else
{
// This is old IMEShare, init it the old way
void *pInitFunc;
pInitFunc = GetProcAddress( hIMEShare, "FInitIMEShare" );
if (pInitFunc)
{
_fHaveIMMEShare = ( (FINIT_CAST)pInitFunc)();
}
else
// init failed, forget it
_fHaveIMMEShare = FALSE;
}
if (_fHaveIMMEShare == FALSE)
{
// Init failed, forget it
FreeLibrary(hIMEShare);
hIMEShare = (HINSTANCE)INVALID_HANDLE_VALUE;
}
}
LeaveCriticalSection(&g_CriticalSection);
return _fHaveIMMEShare;
}
BOOL CW32System::getIMEShareObject(CIMEShare **ppIMEShare)
{
*ppIMEShare = _pIMEShare;
return (_pIMEShare != NULL);
}
HRESULT CW32System::AIMMDefWndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plres)
{
if (pAIMM != NULL && pAIMM != (IActiveIMMApp *)INVALID_HANDLE_VALUE)
{
HRESULT hResult;
LRESULT localLRes;
hResult = pAIMM->OnDefWindowProc(hWnd, msg, wparam, lparam, &localLRes);
if (hResult == S_OK)
{
*plres = localLRes;
return S_OK;
}
}
return S_FALSE;
}
HRESULT CW32System::AIMMGetCodePage(HKL hKL, UINT *uCodePage)
{
if (pAIMM != NULL && pAIMM != (IActiveIMMApp *)INVALID_HANDLE_VALUE)
{
HRESULT hResult;
hResult = pAIMM->GetCodePageA(hKL, uCodePage);
if (SUCCEEDED(hResult))
return S_OK;
}
return S_FALSE;
}
HRESULT CW32System::AIMMActivate(BOOL fRestoreLayout)
{
if (pAIMM != NULL && pAIMM != (IActiveIMMApp *)INVALID_HANDLE_VALUE)
{
HRESULT hResult;
hResult = pAIMM->Activate(fRestoreLayout);
if (SUCCEEDED(hResult))
return S_OK;
}
return S_FALSE;
}
HRESULT CW32System::AIMMDeactivate(void)
{
if (pAIMM != NULL && pAIMM != (IActiveIMMApp *)INVALID_HANDLE_VALUE)
{
HRESULT hResult;
hResult = pAIMM->Deactivate();
if (SUCCEEDED(hResult))
return S_OK;
}
return S_FALSE;
}
HRESULT CW32System::AIMMFilterClientWindows(ATOM *aaClassList, UINT uSize)
{
if (pAIMM != NULL && pAIMM != (IActiveIMMApp *)INVALID_HANDLE_VALUE)
{
HRESULT hResult;
hResult = pAIMM->FilterClientWindows(aaClassList, uSize);
if (SUCCEEDED(hResult))
return S_OK;
}
return S_FALSE;
}
#define RE_OLEAUTAPI(name) DECLSPEC_IMPORT HRESULT (STDAPICALLTYPE *name)
#define RE_OLEAUTAPI_(type, name) DECLSPEC_IMPORT type (STDAPICALLTYPE *name)
typedef RE_OLEAUTAPI(LRTL_CAST)(REFGUID, WORD, WORD, LCID, ITypeLib **);
HRESULT CW32System::LoadRegTypeLib (
REFGUID rguid,
WORD wmajor,
WORD wminor,
LCID lcid,
ITypeLib ** pptlib
)
{
if (g_OleAut32Proc.LoadRegTypeLib == NULL)
SetProcAddr( g_OleAut32Proc.LoadRegTypeLib, DLL_OLEAUT32, "LoadRegTypeLib" );
return ((LRTL_CAST)g_OleAut32Proc.LoadRegTypeLib)(rguid, wmajor, wminor, lcid, pptlib);
}
typedef RE_OLEAUTAPI(LTL_CAST)(const OLECHAR *, ITypeLib **);
HRESULT CW32System::LoadTypeLib ( const OLECHAR *szfile, ITypeLib **pptlib )
{
if (g_OleAut32Proc.LoadTypeLib == NULL)
SetProcAddr( g_OleAut32Proc.LoadTypeLib, DLL_OLEAUT32, "LoadTypeLib" );
return ((LTL_CAST)g_OleAut32Proc.LoadTypeLib)(szfile, pptlib);
}
typedef RE_OLEAUTAPI(LTLEX_CAST)(const OLECHAR *, REGKIND, ITypeLib **);
HRESULT CW32System::LoadTypeLibEx ( const OLECHAR *szfile, REGKIND regkind, ITypeLib **pptlib )
{
if (g_OleAut32Proc.LoadTypeLibEx == NULL)
SetProcAddr( g_OleAut32Proc.LoadTypeLibEx, DLL_OLEAUT32, "LoadTypeLibEx" );
return ((LTLEX_CAST)g_OleAut32Proc.LoadTypeLibEx)(szfile, regkind, pptlib);
}
typedef RE_OLEAUTAPI_(BSTR, SAS_CAST)(const OLECHAR *);
BSTR CW32System::SysAllocString ( const OLECHAR * sz )
{
if (g_OleAut32Proc.SysAllocString == NULL)
SetProcAddr( g_OleAut32Proc.SysAllocString, DLL_OLEAUT32, "SysAllocString" );
return ((SAS_CAST)g_OleAut32Proc.SysAllocString)(sz);
}
typedef RE_OLEAUTAPI_(BSTR, SASL_CAST)(const OLECHAR *, UINT);
BSTR CW32System::SysAllocStringLen ( const OLECHAR *pch, UINT cch )
{
if (g_OleAut32Proc.SysAllocStringLen == NULL)
SetProcAddr( g_OleAut32Proc.SysAllocStringLen, DLL_OLEAUT32, "SysAllocStringLen" );
return ((SASL_CAST)g_OleAut32Proc.SysAllocStringLen)(pch, cch);
}
typedef RE_OLEAUTAPI_(void, SFS_CAST)(BSTR);
void CW32System::SysFreeString ( BSTR bstr )
{
if (g_OleAut32Proc.SysFreeString == NULL)
SetProcAddr( g_OleAut32Proc.SysFreeString, DLL_OLEAUT32, "SysFreeString" );
((SFS_CAST)g_OleAut32Proc.SysFreeString)(bstr);
}
typedef RE_OLEAUTAPI_(UINT, SSL_CAST)(BSTR);
UINT CW32System::SysStringLen ( BSTR bstr )
{
if (g_OleAut32Proc.SysStringLen == NULL)
SetProcAddr( g_OleAut32Proc.SysStringLen, DLL_OLEAUT32, "SysStringLen" );
return ((SSL_CAST)g_OleAut32Proc.SysStringLen)(bstr);
}
typedef RE_OLEAUTAPI_(void, VI_CAST)(VARIANTARG *);
void CW32System::VariantInit ( VARIANTARG * pvarg )
{
if (g_OleAut32Proc.VariantInit == NULL)
SetProcAddr( g_OleAut32Proc.VariantInit, DLL_OLEAUT32, "VariantInit" );
((VI_CAST)g_OleAut32Proc.VariantInit)(pvarg);
}
#define RE_OLE32API(name) DECLSPEC_IMPORT HRESULT (STDAPICALLTYPE *name)
#define RE_OLE32API_(type, name) DECLSPEC_IMPORT type (STDAPICALLTYPE *name)
typedef RE_OLE32API(OCFD_CAST)(LPDATAOBJECT, REFIID, DWORD,
LPFORMATETC, LPOLECLIENTSITE,
LPSTORAGE, void **);
HRESULT CW32System::OleCreateFromData (
LPDATAOBJECT pDataObj,
REFIID riid,
DWORD renderopt,
LPFORMATETC pfetc,
LPOLECLIENTSITE pClientSite,
LPSTORAGE pStg,
void **ppvObj
)
{
if (g_Ole32Proc.OleCreateFromData == NULL)
SetProcAddr( g_Ole32Proc.OleCreateFromData, DLL_OLE32, "OleCreateFromData" );
return ((OCFD_CAST)g_Ole32Proc.OleCreateFromData)(pDataObj, riid, renderopt, pfetc, pClientSite, pStg, ppvObj);
}
typedef RE_OLE32API_(void, CTMF_CAST)(LPVOID);
void CW32System::CoTaskMemFree ( LPVOID pv )
{
if (g_Ole32Proc.CoTaskMemFree == NULL)
SetProcAddr( g_Ole32Proc.CoTaskMemFree, DLL_OLE32, "CoTaskMemFree" );
((CTMF_CAST)g_Ole32Proc.CoTaskMemFree)(pv);
}
typedef RE_OLE32API(CBC_CAST)(DWORD, LPBC *);
HRESULT CW32System::CreateBindCtx ( DWORD reserved, LPBC * ppbc )
{
if (g_Ole32Proc.CreateBindCtx == NULL)
SetProcAddr( g_Ole32Proc.CreateBindCtx, DLL_OLE32, "CreateBindCtx" );
return ((CBC_CAST)g_Ole32Proc.CreateBindCtx)(reserved, ppbc);
}
typedef RE_OLE32API_(HANDLE, ODD_CAST)(HANDLE, CLIPFORMAT, UINT);
HANDLE CW32System::OleDuplicateData ( HANDLE hSrc, CLIPFORMAT cfFormat, UINT uFlags )
{
if (g_Ole32Proc.OleDuplicateData == NULL)
SetProcAddr( g_Ole32Proc.OleDuplicateData, DLL_OLE32, "OleDuplicateData" );
return ((ODD_CAST)g_Ole32Proc.OleDuplicateData)(hSrc, cfFormat, uFlags);
}
typedef RE_OLE32API(CTAC_CAST)(REFCLSID, REFCLSID);
HRESULT CW32System::CoTreatAsClass ( REFCLSID clsidold, REFCLSID clsidnew )
{
if (g_Ole32Proc.CoTreatAsClass == NULL)
SetProcAddr( g_Ole32Proc.CoTreatAsClass, DLL_OLE32, "CoTreatAsClass" );
return ((CTAC_CAST)g_Ole32Proc.CoTreatAsClass)(clsidold, clsidnew);
}
typedef RE_OLE32API(PIFC_CAST)(REFCLSID, LPOLESTR *);
HRESULT CW32System::ProgIDFromCLSID ( REFCLSID clsid, LPOLESTR * lplpszProgId )
{
if (g_Ole32Proc.ProgIDFromCLSID == NULL)
SetProcAddr( g_Ole32Proc.ProgIDFromCLSID, DLL_OLE32, "ProgIDFromCLSID" );
return ((PIFC_CAST)g_Ole32Proc.ProgIDFromCLSID)(clsid, lplpszProgId);
}
typedef RE_OLE32API(OCITO_CAST)(LPSTORAGE, LPOLESTREAM);
HRESULT CW32System::OleConvertIStorageToOLESTREAM ( LPSTORAGE pstg, LPOLESTREAM lpolestream)
{
if (g_Ole32Proc.OleConvertIStorageToOLESTREAM == NULL)
SetProcAddr( g_Ole32Proc.OleConvertIStorageToOLESTREAM, DLL_OLE32, "OleConvertIStorageToOLESTREAM" );
return ((OCITO_CAST)g_Ole32Proc.OleConvertIStorageToOLESTREAM)(pstg, lpolestream);
}
typedef RE_OLE32API(OCITOX_CAST)(LPSTORAGE, CLIPFORMAT, LONG, LONG, DWORD, LPSTGMEDIUM, LPOLESTREAM);
HRESULT CW32System::OleConvertIStorageToOLESTREAMEx (
LPSTORAGE pstg,
CLIPFORMAT cf,
LONG lwidth,
LONG lheight,
DWORD dwsize,
LPSTGMEDIUM pmedium,
LPOLESTREAM lpolestream
)
{
if (g_Ole32Proc.OleConvertIStorageToOLESTREAMEx == NULL)
SetProcAddr( g_Ole32Proc.OleConvertIStorageToOLESTREAMEx, DLL_OLE32, "OleConvertIStorageToOLESTREAMEx" );
return ((OCITOX_CAST)g_Ole32Proc.OleConvertIStorageToOLESTREAMEx)
(pstg,cf, lwidth, lheight, dwsize, pmedium, lpolestream);
}
typedef RE_OLE32API(OS_CAST)(LPPERSISTSTORAGE, LPSTORAGE, BOOL);
HRESULT CW32System::OleSave ( LPPERSISTSTORAGE pPS, LPSTORAGE pstg, BOOL fSameAsLoad )
{
if (g_Ole32Proc.OleSave == NULL)
SetProcAddr( g_Ole32Proc.OleSave, DLL_OLE32, "OleSave" );
return ((OS_CAST)g_Ole32Proc.OleSave)(pPS, pstg, fSameAsLoad);
}
typedef RE_OLE32API(SCDOI_CAST)(ILockBytes *, DWORD, DWORD, IStorage **);
HRESULT CW32System::StgCreateDocfileOnILockBytes (
ILockBytes *plkbyt,
DWORD grfmode,
DWORD res,
IStorage **ppstg
)
{
if (g_Ole32Proc.StgCreateDocfileOnILockBytes == NULL)
SetProcAddr( g_Ole32Proc.StgCreateDocfileOnILockBytes, DLL_OLE32, "StgCreateDocfileOnILockBytes" );
return ((SCDOI_CAST)g_Ole32Proc.StgCreateDocfileOnILockBytes)(plkbyt, grfmode, res, ppstg);
}
typedef RE_OLE32API(CIOH_CAST)(HGLOBAL, BOOL, ILockBytes **);
HRESULT CW32System::CreateILockBytesOnHGlobal ( HGLOBAL hGlobal, BOOL fDel, ILockBytes **pplkbyt )
{
if (g_Ole32Proc.CreateILockBytesOnHGlobal == NULL)
SetProcAddr( g_Ole32Proc.CreateILockBytesOnHGlobal, DLL_OLE32, "CreateILockBytesOnHGlobal" );
return ((CIOH_CAST)g_Ole32Proc.CreateILockBytesOnHGlobal)(hGlobal, fDel, pplkbyt);
}
typedef RE_OLE32API(OCLTF_CAST)(LPCOLESTR, REFIID, DWORD, LPFORMATETC,
LPOLECLIENTSITE, LPSTORAGE, void **);
HRESULT CW32System::OleCreateLinkToFile(
LPCOLESTR pstr,
REFIID rid,
DWORD renderopt,
LPFORMATETC pfetc,
LPOLECLIENTSITE psite,
LPSTORAGE pstg,
void **ppstg
)
{
if (g_Ole32Proc.OleCreateLinkToFile == NULL)
SetProcAddr( g_Ole32Proc.OleCreateLinkToFile, DLL_OLE32, "OleCreateLinkToFile" );
return ((OCLTF_CAST)g_Ole32Proc.OleCreateLinkToFile)(pstr, rid, renderopt, pfetc, psite, pstg, ppstg);
}
typedef RE_OLE32API_(LPVOID, CTMA_CAST)(ULONG);
LPVOID CW32System::CoTaskMemAlloc ( ULONG cb )
{
if (g_Ole32Proc.CoTaskMemAlloc == NULL)
SetProcAddr( g_Ole32Proc.CoTaskMemAlloc, DLL_OLE32, "CoTaskMemAlloc" );
return ((CTMA_CAST)g_Ole32Proc.CoTaskMemAlloc)(cb);
}
typedef RE_OLE32API_(LPVOID, CTMR_CAST)(LPVOID, ULONG);
LPVOID CW32System::CoTaskMemRealloc ( LPVOID pv, ULONG cv)
{
if (g_Ole32Proc.CoTaskMemRealloc == NULL)
SetProcAddr( g_Ole32Proc.CoTaskMemRealloc, DLL_OLE32, "CoTaskMemRealloc" );
return ((CTMR_CAST)g_Ole32Proc.CoTaskMemRealloc)(pv, cv);
}
typedef RE_OLE32API(OI_CAST)(LPVOID);
HRESULT CW32System::OleInitialize ( LPVOID pvres )
{
if (g_Ole32Proc.OleInitialize == NULL)
SetProcAddr( g_Ole32Proc.OleInitialize, DLL_OLE32, "OleInitialize" );
return ((OI_CAST)g_Ole32Proc.OleInitialize)(pvres);
}
typedef RE_OLE32API_(void, OUI_CAST)( void );
void CW32System::OleUninitialize ( void )
{
if (g_Ole32Proc.OleUninitialize == NULL)
SetProcAddr( g_Ole32Proc.OleUninitialize, DLL_OLE32, "OleUninitialize" );
((OUI_CAST)g_Ole32Proc.OleUninitialize)();
}
typedef RE_OLE32API(OSC_CAST)(IDataObject *);
HRESULT CW32System::OleSetClipboard ( IDataObject *pdo )
{
if (g_Ole32Proc.OleSetClipboard == NULL)
SetProcAddr( g_Ole32Proc.OleSetClipboard, DLL_OLE32, "OleSetClipboard" );
return ((OSC_CAST)g_Ole32Proc.OleSetClipboard)(pdo);
}
typedef RE_OLE32API(OFC_CAST)(void);
HRESULT CW32System::OleFlushClipboard ( void )
{
if (g_Ole32Proc.OleFlushClipboard == NULL)
SetProcAddr( g_Ole32Proc.OleFlushClipboard, DLL_OLE32, "OleFlushClipboard" );
return ((OFC_CAST)g_Ole32Proc.OleFlushClipboard)();
}
typedef RE_OLE32API(OICC_CAST)(IDataObject *);
HRESULT CW32System::OleIsCurrentClipboard ( IDataObject *pdo )
{
if (g_Ole32Proc.OleIsCurrentClipboard == NULL)
SetProcAddr( g_Ole32Proc.OleIsCurrentClipboard, DLL_OLE32, "OleIsCurrentClipboard" );
return ((OICC_CAST)g_Ole32Proc.OleIsCurrentClipboard)(pdo);
}
typedef RE_OLE32API(DDD_CAST)(IDataObject *, IDropSource *,
DWORD, DWORD *);
HRESULT CW32System::DoDragDrop ( IDataObject *pdo, IDropSource *pds, DWORD dweffect, DWORD *pdweffect )
{
if (g_Ole32Proc.DoDragDrop == NULL)
SetProcAddr( g_Ole32Proc.DoDragDrop, DLL_OLE32, "DoDragDrop" );
return ((DDD_CAST)g_Ole32Proc.DoDragDrop)(pdo, pds, dweffect, pdweffect);
}
typedef RE_OLE32API(OGC_CAST)(IDataObject **);
HRESULT CW32System::OleGetClipboard ( IDataObject **ppdo )
{
if (g_Ole32Proc.OleGetClipboard == NULL)
SetProcAddr( g_Ole32Proc.OleGetClipboard, DLL_OLE32, "OleGetClipboard" );
return ((OGC_CAST)g_Ole32Proc.OleGetClipboard)(ppdo);
}
typedef RE_OLE32API(RDD_CAST)(HWND, IDropTarget *);
HRESULT CW32System::RegisterDragDrop ( HWND hwnd, IDropTarget *pdt )
{
if (g_Ole32Proc.RegisterDragDrop == NULL)
SetProcAddr( g_Ole32Proc.RegisterDragDrop, DLL_OLE32, "RegisterDragDrop" );
return ((RDD_CAST)g_Ole32Proc.RegisterDragDrop)(hwnd, pdt);
}
typedef RE_OLE32API(OCLFD_CAST)(IDataObject *, REFIID, DWORD,
LPFORMATETC, IOleClientSite *,
IStorage *, void **);
HRESULT CW32System::OleCreateLinkFromData (
IDataObject *pdo,
REFIID rid,
DWORD renderopt,
LPFORMATETC pfetc,
IOleClientSite *psite,
IStorage *pstg,
void **ppv
)
{
if (g_Ole32Proc.OleCreateLinkFromData == NULL)
SetProcAddr( g_Ole32Proc.OleCreateLinkFromData, DLL_OLE32, "OleCreateLinkFromData" );
return ((OCLFD_CAST)g_Ole32Proc.OleCreateLinkFromData)
(pdo, rid, renderopt, pfetc, psite, pstg, ppv);
}
typedef RE_OLE32API(OCSFD_CAST)(IDataObject *, REFIID, DWORD,
LPFORMATETC, IOleClientSite *,
IStorage *, void **);
HRESULT CW32System::OleCreateStaticFromData (
IDataObject *pdo,
REFIID rid,
DWORD renderopt,
LPFORMATETC pfetc,
IOleClientSite *psite,
IStorage *pstg,
void **ppv
)
{
if (g_Ole32Proc.OleCreateStaticFromData == NULL)
SetProcAddr( g_Ole32Proc.OleCreateStaticFromData, DLL_OLE32, "OleCreateStaticFromData" );
return ((OCSFD_CAST)g_Ole32Proc.OleCreateStaticFromData)
(pdo, rid, renderopt, pfetc, psite, pstg, ppv);
}
typedef RE_OLE32API(OD_CAST)(IUnknown *, DWORD, HDC, LPCRECT);
HRESULT CW32System::OleDraw ( IUnknown *punk, DWORD dwAspect, HDC hdc, LPCRECT prect )
{
if (g_Ole32Proc.OleDraw == NULL)
SetProcAddr( g_Ole32Proc.OleDraw, DLL_OLE32, "OleDraw" );
return ((OD_CAST)g_Ole32Proc.OleDraw)(punk, dwAspect, hdc, prect);
}
typedef RE_OLE32API(OSCO_CAST)(IUnknown *, BOOL);
HRESULT CW32System::OleSetContainedObject ( IUnknown *punk, BOOL fContained )
{
if (g_Ole32Proc.OleSetContainedObject == NULL)
SetProcAddr( g_Ole32Proc.OleSetContainedObject, DLL_OLE32, "OleSetContainedObject" );
return ((OSCO_CAST)g_Ole32Proc.OleSetContainedObject)(punk, fContained);
}
typedef RE_OLE32API(CDO_CAST)(IUnknown *, DWORD);
HRESULT CW32System::CoDisconnectObject ( IUnknown *punk, DWORD dwres )
{
if (g_Ole32Proc.CoDisconnectObject == NULL)
SetProcAddr( g_Ole32Proc.CoDisconnectObject, DLL_OLE32, "CoDisconnectObject" );
return ((CDO_CAST)g_Ole32Proc.CoDisconnectObject)(punk, dwres);
}
typedef RE_OLE32API(WFUTS_CAST)(IStorage *, CLIPFORMAT, LPOLESTR);
HRESULT CW32System::WriteFmtUserTypeStg ( IStorage *pstg, CLIPFORMAT cf, LPOLESTR pstr)
{
if (g_Ole32Proc.WriteFmtUserTypeStg == NULL)
SetProcAddr( g_Ole32Proc.WriteFmtUserTypeStg, DLL_OLE32, "WriteFmtUserTypeStg" );
return ((WFUTS_CAST)g_Ole32Proc.WriteFmtUserTypeStg)(pstg, cf, pstr);
}
typedef RE_OLE32API(WCS_CAST)(IStorage *, REFCLSID);
HRESULT CW32System::WriteClassStg ( IStorage *pstg, REFCLSID rid )
{
if (g_Ole32Proc.WriteClassStg == NULL)
SetProcAddr( g_Ole32Proc.WriteClassStg, DLL_OLE32, "WriteClassStg" );
return ((WCS_CAST)g_Ole32Proc.WriteClassStg)(pstg, rid);
}
typedef RE_OLE32API(SCS_CAST)(IStorage *, BOOL);
HRESULT CW32System::SetConvertStg ( IStorage *pstg, BOOL fConv )
{
if (g_Ole32Proc.SetConvertStg == NULL)
SetProcAddr( g_Ole32Proc.SetConvertStg, DLL_OLE32, "SetConvertStg" );
return ((SCS_CAST)g_Ole32Proc.SetConvertStg)(pstg, fConv);
}
typedef RE_OLE32API(RFUTS_CAST)(IStorage *, CLIPFORMAT *, LPOLESTR *);
HRESULT CW32System::ReadFmtUserTypeStg ( IStorage *pstg, CLIPFORMAT *pcf, LPOLESTR *pstr )
{
if (g_Ole32Proc.ReadFmtUserTypeStg == NULL)
SetProcAddr( g_Ole32Proc.ReadFmtUserTypeStg, DLL_OLE32, "ReadFmtUserTypeStg" );
return ((RFUTS_CAST)g_Ole32Proc.ReadFmtUserTypeStg)(pstg, pcf, pstr);
}
typedef RE_OLE32API(RCS_CAST)(IStorage *, CLSID *);
HRESULT CW32System::ReadClassStg ( IStorage *pstg, CLSID *pclsid )
{
if (g_Ole32Proc.ReadClassStg == NULL)
SetProcAddr( g_Ole32Proc.ReadClassStg, DLL_OLE32, "ReadClassStg" );
return ((RCS_CAST)g_Ole32Proc.ReadClassStg)(pstg, pclsid);
}
typedef RE_OLE32API(OR_CAST)(IUnknown *);
HRESULT CW32System::OleRun ( IUnknown *punk )
{
if (g_Ole32Proc.OleRun == NULL)
SetProcAddr( g_Ole32Proc.OleRun, DLL_OLE32, "OleRun" );
return ((OR_CAST)g_Ole32Proc.OleRun)(punk);
}
typedef RE_OLE32API(RevDD_CAST)(HWND);
HRESULT CW32System::RevokeDragDrop ( HWND hwnd )
{
if (g_Ole32Proc.RevokeDragDrop == NULL)
SetProcAddr( g_Ole32Proc.RevokeDragDrop, DLL_OLE32, "RevokeDragDrop" );
return ((RevDD_CAST)g_Ole32Proc.RevokeDragDrop)(hwnd);
}
typedef RE_OLE32API(CSOH_CAST)(HGLOBAL, BOOL, IStream **);
HRESULT CW32System::CreateStreamOnHGlobal ( HGLOBAL hglobal, BOOL fDel, IStream **ppstrm )
{
if (g_Ole32Proc.CreateStreamOnHGlobal == NULL)
SetProcAddr( g_Ole32Proc.CreateStreamOnHGlobal, DLL_OLE32, "CreateStreamOnHGlobal" );
return ((CSOH_CAST)g_Ole32Proc.CreateStreamOnHGlobal)(hglobal, fDel, ppstrm);
}
typedef RE_OLE32API(GHFS_CAST)(IStream *, HGLOBAL *);
HRESULT CW32System::GetHGlobalFromStream ( IStream *pstrm, HGLOBAL *phglobal )
{
if (g_Ole32Proc.GetHGlobalFromStream == NULL)
SetProcAddr( g_Ole32Proc.GetHGlobalFromStream, DLL_OLE32, "GetHGlobalFromStream" );
return ((GHFS_CAST)g_Ole32Proc.GetHGlobalFromStream)(pstrm, phglobal);
}
typedef RE_OLE32API(OCDH_CAST)(REFCLSID, IUnknown *, REFIID, void **);
HRESULT CW32System::OleCreateDefaultHandler (
REFCLSID clsid,
IUnknown *punk,
REFIID riid,
void **ppv
)
{
if (g_Ole32Proc.OleCreateDefaultHandler == NULL)
SetProcAddr( g_Ole32Proc.OleCreateDefaultHandler, DLL_OLE32, "OleCreateDefaultHandler" );
return ((OCDH_CAST)g_Ole32Proc.OleCreateDefaultHandler)(clsid, punk, riid, ppv);
}
typedef RE_OLE32API(CFPI_CAST)(LPCOLESTR, LPCLSID);
HRESULT CW32System::CLSIDFromProgID ( LPCOLESTR pstr, LPCLSID pclsid )
{
if (g_Ole32Proc.CLSIDFromProgID == NULL)
SetProcAddr( g_Ole32Proc.CLSIDFromProgID, DLL_OLE32, "CLSIDFromProgID" );
return ((CFPI_CAST)g_Ole32Proc.CLSIDFromProgID)(pstr, pclsid);
}
typedef RE_OLE32API(OCOTI_CAST)(LPOLESTREAM, IStorage *,
const DVTARGETDEVICE *);
HRESULT CW32System::OleConvertOLESTREAMToIStorage (
LPOLESTREAM pstrm,
IStorage *pstg,
const DVTARGETDEVICE *ptd
)
{
if (g_Ole32Proc.OleConvertOLESTREAMToIStorage == NULL)
SetProcAddr( g_Ole32Proc.OleConvertOLESTREAMToIStorage, DLL_OLE32, "OleConvertOLESTREAMToIStorage" );
return ((OCOTI_CAST)g_Ole32Proc.OleConvertOLESTREAMToIStorage)(pstrm, pstg, ptd);
}
typedef RE_OLE32API(OL_CAST)(IStorage *, REFIID, IOleClientSite *, void **);
HRESULT CW32System::OleLoad (
IStorage *pstg,
REFIID riid,
IOleClientSite *psite,
void **ppv
)
{
if (g_Ole32Proc.OleLoad == NULL)
SetProcAddr( g_Ole32Proc.OleLoad, DLL_OLE32, "OleLoad" );
return ((OL_CAST)g_Ole32Proc.OleLoad)(pstg, riid, psite, ppv);
}
typedef RE_OLE32API(RSM_CAST)(LPSTGMEDIUM);
HRESULT CW32System::ReleaseStgMedium ( LPSTGMEDIUM pmedium )
{
if (g_Ole32Proc.ReleaseStgMedium == NULL)
SetProcAddr( g_Ole32Proc.ReleaseStgMedium, DLL_OLE32, "ReleaseStgMedium" );
return ((RSM_CAST)g_Ole32Proc.ReleaseStgMedium)(pmedium);
}
typedef RE_OLE32API(CCI_CAST)(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID);
HRESULT CW32System::CoCreateInstance (REFCLSID rclsid, LPUNKNOWN pUnknown,
DWORD dwClsContext, REFIID riid, LPVOID *ppv)
{
if (g_Ole32Proc.CoCreateInstance == NULL)
SetProcAddr( g_Ole32Proc.CoCreateInstance, DLL_OLE32, "CoCreateInstance" );
return ((CCI_CAST)g_Ole32Proc.CoCreateInstance)(rclsid, pUnknown, dwClsContext, riid, ppv);
}
BOOL CW32System::ImmInitialize( void )
{
// MAC Only function.
return FALSE;
}
void CW32System::ImmTerminate( void )
{
// MAC only function.
return;
}
#ifndef NOACCESSIBILITY
typedef HRESULT (WINAPI *ACC_VC_CAST)(VARIANTARG FAR*, VARIANTARG FAR*);
HRESULT CW32System::VariantCopy(VARIANTARG FAR* pvargDest, VARIANTARG FAR* pvargSrc)
{
static void *pVariantCopy = NULL;
if (pVariantCopy == NULL)
SetProcAddr( pVariantCopy, DLL_OLEAUT32, "VariantCopy" );
if (pVariantCopy)
return ((ACC_VC_CAST)pVariantCopy)(pvargDest, pvargSrc);
return (E_NOINTERFACE);
}
typedef LRESULT (WINAPI *ACC_LFO_CAST)(REFIID, WPARAM, LPUNKNOWN);
LRESULT CW32System::LResultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN punk)
{
static void *pLResultFromObject = NULL;
if (pLResultFromObject == NULL)
SetProcAddr( pLResultFromObject, DLL_ACC, "LresultFromObject" );
if (pLResultFromObject)
return ((ACC_LFO_CAST)pLResultFromObject)(riid, wParam, punk);
return E_NOINTERFACE;
}
typedef HRESULT (WINAPI *ACC_AOFW_CAST)(HWND, DWORD, REFIID, void **);
HRESULT CW32System::AccessibleObjectFromWindow (HWND hWnd, DWORD dwID, REFIID riidInterface, void ** ppvObject)
{
static void *pAccessibleObjectFromWindow = NULL;
if (pAccessibleObjectFromWindow == NULL)
SetProcAddr( pAccessibleObjectFromWindow, DLL_ACC, "AccessibleObjectFromWindow" );
if (pAccessibleObjectFromWindow)
return ((ACC_AOFW_CAST)pAccessibleObjectFromWindow)(hWnd, dwID, riidInterface, ppvObject);
return (E_NOINTERFACE);
}
typedef BOOL (WINAPI *ACC_BI_CAST)(BOOL);
BOOL CW32System::BlockInput (BOOL fBlock)
{
static void *pBlockInput = NULL;
if (pBlockInput == NULL)
SetProcAddr( pBlockInput, DLL_USER32, "BlockInput" );
if (pBlockInput)
return ((ACC_BI_CAST)pBlockInput)(fBlock);
return FALSE;
}
typedef UINT (WINAPI *ACC_SI_CAST)(UINT, LPINPUT, int);
UINT CW32System::SendInput (UINT nInputs, LPINPUT pInputs, int cbSize)
{
static void *pSendInput = NULL;
if (pSendInput == NULL)
SetProcAddr( pSendInput, DLL_USER32, "SendInput" );
if (pSendInput)
return ((ACC_SI_CAST)pSendInput)(nInputs, pInputs, cbSize);
return 0;
}
typedef VOID (WINAPI *ACC_NWE_CAST)(DWORD, HWND, LONG, LONG);
VOID CW32System::NotifyWinEvent(DWORD dwEvent, HWND hWnd, LONG lObjectType, LONG lObjectId)
{
static void *pNotfiyWinEvent = NULL;
if (pNotfiyWinEvent == INVALID_HANDLE_VALUE)
return;
if (pNotfiyWinEvent == NULL)
SetProcAddr( pNotfiyWinEvent, DLL_USER32, "NotifyWinEvent" );
if (pNotfiyWinEvent)
((ACC_NWE_CAST)pNotfiyWinEvent)(dwEvent, hWnd, lObjectType, lObjectId);
else
pNotfiyWinEvent = INVALID_HANDLE_VALUE;
}
#endif
typedef LONG (WINAPI*IGCSA_CAST)(HIMC, DWORD, LPVOID, DWORD);
LONG CW32System::ImmGetCompositionStringA (
HIMC hIMC,
DWORD dwIndex,
LPVOID lpBuf,
DWORD dwBufLen,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
LONG lCopied = 0;
hResult = pAIMM->GetCompositionStringA(hIMC, dwIndex, dwBufLen, &lCopied, lpBuf);
return (SUCCEEDED(hResult) ? lCopied : 0);
}
if (g_IMM32Proc.ImmGetCompositionStringA == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmGetCompositionStringA, DLL_IMM32, "ImmGetCompositionStringA" );
return ((IGCSA_CAST)g_IMM32Proc.ImmGetCompositionStringA)(hIMC, dwIndex, lpBuf, dwBufLen);
}
typedef LONG (WINAPI*IGCSW_CAST)(HIMC, DWORD, LPVOID, DWORD);
LONG CW32System::ImmGetCompositionStringW (
HIMC hIMC,
DWORD dwIndex,
LPVOID lpBuf,
DWORD dwBufLen,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
LONG lCopied = 0;
hResult = pAIMM->GetCompositionStringW(hIMC, dwIndex, dwBufLen, &lCopied, lpBuf);
return (SUCCEEDED(hResult) ? lCopied : 0);
}
if (g_IMM32Proc.ImmGetCompositionStringW == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmGetCompositionStringW, DLL_IMM32, "ImmGetCompositionStringW" );
return ((IGCSW_CAST)g_IMM32Proc.ImmGetCompositionStringW)(hIMC, dwIndex, lpBuf, dwBufLen);
}
typedef HIMC (WINAPI*IGC_CAST)(HWND);
HIMC CW32System::ImmGetContext ( HWND hWnd )
{
if (IsAIMMLoaded())
{
HRESULT hResult;
HIMC hIMC = 0;
hResult = pAIMM->GetContext(hWnd, &hIMC);
return (SUCCEEDED(hResult) ? hIMC : 0);
}
if (g_IMM32Proc.ImmGetContext == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmGetContext, DLL_IMM32, "ImmGetContext" );
return ((IGC_CAST)g_IMM32Proc.ImmGetContext)(hWnd);
}
typedef BOOL (WINAPI*ISCFA_CAST)(HIMC, LPLOGFONTA);
BOOL CW32System::ImmSetCompositionFontA (
HIMC hIMC,
LPLOGFONTA lpLogFontA,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
hResult = pAIMM->SetCompositionFontA(hIMC, lpLogFontA);
return (SUCCEEDED(hResult));
}
if (g_IMM32Proc.ImmSetCompositionFontA == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmSetCompositionFontA, DLL_IMM32, "ImmSetCompositionFontA" );
return ((ISCFA_CAST)g_IMM32Proc.ImmSetCompositionFontA)(hIMC, lpLogFontA);
}
typedef BOOL (WINAPI*ISCW_CAST)(HIMC, LPCOMPOSITIONFORM);
BOOL CW32System::ImmSetCompositionWindow (
HIMC hIMC,
LPCOMPOSITIONFORM lpCompForm,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
hResult = pAIMM->SetCompositionWindow(hIMC, lpCompForm);
return (SUCCEEDED(hResult));
}
if (g_IMM32Proc.ImmSetCompositionWindow == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmSetCompositionWindow, DLL_IMM32, "ImmSetCompositionWindow" );
return ((ISCW_CAST)g_IMM32Proc.ImmSetCompositionWindow)(hIMC, lpCompForm);
}
typedef BOOL (WINAPI*IRC_CAST)(HWND, HIMC);
BOOL CW32System::ImmReleaseContext (
HWND hWnd,
HIMC hIMC)
{
if (IsAIMMLoaded())
{
HRESULT hResult;
hResult = pAIMM->ReleaseContext(hWnd, hIMC);
return (SUCCEEDED(hResult));
}
if (g_IMM32Proc.ImmReleaseContext == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmReleaseContext, DLL_IMM32, "ImmReleaseContext" );
return ((IRC_CAST)g_IMM32Proc.ImmReleaseContext)(hWnd, hIMC);
}
typedef DWORD (WINAPI*IGP_CAST)(HKL, DWORD);
DWORD CW32System::ImmGetProperty (
HKL hKL,
DWORD dwIndex,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
DWORD dwProperties=0;
hResult = pAIMM->GetProperty(hKL, dwIndex, &dwProperties);
return (SUCCEEDED(hResult) ? dwProperties : 0);
}
if (g_IMM32Proc.ImmGetProperty == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmGetProperty, DLL_IMM32, "ImmGetProperty" );
return ((IGP_CAST)g_IMM32Proc.ImmGetProperty)(hKL, dwIndex);
}
typedef BOOL (WINAPI*IGCW_CAST)(HIMC, DWORD, LPCANDIDATEFORM);
BOOL CW32System::ImmGetCandidateWindow (
HIMC hIMC,
DWORD dwIndex,
LPCANDIDATEFORM lpCandidate,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
hResult = pAIMM->GetCandidateWindow(hIMC, dwIndex, lpCandidate);
return (SUCCEEDED(hResult));
}
if (g_IMM32Proc.ImmGetCandidateWindow == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmGetCandidateWindow, DLL_IMM32, "ImmGetCandidateWindow" );
return ((IGCW_CAST)g_IMM32Proc.ImmGetCandidateWindow)(hIMC, dwIndex, lpCandidate);
}
typedef BOOL (WINAPI*ISCAW_CAST)(HIMC, LPCANDIDATEFORM);
BOOL CW32System::ImmSetCandidateWindow (
HIMC hIMC,
LPCANDIDATEFORM lpCandidate ,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
hResult = pAIMM->SetCandidateWindow(hIMC, lpCandidate);
return (SUCCEEDED(hResult));
}
if (g_IMM32Proc.ImmSetCandidateWindow == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmSetCandidateWindow, DLL_IMM32, "ImmSetCandidateWindow" );
return ((ISCAW_CAST)g_IMM32Proc.ImmSetCandidateWindow)(hIMC, lpCandidate);
}
typedef BOOL (WINAPI*INIME_CAST)(HIMC, DWORD, DWORD, DWORD);
BOOL CW32System::ImmNotifyIME (
HIMC hIMC,
DWORD dwAction,
DWORD dwIndex,
DWORD dwValue,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
hResult = pAIMM->NotifyIME(hIMC, dwAction, dwIndex, dwValue);
return (SUCCEEDED(hResult));
}
if (g_IMM32Proc.ImmNotifyIME == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmNotifyIME, DLL_IMM32, "ImmNotifyIME" );
return ((INIME_CAST)g_IMM32Proc.ImmNotifyIME)(hIMC, dwAction, dwIndex, dwValue);
}
typedef HIMC (WINAPI*IAC_CAST)(HWND, HIMC);
HIMC CW32System::ImmAssociateContext (
HWND hWnd,
HIMC hIMC,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
HIMC hPreviousIMC=0;
hResult = pAIMM->AssociateContext(hWnd, hIMC, &hPreviousIMC);
return (SUCCEEDED(hResult) ? hPreviousIMC : 0);
}
if (g_IMM32Proc.ImmAssociateContext == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmAssociateContext, DLL_IMM32, "ImmAssociateContext" );
return ((IAC_CAST)g_IMM32Proc.ImmAssociateContext)(hWnd, hIMC);
}
typedef UINT (WINAPI*IGVK_CAST)(HWND);
UINT CW32System::ImmGetVirtualKey (
HWND hWnd,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
UINT uVirtualKey=0;
hResult = pAIMM->GetVirtualKey(hWnd, &uVirtualKey);
return (SUCCEEDED(hResult) ? uVirtualKey : 0);
}
if (g_IMM32Proc.ImmGetVirtualKey == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmGetVirtualKey, DLL_IMM32, "ImmGetVirtualKey" );
return ((IGVK_CAST)g_IMM32Proc.ImmGetVirtualKey)(hWnd);
}
// NOTE: We only use ImmEscape for IME_ESC_HANJA_MODE.
// Need to fix up if other methods are used.
typedef HIMC (WINAPI*IES_CAST)(HKL, HIMC, UINT, LPVOID );
HIMC CW32System::ImmEscape (
HKL hKL,
HIMC hIMC,
UINT uEscape,
LPVOID lpData,
BOOL bAimmActivated)
{
char szaHangeul[3] = {0, 0, 0};
// Aimm only support A version..
if (!OnWin9x() && !bAimmActivated)
goto USE_W_VERSION;
if (MbcsFromUnicode(szaHangeul, sizeof(szaHangeul),
(LPCWSTR)lpData, 1, CP_KOREAN, UN_NOOBJECTS) <= 0)
return FALSE;
if (bAimmActivated)
{
HRESULT hResult;
LRESULT lResult=0;
hResult = pAIMM->EscapeA(hKL, hIMC, uEscape, (LPVOID)szaHangeul, &lResult);
return (SUCCEEDED(hResult) ? (HIMC)lResult : 0);
}
if (g_IMM32Proc.ImmEscapeA == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmEscapeA, DLL_IMM32, "ImmEscapeA" );
return ((IES_CAST)g_IMM32Proc.ImmEscapeA)(hKL, hIMC, uEscape, (LPVOID)szaHangeul);
USE_W_VERSION:
if (g_IMM32Proc.ImmEscapeW == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmEscapeW, DLL_IMM32, "ImmEscapeW" );
return ((IES_CAST)g_IMM32Proc.ImmEscapeW)(hKL, hIMC, uEscape, lpData);
}
typedef BOOL (WINAPI*IGOS_CAST)(HIMC);
BOOL CW32System::ImmGetOpenStatus (
HIMC hIMC,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
// AIMM is returning S_OK for OpenStatus == TRUE.
hResult = pAIMM->GetOpenStatus(hIMC);
return (hResult == S_OK);
}
if (g_IMM32Proc.ImmGetOpenStatus == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmGetOpenStatus, DLL_IMM32, "ImmGetOpenStatus" );
return ((IGOS_CAST)g_IMM32Proc.ImmGetOpenStatus)(hIMC);
}
typedef BOOL (WINAPI*ISOS_CAST)(HIMC, BOOL);
BOOL CW32System::ImmSetOpenStatus (
HIMC hIMC,
BOOL fOpen,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
hResult = pAIMM->SetOpenStatus(hIMC, fOpen);
return (SUCCEEDED(hResult));
}
if (g_IMM32Proc.ImmSetOpenStatus == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmSetOpenStatus, DLL_IMM32, "ImmSetOpenStatus" );
return ((ISOS_CAST)g_IMM32Proc.ImmSetOpenStatus)(hIMC, fOpen);
}
typedef BOOL (WINAPI*IGCS_CAST)(HIMC , LPDWORD , LPDWORD );
BOOL CW32System::ImmGetConversionStatus (
HIMC hIMC,
LPDWORD pdwConversion,
LPDWORD pdwSentence,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
hResult = pAIMM->GetConversionStatus(hIMC, pdwConversion, pdwSentence);
return (SUCCEEDED(hResult));
}
if (g_IMM32Proc.ImmGetConversionStatus == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmGetConversionStatus, DLL_IMM32, "ImmGetConversionStatus" );
return ((IGCS_CAST)g_IMM32Proc.ImmGetConversionStatus)(hIMC, pdwConversion, pdwSentence);
}
typedef BOOL (WINAPI*ISCS_CAST)(HIMC , DWORD , DWORD );
BOOL CW32System::ImmSetConversionStatus (
HIMC hIMC,
DWORD dwConversion,
DWORD dwSentence,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
hResult = pAIMM->SetConversionStatus(hIMC, dwConversion, dwSentence);
return (SUCCEEDED(hResult));
}
if (g_IMM32Proc.ImmSetConversionStatus == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmSetConversionStatus, DLL_IMM32, "ImmSetConversionStatus" );
return ((ISCS_CAST)g_IMM32Proc.ImmSetConversionStatus)(hIMC, dwConversion, dwSentence);
}
typedef HWND (WINAPI*IGDW_CAST)( HWND );
HWND CW32System::ImmGetDefaultIMEWnd (
HWND hWnd,
BOOL bAimmActivated)
{
if (bAimmActivated)
{
HRESULT hResult;
HWND hIMEWnd;
hResult = pAIMM->GetDefaultIMEWnd(hWnd, &hIMEWnd);
return SUCCEEDED(hResult) ? hIMEWnd : NULL;
}
if (g_IMM32Proc.ImmGetDefaultIMEWnd == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmGetDefaultIMEWnd, DLL_IMM32, "ImmGetDefaultIMEWnd" );
return ((IGDW_CAST)g_IMM32Proc.ImmGetDefaultIMEWnd)(hWnd);
}
typedef BOOL (WINAPI*ISCSW_CAST)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD);
BOOL CW32System::ImmSetCompositionStringW (
HIMC hIMC,
DWORD dwIndex,
LPVOID lpBuf,
DWORD dwBufLen,
LPVOID lpRead,
DWORD dwReadLen)
{
if (g_IMM32Proc.ImmSetCompositionStringW == NULL)
SetIMEProcAddr( g_IMM32Proc.ImmSetCompositionStringW, DLL_IMM32, "ImmSetCompositionStringW" );
return ((ISCSW_CAST)g_IMM32Proc.ImmSetCompositionStringW)(hIMC, dwIndex, lpBuf, dwBufLen, lpRead, dwReadLen);
}
typedef IMESHAREAPI BOOL (*FSS_CAST)(UINT, UINT);
BOOL CW32System::FSupportSty ( UINT uSty, UINT uStyAltered)
{
if (g_IMEShareProc.FSupportSty == NULL)
SetIMEProcAddr( g_IMEShareProc.FSupportSty, DLL_IMESHARE, "FSupportSty" );
return ((FSS_CAST)g_IMEShareProc.FSupportSty)(uSty, uStyAltered);
}
typedef IMESHAREAPI const IMESTYLE * (IMECDECL*PISFA_CAST)(const UINT);
const IMESTYLE * CW32System::PIMEStyleFromAttr ( const UINT uAttr)
{
if (g_IMEShareProc.PIMEStyleFromAttr == NULL)
SetIMEProcAddr( g_IMEShareProc.PIMEStyleFromAttr, DLL_IMESHARE, "PIMEStyleFromAttr" );
return ((PISFA_CAST)g_IMEShareProc.PIMEStyleFromAttr)( uAttr );
}
typedef IMESHAREAPI const IMECOLORSTY * (IMECDECL*PCSTFIS_CAST)(const IMESTYLE *);
const IMECOLORSTY * CW32System::PColorStyleTextFromIMEStyle ( const IMESTYLE * pIMEStyle)
{
if (g_IMEShareProc.PColorStyleTextFromIMEStyle == NULL)
SetIMEProcAddr( g_IMEShareProc.PColorStyleTextFromIMEStyle, DLL_IMESHARE, "PColorStyleTextFromIMEStyle" );
return ((PCSTFIS_CAST)g_IMEShareProc.PColorStyleTextFromIMEStyle)( pIMEStyle );
}
typedef IMESHAREAPI const IMECOLORSTY * (IMECDECL*PCSBFIS_CAST)(const IMESTYLE *);
const IMECOLORSTY * CW32System::PColorStyleBackFromIMEStyle ( const IMESTYLE * pIMEStyle)
{
if (g_IMEShareProc.PColorStyleBackFromIMEStyle == NULL)
SetIMEProcAddr( g_IMEShareProc.PColorStyleBackFromIMEStyle, DLL_IMESHARE, "PColorStyleBackFromIMEStyle" );
return ((PCSBFIS_CAST)g_IMEShareProc.PColorStyleBackFromIMEStyle)( pIMEStyle );
}
typedef IMESHAREAPI BOOL (IMECDECL*FBIS_CAST)(const IMESTYLE *);
BOOL CW32System::FBoldIMEStyle ( const IMESTYLE * pIMEStyle)
{
if (g_IMEShareProc.FBoldIMEStyle == NULL)
SetIMEProcAddr( g_IMEShareProc.FBoldIMEStyle, DLL_IMESHARE, "FBoldIMEStyle" );
return ((FBIS_CAST)g_IMEShareProc.FBoldIMEStyle)( pIMEStyle );
}
typedef IMESHAREAPI BOOL (IMECDECL*FIIS_CAST)(const IMESTYLE * );
BOOL CW32System::FItalicIMEStyle ( const IMESTYLE * pIMEStyle)
{
if (g_IMEShareProc.FItalicIMEStyle == NULL)
SetIMEProcAddr( g_IMEShareProc.FItalicIMEStyle, DLL_IMESHARE, "FItalicIMEStyle" );
return ((FIIS_CAST)g_IMEShareProc.FItalicIMEStyle)( pIMEStyle );
}
typedef IMESHAREAPI BOOL (IMECDECL*FUIS_CAST)(const IMESTYLE *);
BOOL CW32System::FUlIMEStyle ( const IMESTYLE * pIMEStyle)
{
if (g_IMEShareProc.FUlIMEStyle == NULL)
SetIMEProcAddr( g_IMEShareProc.FUlIMEStyle, DLL_IMESHARE, "FUlIMEStyle" );
return ((FUIS_CAST)g_IMEShareProc.FUlIMEStyle)( pIMEStyle );
}
typedef IMESHAREAPI UINT (IMECDECL*IUIS_CAST)(const IMESTYLE *);
UINT CW32System::IdUlIMEStyle ( const IMESTYLE * pIMEStyle)
{
if (g_IMEShareProc.IdUlIMEStyle == NULL)
SetIMEProcAddr( g_IMEShareProc.IdUlIMEStyle, DLL_IMESHARE, "IdUlIMEStyle" );
return ((IUIS_CAST)g_IMEShareProc.IdUlIMEStyle)( pIMEStyle );;
}
typedef IMESHAREAPI COLORREF (IMECDECL*RFICS_CAST)(const IMECOLORSTY *);
COLORREF CW32System::RGBFromIMEColorStyle ( const IMECOLORSTY * pColorStyle )
{
if (g_IMEShareProc.RGBFromIMEColorStyle == NULL)
SetIMEProcAddr( g_IMEShareProc.RGBFromIMEColorStyle, DLL_IMESHARE, "RGBFromIMEColorStyle" );
return ((RFICS_CAST)g_IMEShareProc.RGBFromIMEColorStyle)( pColorStyle );
}
CONVERTMODE WINAPI CW32System::DetermineConvertMode( HDC hdc, BYTE tmCharSet )
{
CONVERTMODE cm = CVT_NONE;
// Some fonts have problems under Win95 with the GetCharWidthW call; this
// is a simple heuristic to determine if this problem exists.
if (OnWin9x())
{
INT widthA, widthW;
BOOL fResA, fResW;
// FE font on Non-FE Win95 cannot use
// GetCharWidthW and ExtTextOutW
if(IsFECharSet(tmCharSet) && OnWin95FE())
// always use ANSI call for DBC fonts.
cm = CVT_WCTMB;
else
{
fResA = GetCharWidthA( hdc, ' ', ' ', &widthA );
fResW = GetCharWidthW( hdc, L' ', L' ', &widthW );
if ( fResA && fResW && widthA != widthW )
cm = CVT_WCTMB;
else
{
fResA = GetCharWidthA( hdc, 'a', 'a', &widthA );
fResW = GetCharWidthW( hdc, L'a', L'a', &widthW );
if ( fResA && fResW && widthA != widthW )
cm = CVT_WCTMB;
}
}
}
return cm;
}
void WINAPI CW32System::CalcUnderlineInfo(HDC hdc, CCcs *pcccs, TEXTMETRIC *ptm )
{
OUTLINETEXTMETRICA *potm;
unsigned cb;
CTempBuf tb;
if (ptm->tmPitchAndFamily & TMPF_TRUETYPE)
{
cb = GetOutlineTextMetricsA(hdc, 0, NULL);
if ((cb != 0)
&& ((potm = (OUTLINETEXTMETRICA *) tb.GetBuf(cb)) != NULL)
&& GetOutlineTextMetricsA(hdc, cb, potm))
{
pcccs->_dyULOffset = -potm->otmsUnderscorePosition;
pcccs->_dyULWidth = (short) max(1, potm->otmsUnderscoreSize);
pcccs->_dySOOffset = -potm->otmsStrikeoutPosition;
pcccs->_dySOWidth = (short) max(1, (int)potm->otmsStrikeoutSize);
return;
}
}
// Default calculation of size of underline
SHORT dyDescent = pcccs->_yDescent;
if (0 == dyDescent)
{
dyDescent = pcccs->_yHeight >> 3;
}
pcccs->_dyULWidth = (short) max(1, dyDescent / 4);
pcccs->_dyULOffset = (dyDescent - 3 * pcccs->_dyULWidth + 1) / 2;
if ((0 == pcccs->_dyULOffset) && (dyDescent > 1))
{
pcccs->_dyULOffset = 1;
}
pcccs->_dySOOffset = -ptm->tmAscent / 3;
pcccs->_dySOWidth = pcccs->_dyULWidth;
return;
}
BOOL WINAPI CW32System::ShowScrollBar( HWND hWnd, int wBar, BOOL bShow, LONG )
{
return ::ShowScrollBar( hWnd, wBar, bShow );
}
BOOL WINAPI CW32System::EnableScrollBar( HWND hWnd, UINT wSBflags, UINT wArrows )
{
return ::EnableScrollBar( hWnd, wSBflags, wArrows );
}
/*
* ReExtTextOutW(uiCodePage, hdc, x, y, fuOptions, lprc, lpString, cch ,lpDx, uiCodePage)
*
* @mfunc
* Patch around the Win95 FE bug and MetaFile problem.
*
* @rdesc
* Returns whatever ExtTextOut returns
*/
BOOL ReExtTextOutW(
HDC hdc, //@parm handle to device context
int xp, //@parm x-coordinate of reference point
int yp, //@parm y-coordinate of reference point
UINT fuOptions, //@parm text-output options
CONST RECT *lprect, //@parm optional clipping and/or opaquing rectangle
const WCHAR *lpwchString, //@parm points to string
UINT cchCount, //@parm number of characters in string
CONST INT *lpDx, //@parm Ptr to array of intercharacter spacing values
UINT uiCodePage) //@parm CodePage for converting to Ansi
{
// This is a portion of Word code adapted for our needs.
// This is a work around for Win95FE bugs that cause GPFs in GDI if multiple
// characters above Unicode 0x7F are passed to ExtTextOutW.
// Also, when uiCodePage is non-zero, we want to output all characters using
// ExtTextOutA - each character at a time.
Assert(lpDx);
int cch;
const WCHAR *lpwchT = lpwchString;
const WCHAR *lpwchStart = lpwchT;
const WCHAR *lpwchEnd = lpwchString + cchCount;
CONST int *lpdxpCur;
BOOL fRet = 0;
while (lpwchT < lpwchEnd)
{
// characters less than 0x007F do not need special treatment
// we output then in contiguous runs
if (*lpwchT > 0x007F || uiCodePage)
{
if ((cch = lpwchT - lpwchStart) > 0)
{
lpdxpCur = lpDx + (lpwchStart - lpwchString);
// Output the run of chars less than 0x7F
fRet = ExtTextOutW(hdc, xp, yp, fuOptions, lprect, lpwchStart, cch, lpdxpCur);
if (!fRet)
return fRet;
fuOptions &= ~ETO_OPAQUE; // Don't erase mutliple times!!!
// Advance
while (cch--)
xp += *lpdxpCur++;
lpwchStart = lpwchT;
}
// Output chars above 0x7F one at a time to prevent Win95 FE GPF
lpdxpCur = lpDx + (lpwchStart - lpwchString);
if (uiCodePage)
{
// Need to convert to Ansi and use ExtTextOutA
char chAnsi[2];
int cbConv = WideCharToMultiByte(uiCodePage, 0, lpwchStart, 1,
chAnsi, 2, NULL, NULL);
if (cbConv <= 0)
{
chAnsi[0] = '?';
cbConv = 1;
}
fRet = ExtTextOutA(hdc, xp, yp, fuOptions, lprect, chAnsi, cbConv, lpdxpCur);
}
else
fRet = ExtTextOutW(hdc, xp, yp, fuOptions, lprect, lpwchStart, 1, lpdxpCur);
if (!fRet)
return fRet;
fuOptions &= ~ETO_OPAQUE; // Don't erase multiple times!!!
// Advance
if (lpdxpCur)
xp += *lpdxpCur;
lpwchStart++;
}
lpwchT++;
}
// output the final run; also, if we were called with cchCount == 0,
// make a call here to erase the rectangle
if ((cch = lpwchT - lpwchStart) > 0 || !cchCount)
fRet = ExtTextOutW(hdc, xp, yp, fuOptions, lprect, lpwchStart, cch, lpDx + (lpwchStart - lpwchString));
return fRet;
}
void WINAPI CW32System::REExtTextOut(
CONVERTMODE cm,
UINT uiCodePage,
HDC hdc,
int x,
int y,
UINT fuOptions,
CONST RECT *lprc,
const WCHAR *lpString,
UINT cch,
CONST INT *lpDx,
BOOL FEFontOnNonFEWin9x
)
{
bool fConvert = false;
BOOL fForceGdiFont = FALSE;
HFONT hfont = NULL, hfontCur = NULL;
// In order to get the EURO character to print, we need to force the
// printer to use the glyphs inside GDI
if(lpString[0] == EURO &&
(GetDeviceCaps(hdc, TECHNOLOGY) != DT_RASDISPLAY || W32->IsEnhancedMetafileDC(hdc)))
{
fForceGdiFont = TRUE;
hfontCur = SelectFont(hdc, GetStockObject(ANSI_VAR_FONT));
LOGFONT lf;
GetObject(hfontCur, sizeof(LOGFONT), &lf);
lf.lfOutPrecision = OnWin9x() ? OUT_TT_ONLY_PRECIS : OUT_SCREEN_OUTLINE_PRECIS;
hfont = CreateFontIndirect(&lf);
SelectObject(hdc, hfont);
}
if(OnWin9x())
{
// To get around some Win95 printer device problems with ExtTextOutW,
// use ExtTextOutA if string is ASCII or if it's 1252 and any
// nonASCII chars are between 0xA0 and 0xFF.
for(UINT i = 0;
i < cch &&
(lpString[i] <= 0x7F ||
IN_RANGE(0xA0, lpString[i], 0xFF) && uiCodePage == 1252);
i++)
;
if(i == cch) // All ASCII or ANSI: setup to truncate
{ // to low byte and use ExtTextOutA
cm = CVT_LOWBYTE;
fConvert = true;
}
}
if (fConvert || !FEFontOnNonFEWin9x && cm != CVT_NONE)
{
if (cm == CVT_WCTMB)
{
if (IsFECodePage(uiCodePage))
{
if (OnWinNTNonFE() || (OnWin9x() && !OnWin95()))
{
// On NonFE NT4 and Win98, we need to textout each char using
// ExtTextOutA
ReExtTextOutW(hdc, x, y, fuOptions, lprc, lpString, cch, lpDx, uiCodePage);
goto LExit;
}
}
}
// Need to convert and use ExtTextOutA
CTempCharBuf tcb;
CTempBuf tDx;
// Double the buffer size
int cbString = (cm == CVT_LOWBYTE) ? cch : cch * 2;
// String buffer for converted string - allocate on the stack
char *psz = tcb.GetBuf(cbString);
INT *pTempDx = NULL;
if (NULL == psz)
{
// Could not allocate buffer
goto LExit;
}
int cbConv = 0;
if(cm == CVT_WCTMB)
{
cbConv = WideCharToMultiByte(uiCodePage, 0, lpString, cch,
psz, cbString, NULL, NULL);
if(!cbConv)
{
// The conversion failed for one reason or another. We should
// make every effort to use WCTMB before we fall back to
// taking the low-byte of every wchar (below), otherwise we
// risk dropping the high-bytes and displaying garbage.
// Use the cpg from the font, since the uiCodePage passed is
// the requested codepage and the font-mapper may very well
// have mapped to a different one.
TEXTMETRIC tm;
uiCodePage = (GetTextMetrics(hdc, &tm) &&
tm.tmCharSet != DEFAULT_CHARSET &&
(UINT)GetCodePage(tm.tmCharSet) != uiCodePage) ?
GetCodePage(tm.tmCharSet) : 1252;
cbConv = WideCharToMultiByte(uiCodePage, 0, lpString, cch,
psz, cbString, NULL, NULL);
}
if (cbConv > 0 && lpDx)
{
pTempDx = (INT *)tDx.GetBuf(cbConv * sizeof(INT));
if (pTempDx)
{
// Repack lpDx to handle DBC
INT *pDx = pTempDx;
CONST INT*pInputDx = lpDx;
char *pTempChar = psz;
INT cNumBytes = cbConv;
while (cNumBytes > 0)
{
cNumBytes--;
if (GetTrailBytesCount(*pTempChar++, uiCodePage))
{
*pDx++ = *pInputDx++;
*pDx++ = 0;
cNumBytes--;
pTempChar++;
}
else
*pDx++ = *pInputDx++;
}
}
}
}
else
{
Assert(cm == CVT_LOWBYTE);
// drop through and convert using only low-bytes of WCHAR's
}
// WCTMB failed OR cm == CVT_LOWBYTE
if(!cbConv) // Convert WCHARs to CHARs
{
// FUTURE: We come here for both SYMBOL_CHARSET fonts and for
// DBCS bytes stuffed into wchar's (one byte per wchar) when
// the requested code page is not installed on the machine and
// the MBTWC fails. Instead, we could have another conversion
// mode that collects each DBCS char as a single wchar and then
// remaps to a DBCS string for ExtTextOutA. This would allow us
// to display text if the system has the right font even tho it
// doesn't have the right cpg.
// If we are converting this WCHAR buffer in this manner
// (by taking only the low-byte's of the WCHAR's), it is
// because:
// 1) cm == CVT_LOWBYTE
// 2) WCTMB above failed for some reason or another. It may
// be the case that the string is entirely ASCII in which
// case dropping the high-bytes is not a big deal (otherwise
// we assert).
cbConv = cch;
while(cch--)
{
#ifdef DEBUG
if (uiCodePage != CP_SYMBOL && lpString[cch] > 0xFF)
Tracef(TRCSEVWARN, "Non-zero high-byte WCHAR: %x", lpString[cch]);
#endif
psz[cch] = lpString[cch];
}
}
::ExtTextOutA(hdc, x, y, fuOptions, lprc, psz, cbConv, pTempDx ? pTempDx : lpDx);
goto LExit;
}
if (OnWin9xFE() || FEFontOnNonFEWin9x)
ReExtTextOutW(hdc, x, y, fuOptions, lprc, lpString, cch, lpDx, 0);
else
::ExtTextOutW(hdc, x, y, fuOptions, lprc, lpString, cch, lpDx);
LExit:
if (fForceGdiFont)
{
SelectObject(hdc, hfontCur);
SideAssert(DeleteObject(hfont));
}
}
void WINAPI CW32System::REGetCharWidth(
HDC hdc,
WCHAR ch,
SHORT * pWidth,
UINT cpg,
SHORT xOverhang,
INT iDefWidth)
{
BOOL fForceGdiFont = FALSE;
HFONT hfont = NULL, hfontCur = NULL;
int iwidth;
*pWidth = 0;
if ((cpg == CP_SYMBOL || ch <= 127) && ::GetCharWidthA(hdc, ch, ch, &iwidth))
{
*pWidth = (SHORT)iwidth;
goto Done;
}
if(ch == EURO && (GetDeviceCaps(hdc, TECHNOLOGY) != DT_RASDISPLAY || W32->IsEnhancedMetafileDC(hdc)))
{
fForceGdiFont = TRUE;
hfontCur = SelectFont(hdc, GetStockObject(ANSI_VAR_FONT));
LOGFONT lf;
GetObject(hfontCur, sizeof(LOGFONT), &lf);
lf.lfOutPrecision = OnWin9x() ? OUT_TT_ONLY_PRECIS : OUT_SCREEN_OUTLINE_PRECIS;
hfont = CreateFontIndirect(&lf);
SelectObject(hdc, hfont);
}
// For most workarounds, we will use the workarounds on all the OSs.
// We only use specific workaround is MBTWC conversion is needed.
// This is a workaround for Win95 FE bugs
// FUTURE (keithcu) This logic could be simplified.
if (OnWin95() && !IN_RANGE(0x80, ch, 0xFF) && // Not high ANSI?
(cpg == CP_CHINESE_TRAD || cpg == CP_CHINESE_SIM)) // Chinese CodePage?
{
int numOfDBCS = 0;
::GetCharWidthW(hdc, 0x4e00, 0x4e00, &iwidth);
*pWidth = (SHORT)iwidth;
if (IN_RANGE(0x4e00, ch, 0x9fff))
goto Done;
// Use WCTMB heuristic
char ansiChar[2];
BOOL bDefCharUsed = FALSE;
numOfDBCS = ::WideCharToMultiByte( cpg, 0, &ch, 1, ansiChar, 2, NULL, &bDefCharUsed);
WORD wDBCS = (BYTE)ansiChar[0];
if (2 == numOfDBCS)
wDBCS = (BYTE)ansiChar[0] << 8 | (BYTE)ansiChar[1];
if (numOfDBCS > 0 && ::GetCharWidthA( hdc, wDBCS, wDBCS, &iwidth))
{
*pWidth = (SHORT)iwidth;
goto Done;
}
}
//Win '95 GPFs if you pass in 0xFFFF
if (ch == 0xFFFF)
ch = 0xFFFE;
if (::GetCharWidthW(hdc, ch, ch, &iwidth))
*pWidth = (SHORT)iwidth;
if(fForceGdiFont)
{
SelectObject(hdc, hfontCur);
SideAssert(DeleteObject(hfont));
}
Done:
*pWidth -= xOverhang;
if (0 >= *pWidth)
{
// Sometimes GetCharWidth will return a zero length for small
// characters. When this happens we will use the default width
// for the font if that is non-zero otherwise we just us 1 because
// this is the smallest valid value.
// This code can also be triggered if the overhang is bigger than the
// width returned by the OS call to get the character width.
if (0 == iDefWidth)
*pWidth = 1;
else
*pWidth = (SHORT)iDefWidth;
}
}
BOOL WINAPI CW32System::IsEnhancedMetafileDC( HDC hDC )
{
BOOL fEMFDC = FALSE;
DWORD dwObjectType;
dwObjectType = ::GetObjectType( hDC );
if ( OBJ_ENHMETADC == dwObjectType || OBJ_ENHMETAFILE == dwObjectType )
fEMFDC = TRUE;
else if ( OnWin95() && OBJ_DC == dwObjectType )
{
// HACK Alert, Enhanced Metafile DC does not support any Escape function
// and shoudl return 0.
int iEscapeFuction = QUERYESCSUPPORT;
if ( Escape( hDC, QUERYESCSUPPORT, sizeof(int), (LPCSTR)&iEscapeFuction, NULL) == 0 )
fEMFDC = TRUE;
}
return fEMFDC;
}
HPALETTE WINAPI CW32System::ManagePalette(
HDC hdc,
CONST LOGPALETTE *plogpal,
HPALETTE &hpalOld,
HPALETTE &hpalNew
)
{
if (hpalNew == NULL)
{
hpalNew = ::CreatePalette(plogpal);
if (hpalNew != NULL)
{
hpalOld = ::SelectPalette(hdc, hpalNew, TRUE);
::RealizePalette(hdc);
}
}
else
{
// A new palette was created previously and we are restoring the old one
::SelectPalette(hdc, hpalOld, TRUE);
::RealizePalette(hdc);
DeleteObject(hpalNew);
hpalNew = NULL;
}
return hpalNew;
}
int WINAPI CW32System::GetMapMode(HDC hdc)
{
return ::GetMapMode(hdc);
}
BOOL WINAPI CW32System::WinLPtoDP(HDC hdc, LPPOINT lppoints, int nCount)
{
return ::LPtoDP(hdc, lppoints, nCount);
}
long WINAPI CW32System::WvsprintfA( LONG cbBuf, LPSTR szBuf, LPCSTR szFmt, va_list arglist )
{
LONG cb;
cb = ::wvsprintfA( szBuf, szFmt, arglist );
Assert(cb < cbBuf);
return cb;
}
int WINAPI CW32System::MulDiv(int nNumber, int nNumerator, int nDenominator)
{
if ((nNumerator && nNumerator == nDenominator) || (nDenominator && !nNumber))
return nNumber;
return ::MulDiv(nNumber, nNumerator, nDenominator);
}
/*
* GetFacePriorityCharSet(WCHAR* szFaceName)
*
* @func
* return charset *really* supported by given facename
*/
int CALLBACK GetFacePriCharSetProc (
ENUMLOGFONTEX *lpelfe,
NEWTEXTMETRIC *lpntm,
int iFontType,
LPARAM lParam)
{
Assert (lParam);
*(BYTE*)lParam = lpntm->tmCharSet;
return 0;
}
void CW32System::GetFacePriCharSet(HDC hdc, LOGFONT* plf)
{
::EnumFontFamiliesEx(hdc, plf, (FONTENUMPROC)GetFacePriCharSetProc, (LPARAM)&plf->lfCharSet, 0);
}
/*
* CW32System::ReadRegDigitSubstitionMode(void)
*
* @mfunc
* Get the digit substitution mode (available on BiDi/Thai platforms)
*
* @rdesc
* 0 - Context (digit shape follows preceding run or CHARFORMAT's charset
* 1 - None (digits always show as European digit shape)
* 2 - National (digits always show as user locale's native shape)
*/
BYTE CW32System::ReadRegDigitSubstitutionMode()
{
HKEY hk;
DWORD keyDataType;
DWORD dwDataSize;
BYTE rgbValue[2];
BYTE bDigitMode;
bDigitMode = DIGITS_NOTIMPL; // assume "Not Implemented"
// Perform platform check before reading registry
if (!OnWin9xFE() && !OnWinNTFE() &&
IsComplexScriptLcid(GetThreadLocale()))
{
if(RegOpenKeyExA(HKEY_CURRENT_USER,
"Control Panel\\International",
0, // reserved
KEY_QUERY_VALUE,
&hk) == ERROR_SUCCESS)
{
dwDataSize = 2;
if (RegQueryValueExA(hk,
"NumShape",
NULL, // reserved
&keyDataType,
(LPBYTE) &rgbValue,
&dwDataSize) == ERROR_SUCCESS)
{
if (rgbValue[0] > 0x2f)
bDigitMode = rgbValue[0] - 0x30 + 1;
if (bDigitMode > DIGITS_NATIONAL)
bDigitMode = DIGITS_NONE;
}
RegCloseKey(hk);
}
}
return bDigitMode;
}
#ifdef DEBUG
/*
* TestGetCharFlags125x(iFirst, iLast)
*
* @func
* Unit test function for GetCharFlags125x(). Assert if GetCharFlags125x()
* claims that any char in Unicode range iFirst thru iLast 1) should
* roundtrip multibyte conversion using a codepage in the range 1250-1258
* when it doesn't, or 2) shouldn't roundtrip when it does.
*/
BOOL TestGetCharFlags125x(
int iFirst,
int iLast)
{
LONG cch = iLast - iFirst + 1;
LONG i;
Assert(cch <= 0x700 - 0xA0);
char rgach[0x700 - 0xA0];
WCHAR rgch [0x700 - 0xA0];
WCHAR * pch;
for(i = iFirst, pch = rgch; i <= iLast; pch++, i++)
*pch = (WCHAR)i;
for(int CodePage = 1250; CodePage <= 1258; CodePage++)
{
if(cch != WideCharToMultiByte(CodePage, 0, rgch, cch, rgach, cch, "\0", NULL) ||
cch != MultiByteToWideChar(CodePage, 0, rgach, cch, rgch, cch))
{
continue; // Missing code page
}
// 1250 1251 1252 1253 1254 1255 1256 1257 1258
const static WORD rgMask[] = {0x2, 0x4, 0x1, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100};
DWORD dwMask = rgMask[CodePage - 1250] << 8;
for(i = iFirst, pch = rgch; i <= iLast; pch++, i++)
{
AssertSz(!((*pch != (WCHAR)i) ^ !(W32->GetCharFlags125x(i) & dwMask)),
"GetCharFlags125x() failure");
*pch = (WCHAR)i; // Restore value
}
}
return TRUE; // Above AssertSz() reports any errors
}
#endif
/*
* CW32System::InitSysParams(fUpdate)
*
* @mfunc
* This method is used to initialize certain system wide parameters that
* that are used in richedit. This can also be used as an update method
* if we ever handle system parameter change notifications. The update
* parameter id provided for this purpose. Also note that if we ever support
* SysParam updating, we may have to protect access with locks.
*/
void CW32System::InitSysParams(BOOL fUpdate)
{
TRACEBEGIN(TRCSUBSYSUTIL, TRCSCOPEINTERN, "CW32System::InitSysParams");
CLock lock;
if (!_fSysParamsOk || fUpdate)
{
_fSysParamsOk = TRUE;
const LONG dxSelBarDefaultSize = 8;
HDC hdc = GetScreenDC();
HFONT hfontOld;
TEXTMETRIC tm;
_xPerInchScreenDC = GetDeviceCaps(hdc, LOGPIXELSX);
if (_xPerInchScreenDC == 0)
_xPerInchScreenDC = 0x60;
_yPerInchScreenDC = GetDeviceCaps(hdc, LOGPIXELSY);
if (_yPerInchScreenDC == 0)
_yPerInchScreenDC = 0x60;
int cPalette = GetDeviceCaps(hdc, SIZEPALETTE);
// 256 colors is where we seem to need to use the palette.
if (256 == cPalette)
{
_fUsePalette = TRUE;
}
// calculate a himetric selection bar for the window's host.
_dxSelBar = W32->DXtoHimetricX(dxSelBarDefaultSize, _xPerInchScreenDC);
RefreshKeyboardLayout();
_hSystemFont = (HFONT)GetStockObject(SYSTEM_FONT);
hfontOld = SelectFont(hdc, _hSystemFont);
if(hfontOld)
{
W32->GetTextMetrics(hdc, &tm);
_xWidthSys = (INT) tm.tmAveCharWidth;
_yHeightSys = (INT) tm.tmHeight;
_ySysFontLeading = (INT) tm.tmInternalLeading;
_bSysCharSet = tm.tmCharSet;
SelectFont(hdc, hfontOld);
}
_nScrollInset = (WORD)GetProfileIntA("windows", "ScrollInset",
DD_DEFSCROLLINSET);
_nDragDelay = (WORD)GetProfileIntA("windows", "DragDelay",
DD_DEFDRAGDELAY);
_nDragMinDist = (WORD)GetProfileIntA("windows", "DragMinDist",
DD_DEFDRAGMINDIST);
_nScrollDelay = (WORD)GetProfileIntA("windows", "ScrollDelay",
DD_DEFSCROLLDELAY);
_nScrollInterval = (WORD)GetProfileIntA("windows", "ScrollInterval",
DD_DEFSCROLLINTERVAL);
_nScrollVAmount = (WORD)(GetYPerInchScreenDC()*DEFSCROLLVAMOUNT)/100;
_nScrollHAmount = (GetXPerInchScreenDC()*DEFSCROLLHAMOUNT)/100;
_cxBorder = GetSystemMetrics(SM_CXBORDER); // Unsizable window border
_cyBorder = GetSystemMetrics(SM_CYBORDER); // widths
_cxVScroll = GetSystemMetrics(SM_CXVSCROLL); // dimensions
_cyHScroll = GetSystemMetrics(SM_CYHSCROLL); //
_cxDoubleClk = GetSystemMetrics(SM_CXDOUBLECLK);
_cyDoubleClk = GetSystemMetrics(SM_CYDOUBLECLK);
_DCT = GetDoubleClickTime();
_sysiniflags = ::GetProfileIntA("richedit30", "flags", 0);
#ifdef DEBUG
if(OnWinNT5() && (_sysiniflags & SYSINI_DEBUGGCF125X))
{
TestGetCharFlags125x(0xA0, 0x6FF);
TestGetCharFlags125x(0x2000, 0x2122);
}
#endif
_bDigitSubstMode = ReadRegDigitSubstitutionMode();
if (g_pusp)
g_pusp->ApplyDigitSubstitution(_bDigitSubstMode);
}
}
/*
* CW32System::GetSizeCursor(void)
*
* @mfunc
* Get the sizing cursor (double arrow) specified by
* the resource id. If the cursors are not loaded
* load them and cache them.
* parameters:
* idcur - cursor resource id.
*
* @rdesc
* Handle to cursor or null if failure. Returns NULL if
* idcur is null.
*/
HCURSOR CW32System::GetSizeCursor(
LPTSTR idcur)
{
if(!idcur )
return NULL;
//If any cursor isn't loaded, try loading it.
if(!_hcurSizeNS)
_hcurSizeNS = LoadCursor(NULL, IDC_SIZENS);
if(!_hcurSizeWE)
_hcurSizeWE = LoadCursor(NULL, IDC_SIZEWE);
if(!_hcurSizeNWSE)
_hcurSizeNWSE = LoadCursor(NULL, IDC_SIZENWSE);
if(!_hcurSizeNESW)
_hcurSizeNESW = LoadCursor(NULL, IDC_SIZENESW);
//Return cursor corresponding to id passed in.
if(idcur == IDC_SIZENS && _hcurSizeNS)
return _hcurSizeNS;
if(idcur == IDC_SIZEWE && _hcurSizeWE)
return _hcurSizeWE;
if(idcur == IDC_SIZENWSE && _hcurSizeNWSE)
return _hcurSizeNWSE;
if(idcur == IDC_SIZENESW && _hcurSizeNESW)
return _hcurSizeNESW;
AssertSz(FALSE, "Failure loading sizing cursor.");
return NULL;
}
/*
* CW32System:GetRollerLineScrollCount()
*
* @mfunc returns the number of lines to scroll with a roller mouse wheel.
* -1 means scroll by pages
*
* @devnote We have to do different things for different platforms; NT4.0 has
* built in support for this functionality.
*/
/* excerpt from new winuser.h for calls to SystemParametersInfo */
#ifndef SPI_GETWHEELSCROLLLINES
#define SPI_GETWHEELSCROLLLINES 104
#endif
LONG CW32System::GetRollerLineScrollCount()
{
if( _cLineScroll == 0 )
{
#ifndef _WIN64
HKEY hdlKey;
DWORD keyDataType;
CHAR charData[128];
DWORD dwDataBufSize;
// Fall back Value
_cLineScroll = 0;
// Read registry directly for Windows 95 & WinNT3.51, if WinNT 4.0
// and above then use SystemParametersInfo
if((OnWin95()) || (_dwPlatformId == VER_PLATFORM_WIN32_NT) && (_dwMajorVersion < 4))
{
// Read registry directly
if ( RegOpenKeyExA(HKEY_CURRENT_USER,
"Control Panel\\Desktop",
0,
KEY_QUERY_VALUE,
&hdlKey) == ERROR_SUCCESS )
{
dwDataBufSize = sizeof(charData);
if ( RegQueryValueExA(hdlKey,
"WheelScrollLines",
NULL, // reserved
&keyDataType,
(LPBYTE) &charData,
&dwDataBufSize) == ERROR_SUCCESS )
{
_cLineScroll = W32->strtoul( charData ); //String representation
}
}
else
{
// We didn't find line scroll count in the registery. Check for a Mouse
// Wheel window and query the window how many lines to scroll
static UINT idWheelSupport = RegisterWindowMessageA(MSH_WHEELSUPPORT);
static UINT idScrollLine = RegisterWindowMessageA(MSH_SCROLL_LINES);
HWND hwndMsWheel = FindWindowA(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
if (hwndMsWheel && SendMessageA(hwndMsWheel, idWheelSupport, 0, 0))
_cLineScroll = SendMessageA(hwndMsWheel, idScrollLine, 0, 0);
}
RegCloseKey(hdlKey);
}
else if ( (_dwPlatformId == VER_PLATFORM_WIN32_NT) &&
(_dwMajorVersion >= 4) || OnWin9x())
#endif //_WIN64
{
//call this function if on NT4 or Win98 (NOTE: it isn't sufficient to use
//OnWin9x() to determine if we are on a win98 system but since the
//previous if stmt checks to see if we are in a win95 system OnWin9x
//can be use)
SystemParametersInfoA(SPI_GETWHEELSCROLLLINES, 0, &_cLineScroll, 0);
}
}
return _cLineScroll;
}
//+---------------------------------------------------------------------------
//
// Member: CStrIn::CStrIn
//
// Synopsis: Inits the class.
//
// NOTE: Don't inline these functions or you'll increase code size
// by pushing -1 on the stack for each call.
//
//----------------------------------------------------------------------------
CStrIn::CStrIn(LPCWSTR pwstr, UINT CodePage)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrIn::CStrIn");
Init(pwstr, -1, CodePage);
}
CStrIn::CStrIn(LPCWSTR pwstr, int cwch, UINT CodePage)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrIn::CStrIn");
Init(pwstr, cwch, CodePage);
}
//+---------------------------------------------------------------------------
//
// Member: CStrIn::Init
//
// Synopsis: Converts a LPWSTR function argument to a LPSTR.
//
// Arguments: [pwstr] -- The function argument. May be NULL or an atom
// (HIWORD(pwstr) == 0).
//
// [cwch] -- The number of characters in the string to
// convert. If -1, the string is assumed to be
// NULL terminated and its length is calculated.
//
// Modifies: [this]
//
//----------------------------------------------------------------------------
void
CStrIn::Init(
LPCWSTR pwstr,
int cwch,
UINT CodePage) //@parm Code page to use (CP_ACP is default)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrIn::Init");
int cchBufReq;
_cchLen = 0;
// Check if string is NULL or an atom.
if (HIWORD((DWORD_PTR)pwstr) == 0)
{
_pstr = (LPSTR) pwstr;
return;
}
Assert(cwch == -1 || cwch > 0);
//
// Convert string to preallocated buffer, and return if successful.
//
_cchLen = W32->MbcsFromUnicode(_ach, ARRAY_SIZE(_ach), pwstr, cwch, CodePage);
if (_cchLen > 0)
{
if(_ach[_cchLen-1] == 0)
_cchLen--; // account for terminator
_pstr = _ach;
return;
}
//
// Alloc space on heap for buffer.
//
TRACEINFOSZ("CStrIn: Allocating buffer for wrapped function argument.");
cchBufReq = WideCharToMultiByte(
CP_ACP, 0, pwstr, cwch, NULL, 0, NULL, NULL);
Assert(cchBufReq > 0);
_pstr = new char[cchBufReq];
if (!_pstr)
{
// On failure, the argument will point to the empty string.
TRACEINFOSZ("CStrIn: No heap space for wrapped function argument.");
_ach[0] = 0;
_pstr = _ach;
return;
}
Assert(HIWORD((DWORD_PTR)_pstr));
_cchLen = -1 + W32->MbcsFromUnicode(_pstr, cchBufReq, pwstr, cwch);
Assert(_cchLen >= 0);
}
//+---------------------------------------------------------------------------
//
// Class: CStrInMulti (CStrIn)
//
// Purpose: Converts multiple strings which are terminated by two NULLs,
// e.g. "Foo\0Bar\0\0"
//
//----------------------------------------------------------------------------
class CStrInMulti : public CStrIn
{
public:
CStrInMulti(LPCWSTR pwstr, UINT CodePage);
};
//+---------------------------------------------------------------------------
//
// Member: CStrInMulti::CStrInMulti
//
// Synopsis: Converts mulitple LPWSTRs to a multiple LPSTRs.
//
// Arguments: [pwstr] -- The strings to convert.
//
// Modifies: [this]
//
//----------------------------------------------------------------------------
CStrInMulti::CStrInMulti(
LPCWSTR pwstr,
UINT CodePage)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrInMulti::CStrInMulti");
LPCWSTR pwstrT;
// We don't handle atoms because we don't need to.
Assert(HIWORD((DWORD_PTR)pwstr));
//
// Count number of characters to convert.
//
pwstrT = pwstr;
if (pwstr)
{
do {
while (*pwstrT++)
;
} while (*pwstrT++);
}
Init(pwstr, pwstrT - pwstr, CodePage);
}
//+---------------------------------------------------------------------------
//
// Member: CStrOut::CStrOut
//
// Synopsis: Allocates enough space for an out buffer.
//
// Arguments: [pwstr] -- The Unicode buffer to convert to when destroyed.
// May be NULL.
//
// [cwchBuf] -- The size of the buffer in characters.
//
// Modifies: [this].
//
//----------------------------------------------------------------------------
CStrOut::CStrOut(LPWSTR pwstr, int cwchBuf)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrOut::CStrOut");
Assert(cwchBuf >= 0);
_pwstr = pwstr;
_cwchBuf = cwchBuf;
if (!pwstr)
{
Assert(cwchBuf == 0);
_pstr = NULL;
return;
}
Assert(HIWORD((DWORD_PTR)pwstr));
// Initialize buffer in case Windows API returns an error.
_ach[0] = 0;
// Use preallocated buffer if big enough.
if (cwchBuf * 2 <= ARRAY_SIZE(_ach))
{
_pstr = _ach;
return;
}
// Allocate buffer.
TRACEINFOSZ("CStrOut: Allocating buffer for wrapped function argument.");
_pstr = new char[cwchBuf * 2];
if (!_pstr)
{
//
// On failure, the argument will point to a zero-sized buffer initialized
// to the empty string. This should cause the Windows API to fail.
//
TRACEINFOSZ("CStrOut: No heap space for wrapped function argument.");
Assert(cwchBuf > 0);
_pwstr[0] = 0;
_cwchBuf = 0;
_pstr = _ach;
return;
}
Assert(HIWORD((DWORD_PTR)_pstr));
_pstr[0] = 0;
}
//+---------------------------------------------------------------------------
//
// Member: CStrOut::Convert
//
// Synopsis: Converts the buffer from MBCS to Unicode.
//
//----------------------------------------------------------------------------
int
CStrOut::Convert()
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrOut::Convert");
int cch;
if (!_pstr)
return 0;
cch = MultiByteToWideChar(CP_ACP, 0, _pstr, -1, _pwstr, _cwchBuf);
Assert(cch > 0 || _cwchBuf == 0);
Free();
if (cch > 0 && cch <= _cwchBuf && _pwstr[cch-1] == L'\0')
cch--;
return cch;
}
//+---------------------------------------------------------------------------
//
// Member: CStrOut::~CStrOut
//
// Synopsis: Converts the buffer from MBCS to Unicode.
//
// Note: Don't inline this function, or you'll increase code size as
// both Convert() and CConvertStr::~CConvertStr will be called
// inline.
//
//----------------------------------------------------------------------------
CStrOut::~CStrOut()
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrOut::~CStrOut");
Convert();
}
//
// MultiByte --> UNICODE routins
//
//+---------------------------------------------------------------------------
//
// Member: CConvertStr::Free
//
// Synopsis: Frees string if alloc'd and initializes to NULL.
//
//----------------------------------------------------------------------------
void
CConvertStr::Free()
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CConvertStr::Free");
if (_pstr != _ach && HIWORD((DWORD_PTR)_pstr) != 0)
{
delete [] _pstr;
}
_pstr = NULL;
}
//+---------------------------------------------------------------------------
//
// Member: CConvertStrW::Free
//
// Synopsis: Frees string if alloc'd and initializes to NULL.
//
//----------------------------------------------------------------------------
void
CConvertStrW::Free()
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CConvertStrW::Free");
if (_pwstr != _awch && HIWORD((DWORD_PTR)_pwstr) != 0 )
{
delete [] _pwstr;
}
_pwstr = NULL;
}
//+---------------------------------------------------------------------------
//
// Member: CStrInW::CStrInW
//
// Synopsis: Inits the class.
//
// NOTE: Don't inline these functions or you'll increase code size
// by pushing -1 on the stack for each call.
//
//----------------------------------------------------------------------------
CStrInW::CStrInW(LPCSTR pstr)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrInW::CStrInW");
Init(pstr, -1, CP_ACP);
}
CStrInW::CStrInW(LPCSTR pstr, UINT uiCodePage)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrInW::CStrInW");
Init(pstr, -1, uiCodePage);
}
CStrInW::CStrInW(LPCSTR pstr, int cch, UINT uiCodePage)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrInW::CStrInW");
Init(pstr, cch, uiCodePage);
}
//+---------------------------------------------------------------------------
//
// Member: CStrInW::Init
//
// Synopsis: Converts a LPSTR function argument to a LPWSTR.
//
// Arguments: [pstr] -- The function argument. May be NULL or an atom
// (HIWORD(pwstr) == 0).
//
// [cch] -- The number of characters in the string to
// convert. If -1, the string is assumed to be
// NULL terminated and its length is calculated.
//
// Modifies: [this]
//
//----------------------------------------------------------------------------
void
CStrInW::Init(LPCSTR pstr, int cch, UINT uiCodePage)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrInW::Init");
int cchBufReq;
_cwchLen = 0;
// Check if string is NULL or an atom.
if (HIWORD((DWORD_PTR)pstr) == 0)
{
_pwstr = (LPWSTR) pstr;
return;
}
Assert(cch == -1 || cch > 0);
//
// Convert string to preallocated buffer, and return if successful.
//
_cwchLen = MultiByteToWideChar(
uiCodePage, 0, pstr, cch, _awch, ARRAY_SIZE(_awch));
if (_cwchLen > 0)
{
if(_awch[_cwchLen-1] == 0)
_cwchLen--; // account for terminator
_pwstr = _awch;
return;
}
//
// Alloc space on heap for buffer.
//
TRACEINFOSZ("CStrInW: Allocating buffer for wrapped function argument.");
cchBufReq = MultiByteToWideChar(
CP_ACP, 0, pstr, cch, NULL, 0);
Assert(cchBufReq > 0);
_pwstr = new WCHAR[cchBufReq];
if (!_pwstr)
{
// On failure, the argument will point to the empty string.
TRACEINFOSZ("CStrInW: No heap space for wrapped function argument.");
_awch[0] = 0;
_pwstr = _awch;
return;
}
Assert(HIWORD((DWORD_PTR)_pwstr));
_cwchLen = -1 + MultiByteToWideChar(
uiCodePage, 0, pstr, cch, _pwstr, cchBufReq);
Assert(_cwchLen >= 0);
}
//+---------------------------------------------------------------------------
//
// Member: CStrOutW::CStrOutW
//
// Synopsis: Allocates enough space for an out buffer.
//
// Arguments: [pstr] -- The ansi buffer to convert to when destroyed.
// May be NULL.
//
// [cchBuf] -- The size of the buffer in characters.
//
// Modifies: [this].
//
//----------------------------------------------------------------------------
CStrOutW::CStrOutW(LPSTR pstr, int cchBuf, UINT uiCodePage)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrOutW::CStrOutW");
Assert(cchBuf >= 0);
_pstr = pstr;
_cchBuf = cchBuf;
_uiCodePage = uiCodePage;
if (!pstr)
{
Assert(cchBuf == 0);
_pwstr = NULL;
return;
}
Assert(HIWORD((DWORD_PTR)pstr));
// Initialize buffer in case Windows API returns an error.
_awch[0] = 0;
// Use preallocated buffer if big enough.
if (cchBuf <= ARRAY_SIZE(_awch))
{
_pwstr = _awch;
return;
}
// Allocate buffer.
TRACEINFOSZ("CStrOutW: Allocating buffer for wrapped function argument.");
_pwstr = new WCHAR[cchBuf * 2];
if (!_pwstr)
{
//
// On failure, the argument will point to a zero-sized buffer initialized
// to the empty string. This should cause the Windows API to fail.
//
TRACEINFOSZ("CStrOutW: No heap space for wrapped function argument.");
Assert(cchBuf > 0);
_pstr[0] = 0;
_cchBuf = 0;
_pwstr = _awch;
return;
}
Assert(HIWORD((DWORD_PTR)_pwstr));
_pwstr[0] = 0;
}
//+---------------------------------------------------------------------------
//
// Member: CStrOutW::Convert
//
// Synopsis: Converts the buffer from Unicode to MBCS
//
//----------------------------------------------------------------------------
int
CStrOutW::Convert()
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrOutW::Convert");
int cch;
if (!_pwstr)
return 0;
int cchBuf = _cchBuf;
cch = W32->MbcsFromUnicode(_pstr, cchBuf, _pwstr, -1, _uiCodePage);
Free();
if (cch > 0 && cch <= _cchBuf && _pstr[cch-1] == '\0')
cch--;
return cch;
}
//+---------------------------------------------------------------------------
//
// Member: CStrOutW::~CStrOutW
//
// Synopsis: Converts the buffer from Unicode to MBCS.
//
// Note: Don't inline this function, or you'll increase code size as
// both Convert() and CConvertStr::~CConvertStr will be called
// inline.
//
//----------------------------------------------------------------------------
CStrOutW::~CStrOutW()
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CStrOutW::~CStrOutW");
Convert();
}
BOOL CW32System::GetVersion(
DWORD *pdwPlatformId,
DWORD *pdwMajorVersion,
DWORD *pdwMinorVersion
)
{
OSVERSIONINFOA osv;
osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
*pdwPlatformId = 0;
*pdwMajorVersion = 0;
if (::GetVersionExA(&osv))
{
*pdwPlatformId = osv.dwPlatformId;
*pdwMajorVersion = osv.dwMajorVersion;
*pdwMinorVersion = osv.dwMinorVersion;
return TRUE;
}
return FALSE;
}
BOOL CW32System::GetStringTypes(
LCID lcid,
LPCTSTR lpSrcStr,
int cchSrc,
LPWORD lpCharType1,
LPWORD lpCharType3)
{
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
{
if(::GetStringTypeExW(lcid, CT_CTYPE1, lpSrcStr, cchSrc, lpCharType1))
return ::GetStringTypeExW(lcid, CT_CTYPE3, lpSrcStr, cchSrc, lpCharType3);
return FALSE;
}
CStrIn str(lpSrcStr, cchSrc, ConvertLanguageIDtoCodePage(lcid));
LONG cch = str.strlen();
if(::GetStringTypeExA(lcid, CT_CTYPE1, str, cch, lpCharType1))
return ::GetStringTypeExA(lcid, CT_CTYPE3, str, cch, lpCharType3);
return FALSE;
}
BOOL WINAPI CW32System::GetStringTypeEx(
LCID lcid,
DWORD dwInfoType,
LPCTSTR lpSrcStr,
int cchSrc,
LPWORD lpCharType
)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "GetStringTypeEx");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::GetStringTypeExW(lcid, dwInfoType, lpSrcStr, cchSrc, lpCharType);
CStrIn str(lpSrcStr, cchSrc);
return GetStringTypeExA(lcid, dwInfoType, str, str.strlen(), lpCharType);
}
typedef LPSTR (CALLBACK *FnCharChangeCase)(LPSTR);
static LPWSTR CharChangeCase(LPWSTR pwstr, FnCharChangeCase pfn)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CharChangeCaseWrap");
if (HIWORD((DWORD_PTR)pwstr) == 0)
{
LPSTR pstr=0;
int retCode;
char DBChar[3];
retCode = W32->MbcsFromUnicode((LPSTR) &pstr, sizeof(pstr), (LPWSTR) &pwstr, 1);
Assert(HIWORD((DWORD_PTR)pstr) == 0);
if (retCode == 2)
{
// This is a DBC, use string
DWORD iTemp = (DWORD)((DWORD_PTR)pstr);
DBChar[0] = char(iTemp & 0x0ff);
DBChar[1] = char(iTemp >> 8);
DBChar[2] = 0;
pstr = (*pfn)(DBChar);
W32->UnicodeFromMbcs((LPWSTR) &pwstr, sizeof(pwstr) / sizeof(WCHAR), (LPSTR)DBChar, 2);
}
else
{
pstr = (*pfn)(pstr);
W32->UnicodeFromMbcs((LPWSTR) &pwstr, sizeof(pwstr) / sizeof(WCHAR), (LPSTR) &pstr);
}
Assert(HIWORD((DWORD_PTR)pwstr) == 0);
}
else
{
CStrOut strOut(pwstr, W32->wcslen(pwstr));
W32->MbcsFromUnicode(strOut, strOut.BufSize(), pwstr);
(*pfn)(strOut);
}
return pwstr;
}
LPWSTR WINAPI CW32System::CharLower(LPWSTR pwstr)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CharLower");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::CharLowerW(pwstr);
return CharChangeCase(pwstr, CharLowerA);
}
DWORD WINAPI CW32System::CharLowerBuff(LPWSTR pwstr, DWORD cchLength)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CharLowerBuff");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::CharLowerBuffW(pwstr, cchLength);
LPWSTR lpBuffer = pwstr;
for (DWORD pos = 0; pos < cchLength; pos++, lpBuffer++)
*lpBuffer = (WCHAR)CharChangeCase((LPWSTR)*lpBuffer, CharLowerA);
return pos;
}
DWORD WINAPI CW32System::CharUpperBuff(LPWSTR pwstr, DWORD cchLength)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CharUpperBuff");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::CharUpperBuffW(pwstr, cchLength);
LPWSTR lpBuffer = pwstr;
for (DWORD pos = 0; pos < cchLength; pos++, lpBuffer++)
*lpBuffer = (WCHAR)CharChangeCase((LPWSTR)*lpBuffer, CharUpperA);
return pos;
}
typedef HDC (CALLBACK *FnCreateHDCA)(LPCSTR, LPCSTR, LPCSTR, CONST DEVMODEA *);
static HDC WINAPI CreateHDCAux(
LPCWSTR lpszDriver,
LPCWSTR lpszDevice,
LPCWSTR lpszOutput,
CONST DEVMODEW * lpInitData,
FnCreateHDCA pfn
)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CreateHDCWrap");
DEVMODEA devmode;
CStrIn strDriver(lpszDriver);
CStrIn strDevice(lpszDevice);
CStrIn strOutput(lpszOutput);
if ( lpInitData )
{
// converting DEVMODEW to DEVMODEA
int byteCount;
// copying the data between the two strings members
byteCount = (char *)&(devmode.dmFormName)
- (char *)&(devmode.dmSpecVersion);
memcpy(&(devmode.dmSpecVersion),
&(lpInitData->dmSpecVersion),
byteCount);
// copying the data after the second string member
byteCount = (char *)((char *)&devmode + sizeof(DEVMODEA))
- (char *)&(devmode.dmLogPixels);
memcpy(&(devmode.dmLogPixels),
&(lpInitData->dmLogPixels),
byteCount);
// converting the two strings members
W32->MbcsFromUnicode((CHAR *)devmode.dmDeviceName, CCHDEVICENAME, lpInitData->dmDeviceName);
W32->MbcsFromUnicode((CHAR *)devmode.dmFormName, CCHFORMNAME, lpInitData->dmFormName);
}
return (*pfn)(strDriver, strDevice, strOutput,
lpInitData ? &devmode : NULL);
}
HDC WINAPI CW32System::CreateIC(
LPCWSTR lpszDriver,
LPCWSTR lpszDevice,
LPCWSTR lpszOutput,
CONST DEVMODEW * lpInitData)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CreateIC");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::CreateICW( lpszDriver, lpszDevice, lpszOutput, lpInitData );
return CreateHDCAux(lpszDriver, lpszDevice, lpszOutput, lpInitData, CreateICA);
}
HANDLE WINAPI CW32System::CreateFile(
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CreateFile");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::CreateFileW(lpFileName,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
CStrIn str(lpFileName);
return ::CreateFileA(
str,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
}
HFONT WINAPI CW32System::CreateFontIndirect(CONST LOGFONTW * plfw)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CreateFontIndirect");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::CreateFontIndirectW(plfw);
LOGFONTA lfa;
HFONT hFont;
memcpy(&lfa, plfw, offsetof(LOGFONTA, lfFaceName));
MbcsFromUnicode(lfa.lfFaceName, ARRAY_SIZE(lfa.lfFaceName), plfw->lfFaceName,
-1, CP_ACP, UN_NOOBJECTS);
hFont = ::CreateFontIndirectA(&lfa);
return hFont;
}
int WINAPI CW32System::CompareString (
LCID Locale, // locale identifier
DWORD dwCmpFlags, // comparison-style options
LPCWSTR lpString1, // pointer to first string
int cch1, // size, in bytes or characters, of first string
LPCWSTR lpString2, // pointer to second string
int cch2 // size, in bytes or characters, of second string
)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "CompareString");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::CompareStringW(Locale, dwCmpFlags, lpString1, cch1, lpString2, cch2);
CStrIn str1(lpString1, cch1);
CStrIn str2(lpString2, cch2);
return CompareStringA(
Locale,
dwCmpFlags,
str1,
str1.strlen(),
str2,
str2.strlen()
);
}
LRESULT WINAPI CW32System::DefWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "DefWindowProcWrap");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::DefWindowProcW(hWnd, msg, wParam, lParam);
return ::DefWindowProcA(hWnd, msg, wParam, lParam);
}
int WINAPI CW32System::GetObject(HGDIOBJ hgdiObj, int cbBuffer, LPVOID lpvObj)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "GetObject");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::GetObjectW( hgdiObj, cbBuffer, lpvObj);
int nRet;
if(cbBuffer != sizeof(LOGFONTW) || !lpvObj)
{
nRet = ::GetObjectA(hgdiObj, cbBuffer, lpvObj);
if(nRet == sizeof(LOGFONTA))
{
nRet = sizeof(LOGFONTW);
}
}
else
{
LOGFONTA lfa;
nRet = ::GetObjectA(hgdiObj, sizeof(lfa), &lfa);
if(nRet > 0)
{
memcpy(lpvObj, &lfa, offsetof(LOGFONTW, lfFaceName));
UnicodeFromMbcs(((LOGFONTW*)lpvObj)->lfFaceName, ARRAY_SIZE(((LOGFONTW*)lpvObj)->lfFaceName),
lfa.lfFaceName, -1);
nRet = sizeof(LOGFONTW);
}
}
return nRet;
}
DWORD APIENTRY CW32System::GetProfileSection(
LPCWSTR lpAppName,
LPWSTR lpReturnedString,
DWORD nSize
)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "GetProfileSection");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::GetProfileSectionW( lpAppName, lpReturnedString, nSize );
CStrIn strAppName(lpAppName);
// we can't use CStrOut here, since the returned string contains a set of
// strings delimited by single-NULL's and terminated by a double-NULL
char *pszReturnedString;
pszReturnedString = new char[nSize];
Assert(pszReturnedString);
DWORD cch = ::GetProfileSectionA(strAppName, pszReturnedString, nSize);
if(cch)
{
cch = MultiByteToWideChar(CP_ACP, 0, pszReturnedString, cch,
lpReturnedString, nSize);
}
delete pszReturnedString;
return cch;
}
BOOL APIENTRY CW32System::GetTextExtentPoint32(
HDC hdc,
LPCWSTR pwsz,
int cb,
LPSIZE pSize
)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "GetTextExtentPoint32");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::GetTextExtentPoint32W( hdc, pwsz, cb, pSize );
CStrIn str(pwsz);
return ::GetTextExtentPoint32A(hdc, str, cb, pSize);
}
int WINAPI CW32System::GetTextFace(
HDC hdc,
int cch,
LPWSTR lpFaceName
)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "GetTextFace");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::GetTextFaceW( hdc, cch, lpFaceName );
CStrOut str(lpFaceName, cch);
::GetTextFaceA(hdc, str.BufSize(), str);
return str.Convert();
}
BOOL WINAPI CW32System::GetTextMetrics(HDC hdc, LPTEXTMETRICW lptm)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "GetTextMetrics");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::GetTextMetricsW( hdc, lptm);
BOOL ret;
TEXTMETRICA tm;
ret = ::GetTextMetricsA(hdc, &tm);
if (ret)
{
lptm->tmHeight = tm.tmHeight;
lptm->tmAscent = tm.tmAscent;
lptm->tmDescent = tm.tmDescent;
lptm->tmInternalLeading = tm.tmInternalLeading;
lptm->tmExternalLeading = tm.tmExternalLeading;
lptm->tmAveCharWidth = tm.tmAveCharWidth;
lptm->tmMaxCharWidth = tm.tmMaxCharWidth;
lptm->tmWeight = tm.tmWeight;
lptm->tmOverhang = tm.tmOverhang;
lptm->tmDigitizedAspectX = tm.tmDigitizedAspectX;
lptm->tmDigitizedAspectY = tm.tmDigitizedAspectY;
lptm->tmItalic = tm.tmItalic;
lptm->tmUnderlined = tm.tmUnderlined;
lptm->tmStruckOut = tm.tmStruckOut;
lptm->tmPitchAndFamily = tm.tmPitchAndFamily;
lptm->tmCharSet = tm.tmCharSet;
UnicodeFromMbcs(&lptm->tmFirstChar, 1, (LPSTR) &tm.tmFirstChar, 1);
UnicodeFromMbcs(&lptm->tmLastChar, 1, (LPSTR) &tm.tmLastChar, 1);
UnicodeFromMbcs(&lptm->tmDefaultChar, 1, (LPSTR) &tm.tmDefaultChar, 1);
UnicodeFromMbcs(&lptm->tmBreakChar, 1, (LPSTR) &tm.tmBreakChar, 1);
}
return ret;
}
LONG WINAPI CW32System::GetWindowLong(HWND hWnd, int nIndex)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "GetWindowLong");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::GetWindowLongW(hWnd, nIndex);
return ::GetWindowLongA(hWnd, nIndex);
}
LONG_PTR WINAPI CW32System::GetWindowLongPtr(HWND hWnd, int nIndex)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "GetWindowLongPtr");
#ifdef _WIN64
return GetWindowLongPtrW(hWnd, nIndex);
#else
return GetWindowLong(hWnd, nIndex);
#endif
}
DWORD WINAPI CW32System::GetClassLong(HWND hWnd, int nIndex)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "GetClassLong");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::GetClassLongW(hWnd, nIndex);
return ::GetClassLongA(hWnd, nIndex);
}
HBITMAP WINAPI CW32System::LoadBitmap(HINSTANCE hInstance, LPCWSTR lpBitmapName)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "LoadBitmap");
Assert(HIWORD((DWORD_PTR)lpBitmapName) == 0);
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::LoadBitmapW(hInstance, lpBitmapName);
return ::LoadBitmapA(hInstance, (LPCSTR) lpBitmapName);
}
HCURSOR WINAPI CW32System::LoadCursor(HINSTANCE hInstance, LPCWSTR lpCursorName)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "LoadCursor");
Assert(HIWORD((DWORD_PTR)lpCursorName) == 0);
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::LoadCursorW(hInstance, lpCursorName);
return ::LoadCursorA(hInstance, (LPCSTR) lpCursorName);
}
HINSTANCE WINAPI CW32System::LoadLibrary(LPCWSTR lpLibFileName)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "LoadLibrary");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::LoadLibraryW(lpLibFileName);
CStrIn str(lpLibFileName);
return ::LoadLibraryA(str);
}
LRESULT WINAPI CW32System::SendMessage(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "SendMessage");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId && ::IsWindowUnicode(hWnd))
return ::SendMessageW(hWnd, Msg, wParam, lParam);
// We never need Ansi to Unicode translation in our use of SendMessage
// Our list boxes always use Unicode.
switch (Msg)
{
// We don't want to translate these!
// case LB_ADDSTRING:
// case LB_INSERTSTRING:
// case CB_ADDSTRING:
// case CB_SELECTSTRING:
// case CB_INSERTSTRING:
// case LB_GETTEXT:
// case CB_GETLBTEXT:
case WM_GETTEXT:
{
CStrOut str((LPWSTR)lParam, (int)wParam);
::SendMessageA(hWnd, Msg, str.BufSize(), (LPARAM)(LPSTR)str);
return str.Convert();
}
break;
case WM_SETTEXT:
case EM_REPLACESEL:
Assert(FALSE); // We never send these. Dead code?
break;
case EM_SETPASSWORDCHAR:
Assert(FALSE); // We never send these. Dead code?
break;
}
return ::SendMessageA(hWnd, Msg, wParam, lParam);
}
LONG WINAPI CW32System::SetWindowLong(HWND hWnd, int nIndex, LONG dwNewLong)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "SetWindowLong");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::SetWindowLongW(hWnd, nIndex, dwNewLong);
return ::SetWindowLongA(hWnd, nIndex, dwNewLong);
}
LONG WINAPI CW32System::SetWindowLongPtr(HWND hWnd, int nIndex, LONG_PTR dwNewLong)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "SetWindowLongPtr");
#ifdef _WIN64
return ::SetWindowLongPtrW(hWnd, nIndex, dwNewLong);
#else
return SetWindowLong(hWnd, nIndex, dwNewLong);
#endif
}
BOOL WINAPI CW32System::PostMessage(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "PostMessage");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::PostMessageW(hWnd, Msg, wParam, lParam);
return ::PostMessageA(hWnd, Msg, wParam, lParam);
}
BOOL WINAPI CW32System::UnregisterClass(LPCWSTR lpClassName, HINSTANCE hInstance)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "UnregisterClass");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::UnregisterClassW( lpClassName, hInstance);
CStrIn str(lpClassName);
return ::UnregisterClassA(str, hInstance);
}
int WINAPI CW32System::lstrcmp(LPCWSTR lpString1, LPCWSTR lpString2)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "lstrcmp");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::lstrcmpW(lpString1, lpString2);
return W32->wcscmp(lpString1, lpString2);
}
int WINAPI CW32System::lstrcmpi(LPCWSTR lpString1, LPCWSTR lpString2)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "lstrcmpi");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::lstrcmpiW(lpString1, lpString2);
// Fall back on the simple minded CRT algortihm
// The CRT actually has two paths. This is the simple one
const wchar_t * dst = lpString1;
const wchar_t * src = lpString2;
wchar_t f,l;
do {
f = ((*dst <= L'Z') && (*dst >= L'A'))
? *dst + L'a' - L'A'
: *dst;
l = ((*src <= L'Z') && (*src >= L'A'))
? *src + L'a' - L'A'
: *src;
dst++;
src++;
} while ( (f) && (f == l) );
return (int)(f - l);
}
BOOL WINAPI CW32System::PeekMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax,
UINT wRemoveMsg
)
{
TRACEBEGIN(TRCSUBSYSWRAP, TRCSCOPEINTERN, "PeekMessage");
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::PeekMessageW(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
return ::PeekMessageA(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
}
DWORD WINAPI CW32System::GetModuleFileName(
HMODULE hModule,
LPWSTR lpFilename,
DWORD nSize
)
{
if (VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId)
return ::GetModuleFileNameW(hModule, lpFilename, nSize);
CStrOut strout(lpFilename, nSize);
DWORD res = ::GetModuleFileNameA(hModule, strout, nSize);
strout.Convert();
return res;
}
// The high bits of _yHeightUI & _yHeightOther are being used to check if
// font is installed in the system
#define NEED_TO_CHECK_FONT 0x080
struct PreferredFontInfo
{
BYTE _bPitchAndFamilyUI;
BYTE _yHeightUI;
SHORT _iFontUI;
BYTE _bPitchAndFamilyOther;
BYTE _yHeightOther;
SHORT _iFontOther;
};
PreferredFontInfo g_pfinfo[NCHARSETS];
void CW32System::InitPreferredFontInfo()
{
// For UI case, we will use Word9 UI fonts
// For Non-UI case, we will use Word9 default email fonts
short iFont;
UINT uSysDefCodePage = GetSystemDefaultCodePage();
// Japanese Init
static const WCHAR lpUIJapanFontName[] = L"MS UI Gothic";
static const WCHAR lpOthJapanFontName[]
= {0xFF2D,0xFF33,0x0020,0xFF30,0x30B4,0x30B7,0x30C3,0x30AF, 0};
static const WCHAR lpOthJapanFontNameEUC[] = L"MS PGothic";
iFont = GetFontNameIndex( lpUIJapanFontName );
SetPreferredFontInfo( CP_JAPAN, true, iFont, 9 | NEED_TO_CHECK_FONT, 17 );
if (uSysDefCodePage == CP_JAPAN)
iFont = GetFontNameIndex( lpOthJapanFontName );
else
iFont = GetFontNameIndex( lpOthJapanFontNameEUC );
SetPreferredFontInfo( CP_JAPAN, false, iFont, 10 | NEED_TO_CHECK_FONT, 17 );
// Korean Init
static const WCHAR lpUIKoreanFontName[] = {0xAD74, 0xB9BC, 0};
static const WCHAR lpUIKoreanFontNameEUC[] = L"Gulim";
if (uSysDefCodePage == CP_KOREAN)
iFont = GetFontNameIndex( lpUIKoreanFontName );
else
iFont = GetFontNameIndex( lpUIKoreanFontNameEUC );
SetPreferredFontInfo( CP_KOREAN, true, iFont, 9 | NEED_TO_CHECK_FONT, 49 );
SetPreferredFontInfo( CP_KOREAN, false, iFont, 9 | NEED_TO_CHECK_FONT, 49 );
// Traditional Chinese Init
static const WCHAR lpUITChineseFontName[] = {0x65B0, 0x7D30, 0x660E, 0x9AD4, 0};
static const WCHAR lpUITChineseFontNameEUC[] = L"PMingLiU";
iFont = GetFontNameIndex(uSysDefCodePage == CP_CHINESE_TRAD
? lpUITChineseFontName : lpUITChineseFontNameEUC);
SetPreferredFontInfo( CP_CHINESE_TRAD, true, iFont, 9 | NEED_TO_CHECK_FONT, 54 );
SetPreferredFontInfo( CP_CHINESE_TRAD, false, iFont, 9 | NEED_TO_CHECK_FONT, 54 );
// Simplified Chinese Init
static const WCHAR lpUISChineseFontName[] = {0x5B8B, 0x4F53, 0};
static const WCHAR lpUISChineseFontNameEUC[] = L"SimSun";
iFont = GetFontNameIndex(uSysDefCodePage == CP_CHINESE_SIM
? lpUISChineseFontName : lpUISChineseFontNameEUC);
SetPreferredFontInfo( CP_CHINESE_SIM, true, iFont, 9 | NEED_TO_CHECK_FONT, 54 );
SetPreferredFontInfo( CP_CHINESE_SIM, false, iFont, 10 | NEED_TO_CHECK_FONT, 54 );
// English Init
iFont = GetFontNameIndex( szTahoma );
SetPreferredFontInfo(1252, true, iFont, 8, DEFAULT_PITCH | FF_SWISS );
iFont = GetFontNameIndex( szArial );
SetPreferredFontInfo(1252, false, iFont, 10, DEFAULT_PITCH | FF_SWISS );
// SYMBOL_CHARSET
iFont = GetFontNameIndex( szWingdings );
SetPreferredFontInfo(CP_SYMBOL, true, iFont, 8, DEFAULT_PITCH | FF_DONTCARE);
SetPreferredFontInfo(CP_SYMBOL, false, iFont, 10, DEFAULT_PITCH | FF_DONTCARE);
// Vietnamese Init
iFont = GetFontNameIndex( szTahoma );
SetPreferredFontInfo(1258, true, iFont, 8, DEFAULT_PITCH | FF_SWISS );
iFont = GetFontNameIndex( szArial );
SetPreferredFontInfo(1258, false, iFont, 10, DEFAULT_PITCH | FF_SWISS );
// Thai Init
if (OnWinNT5())
iFont = GetFontNameIndex( szMicrosSansSerif );
else
iFont = GetFontNameIndex( szTahoma );
SetPreferredFontInfo(874, true, iFont, 8, DEFAULT_PITCH | FF_SWISS );
iFont = GetFontNameIndex( szCordiaNew );
SetPreferredFontInfo(874, false, iFont, 14, DEFAULT_PITCH | FF_SWISS );
// Devanagari Init
iFont = GetFontNameIndex( szMangal );
SetPreferredFontInfo(CP_DEVANAGARI, true, iFont, 8, DEFAULT_PITCH | FF_SWISS );
SetPreferredFontInfo(CP_DEVANAGARI, false, iFont, 10, DEFAULT_PITCH | FF_SWISS );
// Tamil Init
iFont = GetFontNameIndex( szLatha );
SetPreferredFontInfo(CP_TAMIL, true, iFont, 8, DEFAULT_PITCH | FF_SWISS );
SetPreferredFontInfo(CP_TAMIL, false, iFont, 10, DEFAULT_PITCH | FF_SWISS );
// Georgian and Armenian Init
if(OnWinNT5())
{
iFont = GetFontNameIndex(szArialUnicode);
SetPreferredFontInfo(CP_GEORGIAN, true, iFont, 8, DEFAULT_PITCH | FF_SWISS);
SetPreferredFontInfo(CP_GEORGIAN, false, iFont, 10, DEFAULT_PITCH | FF_SWISS);
SetPreferredFontInfo(CP_ARMENIAN, true, iFont, 8, DEFAULT_PITCH | FF_SWISS);
SetPreferredFontInfo(CP_ARMENIAN, false, iFont, 10, DEFAULT_PITCH | FF_SWISS);
}
_fFEFontInfo = FEDATA_NOT_INIT;
// Check installed keyboard layouts
CheckInstalledKeyboards();
}
void CW32System::CheckInstalledKeyboards()
{
HKL rghkl[MAX_HKLS];
INT cLayouts = ::GetKeyboardLayoutList(MAX_HKLS, rghkl);
LONG cpg;
INT iScript;
for(INT i = 0; i < cLayouts; i++)
{
cpg = ConvertLanguageIDtoCodePage(PRIMARYLANGID(rghkl[i]));
GetCharSet(cpg, &iScript); // Get script index
if(iScript >= 0)
SetPreferredKbd(iScript, rghkl[i]);
}
}
bool CW32System::SetPreferredFontInfo(
int cpg,
bool fUIFont,
SHORT iFont,
BYTE yHeight,
BYTE bPitchAndFamily
)
{
int iPFI;
CLock lock;
GetCharSet( cpg, &iPFI );
if (iPFI == -1)
return false;
if (fUIFont)
{
g_pfinfo[iPFI]._bPitchAndFamilyUI = bPitchAndFamily;
g_pfinfo[iPFI]._yHeightUI = yHeight;
g_pfinfo[iPFI]._iFontUI = iFont;
}
else
{
g_pfinfo[iPFI]._bPitchAndFamilyOther = bPitchAndFamily;
g_pfinfo[iPFI]._yHeightOther = yHeight;
g_pfinfo[iPFI]._iFontOther = iFont;
}
SetFontLegitimateSize(iFont, fUIFont, yHeight & ~NEED_TO_CHECK_FONT, cpg);
return true;
}
bool CW32System::GetPreferredFontInfo(
int cpg,
bool fUIFont,
SHORT& iFont,
BYTE& yHeight,
BYTE& bPitchAndFamily
)
{
int iPFI;
if (GetCharSet( cpg, &iPFI ) && (iPFI == -1))
return false;
if (g_pfinfo[iPFI]._iFontUI == 0)
{
/* No entry. Try default */
iPFI = 0;
}
if (fUIFont)
{
bPitchAndFamily = g_pfinfo[iPFI]._bPitchAndFamilyUI;
yHeight = g_pfinfo[iPFI]._yHeightUI;
iFont = g_pfinfo[iPFI]._iFontUI;
}
else
{
bPitchAndFamily = g_pfinfo[iPFI]._bPitchAndFamilyOther;
yHeight = g_pfinfo[iPFI]._yHeightOther;
iFont = g_pfinfo[iPFI]._iFontOther;
}
if (yHeight & NEED_TO_CHECK_FONT)
{
// Check if the preferred font is installed in the system.
CLock lock;
HDC hDC = GetScreenDC();
// Turn off the checkfont bit
yHeight &= ~NEED_TO_CHECK_FONT;
if (fUIFont)
g_pfinfo[iPFI]._yHeightUI &= ~NEED_TO_CHECK_FONT;
else
g_pfinfo[iPFI]._yHeightOther &= ~NEED_TO_CHECK_FONT;
if (hDC)
{
const short *pFontIndex = fUIFont ? &g_pfinfo[iPFI]._iFontUI : &g_pfinfo[iPFI]._iFontOther;
if (IsFontAvail( hDC, cpg, fUIFont, (short *)pFontIndex))
iFont = *pFontIndex;
}
}
return true;
}
/*
* CW32System::GetPreferredFontHeight(
* bool fUIFont,
* BYTE bOrgCharSet,
* BYTE bNewCharSet,
* SHORT yOrgHeight)
*
*
* @mfunc
* called when we need the default font size when changing from one charset to another.
*
* @rdesc
* The preferred default font size in TWIP if the Original height is same as the
* original charset default font size. Otherwise, it will return the Original height.
*
*/
SHORT CW32System::GetPreferredFontHeight(
bool fUIFont,
BYTE bOrgCharSet,
BYTE bNewCharSet,
SHORT yOrgHeight
)
{
BYTE yOrgPreferredHeight;
LONG idxOrgFont = ScriptIndexFromCharSet(bOrgCharSet);
LONG idxNewFont = ScriptIndexFromCharSet(bNewCharSet);
// No entry, forget it
if (idxOrgFont == -1 || idxNewFont == -1)
return yOrgHeight;
yOrgPreferredHeight = fUIFont ?
g_pfinfo[idxOrgFont]._yHeightUI : g_pfinfo[idxOrgFont]._yHeightOther;
// Get New Preferred Height
if (yOrgPreferredHeight && yOrgPreferredHeight == yOrgHeight/TWIPS_PER_POINT)
{
BYTE yNewHeight = (fUIFont ?
g_pfinfo[idxNewFont]._yHeightUI : g_pfinfo[idxNewFont]._yHeightOther);
if (yNewHeight)
return yNewHeight * TWIPS_PER_POINT;
}
return yOrgHeight;
}
/*
* CW32System::CheckInstalledFEFonts()
*
*
* @mfunc
* called when building FE fonts installed and User default LCID info
*
* @devnote
* This information is necessary when we want to classify Chinese characters
* and Full-width characters.
*
*/
void CW32System::CheckInstalledFEFonts()
{
UINT uUserCodepage;
CLock cLock;
HDC hDC = GetScreenDC();
_fFEFontInfo = 0;
uUserCodepage = ConvertLanguageIDtoCodePage(::GetUserDefaultLCID());
if (!IsFECodePage(uUserCodepage))
uUserCodepage = GetACP();
switch (uUserCodepage)
{
case CP_JAPAN:
_fFEFontInfo |= (FEUSER_LCID | FEUSER_CP_JPN | JPN_FONT_AVAILABLE);
break;
case CP_KOREAN:
_fFEFontInfo |= (FEUSER_LCID | FEUSER_CP_KOR | KOR_FONT_AVAILABLE);
break;
case CP_CHINESE_TRAD:
_fFEFontInfo |= (FEUSER_LCID | FEUSER_CP_BIG5 | BIG5_FONT_AVAILABLE);
break;
case CP_CHINESE_SIM:
_fFEFontInfo |= (FEUSER_LCID | FEUSER_CP_GB | GB_FONT_AVAILABLE);
break;
}
if (hDC)
{
if (!(_fFEFontInfo & JPN_FONT_AVAILABLE) && IsFontAvail(hDC, CP_JAPAN))
_fFEFontInfo |= JPN_FONT_AVAILABLE;
if (!(_fFEFontInfo & KOR_FONT_AVAILABLE) && IsFontAvail(hDC, CP_KOREAN))
_fFEFontInfo |= KOR_FONT_AVAILABLE;
if (!(_fFEFontInfo & BIG5_FONT_AVAILABLE) && IsFontAvail(hDC, CP_CHINESE_TRAD))
_fFEFontInfo |= BIG5_FONT_AVAILABLE;
if (!(_fFEFontInfo & GB_FONT_AVAILABLE) && IsFontAvail(hDC, CP_CHINESE_SIM))
_fFEFontInfo |= GB_FONT_AVAILABLE;
}
}
/*
* CW32System::IsFEFontInSystem( cpg )
*
*
* @mfunc
* check if there is any FE font installed for the given codepage
*
* @devnote
* This information is necessary when we want to classify Chinese characters
* and Full-width characters.
*
*/
bool CW32System::IsFEFontInSystem(int cpg)
{
int fFontExist = 0;
if (_fFEFontInfo == FEDATA_NOT_INIT)
{
CLock Lock;
// Look for FE fonts in the system
CheckInstalledFEFonts();
}
// Check if font for the codepage is in the system
switch (cpg)
{
case CP_JAPAN:
fFontExist = _fFEFontInfo & JPN_FONT_AVAILABLE;
break;
case CP_KOREAN:
fFontExist = _fFEFontInfo & KOR_FONT_AVAILABLE;
break;
case CP_CHINESE_TRAD:
fFontExist = _fFEFontInfo & BIG5_FONT_AVAILABLE;
break;
case CP_CHINESE_SIM:
fFontExist = _fFEFontInfo & GB_FONT_AVAILABLE;
break;
}
return (fFontExist != 0);
}
/*
* CW32System::IsFontAvail( HDC hDC, int cpg, bool fUIFont, short *piFontIndex )
*
*
* @mfunc
* called when checking if a font (UI or non-UI) is installed for a given codepage
*
* @devnote
* We will try to create the font and verify the charset of the font
* actually created. If the fontname index is supplied, we will check
* if the requested font is installed. If the name from GDI is different,
* the GDI font index will be returned in piFontIndex.
*
* @rdesc
* true if a font that supports the given codepage is available.
*/
bool CW32System::IsFontAvail(
HDC hDC, //@parm Screen hDC
int cpg, //@parm cpg
bool fUIFont, //@parm UI font?
short *piFontIndex) //@parm Font Name Index (default = NULL)
{
LOGFONTW lf;
HFONT hfont;
bool retCode = false;
int iPFI;
BYTE bCharSet;
if ((bCharSet = GetCharSet(cpg, &iPFI)) && (iPFI == -1))
return false;
ZeroMemory(&lf, sizeof(lf));
// We want GDI to find a font that will support this charset
// Unspecified entries in LOGFONT will be either default or don't care.
lf.lfCharSet = bCharSet;
if (fUIFont)
{
lf.lfHeight = g_pfinfo[iPFI]._yHeightUI;
lf.lfPitchAndFamily = g_pfinfo[iPFI]._bPitchAndFamilyUI;
wcscpy(lf.lfFaceName, GetFontName((LONG)(g_pfinfo[iPFI]._iFontUI)));
}
else
{
lf.lfHeight = g_pfinfo[iPFI]._yHeightOther;
lf.lfPitchAndFamily = g_pfinfo[iPFI]._bPitchAndFamilyOther;
wcscpy(lf.lfFaceName, GetFontName((LONG)(g_pfinfo[iPFI]._iFontOther)));
}
hfont = CreateFontIndirect(&lf);
if(hfont)
{
TEXTMETRIC tm;
HFONT hfontOld = SelectFont(hDC, hfont);
if (GetTextMetrics(hDC, &tm) && tm.tmCharSet == bCharSet)
{
retCode = true;
if (piFontIndex)
{
const WCHAR *pszFontName = GetFontName(*piFontIndex);
if (pszFontName)
{
WCHAR szNewFaceName[LF_FACESIZE];
// Check if GDI gives us the same font name
szNewFaceName[0] = L'\0';
GetTextFace(hDC, LF_FACESIZE, szNewFaceName);
if (szNewFaceName[0] && wcsicmp(pszFontName, szNewFaceName))
*piFontIndex = GetFontNameIndex(szNewFaceName); // Different name
}
}
}
SelectFont(hDC, hfontOld);
DeleteObject(hfont);
}
return retCode;
}
/*
* CW32System::GetFEFontInfo( void )
*
*
* @mfunc
* called when classifying Chinese characters and Full-width characters
*
* @devnote
* Chinese characters and Full-width characters can be in any
* of the four FE codepages. We want to classfy them according to the
* User default LCID and which FE fonts are installed in the system.
*
* @rdesc
* Codepage for the character.
*/
UINT CW32System::GetFEFontInfo()
{
int iDefUserCodepage = -1;
if (_fFEFontInfo == FEDATA_NOT_INIT)
{
CLock Lock;
// Check if FE fonts are available in the system
CheckInstalledFEFonts();
}
if (_fFEFontInfo & FEUSER_LCID)
iDefUserCodepage = (_fFEFontInfo & FEUSER_CODEPAGE);
if (iDefUserCodepage == FEUSER_CP_BIG5)
return CP_CHINESE_TRAD;
if (iDefUserCodepage == FEUSER_CP_GB)
return CP_CHINESE_SIM;
if (iDefUserCodepage == FEUSER_CP_JPN)
return CP_JAPAN;
if (iDefUserCodepage == FEUSER_CP_KOR)
return CP_KOREAN;
// Check which font is available and return the corresponding codepage
// We check for Simplified Chinese first since it contains more Chinese
// characters than Traditional Chinese.
if (_fFEFontInfo & GB_FONT_AVAILABLE)
return CP_CHINESE_SIM;
if (_fFEFontInfo & BIG5_FONT_AVAILABLE)
return CP_CHINESE_TRAD;
if (_fFEFontInfo & JPN_FONT_AVAILABLE)
return CP_JAPAN;
if (_fFEFontInfo & KOR_FONT_AVAILABLE)
return CP_KOREAN;
return CP_CHINESE_SIM; // Well, no FE font, tough luck.
}
/*
* CW32System::IsDiacriticOrKashida(ch, wC3Type)
*
* @mfunc
* Return TRUE if ch or wC3Type reveals that ch is a nonspacing
* diacritic or a kashida. Because Win9x GetStringTypeExW isn't
* implemented, we use range checks for Win9x.
*
* @rdesc
* True if ch or wC3Type reveals that ch is a nonspacing diacritic
*/
BOOL CW32System::IsDiacriticOrKashida(
WCHAR ch, //@parm On Win9x, check ranges for ch
WORD wC3Type) //@parm On WinNT, use C3-type check
{
if(VER_PLATFORM_WIN32_WINDOWS != _dwPlatformId && wC3Type)
return wC3Type & (C3_DIACRITIC | C3_NONSPACING | C3_VOWELMARK | C3_KASHIDA);
if(!IN_RANGE(0x300, ch, 0xe50)) // Combining diacritics of interest
return FALSE; // fall in this range
return IN_RANGE(0x300, ch, 0x36F) || IsDiacritic(ch) || IsBiDiKashida(ch);
}
/*
* CW32System::IsDiacritic(ch)
*
* @mfunc
* Return TRUE if ch falls in BiDi, Thai, Devanagari or Tamil diacritic range.
*/
BOOL CW32System::IsDiacritic(
WCHAR ch)
{
// BiDi
if (IsBiDiDiacritic(ch))
return TRUE;
// Thai
if (IN_RANGE(0xe31, ch, 0xe4e))
return IN_RANGE(0x0e47, ch, 0x0e4e) || IN_RANGE(0x0e34, ch, 0x0e3a) || ch == 0x0e31;
// Devanagari
if (IN_RANGE(0x0902, ch, 0x0963))
return IN_RANGE(0x0941, ch, 0x0948) || IN_RANGE(0x0951, ch, 0x0954) || ch == 0x094d ||
IN_RANGE(0x0962, ch, 0x0963) || IN_RANGE(0x0901, ch, 0x0902) || ch == 0x093c;
// Tamil
if (IN_RANGE(0x0b82, ch, 0x0bcd))
return ch == 0x0bcd || ch == 0x0bc0 || ch == 0x0b82;
return FALSE;
}