OUTLINETEXTMETRIC Structure Improperly Defined

Started by dedndave, August 30, 2011, 03:11:03 AM

Previous topic - Next topic

dedndave

this structure is incorrectly defined in windows.inc and on MSDN

updated definition...
typedef struct _OUTLINETEXTMETRIC {
  UINT       otmSize;
  TEXTMETRIC otmTextMetrics;
  BYTE       otmMysteryBytes[4];
  PANOSE     otmPanoseNumber;
  BYTE       otmMysteryByte;
  UINT       otmfsSelection;
  UINT       otmfsType;
  int        otmsCharSlopeRise;
  int        otmsCharSlopeRun;
  int        otmItalicAngle;
  UINT       otmEMSquare;
  int        otmAscent;
  int        otmDescent;
  UINT       otmLineGap;
  UINT       otmsCapEmHeight;
  UINT       otmsXHeight;
  RECT       otmrcFontBox;
  int        otmMacAscent;
  int        otmMacDescent;
  UINT       otmMacLineGap;
  UINT       otmusMinimumPPEM;
  POINT      otmptSubscriptSize;
  POINT      otmptSubscriptOffset;
  POINT      otmptSuperscriptSize;
  POINT      otmptSuperscriptOffset;
  UINT       otmsStrikeoutSize;
  int        otmsStrikeoutPosition;
  int        otmsUnderscoreSize;
  int        otmsUnderscorePosition;
  PSTR       otmpFamilyName;
  PSTR       otmpFaceName;
  PSTR       otmpStyleName;
  PSTR       otmpFullName;
} OUTLINETEXTMETRIC, *POUTLINETEXTMETRIC;


i used the term "mystery byte" because they are filled with non-zero, undefined values
notice that the TEXTMETRIC structure will be different sizes for ANSI and UNICODE versions
also, it is worth noting that the otmSize value need not be filled prior to
calling the function as with the "cbSize" member of many structures

dedndave

a few dumps to demonstrate the correct nature of the structure...
---------------------------------
ANSI, lfHeight = 11
---------------------------------

00000103                                                                                           - otmSize dword

0000000D 0000000B 00000002 00000002 00000000 00000005 00000015 00000190 00000000 00000060 00000060 - TEXTMETRIC dwords (11)
1E FF 1F 20                                                                                        - TEXTMETRIC ANSI tchars (4)
00 00 00 27 00                                                                                     - TEXTMETRIC bytes (5)

00 00 00 68                                                                                        - mystery bytes (4)
02 0B 06 04 03 05 04 04 02 04                                                                      - PANOSE bytes (10)
00                                                                                                 - mystery byte (1)

00000040                                                                                           - otmfsSelection dword
00000008 00000001 00000000 00000000 00000800 00000008 FFFFFFFE 00000000 00000006 00000003          - misc dwords (30)
FFFFFFF9 0000000B 0000000F FFFFFFFE 0000000B FFFFFFFE 00000000 00000009 00000008 00000007
00000000 00000002 00000008 00000007 00000000 00000005 00000001 00000004 00000001 FFFFFFFF

000000D4 000000DB 000000E2 000000EA                                                                - string offsets (4)

54 61 68 6F 6D 61 00                                                                               - ANSI sz strings (4)
54 61 68 6F 6D 61 00
52 65 67 75 6C 61 72 00
4D 69 63 72 6F 73 6F 66 74 20 54 61 68 6F 6D 61 20 52 65 67 75 6C 61 72 00

---------------------------------
ANSI, lfHeight = 22
---------------------------------

00000103                                                                                           - otmSize dword

0000001B 00000016 00000005 00000005 00000000 0000000A 0000002B 00000190 00000000 00000060 00000060 - TEXTMETRIC dwords (11)
1E FF 1F 20                                                                                        - TEXTMETRIC ANSI tchars (4)
00 00 00 27 00                                                                                     - TEXTMETRIC bytes (5)

4A 14 00 68                                                                                        - mystery bytes (4)
02 0B 06 04 03 05 04 04 02 04                                                                      - PANOSE bytes (10)
02                                                                                                 - mystery byte (1)

00000040                                                                                           - otmfsSelection dword
00000008 00000001 00000000 00000000 00000800 00000011 FFFFFFFB 00000001 0000000B 00000006          - misc dwords (30)
FFFFFFF3 00000017 0000001D FFFFFFFB 00000016 FFFFFFFB 00000000 00000009 0000000F 0000000E
00000000 00000003 0000000F 0000000E 00000000 0000000A 00000001 00000007 00000001 FFFFFFFE

000000D4 000000DB 000000E2 000000EA                                                                - string offsets (4)

54 61 68 6F 6D 61 00                                                                               - ANSI sz strings (4)
54 61 68 6F 6D 61 00
52 65 67 75 6C 61 72 00
4D 69 63 72 6F 73 6F 66 74 20 54 61 68 6F 6D 61 20 52 65 67 75 6C 61 72 00

