//FormHtml.prg	26.08.2023 18:40
//Sammlung der Funktionen fr die indiText/indiForm
// sammelt alle Funktionen aus KSOX fr den Formulardruck per HTML und OpenOffice-Writer 
//
#include "Gra.ch"
#include "Xbp.ch"
#include "Appevent.ch"
#include "Appedit.ch"
#include "Appbrow.ch"
#include "Font.ch"
#include "Common.ch"
#include "Dll.ch"
#include "Dmlb.ch"
#include "Common.ch"
#include "fileio.ch"
#include "directry.ch"


//06.11.2022 19:22 Adresse aus vers.dbf zusammenstellen fr html-Briefe
FUNCTION BriefAdresse(nArt,cVerskz)	// nArt=1 heiát als Block, nArt=2 heiát in einer Zeile
	LOCAL cAdresse := ""
	DEFAULT nArt TO 1
	DEFAULT cVerskz TO "FH001"
	cVerskz := AllTrim(cVerskz)
	IF cVerskz == "A"			// Adressat ist der Ansprechpartner
		IF nArt == 1
			cAdresse += AllTrim(Anrede()) + CRLF
			cAdresse += AllTrim(1->ansp_vname) + " " + AllTrim(1->ansp_name) + CRLF
			cAdresse += AllTrim(1->ansp_str) + CRLF
			cAdresse += AllTrim(1->ansp_ort) + CRLF
		ELSEIF nArt == 2
			cAdresse += AllTrim(1->ansp_anr) + " " +  AllTrim(1->ansp_vname) + " " + AllTrim(1->ansp_name) + ", " +  AllTrim(1->ansp_str) + ", " +  AllTrim(1->ansp_ort)
		ENDIF 
	ELSE
		IF Len(cVerskz) < 6 .AND. Len(AllTrim(cVerskz)) > 0
			IF !5->(DbSeek(cVerskz,.F.))
				RETURN cVerskz
			ENDIF
		ELSE
			5->(DbGotop())
			IF Len(AllTrim(cVerskz)) == 0 .OR. !5->(DBLocate( {|| cVerskz $ (5->name1 + 5->name2) .OR. cVerskz $ (AllTrim(5->name1) +" "+ AllTrim(5->plz_ort)) } ))
				RETURN cVerskz
			ENDIF
		ENDIF
		IF nArt == 1
			cAdresse += AllTrim(5->name1) + CRLF
			cAdresse += AllTrim(5->name2) + CRLF
			cAdresse += AllTrim(5->strasse) + CRLF
			cAdresse += AllTrim(5->plz_ort) + CRLF
		ELSEIF nArt == 2
			cAdresse += AllTrim(5->name1) + " " +  AllTrim(5->name2) + " " +  AllTrim(5->strasse) + " " +  AllTrim(5->plz_ort)
		ENDIF 
	ENDIF
RETURN cAdresse

//29.10.2022 17:56 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//FUNCTION ModalFen( cString, cTitle, oDlg1, nXsize, nYsize )
FUNCTION ButtonFenster( aInditxt, oDlg1 )
   LOCAL nEvent, mp1, mp2, oXbp, lExit
   LOCAL oDlg, oSle, oMle, oFocus, aPos, nSemi := 0  //, drawingArea
   LOCAL drawingArea := oDlg1:drawingArea  //*
   LOCAL aSize := drawingArea:currentSize()
   LOCAL nXsize := ASize[1]*0.6
   LOCAL nYsize := 200 + Len(aInditxt) * 25
   LOCAL nText := 0
   LOCAL cTitle := "W„hlen Sie einen Brief aus !    -    (Edit mit ALT-Taste)"
//   cString := IIf( cString<>NIL, cString, "Datensatz "+LTrim(Str(Recno()))+" ist z.Zt. gesperrt!" )
   oDlg1 := IIf( oDlg1<>NIL, oDlg1, AppDesktop() )

   drawingArea := oDlg1:drawingArea  //*
   aSize := drawingArea:currentSize()

   aPos  := { ( aSize[1]-nXsize )/2, ( aSize[2]-nYsize+20 ) / 2 }

   oDlg           := AKDialog():new( AppDesktop(), oDlg1, aPos, {nXsize,nYsize} )
   oDlg:title     := cTitle
   oDlg:taskList  := .T.
   oDlg:minButton := .F.
   oDlg:maxButton := .F.
   oDlg:create()
//   oDlg:drawingArea:setColorBG( GRA_CLR_YELLOW )

   oFocus := SetAppFocus( oDlg )

   aSize := oDlg:drawingArea:currentSize()
   nAnztxt := Len(aInditxt)
	FOR i:=1 TO nAnztxt
	   aPos          := { 10, 30 * (nAnztxt-i+1) }
	   oButt := ("oXbpB"+LTrim(Str(i)))
	   &oButt:= XbpPushbutton():new( oDlg:drawingArea,, aPos, {aSize[1]-10,24} )
	   &oButt:caption  := aInditxt[i]
	   &oButt:TabStop  := .T.
	   &oButt:create()
	   &oButt:activate := {|| PostAppEvent( xbeP_Close, i,, &oButt )  }
	   &oButt:cargo := i
	NEXT
   oDlg:setModalState( XBP_DISP_APPMODAL )
   oDlg:show()

   nEvent := xbe_None
   DO WHILE nEvent <> xbeP_Close
      nEvent := AppEvent( @mp1, @mp2, @oXbp )
      IF nEvent == xbeM_LbDown
   		nText := oXbp:cargo
   	ENDIF
      IF nEvent == xbeP_Keyboard
         DO CASE
            CASE mp1 == xbeK_ESC
               cString := "ESC"
               PostAppEvent( xbeP_Activate,,, &oButt )
            CASE mp1 == xbeK_RETURN .OR. mp1 == xbeK_F10
               cString := "!"
               PostAppEvent( xbeP_Activate,,, &oButt )
         ENDCASE
      ENDIF
      oXbp:handleEvent( nEvent, mp1, mp2 )
   ENDDO

   oDlg:setModalState( XBP_DISP_MODELESS )

   oDlg:destroy()
//   SetAppFocus( oFocus )
RETURN nText
//^^ButtonFenster^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

//16.03.2023 16:45 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//FUNCTION ModalFen( cString, cTitle, oDlg1, nXsize, nYsize )
FUNCTION ListboxFenster( aInditxt, oDlg1, cFormName)
   LOCAL nEvent, mp1, mp2, oXbp, lExit
   LOCAL oDlgLF, oFocus, aPos	 //, drawingArea
   LOCAL drawingArea := oDlg1:drawingArea, oDlgDA  //*	16.03.2023 18:34 oDlgDA
   LOCAL aSize := drawingArea:currentSize()
   LOCAL nXsize := ASize[1]*0.9	//*0.6
   LOCAL nYsize := ASize[2]*0.8
   LOCAL nText := 0
   LOCAL cTitle := "W„hlen Sie eine Formularart aus !    -    (Edit mit ALT-Taste)"
   oDlg1 := IIf( oDlg1<>NIL, oDlg1, AppDesktop() )

   drawingArea := oDlg1:drawingArea  //*
   aSize := drawingArea:currentSize()

   aPos  := { ( aSize[1]-nXsize )/2, ( aSize[2]-nYsize+20 ) / 2 }

   oDlgLF           := AKDialog():new( AppDesktop(), oDlg1, aPos, {nXsize,nYsize} )
   oDlgLF:title     := cTitle
   oDlgLF:taskList  := .T.
   oDlgLF:minButton := .F.
   oDlgLF:maxButton := .F.
   oDlgLF:create()
   oDlgLF:lockupdate(.T.)    //+27.11.2011 09:20
   oDlgDA = oDlgLF:drawingArea
   oDlgDA:setColorBG( GRA_CLR_YELLOW )

   oFocus := SetAppFocus( oDlgLF )

   aSize := oDlgDA:currentSize()
    oListBox := XbpListBox():new( oDlgDA,,{Int(12*nV),Int(12*nV)},{aSize[1]-Int(20*nV),aSize[2]-Int(20*nV)})
         Sleep(2)                      //+16.08.2012 10:56 Vista-Problem !
		oListBox:setFontCompoundName( cBFont )
    oListBox:create()
         Sleep(2)                      //+16.08.2012 10:56 Vista-Problem !

      FOR i := 1 TO Len(aInditxt)
         oListBox:addItem(ConvToOEMCP(aInditxt[i]))
//         oListBox:addItem(aInditxt[i])
         Sleep(2)                      //+23.02.2010 08:58 Vista-Problem !
      NEXT
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      oListBox:setData( {1}, .T. )


   oDlgLF:lockupdate(.F.)    //+27.11.2011 09:20
   oDlgLF:invalidateRect()   //+27.11.2011 09:30

   oDlgLF:setModalState( XBP_DISP_APPMODAL )
   oDlgLF:show()
   SetAppFocus(oListBox)

   nEvent := xbe_None
   DO WHILE nEvent <> xbeP_Close
      nEvent := AppEvent( @mp1, @mp2, @oXbp )
//      IF nEvent == xbeM_LbDown
//   		nText := oXbp:cargo
//			ENDIF

      IF nEvent == xbeM_LbDblClick .and. oXbp:isDerivedFrom( "XbpListBox" )
         cFormName := oListBox:getItem( oListBox:getData()[1] )
         nText := oListBox:getData()[1]
         nEvent := xbeP_Close
      ENDIF
      IF nEvent == xbeM_LbClick .and. oXbp:isDerivedFrom( "XbpListBox" )
         cFormName := oListBox:getItem( oListBox:getData()[1] )
         nText := oListBox:getData()[1]
         nEvent := xbeP_Close
      ENDIF
//      IF nEvent == xbeP_User
//         cFormName := oListBox:getItem( oListBox:getData()[1] )
//         nText := oListBox:getData()[1]
//      ENDIF

      IF nEvent == xbeP_Keyboard
         DO CASE
            CASE mp1 == xbeK_ESC
               cString := "ESC"
		         cFormName := ""
		         nText := 0	//oListBox:getData()[1]
               nEvent := xbeP_Close
            CASE mp1 == xbeK_RETURN .OR. mp1 == xbeK_F10
               cString := "!"
		         cFormName := oListBox:getItem( oListBox:getData()[1] )
		         nText := oListBox:getData()[1]
               nEvent := xbeP_Close
            CASE mp1 == xbeK_DOWN //.and. oXbp:isDerivedFrom( "XbpListBox" )
 //              PostAppEvent( xbeP_User )
            CASE mp1 == xbeK_UP //.and. oXbp:isDerivedFrom( "XbpListBox" )
 //              PostAppEvent( xbeP_User )
         ENDCASE
      ENDIF
      oXbp:handleEvent( nEvent, mp1, mp2 )
   ENDDO

   oDlgLF:setModalState( XBP_DISP_MODELESS )

//   oListBox:destroy()
   sleep(5)
   oDlgLF:destroy()
//   SetAppFocus( oFocus )
RETURN nText
//^^ListboxFenster^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


FUNCTION DateiStruktur(nA)
	LOCAL nOldArea := SELECT()
	LOCAL aStruktur := {}, cText := ""
	SELECT &nA
	aStruktur := ASort(DbStruct(),,,{|a1,a2|a1[1]<a2[1]})
	FOR i := 1 TO Len(aStruktur)
		aFeld := aStruktur[i]
		cText += PadR(aFeld[1],12) + ", " + PadR(aFeld[2],4) + ", " + PadR(Str(aFeld[3],2,0),4) + ", " + PadR(Str(aFeld[4],2,0),4) + ";     "
	NEXT
	SELECT(nOldArea)
RETURN cTEXT

//27.11.2023 13:47 bis gestern:
FUNCTION HTML_Brief_alt( cFile, cFormular, cFont, cFSize, cFormSeite, cZeileCM, cNotiz_Bez )	//18.10.2022 cZeileMM -> cZeileCM // cNotiz_Bez
   LOCAL nZei := 8, nAnf, CR := Chr(13), LF := Chr(10)
   LOCAL nHandle, cBuffer, nBytes, cText, cNeuTxt := ""
   LOCAL cDatv := cDatver
   LOCAL nFSize, nFHoehe, nFBreite
   LOCAL nZeileMM
   LOCAL cSZeit, nSZeit, cFZeit, nFZeit, nZ	//30.12.2022 15:29 warten aufs PDF
   DEFAULT cFormular TO ""
   DEFAULT cFont TO '"Times New Roman", serif'
   DEFAULT cFSize TO '18pt'
   DEFAULT cFormSeite TO '1cm 1cm 1cm 2cm'
   DEFAULT cZeileCM TO '0.14'		//11.10.2022 14:58 Zeilenabstand
	PRIVATE cBuero					//11.10.2022 16:56 PRIVATE fr VariFunkErsatz
   nFSize := Val(cFSize)
   nFHoehe := nFSize * 0.352778
   nFBreite := nFSize * 0.2	// 0.2 ist ein gesch„tzter vorl„ufiger Wert 
   nZeileMM := IIf(Val(cZeileCM)<0.2, nFHoehe * Val(cZeileCM)*10, Val(cZeileCM)*10)
	
//	DO WHILE At("\",cDatv) > 0
//		cDatv := Stuff( cDatv, At("\",cDatv), 1, "/" )
//	ENDDO
	IF !"HDBE"$Upper(cFormular)
		cFormular := cDatv + cFormular
	ENDIF
	
	// Zur Vermeidung von Kollision verschiedener Drucke    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	// Test: ist bereits die Datei HTML_Brief.html auf diesem PC ge”ffnet?
	IF FExists("c:\hdbe\HTML_Brief.html")		//22.12.2022 19:13
		nHandle := FOpen( "c:\hdbe\HTML_Brief.html", FO_EXCLUSIVE )
		IF nHandle = -1
		   //+ Die Datei ist bereits auf diesem PC ge”ffnet
		   FClose(nHandle)
		   msgbox("Es ist bereits ein HTML_Brief.html offen!"+CR+LF+"Bitte OfficeWriter schlieáen, dann nochmal versuchen!")
		   RETURN .F.
		ELSE
		   FClose(nHandle)
		ENDIF
	ENDIF
	//--------------------------------
	// Test: ist bereits die Datei HTML_Brief.pdf auf diesem PC ge”ffnet?
	IF FExists("c:\hdbe\HTML_Brief.pdf")		//22.12.2022 19:13
		nHandle := FOpen( "c:\hdbe\HTML_Brief.pdf", FO_EXCLUSIVE )
		IF nHandle = -1
		   //+ Die Datei ist bereits auf diesem PC ge”ffnet
		   FClose(nHandle)
		   msgbox("Es ist bereits ein HTML_Brief.PDF offen!"+CR+LF+"Bitte AdobeReader schlieáen, dann nochmal versuchen!")
		   RETURN .F.
		ELSE
		   FClose(nHandle)
		ENDIF
	ENDIF
	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	IF Len(cFile) > 50
		cText := cFile
		cFile := "HTML_Brief"
	ELSE
	   nHandle := FOpen( cFile, FO_READ )
	   cBuffer := Space(3000)
	   nBytes := FRead( nHandle, @cBuffer, 3000 )
	   cText := AllTrim(cBuffer)
	   FClose( nHandle )
	ENDIF

	// Test mit automatischem Ausfllen bei bestimmtem Formular:
	IF "KSO_GhAusz.png"$cFormular
		cFont := "Times New Roman"
		cFSize := "14pt"
		cFormSeite := "0cm 0cm 0cm 0cm"
		nZeileMM := 4.9
		cText := CR+LF+CR+LF + Space(65) + "Auftrag: " + Str(1->auftrnr,6,0) + CR+LF+CR+LF+CR+LF+CR+LF+CR+LF+CR+LF
		cText += Space(35) + Trim(1->vorname) + " " + Trim(1->name) + CR+LF
	ENDIF         

	IF cFile == "c:\hdbe\dHTML.abr" .OR. cFile == "c:\hdbe\dHTML.mahn"
		cText := StrTran( cText, CR+LF+"     ", CR+LF )	// linken Rand zu NULL machen
	ENDIF

// vermutlich hier berflssig, weil schon in Inditext() 08.11.2022 10:42
   cBuero := SubStr(cBU5,At(" ",cBU5)+1)
   cRufnummer := cBU6

	IF 'Temp'$cFile	// 11.12.2022 17:14 wenn im Text Formatierungen vorkommen (bl_r,bl_a etc...)
	   cNeuTxt := ;
         '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'+CR+LF+;
         '<HTML>'+CR+LF+;
         '<HEAD>'+CR+LF+;
         '	<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">'+CR+LF+;
         '	<TITLE>'+cFile+'</TITLE>'+CR+LF+;
         '	<META NAME="GENERATOR" CONTENT="KSOX.EXE">'+CR+LF+;
         '	<META NAME="CHANGEDBY" CONTENT="' + cBuero + '">'+CR+LF+;
         '	<STYLE TYPE="text/css">'+CR+LF+;
         '	<!--'+CR+LF+;
         '		@page { size: 21cm 29.7cm; margin:  ' + cFormSeite + '; }'+CR+LF+;
         '		P { margin-bottom: 0.21cm }'+CR+LF+;
         '		P#cour { font-family: ' + cFont + '; }'+CR+LF+;
         '	-->'+CR+LF+;
         '	</STYLE>'+CR+LF+;
         '</HEAD>'+CR+LF+;
         IIf( Upper(Right(cFormular,4))==".PNG", ;
         '<BODY LANG="de-DE" BACKGROUND="'+cFormular+'" DIR="LTR" STYLE="background: url('+cFormular+') no-repeat middle center scroll">',;
         '<BODY LANG="de-DE">')+CR+LF+;
         '<PRE STYLE="margin-top:0;margin-bottom:0">'	//+CR+LF+;
	ELSE
	   cNeuTxt := ;
         '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'+CR+LF+;
         '<HTML>'+CR+LF+;
         '<HEAD>'+CR+LF+;
         '	<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">'+CR+LF+;
         '	<TITLE>'+cFile+'</TITLE>'+CR+LF+;
         '	<META NAME="GENERATOR" CONTENT="KSOX.EXE">'+CR+LF+;
         '	<META NAME="CHANGEDBY" CONTENT="' + cBuero + '">'+CR+LF+;
         '	<STYLE TYPE="text/css">'+CR+LF+;
         '	<!--'+CR+LF+;
         '		@page { size: 21cm 29.7cm; margin:  ' + cFormSeite + '; }'+CR+LF+;
         '		P { margin-bottom: 0.21cm }'+CR+LF+;
         '		P#cour { font-family: ' + cFont + '; }'+CR+LF+;
         '		PRE { font-family: ' + cFont + '; font-size: ' + cFSize + '; line-height: ' + LTrim(Str(nZeileMM/10)) + 'cm; }'+CR+LF+;
         '	-->'+CR+LF+;
         '	</STYLE>'+CR+LF+;
         '</HEAD>'+CR+LF+;
         IIf( Upper(Right(cFormular,4))==".PNG", ;
         '<BODY LANG="de-DE" STYLE="background: url('+cFormular+') no-repeat middle center scroll">'+CR+LF+;
         '<PRE STYLE="margin-top:0;margin-bottom:0cm">'+CR+LF+;
         '<FONT style=" font-family: ' + cFont + '; font-size: ' + cFSize + '; line-height: ' + LTrim(Str(nZeileMM/10)) + 'cm; ">', ;
         '<BODY LANG="de-DE">'+CR+LF+;
         '<PRE>' )
	ENDIF
	
   cNeuTxt += ConvToAnsiCP(cText)
         
   cNeuTxt += '</FONT></PRE></BODY></HTML>'

	cNeuTxt := StrTran( cNeuTxt, "</B>", "</B>       ")	// durch <> entstehen 7 Blanks
	
	IF !FExists("c:\hdbe\HTML_Brief.html")
		nHandle := FCreate("c:\hdbe\HTML_Brief.html")
		FClose(nHandle)
		Sleep(100)
	ENDIF
   nHandle := FOpen("c:\hdbe\HTML_Brief.html",FO_READWRITE)
   nBytes := FRead( nHandle, @cBuffer, 20000 )
   nBytes := Max(10000,nBytes)
   FSeek(nHandle, 0)
   nBytes := FWrite( nHandle, PadR(cNeuTxt,nBytes," ") )
   nBytes := FClose( nHandle )

	IF AppKeyState(65553)==1 .OR. "INPUT"$cNeuTxt	// zusammen mit Strg-Taste	//19.12.2022 15:13 mit LibreOffice zu PDF konvertieren
