<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_PythonHelper" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
REM ===			The ScriptForge library and its associated libraries are part of the LibreOffice project.				===
REM ===					Full documentation is available on https://help.libreoffice.org/								===
REM =======================================================================================================================

Option Compatible
Option Explicit

&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
&apos;&apos;&apos;	SF_PythonHelper (aka Basic)
&apos;&apos;&apos;	===============
&apos;&apos;&apos;		Singleton class implementing the &quot;ScriptForge.Basic&quot; service
&apos;&apos;&apos;		Implemented as a usual Basic module
&apos;&apos;&apos;
&apos;&apos;&apos;		The &quot;Basic&quot; service must be called ONLY from a PYTHON script
&apos;&apos;&apos;		Service invocations: Next Python code lines are equivalent:
&apos;&apos;&apos;			bas = CreateScriptService(&apos;ScriptForge.Basic&apos;)
&apos;&apos;&apos;			bas = CreateScriptService(&apos;Basic&apos;)
&apos;&apos;&apos;
&apos;&apos;&apos;		This service proposes a collection of methods to be executed in a Python context
&apos;&apos;&apos;		to simulate the exact behaviour of the identical Basic builtin method.
&apos;&apos;&apos;		Typical example:
&apos;&apos;&apos;			bas.MsgBox(&apos;This has to be displayed in a message box&apos;)
&apos;&apos;&apos;
&apos;&apos;&apos;		The service includes also an agnostic &quot;Python Dispatcher&quot; function.
&apos;&apos;&apos;		It dispatches Python script requests to execute Basic services to the
&apos;&apos;&apos;		appropriate properties and methods via dynamic call techniques
&apos;&apos;&apos;
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;

REM ================================================================== EXCEPTIONS

REM ============================================================ MODULE CONSTANTS

REM ===================================================== CONSTRUCTOR/DESTRUCTOR

REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
	Set Dispose = Nothing
End Function	&apos;	ScriptForge.SF_PythonHelper Explicit destructor

REM ================================================================== PROPERTIES

REM -----------------------------------------------------------------------------
Property Get ObjectType As String
&apos;&apos;&apos;	Only to enable object representation
	ObjectType = &quot;SF_PythonHelper&quot;
End Property	&apos;	ScriptForge.SF_PythonHelper.ObjectType

REM -----------------------------------------------------------------------------
Property Get ServiceName As String
&apos;&apos;&apos;	Internal use
	ServiceName = &quot;ScriptForge.Basic&quot;
End Property	&apos;	ScriptForge.SF_PythonHelper.ServiceName

REM ============================================================== PUBLIC METHODS

REM -----------------------------------------------------------------------------
Public Function PyCDate(ByVal DateArg As Variant) As Variant
&apos;&apos;&apos;	Convenient function to replicate CDate() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		DateArg: a date as a string or as a double
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The converted date as a UNO DateTime structure
&apos;&apos;&apos;		If the input argument could not be recognized as a date, return the argument unchanged
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;		a = bas.CDate(&apos;2021-02-18&apos;)

Dim vDate As Variant				&apos;	Return value
Const cstThisSub = &quot;Basic.CDate&quot;
Const cstSubArgs = &quot;datearg&quot;

	On Local Error GoTo Catch
	vDate = Null

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	vDate = CDate(DateArg)

Finally:
	If VarType(vDate) = V_DATE Then PyCDate = CDateToUnoDateTime(vDate) Else PyCDate = DateArg
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	On Local Error GoTo 0
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper.PyCDate

REM -----------------------------------------------------------------------------
Public Function PyConvertFromUrl(ByVal FileName As Variant) As String
&apos;&apos;&apos;	Convenient function to replicate ConvertFromUrl() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		FileName: a string representing a file in URL format
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The same file name in native operating system notation
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;		a = bas.ConvertFromUrl(&apos;file:////boot.sys&apos;)

Dim sFileName As String			&apos;	Return value
Const cstThisSub = &quot;Basic.ConvertFromUrl&quot;
Const cstSubArgs = &quot;filename&quot;

	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	sFileName = &quot;&quot;

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	sFileName = ConvertFromUrl(FileName)

Finally:
	PyConvertFromUrl = sFileName
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper.PyConvertFromUrl

REM -----------------------------------------------------------------------------
Public Function PyConvertToUrl(ByVal FileName As Variant) As String
&apos;&apos;&apos;	Convenient function to replicate ConvertToUrl() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		FileName: a string representing a file in native operating system notation
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The same file name in URL format
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;		a = bas.ConvertToUrl(&apos;C:\boot.sys&apos;)

Dim sFileName As String			&apos;	Return value
Const cstThisSub = &quot;Basic.ConvertToUrl&quot;
Const cstSubArgs = &quot;filename&quot;

	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	sFileName = &quot;&quot;

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	sFileName = ConvertToUrl(FileName)

Finally:
	PyConvertToUrl = sFileName
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper.PyConvertToUrl

REM -----------------------------------------------------------------------------
Public Function PyCreateUnoService(ByVal UnoService As Variant) As Variant
&apos;&apos;&apos;	Convenient function to replicate CreateUnoService() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		UnoService: a string representing the service to create
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		A UNO object
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;		a = bas.CreateUnoService(&apos;com.sun.star.i18n.CharacterClassification&apos;)

Dim vUno As Variant				&apos;	Return value
Const cstThisSub = &quot;Basic.CreateUnoService&quot;
Const cstSubArgs = &quot;unoservice&quot;

	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	Set vUno = Nothing

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	Set vUno = CreateUnoService(UnoService)

Finally:
	Set PyCreateUnoService = vUno
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper.PyCreateUnoService

REM -----------------------------------------------------------------------------
Public Function PyDateAdd(ByVal Add As Variant _
							, ByVal Count As Variant _
							, ByVal DateArg As Variant _
							) As Variant
&apos;&apos;&apos;	Convenient function to replicate DateAdd() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		Add: The unit to add
&apos;&apos;&apos;		Count: how many times to add (might be negative)
&apos;&apos;&apos;		DateArg: a date as a com.sun.star.util.DateTime UNO structure
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The new date as a string in iso format
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;		a = bas.DateAdd(&apos;d&apos;, 1, bas.Now())		&apos;	Tomorrow

Dim vNewDate As Variant				&apos;	Return value
Dim vDate As Date					&apos;	Alias of DateArg
Const cstThisSub = &quot;Basic.DateAdd&quot;
Const cstSubArgs = &quot;add, count, datearg&quot;

	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	vNewDate = &quot;&quot;

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	If VarType(DateArg) = V_OBJECT Then
		vDate = CDateFromUnoDateTime(DateArg)
	Else
		vDate = SF_Utils._CStrToDate(DateArg)
	End If
	vNewDate = DateAdd(Add, Count, vDate)

Finally:
	If VarType(vNewDate) = V_DATE Then PyDateAdd = CDateToUnoDateTime(vNewDate) Else PyDateAdd = vNewDate
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper.PyDateAdd

REM -----------------------------------------------------------------------------
Public Function PyDateDiff(ByVal Add As Variant _
							, ByVal Date1 As Variant _
							, ByVal Date2 As Variant _
							, ByVal WeekStart As Variant _
							, ByVal YearStart As Variant _
							) As Long
&apos;&apos;&apos;	Convenient function to replicate DateDiff() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		Add: The unit of the date interval
&apos;&apos;&apos;		Date1, Date2: the two dates to be compared
&apos;&apos;&apos;		WeekStart: the starting day of a week
&apos;&apos;&apos;		YearStart: the starting week of a year
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The number of intervals expressed in Adds
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;		a = bas.DateDiff(&apos;d&apos;, bas.DateAdd(&apos;d&apos;, 1, bas.Now()), bas.Now())		&apos;	-1 day

Dim lDiff As Long					&apos;	Return value
Dim vDate1 As Date					&apos;	Alias of Date1
Dim vDate2 As Date					&apos;	Alias of Date2
Const cstThisSub = &quot;Basic.DateDiff&quot;
Const cstSubArgs = &quot;add, date1, date2, [weekstart=1], [yearstart=1]&quot;

	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	lDiff = 0

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	If VarType(Date1) = V_OBJECT Then
		vDate1 = CDateFromUnoDateTime(Date1)
	Else
		vDate1 = SF_Utils._CStrToDate(Date1)
	End If
	If VarType(Date2) = V_OBJECT Then
		vDate2 = CDateFromUnoDateTime(Date2)
	Else
		vDate2 = SF_Utils._CStrToDate(Date2)
	End If
	lDiff = DateDiff(Add, vDate1, vDate2, WeekStart, YearStart)


Finally:
	PyDateDiff = lDiff
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper.PyDateDiff

REM -----------------------------------------------------------------------------
Public Function PyDatePart(ByVal Add As Variant _
							, ByVal DateArg As Variant _
							, ByVal WeekStart As Variant _
							, ByVal YearStart As Variant _
							) As Long
&apos;&apos;&apos;	Convenient function to replicate DatePart() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		Add: The unit of the date interval
&apos;&apos;&apos;		DateArg: The date from which to extract a part
&apos;&apos;&apos;		WeekStart: the starting day of a week
&apos;&apos;&apos;		YearStart: the starting week of a year
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The specified part of the date
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;		a = bas.DatePart(&apos;y&apos;, bas.Now())		&apos;	day of year

Dim lPart As Long					&apos;	Return value
Dim vDate As Date					&apos;	Alias of DateArg
Const cstThisSub = &quot;Basic.DatePart&quot;
Const cstSubArgs = &quot;add, datearg, [weekstart=1], [yearstart=1]&quot;

	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	lPart = 0

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	If VarType(DateArg) = V_OBJECT Then
		vDate = CDateFromUnoDateTime(DateArg)
	Else
		vDate = SF_Utils._CStrToDate(DateArg)
	End If
	lPart = DatePart(Add, vDate, WeekStart, YearStart)


Finally:
	PyDatePart = lPart
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper.PyDatePart

REM -----------------------------------------------------------------------------
Public Function PyDateValue(ByVal DateArg As Variant) As Variant
&apos;&apos;&apos;	Convenient function to replicate DateValue() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		DateArg: a date as a string
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The converted date as a UNO DateTime structure
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;		a = bas.DateValue(&apos;2021-02-18&apos;)

Dim vDate As Variant				&apos;	Return value
Const cstThisSub = &quot;Basic.DateValue&quot;
Const cstSubArgs = &quot;datearg&quot;

	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	vDate = &quot;&quot;

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	vDate = DateValue(DateArg)

Finally:
	If VarType(vDate) = V_DATE Then PyDateValue = CDateToUnoDateTime(vDate) Else PyDateValue = vDate
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper.PyDateValue

REM -----------------------------------------------------------------------------
Public Function PyFormat(ByVal Value As Variant _
							, ByVal Pattern As Variant _
							) As String
&apos;&apos;&apos;	Convenient function to replicate Format() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		Value: a date or a number
&apos;&apos;&apos;		Pattern: the format to apply
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The formatted value
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;	    MsgBox bas.Format(6328.2, &apos;##,##0.00&apos;)

Dim sFormat As String					&apos;	Return value
Dim vValue As Variant				&apos;	Alias of Value
Const cstThisSub = &quot;Basic.Format&quot;
Const cstSubArgs = &quot;value, pattern&quot;

	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	sFormat = &quot;&quot;

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	If VarType(Value) = V_OBJECT Then vValue = CDateFromUnoDateTime(Value) ELse vValue = Value
	If IsEmpty(Pattern) Or Len(Pattern) = 0 Then sFormat = Str(vValue) Else sFormat = Format(vValue, Pattern)


Finally:
	PyFormat = sFormat
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper.PyFormat

REM -----------------------------------------------------------------------------
Public Function PyGetGuiType() As Integer
&apos;&apos;&apos;	Convenient function to replicate GetGuiType() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The GetGuiType value
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;	    MsgBox bas.GetGuiType()

Const cstThisSub = &quot;Basic.GetGuiType&quot;
Const cstSubArgs = &quot;&quot;

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	PyGetGuiType = GetGuiType()


Finally:
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
End Function	&apos;	ScriptForge.SF_PythonHelper.PyGetGuiType

REM -----------------------------------------------------------------------------
Public Function PyGetSystemTicks() As Long
&apos;&apos;&apos;	Convenient function to replicate GetSystemTicks() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The GetSystemTicks value
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;	    MsgBox bas.GetSystemTicks()

Const cstThisSub = &quot;Basic.GetSystemTicks&quot;
Const cstSubArgs = &quot;&quot;

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	PyGetSystemTicks = GetSystemTicks()


Finally:
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
End Function	&apos;	ScriptForge.SF_PythonHelper.PyGetSystemTicks

REM -----------------------------------------------------------------------------
Public Function PyGlobalScope(ByVal Library As Variant) As Object
&apos;&apos;&apos;	Convenient function to replicate GlobalScope() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		Library: &quot;Basic&quot; or &quot;Dialog&quot;
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The GlobalScope value
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;	    bas.Xray(bas.GlobalScope.BasicLibraries())

Const cstThisSub = &quot;Basic.GlobalScope.BasicLibraries&quot;	&apos;	or DialogLibraries
Const cstSubArgs = &quot;&quot;

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	Select Case Library
		Case &quot;Basic&quot;
			PyGlobalScope = GlobalScope.BasicLibraries()
		Case &quot;Dialog&quot;
			PyGlobalScope = GlobalScope.DialogLibraries()
		Case Else
	End Select

Finally:
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
End Function	&apos;	ScriptForge.SF_PythonHelper.PyGlobalScope

REM -----------------------------------------------------------------------------
Public Function PyInputBox(ByVal Msg As Variant _
								, ByVal Title As Variant _
								, ByVal Default As Variant _
								, Optional ByVal XPosTwips As Variant _
								, Optional ByVal YPosTwips As Variant _
								) As String
&apos;&apos;&apos;	Convenient function to replicate InputBox() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		Msg: String expression displayed as the message in the dialog box
&apos;&apos;&apos;		Title: String expression displayed in the title bar of the dialog box
&apos;&apos;&apos;		Default: String expression displayed in the text box as default if no other input is given
&apos;&apos;&apos;		XPosTwips: Integer expression that specifies the horizontal position of the dialog
&apos;&apos;&apos;		YPosTwips: Integer expression that specifies the vertical position of the dialog
&apos;&apos;&apos;			If XPosTwips and YPosTwips are omitted, the dialog is centered on the screen
&apos;&apos;&apos;			The position is specified in twips.
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The entered value or &quot;&quot; if the user pressed the Cancel button
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;	    a = bas.InputBox (&apos;Please enter a phrase:&apos;, &apos;Dear User&apos;)

Dim sInput As String		&apos;	Return value
Const cstThisSub = &quot;Basic.InputBox&quot;
Const cstSubArgs = &quot;msg, [title=&apos;&apos;], [default=&apos;&apos;], [xpostwips], [ypostwips]&quot;

	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	sInput = &quot;&quot;

Check:
	If IsMissing(YPosTwips) Then YPosTwips = 1
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	If IsMissing(XPosTwips) Then
		sInput = InputBox(Msg, Title, Default)
	Else
		sInput = InputBox(Msg, Title, Default, XPosTwips, YPosTwips)
	End If

Finally:
	PyInputBox = sInput
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper.PyInputBox

REM -----------------------------------------------------------------------------
Public Function PyMsgBox(ByVal Text As Variant _
								, ByVal DialogType As Variant _
								, ByVal DialogTitle As Variant _
								) As Integer
&apos;&apos;&apos;	Convenient function to replicate MsgBox() in Python scripts
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		Text: String expression displayed as a message in the dialog box
&apos;&apos;&apos;		DialogType: Any integer expression that defines the number and type of buttons or icons displayed
&apos;&apos;&apos;		DialogTitle: String expression displayed in the title bar of the dialog
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The pressed button
&apos;&apos;&apos;	Example: (Python code)
&apos;&apos;&apos;	    a = bas.MsgBox (&apos;Please press a button:&apos;, bas.MB_EXCLAMATION, &apos;Dear User&apos;)

Dim iMsg As Integer		&apos;	Return value
Const cstThisSub = &quot;Basic.MsgBox&quot;
Const cstSubArgs = &quot;text, [dialogtype=0], [dialogtitle]&quot;

	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	iMsg = -1

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	iMsg = MsgBox(Text, DialogType, DialogTitle)

Finally:
	PyMsgBox = iMsg
	SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper.PyMsgBox

REM -----------------------------------------------------------------------------
Public Sub PyWait(ByVal Millisec As Variant)
&apos;&apos;&apos;	Convenient function to replicate Wait() in Python scripts
&apos;&apos;&apos;	This method is normally not necessary. But constructions like:
&apos;&apos;&apos;		import time
&apos;&apos;&apos;		while True:
&apos;&apos;&apos;			time.sleep(1)
&apos;&apos;&apos;	have the drawback to often freeze the LibreOffice user interface.
&apos;&apos;&apos;		basic = CreateScriptService(&apos;Basic&apos;)
&apos;&apos;&apos;		white True:
&apos;&apos;&apos;			basic.Wait(1000)
&apos;&apos;&apos;	might be a good alternative, although less precise due to the Python/Basic exchanges.
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		Millisec: the amount of time (in milliseconds) to wait before the program is continued

Const cstThisSub = &quot;Basic.Wait&quot;
Const cstSubArgs = &quot;millisec&quot;

	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch

Check:
	SF_Utils._EnterFunction(cstThisSub, cstSubArgs)

Try:
	Wait Millisec

Finally:
	SF_Utils._ExitFunction(cstThisSub)
	Exit Sub
Catch:
	GoTo Finally
End Sub	&apos;	ScriptForge.SF_PythonHelper.PyWait

REM ============================================================= PRIVATE METHODS

REM -----------------------------------------------------------------------------
Public Function _PythonDispatcher(ByRef BasicObject As Variant _
									, ByVal CallType As Variant _
									, ByVal Script As Variant _
									, ParamArray Args() As Variant _
								) As Variant
&apos;&apos;&apos;	Called from Python only
&apos;&apos;&apos;	The method calls the method Script associated with the BasicObject class or module
&apos;&apos;&apos;	with the given arguments
&apos;&apos;&apos;	The invocation of the method can be a Property Get, Property Let or a usual call
&apos;&apos;&apos;	NB: arguments and return values must not be 2D arrays
&apos;&apos;&apos;	The implementation intends to be as AGNOSTIC as possible in terms of objects nature and methods called
&apos;&apos;&apos;	The method returns the value effectively returned by the called component,
&apos;&apos;&apos;	completed with additional metadata. The whole is packaged in a 1D array.
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		BasicObject: a module or a class instance - May also be the reserved string: &quot;SF_Services&quot;
&apos;&apos;&apos;		CallType: one of the constants applicable to a CallByName statement + optional protocol flags
&apos;&apos;&apos;			When CallType is an array (applicable when CallType includes cstObject)
&apos;&apos;&apos;				CallType[0] = CallType scalar
&apos;&apos;&apos;				CallType[1] = argument index on which to apply the scalar value
&apos;&apos;&apos;		Script: the name of the method or property
&apos;&apos;&apos;		Args: the arguments to pass to the method. Input arguments can contain symbolic constants for Null, Missing, etc.
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		A 1D array:
&apos;&apos;&apos;			[0]		The returned value - scalar, object or 1D array
&apos;&apos;&apos;			[1]		The VarType() of the returned value
&apos;&apos;&apos;						Null, Empty and Nothing have different vartypes but return all None to Python
&apos;&apos;&apos;			Additionally, when array:
&apos;&apos;&apos;			[2]		Number of dimensions in Basic
&apos;&apos;&apos;			Additionally, when Basic object:
&apos;&apos;&apos;			[2]		Module (1), Class instance (2) or UNO (3)
&apos;&apos;&apos;			[3]		The object&apos;s ObjectType
&apos;&apos;&apos;			[4]		The object&apos;s service name
&apos;&apos;&apos;			[5]		The object&apos;s name
&apos;&apos;&apos;		When an error occurs Python receives None as a scalar. This determines the occurrence of a failure

Dim vReturn As Variant				&apos;	The value returned by the invoked property or method
Dim vReturnArray As Variant			&apos;	Return value
Dim iCallType As Integer			&apos;	Alias of CallType
Dim iArgIndex As Integer			&apos;	Index companion when CallType is an array
Dim vBasicObject As Variant			&apos;	Alias of BasicObject to avoid &quot;Object reference not set&quot; error
Dim iNbArgs As Integer				&apos;	Number of valid input arguments
Dim vArg As Variant					&apos;	Alias for a single argument
Dim vArgs() As Variant				&apos;	Alias for Args()
Dim sScript As String				&apos;	Argument of ExecuteBasicScript()
Dim vParams As Variant				&apos;	Array of arguments to pass to a ParamArray
Dim sObjectType As String			&apos;	Alias of object.ObjectType
Dim sServiceName As String			&apos;	Alias of BasicObject.ServiceName
Dim bBasicClass As Boolean			&apos;	True when BasicObject is a class
Dim sLibrary As String				&apos;	Library where the object belongs to
Dim bUno As Boolean					&apos;	Return value is a UNO object
Dim bDict As Boolean				&apos;	Return value is a Basic SF_Dictionary class instance
Dim oDict As Object					&apos;	SF_Dictionary class instance
Dim oObjDesc As Object				&apos;	_ObjectDescriptor type
Dim iDims As Integer				&apos;	# of dims of vReturn when array
Dim sess As Object					:	Set sess = ScriptForge.SF_Session
Dim i As Long, j As Long

&apos;	Conventional special input or output values
Const cstNoArgs = &quot;+++NOARGS+++&quot;, cstSymEmpty = &quot;+++EMPTY+++&quot;, cstSymNull = &quot;+++NULL+++&quot;, cstSymMissing = &quot;+++MISSING+++&quot;

&apos;	https://support.office.com/en-us/article/CallByName-fonction-49ce9475-c315-4f13-8d35-e98cfe98729a
&apos;	Determines the CallType
Const vbGet = 2, vbLet = 4, vbMethod = 1, vbSet = 8
&apos;	Protocol flags
Const cstPost = 16			&apos;	Requires a hardcoded post-processing
Const cstDictArg = 32		&apos;	May contain a Dictionary argument
Const cstDateArg = 64		&apos;	May contain a date argument
Const cstDateRet = 128		&apos;	Return value can be a date
Const cstUno = 256			&apos;	Return value can be a UNO object
Const cstArgArray = 512		&apos;	Any argument can be a 2D array
Const cstRetArray = 1024	&apos;	Return value can be an array
Const cstObject = 2048		&apos;	n-th argument is a Basic object when numeric
							&apos;	n (default = 0) can be passed as companion in an array
Const cstHardCode = 4096	&apos;	Method must not be executed with CallByName()
&apos;	Returned object nature
Const objMODULE = 1, objCLASS = 2, objDICT = 3, objUNO = 4

Check:
	If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	_PythonDispatcher = Null

	&apos;	Ignore Null basic objects (Null = Null or Nothing)
	If IsNull(BasicObject) Or IsEmpty(BasicObject) Then GoTo Catch

	&apos;	Intercept CallType when the targeted argument should be identified
	If IsArray(CallType) Then
		iCallType = CallType(0)
		iArgIndex = CallType(1)
	Else
		iCallType = CallType
		iArgIndex = 0
	End If

	&apos;	Reinterpret arguments one by one into vArgs
	&apos;	- convert UNO dates/times
	&apos;	- identify conventional NoArgs/Empty/Null/Missing constants
	&apos;	- convert arrays of property values into Dictionary
	iNbArgs = -1
	vArgs = Array()

	If UBound(Args) &gt;= 0 Then
		For i = 0 To UBound(Args)
			vArg = Args(i)
			&apos;	Are there arguments ?
			If i = 0 And VarType(vArg) = V_STRING Then
				If vArg = cstNoArgs Then Exit For
			End If
			&apos;	Is 1st argument a reference to a Basic object ?
			If i = iArgIndex And (( iCallType And cstObject ) = cstObject) And SF_Utils._VarTypeExt(vArg) = V_NUMERIC Then
				If vArg &lt; 0 Or Not IsArray(_SF_.PythonStorage) Then GoTo Catch
				If vArg &gt; UBound(_SF_.PythonStorage) Then GoTo Catch
				vArg = _SF_.PythonStorage(vArg)
			&apos;	Is argument a symbolic constant for Null, Empty, ... , or a date, or a dictionary ?
			ElseIf VarType(vArg) = V_STRING Then
				If Len(vArg) = 0 Then
				ElseIf vArg = cstSymEmpty Then
					vArg = Empty
				ElseIf vArg = cstSymNull Then
					vArg = Null
				ElseIf vArg = cstSymMissing Then
					Exit For	&apos;	Next arguments must be missing also
				End If
			ElseIf  VarType(vArg) = V_OBJECT Then
				If ( iCallType And cstDateArg ) = cstDateArg Then vArg = CDateFromUnoDateTime(vArg)
			ElseIf ( iCallType And cstDictArg ) = cstDictArg Then
				If IsArray(vArg) Then
					If UBound(vArg) &gt;= 0 Then
						If sess.UnoObjectType(vArg(0)) = &quot;com.sun.star.beans.PropertyValue&quot; Then
							&apos;	Create a dictionary - keys in Python dicts are case-sensitive
							Set oDict = CreateScriptService(&quot;ScriptForge.Dictionary&quot;, True)
							oDict.ImportFromPropertyValues(vArg, Overwrite := True)
							vArg = oDict
						End If
					End If
				End If
			End If
			iNbArgs = iNbArgs + 1

			ReDim Preserve vArgs(iNbArgs)
			vArgs(iNbArgs) = vArg
		Next i
	End If

Try:
	&apos;	Dispatching strategy: based on next constraints
	&apos;			(1) Bug https://bugs.documentfoundation.org/show_bug.cgi?id=138155
	&apos;				The CallByName function fails when returning an array
	&apos;			(2) Python has tuples and tuple of tuples, not 2D arrays
	&apos;			(3) Passing 2D arrays through a script provider always transform it into a sequence of sequences
	&apos;			(4) The CallByName function takes exclusive control on the targeted object up to its exit
	&apos;			(5) A script provider returns a Basic Date variable as Empty
	&apos; RULES:
	&apos;	1.	All methods in any module are invoked with CallByName
	&apos;	2.	Properties in any service are got and set with obj.GetProperty/SetProperty(...)
	&apos; EXCEPTIONS:
	&apos;	3.	Methods in usual modules are called by ExecuteBasicScript() when they manipulate arrays
	&apos;	4.	Methods in class modules using a 2D array or returning arrays, or methods using ParamArray,
&apos;&apos;&apos;			are hardcoded as exceptions or are not implemented
	&apos;	5.	Due to constraint (4), a predefined list of method calls must be hardcoded to avoid blocking use of CallByName
	&apos;		The concerned methods are flagged with cstHardCode

	With _SF_
		&apos;	Initialize Python persistent storage at 1st call
		If IsEmpty(.PythonStorage) Then ._InitPythonStorage()
		&apos;	Reset any error
		._Stackreset()
		&apos;	Set Python trigger to manage signatures in error messages
		.TriggeredByPython = True
	End With

	Select case VarType(BasicObject)
		Case V_STRING
			&apos;	Special entry for CreateScriptService()
			vBasicObject = BasicObject
			If vBasicObject = &quot;SF_Services&quot; Then
				If UBound(vArgs) = 0 Then vParams = Array() Else vParams = SF_Array.Slice(vArgs, 1)
				Select Case UBound(vParams)
					Case -1	:	vReturn = SF_Services.CreateScriptService(vArgs(0))
					Case 0	:	vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0))
					Case 1	:	vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1))
					Case 2	:	vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1), vParams(2))
					Case 3	:	vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1), vParams(2), vParams(3))
					Case 4	:	vReturn = SF_Services.CreateScriptService(vArgs(0), vParams(0), vParams(1), vParams(2), vParams(3), vParams(4))
				End Select
			End If
			If VarType(vReturn) = V_OBJECT And Not IsNull(vReturn) Then
				vBasicObject = vReturn
				sObjectType = vBasicObject.ObjectType
				bBasicClass = ( Left(sObjectType, 3) &lt;&gt; &quot;SF_&quot; )
			End If

		&apos;	Implement dispatching strategy
		Case V_INTEGER
			If BasicObject &lt; 0 Or Not IsArray(_SF_.PythonStorage) Then GoTo Catch
			If BasicObject &gt; UBound(_SF_.PythonStorage) Then GoTo Catch
			vBasicObject = _SF_.PythonStorage(BasicObject)
			sObjectType = vBasicObject.ObjectType
			sServiceName = vBasicObject.ServiceName

			&apos;	Basic modules have type = &quot;SF_*&quot;
			bBasicClass = ( Left(sObjectType, 3) &lt;&gt; &quot;SF_&quot; )
			sLibrary = Split(sServiceName, &quot;.&quot;)(0)

			&apos;	Methods in standard modules are called by ExecuteBasicScript() when arrays are returned
			If Not bBasicClass And (iCallType And vbMethod) = vbMethod And (iCallType And cstRetArray) = cstRetArray Then
				sScript = sLibrary &amp; &quot;.&quot; &amp; sObjectType &amp; &quot;.&quot; &amp; Script
				&apos;	Force validation in targeted function, not in ExecuteBasicScript()
				_SF_.StackLevel = -1
				Select Case UBound(vArgs)
					Case -1	:	vReturn = sess.ExecuteBasicScript(, sScript)
					Case 0	:	vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0))
					Case 1	:	vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1))
					Case 2	:	vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2))
					Case 3	:	vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3))
					Case 4	:	vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4))
					Case 5	:	vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5))
					Case 6	:	vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6))
					Case 7	:	vReturn = sess.ExecuteBasicScript(, sScript, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7))
				End Select
				_SF_.StackLevel = 0

			&apos;	Properties in any service are got and set with obj.GetProperty/SetProperty(...)
			ElseIf (iCallType And vbGet) = vbGet Then	&apos;	In some cases (Calc ...) GetProperty may have an argument
				If UBound(vArgs) &lt; 0 Then vReturn = vBasicObject.GetProperty(Script) Else vReturn = vBasicObject.GetProperty(Script, vArgs(0))
			ElseIf (iCallType And vbLet) = vbLet Then
				vReturn = vBasicObject.SetProperty(Script, vArgs(0))

			&apos;	Methods in class modules using a 2D array or returning arrays are hardcoded as exceptions. Bug #138155
			ElseIf ((iCallType And vbMethod) + (iCallType And cstArgArray)) = vbMethod + cstArgArray Or _
				   ((iCallType And vbMethod) + (iCallType And cstRetArray)) = vbMethod + cstRetArray Then
				If Script = &quot;Methods&quot; Then
					vReturn = vBasicObject.Methods()
				ElseIf Script = &quot;Properties&quot; Then
					vReturn = vBasicObject.Properties()
				Else
					Select Case sServiceName
						Case &quot;ScriptForge.SF_Session&quot;
							Select Case Script
								Case &quot;GetRangeFromCalc&quot;	:	vReturn = vBasicObject.GetRangeFromCalc(vArgs(0), vArgs(1))
							End Select
						Case &quot;SFDatabases.Database&quot;
							If Script = &quot;GetRows&quot; Then		vReturn = vBasicObject.GetRows(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
						Case &quot;SFDatabases.Dataset&quot;
							If Script = &quot;GetRows&quot; Then		vReturn = vBasicObject.GetRows(vArgs(0), vArgs(1))
						Case &quot;SFDialogs.Dialog&quot;
							If Script = &quot;Controls&quot; Then		vReturn = vBasicObject.Controls(vArgs(0))
						Case &quot;SFDialogs.DialogControl&quot;
							If Script = &quot;SetTableData&quot; Then	vReturn = vBasicObject.SetTableData(vArgs(0), vArgs(1), vArgs(2))
						Case &quot;SFDocuments.Document&quot;
							Select Case Script
								Case &quot;ContextMenus&quot;		:	vReturn = vBasicObject.ContextMenus(vArgs(0), vArgs(1))
								Case &quot;Forms&quot;			:	vReturn = vBasicObject.Forms(vArgs(0))
								Case &quot;Styles&quot;			:	vReturn = vBasicObject.Styles(vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5))
								Case &quot;Toolbars&quot;			:	vReturn = vBasicObject.Toolbars(vArgs(0))
							End Select
						Case &quot;SFDocuments.Base&quot;
							Select Case Script
								Case &quot;ContextMenus&quot;		:	vReturn = vBasicObject.ContextMenus(vArgs(0), vArgs(1))
								Case &quot;FormDocuments&quot;	:	vReturn = vBasicObject.FormDocuments()
								Case &quot;Forms&quot;			:	vReturn = vBasicObject.Forms(vArgs(0), vArgs(1))
								Case &quot;Toolbars&quot;			:	vReturn = vBasicObject.Toolbars(vArgs(0))
							End Select
						Case &quot;SFDocuments.Calc&quot;
							Select Case Script
								Case &quot;Charts&quot;			:	vReturn = vBasicObject.Charts(vArgs(0), vArgs(1))
								Case &quot;ContextMenus&quot;		:	vReturn = vBasicObject.ContextMenus(vArgs(0), vArgs(1))
								Case &quot;Forms&quot;			:	vReturn = vBasicObject.Forms(vArgs(0), vArgs(1))
								Case &quot;GetFormula&quot;		:	vReturn = vBasicObject.GetFormula(vArgs(0))
								Case &quot;GetValue&quot;			:	vReturn = vBasicObject.GetValue(vArgs(0))
								Case &quot;SetArray&quot;			:	vReturn = vBasicObject.SetArray(vArgs(0), vArgs(1))
								Case &quot;SetFormula&quot;		:	vReturn = vBasicObject.SetFormula(vArgs(0), vArgs(1))
								Case &quot;SetValue&quot;			:	vReturn = vBasicObject.SetValue(vArgs(0), vArgs(1))
								Case &quot;Shapes&quot;			:	vReturn = vBasicObject.Shapes(vArgs(0), vArgs(1))
								Case &quot;Styles&quot;			:	vReturn = vBasicObject.Styles(vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5))
								Case &quot;Toolbars&quot;			:	vReturn = vBasicObject.Toolbars(vArgs(0))
							End Select
						Case &quot;SFDocuments.Form&quot;
							Select Case Script
								Case &quot;Controls&quot;			:	vReturn = vBasicObject.Controls(vArgs(0))
								Case &quot;Subforms&quot;			:	vReturn = vBasicObject.Subforms(vArgs(0))
							End Select
						Case &quot;SFDocuments.FormControl&quot;
							If Script = &quot;Controls&quot; Then		vReturn = vBasicObject.Controls(vArgs(0))
						Case &quot;SFDocuments.FormDocument&quot;
							Select Case Script
								Case &quot;ContextMenus&quot;		:	vReturn = vBasicObject.ContextMenus(vArgs(0), vArgs(1))
								Case &quot;Forms&quot;			:	vReturn = vBasicObject.Forms(vArgs(0))
								Case &quot;Toolbars&quot;			:	vReturn = vBasicObject.Toolbars(vArgs(0))
							End Select
						Case &quot;SFDocuments.Writer&quot;
							Select Case Script
								Case &quot;ContextMenus&quot;		:	vReturn = vBasicObject.ContextMenus(vArgs(0), vArgs(1))
								Case &quot;Forms&quot;			:	vReturn = vBasicObject.Forms(vArgs(0))
								Case &quot;Styles&quot;			:	vReturn = vBasicObject.Styles(vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5))
								Case &quot;Toolbars&quot;			:	vReturn = vBasicObject.Toolbars(vArgs(0))
							End Select
						Case &quot;SFWidgets.Toolbar&quot;
							Select Case Script
								Case &quot;ToolbarButtons&quot;	:	vReturn = vBasicObject.ToolbarButtons(vArgs(0))
							End Select
					End Select
				End If

			&apos;	Specific methods in class modules may better not be executed with CallByName() because they do not return immediately
			ElseIf bBasicClass And ((iCallType And vbMethod) + (iCallType And cstHardCode)) = vbMethod + cstHardCode Then
				Select Case sServiceName
					Case &quot;SFDialogs.Dialog&quot;
						Select Case Script
							Case &quot;Execute&quot;			:	vReturn = vBasicObject.Execute(vArgs(0))
						End Select
				End Select

			&apos;	Methods in all modules are invoked with CallByName
			ElseIf ((iCallType And vbMethod) = vbMethod) Then
				Select Case UBound(vArgs)
					&apos;	Dirty alternatives to process usual and ParamArray cases
					&apos;	But, up to ... how many ?
					&apos;		- The OFFSETADDRESSERROR has 12 arguments
					&apos;		- The &quot;.uno:DataSort&quot; command may have 14 property name-value pairs
					Case -1	:	vReturn = CallByName(vBasicObject, Script, vbMethod)
					Case 0	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0))
					Case 1	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1))
					Case 2	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2))
					Case 3	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3))
					Case 4	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4))
					Case 5	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5))
					Case 6	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6))
					Case 7	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7))
					Case 8	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8))
					Case 9	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9))
					Case 10	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9), vArgs(10))
					Case 11	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9), vArgs(10), vArgs(11))
					Case 12, 13	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12))
					Case 14, 15	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14))
					Case 16, 17	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16))
					Case 18, 19	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18))
					Case 20, 21	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
											, vArgs(19), vArgs(20))
					Case 22, 23	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
											, vArgs(19), vArgs(20), vArgs(21), vArgs(22))
					Case 24, 25	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
											, vArgs(19), vArgs(20), vArgs(21), vArgs(22), vArgs(23), vArgs(24))
					Case 26, 27	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
											, vArgs(19), vArgs(20), vArgs(21), vArgs(22), vArgs(23), vArgs(24), vArgs(25), vArgs(26))
					Case &gt;= 28	:	vReturn = CallByName(vBasicObject, Script, vbMethod, vArgs(0), vArgs(1), vArgs(2), vArgs(3), vArgs(4), vArgs(5), vArgs(6), vArgs(7) _
											, vArgs(8), vArgs(9), vArgs(10), vArgs(11), vArgs(12), vArgs(13), vArgs(14), vArgs(15), vArgs(16), vArgs(17), vArgs(18) _
											, vArgs(19), vArgs(20), vArgs(21), vArgs(22), vArgs(23), vArgs(24), vArgs(25), vArgs(26), vArgs(27), vArgs(28))
				End Select
			End If

			&apos;	Post processing
			If (iCallType And cstPost) = cstPost Then
				If Script = &quot;Dispose&quot; Then
					&apos;	Special case: Dispose() must update the cache for class objects created in Python scripts
					Set _SF_.PythonStorage(BasicObject) = Nothing
				End If
			End If
		Case Else
	End Select
	
	&apos;	Format the returned array
	vReturnArray = Array()
	&apos;	Distinguish:	Basic object
	&apos;					UNO object
	&apos;					Dictionary
	&apos;					Array
	&apos;					Scalar
	If IsArray(vReturn) Then
		ReDim vReturnArray(0 To 2)
		iDims = SF_Array.CountDims(vReturn)
		&apos;	Replace dates by UNO format
		If iDims = 1 Then
			For i = LBound(vReturn) To UBound(vReturn)
				If VarType(vReturn(i)) = V_DATE Then vReturn(i) = CDateToUnoDateTime(vReturn(i))
			Next i
		ElseIf iDims = 2 Then
			For i = LBound(vReturn, 1) To UBound(vReturn, 1)
				For j = LBound(vReturn, 2) To UBound(vReturn, 2)
					If VarType(vReturn(i, j)) = V_DATE Then vReturn(i, j) = CDateToUnoDateTime(vReturn(i, j))
				Next j
			Next i
		End If
		vReturnArray(0) = vReturn		&apos;	2D arrays are flattened by the script provider when returning to Python
		vReturnArray(1) = VarType(vReturn)
		vReturnArray(2) = iDims
	ElseIf VarType(vReturn) = V_OBJECT And Not IsNull(vReturn) Then
		&apos;	Uno or not Uno ?
		bUno = False
		If (iCallType And cstUno) = cstUno Then		&apos;	UNO considered only when pre-announced in CallType
			Set oObjDesc = SF_Utils._VarTypeObj(vReturn)
			bUno = ( oObjDesc.iVarType = V_UNOOBJECT )
		End If
		If bUno Then
			ReDim vReturnArray(0 To 2)
			Set vReturnArray(0) = vReturn
		Else
			ReDim vReturnArray(0 To 5)
			bDict = ( vReturn.ObjectType = &quot;DICTIONARY&quot; )
			If bDict Then
				vReturnArray(0) = vReturn.ConvertToPropertyValues()
			Else
				vReturnArray(0) = _SF_._AddToPythonSTorage(vReturn)
			End If
		End If
		vReturnArray(1) = V_OBJECT
		Select Case True
			Case bUno			:	vReturnArray(2) = objUNO
			Case bDict			:	vReturnArray(2) = objDICT
			Case bBasicClass	:	vReturnArray(2) = objCLASS
			Case Else			:	vReturnArray(2) = objMODULE
		End Select
		If Not bUno Then
			vReturnArray(3) = vReturn.ObjectType
			vReturnArray(4) = vReturn.ServiceName
			vReturnArray(5) = &quot;&quot;
			If vReturn.ObjectType &lt;&gt; &quot;SF_CalcReference&quot; And Not bDict Then	&apos;	Calc references are implemented as a Type ... End Type data structure
				If SF_Array.Contains(vReturn.Properties(), &quot;Name&quot;, SortOrder := &quot;ASC&quot;) Then vReturnArray(5) = vReturn.Name
			End If
		End If
	Else	&apos;	Scalar or Nothing
		ReDim vReturnArray(0 To 1)
		If VarType(vReturn) = V_DATE Then vReturnArray(0) = CDateToUnoDateTime(vReturn) Else vReturnArray(0) = vReturn
		vReturnArray(1) = VarType(vReturn)
	End If

	&apos;	Tests with non-modal dialogs and sleeping (time.sleep) Python processes show
	&apos;	a more fluid reactivity when next statement is present, at a minimal cost.
	Wait 0

	_PythonDispatcher = vReturnArray
		
Finally:
	_SF_.TriggeredByPython = False		&apos;	Reset normal state
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	ScriptForge.SF_PythonHelper._PythonDispatcher

REM ================================================= END OF SCRIPTFORGE.SF_PythonHelper
</script:module>