I am on my first foray into Excel Interop and after a flying start have hit a wall.
I have an Excel template that contains one sheet which is an assessment form and another which contains guidance notes for how to carry out the assessment.
I also have an XML file with the details of the projects being assessed.
I need to merge the project title, application number and company name into the first sheet and then save the sheet with the filename [Application No] - [Project Title].xlsx.
The first part is working fine. I have Loaded the XML and the code is putting the data into the form where it should be.
My problem is the saving part. I found the .SaveAs method and it creates a couple of files... but they won't open. I then get a HRESULT error 0x800A03EC - Searching the web has explained nothing about this. Something is telling me that this.SaveAs() is referring to the worksheet rather than the work book but I am just guessing there.
I am hoping I have done something stupid and it is an easy fix.
For reference here is my code but like I say I am not sure how useful it is.
private void MergeData()
{
doc.Load(#"C:\XML Data\source.xml");
XmlNodeList forms = doc.SelectNodes("//form1");
for (int i = 0; i < forms.Count; i++)
{
XmlNodeList nodes = forms[i].ChildNodes;
string refNo = nodes[0].InnerText.ToString();
string companyName = nodes[3].InnerText.ToString();
string title = nodes[1].InnerText.ToString();
this.Cells[9, 4] = title;
this.Cells[11, 4] = refNo;
this.Cells[14, 4] = companyName;
this.SaveAs(#"C:\Assessment Forms\" + refNo + " - " + title + ".xlsx");
}
}
Does anyone know how to save these files?
Thanks for reading
EDIT--
I have found this article
C# and Excel Interop issue, Saving the excel file not smooth
and changed the code to include its suggestion
Excel.Application app = this.Application;
Excel.Workbook wb = app.Workbooks.Add(missing);
wb.SaveAs(#"C:\Assessment Forms\" + refNo + " - " + title + ".xlsx");
But it is doing the same.
I am on a deadline so think I am going to have to start copying, pasting and saving manually :(
Not sure what object this is here, but if you are correct in assuming this is a worksheet, try this.Parent.SaveAs
Alternatively if this turns out to be a range, try this.Worksheet.Parent.SaveAs
Related
I have a problem with some code in a service I have. The method just creates a datatable of the report that needs to be created and then writes it to an existing excel file. The problem is that it fails at the save of the file. Somewhat more oddly, it doesn't appear to be catching errors, and I don't know why. I've included the code below. Of note:
excel.Visible=true; doesn't seem to make the excel sheet visible each time so I can't really watch what's going on in the excel itself. I assume it's not becoming visible because it's a service, but I don't really know.
I know that the datatable is producing output as I've had the log (Which is just a text file where I can write events and errors) writes both the cells value and it's location and it has never stopped in the Foreach loop or the for loop within it
I know that it's failing at the wb.Save(); because the Log.WriteLine("WriteTIByEmp 4"); successfully writes to the text file, but the Log.WriteLine("WriteTIByEmp 5"); does not.
The catch (Exception ex) also doesn't seem to be working, as it doesn't write anything about the exception but doesn't even write the Log.WriteLine("Catching Exception");, so I'm a bit lost.
Edit: Just to note, this is all using Interops in the excel portion. It's just that the "using Microsoft.Office.Interop.Excel" is declared at the top of the class to save time and typing as almost all the methods in this particular class are using excel. The excel file is always opening in this process, I can see it in the task manager, and I have had other methods successfully write to excel files in this process. Only this particular method has had issues.
public void WriteTIByEmp(CI.WriteReport Log)
{
try
{
System.Data.DataTable Emps = Pinpoint.TICardsByEmpStatsDaily.GetTICardsByEmployer();
Log.WriteLine("WriteTIByEmp 1");
Application excel = new Application();
excel.Visible = true;
Workbook wb = excel.Workbooks.Open(TIEMPPath);
Worksheet ws = wb.Worksheets[1];
ws.Range["A:G"].Clear();
Log.WriteLine("WriteTIByEmp 2");
int RowNum = 0;
int ColCount = Emps.Columns.Count;
Log.WriteLine("WriteTIByEmp 3");
foreach (DataRow dr in Emps.Rows)
{
RowNum++;
for (int i = 0; i < ColCount; i++)
{
ws.Cells[RowNum, i + 1] = dr[i].ToString();
Log.WriteLine("Cell Val:" + dr[i].ToString() + ". Cell Location: " + RowNum + "," + i);
}
}
Log.WriteLine("WriteTIByEmp 4");
wb.Save();
Log.WriteLine("WriteTIByEmp 5");
wb.Close();
Log.WriteLine("WriteTIByEmp 6");
excel = null;
Log.WriteLine("WriteTIByEmp 7");
}
catch (Exception ex)
{
Log.WriteLine("Catching Exception");
var st = new StackTrace(ex, true);
var frame = st.GetFrame(0);
var line = frame.GetFileLineNumber();
string msg = "Component Causing Error:" + ex.Source + System.Environment.NewLine + "Error Message: " + ex.Message + System.Environment.NewLine + "Line Number: " + line + System.Environment.NewLine + System.Environment.NewLine;
Log.WriteLine(msg, true);
}
}
Meaby try to use Interops
i don't understand how Your code can start Excel application
by this line :
Application excel = new Application();
try this
Microsoft.Office.Interop.Excel.Application xlexcel;
xlexcel = new Microsoft.Office.Interop.Excel.Application();
xlexcel.Visible = true;
I have been in similar situation.
Note: While using Interop Excel is a dependency as well as other processes accessing the file could cause issues. Therefore, I recommend using EPPlus Nuget Package as it works wonders.
https://www.nuget.org/packages/EPPlus/
Please refer to the below sample code.
FileInfo fi = new FileInfo(ExcelFilesPath + "myExcelFile.xlsx");
using (ExcelPackage pck = new ExcelPackage())
{
// Using Existing WorkSheet 1.
ExcelWorksheet ws = pck.Workbook.Worksheets[1];
// Loading Data From DataTable Called dt.
ws.Cells["A1"].LoadFromDataTable(dt, true);
// If you want to enable auto filter
ws.Cells[ws.Dimension.Address].AutoFilter = true;
// Some Formatting
Color colFromHex = System.Drawing.ColorTranslator.FromHtml("#00B388");
ws.Cells[ws.Dimension.Address].Style.Fill.PatternType = ExcelFillStyle.Solid;
ws.Cells[ws.Dimension.Address].Style.Fill.BackgroundColor.SetColor(colFromHex);
ws.Cells[ws.Dimension.Address].Style.Font.Color.SetColor(Color.White);
ws.Cells[ws.Dimension.Address].Style.Font.Bold = true;
ws.Cells["D:K"].Style.Numberformat.Format = "0";
ws.Cells["M:N"].Style.Numberformat.Format = "mm-dd-yyyy hh:mm:ss";
ws.Cells[ws.Dimension.Address].AutoFitColumns();
pck.SaveAs(fi);
}
You can refer to the above code from my project. I am loading the DataTable data into my excel file by providing the Range or Starting Cell.
I had found the issue. The Excel file was open on someone else's computer which resulted in it not being able to save the file, but it couldn't display the excel popup because excel wouldn't become visible (I still don't know why but Probably something to do with it being a service). So it just couldn't save but it wasn't a code error so it didn't show up in the log and couldn't continue so the code was just stuck. I'll make a copy for the purposes of updating in the future.
As an unexperienced developer I have no idea whether this question is phrased properly (I did check the internet but I havent found a solution that worked for me that is why I signed up here). I am trying to make a form where users can upload files to attach to their form (in SharePoint 2013) and I used the following code as an example. The idea is to temporary accept the files and display them to the user and upload them to the document library when the form is submitted.
In my code however, this results in "acces denied" and when I debugged it, the following piece of my code seemed to be causing the problem:
public void BtnAttachmentUpload_Click(object sender, EventArgs e)
{
fileName = System.IO.Path.GetFileName(FileUpload.PostedFile.FileName);
if (fileName != "")
{
string _fileTime = DateTime.Now.ToFileTime().ToString();
string _fileorgPath = System.IO.Path.GetFullPath(FileUpload.PostedFile.FileName);
string _newfilePath = _fileTime + "~" + fileName;
length = (FileUpload.PostedFile.InputStream.Length) / 1024;
string tempFolder = Environment.GetEnvironmentVariable("TEMP");
string _filepath = tempFolder + "\\" + _newfilePath;
FileUpload.PostedFile.SaveAs(_filepath);
AddRow(fileName, _filepath, DocNo, true);
DocNo = DocNo + 1;
Label.Text = "Successfully added in list";
}
}
The last line of the first section(FileUpload.PostedFile.SaveAs(_filepath);) is where it gives the following error:
"System.UnauthorizedAccessException: 'Access to the path
'C:\Users\Spapps\AppData\Local\Temp\131613662837501509~testdoc2.pdf'
is denied.' "
Is this a known issue and is there a solution that can help me out?
Try with spsecurity.runwithelevatedprivileges
I've been looking to close this question but didnt find how to so Ill state it here as an answer. I havent found a solution, but I worked around this issue in my project by altering the approach; I do not temporarily upload and display the files anymore. They are deleted from the doclib if the procedure is cancelled.
I have a WinForms app written in C# and I want to programmatically export some data into the some named ranges in an Excel Template. I've looked on these forums and elsewhere and the closest code I can find to what I want is as follows -
private Excel.Workbook m_workbook;
object missing = Type.Missing;
public void testNamedRangeFind()
{
m_workbook = Globals.ThisAddIn.Application.ActiveWorkbook;
int i = m_workbook.Names.Count;
string address = "";
string sheetName = "";
if (i != 0)
{
foreach (Excel.Name name in m_workbook.Names)
{
string value = name.Value;
//Sheet and Cell e.g. =Sheet1!$A$1 or =#REF!#REF! if refers to nothing
string linkName = name.Name;
//gives the name of the link e.g. sales
if (value != "=#REF!#REF!")
{
address = name.RefersToRange.Cells.get_Address(true, true, Excel.XlReferenceStyle.xlA1, missing, missing);
sheetName = name.RefersToRange.Cells.Worksheet.Name;
}
Debug.WriteLine("" + value + ", " + linkName + " ," + address + ", " + sheetName);
}
}
}
However I get an error saying 'The name Globals does not exist in the current context'.
Can someone please explain what it is I am not understanding about this code, or alternatively point me at some other code that will enable me to post values from my Database into the Excel Template named ranges.
This code runs on VSTO (Visual Studio Tools for Office) and uses the Microsoft.Office.Interop.Excel.
So you should create an Office Excel Workbook solution in Visual Studio:
File -> New -> Visual C# -> Office -> [ Select your Office version ] -> Excel Workbook
I've got about thousand of Excel (xls, old format) files spread out across many folders on the hard-drive. These files have the same macros that connects to a database. And the macros contains connection string. Macros is password protected, but luckily I know the password.
Question: what is the best way to change the connection string in macros inside all the files?
I have experience of working with NPOI to create/modify xls files. I have seen Interop libraries unlocking password-protected Word files and doing some editing. But I have never seen examples of programmatically changing of the macros text inside Excel file. Is that even possible?
p.s. I don't have problems writing code. The problem is choosing the right tools.
You might want use the following code as a starting point. This code uses COM Interop to extract the VBA script and perform a find-replace. I tried this out on a password-protected spreadsheet with a very basic script and it worked well. It is, admittedly, basic, but you may be able to extract what you need.
string filename = "Test.xls";
string password = "password";
Excel._Application app = new Excel.Application();
Excel._Workbook workbook = app.Workbooks.Open(Filename: filename, Password: password);
if (workbook.HasVBProject)
{
VBProject project = workbook.VBProject;
foreach (VBComponent component in project.VBComponents)
{
if (component.Type == vbext_ComponentType.vbext_ct_StdModule ||
component.Type == vbext_ComponentType.vbext_ct_ClassModule)
{
CodeModule module = component.CodeModule;
string[] lines =
module.get_Lines(1, module.CountOfLines).Split(
new string[] { "\r\n" },
StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Contains("A1"))
{
lines[i] = lines[i].Replace("A1", "D1");
module.ReplaceLine(i + 1, lines[i]);
}
}
}
}
}
workbook.Save();
workbook.Close();
app.Quit();
I have this code:
Microsoft.Office.Interop.Excel.Application xla = new Microsoft.Office.Interop.Excel.Application();
xla.Visible = false;
Workbook wb = xla.Workbooks.Add(XlSheetType.xlWorksheet);
Worksheet ws = (Worksheet)xla.ActiveSheet;
ws.Name = "Serial";
int i = 1;
foreach (DataRow comp in dsView.Tables[0].Rows)
{
ws.Cells[i, 1] = "'" + comp[0].ToString();
ws.Cells[i, 2] = "'" + comp[1].ToString();
ws.Cells[i, 3] = "'" + comp[2].ToString();
i++;
}
if (File.Exists(#"d:\DDD.xlsx"))
File.Delete(#"d:\DDD.xlsx");
xla.Save(#"d:\DDD.xlsx"); ---->>>> on this line i get the error
The error:
Exception from HRESULT: 0x800A03EC
I am working on C# winforms with Office 2012
Your problem is that the variable xla is your excel application and not a workbook. You want to save the workbook.
so
xla.Save(#"d:\DDD.xlsx"); ---->>>> on this line i get the error
should be
wb.SaveAs(#"d:\DDD.xlsx", System.Reflection.Missing.Value,System.Reflection.Missing.Value,System.Reflection.Missing.Value,
System.Reflection.Missing.Value,System.Reflection.Missing.Value,Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange,System.Reflection.Missing.Value,
System.Reflection.Missing.Value,System.Reflection.Missing.Value,System.Reflection.Missing.Value,System.Reflection.Missing.Value);
When I run Excel.Application.Save() with Visual Studio 2010 and Excel 2010 interop (Office 14) targeting .NET 4, it displays a dialog to select a location to save the file. Clicking Cancel on that dialog results in a COM exception. But clicking Save has odd results: When I supply a valid file path and name as a parameter like Excel.Application.Save(#"C:\blah.xlsx"), I end up with two files saved. The first is named Sheet1.xlsx and contains what I'd expect, even though I didn't choose that name in the dialog. The other is named blah.xlsx (as per my file name parameter) and won't open correctly in Excel. If I call Excel.Application.Save() without a file name as a parameter, a valid file is saved with the name and path I selected in the dialog, but I also get a "RESUME.XLW" file as well. So it seems that the Application.Save method may not be a good choice to use. Instead, you can do something like this, which works as you'd expect:
using System;
using Excel = Microsoft.Office.Interop.Excel;
namespace WindowsFormsApplication2
{
static class Program
{
static void Main()
{
Excel.Application xlApp = new Excel.Application();
Excel.Workbook book = xlApp.Workbooks.Add(Excel.XlSheetType.xlWorksheet);
Excel.Worksheet sheet = book.ActiveSheet;
sheet.Name = "Booya";
Excel.Range range = sheet.Cells[1, 1];
range.Value = "This is some text";
book.SaveAs(#"C:\blah.xlsx");
}
}
}