I'm using Microsoft.Office.Interop.Excel in a .Net Framework 4.5 Windows Service project on my 64bit Windows 7 desktop workstation and everything appears to be working except the PageSetup properties and more importantly the PrintOut method of the Worksheet object.
Here's the code:
Microsoft.Office.Interop.Excel.Application ExcelApp = null;
Microsoft.Office.Interop.Excel.Workbook WBook = new Microsoft.Office.Interop.Excel.Workbook;
Microsoft.Office.Interop.Excel.Worksheet WSheet = new Microsoft.Office.Interop.Excel.Worksheet);
ExcelApp = new Microsoft.Office.Interop.Excel.Application();
WBook = ExcelApp.Workbooks.Add();
WSheet = WBook.Worksheets[1];
//Do some stuff with the sheet
//None of this works, throws an error: Unable to set the Orientation property of the PageSetup class
WSheet.PageSetup.Orientation = Microsoft.Office.Interop.Excel.XlPageOrientation.xlLandscape;
WSheet.PageSetup.Zoom = false;
WSheet.PageSetup.FitToPagesWide = 1;
WSheet.PageSetup.FitToPagesTall = false;
//Throws Error (see below)
WSheet.PrintOut(null, null, null, null, null, null, null);
PrintOut() Error: No printers are installed. To install a printer click the File tab, and then click Print. Click No Printers Installed, and then click Add Printer. Follow the instructions in the Add Printer dialog box.
I definitely have printers defined in my Devices and Printers. I have a network printer set as my Default. I have even added this printer to Win.ini as I've seen this recommended in other posts but to no avail.
I figured this out while writing up the question.
Make sure you are running your Windows Service under an account that has printers set up and a specified Default printer. I was running the service under Local Service account, once I switched it to run under my personal account both the PageSetup properties and the PrintOut() method worked!
Related
I have an SSIS package being called from a batch file and I am trying to schedule it via the task scheduler. The package works fine in Visual Studio, and it works when I execute the batch file, but it fails when I run the package through the scheduler. I've read all other post on this topic and I don't see anything relevant to mine, the problem is not configuration of the task scheduler properties (i.e the account it's using, run at highest privilege, start in directory, etc..).
I run multiple packages successfully through the task scheduler with no issues, this one just happens to use a c# script task that I had to add an assembly reference to and I think that's what is causing the problems when the package runs via the scheduler as the other packages use c# script task without issue but I did not add any assemblies.
This is the C# script which is used to format an excel spreadsheet after it's populated with data.
using System;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
#endregion
namespace ST_2bdf93d5542441248076f053703d32c9
{
[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
public void Main()
{
int lastUsedColumn = 0;
string inputFile = (string)Dts.Variables["RecommendationFileName"].Value;
string RecommendationName = (string)Dts.Variables["RecommendationName"].Value;
Excel.Application ExcelApp = new Excel.Application();
Excel.Workbook ExcelWorkbook = ExcelApp.Workbooks.Open(inputFile);
//ExcelApp.Visible = true; //Use this to show the excel application/spreadsheet while the package is running. Not good for prod, just testing.
ExcelApp.Visible = false;
Excel.Worksheet xlWorkSheetFocus = (Excel.Worksheet)ExcelWorkbook.Worksheets.get_Item(3);
xlWorkSheetFocus.Activate();
xlWorkSheetFocus.Select(Type.Missing);
Excel.Range usedRange = xlWorkSheetFocus.UsedRange;
foreach (Excel.Worksheet ExcelWorksheet in ExcelWorkbook.Sheets)
{
ExcelWorksheet.Columns.AutoFit(); //Autofit the column to width for each worksheet, we adjust some column widths manually later.
if (ExcelWorksheet.Name == "Recommendations")
{
ExcelWorksheet.Cells[1, 4].EntireColumn.ColumnWidth = 125;
ExcelWorksheet.Cells[1, 4].EntireColumn.WrapText = true;
}
if (ExcelWorksheet.Name == "Passed")
{
ExcelWorksheet.Cells[1, 4].EntireColumn.ColumnWidth = 125;
ExcelWorksheet.Cells[1, 4].EntireColumn.WrapText = true;
}
if ((ExcelWorksheet.Name != "Recommendations") & (ExcelWorksheet.Name != "Passed"))
{
// Find the last real column in each worksheet
lastUsedColumn = ExcelWorksheet.Cells.Find("*", System.Reflection.Missing.Value,
System.Reflection.Missing.Value, System.Reflection.Missing.Value,
Excel.XlSearchOrder.xlByColumns, Excel.XlSearchDirection.xlPrevious,
false, System.Reflection.Missing.Value, System.Reflection.Missing.Value).Column;
ExcelWorksheet.Rows["1"].Insert(); //insert empty top row
ExcelWorksheet.Rows["2"].Insert(); //insert empty second row
ExcelWorksheet.Rows["3"].Insert(); //insert empty second row
ExcelWorksheet.Cells[1, 1].Interior.Color = 0x565656; //Row 1 = Dark Gray
ExcelWorksheet.Cells[2, 1].Interior.Color = 0x565656; //Row 2 = Dark Gray
ExcelWorksheet.Cells[3, 1].Interior.Color = 0x3ad7bd; //Row 3 = Green
ExcelWorksheet.Range[ExcelWorksheet.Cells[4, 1], ExcelWorksheet.Cells[4, lastUsedColumn]].Interior.Color = 0xCECECE; //Row 4 = Light Gray
//Bold the Fourth row of each spreadsheet (column headers are here)
ExcelWorksheet.Range["A4"].EntireRow.Font.Bold = true;
//Add a link back to the Recommendations page in row 2
ExcelWorksheet.Hyperlinks.Add(ExcelWorksheet.Cells[2, 1], "#Recommendations!A2", Type.Missing, "Return to Recommendations", "Return to Recommendations");
//Change row 1 to White, Bold, and 12pt font Arial, this is the report Title
ExcelWorksheet.Cells[1, 1].Font.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.White);
ExcelWorksheet.Cells[1, 1].Font.Bold = true;
ExcelWorksheet.Cells[1, 1].Font.size = 12;
ExcelWorksheet.Cells[1, 1].Font.Name = "Arial";
Excel.Range formatRange;
formatRange = ExcelWorksheet.get_Range("c1", "c1");
}
}
ExcelWorkbook.Save();
GC.Collect();
GC.WaitForPendingFinalizers();
ExcelWorkbook.Close(Type.Missing, Type.Missing, Type.Missing);
Marshal.FinalReleaseComObject(ExcelWorkbook);
ExcelApp.Quit();
Marshal.FinalReleaseComObject(ExcelApp);
}
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
}
}
And here are the references I added to this script task:
My question is, knowing that it has something to do with these references, does anyone understand why this happens? I am running the task with a local admin account and the batch file is on the local filesystem, everything else works in the package until this script task when using the task scheduler. I tries to copy the Excel Interop DLL file to the same folder as the batch file and re-added the reference to see if maybe that was the issue to no avail. My other script task which I did not have to add any assembly references to work just fine this way.
ding ding ding
I had to add an assembly reference to and I think that's what is causing the problems
Correct. You are using the Excel object model, via Microsoft.Office.Interop.Excel, to build/modify an Excel Workbook. The scheduler server does not have Office installed so the package fails as it can't find the required libraries. The correct resolution is to install Office on the server.
I tries (sic) to copy the Excel Interop DLL file to the same folder as the batch file
You do not want to "solve" the problem by copying the required assemblies to the scheduler. Even if you get all the required files installed, you've now opened your company up to failing an audit.
Office isn't free, the fine folks in Redmond built it, your organization will want to pay for it because paying upfront is so much cheaper than an audit finding a willful violation. Compare and contrast these conversations
"Oh yeah, we installed XYZ on this box an forgot about it" Auditors: ok, fine, true up your licensing and pay for what you're using. $
"Oh yeah, we mirrored on the libraries over there, installed them to the GAC, etc" Auditors: So it wasn't just an accident, that was deliberate and ignorance is not a defense. You owe us licensing fees and the following penalties. $$$
I came to realize that Interop was not going to work headless, either through the agent or task scheduler, so I switched to ClosedXML, built a console app, and execute it that way and it works.
I am working with Winapp driver, appium and c# where i am automating a desktop application.
My scerios is: I have aplication where i click on the button which opens excel sheet which is now shows in Taskbar of the desktop. Now i want to switch to the excel sheet from my desktop application.
I am not able to find a single solution for the same. Help will be appreciated.
1.) Try getting WindowHandles() by :
Set<String> windowHandles = driver.getWindowHandles();
If this set has 2 values, then you can easily switch between both the apps via :
driver.switchTo.window(windowHandleOfExcel);
2.) If the set contains only one handle, then you need to create a new Desktop session for you excel , you can do the same by :
//get a root driver
//all the opened application will be children of this root driver
//get the expected child driver
DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability("app", "Root");
WindowsDriver rootDriver = new WindowsDriver(new URL("http://127.0.0.1:4723"), cap);
WebElement ele = d.findElementByName("Book - Excel"); //Pass the header or title of the excel opened
String toplevel = ele.getAttribute("NativeWindowHandle");
int x = (Integer.parseInt(toplevel));
toplevel = Integer.toHexString(x);
DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability("appTopLevelWindow", toplevel);
WindowsDriver childdriver = new WindowsDriver(new URL("http://127.0.0.1:4723"), cap);
childDriver is the driver that is pointing for the Excel app.
Hope this helps.
Similar questions have been asked before, but I want to try and refine it to my situation.
I am downloading a legacy file type (Excel 2003 (.xls)) and I need to strip the data from the file. The problem is I get :
{"Unable to cast COM object of type 'Microsoft.Office.Interop.Excel.ApplicationClass'
to interface type 'Microsoft.Office.Interop.Excel._Application'. This operation failed
because the QueryInterface call on the COM component for the interface
I am currently trying to get this working on my machine before I send the app to production, which will/does have excel on the server.
I have tried reinstalling office, but that did not work. I think the problem lies more in the fact that I have office 2013 on my box and I am attempting to run a decade old file type through it.
I tried to use this:
public void Convert(String file)
{
var app = new Application();
var wb = app.Workbooks.Open(file);
wb.SaveAs(file + "x", XlFileFormat.xlOpenXMLWorkbook);
wb.Close();
app.Quit();
}
That still causes the same problem, because the file will not open.
Any suggestions?
UPDATE
Here is the full method I am using
public Worksheet GetExcelBy(string url)
{
var fileName = #"C:\temp\tempfile.xls";
var webClient = new WebClient();
webClient.DownloadFile(url, fileName);
Convert(fileName);
var excel = new Application();
var workbook = excel.Workbooks.Open(fileName);
return (Worksheet)workbook.Worksheets["Data 6"];
}
this is the URL:
http://tonto.eia.doe.gov/dnav/pet/xls/pet_pri_spt_s1_d.xls
I presume the line with var excel = new Application(); is the line where the exception is raised. From my experience in the matter, as I also tried to follow other advice found on the internet, the solution I accidentally found was to explicitly define the non use of 32 bit access mode for the interop dll.
For doing so in visual studio, I had to tick and then untick the box "Prefer 32-bit" in the build section of the project configuration, which added <Prefer32Bit>false</Prefer32Bit> in the .csproj file.
I am running some C# code as part of a script component running in my SSIS package. I am trying to open an Excel file and change the name of the sheet prior to importing the file in the next step of my SSIS package. I am getting an error on the line where I am trying to initialize "oSheet".
The error specifies: "Error 1 One or more types required to compile a dynamic expression cannot be found. Are you missing a reference? C:\Temp\Vsta\SSIS_ST110\VstaTP9LtckEMUWOXYp4Zy3YpQ\Vstau3xOw__Ey1kaOxXFoq0ff8g\ScriptMain.cs 107 26 ST_005c649f34584ed6873a7fde862ab2c9
"
I've not used C# for a while and was hoping someone could point me in the right direction. Thanks in advance!
Code:
public void Main()
{
String s = (String)Dts.Variables["FilePath"].Value;
String FileName = s.Substring(45,s.Length - 45); //45 = hardcoded value for known index of the start of the file name
MessageBox.Show(FileName);
Excel.Application oXL;
Excel._Workbook oWB;
Excel._Worksheet oSheet;
Excel.Range oRng;
try
{
oXL = new Microsoft.Office.Interop.Excel.Application();
oXL.Visible = false;
oWB = (Excel.Workbook)oXL.Workbooks.Open(s);
oSheet = (Excel._Worksheet)oWB.ActiveSheet;
//oSheet = (Excel._Worksheet)oXL.ActiveSheet;
//oSheet = (Excel._Worksheet)oWB.Worksheets.Item(0);
//oSheet = (Excel._Worksheet)oXL.Worksheets[FileName];
oSheet.Name = "NLTWNH";
oWB.Close(s);
}
catch (Exception ex)
{
//do nothing
}
Dts.TaskResult = (int)ScriptResults.Success;
}
First, add a reference to the Microsoft Excel Interop DLL. You do this by right clicking the References folder in the Solution Explorer. Then click Add Reference.
Click on the COM tab in the "Add Reference" window, and scroll down to your version of Excel's Object Library (I have chosen 15, but you may chose another version). Then click OK.
Now, it looks like your using statement should do something like this:
using Excel = Microsoft.Office.Interop.Excel;
Also, note that your oXL constructor can now just be
oXL = new Excel.Application();
I was missing a reference to "Microsoft.CSharp.dll" in my SSIS script task. To add the reference in Visual Studio 2012 click Project, Add Reference, then in the Framework tab scroll to find Miscrosoft.CSharp, check the corresponding box, and click OK.
I have a weird problem where Excel is behaving differently on my development machine and a testing machine.
In my add-in, I've turned off ScreenUpdating in several places for long running processes. On my machine this works fine. On the testing machine, Excel sets ScreenUpdating = true as soon as I write to a cell.
The following code demonstrates the issue for me.
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Microsoft.Office.Interop.Excel.Application excel = Globals.ThisAddIn.Application;
MessageBox.Show(excel.ScreenUpdating.ToString());
excel.ScreenUpdating = false;
MessageBox.Show(excel.ScreenUpdating.ToString());
Workbook workbook = Globals.ThisAddIn.Application.ActiveWorkbook;
Worksheet w = (Worksheet)workbook.Worksheets[1];
((Range)w.Cells[1, 1]).Value = "Test";
MessageBox.Show(excel.ScreenUpdating.ToString());
}
On my machine, opening Excel gives three message boxes saying
"True", "False", "False".
On the test machine they say
"True", "False" and "True".
I've also stepped through with a remote debugger and watched the ScreenUpdating property change immediately after the cell value is set. Further, this isn't the only thing that resets ScreenUpdating. Adding or removing a Worksheet or Workbook will also do this.
The Excel version on each system is the same (14.0.6112.5000 (32-bit)).
What could be causing this? How can I fix it so that Excel respects my settings?
I am experincing the same problem with ScreenUpdating (and other settings) being reset to true by the Bloomberg add-in with VSTO add-in. Their support are working on a solution but in the meanwhile the following solution works ok:
By hiding each sheet when interacting with its cells the screen won't update and you'll get the performance benefits. Make sure to not try to hide the last sheet as it will raise an error. Not sure if this is suitable for your project but it is a workable solution for mine.
Here is some example code in VB.NET to hide a sheet:
' Create a book with a single worksheet
Dim Book As Excel.Workbook
Book = Globals.ThisAddIn.Application.Workbooks.Add(Excel.XlWBATemplate.xlWBATWorksheet)
'% Create sheet variable
Dim Sheet As Excel.Worksheet
Sheet = TryCast(Book.ActiveSheet, Excel.Worksheet)
' Visible
Sheet.Visible = Excel.XlSheetVisibility.xlSheetVisible
' Hidden but user able to show
Sheet.Visible = Excel.XlSheetVisibility.xlSheetHidden
' Hidden for user as well
Sheet.Visible = Excel.XlSheetVisibility.xlSheetVeryHidden
Other addins in Excel can interfere with that single global setting.
It is for that reason you are supposed to save the current ScreenUpdating state to a local variable before, and restore it after, each use.
Ignore the changing of that setting in the ThisAddIn_Startup event (as you would not normally do your work there anyway).
If an add-in is interfering with your ScreenUpdating somehow, you can stop them form doing it by disabling events temporarily. using EnableEvents. It is possible that this will break the functionality of that addon, but it worked fine for my needs.