From ca82946aebf97fa6d22be5bd91f1a0b43ac09535 Mon Sep 17 00:00:00 2001
From: claudiamurialdo <33756655+claudiamurialdo@users.noreply.github.com>
Date: Tue, 17 Oct 2023 16:47:45 -0300
Subject: [PATCH] Provide support for ExcelLite implementation for .xls
documents (#882)
* Provide support for ExcelLite implementation for .xls documents (Excel Office 97 to 2003).
* Remove unneeded package reference to GemBox.Spreadsheet.
(cherry picked from commit f531a26096d729cdea357b5bd4a41332da0f0715)
---
.../src/dotnetframework/GxExcel/GxExcelI.cs | 19 ++++---
.../dotnetframework/GxExcel/GxExcelLite.cs | 49 ++++++++++++++++--
.../DotNetCoreUnitTest.csproj | 5 ++
.../DotNetCoreUnitTest/Excel/ExcelLiteTest.cs | 36 +++++++++++++
dotnet/test/DotNetCoreUnitTest/SampleXLS.xls | Bin 0 -> 30208 bytes
5 files changed, 97 insertions(+), 12 deletions(-)
create mode 100644 dotnet/test/DotNetCoreUnitTest/Excel/ExcelLiteTest.cs
create mode 100644 dotnet/test/DotNetCoreUnitTest/SampleXLS.xls
diff --git a/dotnet/src/dotnetframework/GxExcel/GxExcelI.cs b/dotnet/src/dotnetframework/GxExcel/GxExcelI.cs
index e5401195e..149d69078 100644
--- a/dotnet/src/dotnetframework/GxExcel/GxExcelI.cs
+++ b/dotnet/src/dotnetframework/GxExcel/GxExcelI.cs
@@ -52,7 +52,6 @@ public bool checkExcelDocument()
{
if (Document == null)
{
-#if !NETCORE
if (this.fileName.EndsWith(Constants.EXCEL2003Extension) || this.template.EndsWith(Constants.EXCEL2003ExtensionTemplate))
{
if (document == null || document.ErrCode == 99)
@@ -63,6 +62,7 @@ public bool checkExcelDocument()
document.ReadOnly = ReadOnly;
document.Init(initErrDesc);
}
+#if !NETCORE
if (document == null || document.ErrCode != 0) //Automation
{
GXLogging.Debug(log,"Interop.GXOFFICE2Lib.ExcelDocumentClass");
@@ -70,11 +70,11 @@ public bool checkExcelDocument()
document.ReadOnly = ReadOnly;
document.Init("");
}
- }
- else
#endif
- {
- document = new GeneXus.Office.ExcelGXEPPlus.ExcelDocument();
+ }
+ else
+ {
+ document = new GeneXus.Office.ExcelGXEPPlus.ExcelDocument();
document.ReadOnly = ReadOnly;
}
@@ -437,9 +437,14 @@ public static object GetEnumValue(Assembly ass, string enumSuperClass, string en
return fi.GetValue(null);
}
+ internal static object GetEnumValue(Assembly ass, string enumNameClass, string enumField)
+ {
+ Type prn1 = ass.GetType(enumNameClass);
+ return prn1.GetProperty(enumField).GetValue(null);
+ }
- }
- public interface IGxError
+ }
+ public interface IGxError
{
void setErrCod(short errCod);
void setErrDes(String errDes);
diff --git a/dotnet/src/dotnetframework/GxExcel/GxExcelLite.cs b/dotnet/src/dotnetframework/GxExcel/GxExcelLite.cs
index a17605cae..59f035170 100644
--- a/dotnet/src/dotnetframework/GxExcel/GxExcelLite.cs
+++ b/dotnet/src/dotnetframework/GxExcel/GxExcelLite.cs
@@ -6,6 +6,8 @@
using log4net;
using GeneXus.Application;
using GeneXus.Office.Excel;
+using GxClasses.Helpers;
+
namespace GeneXus.Office.ExcelLite
{
@@ -368,7 +370,16 @@ public class ExcelDocument : IGxError, IExcelDocument
{
static readonly ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static string nmspace;
+#if NETCORE
+ public static string license = "FREE-LIMITED-KEY";
+ const string LoadMethod = "Load";
+ const string SaveMethod = "Save";
+#else
public static string license;
+ const string LoadMethod = "LoadXls";
+ const string SaveMethod = "SaveXls";
+#endif
+
public static Assembly ass;
public short Init(string previousMsgError)
@@ -381,17 +392,25 @@ public short Init(string previousMsgError)
{
if (nmspace==null)
{
+#if NETCORE
+ ass = AssemblyLoader.LoadAssembly(new AssemblyName("GemBox.Spreadsheet"));
+#else
+
ass = loadAssembly(Path.Combine(GxContext.StaticPhysicalPath(), "GemBox.Spreadsheet.dll"));
if (ass==null)
{
ass = loadAssembly(Path.Combine(GxContext.StaticPhysicalPath(), "bin", "GemBox.Spreadsheet.dll"));
}
+#endif
if (ass!=null)
{
nmspace="GemBox.Spreadsheet";
}
else
{
+#if NETCORE
+ ass = AssemblyLoader.LoadAssembly(new AssemblyName("GemBox.ExcelLite"));
+#else
if (ass==null)
{
ass = loadAssembly(Path.Combine(GxContext.StaticPhysicalPath(), @"GemBox.ExcelLite.dll"));
@@ -400,6 +419,7 @@ public short Init(string previousMsgError)
{
ass = loadAssembly(Path.Combine(GxContext.StaticPhysicalPath(), "bin", "GemBox.ExcelLite.dll"));
}
+#endif
if (ass!=null)
{
nmspace="GemBox.ExcelLite";
@@ -409,11 +429,15 @@ public short Init(string previousMsgError)
}
else
{
+#if NETCORE
+ ass = AssemblyLoader.LoadAssembly(new AssemblyName(nmspace));
+#else
ass = loadAssembly(Path.Combine(GxContext.StaticPhysicalPath(), nmspace + ".dll"));
if (ass==null)
{
ass = loadAssembly(Path.Combine(GxContext.StaticPhysicalPath(), "bin", nmspace + ".dll"));
}
+#endif
}
GXLogging.Debug(log, "nmspace:" + nmspace);
@@ -434,6 +458,7 @@ public short Init(string previousMsgError)
GXLogging.Error(log, @"Error setting license.", e);
}
}
+
}
return 0;
}
@@ -458,7 +483,6 @@ private Assembly loadAssembly(string fileName)
{
return null;
}
-
}
public short Open(String fileName)
{
@@ -479,7 +503,11 @@ public short Open(String fileName)
if (stream != null)
{
stream.Position = 0;
- GxExcelUtils.Invoke(ef, "LoadXls", new object[] { stream });
+#if NETCORE
+ GxExcelUtils.InvokeStatic(ass, classType.FullName, LoadMethod, new object[] { stream });
+#else
+ GxExcelUtils.Invoke(ef, LoadMethod, new object[] { stream });
+#endif
}
}
else
@@ -495,7 +523,12 @@ public short Open(String fileName)
if (stream != null)
{
stream.Position = 0;
- GxExcelUtils.Invoke(ef, "LoadXls", new object[] { stream });
+
+#if NETCORE
+ ef = GxExcelUtils.InvokeStatic(ass, classType.FullName, LoadMethod, new object[] { stream });
+#else
+ GxExcelUtils.Invoke(ef, LoadMethod, new object[] { stream });
+#endif
}
}
else
@@ -523,8 +556,14 @@ public short Save()
{
GxFile file = new GxFile(Path.GetDirectoryName(xlsFileName), xlsFileName, GxFileType.Private);
MemoryStream content = new MemoryStream();
- GxExcelUtils.Invoke(ef, "SaveXls", new object[]{content});
- content.Position = 0;
+
+#if NETCORE
+ object saveOption = GxExcelUtils.GetEnumValue(ExcelDocument.ass, ExcelDocument.nmspace + ".SaveOptions", "XlsDefault");
+ GxExcelUtils.Invoke(ef, SaveMethod, new object[] { content, saveOption });
+#else
+ GxExcelUtils.Invoke(ef, SaveMethod, new object[]{content});
+#endif
+ content.Position = 0;
file.Create(content);
}
catch (Exception e)
diff --git a/dotnet/test/DotNetCoreUnitTest/DotNetCoreUnitTest.csproj b/dotnet/test/DotNetCoreUnitTest/DotNetCoreUnitTest.csproj
index fd4e5ca50..56882bd28 100644
--- a/dotnet/test/DotNetCoreUnitTest/DotNetCoreUnitTest.csproj
+++ b/dotnet/test/DotNetCoreUnitTest/DotNetCoreUnitTest.csproj
@@ -67,12 +67,14 @@
all
+
+
@@ -150,6 +152,9 @@
Always
+
+ PreserveNewest
+
diff --git a/dotnet/test/DotNetCoreUnitTest/Excel/ExcelLiteTest.cs b/dotnet/test/DotNetCoreUnitTest/Excel/ExcelLiteTest.cs
new file mode 100644
index 000000000..91b818cf7
--- /dev/null
+++ b/dotnet/test/DotNetCoreUnitTest/Excel/ExcelLiteTest.cs
@@ -0,0 +1,36 @@
+using System.IO;
+using GeneXus.Office;
+using GeneXus.Utils;
+using UnitTesting;
+using Xunit;
+
+namespace DotNetCoreUnitTest.Excel
+{
+ public class ExcelLiteTest : FileSystemTest
+ {
+ [Fact]
+ public void ExcelLiteReadTest()
+ {
+ ExcelDocumentI excelDocument= new ExcelDocumentI();
+ string fileName = Path.Combine(BaseDir, "SampleXLS.xls");
+ excelDocument.Open(fileName);
+ Assert.Equal(0, excelDocument.ErrCode);
+ double number = excelDocument.get_Cells(2, 1).Number;
+ Assert.Equal(1, number);
+ string text = excelDocument.get_Cells(2, 2).Text;
+ Assert.Equal("A", text);
+
+ number = excelDocument.get_Cells(3, 1).Number;
+ Assert.Equal(2, number);
+ text = excelDocument.get_Cells(3, 2).Text;
+ Assert.Equal("A", text);
+
+ number = excelDocument.get_Cells(101, 1).Number;
+ Assert.Equal(100, number);
+ text = excelDocument.get_Cells(101, 2).Text;
+ Assert.Equal("A", text);
+
+ excelDocument.Close();
+ }
+ }
+}
diff --git a/dotnet/test/DotNetCoreUnitTest/SampleXLS.xls b/dotnet/test/DotNetCoreUnitTest/SampleXLS.xls
new file mode 100644
index 0000000000000000000000000000000000000000..ef1708f44924fcf0713f64e994ac4aa8beacbc8f
GIT binary patch
literal 30208
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
literal 0
HcmV?d00001