//geht nicht   	IF RunShell (' /C START C:\HDBE\swriter.libre.lnk --headless --convert-to pdf:"writer_pdf_Export" C:\HDBE\HTML_Brief.html',cComCom,.T.)
//geht nicht   	IF RunShell (" /C START C:\Progra~1\LibreOffice\program\swriter.exe --headless --convert-to pdf:'writer_pdf_Export' C:\HDBE\HTML_Brief.html",cComCom,.T.)
// so nicht! komplette Pfadangabe statt Link   	IF RunShell (' --headless --convert-to pdf:"writer_pdf_Export" --outdir "C:\HDBE" C:\HDBE\HTML_Brief.html', 'C:\HDBE\swriter.libre.lnk',.T.) == 0
		IF FExists('C:\Program Files\LibreOffice\program\swriter.exe')
			dHeute := DATE()		//02.01.2023 13:03
			cSZeit := Time()		//30.12.2022 15:36
			nSZeit := Val(SubStr(cSZeit,1,2))*3600 + Val(SubStr(cSZeit,4,2))*60 + Val(SubStr(cSZeit,7,2))
		  	IF RunShell (' --headless --convert-to pdf:"writer_pdf_Export" --outdir "C:\HDBE" C:\HDBE\HTML_Brief.html', 'C:\Program Files\LibreOffice\program\swriter.exe',.T.) == 0
		// geht mit OpenOffice nicht!	IF	RunShell (' -headless -convert-to pdf:"writer_pdf_Export" C:\HDBE\HTML_Brief.html', 'C:\Program Files (x86)\OpenOffice 4\program\swriter.exe',.T.)
	//30.12.2022 15:36 statt sleep(300):
				dFDatum := Directory("C:\HDBE\HTML_Brief.pdf")[1,F_WRITE_DATE]		//02.01.2023 13:03
				cFZeit := Directory("C:\HDBE\HTML_Brief.pdf")[1,F_WRITE_TIME]
				nFZeit := Val(SubStr(cFZeit,1,2))*3600 + Val(SubStr(cFZeit,4,2))*60 + Val(SubStr(cFZeit,7,2))
				nZ := 0
				DO WHILE (nSZeit > nFZeit .OR. DATE() > dFDatum ) .AND. .NOT. nZ > 20
					sleep(100)
					cFZeit := Directory("C:\HDBE\HTML_Brief.pdf")[1,F_WRITE_TIME]
					nFZeit := Val(SubStr(cFZeit,1,2))*3600 + Val(SubStr(cFZeit,4,2))*60 + Val(SubStr(cFZeit,7,2))
					nZ++
				ENDDO

				IF nZ > 20
					msgbox("Achtung: Die PDF-DAtei ist vermutlich von einem frheren Fall!")
				ELSEIF FExists('C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe')
					RunShell (' /N C:\HDBE\HTML_Brief.pdf','C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe',.T.)
				ELSEIF FExists('C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe')
					RunShell (' /N C:\HDBE\HTML_Brief.pdf','C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe',.T.)
				ELSE
					msgbox("Der Adobe Reader DC ist nicht ordentlich installiert!")
				ENDIF
			ENDIF
		ELSE
			msgbox("LibreOffice ist nicht ordentlich installiert")
		ENDIF
	ELSE
		//26.08.2023 20:37 das muss in dieser Reihenfolge (lt. Alaska):
    	RunShell ( "c:\hdbe\HTML_Brief.html","c:\Program Files\LibreOffice\program\swriter.exe",.T.)	//01.09.2023 .T.
	ENDIF
   IF !Empty(cNotiz_Bez)
      cVermerk := ConvToOEMCP(cNotiz_Bez) + ": "+DtoC(DATE()) + ", " + BriefAdresse(2,"A")	// 2==1-zeilig, "A"==Ansprechpartner
	   IF !cVermerk$1->notiz
	      1->(DbRlock())
	      1->notiz += CRLF + cVermerk
	      1->(DbCommit())
	   ENDIF
	ENDIF
RETURN .T.

//27.11.2023 13:48 ab heute:
FUNCTION HTML_Brief( cFile, cFormular, cFont, cFSize, cFormSeite, cZeileCM, cNotiz_Bez )	//18.10.2022 cZeileMM -> cZeileCM // cNotiz_Bez
   LOCAL nZei := 8, nAnf, CR := Chr(13), LF := Chr(10)
   LOCAL nHandle, cBuffer, nBytes, cText, cNeuTxt := ""
   LOCAL cDatv := cDatver
   LOCAL nFSize, nFHoehe, nFBreite
   LOCAL nZeileMM
   LOCAL cSZeit, nSZeit, cFZeit, nFZeit, nZ	//30.12.2022 15:29 warten aufs PDF
   DEFAULT cFormular TO ""
   DEFAULT cFont TO '"Times New Roman", serif'
   DEFAULT cFSize TO '18pt'
   DEFAULT cFormSeite TO '1cm 1cm 1cm 2cm'
   DEFAULT cZeileCM TO '0.14'		//11.10.2022 14:58 Zeilenabstand
	PRIVATE cBuero					//11.10.2022 16:56 PRIVATE fr VariFunkErsatz
   nFSize := Val(cFSize)
   nFHoehe := nFSize * 0.352778
   nFBreite := nFSize * 0.2	// 0.2 ist ein gesch„tzter vorl„ufiger Wert 
   nZeileMM := IIf(Val(cZeileCM)<0.2, nFHoehe * Val(cZeileCM)*10, Val(cZeileCM)*10)
	
//	DO WHILE At("\",cDatv) > 0
//		cDatv := Stuff( cDatv, At("\",cDatv), 1, "/" )
//	ENDDO
	IF !"HDBE"$Upper(cFormular)
		cFormular := cDatv + cFormular
	ENDIF
	
	// Zur Vermeidung von Kollision verschiedener Drucke    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	// Test: ist bereits die Datei HTML_Brief.html auf diesem PC ge”ffnet?
	IF FExists("c:\hdbe\HTML_Brief.html")		//22.12.2022 19:13
		nHandle := FOpen( "c:\hdbe\HTML_Brief.html", FO_EXCLUSIVE )
		IF nHandle = -1
		   //+ Die Datei ist bereits auf diesem PC ge”ffnet
		   FClose(nHandle)
		   msgbox("Es ist bereits ein HTML_Brief.html offen!"+CR+LF+"Bitte OfficeWriter schlieáen, dann nochmal versuchen!")
		   RETURN .F.
		ELSE
		   FClose(nHandle)
		ENDIF
	ENDIF
	//--------------------------------
	// Test: ist bereits die Datei HTML_Brief.pdf auf diesem PC ge”ffnet?
	IF FExists("c:\hdbe\HTML_Brief.pdf")		//22.12.2022 19:13
		nHandle := FOpen( "c:\hdbe\HTML_Brief.pdf", FO_EXCLUSIVE )
		IF nHandle = -1
		   //+ Die Datei ist bereits auf diesem PC ge”ffnet
		   FClose(nHandle)
		   msgbox("Es ist bereits ein HTML_Brief.PDF offen!"+CR+LF+"Bitte AdobeReader schlieáen, dann nochmal versuchen!")
		   RETURN .F.
		ELSE
		   FClose(nHandle)
		ENDIF
	ENDIF
	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	IF Len(cFile) > 50
		cText := cFile
		cFile := "HTML_Brief"
	ELSE
	   nHandle := FOpen( cFile, FO_READ )
	   cBuffer := Space(3000)
	   nBytes := FRead( nHandle, @cBuffer, 3000 )
	   cText := AllTrim(cBuffer)
	   FClose( nHandle )
	ENDIF

	// Test mit automatischem Ausfllen bei bestimmtem Formular:
	IF "KSO_GhAusz.png"$cFormular
		cFont := "Times New Roman"
		cFSize := "14pt"
		cFormSeite := "0cm 0cm 0cm 0cm"
		nZeileMM := 4.9
		cText := CR+LF+CR+LF + Space(65) + "Auftrag: " + Str(1->auftrnr,6,0) + CR+LF+CR+LF+CR+LF+CR+LF+CR+LF+CR+LF
		cText += Space(35) + Trim(1->vorname) + " " + Trim(1->name) + CR+LF
	ENDIF         

	IF cFile == "c:\hdbe\dHTML.abr" .OR. cFile == "c:\hdbe\dHTML.mahn"
		cText := StrTran( cText, CR+LF+"     ", CR+LF )	// linken Rand zu NULL machen
	ENDIF

// vermutlich hier berflssig, weil schon in Inditext() 08.11.2022 10:42
   cBuero := SubStr(cBU5,At(" ",cBU5)+1)
   cRufnummer := cBU6

	IF 'Temp'$cFile	// 11.12.2022 17:14 wenn im Text Formatierungen vorkommen (bl_r,bl_a etc...)
	   cNeuTxt := ;
         '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'+CR+LF+;
         '<HTML>'+CR+LF+;
         '<HEAD>'+CR+LF+;
         '	<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">'+CR+LF+;
         '	<TITLE>'+cFile+'</TITLE>'+CR+LF+;
         '	<META NAME="GENERATOR" CONTENT="KSOX.EXE">'+CR+LF+;
         '	<META NAME="CHANGEDBY" CONTENT="' + cBuero + '">'+CR+LF+;
         '	<STYLE TYPE="text/css">'+CR+LF+;
         '	<!--'+CR+LF+;
         '		@page { size: 21cm 29.7cm; margin:  ' + cFormSeite + '; }'+CR+LF+;
         '		P { margin-bottom: 0.21cm }'+CR+LF+;
         '		P#cour { font-family: ' + cFont + '; }'+CR+LF+;
         '	-->'+CR+LF+;
         '	</STYLE>'+CR+LF+;
         '</HEAD>'+CR+LF+;
         IIf( Upper(Right(cFormular,4))==".PNG", ;
         '<BODY LANG="de-DE" BACKGROUND="'+cFormular+'" DIR="LTR" STYLE="background: url('+cFormular+') no-repeat middle center scroll">',;
         '<BODY LANG="de-DE">')+CR+LF+;
         '<PRE STYLE="margin-top:0;margin-bottom:0">'	//+CR+LF+;
	ELSE
	   cNeuTxt := ;
         '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'+CR+LF+;
         '<HTML>'+CR+LF+;
         '<HEAD>'+CR+LF+;
         '	<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">'+CR+LF+;
         '	<TITLE>'+cFile+'</TITLE>'+CR+LF+;
         '	<META NAME="GENERATOR" CONTENT="KSOX.EXE">'+CR+LF+;
         '	<META NAME="CHANGEDBY" CONTENT="' + cBuero + '">'+CR+LF+;
         '	<STYLE TYPE="text/css">'+CR+LF+;
         '	<!--'+CR+LF+;
         '		@page { size: 21cm 29.7cm; margin:  ' + cFormSeite + '; }'+CR+LF+;
         '		P { margin-bottom: 0.21cm }'+CR+LF+;
         '		P#cour { font-family: ' + cFont + '; }'+CR+LF+;
         '		PRE { font-family: ' + cFont + '; font-size: ' + cFSize + '; line-height: ' + LTrim(Str(nZeileMM/10)) + 'cm; }'+CR+LF+;
         '	-->'+CR+LF+;
         '	</STYLE>'+CR+LF+;
         '</HEAD>'+CR+LF+;
         IIf( Upper(Right(cFormular,4))==".PNG", ;
         '<BODY LANG="de-DE" STYLE="background: url('+cFormular+') no-repeat middle center scroll">'+CR+LF+;
         '<PRE STYLE="margin-top:0;margin-bottom:0cm">'+CR+LF+;
         '<FONT style=" font-family: ' + cFont + '; font-size: ' + cFSize + '; line-height: ' + LTrim(Str(nZeileMM/10)) + 'cm; ">', ;
         '<BODY LANG="de-DE">'+CR+LF+;
         '<PRE>' )
	ENDIF
	
   cNeuTxt += ConvToAnsiCP(cText)
         
   cNeuTxt += '</FONT></PRE></BODY></HTML>'

	cNeuTxt := StrTran( cNeuTxt, "</B>", "</B>       ")	// durch <> entstehen 7 Blanks
	
	IF !FExists("c:\hdbe\HTML_Brief.html")
		nHandle := FCreate("c:\hdbe\HTML_Brief.html")
		FClose(nHandle)
		Sleep(100)
	ENDIF
   nHandle := FOpen("c:\hdbe\HTML_Brief.html",FO_READWRITE)
   nBytes := FRead( nHandle, @cBuffer, 20000 )
   nBytes := Max(10000,nBytes)
   FSeek(nHandle, 0)
   nBytes := FWrite( nHandle, PadR(cNeuTxt,nBytes," ") )
   nBytes := FClose( nHandle )

	IF AppKeyState(65553)==1 .OR. "INPUT"$cNeuTxt	// zusammen mit Strg-Taste	//19.12.2022 15:13 mit LibreOffice zu PDF konvertieren
//geht nicht   	IF RunShell (' /C START C:\HDBE\swriter.libre.lnk --headless --convert-to pdf:"writer_pdf_Export" C:\HDBE\HTML_Brief.html',cComCom,.T.)
//geht nicht   	IF RunShell (" /C START C:\Progra~1\LibreOffice\program\swriter.exe --headless --convert-to pdf:'writer_pdf_Export' C:\HDBE\HTML_Brief.html",cComCom,.T.)
// so nicht! komplette Pfadangabe statt Link   	IF RunShell (' --headless --convert-to pdf:"writer_pdf_Export" --outdir "C:\HDBE" C:\HDBE\HTML_Brief.html', 'C:\HDBE\swriter.libre.lnk',.T.) == 0
		IF FExists('C:\Program Files\LibreOffice\program\swriter.exe')
			dHeute := DATE()		//02.01.2023 13:03
			cSZeit := Time()		//30.12.2022 15:36
			nSZeit := Val(SubStr(cSZeit,1,2))*3600 + Val(SubStr(cSZeit,4,2))*60 + Val(SubStr(cSZeit,7,2))
		  	IF RunShell (' --headless --convert-to pdf:"writer_pdf_Export" --outdir "C:\HDBE" C:\HDBE\HTML_Brief.html', 'C:\Program Files\LibreOffice\program\swriter.exe',.T.) == 0
		// geht mit OpenOffice nicht!	IF	RunShell (' -headless -convert-to pdf:"writer_pdf_Export" C:\HDBE\HTML_Brief.html', 'C:\Program Files (x86)\OpenOffice 4\program\swriter.exe',.T.)
	//30.12.2022 15:36 statt sleep(300):
				dFDatum := Directory("C:\HDBE\HTML_Brief.pdf")[1,F_WRITE_DATE]		//02.01.2023 13:03
				cFZeit := Directory("C:\HDBE\HTML_Brief.pdf")[1,F_WRITE_TIME]
				nFZeit := Val(SubStr(cFZeit,1,2))*3600 + Val(SubStr(cFZeit,4,2))*60 + Val(SubStr(cFZeit,7,2))
				nZ := 0
				DO WHILE (nSZeit > nFZeit .OR. DATE() > dFDatum ) .AND. .NOT. nZ > 20
					sleep(100)
					cFZeit := Directory("C:\HDBE\HTML_Brief.pdf")[1,F_WRITE_TIME]
					nFZeit := Val(SubStr(cFZeit,1,2))*3600 + Val(SubStr(cFZeit,4,2))*60 + Val(SubStr(cFZeit,7,2))
					nZ++
				ENDDO

				IF nZ > 20
					msgbox("Achtung: Die PDF-DAtei ist vermutlich von einem frheren Fall!")
				ELSEIF FExists('C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe')
					RunShell (' /N C:\HDBE\HTML_Brief.pdf','C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe',.T.)
				ELSEIF FExists('C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe')
					RunShell (' /N C:\HDBE\HTML_Brief.pdf','C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe',.T.)
				ELSE
					msgbox("Der Adobe Reader DC ist nicht ordentlich installiert!")
				ENDIF
			ENDIF
		ELSE
			msgbox("LibreOffice ist nicht ordentlich installiert")
		ENDIF
	ELSE
		//26.08.2023 20:37 das muss in dieser Reihenfolge (lt. Alaska):
    	RunShell ( "c:\hdbe\HTML_Brief.html","c:\Program Files\LibreOffice\program\swriter.exe",.T.)	//01.09.2023 .T.
	ENDIF
   IF !Empty(cNotiz_Bez)
      cVermerk := ConvToOEMCP(cNotiz_Bez) + ": "+DtoC(DATE()) + ", " + BriefAdresse(2,"A")	// 2==1-zeilig, "A"==Ansprechpartner
	   IF !cVermerk$1->notiz
	      1->(DbRlock())
	      1->notiz += CRLF + cVermerk
	      1->(DbCommit())
	   ENDIF
	ENDIF
RETURN .T.

//aus FUNCTION HTML_Brief fr Indiform()
//cOrdner = FormArt-Bezeichnung ohne .txt
//cMail_Adr = Mail-Adresse aus inditext.txt	19.11.2023 11:49
//cMail_Betr = Mail-Betreff aus inditext.txt	19.11.2023 11:49
FUNCTION HTML_Form( cContainer, cFormular, cFont, cFSize, cFormSeite, cZeileCM, cNotiz_Bez, cOrdner, cFile, cMail_Adr, cMail_Betr)	
   LOCAL nZei := 8, nAnf, CR := Chr(13), LF := Chr(10)
   LOCAL nHandle, cBuffer := Space(10000), nBytes, cText, cNeuTxt := ""
   LOCAL nFSize, nFHoehe, nFBreite
   LOCAL nZeileMM
   LOCAL cSZeit, nSZeit, cFZeit, nFZeit, nZ	//30.12.2022 15:29 warten aufs PDF
   LOCAL cHeute := DtoC(DATE())
   LOCAL oProgress	//26.10.2023 18:56
   LOCAL cMail_Body	//21.11.2023 09:47
   LOCAL cMailClient := cDatver+"ThunderbirdPortable\ThunderbirdPortable.exe"
   DEFAULT cFormular TO ""
   DEFAULT cFont TO '"Times New Roman", serif'
   DEFAULT cFSize TO '18pt'
   DEFAULT cFormSeite TO '1cm 1cm 1cm 2cm'
   DEFAULT cZeileCM TO '0.14'		//11.10.2022 14:58 Zeilenabstand
