SQL job failed to run a C#.net console application - c#

I have a simple excel file that has the following code:
Private Sub Workbook_Open()
MsgBox "Hello World!"
End Sub
I tried to run a sql job to open this excel file but it failed, became unresponsive. On googling, I found the reason 'why' SQL job wouldn't open excel file
Job On Sql Server Agent does not complete, but it does in BIDS?
So I thought of creating a simple console application in C# which would simply open the excel file and run my macro. Here's my code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using System.Threading;
namespace T_OpenExcel
{
class Program
{
static void Main(string[] args)
{
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
//Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Open(#"E:\data_extracts\TestHelloWorld.xlsm", 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
RunMacro(xlWorkBook, new Object[] { "TestHello" });
Thread.Sleep(5000);
xlWorkBook.Close(true, misValue, misValue);
xlApp.Quit();
}
private static void RunMacro(Excel.Workbook xlWorkBook, object[] p)
{
//throw new NotImplementedException();
}
}
}
I could successfully run this code in IDE. Now I want to run this from SQL job in SSMS, sql server 2008.
I grabbed T_OpenExcel.exe file from my C# project( T_OpenExcel-->bin-->Debug-->T_OpenExcel.exe). I created a SQL Job.Here are some of my details:
Step name: OpenHelloWorldExcel
Type:Operating system(CmdExec)
Run as: SQL Server Agent Service Account
Command: C:\Users\shress2\Documents\visual studio 2010\projects\T_OpenExcel\T_OpenExcel\bin\Debug\T_OpenExcel.exe
On running this job, I get the following status
Start Job 'TestHelloWorld' Status Success
Execute job 'TestHelloWorld' Status Error
On viewing history, it shows:
Message
Executed as user: GSOPS4\SYSTEM. Unhandled Exception: System.Runtime.InteropServices.COMException: Microsoft Excel cannot access the file 'E:\data_extracts\TestHelloWorld.xlsm'.
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. at Microsoft.Office.Interop.Excel.Workbooks.Open(String Filename, Object UpdateLinks, Object ReadOnly, Object Format, Object Password, Object WriteResPassword, Object IgnoreReadOnlyRecommended, Object Origin, Object Delimiter, Object Editable, Object Notify, Object Converter, Object AddToMru, Object Local, Object CorruptLoad) at T_OpenExcel.Program.Main(String[] args) in C:\Users\shress2\documents\visual studio 2010\projects\T_OpenExcel\T_OpenExcel\Program.cs:line 23. Process Exit Code -532462766. The step failed.
I checked E:\data_extracts\TestHelloWorld.xlsm directory and found it working. I made sure my xlsm file is not being used by anyone. I couldn't figure out why its failing to run it. Any help is greatly appreciated. Thanks in adv!

The problem appears to be that you're attempting to show a messagebox while opening the Excel file, but you're automating it, so there's no human to click the button on the messagebox. The rest of the code can't execute because the file is sitting there waiting for someone to click the button.
On subsequent runs, the server can't access it because it's still sitting there, invisible to normal users, waiting for the button to be clicked. hence the errors.
Short version: Don't proompt for user input on an app that will be run unattended.

Related

Get excel filename and path error - C#

I am getting a very stupid error. I am new to VSTO and I need to get the location of the Excel file in some variable in my Addin.
string name = ActiveWorkbook.FullName;
I am getting a red line below ActiveWorkbook with error:
The name ActiveWorkBook does not exist in the current context.
I have added reference of Microsoft.Office.Interop.Excel in the code but its showing this error. I am new to this.. am I missing something?
In Excel VSTO, you need to use Globals.ThisAddIn.Application to get access to the Excel Application Model, see below :
var wb = Globals.ThisAddIn.Application.ActiveWorkbook;
string name = wb.FullName;
see also Programming VSTO Add-ins
If your code is inside the ThisAddIn class you can directly call: this.Application.ActiveWorkbook
ActiveWorkbook is not a class. It's the property of the Application interface. You can not call it in the class-name manner.
Then, you need to change your code to this.Application.ActiveWorkbook.FullName;

Trying to access excel COM object as admin user

The objective is to access the running Excel workbook in the machine. Intention is to close the respective workbook though this application which was opened by the user.
Achieved: I used the following code snippet to access the Excel COM object
Excel.Application instance = null;
try
{
instance = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
}
catch (Exception ex)//Excel not open
{
wasFoundRunning = false;
}
if (wasFoundRunning)
{
foreach (Excel.Workbook ss in instance.Workbooks)
{
string s = ss.Name;
}
}
Issue: Above code works only if the excel sheet and the application opened by the same user in the machine. I have to run the application as administrator and it fails. Exception as follows and it means that it cannot find any excel sheet running.
Exception: Operation unavailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))
It fails if I run my application elevated and user opens the sheet.
Any ideas to fix this?

