From 73dccaebc1a651eda52ad7c11161d3ebeffbcb92 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 21 Dec 2022 11:16:01 +0000 Subject: [PATCH 01/52] one1 --- src/ExcelUtils.pas | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index e32d5f90..2b98f3ec 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -88,7 +88,9 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen var NonsensePassword :OleVariant; FromPage, ToPage : OleVariant; + activeSheet : OleVariant; ExitAction :TExitAction; + Sheet : integer; begin //Excel is particuarily sensitive to having \\ at end of filename, eg it won't create file. //so we remove any double \\ @@ -196,7 +198,24 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen begin //CSV pops up alert. must be hidden for automation ExcelApp.Application.DisplayAlerts := False ; - ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat); + + +(* + For Each xWs In Application.ActiveWorkbook.Worksheets + xWs.Copy + xcsvFile = CurDir & "\" & xWs.Name & ".csv" + Application.ActiveWorkbook.SaveAs Filename: = xcsvFile, _ + FileFormat: = xlCSV, CreateBackup: = False + Application.ActiveWorkbook.Saved = True + Application.ActiveWorkbook.Close + Next*) + for Sheet := 0 to ExcelApp.Application.ActiveWorkbook.WorkSheets.Count() -1 do + begin + activeSheet := ExcelApp.Application.ActiveWorkbook.WorkSheets[Sheet]; + activeSheet.SaveAs( OutputFilename + inttostr(Sheet), OutputFileFormat); + end; + + ExcelApp.ActiveWorkBook.save; end else From 01ad68804a6ff530c978c4dc21b872bc9386992e Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 21 Dec 2022 16:27:42 +0000 Subject: [PATCH 02/52] output multisheets to multiple files --- src/ExcelUtils.pas | 17 ++++++++++++++--- src/MainUtils.pas | 12 +++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index 2b98f3ec..7a6d4b26 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -89,6 +89,7 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen NonsensePassword :OleVariant; FromPage, ToPage : OleVariant; activeSheet : OleVariant; + dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String; ExitAction :TExitAction; Sheet : integer; begin @@ -209,10 +210,20 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen Application.ActiveWorkbook.Saved = True Application.ActiveWorkbook.Close Next*) - for Sheet := 0 to ExcelApp.Application.ActiveWorkbook.WorkSheets.Count() -1 do + dynamicoutputDir := ExtractFilePath(OutputFilename); // includes last \ + dynamicoutputFile := ChangefileExt ( ExtractFileName(OutputFilename),''); + dynamicoutputExt := ExtractFileExt(OutputFilename); + + for Sheet := 1 to ExcelApp.ActiveWorkbook.WorkSheets.Count do begin - activeSheet := ExcelApp.Application.ActiveWorkbook.WorkSheets[Sheet]; - activeSheet.SaveAs( OutputFilename + inttostr(Sheet), OutputFileFormat); + activeSheet := ExcelApp.ActiveWorkbook.Sheets[Sheet]; + dynamicSheetName := activeSheet.Name; + LogDebug(dynamicSheetName); + dynamicSheetName := SafeFileName(dynamicSheetName); + dynamicOutputFilename := dynamicoutputDir + dynamicoutputFile + '_(' + inttostr(Sheet) + dynamicSheetName + ')' + dynamicoutputExt; + LogDebug(dynamicOutputFileName); + + activeSheet.SaveAs( dynamicoutputFilename, OutputFileFormat); end; diff --git a/src/MainUtils.pas b/src/MainUtils.pas index 76155b7e..a75bc4d7 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -217,6 +217,7 @@ TDocumentConverter = class // Check Should Ignore function CheckShouldIgnore(DocumentPath : String): Boolean; + function SafeFileName(FileName: String ) : String; public @@ -648,7 +649,8 @@ function TDocumentConverter.Execute: string; try StartTime := GettickCount(); - logdebug('Executing Conversion ... ',VERBOSE); + logdebug('Executing Conversion ... ',VERBOSE); + ConversionInfo := ExecuteConversion(FileToConvert, FileToCreate, OutputFileFormat); if ConversionInfo.Successful then @@ -1584,6 +1586,14 @@ procedure TDocumentConverter.WriteOfficeAppVersion(Version: String); LogDebug('Writing Version to File:' + ConfigFileName,VERBOSE); end; +function TDocumentConverter.SafeFileName(FileName: String): String; +begin + Filename := StringReplace(Filename,'&','_',[rfReplaceAll,rfIgnoreCase]); + Filename := StringReplace(Filename,'/','_',[rfReplaceAll,rfIgnoreCase]); + Filename := StringReplace(Filename,'\\','_',[rfReplaceAll,rfIgnoreCase]); + result := Filename; +end; + procedure TDocumentConverter.SetBitmapMissingFonts(const Value: boolean); begin FBitmapMissingFonts := Value; From 8ebabf338a80cd2720d18c4ea1530e35fad80b4d Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 21 Dec 2022 16:27:48 +0000 Subject: [PATCH 03/52] version --- src/MainUtils.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MainUtils.pas b/src/MainUtils.pas index a75bc4d7..36ecf7f3 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -33,8 +33,8 @@ interface MSVISIO = 4; - DOCTO_VERSION = '1.9.40'; // dont use 0x - choco needs incrementing versions. - DOCTO_VERSION_NOTE = ' (Test Version) '; + DOCTO_VERSION = '2.0.41'; // dont use 0x - choco needs incrementing versions. + DOCTO_VERSION_NOTE = ' (Test Version XLS Multisheet) '; type From 5b1c93c8e67221204db5affa5d63ae24df5190cd Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 21 Dec 2022 16:28:22 +0000 Subject: [PATCH 04/52] config --- src/docto.dproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/docto.dproj b/src/docto.dproj index dbb818c3..b8a068d8 100644 --- a/src/docto.dproj +++ b/src/docto.dproj @@ -208,7 +208,7 @@ 1 - -VS -f "..\test\inputfilesvs/payslips.vsdx" -o "..\test\generatedfiles\" -t vsPDF -l 10 + -XL -f "C:\Development\github\docto\test\inputfilesxl\Week 1 Test.xls" -o "C:\Development\github\docto\test\GeneratedFiles" -T xlCSV -l 10 63 false true @@ -356,13 +356,13 @@ true - + .\ true - + .\ true From d0d0a8ce825217be21851cb8528d26a394e71d78 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Thu, 1 Jun 2023 20:00:03 +0100 Subject: [PATCH 05/52] update --- src/ExtraFiles.res | Bin 349676 -> 349788 bytes test/inputfilesxl/Week 1 Test.xls | Bin 53760 -> 35840 bytes test/inputfilesxl/wk1test.xls | Bin 0 -> 53760 bytes test/testxlsfile.bat | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 test/inputfilesxl/wk1test.xls diff --git a/src/ExtraFiles.res b/src/ExtraFiles.res index 11b8eadce3eb4af4de9e525ff7694654f66edb7d..4a9a4c492d7bcd850064665f254ece82fe0386af 100644 GIT binary patch delta 157 zcmaE}TJ+8u(G4qvS=Wj&Fz8G+)Dzu&NZ5fnTQ@VWptK|{Gp8iAh?h$N4BWsx1t67L ztWc7#09K->5Kxp~kXlqysil{apR7=xnUkZCn^=;Z0hcfYN$9{#fhjivD^D#+ZvHFQ W{#T3ZwCOI(Kjjp delta 49 zcmcb!M)b{U(G4qvS#8A_7<48t)Dzu&NZ5h7xk$XdNSqOfnShuXh*`E5iL<`40|2u# B5Iz6^ diff --git a/test/inputfilesxl/Week 1 Test.xls b/test/inputfilesxl/Week 1 Test.xls index a10f1d6c4a00c5be9182aa0f7c2eaa63a65153ea..fc48dda99c133cac21c1a8a245ce47b43481b1c4 100644 GIT binary patch delta 1681 zcmeHH&ubG=5T3W$#x}M!V%1=ywt7;mCT*(KP&LUWrKN3RvXzQh+%`{Ly6(o!Mr=h= z5K*dN>k|wf#6$5U@kb7N5Rck|)Oaj-@FFOv^x#RwI-5jO3;GY}!o2s*eDlrhz8&7! zlw~Z#O}L0K>8|Gk0Px_zJ;D~qmKqy?s11%Z_!Nbz%*_q440n+LYp|?evW^xa8O!>^ zP(gg4gA5WV;D&WD4+Iv{PdF@$wv?UzE9)SOwam_!`*tHH>`jHkRs|EJP`v2YmEAn= zuz8@=ny@_Ih>|?NrkaDbE=?EpCu;OimWkFc5Z{j6b+%zfh7 zk&G8`!+#_e6~2@!~1t{8Sy%aoxO^#Lb*RT@68ef+tL}-$9lvrQ)q`v z`Ro#I*^tLKxkRs0DEVr$N9BAI6$7DxiN3D|V`h zl;M|E@b!sdhz4UqcQ^E@vQCpG3hQZ^s)l69nhKF{RE+vMMF?n$A{i9Ip%C=YxGaey z2?`NiRt>5P^q7=V4CvAZqx3Y@lT=706ndtRjX_aUsUDL~7v&g;4a*6?BB{d>={QXm z(xNn}DXBu!bg!nLloW_a36#mB6uN_=7>q)xYHzqVh$Jc_$e*Cpz%MiXupXy6gmg_c zM9nV^4TE3Ph85(^*ETc!S|P=B@ryLQM~hSF(4~>&kfhMkk7AYH`bsA{2R%X$a}U%p z?XER6H-0BKpB=4z_;lLN zf5)4Ky_j_t!G~EVyZ%y{JbL9?URicqR_3r0OXe?d7RtWlM@b7yy-HVm&C+&r0r&xN CPP*p+ delta 1812 zcmeH{U2Ka{7{{OI?PxM2L?IACaj`;Z7!8^okpauR9?m?gaHe?>kx~5*OmeX@BQD=bY!`oaa1w8Mbmc zwNncFzrk+-mg8?&xoKy_{_;Jt7mg2J(=6ZuL4H)X#=*>M*wQWwkYTOllpIyw0T=A1dI=A8ZjJE4~@Q>kMQ} zQX*e2wJEQaHnpwd#cha}?6oaipk3@q-d+63GX6ya(ZeG|dB-uvx}^yO44NA&Pu zB1a0{E5gAw6`1cBObB^H_h3lg(BH81=(E_7d=Z>3Mf%yrk&LF&ZwcjEb*C<+HX6Z}+$LuUca0=Tfk8Y=HjO~Nr&PEsdc z`122{3(Rw#l^@DhnP(0147ajXjiaP49EGQEe^i?6Y0Q&{_K94T0;8dnSYFWmZdUEv z8Z%Bvqj?;~ zQcx3&Y#~;SBRi4HY@9=VeSJ`IY34N@Y=_!Yv7BDov5aT6D5rac3^d!4-2s20cJC_6 zd6sxE+t3neZ|i7l?(_w_B2BHd3TyN#)Nr-xF&pyR6%VSK?i+Ia=xeo}d=@Ko z<8vWyb&Yz&BIwIUiRnUD!kfhO?lll9KoC@dDzFx;1Jz(Xr~w5SkG cvZME;w&1}D~Z?; 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 literal 0 HcmV?d00001 diff --git a/test/testxlsfile.bat b/test/testxlsfile.bat index 95b42227..b1eafdcc 100644 --- a/test/testxlsfile.bat +++ b/test/testxlsfile.bat @@ -1,2 +1,2 @@ REM Load csv files convert to xls -"../exe/docto.exe" -XL -f "C:\dev\github\docto\test\inputfilesxl\Week 1 Test.xls" -o "C:\dev\github\docto\test\GeneratedFiles" -T xlPDF -l 10 \ No newline at end of file +"../exe/docto.exe" -XL -f "C:\Development\github\docto\test\inputfilesxl\Week 1 Test.xls" -o "C:\Development\github\docto\test\GeneratedFiles" -T xlPDF -l 10 \ No newline at end of file From 24481b04dfc3f646ab8b0cd6e18bcdc93d79079d Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Sun, 22 Jun 2025 10:52:51 +0100 Subject: [PATCH 06/52] Move To sub methods --- src/ExcelUtils.pas | 103 +++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 31 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index 44246b0e..9b957164 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -22,6 +22,8 @@ interface Private ExcelApp : OleVariant; FExcelVersion : String; + function SingleFileExecuteConversion(fileToConvert, OutputFilename: String; OutputFileFormat: Integer): TConversionInfo; + procedure SaveAsPDF(OutputFilename : string) ; public constructor Create() ; @@ -101,6 +103,7 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen Result.InputFile := fileToConvert; Result.Successful := false; NonsensePassword := 'tfm554!ghAGWRDD'; + LogDebug('in conversion file'); try ExcelApp.Workbooks.Open( FileToConvert, //FileName , EmptyParam, //UpdateLinks , @@ -158,38 +161,35 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen aSave: // Go ahead and save begin + Result := SingleFileExecuteConversion(fileToConvert, OutputFilename, OutputFileFormat); + end; + end; - //Unlike Word, in Excel you must call a different function to save a pdf and XPS. - if OutputFileFormat = xlTypePDF then - begin - if pdfPrintToPage > 0 then - begin - logdebug('PrintFromPage: ' + inttostr(pdfPrintFromPage),debug); - logdebug('PrintToPage: ' + inttostr(pdfPrintToPage),debug); +end; - FromPage := pdfPrintFromPage; - ToPage := pdfPrintToPage; - end else - begin - FromPage := EmptyParam; - ToPage := EmptyParam; - end ; +//Useful Links: +// https://docs.microsoft.com/en-us/office/vba/api/excel.workbooks.open +// https://docs.microsoft.com/en-us/office/vba/api/excel.workbook.exportasfixedformat - ExcelApp.Application.DisplayAlerts := False ; - ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, - OutputFilename, - EmptyParam, //Quality - IncludeDocProps, // IncludeDocProperties, - False,// IgnorePrintAreas, - FromPage , // From, - ToPage, // To, - pdfOpenAfterExport, // OpenAfterPublish, (default false); - EmptyParam// FixedFormatExtClassPtr - ) ; +function TExcelXLSConverter.SingleFileExecuteConversion(fileToConvert: String; OutputFilename: String; OutputFileFormat : Integer): TConversionInfo; +var + NonsensePassword :OleVariant; + FromPage, ToPage : OleVariant; + activeSheet : OleVariant; + dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String; + ExitAction :TExitAction; + Sheet : integer; +begin - ExcelApp.ActiveWorkBook.Saved := True + logdebug('SingleFileExecuteConversion',VERBOSE); + + //Unlike Word, in Excel you must call a different function to save a pdf and XPS. + if OutputFileFormat = xlTypePDF then + begin + + SaveAsPDF(OutputFilename); end @@ -201,6 +201,9 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen end else if OutputFileFormat = xlCSV then begin + + LogDebug('output to csv format'); + //CSV pops up alert. must be hidden for automation ExcelApp.Application.DisplayAlerts := False ; @@ -214,17 +217,20 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen Application.ActiveWorkbook.Saved = True Application.ActiveWorkbook.Close Next*) - dynamicoutputDir := ExtractFilePath(OutputFilename); // includes last \ + dynamicoutputDir := ExtractFilePath(OutputFilename); // includes last \ dynamicoutputFile := ChangefileExt ( ExtractFileName(OutputFilename),''); dynamicoutputExt := ExtractFileExt(OutputFilename); for Sheet := 1 to ExcelApp.ActiveWorkbook.WorkSheets.Count do begin - activeSheet := ExcelApp.ActiveWorkbook.Sheets[Sheet]; + activeSheet := ExcelApp.ActiveWorkbook.Sheets[Sheet]; dynamicSheetName := activeSheet.Name; + LogDebug(dynamicSheetName); + dynamicSheetName := SafeFileName(dynamicSheetName); dynamicOutputFilename := dynamicoutputDir + dynamicoutputFile + '_(' + inttostr(Sheet) + dynamicSheetName + ')' + dynamicoutputExt; + LogDebug(dynamicOutputFileName); activeSheet.SaveAs( dynamicoutputFilename, OutputFileFormat); @@ -234,7 +240,7 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen ExcelApp.ActiveWorkBook.save; //ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat); - //ExcelApp.ActiveWorkBook.saved := true; + //ExcelApp.ActiveWorkBook.saved := true; end else begin @@ -250,8 +256,6 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen Result.OutputFile := OutputFilename; ExcelApp.ActiveWorkbook.Close(); - end; - end; end; @@ -277,4 +281,41 @@ function TExcelXLSConverter.OfficeAppVersion(): String; result := FExcelVersion; end; + +procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; +var + + FromPage, ToPage : OleVariant; + +begin + + if pdfPrintToPage > 0 then + begin + logdebug('PrintFromPage: ' + inttostr(pdfPrintFromPage),debug); + logdebug('PrintToPage: ' + inttostr(pdfPrintToPage),debug); + + FromPage := pdfPrintFromPage; + ToPage := pdfPrintToPage; + + end else + begin + FromPage := EmptyParam; + ToPage := EmptyParam; + end ; + + ExcelApp.Application.DisplayAlerts := False ; + ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, + OutputFilename, + EmptyParam, // Quality + IncludeDocProps, // IncludeDocProperties, + False, // IgnorePrintAreas, + FromPage , // From, + ToPage, // To, + pdfOpenAfterExport, // OpenAfterPublish, (default false); + EmptyParam // FixedFormatExtClassPtr + ) ; + + ExcelApp.ActiveWorkBook.Saved := True +end; + end. From 7e9a34444d78b0eaa15bbc515ce0b5426f87789e Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Sun, 22 Jun 2025 10:52:59 +0100 Subject: [PATCH 07/52] ver --- src/MainUtils.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MainUtils.pas b/src/MainUtils.pas index 1e3d54ab..691e71d0 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -33,8 +33,8 @@ interface MSVISIO = 4; - DOCTO_VERSION = '2.0.41'; // dont use 0x - choco needs incrementing versions. - DOCTO_VERSION_NOTE = ' (Test Version XLS Multisheet) '; + DOCTO_VERSION = '2.0.42'; // dont use 0x - choco needs incrementing versions. + DOCTO_VERSION_NOTE = ' (Test Version XLS Multisheet B) '; type From 7e5f12171418ffc1fa1c3558ef396d23c6a2af43 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Sun, 22 Jun 2025 10:53:12 +0100 Subject: [PATCH 08/52] new t est file with multiple sheets --- test/inputfilesxl/wk1test-MultiSheet.xls | Bin 0 -> 61952 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/inputfilesxl/wk1test-MultiSheet.xls diff --git a/test/inputfilesxl/wk1test-MultiSheet.xls b/test/inputfilesxl/wk1test-MultiSheet.xls new file mode 100644 index 0000000000000000000000000000000000000000..8149bd1a00386e0f0954423c3a0e0245791318de GIT binary patch literal 61952 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 literal 0 HcmV?d00001 From a1ea1cfd02d6ff94dae216c0daba0625e96114b0 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Sun, 22 Jun 2025 10:58:43 +0100 Subject: [PATCH 09/52] add xps --- src/ExcelUtils.pas | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index 9b957164..f5580538 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -24,6 +24,7 @@ interface FExcelVersion : String; function SingleFileExecuteConversion(fileToConvert, OutputFilename: String; OutputFileFormat: Integer): TConversionInfo; procedure SaveAsPDF(OutputFilename : string) ; + procedure SaveAsXPS(OutputFilename: string); public constructor Create() ; @@ -195,9 +196,7 @@ function TExcelXLSConverter.SingleFileExecuteConversion(fileToConvert: String; O end else if OutputFileFormat = xlTypeXPS then begin - ExcelApp.Application.DisplayAlerts := False ; - ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypeXPS, OutputFilename ); - ExcelApp.ActiveWorkBook.save; + SaveAsXPS(OutputFilename); end else if OutputFileFormat = xlCSV then begin @@ -318,4 +317,13 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; ExcelApp.ActiveWorkBook.Saved := True end; + +procedure TExcelXLSConverter.SaveAsXPS(OutputFilename : string) ; +begin + + ExcelApp.Application.DisplayAlerts := False ; + ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypeXPS, OutputFilename ); + ExcelApp.ActiveWorkBook.save; +end; + end. From 44b7f42c17dc9e83f8c49bcae3d1087aae0f150a Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Sun, 22 Jun 2025 17:59:46 +0100 Subject: [PATCH 10/52] Move csv --- src/ExcelUtils.pas | 128 ++++++++++++----------- test/inputfilesxl/wk1test-MultiSheet.xls | Bin 61952 -> 55296 bytes 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index f5580538..5a978156 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -201,45 +201,15 @@ function TExcelXLSConverter.SingleFileExecuteConversion(fileToConvert: String; O else if OutputFileFormat = xlCSV then begin - LogDebug('output to csv format'); - //CSV pops up alert. must be hidden for automation - ExcelApp.Application.DisplayAlerts := False ; - - -(* - For Each xWs In Application.ActiveWorkbook.Worksheets - xWs.Copy - xcsvFile = CurDir & "\" & xWs.Name & ".csv" - Application.ActiveWorkbook.SaveAs Filename: = xcsvFile, _ - FileFormat: = xlCSV, CreateBackup: = False - Application.ActiveWorkbook.Saved = True - Application.ActiveWorkbook.Close - Next*) - dynamicoutputDir := ExtractFilePath(OutputFilename); // includes last \ - dynamicoutputFile := ChangefileExt ( ExtractFileName(OutputFilename),''); - dynamicoutputExt := ExtractFileExt(OutputFilename); - - for Sheet := 1 to ExcelApp.ActiveWorkbook.WorkSheets.Count do - begin - activeSheet := ExcelApp.ActiveWorkbook.Sheets[Sheet]; - dynamicSheetName := activeSheet.Name; - LogDebug(dynamicSheetName); + // to get sheets + // Sheets(Array("Sheet4", "Sheet5")) or Sheets(3) or Sheets(Array(1,2)) - dynamicSheetName := SafeFileName(dynamicSheetName); - dynamicOutputFilename := dynamicoutputDir + dynamicoutputFile + '_(' + inttostr(Sheet) + dynamicSheetName + ')' + dynamicoutputExt; - LogDebug(dynamicOutputFileName); - activeSheet.SaveAs( dynamicoutputFilename, OutputFileFormat); - end; - - - ExcelApp.ActiveWorkBook.save; - - //ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat); - //ExcelApp.ActiveWorkBook.saved := true; + ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat); + ExcelApp.ActiveWorkBook.saved := true; end else begin @@ -288,41 +258,79 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; begin - if pdfPrintToPage > 0 then - begin - logdebug('PrintFromPage: ' + inttostr(pdfPrintFromPage),debug); - logdebug('PrintToPage: ' + inttostr(pdfPrintToPage),debug); + if pdfPrintToPage > 0 then + begin + logdebug('PrintFromPage: ' + inttostr(pdfPrintFromPage),debug); + logdebug('PrintToPage: ' + inttostr(pdfPrintToPage),debug); + + FromPage := pdfPrintFromPage; + ToPage := pdfPrintToPage; + + end else + begin + FromPage := EmptyParam; + ToPage := EmptyParam; + end ; + + ExcelApp.Application.DisplayAlerts := False ; + ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, + OutputFilename, + EmptyParam, // Quality + IncludeDocProps, // IncludeDocProperties, + False, // IgnorePrintAreas, + FromPage , // From, + ToPage, // To, + pdfOpenAfterExport, // OpenAfterPublish, (default false); + EmptyParam // FixedFormatExtClassPtr + ) ; + + ExcelApp.ActiveWorkBook.Saved := True +end; - FromPage := pdfPrintFromPage; - ToPage := pdfPrintToPage; - end else - begin - FromPage := EmptyParam; - ToPage := EmptyParam; - end ; +procedure TExcelXLSConverter.SaveAsXPS(OutputFilename : string) ; +begin ExcelApp.Application.DisplayAlerts := False ; - ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, - OutputFilename, - EmptyParam, // Quality - IncludeDocProps, // IncludeDocProperties, - False, // IgnorePrintAreas, - FromPage , // From, - ToPage, // To, - pdfOpenAfterExport, // OpenAfterPublish, (default false); - EmptyParam // FixedFormatExtClassPtr - ) ; - - ExcelApp.ActiveWorkBook.Saved := True + ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypeXPS, OutputFilename ); + ExcelApp.ActiveWorkBook.save; end; - -procedure TExcelXLSConverter.SaveAsXPS(OutputFilename : string) ; +procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); +var + FromPage, ToPage : OleVariant; + activeSheet : OleVariant; + dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String; + ExitAction :TExitAction; + Sheet : integer; begin + LogDebug('output to csv format'); + //CSV pops up alert. must be hidden for automation ExcelApp.Application.DisplayAlerts := False ; - ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypeXPS, OutputFilename ); + + + + dynamicoutputDir := ExtractFilePath(OutputFilename); // includes last \ + dynamicoutputFile := ChangefileExt ( ExtractFileName(OutputFilename),''); + dynamicoutputExt := ExtractFileExt(OutputFilename); + + for Sheet := 1 to ExcelApp.ActiveWorkbook.WorkSheets.Count do + begin + activeSheet := ExcelApp.ActiveWorkbook.Sheets[Sheet]; + dynamicSheetName := activeSheet.Name; + + LogDebug(dynamicSheetName); + + dynamicSheetName := SafeFileName(dynamicSheetName); + dynamicOutputFilename := dynamicoutputDir + dynamicoutputFile + '_(' + inttostr(Sheet) + dynamicSheetName + ')' + dynamicoutputExt; + + LogDebug(dynamicOutputFileName); + + activeSheet.SaveAs( dynamicoutputFilename, OutputFileFormat); + end; + + ExcelApp.ActiveWorkBook.save; end; diff --git a/test/inputfilesxl/wk1test-MultiSheet.xls b/test/inputfilesxl/wk1test-MultiSheet.xls index 8149bd1a00386e0f0954423c3a0e0245791318de..bcd9766112d23e20243b0dfc6ae2e1bf801c513b 100644 GIT binary patch delta 2314 zcmeHGO-vI}5S}fi5?WwaOQFTqHc>oys1V};f>93`q6g5Jh#;jx3mO$o5TsPLXv73P z2v6alC=xkfRHzR_ywoN}6B8xTaMBo2@n|ejFD6>&b^Ehz*%%JSi*GXR+izxP=6(A; z-$I6OD&x{d?(jfKk@^q-_-iIP8s;1-GO8(~_3G^^`dVYth`AX19<~BZZWj%F2)7b5M=jH2}d#6+<$vjo}3e+=^RdSIRFS?YzCD zFcyu^B+1Sg!{?w8x2D)zCNjs{xgw$#?4(I3G@286PJk`(X)Lr^Sf9B;2Rh)u3Xp|) zktH?HNykZ_VX@Ggr3Y_3m%VTXynT<~(?UC|l_tYJ#2;32`0n{;At zK&#p50(jR&d}aH{6K5saR$k3 zL*3J;nswIzCZ-g4qK=tY94c%rD(Sz%7=IpA*l~^;o?E!V*`V2Xf9gfu$2Z(oBnUoN zJlo-VD($PPX6xwN*|XM)U*T|gKSt}&>(LLOH=sMv8_`+(ApSR@H>2Zi2RC{PdMkPP o#XiuuX)tsobN)li&@pl%bY9iwCqF_Su9lo!6m?EaLoG(uZ$<&@ga7~l delta 2922 zcmd^9T})g>6h3qJvMhhQ_ga=;DR)h=wb(2mQCcWq3$0BWTO`EN)&d3kqex4og;I2v zs?jJ9$e1EnK%*w6{K~$>kD1D3|Cz**$h&B5Z$$G@<|o zqRFG$EG5%Q{u2xSk_G>%1^;$5?~7Xaa0hP#)+T>BEEqdg zA8T%IFL;@pv^}6d@o;UD@2oJ;IEfwF=J6u;3H$1hfdv5Q6uA0K^dhoosd>F~y_8f~B&s-|s}hn`Ol zAQaJ-RC92+tI_~0HsQS9gsI(VQsO|GuoUcuW+ z_V)*6?rl`?(Y=i~86@jioc?nlQ(_A2Pcj?+f8gq*P4M$5oucEo6D@qKxC~R`i2Qy( z41K(+^g;d4zzkzDY`Lx)YNd8)+o^?`sR=%M)I8dPxT64N7QDp30VKC3-H4>rErKps z-XZmxpgB=+0{Pmw<&iT^Q~;xtlViWm|xH<;&SqJ<|iCW6Pt zv$5B);?3J)VZhFoe#GxWhe+)ZUgkoJvC9U{jLRd8t?PH);(JRsAsglKW}HS^*RUp} zwNjE9Qigo&j*HIbW;=6GZ*MOoiITa|I2H@pj9fy$#Dd1z+QL~bl=Xj)6iGHe-QWL? z`!0PbA9i`9_~{X%^eaTedib$avVL{pA(N8P>U?Dv$y%%j-{9`0Xor`->Gw5jBRoH=+dH z8+McxRe}^+8?HQy73jN{R5hvsc@WcTDv-I12eo^#0(r2^QXidq`2{A~Yp)VrzqYER z<`_xM9r=MVKc62>y=(8~NyhsIO1Y-ba(~IU{eg)r`n9V5(#|PXF6zebTd(bG{@NJ( zCH3}h{d(X<%~uP{e&7Ib5O@kW1k?fbKm%|XXarE Date: Sun, 22 Jun 2025 17:59:59 +0100 Subject: [PATCH 11/52] add param --- src/MainUtils.pas | 10 ++++++++++ src/res/HelpLog.txt | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/MainUtils.pas b/src/MainUtils.pas index 691e71d0..b5cd9df2 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -71,6 +71,7 @@ TDocumentConverter = class FKeepIRM: boolean; FDocStructureTags: boolean; FBitmapMissingFonts: boolean; + Fsheets: TStrings; procedure SetCompatibilityMode(const Value: Integer); @@ -95,6 +96,7 @@ TDocumentConverter = class procedure SetKeepIRM(const Value: boolean); procedure SetDocStructureTags(const Value: boolean); procedure SetBitmapMissingFonts(const Value: boolean); + procedure Setsheets(const Value: TStrings); protected @@ -184,6 +186,7 @@ TDocumentConverter = class property pdfPrintToPage : integer read FpdfPrintToPage; property useISO190051 : boolean read FuseISO190051; property pdfOptimizeFor : integer read fpdfOptimizeFor write fpdfOptimizeFor; + property sheets : TStrings read Fsheets write Setsheets; property ExportMarkup : integer read fExportMarkup; property IncludeDocProps : boolean read FIncludeDocProps write SetIncludeDocProps; @@ -519,6 +522,7 @@ constructor TDocumentConverter.Create; FBitmapMissingFonts := true; FInputFiles := TStringList.Create; fDontUseAutoVBA := true; + fSheets := TStringList.Create; end; @@ -540,6 +544,7 @@ destructor TDocumentConverter.Destroy; FInputFiles.Free; + fSheets.Free; if assigned(FNetHandle) then begin @@ -1860,6 +1865,11 @@ procedure TDocumentConverter.SetRemoveFileOnConvert(const Value: boolean); +procedure TDocumentConverter.Setsheets(const Value: TStrings); +begin + Fsheets := Value; +end; + procedure TDocumentConverter.SetSkipDocsWithTOC(const Value: Boolean); begin FSkipDocsWithTOC := Value; diff --git a/src/res/HelpLog.txt b/src/res/HelpLog.txt index 6ecb0414..ddbdbfec 100644 --- a/src/res/HelpLog.txt +++ b/src/res/HelpLog.txt @@ -112,10 +112,14 @@ Long Parameters: --PDF-no-BitmapMissingFonts Do not bitmap missing fonts, fonts will be substituted. --use-ISO190051 - Create PDF to the ISO 19005-1 standard. + Create PDF to the ISO 19005-1 standard. + --enable-wordvbaauto By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word Only. + --sheets + Select which sheets to save. Can be comma seperated list of 0 index numbers or sheet names + Experimental: From ad7310f3ea9554227a9f3ea4a03d9b97418ad6c4 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Sun, 22 Jun 2025 18:01:21 +0100 Subject: [PATCH 12/52] named --- src/MainUtils.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/MainUtils.pas b/src/MainUtils.pas index b5cd9df2..d7b6cf2d 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -522,7 +522,7 @@ constructor TDocumentConverter.Create; FBitmapMissingFonts := true; FInputFiles := TStringList.Create; fDontUseAutoVBA := true; - fSheets := TStringList.Create; + fSelectedSheets := TStringList.Create; end; @@ -544,7 +544,7 @@ destructor TDocumentConverter.Destroy; FInputFiles.Free; - fSheets.Free; + fSelectedSheets.Free; if assigned(FNetHandle) then begin @@ -1867,7 +1867,7 @@ procedure TDocumentConverter.SetRemoveFileOnConvert(const Value: boolean); procedure TDocumentConverter.Setsheets(const Value: TStrings); begin - Fsheets := Value; + fSelectedSheets := Value; end; procedure TDocumentConverter.SetSkipDocsWithTOC(const Value: Boolean); From d83db6cc82141a5010707c4056315d7edcd03041 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Sun, 22 Jun 2025 19:29:47 +0100 Subject: [PATCH 13/52] working with selected tabs (selected manually) --- src/ExcelUtils.pas | 63 +++++++++++++++++++++-- src/MainUtils.pas | 7 +-- src/res/HelpLog.txt | 5 +- test/inputfilesxl/wk1test-MultiSheet.xls | Bin 55296 -> 55296 bytes 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index 5a978156..4d45c295 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -14,7 +14,9 @@ ****************************************************************) interface -uses Classes,Sysutils, MainUtils, ResourceUtils, ActiveX, ComObj, WinINet, Variants, Excel_TLB_Constants,StrUtils; +uses Classes,Sysutils, MainUtils, ResourceUtils, ActiveX, ComObj, WinINet, Variants, + + Excel_TLB_Constants,StrUtils; type @@ -25,6 +27,7 @@ interface function SingleFileExecuteConversion(fileToConvert, OutputFilename: String; OutputFileFormat: Integer): TConversionInfo; procedure SaveAsPDF(OutputFilename : string) ; procedure SaveAsXPS(OutputFilename: string); + procedure SaveAsCSV(OutputFilename: string); public constructor Create() ; @@ -254,9 +257,12 @@ function TExcelXLSConverter.OfficeAppVersion(): String; procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; var - FromPage, ToPage : OleVariant; + FromPage, ToPage, SheetList, ExcelSheets : OleVariant; + Sheet1,Sheet2,Sheet3 , Workbook , SheetsArray: OleVariant; + activeSheet : OleVariant; begin + ExcelApp.Application.DisplayAlerts := False ; if pdfPrintToPage > 0 then begin @@ -271,9 +277,53 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; FromPage := EmptyParam; ToPage := EmptyParam; end ; +(* + Sheets(Array("Wednesday Lunch", "Sheet2", "Sheet3")).Select + Sheets("Wednesday Lunch").Activate + ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _ + "C:\Development\github\docto\test\GeneratedTestputFiles\wk1test-MultiShasdfasdfeetmulti635345.pdf" _ + , Quality:=xlQualityStandard, IncludeDocProperties:=True, IgnorePrintAreas _ + :=False, OpenAfterPublish:=False + ActiveCell.FormulaR1C1 = "" + Range("AM13").Select +End Sub*) + + if SelectedSheets.Count = 0 then + begin + logDebug('Selecting sheets',VERBOSE); + SheetList := VarArrayCreate([0, 2], varVariant); // 3 sheets + SheetList[0] := 'Wednesday Lunch'; + SheetList[1] := 'Sheet2'; + SheetList[2] := 'Sheet3'; + + Workbook := ExcelApp.activeWorkbook; + // Get references to the individual sheets + // Sheet1 := Workbook.Worksheets[3]; + // Sheet2 := Workbook.Worksheets[2] ; + // Sheet3 := Workbook.Worksheets[1]; + + // Create a variant array of the sheet COM objects + SheetsArray := VarArrayCreate([0, 1], varVariant); + SheetsArray[0] := 2; + SheetsArray[1] := 3; +// SheetsArray[2] := 3; + + // Select the sheets +// ExcelApp.activeWorkbook.worksheets(SheetsArray).Select; + +// ExcelApp.activeWorkbook.worksheets.Select(3); +//ExcelApp.activeWorkbook.Sheets.Item[2].Select; + + activeSheet := ExcelApp.ActiveWorkbook.Sheets[2]; + logDebug('SeT sheets',VERBOSE); + // ExcelApp.ActiveWorkBook.save; + end ; + + + ExcelApp.Application.DisplayAlerts := False ; - ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, + activeSheet.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, OutputFilename, EmptyParam, // Quality IncludeDocProps, // IncludeDocProperties, @@ -284,7 +334,13 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; EmptyParam // FixedFormatExtClassPtr ) ; + + + + + ExcelApp.ActiveWorkBook.Saved := True + end; @@ -309,6 +365,7 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); //CSV pops up alert. must be hidden for automation ExcelApp.Application.DisplayAlerts := False ; + // if fSelectedSheets.Count > 0 then dynamicoutputDir := ExtractFilePath(OutputFilename); // includes last \ diff --git a/src/MainUtils.pas b/src/MainUtils.pas index d7b6cf2d..627bdbdf 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -19,7 +19,7 @@ interface Const VERBOSE = 10; - DEBUG = 9; + DEBUG = 9; HELP = 8; CHATTY = 5; STANDARD = 2; @@ -71,7 +71,7 @@ TDocumentConverter = class FKeepIRM: boolean; FDocStructureTags: boolean; FBitmapMissingFonts: boolean; - Fsheets: TStrings; + fSelectedSheets: TStrings; procedure SetCompatibilityMode(const Value: Integer); @@ -186,7 +186,8 @@ TDocumentConverter = class property pdfPrintToPage : integer read FpdfPrintToPage; property useISO190051 : boolean read FuseISO190051; property pdfOptimizeFor : integer read fpdfOptimizeFor write fpdfOptimizeFor; - property sheets : TStrings read Fsheets write Setsheets; + property SelectedSheets : TStrings read fSelectedSheets write Setsheets; + property ExportMarkup : integer read fExportMarkup; property IncludeDocProps : boolean read FIncludeDocProps write SetIncludeDocProps; diff --git a/src/res/HelpLog.txt b/src/res/HelpLog.txt index ddbdbfec..29070d70 100644 --- a/src/res/HelpLog.txt +++ b/src/res/HelpLog.txt @@ -118,8 +118,9 @@ Long Parameters: By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word Only. --sheets - Select which sheets to save. Can be comma seperated list of 0 index numbers or sheet names - + Select which sheets to save. Can be comma seperated list of 0 index numbers or sheet names. Excel Only. + --allsheets + If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names Experimental: diff --git a/test/inputfilesxl/wk1test-MultiSheet.xls b/test/inputfilesxl/wk1test-MultiSheet.xls index bcd9766112d23e20243b0dfc6ae2e1bf801c513b..e8adeea7f0f8ba11356d4b215b0093c21d3e5709 100644 GIT binary patch delta 72 zcmV-O0Jr~uumgaw1F+@-1poj500Oh?0=ZoQ4zs0Ta~qS8mnySDd`=qy0+W%KDU;S< e6tm8k3mpWH0=ZoQ2(zVNa~lB$laZGxvqF4M8oXmmTt3g){g Date: Sun, 22 Jun 2025 20:32:30 +0100 Subject: [PATCH 14/52] using active sheet pdf manually selected sheets. not selected sheets --- src/ExcelUtils.pas | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index 4d45c295..fefe19f3 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -312,11 +312,12 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; // ExcelApp.activeWorkbook.worksheets(SheetsArray).Select; // ExcelApp.activeWorkbook.worksheets.Select(3); -//ExcelApp.activeWorkbook.Sheets.Item[2].Select; +//ExcelApp.activeWorkbook.Sheets.Item[2] .Select; + + activeSheet := ExcelApp.ActiveWorkbook.Sheets.Item[3]; - activeSheet := ExcelApp.ActiveWorkbook.Sheets[2]; logDebug('SeT sheets',VERBOSE); - // ExcelApp.ActiveWorkBook.save; + ExcelApp.ActiveWorkBook.save; end ; From d1de629825c3d3e91dd64ebd321fd9f496b11c67 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Sun, 22 Jun 2025 20:32:41 +0100 Subject: [PATCH 15/52] update --- test/inputfilesxl/wk1test-MultiSheet.xls | Bin 55296 -> 55296 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/inputfilesxl/wk1test-MultiSheet.xls b/test/inputfilesxl/wk1test-MultiSheet.xls index e8adeea7f0f8ba11356d4b215b0093c21d3e5709..129dd4c7e49db5038888a54dd7f81a408c36e1b5 100644 GIT binary patch delta 43 ycmZqJz}&EbdBfubM%B$v5+0iYsT0!$WLX>bODe3{e0NK~;^bOuj?E?4dKdwrx)SdI delta 48 zcmZqJz}&EbdBfubM#arf5+0iYsT0!$WLX*dpKPAD`R Date: Sat, 11 Oct 2025 18:37:00 +0100 Subject: [PATCH 16/52] sheets --- src/MainUtils.pas | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/MainUtils.pas b/src/MainUtils.pas index 627bdbdf..ef821b0f 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -1250,6 +1250,14 @@ procedure TDocumentConverter.LoadConfig(Params: TStrings); HaltWithConfigError(205,'Invalid value for --PDF-OPTIMIZEFOR :' + value); end; END + else if (id = '--SHEETS') then + begin + fSelectedSheets.DelimitedText := value; + if fSelectedSheets.Count = 0 then + begin + HaltWithConfigError(205,'Expecting > 0 selected sheets: ' + value); + end; + end else if (id = '--EXPORTMARKUP') then begin if (WordConstants.Exists(value)) then @@ -1282,6 +1290,7 @@ procedure TDocumentConverter.LoadConfig(Params: TStrings); FBitmapMissingFonts := false; dec(iParam); end + else if (id = '-W') or (id = '--WEBHOOK') then begin From 20af80663c408f53f09192a15ec8d4017d74e1ec Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Tue, 18 Nov 2025 16:56:04 +0000 Subject: [PATCH 17/52] MWE --- src/ExcelUtils.pas | 62 ++++++++++++++---------------- src/MainUtils.pas | 2 +- test/inputfilesxl/Week 1 Test.xls | Bin 35840 -> 37376 bytes 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index fefe19f3..dead6c6d 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -259,9 +259,11 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; FromPage, ToPage, SheetList, ExcelSheets : OleVariant; Sheet1,Sheet2,Sheet3 , Workbook , SheetsArray: OleVariant; - activeSheet : OleVariant; + activeSheet, WorkSheets, ws : OleVariant; + I :integer; begin + logdebug('Save as pdf',debug); ExcelApp.Application.DisplayAlerts := False ; if pdfPrintToPage > 0 then @@ -288,44 +290,34 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; Range("AM13").Select End Sub*) - if SelectedSheets.Count = 0 then +logdebug('SelectedSheets.Count:' + inttostr( SelectedSheets.Count), debug); + if SelectedSheets.Count > 0 then begin - logDebug('Selecting sheets',VERBOSE); - SheetList := VarArrayCreate([0, 2], varVariant); // 3 sheets - SheetList[0] := 'Wednesday Lunch'; - SheetList[1] := 'Sheet2'; - SheetList[2] := 'Sheet3'; - - Workbook := ExcelApp.activeWorkbook; - // Get references to the individual sheets - // Sheet1 := Workbook.Worksheets[3]; - // Sheet2 := Workbook.Worksheets[2] ; - // Sheet3 := Workbook.Worksheets[1]; - - // Create a variant array of the sheet COM objects - SheetsArray := VarArrayCreate([0, 1], varVariant); - SheetsArray[0] := 2; - SheetsArray[1] := 3; -// SheetsArray[2] := 3; - - // Select the sheets -// ExcelApp.activeWorkbook.worksheets(SheetsArray).Select; - -// ExcelApp.activeWorkbook.worksheets.Select(3); -//ExcelApp.activeWorkbook.Sheets.Item[2] .Select; - - activeSheet := ExcelApp.ActiveWorkbook.Sheets.Item[3]; - - logDebug('SeT sheets',VERBOSE); - ExcelApp.ActiveWorkBook.save; - end ; + + + logDebug('Selecting sheets' + SelectedSheets.Text,VERBOSE); + + + WorkSheets := ExcelApp.Worksheets; + + logDebug('count:' + inttostr(WorkSheets.Count), verbose); + + for I := 1 to WorkSheets.Count do + begin + Logdebug('cycle:' + inttostr(I) ,debug); + ws := WorkSheets.Item[I]; + + Logdebug('cycleB',debug); + + logDebug('worksheet:' + ws.Name, VERBOSE); + ExcelApp.Application.DisplayAlerts := False ; - activeSheet.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, - OutputFilename, + ws.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, + OutputFilename + 'mm' + inttostr(I), EmptyParam, // Quality IncludeDocProps, // IncludeDocProperties, False, // IgnorePrintAreas, @@ -336,6 +328,10 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; ) ; + end; + + end ; + diff --git a/src/MainUtils.pas b/src/MainUtils.pas index ef821b0f..a4bd9206 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -33,7 +33,7 @@ interface MSVISIO = 4; - DOCTO_VERSION = '2.0.42'; // dont use 0x - choco needs incrementing versions. + DOCTO_VERSION = '2.0.43'; // dont use 0x - choco needs incrementing versions. DOCTO_VERSION_NOTE = ' (Test Version XLS Multisheet B) '; type diff --git a/test/inputfilesxl/Week 1 Test.xls b/test/inputfilesxl/Week 1 Test.xls index fc48dda99c133cac21c1a8a245ce47b43481b1c4..44a8232bb22eb919b4de2cfc46ed517d7828eaa1 100644 GIT binary patch delta 2672 zcmah~Yiv|S6#nM!tGnG-%hGlWZI@OaLV+SsC{%WN^+kEq(Aoqetk$7z`mnH1Y9+q!2O22q!Xeh; z0QR629aw^Vj8Qew_qjoH1|H*%{3kb0OxBe_d&+M;*N{It@;q*w6xz6jhEnLLJW!09uqa%{qR40qrCeaPIJTjMS5 z&6tPY4DNE`d7Uc(J3`DVkVqggKT=X!Qc||ae5b^dUA=Rq5)I(_wq2cVUAtO)BJ~G5 zUv3}Z&NEspR%_RkX8>7Ue{m7X7U!v?(z#})rt|(=Y^7s zM+kgd9YDORbyu8W>X|$)6(vbklTz>jhuRJtYCEJ5zL|i<(74vI+|#0t(8D zl$TnX&B&_n9Z?7NIRkJ~x0e>39D}YD?t*IyKZCv}^WEkj(S*@=nCieVa`?63aN6+T zA-ExA;tdv1$>s6uC6+!yNy+Kx(=x+)lQ|5n7yYDIcEUKKTfp*{k6ynPP(o@PHT%~u z77If3q2vXlT8rruST45eI4xct;>eXZH=GdD%=pIBLd-P(sj3j7K$h1e{6`HBSQ4=H zYGh2Vuf1O+3@1r5P^*nQFq5kV6d9%~2MT1YZlTCFJL{rCgylz@z83lNNc}hA85B|0 zR6Mm@k41-(P0WzZn?DN|C%KvA)^UxP+FK^Mg5QS!C!)a0M zL6HAhEr&y^1=$r0y5(TZ3f%?s?sJA{J%l2f8D>XjvFzRdJ9@Ou2E3RoWfsEJv25hf zMt+)w9=UD%xw%39@q(Kf9}b=Q5M!!RhY0;wQo=RZI7`0Lm@St#-uJ26hA9xh)BG>y zG@Yur#@6gG&f^F1wpb-RVx73pJYB~qzQquJ!As~AuZc48CaGJ9)#wpIu{qYX$n6g> z0(JTXICv41wj9h;J**CRpo9>L17~*wH+P$tT7Gl%jnlyzuwq6~OFEDs#zzD+&CX>y z&GiHtPl(6l+)tpXBSG8i<6_*23LxD{h?LB^dt?O<;EN zX7l&eOc#X%n44r~Xwh*+H(Ms4bEnLx-cCvSG;dr_l{%nHtt3N)0OlucPE=X@Q{e_s z3T(g)_Sk+F?J}EwCSiQ2wJJw3UHT?vK$%vw02b2p4Z19r=i|%#il!=Gthip;(Xu?G zP8L?25Fs?}0sh>>1NH3ebCluDL}@kb+`LFE)z5d)@fmU`I!g}3gMI3}Rp;rxEbF|5 z;h!+7Hf*(xwfU)SV{LjWtw<*+MYB>hIdQ2}+2|=8r)xSHyLa`@gICw7v#E%wA*KF& z>;{w3%>d?+62TfH8=n#bV)_f*c>tWq2ojP6J^l2cfciFNMrEvs!{=wlip$Oquo`j)!`c?q}}P7 zmUfvl!}ttb5qZdfAFo5#-)_t#R*=Lc$7#acsXJvp@OiAu$oXw zc$T2}QO+^KTEaTQdcp?6MuOr$Bs@CR@blpD4%fC9L?-tjyN(YSEqmqP#}A8gdGJJ^ Lm-nu<2TuP2`R(Id delta 1451 zcmah|U2KzO6n@Uvex2*uZiB8X{b5D$LI~3-4Cpqx3T)jE-O6yA7b6x{vud*~taA)z zThv{c8P@I%i$4iL!-dleSiT!g%mOii5u=iLBSyo8*D7);vGu%PJ7#)gPtN}imH86yWik zDHV~bLzva7Vz6jbD|Lun^s3g9G+vUN=7XDIveMzr)HhX`S{hq7ja*51OdARPCYdl~ z+5noL0JZl`x2i?VkvCFDmkIeA6Tb71?pRVWT`2yG zw!3YBb`p5}3g07I&cD~B<=gX0dY0k98XSBYFk41u`~x$4s&JmCEpbjhEv%K3y@aeo z3fpv~e3%1sOlgiP=Gle|@?$C0b79V=10+b&TiSa^pQAl>jF5QZ_@Mr>qE?SS)Iae# z@fw`sw_^)r*CskH6L~c?bckrX2y_)}GD2l+C${h@db=N0t??XGxY30!G19Y_wrUGK z0V0?9w)Z=7iw}?gVD&I|4R*bDm$(@I%DPjxIJpCaZZXg|Z{49=Y}^HD`K#|6PTUPE zTYC`}KlUH@@Ek#kiOVqpDaFi^q7Ud{K=>oa40ssO-i}y^8nnd|m&s#64UF<#OeQ^` z1{Ewr0y|DB6nzsu*4FR>YI#gE|4ZleToIfqwZ4{zGE>Uo;2f^94Clnk%byrR{Iy&k z42sO4QG7P|hqyMB-G73=jD+$jexhaalbIUn5yJQ$_i!6a_?hKNO44q6m!&YbAS6kw zj%?NDh8rqvat7QDZoHJlN_4uWMmKF7i=!gvAJ#6N&Z?CgHi!rDeYT<|KRfx;f(Z{T zjo;e7dZ(eW?mo3k3U+UfKao4D6fzjSH6Eng@Uc(=g&1l}dc1wY7qh}q99{c?YKyKtB}z}(Ip tWPVB1F8-N&)v}aLR9uZG?(?I?RCZo5#Khm(^Yo&a&ZR9a4AdXT*T09qJ(>Uj From bdb7bfce3e21fae8885eff900a38d1a3ddc15c76 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Tue, 18 Nov 2025 17:07:49 +0000 Subject: [PATCH 18/52] save csv files --- src/ExcelUtils.pas | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index dead6c6d..eda8cad3 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -208,11 +208,11 @@ function TExcelXLSConverter.SingleFileExecuteConversion(fileToConvert: String; O // to get sheets // Sheets(Array("Sheet4", "Sheet5")) or Sheets(3) or Sheets(Array(1,2)) + ExcelApp.Application.DisplayAlerts := False ; + SaveAsCSV( OutputFilename); - - - ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat); - ExcelApp.ActiveWorkBook.saved := true; +// ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat); + // ExcelApp.ActiveWorkBook.saved := true; end else begin @@ -279,16 +279,7 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; FromPage := EmptyParam; ToPage := EmptyParam; end ; -(* - Sheets(Array("Wednesday Lunch", "Sheet2", "Sheet3")).Select - Sheets("Wednesday Lunch").Activate - ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _ - "C:\Development\github\docto\test\GeneratedTestputFiles\wk1test-MultiShasdfasdfeetmulti635345.pdf" _ - , Quality:=xlQualityStandard, IncludeDocProperties:=True, IgnorePrintAreas _ - :=False, OpenAfterPublish:=False - ActiveCell.FormulaR1C1 = "" - Range("AM13").Select -End Sub*) + logdebug('SelectedSheets.Count:' + inttostr( SelectedSheets.Count), debug); if SelectedSheets.Count > 0 then @@ -371,6 +362,7 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); for Sheet := 1 to ExcelApp.ActiveWorkbook.WorkSheets.Count do begin + LogDebug('CSV Loop'); activeSheet := ExcelApp.ActiveWorkbook.Sheets[Sheet]; dynamicSheetName := activeSheet.Name; From 1c804e77ba09e4f6846fd6318d11303ff71ec4b9 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Tue, 18 Nov 2025 21:46:19 +0000 Subject: [PATCH 19/52] Export all worksheets --- src/ExcelUtils.pas | 39 +++-- src/MainUtils.pas | 10 +- src/docto.dpr | 3 +- src/docto.dproj | 183 ++++++++++++++++++++---- src/docto.dproj.local | 4 + src/shared/DynamicFileNameGenerator.pas | 71 +++++++++ 6 files changed, 266 insertions(+), 44 deletions(-) create mode 100644 src/shared/DynamicFileNameGenerator.pas diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index eda8cad3..154729ff 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -15,6 +15,7 @@ interface uses Classes,Sysutils, MainUtils, ResourceUtils, ActiveX, ComObj, WinINet, Variants, +DynamicFileNameGenerator, Excel_TLB_Constants,StrUtils; @@ -29,6 +30,8 @@ interface procedure SaveAsXPS(OutputFilename: string); procedure SaveAsCSV(OutputFilename: string); + function isWorkSheetEmpty(WorkSheet : OleVariant): boolean; + public constructor Create() ; function CreateOfficeApp() : boolean; override; @@ -241,6 +244,14 @@ function TExcelXLSConverter.FormatsExtensions: TStringList; result := Extensions; end; +function TExcelXLSConverter.isWorkSheetEmpty(WorkSheet: OleVariant): boolean; +begin + + // this will tell if a sheet is empty. + Result := ExcelApp.WorksheetFunction.CountA(WorkSheet.Cells) = 0; + +end; + function TExcelXLSConverter.OfficeAppVersion(): String; begin FExcelVersion := ReadOfficeAppVersion; @@ -261,7 +272,7 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; Sheet1,Sheet2,Sheet3 , Workbook , SheetsArray: OleVariant; activeSheet, WorkSheets, ws : OleVariant; I :integer; - + FileNameGen: TDynamicFileNameGenerator; begin logdebug('Save as pdf',debug); ExcelApp.Application.DisplayAlerts := False ; @@ -292,15 +303,24 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; WorkSheets := ExcelApp.Worksheets; logDebug('count:' + inttostr(WorkSheets.Count), verbose); - + FileNameGen := TDynamicFileNameGenerator.Create(OutputFilename); for I := 1 to WorkSheets.Count do begin + + Logdebug('cycle:' + inttostr(I) ,debug); ws := WorkSheets.Item[I]; - Logdebug('cycleB',debug); +Logdebug('cycleB',debug); logDebug('worksheet:' + ws.Name, VERBOSE); + if self.isWorkSheetEmpty(ws) then + begin + logInfo('The worksheet "' . ws.Name. '" is Empty and will not be output', STANDARD); + Continue; + end; + + @@ -308,7 +328,7 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; ExcelApp.Application.DisplayAlerts := False ; ws.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, - OutputFilename + 'mm' + inttostr(I), + FileNameGen.Generate(ws.Name), EmptyParam, // Quality IncludeDocProps, // IncludeDocProperties, False, // IgnorePrintAreas, @@ -347,6 +367,7 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String; ExitAction :TExitAction; Sheet : integer; + FileNameGen : TDynamicFileNameGenerator; begin LogDebug('output to csv format'); @@ -356,20 +377,18 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); // if fSelectedSheets.Count > 0 then - dynamicoutputDir := ExtractFilePath(OutputFilename); // includes last \ - dynamicoutputFile := ChangefileExt ( ExtractFileName(OutputFilename),''); - dynamicoutputExt := ExtractFileExt(OutputFilename); + FileNameGen := TDynamicFileNameGenerator.Create(OutputFilename); for Sheet := 1 to ExcelApp.ActiveWorkbook.WorkSheets.Count do begin - LogDebug('CSV Loop'); + LogDebug('CSV Loop'); activeSheet := ExcelApp.ActiveWorkbook.Sheets[Sheet]; dynamicSheetName := activeSheet.Name; LogDebug(dynamicSheetName); - dynamicSheetName := SafeFileName(dynamicSheetName); - dynamicOutputFilename := dynamicoutputDir + dynamicoutputFile + '_(' + inttostr(Sheet) + dynamicSheetName + ')' + dynamicoutputExt; + // dynamicSheetName := SafeFileName(dynamicSheetName); + dynamicOutputFilename := FileNameGen.Generate(dynamicSheetName); //dynamicoutputDir + dynamicoutputFile + '_(' + inttostr(Sheet) + dynamicSheetName + ')' + dynamicoutputExt; LogDebug(dynamicOutputFileName); diff --git a/src/MainUtils.pas b/src/MainUtils.pas index a4bd9206..72a8365d 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -221,7 +221,7 @@ TDocumentConverter = class // Check Should Ignore function CheckShouldIgnore(DocumentPath : String): Boolean; - function SafeFileName(FileName: String ) : String; + public @@ -1658,13 +1658,7 @@ procedure TDocumentConverter.WriteOfficeAppVersion(Version: String); LogDebug('Writing Version to File:' + ConfigFileName,VERBOSE); end; -function TDocumentConverter.SafeFileName(FileName: String): String; -begin - Filename := StringReplace(Filename,'&','_',[rfReplaceAll,rfIgnoreCase]); - Filename := StringReplace(Filename,'/','_',[rfReplaceAll,rfIgnoreCase]); - Filename := StringReplace(Filename,'\\','_',[rfReplaceAll,rfIgnoreCase]); - result := Filename; -end; + procedure TDocumentConverter.SetBitmapMissingFonts(const Value: boolean); begin diff --git a/src/docto.dpr b/src/docto.dpr index a8808279..52555e85 100644 --- a/src/docto.dpr +++ b/src/docto.dpr @@ -35,7 +35,8 @@ uses Excel_TLB_Constants in 'Excel_TLB_Constants.pas', PowerPoint_TLB_Constants in 'PowerPoint_TLB_Constants.pas', VisioUtils in 'VisioUtils.pas', - Visio_TLB in 'Visio_TLB.pas'; + Visio_TLB in 'Visio_TLB.pas', + DynamicFileNameGenerator in 'shared\DynamicFileNameGenerator.pas'; var i, Converter : integer; diff --git a/src/docto.dproj b/src/docto.dproj index cfaf3d75..940ca44b 100644 --- a/src/docto.dproj +++ b/src/docto.dproj @@ -297,6 +297,7 @@ + @@ -387,111 +388,224 @@ True - + + + docto.exe + true + + + + + .\ + true + + + + + .\ + true + + + + docto.exe + true + + + + .\ true - + + + .\ + true + + + .\ true - + .\ true - + + + .\ + true + + + .\ true - + + + .\ + true + + + + + .\ + true + + + - docto.exe + .\ true - + .\ true - + .\ true - + + + + true + + + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + + .\ true - + + + true + + + + + .\ + true + + + .\ true - + .\ true - + .\ true - + + + .\ + true + + + .\ true - + .\ true - + .\ true - + + + .\ + true + + + .\ true - + .\ true - + .\ true - - - + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + + + + .\ true @@ -506,14 +620,21 @@ true - - + + .\ true - - + + + .\ + true + + + + + .\ true @@ -529,12 +650,24 @@ true + + + .\ + true + + .\ true + + + .\ + true + + .\ diff --git a/src/docto.dproj.local b/src/docto.dproj.local index 77c41533..36a1d6c2 100644 --- a/src/docto.dproj.local +++ b/src/docto.dproj.local @@ -6,6 +6,8 @@ 2021/12/02 22:25:13.000.761,=D:\Development\GitHub\DocTo\src\New1.bat 2021/12/02 22:25:32.000.527,D:\Development\GitHub\DocTo\src\New1.bat=D:\Development\GitHub\DocTo\test\TestDocTo_Quiet.bat 2023/09/11 17:39:20.000.384,=C:\Development\github\docto\src\res\xlsFormats.txt + 2025/11/18 17:53:47.458,=C:\Development\github\docto\src\Unit1.pas + 2025/11/18 17:54:21.396,C:\Development\github\docto\src\shared\DynamicFileNameGenerator.pas=C:\Development\github\docto\src\Unit1.pas @@ -31,6 +33,8 @@ + + diff --git a/src/shared/DynamicFileNameGenerator.pas b/src/shared/DynamicFileNameGenerator.pas new file mode 100644 index 00000000..4a10aa3d --- /dev/null +++ b/src/shared/DynamicFileNameGenerator.pas @@ -0,0 +1,71 @@ +unit DynamicFileNameGenerator; + +interface + +uses Classes, MainUtils, ResourceUtils, ActiveX, ComObj, WinINet, Variants, sysutils, Types, StrUtils; + +type + +TDynamicFileNameGenerator = Class(TObject) +protected + + fOrigionalFilename : string; + dynamicoutputDir :string; + dynamicoutputFile :string; + dynamicoutputExt :string; + fFilenameParts : TStringList; + procedure Deconstruct(); +public + Constructor Create(FileName: String); + function Generate(tag: String ) : String; + function SafeFileName(FileName: String ) : String; +End; + + +implementation + +{ TDynamicFileNameGenerator } + +constructor TDynamicFileNameGenerator.Create(FileName: String); +begin + + fOrigionalFilename := Filename; + self.Deconstruct; +end; + +procedure TDynamicFileNameGenerator.Deconstruct; + + +begin + dynamicoutputDir := ExtractFilePath(fOrigionalFilename); // includes last \ + dynamicoutputFile := ChangefileExt ( ExtractFileName(fOrigionalFilename),''); + dynamicoutputExt := ExtractFileExt(fOrigionalFilename); + + +end; + +function TDynamicFileNameGenerator.Generate(tag: String): String; +var +dynamicFileName : String; +dynamicOutputFilename : string; + +begin + dynamicFileName := SafeFileName(tag); + result := dynamicoutputDir + dynamicoutputFile + '_(' + tag + ')' + dynamicoutputExt; + +end; + +function TDynamicFileNameGenerator.SafeFileName(FileName: String): String; +begin + Filename := StringReplace(Filename,'&','_',[rfReplaceAll,rfIgnoreCase]); + Filename := StringReplace(Filename,'/','_',[rfReplaceAll,rfIgnoreCase]); + Filename := StringReplace(Filename,'\\','_',[rfReplaceAll,rfIgnoreCase]); + Filename := StringReplace(Filename,'<','_',[rfReplaceAll,rfIgnoreCase]); + Filename := StringReplace(Filename,'>','_',[rfReplaceAll,rfIgnoreCase]); + Filename := StringReplace(Filename,':','_',[rfReplaceAll,rfIgnoreCase]); + Filename := StringReplace(Filename,'?','_',[rfReplaceAll,rfIgnoreCase]); + Filename := StringReplace(Filename,'*','_',[rfReplaceAll,rfIgnoreCase]); + result := Filename; +end; + +end. From 5a28a7162c52a4f925c35db9976b55a973aedee2 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Tue, 18 Nov 2025 21:46:48 +0000 Subject: [PATCH 20/52] further tests --- .../app/Services/DocToCommandBuilder.php | 26 ++++++++ companion/app/Services/FileGatherService.php | 4 +- .../Remove/RemoveInputFilePestTest.php | 62 +++++++++++++++++- .../output/OutputDirCreationPestTest.php | 32 ++++++++- test/inputfilesxl/Book1 Single Sheet.xlsx | Bin 0 -> 9506 bytes 5 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 companion/app/Services/DocToCommandBuilder.php create mode 100644 test/inputfilesxl/Book1 Single Sheet.xlsx diff --git a/companion/app/Services/DocToCommandBuilder.php b/companion/app/Services/DocToCommandBuilder.php new file mode 100644 index 00000000..a1a679f6 --- /dev/null +++ b/companion/app/Services/DocToCommandBuilder.php @@ -0,0 +1,26 @@ +add(config('services.docto.path')); + } + + public function add($param, $value = null){ + $this->params[] = [$param,$value]; + return $this; + } + + public function build(){ + $cmd = ''; + foreach($this->params as $paramset){ + $cmd .= $paramset[0] . ' ' . $paramset[1] . ' '; + } + return $cmd; + } + } diff --git a/companion/app/Services/FileGatherService.php b/companion/app/Services/FileGatherService.php index b7db42ee..e776a0ac 100644 --- a/companion/app/Services/FileGatherService.php +++ b/companion/app/Services/FileGatherService.php @@ -19,8 +19,8 @@ public static function GatherFiles(Collection $list, $tempDirName) $inputfilesdir = \Illuminate\Support\Facades\Storage::path('inputfiles\\' . $dir ); $cmd = "xcopy \"$inputfilesdir\" \"$tempDirPath\\\" "; $result = \Illuminate\Support\Facades\Process::run( $cmd ); - echo "\n $cmd \n"; - echo "\n" . $result->output() . "\n"; + // echo "\n $cmd \n"; + // echo "\n" . $result->output() . "\n"; }); return collect(Storage::listContents($tempDirName)); } diff --git a/companion/tests/Feature/Remove/RemoveInputFilePestTest.php b/companion/tests/Feature/Remove/RemoveInputFilePestTest.php index 696ec73d..3e95b1f0 100644 --- a/companion/tests/Feature/Remove/RemoveInputFilePestTest.php +++ b/companion/tests/Feature/Remove/RemoveInputFilePestTest.php @@ -29,7 +29,15 @@ $dirfilescount = $dirfiles->count(); // do conversion $docto = config('services.docto.path'); - $doctocmd = "$docto -WD -f $testinputfilesdir_temp -fx .doc -o $testoutputdir_temp -t wdFormatPDF -R true"; + // $doctocmd = "$docto -WD -f $testinputfilesdir_temp -fx .doc -o $testoutputdir_temp -t wdFormatPDF -R true"; + $doctocmd = \App\Services\DocToCommandBuilder::docto() + ->add('-WD') + ->add('-f',$testinputfilesdir_temp) + ->add('-fx','.doc') + ->add('-o',$testoutputdir_temp) + ->add('-t wdFormatPDF') + ->add('-R','true') // the important one fo rthis test + ->build(); // echo $doctocmd; $output = \Illuminate\Support\Facades\Process::run($doctocmd); @@ -40,3 +48,55 @@ }); + + + +it('doesnt delete files from directory', function (){ + // setup + // $testinputfilesdir = \Illuminate\Support\Facades\Storage::path('inputfiles\\plain'); + $testinputfilesdir_temp = \Illuminate\Support\Facades\Storage::path('inputfilestemp'); + + + $testinputfilesdir_temp = \Illuminate\Support\Facades\Storage::path('inputfilestemp'); + + $testoutputdir_temp = \Illuminate\Support\Facades\Storage::path('outputtemp2'); + + \Illuminate\Support\Facades\Storage::createDirectory('outputtemp2'); + + // $cmd = "xcopy \"$testinputfilesdir\" \"$testinputfilesdir_temp\\\" "; + // echo "\n". $cmd; + // $result = \Illuminate\Support\Facades\Process::run( $cmd ); + + //echo "\n" . $result->output() . "\n"; + // $dirfiles = collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp')); + $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['plain']),'inputfilestemp'); + $docfiles = $dirfiles->filter(function ($item){ + return str($item->path())->endsWith('.doc'); + }); + + expect($docfiles->count())->toBeGreaterThan(0); + $docfilecount = count($docfiles->toArray()); + + $dirfilescount = $dirfiles->count(); + // do conversion + $docto = config('services.docto.path'); + // $doctocmd = "$docto -WD -f $testinputfilesdir_temp -fx .doc -o $testoutputdir_temp -t wdFormatPDF -R true"; + $doctocmd = \App\Services\DocToCommandBuilder::docto() + ->add('-WD') + ->add('-f',$testinputfilesdir_temp) + ->add('-fx','.doc') + ->add('-o',$testoutputdir_temp) + ->add('-t wdFormatPDF') + // ->add('-R','true') // the important one fo rthis test + ->build(); + // echo $doctocmd; + $output = \Illuminate\Support\Facades\Process::run($doctocmd); + + + // check files have been converted and originoals have been created. + expect(collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp'))->count())->tobe( $docfilecount); + + expect(collect(\Illuminate\Support\Facades\Storage::listContents('outputtemp2'))->count())->tobe( $docfilecount); + + + }); diff --git a/companion/tests/Feature/output/OutputDirCreationPestTest.php b/companion/tests/Feature/output/OutputDirCreationPestTest.php index ba3a4542..d1f40a7e 100644 --- a/companion/tests/Feature/output/OutputDirCreationPestTest.php +++ b/companion/tests/Feature/output/OutputDirCreationPestTest.php @@ -9,7 +9,10 @@ $docto = config('services.docto.path'); $inputdir = \Illuminate\Support\Facades\Storage::path($gatherdir); $fulloutputdir = \Illuminate\Support\Facades\Storage::path($outputdir); - $cmd = "$docto -WD -f $inputdir -o $fulloutputdir -t wdFormatHTML"; + // $cmd = "$docto -WD -f $inputdir -o $fulloutputdir -t wdFormatHTML"; + $cmd = \App\Services\DocToCommandBuilder::docto()->add('-WD')->add('-f',$inputdir) + ->add('-o',$fulloutputdir) + ->add('-t wdFormatHTML')->build(); \Illuminate\Support\Facades\Log::debug($cmd); \Illuminate\Support\Facades\Log::debug($fulloutputdir); $output = Process::run($cmd); @@ -17,7 +20,7 @@ }); - test('will not create extention directory', function () { + test('will not create extension directory', function () { $gatherdir = uniqid(); $outputdir = uniqid(); $files = \App\Services\FileGatherService::GatherFiles(collect(['single']),$gatherdir); @@ -26,7 +29,11 @@ $fulloutputdir = \Illuminate\Support\Facades\Storage::path($outputdir); // a bug caused docto to create and ouput to extension directory. $pdfdir = $fulloutputdir . '\\.pdf'; - $cmd = "$docto -WD -f $inputdir -o $fulloutputdir -t wdFormatPDF"; + // $cmd = "$docto -WD -f $inputdir -o $fulloutputdir -t wdFormatPDF"; + $cmd = \App\Services\DocToCommandBuilder::docto()->add('-WD') + ->add('-f',$inputdir) + ->add('-o',$fulloutputdir) + ->add('-t wdFormatPDF')->build(); \Illuminate\Support\Facades\Log::debug($cmd); \Illuminate\Support\Facades\Log::debug($fulloutputdir); $output = Process::run($cmd); @@ -36,3 +43,22 @@ + + test('can create non existant directory with bulder', function () { + $gatherdir = uniqid(); + $outputdir = uniqid(); + $files = \App\Services\FileGatherService::GatherFiles(collect(['single']),$gatherdir); + $docto = config('services.docto.path'); + $inputdir = \Illuminate\Support\Facades\Storage::path($gatherdir); + $fulloutputdir = \Illuminate\Support\Facades\Storage::path($outputdir); + $cmd = \App\Services\DocToCommandBuilder::docto()->add('-WD') + ->add('-f',$inputdir) + ->add('-o',$fulloutputdir) + ->add('-t wdFormatHTML')->build(); + // $cmd = "$docto -WD -f $inputdir -o $fulloutputdir -t wdFormatHTML"; + \Illuminate\Support\Facades\Log::debug($cmd); + \Illuminate\Support\Facades\Log::debug($fulloutputdir); + $output = Process::run($cmd); + expect(\Illuminate\Support\Facades\Storage::exists($outputdir))->toBeTrue(); + +}); diff --git a/test/inputfilesxl/Book1 Single Sheet.xlsx b/test/inputfilesxl/Book1 Single Sheet.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..83347506ec75ca84d58d92bcbae98647dbdd0bb8 GIT binary patch literal 9506 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 F`+tS{VE+IB literal 0 HcmV?d00001 From 4994708cff7d9b4b5fa18dcbd3c22ebeebda183e Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Tue, 18 Nov 2025 21:55:05 +0000 Subject: [PATCH 21/52] tidy --- src/ExcelUtils.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index 154729ff..e28fbdce 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -308,15 +308,15 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; begin - Logdebug('cycle:' + inttostr(I) ,debug); + ws := WorkSheets.Item[I]; -Logdebug('cycleB',debug); + logDebug('worksheet:' + ws.Name, VERBOSE); if self.isWorkSheetEmpty(ws) then begin - logInfo('The worksheet "' . ws.Name. '" is Empty and will not be output', STANDARD); + logInfo('The worksheet "' + ws.Name + '" is Empty and will not be output', STANDARD); Continue; end; From 7c329f8284262b3a61acdc8d39fb0e762a5984b9 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Tue, 18 Nov 2025 22:07:59 +0000 Subject: [PATCH 22/52] export worksheet --- src/ExcelUtils.pas | 61 ++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index e28fbdce..bf697782 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -25,10 +25,14 @@ interface Private ExcelApp : OleVariant; FExcelVersion : String; + + olevar_FromPage, olevar_ToPage : OleVariant; + function SingleFileExecuteConversion(fileToConvert, OutputFilename: String; OutputFileFormat: Integer): TConversionInfo; procedure SaveAsPDF(OutputFilename : string) ; procedure SaveAsXPS(OutputFilename: string); procedure SaveAsCSV(OutputFilename: string); + procedure ExportWorkSheetasPDF(ws :OleVariant; FileNameGen : TDynamicFileNameGenerator); function isWorkSheetEmpty(WorkSheet : OleVariant): boolean; @@ -176,6 +180,31 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen end; +procedure TExcelXLSConverter.ExportWorkSheetasPDF(ws: OleVariant; FileNameGen: TDynamicFileNameGenerator); +begin + if self.isWorkSheetEmpty(ws) then + begin + logInfo('The worksheet "' + ws.Name + '" is Empty and will not be output', STANDARD); + + end else + begin + + + ExcelApp.Application.DisplayAlerts := False ; + ws.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, + FileNameGen.Generate(ws.Name), + EmptyParam, // Quality + IncludeDocProps, // IncludeDocProperties, + False, // IgnorePrintAreas, + olevar_FromPage , // From, + olevar_ToPage, // To, + pdfOpenAfterExport, // OpenAfterPublish, (default false); + EmptyParam // FixedFormatExtClassPtr + ) ; + end; + +end; + //Useful Links: // https://docs.microsoft.com/en-us/office/vba/api/excel.workbooks.open // https://docs.microsoft.com/en-us/office/vba/api/excel.workbook.exportasfixedformat @@ -282,13 +311,14 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; logdebug('PrintFromPage: ' + inttostr(pdfPrintFromPage),debug); logdebug('PrintToPage: ' + inttostr(pdfPrintToPage),debug); - FromPage := pdfPrintFromPage; - ToPage := pdfPrintToPage; + olevar_FromPage := pdfPrintFromPage; + olevar_ToPage := pdfPrintToPage; end else begin - FromPage := EmptyParam; - ToPage := EmptyParam; + olevar_FromPage := EmptyParam; + olevar_ToPage := EmptyParam; + end ; @@ -314,29 +344,8 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; logDebug('worksheet:' + ws.Name, VERBOSE); - if self.isWorkSheetEmpty(ws) then - begin - logInfo('The worksheet "' + ws.Name + '" is Empty and will not be output', STANDARD); - Continue; - end; - - - - - - - ExcelApp.Application.DisplayAlerts := False ; - ws.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, - FileNameGen.Generate(ws.Name), - EmptyParam, // Quality - IncludeDocProps, // IncludeDocProperties, - False, // IgnorePrintAreas, - FromPage , // From, - ToPage, // To, - pdfOpenAfterExport, // OpenAfterPublish, (default false); - EmptyParam // FixedFormatExtClassPtr - ) ; + ExportWorkSheetasPDF(ws,FileNameGen); end; From 9751e46f98773e1b1592831525f3b449d3a222e2 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Tue, 18 Nov 2025 22:56:53 +0000 Subject: [PATCH 23/52] output correct filename --- src/ExcelUtils.pas | 60 +++++++++++++++++++--- src/MainUtils.pas | 12 +++-- src/shared/DynamicFileNameGenerator.pas | 18 ++++++- test/inputfilesxl/Book1 Single Sheet.xlsx | Bin 9506 -> 10328 bytes 4 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index bf697782..0744377f 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -33,6 +33,7 @@ interface procedure SaveAsXPS(OutputFilename: string); procedure SaveAsCSV(OutputFilename: string); procedure ExportWorkSheetasPDF(ws :OleVariant; FileNameGen : TDynamicFileNameGenerator); + procedure ExportWorkbookasPDF(OutputFileName: String); function isWorkSheetEmpty(WorkSheet : OleVariant): boolean; @@ -180,6 +181,29 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen end; +procedure TExcelXLSConverter.ExportWorkbookasPDF(OutputFileName: String); +var +activeWkBk: OleVariant; +begin + + activeWkBk := ExcelApp.ActiveWorkbook; + ExcelApp.ActiveWorkBook.save; + + ExcelApp.Application.DisplayAlerts := False ; + activeWkBk.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, + OutputFileName, + EmptyParam, // Quality + IncludeDocProps, // IncludeDocProperties, + False, // IgnorePrintAreas, + olevar_FromPage , // From, + olevar_ToPage, // To, + pdfOpenAfterExport, // OpenAfterPublish, (default false); + EmptyParam // FixedFormatExtClassPtr + ) ; + fOutputFiles.Add(OutputFileName); + +end; + procedure TExcelXLSConverter.ExportWorkSheetasPDF(ws: OleVariant; FileNameGen: TDynamicFileNameGenerator); begin if self.isWorkSheetEmpty(ws) then @@ -203,6 +227,8 @@ procedure TExcelXLSConverter.ExportWorkSheetasPDF(ws: OleVariant; FileNameGen: T ) ; end; + fOutputFiles.Add(FileNameGen.Generate(ws.Name)); + end; //Useful Links: @@ -299,8 +325,9 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; FromPage, ToPage, SheetList, ExcelSheets : OleVariant; Sheet1,Sheet2,Sheet3 , Workbook , SheetsArray: OleVariant; - activeSheet, WorkSheets, ws : OleVariant; - I :integer; + activeSheet, WorkSheets, ws, wsName : OleVariant; + I,j, sheetNumber :integer; + sheetName : olevariant; FileNameGen: TDynamicFileNameGenerator; begin logdebug('Save as pdf',debug); @@ -322,7 +349,7 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; end ; -logdebug('SelectedSheets.Count:' + inttostr( SelectedSheets.Count), debug); + logdebug('SelectedSheets.Count:' + inttostr( SelectedSheets.Count), debug); if SelectedSheets.Count > 0 then begin @@ -334,12 +361,27 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; logDebug('count:' + inttostr(WorkSheets.Count), verbose); FileNameGen := TDynamicFileNameGenerator.Create(OutputFilename); - for I := 1 to WorkSheets.Count do + + //for I := 1 to WorkSheets.Count do + for j := 0 to SelectedSheets.Count -1 do begin + sheetName := SelectedSheets[j]; + + + if (TryStrToInt(sheetName,sheetNumber) )then + begin + ws := WorkSheets.Item[sheetNumber]; + end else + begin + + ws := WorkSheets.Item[sheetName]; + + end; + + - ws := WorkSheets.Item[I]; @@ -348,9 +390,13 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; ExportWorkSheetasPDF(ws,FileNameGen); - end; + end; + + end else + begin - end ; + self.ExportWorkbookasPDF(OutputFileName); + end; diff --git a/src/MainUtils.pas b/src/MainUtils.pas index 72a8365d..81db0f81 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -9,7 +9,7 @@ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Intereting article +Interesting article https://support.microsoft.com/en-gb/topic/considerations-for-server-side-automation-of-office-48bcfe93-8a89-47f1-0bce-017433ad79e2 ****************************************************************) interface @@ -33,7 +33,7 @@ interface MSVISIO = 4; - DOCTO_VERSION = '2.0.43'; // dont use 0x - choco needs incrementing versions. + DOCTO_VERSION = '2.0.44'; // dont use 0x - choco needs incrementing versions. DOCTO_VERSION_NOTE = ' (Test Version XLS Multisheet B) '; type @@ -74,6 +74,7 @@ TDocumentConverter = class fSelectedSheets: TStrings; + procedure SetCompatibilityMode(const Value: Integer); procedure SetIgnore_MACOSX(const Value: boolean); procedure SetEncoding(const Value: Integer); @@ -143,6 +144,9 @@ TDocumentConverter = class FOutputIsFile: Boolean; FOutputIsDir: Boolean; + + fOutputFiles : TStrings; + procedure SetInputFile(const Value: String); procedure SetOutputFile(const Value: String); procedure SetOutputFileFormat(const Value: Integer); @@ -524,6 +528,7 @@ constructor TDocumentConverter.Create; FInputFiles := TStringList.Create; fDontUseAutoVBA := true; fSelectedSheets := TStringList.Create; + fOutputFiles := TStringlist.Create; end; @@ -681,7 +686,8 @@ function TDocumentConverter.Execute: string; if ConversionInfo.Successful then begin - logInfo('File Converted: ' + ConversionInfo.OutputFile); + // logInfo('File Converted: ' + ConversionInfo.OutputFile); + logInfo('Files Converted: ' + fOutputFiles.Text); // Check if file needs to be deleted. if RemoveFileOnConvert then diff --git a/src/shared/DynamicFileNameGenerator.pas b/src/shared/DynamicFileNameGenerator.pas index 4a10aa3d..5c808f66 100644 --- a/src/shared/DynamicFileNameGenerator.pas +++ b/src/shared/DynamicFileNameGenerator.pas @@ -7,6 +7,9 @@ interface type TDynamicFileNameGenerator = Class(TObject) + private + FIgnoreTag: Boolean; + procedure SetIgnoreTag(const Value: Boolean); protected fOrigionalFilename : string; @@ -19,6 +22,7 @@ interface Constructor Create(FileName: String); function Generate(tag: String ) : String; function SafeFileName(FileName: String ) : String; + property IgnoreTag : Boolean read FIgnoreTag write SetIgnoreTag; End; @@ -29,6 +33,7 @@ implementation constructor TDynamicFileNameGenerator.Create(FileName: String); begin + FIgnoreTag := false; fOrigionalFilename := Filename; self.Deconstruct; end; @@ -51,7 +56,13 @@ function TDynamicFileNameGenerator.Generate(tag: String): String; begin dynamicFileName := SafeFileName(tag); - result := dynamicoutputDir + dynamicoutputFile + '_(' + tag + ')' + dynamicoutputExt; + if FIgnoreTag then + begin + result := fOrigionalFilename; + end else + begin + result := dynamicoutputDir + dynamicoutputFile + '_(' + tag + ')' + dynamicoutputExt; + end; end; @@ -68,4 +79,9 @@ function TDynamicFileNameGenerator.SafeFileName(FileName: String): String; result := Filename; end; +procedure TDynamicFileNameGenerator.SetIgnoreTag(const Value: Boolean); +begin + FIgnoreTag := Value; +end; + end. diff --git a/test/inputfilesxl/Book1 Single Sheet.xlsx b/test/inputfilesxl/Book1 Single Sheet.xlsx index 83347506ec75ca84d58d92bcbae98647dbdd0bb8..591c871fe55f5be8d5d002bf3ec1e2326067f1dc 100644 GIT binary patch delta 4372 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 Date: Tue, 18 Nov 2025 22:56:58 +0000 Subject: [PATCH 24/52] res --- src/ExtraFiles.res | Bin 349788 -> 350080 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/ExtraFiles.res b/src/ExtraFiles.res index 4a9a4c492d7bcd850064665f254ece82fe0386af..b2f14ef9e20e5c8ceedbbc7242abe65034958efe 100644 GIT binary patch delta 917 zcmZWn%}*0S6fa8~NRuYSrVv2jML`m@8xK91tfm4*43&+oz|Bl|XW23HmEGxw2ZKfv zFW&ah8_~pgQaNz&#=*bCf5QlRakdqA(M=}%=Djz+-|u~V`&fE@RC+sMOpQjy#JxvS zB38&t*+3m!4Xd0mq_DfOS+n+umjv$CZL7s(;#k8TYExxNsd|ZbybRvX3Yvz>TSapU7Zs4qR-=t|8%g4nWTCI z14#)+Qx8O?2eMn=(T(c#XU~k8$%{kSvl~`VhM8!w_$v2)DwDYpy)#SE*W&DaQ@{=m zLM`zYEQN*qw&xKCpZkt~6`hge$EC4LGlhI14^S>+j#?C#yCQHqEri-iL@$;XMztM% zST+yzAC!Qq_6Kcl!miGPZBCz>=K!IPvC>R1_!^jEM?u#ojt|37{65snXTmDt(8Ayd z#t?*9;vil{pd?fvJh%yjySN9u&04w!5CI$vAb=x=Llf3}4yNbqv3Nx3Mfy!oqw@|9 z6yf_Z@oHlS+~Fo`Y9DooXa_*TIQAzKJQ8RD10WNi>Fa2hP#VV pM9Us(I{v==#>h=)GMP#|f|rLYuMby7^fB}q)hGMqa3yzg{Wl0vIhp_f delta 185 zcmZozFM4N<=mG(z7fh3x1UxoJvE5>t93tGpv{r2LEn#E1l6-}*)S}|d{5&hwVqPx) zw6x6RRG5&$W^IvVM#hrOeWL6_(h3T^TnY-hx~X}INja&yxrxa|`H7_^`9-C9lh>=u zv-yGqiYH%G*HeTr6@Z32LKNsJgy$EfDEQ~)RO*4u*({^k!^F(Mz|g!xyM2W=BM>tI PF*6XeY+s?xdP5rkeG5GU From c1c65b1906294cc736d53405415c5efd9353023b Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 08:36:35 +0000 Subject: [PATCH 25/52] sheet selection --- src/ExcelUtils.pas | 65 ++++++++++++++++++++++++------ src/MainUtils.pas | 9 +++++ test/inputfilesxl/Week 1 Test.xls | Bin 37376 -> 37376 bytes 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index 0744377f..873ae461 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -418,10 +418,11 @@ procedure TExcelXLSConverter.SaveAsXPS(OutputFilename : string) ; procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); var FromPage, ToPage : OleVariant; - activeSheet : OleVariant; + activeSheet, olesheetNumber : OleVariant; + sheetNumber : integer; dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String; ExitAction :TExitAction; - Sheet : integer; + Sheet, ix : integer; FileNameGen : TDynamicFileNameGenerator; begin LogDebug('output to csv format'); @@ -434,22 +435,62 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); FileNameGen := TDynamicFileNameGenerator.Create(OutputFilename); - for Sheet := 1 to ExcelApp.ActiveWorkbook.WorkSheets.Count do + // output all sheets with seperate names + if fSelectedSheets_All then begin - LogDebug('CSV Loop'); - activeSheet := ExcelApp.ActiveWorkbook.Sheets[Sheet]; - dynamicSheetName := activeSheet.Name; - LogDebug(dynamicSheetName); - // dynamicSheetName := SafeFileName(dynamicSheetName); - dynamicOutputFilename := FileNameGen.Generate(dynamicSheetName); //dynamicoutputDir + dynamicoutputFile + '_(' + inttostr(Sheet) + dynamicSheetName + ')' + dynamicoutputExt; - LogDebug(dynamicOutputFileName); + for Sheet := 1 to ExcelApp.ActiveWorkbook.WorkSheets.Count do + begin + LogDebug('CSV Loop'); + activeSheet := ExcelApp.ActiveWorkbook.Sheets[Sheet]; + dynamicSheetName := activeSheet.Name; - activeSheet.SaveAs( dynamicoutputFilename, OutputFileFormat); - end; + LogDebug(dynamicSheetName); + + dynamicOutputFilename := FileNameGen.Generate(dynamicSheetName); + + LogDebug(dynamicOutputFileName); + + activeSheet.SaveAs( dynamicoutputFilename, OutputFileFormat); + end; + + end + // If we have been given Sheetnames or ids, just output them. + else if SelectedSheets.Count > 0 then + + begin + for ix := 0 to SelectedSheets.Count -1 do + begin + LogDebug('CSV Loop:' + SelectedSheets[ix]); + if (TryStrToInt(SelectedSheets[ix],sheetNumber) )then + begin + LogDebug('TryStrToInt:' + SelectedSheets[ix]); + activeSheet := ExcelApp.ActiveWorkbook.Sheets[sheetNumber]; + end else + begin + activeSheet := ExcelApp.ActiveWorkbook.Sheets[SelectedSheets[ix]]; + end; + + + dynamicSheetName := activeSheet.Name; + + LogDebug(dynamicSheetName); + + dynamicOutputFilename := FileNameGen.Generate(dynamicSheetName); + + LogDebug(dynamicOutputFileName); + + activeSheet.SaveAs( dynamicoutputFilename, OutputFileFormat); + end; + + end else + // Do default which is usually first sheet, with name provided. + begin + ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat); + end; ExcelApp.ActiveWorkBook.save; end; diff --git a/src/MainUtils.pas b/src/MainUtils.pas index 81db0f81..909339b0 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -75,6 +75,7 @@ TDocumentConverter = class + procedure SetCompatibilityMode(const Value: Integer); procedure SetIgnore_MACOSX(const Value: boolean); procedure SetEncoding(const Value: Integer); @@ -146,6 +147,7 @@ TDocumentConverter = class FOutputIsDir: Boolean; fOutputFiles : TStrings; + fSelectedSheets_All : boolean; procedure SetInputFile(const Value: String); procedure SetOutputFile(const Value: String); @@ -528,6 +530,7 @@ constructor TDocumentConverter.Create; FInputFiles := TStringList.Create; fDontUseAutoVBA := true; fSelectedSheets := TStringList.Create; + fSelectedSheets_All := false; fOutputFiles := TStringlist.Create; @@ -1264,6 +1267,12 @@ procedure TDocumentConverter.LoadConfig(Params: TStrings); HaltWithConfigError(205,'Expecting > 0 selected sheets: ' + value); end; end + else if (id = '--ALLSHEETS') then + begin + fSelectedSheets_All := true; + + dec(iParam); + end else if (id = '--EXPORTMARKUP') then begin if (WordConstants.Exists(value)) then diff --git a/test/inputfilesxl/Week 1 Test.xls b/test/inputfilesxl/Week 1 Test.xls index 44a8232bb22eb919b4de2cfc46ed517d7828eaa1..5e3784952e25e65124eb8de6ac317f72db5446a9 100644 GIT binary patch delta 257 zcmZoz!ql*YX~PpHM#jxgnV5|A!YmkofS(~eH6<^#I3=-C!KXAYIir<JadD>swWTvKTuh%l(JEqdUs5zXBirOx znN@7QnG6hXGeM%0`;uHXvt|EcntZ{Ub5h<-R?a!sbt5<5%M0RX^qFi}=gr7DxwbBz piyde^#GRYp*9r22RB!6bVPd;*Xk)j2U{ME9R zZ;~AYgFzSrLq#-@j-Q;E6|wn&Rf8HM-{i!^LtG+h3=DJ985nM*17+rHKA9xW&d4zN zVP+L;SSAC*x6KJz)0rpb-DEwnh<#1O=6iWT{EQ)!4ePuag(lb5#S04ntwnR_=4W++ c{G0l6nAieh7`fL(OfH(x#+b1A=LB{}04+FB=Kufz From 5fcec77fd7af428e3e64e040152982188e2646b8 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 08:53:48 +0000 Subject: [PATCH 26/52] ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 04816ec1..0705def9 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ test/Generated* test/InputFiles3* test/test1/* newdir2/ +src/__recovery /releases src/docto.exe From a0b80e9567d29dde40917dbaaf6a2c2a9fbc082c Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 09:16:35 +0000 Subject: [PATCH 27/52] save sheets as pdf, error xps --- src/ExcelUtils.pas | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index 873ae461..eae11958 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -348,19 +348,37 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; end ; + WorkSheets := ExcelApp.Worksheets; - logdebug('SelectedSheets.Count:' + inttostr( SelectedSheets.Count), debug); - if SelectedSheets.Count > 0 then + + logDebug('count:' + inttostr(WorkSheets.Count), verbose); + FileNameGen := TDynamicFileNameGenerator.Create(OutputFilename); + + if fSelectedSheets_All then begin + for I := 1 to WorkSheets.Count do + begin + + + ws := WorkSheets.Item[I]; + + logDebug('worksheet:' + ws.Name, VERBOSE); + + ExportWorkSheetasPDF(ws,FileNameGen); + + + end; + + end else if SelectedSheets.Count > 0 then + begin + logdebug('SelectedSheets.Count:' + inttostr( SelectedSheets.Count), debug); + logDebug('Selecting sheets' + SelectedSheets.Text,VERBOSE); - WorkSheets := ExcelApp.Worksheets; - logDebug('count:' + inttostr(WorkSheets.Count), verbose); - FileNameGen := TDynamicFileNameGenerator.Create(OutputFilename); //for I := 1 to WorkSheets.Count do for j := 0 to SelectedSheets.Count -1 do @@ -410,6 +428,11 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; procedure TExcelXLSConverter.SaveAsXPS(OutputFilename : string) ; begin + if (SelectedSheets.Count > 0) or (fSelectedSheets_All = true) then + begin + raise ENotImplemented.Create('--sheets, --allsheets is not available for conversion to XPS'); + end; + ExcelApp.Application.DisplayAlerts := False ; ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypeXPS, OutputFilename ); ExcelApp.ActiveWorkBook.save; @@ -418,7 +441,7 @@ procedure TExcelXLSConverter.SaveAsXPS(OutputFilename : string) ; procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); var FromPage, ToPage : OleVariant; - activeSheet, olesheetNumber : OleVariant; + activeSheet : OleVariant; sheetNumber : integer; dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String; ExitAction :TExitAction; @@ -464,12 +487,13 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); for ix := 0 to SelectedSheets.Count -1 do begin LogDebug('CSV Loop:' + SelectedSheets[ix]); + + // Check if number requested and set sheetNumber if (TryStrToInt(SelectedSheets[ix],sheetNumber) )then begin - LogDebug('TryStrToInt:' + SelectedSheets[ix]); - activeSheet := ExcelApp.ActiveWorkbook.Sheets[sheetNumber]; end else + // otherwise use string name. begin activeSheet := ExcelApp.ActiveWorkbook.Sheets[SelectedSheets[ix]]; end; From 5e6993cacf1c7b3421a9d35f72caab8a6701f65b Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 09:16:47 +0000 Subject: [PATCH 28/52] halt error --- src/MainUtils.pas | 3 ++- test/inputfilesxl/Week 1 Test.xls | Bin 37376 -> 38400 bytes 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MainUtils.pas b/src/MainUtils.pas index 909339b0..e237cbe2 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -769,7 +769,8 @@ function TDocumentConverter.Execute: string; ErrorMessage := StringReplace(E.Message,#13,'--',[rfReplaceAll]); if (HaltOnWordError) then begin - HaltWithError(220,E.ClassName + ' ' + ErrorMessage + ' ' + FileToConvert + ':' + FileToCreate); + LogError( FileToConvert ); + HaltWithError(220,E.ClassName + ' ' + ErrorMessage ); end else begin diff --git a/test/inputfilesxl/Week 1 Test.xls b/test/inputfilesxl/Week 1 Test.xls index 5e3784952e25e65124eb8de6ac317f72db5446a9..8ed57b5be88f06f1865afcdd68233efdac05dfcb 100644 GIT binary patch delta 285 zcmZoz!ql*aX@UWx=R`wk77qpnhK+&i88`oDRAOXgnC!qTi$>OfMP`A?9n7+}46KZf z3`Go?42cXm42BF+3?~>E8UEMrVFH>2#OSgTKvNO2K=Y-UfvO<(Z1!W}O=GjqV_>+S zH#sqD&gPRz9;};#vv)I2$~z#-kQu(*IPwmo1JGcGx3(wUQ;$K|Ao0z2^S;aTm;q(X zf%xD5|NkdH=o8_w19I%40+aehSlxhZ_sN3&&nHdDVO5yW3&-}^1CR8z6 SOfH>R&*K18!yo`67#IMZWK7Zk delta 323 zcmZoz!_=^ZX@UWx`$R)&7B>b4hK+&i88`oDRAOXgob13Xi$>OfMP`A?9n7+}jI4}~ z3`Go?42cXm42BF+3?~>E8UEMrVFH@O#DF0y!H6siG+&w-s0w1wWCfB*mgHwVgE0P*AplSIG*_CSsU5Ko#cGFfKw tlZgo&lcwabUO2R|TYqxlly;`@tjWKoR56-OE}dG>V+T~oAOIp57yw?xSmOWy From d7eb72f77ee38a415602899cc251e35fc86d0367 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 09:19:06 +0000 Subject: [PATCH 29/52] not implemented --- src/MainUtils.pas | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/MainUtils.pas b/src/MainUtils.pas index e237cbe2..3cd5e246 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -764,6 +764,20 @@ function TDocumentConverter.Execute: string; end; end; + on E: ENotImplemented do + begin + ErrorMessage := StringReplace(E.Message,#13,'--',[rfReplaceAll]); + if (HaltOnWordError) then + begin + LogError( FileToConvert ); + HaltWithError(301,E.ClassName + ' ' + ErrorMessage ); + end + else + begin + LogError(E.ClassName + ' ' + ErrorMessage + ' ' + FileToConvert + ':' + FileToCreate); + + end; + end; on E: Exception do begin ErrorMessage := StringReplace(E.Message,#13,'--',[rfReplaceAll]); From 0bae300e2412bf1d13fe733df53ea0b6453ba900 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 09:24:30 +0000 Subject: [PATCH 30/52] note --- test/testxlspass.bat | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/testxlspass.bat b/test/testxlspass.bat index 5084bab8..aab0e297 100644 --- a/test/testxlspass.bat +++ b/test/testxlspass.bat @@ -1,2 +1,3 @@ REM Load csv files convert to xls -"../exe/32/docto.exe" -XL -f "C:\dev\github\docto\test\inputfilesxl\Book1 with password.xls" -o "C:\dev\github\docto\test\GeneratedFiles" -T xlpdf -l 10 \ No newline at end of file +REM will skip password protected file +"../exe/32/docto.exe" -XL -f "C:\development\github\docto\test\inputfilesxl\Book1 with password.xls" -o "C:\development\github\docto\test\GeneratedFiles" -T xlpdf -l 10 \ No newline at end of file From 7b5b72b38ddf3943a3bf8ac9e4188d563f3b80ef Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 13:10:55 +0000 Subject: [PATCH 31/52] xl macros --- src/MainUtils.pas | 9 +++------ src/res/HelpLog.txt | 4 +++- test/inputfilesxl/Book1WithMacros.xlsm | Bin 16711 -> 17797 bytes 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/MainUtils.pas b/src/MainUtils.pas index 3cd5e246..6b9f45b2 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -1333,15 +1333,12 @@ procedure TDocumentConverter.LoadConfig(Params: TStrings); end else if (id = '--ENABLE-MACROAUTORUN') or - (id = '--ENABLE-WORDVBAAUTO') + (id = '--ENABLE-WORDVBAAUTO') or + (id = '--ENABLE-XLVBAAUTO') then begin fDontUseAutoVBA := false; - if (OfficeAppName <> 'Word')then - begin - // Excel Application.EnableEvents = False - // HaltWithError(301,'Parameter ' + id + ' not Implemented for ' + OfficeAppName ); - end; + end else if (id = '-X') or diff --git a/src/res/HelpLog.txt b/src/res/HelpLog.txt index 29070d70..e0ce82c9 100644 --- a/src/res/HelpLog.txt +++ b/src/res/HelpLog.txt @@ -114,8 +114,10 @@ Long Parameters: --use-ISO190051 Create PDF to the ISO 19005-1 standard. + --enable-macroautorun --enable-wordvbaauto - By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word Only. + --enable-xlvbaauto + By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only. --sheets Select which sheets to save. Can be comma seperated list of 0 index numbers or sheet names. Excel Only. diff --git a/test/inputfilesxl/Book1WithMacros.xlsm b/test/inputfilesxl/Book1WithMacros.xlsm index e71827a5d5a7ee998a5af8719f184a5e54d3652c..662c71193831d6b0b9bf0e8b2c380d4cd6b75cf7 100644 GIT binary patch delta 12075 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 I{VU%80BtBXod5s; delta 11000 zcmZ8{18|^0vu$i_oQ<80ZEm=+ZQJG-8ynlUHnx+EZQHiq-v7Q=_tl-M>7J_Y>YADE zs-Bv2f+InP13+uRpkcSWZF3vJK|sh7;GxMO$9YOmA`;l3Nr9%}*qk(vA^xxWDw>P5 zh?pDG{5=+>CG&*40Jd1Pk15d*Fr70p3pmA_5ZQaI)e}8>->(br{=vD3J4!^5bldzC z#ilp|XAcRh*{qvn_S*Wxd2^J0oy*P6MXg!_mOvO6~`O0Z8#QdHKv8CY30sUBw5n%6c$V~KG?U2 zAB@DWuB#1js&q@uJu=^TH*A1tr74z)d2!!!jS-~I?~=3Aq6Ww68h8{EesfoC4h}#3 zaBpni@{Kn>x|p4-a;;|796`yMP=j&qI;I^lz<$wICv?D&0w@|T93sh@4CUeck;$+= z#Ta%fDs+Ttv~LUb+pYUjuz6bb#TP|zZp~H6S3zk3*=q5VNjycwlL-Nhwf18|{Wm}1%S&s5l?U-?Adm=1+B}{j)`4-d0 zc7?s+Y=@&LY~wYR9$-h&W)sTp{=ghVHy65Ns@`c9Oxrs~#ER?$$UmxsnMBDfsZ`R5 z+T?dbWhVv8rjrO{dXC)W!7?_<|2AHps!cF097-1X+fiKisD{QM;G_FMM(JYsP% zB6=2r88FhD7hbG1_0u+fr8+i2AYCvQNF3%Fw~)N)mp$SRr`wK z(c@L#dxlrRVe9IXqhIT~E1wd_%#9LfvP+ktTJBG$Bo^}1O4-oO18cZkbL`RGbB*Y$ z4R7DGgxz$>;dXlqiEyzklZ9ZR$XeA3rJTQ9p~ZjqHSs7{%OHGmnG(*1i;Ri)#84p^hkR_+5tq$}Nw|7g?66eFKq+!%}cS z^Vg0XX`)C376Yygt(H{fTk2tyxOk*q$k#my%jFjEgQ~a6q4*AsY|d%2`GDa#fZ3OP zV-dijm?#VGgaP*!H_4Hr%F@wT;jw;|SnkKbTs4WzGMBn_drak}dv4|h`NKm=C z^M1tU82w{WURj;q@glA|HbW_39b_7GCB1{78@Qn;q&B9yeJ?y17hFxIqB?&V=5KE_GOgL)KsLt{ap=PQ8tPmYhEz;09Aa+~D1Zt1Ay@-P zxEHC((uSX4n`gvx0;KnIe9PD@I7jgMCawIZ1P4$2DgT-*gZM$+lf99sA!+E z73OIf2v$3h#OzB#i%RwequkDInr-DPP5%#zgTj9F>P#V@aTBgk0zy7pHUiyq8ykDe z0=c0x8uxl+vils?`QIUeeJ3{>rFBqjn33b^r4%XGr=7`4wbRM8N39YvhW;JM+>h~1 z9-LVWz!Ugf$s1V019B?Ri}kHb_FuUU5rKf9{dY||o155}F#JdUryS2UCL(b;(7Ul- z1rVIv-r4qI$v3yBtP?iKjI$E)8k^1)R9TqgJ8;p!$hjUAe-sv_2-)!^&I*DfcHYOr zlKnX$oS~dpCapRk%dnQzbVZC5|LiO&dCKjoIgd-*UElb$0cNdjJF9dbKNaYBeuKep7$ z>&St;y1o8-p|Id%#Y=qR)mwvXCLV%aui2*`sHnc?FXSIbSj`NWGpZCK2T&Tqwz*%- ztN8HaC%u-lL@dS<8d~woV}qA+m4Vt2LWH($QFx%{Cl$YTe`uCziP_mwF1nsp|B}>&u6*;o zmAr_AV@n8qaHFML>netE-*F7uCPLuP&UmURh2Mx3=ZZ?w>LeTono*a`{2+c{iewVI zqk{-?(=hcdkw3V$2iC~vU{LKsP$~3Vl&KIURi113{XdIIBbpeQ3zKy8!_{#WAKd}N zfl=wEcbeP<4kCtZKCjQ~le^GvKH&cNrC+bUwUJuN7Mfg1>2e`f@9X0OYg4cL^ZN9L z<7A%lrf;D8{bekr`|F1Lp>}s2gQ3gk_Vy$JYs=^1NG=wCbqxzxfKg~5UJ&Kjwe)gq1PsvCB0BAJslDi1!&4uE?BMOTT4^J^X(fwEs}ZY% zTsMkx#dhP~E>9o3zP8Vn-blD>4Q~&hjaG)x!mnr-4m()lW8Rgn4ZpwqRudRDM=tEBPp(M+N7yiItj~lfX!Ukt(*~&NFST0W z^EM_m__q;8->|ZSp)qrMg>ywN5hgbLu1Mp3W=Eh`oT8e6OvE#S>h9HuHc0A_JM;nP zXEz+e9?~0u&H#J7l;iPiYa}*H9G~lQv^=lVs&xFwfG-6Sv1puIpahn8><$ zJ=1zKY*XKdDM<_DzGZqMB@p&%GKpW;5tY_Sh~*qm8)>r2+qB#`5zfNHeOH#W+K#Q{ z95saP)y(gtK5f7V@|ZEcy<6fe8i3I-OYy|K^wzPb z@wICh*4NwQyXb=W?rr&<=&|{6;+uk10Ixv^3>*U1MnD+Gr?yB|g{JjoV#aa?J2E)B zm})0l!hZDNRCqn*yW3v^H&7=i$XKnLw?yuYA0|g4{td8CgtS(k=Gp5#_VJZYiykUY zx(m-=Z{?%HViWbt5MmaY`GtM#wVC~TIOeDW) z47H_&&NIuk8Un4jjx49q$S78#B$O@w6ckF+13b1bjg~OY)TFFdFKEZu{Y&mpt)%l> zSoumVuHPlHZJ*r?lD}ishl(U}YbVJ5g<^_J^-3I|)1w2D5LsvN@@;6;{J!yP?xhRT z5N0@hbLJUwXYM7n2-(0^$d)Da-%+Zz|12Ne!mlJ-!2|j_38P~>!MTq(Pzu%68EBwm z!u=ux9Zx5i{4;7X;tpQicJ=?7FLgxBawW!)a!1O$=BFBG_pyankI%@_5Ms-%r1$2X z(etL3gFkl4ZEz4S{B?q|I5aCBq&}T@PB;nW*+;Cn6`rrBF0%cQrE{#dqHje)UGR|X z*qQf<1P6K<>2k)IWi&cu`y(0}6xRN*(83_d&9gt-xQKD`-BeQwjAV^#x(L#qNoGC2 z{$1}_FokyW=k>G)I7<|d<%R50NPoP};*KP;>qo99Xhg$ob#PJAefd&ZLvKhf(SLzFl8JHIVTE*B<*u^}x2$y5 z<9IT3vrT%|SRzCoU4wcLN07#>&EXuOcny_jWU&vJBpd`hB8!*VOuOFGHK9vX`_cWf zrsl{eyc+T_AxOdwE;`)4^*qDM_kU-SP58pa0o=7s(mtosB$(4EOyWZnXTj#klK-&o zjPDbqGcOf3r%op}Rm_;iXC_WdP{>f&w90A98yg(#lIW_!N7U>7-Yr)~QJQ{;NZhE# zTu;J0vvtv-YQH3HpK2KI+5*zJSR_`-4p4juzE0Nea=uGv6V6H^axlB{wxBjR- zu(Tj>enR@h_MqEf5q^gHD7Dx>pw0QUgN{(Q4Rg`e;b_6>LFpms!Pk2na}i2^ziblc z0NElyD#7x&;qxF9rU84@(T{deQbw<40GmZjLGo_5(soTp4j6lkHxWeErD7DVDvZzIPrd4jG7voo5neEa3l|D>^#-~5`TZ~J$LFq1nglY!wrf*7f z**(e9`@pHv(`*nKwvMnTo%tFG`jaz9AnTLT`B|pD3U1o|X;G8w6ZGi6QVFaAl=H7@ zZ%|cV7$AcxyRE3|klLV?Q00D>+mbyX=HsPXmVTPKNTtv?eqy<>=1|pOiy*8Qi(qQt z{C4edF{Ya{hF4C&ds)8*i3twcyoH9a>M^Xu;imONaDXH4Ho5+rzuCC zS6o|V;>yp(AjPl92r4HWXuFrhpFHO!7OUVQ2s?!js9?*+*cSf5zDh&M== z^p}tEiW{49-IM+<6*%&;$`Dr6TQK}ep%r4-uh0$Jq92O8BDXCmNmiWZo}SGll{=PF zNa2EG39eB7LrHZMARc7|P>80Hms_xOefgLo%~988IU9{4jcid{lQu3hpVsQkgX>!3 zyPRW4u{k|G!ax$*`Am|UkMmvqD*tndU4 z&y+jO1)YBcErJH#d1I!bFZijE-&B~n0*)A-Gu$zm+=!UjmzOTDaHCt-NS_5rv*QWG z((*#!nlzWxdzz8Rbya2Vo)~}KGjdcc(xmxYdbACl%$|&&O-QCFWD_03yW<%>v}Jfa z_|;%G!VZtw)F)Q}eKwU%LmBzoj7>Gahd~H4ij}9kgCH~7Yw%gbhuik*HgWSe@|HJu z%xPx@4xiXcR3RUh6^x$|RAmWXuNgT{(r#U#4eNBWPkmP^d^sOD)LZDcQM(R~>JZi6;^9FMx&Mg}~?Pj_$U zS~uQF>8Hh>7&ozyZ3~B##^D}SQ5iXnyoSi=r-(RH?@}5yOnTQtnL`(~2EHupmo9lS zf*H&jLQ^lp_Hq2Gz5chiKe6rYp?r-3Mt#Lb9rY0Jt z{z+Apm&^r#X%4CG@jU(Q(;)N;0gJgkBTc^u-!=B`v2ZoLB{Wi{Cm} zICw58kQr$>G8}}H;T8FH2%#iyDOT^YD6A;0&A-r$c$`LGM@_ zxaKYildZ{{YP;KV2bw=AeB%WQrk(8y)&(|G^v=aahGQ~sI}PtRNvA>s(8x0)Ht}m6 zLF9G0`X=r$S@k!!DZko2;rDQ)`mSHzjO^MQLxwl0UJYFO+1PBMZ_;|An|uOnx3&zc zKtltNH~pR9a%m$Whh90OIdknEyK|9p%hVH94aV(^|AuVHpC|rw1f$FkpRzB5;?5L7>gP#<>L78dC~3TtVZI2sR zd#w>&wHvdrsmd`EHM$sybM;?#*F$v`qUO!m@q5+&%S=(-7?^0}_SLKnEbi^Mlf zl8vAx!#Ckf*NMIIzL`zZYv;c%tYbbZ`p711|K@7zyBU{7*M7Qkcelv({P@f>W1Qt; z6HiHc=2+xSsHmf@SL|I>R;!o>E~N?_{(3{-s`+`yO4R@T{b=wjdfPXh2r=>-X+KtC z-idlrME1b>W?wKZj90G490il2X8_rt@oe-rPn>z2N^7>+a=8UBN#7rylqrO)re}FA z=g!n0N~z>q!iAbEi7}kpXh?{75ea7)R2RcVVJz-~(?PN!~>7~s*^{3#n#mTNt<&yj| z#alh+bj`OT?|0~*HGc&RZ>E~ZFOr#6&lcJ^1~nq0d(8kA56V8-F*rDRo@koj1Ric- z&IhVi@3c=kD}hD9@(;|fjx{@g%4q13bV6&!m!nE=(xUJMmQ6g&w~>9sE=zpTK7uC@ zBpx!6G)4|jsRVx*f9@#=-s1e6h?+mr`=V}SsZrkJyEIL*VGHz>&}F3{a-t{r zivQ+Gy;mK^W1X7FS@=C2o@aq>G<8`fBKL{_X)TbXvWJml3u{!+3x=!-B3Uw6e}8_&m^XpQH^{SfvNIy~Mc$k6o$^u1{baB(WTX9(&&c+jL!$JTX_%%Lw^ z?4Va|3D*jt>%KK>t zj3KBTnEyBuRpfOvGoz$?Gcb)A=g@FzqSnS>EjfBQo??;HD^Gsb(CnpDqDgNXS`5sP z6yHm1&_wb4?nv8wA2=-RR>3L8&qEyx-w|9IlK5l0TLN?TVfyzY@Rxo+W=f z5Ro^I8*iv*Oh#Bd&}_(T@GiPJ;GHjf3$hE^oA4R*T6kN$=MH2es{;fN@)ynv^fn== z=I0m0JH#`UJ)S$P`}gPX*Hb;+AOg@MJ^K*$sO}igkoIuT!Tr`ImemyTmHPfrgEOX`8?A zR|*4hQjO-ClnSh&UWp3ocV%Aa)V-na_hg$%*wcgtuj-{YKh%wESiSAKKKL7&Gl@lCp@Cg>K- zSSd3#Z`3iuBrP!K)z8`~0Mr!+tIbJ&|Dxct1pobup+-&P)~%?4Q8z`CltfyrtV&C* zqT1?p4_8)CjlEA@L8WtD0ON{>D|J|)Q`pOAk^+sZXgSSrJYE&otD!Y?p+hIzx_FoB zQpi*jQl`m;zEz7B5NyRUIi;|kc{T8bGET$smvCQo!YB-$#1y6*8?Y8aZ@4y?orL zZN%?o_$zF17eG0~k~~vVG+>hS1`CJvB?DyQ#8NOjZ)@#9>l#4s>3o>LY#HGM}y3M0z=>Z3)RhxZ6DcGs+$R5Ky2wl)>;E0Rg*){6;7i zwcPL#hS9v*$h;o8W-}8%q!Ii4QW=XRzYNFYfaAmjzB(g?pPb}S{lc1a6FT49IM7;& zeXa+4j)4U(waqZ-^j&`Fs(Fs%*^p2!2g{<%<5dZQa+S42>Xl3~*1)6=(NXX)1)Y3$ zmT0b$Jxx2$3@DMN7_H6ZF*IJ<6(OJVOG5}O-7b3yA2n9b;gVyPXp-AsR}KaTlVaBR zP5dTb_we1cN5)->V(ot1d6X>NVSi*g0p!IGseV=M0 zwiwNI&$ZtRno5K!E|=fL#+(+tOB4hHLiy-Iqnj60%|NAVB$G_I#g=p`+C z_zkVt3tAm`;Th-Ri8Z9dp$C-TGefP)jI?**$9svm?%|l5FXR8 zV%pVpK@t2%ky@~xgkH?WW{d0aclhFtIa4di8Hk^-f~tg8CDR)HsnZg-z`C^kjG6uP z;vC;L?R+N&F-N9VO-^v{o#`Cv0-^@qN$jtjfMd9%Oa$Koop&)t{va{t`q8daANnRn zmVy@6jmBdXR>>h}(UEGmZEEMRaxX?pB=L~(vm7ZU*ap1>^N0a~7c{JPk>Y*!F5_Jq zJ0mxTjHhcxj)#p8&vaYgeo6Lj#+Qk9=pD$G0Ts8FcH2+L2PSu;+MyDuxvE`?-ae9N zU`FNGMhvQVo#6S2B08ts1-A;xA z#uT?0I=%-QHEeu{C!@p$cNX(5S-GF6C$k3^W`1V zh6p<6kFEbqCySa})A3{n&Amd^K%7=)4OZ;cKUP8-`Z4a}v8;Nyxr}$#@s}W zr&}ei_OkjqUipoy75khPe(Ym%;09d#$6kw$K(9@oL$(EUpKTYa9kN@kI27tY@g*`q zqLBEO7sQV87@~>WYqyeH^Y#(0Z$m=4P z`lRksf1HgK9k=PI30cTGEP48+M6f3Lg-M$4_&0!6LZ zJ5_mIA@#P*ivkYqP9YGObv=#MIvj&NOK5G#QQQD3Xnlq#Cv01^4vKuKbxL65EV{>x z`9ve^<&Py_9NaZ9r@xan)jWsN@DNPkUt03a&sI8|q!ex|)wi(%u(}I7&EAx`4I5>+ z&-ZoS^NI=F;D zOqVj^M)|6alef&WxX*dM!TA>9vbT&fhk9-u6ylVKQ!A62IQ}q`s0+6C5pJr#)^wP1 zd_-qGO#uZN3=WNb7XEXgH0qb?2bOV>Y%y?c{vnpg1Upcg`w^@~&w_t4*(PDf%*#-S zvtSVWiKW)rk~e|#%vtw^L{W{9<9f_ai{j$KGAsm%Cv#fND@@;W#hr`Z>*CYv$68B& z9NbCnGEKegE>+5}D4oU3>>9%Wk6B3~*MVKav^pEHMMjB-4quHnn}F!v!TC-Psg#q1GIUs?*;x;#)xJ>y{gXi_cxk^mwRmmj+`0 z0t=!rqifUmg_&|BL@OUc)+xmENTElw82Oa92O@H9^yA3~!SAz9P@6YT)) z`bA~m#`Q#vE!G>TThCmQ8_u= z4q4*?nuH$YJF4kMw1Kz~Qma6hcN(*1lwJQNZe<-G)eK)5DZt*><+ zze_!f`WfbYE}jfj-$;>Jbsqvgezr)JI;JJCsgIA6U3xoo(UQX?V>0HhuT0rNp_N&@ zB4A=y?&|-gstU6rzS?9AafLds8ZqXkuLtoZh88KdeuA2zw)tq@t+pY3|dQ;C{H zXSI(J249Cl$9LQ#lU8ZeDg#+Zv&e&q09I0@9Lo$k6N?xWj7pXQ(%xnJ^>r-DJ_HDx z!O*kk0c^8pn0-m_1noT=stSwp8_&*CaM*wg8#hzF05Qg%&H}?x~q7!wCV;;6FiLCxywt(n)VV2xQfi^ z|2Qo5`nVQ6=L?=x#^s~qSYTar7k+3IQ>kqnExmOQs8WgESxu+zzsBvQh#h7;eQ(x= zw0)qqn#wiiz8%tEvCS7;DWThZU9b%(Dei4w)zP!7bj9MX+E`Om3WTu}Mw^}IV6ArL z@UZ+5eY}lXDE9#``_%iORlmCh(I)gs_+PkC!z9-;805VAPXdL8FL(jKWgTz~q$|jXvr=NyON;N^GTV56!!s160LzV%&E1H4b+T+C(KO2l)Gn@GvMcGqn2Gc~R(X z1YuCrL^e)1lJ~vF+@cqjX)0)0Dr==y8Q~3KcC${-)+aIPp|E1HMiS=uRBTo>h@CBHFbM>fy=r+Od*THyCU17Kl67y z{;=C!zDED;QWUGF^oaPM8`cou0ssFfpjkq)poLfroiTK{i^CAZMPkH Date: Wed, 19 Nov 2025 13:11:20 +0000 Subject: [PATCH 32/52] switch off auto vba for excel --- src/ExcelUtils.pas | 43 ++++++++++++++++++++++++++++++++++++++----- src/docto.dproj | 1 + 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index eae11958..8910c251 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -41,7 +41,9 @@ interface constructor Create() ; function CreateOfficeApp() : boolean; override; function DestroyOfficeApp() : boolean; override; + function ExecuteConversion(fileToConvert: String; OutputFilename: String; OutputFileFormat : Integer): TConversionInfo; override; + function AvailableFormats() : TStringList; override; function FormatsExtensions(): TStringList; override; function OfficeAppVersion() : String; override; @@ -102,7 +104,7 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen var NonsensePassword :OleVariant; FromPage, ToPage : OleVariant; - activeSheet : OleVariant; + activeSheet, oldEnableEvents, oldAutoSecurity : OleVariant; dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String; ExitAction :TExitAction; Sheet : integer; @@ -114,6 +116,19 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen ExitAction := aSave; Result.InputFile := fileToConvert; Result.Successful := false; + + + // disable Macros before opening file. + if (fDontUseAutoVBA) then + begin + oldEnableEvents := ExcelApp.EnableEvents; + ExcelApp.EnableEvents := false; + oldAutoSecurity := ExcelApp.AutomationSecurity; + ExcelApp.AutomationSecurity := 3; // msoAutomationSecurityForceDisable + end; + + try + NonsensePassword := 'tfm554!ghAGWRDD'; LogDebug('in conversion file'); try @@ -174,9 +189,27 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen begin Result := SingleFileExecuteConversion(fileToConvert, OutputFilename, OutputFileFormat); + + // To avoid pop ups it is important to save the sheet. However not if the macros have run. + if (fDontUseAutoVBA) then + begin + // ExcelApp.ActiveWorkBook.save; + end else + begin + // Saved has previously been set to true. + // should close without dialog. + // ExcelApp.ActiveWorkbook.Close(); + end; end; end; + finally + if (fDontUseAutoVBA) then + begin + ExcelApp.EnableEvents := oldEnableEvents; + ExcelApp.AutomationSecurity := oldAutoSecurity; + end; + end; end; @@ -187,7 +220,7 @@ procedure TExcelXLSConverter.ExportWorkbookasPDF(OutputFileName: String); begin activeWkBk := ExcelApp.ActiveWorkbook; - ExcelApp.ActiveWorkBook.save; + ExcelApp.Application.DisplayAlerts := False ; activeWkBk.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, @@ -356,7 +389,7 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; if fSelectedSheets_All then begin - + logDebug('in fSelectedSheets_All'); for I := 1 to WorkSheets.Count do begin @@ -435,7 +468,7 @@ procedure TExcelXLSConverter.SaveAsXPS(OutputFilename : string) ; ExcelApp.Application.DisplayAlerts := False ; ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypeXPS, OutputFilename ); - ExcelApp.ActiveWorkBook.save; + end; procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); @@ -516,7 +549,7 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat); end; - ExcelApp.ActiveWorkBook.save; + end; end. diff --git a/src/docto.dproj b/src/docto.dproj index 940ca44b..5aec89cb 100644 --- a/src/docto.dproj +++ b/src/docto.dproj @@ -226,6 +226,7 @@ 1033 CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.3.2.15;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= (None) + -XL -f "Book1WithMacros.xlsm" -o c:/DriveETemp/sheet222macdro.pdf -t xlPDF -l 10 --enable-xlvbaauto ../exe From 513a3a1bb595e1ee72f2d6099cd0b1f4a496f691 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 13:18:18 +0000 Subject: [PATCH 33/52] tidy --- src/ExcelUtils.pas | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index 8910c251..da65259c 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -193,13 +193,15 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen // To avoid pop ups it is important to save the sheet. However not if the macros have run. if (fDontUseAutoVBA) then begin - // ExcelApp.ActiveWorkBook.save; - end else - begin + ExcelApp.ActiveWorkBook.save; + end ; + + ExcelApp.ActiveWorkBook.Saved := true; // Saved has previously been set to true. // should close without dialog. - // ExcelApp.ActiveWorkbook.Close(); - end; + ExcelApp.ActiveWorkbook.Close(); + + end; end; @@ -317,7 +319,7 @@ function TExcelXLSConverter.SingleFileExecuteConversion(fileToConvert: String; O // Close Excel Sheet. Result.Successful := true; Result.OutputFile := OutputFilename; - ExcelApp.ActiveWorkbook.Close(); + end; From 62e22d31041b79baedfd2829f022f489392f053c Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 14:38:32 +0000 Subject: [PATCH 34/52] update help --- readme.md | 33 ++++++++++++++++++++++----------- src/res/HelpLog.txt | 2 +- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/readme.md b/readme.md index cf1e421d..1b978bb0 100644 --- a/readme.md +++ b/readme.md @@ -128,8 +128,8 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u ## Command Line Help Help - Docto Version:%s - Office Version : %s + DocTo Version: %s + Office Version: %s Open Source: https://github.com/tobya/DocTo/ Description: DocTo converts Word Documents and Excel Spreadsheets to other formats. @@ -140,19 +140,22 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u -H This message --HELP -? - -WD Use Word for Converstion (Default). Help '-h -wd' + -WD Use Word for Conversion (Default). Help '-h -wd' --word -XL Use Excel for Conversion. Help '-h -xl' --excel -PP Use Powerpoint for Conversion. help '-h -pp' --powerpoint - -VS Use Visio for Conversion. + -VS Use Visio for Conversion. --visio -F Input File or Directory --inputfile - -FX Input file search for if -f is directory. Can use .rtf test*.txt etc + -FX Input Extension to search for if directory. (.rtf .txt etc) Default ".doc*" (will find ".docx" also) --inputextension + --inputfilter + Filter Files to input. Property*.doc will match Property1.doc, + Property2.doc etc -O Output File or Directory to place converted Docs --outputfile -OX Output Extension if -F is Directory. Please include '.' eg. '.pdf' . @@ -162,7 +165,6 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u Available from https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.word.wdsaveformat or https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.excel.xlfileformat - or https://docs.microsoft.com/en-us/office/vba/api/powerpoint.presentation.saveas See current List Below. --format -TF Force Format. -T value if an integer, is checked against current list @@ -219,9 +221,9 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u --no-subdirs Only convert specified directory. Do not recurse sub directories --ExportMarkup Value for wdExportItem - default wdExportDocumentContent. use wdExportDocumentWithMarkup to export all word comments with pdf - --no-IncludeDocProperties + --no-IncludeDocProperties --no-DocProp - Do not include Document Properties in the exported pdf file. + Do not include Document Properties in the exported pdf file. --PDF-OpenAfterExport If you wish for a converted PDF to be opened after creation. No value req. --PDF-FromPage @@ -237,11 +239,19 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u --PDF-No-DocStructureTags Do not include DocStructureTags to help screen readers. --PDF-no-BitmapMissingFonts - Do not bitmap missing fonts, fonts will be substituted. - --use-ISO190051 + Do not bitmap missing fonts, fonts will be substituted. + --use-ISO190051 Create PDF to the ISO 19005-1 standard. + --enable-macroautorun + --enable-wordvbaauto + --enable-xlvbaauto + By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only. + --sheets + Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. + --allsheets + If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names Experimental: @@ -260,8 +270,9 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u 205 : Invalid Parameter Value 220 : Word or COM Error 221 : Word not Installed + 301 : Not Implemented 400 : Unknown Error - + # Parameter Overview ## Usage diff --git a/src/res/HelpLog.txt b/src/res/HelpLog.txt index e0ce82c9..215e5d49 100644 --- a/src/res/HelpLog.txt +++ b/src/res/HelpLog.txt @@ -120,7 +120,7 @@ Long Parameters: By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only. --sheets - Select which sheets to save. Can be comma seperated list of 0 index numbers or sheet names. Excel Only. + Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. --allsheets If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names From 907fb38823d5dc19bcce7e8defa86213062cc9c4 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 14:39:04 +0000 Subject: [PATCH 35/52] update --- src/ExtraFiles.res | Bin 350080 -> 350136 bytes test/inputfilesxl/Book1WithMacros.xlsm | Bin 17797 -> 17796 bytes test/inputfilesxl/Week 1 Test.xls | Bin 38400 -> 38400 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/ExtraFiles.res b/src/ExtraFiles.res index b2f14ef9e20e5c8ceedbbc7242abe65034958efe..c93bc94f0942e0a3bfc22bf69e84b496c18c9b13 100644 GIT binary patch delta 112 zcmZozFS=vB=!P4@jJG%66h19%oST?jl%H5yl3!Gs$IGRlpsSmjmzb23s#~64lv0+I z2$Dh(ugICaLOq9FU%|B^IW=dqu*OtoMuz4U+U+Z}8G)Dyh?#+yW%~+k)*IRYMmZ=N delta 62 zcmdn7UbJDo=!P4@tV_fh7<492)DzwONqCd+tI PF*6XeY=5B5dP5rk5_=gI diff --git a/test/inputfilesxl/Book1WithMacros.xlsm b/test/inputfilesxl/Book1WithMacros.xlsm index 662c71193831d6b0b9bf0e8b2c380d4cd6b75cf7..f94a4ac5493251e380029e54a544325c16483ecf 100644 GIT binary patch delta 8572 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 C;(*rx delta 8613 zcmV;WAzI#qivfj;0k8rG1^yG0PqdQ<2T=v~j2}OqlU)Z&e_&a2Q43O?MAdZKLxHP;;C;@&g&K+ zR;*(3WdPN+Iu9=&8!pJIf@5#7qiqFzUHD-W8f)AMOh;SQEEl}vYk3CH#*XyS`LStW z{2>I};~1QVlO_mCe^x7)SfFqaJl!pSO_IQi{4_#A6htU>afTwt@sO7|k(YRu6U@@@ zx^ZzRfE)2{`J!aq{k}4Et)OetS8@R*F%pFubKSsl6aq*rsw5Q+k#xoz35woF=vUP{ zV9!bpwW7`G-#rr)N)(g|QG=G`Az5`dM3!1Fs;NE;mkE8Qe-&?4RV^QxEc?~6;Q4|t zC4_FtnzolJ+}*ZXz7swvnOI2_xbe(~Osbj=b543$ z?zN<#r@9Toe>pN;lkI51X4tdhjmE3F{~*=>(2TZ0IO^8CV|3HKX-EyV?LBJ>zM1OC z@&gNw^>UcNYPcE9_pFem60T_<=Ki4Uu>{W8@suOfm*O_nUwzlg0y|BS7sM{IJ!pK4 zE#xN|_A+dzS?Ug)jCZ7l8yd(Bz19p>b*pY|3{QdTe}^#Znh4b%;ikf8vW*%J%R?8HhPFHO?eQ5jM%O!$A? zvxEA>@##`5OCsb#ko*ZAyg6ORqytIq4g`GPlZ_oeHYY&Q&fre4abTi2c5UP&*~Ia1 zGE1H8Q;n=T{`!-*oNo-PDUm(Ytt#1J9I7_k&mJb%yNP|CK2%>gPgLCZtN+dM7EWK$ z6P>fW6CGz?uNT)R`d+1rhx_bQ=jb|4qSO7O`8@h-k$xMuv%v~B5d_%WB({_L8%Tdh z%48;HCOoR*1hAzlt*=^bZ3V5?RkUEYwy3qBZPz}5UAMN{tx###c5MrNY}szt?EgED znLCpQA?R=0-_J9@|J-xW`}v*keCIp&$l=0cd-j(cXBlQOv#_^^a#^;?U4xy#je{{A z77Ot9(9n=_hV?!3chmy^i?Z6#d6RzuE06_HpXUI%z*N8vJ`mj?IzaQE^2?n6bK!m&Fb^mP zDuBxYCqS*{1}cFnU_MX{)Bu0AKpn6ESO_cv>Vd_;KL8B?jXf_w!?6*d{G0Gx0xSiV z0apOafo7luxDr?av;yx3RswCnD&Q($HE=bs2KWGQ4e&vr9rzG%EwC2o00KZK&;td4|D@Pz=weiKp5x+B0v=A1E{<-eq%sfzHh{H6R;Ve+58dUdf25!h{A_i zs1<8TH@o;+W|_;{ms|nwlfNDpRE@KlyTUo!Ior2@wO`#62}U=?SbN)+SUl8QX?3?- zLhg!qxRcFZ(d;)o1Mx((HxTcMMwoLu)3*CptXtR9wZp%21zVRub9Qa>mwY}^cy~e@ z^ph$dBY&qqaqs&60P8iHdcvVtdxJ09+Z&Bovs+kCSAR4XT?gvf)*a{%1>4z*rlw^+ zzpI+Hx3sOOXl!oIp8YY$_7=lcUE#DDD>?@c8O=SN`}za@TQH=w^R~Tgv#`nAEM-O0 zn4Xicw?u;j;gHj{giX@2*%Lwb;DG)m7c0rNxqltD2WKR(1TXb!t{3{QSS+Il&W31o!xA>NA$yglA=ZNda&^M!Z^c0BJg7wv zY9+lt%yYk*cX-aN?2#YLd1}UqQt#|<%{g>mTX$%0D9*f|-E9rCLk9=minBq_k{q{p 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 diff --git a/test/inputfilesxl/Week 1 Test.xls b/test/inputfilesxl/Week 1 Test.xls index 8ed57b5be88f06f1865afcdd68233efdac05dfcb..0abb0766e522871ac9fd8e7cdfbb68e674a16f58 100644 GIT binary patch delta 29 lcmZoz!_=^bX~T^o)&{00`T?8o7WFGmK5NafxnxQYBLKs54Bh|$ delta 34 qcmZoz!_=^bX~T^oR));*<;I)u7WFG~D9rp{XcBpcadXL(9!3EE$_|SF From d50cc59ef48fa0b4d2bb596a7fbf2ad98423ffd4 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 15:37:34 +0000 Subject: [PATCH 36/52] check for 0 index --- src/ExcelUtils.pas | 34 +++++++++++++++++++++++------- src/Exceptions/DocToExceptions.pas | 12 +++++++++++ 2 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 src/Exceptions/DocToExceptions.pas diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index eae11958..528327f1 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -15,7 +15,7 @@ interface uses Classes,Sysutils, MainUtils, ResourceUtils, ActiveX, ComObj, WinINet, Variants, -DynamicFileNameGenerator, +DynamicFileNameGenerator, DocToExceptions, Excel_TLB_Constants,StrUtils; @@ -36,6 +36,7 @@ interface procedure ExportWorkbookasPDF(OutputFileName: String); function isWorkSheetEmpty(WorkSheet : OleVariant): boolean; + procedure CheckWorkSheetIndexValid(index : integer); public constructor Create() ; @@ -68,6 +69,15 @@ function TExcelXLSConverter.AvailableFormats() : TStringList; { TWordDocConverter } +procedure TExcelXLSConverter.CheckWorkSheetIndexValid(index: integer); +begin + + if (index = 0) then + begin + raise ESheetIndexOutOfBounds.Create('Excel Worksheets start at 1. 0 is not valid index'); + end; +end; + constructor TExcelXLSConverter.Create; begin inherited; @@ -307,6 +317,8 @@ function TExcelXLSConverter.isWorkSheetEmpty(WorkSheet: OleVariant): boolean; end; + + function TExcelXLSConverter.OfficeAppVersion(): String; begin FExcelVersion := ReadOfficeAppVersion; @@ -330,8 +342,11 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; sheetName : olevariant; FileNameGen: TDynamicFileNameGenerator; begin - logdebug('Save as pdf',debug); - ExcelApp.Application.DisplayAlerts := False ; + + + logdebug('Save as pdf',debug); + + ExcelApp.Application.DisplayAlerts := False ; if pdfPrintToPage > 0 then begin @@ -375,24 +390,26 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; begin logdebug('SelectedSheets.Count:' + inttostr( SelectedSheets.Count), debug); - logDebug('Selecting sheets' + SelectedSheets.Text,VERBOSE); + logDebug( SelectedSheets.Text,VERBOSE); + - //for I := 1 to WorkSheets.Count do for j := 0 to SelectedSheets.Count -1 do begin sheetName := SelectedSheets[j]; - + logDebug( sheetName,VERBOSE); if (TryStrToInt(sheetName,sheetNumber) )then begin + logdebug( 'TryStrToInt',VERBOSE); + self.CheckWorkSheetIndexValid(sheetNumber); ws := WorkSheets.Item[sheetNumber]; end else begin - + logdebug( 'not TryStrToInt',VERBOSE); ws := WorkSheets.Item[sheetName]; end; @@ -403,7 +420,7 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; - logDebug('worksheet:' + ws.Name, VERBOSE); + logDebug('worksheetxx:' + ws.Name, VERBOSE); ExportWorkSheetasPDF(ws,FileNameGen); @@ -491,6 +508,7 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); // Check if number requested and set sheetNumber if (TryStrToInt(SelectedSheets[ix],sheetNumber) )then begin + self.CheckWorkSheetIndexValid(sheetNumber); activeSheet := ExcelApp.ActiveWorkbook.Sheets[sheetNumber]; end else // otherwise use string name. diff --git a/src/Exceptions/DocToExceptions.pas b/src/Exceptions/DocToExceptions.pas new file mode 100644 index 00000000..16785638 --- /dev/null +++ b/src/Exceptions/DocToExceptions.pas @@ -0,0 +1,12 @@ +unit DocToExceptions; + +interface +uses Classes, MainUtils, ResourceUtils, ActiveX, ComObj, WinINet, Variants, sysutils, Types, StrUtils,Word_TLB_Constants, TypInfo; + +type + + ESheetIndexOutOfBounds = class(Exception); + +implementation + +end. From 0c779d6f8e828a5298da5ae84040338676366ba8 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 15:37:52 +0000 Subject: [PATCH 37/52] files --- src/docto.dpr | 3 +- src/docto.dproj | 133 ++++++++++++++++++++++++++++++++++++++++++ src/docto.dproj.local | 4 ++ 3 files changed, 139 insertions(+), 1 deletion(-) diff --git a/src/docto.dpr b/src/docto.dpr index 52555e85..5b540d70 100644 --- a/src/docto.dpr +++ b/src/docto.dpr @@ -36,7 +36,8 @@ uses PowerPoint_TLB_Constants in 'PowerPoint_TLB_Constants.pas', VisioUtils in 'VisioUtils.pas', Visio_TLB in 'Visio_TLB.pas', - DynamicFileNameGenerator in 'shared\DynamicFileNameGenerator.pas'; + DynamicFileNameGenerator in 'shared\DynamicFileNameGenerator.pas', + DocToExceptions in 'Exceptions\DocToExceptions.pas'; var i, Converter : integer; diff --git a/src/docto.dproj b/src/docto.dproj index 940ca44b..31c05e67 100644 --- a/src/docto.dproj +++ b/src/docto.dproj @@ -298,6 +298,7 @@ + @@ -388,18 +389,48 @@ True + + + .\ + true + + docto.exe true + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + .\ true + + + .\ + true + + .\ @@ -418,6 +449,18 @@ true + + + .\ + true + + + + + .\ + true + + .\ @@ -466,6 +509,12 @@ true + + + .\ + true + + .\ @@ -502,6 +551,18 @@ true + + + docto.exe + true + + + + + .\ + true + + .\ @@ -519,6 +580,54 @@ true + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + .\ @@ -549,6 +658,12 @@ true + + + .\ + true + + .\ @@ -579,6 +694,12 @@ true + + + .\ + true + + .\ @@ -609,6 +730,12 @@ true + + + .\ + true + + true @@ -662,6 +789,12 @@ true + + + .\ + true + + .\ diff --git a/src/docto.dproj.local b/src/docto.dproj.local index 36a1d6c2..16057aef 100644 --- a/src/docto.dproj.local +++ b/src/docto.dproj.local @@ -8,12 +8,16 @@ 2023/09/11 17:39:20.000.384,=C:\Development\github\docto\src\res\xlsFormats.txt 2025/11/18 17:53:47.458,=C:\Development\github\docto\src\Unit1.pas 2025/11/18 17:54:21.396,C:\Development\github\docto\src\shared\DynamicFileNameGenerator.pas=C:\Development\github\docto\src\Unit1.pas + 2025/11/19 14:43:02.361,=C:\Development\github\docto\src\Unit1.pas + 2025/11/19 14:43:31.175,C:\Development\github\docto\src\Exceptions\DocToExceptions.pas=C:\Development\github\docto\src\Unit1.pas + + From ce8be0d67c6b1ba688c036aea8034a6ccf07575e Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 17:37:50 +0000 Subject: [PATCH 38/52] Disable Excel Auto Macros (#241) Co-authored-by: Toby Allen --- readme.md | 33 +++++++++++------ src/ExcelUtils.pas | 47 +++++++++++++++++++++---- src/ExtraFiles.res | Bin 350080 -> 350136 bytes src/MainUtils.pas | 9 ++--- src/docto.dproj | 1 + src/res/HelpLog.txt | 6 ++-- test/inputfilesxl/Book1WithMacros.xlsm | Bin 16711 -> 17796 bytes test/inputfilesxl/Week 1 Test.xls | Bin 38400 -> 38400 bytes 8 files changed, 71 insertions(+), 25 deletions(-) diff --git a/readme.md b/readme.md index cf1e421d..1b978bb0 100644 --- a/readme.md +++ b/readme.md @@ -128,8 +128,8 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u ## Command Line Help Help - Docto Version:%s - Office Version : %s + DocTo Version: %s + Office Version: %s Open Source: https://github.com/tobya/DocTo/ Description: DocTo converts Word Documents and Excel Spreadsheets to other formats. @@ -140,19 +140,22 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u -H This message --HELP -? - -WD Use Word for Converstion (Default). Help '-h -wd' + -WD Use Word for Conversion (Default). Help '-h -wd' --word -XL Use Excel for Conversion. Help '-h -xl' --excel -PP Use Powerpoint for Conversion. help '-h -pp' --powerpoint - -VS Use Visio for Conversion. + -VS Use Visio for Conversion. --visio -F Input File or Directory --inputfile - -FX Input file search for if -f is directory. Can use .rtf test*.txt etc + -FX Input Extension to search for if directory. (.rtf .txt etc) Default ".doc*" (will find ".docx" also) --inputextension + --inputfilter + Filter Files to input. Property*.doc will match Property1.doc, + Property2.doc etc -O Output File or Directory to place converted Docs --outputfile -OX Output Extension if -F is Directory. Please include '.' eg. '.pdf' . @@ -162,7 +165,6 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u Available from https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.word.wdsaveformat or https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.excel.xlfileformat - or https://docs.microsoft.com/en-us/office/vba/api/powerpoint.presentation.saveas See current List Below. --format -TF Force Format. -T value if an integer, is checked against current list @@ -219,9 +221,9 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u --no-subdirs Only convert specified directory. Do not recurse sub directories --ExportMarkup Value for wdExportItem - default wdExportDocumentContent. use wdExportDocumentWithMarkup to export all word comments with pdf - --no-IncludeDocProperties + --no-IncludeDocProperties --no-DocProp - Do not include Document Properties in the exported pdf file. + Do not include Document Properties in the exported pdf file. --PDF-OpenAfterExport If you wish for a converted PDF to be opened after creation. No value req. --PDF-FromPage @@ -237,11 +239,19 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u --PDF-No-DocStructureTags Do not include DocStructureTags to help screen readers. --PDF-no-BitmapMissingFonts - Do not bitmap missing fonts, fonts will be substituted. - --use-ISO190051 + Do not bitmap missing fonts, fonts will be substituted. + --use-ISO190051 Create PDF to the ISO 19005-1 standard. + --enable-macroautorun + --enable-wordvbaauto + --enable-xlvbaauto + By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only. + --sheets + Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. + --allsheets + If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names Experimental: @@ -260,8 +270,9 @@ https://webapps.stackexchange.com/questions/74859/what-format-does-word-online-u 205 : Invalid Parameter Value 220 : Word or COM Error 221 : Word not Installed + 301 : Not Implemented 400 : Unknown Error - + # Parameter Overview ## Usage diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index 528327f1..e1373fad 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -42,7 +42,9 @@ interface constructor Create() ; function CreateOfficeApp() : boolean; override; function DestroyOfficeApp() : boolean; override; + function ExecuteConversion(fileToConvert: String; OutputFilename: String; OutputFileFormat : Integer): TConversionInfo; override; + function AvailableFormats() : TStringList; override; function FormatsExtensions(): TStringList; override; function OfficeAppVersion() : String; override; @@ -112,7 +114,7 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen var NonsensePassword :OleVariant; FromPage, ToPage : OleVariant; - activeSheet : OleVariant; + activeSheet, oldEnableEvents, oldAutoSecurity : OleVariant; dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String; ExitAction :TExitAction; Sheet : integer; @@ -124,6 +126,19 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen ExitAction := aSave; Result.InputFile := fileToConvert; Result.Successful := false; + + + // disable Macros before opening file. + if (fDontUseAutoVBA) then + begin + oldEnableEvents := ExcelApp.EnableEvents; + ExcelApp.EnableEvents := false; + oldAutoSecurity := ExcelApp.AutomationSecurity; + ExcelApp.AutomationSecurity := 3; // msoAutomationSecurityForceDisable + end; + + try + NonsensePassword := 'tfm554!ghAGWRDD'; LogDebug('in conversion file'); try @@ -184,9 +199,29 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen begin Result := SingleFileExecuteConversion(fileToConvert, OutputFilename, OutputFileFormat); + + // To avoid pop ups it is important to save the sheet. However not if the macros have run. + if (fDontUseAutoVBA) then + begin + ExcelApp.ActiveWorkBook.save; + end ; + + ExcelApp.ActiveWorkBook.Saved := true; + // Saved has previously been set to true. + // should close without dialog. + ExcelApp.ActiveWorkbook.Close(); + + end; end; + finally + if (fDontUseAutoVBA) then + begin + ExcelApp.EnableEvents := oldEnableEvents; + ExcelApp.AutomationSecurity := oldAutoSecurity; + end; + end; end; @@ -197,7 +232,7 @@ procedure TExcelXLSConverter.ExportWorkbookasPDF(OutputFileName: String); begin activeWkBk := ExcelApp.ActiveWorkbook; - ExcelApp.ActiveWorkBook.save; + ExcelApp.Application.DisplayAlerts := False ; activeWkBk.ExportAsFixedFormat(XlFixedFormatType_xlTypePDF, @@ -294,7 +329,7 @@ function TExcelXLSConverter.SingleFileExecuteConversion(fileToConvert: String; O // Close Excel Sheet. Result.Successful := true; Result.OutputFile := OutputFilename; - ExcelApp.ActiveWorkbook.Close(); + end; @@ -371,7 +406,7 @@ procedure TExcelXLSConverter.SaveAsPDF(OutputFilename : string) ; if fSelectedSheets_All then begin - + logDebug('in fSelectedSheets_All'); for I := 1 to WorkSheets.Count do begin @@ -452,7 +487,7 @@ procedure TExcelXLSConverter.SaveAsXPS(OutputFilename : string) ; ExcelApp.Application.DisplayAlerts := False ; ExcelApp.activeWorkbook.ExportAsFixedFormat(XlFixedFormatType_xlTypeXPS, OutputFilename ); - ExcelApp.ActiveWorkBook.save; + end; procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); @@ -534,7 +569,7 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat); end; - ExcelApp.ActiveWorkBook.save; + end; end. diff --git a/src/ExtraFiles.res b/src/ExtraFiles.res index b2f14ef9e20e5c8ceedbbc7242abe65034958efe..c93bc94f0942e0a3bfc22bf69e84b496c18c9b13 100644 GIT binary patch delta 112 zcmZozFS=vB=!P4@jJG%66h19%oST?jl%H5yl3!Gs$IGRlpsSmjmzb23s#~64lv0+I z2$Dh(ugICaLOq9FU%|B^IW=dqu*OtoMuz4U+U+Z}8G)Dyh?#+yW%~+k)*IRYMmZ=N delta 62 zcmdn7UbJDo=!P4@tV_fh7<492)DzwONqCd+tI PF*6XeY=5B5dP5rk5_=gI diff --git a/src/MainUtils.pas b/src/MainUtils.pas index 3cd5e246..6b9f45b2 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -1333,15 +1333,12 @@ procedure TDocumentConverter.LoadConfig(Params: TStrings); end else if (id = '--ENABLE-MACROAUTORUN') or - (id = '--ENABLE-WORDVBAAUTO') + (id = '--ENABLE-WORDVBAAUTO') or + (id = '--ENABLE-XLVBAAUTO') then begin fDontUseAutoVBA := false; - if (OfficeAppName <> 'Word')then - begin - // Excel Application.EnableEvents = False - // HaltWithError(301,'Parameter ' + id + ' not Implemented for ' + OfficeAppName ); - end; + end else if (id = '-X') or diff --git a/src/docto.dproj b/src/docto.dproj index 31c05e67..a00d2dc0 100644 --- a/src/docto.dproj +++ b/src/docto.dproj @@ -226,6 +226,7 @@ 1033 CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=0.3.2.15;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= (None) + -XL -f "Book1WithMacros.xlsm" -o c:/DriveETemp/sheet222macdro.pdf -t xlPDF -l 10 --enable-xlvbaauto ../exe diff --git a/src/res/HelpLog.txt b/src/res/HelpLog.txt index 29070d70..215e5d49 100644 --- a/src/res/HelpLog.txt +++ b/src/res/HelpLog.txt @@ -114,11 +114,13 @@ Long Parameters: --use-ISO190051 Create PDF to the ISO 19005-1 standard. + --enable-macroautorun --enable-wordvbaauto - By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word Only. + --enable-xlvbaauto + By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only. --sheets - Select which sheets to save. Can be comma seperated list of 0 index numbers or sheet names. Excel Only. + Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. --allsheets If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names diff --git a/test/inputfilesxl/Book1WithMacros.xlsm b/test/inputfilesxl/Book1WithMacros.xlsm index e71827a5d5a7ee998a5af8719f184a5e54d3652c..f94a4ac5493251e380029e54a544325c16483ecf 100644 GIT binary patch delta 11975 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 z z9*GVo##6Ri%(|&W;|i&j9>0WPxh0Z?U^)LX_bRdL1a3`ZZfx}rZr-M?uwF5>Jol?E z^xq#)_C+K{_|E|#7_muS=VOg8;M~BfewsC(hc5%eKT2#y(~np{kRwX1j%5*Q^6jl; zhtUB`yktMgl!CSEBU64*WO;_L2pHc{_}IhK3KyLKBmf@aiCbSfF0)2xx1#j&tM1ak zMXd=h8<3PBt&C4Z_nuLFv&EcvpKlP-_JNUjo#33ZyGqu!gC!zYSotwQjIf%Wjlga# zb98;@-3ITg4GKHwqeCxcDoK<0jP4=w;PX)U*tTa>(h8kMWib0l7G)?2z)p^uW1YcZ zW)+K$UCCBJ-n-!SIg0=3K>ot@U4eo}uBO_^I_)#t*VbhXV-BmnN zT6Kk~4gG`GwaZ7(mi`thdAk%o6$qVBB@kfXnrC0|6uoPdP^)bmDZTa# zs#1&DUP-6zza;3Tiu=uc{MxJwV}D0$Gns43dp%^hY@aW@T*9#NJZ~RVQrz3VqG#Yx z>5j`=wZ5vX5)AJkia9gK#a`{scxp zHc>^!3F)>X;s-2+1!n#8oH*PTvM3}*A_q4j+3VlN+@dG8DH=F=8e5fCIni}dPK!?N z)&~jMp|l=Ue~li@CQ3)}pYjI+0`tG%KTjU)B`ORxjtg!V1rhvTX!&1eCiqU2 zn&3b32LXZpU+|w73g!|Mgo@z+Z}3opGsS43;yA%uyfpNRGLTRV{{Sc~1pL1&Qi%V( h9*__a>HqX^|EB^sm`Gdz3WX1>D^3PGCh$My{~tHh`YQkc diff --git a/test/inputfilesxl/Week 1 Test.xls b/test/inputfilesxl/Week 1 Test.xls index 8ed57b5be88f06f1865afcdd68233efdac05dfcb..0abb0766e522871ac9fd8e7cdfbb68e674a16f58 100644 GIT binary patch delta 29 lcmZoz!_=^bX~T^o)&{00`T?8o7WFGmK5NafxnxQYBLKs54Bh|$ delta 34 qcmZoz!_=^bX~T^oR));*<;I)u7WFG~D9rp{XcBpcadXL(9!3EE$_|SF From 463787c238890e956532b6fba11fd0e396b966b8 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 17:38:35 +0000 Subject: [PATCH 39/52] update --- src/docto.dproj.local | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/docto.dproj.local b/src/docto.dproj.local index 36a1d6c2..29b7e8a7 100644 --- a/src/docto.dproj.local +++ b/src/docto.dproj.local @@ -8,6 +8,8 @@ 2023/09/11 17:39:20.000.384,=C:\Development\github\docto\src\res\xlsFormats.txt 2025/11/18 17:53:47.458,=C:\Development\github\docto\src\Unit1.pas 2025/11/18 17:54:21.396,C:\Development\github\docto\src\shared\DynamicFileNameGenerator.pas=C:\Development\github\docto\src\Unit1.pas + 2025/11/19 14:43:02.361,=C:\Development\github\docto\src\Unit1.pas + 2025/11/19 14:43:31.175,C:\Development\github\docto\src\Exceptions\DocToExceptions.pas=C:\Development\github\docto\src\Unit1.pas From 70bf41449e7a94036359271d724636f0ed701ce2 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 18:45:22 +0000 Subject: [PATCH 40/52] Move files for file gather --- companion/app/Services/FileGatherService.php | 14 +++-- companion/config/filesystems.php | 6 +++ companion/config/services.php | 3 +- .../Remove/RemoveInputFilePestTest.php | 7 +-- .../XLS/MultiSheet/MultiSheetPestTest.php | 53 +++++++++++++++++++ 5 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php diff --git a/companion/app/Services/FileGatherService.php b/companion/app/Services/FileGatherService.php index e776a0ac..2acff1a5 100644 --- a/companion/app/Services/FileGatherService.php +++ b/companion/app/Services/FileGatherService.php @@ -7,6 +7,14 @@ class FileGatherService { + /** + * Gather files will take files from specific subdir of the resource InputFiles directory and + * copy them to a temporary directory wehre they can be used for a test. + * @param Collection $list + * @param $tempDirName + * @return Collection + * @throws \League\Flysystem\FilesystemException + */ public static function GatherFiles(Collection $list, $tempDirName) { // remove exisitn files @@ -15,12 +23,10 @@ public static function GatherFiles(Collection $list, $tempDirName) } $tempDirPath = Storage::path($tempDirName); - $list->each(function ($dir) use ($tempDirName, $tempDirPath){ - $inputfilesdir = \Illuminate\Support\Facades\Storage::path('inputfiles\\' . $dir ); + $list->each(function ($inputdir) use ($tempDirName, $tempDirPath){ + $inputfilesdir = \Illuminate\Support\Facades\Storage::disk('inputfiles')->path($inputdir ); $cmd = "xcopy \"$inputfilesdir\" \"$tempDirPath\\\" "; $result = \Illuminate\Support\Facades\Process::run( $cmd ); - // echo "\n $cmd \n"; - // echo "\n" . $result->output() . "\n"; }); return collect(Storage::listContents($tempDirName)); } diff --git a/companion/config/filesystems.php b/companion/config/filesystems.php index 0e7d6952..63fb5fc1 100644 --- a/companion/config/filesystems.php +++ b/companion/config/filesystems.php @@ -42,6 +42,12 @@ 'throw' => false, ], + 'inputfiles' => [ + 'driver' => 'local', + 'root' => resource_path('inputfiles'), + 'throw' => false, + ], + 'public' => [ 'driver' => 'local', diff --git a/companion/config/services.php b/companion/config/services.php index d7fcf9a0..d5bda7eb 100644 --- a/companion/config/services.php +++ b/companion/config/services.php @@ -15,7 +15,8 @@ */ 'docto' => [ - 'path' => env('DOCTO_PATH','..\\exe\\32\\docto.exe'), + // 'path' => env('DOCTO_PATH','..\\exe\\32\\docto.exe'), + 'path' => env('DOCTO_PATH','..\\exe\\64\\docto.exe'), ], 'mailgun' => [ diff --git a/companion/tests/Feature/Remove/RemoveInputFilePestTest.php b/companion/tests/Feature/Remove/RemoveInputFilePestTest.php index 3e95b1f0..4fd51f79 100644 --- a/companion/tests/Feature/Remove/RemoveInputFilePestTest.php +++ b/companion/tests/Feature/Remove/RemoveInputFilePestTest.php @@ -92,11 +92,12 @@ // echo $doctocmd; $output = \Illuminate\Support\Facades\Process::run($doctocmd); - + expect(collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp'))->count())->toBeGreaterThan(0); // check files have been converted and originoals have been created. expect(collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp'))->count())->tobe( $docfilecount); - - expect(collect(\Illuminate\Support\Facades\Storage::listContents('outputtemp2'))->count())->tobe( $docfilecount); + $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::listContents('outputtemp2')); + expect($outputDirFiles->count())->toBeGreaterThan( 0); + expect($outputDirFiles->count())->tobe( $docfilecount); }); diff --git a/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php new file mode 100644 index 00000000..464d4cb5 --- /dev/null +++ b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php @@ -0,0 +1,53 @@ +output() . "\n"; + // $dirfiles = collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp')); + $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['plain']), 'inputfilestemp'); + $docfiles = $dirfiles->filter(function ($item) { + return str($item->path())->endsWith('.doc'); + }); + + expect($docfiles->count())->toBeGreaterThan(0); + $docfilecount = count($docfiles->toArray()); + + $dirfilescount = $dirfiles->count(); + // do conversion + $docto = config('services.docto.path'); + // $doctocmd = "$docto -WD -f $testinputfilesdir_temp -fx .doc -o $testoutputdir_temp -t wdFormatPDF -R true"; + $doctocmd = \App\Services\DocToCommandBuilder::docto() + ->add('-WD') + ->add('-f', $testinputfilesdir_temp) + ->add('-fx', '.doc') + ->add('-o', $testoutputdir_temp) + ->add('-t wdFormatPDF') + ->add('-R', 'true') // the important one fo rthis test + ->build(); + // echo $doctocmd; + $output = \Illuminate\Support\Facades\Process::run($doctocmd); + + + // check files have been converted and originoals have been created. + expect(collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp'))->count())->tobe($dirfilescount - $docfilecount); + expect(collect(\Illuminate\Support\Facades\Storage::listContents('outputtemp2'))->count())->tobe($docfilecount); + + + }); From 1c807c2db6740ca0d403a7f0d822625ecd2399f0 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 18:45:58 +0000 Subject: [PATCH 41/52] Required Test .doc --- .../password/CullohillApplePie_Protected.doc | Bin 0 -> 30720 bytes .../plain/Ballymaloe Mincemeat Tart.doc | Bin 0 -> 31744 bytes .../Ballymaloe+Hot+Buttered+Lobster (2).doc | Bin 0 -> 36352 bytes .../Ballymaloe+Hot+Buttered+Lobster 3 .doc | Bin 0 -> 35840 bytes .../Bookmarks+Chocolate+and+Hazelnut+Tart.doc | Bin 0 -> 33280 bytes .../plain/CullohillApplePie - Copy.doc | Bin 0 -> 28672 bytes .../resources/inputfiles/single/ASingleFile.doc | 0 7 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 companion/resources/inputfiles/password/CullohillApplePie_Protected.doc create mode 100644 companion/resources/inputfiles/plain/Ballymaloe Mincemeat Tart.doc create mode 100644 companion/resources/inputfiles/plain/Ballymaloe+Hot+Buttered+Lobster (2).doc create mode 100644 companion/resources/inputfiles/plain/Ballymaloe+Hot+Buttered+Lobster 3 .doc create mode 100644 companion/resources/inputfiles/plain/Bookmarks+Chocolate+and+Hazelnut+Tart.doc create mode 100644 companion/resources/inputfiles/plain/CullohillApplePie - Copy.doc create mode 100644 companion/resources/inputfiles/single/ASingleFile.doc diff --git a/companion/resources/inputfiles/password/CullohillApplePie_Protected.doc b/companion/resources/inputfiles/password/CullohillApplePie_Protected.doc new file mode 100644 index 0000000000000000000000000000000000000000..4d8527aac791360b3df8fd3b5ff99ffc80f9ed4c GIT binary patch literal 30720 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

