Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Can't be done from VB! A challenge for you API'ers

0 views
Skip to first unread message

Flash

unread,
Jun 1, 2001, 4:57:14 PM6/1/01
to
Here's the challenge:

get the OTMEMsquare for the selected font. This requires calling
GetOutlineTextMetrics. However, you have to call GetOutlineTextMetrics
twice really, once for the size of the structure, and the second time to
fill it.

However, the second call crashes VB. There must be some trick.

Below is the code that should work...but you get a big VB crash on the
second call to GetoutlineTextMetric.

PS...a valid otmemsquare value will typically be 2000, or some large number,
not -21 or something, as is returned if the return code of
GetOutlineTextMetric is 0 (which indicates an error occurred).

You'll be a VB super hero if you can retrieve the proper otmemSQuare result
for the selected font!!!!!!

Eric Robishaw


Here's the sample code:
Public Type POINTAPI '4 Bytes - Synonymous with LONG
x As Long
y As Long
Col As Long
End Type
Public Type TEXTMETRIC
tmHeight As Long
tmAscent As Long
tmDescent As Long
tmInternalLeading As Long
tmExternalLeading As Long
tmAveCharWidth As Long
tmMaxCharWidth As Long
tmWeight As Long
tmOverhang As Long
tmDigitizedAspectX As Long
tmDigitizedAspectY As Long
tmFirstChar As Byte
tmLastChar As Byte
tmDefaultChar As Byte
tmBreakChar As Byte
tmItalic As Byte
tmUnderlined As Byte
tmStruckOut As Byte
tmPitchAndFamily As Byte
tmCharSet As Byte
End Type
Public Type PANOSE
ulculture As Long
bFamilyType As Byte
bSerifStyle As Byte
bWeight As Byte
bProportion As Byte
bContrast As Byte
bStrokeVariation As Byte
bArmStyle As Byte
bLetterform As Byte
bMidline As Byte
bXHeight As Byte
End Type


Public Type OUTLINETEXTMETRIC
otmSize As Long
otmTextMetrics As TEXTMETRIC
otmFiller As Byte
otmPanoseNumber As PANOSE
otmfsSelection As Long
otmfsType As Long
otmsCharSlopeRise As Long
otmsCharSlopeRun As Long
otmItalicAngle As Long
otmEMSquare As Long
otmAscent As Long
otmDescent As Long
otmLineGap As Long
otmsCapEmHeight As Long
otmsXHeight As Long
otmrcFontBox As RECT
otmMacAscent As Long
otmMacDescent As Long
otmMacLineGap As Long
otmusMinimumPPEM As Long
otmptSubscriptSize As POINTAPI
otmptSubscriptOffset As POINTAPI
otmptSuperscriptSize As POINTAPI
otmptSuperscriptOffset As POINTAPI
otmsStrikeoutSize As Long
otmsStrikeoutPosition As Long
otmsUnderscorePosition As Long
otmsUnderscoreSize As Long
otmpFamilyName As String
otmpFaceName As String
otmpStyleName As String
otmpFullName As String
End Type
Public Declare Function GetOutlineTextMetrics_1 Lib "gdi32" _
Alias "GetOutlineTextMetricsA" _
(ByVal hdc As Long, ByVal cbData As Long, ByVal lpotm As Long) As Long

Public Declare Function GetOutlineTextMetrics Lib "gdi32" Alias
"GetOutlineTextMetricsA" (ByVal hdc As Long, ByVal cbData As Long, lpotm As
Any) As Long


Private function get OtmemSq (hdc) as long
dim size as long, otm as outlinetextmetric

size=GetOutlineTextMetric_1(hdc,0,0)
otm.otmsize = size
getoutlinetextmetric (hdc, size, otm) 'this will crash vb
'and getoutlinetextmetric (hdc, lenb(otm), otm) returns a 0, and a
bogus value in the otmemsqure
otmEmsq = otm.otmemsquare
end function


schunkenstein

unread,
Jun 1, 2001, 5:46:08 PM6/1/01
to
I soulcd be mistaken, but with most winapi types, when the first param of
the type says "size" it is talking about the sive of the type. (Len(MyType))

This way, the same API function can deal with mutiliple verions of the
parameterized type.

Try this....

Private function get OtmemSq (hdc) as long
dim size as long, otm as outlinetextmetric

size=GetOutlineTextMetric_1(hdc,0,0)

' otm.otmsize = size
otm.otmsize = len(otm)

getoutlinetextmetric (hdc, size, otm) 'this will crash vb
'and getoutlinetextmetric (hdc, lenb(otm), otm) returns a 0, and a
'bogus value in the otmemsqure
otmEmsq = otm.otmemsquare
end function


"Flash" <ERob...@bigfoot.com> wrote in message
news:udWTZzt6AHA.1756@tkmsftngp07...

schunkenstein

