Sample Uniscribe code in .NET since it is not available on the web currently:
_
Public Structure GCP_RESULTS
Public StructSize As UInteger
_
Public OutString As String
Public Order As IntPtr
Public Dx As IntPtr
Public CaretPos As IntPtr
Public [Class] As IntPtr
Public Glyphs As IntPtr
Public GlyphCount As UInteger
Public MaxFit As Integer
End Structure
_
Public Structure SCRIPT_CONTROL
Public ScriptControlFlags As UInteger
End Structure
_
Public Structure SCRIPT_STATE
Public ScriptStateFlags As UShort
End Structure
_
Public Structure SCRIPT_ANALYSIS
Public ScriptAnalysisFlags As UShort
Public s As SCRIPT_STATE
End Structure
_
Public Structure SCRIPT_VISATTR
Public ScriptVisAttrFlags As UShort
End Structure
_
Public Structure SCRIPT_ITEM
Public iCharPos As Integer
Public a As SCRIPT_ANALYSIS
End Structure
_
Public Structure GOFFSET
Public du As Integer
Public dv As Integer
End Structure
_
Public Structure ABC
Public abcA As Integer
Public abcB As UInteger
Public abcC As Integer
End Structure
Public Const E_OUTOFMEMORY As Integer = &H8007000E
Public Const E_PENDING As Integer = &H8000000A
Public Const USP_E_SCRIPT_NOT_IN_FONT As Integer = &H80040200
_
Public Shared Function GetCharacterPlacement(hdc As IntPtr, lpString As String, nCount As Integer, nMaxExtent As Integer, ByRef lpResults As GCP_RESULTS, dwFlags As UInteger) As UInteger
End Function
_
Public Shared Function ScriptItemize( wcInChars As String, cInChars As Integer, cMaxItems As Integer, psControl As SCRIPT_CONTROL, psState As SCRIPT_STATE, pItems() As SCRIPT_ITEM, ByRef pcItems As Integer) As Integer
End Function
_
Public Shared Function ScriptShape(hdc As IntPtr, ByRef psc As IntPtr, wcChars As String, cChars As Integer, cMaxGlyphs As Integer, ByRef psa As SCRIPT_ANALYSIS, wOutGlyphs() As UShort, wLogClust() As UShort, psva() As SCRIPT_VISATTR, ByRef cGlyphs As Integer) As Integer
End Function
_
Public Shared Function ScriptPlace(hdc As IntPtr, ByRef psc As IntPtr, wGlyphs() As UShort, cGlyphs As Integer, psva() As SCRIPT_VISATTR, ByRef psa As SCRIPT_ANALYSIS, iAdvance() As Integer, pGoffset() As GOFFSET, ByRef pABC As ABC) As Integer
End Function
_
Public Shared Function ScriptFreeCache(ByRef psc As IntPtr) As Integer
End Function
_
Public Shared Function GetDC(hWnd As IntPtr) As IntPtr
End Function
_
Public Shared Function ReleaseDC(hWnd As IntPtr, hdc As IntPtr) As Integer
End Function
_
Private Shared Function SelectObject(ByVal hdc As IntPtr, ByVal hObject As IntPtr) As IntPtr
End Function
Structure CharPosInfo
Public Index As Integer
Public Width As Integer
Public PriorWidth As Integer
Public X As Integer
Public Y As Integer
End Structure
Public Shared Function GetWordDiacriticPositions(Str As String, useFont As Font) As CharPosInfo()
Dim hdc As IntPtr
Dim CharPosInfos As New List(Of CharPosInfo)
hdc = GetDC(IntPtr.Zero) 'desktop device context
Dim oldFont As IntPtr = SelectObject(hdc, useFont.ToHfont())
Dim MaxItems As Integer = 16
Dim Control As New SCRIPT_CONTROL With {.ScriptControlFlags = 0}
Dim State As New SCRIPT_STATE With {.ScriptStateFlags = 1} '0 LTR, 1 RTL
Dim Items() As SCRIPT_ITEM = Nothing
Dim ItemCount As Integer
Dim Result As Integer
Do
ReDim Items(MaxItems - 1)
Result = ScriptItemize(Str, Str.Length, MaxItems, Control, State, Items, ItemCount)
If Result = 0 Then
ReDim Preserve Items(ItemCount) 'there is a dummy last item so adding one here
Exit Do
ElseIf Result = E_OUTOFMEMORY Then
End If
MaxItems *= 2
Loop While True
If Result = 0 Then
'last item is dummy item pointing to end of string
Dim Cache As IntPtr = IntPtr.Zero
For Count = 0 To ItemCount - 2
Dim Logs() As UShort = Nothing
Dim Glyphs() As UShort = Nothing
Dim VisAttrs() As SCRIPT_VISATTR = Nothing
ReDim Glyphs((Items(Count + 1).iCharPos - Items(Count).iCharPos) * 3 2 + 16 - 1)
ReDim VisAttrs((Items(Count + 1).iCharPos - Items(Count).iCharPos) * 3 2 + 16 - 1)
ReDim Logs(Items(Count + 1).iCharPos - Items(Count).iCharPos - 1)
Dim dc As IntPtr = IntPtr.Zero
Do
Dim GlyphsUsed As Integer
Result = ScriptShape(dc, Cache, Str.Substring(Items(Count).iCharPos), Items(Count + 1).iCharPos - Items(Count).iCharPos, Glyphs.Length, Items(Count).a, Glyphs, Logs, VisAttrs, GlyphsUsed)
If Result = 0 Then
ReDim Preserve Glyphs(GlyphsUsed - 1)
ReDim Preserve VisAttrs(GlyphsUsed - 1)
Exit Do
ElseIf Result = E_PENDING Then
dc = hdc
ElseIf Result = E_OUTOFMEMORY Then
ReDim Glyphs(Glyphs.Length * 2 - 1)
ReDim VisAttrs(VisAttrs.Length * 2 - 1)
ElseIf Result = USP_E_SCRIPT_NOT_IN_FONT Then
Else
End If
Loop While True
If Result = 0 Then
Dim Advances(Glyphs.Length - 1) As Integer
Dim Offsets(Glyphs.Length - 1) As GOFFSET
Dim abc As New ABC With {.abcA = 0, .abcB = 0, .abcC = 0}
dc = IntPtr.Zero
Do
Result = ScriptPlace(dc, Cache, Glyphs, Glyphs.Length, VisAttrs, Items(Count).a, Advances, Offsets, abc)
If Result E_PENDING Then Exit Do
dc = hdc
Loop While True
If Result = 0 Then
Dim LastPriorWidth As Integer = 0
Dim RunStart As Integer = 0
For CharCount = 0 To Logs.Length - 1
Dim PriorWidth As Integer = 0
Dim RunCount As Integer = 0
For ResCount As Integer = Logs(CharCount) To If(CharCount = Logs.Length - 1, 0, Logs(CharCount + 1)) Step -1
'fDiacritic or fZeroWidth
If (VisAttrs(ResCount).ScriptVisAttrFlags And (32 Or 64)) 0 Then
CharPosInfos.Add(New CharPosInfo With {.Index = RunStart + RunCount, .PriorWidth = LastPriorWidth, .Width = Advances(ResCount), .X = Offsets(ResCount).du, .Y = Offsets(ResCount).dv})
End If
If CharCount = Logs.Length - 1 OrElse Logs(CharCount) Logs(CharCount + 1) Then
PriorWidth += Advances(ResCount)
RunCount += 1
End If
Next
LastPriorWidth += PriorWidth
If CharCount = Logs.Length - 1 OrElse Logs(CharCount) Logs(CharCount + 1) Then
RunStart = CharCount + 1
End If
Next
End If
End If
Next
ScriptFreeCache(Cache)
End If
SelectObject(hdc, oldFont)
ReleaseDC(IntPtr.Zero, hdc)
Return CharPosInfos.ToArray()
End Function