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;
Related
I'm trying to modify and saving a normal.dotm template programmaticly with a Word COM AddIn in C#. I'm using the following code:
Template template = m_Application.NormalTemplate;
m_Application.CustomizationContext = template;
DoStuffWithTemplate();
template.Save();
This works absolutly fine... But, if the word template path is not at the default location on harddisk, but rather on a network disk, it will fail with the following exception:
System.Runtime.InteropServices.COMException (0x800A176B)
Works fine:
C:\Users\...\Templates\Normal.dotm
Throws Exception:
\\XYZ\Templates\Normal.dotm
I added the network path to the trusted locations inside the word trust center, but it still didn't work. I also run the application as administrator...
I'm using Word 2016, but the error occures also on Word 2010.
Thanks for your help!
edit:
Now I use the following work-around, but the changes are obviously only temporary now:
Template template = m_Application.NormalTemplate;
m_Application.CustomizationContext = template;
DoStuffWithTemplate();
if (template.FullName.StartsWith("\\\\"))
{
if (!template.Saved)
{
template.Saved = true;
}
}
else
{
template.Save();
}
I am trying to set the print margins in a Word Doc I am printing from my c# application but I am having trouble accessing the methods that I need to call (based on what they are in MS Word VBA)
In VBA the code looks like this:
Options.printBackground = False
With ActiveDocument.PageSetup
.TopMargin = CentimetersToPoints(0.61)
.BottomMargin = CentimetersToPoints(0.43)
.LeftMargin = CentimetersToPoints(1.27)
.RightMargin = CentimetersToPoints(0.43)
.Gutter = CentimetersToPoints(0)
End With
Here is my c# code
oWordDoc.PageSetup.TopMargin = Microsoft.Office.Interop.Word.Application.CentimetersToPoints(float.Parse ("0.61")) ;
The error I am getting is:
An object reference is required for the non-static field, method, or property 'Microsoft.Office.Interop.Word._Application.CentimetersToPoints(float)'
I have tried several varaiations after searching the VS 2010 Object Browser for CentimetersToPoints
The available interfaces in the Object Browser are:
Microsoft.Office.Interop.Word._Application.CentimetersToPoints(float)
Microsoft.Office.Interop.Word.ApplicationClass.CentimetersToPoints(float)
Microsoft.Office.Interop.Word._Global.CentimetersToPoints(float)
Microsoft.Office.Interop.Word.GlobalClass.CentimetersToPoints(float)
how can I access methods like this?
thanks
As the error message indicates, you need a reference to the Word.Application object to access this method, since it is not static.
I guess you have a oWordApp somewhere that you use to create or open the oWordDoc, so you can access the method from this object.
Or you can retreive the instance of the Word.Application from your oWordDoc (Word.Document) object.
oWordDoc.PageSetup.TopMargin = oWordDoc.Application.CentimetersToPoints(float.Parse("0.61"));
I have c# code behind my Excel-dna addin which is successfully downloading data from a service. I have created a ribbon in Excel-dna with a button which triggers the download, and now I want to display the data in a new worksheet. How do I create a worksheet and add rows?
I tried calling xlcWorkbookInsert from my c# code using:
ExcelReference newSheet = (ExcelReference)XlCall.Excel(XlCall.xlcWorkbookInsert, 1);
but I always get a ExcelDna.Integration.XlCallException exception. Is this the correct approach, or is there a simpler way to go about doing this?
I also tried pasting an object[,] of data to an existing sheet:
ExcelReference sheet1 = (ExcelReference)XlCall.Excel(XlCall.xlSheetId, "Sheet1");
ExcelReference myTargetPasteArea = new ExcelReference(1, 1, 2, 10, sheet1.SheetId);
myTargetPasteArea.SetValue(result);
There are no errors this time, but nothing happens (although I can see the code being executed when I step through in debug).
Your code is calling to Excel via the C API (that's how the XlCall.Excel(...) and ExcelReference stuff in Excel-DNA works). But you can't call the C API directly from your ribbon event handler. You have two options:
Make a detour via a macro. This is easy if you change your ribbon xml code:
<button onAction="RunTagMacro" tag="MyMacro" />
and then define a macro:
public static void MyMacro()
{
// ... do your work here ....
}
You can also call the macro yourself from the event handler - the RunTagMacro internally just calls
object app = ExcelDnaUtil.Application;
app.GetType().InvokeMember("Run", BindingFlags.InvokeMethod,
null, app, new object[] { control.Tag }, new CultureInfo(1033));
Another option is to change your interaction code to use the COM API. For this you'll need to use the 'dynamic' support in .NET 4, or reference an interop assembly - either the version-specific Primary Interop Assemblies for Office, or some version-independent interop assemblies like NetOffice.
XlCall.Excel(XlCall.xlcWorkbookInsert, 1);
returns a bool: true - success, false - failure
So casting it to ExcelReference is the cause of the exception.
You may need an xlcNew before that xlcWorkbookInsert. Take a look in the Excel-Dna source at the GetApplication method in Excel.cs.
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
Just after a little help with late binding.
I am trying to late bind excel and i don't have any issues doing that. It is only when I have more than one instance of excel open where I run into some problems.
I would like to be able to determine what instance of excel to bind to (and the link events etc.). Main reason being I have an application that opens a excel document from a third party tool and the events aren't handled. I want to be able to tap into the particular excel instance that I know is open to catch the events. Only problem is if excel is already open by the user (doesn't matter how).
If excel is opened after the bind, obviously, I don't get a problem. It is only when excel is already open.
It seems that the binding is done to the first instace that is open.
Here is the actual code:
Type excelType = Type.GetTypeFromProgID("Excel.Application");
// Throw exception if the type wasn't found
if (excelType == null)
throw new Exception(error);
//Get the Excel.Application Type by creating a new type instance
excelApplication = Marshal.GetActiveObject("Excel.Application");
//Throw exception if the object couldn't be created
if (excelApplication == null)
throw new Exception(error);
this.withEvents = withEvents;
//Create link between the Word.Applications events and the ApplicationEvents2_WordEvents class
if (this.withEvents)
{
excelEvents = new ExcelApplicationEvents();
//holds the connection point references of the Word.Application object
IConnectionPointContainer connectionPointContainer = excelApplication as IConnectionPointContainer;
//Find the connection point of the GUID found from Red Gate's .Net Reflector
Guid guid = new Guid("00024413-0000-0000-C000-000000000046");
connectionPointContainer.FindConnectionPoint(ref guid, out connectionPoint);
//Advise the Word.Application to send events to the event handler
connectionPoint.Advise(excelEvents, out sinkCookie);
excelEvents.WorkbookBeforeSaveEvent += new EventHandler<WorkbookEventArgs>(ExcelEventsWorkbookBeforeSaveEvent);
}
Any Ideas?
Cheers,
Dale.
Getting a particular instance of Excel requires that you make use of the AccessibleObjectFromWindow API.
This is explained well in the article Getting the Application Object in a Shimmed Automation Add-in by Andrew Whitechapel.
What you want, however, is to execute it using late binding. This is described in detail by divo here: How to use use late binding to get excel instance.