unread,
Jun 1, 2001, 5:48:20 PM6/1/01
to
Oh, and fret not....I promises you, there is very, very, VERY little that
can't be done inside VB.

Granted most are sloppy hacks, but the again, the winapi IS a sloppy hack in
and of itself.

Tom Esh

unread,
Jun 2, 2001, 12:45:12 AM6/2/01
to
On Fri, 1 Jun 2001 14:46:08 -0700, "schunkenstein"
<mi...@starstream.net> wrote:
>I soulcd be mistaken, but with most winapi types, when the first param of
>the type says "size" it is talking about the sive of the type. (Len(MyType))
Often yes, but this one where you have to read the docs carefully.
OUTLINETEXTMETRIC is actually a variable-length structure (because of
the strings). You could try passing Len(type), but it still may not
work. Api functions that request a data size use it primarily to avoid
causing (or avoid special handling of) the exception error that would
occur if the output buffer (or struct) were too small for the data.
Some functions will tuncate the data if the specified output buffer
size is too small (providing at least some data), but others just fail
(with or without a specific error val returned). How it's handled
depends on the particular function, and it is not always documented.

-Tom
(please post replies to the newsgroup)

Tom Esh

unread,
Jun 2, 2001, 12:45:11 AM6/2/01
to
First I should say I've never had a reason to use this particular
function, but a challenge is a challenge <g> That aside, there are
several issues / problems here:
1) GetOutlineTextMetrics fails if the hdc has a non-TrueType font
selected into it. (That might explain why your first call to obtain
the data size didn't work.)

2) Your POINTAPI declare has an extra member in it somehow. Should be
just:
Public Type POINTAPI
X As Long
Y As Long
End Type

3) Both TEXTMETRIC and PANOSE structs break dword alignment, which is
a ~big~ problem with VB and pretty much altogether hoses being able to
use an OUTLINETEXTMETRIC struct in the call. Essentially you have to
obtain the size, use it to allocate a byte array, and pass a pointer
to the byte array. Then of course, ferret out the pieces you need.
(FWIW whenever I get into one of these situations where things are all
whored up because some lame-ass MS coder broke the dword rule, I find
it's sometimes helpful to dump the byte array to a file and look at it
with a hex viewer.)

4) Also in case you intend to use them, the last 4 members of the
OUTLINETEXTMETRIC struct aren't really strings, but rather ~byte
offsets~ (As Longs) to the actual null-terminated string data, which
gets tacked on to the end of the data block.

Public Declare Function GetOutlineTextMetricsAny Lib "gdi32" Alias


"GetOutlineTextMetricsA" (ByVal hdc As Long, ByVal cbData As Long,

lpOTM As Any) As Long

Public Declare Sub MemCopy Lib "kernel32" Alias "RtlMoveMemory"
(lpDest As Any, lpSource As Any, ByVal dwBytes As Long)

Public Function OtmemSq(hdc) As Long
Dim Size As Long
Dim Buf() As Byte

Size = GetOutlineTextMetricsAny(hdc, 0&, ByVal 0&)
If Size > 0& Then
ReDim Buf(0 To Size - 1)
'set the .otmSize member...
MemCopy Buf(0), Size, 4&
If GetOutlineTextMetricsAny(hdc, Size, Buf(0)) <> 0& Then
'A careful look at the structs shows .otmEMSquare will be
'at byte offset# 92...
MemCopy OtmemSq, ByVal VarPtr(Buf(92)), 4&
End If
End If
End Function

-HTH

Flash

unread,
Jun 2, 2001, 8:28:03 PM6/2/01
to
You are the man!

Thanks a million!


"Tom Esh" <tjeshGi...@earthlink.net> wrote in message
news:3b1866fd...@msnews.microsoft.com...

schunkenstein

unread,
Jun 4, 2001, 3:40:18 PM6/4/01
to
My modo is, "If the API sucks, shit-can it"

Sould like you should find another way if that API is that poorly designed.


"Tom Esh" <tjeshGi...@earthlink.net> wrote in message

news:3b18681b...@msnews.microsoft.com...

Tom Esh

unread,
Jun 4, 2001, 4:26:08 PM6/4/01
to
>My modo is, "If the API sucks, shit-can it"
...And replace it with what? Dig into the data (.ttf file) itself ?
Problem there is the info you're after may be ~derived~ from the data
at runtime, as is often the case with fonts. Also the format may
change (which it has at least once), where as the Api will work
regardless. Like it or not, the API is the ~only~ way to accomplish
many Windows tasks. The case in question is only a problem when the
API uses different alignment (rare) and the language doesn't provide a
means to specify alignment or packing (i.e. VB), however there ~are~
ways to work around it. The only real alternative is to not do it.

On Mon, 4 Jun 2001 12:40:18 -0700, "schunkenstein"
<mi...@starstream.net> wrote:
>My modo is, "If the API sucks, shit-can it"
>
>Sould like you should find another way if that API is that poorly designed.

-Tom

0 new messages