U(>y?PKvVR87}7PS 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 CA_gx2 literal 0 HcmV?d00001 diff --git a/companion/resources/inputfiles/plain/Ballymaloe+Hot+Buttered+Lobster (2).doc b/companion/resources/inputfiles/plain/Ballymaloe+Hot+Buttered+Lobster (2).doc new file mode 100644 index 0000000000000000000000000000000000000000..472fd9d87d608c87f1c966692a4de36394a5ae25 GIT binary patch literal 36352 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 literal 0 HcmV?d00001 diff --git a/companion/resources/inputfiles/plain/Bookmarks+Chocolate+and+Hazelnut+Tart.doc b/companion/resources/inputfiles/plain/Bookmarks+Chocolate+and+Hazelnut+Tart.doc new file mode 100644 index 0000000000000000000000000000000000000000..ea9c6b061d0197672d820efa49a909ef1cf55247 GIT binary patch literal 33280 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 Yiu^%Bd{7MYYxk`a1#7d=e>V;M7l!j Date: Wed, 19 Nov 2025 21:11:31 +0000 Subject: [PATCH 42/52] fix tests --- .../app/Services/DocToCommandBuilder.php | 5 +- .../Remove/RemoveInputFilePestTest.php | 17 +- .../XLS/MultiSheet/MultiSheetPestTest.php | 153 ++++++++++++++---- src/docto.dproj.local | 10 +- 4 files changed, 142 insertions(+), 43 deletions(-) diff --git a/companion/app/Services/DocToCommandBuilder.php b/companion/app/Services/DocToCommandBuilder.php index a1a679f6..a4fbb7e3 100644 --- a/companion/app/Services/DocToCommandBuilder.php +++ b/companion/app/Services/DocToCommandBuilder.php @@ -19,7 +19,10 @@ public function add($param, $value = null){ public function build(){ $cmd = ''; foreach($this->params as $paramset){ - $cmd .= $paramset[0] . ' ' . $paramset[1] . ' '; + $cmd .= ' ' . $paramset[0] ; + if (isset($paramset[1])){ + $cmd .= ' "' . $paramset[1] . '" '; + } } return $cmd; } diff --git a/companion/tests/Feature/Remove/RemoveInputFilePestTest.php b/companion/tests/Feature/Remove/RemoveInputFilePestTest.php index 4fd51f79..2480e72b 100644 --- a/companion/tests/Feature/Remove/RemoveInputFilePestTest.php +++ b/companion/tests/Feature/Remove/RemoveInputFilePestTest.php @@ -40,11 +40,11 @@ ->build(); // echo $doctocmd; $output = \Illuminate\Support\Facades\Process::run($doctocmd); - +// print_r($output); // check files have been converted and originoals have been created. - expect(collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp'))->count())->tobe($dirfilescount - $docfilecount); - expect(collect(\Illuminate\Support\Facades\Storage::listContents('outputtemp2'))->count())->tobe( $docfilecount); + expect(collect(\Illuminate\Support\Facades\Storage::AllFiles('inputfilestemp'))->count())->tobe($dirfilescount - $docfilecount); + expect(collect(\Illuminate\Support\Facades\Storage::AllFiles('outputtemp2'))->count())->tobe( $docfilecount); }); @@ -92,12 +92,15 @@ // echo $doctocmd; $output = \Illuminate\Support\Facades\Process::run($doctocmd); - expect(collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp'))->count())->toBeGreaterThan(0); + expect(collect(\Illuminate\Support\Facades\Storage::AllFiles('inputfilestemp'))->count())->toBeGreaterThan(0); // check files have been converted and originoals have been created. - expect(collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp'))->count())->tobe( $docfilecount); - $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::listContents('outputtemp2')); + expect(collect(\Illuminate\Support\Facades\Storage::AllFiles('inputfilestemp'))->count())->tobe( $docfilecount); + $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::AllFiles('outputtemp2')); expect($outputDirFiles->count())->toBeGreaterThan( 0); expect($outputDirFiles->count())->tobe( $docfilecount); - + // This will delete all files in the storage/tests directory. + // this happens once a test run to prevent files from building up. + // could be done a bit more organised if desired. + \Illuminate\Support\Facades\Storage::deleteDirectory('\\'); }); diff --git a/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php index 464d4cb5..3bb8790b 100644 --- a/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php +++ b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php @@ -1,53 +1,146 @@ count())->tobe(0); + $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['multisheet']), $inputfiledir); - $testinputfilesdir_temp = \Illuminate\Support\Facades\Storage::path('inputfilestemp'); + $doctocmd = \App\Services\DocToCommandBuilder::docto() + ->add('-XL') + ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' ) + ->add('-o', $testoutputdir_temp .'\\Book1 MultiSheet Test.pdf') + ->add('-t', 'xlPDF') + ->add('--sheets', 'Tab3') + ->add('-L 10') + ->build(); - $testoutputdir_temp = \Illuminate\Support\Facades\Storage::path('outputtemp2'); + $output = \Illuminate\Support\Facades\Process::run($doctocmd); + // print_r($output); + $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir)); + + expect($outputDirFiles->count())->toBeGreaterThan(0); + expect($outputDirFiles->count())->tobe(1); + // Sheet named + $sheetNamed = $outputDirFiles->filter(function ($item) { + // echo $item . "\n"; + if (str($item)->contains('Book1 MultiSheet Test_(Sheet1).pdf') ) return true; + if (str($item)->contains('Book1 MultiSheet Test_(Sheet2).pdf') ) return true; + Return false; + }); - \Illuminate\Support\Facades\Storage::createDirectory('outputtemp2'); - // $cmd = "xcopy \"$testinputfilesdir\" \"$testinputfilesdir_temp\\\" "; - // echo "\n". $cmd; - // $result = \Illuminate\Support\Facades\Process::run( $cmd ); + $sheetNamed3 = $outputDirFiles->filter(function ($item) { + // echo $item . "\n"; + if (str($item)->contains('Book1 MultiSheet Test_(Tab3).pdf') ) return true; - //echo "\n" . $result->output() . "\n"; - // $dirfiles = collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp')); - $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['plain']), 'inputfilestemp'); - $docfiles = $dirfiles->filter(function ($item) { - return str($item->path())->endsWith('.doc'); }); - expect($docfiles->count())->toBeGreaterThan(0); - $docfilecount = count($docfiles->toArray()); + expect($sheetNamed->count())->tobe(0); + expect($sheetNamed3->count())->tobe(1); + + // Storage::deleteDirectory($outputfiledir); + }); + + + it('can pdf each sheet in a multi sheet xls', function () { + + $inputfiledir = 'inputfilesxls'; + $outputfiledir = 'outputfilesxls' . uniqid(); + // setup + $testinputfilesdir_temp = Storage::path($inputfiledir); + $testoutputdir_temp = Storage::path($outputfiledir); + + Storage::createDirectory($outputfiledir); + + $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['multisheet']), $inputfiledir); - $dirfilescount = $dirfiles->count(); - // do conversion - $docto = config('services.docto.path'); - // $doctocmd = "$docto -WD -f $testinputfilesdir_temp -fx .doc -o $testoutputdir_temp -t wdFormatPDF -R true"; $doctocmd = \App\Services\DocToCommandBuilder::docto() - ->add('-WD') - ->add('-f', $testinputfilesdir_temp) - ->add('-fx', '.doc') - ->add('-o', $testoutputdir_temp) - ->add('-t wdFormatPDF') - ->add('-R', 'true') // the important one fo rthis test + ->add('-XL') + ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' ) + ->add('-o', $testoutputdir_temp .'\\Book1 MultiSheet Test.pdf') + ->add('-t', 'xlPDF') + ->add('--sheets', '1,2') + ->add('-L 10') ->build(); - // echo $doctocmd; + $output = \Illuminate\Support\Facades\Process::run($doctocmd); + // print_r($output); + $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir)); + + expect($outputDirFiles->count())->toBeGreaterThan(0); + expect($outputDirFiles->count())->tobe(2); + // Sheet named + $sheetNamed = $outputDirFiles->filter(function ($item) { + // echo $item . "\n"; + if (str($item)->contains('Book1 MultiSheet Test_(Sheet1).pdf') ) return true; + if (str($item)->contains('Book1 MultiSheet Test_(Sheet2).pdf') ) return true; + Return false; + }); - // check files have been converted and originoals have been created. - expect(collect(\Illuminate\Support\Facades\Storage::listContents('inputfilestemp'))->count())->tobe($dirfilescount - $docfilecount); - expect(collect(\Illuminate\Support\Facades\Storage::listContents('outputtemp2'))->count())->tobe($docfilecount); + $sheetNamed3 = $outputDirFiles->filter(function ($item) { + // echo $item . "\n"; + if (str($item)->contains('Book1 MultiSheet Test_(Tab3).pdf') ) return true; + + }); + + expect($sheetNamed->count())->tobe(2); + expect($sheetNamed3->count())->tobe(0); + + Storage::deleteDirectory('outputtempxls2'); + }); + + + + it('outputs correct tab multi sheet xls', function () { + + $inputfiledir = 'inputfilesxls'; + $outputfiledir = 'outputfilesxls' . uniqid(); + // setup + $testinputfilesdir_temp = Storage::path($inputfiledir); + $testoutputdir_temp = Storage::path($outputfiledir); + + Storage::createDirectory($outputfiledir); + + $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['multisheet']), $inputfiledir); + + $doctocmd = \App\Services\DocToCommandBuilder::docto() + ->add('-XL') + ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' ) + ->add('-o', $testoutputdir_temp .'\\TabTest.csv') + ->add('-t', 'xlCSV') + ->add('--sheets', '3') + ->add('-L 10') + ->build(); + + $output = \Illuminate\Support\Facades\Process::run($doctocmd); + // print_r($output); + $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir)); + + expect($outputDirFiles->count())->toBeGreaterThan(0); + expect($outputDirFiles->count())->tobe(1); + // Sheet named + $fileText = file_get_contents(Storage::path($outputDirFiles[0])); + expect(str($fileText)->contains('This is Tab3'))->toBeTrue(); }); diff --git a/src/docto.dproj.local b/src/docto.dproj.local index 16057aef..25748df8 100644 --- a/src/docto.dproj.local +++ b/src/docto.dproj.local @@ -4,12 +4,12 @@ 2020/05/25 15:25:09.000.399,=D:\Development\GitHub\DocTo\src\res\HelpCompatibilityMode.txt 2020/05/25 15:31:23.000.508,D:\Development\GitHub\DocTo\src\res\WdCompatibilityMode.txt= 2021/12/02 22:25:13.000.761,=D:\Development\GitHub\DocTo\src\New1.bat - 2021/12/02 22:25:32.000.527,D:\Development\GitHub\DocTo\src\New1.bat=D:\Development\GitHub\DocTo\test\TestDocTo_Quiet.bat + 2021/12/02 22:25:32.000.527,D:\Development\GitHub\DocTo\test\TestDocTo_Quiet.bat=D:\Development\GitHub\DocTo\src\New1.bat 2023/09/11 17:39:20.000.384,=C:\Development\github\docto\src\res\xlsFormats.txt - 2025/11/18 17:53:47.458,=C:\Development\github\docto\src\Unit1.pas - 2025/11/18 17:54:21.396,C:\Development\github\docto\src\shared\DynamicFileNameGenerator.pas=C:\Development\github\docto\src\Unit1.pas - 2025/11/19 14:43:02.361,=C:\Development\github\docto\src\Unit1.pas - 2025/11/19 14:43:31.175,C:\Development\github\docto\src\Exceptions\DocToExceptions.pas=C:\Development\github\docto\src\Unit1.pas + 2025/11/18 17:53:47.000.458,=C:\Development\github\docto\src\Unit1.pas + 2025/11/18 17:54:21.000.396,C:\Development\github\docto\src\Unit1.pas=C:\Development\github\docto\src\shared\DynamicFileNameGenerator.pas + 2025/11/19 14:43:02.000.361,=C:\Development\github\docto\src\Unit1.pas + 2025/11/19 14:43:31.000.175,C:\Development\github\docto\src\Unit1.pas=C:\Development\github\docto\src\Exceptions\DocToExceptions.pas From d44f4996c4d52a5589d155ec198d00674eddd6df Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 21:11:37 +0000 Subject: [PATCH 43/52] ver --- src/MainUtils.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MainUtils.pas b/src/MainUtils.pas index 6b9f45b2..dfd57039 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -33,7 +33,7 @@ interface MSVISIO = 4; - DOCTO_VERSION = '2.0.44'; // dont use 0x - choco needs incrementing versions. + DOCTO_VERSION = '1.16.45'; // dont use 0x - choco needs incrementing versions. DOCTO_VERSION_NOTE = ' (Test Version XLS Multisheet B) '; type From f5119e8ee2911e9d7724a091ca0bb65c413c32ea Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 21:11:56 +0000 Subject: [PATCH 44/52] try to output csv --- src/ExcelUtils.pas | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index e1373fad..9fcf32d1 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -493,7 +493,7 @@ procedure TExcelXLSConverter.SaveAsXPS(OutputFilename : string) ; procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); var FromPage, ToPage : OleVariant; - activeSheet : OleVariant; + activeSheet, sheetName : OleVariant; sheetNumber : integer; dynamicoutputDir, dynamicoutputFile, dynamicoutputExt, dynamicOutputFileName, dynamicSheetName : String; ExitAction :TExitAction; @@ -539,19 +539,11 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); for ix := 0 to SelectedSheets.Count -1 do begin LogDebug('CSV Loop:' + SelectedSheets[ix]); + sheetName := SelectedSheets[ix]; // Check if number requested and set sheetNumber - if (TryStrToInt(SelectedSheets[ix],sheetNumber) )then - begin - self.CheckWorkSheetIndexValid(sheetNumber); - activeSheet := ExcelApp.ActiveWorkbook.Sheets[sheetNumber]; - end else - // otherwise use string name. - begin - activeSheet := ExcelApp.ActiveWorkbook.Sheets[SelectedSheets[ix]]; - end; - - + // ------------- + activeSheet := ExcelApp.ActiveWorkbook.Sheets[sheetName]; dynamicSheetName := activeSheet.Name; LogDebug(dynamicSheetName); From dc201036f48d494f5f5bc1246c7ba0921dcde790 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 21:38:11 +0000 Subject: [PATCH 45/52] New parameter notes --- .../generator_templates/AllParameters.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/companion/resources/generator_templates/AllParameters.md b/companion/resources/generator_templates/AllParameters.md index 89c34088..9d5bc41c 100644 --- a/companion/resources/generator_templates/AllParameters.md +++ b/companion/resources/generator_templates/AllParameters.md @@ -213,6 +213,27 @@ If you wish for the converted PDF to be opened after creation. No value req. Only convert certain pages in the document. +### Convert all or Specific Individual Sheets +_Excel_ + +By default when doing a conversion with XL, the first sheet is the only sheet that gets +output. Often this is what you want, however if you wish to have a specific sheet output +you can specify that or you can output all sheets and they will be given individual names. + +> --allsheets + +Output all sheets. Seperate files will be created for each sheet and named appropriatly. +eg. If you have a workbook.xls with Sheet1 and MySheet and you convert to pdf. You will get +2 files named workbook_(Sheet1).pdf and workbook_(MySheet).pdf + +> --sheets "1,2" + +You can specify to only convert certain sheets, eg 1 and 2 or "Sheet1,MySheet" + +````cmd +Note: --sheets does not work with -t xlCSV . You must use --allsheets and output all. +```` + ### Document Properties > --no-IncludeDocProperties --no-DocProp [no value required] From bc49cfae61e227322c3cf2026105300fc281cc45 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 21:42:54 +0000 Subject: [PATCH 46/52] New details --- .../app/Services/ResourceFileService.php | 3 ++ pages/all/HelpLog.md | 12 +++-- pages/all/HelpLog.txt.md | 12 +++-- src/ExcelUtils.pas | 46 ++++++++++++++----- src/Exceptions/DocToExceptions.pas | 6 ++- src/MainUtils.pas | 16 ++++++- src/res/HelpLog.txt | 5 +- 7 files changed, 77 insertions(+), 23 deletions(-) diff --git a/companion/app/Services/ResourceFileService.php b/companion/app/Services/ResourceFileService.php index df0e2072..0e236a2c 100644 --- a/companion/app/Services/ResourceFileService.php +++ b/companion/app/Services/ResourceFileService.php @@ -5,6 +5,8 @@ class ResourceFileService { public static function LoadResourceFile($fn) { + + $fullfn = docto_path('\\src\\res\\' . $fn); return file_get_contents($fullfn); @@ -18,6 +20,7 @@ public static function LoadResourceFiles(){ if (strlen($fn) > 2 ){ // ignore . .. //echo $fileinfo['filename'] . ':' . strlen($fileinfo['filename']); if (strpos( $fn , '__history') !== false){continue;} + if (strpos( $fn , '__recovery') !== false){continue;} $info = pathinfo($fn); $AllContent[$info['filename']] = ['filename'=> $fn, 'contents' => static::LoadResourceFile($fn)]; diff --git a/pages/all/HelpLog.md b/pages/all/HelpLog.md index 90790e77..fe0dc62b 100644 --- a/pages/all/HelpLog.md +++ b/pages/all/HelpLog.md @@ -117,10 +117,15 @@ Long Parameters: --PDF-no-BitmapMissingFonts Do not bitmap missing fonts, fonts will be substituted. --use-ISO190051 - Create PDF to the ISO 19005-1 standard. + Create PDF to the ISO 19005-1 standard. + --enable-macroautorun --enable-wordvbaauto - By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word Only. - + --enable-xlvbaauto + By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only. + --sheets + Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. Unavailable for xlCSV + --allsheets + If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names Experimental: @@ -137,6 +142,7 @@ ERROR CODES: 203 : Unknown switch in command 204 : Input File does not exist 205 : Invalid Parameter Value +210 : DocTo Error 220 : Word or COM Error 221 : Word not Installed 301 : Not Implemented diff --git a/pages/all/HelpLog.txt.md b/pages/all/HelpLog.txt.md index 6ecb0414..e4be18a5 100644 --- a/pages/all/HelpLog.txt.md +++ b/pages/all/HelpLog.txt.md @@ -112,10 +112,15 @@ Long Parameters: --PDF-no-BitmapMissingFonts Do not bitmap missing fonts, fonts will be substituted. --use-ISO190051 - Create PDF to the ISO 19005-1 standard. + Create PDF to the ISO 19005-1 standard. + --enable-macroautorun --enable-wordvbaauto - By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word Only. - + --enable-xlvbaauto + By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only. + --sheets + Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. Unavailable for xlCSV + --allsheets + If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names Experimental: @@ -132,6 +137,7 @@ ERROR CODES: 203 : Unknown switch in command 204 : Input File does not exist 205 : Invalid Parameter Value +210 : DocTo Error 220 : Word or COM Error 221 : Word not Installed 301 : Not Implemented diff --git a/src/ExcelUtils.pas b/src/ExcelUtils.pas index 9fcf32d1..c11ba223 100644 --- a/src/ExcelUtils.pas +++ b/src/ExcelUtils.pas @@ -140,7 +140,7 @@ function TExcelXLSConverter.ExecuteConversion(fileToConvert: String; OutputFilen try NonsensePassword := 'tfm554!ghAGWRDD'; - LogDebug('in conversion file'); + try ExcelApp.Workbooks.Open( FileToConvert, //FileName , EmptyParam, //UpdateLinks , @@ -490,6 +490,7 @@ procedure TExcelXLSConverter.SaveAsXPS(OutputFilename : string) ; end; +// Save to 1 or move csv files procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); var FromPage, ToPage : OleVariant; @@ -500,42 +501,63 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); Sheet, ix : integer; FileNameGen : TDynamicFileNameGenerator; begin - LogDebug('output to csv format'); + // LogDebug('output to csv format'); + - //CSV pops up alert. must be hidden for automation ExcelApp.Application.DisplayAlerts := False ; - // if fSelectedSheets.Count > 0 then + if SelectedSheets.Count > 0 then + begin + raise EInvalidParameterCombination.Create('--sheet cannot be used with xlCSV. Use --allsheets instead'); + end; FileNameGen := TDynamicFileNameGenerator.Create(OutputFilename); +// ******************************************************** +// Very Strange Behaviour +// +// When The sheets are output in order going from 1 to Worksheet.Count then each +// sheet is output correctly as a CSV file. However if an attempt is made to +// output a single sheet, either by index or sheet name the first sheet is +// always output. It makes no sense, the code is identical. I have tried many +// times. Therefore I am going to just leave it and always output all. + + + // output all sheets with seperate names - if fSelectedSheets_All then + if (fSelectedSheets_All) or (SelectedSheets.Count > 0) then begin for Sheet := 1 to ExcelApp.ActiveWorkbook.WorkSheets.Count do begin - LogDebug('CSV Loop'); + // LogDebug('CSV Loop'); activeSheet := ExcelApp.ActiveWorkbook.Sheets[Sheet]; dynamicSheetName := activeSheet.Name; - LogDebug(dynamicSheetName); + // LogDebug(dynamicSheetName); dynamicOutputFilename := FileNameGen.Generate(dynamicSheetName); - LogDebug(dynamicOutputFileName); + // LogDebug(dynamicOutputFileName); activeSheet.SaveAs( dynamicoutputFilename, OutputFileFormat); + fOutputFiles.Add(dynamicoutputFilename); end; - - end + end + (* end // If we have been given Sheetnames or ids, just output them. else if SelectedSheets.Count > 0 then begin + + + + // This code doesnt work, it should but it doesnt, it always outputs the + // first sheet. + for ix := 0 to SelectedSheets.Count -1 do begin LogDebug('CSV Loop:' + SelectedSheets[ix]); @@ -555,10 +577,12 @@ procedure TExcelXLSConverter.SaveAsCSV(OutputFilename: string); activeSheet.SaveAs( dynamicoutputFilename, OutputFileFormat); end; - end else + end else *) // Do default which is usually first sheet, with name provided. + else begin ExcelApp.activeWorkbook.SaveAs( OutputFilename, OutputFileFormat); + fOutputFiles.Add(OutputFilename); end; diff --git a/src/Exceptions/DocToExceptions.pas b/src/Exceptions/DocToExceptions.pas index 16785638..b0918055 100644 --- a/src/Exceptions/DocToExceptions.pas +++ b/src/Exceptions/DocToExceptions.pas @@ -1,11 +1,13 @@ unit DocToExceptions; interface -uses Classes, MainUtils, ResourceUtils, ActiveX, ComObj, WinINet, Variants, sysutils, Types, StrUtils,Word_TLB_Constants, TypInfo; +uses Classes, ActiveX, ComObj, WinINet, Variants, sysutils, Types, StrUtils, TypInfo; type - ESheetIndexOutOfBounds = class(Exception); + EDocToException = class(Exception); + ESheetIndexOutOfBounds = class(EDocToException); + EInvalidParameterCombination = class(EDocToException); implementation diff --git a/src/MainUtils.pas b/src/MainUtils.pas index dfd57039..f793e981 100644 --- a/src/MainUtils.pas +++ b/src/MainUtils.pas @@ -14,7 +14,7 @@ ****************************************************************) interface uses classes, Windows, sysutils, ActiveX, ComObj, WinINet, Variants, iduri, - Types, ResourceUtils, StrUtils, + Types, ResourceUtils, StrUtils, DocToExceptions, PathUtils, ShellAPI, datamodssl, Word_TLB_Constants; Const @@ -778,6 +778,20 @@ function TDocumentConverter.Execute: string; end; end; + on E: EDocToException do + begin + ErrorMessage := StringReplace(E.Message,#13,'--',[rfReplaceAll]); + if (HaltOnWordError) then + begin + LogError( FileToConvert ); + HaltWithError(210,E.ClassName + ' ' + ErrorMessage ); + end + else + begin + LogError(E.ClassName + ' ' + ErrorMessage + ' ' + FileToConvert + ':' + FileToCreate); + + end; + end; on E: Exception do begin ErrorMessage := StringReplace(E.Message,#13,'--',[rfReplaceAll]); diff --git a/src/res/HelpLog.txt b/src/res/HelpLog.txt index 215e5d49..e4be18a5 100644 --- a/src/res/HelpLog.txt +++ b/src/res/HelpLog.txt @@ -113,14 +113,12 @@ Long Parameters: Do not bitmap missing fonts, fonts will be substituted. --use-ISO190051 Create PDF to the ISO 19005-1 standard. - --enable-macroautorun --enable-wordvbaauto --enable-xlvbaauto By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only. - --sheets - Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. + Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. Unavailable for xlCSV --allsheets If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names @@ -139,6 +137,7 @@ ERROR CODES: 203 : Unknown switch in command 204 : Input File does not exist 205 : Invalid Parameter Value +210 : DocTo Error 220 : Word or COM Error 221 : Word not Installed 301 : Not Implemented From b5a2674529edafa5480400a766b8a103a47b5ea8 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Wed, 19 Nov 2025 21:43:17 +0000 Subject: [PATCH 47/52] multi --- .../multisheet/Book1 MultiSheet Test.xlsx | Bin 0 -> 12216 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 companion/resources/inputfiles/multisheet/Book1 MultiSheet Test.xlsx diff --git a/companion/resources/inputfiles/multisheet/Book1 MultiSheet Test.xlsx b/companion/resources/inputfiles/multisheet/Book1 MultiSheet Test.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..8081666b6543ab2b6bafd27dc2614edf890d21de GIT binary patch literal 12216 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 Date: Thu, 20 Nov 2025 08:33:13 +0000 Subject: [PATCH 48/52] spelling --- companion/app/Services/CommandInfoService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/companion/app/Services/CommandInfoService.php b/companion/app/Services/CommandInfoService.php index 09ed17d4..299df24f 100644 --- a/companion/app/Services/CommandInfoService.php +++ b/companion/app/Services/CommandInfoService.php @@ -727,7 +727,7 @@ public static function Explanations() "dddeletefiles" => ['cmd' => '--deletefiles', 'desc' => "Delete the converted file after conversion."], "ddbookmarksource" => ['cmd' => '--bookmarksource', 'desc' => "Where to get Bookmarks from for PDF. This parameter is only relevant for PDF files."], "ddexportmarkup" => ['cmd' => '--ExportMarkup', 'desc' => "Export Comments and other markup from Word Document to PDF"], - "ddnosubdirs" => ['cmd' => '--no-subdirs', 'desc' => "Don't rescurse subdirs. Only convert files in requested dir. "], + "ddnosubdirs" => ['cmd' => '--no-subdirs', 'desc' => "Don't recurse sub-dirs. Only convert files in requested dir. "], "dduseISO190051" => ['cmd' => '--use-iso19005-1', 'desc' => 'Output PDFs from Word as ISO standard 19005-1 for self contained PDFS. Sometimes also refered to as (PDF/A)[https://en.wikipedia.org/wiki/PDF/A]'], "ddinputfilter" => ['cmd' => '--inputfilter', 'desc' => 'Input filter to use to find documents. eg Project*.doc* will match ProjectA.doc, Project123.doc, ProjectABC.docx '], From 60517f4bcd90f229da96626c803e685b88fb5559 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Thu, 20 Nov 2025 08:37:01 +0000 Subject: [PATCH 49/52] param --- companion/app/Services/CommandInfoService.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/companion/app/Services/CommandInfoService.php b/companion/app/Services/CommandInfoService.php index 299df24f..7a0d65d7 100644 --- a/companion/app/Services/CommandInfoService.php +++ b/companion/app/Services/CommandInfoService.php @@ -730,6 +730,9 @@ public static function Explanations() "ddnosubdirs" => ['cmd' => '--no-subdirs', 'desc' => "Don't recurse sub-dirs. Only convert files in requested dir. "], "dduseISO190051" => ['cmd' => '--use-iso19005-1', 'desc' => 'Output PDFs from Word as ISO standard 19005-1 for self contained PDFS. Sometimes also refered to as (PDF/A)[https://en.wikipedia.org/wiki/PDF/A]'], "ddinputfilter" => ['cmd' => '--inputfilter', 'desc' => 'Input filter to use to find documents. eg Project*.doc* will match ProjectA.doc, Project123.doc, ProjectABC.docx '], + "ddsheets" => ['cmd' => '--sheets', 'desc' => 'Output specific sheet from a workbook. Sheet will be output with a specific named file. MyWorksheet_(SheetName) This does not work with xlCSV'], + "ddallsheets" => ['cmd' => '--allsheets', 'desc' => 'Output all sheets in a workbook. Each sheet will be output to a separate named file. MyWorksheet_(SheetName)'], + ]; From 508238f2c59c3c936501411683e14d563635ce2f Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Sat, 22 Nov 2025 08:41:01 +0000 Subject: [PATCH 50/52] test --- .../XLS/MultiSheet/MultiSheetPestTest.php | 73 +++++++++++++++++-- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php index 3bb8790b..ff7e4d55 100644 --- a/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php +++ b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php @@ -110,8 +110,7 @@ }); - - it('outputs correct tab multi sheet xls', function () { + it('can pdf output all sheets multi sheet xls', function () { $inputfiledir = 'inputfilesxls'; $outputfiledir = 'outputfilesxls' . uniqid(); @@ -126,9 +125,9 @@ $doctocmd = \App\Services\DocToCommandBuilder::docto() ->add('-XL') ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' ) - ->add('-o', $testoutputdir_temp .'\\TabTest.csv') - ->add('-t', 'xlCSV') - ->add('--sheets', '3') + ->add('-o', $testoutputdir_temp .'\\Book1 MultiSheet Test.pdf') + ->add('-t', 'xlPDF') + ->add('--allsheets') ->add('-L 10') ->build(); @@ -137,10 +136,68 @@ $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir)); expect($outputDirFiles->count())->toBeGreaterThan(0); - expect($outputDirFiles->count())->tobe(1); + expect($outputDirFiles->count())->tobe(3); // Sheet named - $fileText = file_get_contents(Storage::path($outputDirFiles[0])); - expect(str($fileText)->contains('This is Tab3'))->toBeTrue(); + $sheetNamed = $outputDirFiles->filter(function ($item) { + // echo $item . "\n"; + if (str($item)->contains('Book1 MultiSheet Test_(Sheet1).pdf') ) return true; + if (str($item)->contains('Book1 MultiSheet Test_(Sheet2).pdf') ) return true; + if (str($item)->contains('Book1 MultiSheet Test_(Tab3).pdf') ) return true; + // this is not expected to match. Emtpy sheets dont output + if (str($item)->contains('Book1 MultiSheet Test_(Sheet4).pdf') ) return true; + Return false; + }); + + expect($sheetNamed->count())->tobe(3); + Storage::deleteDirectory($outputfiledir); }); + + it('outputs correct all sheets multi sheet xls', function ($format, $ext) { + + $inputfiledir = 'inputfilesxls'; + $outputfiledir = 'outputfilesxls' . uniqid(); + // setup + $testinputfilesdir_temp = Storage::path($inputfiledir); + $testoutputdir_temp = Storage::path($outputfiledir); + + Storage::createDirectory($outputfiledir); + + $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['multisheet']), $inputfiledir); + + $doctocmd = \App\Services\DocToCommandBuilder::docto() + ->add('-XL') + ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' ) + ->add('-o', $testoutputdir_temp .'\\TabTest.' . $ext) + ->add('-t', $format) + ->add('--allsheets') + ->add('-L 10') + ->build(); + + $output = \Illuminate\Support\Facades\Process::run($doctocmd); + // print_r($output->output()); + $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir)); + + expect($outputDirFiles->count())->toBeGreaterThan(0); + expect($outputDirFiles->count())->tobe(4); + + + // Sheet named + $fileText = file_get_contents(Storage::path($outputfiledir . '\\TabTest_(Tab3).' . $ext)); + expect(str($fileText)->contains('This is Tab3'))->toBeTrue(); + expect(str($fileText)->contains('This is Sheet 1'))->not()->toBeTrue(); + + // Sheet named + $fileText = file_get_contents(Storage::path($outputfiledir . '\\TabTest_(Sheet1).' . $ext)); + expect(str($fileText)->contains('This is Sheet 1'))->toBeTrue(); + expect(str($fileText)->contains('This is Tab3'))->not()->toBeTrue(); + + + + })->with([ + ['xlCSV', 'csv'], + ['xlUnicodeText', 'txt'], + ['xlCSVWindows', 'csv'], + ['xlTextWindows', 'txt'], + ]); From 12d97d25de866c61bca9e7c474bcb6c66a4711c2 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Sat, 22 Nov 2025 08:41:48 +0000 Subject: [PATCH 51/52] reset --- .../XLS/MultiSheet/MultiSheetPestTest.php | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php index ff7e4d55..72cb70d5 100644 --- a/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php +++ b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php @@ -149,12 +149,12 @@ }); expect($sheetNamed->count())->tobe(3); - + Storage::deleteDirectory($outputfiledir); }); - it('outputs correct all sheets multi sheet xls', function ($format, $ext) { + it('outputs correct all sheets multi sheet xls', function () { $inputfiledir = 'inputfilesxls'; $outputfiledir = 'outputfilesxls' . uniqid(); @@ -169,8 +169,8 @@ $doctocmd = \App\Services\DocToCommandBuilder::docto() ->add('-XL') ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' ) - ->add('-o', $testoutputdir_temp .'\\TabTest.' . $ext) - ->add('-t', $format) + ->add('-o', $testoutputdir_temp .'\\TabTest.csv') + ->add('-t', 'xlCSV') ->add('--allsheets') ->add('-L 10') ->build(); @@ -184,20 +184,15 @@ // Sheet named - $fileText = file_get_contents(Storage::path($outputfiledir . '\\TabTest_(Tab3).' . $ext)); + $fileText = file_get_contents(Storage::path($outputfiledir . '\\TabTest_(Tab3).csv')); expect(str($fileText)->contains('This is Tab3'))->toBeTrue(); expect(str($fileText)->contains('This is Sheet 1'))->not()->toBeTrue(); // Sheet named - $fileText = file_get_contents(Storage::path($outputfiledir . '\\TabTest_(Sheet1).' . $ext)); + $fileText = file_get_contents(Storage::path($outputfiledir . '\\TabTest_(Sheet1).csv')); expect(str($fileText)->contains('This is Sheet 1'))->toBeTrue(); expect(str($fileText)->contains('This is Tab3'))->not()->toBeTrue(); - })->with([ - ['xlCSV', 'csv'], - ['xlUnicodeText', 'txt'], - ['xlCSVWindows', 'csv'], - ['xlTextWindows', 'txt'], - ]); + }); From 4d264ce4eb4df7cb5249334b22a5ae59a6118a21 Mon Sep 17 00:00:00 2001 From: Toby Allen Date: Sat, 22 Nov 2025 09:15:11 +0000 Subject: [PATCH 52/52] Extra tests --- companion/app/Services/FileGatherService.php | 6 +- .../resources/inputfiles/docx/DocXFile.docx | Bin 0 -> 15854 bytes .../inputfiles/single/ASingleFile.doc | Bin 0 -> 30208 bytes .../Feature/DocX/CompatibilityPestTest.php | 141 ++++++++++++++++++ companion/tests/Feature/VersionPestTest.php | 29 ++++ .../XLS/MultiSheet/MultiSheetPestTest.php | 41 ++++- src/docto.dproj.local | 6 +- src/res/HelpLog.txt | 4 +- 8 files changed, 220 insertions(+), 7 deletions(-) create mode 100644 companion/resources/inputfiles/docx/DocXFile.docx create mode 100644 companion/tests/Feature/DocX/CompatibilityPestTest.php create mode 100644 companion/tests/Feature/VersionPestTest.php diff --git a/companion/app/Services/FileGatherService.php b/companion/app/Services/FileGatherService.php index 2acff1a5..dbc3f804 100644 --- a/companion/app/Services/FileGatherService.php +++ b/companion/app/Services/FileGatherService.php @@ -15,8 +15,12 @@ class FileGatherService * @return Collection * @throws \League\Flysystem\FilesystemException */ - public static function GatherFiles(Collection $list, $tempDirName) + public static function GatherFiles(Collection | string $list, $tempDirName) { + if (is_string($list)){ + $list = collect([$list]); + } + // remove exisitn files if (\Illuminate\Support\Facades\Storage::exists($tempDirName)){ \Illuminate\Support\Facades\Storage::deleteDirectory($tempDirName); diff --git a/companion/resources/inputfiles/docx/DocXFile.docx b/companion/resources/inputfiles/docx/DocXFile.docx new file mode 100644 index 0000000000000000000000000000000000000000..c2e376ef9e3e48af96c4172eded909f2f563d8e3 GIT binary patch literal 15854 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 literal 0 HcmV?d00001 diff --git a/companion/resources/inputfiles/single/ASingleFile.doc b/companion/resources/inputfiles/single/ASingleFile.doc index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e9d0f8dd03139edf0270606de471efa77e07afcd 100644 GIT binary patch literal 30208 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 literal 0 HcmV?d00001 diff --git a/companion/tests/Feature/DocX/CompatibilityPestTest.php b/companion/tests/Feature/DocX/CompatibilityPestTest.php new file mode 100644 index 00000000..387eeb6c --- /dev/null +++ b/companion/tests/Feature/DocX/CompatibilityPestTest.php @@ -0,0 +1,141 @@ +add('-WD') + ->add('-f', $testinputfilesdir_temp ) + ->add('-o', $testoutputdir_temp ) + ->add('-t', 'wdformatPDF') + ->build(); + + $output = \Illuminate\Support\Facades\Process::run($doctocmd); + // print_r($output->output()); + $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir)); + + expect($outputDirFiles->count())->toBeGreaterThan(0); + expect($outputDirFiles->count())->tobe(1); + }); + + + + it ('can convert doc to docx with compatibility',function (){ + + $inputfiledir = 'inputfiles_docx'. uniqid(); + $outputfiledir = 'outputfiles_docx' . uniqid(); + // setup + $testinputfilesdir_temp = Storage::path($inputfiledir); + $testoutputdir_temp = Storage::path($outputfiledir); + + Storage::createDirectory($outputfiledir); + + $dirfiles = \App\Services\FileGatherService::GatherFiles('plain', $inputfiledir); + + $doctocmd = \App\Services\DocToCommandBuilder::docto() + ->add('-WD') + ->add('-f', $testinputfilesdir_temp ) + ->add('-o', $testoutputdir_temp ) + ->add('-ox', '.docx') + ->add('-t', 'wdFormatDocumentDefault') + ->add('--COMPATIBILITY', '65535') + ->add('-L',10) + ->build(); + + $output = \Illuminate\Support\Facades\Process::run($doctocmd); + // print_r($output->output()); + $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir)); + + expect($outputDirFiles->count())->toBeGreaterThan(0); + expect($outputDirFiles->count())->tobe(5); + + // ensure -ox parameter is used. + $file1 = $outputDirFiles->first(); + expect(str($file1)->endsWith('.docx'))->toBeTrue(); + + + }); + + it ('can convert doc to docx with -c compatibility',function (){ + + $inputfiledir = 'inputfiles_docx'. uniqid(); + $outputfiledir = 'outputfiles_docx' . uniqid(); + // setup + $testinputfilesdir_temp = Storage::path($inputfiledir); + $testoutputdir_temp = Storage::path($outputfiledir); + + Storage::createDirectory($outputfiledir); + + $dirfiles = \App\Services\FileGatherService::GatherFiles('plain', $inputfiledir); + + $doctocmd = \App\Services\DocToCommandBuilder::docto() + ->add('-WD') + ->add('-f', $testinputfilesdir_temp ) + ->add('-o', $testoutputdir_temp ) + ->add('-ox', '.docx') + ->add('-t', 'wdFormatDocumentDefault') + ->add('-c', '65535') + ->add('-L',10) + ->build(); + + $output = \Illuminate\Support\Facades\Process::run($doctocmd); + // print_r($output->output()); + $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir)); + + expect($outputDirFiles->count())->toBeGreaterThan(0); + expect($outputDirFiles->count())->tobe(5); + + // ensure -ox parameter is used. + $file1 = $outputDirFiles->first(); + expect(str($file1)->endsWith('.docx'))->toBeTrue(); + + + }); + + + it ('can convert doc to alternative compatibility',function ($marker,$compatibility) { + + $inputfiledir = 'inputfiles_docx'. uniqid(); + $outputfiledir = 'outputfiles_docx' . uniqid(); + // setup + $testinputfilesdir_temp = Storage::path($inputfiledir); + $testoutputdir_temp = Storage::path($outputfiledir); + + Storage::createDirectory($outputfiledir); + + $dirfiles = \App\Services\FileGatherService::GatherFiles('plain', $inputfiledir); + + $doctocmd = \App\Services\DocToCommandBuilder::docto() + ->add('-WD') + ->add('-f', $testinputfilesdir_temp ) + ->add('-o', $testoutputdir_temp ) + ->add('-t', 'wdFormatDocumentDefault') + ->add('--COMPATIBILITY', $compatibility) + ->add('-L',10) + ->build(); + + $output = \Illuminate\Support\Facades\Process::run($doctocmd); + // print_r($output->output()); + $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir)); + + expect($outputDirFiles->count())->toBeGreaterThan(0); + expect($outputDirFiles->count())->tobe(5); + + + })->with( + [ + ['wdCurrent', 65535], + ['wdWord2003', 11], + ['wdWord2007', 12], + ['wdWord2010', 14], + ['wdWord2013', 15], + ]); diff --git a/companion/tests/Feature/VersionPestTest.php b/companion/tests/Feature/VersionPestTest.php new file mode 100644 index 00000000..ec4a3414 --- /dev/null +++ b/companion/tests/Feature/VersionPestTest.php @@ -0,0 +1,29 @@ +add('-h') + ->build(); + + $result = \Illuminate\Support\Facades\Process::run($doctocmd); + // print_r($output->output()); + $outputString = $result->output(); + + expect($outputString)->toContain('DocTo Version: 1.16.45'); + + + }); + diff --git a/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php index 72cb70d5..1e6f7527 100644 --- a/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php +++ b/companion/tests/Feature/XLS/MultiSheet/MultiSheetPestTest.php @@ -149,7 +149,7 @@ }); expect($sheetNamed->count())->tobe(3); - + Storage::deleteDirectory($outputfiledir); }); @@ -196,3 +196,42 @@ }); + + + + // these formats only output single sheet. + it('outputs correct single sheet multi sheet xls', function ($format, $ext) { + + $inputfiledir = 'inputfilesxls'; + $outputfiledir = 'outputfilesxls' . uniqid(); + // setup + $testinputfilesdir_temp = Storage::path($inputfiledir); + $testoutputdir_temp = Storage::path($outputfiledir); + + Storage::createDirectory($outputfiledir); + + $dirfiles = \App\Services\FileGatherService::GatherFiles(collect(['multisheet']), $inputfiledir); + + $doctocmd = \App\Services\DocToCommandBuilder::docto() + ->add('-XL') + ->add('-f', $testinputfilesdir_temp .'\\Book1 MultiSheet Test.xlsx' ) + ->add('-o', $testoutputdir_temp .'\\TabTest.' . $ext) + ->add('-t', $format) + ->add('--allsheets') + ->add('-L 10') + ->build(); + + $output = \Illuminate\Support\Facades\Process::run($doctocmd); + // print_r($output->output()); + $outputDirFiles = collect(\Illuminate\Support\Facades\Storage::allFiles($outputfiledir)); + + expect($outputDirFiles->count())->toBeGreaterThan(0); + expect($outputDirFiles->count())->tobe(1); + + + + })->with([ + ['xlUnicodeText', 'txt'], + ['xlCSVWindows', 'csv'], + ['xlTextWindows', 'txt'], + ]); diff --git a/src/docto.dproj.local b/src/docto.dproj.local index 25748df8..ea67e01a 100644 --- a/src/docto.dproj.local +++ b/src/docto.dproj.local @@ -4,12 +4,12 @@ 2020/05/25 15:25:09.000.399,=D:\Development\GitHub\DocTo\src\res\HelpCompatibilityMode.txt 2020/05/25 15:31:23.000.508,D:\Development\GitHub\DocTo\src\res\WdCompatibilityMode.txt= 2021/12/02 22:25:13.000.761,=D:\Development\GitHub\DocTo\src\New1.bat - 2021/12/02 22:25:32.000.527,D:\Development\GitHub\DocTo\test\TestDocTo_Quiet.bat=D:\Development\GitHub\DocTo\src\New1.bat + 2021/12/02 22:25:32.000.527,D:\Development\GitHub\DocTo\src\New1.bat=D:\Development\GitHub\DocTo\test\TestDocTo_Quiet.bat 2023/09/11 17:39:20.000.384,=C:\Development\github\docto\src\res\xlsFormats.txt 2025/11/18 17:53:47.000.458,=C:\Development\github\docto\src\Unit1.pas - 2025/11/18 17:54:21.000.396,C:\Development\github\docto\src\Unit1.pas=C:\Development\github\docto\src\shared\DynamicFileNameGenerator.pas + 2025/11/18 17:54:21.000.396,C:\Development\github\docto\src\shared\DynamicFileNameGenerator.pas=C:\Development\github\docto\src\Unit1.pas 2025/11/19 14:43:02.000.361,=C:\Development\github\docto\src\Unit1.pas - 2025/11/19 14:43:31.000.175,C:\Development\github\docto\src\Unit1.pas=C:\Development\github\docto\src\Exceptions\DocToExceptions.pas + 2025/11/19 14:43:31.000.175,C:\Development\github\docto\src\Exceptions\DocToExceptions.pas=C:\Development\github\docto\src\Unit1.pas diff --git a/src/res/HelpLog.txt b/src/res/HelpLog.txt index e4be18a5..eecaa263 100644 --- a/src/res/HelpLog.txt +++ b/src/res/HelpLog.txt @@ -118,9 +118,9 @@ Long Parameters: --enable-xlvbaauto By Default any autorun vba will not run, use this parameter if you wish vba to Autorun. Word / Excel Only. --sheets - Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. Unavailable for xlCSV + Select which sheets to save. Can be comma seperated list of sheet names or indexes. Excel Only. PDF Only --allsheets - If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names + If converting to CSV default behaviour is to convert first sheet. This will convert all with appropriate names. PDF, CSV only Experimental: