I get it, there is more than one way to do the same thing in with the LO API. One of the dilemma’s I have had is in trying to employ various VBNET examples I’ve found here and elsewhere which purport to use the Libre Office API, but which do not result in identical/equivalently instantiated (Writer) variables for the same object (e.g., the document) and which do not allow the same methods to be used on them and also which do not allow communication with one another. The code below demonstrates all these dilemmas. Simply put, it seems that ‘one way’ of doing something is completely independent of the other(s?) and which does not allow interaction with any other(s?). Notably, I have not installed Open Office nor its SDK on my new development computer, IOWs I never installed anything but LO on it, but I am left to wonder if OO isn’t somehow still available in the LO SDK/API…?
In all this, I have examined the LO Object model, other LO documentation, the Pitonyak document on LO/OO Macros in LO Basic, numerous LO Basic examples and other language examples which I’ve converted (used online converters) to VBNet and through all of it I have found no ‘primer’ to help direct my programming efforts to find a single (or even multiple) protocols (i.e., proper syntax, ‘Typing’ methods) for employing ~all~ of the LO API functionality.
The below code is a .Net Framwork (4.8) VBNet, single file, project. It runs, but demonstrates how some methods for creating a VBNet project run successfully and others do not. In the code my comments include questions about this.
This is a big ask, there are a lot of embedded questions, but can someone please look at the VBNet code below and then help me with these 4 primary questions:
- Is the Open Office API being employed for either or both of the examples? How can I look at an example (in any language) and know if its using the Libre Office API or the Open Office API. I know that LO came out of OO and the two must be somewhat similar/inter-changeable, but its unclear where the demarcation line between the two lies.
- Does LO API require employing OO constructs, variables and/or methods. How can I know when to use any of these objects?
- Why does the code underlying the 3rd button fail?
- Why does the code underlying the 4th button fail?
To test/use this code, create a VBNet solution (.Net Framework 4.8) with one form in it. Add 4 buttons (named 1 through 4) and a textbox. Then attach the appropriate code below to the buttons and the textbox. Attached is a picture of the form I created in the solution I created in Visual Studio…The text added to the buttons and elsewhere on the form is instructive. You’ll also need to have a LO Writer Document with the text ‘FindMe’ shown in several locations. Finally, you need to also add an OpenFileDialog to the form. It is used when you double click in the text box.
Option Explicit Off
Option Strict Off
'I’m Sure Not All These Imports are Required, but… Where Can I find which are needed to do what in LO Documentation?
Imports System
Imports System.IO
Imports System.Collections
Imports Microsoft.VisualBasic
'Imports uno
'Imports unoidl
Imports uno.util
Imports unoidl.com.sun.star
Imports unoidl.com.sun.star.text
Imports unoidl.com.sun.star.lang
Imports unoidl.com.sun.star.uno
Imports unoidl.com.sun.star.bridge
Imports unoidl.com.sun.star.frame
Imports unoidl.com.sun.star.view
Imports unoidl.com.sun.star.beans
Imports unoidl.com.sun.star.container
Imports unoidl.com.sun.star.util
Imports unoidl.com.sun.star.packages.zip
Imports unoidl.com.sun.star.sdb.tools
Imports unoidl.com.sun.star.sdbcx
Imports unoidl.com.sun.star.sdbc
Imports unoidl.com.sun.star.awt
Imports unoidl.com.sun.star.graphic
Imports unoidl.com.sun.star.drawing
Imports unoidl.com.sun.star.script.provider
Public Class Form1
Public loDocXComponentContext As XComponentContext = Nothing
Public loXMultiServiceFactory As XMultiServiceFactory = Nothing
Public loXMultiComponentFactory As XMultiComponentFactory = Nothing
Public loDocXComponentLoader As unoidl.com.sun.star.frame.XComponentLoader = Nothing
Public loXDocDesktop As unoidl.com.sun.star.frame.XDesktop = Nothing
Public loDocArProps() As unoidl.com.sun.star.beans.PropertyValue = Nothing
Public loDocXComponent As unoidl.com.sun.star.lang.XComponent
Public loDocXTextDocument As unoidl.com.sun.star.text.XTextDocument = Nothing
Public loDocXText As unoidl.com.sun.star.text.XText = Nothing
Public loDocXTextRange As unoidl.com.sun.star.text.XTextRange = Nothing
Public loDocXTextCursor As unoidl.com.sun.star.text.XTextCursor = Nothing
Public loDocXGraphicProvider As unoidl.com.sun.star.graphic.XGraphicProvider = Nothing
Public loDocXServiceManager As Object
Public loDocXSimpleText As unoidl.com.sun.star.text.XSimpleText = Nothing
Public loXDispatchHelper As XDispatchHelper
Public loXDispatchProvider As unoidl.com.sun.star.frame.XDispatchProvider = Nothing
Public loDocFrame As unoidl.com.sun.star.frame.Frame = Nothing
Public loDocXFrame As unoidl.com.sun.star.frame.XFrame = Nothing
Public loDocXViewCursor As unoidl.com.sun.star.view.XViewCursor = Nothing
Public loDocXFrameCursor As unoidl.com.sun.star.text.XTextCursor = Nothing
Public loDocXTextTable As unoidl.com.sun.star.text.XTextTable = Nothing
Public loDocXTextFrame As unoidl.com.sun.star.text.XTextFrame = Nothing
Public loDocXTextContent As unoidl.com.sun.star.text.XTextContent = Nothing
Public loDocXTableRows As unoidl.com.sun.star.table.XTableRows = Nothing
Public loDocXDrawPage As unoidl.com.sun.star.drawing.XDrawPage = Nothing
Public loDocGraphic As unoidl.com.sun.star.graphic.GraphicObject = Nothing
Public loDocXGraphic As unoidl.com.sun.star.graphic.XGraphic = Nothing
Public oShapes As unoidl.com.sun.star.drawing.ShapeCollection = Nothing
Public loDocXShapes As unoidl.com.sun.star.drawing.XShapes = Nothing
Public loDocXShape As unoidl.com.sun.star.drawing.XShape = Nothing
Public loShapeCollection As unoidl.com.sun.star.drawing.ShapeCollection = Nothing
Public loLine As unoidl.com.sun.star.drawing.ShapeCollection = Nothing
Private strFilePath As String = ""
Private Sub btnDilemma01_Click(sender As Object, e As EventArgs) Handles btnDilemma01.Click
Try
ClearAllVariablesToStartOver()
'THIS SUB OPENS A WRITER DOCUMENT USING METHODOLOGIES FOUND IN THE LIBREOFFICE 'WRITERDEMO' WRITTEN IN VB.NET
getExistingWriterFile(strFilePath)
Catch ex As System.Exception
End Try
End Sub
Private Sub btnDilemma02_Click(sender As Object, e As EventArgs) Handles btnDilemma02.Click
Try
ClearAllVariablesToStartOver()
'THIS SUB OPENS THE SAME FILE IN A ~DIFFERENT WAY~ THAN IN THE WRITER DEMO
'IT THEN PERFORMS A ~SUCCESSFUL~ SEARCH AND REPLACE
'See Additional Comments Have Ahead of this Sub
Search_Replace_All(strFilePath, "FindMe", "ReplaceWithMe")
Catch ex As System.Exception
End Try
End Sub
Private Sub btnDilemma03_Click(sender As Object, e As EventArgs) Handles btnDilemma03.Click
Try
ClearAllVariablesToStartOver()
'IF THE SEARCH AND REPLACE SUB IS RE-WRITTEN TO USE THE WRITER DOCUMENT VARIABLES INSTANTIATED AS IN THE 'WRITER DEMO'
'AND THEN PASSED TO A ~MODIFIED/GENERALIZED~ (Overloaded) VERSION OF THE SEARCH AND REPLACE SUB, THE CODE FAILS.
'EVEN THOUGH THE 'DESKTOP' VARIABLE SEEMS TO BE POINTING TO THE SAME DOCUMENT???
getExistingWriterFile(strFilePath)
Search_Replace_All(loDocXTextDocument, "FindMe", "ReplaceWithMe")
Catch ex As System.Exception
End Try
End Sub
Private Sub btnDilemma04_Click(sender As Object, e As EventArgs) Handles btnDilemma04.Click
Try
ClearAllVariablesToStartOver()
'IF ANOTHER DOWNLOADED SEARCH FUNCTION IS USED, IT SEEMS TO WANT TO WORK
'THIS ONE TRIES TO USE 'EXECUTEDISPATCH' BUT FAILS BECAUSE THE VARIABLE
'XDispatchProvider IS NOT PROPERLY INSTANTIATED. I'VE TRIED MULTIPLE METHODS
'TO CAPTURE/INSTANTIATE IT BUT NONE SEEM TO WORK, HELP!
getExistingWriterFile(strFilePath)
SearchDocumentForText("FindMe")
Catch ex As System.Exception
MsgBox("Why Does this Fail?")
End Try
End Sub
Private Sub tbxPathToLODocument_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles tbxPathToLODocument.MouseDoubleClick
ofdGetLODocumentPath.ShowDialog()
strFilePath = ofdGetLODocumentPath.FileName
tbxPathToLODocument.Text = strFilePath
End Sub
'THE FOLLOWING WORKS TO OPEN AN LO WRITER DOCUMENT USING THE APPROACH SHOWN IN THE 'WRITERDEMO' WRITTEN FOR VBNET FOUND IN THE (SINGLE) VBNET EXAMPLE AMONG THE LISTING OF EXAMPLES ON THE LO API WEBSITE
'SOME OBJECTS ARE INSTANTIATED TO NOTHING? SPECIFICALLY THE loXDispatchProvider to not err but is instantiated to 'Nothing'
'*****THIS PREVENTS ME FROM USING THE 'EXECUTEDISPATCH' FUNCTION IN THE FUNCTION - 'SearchDocumentForText'
'WHICH IS THE LAST FUNCTION IN THIS FILE.
Public Function getExistingWriterFile(ByRef strPathToExistingDocFile As String) As String
Try
If strPathToExistingDocFile = "" Then
MsgBox("You forgot to select the LO Document. Exiting.")
Return "NG"
End If
'THE FOLLOWING HAVE PROVEN TO LOAD ~AND WORK~ SUCCESSFULLY IT GETTING AND USING AN EXISTING WRITER DOCUMENT
Dim strFunctionResponse As String = "OK"
loDocXComponentContext = Bootstrap.bootstrap()
loXMultiServiceFactory = DirectCast(loDocXComponentContext.getServiceManager(), XMultiServiceFactory)
loXMultiComponentFactory = DirectCast(loDocXComponentContext.getServiceManager(), XMultiComponentFactory)
loXDocDesktop = loXMultiServiceFactory.createInstance("com.sun.star.frame.Desktop")
loDocXComponentLoader = DirectCast(loXDocDesktop, unoidl.com.sun.star.frame.XComponentLoader)
loDocArProps = {} 'This Global Variable is Declared Thusly: Public loDocArProps() As unoidl.com.sun.star.beans.PropertyValue = Nothing
loDocXComponent = loDocXComponentLoader.loadComponentFromURL(GetAbsoluteURI(strPathToExistingDocFile), "_blank", 0, loDocArProps)
loDocXTextDocument = DirectCast(loDocXComponent, unoidl.com.sun.star.text.XTextDocument)
loDocXText = loDocXTextDocument.getText
loDocXTextRange = loDocXTextDocument.getText
loDocXGraphicProvider = CType(loXMultiComponentFactory.createInstanceWithContext("com.sun.star.graphic.GraphicProvider", loDocXComponentContext), XGraphicProvider)
loDocXTextCursor = loDocXText.createTextCursor()
loXDispatchHelper = CType(loXMultiComponentFactory.createInstanceWithContext("com.sun.star.frame.DispatchHelper", loDocXComponentContext), unoidl.com.sun.star.frame.XDispatchHelper)
loXDispatchProvider = CType(loXMultiComponentFactory.createInstanceWithContext("unoidl.com.sun.star.frame.XDispatchProvider", loDocXComponentContext), unoidl.com.sun.star.frame.XDispatchProvider)
''Doesn't work: loDocXTextContent = DirectCast(loXDocDesktop, unoidl.com.sun.star.text.XTextContent)
'loXDispatchProvider = DirectCast(loXMultiComponentFactory.createInstanceWithContext("unoidl.com.sun.star.frame.XDispatchProvider", loDocXComponentContext), XDispatchProvider)
'loXDispatchProvider = DirectCast(loDocXComponentContext.getServiceManager(), unoidl.com.sun.star.frame.XDispatchProvider)
'loXDispatchProvider = loXMultiComponentFactory.createInstance("com.sun.star.frame.XDispatchProvider")
'loXDispatchProvider = loXMultiComponentFactory.createInstance("com.sun.star.frame.XDispatchProvider")
Return strFunctionResponse
Catch ex As System.Exception
Return "NG"
Finally
End Try
End Function
'THE FOLLOWING ALSO WORKS! BUT THE METHODS 'CREATESEARCHDESCRIPTOR' 'SETSEARCHSTRING' 'SETREPLACESTRING' 'REPLACEALL' ARE ALL ~NOT~ EXPOSED THROUGH
'VISUAL STUDIO 'DOT' EXTENSION SEARCHES. THEY ARE DOT EXTENSIONS TO AN OBJECT VARIABLE SO NO ERROR IS DECLARED.
'BUT OBVIOUSLY THEY...(AND OTHERS?) ASSOCIATED WITH AN LO/OO OBJECT MUST BE AVAILABLE BECAUSE THIS WORKS.
'THIS SUB WAS DOWNLOADED FROM SOMEWHERE I'VE FORGOTTEN (SORRY)
'IT ~SEEMS~ TO BE WRITTEN TO THE OO API/SDK...NOT THE LO API, BUT RUNS ON MY COMPUTER WHERE OO IS NOT INSTALLED??
'THIS SUB LOADS A SEPERATE INSTANCE OF LO/OO AND OPENS THE SAME DOCUMENT
Public Sub Search_Replace_All(ByRef strDocumentPath As String, ByRef strToSearchFor As String, ByRef strToReplaceWith As String)
Dim oSM 'Root object for accessing OpenOffice from VB
Dim oDesk, oDoc As Object 'First objects from the API
Dim arg() = {} 'Ignore it for the moment
'Instantiate OOo : this line is mandatory with VB for OOo API
oSM = CreateObject("com.sun.star.ServiceManager")
'Create the first and most important service
oDesk = oSM.createInstance("com.sun.star.frame.Desktop")
'Create a new doc
oDoc = oDesk.loadComponentFromURL(GetAbsoluteURI(strDocumentPath), "_blank", 0, arg)
Dim objText As Object, objCursor As Object
objText = oDoc.GetText
objCursor = objText.createTextCursor
' replace all
Dim oSrch As Object
oSrch = oDoc.createReplaceDescriptor
oSrch.setSearchString(strToSearchFor)
oSrch.setReplaceString(strToReplaceWith)
oDoc.replaceAll(oSrch)
End Sub
'THE FOLLOWING DOES NOT WORK AND I DO NOT UNDERSTAND WHY. COMPARE THIS SUB TO THE SUB JUST BEFORE IT.
'THE FOLLOWING ONE FAILS AT THE LINE 'objCursor = objText.createTextCursor'
Public Sub Search_Replace_All(ByRef theDocument As unoidl.com.sun.star.text.XTextDocument,
ByRef strTextToFind As String,
ByRef strTextToReplaceWith As String)
'DOWNLOADED AS A VB.NET (WORKABLE?) FUNCTION
'Dim oSM 'Root object for accessing OpenOffice from VB
'Dim oDesk, oDoc As Object 'First objects from the API
'Dim arg() = {} 'Ignore it for the moment
''Instanciate OOo : this line is mandatory with VB for OOo API
'oSM = CreateObject("com.sun.star.ServiceManager")
''Create the first and most important service
'oDesk = oSM.createInstance("com.sun.star.frame.Desktop")
''Create a new doc
'oDoc = oDesk.loadComponentFromURL(GetAbsoluteURI(strDocumentPath), "_blank", 0, arg)
Dim objText As Object, objCursor As Object
objText = theDocument.getText
objCursor = objText.createTextCursor
' replace all
Dim oSrch As Object
oSrch = CType(theDocument, Object).createSearchDescriptor
oSrch = CType(theDocument, Object).createReplaceDescriptor
oSrch.setSearchString(strTextToFind)
oSrch.setReplaceString(strTextToReplaceWith)
CType(theDocument, Object).replaceAll(oSrch)
End Sub
Public Function GetAbsoluteURI(ByRef strFileSpec As String) As String
Dim newURI As Uri
Dim ConvertedURI As String = ""
Try
newURI = New System.Uri(strFileSpec)
ConvertedURI = newURI.AbsoluteUri
Return ConvertedURI
Catch ex As system.Exception
Return MsgBox("Did you forget to select a valid LO Writer Document?")
End Try
End Function
Private Sub ClearAllVariablesToStartOver()
loDocXComponentContext = Nothing
loXMultiServiceFactory = Nothing
loXMultiComponentFactory = Nothing
loDocXComponentLoader = Nothing
loXDocDesktop = Nothing
loDocArProps = {}
loDocXComponent = Nothing
loDocXTextDocument = Nothing
loDocXText = Nothing
loDocXTextRange = Nothing
loDocXTextCursor = Nothing
loDocXGraphicProvider = Nothing
loDocXServiceManager = Nothing
loDocXSimpleText = Nothing
loXDispatchHelper = Nothing
loXDispatchProvider = Nothing
loDocFrame = Nothing
loDocXFrame = Nothing
loDocXViewCursor = Nothing
loDocXFrameCursor = Nothing
loDocXTextTable = Nothing
loDocXTextFrame = Nothing
loDocXTextContent = Nothing
loDocXTableRows = Nothing
loDocXDrawPage = Nothing
loDocGraphic = Nothing
loDocXGraphic = Nothing
oShapes = Nothing
loDocXShapes = Nothing
loDocXShape = Nothing
loShapeCollection = Nothing
loLine = Nothing
End Sub
'THE FOLLOWING IS ANOTHER FUNCTION I'VE DOWNLOADED BUT CANNOT MAKE WORK BECAUSE I'M UNABLE TO PROPERLY INSTANTIATE THE
''loXDispatchProvider' VARIABLE. IN THE 'getExistingWriterFile' FUNCTION, 'loXDispatchProvider' IS INSTANTIATED TO 'NOTHING'
Public Sub SearchDocumentForText(ByRef strSearchText As String)
Dim localProps(21) As unoidl.com.sun.star.beans.PropertyValue
Try
'ARE ALL THESE PROPERTIES NECESSARY EACH TIME A SEARCH IS PERFORMED?
localProps(0) = CreateProp("SearchItem.StyleFamily", New uno.Any(2))
localProps(1) = CreateProp("SearchItem.CellType", New uno.Any(1))
localProps(2) = CreateProp("SearchItem.RowDirection", New uno.Any(True))
localProps(3) = CreateProp("SearchItem.AllTables", New uno.Any(False))
localProps(4) = CreateProp("SearchItem.SearchFiltered", New uno.Any(False))
localProps(5) = CreateProp("SearchItem.Backward", New uno.Any(False))
localProps(6) = CreateProp("SearchItem.Pattern", New uno.Any(False))
localProps(7) = CreateProp("SearchItem.Content", New uno.Any(False))
localProps(8) = CreateProp("SearchItem.AsianOptions", New uno.Any(False))
localProps(9) = CreateProp("SearchItem.AlgorithmType", New uno.Any(0))
localProps(10) = CreateProp("SearchItem.SearchFlags", New uno.Any(0))
localProps(11) = CreateProp("SearchItem.SearchItem.SearchString", New uno.Any(strSearchText))
localProps(12) = CreateProp("SearchItem.ReplaceString", New uno.Any(""))
localProps(13) = CreateProp("SearchItem.Locale", New uno.Any(255))
localProps(14) = CreateProp("SearchItem.ChangedChars", New uno.Any(2))
localProps(15) = CreateProp("SearchItem.DeletedChars", New uno.Any(2))
localProps(16) = CreateProp("SearchItem.InsertedChars", New uno.Any(2))
localProps(17) = CreateProp("SearchItem.TransliterateFlags", New uno.Any(256))
localProps(18) = CreateProp("SearchItem.Command", New uno.Any(0))
localProps(19) = CreateProp("SearchItem.SearchFormatted", New uno.Any(False))
localProps(20) = CreateProp("SearchItem.AlgorithmType2", New uno.Any(1))
localProps(21) = CreateProp("SearchItem.Quiet", New uno.Any(True))
'THE FOLLOWING DOES DO ANYTHING BECAUSE THE VARIABLE 'loXDispatchProvider'
'ISN'T PROPERLY FILLED IN THE CALLING FUNCTION. AS WRITTEN, IT IS FILLED WITH 'Nothing'
'IT ISN'T OBVIOUS HOW TO FILL IT PROPERLY, PLEASE HELP!
'AND... IF IT WERE TO BE FILLED PROPERLY, THE LINE OF CODE SEEMS TO WANT TO
'1) PROVIDE A CURSOR TO THE FOUND LOCATION (THE TYPE GENERATED IS AN 'ANY' WHICH CANNOT BE CAST TO A CURSOR....
'or
'2) MOVE 'a' CURSOR THE THE FOUND LOCATION
'IS EITHER TRUE?
loXDispatchHelper.executeDispatch(loXDispatchProvider, "ExecuteSearch", "", 0, loDocArProps)
Catch ex As System.Exception
End Try
End Sub
Public Function CreateProp(ByRef name As String, ByRef value As uno.Any) As unoidl.com.sun.star.beans.PropertyValue
Dim prop As New unoidl.com.sun.star.beans.PropertyValue
Try
prop.Name = name
prop.Value = value 'CType(value, Object)
Return prop
Catch ex As System.Exception
Return Nothing
End Try
End Function
End Class