Excel C# interop worksheet delete

I have an app using Excel COM interop. It copies a template XLS to an existing doc, replacing same-named tabs by Delete old then Copy new from template.
I am getting 800A03ec exception when my app tries to delete a worksheet.
This problem is in code that has been working for years but now fails after an upgrade to Office 2016.
I find that if I set app.Visible = true, the operation completes properly! But I do not want Excel visible.
If app.Visible = false, I do not get an error from the first worksheet Delete(), but exception occurs on the second.
The first delete of the last tab seems to go OK, but 'Sheets' array of the worksheets object doesn't decrease as I would expect. However the corresponding Sheet item in the array becomes a "null" worksheet.
The second delete, of the tab before it, throws an exception on delete.
I have thoroughly ensured:
No COM reference leaks
All COM references are discarded before each delete, except for the worksheet to be deleted and its parent app, etc. objects
DisplayAlerts is false
Worksheets are simple and ordinary, nothing hidden etc.
Why would it work when app is visible, but not work when app is hidden??
UPDATE: code fragment
int _DeleteTargetTab(string tabName)
{
List<object> comRefs = new List<object>();
int prevTabIndex;
int tabToDelete = _FindTargetTemplateIndex(tabName, out prevTabIndex);
if (tabToDelete > 0)
{
try
{
Excel.Sheets targetSheets = _workbook.Sheets;
comRefs.Add(targetSheets);
Excel.Worksheet targetWorksheet = targetSheets[tabToDelete];
comRefs.Add(targetWorksheet);
targetWorksheet.Delete();
}
finally
{
ExcelUtility.ReleaseAll(comRefs);
}
}
return prevTabIndex;
}
and ExcelUtility.ReleaseAll() calls Marshal.ReleaseComObject(), then GC.Collect() and GC.WaitForPendingFinalizers().
Target worksheet has 8 tabs. Last tab is deleted, then copied, without exception. Then on tab 7 delete throws an exception, only when app is hidden. Works fine on older Office.
Copy code is
void _CopyTemplateTabToTarget(Excel.Worksheet templateWorksheet, int prevTargetTabIndex)
{
List<object> comRefs = new List<object>();
try
{
Excel.Sheets targetSheets = _workbook.Sheets;
comRefs.Add(targetSheets);
Excel.Worksheet prevSheet = targetSheets[prevTargetTabIndex];
comRefs.Add(prevSheet);
templateWorksheet.Copy(Type.Missing, prevSheet);
}
finally
{
ExcelUtility.ReleaseAll(comRefs);
}
}
Init code is
_app = new Excel.Application();
_app.DisplayAlerts = false;
_app.Visible = false;
I got further by adding this:
//
// Super important to activate a tab other than what needs to be deleted.
// Cast is required because an event and method have the same name "Activate".
//
((Excel._Worksheet)_weeklyDataSheet).Activate();
Then that got me to some code around my apps' Save function that used to work but was throwing exception:
_weeklyDataSheet.Select(Type.Missing);
I changed that to Activate() as well and made more progress. But yet Excel still threw exception on Delete() this time on the third workbook.
I was forced to run app Visible for the week's report. But even that ran through about 80 workbooks and then Excel locked up, mouse cursor rapidly flashing between arrow and wait timer animation, and my app got RPC error eventually.
Conclusion: ABANDON COM APIS for Office 2016. Microsoft seems not to support them properly anymore.

Exception when calling RTD server from Excel