---------------------------------
UNICODE, lfHeight = 11
---------------------------------

00000136                                                                                           - otmSize dword

0000000D 0000000B 00000002 00000002 00000000 00000005 00000015 00000190 00000000 00000060 00000060 - TEXTMETRIC dwords (11)
0020 FFFC 001F 0020                                                                                - TEXTMETRIC UNICODE tchars (4)
00 00 00 27 00                                                                                     - TEXTMETRIC bytes (5)

00 00 00 68                                                                                        - mystery bytes (4)
02 0B 06 04 03 05 04 04 02 04                                                                      - PANOSE bytes (10)
00                                                                                                 - mystery byte (1)

00000040                                                                                           - otmfsSelection dword
00000008 00000001 00000000 00000000 00000800 00000008 FFFFFFFE 00000000 00000006 00000003          - misc dwords (30)
FFFFFFF9 0000000B 0000000F FFFFFFFE 0000000B FFFFFFFE 00000000 00000009 00000008 00000007
00000000 00000002 00000008 00000007 00000000 00000005 00000001 00000004 00000001 FFFFFFFF

000000D8 000000E6 000000F4 00000104                                                                - string offsets (4)

54 00 61 00 68 00 6F 00 6D 00 61 00 00 00                                                          - UNICODE sz strings (4)
54 00 61 00 68 00 6F 00 6D 00 61 00 00 00
52 00 65 00 67 00 75 00 6C 00 61 00 72 00 00 00
4D 00 69 00 63 00 72 00 6F 00 73 00 6F 00 66 00 74 00 20 00 54 00 61 00 68 00 6F 00 6D 00 61 00 20 00 52 00 65 00 67 00 75 00 6C 00 61 00 72 00 00 00

---------------------------------
UNICODE, lfHeight = 22
---------------------------------

00000136                                                                                           - otmSize dword

0000001B 00000016 00000005 00000005 00000000 0000000A 0000002B 00000190 00000000 00000060 00000060 - TEXTMETRIC dwords (11)
0020 FFFC 001F 0020                                                                                - TEXTMETRIC UNICODE tchars (4)
00 00 00 27 00                                                                                     - TEXTMETRIC bytes (5)

00 00 00 68                                                                                        - mystery bytes (4)
02 0B 06 04 03 05 04 04 02 04                                                                      - PANOSE bytes (10)
00                                                                                                 - mystery byte (1)

00000040                                                                                           - otmfsSelection dword
00000008 00000001 00000000 00000000 00000800 00000011 FFFFFFFB 00000001 0000000B 00000006          - misc dwords (30)
FFFFFFF3 00000017 0000001D FFFFFFFB 00000016 FFFFFFFB 00000000 00000009 0000000F 0000000E
00000000 00000003 0000000F 0000000E 00000000 0000000A 00000001 00000007 00000001 FFFFFFFE

000000D8 000000E6 000000F4 00000104                                                                - string offsets (4)

54 00 61 00 68 00 6F 00 6D 00 61 00 00 00                                                          - UNICODE sz strings (4)
54 00 61 00 68 00 6F 00 6D 00 61 00 00 00
52 00 65 00 67 00 75 00 6C 00 61 00 72 00 00 00
4D 00 69 00 63 00 72 00 6F 00 73 00 6F 00 66 00 74 00 20 00 54 00 61 00 68 00 6F 00 6D 00 61 00 20 00 52 00 65 00 67 00 75 00 6C 00 61 00 72 00 00 00

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

sinsi

Light travels faster than sound, that's why some people seem bright until you hear them.

dedndave

that's what i thought, at first
but the PANOSE structure is always on an odd address - lol
plus, the otmMysteryBytes and otmMysteryByte all get filled with data
i read through a few miles of Panose documentation, and they don't appear to be related

at any rate, by the time you get to otmfsSelection, things ARE dword aligned
it looks like it was by accident   :P

dedndave

one thing i noticed - the GetOutlineTextMetrics function is hardly ever used
i searched the forum for references to the function and the structure - 0 hits
i guess noone could get any useful info out of it - lol

qWord

hi,
here the definition from japhet's WinInc -maybe it solves your mystery problem   :P:

PANOSE struct
bFamilyType BYTE ?
bSerifStyle BYTE ?
bWeight BYTE ?
bProportion BYTE ?
bContrast BYTE ?
bStrokeVariation BYTE ?
bArmStyle BYTE ?
bLetterform BYTE ?
bMidline BYTE ?
bXHeight BYTE ?
PANOSE ends

TEXTMETRICA struct 8 ;v2.02: alignment changed from 4 to 8
tmHeight SDWORD ?
tmAscent SDWORD ?
tmDescent SDWORD ?
tmInternalLeading SDWORD ?
tmExternalLeading SDWORD ?
tmAveCharWidth SDWORD ?
tmMaxCharWidth SDWORD ?
tmWeight SDWORD ?
tmOverhang SDWORD ?
tmDigitizedAspectX SDWORD ?
tmDigitizedAspectY SDWORD ?
tmFirstChar BYTE ?
tmLastChar BYTE ?
tmDefaultChar BYTE ?
tmBreakChar BYTE ?
tmItalic BYTE ?
tmUnderlined BYTE ?
tmStruckOut BYTE ?
tmPitchAndFamily BYTE ?
tmCharSet BYTE ?
TEXTMETRICA ends

TEXTMETRICW struct 8 ;v2.02: alignment changed from 4 to 8
tmHeight SDWORD ?
tmAscent SDWORD ?
tmDescent SDWORD ?
tmInternalLeading SDWORD ?
tmExternalLeading SDWORD ?
tmAveCharWidth SDWORD ?
tmMaxCharWidth SDWORD ?
tmWeight SDWORD ?
tmOverhang SDWORD ?
tmDigitizedAspectX SDWORD ?
tmDigitizedAspectY SDWORD ?
tmFirstChar WCHAR ?
tmLastChar WCHAR ?
tmDefaultChar WCHAR ?
tmBreakChar WCHAR ?
tmItalic BYTE ?
tmUnderlined BYTE ?
tmStruckOut BYTE ?
tmPitchAndFamily BYTE ?
tmCharSet BYTE ?
TEXTMETRICW ends

OUTLINETEXTMETRICA struct
otmSize DWORD ?
otmTextMetrics TEXTMETRICA <>
otmFiller BYTE ?
otmPanoseNumber PANOSE <>
otmfsSelection DWORD ?
otmfsType DWORD ?
otmsCharSlopeRise DWORD ?
otmsCharSlopeRun DWORD ?
otmItalicAngle DWORD ?
otmEMSquare DWORD ?
otmAscent DWORD ?
otmDescent DWORD ?
otmLineGap DWORD ?
otmsCapEmHeight DWORD ?
otmsXHeight DWORD ?
otmrcFontBox RECT <>
otmMacAscent DWORD ?
otmMacDescent DWORD ?
otmMacLineGap DWORD ?
otmusMinimumPPEM DWORD ?
otmptSubscriptSize POINT <>
otmptSubscriptOffset POINT <>
otmptSuperscriptSize POINT <>
otmptSuperscriptOffset POINT <>
otmsStrikeoutSize DWORD ?
otmsStrikeoutPosition DWORD ?
otmsUnderscoreSize DWORD ?
otmsUnderscorePosition DWORD ?
otmpFamilyName PSTR ?
otmpFaceName PSTR ?
otmpStyleName PSTR ?
otmpFullName PSTR ?
OUTLINETEXTMETRICA ends

OUTLINETEXTMETRICW struct
otmSize DWORD ?
otmTextMetrics TEXTMETRICW <>
otmFiller BYTE ?
otmPanoseNumber PANOSE <>
otmfsSelection DWORD ?
otmfsType DWORD ?
otmsCharSlopeRise DWORD ?
otmsCharSlopeRun DWORD ?
otmItalicAngle DWORD ?
otmEMSquare DWORD ?
otmAscent DWORD ?
otmDescent DWORD ?
otmLineGap DWORD ?
otmsCapEmHeight DWORD ?
otmsXHeight DWORD ?
otmrcFontBox RECT <>
otmMacAscent DWORD ?
otmMacDescent DWORD ?
otmMacLineGap DWORD ?
otmusMinimumPPEM DWORD ?
otmptSubscriptSize POINT <>
otmptSubscriptOffset POINT <>
otmptSuperscriptSize POINT <>
otmptSuperscriptOffset POINT <>
otmsStrikeoutSize DWORD ?
otmsStrikeoutPosition DWORD ?
otmsUnderscoreSize DWORD ?
otmsUnderscorePosition DWORD ?
otmpFamilyName PSTR ?
otmpFaceName PSTR ?
otmpStyleName PSTR ?
otmpFullName PSTR ?
OUTLINETEXTMETRICW ends
FPU in a trice: SmplMath
It's that simple!

dedndave

qWord
i don't think that solves the problem
if you look at the dumps above, the last bytes of the TEXTMETRIC structure are accounted for

by changing the alignment of TEXTMETRIC, you may get correct results for some values
but, something is going to be out of whack

it is likely that Andreas' method has mis-aligned PANOSE bytes
because we rarely use these values (never), we would not notice the misalignment

ToutEnMasm


You have an old structure,
This one is extrct from SDK 7.1