//	PRIVATE cAuftrOrdner := cDatver + "Indiform\AUFTRAG\" + StrZero(1->auftrnr,6,0)	// nur bei KSOX
	PRIVATE cAuftrOrdner := cDatver + "Scans\Dokumente\" + StrZero(1->auftrnr,6,0)	// im Ordner der gescannten Dokumente
   PRIVATE cFilehtml, cFilepdf
	PRIVATE cBuero						//11.10.2022 16:56 PRIVATE fr VariFunkErsatz
	PRIVATE cBetreff := cMail_Betr	//21.11.2023 10:09

   cMail_Body := VariFunkErsatz(MemoRead(cDatver+cFormular[1]+"\Body.txt"))	//21.11.2023 09:47

	
   nFSize := Val(cFSize)
   nFHoehe := nFSize * 0.352778
   nFBreite := nFSize * 0.2	// 0.2 ist ein gesch„tzter vorl„ufiger Wert 
   nZeileMM := IIf(Val(cZeileCM)<0.2, nFHoehe * Val(cZeileCM)*10, Val(cZeileCM)*10)
	
	IF ".txt"$cFile
		cFile := Stuff(cFile,At(".txt",cFile),4,"")	//06.09.2023 19:16
		IF "\"$cFile	//27.11.2023 12:03
			cFile := SubStr(cFile,3)		//27.11.2023 12:02
		ENDIF
	ENDIF
	cOrdner := "\" + cFile		//06.09.2023 19:16
	cAuftrOrdner += cOrdner		//06.09.2023 19:20
	
   IF !FExists( cAuftrOrdner,"D" )
      RunShell( "/C MD "+cAuftrOrdner,, .T. )
      sleep(100)
   ENDIF
   IF !FExists( cAuftrOrdner,"D" )
		msgbox("Der Ordner " + 	cAuftrOrdner + " kann nicht erzeugt werden!")
		RETURN .F.
	ENDIF
	
	cFilehtml := cAuftrOrdner + "\" + cFile + "_" + StrZero(1->auftrnr,6,0) + "_" + cHeute + ".html"
	cFilehtmlur := cAuftrOrdner + "\" + cFile + "_" + StrZero(1->auftrnr,6,0) + "_" + "*" + ".html"
	cFilepdf := cAuftrOrdner + "\" + cFile + "_" + StrZero(1->auftrnr,6,0) + "_" + cHeute + ".pdf"
	cFilepdfur := cAuftrOrdner + "\" + cFile + "_" + StrZero(1->auftrnr,6,0) + "_" + "*" + ".pdf"
	
	cFormular := Stuff(cFormular,At("\",cFormular),1,"/")
	aFormSize := FormSize(cFormular)	//02.11.2023 10:58	um portrait/landscape zu unterscheiden
	cFormular := '../../../../' + cFormular
	
	IF !"ORIGINAL.PDF"$Upper(cFormular)	//31.10.2023 19:00 wenn kein Original-PDF-Formular
		// Zur Vermeidung von Kollision verschiedener Drucke    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
		// Check: ist bereits die Datei cFilehtml auf diesem PC ge”ffnet?
		IF FExists(cFilehtml)		//22.12.2022 19:13
			nHandle := FOpen( cFilehtml, FO_EXCLUSIVE )
			IF nHandle = -1
			   //+ Die Datei ist bereits auf diesem PC ge”ffnet
			   FClose(nHandle)
			   msgbox("Es ist bereits ein " + cFilehtml + " offen!"+CR+LF+;
			   			"Bitte " + cFilehtml + " im OfficeWriter schlieáen, dann nochmal versuchen!")
			   RETURN .F.
			ELSEIF ConfirmBox( oCB, "Soll sie berschrieben werden?", ;
	                        "Diese Datei ist schon vorhanden mit Datum von heute!", ;
	                        XBPMB_YESNO, ;
	                        XBPMB_QUESTION ) == XBPMB_RET_YES
			   FClose(nHandle)
			ELSE 
			   FClose(nHandle)
			   RETURN .F.
			ENDIF
		ELSEIF FExists(cFilehtmlur)		//06.09.2023 11:25
	      aHtmlFiles := Directory( cFilehtmlur )
			ASort(aHtmlFiles,,,{|aX,aY|aX[3]>aY[3]})		//absteigend sortiert nach WriteDatum
			cHFDatum := SubStr(aHtmlFiles[1,1],RAt("_",aHtmlFiles[1,1])+1,10)	// bisher neueste Datei dieser Art
					
			IF ConfirmBox( oCB, "Soll sie heute nochmal erzeugt werden?", ;
	                        "Diese Datei ist schon vorhanden mit Datum vom "+cHFDatum+"!", ;
	                        XBPMB_YESNO, ;
	                        XBPMB_QUESTION ) == XBPMB_RET_YES
			ELSE
				cFilehtml := Stuff(cFilehtmlur,RAt("_",cFilehtmlur)+1,1,cHFDatum)
				cFilepdf := Stuff(cFilepdfur,RAt("_",cFilepdfur)+1,1,cHFDatum)
			ENDIF
		ENDIF
		//--------------------------------
		
		// Test: ist bereits die Datei cFilepdf auf diesem PC ge”ffnet?
		IF FExists(cFilepdf)		//22.12.2022 19:13
			nHandle := FOpen( cFilepdf, FO_EXCLUSIVE )
			IF nHandle = -1
			   //+ Die Datei ist bereits auf diesem PC ge”ffnet
			   FClose(nHandle)
			   msgbox("Es ist bereits eine Datei " + cFilepdf + " offen!"+CR+LF+;
			   			"Bitte AdobeReader schlieáen, dann nochmal versuchen!")
			   RETURN .F.
			ELSE
			   FClose(nHandle)
			ENDIF
		ENDIF
	ELSE		//31.10.2023 19:06 nur fr ORIGINAL.PDF-Formulare: (sofort darstellen)
		cFilepdf := SubStr(cFormular,13)
		IF FExists('C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe')
			RunShell ("&cFilepdf","C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe",.T.)
		ELSEIF FExists('C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe')
			RunShell ("&cFilepdf","C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe",.T.)
		ELSE
			msgbox("Der Adobe Reader DC ist nicht ordentlich installiert!")
			RETURN .F.
		ENDIF
	   IF !Empty(cNotiz_Bez)
	      cVermerk := ConvToOEMCP(cNotiz_Bez) + ": "+DtoC(DATE()) + ", " + BriefAdresse(2,"A")	// 2==1-zeilig, "A"==Ansprechpartner
		   IF !cVermerk$1->notiz
		      1->(DbRlock())
		      1->notiz += CRLF + cVermerk
		      1->(DbCommit())
		   ENDIF
		ENDIF
		RETURN .T.
	ENDIF
	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

   cBuero := SubStr(cBU5,At(" ",cBU5)+1)
   cRufnummer := cBU6

	//die Version mit Temp drfte hier eigentlich nie vorkommen ... (06.09.2023 11:28)
	IF 'Temp'$cFile	// 11.12.2022 17:14 wenn im Text Formatierungen vorkommen (bl_r,bl_a etc...)
	   cNeuTxt := ;
         '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'+CR+LF+;
         '<HTML>'+CR+LF+;
         '<HEAD>'+CR+LF+;
         '	<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">'+CR+LF+;
         '	<TITLE>'+cFile+'</TITLE>'+CR+LF+;
         '	<META NAME="GENERATOR" CONTENT="KSOX.EXE">'+CR+LF+;
         '	<META NAME="CHANGEDBY" CONTENT="' + cBuero + '">'+CR+LF+;
         '	<STYLE TYPE="text/css">'+CR+LF+;
         '	<!--'+CR+LF+;
         '		@page { size: '+aFormSize[1]+' '+aFormSize[2]+'; margin:  ' + cFormSeite + '; }'+CR+LF+;
         '		P { margin-bottom: 0.21cm }'+CR+LF+;
         '		P#cour { font-family: ' + cFont + '; }'+CR+LF+;
         '	-->'+CR+LF+;
         '	</STYLE>'+CR+LF+;
         '</HEAD>'+CR+LF+;
         IIf( Upper(Right(cFormular,4))==".PNG", ;
         '<BODY LANG="de-DE" BACKGROUND="'+cFormular+'" DIR="LTR" STYLE="background: url('+cFormular+') no-repeat middle center scroll">',;
         '<BODY LANG="de-DE">')+CR+LF+;
         '<PRE STYLE="margin-top:0;margin-bottom:0">'	//+CR+LF+;
	ELSEIF !"<INPUT"$Upper(cContainer) 	//27.11.2023 14:31 als Brief, nicht als Formular mit Input
	   cNeuTxt := ;
         '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'+CR+LF+;
         '<HTML>'+CR+LF+;
         '<HEAD>'+CR+LF+;
         '	<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">'+CR+LF+;
         '	<TITLE>'+cFile+'</TITLE>'+CR+LF+;
         '	<META NAME="GENERATOR" CONTENT="KSOX.EXE">'+CR+LF+;
         '	<META NAME="CHANGEDBY" CONTENT="' + cBuero + '">'+CR+LF+;
         '	<STYLE TYPE="text/css">'+CR+LF+;
         '	<!--'+CR+LF+;
         '		@page { size: 21cm 29.7cm; margin:  ' + cFormSeite + '; }'+CR+LF+;
         '		P { margin-bottom: 0.21cm }'+CR+LF+;
         '		P#cour { font-family: ' + cFont + '; }'+CR+LF+;
         '		PRE { font-family: ' + cFont + '; font-size: ' + cFSize + '; line-height: ' + LTrim(Str(nZeileMM/10)) + 'cm; }'+CR+LF+;
         '	-->'+CR+LF+;
         '	</STYLE>'+CR+LF+;
         '</HEAD>'+CR+LF+;
         IIf( Upper(Right(cFormular,4))==".PNG", ;
         '<BODY LANG="de-DE" STYLE="background: url('+cFormular+') no-repeat middle center scroll">'+CR+LF+;
         '<PRE STYLE="margin-top:0;margin-bottom:0cm">'+CR+LF+;
         '<FONT style=" font-family: ' + cFont + '; font-size: ' + cFSize + '; line-height: ' + LTrim(Str(nZeileMM/10)) + 'cm; ">', ;
         '<BODY LANG="de-DE">'+CR+LF+;
         '<PRE>' )
	ELSE
	   cNeuTxt := ;
         '<!DOCTYPE HTML>'+CR+LF+;
         '<HTML LANG="de-DE">'+CR+LF+;
         '<HEAD>'+CR+LF+;
         '	<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">'+CR+LF+;
         '	<TITLE>'+cFile+'</TITLE>'+CR+LF+;
         '	<META NAME="GENERATOR" CONTENT="KSOX.EXE">'+CR+LF+;
         '	<META NAME="CHANGEDBY" CONTENT="' + cBuero + '">'+CR+LF+;
         '	<META NAME="VIEWPORT" CONTENT="width=device-width, initial-scale=1.0">'+CR+LF+;
         '	<STYLE TYPE="text/css">'+CR+LF+;
         '		@page { size: '+aFormSize[1]+' '+aFormSize[2]+'; margin:  ' + cFormSeite + '; }}'+CR+LF+;
         '		P { line-height:100%;margin:0; }'+CR+LF+;
         '		P#cour { font-family: ' + cFont + '; }'+CR+LF+;
         '		PRE { font-family: ' + cFont + '; font-size: ' + cFSize + '; line-height: ' + cZeileCM + '; }'+CR+LF+;
			'		DIV { position:absolute; }'+CR+LF+;
			'		FORM { margin:0;padding:0;border:0px; }'+CR+LF+;
         '	</STYLE>'+CR+LF+;
         '</HEAD>'+CR+LF+;
         IIf( Upper(Right(cFormular,4))==".PNG", ;
			'<BODY LANG="de-DE" STYLE="min-width:'+aFormSize[1]+';min-height:'+aFormSize[2]+';border:none;padding:0px;margin:0px;">'+CR+LF+;
			'<PRE STYLE="margin:0px;padding:0px;border:none;font-family:'+cFont+';font-size:'+cFSize+';line-height:'+cZeileCM+';">'+CR+LF+;
			'<FORM NAME="Formular" action="mailto:'+cMail_Adr+'?subject='+cMail_Betr+'">'+CR+LF+;		// (body &) attachment geht bei mailto nicht !!
			'<DIV id="Rahmen1" STYLE="position:relative;width:'+aFormSize[1]+';height:'+aFormSize[2]+';margin:0px;padding:0px;border:none;background-color:transparent;">'+CR+LF+;
			'<div style="position:absolute;top:0;left:0;width:'+aFormSize[1]+';height:'+aFormSize[2]+';margin:0px;padding:0px;border:none;background-color:transparent;">'+CR+LF+;
			'<img src="'+cFormular+'" alt="Bild1" style="position:absolute;margin:0px;padding:0px;border:none;width:'+aFormSize[1]+';height:'+aFormSize[2]+';" title="Seite1" /></div>'+CR+LF, ;
			'<BODY LANG="de-DE">'+CR+LF+;
			'<PRE>' )

	ENDIF
//			'<FORM NAME="Formular" action="mailto:adebar@storch.xx?subject=BETREFF&body=BODY&attachment=ANHANG">'+CR+LF+;
//			'<FORM NAME="Formular" action="mailto:'+cMail_Adr+'?subject='+cMail_Betr+'&body='+cMail_Body+'&attachment='+cFilePDF+'">'+CR+LF+;

   cNeuTxt += ConvToAnsiCP(cContainer)
	IF !"<INPUT"$Upper(cContainer) 	//27.11.2023 14:27 als Brief, nicht als Formular mit Input
   	cNeuTxt += '</FONT></PRE></BODY></HTML>'
	ELSE
	   cNeuTxt += '</DIV>'		//24.10.2023 09:52
   	cNeuTxt += '</FORM></PRE></BODY></HTML>'
	ENDIF
	IF !FExists(cFilehtml)
		nHandle := FCreate(cFilehtml)
		FClose(nHandle)
		Sleep(100)
	ENDIF
//   nHandle := FOpen(cFilehtml,FO_READWRITE)
//   nBytes := FRead( nHandle, @cBuffer, 40000 )
//   nBytes := Max(40000,nBytes)
//   FSeek(nHandle, 0)
//   nBytes := FWrite( nHandle, PadR(cNeuTxt,nBytes," ") )
//   nBytes := FClose( nHandle )
//	sleep(50)
//
   nHandle := FCreate(cFilehtml)
   nBytes := FWrite( nHandle, cNeuTxt )
   nBytes := FClose( nHandle )
	sleep(50)
	
	IF AppKeyState(65553)==1 .OR. "INPUT"$Upper(cNeuTxt)	// zusammen mit Strg-Taste	//19.12.2022 15:13 mit LibreOffice zu PDF konvertieren
		IF FExists('C:\Program Files\LibreOffice\program\swriter.exe')
			dHeute := DATE()		//02.01.2023 13:03
			cSZeit := Time()		//30.12.2022 15:36
			nSZeit := Val(SubStr(cSZeit,1,2))*3600 + Val(SubStr(cSZeit,4,2))*60 + Val(SubStr(cSZeit,7,2))

      //+26.10.2023 18:57 Fortschrittsanzeige
      oProgress := ProgressBar():new( AppDeskTop(),, {400,350}, {AppDeskTop():currentsize()[1]-800,24},, .F. )
      oProgress:create()
      oProgress:color   := GRA_CLR_GREEN
      oProgress:minimum := 1
      oProgress:maximum := 20

//		  	IF RunShell (' --headless --convert-to pdf:"writer_pdf_Export:{\"PageRange\":{\"type\":\"string\",\"value\":\"1-\"}}" --outdir "&cAuftrOrdner" &cFilehtml', 'C:\Program Files\LibreOffice\program\swriter.exe',.T.) == 0
			IF RunShell (' --headless --convert-to pdf:"writer_pdf_Export" --outdir "&cAuftrOrdner" &cFilehtml', 'C:\Program Files\LibreOffice\program\swriter.exe',.T.) == 0
				IF Len(Directory(cFilepdf)) > 0		// gibt es diese Datei schon mit frherem Zeitstempel von heute?:
					dFDatum := Directory(cFilepdf)[1,F_WRITE_DATE]		//02.01.2023 13:03
					cFZeit := Directory(cFilepdf)[1,F_WRITE_TIME]
					nFZeit := Val(SubStr(cFZeit,1,2))*3600 + Val(SubStr(cFZeit,4,2))*60 + Val(SubStr(cFZeit,7,2))
					nZ := 0

                  oProgress:increment()      //+26.10.2023 18:59

					DO WHILE (nSZeit > nFZeit .OR. DATE() > dFDatum ) .AND. .NOT. nZ > 20
						sleep(100)
						dFDatum := Directory(cFilepdf)[1,F_WRITE_DATE]		//02.01.2023 13:03
						cFZeit := Directory(cFilepdf)[1,F_WRITE_TIME]
						nFZeit := Val(SubStr(cFZeit,1,2))*3600 + Val(SubStr(cFZeit,4,2))*60 + Val(SubStr(cFZeit,7,2))
						nZ++

                  oProgress:increment()      //+26.10.2023 18:59

					ENDDO
				ELSE		//05.10.2023 18:14 jetzt Schleife fr erste Datei des Tages
					nZ := 0
					DO WHILE Len(Directory(cFilepdf)) == 0 .AND. .NOT. nZ > 20
                  oProgress:increment()      //+27.11.2023 14:35
						sleep(50)
						nZ++
					ENDDO
				ENDIF

         oProgress:destroy()      //+26.10.2023 18:59
				
				IF nZ > 20
					msgbox("Achtung: Die PDF-DAtei ist vermutlich von einem frheren Fall!")
//				ELSEIF FExists('C:\Program Files\LibreOffice\program\sdraw.exe')
//					RunShell ("&cFilehtml","C:\Program Files\LibreOffice\program\sdraw.exe",.T.)
				ELSEIF FExists('C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe')
					RunShell ("&cFilepdf","C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe",.T.)
				ELSEIF FExists('C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe')
					RunShell ("&cFilepdf","C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe",.T.)
				ELSE
					msgbox("Der Adobe Reader DC ist nicht ordentlich installiert!")
				ENDIF
			ENDIF
		ELSE
			msgbox("LibreOffice ist nicht ordentlich installiert")
		ENDIF
	ELSE
		//26.08.2023 20:37 das muss in dieser Reihenfolge (lt. Alaska):
		RunShell ( "&cFilehtml","c:\Program Files\LibreOffice\program\swriter.exe")
	ENDIF

	//21.11.2023 16:23 Mail mit Anhang senden aus dem Programm, weil ...
	//						... weil mit mailto: aus dem Formular kein Attachment zu mailen geht!!
	IF ConfirmBox( oCB, "Ggf. vorher ausfllen und dann:"+CRLF+;
							"mailen = Ja --- abbrechen = NEIN", ;
                     "M”chten Sie das Formular mailen an "+cMail_Adr+"?", ;
                     XBPMB_YESNO, ;
                     XBPMB_QUESTION ) == XBPMB_RET_YES
//27.11.2023 12:35  vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
		IF !"INPUT"$Upper(cNeuTxt)
			dHeute := DATE()		//02.01.2023 13:03
			cSZeit := Time()		//30.12.2022 15:36
			nSZeit := Val(SubStr(cSZeit,1,2))*3600 + Val(SubStr(cSZeit,4,2))*60 + Val(SubStr(cSZeit,7,2))

	//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//	//27.11.2023 18:39 die gerade im Writer ge„nderte HTML-Datei bis auf </HTML> krzen:^
//   nHandle := FOpen(cFilehtml,FO_READWRITE)
//   nBytes := FSize(nHandle)
//   cBuffer := Space(nBytes)
//   nBytes := FRead( nHandle, @cBuffer, nBytes )
////   nBytes := IIf(Empty(cBuffer),40000,Len(cBuffer))	//Max(40000,nBytes)
//   FSeek(nHandle, 0)
//   IF !Empty(cBuffer)
//	   cBuffer := SubStr(cBuffer,1,At("</HTML>",cBuffer)+7)
////   	nBytes := FWrite( nHandle, PadR(cBuffer,nBytes," ") )
//		FClose(nHandle)
//   	nHandle := FCreate(cFilehtml)
//		nBytes := FWrite( nHandle, cBuffer, Len(cBuffer) )
//   ENDIF
//   nBytes := FClose( nHandle )
//	sleep(50)
   nHandle := FCreate(cFilehtml)
   nBytes := FWrite( nHandle, cNeuTxt )
   nBytes := FClose( nHandle )
	sleep(50)
			////cFilehtml := Stuff(cFilehtml,At(".html",Upper(cFilehtml)),4,".odt")
//	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	      //+26.10.2023 18:57 Fortschrittsanzeige
	      oProgress := ProgressBar():new( AppDeskTop(),, {400,350}, {AppDeskTop():currentsize()[1]-800,24},, .F. )
	      oProgress:create()
	      oProgress:color   := GRA_CLR_GREEN
	      oProgress:minimum := 1
	      oProgress:maximum := 20
			RunShell (' --headless --convert-to pdf:"writer_pdf_Export" --outdir "&cAuftrOrdner" &cFilehtml', 'C:\Program Files\LibreOffice\program\swriter.exe',.T.)
				IF Len(Directory(cFilepdf)) > 0		// gibt es diese Datei schon mit frherem Zeitstempel von heute?:
					dFDatum := Directory(cFilepdf)[1,F_WRITE_DATE]		//02.01.2023 13:03
					cFZeit := Directory(cFilepdf)[1,F_WRITE_TIME]
					nFZeit := Val(SubStr(cFZeit,1,2))*3600 + Val(SubStr(cFZeit,4,2))*60 + Val(SubStr(cFZeit,7,2))
					nZ := 0

                  oProgress:increment()      //+26.10.2023 18:59

					DO WHILE (nSZeit > nFZeit .OR. DATE() > dFDatum ) .AND. .NOT. nZ > 20
						sleep(100)
						dFDatum := Directory(cFilepdf)[1,F_WRITE_DATE]		//02.01.2023 13:03
						cFZeit := Directory(cFilepdf)[1,F_WRITE_TIME]
						nFZeit := Val(SubStr(cFZeit,1,2))*3600 + Val(SubStr(cFZeit,4,2))*60 + Val(SubStr(cFZeit,7,2))
						nZ++

                  oProgress:increment()      //+26.10.2023 18:59

					ENDDO
				ELSE		//05.10.2023 18:14 jetzt Schleife fr erste Datei des Tages
					nZ := 0
					DO WHILE Len(Directory(cFilepdf)) == 0 .AND. .NOT. nZ > 20
                  oProgress:increment()      //+27.11.2023 14:35
						sleep(50)
						nZ++
					ENDDO
				ENDIF
         oProgress:destroy()      //+26.10.2023 18:59
		ENDIF
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	   Runshell( [-compose "to=']+cMail_Adr+[',subject=']+cMail_Betr+[',body=']+cMail_Body+[',attachment=']+cFilePDF+['"], cMailClient, .T. ) //18.09.2020 09:39 von .F. auf .T., weil bei Sonnex Vorschau einfriert...
	ELSE 
		RETURN .T.
	ENDIF

   IF !Empty(cNotiz_Bez)
      cVermerk := ConvToOEMCP(cNotiz_Bez) + ": "+DtoC(DATE()) + ", " + BriefAdresse(2,"A")	// 2==1-zeilig, "A"==Ansprechpartner
	   IF !cVermerk$1->notiz
	      1->(DbRlock())
	      1->notiz += CRLF + cVermerk
	      1->(DbCommit())
	   ENDIF
	ENDIF
RETURN .T.

//19.01.2023 12:39 aus der Knowledgebase -- wird hier aber tats„chlich NICHT gebraucht
// LongFilename2ShortFilename
FUNCTION Lfn2Sfn(cLfn)
LOCAL cSfn := space(len(clfn)+1)
LOCAL nsfn
    IF Set(_SET_CHARSET) == CHARSET_OEM
        cLfn := ConvToAnsiCp(cLfn)
    ENDIF
    nsfn := DllCall("Kernel32.dll",DLL_STDCALL, "GetShortPathNameA", ;
                     cLfn, @cSfn, len(cSfn)-1)
    cSfn := Left(cSfn, nsfn)
RETURN cSfn

//07.10.2022 18:00 Zeichenkette-Liste aus Inditext.txt in Array aLines bertragen
//						die Parameter cFile etc. in einer Array-Zeile ausw„hlen
//						die betreffende Textdatei cFile mit MemoRead einlesen
//						die Variablen mit VariFunkErsatz im Text einsetzen
//						den Text ber HTML_Brief ausdrucken
FUNCTION Inditext(oDlg1,cFAV)		//12.09.2023 11:31 cFAV Fall/Adressen/Versicherung (identifiziert den Knopf F\ A\ V\)
	LOCAL cTexte := MemoRead(cDatver+cFAV+"Inditext.txt")
	LOCAL nMaxLines := MlCount(cTexte, 90)
	LOCAL aLines[nMaxLines], n
	LOCAL aParam := {}, nPosition
	LOCAL cFile, cFormular, cFont := '"Consolas", monospace', cFSize := '12pt', cFormSeite := '1cm 1cm 1cm 2cm', cZeileCM := '0.49cm'	// 28.10.2022 cZeileMM -> cZeileCM
	LOCAL cContainer := ""
	LOCAL cNotiz_Bez := ""
	LOCAL cMail_Adr := "Adresse von Hand eingeben"		//19.11.2023 11:43
	LOCAL cMail_Betr := ConvToAnsiCP("Formular fr Sterbefall")		//19.11.2023 11:43
	LOCAL nTxtnr := 0
	LOCAL CR := Chr(13), LF := Chr(10)
	PRIVATE cBuero					//11.10.2022 16:56 PRIVATE fr VariFunkErsatz
	PRIVATE cRufnummer := "0208 631349"	//11.10.2022 16:56 PRIVATE fr VariFunkErsatz
	PRIVATE cHeute := DtoC(DATE())

   cBuero := SubStr(cBU5,At(" ",cBU5)+1)
   cRufnummer := cBU6
	
	FOR n := 1 TO nMaxLines
		aLines[n] := Trim(MemoLine(cTexte, 200, n))
	NEXT

//	nTxtnr := ButtonFenster(aLines, oDlg1)	// in best4f.prg - zur Auswahl des Formulars in inditext.txt 
	nTxtnr := ListboxFenster(aLines, oDlg1, @cFormName)	// in best4f.prg - zur Auswahl des Formulars in inditext.txt 
	IF Empty(nTxtnr)
		RETURN .F.
	ENDIF
	cText := aLines[nTxtnr]

	DO WHILE (nPosition := At("," , cText)) > 0
		AAdd(aParam, SubStr(cText, 1, nPosition-1))
		cText := SubStr(cText, nPosition+1)
	ENDDO
	IF Len(cText) > 0
		AAdd(aParam, cText)
	ENDIF
	
	cFile := cFAV+aParam[1]		//12.09.2023 12:31 cFAV - cFile f„ngt dann an mit z.B. "F\"
	IIf(Len(aParam) > 1,	cFormular := cFAV+aParam[2], )	//12.09.2023 12:31 cFAV - cFormular f„ngt dann an mit z.B. "F\"
	IIf(Len(aParam) > 2,	cFont := aParam[3], )
	IIf(Len(aParam) > 3,	cFSize := aParam[4], )
	IIf(Len(aParam) > 4,	cFormSeite := aParam[5], )
	IIf(Len(aParam) > 5,	cZeileCM := aParam[6], )
	IIf(Len(aParam) > 6,	cNotiz_Bez := aParam[7], )
	IIf(Len(aParam) > 7,	cMail_Adr := aParam[8], )		//19.11.2023 11:40
	IIf(Len(aParam) > 8,	cMail_Betr := aParam[9], )		//19.11.2023 11:40

	//21.11.2023 18:25 5->VERSKZ statt cMail_Adr in der inditext.txt: 
	IF  !"@"$cMail_Adr .AND. Len(cMail_Adr) < 6 
		IF 5->(DbSeek(cMail_Adr,.F.))
			cMail_Adr := 5->email
		ENDIF
	ENDIF

	IF AppKeyState(65554)==1	// zusammen mit ALT-Taste
	   ? RunShell (" /C START Notepad "+cDatver+cFAV+"inditext.txt",cComCom,.T.)	//12.09.2023 12:30 cFAV
	   ? RunShell (" /C START Notepad "+cDatver+cFile,cComCom,.T.)
	   cFileText := MemoRead(cDatver+cFile)
	   IF (")"+CR)$cFileText .OR. (")"+LF)$cFileText
	   	msgbox("Nach den Variablen unbedingt einen Leerschritt einbauen!")
	   ENDIF
	   RETURN .F.
	ENDIF

//30.10.2023 18:44 PDF-Formular in PNG umwandeln (nur einmalig beim ersten Mal)  vvvvvvvvvvvvvvvvvvvvvvv
	IF ".PDF"$Upper(cFormular) .AND. !"ORIGINAL.PDF"$Upper(cFormular)
		cFormularPNG := Stuff(cFormular,At(".PDF",Upper(cFormular)),4,".PNG")
		IF !FExists(cFormularPNG)
			cFormularPDF := cFormular
			xyz := RunShell (' --headless --convert-to png --outdir "F" &cFormularPDF', 'C:\Program Files\LibreOffice\program\sdraw.exe',.T.)
	//	  	xyz := RunShell (' --headless --convert-to png:"writer_png_Export:{\"PageRange\":{\"type\":\"string\",\"value\":\"2\"}}" --outdir "F" &cFormularPDF', 'C:\Program Files\LibreOffice\program\sdraw.exe',.T.)
			msgbox(cFormularPDF + " wird in eine PNG_Datei umgewandelt.")
			IF !FExists(cFormularPNG)
				msgbox("Umwandeln in PNG-Datei hat nicht geklappt!")
			ELSE
				cFormular := cFormularPNG
			ENDIF
		ELSE
			cFormular := cFormularPNG
		ENDIF
	ENDIF
//31.10.2023 09:22 DOC-Formular in PNG umwandeln (nur einmalig beim ersten Mal)  vvvvvvvvvvvvvvvvvvvvvvv
	IF ".DOC"$Upper(cFormular)
		cFormularPNG := Stuff(cFormular,At(".DOC",Upper(cFormular)),4,".PNG")
		IF !FExists(cFormularPNG)
			cFormularDOC := cFormular
			xyz := RunShell (' --headless --convert-to png --outdir "F" &cFormularDOC', 'C:\Program Files\LibreOffice\program\swriter.exe',.T.)
			msgbox(cFormularDOC + " wird in eine PNG_Datei umgewandelt.")
			IF !FExists(cFormularPNG)
				msgbox("Umwandeln in PNG-Datei hat nicht geklappt!")
			ELSE
				cFormular := cFormularPNG
			ENDIF
		ELSE
			cFormular := cFormularPNG
		ENDIF
	ENDIF
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	IF Val(cZeileCM) == 0
		cFileInhalt := ConvToOEMCP(MemoRead(cDatver+cFile))	// wenn cFile nicht mit KSOX erzeugt wurde, dann kein ConvToOEMCP
//		cFile := MemoRead(cFile)	// wenn cFile nicht mit KSOX erzeugt wurde, dann kein ConvToOEMCP
		cContainer := VariFunkErsatz(cFileInhalt)	// in cFileInhalt steckt jetzt der komplette Text (nicht nur der Filename!)
	ELSE
		cFileInhalt := ConvToOEMCP(MemoRead(cDatver+cFile))	// den Formular-Text mit den eingebauten Variablen in cFile einlesen
		cFileInhalt := VariPosition(cFileInhalt,@cContainer, cFont, cFSize, cFormSeite, cZeileCM, cFile)	// in cFileInhalt steckt jetzt der komplette Text (nicht nur der Filename!)
	// in cContainer (== BriefText) werden von der Fkt. VariPosition() alle Variablen im Text positioniert bergeben.
	ENDIF
	IF AppKeyState(65552)==1	// zusammen mit Shift-Taste
//	IF Val(aParam[5])>0 .OR. AppKeyState(65552)==1	// zusammen mit Shift-Taste	27.11.2023 10:52 aParam[5]=cFormSeite
		RETURN HTML_Brief(cContainer, cFormular, cFont, cFSize, cFormSeite, cZeileCM, cNotiz_Bez)
	ELSE
//		RETURN HTML_Form(cContainer, cFormular, cFont, cFSize, cFormSeite, cZeileCM, cNotiz_Bez, "", cFile)
		RETURN HTML_Form(cContainer, cFormular, cFont, cFSize, cFormSeite, cZeileCM, cNotiz_Bez, "", cFile, cMail_Adr, cMail_Betr)	//19.11.2023 11:47
	ENDIF
RETURN .F.	//11.09.2023 16:48


//07.10.2022 18:00 Zeichenkette-Liste aus Inditext.txt in Array aLines bertragen
//						die Parameter cFile etc. in einer Array-Zeile ausw„hlen
//						die betreffende Textdatei cFile mit MemoRead einlesen
//						die Variablen mit VariFunkErsatz im Text einsetzen
//						den Text ber HTML_Brief ausdrucken
FUNCTION Indiform(oDlg1)
	LOCAL cTexte := MemoRead(cDatver+"Indiform\Indiform.txt")
	LOCAL nMaxLines := MlCount(cTexte, 90)
	LOCAL aLines[nMaxLines], n
	LOCAL aParam := {}, nPosition
	LOCAL cFile, cFormular, cFont := '"Consolas", monospace', cFSize := '12pt', cFormSeite := '1cm 1cm 1cm 2cm', cZeileCM := '0.49cm'	// 28.10.2022 cZeileMM -> cZeileCM
	LOCAL cContainer := ""
	LOCAL cNotiz_Bez := ""
	LOCAL nTxtnr := 0, cFormName, nFormN, aFormName:={}		//17.03.2023 18:38 cFormName
	LOCAL CR := Chr(13), LF := Chr(10)
	PRIVATE cBuero					//11.10.2022 16:56 PRIVATE fr VariFunkErsatz
	PRIVATE cRufnummer := "0208 631349"	//11.10.2022 16:56 PRIVATE fr VariFunkErsatz
	PRIVATE cHeute := DtoC(DATE())

   cBuero := SubStr(cBU5,At(" ",cBU5)+1)
   cRufnummer := cBU6
	
	FOR n := 1 TO nMaxLines
		aLines[n] := Trim(MemoLine(cTexte, 110, n))
	NEXT


	// holt die Auswahl aller Formular-Arten in Indiform.txt
	nTxtnr := ListboxFenster(aLines, oDlg1, @cFormName)	// in best4f.prg - zur Auswahl des Formulars in indiform.txt 
	IF Empty(nTxtnr)
		RETURN .F.
	ENDIF

	// holt den Dateinamen aus cFormName vvvvvvvvvvvvvvvvvvvvvvvv
	// wie bei php: aPosition = explode(cPosition)
	DO WHILE (nFormN := At("," , cFormName)) > 0
		AAdd(aFormName, SubStr(cFormName, 1, nFormN-1))
		cFormName := SubStr(cFormName, nFormN+1)
	ENDDO
	IF Len(cFormName) > 0
		AAdd(aFormName, cFormName)
	ENDIF

	IF ".txt"$aFormName[1]
		cFormName := aFormName[1]
		aFormName[1] := SubStr(cFormName,1,At(".txt",cFormName)-1)	// der Ordner der Formular-Art
	ELSE
		cFormName = aFormName[1] + ".txt"									// das txt-Formular
	ENDIF

	// ALT-Klick: die betroffenen txt-Dateien in den Editor laden:
	IF AppKeyState(65554)==1	// zusammen mit ALT-Taste
	   ? RunShell (" /C START Notepad "+cDatver+"Indiform\"+aFormName[1]+"\"+cFormName,cComCom,.T.)
	   ? RunShell (" /C START Notepad "+cDatver+"Indiform\Indiform.txt",cComCom,.T.)
	   RETURN .F.
	ENDIF


	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	// erzeugt das Verzeichnis fr die Formular-Art, wenn noch nicht vorhanden vvvvvvvvvvvvvvv
   IF !FExists( cDatver + "Indiform\" + aFormName[1],"D" )
		IF ConfirmBox( oCB, "Soll er angelegt werden?", ;
                        "Ordner Indiform\"+aFormName[1]+" ist noch nicht vorhanden!", ;
                        XBPMB_YESNO, ;
                        XBPMB_QUESTION ) == XBPMB_RET_YES
         RunShell( "/C MD "+cDatver + "Indiform\" + aFormName[1],, .T. )
         sleep(50)
      ENDIF
		IF FExists( cDatver + "Indiform\" + aFormName[1],"D" ) .AND. ConfirmBox( oCB, "Fertig mit Fllen?", ;
                        "Ordner Indiform\"+aFormName[1]+" jetzt mit txt-Formularen fllen!", ;
                        XBPMB_YESNO, ;
                        XBPMB_QUESTION ) == XBPMB_RET_NO
      	RETURN .F.
      ENDIF
      IF !FExists(cDatver + "Indiform\" + aFormName[1] + "\" + cFormName)
      	msgbox("Datei "+cDatver + aFormName[1] + "\" + cFormName + " existiert nicht!")
      	RETURN .F.
      ENDIF
   ENDIF
	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

	// liest die txt-Datei dieser Formular-Art mit all deren Formularen vvvvvvvvvvvvvvvvvvvvvv
	cTexte := MemoRead(cDatver + "Indiform\" + aFormName[1] + "\" + cFormName)
	nMaxLines := MlCount(cTexte, 90)
	aLines := Array(nMaxLines)
	FOR n := 1 TO nMaxLines
		aLines[n] := Trim(MemoLine(cTexte, 110, n))
	NEXT

	// holt die Auswahl aller Formulare dieser Art
	nTxtnr := ListboxFenster(aLines, oDlg1, @cFormName)	// in best4f.prg - zur Auswahl des Formulars in aFormName[1] 
	IF Empty(nTxtnr)
		RETURN .F.
	ENDIF
	// liest die gew„hlte Zeile in cText ein:
	cText := aLines[nTxtnr]
	// Umwandlung in Array:
	DO WHILE (nPosition := At("," , cText)) > 0
		AAdd(aParam, SubStr(cText, 1, nPosition-1))
		cText := SubStr(cText, nPosition+1)
	ENDDO
	IF Len(cText) > 0
		AAdd(aParam, cText)
	ENDIF
	// Zuweisung der Parameter:
	cFileName := "Indiform\" + aFormName[1] + "\" + aParam[1]
	IIf(Len(aParam) > 1,	cFormular := "Indiform\" + aFormName[1] + "\" + aParam[2], )
	IIf(Len(aParam) > 2,	cFont := aParam[3], )
	IIf(Len(aParam) > 3,	cFSize := aParam[4], )
	IIf(Len(aParam) > 4,	cFormSeite := aParam[5], )
	IIf(Len(aParam) > 5,	cZeileCM := aParam[6], )
	IIf(Len(aParam) > 6,	cNotiz_Bez := aParam[7], )
	// ALT-Klick: die betroffenen txt-Dateien in den Editor laden:
	IF AppKeyState(65554)==1	// zusammen mit ALT-Taste
	   ? RunShell (" /C START Notepad "+cDatver+"Indiform\"+aFormName[1]+"\"+aFormName[1]+".txt",cComCom,.T.)
	   ? RunShell (" /C START Notepad "+cDatver+cFileName,cComCom,.T.)
	   cFileText := MemoRead(cDatver+cFileName)
	   IF (")"+CR)$cFileText .OR. (")"+LF)$cFileText
	   	msgbox("Nach den Variablen unbedingt einen Leerschritt einbauen!")
	   ENDIF
	   RETURN .F.
	ENDIF

	IF Val(cZeileCM) == 0
		cFileTEXT := ConvToOEMCP(MemoRead(cDatver+cFileName))	// wenn cFile nicht mit KSOX erzeugt wurde, dann kein ConvToOEMCP
//		cFile := MemoRead(cFile)	// wenn cFile nicht mit KSOX erzeugt wurde, dann kein ConvToOEMCP
		cContainer := VariFunkErsatz(cFileText)	// in cFileText steckt jetzt der komplette Text (nicht nur der Filename!)
	ELSE
		cFileText := ConvToOEMCP(MemoRead(cDatver+cFileName))	// den Formular-Text mit den eingebauten Variablen in cFileText einlesen
		cFileText := VariPosition(cFileText,@cContainer, cFont, cFSize, cFormSeite, cZeileCM)	// in cFileText steckt jetzt der komplette Text (nicht nur der Filename!)
	// in cContainer (== BriefText) werden von der Fkt. VariPosition() alle Variablen im Text positioniert bergeben.
	ENDIF
//zum Test	MemoWrit("XXcFile.txt",cFile)
//zum Test	MemoWrit("XXcCont.txt",cContainer)
RETURN HTML_Form(cContainer, cFormular, cFont, cFSize, cFormSeite, cZeileCM, cNotiz_Bez, aFormName[1], cFormName)

/*03.07.2008 17:18 zum Ersetzen von Variablenbezeichnungen in einem Text durch den Variablenwert
      Die Bezeichnung muss von einem $ angefhrt werden und mit einem Space enden: z.B. $1->auftrnr ...
      Vielleicht kann man auch Funktionen einbauen, indem man sie in Klammern setzt?: auch ohne!!*/
   /* Variablen-Namen: entweder Feldvariablen der aktuellen WorkArea, z.B. $(
                       oder bei "N" mit LenDec am Ende, z.B. 62 
                       "N"-Variable mssen im Text in Klammern stehen: $(nRate62) */
  /*12.10.2022 14:11 IMMER die Variablen in Klammern() setzen, denn 'FieldInfo(FieldPos(SubStr' verl„sst sich darauf.*/
// umbenannt in VariFunkErsatz, weil ohne Funk es bereits in AAA existierte
FUNCTION VariFunkErsatz( cString)
   LOCAL nVarLen, nTabLen := 0
   PRIVATE cVariable 
   DO WHILE At("$",cString) > 0
      /* der Variablen-Name:*/
      IF At("$",cString) == At("$('", cString)	/*literal String in '' */
	      cVariable := SubStr( cString, At("$",cString)+1, At("') ",cString,At("$",cString))-At("$",cString)+1 )
	      /* die L„nge des Namens der Variablen: */
	      nVarLen := At(") ",cString,At("$(",cString))-At("$(",cString)+1
      ELSE
      	//09.12.2023 21:04	vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	      cVariable := SubStr( cString, At("$",cString)+1, At(") ",cString,At("$",cString))-At("$",cString) )
			nVarLen := Len(cVariable)		// fr Ersetzung in der Variablen cString s.u.
			//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			IF At("),",cString) > 0 .AND. At(") ",cString) > At("),",cString)
		      cVariable := SubStr( cString, At("$",cString)+1, At("),",cString,At("$",cString))-At("$",cString) )
		      /* die L„nge des Namens der Variablen: */
		      nVarLen := At(", ",cString,At("$",cString))-At("$",cString)
//09.12.2023 20:54 aus VariPosition wegen CodeBlock etc... vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
			ELSEIF Len(cVariable)>=5 .AND. (","$cVariable .OR. "{||"$cVariable .OR. "->"$cVariable .OR. ":"$cVariable)
				IF (At("{||",cVariable)>0 .AND. At("})",cVariable)>0)		//29.08.2023 19:10 wenn ein CodeBlock drin ist ohne Position
					cPosition := "0,0"
					cVariable := SubStr(cVariable,2,Len(cVariable)-2)
				ELSEIF !","$cVariable .OR. (At("{||",cVariable)>0 .AND. At("}",cVariable) > RAt(",",cVariable))	// wenn komma nur im Codeblock
					cPosition := "0,0"																									// -> keine Position
					cVariable := SubStr(cVariable,2,Len(cVariable)-2)
				ELSEIF "')"$cVariable .AND. At(")",cVariable) > RAt(",",cvariable)			// literal String ohne Position
					cPosition := "0,0"																		// -> keine Position
					cVariable := SubStr(cVariable,2,Len(cVariable)-2)
				ELSEIF "))"$cVariable .AND. At("))",cVariable) == Len(cVariable)-1			// Function ohne Position
					cPosition := "0,0"																		// -> keine Position
					cVariable := SubStr(cVariable,2,Len(cVariable)-2)
				ELSE
					IF At("{||",cVariable)>0 .AND. At("}",cVariable) < RAt(",",cVariable)			// Komma auch hinter dem Codeblock
						nAnf := At(",",cVariable,At("}",cVariable))+1		//Codeblock
					ELSEIF (nAnf := RAt(')',cVariable,Len(cVariable)-1)) > 0			//cVariable = Function
						nAnf += 2
					ELSE
						nAnf := At(",",cVariable)+1								//Variable
					ENDIF 
					nEnd := Len(cVariable)
					cPosition := SubStr(cVariable,nAnf,nEnd-nAnf)
					cVariable := SubStr(cVariable,2,nAnf-3)				// isoliert die Variable/den CodeBlock
				ENDIF
				//29.08.2023 20:59 fhrt den CodeBlock aus und macht daraus eine literale String mit Hilfe Chr(39)
				IF "{||"$cVariable
					xVariable := Eval(&cVariable)	// 29.08.2023 19:19 den CodeBlock ausfhren
					IF ValType(xVariable) == "C"
						cVariable := Chr(39)+xVariable+Chr(39)
					ELSEIF ValType(xVariable) == "N"
						cVariable := Chr(39)+AllTrim(Str(xVariable))+Chr(39)
					ELSEIF ValType(xVariable) == "D"
						cVariable := Chr(39)+DtoC(xVariable)+Chr(39)
					ENDIF
				ENDIF
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
		   ELSE	// bleibt noch wie im VariFunkErsatz-Original (09.12.2023 21:01)
		      cVariable := SubStr( cString, At("$",cString)+1, At(") ",cString,At("$",cString))-At("$",cString) )
		      /* die L„nge des Namens der Variablen: */
		      nVarLen := At(" ",cString,At("$",cString))-At("$",cString)
			ENDIF
	   ENDIF

	   IF TYPE(cVariable)$"UE"
	   	msgbox("Fehler bei der Variablen:"+cVariable)
	   	cString := Stuff(cString,At("$",cString),nVarLen,"X X X X X")
	   	LOOP
	   ENDIF

   	cVariable = IIf("IIF"==SubStr(Upper(cVariable),0,3),&cVariable,cVariable)	//28.08.2023 09:41 Testweise
   	aF_Info := IIf(ValType(&cVariable)=="N" .AND. "->"$cVariable, F_Info(cVariable), {,})	//28.03.2023 19:06 FieldInfo()

//      DO WHILE nTabLen++ < Len(cString) - nVarLen
//         IF At(Space(nTabLen) := 
      /* wenn nach der Variablen mehr als ein Space, dann PadR, damit Tab-Abst„nde erhalten bleiben: */
//      cString := Stuff(cString,At("$",cString),nVarLen, ;
      cString := Stuff(cString,At("$",cString),nVarLen+1, ;
                           IIf(At(" ",cString,At("$",cString))!=At("  ",cString,At("$",cString)), ;
                               ; /* wenn also der Abstand nur ein Space ist ... */
                                 IIf(ValType(&cVariable)$"CM", ;
                                     ; /* ... dann StringVariable mit AllTrim komprimieren: */
                                       AllTrim(&cVariable), ;
                                     ; /* NumVariable in Strings verwandeln: */
                                       IIf(ValType(&cVariable)=="N", ;
                                           ; /* Mem- oder Feldvariable? */
                                             IIf("->"$cVariable, ;
                                                 ; /* Feldvariable: Dezimalstellen aus FieldInfo holen: */
                                                   Str(&cVariable, ;		/*12.10.2022 13:59  nVarLen-6 als nCount fr Substr(cVariable)  4mal in VariFunkErsatz() */
					                                      aF_Info[1], ;	/* FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-6)),FLD_LEN), ; */
               					                       aF_Info[2]  ;   /* FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-6)),FLD_DEC) ; */
                                                      ), ;
                                                 ; /* Memvariable: Dezimalstellen aus 2stelliger Zahl holen: */
                                                   Str(&cVariable, ;
                                                                  Val(cVariable[At(")",cVariable)-2]), ;
                                                                  Val(cVariable[At(")",cVariable)-1]) ;
                                                      ) ;
                                                ), ;
                                           ; /* Datumsvariable in String verwandeln */
                                             IIf(ValType(&cVariable)=="D", ;
                                                   DtoC(&cVariable), ;
                                                   IIf( Upper(cVariable[1])$"D", ;
                                                         DtoC( DATE() + Val(SubStr(cVariable,2))), ;
                                                         "" ;
                                                      ) ;
                                                ) ;
                                          ) ;
                                    ), ;
                               ; /* wenn aber der Abstand mehr als ein Space ist (=TAB) */
                                 IIf(ValType(&cVariable)$"CM", ;
                               ; /* damit die Variable nach der Umwandlung denselben Platz einnimmt: */
                                       PadR(AllTrim(&cVariable), nVarLen ), ;
                                     ; /* NumVariable in Strings verwandeln: */
                                       IIf(ValType(&cVariable)=="N", ;
                                           ; /* Mem- oder Feldvariable? */
                                             IIf("->"$cVariable, ;
                                                 ; /* Feldvariable: Dezimalstellen aus FieldInfo holen: */
                                                   Str(&cVariable, ;
					                                      aF_Info[1], ;	/* FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-6)),FLD_LEN), ; */
               					                       aF_Info[2]  ;   /* FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-6)),FLD_DEC) ; */
                                                      ), ;
                                                 ; /* Memvariable: Dezimalstellen aus 2stelliger Zahl holen: */
                                                   Str(&cVariable, ;
                                                                  Val(cVariable[At(")",cVariable)-2]), ;
                                                                  Val(cVariable[At(")",cVariable)-1]) ;
                                                      ) ;
                                                ), ;
                                           ; /* Datumsvariable in String verwandeln */
                                             IIf(ValType(&cVariable)=="D", ;
                                                   PadR(DtoC(&cVariable), nVarLen ), ;
                                                   "" ;
                                                ) ;
                                          ) ;
                                    ) ;
                              ) ;
                      )
       /* & = Makro-Operator: wegen 'Wert der Variablen' */
   ENDDO
RETURN cString

// 13.10.2022 11:06 entwickelt aus VariErsatz(): (muss noch durch die ganze IIf-Fl”te erg„nzt werden!
/*03.07.2008 17:18 zum Ersetzen von Variablenbezeichnungen in einem Text durch den Variablenwert
      Die Bezeichnung muss von einem $ angefhrt werden und mit einem Space enden: z.B. $1->auftrnr ...
      Vielleicht kann man auch Funktionen einbauen, indem man sie in Klammern setzt?: auch ohne!!*/
   /* Variablen-Namen: entweder Feldvariablen der aktuellen WorkArea, z.B. $(
                       oder bei "N" mit LenDec am Ende, z.B. 62 
                       "N"-Variable mssen im Text in Klammern stehen: $(nRate62) */
  /*12.10.2022 14:11 IMMER die Variablen in Klammern() setzen, denn 'FieldInfo(FieldPos(SubStr' verl„sst sich darauf.*/
FUNCTION VariPosition_KSO( cString, cContainer, cFont, cFSize, cFormSeite, cZeileCM)
   LOCAL nVarLenR, nVarLen, nTabLen := 0
   LOCAL nPosition, cPosition, aPosition := {}, nAnf, nEnd, aPos := {0,0}, nTop, nLeft
   LOCAL mmpx := 0.352778		//0.2835	// mm pro Pixel 
   LOCAL nFSize := Val(cFSize), nFHoehe := nFSize * 0.352778, nFBreite := nFSize * 0.195	// 0.2 ist ein gesch„tzter vorl„ufiger Wert
   LOCAL nZeileMM := IIf(Val(cZeileCM)<0.2, nFHoehe * Val(cZeileCM)*10, Val(cZeileCM)*10)		// nZeileMM aus cZeileCM berechnen
   LOCAL aFormSeite := {}
   LOCAL cPos1 := 0, cPos2 := 0, cMargTop := 0, cSpace := ""
   LOCAL cEingabeCM := "0", nEingabeVor := 0	//18.12.2022 21:09
   LOCAL cVarInhalt
   PRIVATE cVariable 
   DEFAULT cContainer TO ""

	nFBreite := FontBreite(cFont,cFSize)	//28.12.2022 14:26 Buchstabenbreite aus aTextBox ausgerechnet
	
	// berechnet den Anfangs-Top-Abstand aus cFormSeite/Inditext.txt^ vvvvvvvvvvvvvvvvvvvvvvvv
	// wie bei php: aPosition = explode(cPosition)
	DO WHILE (nFormS := At(" " , cFormSeite)) > 0
		AAdd(aFormSeite, Val(SubStr(cFormSeite, 1, nFormS-1)))
		cFormSeite := SubStr(cFormSeite, nFormS+1)
	ENDDO
	IF Len(cFormSeite) > 0
		AAdd(aFormSeite, Val(cFormSeite))
	ENDIF
	nTop := IIf(Len(aFormSeite)>4,aFormSeite[2],IIf(Len(aFormSeite)==4,aFormSeite[1],0))
	nLeft := IIf(Len(aFormSeite)>4,aFormSeite[5],IIf(Len(aFormSeite)==4,aFormSeite[4],0))
//	aPos := {nLeft*100,nTop*100}
   //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

	cContainer += '<FORM NAME="Formular">'
   DO WHILE At("$",cString) > 0
   	// die Positionierung der Variablen |left,top,width,height|
   	aPosition := {}

      /* der Variablen-Name:*/
      IF At("$",cString) == At("$('", cString)	/*literal String in '' */
	      cVariable := SubStr( cString, At("$",cString)+1, At(") ",cString,At("$",cString))-At("$",cString) )
      ELSE
	      cVariable := SubStr( cString, At("$",cString)+1, At(" ",cString,At("$",cString))-At("$",cString)-1 )
	   ENDIF
		nVarLenR := Len(cVariable)		// fr Ersetzung in der Variablen cString s.u.
			      
      IF ","$cVariable .AND. Len(cVariable)>5
			nAnf := At(",",cVariable)+1
			nEnd := Len(cVariable)
			WHILE nEnd-nAnf > 12
				nAnf := At(",",cVariable,nAnf)+1
			ENDDO
			cPosition := SubStr(cVariable,nAnf,nEnd-nAnf)

			// berechnet die absolute Lage der Variablen auf der Seite:   vvvvvvvvvvvvvvvvvvvvvvvvvvv
			// wie bei php: aPosition = explode(cPosition)
			DO WHILE (nPosition := At("," , cPosition)) > 0
				AAdd(aPosition, Val(SubStr(cPosition, 1, nPosition-1)))
				cPosition := SubStr(cPosition, nPosition+1)
			ENDDO
			IF Len(cPosition) > 0
				AAdd(aPosition, Val(cPosition) - nZeileMM * 10)	// -nZeileMM, weil die Einstellung.txt die Werte vom Unterstrich hat... 
			ENDIF																//				...w„hrend ein SPAN seine Positionswerte oben links hat
			// hier ggf. einfgen die fehlenden Parameter width und height 
      	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

			cVariable := SubStr(cVariable,2,nAnf-3)
		ELSE
			cVariable := SubStr( cVariable, At("(",cVariable)+1, At(")",cVariable,At("(",cVariable))-At("(",cVariable)-1 )
			aPosition := {0,0}		// vorl„ufig ...
		ENDIF      
      /* die L„nge des Namens der Variablen: */
      nVarLen := Len(cVariable)

//   	cVarInhalt := AllTrim(&cVariable)	// erstmal ... , eigentlich die ganze IIf-Fl”te ...
		IF Len(AllTrim(cVariable)) == 0 
			cVarInhalt := "" 
		ELSEIF CRLF$cVariable					// kommt nur bei Texten in ** vor
			cVariable := Stuff(cVariable,At("'",cVariable),1,"")
			cVarInhalt := Stuff(cVariable,At("'",cVariable),1,"")		// der cVarInhalt ist gleich der 'cVariablen' ohne die ''
		ELSE
		   IF TYPE(cVariable)$"UE"
		   	msgbox("Fehler bei der Variablen:"+cVariable)
		   	cString := Stuff(cString,At("$",cString),nVarLen,"X X X X X")
		   	LOOP
		   ENDIF
		   IF Val(cVariable) < 20			//18.12.2022 20:43 wenn es KEIN Eingabefeld ist
		   	cEingabeCM := "0"
		   	aF_Info := IIf(ValType(&cVariable)=="N" .AND. "->"$cVariable, F_Info(cVariable), {,})	//28.03.2023 19:06 FieldInfo()
				cVarInhalt := IIf(ValType(&cVariable)$"CM", ;
                   ; /* ... dann StringVariable mit AllTrim komprimieren: */
                     AllTrim(&cVariable), ;
                   ; /* NumVariable in Strings verwandeln: */
                     IIf(ValType(&cVariable)=="N", ;
                         ; /* Mem- oder Feldvariable? */
                           IIf("->"$cVariable, ;
                               ; /* Feldvariable: Dezimalstellen aus FieldInfo holen: */
                                 Str(&cVariable, ;		/*12.10.2022 13:59  nVarLen-6 als nCount fr Substr(cVariable)  4mal in VariErsatz() */
                                      aF_Info[1], ;	/* FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-3)),FLD_LEN), ; */
                                      aF_Info[2]  ;   /* FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-3)),FLD_DEC) ; */
                                    ), ;
                               ; /* Memvariable: Dezimalstellen aus 2stelliger Zahl holen: */
                                 Str(&cVariable, ;
                                                Val(cVariable[At(")",cVariable)-2]), ;
                                                Val(cVariable[At(")",cVariable)-1]) ;
                                    ) ;
                              ), ;
                         ; /* Datumsvariable in String verwandeln */
                           IIf(ValType(&cVariable)=="D", ;
                                 DtoC(&cVariable), ;
                                 IIf( Upper(cVariable[1])$"D", ;
                                       DtoC( DATE() + Val(SubStr(cVariable,2))), ;
                                       "" ;
                                    ) ;
                              ) ;
                        ) ;
                  )
			ELSE
				cEingabeCM := LTrim(Str(Val(cVariable)/100))+"cm"
				cVarInhalt := Space(Val(cVariable)/10/nFBreite)	//23.12.2022 15:43
			ENDIF
		ENDIF
	  cVarInhalt := AllTrim(cVarInhalt)	//24.12.2022 09:10	+" "
     cString := Stuff(cString,At("$",cString),nVarLenR+1,cVarInhalt)	// diese Zeile scheint nicht mehr gebraucht zu werden. DOCH!
	   IF aPosition[1] == 0 .AND. aPosition[2] == 0	.AND. Len(cVarInhalt) > 0	// wenn keine Positionsangabe, dann anh„ngen an vorige span
	   	cContainer := Stuff(cContainer,RAt("</span>",cContainer), 0, IIf(cVarInhalt[1]==",", cVarInhalt, " "+cVarInhalt))
	   	aPos[1] += Len(cVarInhalt) * nFBreite * 10
		ELSEIF Len(aPosition) == 2	.AND. AllTrim(Str(aPosition[2])) == AllTrim(Str(aPos[2]))	.AND. !Empty(cPos2)		// geht in derselben Zeile weiter
	   	IF  Val(cEingabeCM) == 0
		   	cSpace := Space((aPosition[1] - aPos[1])/(nFBreite*10))							// statt margin-left
		   	cContainer := Stuff(cContainer,RAt("</span>",cContainer), 0, cSpace+cVarInhalt)
		   ELSE
		   	cSpace := Space((aPosition[1] - aPos[1])/(nFBreite*10)-nEingabeVor)			// statt margin-left
//		   	cContainer += '<span style="margin-top:'+cMargTop+'cm; line-height:'+cZeileCM+';vertical-align:text-bottom;">' 
		   	cContainer += '<span style="margin-top:'+Str(Val(cMargTop)/2)+'cm;vertical-align:bottom;">' 
		   	cContainer += cSpace+'<INPUT TYPE=TEXT NAME="Textfeld 1" SIZE=5 STYLE="width:'+cEingabeCM+'; height:'+cZeileCM+'; font-family: Arial, sans-serif; font-size: 11pt" /></span>'
		   ENDIF
	   	cPos1 := AllTrim(Str(aPosition[1]/100))							// margin-left fr den „usseren SPAN
   		cPos2 := AllTrim(Str((aPosition[2] - aPos[2])/100))			// margin-top fr den „usseren SPAN
   		aPos[2] += Val(cPos2)*100													// vertikale Position der vorigen Zeile
   		aPos[1] := aPosition[1] + Len(cVarInhalt) * nFBreite * 10		// horizontale Position rechts vom VarInhalt
		ELSEIF Len(aPosition) == 2								// nur Pos nicht Size
	   	WHILE aPosition[2] - aPos[2] > nZeileMM * 20						// wenn vertikale Position mehr als zwei Zeilen weiter als die Vorzeile
	   		cContainer += " "+CRLF												// einschieben eines CRLF
	   		aPos[1] := nFBreite * 10
	   		aPos[2] += nZeileMM * 10											// vertikale Position um eine Zeile weiterz„hlen
	   	ENDDO
	   	IF aPosition[2] - aPos[2] > 0											// wenn ein Zeilenabstand ist
	   		IF aPosition[2] - aPos[2] > nZeileMM * 10
	   			cContainer += " "+CRLF												// einschieben eines CRLF
		   		aPos[1] := nFBreite * 10
	   			aPos[2] += nZeileMM * 10											// vertikale Position um eine Zeile weiterz„hlen
				ENDIF
				cMargTop := LTrim(Str((aPosition[2] - aPos[2])/100))
			ELSE
				cMargTop := "0"
		   ENDIF
	   	cPos1 := AllTrim(Str(aPosition[1]/100))							// margin-left fr den „usseren SPAN
   		cPos2 := cMargTop	//AllTrim(Str((aPosition[2] - aPos[2])/100))			// margin-top fr den „usseren SPAN
   		aPos[2] += Val(cPos2)*100													// vertikale Position der vorigen Zeile
   		aPos[1] := aPosition[1] + Len(cVarInhalt) * nFBreite * 10		// horizontale Position rechts vom VarInhalt
			IF Val(cVariable) < 20
		   	cSpace := Space(aPosition[1]/(nFBreite*10))							// margin-left
		   	cContainer += '<span style="margin-top:'+cMargTop+'cm; line-height:'+cZeileCM+';vertical-align:text-bottom;">'+cSpace+cVarInhalt+'</span>' 
			ELSE
		   	cSpace := Space(aPosition[1]/(nFBreite*10))							// margin-left
//		   	cContainer += '<span style="margin-top:'+cMargTop+'cm; line-height:'+cZeileCM+';vertical-align:text-bottom;">' 
		   	cContainer += '<span style="margin-top:'+Str(Val(cMargTop)/2)+'cm;vertical-align:bottom;">' 
		   	cContainer += cSpace+'<INPUT TYPE=TEXT NAME="Textfeld 1" SIZE=5 STYLE="width:'+cEingabeCM+'; height:'+cZeileCM+'; font-family: Arial, sans-serif; font-size: 11pt" /></span>'
		   ENDIF
		ELSEIF Len(aPosition) == 4	// kommt vorerst mal garnicht vor
	   	cContainer += '<div  CLASS="sd-abs-pos" style="position:absolute;left:'+Str(aPosition[1])+';top:'+Str(aPosition[2])+';width:'+aPosition[3]+';height:'+aPosition[4]+';">'+cVarInhalt+'</div>'
		ENDIF
		nEingabeVor := Val(cEingabeCM)
	ENDDO
	cContainer += '</FORM>'
RETURN cString

// 13.10.2022 11:06 entwickelt aus VariFunkErsatz(): (muss noch durch die ganze IIf-Fl”te erg„nzt werden!
/*03.07.2008 17:18 zum Ersetzen von Variablenbezeichnungen in einem Text durch den Variablenwert
      Die Bezeichnung muss von einem $ angefhrt werden und mit einem Space enden: z.B. $1->auftrnr ...
      Vielleicht kann man auch Funktionen einbauen, indem man sie in Klammern setzt?: auch ohne!!*/
   /* Variablen-Namen: entweder Feldvariablen der aktuellen WorkArea, z.B. $(
                       oder bei "N" mit LenDec am Ende, z.B. 62 
                       "N"-Variable mssen im Text in Klammern stehen: $(nRate62) */
  /*12.10.2022 14:11 IMMER die Variablen in Klammern() setzen, denn 'FieldInfo(FieldPos(SubStr' verl„sst sich darauf.*/
FUNCTION VariPosition_Nolte( cString, cContainer, cFont, cFSize, cFormSeite, cZeileCM, cFile)	//16.09.2023 20:52 cFile
   LOCAL nVarLenR, nVarLen, nTabLen := 0
   LOCAL nPosition, cPosition, aPosition := {}, nAnf, nEnd, aPos := {0,0}, nTop, nLeft
   LOCAL mmpx := 0.352778		//0.2835	// mm pro Pixel 
   LOCAL nFSize := Val(cFSize), nFHoehe := nFSize * 0.352778, nFBreite := nFSize * 0.195	// 0.2 ist ein gesch„tzter vorl„ufiger Wert
   LOCAL nZeileMM := IIf(Val(cZeileCM)<0.2, nFHoehe * Val(cZeileCM)*10, Val(cZeileCM)*10)		// nZeileMM aus cZeileCM berechnen
   LOCAL aFormSeite := {}
   LOCAL cPos1 := "0", cPos2 := "0", cMargTopCM := "0", cSpace := "", cMargLeftCM := "0"
   LOCAL cEingabeCM := "0", nEingabeVor := 0	//18.12.2022 21:09
   LOCAL cVarInhalt
   LOCAL cEFSize := LTrim(Str(nFSize-1))+"pt"	//04.09.2023 16:43 FontSize der Eingabefelder
//   LOCAL cInpZeileCM := "0.59cm"	//04.09.2023 20:42	LTrim(Str((nFSize-1)*mmpx*0.12))+"cm"	//04.09.2023 16:44	Zeilenh”he der Eingabefelder
   LOCAL cInpZeileCM := Max("0.59",LTrim(Str((nFSize-1)*mmpx*0.12)))+"cm"	//04.09.2023 16:44	Zeilenh”he der Eingabefelder
   PRIVATE cVariable, nSp := 0	//03.09.2023 13:42 fr die id der SPANs 
   DEFAULT cContainer TO ""

	nFBreite := FontBreite(cFont,cFSize)	//28.12.2022 14:26 Buchstabenbreite aus aTextBox ausgerechnet
	
	// berechnet den Anfangs-Top-Abstand aus cFormSeite/Inditext.txt^ vvvvvvvvvvvvvvvvvvvvvvvv
	// wie bei php: aPosition = explode(cPosition)
	DO WHILE (nFormS := At(" " , cFormSeite)) > 0
		AAdd(aFormSeite, Val(SubStr(cFormSeite, 1, nFormS-1)))
		cFormSeite := SubStr(cFormSeite, nFormS+1)
	ENDDO
	IF Len(cFormSeite) > 0
		AAdd(aFormSeite, Val(cFormSeite))
	ENDIF
	nTop := IIf(Len(aFormSeite)>4,aFormSeite[2],IIf(Len(aFormSeite)==4,aFormSeite[1],0))
	nLeft := IIf(Len(aFormSeite)>4,aFormSeite[5],IIf(Len(aFormSeite)==4,aFormSeite[4],0))
//	aPos := {nLeft*100,nTop*100}
   //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

	cContainer += '<FORM NAME="Formular" action="mailto:adebar@storch.xx?subject=BETREFF&body=BODY&attachment='+cDatver+cFile+'">'	//16.09.2023 19:51 action
   DO WHILE At("$",cString) > 0
   	// die Positionierung der Variablen |left,top,width,height|
   	aPosition := {}

      /* der Variablen-Name:*/
      IF At("$",cString) == At("$('", cString)	/*literal String in '' */
	      cVariable := SubStr( cString, At("$",cString)+1, At(") ",cString,At("$",cString))-At("$",cString) )
      ELSE
	      cVariable := SubStr( cString, At("$",cString)+1, At(" ",cString,At("$",cString))-At("$",cString)-1 )
	   ENDIF
		nVarLenR := Len(cVariable)		// fr Ersetzung in der Variablen cString s.u.
			      
      IF ","$cVariable .AND. Len(cVariable)>5
			IF (At("{||",cVariable)>0 .AND. At("})",cVariable)>0)		//29.08.2023 19:10 wenn ein CodeBlock drin ist ohne Position
				cPosition := "0,0"
				cVariable := SubStr(cVariable,2,Len(cVariable)-2)
			ELSE
				nAnf := RAt(",",cVariable)-1
				nEnd := Len(cVariable)
			//	WHILE nEnd-nAnf > 12
					nAnf := RAt(",",cVariable,nAnf)+1
			//	ENDDO
				cPosition := SubStr(cVariable,nAnf,nEnd-nAnf)
				cVariable := SubStr(cVariable,2,nAnf-3)				// isoliert die Variable/den CodeBlock
			ENDIF
			// berechnet die absolute Lage der Variablen auf der Seite:   vvvvvvvvvvvvvvvvvvvvvvvvvvv
			// wie bei php: aPosition = explode(cPosition)
			DO WHILE (nPosition := At("," , cPosition)) > 0
				AAdd(aPosition, Val(SubStr(cPosition, 1, nPosition-1)))
				cPosition := SubStr(cPosition, nPosition+1)
			ENDDO
			IF Len(cPosition) > 0
				AAdd(aPosition, Val(cPosition) - nZeileMM * 10)	// -nZeileMM, weil die Einstellung.txt die Werte vom Unterstrich hat... 
			ENDIF																//				...w„hrend ein SPAN seine Positionswerte oben links hat
			// hier ggf. einfgen die fehlenden Parameter width und height 
      	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			//29.08.2023 20:59 fhrt den CodeBlock aus und macht daraus eine literale String mit Hilfe Chr(39)
			IF "{||"$cVariable
				xVariable := Eval(&cVariable)	// 29.08.2023 19:19 den CodeBlock ausfhren
				IF ValType(xVariable) == "C"
					cVariable := Chr(39)+xVariable+Chr(39)
				ELSEIF ValType(xVariable) == "N"
					cVariable := Chr(39)+AllTrim(Str(xVariable))+Chr(39)
				ELSEIF ValType(xVariable) == "D"
					cVariable := Chr(39)+DtoC(xVariable)+Chr(39)
				ENDIF
			ENDIF
		ELSE
			cVariable := SubStr( cVariable, At("(",cVariable)+1, At(")",cVariable,At("(",cVariable))-At("(",cVariable)-1 )
			aPosition := {0,0}		// vorl„ufig ...
		ENDIF      
      /* die L„nge des Namens der Variablen: */
      nVarLen := Len(cVariable)

//   	cVarInhalt := AllTrim(&cVariable)	// erstmal ... , eigentlich die ganze IIf-Fl”te ...
		IF Len(AllTrim(cVariable)) == 0 
			cVarInhalt := "" 
		ELSEIF CRLF$cVariable					// kommt nur bei Texten in ** vor
			cVariable := Stuff(cVariable,At("'",cVariable),1,"")
			cVarInhalt := Stuff(cVariable,At("'",cVariable),1,"")		// der cVarInhalt ist gleich der 'cVariablen' ohne die ''
		ELSEIF RAt("')",cVariable)==Len(cVariable)-1			//10.09.2023 15:31
			cVarInhalt := &cVariable
		ELSE
		   IF TYPE(cVariable)$"UE"
		   	msgbox("Fehler bei der Variablen:"+cVariable)
		   	cString := Stuff(cString,At("$",cString),nVarLen,"X X X X X")
		   	LOOP
		   ENDIF
		   IF Val(cVariable) < 20			//18.12.2022 20:43 wenn es KEIN Eingabefeld ist
		   	cEingabeCM := "0"
		   	cVariable = IIf("IIF"==SubStr(Upper(cVariable),0,3),&cVariable,cVariable)	//28.08.2023 09:41 Testweise
		   	aF_Info := IIf("->"$cVariable .AND. ValType(&cVariable)=="N", F_Info(cVariable), {,})	//28.03.2023 19:06 FieldInfo()
				cVarInhalt := IIf(ValType(&cVariable)$"CM", ;
                   ; /* ... dann StringVariable mit AllTrim komprimieren: */
                     AllTrim(&cVariable), ;
                   ; /* NumVariable in Strings verwandeln: */
                     IIf(ValType(&cVariable)=="N", ;
                         ; /* Mem- oder Feldvariable? */
                           IIf("->"$cVariable, ;
                               ; /* Feldvariable: Dezimalstellen aus FieldInfo holen: */
                                 Str(&cVariable, ;		/*12.10.2022 13:59  nVarLen-6 als nCount fr Substr(cVariable)  4mal in VariFunkErsatz() */
                                      aF_Info[1], ;	/* FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-3)),FLD_LEN), ; */
                                      aF_Info[2]  ;   /* FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-3)),FLD_DEC) ; */
                                    ), ;
                               ; /* Memvariable: Dezimalstellen aus 2stelliger Zahl holen: */
                                 Str(&cVariable, ;
                                                Val(cVariable[At(")",cVariable)-2]), ;
                                                Val(cVariable[At(")",cVariable)-1]) ;
                                    ) ;
                              ), ;
                         ; /* Datumsvariable in String verwandeln */
                           IIf(ValType(&cVariable)=="D", ;
                                 DtoC(&cVariable), ;
                                 IIf( Upper(cVariable[1])$"D", ;
                                       DtoC( DATE() + Val(SubStr(cVariable,2))), ;
                                       "" ;
                                    ) ;
                              ) ;
                        ) ;
                  )
			  cVarInhalt := AllTrim(cVarInhalt)	//31.08.2023 21:53 hierher von hinten //24.12.2022 09:10	+" "
			ELSE
				cEingabeCM := LTrim(Str(Val(cVariable)/100))+"cm"
				cVarInhalt := Space(Val(cVariable)/10/nFBreite)	//23.12.2022 15:43
			ENDIF
		ENDIF
//	  cVarInhalt := AllTrim(cVarInhalt)	//24.12.2022 09:10	+" "
     cString := Stuff(cString,At("$",cString),nVarLenR+1,cVarInhalt)	// diese Zeile scheint nicht mehr gebraucht zu werden. DOCH!
	   IF aPosition[1] == 0 .AND. aPosition[2] == 0	.AND. Len(cVarInhalt) > 0	// wenn keine Positionsangabe, dann anh„ngen an vorige span
	   	cContainer := Stuff(cContainer,RAt("</span>",cContainer), 0, IIf(cVarInhalt[1]==",", cVarInhalt, " "+cVarInhalt))
	   	aPos[1] += Len(cVarInhalt) * nFBreite * 10
		ELSEIF Len(aPosition) == 2	.AND. Val(Str(aPosition[2])) == Val(Str(aPos[2]))	.AND. !Empty(cPos2)		// geht in derselben Zeile weiter
	   	IF aPosition[1] == 0				//30.08.2023 09:54 wenn direkt angeschlossen werden soll (in derselben Zeile)
	   		aPosition[1] := aPos[1]
	   	ENDIF
	   	nSpace := (aPosition[1] - aPos[1])/(nFBreite*10)	//24.09.2023 18:46 nach hier vor das if
	   	cSpace := Space(nSpace)										//24.09.2023 18:46 nach hier vor das if
	   	IF  Val(cEingabeCM) == 0
	//24.09.2023 18:37	   	cSpace := Space((aPosition[1] - aPos[1])/(nFBreite*10))							// statt margin-left
		   	cContainer := Stuff(cContainer,RAt("</span>",cContainer), 0, cSpace+cVarInhalt)
	   		aPos[1] := aPosition[1] + Len(cVarInhalt) * nFBreite * 10		// horizontale Position rechts vom VarInhalt
		   ELSE
	//24.09.2023 18:39	   	cSpace := Space((aPosition[1] - aPos[1])/(nFBreite*10))			// statt margin-left
	//	   	cSpace := Space(nSpace)			// statt margin-left
				cMargLeftCM := LTrim(Str((nSpace-Int(nSpace))*nFBreite/10))+"cm"
		   //	cMargLeftCM := LTrim(Str(((aPosition[1] - aPos[1])/100)))+"cm"
//auf derselben Zeile keine verschiedenen line-height!!   	cContainer += '<span style="margin-top:'+cMargTopCM+'cm; line-height:'+cZeileCM+';vertical-align:text-bottom;">' 
	//	   	cContainer += '<span style="margin-top:'+LTrim(Str(Val(cMargTopCM)/2))+'cm;">'	//vertical-align:bottom;">' 
		   	cContainer += '<span style="display:block;margin-left:'+cMargLeftCM+';">'	//23.09.2023 18:27
		//   	cContainer += '<span style="display:block;height:'+cZeileCM+';line-height:'+cZeileCM+';">' 
		   	cInpSize := LTrim(Str(Max(2,Int(Val(cEingabeCM)*10/nFBreite))))
		   	cContainer += cSpace+'<INPUT TYPE=TEXT NAME="Textfeld 1" SIZE='+cInpSize+' STYLE="font-family: Arial, sans-serif; font-size: '+cEFSize+';height:'+cInpZeileCM+' !important;" /></span>'
				//24.09.2023 12:14 berschreibt fr Inputfelder:
				aPos[1] := aPosition[1] + Val(cEingabeCM)*100	//24.09.2023 12:15
		   ENDIF
	   	cPos1 := AllTrim(Str(aPosition[1]/100))							// margin-left fr den „usseren SPAN
   		cPos2 := AllTrim(Str((aPosition[2] - aPos[2])/100))			// margin-top fr den „usseren SPAN
   		aPos[2] += Val(cPos2)*100													// vertikale Position der vorigen Zeile
//24.09.2023 12:49   		aPos[1] := aPosition[1] + Len(cVarInhalt) * nFBreite * 10		// horizontale Position rechts vom VarInhalt
		ELSEIF Len(aPosition) == 2								// nur Pos nicht Size
	   	WHILE (aPosition[2] - aPos[2]) >= (nZeileMM * 20)						// wenn vertikale Position mehr als 1.5 Zeilen weiter als die Vorzeile
	   		cContainer += Chr(10)+'<span style="display:block;height:'+cZeileCM+';line-height:'+cZeileCM+';"> </span>'	// einschieben eines span statt CRLF
	   		aPos[1] := nFBreite * 10
	   		aPos[2] += nZeileMM * 10											// vertikale Position um eine Zeile weiterz„hlen
	   	ENDDO
/*	  		IF (aPosition[2] - aPos[2]) > (nZeileMM * 10)
	   		cContainer += '<span style="display:block;height:'+cZeileCM+';line-height:'+cZeileCM+';"> </span>'	// einschieben eines span statt CRLF
	   		aPos[1] := nFBreite * 10
   			aPos[2] += nZeileMM * 10											// vertikale Position um eine Zeile weiterz„hlen
//			ELSE
//				cMargTopCM := "0"
//				cMargTopCM := LTrim(Str((aPosition[2] - aPos[2])/100))
		   ENDIF*/
			cMargTopCM := LTrim(Str((aPosition[2] - aPos[2] - nZeileMM * 10)/100))+"cm"	//20.09.2023 09:20
	   	cPos1 := AllTrim(Str(aPosition[1]/100))							// margin-left fr den „usseren SPAN
   		cPos2 := cMargTopCM	//AllTrim(Str((aPosition[2] - aPos[2])/100))			// margin-top fr den „usseren SPAN
   		aPos[2] += Val(cPos2)*100													// vertikale Position der vorigen Zeile
   		aPos[1] := aPosition[1] + Len(cVarInhalt) * nFBreite * 10		// horizontale Position rechts vom VarInhalt
			//02.09.2023 20:18 fr 1/10mm-genaue Positionierung:
			nSpace := aPosition[1]/(nFBreite*10)
//24.09.2023 18:51	cMargLeftCM := LTrim(Str(((aPosition[1]/100)/(nFBreite/10) - Int((aPosition[1]/100)/(nFBreite/10)))*(nFBreite/10)))+"cm"	//20.09.2023 09:19
			cMargLeftCM := LTrim(Str((nSpace - Int(nSpace))*(nFBreite/10)))+"cm"	//24.09.2023 18:52
			IF cVarInhalt == "SENDEN"
				cSpace := Space(nSpace)							// 24.09.2023 18:49
		   	cZHoeheCM := LTrim(Str(Val(cZeileCM)+Val(cMargTopCM)))+"cm"	//23.09.2023 18:42
				cContainer += Chr(10)+'<span style="display:block; height:'+cZHoeheCM+'; line-height:'+cZHoeheCM+';margin-left:'+cMargLeftCM+';margin-top:0cm;">'
				cContainer += cSpace+'<input type="submit" value="SENDEN" STYLE="width:3cm;height:'+cInpZeileCM+';"></span>'
				aPos[2] += nZeileMM * 10		//23.09.2023 14:01 Start fr den Weg zur n„chsten Zeile
			ELSEIF Val(cVariable) < 20		// cSpace ist ein ganzzahliges Vielfaches von nFBreite (=Buchstabenbreite)
		   	cSpace := Space(nSpace)							//24.09.2023 18:49
		   	cZHoeheCM := LTrim(Str(Val(cZeileCM)+Val(cMargTopCM)))+"cm"	//23.09.2023 18:42
		   	cContainer += Chr(10)+'<span style="display:block;height:'+cZHoeheCM+';line-height:'+cZHoeheCM+';margin-left:'+cMargLeftCM+';margin-top:0cm;">'+cSpace+cVarInhalt+'</span>' 
				aPos[2] += nZeileMM * 10		//23.09.2023 14:01 Start fr den Weg zur n„chsten Zeile
			ELSE	// hier ist Val(cVariable) dann >20, also ein Eingabefeld
		   	cSpace := Space(nSpace)							//24.09.2023 18:49
		   	
//		   	cMargleftCM := LTrim(Str(aPosition[1]/100))+"cm"
	//	   	cSpace := ""
		   	
//		   	cContainer += Chr(10)+'<span style="display:block;height:'+cZeileCM+';line-height:'+cZeileCM+';margin-left:'+cMargLeftCM+';margin-top:'+LTrim(Str(Val(cMargTopCM)/2))+'cm;">' 
		   	cZHoeheCM := LTrim(Str(Val(cZeileCM)+Val(cMargTopCM)))+"cm"	//23.09.2023 18:42
		   	cContainer += Chr(10)+'<span style="display:block;height:'+cZHoeheCM+';line-height:'+cZHoeheCM+';margin-left:'+cMargLeftCM+';margin-top:0cm;vertical-align:bottom;">' 
//17.09.2023 21:42		   	cContainer += cSpace+'<INPUT TYPE=TEXT NAME="Textfeld 1" SIZE=5 STYLE="width:'+cEingabeCM+'; height:'+cInpZeileCM+';padding-bottom:0; font-family: Arial, sans-serif; font-size: '+cEFSize+';" /></span>'
		   	cInpSize := LTrim(Str(Max(2,Int(Val(cEingabeCM)*10/nFBreite))))
		   	cContainer += cSpace+'<INPUT TYPE=TEXT NAME="Textfeld1" SIZE='+cInpSize+' STYLE="font-family: Arial, sans-serif; font-size: '+cEFSize+';height:'+cInpZeileCM+' !important;" /></span>'
				aPos[2] += nZeileMM * 10		//23.09.2023 14:01 Start fr den Weg zur n„chsten Zeile
				//24.09.2023 12:14 berschreibt fr Inputfelder:
				aPos[1] := aPosition[1] + Val(cEingabeCM)*100	//24.09.2023 12:15
		   ENDIF
		ELSEIF Len(aPosition) == 4	// kommt vorerst mal garnicht vor
	   	cContainer += '<div  CLASS="sd-abs-pos" style="position:absolute;left:'+Str(aPosition[1])+';top:'+Str(aPosition[2])+';width:'+aPosition[3]+';height:'+aPosition[4]+';">'+cVarInhalt+'</div>'
		ENDIF
		nEingabeVor := Val(cEingabeCM)
	ENDDO
	cContainer += '</FORM>'
RETURN cString

// 13.10.2022 11:06 entwickelt aus VariFunkErsatz(): (muss noch durch die ganze IIf-Fl”te erg„nzt werden!
/*03.07.2008 17:18 zum Ersetzen von Variablenbezeichnungen in einem Text durch den Variablenwert
      Die Bezeichnung muss von einem $ angefhrt werden und mit einem Space enden: z.B. $1->auftrnr ...
      Vielleicht kann man auch Funktionen einbauen, indem man sie in Klammern setzt?: auch ohne!!*/
   /* Variablen-Namen: entweder Feldvariablen der aktuellen WorkArea, z.B. $(
                       oder bei "N" mit LenDec am Ende, z.B. 62 
                       "N"-Variable mssen im Text in Klammern stehen: $(nRate62) */
  /*12.10.2022 14:11 IMMER die Variablen in Klammern() setzen, denn 'FieldInfo(FieldPos(SubStr' verl„sst sich darauf.*/
FUNCTION VariPosition( cString, cContainer, cFont, cFSize, cFormSeite, cZeileCM, cFile)	//28.09.2023 12:51 cFAV ??
   LOCAL CR := Chr(13), LF := Chr(10)
   LOCAL nVarLenR, nVarLen, nTabLen := 0
   LOCAL nPosition, cPosition, aPosition := {}, nAnf, nEnd, aPos := {0,0}, nTop, nLeft
   LOCAL mmpx := 0.352778		//0.2835	// mm pro Pixel 
   LOCAL nFSize := Val(cFSize), nFHoehe := nFSize * 0.352778, nFBreite := nFSize * 0.195	// 0.2 ist ein gesch„tzter vorl„ufiger Wert
   LOCAL nZeileMM := IIf(Val(cZeileCM)<0.2, nFHoehe * Val(cZeileCM)*10, Val(cZeileCM)*10)		// nZeileMM aus cZeileCM berechnen
   LOCAL aFormSeite := {}
   LOCAL cPos1 := "0", cPos2 := "0", cMargTopCM := "0", cSpace := "", cMargLeftCM := "0"
   LOCAL cEingabeCM := "0", nEingabeVor := 0	//18.12.2022 21:09
   LOCAL cVarInhalt
   LOCAL cEFSize := LTrim(Str(nFSize-1))+"pt"	//04.09.2023 16:43 FontSize der Eingabefelder
//   LOCAL cInpZeileCM := "0.59cm"	//04.09.2023 20:42	LTrim(Str((nFSize-1)*mmpx*0.12))+"cm"	//04.09.2023 16:44	Zeilenh”he der Eingabefelder
   LOCAL cInpZeileCM := Max("0.59",LTrim(Str((nFSize-1)*mmpx*0.12)))+"cm"	//04.09.2023 16:44	Zeilenh”he der Eingabefelder
   LOCAL cTextHoeheCM := ""
   LOCAL cFormular, nSO := 0			//21.10.2023 12:38	nSO ist der SeitenOffset der DIVabs fr die weiteren Seiten
	LOCAL cRahmID, cBildALT			//30.10.2023 12:44
	LOCAL check := '', cRadioName := "Radio0"		//18.11.2023 14:59 checked == groáes X fr CheckBox ist angehakt
   PRIVATE cVariable, nSp := 0	//03.09.2023 13:42 fr die id der SPANs 
   DEFAULT cContainer TO ""

	nFBreite := FontBreite(cFont,cFSize)	//28.12.2022 14:26 Buchstabenbreite aus aTextBox ausgerechnet
//	nInpFBreite := FontBreite("Arial","11pt")	//27.09.2023 14:25
	nInpFBreite := FontBreite(cFont,"11pt")	//28.11.2023 16:18
	
	// berechnet den Anfangs-Top-Abstand aus cFormSeite/Inditext.txt^ vvvvvvvvvvvvvvvvvvvvvvvv
	// wie bei php: aPosition = explode(cPosition)
	DO WHILE (nFormS := At(" " , cFormSeite)) > 0
		AAdd(aFormSeite, Val(SubStr(cFormSeite, 1, nFormS-1)))
		cFormSeite := SubStr(cFormSeite, nFormS+1)
	ENDDO
	IF Len(cFormSeite) > 0
		AAdd(aFormSeite, Val(cFormSeite))
	ENDIF
	nTop := IIf(Len(aFormSeite)>4,aFormSeite[2],IIf(Len(aFormSeite)==4,aFormSeite[1],0))
	nLeft := IIf(Len(aFormSeite)>4,aFormSeite[5],IIf(Len(aFormSeite)==4,aFormSeite[4],0))
//	aPos := {nLeft*100,nTop*100}
   //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

//	cContainer += '<FORM NAME="Formular" action="mailto:adebar@storch.xx?subject=BETREFF&body=BODY&attachment='+cDatver+cFile+'">'	//16.09.2023 19:51 action
	cContainer += ''
   DO WHILE At("$",cString) > 0
   	// die Positionierung der Variablen |left,top,width,height|
   	aPosition := {}
		cEingabeCM := "0"		//27.09.2023 10:21 von hinten hierhin (wegen 'gespeicherte Daten in Inputfelder')
		cTextHoeheCM := ""	//05.10.2023 18:50
		
      /* der Variablen-Name:*/
//      IF At("$",cString) == At("$('", cString)	/*literal String in '' */
//	      cVariable := SubStr( cString, At("$",cString)+1, At(") ",cString,At("$",cString))-At("$",cString) )
//      ELSE
//	      cVariable := SubStr( cString, At("$",cString)+1, At(" ",cString,At("$",cString))-At("$",cString)-1 )
//	   ENDIF
      cVariable := SubStr( cString, At("$",cString)+1, At(") ",cString,At("$",cString))-At("$",cString) )
		nVarLenR := Len(cVariable)		// fr Ersetzung in der Variablen cString s.u.
			      
      IF Len(cVariable)>=5 .AND. (","$cVariable .OR. "{||"$cVariable .OR. "->"$cVariable)
			IF (At("{||",cVariable)>0 .AND. At("})",cVariable)>0)		//29.08.2023 19:10 wenn ein CodeBlock drin ist ohne Position
				cPosition := "0,0"
				cVariable := SubStr(cVariable,2,Len(cVariable)-2)
			ELSEIF !","$cVariable .OR. (At("{||",cVariable)>0 .AND. At("}",cVariable) > RAt(",",cVariable))	// wenn komma nur im Codeblock
				cPosition := "0,0"																									// -> keine Position
				cVariable := SubStr(cVariable,2,Len(cVariable)-2)
			ELSEIF "')"$cVariable .AND. At(")",cVariable) > RAt(",",cvariable)			// literal String ohne Position
				cPosition := "0,0"																		// -> keine Position
				cVariable := SubStr(cVariable,2,Len(cVariable)-2)
			ELSEIF "))"$cVariable .AND. At("))",cVariable) == Len(cVariable)-1			// Function ohne Position
				cPosition := "0,0"																		// -> keine Position
				cVariable := SubStr(cVariable,2,Len(cVariable)-2)
			ELSE
				IF At("{||",cVariable)>0 .AND. At("}",cVariable) < RAt(",",cVariable)			// Komma auch hinter dem Codeblock
					nAnf := At(",",cVariable,At("}",cVariable))+1		//Codeblock
				ELSEIF (nAnf := RAt(')',cVariable,Len(cVariable)-1)) > 0			//cVariable = Function
					nAnf += 2
				ELSE
					nAnf := At(",",cVariable)+1								//Variable
				ENDIF 
				nEnd := Len(cVariable)
				cPosition := SubStr(cVariable,nAnf,nEnd-nAnf)
				cVariable := SubStr(cVariable,2,nAnf-3)				// isoliert die Variable/den CodeBlock
			ENDIF
			// berechnet die absolute Lage der Variablen auf der Seite:   vvvvvvvvvvvvvvvvvvvvvvvvvvv
			// wie bei php: aPosition = explode(cPosition)
			DO WHILE (nPosition := At("," , cPosition)) > 0
				AAdd(aPosition, Val(SubStr(cPosition, 1, nPosition-1)))
				cPosition := SubStr(cPosition, nPosition+1)
			ENDDO
			IF Len(cPosition) > 0 .AND. Val(cPosition) != 0
				AAdd(aPosition, Int(Val(cPosition) - nZeileMM * 10))	// -nZeileMM, weil die Einstellung.txt die Werte vom Unterstrich hat... 
			ELSEIF Len(cPosition) > 0
				AAdd(aPosition,0)
			ENDIF																//				...w„hrend ein SPAN/DIV seine Positionswerte oben links hat
			// hier ggf. einfgen die fehlenden Parameter width und height 
			// hat die Variable auf der Seite einen feste L„nge? = width: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
			//27.09.2023 10:19 damit gespeicherte Falldaten in Input-Felder des Formulars gesteckt werden
			IF Len(aPosition)==3	//13.11.2023 18:26 wenn ein Inputfeld
				cEingabeCM := LTrim(Str(aPosition[1]/100))+"cm"
				aRemove(aPosition,1)
				cVariable := cVariable			// kann demn„chst weg...
			ENDIF
//			nBlock := RAt("}",cVariable)
//			IF (nAnf := RAt(",",cVariable)) > 0 .AND. IIf(nBlock>0,nAnf>nBlock,.T.) .AND. (nEnd := Val(SubStr(cVariable,nAnf+1))) > 0
//				cEingabeCM := LTrim(Str(nEnd/100))+"cm"
//				cVariable := SubStr(cVariable,1,nAnf-1)
//			ENDIF
      	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			//29.08.2023 20:59 fhrt den CodeBlock aus und macht daraus eine literale String mit Hilfe Chr(39)
			IF "{||"$cVariable
				xVariable := Eval(&cVariable)	// 29.08.2023 19:19 den CodeBlock ausfhren
				IF ValType(xVariable) == "C"
					cVariable := Chr(39)+xVariable+Chr(39)
				ELSEIF ValType(xVariable) == "N"
					cVariable := Chr(39)+AllTrim(Str(xVariable))+Chr(39)
				ELSEIF ValType(xVariable) == "D"
					cVariable := Chr(39)+DtoC(xVariable)+Chr(39)
				ENDIF
			ENDIF
		ELSEIF ".PNG"$Upper(cVariable)	// 19.10.2023 18:56 Formular fr die zweite Seite
			nSO += 1		//Seitenoffset fr die DIVabs-Felder der weiteren Seiten
			cRahmID = "Rahmen"+LTrim(Str(1+nSO))
			cBildALT = "Bild"+LTrim(Str(1+nSO))
			cFormular := 'F/'+SubStr(cVariable,3,Len(cVariable)-4)
			aFormSize := FormSize(cFormular)	//02.11.2023 10:58
			cFormular := '../../../../'+cFormular
		//	cContainer += '<DIV style="position:relative;min-width:21cm;min-height:29.7cm;background-color:transparent;">'
		//	cContainer += '<h1 style="page-break-before: always;">Seite 2</h1>'		//
	//		cContainer += '<img src="'+cFormular+'" alt="Bild2" align="left" width="992px" height="1403px" style="margin-top:29.7cm;" />'
		//	cContainer += '<img src="'+cFormular+'" alt="Bild2" style="margin:0;border:0;width:21cm;height:29.7cm;" title="Seite2" />'
		//	cContainer += '<p style="">'+CR+LF
		//	cContainer += '<img src="'+cFormular+'" alt="Bild2" align="left" width="992px" height="1403px" style="position_absolute;top:0;margin-top:0cm;" />'
		//	cContainer += '</p></div>'+CR+LF

			cContainer += '</DIV>'+CR+LF
			cContainer += '<DIV id="'+cRahmID+'"style="position:relative;width:'+aFormSize[1]+';height:'+aFormSize[2]+';margin:0px;padding:0px;border:none;float:left;background-color:transparent;border:0;page-break-before:always;">'+CR+LF
			cContainer += '<div style="position:absolute;top:0;left:0;width:'+aFormSize[1]+';height:'+aFormSize[2]+';margin:0px;padding:0px;border:none;background-color:transparent;">'+CR+LF
			cContainer += '<img src="'+cFormular+'" alt="'+cBildALT+'" align="left" style="position_absolute;margin:0px;padding:0px;border:none;width:'+aFormSize[1]+';height:'+aFormSize[2]+';" title="Seite2ff" />'
			cContainer += '</div>'+CR+LF
			cVarInhalt := ""
			cString := Stuff(cString,At("$",cString),nVarLenR+1,cVarInhalt)	// ersetzt in cString die Variablenbezeichnung durch ihren Inhalt
			LOOP
			
		ELSE
			cVariable := SubStr( cVariable, At("(",cVariable)+1, At(")",cVariable,At("(",cVariable))-At("(",cVariable)-1 )
			aPosition := {0,0}		// vorl„ufig ...
		ENDIF      
      /* die L„nge des Namens der Variablen: */
      nVarLen := Len(cVariable)

		IF Len(AllTrim(cVariable)) == 0 
			cVarInhalt := "" 
		ELSEIF CRLF$cVariable					// kommt nur bei Texten in ** vor
			cVariable := Stuff(cVariable,At("'",cVariable),1,"")
			cVarInhalt := Stuff(cVariable,At("'",cVariable),1,"")		// der cVarInhalt ist gleich der 'cVariablen' ohne die ''
		ELSEIF RAt("')",cVariable)==Len(cVariable)-1			//10.09.2023 15:31 wenn am Ende ') steht, also Literal
			cVarInhalt := &cVariable
		ELSEIF Val(cEingabeCM) > 0 .AND. Val(cVariable) > 100		//05.10.2023 18:40
			cTextHoeheCM := Str(Val(cVariable)/100)+"cm"
			cVarInhalt := ""
		ELSE
		   IF TYPE(cVariable)$"UE"
		   	msgbox("Fehler bei der Variablen:"+cVariable)
		   	cString := Stuff(cString,At("$",cString),nVarLen,"X X X X X")
		   	LOOP
		   ENDIF
		   IF Val(cVariable) < 20			//18.12.2022 20:43 wenn es KEIN Eingabefeld ist
		   	cVariable = IIf("IIF"==SubStr(Upper(cVariable),0,3),&cVariable,cVariable)	//28.08.2023 09:41 Testweise
		   	aF_Info := IIf("->"$cVariable .AND. ValType(&cVariable)=="N", F_Info(cVariable), {,})	//28.03.2023 19:06 FieldInfo()
				cVarInhalt := IIf(ValType(&cVariable)$"CM", ;
                   ; /* ... dann StringVariable mit AllTrim komprimieren: */
                     AllTrim(&cVariable), ;
                   ; /* NumVariable in Strings verwandeln: */
                     IIf(ValType(&cVariable)=="N", ;
                         ; /* Mem- oder Feldvariable? */
                           IIf("->"$cVariable, ;
                               ; /* Feldvariable: Dezimalstellen aus FieldInfo holen: */
                                 Str(&cVariable, ;		/*12.10.2022 13:59  nVarLen-6 als nCount fr Substr(cVariable)  4mal in VariFunkErsatz() */
                                      aF_Info[1], ;	/* FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-3)),FLD_LEN), ; */
                                      aF_Info[2]  ;   /* FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-3)),FLD_DEC) ; */
                                    ), ;
                               ; /* Memvariable: Dezimalstellen aus 2stelliger Zahl holen: */
                                 Str(&cVariable, ;
                                                Val(cVariable[At(")",cVariable)-2]), ;
                                                Val(cVariable[At(")",cVariable)-1]) ;
                                    ) ;
                              ), ;
                         ; /* Datumsvariable in String verwandeln */
                           IIf(ValType(&cVariable)=="D", ;
                                 DtoC(&cVariable), ;
                                 IIf( Upper(cVariable[1])$"D", ;
                                       DtoC( DATE() + Val(SubStr(cVariable,2))), ;
                                       "" ;
                                    ) ;
                              ) ;
                        ) ;
                  )
			  cVarInhalt := AllTrim(cVarInhalt)	//31.08.2023 21:53 hierher von hinten //24.12.2022 09:10	+" "
			ELSE
				cEingabeCM := LTrim(Str(Val(cVariable)/100))+"cm"
				cVarInhalt := ""	//04.11.2023 16:41 Eingabefeld  Space(Val(cVariable)/10/nFBreite)	//23.12.2022 15:43
			ENDIF
		ENDIF
     cString := Stuff(cString,At("$",cString),nVarLenR+1,cVarInhalt)	// diese Zeile scheint nicht mehr gebraucht zu werden. DOCH!

		//27.09.2023 12:23 Formular-Aufbau mit absolut-positionierten DIVs:
//		cTopCM := LTrim(Str((aPosition[2]+0)/100))+"cm"	//26.10.2023 16:56 +8 -Input um 0.8mm nach unten schieben
//		cLeftCM := LTrim(Str(aPosition[1]/100))+"cm"
   	cInpSize := LTrim(Str(Max(Len(cVarInhalt),Int(Val(cEingabeCM)*10/nFBreite))))
   	cETFSize := LTrim(Str(nFSize-2))+"pt"
//		cInpZeileCM := LTrim(Str((nFSize)*mmpx*0.12))+"cm"	//04.09.2023 16:44	Zeilenh”he der Eingabefelder
		cInpZeileCM := LTrim(Str((nFSize)*mmpx*0.12))+"cm"	//04.09.2023 16:44	Zeilenh”he der Eingabefelder
		nHDiff := (Val(cZeileCM)-Val(cInpZeileCM))*100		//03.11.2023 19:58
		cTopCM := LTrim(Str((aPosition[2]+nHDiff)/100))+"cm"	//03.11.2023 20:00 +nHDiff -Input um nHDiff nach unten schieben
		cLeftCM := LTrim(Str(aPosition[1]/100))+"cm"
		nDIV := RAt('</div>',cContainer)			// letztes DIV
		nINP := RAt('" /></div>',cContainer)	// letztes Input
	   IF aPosition[1] == 0 .AND. (aPosition[2]==0 .OR. aPosition[2]==aPos[2]) .AND. Len(cVarInhalt) > 0	.AND. nDIV > nINP+5	// wenn keine Positionsangabe, dann anh„ngen an vorige DIV
	   	cContainer := Stuff(cContainer,RAt("</div>",cContainer), 0, IIf(cVarInhalt[1]==",", cVarInhalt, " "+cVarInhalt))
	   	aPos[1] += Len(cVarInhalt) * nFBreite * 10
	   ELSEIF aPosition[1] == 0 .AND. (aPosition[2]==0 .OR. aPosition[2]==aPos[2]) .AND. Len(cVarInhalt) > 0	// wenn keine Positionsangabe, dann anh„ngen an vorige INP
	   	cContainer := Stuff(cContainer,RAt('" /></div>',cContainer), 0, IIf(cVarInhalt[1]==',', cVarInhalt, ' '+cVarInhalt))
	   	//bleibt gleich!! aPos[1] += Len(cVarInhalt) * nFBreite * 10
		ELSEIF Len(aPosition) == 2
			IF cVarInhalt == "SENDEN"
				cContainer += '<div style="position:absolute;top:'+cTopCM+';left:'+cLeftCM+';width:'+cEingabeCM+';height:'+cZeileCM+';">'
		   	cContainer += '<INPUT TYPE="SUBMIT" VALUE="SENDEN" STYLE="width:3cm;height:'+cInpZeileCM+';" /></div>'+CR+LF
		   	aPos[1] := aPosition[1]+300	// weil der Knopf 3cm breit sit
		   	aPos[2] := aPosition[2]
			ELSEIF Val(cEingabeCM) == 0
				cDivCM := LTrim(Str(Len(cVarInhalt)*nFBreite/10))+"cm"
				cContainer += '<div style="position:absolute;top:'+cTopCM+';left:'+cLeftCM+';width:'+cDivCM+';height:'+cZeileCM+';">'
		   	//cContainer += '<INPUT TYPE=TEXT NAME="Textfeld1" STYLE="border:none;border-color:transparent;font-family: Consolas, sans-serif; font-size: '+cETFSize+';width:'+cDivCM+';height:'+cZeileCM+' !important;vertical-align:bottom;padding:0px;pointer-events:none;background-color:red;padding-top:5px !important;" value="'+cVarInhalt+'" readonly /></div>'
		   	cContainer += '<INPUT TYPE=TEXT NAME="Textfeld1" STYLE="border:none;border-color:transparent;font-size: '+cETFSize+';font-family:'+cFont+'; width:'+cDivCM+';height:'+cInpZeileCM+' !important;background-color:transparent;" readonly value="'+cVarInhalt+'" /></div>'+CR+LF
				//24.09.2023 12:14 berschreibt fr Inputfelder:
//				aPos[1] := aPosition[1] + Val(cEingabeCM)*100	//24.09.2023 12:15
				aPos[1] := aPosition[1] + Len(cVarInhalt)*nFBreite*10
				aPos[2]=aPosition[2]
			ELSEIF Val(cTextHoeheCM) > 0
				cTopCM := LTrim(Str(aPosition[2]/100+Val(cZeileCM)-Val(cTextHoeheCM)))+"cm"
				cLeftCM := LTrim(Str(aPosition[1]/100))+"cm"
				cContainer += '<div style="position:absolute;top:'+cTopCM+';left:'+cLeftCM+';width:'+cEingabeCM+';height:'+cTextHoeheCM+';">'
		   	cContainer += '<TEXTAREA TYPE=TEXT NAME="Textfeld1" STYLE="font-size: '+cETFSize+';font-family:'+cFont+'; width:'+cEingabeCM+';height:'+cTextHoeheCM+' !important;overflow:hidden;">'+cVarInhalt+'</textarea></div>'+CR+LF
				//24.09.2023 12:14 berschreibt fr Inputfelder:
				aPos[1] := aPosition[1] + Val(cEingabeCM)*100	//24.09.2023 12:15
				aPos[2]=aPosition[2]
			ELSE
				cContainer += '<div style="position:absolute;top:'+cTopCM+';left:'+cLeftCM+';width:'+cEingabeCM+';height:'+cZeileCM+';padding-bottom:0px;border:none;">'
//19.11.2023 10:38				IF Upper(cVarInhalt) == "X"
				IF !Empty(cVarInhalt) .AND. "C"==Upper(cVarInhalt[1]) .AND. "X"==Upper(cVarInhalt[Len(cVarInhalt)])
					check := IIf(cVarInhalt=="X",'checked="checked"',"")
			   	cContainer += '<INPUT TYPE=CHECKBOX NAME="CHECKBOX1" STYLE="font-size: '+cETFSize+';font-family:'+cFont+'; width:'+cZeileCM+';height:'+cZeileCM+' !important;" value="'+cVarInhalt+'" '+check+' /></div>'+CR+LF
				ELSEIF !Empty(cVarInhalt) .AND. "R"==Upper(cVarInhalt[1]) .AND. "X"==Upper(cVarInhalt[Len(cVarInhalt)])
					check := IIf(cVarInhalt[Len(cVarInhalt)]=="X",'checked="checked"',"")
					cRadioName := SubStr(cVarInhalt,1,Len(cVarInhalt)-1)
			   	cContainer += '<INPUT TYPE=RADIO NAME="'+cRadioName+'" STYLE="font-size: '+cETFSize+';font-family:'+cFont+'; width:'+cZeileCM+';height:'+cZeileCM+' !important;" value="'+cVarInhalt+'" '+check+' /></div>'+CR+LF
			   ELSE
			   	cContainer += '<INPUT TYPE=TEXT NAME="Textfeld1" STYLE="position:absolute;bottom:0px !important;padding-bottom:0px !important;font-size: '+cETFSize+';font-family:'+Chr(39)+cFont+Chr(39)+'; width:'+cEingabeCM+';height:'+cInpZeileCM+' !important;" value="'+cVarInhalt+'" /></div>'+CR+LF
			   ENDIF
				//24.09.2023 12:14 berschreibt fr Inputfelder:
				aPos[1] := aPosition[1] + Val(cEingabeCM)*100	//24.09.2023 12:15
				aPos[2]=aPosition[2]
		   ENDIF
	   ENDIF
		nEingabeVor := Val(cEingabeCM)
	ENDDO
/*	IF nSO > 0
		cContainer += '</DIV>'
	ENDIF*/
RETURN cString

// 28.03.2023 19:00 holt in der richtigen Area FLD_LEN und FLD_DEC
FUNCTION F_Info(cVariable)
	LOCAL nFLD := Array(2)
	IF cVariable[1] == "("
		cA := SubStr(cVariable,2,At("->",cVariable))
		cVar := SubStr(cVariable,At(">",cVariable)+1,Len(cVariable)-Len(cA)-2)
	ELSE
		cA := SubStr(cVariable,1,At("->",cVariable)+1)
		cVar := SubStr(cVariable,At(">",cVariable)+1,Len(cVariable)-Len(cA))
	ENDIF
	nFLD[1] := &cA->(FieldInfo(&cA->(FieldPos(cVar)),FLD_LEN))
	nFLD[2] := &cA->(FieldInfo(&cA->(FieldPos(cVar)),FLD_DEC))
//               FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-3)),FLD_LEN), ;
//               FieldInfo(FieldPos(SubStr(cVariable,At(">",cVariable)+1,nVarLen-3)),FLD_DEC) ;
RETURN nFLD

//gewinnt die genaue Fontbreite aus der GraQueryTextBox
FUNCTION FontBreite(cFontName,cFontPt)
LOCAL nFBreite, oPSb, oFontb, aTextBox, cFont := LTrim(Str(Val(cFontPt)))+"."+cFontName

	oPSb := PrinterPS(cDruckerName)	//27.08.2023 cDruckerName
	oFontb := XbpFont():new(oPSb)
	oFontb:CREATE(cFont)
	GraSetFont(oPSb,oFontb)
	aTextBox := GraQueryTextBox(oPSb,Space(10))	//18.09.2023 16:03 Space(10) ist aber identisch mit "          " !!
	nFBreite := aTextBox[5,1]/100
	
RETURN nFBreite

//06.11.2022 10:37 Suche in offener Auftragsdatei
FUNCTION SucheInDatei(nA,cFeld,cInhalt)
	LOCAL nOldArea := SELECT()
	LOCAL cAntwort := "nein"
	LOCAL cAuf := Str(1->auftrnr,6,0)
	LOCAL nRec
	PRIVATE cF := cFeld
	SELECT(nA)
	nRec := RecNo()
	DbSuspendNotifications()
      DbSeek(cAuf,.F.)	//13.11.2018 18:48 statt: FIND &cAuf
      DO WHILE 3->auftrnr=Val(cAuf) .and. .not. eof()
			IF Upper(cInhalt)$Upper(3->&cF)
				cAntwort := "ja"
			ENDIF
			DbSkip()
		ENDDO
	DbGoto(nRec)
	DbResumeNotifications()
	SELECT(nOldArea)
RETURN cAntwort

//12.09.2023 21:17 Prompt abtrennen
FUNCTION OhnePrompt(cText,cTrenner)
	DEFAULT cTrenner TO ":"
RETURN AllTrim(SubStr(cText,At(cTrenner,cText)+1))

//02.11.2023 10:54 wofr wird das noch gebraucht??:
//28.09.2023 09:40 Seitenumbruch fr weitere Seiten mit Formular
FUNCTION NeuesFormular(cHintergrund)
	DEFAULT cHintergrund TO ""
RETURN cHintergrund

//02.11.2023 10:50 berechnet width/height des Formulars (==> portrait oder landscape)
FUNCTION FormSize(cFormular)
	LOCAL oBitmap, cXCM, cYcm
	oBitmap := XbpBitmap():new():CREATE(XbpPresSpace():new())
	oBitmap:loadFile(cDatver + cFormular)
	cXCM := IIf(oBitmap:xsize < oBitmap:ysize,"21cm","29.7cm")
	cYCM := IIf(oBitmap:ysize < oBitmap:xsize,"21cm","29.7cm")
RETURN {cXCM,cYCM}

//02.11.2023 13:20 um CodeBl”cke im inditext einzusparen: vvvvvvvvvvvvvvvvvvvvvvvvvvvvv
//02.11.2023 13:26 zum Ankreuzen der richtigen Bestattungsart
FUNCTION EFzuX(bestart)
RETURN IIf(1->best_art==bestart,"X","")

//02.11.2023 13:16
FUNCTION EF_Friedhof()
RETURN IIf(!Empty(1->&TO2),1->&TO2,1->&TO4)

//02.11.2023 13:16
FUNCTION EF_Wochentag()
RETURN IIf(!Empty(oBest:TW2),oBest:TW2,oBest:TW4)

//02.11.2023 13:16
FUNCTION EF_Datum()
RETURN IIf(!Empty(1->&TD2),1->&TD2,1->&TD4)

//02.11.2023 13:16
FUNCTION EF_Uhrzeit()
RETURN IIf(!Empty(1->&TZ2),1->&TZ2,1->&TZ4)
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
