I am trying to read a digital signature in the excel file
I need to read Signature Text(The person's name) and Signature Title(His designation/Title under signature line) .I can do it via Interop.Excel and openOffice.xml , but i still need to do the same thing via EPPlus. Is it possible to do the same thing via EPPlus. Please find the code for Interop.Excel
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(strFile)
SignatureSet allSignatures = excelWorkbook.Signatures;
foreach (Signature digitalSign in allSignatures)
{
signedTitle = digitalSign.Setup.SuggestedSignerLine2;
signedName = digitalSign.Details.SignatureText;
}
Is this what you need:
using (var xls = new ExcelPackage(fileInfo))
{
var name = xls.Workbook.Properties.Author;
var title = xls.Workbook.Properties.Title;
}
I don't see any other signatures (other than Zip file-related) in EPPlus:
https://github.com/JanKallman/EPPlus/search?q=signature&unscoped_q=signature
Related
After exporting data into an Excel workbook with macros (xlsm), I run the macro and then remove the macro in order to be able to save the workbook as xlsx. For removing macros, I open the xlsm as zip archive (via C# ZipFile class), remove the entry "xl/vbaProject.bin" and remove a relation within "xl/_rels/workbook.xml.rels". Then I rename the file from xlsm to xlsx. That works fine so far but when I open the xlsx file in Excel, I get "Excel cannot open the file because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file", so there seems something to be missing in order to completely remove the vba code within the workbook. Can anyone help me here?
const string vbaProjectEntryName = "xl/vbaProject.bin"; // Contains the VBA code
const string relationsEntryName = "xl/_rels/workbook.xml.rels"; // Relation/Link to the vba project
using (var zip = ZipFile.Open(fileName, ZipArchiveMode.Update))
{
var entry = zip.GetEntry(vbaProjectEntryName);
if (entry != null)
{
entry.Delete();
entry = zip.GetEntry(relationsEntryName);
if (entry != null)
{
var contents = string.Empty;
using (var streamReader = new StreamReader(entry.Open()))
{
contents = streamReader.ReadToEnd();
}
var relationText = "<Relationship Id=\"rId6\" Type=\"http://schemas.microsoft.com/office/2006/relationships/vbaProject\" Target=\"vbaProject.bin\"/>";
contents = contents.Replace(relationText, string.Empty);
entry.Delete();
entry = zip.CreateEntry(relationsEntryName);
using (var streamWriter = new StreamWriter(entry.Open()))
{
streamWriter.Write(contents);
}
}
}
}
Has anybody an idea what may cause this error
'Wrong Local header signature: 0xE011CFD0'
var path = #"C:\Excel.xls";
using (var fs = File.OpenRead(path))
{
var wb = new XSSFWorkbook(fs);
}
Im using: https://github.com/dotnetcore/NPOI
Leaving this in case other people pass by here.
.xls is the old Excel format. With that format you should create a new HSSFWorkbook instance. The XSSFWorkbook is used with the new .xlsx format.
Both types implement the IWorkbook interface so you can build your code around this interface and determine the workbook instance's type at runtime.
I created a simple Excel component and here is the constructor:
private readonly bool _useOldExcelFormat;
private readonly IWorkbook _workbook;
public NpoiExcelManager(bool useOldExcelFormat = false)
{
_useOldExcelFormat= useOldExcelFormat;
if (_useOldExcelFormat)
{
_workbook = new HSSFWorkbook();
}
else
{
_workbook = new XSSFWorkbook();
}
}
You'll discover a few differences between HSSFWorkbook and XSSFWorkbook so sometimes you'd have to write specific code for each implementation but those cases are very rare.
I'd say around 95% of the IWorkbook interface is working for both implementations.
Ok, I found solution:
Saved that Excel file as an .xlsx but without macros or .xlsm and it worked
I got Excel xlsx document with hyperlinks.
Hyperlinks have adresses and subaddresses (that's the way VBA call Html fragments, all after # sign)
Epplus library has Hyperlink property for every cell, but it has only first part of html address, so instead of
stackoverflow.com#footer
I got:
stackoverflow.com
Is there any way to read the html fragment part with this library ?
Code for reading hyperlinks via epplus:
FileInfo xlsxFile = new FileInfo(_filePath);
using (ExcelPackage pck = new ExcelPackage(xlsxFile))
{
var wb = pck.Workbook;
if (wb == null)
return null;
var ws = wb.Worksheets.FirstOrDefault();
ExcelRange er = ws.Cells[0,0];
var hyperlink = er.Hyperlink;
It seems to be an issue with the way excel store hyperlinks and the way Epplus reads them. Excel stores the hyperlinks both in the worksheet itself as well as the relationship file for the worksheet which is a file that stores any kind of cross referencing between workbook parts (worksheets, styles, strings, etc). This all has to do with the structure of the an xlsx file which is xml based off of the OpenOffice XML standard: OpenOffice XML Info
So the problem is Epplus is relying on that relationship file which does not contain the fragment while the `hyperlink' node in the worksheet xml does. You can see all of this in its gory detail if you open up the xlsx file as a zip file by renaming it.
So, the short answer is you are forced to use the `.Value' of the cell object. Not as clean but it will work. For example, if I create a cell like this:
with this code:
var fi = new FileInfo(#"c:\temp\Html_Fragment.xlsx");
using (var pck = new ExcelPackage(fi))
{
var wb = pck.Workbook;
var ws = wb.Worksheets.FirstOrDefault();
ExcelRange er = ws.Cells[1,1];
var hyperlink = er.Hyperlink;
Console.WriteLine(er.Value);
Console.WriteLine("{{Value: {0}, Hyperlink: {1}}}", er.Value, er.Hyperlink.AbsoluteUri);
}
Gives this:
{
Value: https://msdn.microsoft.com/en-us/library/aa982683(v=office.12).aspx#Anchor_3,
Hyperlink: https://msdn.microsoft.com/en-us/library/aa982683(v=office.12).aspx
}
I'm using CarlosAg ExcelXmlWriter library which generates XML Excel spreadsheets 2003 (*.xml)
I need to find coomercial or free tool just that converts this generated xml spreadsheet into
PDF. I tried SautinSoft library but it didn't work with my desired extension (xml) it only works with xlsx or xls extesnions
thanks guys in advance
Try Aspose.
http://www.aspose.com/categories/.net-components/aspose.cells-for-.net/default.aspx
You might also need the PDF component, not sure how they do it now.
Can you simply use some pdf printer to do it?
Try to use a free solution (EpPlus): https://github.com/EPPlusSoftware/EPPlus
Or SpreadSheet https://spreadsheetlight.com/
An another way:
static void ConvertFromStream()
{
// The conversion process will be done completely in memory.
string inpFile = #"..\..\..\example.xml";
string outFile = #"ResultStream.pdf";
byte[] inpData = File.ReadAllBytes(inpFile);
byte[] outData = null;
using (MemoryStream msInp = new MemoryStream(inpData))
{
// Load a document.
DocumentCore dc = DocumentCore.Load(msInp, new XMLLoadOptions());
// Save the document to PDF format.
using (MemoryStream outMs = new MemoryStream())
{
dc.Save(outMs, new PdfSaveOptions() );
outData = outMs.ToArray();
}
// Show the result for demonstration purposes.
if (outData != null)
{
File.WriteAllBytes(outFile, outData);
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(outFile) { UseShellExecute = true });
}
}
I can successfully inject a piece of VBA code into a generated excel workbook, but what I am trying to do is use the Workbook_Open() event so the VBA code executes when the file opens. I am adding the sub to the "ThisWorkbook" object in my xlsm template file. I then use the openxml productivity tool to reflect the code and get the encoded VBA data.
When the file is generated and I view the VBA, I see "ThisWorkbook" and "ThisWorkbook1" objects. My VBA is in "ThisWorkbook" object but the code never executes on open. If I move my VBA code to "ThisWorkbook1" and re-open the file, it works fine. Why is an extra "ThisWorkbook" created? Is it not possible to inject an excel spreadsheet with a Workbook_Open() sub? Here is a snippet of the C# code I am using:
private string partData = "..."; //base 64 encoded data from reflection code
//open workbook, myWorkbook
VbaProjectPart newPart = myWorkbook.WorkbookPart.AddNewPart<VbaProjectPart>("rId1");
System.IO.Stream data = GetBinaryDataStream(partData);
newPart.FeedData(data);
data.Close();
//save and close workbook
Anyone have ideas?
Based on my research there isn't a way to insert the project part data in a format that you can manipulate in C#. In the OpenXML format, the VBA project is still stored in a binary format. However, copying the VbaProjectPart from one Excel document into another should work. As a result, you'd have to determine what you wanted the project part to say in advance.
If you are OK with this, then you can add the following code to a template Excel file in the 'ThisWorkbook' Microsoft Excel Object, along with the appropriate Macro code:
Private Sub Workbook_Open()
Run "Module1.SomeMacroName()"
End Sub
To copy the VbaProjectPart object from one file to the other, you would use code like this:
public static void InsertVbaPart()
{
using(SpreadsheetDocument ssDoc = SpreadsheetDocument.Open("file1.xlsm", false))
{
WorkbookPart wbPart = ssDoc.WorkbookPart;
MemoryStream ms;
CopyStream(ssDoc.WorkbookPart.VbaProjectPart.GetStream(), ms);
using(SpreadsheetDocument ssDoc2 = SpreadsheetDocument.Open("file2.xlsm", true))
{
Stream stream = ssDoc2.WorkbookPart.VbaProjectPart.GetStream();
ms.WriteTo(stream);
}
}
}
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[short.MaxValue + 1];
while (true)
{
int read = input.Read(buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write(buffer, 0, read);
}
}
Hope that helps.
I found that the other answers still resulted in the duplicate "Worksheet" object. I used a similar solution to what #ZlotaMoneta said, but with a different syntax found here:
List<VbaProjectPart> newParts = new List<VbaProjectPart>();
using (var originalDocument = SpreadsheetDocument.Open("file1.xlsm"), false))
{
newParts = originalDocument.WorkbookPart.GetPartsOfType<VbaProjectPart>().ToList();
using (var document = SpreadsheetDocument.Open("file2.xlsm", true))
{
document.WorkbookPart.DeleteParts(document.WorkbookPart.GetPartsOfType<VbaProjectPart>());
foreach (var part in newParts)
{
VbaProjectPart vbaProjectPart = document.WorkbookPart.AddNewPart<VbaProjectPart>();
using (Stream data = part.GetStream())
{
vbaProjectPart.FeedData(data);
}
}
//Note this prevents the duplicate worksheet issue
spreadsheetDocument.WorkbookPart.Workbook.WorkbookProperties.CodeName = "ThisWorkbook";
}
}
You need to specify "codeName" attribute in the "xl/workbook..xml" object
After feeding the VbaProjectPart with macro. Add this code:
var workbookPr = spreadsheetDocument.WorkbookPart.Workbook.Descendants<WorkbookProperties>().FirstOrDefault();
workbookPr.CodeName = "ThisWorkBook";
After opening the file everything should work now.
So, to add macro you need to:
Change document type to macro enabled
Add VbaProjectPart and feed it with earlier created macro
Add workbookPr codeName attr in xl/workbook..xml with value "ThisWorkBook"
Save as with .xlsm ext.