Quote
OUTLINETEXTMETRICA   STRUCT
   otmSize DWORD ?
   otmTextMetrics TEXTMETRICA <>
   otmFiller BYTE ?
   otmPanoseNumber PANOSE <>
   otmfsSelection DWORD ?
   otmfsType DWORD ?
   otmsCharSlopeRise DWORD ?
   otmsCharSlopeRun DWORD ?
   otmItalicAngle DWORD ?
   otmEMSquare DWORD ?
   otmAscent DWORD ?
   otmDescent DWORD ?
   otmLineGap DWORD ?
   otmsCapEmHeight DWORD ?
   otmsXHeight DWORD ?
   otmrcFontBox RECT <>
   otmMacAscent DWORD ?
   otmMacDescent DWORD ?
   otmMacLineGap DWORD ?
   otmusMinimumPPEM DWORD ?
   otmptSubscriptSize POINT <>
   otmptSubscriptOffset POINT <>
   otmptSuperscriptSize POINT <>
   otmptSuperscriptOffset POINT <>
   otmsStrikeoutSize DWORD ?
   otmsStrikeoutPosition DWORD ?
   otmsUnderscoreSize DWORD ?
   otmsUnderscorePosition DWORD ?
   otmpFamilyName DWORD ?
   otmpFaceName DWORD ?
   otmpStyleName DWORD ?
   otmpFullName DWORD ?
OUTLINETEXTMETRICA      ENDS

TEXTMETRICA   STRUCT
   tmHeight DWORD ?
   tmAscent DWORD ?
   tmDescent DWORD ?
   tmInternalLeading DWORD ?
   tmExternalLeading DWORD ?
   tmAveCharWidth DWORD ?
   tmMaxCharWidth DWORD ?
   tmWeight DWORD ?
   tmOverhang DWORD ?
   tmDigitizedAspectX DWORD ?
   tmDigitizedAspectY DWORD ?
   tmFirstChar BYTE ?
   tmLastChar BYTE ?
   tmDefaultChar BYTE ?
   tmBreakChar BYTE ?
   tmItalic BYTE ?
   tmUnderlined BYTE ?
   tmStruckOut BYTE ?
   tmPitchAndFamily BYTE ?
   tmCharSet BYTE ?
TEXTMETRICA      ENDS
PANOSE   STRUCT
   bFamilyType BYTE ?
   bSerifStyle BYTE ?
   bWeight BYTE ?
   bProportion BYTE ?
   bContrast BYTE ?
   bStrokeVariation BYTE ?
   bArmStyle BYTE ?
   bLetterform BYTE ?
   bMidline BYTE ?
   bXHeight BYTE ?
PANOSE      ENDS

dedndave

that's not fixed, Yves   :P

there is a real "hint" to notice with this structure
at the end of the struture, the function appends 4 sz strings (unicode or ansi)
the first string has an offset of 0D4h for ANSI and 0D8h for UNICODE
these correspond to structure sizes (the defined part) of 212 and 216 bytes, respectively
the difference is accounted for by the 4 TCHAR's in TEXTMETRIC

these 4 offsets are added to the beginning address of the structure to obtain the string addresses
a good test to see if your structure is properly defined is to display these 4 strings
however, it still may not be correct
display the 10 Panose bytes   :U
they will all typically be less than 10h

none of the definitions you have shown me account for these 15 bytes
4A 14 00 68                   - mystery bytes (4)
02 0B 06 04 03 05 04 04 02 04 - PANOSE bytes (10)
02                            - mystery byte (1)


ToutEnMasm


The structure have differents values  with the system.
There is  a NEWTEXTMETRICA
Give  a function and i can see if there is a problem.

dedndave

NEWTEXTMETRIC is used for font enumeration - a different structure with a similar name

if you guys don't want to believe me, it's ok   :bg

ToutEnMasm

I believe it with a little source code to see what append on different system.
There is also one different alignment for each structure

dedndave

once you have selected the desired font/size into the hDC.....
        INVOKE  GetOutlineTextMetrics,hDC,0,0
        add     eax,3
        and     eax,-4
        sub     esp,eax
        mov     ebx,esp
        xchg    eax,esi
        INVOKE  GetOutlineTextMetrics,hDC,esi,ebx

;EBX = address of OUTLINETEXTMETRIC on the stack
;ESI = number of bytes to balance the stack

;use EBX to address and examine the structure here

        add     esp,esi             ;balance the stack when done

if the pointer parm is 0, the function returns the number of bytes required
it's similar to reading a registry value - call it once to get the size, then again to get the data

dedndave

Yves,

i cleaned up my test program a little bit   :lol

it has all kinds of nonsence in it

MichaelW

#14
EDIT: Updated the attachment to demonstrate that appending a dword alignment to the MASM32 structures causes the structure layout to exactly match the layout that the Microsoft C compilers implement.
eschew obfuscation