#include "..\Direct2D.au3" #include "..\DirectWrite.au3" #include "..\Direct2D_1.au3" ;~ #include "ObjectFromTag.au3" #include #include #include #include Local $hKernel32 = DllOpen("Kernel32.dll") Global $oError = ObjEvent("AutoIt.Error", "_ErrFunc") Global $sIID_IDWriteTextRenderer1="{D3E0E934-22A0-427E-AAE4-7D9574B59DB1}" Global $tagIDWriteTextRenderer1=$tagIDWriteTextRenderer Func _ErrFunc() ConsoleWrite("COM Error, ScriptLine(" & $oError.ScriptLine & ") : Number 0x" & Hex($oError.Number, 8) & " - " & $oError.WinDescription & @CRLF) EndFunc ;==>_ErrFunc Global $pOldFuncTest, $pIDWriteTextRenderer_Old, $pRenderer_QueryInterfaceDefault Local $sString = "One line more text Even More" Local $hGui = GUICreate("Direct2D test", 805, 450) GUISetState() ;~ Local $oFactory = _D2D_Factory_Create() Local $oFactory=_D2D_Factory1_Create() Local $oRender = _D2D_Factory_CreateHwndRenderTarget($oFactory, $hGui) Local $oBrush = _D2D_RenderTarget_CreateSolidColorBrush($oRender, 0.2, 0.3, 1, 0.8) ;here a we define an application value that will be used with a call to a custom text renderer Local $tagMyContext="struct;ptr;endstruct";it will hve only one parameter, pointer to $oRender $tMyConext=DllStructCreate($tagMyContext) $ptrRnder=Ptr($oRender()) DllStructSetData($tMyConext,1,$ptrRnder) $pMyContext=DllStructGetPtr($tMyConext) Local $oDW_Factory = _DWrite_Factory_Create() Local $oDW_Format = _DWrite_Factory_CreateTextFormat($oDW_Factory, "Arial", 30, $DWRITE_FONT_WEIGHT_REGULAR, $DWRITE_FONT_STYLE_ITALIC) Local $oDW_Layout = _DWrite_Factory_CreateTextLayout($oDW_Factory, $sString, $oDW_Format, 300, 450) ;max width, max height Global $tStruct Global $oMyRenderer = ObjectFromTag("MyRenderer_", $tagIDWriteTextRenderer, $tStruct, False, False, True, $sIID_IDWriteTextRenderer) ;IDWriteTxtRenderer If IsObj($oMyRenderer) Then $pMyRenderer=Ptr($oMyRenderer()) Else $pMyRenderer=$oMyRenderer EndIf $tTestStruct=DllStructCreate("int") DllStructSetData($tTestStruct,1,5) $pStruct=DllStructGetPtr($tTestStruct) ;set some properties for text $oDW_Layout.SetFontWeight($DWRITE_FONT_WEIGHT_EXTRA_BOLD, 10, 20) $oDW_Layout.SetFontSize(20, 10, 5) $oDW_Layout.SetUnderline(1, 9, 15) Local $tMatrix_Scale = _D2D_Matrix3x2_Scale(2, 1, -150, 200) $oRender.SetTransform($tMatrix_Scale) $oRender.BeginDraw() _D2D_RenderTarget_Clear($oRender, 1, 0.9, 0.9) $tPoint=_D2D1_POINT_2F(20,40) $oDW_Layout.Draw($pMyContext,$oMyRenderer,20,40);>>>Here the Draw method is called, and only bounding rectangle are drawn for now $oRender.DrawTextLayout(20,40, $oDW_Layout, $oBrush, 2);now draw text $oRender.EndDraw(0, 0) While GUIGetMsg() <> -3 WEnd $oDW_Layout = 0 $oDW_Typography = 0 $oDW_Format = 0 $oDW_Factory = 0 $oBrush = 0 $oRender = 0 $oFactory = 0 GUIDelete($hGui) #Region Custom text renderer callbacks ;~ HRESULT DrawGlyphRun( ;~ void *clientDrawingContext, ;~ FLOAT baselineOriginX, ;~ FLOAT baselineOriginY, ;~ DWRITE_MEASURING_MODE measuringMode, ;~ [in] DWRITE_GLYPH_RUN const *glyphRun, ;~ [in] DWRITE_GLYPH_RUN_DESCRIPTION const *glyphRunDescription, ;~ IUnknown *clientDrawingEffect ;~ ); Func MyRenderer_DrawGlyphRun($pSelf, $pClientDrawingContext, $fBaselineOriginX, $fBaselineOriginY, $iMeasuringMode, $pGlyphRun, $pGlyphRunDescription, $pClientDrawingEffect); Ret: long Par: struct*;float;float;uint;struct*;struct*;struct* ConsoleWrite("MyRenderer_DrawGlyphRun()" & @CRLF & @CRLF) ConsoleWrite(@TAB & "$pSelf=" & $pSelf & @CRLF) ConsoleWrite(@TAB & "$pClientDrawingContext=" & $pClientDrawingContext & @CRLF) ConsoleWrite(@TAB & "x:" & $fBaselineOriginX & ", y:" & $fBaselineOriginY & @CRLF) ConsoleWrite(@TAB & "$pClientDrawingEffect=" & $pClientDrawingEffect & @CRLF) ConsoleWrite(@TAB & "$pGlyphRun=" & $pGlyphRun & @CRLF) $tData = DllStructCreate($tagDWRITE_GLYPH_RUN, $pGlyphRun) $tData2=DllStructCreate($tagDWRITE_GLYPH_RUN_DESCRIPTION, $pGlyphRunDescription) ConsoleWrite(@TAB & "StringLen=" & DllStructGetData($tData2,"StringLength") & @CRLF) $tStringPtr=DllStructGetData($tData2,"String") ConsoleWrite(@TAB & "type of $tStrigPtr is " & VarGetType($tStringPtr) & @CRLF) ConsoleWrite(@TAB & "value of StringPtr is " & $tStringPtr & @CRLF) $tTag="struct;wchar" & " Text[" & DllStructGetData($tData2,"StringLength") & "];endstruct" ConsoleWrite(@TAB & "Tag=" & $tTag & @CRLF) $tString=DllStructCreate($tTag,$tStringPtr) If @error Then ConsoleWrite(@TAB & "!DllStructCreate error:" & @error & ", ptr=" & $pGlyphRun & @CRLF) Else ConsoleWrite(@TAB & "FontEmSize:" & DllStructGetData($tData, "FontEmSize") & @CRLF) EndIf $iCount=DllStructGetData($tData,"glyphCount") ConsoleWrite("$iCount=" & $iCount & @CRLF) ConsoleWrite(@TAB & "Text=" & DllStructGetData($tString,"Text") & @CRLF) $tWidths=DllStructCreate("struct;float[" & $iCount & "]",DllStructGetData($tData,"GlyphAdvances")) $fTotalWidth=0 For $i=1 To $iCount $fTotalWidth=$fTotalWidth+DllStructGetData($tWidths,1,$i) ;~ ConsoleWrite(@TAB & "advance("& $i & ")=" & DllStructGetData($tWidths,1,$i) & @CRLF) Next ConsoleWrite(@TAB & "TotalWidth=" & $fTotalWidth & @CRLF) $tDrawingContext=DllStructCreate($tagMyContext,$pClientDrawingContext) $pRenderPointer=DllStructGetData($tDrawingContext,1) ConsoleWrite("$pRenderPointer=" & $pRenderPointer & @CRLF) $oRender2=ObjCreateInterface($pRenderPointer,$sIID_ID2D1HwndRenderTarget, $tagID2D1HwndRenderTarget) $oRender2.AddRef() $fxStart=$fBaselineOriginX $fYStart=$fBaselineOriginY-DllStructGetData($tData, "FontEmSize") $fxEnd=$fBaselineOriginX+$fTotalWidth $fYEnd=$fBaselineOriginY $tBoundingRect=_D2D1_RECT_F($fxStart,$fYStart,$fxEnd,$fYEnd) $oRender2.DrawRectangle($tBoundingRect,$oBrush,1,Null) Return 0 ; S_OK = 0x00000000 EndFunc ;==>MyRenderer_DrawGlyphRun ;~ HRESULT DrawUnderline( ;~ void *clientDrawingContext, ;~ FLOAT baselineOriginX, ;~ FLOAT baselineOriginY, ;~ [in] DWRITE_UNDERLINE const *underline, ;~ IUnknown *clientDrawingEffect ;~ ); ;~ https://github.com/HackerFantastic/Terminal/blob/master/src/renderer/dx/CustomTextRenderer.cpp ;~ https://www.autoitscript.com/forum/topic/153859-objevent-possible-with-addfocuschangedeventhandler/?tab=comments#comment-1111701 Func MyRenderer_DrawUnderline($pSelf, $pClientDrawingContext, $fBaselineOriginX, $fBaselineOriginY, $pUnderline, $pClientDrawingEffect);DrawUnderline hresult(struct*;float;float;struct*;struct*);) ;$pSelf, $pClientDrawingContext, $fBaselineOriginX, $fBaselineOriginY, $fWidth, $fThickness, $fOffset, $fRunHeight, $iReadingDirection, $iFlowDirection, $ptr, $iMeasuringMode, $struct2 ConsoleWrite("MyRenderer_DrawUnderline()" & @CRLF & @CRLF) ConsoleWrite(@TAB & "$pClientDrawingContext=" & $pClientDrawingContext & @CRLF) ;~ MsgBox(0,"Test","test") ConsoleWrite(@TAB & "x=" & $fBaselineOriginX & ", y=" & $fBaselineOriginY & @CRLF) ConsoleWrite(@TAB & "$pUnderline=" & $pUnderline & @CRLF) $tUnderline=DllStructCreate($tagDWRITE_UNDERLINE,$pUnderline) ConsoleWrite(@TAB & "width=" & DllStructGetData($tUnderline,"Width") & @CRLF) Local $tagIUnknown = _ ; IUnknown interface description "QueryInterface hresult(ptr;ptr*);" & _ "AddRef dword();" & _ "Release dword();" ConsoleWrite(@TAB & "$pClientDrawingEffect=" & $pClientDrawingEffect & @CRLF) Return 0 ; S_OK = 0x00000000 EndFunc ;==>MyRenderer_DrawUnderline Func MyRenderer_QueryInterface($pSelf, $pRIID, $pObj) ; Ret: long Par: ptr;ptr* ConsoleWrite("MyRenderer_QueryInterface()" & @CRLF & @CRLF) ConsoleWrite(@TAB & "$pSelf=" & $pSelf & @CRLF) ConsoleWrite(@TAB & "$pObj=" & $pObj & @CRLF) $sRIIDQuery = _WinAPI_StringFromGUID($pRIID) ConsoleWrite(@TAB & "$sIID=" & $sRIIDQuery & @CRLF) Local $tRef = DllStructCreate("int", $pSelf - 8) ; reference counter is size of two ints before Local $iRef = DllStructGetData($tRef, 1) DllStructSetData($tRef,1,$iRef+1) $iRef = DllStructGetData($tRef, 1) ;~ ConsoleWrite("$iRef=" & $iRef & @CRLF) Return 0 ; S_OK = 0x00000000 #forceref $pSelf, $pRIID, $pObj EndFunc ;==>MyRenderer_QueryInterface Func MyRenderer_AddRef($pSelf) ; Ret: dword ConsoleWrite("MyRenderer_AddRef()" & @CRLF & @CRLF) Local $tRef = DllStructCreate("int", $pSelf - 8) ; reference counter is size of two ints before Local $iRef = DllStructGetData($tRef, 1) + 1 ; increment DllStructSetData($tRef, 1, $iRef) Return $iRef ; For AddRef/Release #forceref $pSelf EndFunc ;==>MyRenderer_AddRef Func MyRenderer_Release($pSelf) ; Ret: dword ;~ ConsoleWrite("MyRenderer_Release()" & @CRLF & @CRLF) Local $tRef = DllStructCreate("int", $pSelf - 8) ; reference counter is size of two ints before Local $iRef = DllStructGetData($tRef, 1) - 1 ; decrement DllStructSetData($tRef, 1, $iRef) Return $iRef ; For AddRef/Release #forceref $pSelf EndFunc ;==>MyRenderer_Release Func MyRenderer_IsPixelSnappingEnabled($pSelf, $struct, $bool) ; Ret: long Par: struct*;bool* ConsoleWrite("MyRenderer_IsPixelSnappingEnabled()" & @CRLF & @CRLF) Return 0 ; S_OK = 0x00000000 #forceref $pSelf, $struct, $bool EndFunc ;==>MyRenderer_IsPixelSnappingEnabled Func MyRenderer_GetCurrentTransform($pSelf, $struct1, $struct2) ; Ret: long Par: struct*;struct* ConsoleWrite("MyRenderer_GetCurrentTransform()" & @CRLF & @CRLF) Return 0 ; S_OK = 0x00000000 #forceref $pSelf, $struct1, $struct2 EndFunc ;==>MyRenderer_GetCurrentTransform Func MyRenderer_GetPixelsPerDip($pSelf, $struct, $float) ; Ret: long Par: struct*;float* ConsoleWrite("MyRenderer_GetPixelsPerDip()" & @CRLF & @CRLF) Return 0 ; S_OK = 0x00000000 #forceref $pSelf, $struct, $float EndFunc ;==>MyRenderer_GetPixelsPerDip Func MyRenderer_DrawStrikethrough($pSelf, $struct1, $float1, $float2, $struct2, $struct3) ; Ret: long Par: struct*;float;float;struct*;struct* ConsoleWrite("MyRenderer_DrawStrikethrough()" & @CRLF & @CRLF) Return 0 ; S_OK = 0x00000000 #forceref $pSelf, $struct1, $float1, $float2, $struct2, $struct3 EndFunc ;==>MyRenderer_DrawStrikethrough Func MyRenderer_DrawInlineObject($pSelf, $struct1, $float1, $float2, $struct2, $bool1, $bool2, $struct3) ; Ret: long Par: struct*;float;float;struct*;bool;bool;struct* ConsoleWrite("MyRenderer_DrawInlineObject()" & @CRLF & @CRLF) Return 0 ; S_OK = 0x00000000 #forceref $pSelf, $struct1, $float1, $float2, $struct2, $bool1, $bool2, $struct3 EndFunc ;==>MyRenderer_DrawInlineObject #EndRegion Custom text renderer callbacks ;https://www.autoitscript.com/forum/topic/206615-convert-getref-function-from-vbscript-to-autoit/?tab=comments#comment-1489832 ;https://www.autoitscript.com/forum/topic/205154-using-objcreateinterface-and-objectfromtag-functions/?tab=comments#comment-1475246 Func ObjectFromTag( $sFunctionPrefix, $tagInterface, ByRef $tInterface, $bObject = True, $bPrint = False, $bIsUnknown = True, $sIID = "{00000000-0000-0000-C000-000000000046}" ) ; Last param is IID_IUnknown by default Local $sInterface = $tagInterface ; Copy interface description Local $tagIUnknown = _ ; IUnknown interface description "QueryInterface hresult(ptr;ptr*);" & _ "AddRef dword();" & _ "Release dword();" If $bIsUnknown Then $tagInterface = $tagIUnknown & $tagInterface ; Adding IUnknown methods Local $aMethods = StringSplit( StringTrimRight( StringReplace( StringRegExpReplace( $tagInterface, "\h*(\w+)\h*(\w+\*?)\h*(\(\h*(.*?)\h*\))\h*(;|;*\z)", "$1\|$2\|$4" & @LF ), ";" & @LF, @LF ), 1 ), @LF, 3 ) Local $iMethods = UBound( $aMethods ), $aSplit, $aSplit2, $iSplit2, $sParams, $sParams2, $oParams = ObjCreate( "Scripting.Dictionary" ), $oParams2 = ObjCreate( "Scripting.Dictionary" ), $hCallback, $iPar, $s, $t $tInterface = DllStructCreate( "int RefCount;int Size;ptr Object;ptr Methods[" & $iMethods & "];int_ptr Callbacks[" & $iMethods & "];ulong_ptr Slots[16]" ) ; 16 pointer sized elements more to create space for possible private props If @error Then Return SetError( 1, 0, 0 ) For $i = 0 To $iMethods - 1 $aSplit = StringSplit( $aMethods[$i], "|", 2 ) $aSplit[0] = $sFunctionPrefix & $aSplit[0] ; Method name If $aSplit[1] = "hresult" Then $aSplit[1] = "long" ; Return type $sParams = $aSplit[2] ? "ptr;" & StringReplace( StringReplace( StringReplace( StringReplace( $aSplit[2], "object", "idispatch" ), "bstr", "ptr" ), "variant", "ptr" ), "hresult", "long" ) : "ptr" ; Params ;~ $sParams=StringReplace($sParams,"struct*","ptr*") If $bPrint Then $iPar = StringInStr( $sParams, ";", 2 ) If $iPar Then $sParams2 = StringRight( $sParams, StringLen( $sParams ) - $iPar ) If StringInStr( $aSplit[0], "_QueryInterface", 2 ) Then $s = ", $pRIID, $pObj" Else $oParams.RemoveAll() $oParams2.RemoveAll() $aSplit2 = StringSplit( $sParams2, ";", 2 ) $iSplit2 = UBound( $aSplit2 ) For $j = 0 To $iSplit2 - 1 $aSplit2[$j] = StringRegExpReplace( $aSplit2[$j], "\*$", "" ) $oParams( $aSplit2[$j] ) += 1 Next $s = "" For $j = 0 To $iSplit2 - 1 $s &= ", $" & $aSplit2[$j] If $oParams.Item( $aSplit2[$j] ) > 1 Then $oParams2( $aSplit2[$j] ) += 1 $s &= $oParams2( $aSplit2[$j] ) EndIf Next EndIf EndIf $t = $iPar ? "Ret: " & $aSplit[1] & " " & "Par: " & $sParams2 : "Ret: " & $aSplit[1] ConsoleWrite( "Func " & $aSplit[0] & ( $iPar ? "( $pSelf" & $s & " ) ; " : "( $pSelf ) ; " ) & $t & @CRLF ) ConsoleWrite( " ConsoleWrite( """ & $aSplit[0] & "()"" & @CRLF & @CRLF )" & @CRLF ) ConsoleWrite( " Return " & ( ( StringInStr( $aSplit[0], "_AddRef", 2 ) Or StringInStr( $aSplit[0], "_Release", 2 ) ) ? "1 ; For AddRef/Release" : "0 ; S_OK = 0x00000000" ) & @CRLF ) ConsoleWrite( " #forceref" & ( $iPar ? " $pSelf" & $s : " $pSelf" ) & @CRLF & "EndFunc" & @CRLF ) EndIf $hCallback = DllCallbackRegister( $aSplit[0], $aSplit[1], $sParams ) ;~ ConsoleWrite($aSplit[0] & " "& $aSplit[1] & "(" & $sParams & ")" & @CRLF) If $bPrint Then ConsoleWrite( "@error = " & @error & @CRLF & @CRLF ) DllStructSetData( $tInterface, "Methods", DllCallbackGetPtr( $hCallback ), $i + 1 ) ; Save callback pointer DllStructSetData( $tInterface, "Callbacks", $hCallback, $i + 1 ) ; Save callback handle Next DllStructSetData( $tInterface, "RefCount", 1 ) ; Initial ref count is 1 DllStructSetData( $tInterface, "Size", $iMethods ) ; Number of interface methods DllStructSetData( $tInterface, "Object", DllStructGetPtr( $tInterface, "Methods" ) ) ; Interface method pointers ConsoleWrite("ObjectFromTag=" & DllStructGetPtr( $tInterface, "Object") & @CRLF) Return $bObject ? ObjCreateInterface( DllStructGetPtr( $tInterface, "Object" ), $sIID, $sInterface, $bIsUnknown ) : DllStructGetPtr( $tInterface, "Object" ) EndFunc ; Pointer that's wrapped into object ; Pointer ( = $pSelf ) Func DeleteObjectFromTag( ByRef $tInterface ) For $i = 1 To DllStructGetData( $tInterface, "Size" ) DllCallbackFree( DllStructGetData( $tInterface, "Callbacks", $i ) ) Next $tInterface = 0 EndFunc