I am having trouble with an application that uses Excel interop. With Excel 2010 and 2013 it works perfectly fine. Unfortunately it no longers works for my colleague now that he has upgraded to Office 2016. I will also upgrade very soon and need to find a solution.
What is being done?
A click event fires a background worker...
private void btnPrep_Click(object sender, EventArgs e)
{
lblWorking.Visible = true;
pBar1.Visible = true;
//...
//...
bwPrep.RunWorkerAsync(args);
}
... which in turn calls a method "Xls2Xml"...
private void bwPrep_DoWork(object sender, DoWorkEventArgs e)
{
//...
//...
foreach (var x in y)
{
var fils = di.GetFiles();
if (fils.Any(f => f.Name.Contains(".xls")))
{
bwPrep.ReportProgress(0, lang);
Xls2Xml(fils.First(f => f.Name.Contains(".xls")).FullName, dest);
}
}
}
... in which I use interop:
private void Xls2Xml(string xlsPath, string destination)
{
var pfad = xlsPath;
var xlapp = new XL.Application();
var wbooks = xlapp.Workbooks;
var wb = wbooks.Open(pfad);
var sheets = wb.Sheets;
XL.Worksheet sheet = sheets[1];
//...
//...
Marshal.ReleaseComObject(sheet);
Marshal.ReleaseComObject(sheets);
Marshal.ReleaseComObject(wb);
Marshal.ReleaseComObject(wbooks);
Marshal.ReleaseComObject(xlapp);
}
This works fine with Excel 2010 and 2013. Excel 2016 causes a COM error. First, it was RPC_E_SERVERCALL_RETRYLATER ("application busy").
Googling gave me a recommendation to add this line before calling the background worker:
System.Threading.SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
What this did was to change the resulting error into "Call was rejected by callee" (RPC_E_CALL_REJECTED).
I made sure that the correct versions of Excel interop and Office library are referenced (1.9 / 16).
The error occurs on the line var xlapp = new XL.Application();, no other instance of Excel application is created before this line. Excel is properly installed and activated, a repair installation did not solve the issue either.
Have any of you come across similar issues?
Solved.
It turned out to be something my colleague conveniently forgot to mention because he completely forgot about it: the culprit was the Kutools Add-In.
Although it was installed before and hadn't caused problems back then, one of the latest Office updates must have changed some behavior. Deactivating Kutools was all it took.
Related
I have a Windows form app project (C#).
I am trying unsuccessfully to write code so that when I click a button I created, it will load an excel file that actually has macros in it and delete them all.
I know you can delete macros manually in the excel file itself but I need a way to do it programmatically (I just delete them all for the user).
I know that the macros in Excel files are written in VBA language, so I try to use the related libraries in c# but I get an error when I try to use VBProject, VBComponent.
This what I tried so far:
using Microsoft.Office.Interop.Excel;
namespace MacroRemover
{
public partial class Main : Form
{
private void Btn_Click(object sender, EventArgs e)
{
string filePath = "path\\to\\file.xlsm";
Application excel = new Application();
Workbook workbook = excel.Workbooks.Open(filePath);
VBProject vbProject = workbook.VBProject;
foreach (VBComponent component in vbProject.VBComponents)
{
vbProject.VBComponents.Remove(component);
}
workbook.Save();
workbook.Close();
excel.Quit();
}
}
}
Any way that works will help me, I would appreciate the help
Thanks in advance guys!!!
If you don't need to save xlsm format of the file, you can save this file to xlsx format and all scripts will be removed.
using Aspose.Cells;
var workbook = new Workbook("input.xlsm");
workbook.Save("Output.xlsx");
Thanks for all the replies, #tttony's response helped me to understand more deeply and #Bushuev's response here is definitely a possible and simple solution for deleting the macros.
I finally managed to delete all the macros like this:
string filePath = Path_TxtBox.Text;
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Workbook workbook = excel.Workbooks.Open(filePath);
VBProject project = workbook.VBProject;
for (int i = project.VBComponents.Count; i >= 1; i--)
{
VBComponent component = project.VBComponents.Item(i);
try
{
project.VBComponents.Remove(component);
}
catch (ArgumentException)
{
continue;
}
}
for (int i = project.VBComponents.Count; i >= 1; i--)
{
VBComponent component = project.VBComponents.Item(i);
component.CodeModule.DeleteLines(1, component.CodeModule.CountOfLines);
}
workbook.Save();
workbook.Close();
excel.Quit();
MessageBox.Show("Macros Removed");
It should only be noted that I encountered an error: 'Programmatic access to Visual Basic Project is not trusted'
It was solved after I realized that I had to change the option to access the VBA Project object model in the Trust Center settings.
So basically my app triggers an excel macro, from a file, that updates the file and then closes it.
When I open the file I set the "DisplayAlerts = false" variable in order to ignore all popups and it works as expected in my computer... however, a colleague of mine tried to use it and for every file, he gets the popup asking if he wants to save all changes...
Checked other questions about the popups in excel but all suggested solutions use "oBook.Saved = true;" or "oBook.Close(false);", but these did not work for me.
my code is as follows:
using Microsoft.Office.Interop.Excel;
public static bool Trigger_Macro_From_File(string path)
{
ApplicationClass oExcel = null;
Workbook oBook = null;
try
{
string filename = Path.GetFileName(path);
string macro_name = "!some_macro";
string macro = #"'" + filename + #"'" + macro_name;
// Create an instance of Microsoft Excel
oExcel = new ApplicationClass
{
DisplayAlerts = false,
Visible = false
};
oBook = oExcel.Workbooks.Open(path);
RunMacro(oExcel, new Object[] { macro });
oBook.Save();
oBook.Saved = true;
return true;
}
catch (Exception ex)
{
return false;
}
finally
{
oBook?.Close(false);
System.Runtime.InteropServices.Marshal.ReleaseComObject(oBook);
oBook = null;
oExcel?.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(oExcel);
oExcel = null;
GC.Collect();
}
}
Does anyone know anything about this?
Thanks in advance.
You could double-check that no other "Microsoft Excel" process is running in the Task Manager.
Let's say at some point in your development process you started your program and open the workbook with something like
xlWorkbook = xlApp.Workbooks.Open(filePath);
Then you encountered an exception for some reason, and killed the program without closing the file properly (workbook.Close(..), app.Quit(..) and so on).
The Microsoft Excel process is still running in the background, and has a handle on the file you want to edit. So you cannot execute an instruction that saves the file under the same name. This is why the popup is appearing.
This scenario is taken from the point of view of the developer, but the same behavior could have happened on your coworker's computer if your app crashed without quitting properly, and gets re-started.
Also, be careful that finally statement might not always be executed, so double-check which scenario could cause your app to close without releasing the COM object.
I have a C# (using Razor) Web Application that runs through my company's intranet.
I have been using ClosedXML to manage all of my Excel needs and it works great, however, now I need to run Macros inside Excel Files and apparently ClosedXML cannot do this, so I must use Excel Interop.
My code below gives the dreaded:
Microsoft Excel cannot access the file ... There are several possible
reasons: • The file name or path does not exist. • The file is being
used by another program. • The workbook you are trying to save has the
same name as a currently open workbook.
The file name and path DOES exist
I made sure that Excel is not even running on the server
The workbook is not open (see above).
Things I've tried.
I've tried to create security provisions for the C:\Windows\System32\config\systemprofile and SysWOW64\config\systemprofile.
(Side Note: I could not find IIS_USRS when I tried to add the security provisions - this may be the problem.)
I've also tried editing the Excel Application properties via dcomcnfg and I still get the same error.
here's what I'm trying to do:
//C# with Razor Syntax
#using MSExcel = Microsoft.Office.Interop.Excel
#using System.Runtime.InteropServices
#using System.Web
#using System.IO
string worksheetName = "Sheet1";
string[] macros = new string[] { "Module1.Reset_List()", "Module1.Run_Setup()"};
string workbookPath = HttpContext.Current.Server.MapPath(#"~/uploads/test.xlsm");
FileInfo xlsFile = new FileInfo(workbookPath);
string msg = (File.Exists(xlsFile.FullName)) ? "Found It!" : "Can't Find It...";
<p>#msg</p>; // <-- This always returns "Found It!"
//Create the Excel Object
MSExcel.Application xlsApp = new MSExcel.Application();
xlsApp.Visible = true;
try
{
//Identify the workbook (open the file)
// *** the error occurs on the line below *** //
MSExcel.Workbook xlsBook = xlsApp.Workbooks.Open(xlsFile.FullName);
xlsBook.Activate();
//Identify the worksheet
MSExcel.Worksheet xlsSheet = (MSExcel.Worksheet)xlsBook.Sheets[worksheetName];
xlsSheet.Activate();
foreach (string macro in macros)
{
xlsApp.Run(macro);
}
xlsBook.Save();
xlsBook.Close(false, "", false);
xlsApp.Quit();
}
catch (Exception e)
{
<p>#e.Message</p>
Marshal.ReleaseComObject(xlsApp);
xlsApp = null;
}
if (xlsApp != null)
{
Marshal.ReleaseComObject(xlsApp);
xlsApp = null;
}
I want to try the Windows form application that converts a office file (Excel, Word, Powerpoint) into a PDF file.
My client's PC will not install Visual Studio and Office version is 2007.
My application uses Microsoft.Office.Iterop.Excel.dll to covert to the PDF format.
This dll file cannot be found on my client's PC and an error has occurred as following.
System.AugumentException: Value does not fall within the expected range.
at Microsoft.Office.Interop.Excel._Workbook.ExportAsFixedFromat(.......)
How can I solve this problem?
My code is following
public bool ExportWorkbookToPdf(string workbookPath, string outputPath)
{
// If either required string is null or empty, stop and bail out
if (string.IsNullOrEmpty(workbookPath) || string.IsNullOrEmpty(outputPath))
{
return false;
}
// Create COM Objects
Microsoft.Office.Interop.Excel.Application excelApplication;
Microsoft.Office.Interop.Excel.Workbook excelWorkbook;
// Create new instance of Excel
excelApplication = new Microsoft.Office.Interop.Excel.Application();
// Make the process invisible to the user
excelApplication.ScreenUpdating = false;
// Make the process silent
excelApplication.DisplayAlerts = false;
// Open the workbook that you wish to export to PDF
excelWorkbook = excelApplication.Workbooks.Open(workbookPath);
MessageBox.Show(workbookPath);
// If the workbook failed to open, stop, clean up, and bail out
if (excelWorkbook == null)
{
excelApplication.Quit();
excelApplication = null;
excelWorkbook = null;
MessageBox.Show("in null");
return false;
}
var exportSuccessful = true;
try
{
// Call Excel's native export function (valid in Office 2007 and Office 2010, AFAIK)
excelWorkbook.ExportAsFixedFormat(Microsoft.Office.Interop.Excel.XlFixedFormatType.xlTypePDF, outputPath);
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message);
// Mark the export as failed for the return value...
exportSuccessful = false;
// Do something with any exceptions here, if you wish...
// MessageBox.Show...
}
finally
{
// Close the workbook, quit the Excel, and clean up regardless of the results...
excelWorkbook.Close();
excelApplication.Quit();
excelApplication = null;
excelWorkbook = null;
}
// You can use the following method to automatically open the PDF after export if you wish
// Make sure that the file actually exists first...
if (System.IO.File.Exists(outputPath))
{
MessageBox.Show(outputPath);
System.Diagnostics.Process.Start(outputPath);
}
return exportSuccessful;
}
As already said in the comments, each client needs to install the 2007 Microsoft Office Add-in: Microsoft Save as PDF. It doesn't matter if you are on Windows 8.1 or have any PDF reader installed. You need that Add-in to write PDFs with Office 2007. (You don't need any Add-In with Office 2010 or 2013.)
Hi I have pasted below a piece of code where I am displaying a report. I am using Visual Studio 2008 Crystal Report engine. It works all good with the piece of code
Problem: Everytime a report is being run it generates a ('.*tmp', '.*rpt') files typically in a temp folder c:\windows\temp however we can get rid of the *.tmp files by setting a recycle on the application pool but need a way to get rid of the .rpt files.
Found solution: Call Close() and Dispose() on the report object. The way I am doing is crReportDoc.Close() then crReportDoc.Dispose()
Actual Problem: If Dispose() is called the report comes up with the following error 'Object reference not set to an instance of an object'
I will really appreciate if one of the fellow mates can help me with a solution as I am quite new to programming.
Thanks
Dim crReportDoc = New CrystalDecisions.CrystalReports.Engine.ReportDocument
crReportDoc = Session("ReportDocument")
ReportViewer.DisplayToolbar = True
ReportViewer.EnableDrillDown = True
ReportViewer.DisplayGroupTree = False
ReportViewer.Visible = True
ReportViewer.DisplayToolbar = True
ReportViewer.ReportSource = crReportDoc
Some times even though you call dispose on your ReportDocument object followed by GC.Collect() still the .rpt files in Temp folder are not cleaned up. And there is a limit to no. of .rpt files in a Temp folder after which CR stops executing further report requests.
Strangely this happens when you declare your ReportDocument object in side a function or event handler.
But if you declare your ReportDocument in a Page wide global Context then crystal reports happily cleans of temp .rpt files when you call the Dispose method in the Page_Unload() event !!!!
For CRystal Report Versions 13 and above. To clear temporary files. Call the dispose in the CrystalReportViewer's Unload event
protected void crReportViewer_Unload(object sender, EventArgs e)
{
CloseReport();
}
/// <summary>
/// This method is used to clear the temporary files created by Crystal Reports
/// </summary>
protected void CloseReport()
{
try
{
if(cryRpt != null)
{
Sections objSections = cryRpt.ReportDefinition.Sections;
foreach (Section objSection in objSections)
{
ReportObjects objReports = objSection.ReportObjects;
foreach(ReportObject rptObj in objReports)
{
if(rptObj.Kind.Equals(CrystalDecisions.Shared.ReportObjectKind.SubreportObject))
{
SubreportObject subreportObject = (SubreportObject)rptObj;
ReportDocument subReportDocument = subreportObject.OpenSubreport(subreportObject.SubreportName);
subReportDocument.Close();
}
}
}
cryRpt.Close();
cryRpt.Dispose();
}
if(crReportViewer != null)
{
crReportViewer.ReportSource = null;
crReportViewer.Dispose();
}
}
catch
{
}
}