FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour bug fix FWH: Fix Chinese IME garble on MDICHILD + Resource Dialog + TGET
Posts: 139
Joined: Mon Oct 17, 2005 03:03 AM

bug fix FWH: Fix Chinese IME garble on MDICHILD + Resource Dialog + TGET

Posted: Wed Sep 23, 2026 06:06 AM

中文:
FWH:修正 MDICHILD + Resource Dialog + TGET 中文輸入法亂碼
這個 bug 存在許多年了,一直沒有解決!
今天透過 AI 解決了這個問題!

English:
FWH: Fix Chinese IME garble on MDICHILD + Resource Dialog + TGET
This bug has existed for many years and was never fixed.
Today it was finally solved with the help of AI!

https://www4.zzz.com.tw/phpBB3/viewtopic.php?f=2&t=379

patch_isdialogmessage.c

/*
 * Smart IsDialogMessage:
 *   FW_SetUnicode(.T.) -> IsDialogMessageW  (fixes Unicode modeless CJK IME)
 *   FW_SetUnicode(.F.) -> real IsDialogMessageA (ANSI/Big5 modeless must stay A)
 *
 * FWH message loop always imports IsDialogMessageA; we IAT-hook it.
 */
#include <Windows.h>
#include <hbapi.h>
#include "hbinit.h"

#ifndef _WIN64

#ifndef IMAGE_ORDINAL_FLAG32
#define IMAGE_ORDINAL_FLAG32 IMAGE_ORDINAL_FLAG
#endif

BOOL FW_GetUnicode( void );

typedef BOOL ( WINAPI * PFN_IsDialogMessageA )( HWND, LPMSG );

static PFN_IsDialogMessageA s_pRealIsDialogMessageA = NULL;

static BOOL WINAPI FW_IsDialogMessageDispatch( HWND hDlg, LPMSG lpMsg )
{
   if( FW_GetUnicode() )
      return IsDialogMessageW( hDlg, lpMsg );

   if( s_pRealIsDialogMessageA )
      return s_pRealIsDialogMessageA( hDlg, lpMsg );

   return IsDialogMessageA( hDlg, lpMsg );
}

static BOOL PatchIAT( HMODULE hMod, const char * cDll, const char * cFunc, PROC pNew )
{
   PIMAGE_DOS_HEADER pDos;
   PIMAGE_NT_HEADERS pNt;
   PIMAGE_IMPORT_DESCRIPTOR pImp;
   DWORD nImpRva;

   if( ! hMod )
      return FALSE;

   pDos = (PIMAGE_DOS_HEADER) hMod;
   if( pDos->e_magic != IMAGE_DOS_SIGNATURE )
      return FALSE;

   pNt = (PIMAGE_NT_HEADERS)( (BYTE *) hMod + pDos->e_lfanew );
   if( pNt->Signature != IMAGE_NT_SIGNATURE )
      return FALSE;

   nImpRva = pNt->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ].VirtualAddress;
   if( ! nImpRva )
      return FALSE;

   pImp = (PIMAGE_IMPORT_DESCRIPTOR)( (BYTE *) hMod + nImpRva );

   for( ; pImp->Name; pImp++ )
   {
      char * cName = (char *)( (BYTE *) hMod + pImp->Name );
      PIMAGE_THUNK_DATA pThunk;
      PIMAGE_THUNK_DATA pOrig;
      DWORD nOrigRva;

  if( lstrcmpiA( cName, cDll ) != 0 )
     continue;

  nOrigRva = pImp->OriginalFirstThunk ? pImp->OriginalFirstThunk : pImp->FirstThunk;
  pOrig  = (PIMAGE_THUNK_DATA)( (BYTE *) hMod + nOrigRva );
  pThunk = (PIMAGE_THUNK_DATA)( (BYTE *) hMod + pImp->FirstThunk );

  for( ; pOrig->u1.AddressOfData; pOrig++, pThunk++ )
  {
     PIMAGE_IMPORT_BY_NAME pBy;
     DWORD dwOld;

     if( pOrig->u1.Ordinal & IMAGE_ORDINAL_FLAG32 )
        continue;

     pBy = (PIMAGE_IMPORT_BY_NAME)( (BYTE *) hMod + pOrig->u1.AddressOfData );
     if( lstrcmpA( (char *) pBy->Name, cFunc ) != 0 )
        continue;

     if( VirtualProtect( &pThunk->u1.Function, sizeof( PROC ),
                         PAGE_READWRITE, &dwOld ) )
     {
        pThunk->u1.Function = (ULONG_PTR) pNew;
        VirtualProtect( &pThunk->u1.Function, sizeof( PROC ), dwOld, &dwOld );
        return TRUE;
     }
  }
   }
   return FALSE;
}

static void fw_patch_isdlg( void )
{
   HMODULE hUser;
   HMODULE hExe;

   if( s_pRealIsDialogMessageA == NULL )
   {
      hUser = GetModuleHandleA( "user32.dll" );
      if( hUser )
         s_pRealIsDialogMessageA =
            ( PFN_IsDialogMessageA ) GetProcAddress( hUser, "IsDialogMessageA" );
   }

   hExe = GetModuleHandleA( NULL );
   PatchIAT( hExe, "USER32.dll", "IsDialogMessageA",
             (PROC) FW_IsDialogMessageDispatch );
   PatchIAT( hExe, "user32.dll", "IsDialogMessageA",
             (PROC) FW_IsDialogMessageDispatch );
}

