Serienbrief erstellen mit VBScript (VBS) und der OOo API

Programmierung unter AOO/LO (StarBasic, Python, Java, ...)

Moderator: Moderatoren

RVAma
Beiträge: 4
Registriert: Do, 17.12.2015 10:44

Serienbrief erstellen mit VBScript (VBS) und der OOo API

Beitrag von RVAma »

Guten Tag,

ich habe ein Problem bei der Erstellung eines Serienbriefes mit VBS und der OpenOffice API, genauer gesagt bei der Verlinkung der Datenquelle.

Kurze Erläuterung der Umstände
Wir benutzen ein Customer Relationship Management (CRM) Programm (nicht SAP), welches eine Word-Serienbrieffunktion hat. Diese Funktion ist in Visual Basic Script programmiert. Meine Aufgabe ist es nun, die gleiche Funktion für OASIS Open Document Dokumente zu erstellen, ebenfalls in VBS.
Ich verwende dafür die OpenOffice.org API (https://www.openoffice.org/api/) und LibreOffice als Testumgebung (mit OpenOffice wird später auch getestet).
Im CRM klicke ich auf den "Word Serienbrief"-Button, das dahinterliegende Word Modul, welches mir als Vorlage dient, erstellt zuerst aus den ausgewählten CRM Daten eine .csv (z. B. Personendaten mit Anschrift, Firma, Anrede, etc.). Danach wird im Code aus einer vorher ausgewählte Vorlage (kann beliebiger Text sein) der Inhalt geladen. Aus dieser Vorlage wird ein neues Word-Dokument erzeugt mit dem selben Inhalt, zusätzlich wird für das neue Dokument die .csv als Datenquelle verlinkt. Bevor das Modul mit seiner Routine fertig ist, wird das neu erstellte Dokument geöffnet und der Benutzer kann nun die Felder eintragen, wo die Personenbezogenen Daten stehen sollen.

Mein System
Windows 7 Professional 64 Bit Version 6.1 (Build 7601: SP1)
LibreOffice 5.0.2.2
Java 1.8.0_66

Der Fehler
Soweit vom Grundablauf funktioniert es auch in LibreOffice bzw. OpenOffice, was ich zusammengebastelt habe. Allerdings nur beim 1. Öffnen. Wenn ich das Dokument schließe und neu aufmache, geht die Verlinkung mit der Datenquelle verloren. Der Eintrag der Datenquelle ("opog") ist immer noch zu sehen (F4 im Writer):
Bild
aber sobald ich die Tabellen anzeigen lassen möchte, kommt die Fehlermeldung
"The connection to the data source could not be established
The driver class '' could not be loaded"

"Error code: 1000
The driver class '' could not be loaded"

"SQL Status: HY000
The driver class '' could not be loaded"
http://i.imgur.com/7s368Dh.png

Warum erkennt er nicht mal den Treiber? Ich vermute, dass hier irgendwo der Fehler liegt.

Wenn ich den Writer offen lasse und die Datenbank mit LibreOffice Base öffne und wieder schließe, kommt ein "wollen Sie speichern?" Dialog. Wenn ich OK klicke und speichere, obwohl ich keine Änderungen vorgenommen habe, funktioniert die Verlinkung der Datenquelle auch beim erneuten Öffnen.

Im Internet habe ich zu dem Fehler Aussagen über fehlendes Java gefunden, aber daran wird das wohl nicht liegen, da es wahrscheinlich nur das manuelle Erstellen über LibreOffice/OpenOffice betrifft. Meinem LibreOffice ist Java bekannt:

Bild

muss ich Java evtl. im Code in irgendeiner Form für den Datenbanktreiber "mitgeben" bzw. mithilfe von Java die Datenquelle erstellen/registrieren?

Wenn ich das alles manuell mache, also über LibreOffice die Datenbank erstelle usw., funktioniert es ohne Probleme.

Technische Details
Als Basis für meinen Code habe ich das verwendet, was Dirk Reusswig hier gepostet hat: viewtopic.php?t=4572#p94841
Man beachte aber, dass sein Code einige Fehler enthält. In der Funktion "Oo_InstallDatasource" z. B. setzt er die PropertyValues "HeaderLines" und "Charset", welche korrekt "HeaderLine" und "CharSet" heißen. Falsche Schreibweisen bzw. nicht existierende Parameter werden ignoriert (ohne Fehlermeldung etc.).
In diesem Thread habe ich auch geguckt: viewtopic.php?t=9084
Ich benutze folgende OOo API Services: Datenquelle-URL (Verbindungs- bzw. Datenbanktyp): sdbc:flat (Parameter Referenz: https://www.openoffice.org/api/docs/com ... rties.html - ACHTUNG: Ich benutze nicht den FLATConnectionProperties Service, das ist lediglich eine Referenz für die Parameter, die ich an DataSource.Info übergebe)

Wenn ich nach der Erstellung beim 1. Öffnen die Datenbank mit Base öffne und die Eigenschaften checke, sieht alles korrekt aus:
Bild
Bild
Bild


Mein Code

Code: Alles auswählen

Dim objServiceManager
Dim objDesktop
Dim objCoreReflection
Dim objDatasource
Dim objConnection
Dim objMailMerge
Dim OODatei
Dim OOPfad
Dim OODataSourceName
Dim MyProps()

Set objServiceManager = Nothing
Set objDesktop = Nothing
Set objCoreReflection = Nothing

Sub ErstelleDok()
'[...] irrelevanter code vorher: Eigenschaften setzen, CSV generieren, Dateien kopieren und verschieben

	'csv zu utf-8 konvertieren
	KonvUTF8noBom(strDateiPfad_CSV)

	'Verbindung zu OpenOffice
	Set objServiceManager = CreateObject("com.sun.star.ServiceManager")
	Set objDesktop = objServiceManager.CreateInstance("com.sun.star.frame.Desktop")
	Set objCoreReflection = objServiceManager.CreateInstance("com.sun.star.reflection.CoreReflection")

	'Pfadangaben zu Testdateien
	OODatei = "file:///C:/Users/RVama/Desktop/Test.odt"
	'OODatei = "file:///C:/Users/RVAdmin/Desktop/Test1.odt"
	'OOPfad = "file:///C:/Users/RVama/Desktop/"
	OOPfad = "C:/Users/RVama/Desktop/"
	OODataSourceName = "opog"

	'Datenquelle erstellen, registrieren, verbinden
	Set objDatasource = OO_InstallDatasource(OOPfad, OODataSourceName)
	Set objConnection = objDatasource.getConnection("", "")
	'Set objConnection = objDatasource.connectWithCompletion("", "") 

	'Daten aus "Steuerdatei" einfügen
	Set objMailMerge = objServiceManager.CreateInstance("com.sun.star.text.MailMerge")
	With objMailMerge
		.DataSourceName = OODataSourceName	'Datenbankname (nicht der Dateiname der Datenquelle)
		.ActiveConnection = objConnection
		.DocumentURL = OODatei
		.CommandType = 0					'0 = Tabelle
		.Command = strDateiName_CSV 			'Tabellenname in der Datenbank (= Dateiname der Datenquelle)
		.OutputType = 2
		'.OutputURL = OOPfad
		.SaveAsSingleFile = True
	End With
	Call objMailMerge.Execute(MyProps)

	'[...] irrelevanter code danach: Dokument öffnen, Fehlermeldungen ausgeben bei Fehlern
End Sub

'Datei als UTF-8 no BOM speichern, dazu:
	'1) Inhalt der Datenquelle (CSV) einlesen und zwischenspeichern
	'2) den Inhalt an einen Stream übergeben
	'3) Pointer-Position des Streams auf 3 setzten, um den BOM-Teil zu überspringen
	'4) Inhalt (ohne BOM) in einen neuen, binären Stream kopieren und diesen als Datei speichern
	'BOM: https://de.wikipedia.org/wiki/Byte_Order_Mark
Function KonvUTF8noBom(Datei)
    dim content
    
    'CSV einlesen
    dim fso : set fso  = CreateObject("Scripting.FileSystemObject")
    'als Unicode öffnen
    dim file : set file = fso.OpenTextFile(Datei, 1, false, -1)
    
    'Inhalt speichern und Datei schließen
    content = file.ReadAll
    file.close
    'MsgBox "length: " & len(content) & vbCrLf & "Inhalt: " & content
    
	'UTF-8 (mit BOM) Stream erzeugen und CSV-Inhalt übergeben
	dim stream : set stream = CreateObject("ADODB.Stream")
	with stream
		.Charset  		= "utf-8"
		.Type     		= 2 'text
		.Mode			= 3 'ReadWrite
		.LineSeparator  = 10 'Line feed only
		.Open
		.WriteText content
		'.Position = 0
		'.SaveToFile 	Datei, 2 'überschreibe Datei
		.Position 		= 3 'BOM überspringen
		'.Close
	end with
	
	'binären Stream erzeugen, um Inhalt ohne BOM-Anteil übergeben zu können
	dim bStream : set bStream = CreateObject("adodb.stream")
	with bStream
	    .Type = 1 'binär
	    .Mode = 3 'ReadWrite
	    .Open
    end with
    
    'kopieren
    stream.CopyTo bStream
    
    stream.Flush
    stream.Close
    
    'speichern
    bStream.SaveToFile Datei, 2 'überschreibe Datei
    bStream.Flush
    bStream.Close
End Function


Function OO_InstallDatasource(filePath, filename)
	Dim databaseContext
	Dim dataSource
	
	Dim dsProps(4)
	Dim IDs_props()
	Dim continue
	
	continue = True
	
	Set databaseContext = objServiceManager.CreateInstance("com.sun.star.sdb.DatabaseContext")
	
	'Wenn Datenquelle unter dem gleichen Namen bereits registriert ist -> entfernen
	If (databaseContext.hasByName(filename)) Then
		If (OO_RemoveDatasource(filename) = False) Then
			continue = False
			If Not (IsEmpty(dataSource)) Then Set dataSource = Nothing
			If Not (IsEmpty(databaseContext)) Then Set databaseContext = Nothing
		End If
	End If
	
	If (continue) Then
		Set dataSource = databaseContext.CreateInstance()
		Call dataSource.DatabaseDocument.StoreAsUrl("file:///" & filePath & "Test_ama" & ".odb", IDs_props)
		
		dataSource.URL = "sdbc:flat:" & "file:///" & filePath & "Test_ama" & ".csv"
		Set dsProps(0) = OO_createStruct("com.sun.star.beans.PropertyValue")
		dsProps(0).Name = "HeaderLine"
		dsProps(0).Value = true
		Set dsProps(1) = OO_createStruct("com.sun.star.beans.PropertyValue")
		dsProps(1).Name = "FieldDelimiter"
		dsProps(1).Value = Chr(59) ' ;
		Set dsProps(2) = OO_createStruct("com.sun.star.beans.PropertyValue")
		dsProps(2).Name = "StringDelimiter"
		dsProps(2).Value = Chr(34) ' "
		Set dsProps(3) = OO_createStruct("com.sun.star.beans.PropertyValue")
		dsProps(3).Name = "CharSet"
		dsProps(3).Value = "UTF-8"
		Set dsProps(4) = OO_createStruct("com.sun.star.beans.PropertyValue")
		dsProps(4).Name = "Extension"
		dsProps(4).Value = "csv"
		dataSource.Info = dsProps
		
		Call databaseContext.registerObject(filename, dataSource)
		
		Set OO_InstallDatasource = dataSource
	End If
End Function

Function OO_RemoveDatasource(RDs_strDatasourceName)
	OO_RemoveDatasource = False
	
	Dim RDs_objDatabaseContext 
	Set RDs_objDatabaseContext = objServiceManager.CreateInstance("com.sun.star.sdb.DatabaseContext")
	
	If RDs_objDatabaseContext.hasByName(RDs_strDatasourceName) Then
		Call RDs_objDatabaseContext.revokeObject(RDs_strDatasourceName)
		OO_RemoveDatasource = True
	End If
End Function

Function OO_createStruct(strTypeName)
	Dim classSize
	Set classSize = objCoreReflection.forname(strTypeName)
	
	Dim aStruct
	classSize.CreateObject aStruct

	Set OO_createStruct = aStruct
End Function
Und das ganze in einem pastebin, fürs einfachere Lesen:
http://pastebin.com/ivBYnn3N

Erklärung zum Code
- Die CSV wird vom vorhanden Word-Code generiert. Ich muss diese jedoch umkodieren, damit Sonderzeichen in LibreOffice/OpenOffice korrekt erkannt und angezeigt werden.
- obwohl ich bei dataSource.URL den Pfad zu einer bestimmten Datei angebe (diese befindet sich auf dem Desktop), werden in der Datenbank trotzdem alle .csv Dateien als Tabellen angelegt, die im selben Ordner liegen. Wenn ich bei dataSource.URL nur den Ordnerpfad eintrage, ohne Datei, passiert das gleiche.


Hat jemand Erfahrung mit der ganzen Kiste und weiß mehr? Ich weiß nicht was ich noch probieren kann :(
Evtl. andere Verbindungsmethoden als DataSource.getConnection()?
Zuletzt geändert von RVAma am Mo, 21.12.2015 09:59, insgesamt 2-mal geändert.
Stephan
********
Beiträge: 12369
Registriert: Mi, 30.06.2004 19:36
Wohnort: nahe Berlin

Re: Serienbrief erstellen mit VBScript (VBS) und der OOo API

Beitrag von Stephan »

Allgemein:
Ich würde solche Tests nicht mit Libreoffice machen, denn LO-Versionen sind häufig ziemlich fehlerhaltig. Ich würde also zunächst mit OpenOffice arbeiten und erst wenn es dort klappt versuchen die Lösung auf LO zu übertragen.
Möglicherweise würde ich zu Testzwecken sogar eine alte OOo-Version Version verwenden, wie z.B. OOo 3.3.0

Konkret kann ich nichts sagen, auch wenn Deine Anfrage vorbildlich ausführlich formuliert ist. Möglicherweise könntest Du Dir einmal die Extension http://calc-info.de/makros.htm#serienbriefbedingungen installieren und schauen was dir diese zur Datenbankanbindung Deines Dokuments sagt. Wir die DB erkannt oder nicht?
(das ist aber mehr eine Frage für mich zu mehr Klarheit wie die Situation im Dokument ist)

Außerdem:
Muss denn das Ganze per DB gelöst werden? DB machen in OO/LO immer mal wieder Probleme und in Praxis ist es manchmal durchaus sinnvoll ohne zu arbeiten, wenn Du ja ohnehin bereits Makros benutzt.


Eines macht mich neugierig:
Es handelt sich um das CRM von combit? https://www.combit.net/crm-loesungen/
Dort ist die Serienbrieffunktion per VBS angebunden und durch den Anwender frei anpassbar?


Gruß
Stephan
RVAma
Beiträge: 4
Registriert: Do, 17.12.2015 10:44

Re: Serienbrief erstellen mit VBScript (VBS) und der OOo API

Beitrag von RVAma »

Stephan hat geschrieben:Möglicherweise könntest Du Dir einmal die Extension http://calc-info.de/makros.htm#serienbriefbedingungen installieren und schauen was dir diese zur Datenbankanbindung Deines Dokuments sagt. Wir die DB erkannt oder nicht?
selbe Ergebnis, beim ersten Öffnen funktioniert alles so wie es soll, wenn ich das Dokument schließe und wieder öffne, kommt das:
http://i.imgur.com/ssdrcjC.png

Stephan hat geschrieben:Außerdem:
Muss denn das Ganze per DB gelöst werden? DB machen in OO/LO immer mal wieder Probleme und in Praxis ist es manchmal durchaus sinnvoll ohne zu arbeiten, wenn Du ja ohnehin bereits Makros benutzt.
Nee muss es nicht, solange die Anforderungen erfüllt werden. Was gibt es denn für Alternativen? Und funktioniert diese Alternative auch mit mehreren Datensätzen? Diese Funktion soll später von Endkunden benutzt werden, soll also heißen wir benötigen eine Lösung, die ohne zusätzliche Extensions oder dergleichen funktioniert, das CRM und OpenOffice/LibreOffice sollen alles sein, was man benötigt.
Hast du dabei an Makros gedacht? Ich hab kaum Erfahrung mit OOo oder LO, mit Makros habe ich auch noch nie gearbeitet. Wenn es möglich ist Makros als Extension von extern zu installieren, also z. B. durch ein Skript, dann wäre das noch eine Option. Es sollte so einfach wie möglich gehalten werden für die Benutzer.

Stephan hat geschrieben:Es handelt sich um das CRM von combit? https://www.combit.net/crm-loesungen/
Dort ist die Serienbrieffunktion per VBS angebunden und durch den Anwender frei anpassbar?
Ups, da habe ich einen Pfad vergessen rauszunehmen aus dem Code :lol:

Ja, das ist das cRM. Das c steht hier aber für combit, nicht für customer.
Der 2. Teil ist aber nicht ganz korrekt: im klassischen cRM gibt es keine Serienbrieffunktion, das Word-Serienbrief-Modul ist Teil eines zusätzlichen Softwarepaketes.
Stephan
********
Beiträge: 12369
Registriert: Mi, 30.06.2004 19:36
Wohnort: nahe Berlin

Re: Serienbrief erstellen mit VBScript (VBS) und der OOo API

Beitrag von Stephan »

selbe Ergebnis, beim ersten Öffnen funktioniert alles so wie es soll, wenn ich das Dokument schließe und wieder öffne, kommt das: http://i.imgur.com/ssdrcjC.png
Falls das mit LO passiert würde ich zuallererst mit einer bewährten OOo-Version testen um auszuschließen das der Fehler nur an LO liegt.
Nee muss es nicht, solange die Anforderungen erfüllt werden. Was gibt es denn für Alternativen?
In einer Dokumentvorlage Platzhalter verwenden, z.B. in Form einfacher markierter Text wie @@@Name@@@, @@@Vorname@@@ usw. oder in Form von Feldbefehlen z.B. einem Benutzerfeld (Einfügen-Feldbefehl-Andere-Variablen-Benutzerfeld).
Und funktioniert diese Alternative auch mit mehreren Datensätzen?
Ja. Neues Dokument auf Basis der Dokumentvorlage mit den Platzhaltern öffnen, Platzhalter per Makro durch Inhalte des aktuellen Datensatzes ersetzen, Datei speichern und schließen. Diese Abfolge nun für jeden einzelnen Datensatz wiederholen.
Eine Grenze gibt es in Praxis nur durch die relative Langsamkeit dieses Vorgehens, einige Dutzend Datensätze machen kein Problem, bei einigen tausend könnte es entnervend lange dauern.
Hast du dabei an Makros gedacht?
Nein, ich schrieb "Makro" aus Gedankenlosigkeit, ich meinte hier im Konkreten das VB-Script, weil Du das ohnehin schon benutzt.
also z. B. durch ein Skript,
das man Makros in OO per Script installierte stammt aus seeligen Zeiten von OOo 1.x, es gibt heute keinerlei Grund mehr so zu verfahren, sondern eine Installation als Extension ist vorzuziehen.
Normalerweise per Extensionmanager (Extras-Extensionmanager) aber ggf. kann man die Installation der Extension auch per Script durchführen, was in manchen Ausnahmefällen Sinn machen kann, meinethalben wenn man es sich in den Kopf gesetzt hat die Extension in ein erläuterndes Textdokument zu integrieren und von dort aus die Installation per Schaltfläche zu starten.
das Word-Serienbrief-Modul ist Teil eines zusätzlichen Softwarepaketes.
Eines dieser hier:
https://www.combit.net/crm-software/loe ... r-den-crm/

Wenn ja, Welches?

Bitte gib doch einmal ein paar genauere Infos, weil mich das Thema beruflich interessiert. Gibt es eine Demoversion des zusätzlichen Softwarepakets?
Das man hier mit VBS arbeiten kann finde ich deshalb interessant weil man ja dadurch eine generelle Schnittstelle für OO schreiben könnte.


Gruß
Stephan
RVAma
Beiträge: 4
Registriert: Do, 17.12.2015 10:44

Re: Serienbrief erstellen mit VBScript (VBS) und der OOo API

Beitrag von RVAma »

Stephan hat geschrieben:
selbe Ergebnis, beim ersten Öffnen funktioniert alles so wie es soll, wenn ich das Dokument schließe und wieder öffne, kommt das: http://i.imgur.com/ssdrcjC.png
Falls das mit LO passiert würde ich zuallererst mit einer bewährten OOo-Version testen um auszuschließen das der Fehler nur an LO liegt.
OOo 3.3/LO 5.0 führte zum selben Ergebnis, gab keine Unterschiede. War also kein Fehler seitens LO. Die neuste OOo Version habe ich aber nicht ausprobiert.
Stephan hat geschrieben:
das Word-Serienbrief-Modul ist Teil eines zusätzlichen Softwarepaketes.
Eines dieser hier:
https://www.combit.net/crm-software/loe ... r-den-crm/

Wenn ja, Welches?

Bitte gib doch einmal ein paar genauere Infos, weil mich das Thema beruflich interessiert. Gibt es eine Demoversion des zusätzlichen Softwarepakets?
Das man hier mit VBS arbeiten kann finde ich deshalb interessant weil man ja dadurch eine generelle Schnittstelle für OO schreiben könnte.
Ja, es ist das unter "Faktura & Warenwirtschaft" - "Faktura Solutions": https://www.combit.net/crm-software/crm ... irtschaft/ (das Faktura-Modul (FM) von UNIRENT, mehr Details hier: https://www.combit.net/de-de/crm-softwa ... f#zoom=100).
UNIRENT ist offizieller Partner von combit und lizensierter Entwickler bzw. Anbieter. Wenn du eigene Funktionen bauen möchtest, müsstest du erst Partner werden, dann erhälst du das combit SDK und kannst damit loslegen.
Das ist zumindest der normale Vorgang, wenn du/ihr eigene Lösungen nur intern einsetzen wollt, ohne sie zu verkaufen, dann weiß ich nicht wie das geregelt ist. Am besten bei combit selbst mal anfragen welche Optionen es gibt.
So viel kann ich dir dazu aber auch nicht sagen, sind grad alle im Urlaub und ich bin noch neu und habe keine richtige Einweisung in die ganze Materie erhalten, mir wurde das Word-Modul vorgesetzt und ich sollte es für OpenOffice umschreiben :D

Das cRM unterstützt aber nicht nur VBS, sondern alle Sprachen des Windows Script Host (https://de.wikipedia.org/wiki/Windows_Script_Host)
Aus der combit Software Development Kit (SDK) Dokumentation:
Welche Scriptsprachen werden unterstützt?
Grundsätzlich werden alle Scriptsprachen des Windows Scripting Host unterstützt. Am weitesten verbreitet sind VBScript und JScript, die direkt vom Hersteller Microsoft angeboten werden. Es gibt aber auch andere Umsetzungen wie z.B. Python. Die Auswahl der Sprache erfolgt dabei über die Dateiendung, z.B. "vbs" bei VBScript und "js" bei JScript.
Hinweis: VBScript und JScript sind üblicherweise schon auf Ihrem System installiert. Falls nicht oder falls andere Sprachen verwendet werden sollen, müssen diese vom jeweiligen Hersteller bezogen werden und entsprechend seinen Angaben auf dem System installiert werden.
Neben den Scriptsprachen des Windows Scripting Host wird auch C# als Scriptsprache unterstützt. Die Dateiendung lautet in diesem Fall "csscript"
Mehr Infos findest du außerdem hier:
http://www.unirent.net/index.php/produk ... tura-modul
http://www.unirent.net/index.php/produk ... schulungen


Ich danke dir für deine Zeit, nach weiterem Herumprobieren konnte ich den Fehler nun ausfindig machen.
Es lag an folgender Zeile:

Code: Alles auswählen

Call dataSource.DatabaseDocument.StoreAsUrl("file:///" & filePath & "Test_ama" & ".odb", IDs_props)
Die .odb darf erst erstellt werden, nachdem in der dazugehörigen DataSource die Eigenschaften gesetzt wurden.
Korrekt sieht der Code also so aus:

Code: Alles auswählen

If (continue) Then
      Set dataSource = databaseContext.CreateInstance()
      
      dataSource.URL = "sdbc:flat:" & "file:///" & filePath & "Test_ama" & ".csv"
      Set dsProps(0) = OO_createStruct("com.sun.star.beans.PropertyValue")
      dsProps(0).Name = "HeaderLine"
      dsProps(0).Value = true
      Set dsProps(1) = OO_createStruct("com.sun.star.beans.PropertyValue")
      dsProps(1).Name = "FieldDelimiter"
      dsProps(1).Value = Chr(59) ' ;
      Set dsProps(2) = OO_createStruct("com.sun.star.beans.PropertyValue")
      dsProps(2).Name = "StringDelimiter"
      dsProps(2).Value = Chr(34) ' "
      Set dsProps(3) = OO_createStruct("com.sun.star.beans.PropertyValue")
      dsProps(3).Name = "CharSet"
      dsProps(3).Value = "UTF-8"
      Set dsProps(4) = OO_createStruct("com.sun.star.beans.PropertyValue")
      dsProps(4).Name = "Extension"
      dsProps(4).Value = "csv"
      dataSource.Info = dsProps
      
      Call dataSource.DatabaseDocument.StoreAsUrl("file:///" & filePath & "Test_ama" & ".odb", IDs_props)
      Call databaseContext.registerObject(filename, dataSource)
      Set OO_InstallDatasource = dataSource
End If
Sowas dummes :/
Auch, dass es beim 1. Öffnen (unabhängig ob durch Script geöffnet oder manuell) funktioniert, danach aber nicht mehr, ist komisch.

Hier nochmal mein überarbeiteter Code, für alle, die in Zukunft evtl hier landen:
pastebin: http://pastebin.com/BTb7R8M8

Code: Alles auswählen

Dim objServiceManager
Dim objDesktop
Dim objCoreReflection
Dim objDatasource
Dim objConnection
Dim objMailMerge
Dim OODatei
Dim OOPfad
Dim OODataSourceName
Dim MyProps()

Set objServiceManager = Nothing
Set objDesktop = Nothing
Set objCoreReflection = Nothing

Sub ErstelleDok()
'[...] irrelevanter code vorher: Eigenschaften setzen, CSV generieren, Dateien kopieren und verschieben

   'csv zu utf-8 konvertieren
   KonvUTF8noBom(strDateiPfad_CSV)

   'Verbindung zu OpenOffice
   Set objServiceManager = CreateObject("com.sun.star.ServiceManager")
   Set objDesktop = objServiceManager.CreateInstance("com.sun.star.frame.Desktop")
   Set objCoreReflection = objServiceManager.CreateInstance("com.sun.star.reflection.CoreReflection")

   'Pfadangaben zu Testdateien
   OODatei = "file:///C:/Users/RVama/Desktop/Test.odt"
   'OODatei = "file:///C:/Users/RVAdmin/Desktop/Test1.odt"
   'OOPfad = "file:///C:/Users/RVama/Desktop/"
   OOPfad = "C:/Users/RVama/Desktop/"
   OODataSourceName = "opog"

   'Datenquelle erstellen, registrieren, verbinden
   Set objDatasource = OO_InstallDatasource(OOPfad, OODataSourceName)
   Set objConnection = objDatasource.getConnection("", "")
   'Set objConnection = objDatasource.connectWithCompletion("", "")

   'Daten aus "Steuerdatei" einfügen
   Set objMailMerge = objServiceManager.CreateInstance("com.sun.star.text.MailMerge")
   With objMailMerge
      .DataSourceName = OODataSourceName   'Datenbankname (nicht der Dateiname der Datenquelle)
      .ActiveConnection = objConnection
      .DocumentURL = OODatei
      .CommandType = 0               '0 = Tabelle
      .Command = strDateiName_CSV          'Tabellenname in der Datenbank (= Dateiname der Datenquelle)
      .OutputType = 2
      '.OutputURL = OOPfad
      .SaveAsSingleFile = True
   End With
   Call objMailMerge.Execute(MyProps)

   '[...] irrelevanter code danach: Dokument öffnen, Fehlermeldungen ausgeben bei Fehlern
End Sub

'Datei als UTF-8 no BOM speichern, dazu:
   '1) Inhalt der Datenquelle (CSV) einlesen und zwischenspeichern
   '2) den Inhalt an einen Stream übergeben
   '3) Pointer-Position des Streams auf 3 setzten, um den BOM-Teil zu überspringen
   '4) Inhalt (ohne BOM) in einen neuen, binären Stream kopieren und diesen als Datei speichern
   'BOM: https://de.wikipedia.org/wiki/Byte_Order_Mark
Function KonvUTF8noBom(Datei)
    dim content
   
    'CSV einlesen
    dim fso : set fso  = CreateObject("Scripting.FileSystemObject")
    'als Unicode öffnen
    dim file : set file = fso.OpenTextFile(Datei, 1, false, -1)
   
    'Inhalt speichern und Datei schließen
    content = file.ReadAll
    file.close
    'MsgBox "length: " & len(content) & vbCrLf & "Inhalt: " & content
   
   'UTF-8 (mit BOM) Stream erzeugen und CSV-Inhalt übergeben
   dim stream : set stream = CreateObject("ADODB.Stream")
   with stream
      .Charset        = "utf-8"
      .Type           = 2 'text
      .Mode         = 3 'ReadWrite
      .LineSeparator  = 10 'Line feed only
      .Open
      .WriteText content
      '.Position = 0
      '.SaveToFile    Datei, 2 'überschreibe Datei
      .Position       = 3 'BOM überspringen
      '.Close
   end with
   
   'binären Stream erzeugen, um Inhalt ohne BOM-Anteil übergeben zu können
   dim bStream : set bStream = CreateObject("adodb.stream")
   with bStream
       .Type = 1 'binär
       .Mode = 3 'ReadWrite
       .Open
    end with
   
    'kopieren
    stream.CopyTo bStream
   
    stream.Flush
    stream.Close
   
    'speichern
    bStream.SaveToFile Datei, 2 'überschreibe Datei
    bStream.Flush
    bStream.Close
End Function


Function OO_InstallDatasource(filePath, filename)
	Dim databaseContext
	Dim dataSource
	
	Dim dsProps(4)
	Dim IDs_props()
	Dim continue
	
	continue = True
	
	Set databaseContext = objServiceManager.CreateInstance("com.sun.star.sdb.DatabaseContext")
	
	'Wenn Datenquelle unter dem gleichen Namen bereits registriert ist -> entfernen
	If (databaseContext.hasByName(filename)) Then
		If (OO_RemoveDatasource(filename) = False) Then
			continue = False
			If Not (IsEmpty(dataSource)) Then Set dataSource = Nothing
			If Not (IsEmpty(databaseContext)) Then Set databaseContext = Nothing
		End If
	End If
	
	If (continue) Then
		Set dataSource = databaseContext.CreateInstance()
		
		'Parameter für Datenbanktreiber "flat" setzen (Verbinungs- bzw. Datenbanktyp)
		'https://www.openoffice.org/api/docs/common/ref/com/sun/star/sdbc/FLATConnectionProperties.html
		dataSource.URL = "sdbc:flat:" & filePath & "Test_ama" & ".csv"
		Set dsProps(0) = OO_setPropVal("HeaderLine", true)
		Set dsProps(1) = OO_setPropVal("FieldDelimiter", Chr(59)) ';
		Set dsProps(2) = OO_setPropVal("StringDelimiter", Chr(34)) '"
		Set dsProps(3) = OO_setPropVal("CharSet", "UTF-8")
		Set dsProps(4) = OO_setPropVal("Extension", "csv")
		dataSource.Info = dsProps
		
		'dumpDsProps(dsProps)
		'MsgBox TypeName(dsProps(0))
		
		'.odb Datenbankdatei anlegen
		Call dataSource.DatabaseDocument.StoreAsUrl("file:///" & filePath & "Test_ama" & ".odb", IDs_props)
		'Datenbank im Datenquellen-Register eintragen
		Call databaseContext.registerObject(filename, dataSource)
		
		Set OO_InstallDatasource = dataSource
	End If
End Function

Function OO_RemoveDatasource(RDs_strDatasourceName)
   OO_RemoveDatasource = False
   
   Dim RDs_objDatabaseContext
   Set RDs_objDatabaseContext = objServiceManager.CreateInstance("com.sun.star.sdb.DatabaseContext")
   
   If RDs_objDatabaseContext.hasByName(RDs_strDatasourceName) Then
      Call RDs_objDatabaseContext.revokeObject(RDs_strDatasourceName)
      OO_RemoveDatasource = True
   End If
End Function

Function OO_setPropVal(propName, propValue)
	dim propVal
	Set propVal = OO_createStruct("com.sun.star.beans.PropertyValue")
	propVal.Name = propName
	propVal.Value = propValue
	Set OO_setPropVal = propVal
End Function

Function OO_createStruct(strTypeName)
   Dim classSize
   Set classSize = objCoreReflection.forname(strTypeName)
   
   Dim aStruct
   classSize.CreateObject aStruct

   Set OO_createStruct = aStruct
End Function

Sub dumpDsProps(arr)
	Dim s
	For i = 0 To uBound(arr)
	    s = s & i & ": " & arr(i).Name & " - " & arr(i).Value & vbCrLf
	Next

	MsgBox s
End Sub
RVAma
Beiträge: 4
Registriert: Do, 17.12.2015 10:44

Re: Serienbrief erstellen mit VBScript (VBS) und der OOo API

Beitrag von RVAma »

Sorry für den Doppelpost,

@Stephan, ich habe mir in der Zwischenzeit das combit cRM genauer angeguckt und ich muss meine Aussage von vorher revidieren:
in der Standardausführung des cRM ist es sehr wohl möglich, jederzeit und überall eigene Scripts einzubinden und Schaltflächen für diese zu bauen, sodass sie mit einem Klick ausgegührt werden können. Keine extra Lizenzen etc. So kannst du u.A. diverese Schnittstellen bauen, ob MS Office, OpenOffice, Mozilla Thunderbird, Outlook, was auch immer :)
Die Standardversion ist schon sowas wie eine Entwicklerversion, damit kann man einiges machen.

Dafür lassen sich auch verschiedene Sprachen benutzen, wie ich geschrieben habe.

Meine OO-Schnittstellenschaltfläche sieht z. B. so aus (man ignoriere die Namen, die sind von der Word-Schaltfläche übernommen :p)
http://imgur.com/QminvzR
"ErstelleWordDok_Einzel" ist der Funktionsnamen, gefolgt von dem Parameter "0"
in der cuWordbrief.vbs sieht die Funktionssignatur so aus:

Code: Alles auswählen

Sub ErstelleWordDok_Einzel(LogTyp)
das cRM führt die Funktion mit dem eingetragenen Parameter dann aus.
Antworten