I have written an example that does some of the more obvious things that one might want to perform with word. Use things one by one, don't try to set all ifs to 1 at once. I know the code is not fancy, but nevertheless I do think that it might help others to get familiar with this complicated topic.
I also suggest that every newbee to COM ingests this (it helped me a lot to understand the fundamental principles, yet it is short enough to really get through it):
Code: Select all
EnableExplicit
XIncludeFile "MSWORD.pbi"
;Constants: \vt=#VT_I4 with \iVal=...
;Boolean: \vt=#VT_BOOL with \bool=...
;BSTR: \vt=#VT_BSTR with \bstrVal=... [SysAllocString_(@"...") and SysFreeString_(...)]
;Variant-Helper from COMate: https://www.purebasic.fr/english/viewtopic.php?t=40150
;{ ;more explanations about the VARIANT types
; Define.VARIANT var
; Define.IDispatch obj
;
; ;String
; var\vt = #VT_BSTR
; var\bstrVal = SysAllocString_("foo")
;
; ;Free string when done
; SysFreeString_(var\bstrVal)
;
; ;Enum constant
; var\vt = #VT_I4
; var\lVal = 10
;
; ;Boolean
; var\vt = #VT_BOOL
; var\boolVal = #VARIANT_TRUE ;#VARINT_FALSE
;
; ;Object
; var\vt = #VT_DISPATCH
; var\pdispVal = obj
;
; ;Empty optional parameter
; var\vt = #VT_ERROR
; var\scode = #DISP_E_PARAMNOTFOUND
;
; ;Variants that are defined as .i in the PB Interface are passed by address (by reference),
; ;if defined As .p-variant are passed directly (by value)
;
; ;Values that are not variants are passed directly as defined in the PB Interface method.
;
; ---------
;
; For variant string better ...
;
; ;String
; Define var.VARIANT
;
; var\vt = #VT_BSTR
; var\bstrVal = SysAllocString_("foo")
;
; VariantClear_(var)
;}
Procedure action()
Protected._Application app
Protected._Document doc
Protected documents.Documents
Protected selection.Selection
Protected.Range contentrange,range
Protected.VARIANT fn,none,dontsave,visible,what,which,count,name,dim par(30)
Protected.l hr
Protected.s file
Protected table.Table
protected a.l,a1.l,a2.l,b.l,*b,characters.Characters,find.Find,bookmarks.Bookmarks,dim bookmark.Bookmark(10)
none\vt = #VT_ERROR
none\scode = #DISP_E_PARAMNOTFOUND
visible\vt=#VT_BOOL
visible\bool=#True
OleInitialize_(0)
if 0
;{ ;creates a new document inside a Word instance that is already running (CAVE: You must make sure beforehands that it exists, otherwise an invisible instance will be created that can only be terminated via the task manager!)
If CoCreateInstance_(?CLSID_Document, 0, #CLSCTX_LOCAL_SERVER, ?IID__Document, @doc) <> #S_OK ;create new document
MessageRequester("Error:", "Couldn't create document")
End
EndIf
if doc
;doc\Activate()
doc\get_Application(@app)
;app\Activate()
;app\put_WindowState(#wdWindowStateNormal)
;app\ShowMe()
app\get_Documents(@documents)
else
MessageRequester("Error:", "Couldn't create document")
End
endif
;}
endif
if 1
;{ ;start Word
If CoCreateInstance_(?CLSID_Application, 0, #CLSCTX_LOCAL_SERVER, ?IID__Application, @app) <> #S_OK ;Word öffnen
MessageRequester("Warning:","Couldn't init oWord",0)
End
EndIf
app\Activate()
app\put_WindowState(#wdWindowStateNormal) ;enumeration: https://learn.microsoft.com/en-us/office/vba/api/word.wdwindowstate
;app\put_Width(400)
;app\put_Height(300)
;app\put_Left(10)
;app\put_Top(10)
app\put_Caption("Word from PureBasic")
app\put_Visible(#True)
;}
endif
if 1
;{ ;create a new document in the freshly started Word instance that was created right above
if app\get_Documents(@documents)<>#S_OK
MessageRequester("Error:","Couldn't get documents")
app\Quit(@dontsave,@none,@none)
app\Release()
end
endif
If documents\Add(@none,@none,@none,@visible,@doc) = #S_OK
app\get_Selection(@selection)
selection\InsertAfter("This is"+chr(9)+"a test."+chr(13))
;Use selection\put_Text("Text") to overwrite the selection directly instead of inserting after it if desired.
selection\InsertAfter("This is;a test."+chr(13))
selection\EndKey(@none,@none,@a)
selection\Release()
else
MessageRequester("Error:","Couldn't create document")
documents\Release()
app\Quit(@dontsave,@none,@none)
app\Release()
end
EndIf
;}
endif
;{ ;do something with the document
doc\get_Content(@contentrange)
If contentrange
contentrange\InsertAfter("Hello World!")
app\get_Selection(@selection)
;selection\HomeKey(@none,@none,@a) ;put cursor at the beginning of the current line
;selection\EndKey(@none,@none,@a) ;put cursor at the end of the current line
if 0
;{ ;create table
;select whole document:
doc\get_Characters(@characters)
characters\get_Count(@a)
characters\Release()
selection\SetRange(0,a) ;select whole document (a-1 would be without the end sign that is visible as a selected space at the very end)
selection\get_Range(@range)
;create table from selected text
par(1)\vt=#VT_I4 ;Separator: Specifies the character used to separate text into cells. Can be a character or one of the WdTableFieldSeparator (=wdSeparateBy...) constant. If this argument is omitted, the value of the DefaultTableSeparator property is used.
par(1)\iVal=#wdSeparateByCommas ;Commas=";"!!! ;rows are governed via chr(13) - here only the division into cells is affected
;enumeration: https://learn.microsoft.com/en-us/office/vba/api/word.wdtablefieldseparator
par(2)\vt=#VT_I4 ;num of rows (none=depends on selected contentrange)
par(2)\iVal=5 ;doesn't seem to have any influence
par(3)\vt=#VT_I4 ;num of columns (@none statt @par(3)=depends on selected contentrange)
par(3)\iVal=5
par(5)\vt=#VT_I4 ;table format template (one of the #wdTableFormat constants)
par(5)\iVal=#wdTableFormatGrid1 ;enumeration: https://learn.microsoft.com/en-us/office/vba/api/word.wdtableformat
par(14)\vt=#VT_BOOL ;AutoFit: True to decrease the width of the table columns as much as possible without changing the way text wraps in the cells.
par(14)\bool=#True ;doesn't seem to have any influence; to switch on and of see par(16)
par(15)\vt=#VT_I4 ;AutoFitBehavior: Sets the AutoFit rules for how Word sizes a table. Can be one of the WdAutoFitBehavior (=wdAutoFit...) constant. If DefaultTableBehavior is wdWord8TableBehavior, this argument is ignored.
par(15)\iVal=#wdAutoFitContent ;enumeration: https://learn.microsoft.com/en-us/office/vba/api/word.wdautofitbehavior
par(16)\vt=#VT_I4 ;DefaultTableBehavior: Sets a value that specifies whether Microsoft Word automatically resizes cells in a table to fit the contentranges (AutoFit). Can be one of the WdDefaultTableBehavior constant.
par(16)\iVal=#wdWord9TableBehavior ;AutoFit=on (only other constant available: wdWord8TableBehavior=AutoFit off)
if range\ConvertToTable(@par(1),@par(2),@par(3),@none,@par(5),@none,@none,@none,@none,@none,@none,@none,@none,@par(14),@par(15),@par(16),@table)<>0 ;help: use "range converttotable" as Google search term
MessageRequester("","Tabellenerzeugung fehlgeschlagen")
endif
if table
table\Release()
endif
range\Release()
;}
endif
if 0
;{ ;find text and mark or replace it
selection\SetRange(0,0)
selection\get_Find(@find) ;https://learn.microsoft.com/en-us/office/vba/api/word.find.execute
find\put_Text("test")
par(1)\vt=#VT_BSTR ;FindText
par(1)\bstrVal=SysAllocString_(@"test")
par(2)\vt=#VT_BOOL ;MatchCase
par(2)\bool=#False
par(3)\vt=#VT_BOOL ;MatchWholeWord
par(3)\bool=#False
par(4)\vt=#VT_BOOL ;MatchWildcards
par(4)\bool=#False
par(5)\vt=#VT_BOOL ;MatchSoundsLike
par(5)\bool=#False
par(6)\vt=#VT_BOOL ;MatchAllWordForms
par(6)\bool=#False
par(7)\vt=#VT_BOOL ;Forward
par(7)\bool=#True
par(8)\vt=#VT_I4 ;Wrap
par(8)\iVal=#wdFindStop
par(9)\vt=#VT_BOOL ;Format
par(9)\bool=#False
find\ClearFormatting()
;find:
;find\Execute(@par(1),@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@a) ;returns 65535 in a if text is found, 0 otherwise (simple variant)
find\Execute(@par(1),@par(2),@par(3),@par(4),@par(5),@par(6),@par(7),@par(8),@par(9),@none,@none,@none,@none,@none,@none,@a) ;returns 65535 in a if text is found, 0 otherwise (with additional parameters)
;replace:
;par(10)\vt=#VT_BSTR ;ReplaceWith
;par(10)\bstrVal=SysAllocString_(@"GLATZE")
;par(11)\vt=#VT_I4 ;Replace
;par(11)\iVal=#wdReplaceAll
;find\Execute(@par(1),@par(2),@par(3),@par(4),@par(5),@par(6),@par(7),@par(8),@par(9),@par(10),@par(11),@none,@none,@none,@none,@a) ;returns 65535 in a if text is found, 0 otherwise
;SysFreeString_(par(10)\bstrVal)
;MessageRequester("",str(a)) ;65535=found, 0=not found
SysFreeString_(par(1)\bstrVal)
find\Release()
;}
endif
if 1
;{ ;working with bookmarks to find text passages later
;{ ;delete whole text
;{ ;complicated but flexible method
if 0
par(1)\vt=#vt_I4
par(1)\iVal=#wdCollapseStart
contentrange\Collapse(@par(1)) ;sets start and end of selection to its start - only makes sense when the selection begins with 0 so that everything is deleted indeed
;otherwise use selection\SetRange(0,0), that's easier
doc\get_Characters(@characters)
characters\get_Count(@a1)
characters\Release()
par(1)\vt=#vt_I4
par(1)\iVal=#wdCharacter ;unit that is used to count (every character here)
par(2)\vt=#vt_I4
par(2)\iVal=a1 ;number of units to be deleted
contentrange\Delete(@par(1),@par(2),@a) ;a=number of deleted units
endif
;}
;{ ;simple method (one line only):
contentrange\Delete(@none,@none,@a) ;a=number of deleted units (this will be 1 here, whyever...) - with @none,@none it doesn't seem to matter what the current selection looks like, everything is deleted
;}
;}
;get Bookmarks interface handle
doc\get_Bookmarks(@bookmarks)
;create new Bookmarks
bookmarks\Add("B1",@none,@bookmark(1)) ;@range instead of @none in any form doesn't seem to work, the bookmark won't be created with it
selection\InsertAfter("New text.")
selection\get_End(@a)
selection\SetRange(a,a) ;delete selection and set cursor the the end of the former one (the bookmark will always consist of the whole selection which is not desired here but might be very well to create something out of it later (e.g. a table))
bookmarks\Add("B2",@none,@bookmark(2)) ;@range instead of @none in any form doesn't seem to work, the bookmark won't be created with it
selection\InsertAfter("More new text.")
bookmarks\Exists("B1",@a) ;a=65535: true, a=0: false
if bookmark(1)
bookmark(1)\Select()
bookmark(1)\Release()
else
MessageRequester("","bookmark 1 couldn't be created")
endif
if bookmark(2)
bookmark(2)\Select() ;set cursor to second Bookmark (no selection was saved here, just a position, see above)
bookmark(2)\Release()
else
MessageRequester("","bookmark 2 couldn't be created")
endif
bookmarks\Release()
;}
endif
selection\Release()
contentrange\Release()
EndIf
;}
if 0
;{ ;save document
;https://learn.microsoft.com/en-us/office/vba/api/word.saveas2 (der letzte dort genannte Parameter [CompatibilityMode] wird hier nicht benutzt)
file = "C:\temp\test2.docx" ;without parameters the default ending must be used which can be .doc on some machines (here the corresponding parameter is set so we can use .docx safely)
fn\vt = #VT_BSTR
fn\bstrVal = SysAllocString_(@file) ;SysAllocString creates the BSTR that is needed here (siehe https://learn.microsoft.com/en-us/previous-versions/windows/desktop/automat/bstr)
par(2)\vt=#VT_I4
par(2)\iVal=#wdFormatDocumentDefault ;#wdFormatDocument would be *.doc - enumeration: https://learn.microsoft.com/en-us/office/vba/api/word.wdsaveformat
hr=doc\SaveAs(@fn,@par(2),@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none) ;overwrites without asking (cannot be changed, take care of it yourself)
;hr=doc\SaveAs(@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none,@none) ;saves with default filename and destination - overwrites without asking (cannot be changed, take care of it yourself)
SysFreeString_(fn\bstrVal)
;}
endif
dontsave\vt=#VT_I4
dontsave\iVal=#wdDoNotSaveChanges ;enumeration: https://learn.microsoft.com/en-us/office/vba/api/word.wdsaveoptions
;doc\Close(@dontsave,@none,@none) ;close document it you like
doc\Release()
documents\Release()
;app\Quit(@dontsave,@none,@none) ;terminate word if you like
app\Release()
OleUninitialize_()
EndProcedure
action()
end