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?
Related
I have a program that reads some data from a website, then clicks a link on that website and reads data again from the new site after navigation.
Everything works fine as long as the program is started with admin rights. The problem occurs when I start the program without admin rights. Here is some code:
void ReadHTML(string url)
{
try
{
InternetExplorer ie = new InternetExplorer();
IWebBrowserApp wb = (IWebBrowserApp)ie;
wb.Visible = false;
wb.Navigate(main.pathHcmOverview, null, null, null, null);
while (wb.Busy) ; // Here the program crashes already with exit code 0x800706ba
HTMLDocument doc = (HTMLDocument)wb.Document;
// Do something with the doc [I cut the code here as it is not relevant for the problem]
wb.Quit();
}
catch (Exception err)
{
}
}
The navigation command works, but the next command throws an error: "RPC Server not available - 0x800706ba".
Now my question: Can I use the code above only with admin rights? I did not find any information on that yet.
And if so, is there an alternative to accomplish my goal without admin rights?
I was able to resolve the problem by changing the following line
InternetExplorer ie = new InternetExplorer();
into
InternetExplorerMedium ie = new InternetExplorerMedium();
Tests worked fine after that. I will read into the documents now about the exact differences between those two.
We have a WPF application need to display a new Outlook item, allow user to edit before send. The application start with administrator privileges, so if user's Outlook opened already, then there's an error when getting Outlook instance. How to solve it? Please help me, thanks.
You can't automate Outlook if it is run under different security context. But you can detect such cases trying to get an Outlook instance using the Marshal.GetActiveObject method which obtains a running instance of the specified object from the running object table (ROT). For example:
Outlook.Application GetApplicationObject()
{
Outlook.Application application = null;
// Check whether there is an Outlook process running.
if (Process.GetProcessesByName("OUTLOOK").Count() > 0)
{
// If so, use the GetActiveObject method to obtain the process and cast it to an Application object.
application = Marshal.GetActiveObject("Outlook.Application") as Outlook.Application;
if(application == null)
MessageBox.Show("You need to run Outlook under the same security context");
}
else
{
// If not, create a new instance of Outlook and log on to the default profile.
application = new Outlook.Application();
Outlook.NameSpace nameSpace = application.GetNamespace("MAPI");
nameSpace.Logon("", "", Missing.Value, Missing.Value);
nameSpace = null;
}
// Return the Outlook Application object.
return application;
}
So, when the Outlook.exe process exists and you can't get the object all you can do is to ask users to run the application under the same security context.
There isn't much you can do short of starting your app in the same security context.
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.
I'm writing an application which works with excel files.
I need a feature to delete a sheet.
I have to use an assembly Microsoft.Office.Interop.Excel.dll.
It's running fine on developer machine but when I try to deploy it on server I'm getting an error:
Could not load file or assembly 'office, Version=14.0.0.0,
Culture=neutral, PublicKeyToken=71e9bce111e9429c' or one of its
dependencies
I understand that problem occurs when MS Office is not installed on a machine.
Customer don't want to install and buy MS Office on a server not at any price.
I install "Redistributable Primary Interop Assemblies" on developer machine as advised here: http://forums.asp.net/t/1530230.aspx/1
and compile my project again.
Code sample:
public bool DeleteSheet(string tableName)
{
Excel.Application app = null;
Excel.Workbooks wbks = null;
Excel._Workbook _wbk = null;
Excel.Sheets shs = null;
bool found = false;
try
{
app = new Excel.Application();
app.Visible = false;
app.DisplayAlerts = false;
app.AlertBeforeOverwriting = false;
wbks = app.Workbooks;
_wbk = wbks.Add(xlsfile);
shs = _wbk.Sheets;
int nSheets = shs.Count;
for (int i = 1; i <= nSheets; i++)
{
Excel._Worksheet _iSheet = (Excel._Worksheet)shs.get_Item(i);
if (_iSheet.Name == tableName)
{
_iSheet.Delete();
found = true;
Marshal.ReleaseComObject(_iSheet);
break;
}
Marshal.ReleaseComObject(_iSheet);
}
if (!found)
throw new Exception(string.Format("Table \"{0}\" was't found", tableName));
_wbk.SaveAs(connect, _wbk.FileFormat, Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange,
Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
}
finally
{
_wbk.Close(null, null, null);
wbks.Close();
app.Quit();
Marshal.ReleaseComObject(shs);
Marshal.ReleaseComObject(_wbk);
Marshal.ReleaseComObject(wbks);
Marshal.ReleaseComObject(app);
}
return true;
}
An exception
Retrieving the COM class factory for component with CLSID
{00024500-0000-0000-C000-000000000046} failed due to the following
error: 80040154 Class not registered (Exception from HRESULT:
0x80040154 (REGDB_E_CLASSNOTREG)).
occurs on the line
app = new Excel.Application();
Can anyone advise on how to get this feature working successfully?
You can't use Microsoft.Office.Interop.Excel without having ms office installed.
Just search in google for some libraries, which allows to modify xls or xlsx:
http://code.google.com/p/excellibrary/
http://simpleooxml.codeplex.com/ (only xlsx)
If the "Customer don't want to install and buy MS Office on a server not at any price", then you cannot use Excel ... But I cannot get the trick: it's all about one basic Office licence which costs something like 150 USD ... And I guess that spending time finding an alternative will cost by far more than this amount!
you can create a service and generate excel on server and then allow clients download excel.
cos buying excel license for 1000 ppl, it is better to have one license for server.
hope that helps.
Look for GSpread.NET.
You can work with Google Spreadsheets by using API from Microsoft Excel.
You don't need to rewrite old code with the new Google API usage. Just add a few row:
Set objExcel = CreateObject("GSpreadCOM.Application");
app.MailLogon(Name, ClientIdAndSecret, ScriptId);
It's an OpenSource project and it doesn't require Office to be installed.
The documentation available over here http://scand.com/products/gspread/index.html
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.