HB_CALL_ON_STARTUP_BEGIN( _fw_patch_isdialogmessage )
   fw_patch_isdlg();
HB_CALL_ON_STARTUP_END( _fw_patch_isdialogmessage )

#if defined( HB_PRAGMA_STARTUP )
   #pragma startup _fw_patch_isdialogmessage
#elif defined( HB_DATASEG_STARTUP )
   #define HB_DATASEG_BODY HB_DATASEG_FUNC( _fw_patch_isdialogmessage )
   #include "hbiniseg.h"
#endif

HB_FUNC( FW_PATCHISDIALOGMESSAGE )
{
   fw_patch_isdlg();
   hb_retl( TRUE );
}

#endif /* !_WIN64 */

your main.prg

   HB_CDPSELECT( "UTF8" )
   FW_SetUnicode( .T. )
   FW_PatchIsDialogMessage()

fix window.prg ::Link()

      if lSubClass
         // add:2026.09.23: 解決 folder 內的 tget 無法輸入中文字問題.
         //::nOldProc = XXChangeProc( ::hWnd, nAt, ::lxUnicode )
         // FW Unicode: always Unicode subclass so WM_CHAR delivers full codepoints
         // (Resource ANSI EDITTEXT otherwise LOBYTE-truncates Chinese to -:,f).
         ::nOldProc = XXChangeProc( ::hWnd, nAt,;
               IsWindowUnicode( ::hWnd ) .or. FW_SetUnicode() )
      endif
line ID: ssbbstw

WeChat ID: ssbbstw
Posts: 150
Joined: Fri Sep 25, 2026 01:40 AM

Re: bug fix FWH: Fix Chinese IME garble on MDICHILD + Resource Dialog + TGET

Posted: Fri Sep 25, 2026 01:51 AM

Hi ssbbs,

Thanks for sharing this - we reviewed the patch against the current FWH sources and your diagnosis matches what is in the code. There is also a way to reach the same result without IAT patching.

1) The modeless-dialog path. The FWH message loop (source/internal/wndrun.c, the two IsDialogMessage calls around lines 145 and 151) always resolves to IsDialogMessageA in the standard FWH build, even when FW_SetUnicode(.T.) is on. That is exactly the garble you describe on MDICHILD + resource dialogs, and dispatching to IsDialogMessageW is the right idea. The same dispatch can be done inside FWH itself, so no per-application IAT hook is needed.

2) The subclass side. Your window.prg Link() change targets the right spot, but note that in the current source/internal/xxproc.c, XXChangeProc() chooses the ANSI or Unicode subclass only from IsWindowUnicode(hWnd) - the lUnicode parameter and the FW_GetUnicode() fallback are commented out (line 28). So the PRG change alone has no effect today; xxproc.c needs the equivalent condition restored, e.g.:

if( ! IsWindowUnicode( hWnd ) && ! ( HB_ISLOG( 3 ) ? hb_parl( 3 ) : FW_GetUnicode() ) )

With that, an ANSI EDITTEXT created from a resource script gets a Unicode subclass whenever FW_SetUnicode(.T.) is on, and WM_CHAR delivers full codepoints instead of the LOBYTE truncation you mention.

3) One detail: FW_GetUnicode() is declared in xxproc.c but is not exported by the current libs, so a standalone patch_isdialogmessage.c linking against it will need its own getter (from PRG, FW_SetUnicode() with no argument returns the current flag).

Summary: the clean fix is two small library changes (the IsDialogMessageW dispatch in wndrun.c, plus honoring lUnicode/FW_GetUnicode in xxproc.c) instead of a per-app IAT patch. We will evaluate integrating that so Chinese IME works out of the box on MDICHILD + resource dialogs. Thanks for the detailed write-up.

Posts: 139
Joined: Mon Oct 17, 2005 03:03 AM

Re: bug fix FWH: Fix Chinese IME garble on MDICHILD + Resource Dialog + TGET

Posted: Fri Sep 25, 2026 02:46 AM

Are you sure the package file our users received contains all files in the .\source\internal\ directory?

line ID: ssbbstw

WeChat ID: ssbbstw
Posts: 150
Joined: Fri Sep 25, 2026 01:40 AM

Re: bug fix FWH: Fix Chinese IME garble on MDICHILD + Resource Dialog + TGET

Posted: Fri Sep 25, 2026 04:18 AM

Hi ssbbs, good catch, and you're right to ask. The files under source\internal are not part of the package users receive, so my earlier reply pointed at code you can't see or patch yourself. Sorry for the confusion. The practical takeaway is the same: the fix belongs inside the FWH library, so nobody needs a per-app IAT hook. Antonio and the team will decide on including it in a coming FWH build. Until then, your patch is a valid workaround for 32-bit builds.

Continue the discussion