I wrote a VSTO Excel addin using Visual Studio 2010 and after having managed to work around most of the obstacles Microsoft throws into the path of the righteous developer, I finally have to admit defeat.
My project contains a Ribbon with some controls, a custom task pane that allows users to search a database via a RESTful interface and a RTD server that lets them put this data in their worksheets. So far, so ... well, painful, I guess: After a lot of struggle with Interop, ComVisibility and AppDomains (what a great idea!), my current status is as follows.
In the worksheets, I call a wrapper function for RTD like this (snipped):
Public Function call(value as String)
Dim addin as Office.ComAddIn
Set addin = Application.ComAddIns("MyAddin")
addin.Object.RTD(value)
End Function
This is (part of) the addin class:
namespace Some
{
[Guid("...")]
[ComVisibleAttribute(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class MyAddin {
[snip]
public String RTD(String value)
{
String returner = null;
try
{
returner = Globals.ThisAddin.Application.WorksheetFunction.RTD(SERVERID, "", value);
}
catch(COMException ce)
{
returner = ce.StackTrace;
}
return returner;
}
}
}
And the relevant part of the RTD Server class:
namespace Some
{
[Guid("...")]
[ComVisibleAttribute(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("MyRTDServer")]
public class Server : Excel.IRtdServer
{
[snip]
}
}
In Debug mode I:
Create a, empty new workbook
Add an "=RTD(...)" formula to a cell
Add a wrapper function call "=call(...)" to a cell
Save the workbook
Open the workbook
Stop Debugging and start it again
Open the workbook
I observe:
At 3, everything works fine
At 5, everything works fine
At 7, when recalculating my cells, I get a Unable to get the RTD property of the WorksheetFunction class exception in the cell of 3) and #N/A in the cell of 2). However, I can see that the topics are registered in the RTD server and as soon as the data is available, the exception is replaced with the correct data. Also, if I do NOT recalculate the cells, they display the saved value and then correctly update to the retrieved value once the data is available.
If in deployed mode, I observe:
At 2, I get #N/A
At 3, I get a Unable to get the RTD property of the WorksheetFunction class exception
Any help, please? :(
EDIT:
Testing the same procedure with a very basic RTD server in a blank Addin project shows exactly the same results: a loaded excel file displays #N/A if an RTD-formula is recalculated before the server has the data available.
I would like to inquire: WTF?
Cheers,
Che
The 'Unable to get the RTD property....' error is just the Excel object model's way of saying there was an error in the function call.
Does your RTD server have any dependencies on the rest of your add-in? The fact that 2) fails when deployed, makes it look like the RTD server needs some other bits to be initialized before it runs happily. The way the VSTO add-in is put together, your assembly is likely to be loaded totally separately for the RTD server and for the COM add-in, and in your problematic cases the RTD instance is loaded first.
Perhaps you can test with a sample RTD server instead of your own, just to confirm that the error is there and not in the wrapper or elsewhere in the VSTO add-in. Then you can dig into your RTD server to see what goes wrong.
-Govert
Excel-DNA - Free and easy .NET for Excel

How to use getActiveObject("Excel.Application")

I need to finish an application in C#.
Now I want to get a function that control a Excel file to get data.
I used getActiveObject("Excel.Application"), but this returns nothing. I can't use Excel.Application in VS2008, and Microsoft.Office.Interop.Excel.Application is used instead.
So is there another way to do this?
Microsoft.Office.Interop.Excel.Application e =
(Microsoft.Office.Interop.Excel.Application)Marshal.GetActiveObject(
"Excel.Application");
After about a half a day of playing around I finally figured out how to make this work so you can latch onto an open copy of excel. My users have been complaining mightily about having too many instances of Excel open.
Here is a snippet of what I did to get it working:
_Application excelApp;
try
{
excelApp = (_Application)Marshal.GetActiveObject("Excel.Application");
}
catch(Exception)
{
// this is important. If Excel is not running, GetActiveObject will throw
// an exception
excelApp = null;
}
if( excelApp == null )
{
excelApp = new ApplicationClass();
}
I have been chasing this for a while and finally had some time to hunker down and figure it out.
I also have been working on Excel Addins, in namespaces use
using Excel=Microsoft.Interop.Office.Excel;
instead of Microsoft.Interop.Office.Excel use the above line, for more understanding look at my code:
using System.IO;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.Office.Interop.Excel;
using static MMCAPP2010.Profile;
using System.Runtime.InteropServices;
namespace MMCAPP2010
{
public class ExcelTemplateLoad
{
public void DeserializeObject(string filename)
{
Excel.Application instance;
Workbook wb = null;
try
{
//getting the current running instance of an excel application
instance = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
}
catch
{
instance = new Excel.Application();
}
//opening the template
wb = instance.Workbooks.Open(#"C:\Users\U1152927\Downloads\sample.xltx");
In order to be able to refer to the Excel object model as "Excel", then you can create an alias via a using statement at the top of your namespace (or document) as follows:
using Excel = Microsoft.Office.Interop.Excel;
Thereafter, you can refer to Excel.Application instead of the long-winded Microsoft.Office.Interop.Excel.Application.
As for why your call to Marshal.GetActiveObject is failing, I can't say for sure. A couple of thoughts:
(1) Are you certain that there is a running instance of Excel already present? If not, then create a new Excel application:
Excel.Application xlApp = new Excel.Application();
(2) If there definitely is an Excel application already running, then it is possible that the Excel instance has not yet been added to the Running Objects Table (ROT) if the Excel Application has never lost focus. See: Visual C# .NET Error Attaching to Running Instance of Office Application for more on this. I believe that the Marshal.GetActiveObject method should throw an exception in this case -- not quietly return null -- but this still seems potentially relevant.
I hope this helps...
Mike
Please see the MS KB as given in the link below...
http://support.microsoft.com/kb/238610

Categories

Resources