Thank you very much for the example Lex. As always your advice is 2nd to none
Very cool. It seems a tiny bit slow to complete, but I think thats fine.
Here is the full code for anyone that wants to try it (I know people hate me taking functions out of the standard library etc... but I just cant help it. I hate to include all that code when its not needed

)
I would like to wrap all this into 1 easy to use function and add some of my own options. As long as no-one has any objections Id like to neaten this and supercede my function with this
Code:
; Get COLOR_3DFACE (default GUI colour.)
SetFormat, Integer, H
bgc := DllCall("GetSysColor","int",15)
bgc := bgc >> 16 | bgc & 0xFF00 | (bgc & 0xFF) << 16
bgc := SubStr("000000" SubStr(bgc, 3), -5)
SetFormat, Integer, D
html =
(
<body bgcolor="#%bgc%" scroll="no" style="margin: 0">
<html>
<body>
<b>This text is bold</b>
<br>
<strong>
This text is strong
</strong>
<br>
<big>
This text is big
</big>
<br>
<em>
This text is emphasized
</em>
<br>
<i>
This text is italic
</i>
<br>
<small>
This text is small
</small>
<br>
This text contains
<sub>
subscript
</sub>
<br>
This text contains
<sup>
superscript
</sup>
</body>
</html><br>
</body>
)
GuiAddHtml(html, "W200")
Gui, Show
Return
GuiAddHtml(html, Options="") ; (only positioning options should be used)
{
IE_Init()
Gui, +LastFound
if ! RegExMatch(Options, "(?<!\S)W(\d+)", w)
w1 := 100
ie := IE_Add(WinExist(), 0, 0, w1, 100)
WinSet, ExStyle, -0x200, % "ahk_id " COM_AtlAxGetContainer(ie)
IE_LoadURL(ie, "about:blank")
doc := IE_Document(ie)
COM_Invoke(doc, "write", html)
COM_Invoke(doc, "close")
body := COM_Invoke(doc, "body")
if !(w && RegExMatch(Options, "(?<!\S)H\d+"))
{
; Wait up to one second for document to load, in case images were specified.
; Loop 10 {
; if COM_Invoke(doc, "readyState") = "complete"
; break
; Sleep, 100
; }
; body.offsetHeight seems to simply be the height of the control,
; so use the bottom of the lowest element.
h := 0
all := COM_Invoke(body, "all")
Loop % COM_Invoke(all, "length") {
item := COM_Invoke(all, "item", A_Index-1)
x := COM_Invoke(item, "clientLeft") + COM_Invoke(item, "offsetLeft")
+ COM_Invoke(item, "offsetWidth")
y := COM_Invoke(item, "clientTop") + COM_Invoke(item, "offsetTop")
+ COM_Invoke(item, "offsetHeight")
if (y > h)
h := y
if (x > w1)
w1 := x
COM_Release(item)
}
COM_Release(all)
}
COM_Release(body)
COM_Release(doc)
Gui, Add, Text, W%w1% H%h% %Options% hwndhtext Hidden, guihtml%ie%
GuiControlGet, t, Pos, guihtml%ie%
IE_Move(ie, tX, tY, tW, tH)
return ie
}
Esc::ExitApp
IE_Init()
{
COM_AtlAxWinInit()
}
COM_AtlAxWinInit(Version = "")
{
COM_CoInitialize()
If Not DllCall("GetModuleHandle", "str", "atl" . Version)
DllCall("LoadLibrary" , "str", "atl" . Version)
Return DllCall("atl" . Version . "\AtlAxWinInit")
}
COM_CoInitialize()
{
Return DllCall("ole32\CoInitialize", "Uint", 0)
}
IE_Add(hWnd, x, y, w, h)
{
Return COM_AtlAxGetControl(COM_AtlAxCreateContainer(hWnd, x, y, w, h, "Shell.Explorer"))
}
COM_AtlAxCreateContainer(hWnd, l, t, w, h, Name = "", Version = "")
{
Return DllCall("CreateWindowEx", "Uint",0x200, "str", "AtlAxWin" . Version, "Uint", Name ? &Name : 0, "Uint", 0x54000000, "int", l, "int", t, "int", w, "int", h, "Uint", hWnd, "Uint", 0, "Uint", 0, "Uint", 0)
}
COM_AtlAxGetControl(hWnd, Version = "")
{
If DllCall("atl" . Version . "\AtlAxGetControl", "Uint", hWnd, "UintP", punk)=0
pdsp:=COM_QueryInterface(punk), COM_Release(punk)
Return pdsp
}
COM_QueryInterface(ppv, IID = "")
{
If DllCall(NumGet(NumGet(1*ppv)+0), "Uint", ppv, "Uint", COM_GUID4String(IID,IID ? IID : IID=0 ? "{00000000-0000-0000-C000-000000000046}" : "{00020400-0000-0000-C000-000000000046}"), "UintP", ppv)=0
Return ppv
}
COM_GUID4String(ByRef CLSID, String)
{
VarSetCapacity(CLSID, 16)
DllCall("ole32\CLSIDFromString", "Uint", COM_Unicode4Ansi(String,String,38), "Uint", &CLSID)
Return &CLSID
}
COM_Unicode4Ansi(ByRef wString, sString, nSize = "")
{
If (nSize = "")
nSize:=DllCall("kernel32\MultiByteToWideChar", "Uint", 0, "Uint", 0, "Uint", &sString, "int", -1, "Uint", 0, "int", 0)
VarSetCapacity(wString, nSize * 2 + 1)
DllCall("kernel32\MultiByteToWideChar", "Uint", 0, "Uint", 0, "Uint", &sString, "int", -1, "Uint", &wString, "int", nSize + 1)
Return &wString
}
COM_AtlAxGetContainer(pdsp)
{
DllCall(NumGet(NumGet(1*pdsp)+ 0), "Uint", pdsp, "Uint", COM_GUID4String(IID_IOleWindow,"{00000114-0000-0000-C000-000000000046}"), "UintP", pwin)
DllCall(NumGet(NumGet(1*pwin)+12), "Uint", pwin, "UintP", hCtrl)
DllCall(NumGet(NumGet(1*pwin)+ 8), "Uint", pwin)
Return DllCall("GetParent", "Uint", hCtrl)
}
IE_LoadURL(pwb, u)
{
pUrl := COM_SysAllocString(u)
VarSetCapacity(var, 8 * 2, 0)
DllCall(NumGet(NumGet(1*pwb)+44), "Uint", pwb, "Uint", pUrl, "Uint", &var, "Uint", &var, "Uint", &var, "Uint", &var)
COM_SysFreeString(pUrl)
}
COM_SysFreeString(bstr)
{
Return DllCall("oleaut32\SysFreeString", "Uint", bstr)
}
COM_SysAllocString(sString)
{
Return DllCall("oleaut32\SysAllocString", "Uint", COM_Ansi2Unicode(sString,wString))
}
COM_Ansi2Unicode(ByRef sString, ByRef wString, nSize = "")
{
If (nSize = "")
nSize:=DllCall("kernel32\MultiByteToWideChar", "Uint", 0, "Uint", 0, "Uint", &sString, "int", -1, "Uint", 0, "int", 0)
VarSetCapacity(wString, nSize * 2 + 1)
DllCall("kernel32\MultiByteToWideChar", "Uint", 0, "Uint", 0, "Uint", &sString, "int", -1, "Uint", &wString, "int", nSize + 1)
Return &wString
}
IE_Document(pwb)
{
DllCall(NumGet(NumGet(1*pwb)+72), "Uint", pwb, "UintP", pdoc)
Return pdoc
}
COM_Invoke(pdisp, sName, arg0="vT_NoNe",arg1="vT_NoNe",arg2="vT_NoNe",arg3="vT_NoNe",arg4="vT_NoNe",arg5="vT_NoNe",arg6="vT_NoNe",arg7="vT_NoNe",arg8="vT_NoNe",arg9="vT_NoNe")
{
Global _hResult_
sParams := 0123456789
Loop, Parse, sParams
If (arg%A_LoopField% == "vT_NoNe")
{
nParams := A_Index - 1
Break
}
sParams := SubStr(sParams,1,nParams)
VarSetCapacity(DispParams,16,0), VarSetCapacity(varResult,16,0), VarSetCapacity(IID_NULL,16,0), VarSetCapacity(varg,nParams*16,0)
NumPut(&varg,DispParams,0), NumPut(nParams,DispParams,8)
If (nFlags := SubStr(sName,0) <> "=" ? 3 : 12) = 12
NumPut(&varResult,DispParams,4), NumPut(1,DispParams,12), NumPut(-3,varResult), sName:=SubStr(sName,1,-1)
Loop, Parse, sParams
If arg%A_LoopField% Is Not Integer
NumPut(8,varg,(nParams-A_Index)*16,"Ushort"), NumPut(COM_SysAllocString(arg%A_LoopField%),varg,(nParams-A_Index)*16+8)
Else NumPut(SubStr(arg%A_LoopField%,1,1)="+" ? 9 : 3,varg,(nParams-A_Index)*16,"Ushort"), NumPut(arg%A_LoopField%,varg,(nParams-A_Index)*16+8)
If (0 = _hResult_:=DllCall(NumGet(NumGet(1*pdisp)+20), "Uint", pdisp, "Uint", &IID_NULL, "UintP", COM_Unicode4Ansi(wName, sName), "Uint", 1, "Uint", LCID, "intP", dispID))
&& (0 = _hResult_:=DllCall(NumGet(NumGet(1*pdisp)+24), "Uint", pdisp, "int", dispID, "Uint", &IID_NULL, "Uint", LCID, "Ushort", nFlags, "Uint", &dispParams, "Uint", &varResult, "Uint", 0, "Uint", 0))
&& (3 = nFlags)
Result:=(vt:=NumGet(varResult,0,"Ushort"))=8||vt<0x1000&&DllCall("oleaut32\VariantChangeTypeEx","Uint",&varResult,"Uint",&varResult,"Uint",LCID,"Ushort",1,"Ushort",8)=0 ? COM_Ansi4Unicode(bstr:=NumGet(varResult,8)) . SubStr(COM_SysFreeString(bstr),1,0) : NumGet(varResult,8)
Loop, % nParams
NumGet(varg,(A_Index-1)*16,"Ushort")=8 ? COM_SysFreeString(NumGet(varg,(A_Index-1)*16+8)) : ""
Return Result
}
COM_Ansi4Unicode(pString, nSize = "")
{
If (nSize = "")
nSize:=DllCall("kernel32\WideCharToMultiByte", "Uint", 0, "Uint", 0, "Uint", pString, "int", -1, "Uint", 0, "int", 0, "Uint", 0, "Uint", 0)
VarSetCapacity(sString, nSize)
DllCall("kernel32\WideCharToMultiByte", "Uint", 0, "Uint", 0, "Uint", pString, "int", -1, "str", sString, "int", nSize + 1, "Uint", 0, "Uint", 0)
Return sString
}
COM_Release(ppv)
{
Return DllCall(NumGet(NumGet(1*ppv)+8), "Uint", ppv)
}
IE_Move(pwb, l, t, w, h)
{
WinMove, % "ahk_id " . COM_AtlAxGetContainer(pwb), , l, t, w, h
}
I had actually nearly finished writing a way to wrap the old version without having to use a new gui. I would add all the text in a straight line, and after each new piece of text was added, then it would check the x position that it was added and its width and then determine whther to guicontrol it to the next line and continue from there, which i actually think was a quite neat way to do it.