Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Unicode support for DDT

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Unicode support for DDT

    The following modules make it possible to use Unicode strings with DDT. The tool
    replaces the calls to ANSI functions inside the EXE files' import header with calls
    to UNICODE. If unicode API is not available, then function call parameters are translated
    back to ANSI.
    Please note that this is beta code at best, and not all DDT functionality has been tested;
    so use at your own risk. I already have successfully translated an application to UNICODE using that
    tool, however, some manual corrections might be necessary.

    Please add the following lines of code to your application before including the modules:
    Code:
    MACRO DbgEnter(x) = ! nop
    MACRO DbgLeave(x) = ! nop
    MACRO Dbg(x) = ! nop
    %TEST_UNICODE_ANSI = 0

    ------------------

  • #2
    Header file UCWRAP.BI

    Code:
    %IMAGE_ORDINAL_FLAG = &H80000000
    
    TYPE IMAGE_IMPORT_BY_NAME
        Hint AS WORD
        ImpName AS ASCIIZ * 254
    
    END TYPE
    
    TYPE IMAGE_IMPORT_DESCRIPTOR
        OriginalFirstThunk AS DWORD
        TimeDateStamp AS DWORD
        ForwarderChain AS DWORD
        pName AS DWORD
        FirstThunk AS DWORD
    
    END TYPE
    
    TYPE UCWrapper_FunctionPointersType
        pCreateDialogIndirectParam AS DWORD
        pCreateWindowEx AS DWORD
        pDispatchMessage AS DWORD
        pGetMenuItemInfo AS DWORD      ' not needed?
        pGetWindowLong AS DWORD        ' not needed? doesn't retrieve any unicode strings
        pGetWindowText AS DWORD
        pGetWindowTextLength AS DWORD
        pIsDialogMessage AS DWORD
        pLoadImage AS DWORD            ' not needed
        pMessageBox AS DWORD
        pPeekMessage AS DWORD
        pPostMessage AS DWORD
        pSendMessage AS DWORD
        pSetWindowLong AS DWORD        ' not needed
        pSetWindowText AS DWORD
        pSystemParametersInfo AS DWORD ' not needed
        pInsertMenuItem AS DWORD
    
    END TYPE
    
    TYPE UCWrapper_UCWrapperType
        fp AS UCWrapper_FunctionPointersType
    
        lUseUnicode AS LONG                 ' use unicode flag
    
    END TYPE
    
    GLOBAL gUCWrapper AS UCWrapper_UCWrapperType
    
    DECLARE FUNCTION UCWrapper_Dyn_TextOut(BYVAL hdc AS LONG, BYVAL nXStart AS LONG, BYVAL nYStart AS LONG, BYVAL lpString AS DWORD, BYVAL cbString AS LONG) AS LONG
    DECLARE FUNCTION UCWrapper_Dyn_DrawText(BYVAL hdc AS LONG, BYVAL lpString AS DWORD, BYVAL nCount AS LONG,  BYVAL lpRect AS DWORD, BYVAL uFormat AS DWORD) AS LONG
    DECLARE FUNCTION UCWrapper_GetUnicodeSZString(BYVAL lpAddress AS DWORD) AS STRING
    DECLARE FUNCTION UCWrapper_CreateDialogIndirectParam(BYVAL hInstance AS LONG, BYVAL lpTemplate AS DWORD, BYVAL hwndParent AS LONG, BYVAL lpDialogFunc AS DWORD, _
                                                 BYVAL lParamInit AS LONG) AS LONG
    DECLARE FUNCTION UCWrapper_CreateWindowEx(BYVAL dwExStyle AS DWORD, BYVAL lpClassName AS DWORD, BYVAL lpWindowName AS DWORD, BYVAL dwStyle AS DWORD, BYVAL x AS LONG, _
                                      BYVAL y AS LONG, BYVAL nWidth AS LONG, BYVAL nHeight AS LONG, BYVAL hwndParent AS LONG, BYVAL hMenu AS LONG, _
                                      BYVAL hInstance AS LONG, BYVAL lpParam AS LONG) AS LONG
    DECLARE FUNCTION UCWrapper_DispatchMessage(BYVAL lpmsg AS DWORD) AS LONG
    DECLARE FUNCTION UCWrapper_GetWindowText(BYVAL hwnd AS LONG, BYVAL lpString AS DWORD, BYVAL nMaxCount AS LONG) AS LONG
    DECLARE FUNCTION UCWrapper_GetWindowTextLength(BYVAL hwnd AS LONG) AS LONG
    DECLARE FUNCTION UCWrapper_IsDialogMessage(BYVAL hDlg AS LONG, BYVAL lpmsg AS DWORD) AS LONG
    DECLARE FUNCTION UCWrapper_MessageBox(BYVAL hwnd AS LONG, BYVAL lpText AS DWORD, BYVAL lpCaption AS DWORD, BYVAL uType AS DWORD) AS LONG
    DECLARE FUNCTION UCWrapper_PeekMessage(BYVAL lpmsg AS DWORD, BYVAL hwnd AS LONG, BYVAL wMsgFilterMin AS LONG, BYVAL wMsgFilterMax AS LONG, _
                                   BYVAL wRemoveMsg AS LONG) AS LONG
    DECLARE FUNCTION UCWrapper_PostMessage(BYVAL hwnd AS LONG, BYVAL msg AS DWORD, BYVAL wparam AS DWORD, BYVAL lparam AS DWORD) AS LONG
    DECLARE FUNCTION UCWrapper_SendMessage(BYVAL hwnd AS LONG, BYVAL msg AS DWORD, BYVAL wparam AS DWORD, BYVAL lparam AS DWORD) AS LONG
    DECLARE FUNCTION UCWrapper_SetWindowText(BYVAL hwnd AS LONG, BYVAL lpString AS DWORD) AS LONG
    DECLARE FUNCTION UCWrapper_PatchFunction(BYVAL hModule AS DWORD, BYVAL hLib AS LONG, sFuncName AS STRING, BYVAL pPatch AS DWORD) AS DWORD
    DECLARE SUB UCWrapper_PatchToUnicode
    DECLARE FUNCTION InternalGetWindowText (BYVAL hWnd AS LONG, lpString AS ASCIIZ, BYVAL cch AS LONG) AS LONG

    ------------------

    Comment


    • #3
      Source file UCWRAP.INC

      Code:
      FUNCTION UCWrapper_InsertMenuItem(BYVAL hMenu AS LONG, BYVAL uItem AS DWORD, BYVAL fByPosition AS LONG, BYVAL lpmii AS DWORD) AS LONG
          ' insert menu item call stub
          DbgEnter("UCWrapper_InsertMenuItem")
      
          LOCAL sTxt AS STRING
          LOCAL lRet AS LONG
          LOCAL pmii AS MENUITEMINFO PTR
          LOCAL mii AS MENUITEMINFO
      
          pmii = lpmii
          mii = @pmii
          IF ISFALSE gUCWrapper.lUseUnicode AND ISFALSE mii.fType THEN
              ' transform to ansi
              sTxt = UCWrapper_GetUnicodeSZString(mii.dwTypeData)
              sTxt = ACODE$(sTxt) + $NUL
              mii.dwTypeData = STRPTR(sTxt)
      
          END IF
      
          CALL DWORD gUCWrapper.fp.pInsertMenuItem USING UCWrapper_InsertMenuItem(hMenu, uItem, fByPosition, VARPTR(mii)) TO lRet
      
          DbgLeave("UCWrapper_InsertMenuItem")
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_Dyn_TextOut(BYVAL hdc AS LONG, BYVAL nXStart AS LONG, BYVAL nYStart AS LONG, BYVAL lpString AS DWORD, BYVAL cbString AS LONG) AS LONG
          ' always-unicode-textout for use inside prog (no hooking / patching)
          DbgEnter("UCWrapper_Dyn_TextOut")
          STATIC hLib AS LONG
          STATIC hProc AS LONG
      
          LOCAL sTxt AS STRING
          LOCAL lRet AS LONG
      
          IF hProc = 0 THEN
              hLib = GetModuleHandle("GDI32.DLL")
              hProc = GetProcAddress(hLib, "TextOut" + IIF$(gUCWrapper.lUseUnicode, "W", "A"))
      
          END IF
      
          IF hProc THEN
              IF ISFALSE gUCWrapper.lUseUnicode THEN
                  sTxt = ACODE$(UCWrapper_GetUnicodeSZString(lpString)) + $NUL
                  CALL DWORD hProc USING UCWrapper_Dyn_TextOut(hdc, nXStart, nYStart, STRPTR(sTxt), cbString) TO lRet
      
              ELSE
                  CALL DWORD hProc USING UCWrapper_Dyn_TextOut(hdc, nXStart, nYStart, lpString, cbString) TO lRet
      
              END IF
      
          END IF
      
          DbgLeave("UCWrapper_Dyn_TextOut")
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_Dyn_DrawText(BYVAL hdc AS LONG, BYVAL lpString AS DWORD, BYVAL nCount AS LONG,  BYVAL lpRect AS DWORD, BYVAL uFormat AS DWORD) AS LONG
          ' always-unicode-drawtext for use inside prog (no hooking/patching)
          DbgEnter("UCWrapper_Dyn_DrawText")
      
          STATIC hLib AS LONG
          STATIC hProc AS LONG
      
          LOCAL sTxt AS STRING
          LOCAL lRet AS LONG
      
          IF hProc = 0 THEN
              hLib = GetModuleHandle("USER32.DLL")
              hProc = GetProcAddress(hLib, "DrawText" + IIF$(gUCWrapper.lUseUnicode, "W", "A"))
      
          END IF
      
          IF hProc THEN
              IF ISFALSE gUCWrapper.lUseUnicode THEN
                  sTxt = ACODE$(UCWrapper_GetUnicodeSZString(lpString)) + $NUL
                  CALL DWORD hProc USING UCWrapper_Dyn_DrawText(hdc, STRPTR(sTxt), nCount, lpRect, uFormat) TO lRet
      
              ELSE
                  CALL DWORD hProc USING UCWrapper_Dyn_DrawText(hdc, lpString, nCount, lpRect, uFormat) TO lRet
      
              END IF
      
          END IF
      
          DbgLeave("UCWrapper_Dyn_DrawText")
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_GetUnicodeSZString(BYVAL lpAddress AS DWORD) AS STRING
          ' returns unicode string at lpAddress
          LOCAL pw AS WORD PTR
          LOCAL sRet AS STRING
          DbgEnter("UCWrapper_GetUnicodeSZString")
      
          IF lpAddress THEN
              pw = lpAddress
      
              DO WHILE @pw
                  sRet = sRet + MKWRD$(@pw)
      
                  pw = pw + 2
      
              LOOP
      
          END IF
      
          DbgLeave("UCWrapper_GetUnicodeSZString")
          FUNCTION = sRet
      END FUNCTION
      
      #IF 0 ' NOT NEEDED
      FUNCTION UCWrapper_MultiByteToWideChar(BYVAL CodePage AS DWORD, BYVAL dwFlags AS DWORD, BYVAL lpMultiByteStr AS DWORD, BYVAL cbMultiByte AS LONG, _
                                             BYVAL lpWideCharStr AS DWORD, BYVAL cchWideChar AS LONG) AS LONG
          ' patches the multibytetowidechar function so it does NO conversion when creating the dialog box template
          DbgEnter("UCWrapper_MultiByteToWideChar")
          LOCAL szStr AS ASCIIZ PTR
          LOCAL sStr AS STRING
          LOCAL lRet AS LONG
      
      
          IF cbMultiByte = -1 THEN
              szStr = lpMultiByteStr
              sStr = @szStr + $NUL + $NUL
      
          ELSE
              sStr = PEEK$(lpMultiByteStr, cbMultiByte)
      
          END IF
      
          lRet = LEN(sStr)
      
          PRINT #1, sStr + $CRLF
      
          IF ISTRUE lpWideCharStr AND ISTRUE cchWideChar THEN
              POKE$ lpWideCharStr, sStr
      
          END IF
      
          DbgLeave("UCWrapper_MultiByteToWideChar")
      
          FUNCTION = lRet
      END FUNCTION
      #ENDIF
      
      FUNCTION UCWrapper_CreateDialogIndirectParam(BYVAL hInstance AS LONG, BYVAL lpTemplate AS DWORD, BYVAL hwndParent AS LONG, BYVAL lpDialogFunc AS DWORD, _
                                                   BYVAL lParamInit AS LONG) AS LONG
          DbgEnter("UCWrapper_CreateDialogIndirectParam")
          LOCAL lLastChar AS LONG
          LOCAL pwChar AS WORD PTR
          LOCAL sTitle AS STRING
      
          LOCAL dwStart AS LONG
          LOCAL dwLen AS LONG
      
          LOCAL lRet AS LONG
      
          ' since PB converts to unicode, we have to re-convert the "ultra-wide-char" title back to wide-char.
          pwChar = lpTemplate + SIZEOF(DLGTEMPLATE) + 4
      
          DO UNTIL @pwChar = 0 AND lLastChar = 0
              IF @pwChar THEN sTitle = sTitle + MKWRD$(@pwChar)
      
              lLastChar = @pwChar
              pwChar = pwChar + 2
      
          LOOP
      
          pwChar = pwChar + 2
          dwStart = pwChar
      
          DO UNTIL @pwChar = 0
              dwLen = dwLen + 2
              pwChar = pwChar + 2
      
          LOOP
      
          sTitle = sTitle + NUL$(2)
          POKE$ lpTemplate + SIZEOF(DLGTEMPLATE) + 4, sTitle
          MoveMemory BYVAL lpTemplate + SIZEOF(DLGTEMPLATE) + 4 + LEN(sTitle) + 0, BYVAL dwStart, dwLen + 2
      
          Dbg("UC: " + FORMAT$(gUCWrapper.lUseUnicode))
          ' no transformation needed
      
          CALL DWORD gUCWrapper.fp.pCreateDialogIndirectParam USING UCWrapper_CreateDialogIndirectParam(hInstance, lpTemplate, hwndParent, lpDialogFunc, _
                     lParamInit) TO lRet
      
          DbgLeave("UCWrapper_CreateDialogIndirectParam")
      
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_CreateWindowEx(BYVAL dwExStyle AS DWORD, BYVAL lpClassName AS DWORD, BYVAL lpWindowName AS DWORD, BYVAL dwStyle AS DWORD, BYVAL x AS LONG, _
                                        BYVAL y AS LONG, BYVAL nWidth AS LONG, BYVAL nHeight AS LONG, BYVAL hwndParent AS LONG, BYVAL hMenu AS LONG, _
                                        BYVAL hInstance AS LONG, BYVAL lpParam AS LONG) AS LONG
          DbgEnter("UCWrapper_CreateWindowEx")
          LOCAL lRet AS LONG
      
          LOCAL pszClass AS ASCIIZ PTR
          LOCAL ucClassName AS STRING
          LOCAL ansiWindowName AS STRING
      
      
          Dbg("UC: " + FORMAT$(gUCWrapper.lUseUnicode))
      
          IF ISFALSE gUCWrapper.lUseUnicode THEN
              'ansiClassName = ACODE$(UCWrapper_GetUnicodeSZString(lpClassName)) + $NUL
              ansiWindowName = ACODE$(UCWrapper_GetUnicodeSZString(lpWindowName)) + $NUL
      
              CALL DWORD gUCWrapper.fp.pCreateWindowEx USING UCWrapper_CreateWindowEx(dwExStyle, BYVAL lpClassName, STRPTR(ansiWindowName), dwStyle, x, y, _
                         nWidth, nHeight, hwndParent, hMenu, hInstance, lpParam) TO lRet
      
          ELSE
              pszClass = lpClassName
              ucClassName = UCODE$(@pszClass) + NUL$(2)
              CALL DWORD gUCWrapper.fp.pCreateWindowEx USING UCWrapper_CreateWindowEx(dwExStyle, STRPTR(ucClassName), lpWindowName, dwStyle, x, y, _
                         nWidth, nHeight, hwndParent, hMenu, hInstance, lpParam) TO lRet
      
          END IF
      
          DbgLeave("UCWrapper_CreateWindowEx")
      
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_DispatchMessage(BYVAL lpmsg AS DWORD) AS LONG
          ' no debug code here -> perf.
          LOCAL lRet AS LONG
      
          CALL DWORD gUCWrapper.fp.pDispatchMessage USING UCWrapper_DispatchMessage(lpmsg) TO lRet
      
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_GetWindowText(BYVAL hwnd AS LONG, BYVAL lpString AS DWORD, BYVAL nMaxCount AS LONG) AS LONG
          DbgEnter("UCWrapper_GetWindowText")
          LOCAL sBuf AS STRING
      
          LOCAL lRet AS LONG
      
          Dbg("UC: " + FORMAT$(gUCWrapper.lUseUnicode))
      
          IF ISFALSE gUCWrapper.lUseUnicode THEN
              sBuf = NUL$(nMaxCount \ 2 - 2)
              CALL DWORD gUCWrapper.fp.pGetWindowText USING UCWrapper_GetWindowText(hwnd, STRPTR(sBuf), nMaxCount) TO lRet
              POKE$ lpString, UCODE$(sBuf) + NUL$(2)
      
          ELSE
              LOCAL hLib AS LONG
              LOCAL hProc AS LONG
      
              hLib = GetModuleHandle("USER32.DLL")
              hProc = GetProcAddress(hLib, "InternalGetWindowText")
      
              IF hProc THEN
                  CALL DWORD hProc USING InternalGetWindowText(hwnd, BYVAL lpString, nMaxCount \ 2) TO lRet
      
                  IF lRet = 0 THEN
                      CALL DWORD gUCWrapper.fp.pGetWindowText USING UCWrapper_GetWindowText(hwnd, lpString, nMaxCount \ 2) TO lRet
      
                  END IF
      
              ELSE
                  CALL DWORD gUCWrapper.fp.pGetWindowText USING UCWrapper_GetWindowText(hwnd, lpString, nMaxCount \ 2) TO lRet
      
              END IF
      
          END IF
      
          DbgLeave("UCWrapper_GetWindowText")
      
          FUNCTION = lRet * 2 ' needed so CONTROL GET TEXT gets right number of characters
      END FUNCTION
      
      FUNCTION UCWrapper_GetWindowTextLength(BYVAL hwnd AS LONG) AS LONG
          DbgEnter("UCWrapper_GetWindowTextLength")
          LOCAL lRet AS LONG
      
          Dbg("UC: " + FORMAT$(gUCWrapper.lUseUnicode))
      
          CALL DWORD gUCWrapper.fp.pGetWindowTextLength USING UCWrapper_GetWindowTextLength(hwnd) TO lRet
      
          IF gUCWrapper.lUseUnicode THEN
              ' return double length so double buffer is allocated
              lRet = lRet * 2 + 2
      
          END IF
      
          DbgLeave("UCWrapper_GetWindowTextLength")
      
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_IsDialogMessage(BYVAL hDlg AS LONG, BYVAL lpmsg AS DWORD) AS LONG
          ' no debug code here -> perf.
          LOCAL lRet AS LONG
      
          CALL DWORD gUCWrapper.fp.pIsDialogMessage USING UCWrapper_IsDialogMessage(hDlg, lpmsg) TO lRet
      
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_MessageBox(BYVAL hwnd AS LONG, BYVAL lpText AS DWORD, BYVAL lpCaption AS DWORD, BYVAL uType AS DWORD) AS LONG
          DbgEnter("UCWrapper_MessageBox")
          LOCAL lRet AS LONG
          LOCAL ansiText AS STRING
          LOCAL ansiCaption AS STRING
      
          Dbg("UC: " + FORMAT$(gUCWrapper.lUseUnicode))
      
          IF ISFALSE gUCWrapper.lUseUnicode THEN
              ' transform to ansi
              ansiText = ACODE$(UCWrapper_GetUnicodeSZString(lpText)) + $NUL
              ansiCaption = ACODE$(UCWrapper_GetUnicodeSZString(lpCaption)) + $NUL
      
              CALL DWORD gUCWrapper.fp.pMessageBox USING UCWrapper_MessageBox(hwnd, STRPTR(ansiText), STRPTR(ansiCaption), uType) TO lRet
      
          ELSE
              ' call directly
              CALL DWORD gUCWrapper.fp.pMessageBox USING UCWrapper_MessageBox(hwnd, lpText, lpCaption, uType) TO lRet
      
          END IF
      
          DbgLeave("UCWrapper_MessageBox")
      
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_PeekMessage(BYVAL lpmsg AS DWORD, BYVAL hwnd AS LONG, BYVAL wMsgFilterMin AS LONG, BYVAL wMsgFilterMax AS LONG, _
                                     BYVAL wRemoveMsg AS LONG) AS LONG
          ' no debug code here -> perf.
          LOCAL lRet AS LONG
      
          CALL DWORD gUCWrapper.fp.pPeekMessage USING UCWrapper_PeekMessage(lpmsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg) TO lRet
      
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_PostMessage(BYVAL hwnd AS LONG, BYVAL msg AS DWORD, BYVAL wparam AS DWORD, BYVAL lparam AS DWORD) AS LONG
          ' no debug code here -> perf.
          LOCAL lRet AS LONG
      
          CALL DWORD gUCWrapper.fp.pPostMessage USING UCWrapper_PostMessage(hwnd, msg, wparam, lparam) TO lRet
      
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_SendMessage(BYVAL hwnd AS LONG, BYVAL msg AS DWORD, BYVAL wparam AS DWORD, BYVAL lparam AS DWORD) AS LONG
          ' no debug code here -> perf.
          LOCAL lRet AS LONG
      
          CALL DWORD gUCWrapper.fp.pSendMessage USING UCWrapper_SendMessage(hwnd, msg, wparam, lparam) TO lRet
      
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_SetWindowText(BYVAL hwnd AS LONG, BYVAL lpString AS DWORD) AS LONG
          DbgEnter("UCWrapper_SetWindowText")
          LOCAL lRet AS LONG
          LOCAL ansiString AS STRING
      
          Dbg("UC: " + FORMAT$(gUCWrapper.lUseUnicode))
      
          IF ISFALSE gUCWrapper.lUseUnicode THEN
              ' transform
              ansiString = ACODE$(UCWrapper_GetUnicodeSZString(lpString)) + $NUL
              CALL DWORD gUCWrapper.fp.pSetWindowText USING UCWrapper_SetWindowText(hwnd, STRPTR(ansiString)) TO lRet
      
          ELSE
              ' call directly
              CALL DWORD gUCWrapper.fp.pSetWindowText USING UCWrapper_SetWindowText(hwnd, lpString) TO lRet
      
          END IF
      
          DbgLeave("UCWrapper_SetWindowText")
      
          FUNCTION = lRet
      END FUNCTION
      
      FUNCTION UCWrapper_PatchFunction(BYVAL hModule AS DWORD, BYVAL hLib AS LONG, sFuncName AS STRING, BYVAL pPatch AS DWORD) AS DWORD
          ' patches a function inside a module
          ' hModule: base address
          ' sFuncName: function to patch
          ' pPatch: pointer to patch function
          ' returns orig function name
          DbgEnter("UCWrapper_PatchFunction")
          LOCAL lpImageDosHeader AS IMAGE_DOS_HEADER PTR
          LOCAL lpImageNtHeaders AS IMAGE_NT_HEADERS PTR
          LOCAL lpImageImportDescriptor AS IMAGE_IMPORT_DESCRIPTOR PTR
          LOCAL lpImageImportByName AS IMAGE_IMPORT_BY_NAME PTR
          LOCAL lpFuncNameRef AS DWORD PTR
          LOCAL lpFuncAddr AS DWORD PTR
          LOCAL flOldProtect AS DWORD
      
          LOCAL dwRet AS DWORD
      
          LOCAL hProc AS DWORD
      
          hProc = GetProcAddress(hLib, BYCOPY sFuncName)
          'msgbox format$(hModule) + " " + sFuncName
      
          lpImageDosHeader = hModule
          IF @lpImageDosHeader.e_magic <> %IMAGE_DOS_SIGNATURE THEN
              ' invalid DOS signature
              EXIT FUNCTION
      
          END IF
      
          lpImageNtHeaders = lpImageDosHeader + @lpImageDosHeader.e_lfanew
          IF @lpImageNtHeaders.Signature <> %IMAGE_NT_SIGNATURE THEN
              ' invalid NT signature
              EXIT FUNCTION
      
          END IF
      
          IF @lpImageNtHeaders.FileHeader.SizeOfOptionalHeader <> SIZEOF(@lpImageNtHeaders.OptionalHeader) OR _
             @lpImageNtHeaders.OptionalHeader.Magic <> %IMAGE_NT_OPTIONAL_HDR32_MAGIC THEN
              ' invalid NT header
              EXIT FUNCTION
      
          END IF
      
          IF @lpImageNtHeaders.OptionalHeader.NumberOfRvaAndSizes <= %IMAGE_DIRECTORY_ENTRY_IMPORT THEN
              ' no import section
              EXIT FUNCTION
      
          END IF
      
          lpImageImportDescriptor = lpImageDosHeader + @lpImageNtHeaders.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_IMPORT).VirtualAddress
          IF lpImageImportDescriptor = lpImageDosHeader THEN
              ' no import table
              EXIT FUNCTION
      
          END IF
      
          DO WHILE @lpImageImportDescriptor.OriginalFirstThunk <> 0
              'msgbox "outerloop"
              lpFuncNameRef = @lpImageImportDescriptor.OriginalFirstThunk + lpImageDosHeader
              lpFuncAddr = @lpImageImportDescriptor.FirstThunk + lpImageDosHeader
      
              DO WHILE @lpFuncNameRef <> 0
                  'MSGBOX "innerloop"
                  lpImageImportByName = @lpFuncNameRef + lpImageDosHeader
                  'msgbox "innerloop2"
                  IF ISFALSE (@lpFuncNameRef AND %IMAGE_ORDINAL_FLAG) THEN
                      'MSGBOX "inif" + str$(lpImageImportByName) + str$(@lpFuncNameRef) + str$(lpImageDosHeader) + str$(lpFuncNameRef) + str$(lpFuncAddr)
                      'msgbox format$(@lpFuncAddr)
                      'MSGBOX FORMAT$(hProc) + str$(@lpFuncAddr) + str$(lpFuncAddr)
                      IF @lpFuncAddr = hProc THEN '@lpImageImportByName.ImpName = sFuncName THEN
                          'msgbox "inif2"
                          IF VirtualProtect(BYVAL lpFuncAddr, 4, %PAGE_READWRITE, flOldProtect) = 0 THEN
                              ' virtual protect error
                              EXIT FUNCTION
      
                          END IF
      
                          dwRet = @lpFuncAddr
                          @lpFuncAddr = pPatch
      
                          IF FlushInstructionCache(GetCurrentProcess(), BYVAL @lpFuncAddr, 4) = 0 THEN
                              EXIT FUNCTION
      
                          END IF
      
                          IF flOldProtect <> %PAGE_READWRITE THEN
                              VirtualProtect BYVAL lpFuncAddr, 4, flOldProtect, flOldProtect
                              FUNCTION = dwRet
                              EXIT FUNCTION
      
                          END IF
      
                      END IF
      
                  END IF
                  'msgbox "innerloop3"
      
                  INCR lpFuncNameRef
                  INCR lpFuncAddr
      
              LOOP
      
              INCR lpImageImportDescriptor
      
          LOOP
      
          'IF dwRet = 0 THEN msgbox sFuncName
      
          DbgLeave("UCWrapper_PatchFunction")
          FUNCTION = dwRet
      END FUNCTION
      
      SUB UCWrapper_PatchToUnicode
          ' patches calls in PE import header to unicode calls
          DbgEnter("UCWrapper_PatchToUnicode")
          LOCAL ovi AS OSVERSIONINFO
          LOCAL hModule AS LONG
          LOCAL hLib AS LONG
          LOCAL sExt AS STRING
      
          ovi.dwOSVersionInfoSize = SIZEOF(ovi)
          GetVersionEx ovi
      
          gUCWrapper.lUseUnicode = (ovi.dwPlatformId = (%VER_PLATFORM_WIN32_NT)) AND ISFALSE %TEST_UNICODE_ANSI
      
          Dbg("Is Unicode: " + FORMAT$(gUCWrapper.lUseUnicode))
      
          hLib = GetModuleHandle("USER32.DLL")
      
          IF gUCWrapper.lUseUnicode THEN
              sExt = "W"
      
          ELSE
              sExt = "A"
      
          END IF
      
          hModule = GetModuleHandle(BYVAL %NULL)
      
          IF hModule THEN
              IF UCWrapper_PatchFunction(hModule, hLib, "CreateDialogIndirectParamA", CODEPTR(UCWrapper_CreateDialogIndirectParam)) THEN
                  gUCWrapper.fp.pCreateDialogIndirectParam = GetProcAddress(hLib, "CreateDialogIndirectParam" + sExt)
      
              END IF
      
              IF UCWrapper_PatchFunction(hModule, hLib, "CreateWindowExA", CODEPTR(UCWrapper_CreateWindowEx)) THEN
                  gUCWrapper.fp.pCreateWindowEx = GetProcAddress(hLib, "CreateWindowEx" + sExt)
      
              END IF
      
              IF UCWrapper_PatchFunction(hModule, hLib, "InsertMenuItemA", CODEPTR(UCWrapper_InsertMenuItem)) THEN
                  gUCWrapper.fp.pInsertMenuItem = GetProcAddress(hLib, "InsertMenuItem" + sExt)
      
              END IF
      
              IF UCWrapper_PatchFunction(hModule, hLib, "GetWindowTextA", CODEPTR(UCWrapper_GetWindowText)) THEN
                  gUCWrapper.fp.pGetWindowText = GetProcAddress(hLib, "GetWindowText" + sExt)
      
              END IF
      
              IF UCWrapper_PatchFunction(hModule, hLib, "GetWindowTextLengthA", CODEPTR(UCWrapper_GetWindowTextLength)) THEN
                  gUCWrapper.fp.pGetWindowTextLength = GetProcAddress(hLib, "GetWindowTextLength" + sExt)
      
              END IF
      
              'IF UCWrapper_PatchFunction(hModule, "IsDialogMessageA", CODEPTR(UCWrapper_IsDialogMessage)) THEN
              '    gUCWrapper.fp.pIsDialogMessage = GetProcAddress(hLib, "IsDialogMessage" + sExt)
              '
              'END IF
      
              IF UCWrapper_PatchFunction(hModule, hLib, "MessageBoxA", CODEPTR(UCWrapper_MessageBox)) THEN
                  gUCWrapper.fp.pMessageBox = GetProcAddress(hLib, "MessageBox" + sExt)
      
              END IF
      
              'IF UCWrapper_PatchFunction(hModule, "PeekMessageA", CODEPTR(UCWrapper_PeekMessage)) THEN
              '    gUCWrapper.fp.pPeekMessage = GetProcAddress(hLib, "PeekMessage" + sExt)
              '
              'END IF
      
              'IF UCWrapper_PatchFunction(hModule, "PostMessageA", CODEPTR(UCWrapper_PostMessage)) THEN
              '    gUCWrapper.fp.pPostMessage = GetProcAddress(hLib, "PostMessage" + sExt)
              '
              'END IF
      
              IF UCWrapper_PatchFunction(hModule, hLib, "SendMessageA", CODEPTR(UCWrapper_SendMessage)) THEN
                  gUCWrapper.fp.pSendMessage = GetProcAddress(hLib, "SendMessage" + sExt)
      
              END IF
      
              IF UCWrapper_PatchFunction(hModule, hLib, "SetWindowTextA", CODEPTR(UCWrapper_SetWindowText)) THEN
                  gUCWrapper.fp.pSetWindowText = GetProcAddress(hLib, "SetWindowText" + sExt)
      
              END IF
      
              'UCWrapper_PatchFunction hModule, "MultiByteToWideChar", CODEPTR(UCWrapper_MultiByteToWideChar)
      
          END IF
      
          DbgLeave("UCWrapper_PatchToUnicode")
      
      END SUB

      ------------------

      Comment


      • #4
        Demo file: test_ucwrap.bas

        This is a small demo file creating and displaying an unicode-enabled DDT dialog.
        It also displays some japanese characters (but you need MS Mincho installed for seeing them,
        I think this one comes with Win2000 or XP). I haven't used a language file or stringtable
        for the strings in that test file, just a small BinBas of a japanese unicode file.

        (On a side note, I have copied the japanese text from some google result, I don't understand
        japanese )

        Code:
        #COMPILE EXE
        #DIM ALL
        
        #INCLUDE "WIN32API.INC"
        
        MACRO DbgEnter(x) = ! nop
        MACRO DbgLeave(x) = ! nop
        MACRO Dbg(x) = ! nop
        %TEST_UNICODE_ANSI = 0
        
        #INCLUDE "UCWRAP.BI"
        #INCLUDE "UCWRAP.INC"
        
        FUNCTION BinBas() AS STRING
        
            FUNCTION = PEEK$( CODEPTR( BinBas_Data ), 68 )
            EXIT FUNCTION
        
        BinBas_Data:
        !db 255,254,218,048,252,048,184,048,110,048,186,078,023,108,166,094,146,048
        !db 205,083,032,102,087,048,095,048,233,048,243,048,173,048,243,048,176,048
        !db 146,048,076,136,106,048,070,048,181,048,252,048,193,048,168,048,243,048
        !db 184,048,243,048,110,048,229,101,044,103,158,138,072,114
        
        END FUNCTION
        
        CALLBACK FUNCTION TestProc
            LOCAL txt AS STRING
        
            SELECT CASE CBMSG
            CASE %WM_COMMAND
                SELECT CASE CBCTL
                CASE %IDOK
                    CONTROL GET TEXT CBHNDL, 1002 TO txt
                    
                    MSGBOX txt, , UCODE$("Test output")
                    
                CASE %IDCANCEL
                    DIALOG END CBHNDL
                    
                END SELECT
                
            END SELECT
        
        END FUNCTION
        
        
        FUNCTION PBMAIN () AS LONG
            LOCAL hDlg AS LONG
        
            UCWrapper_PatchToUnicode
        
            'msgbox ucode$("patched."), , UCODE$("title")
            
            DIALOG FONT "MS Mincho", 9
        
            DIALOG NEW %HWND_DESKTOP, UCODE$("dialog testa"), , , 200, 100, %WS_POPUP OR %WS_CAPTION OR %WS_SYSMENU, %WS_EX_RTLREADING TO hDlg
            SetWindowLong hDlg, %GWL_EXSTYLE, GetWindowLong(hDlg, %GWL_EXSTYLE) OR %WS_EX_RTLREADING
        
            CONTROL ADD LABEL, hDlg, 1001, BinBas(), 1, 1, 190, 25
            
            CONTROL ADD TEXTBOX, hDlg, 1002, UCODE$("textbox"), 1, 30, 100, 12
            
            CONTROL ADD BUTTON, hDlg, %IDOK, UCODE$("Display"), 100, 80, 45, 15
            CONTROL ADD BUTTON, hDlg, %IDCANCEL, UCODE$("Cancel"), 150, 80, 45, 15
        
            DIALOG SHOW MODAL hDlg CALL TestProc
        
        END FUNCTION

        ------------------


        [This message has been edited by Lothar Pink (edited January 08, 2007).]

        Comment

        Working...
        X