Translating a VBA call into C# in an Excel add-in installer - c#

My Excel addin is written in C#, but the installer makes a call to Excel through a VBA macro. I want to get rid of VBA.
I wonder what the following VBA does to the registry. From what I see, it adds a value in HKCU\Software\Microsoft\Office\14.0\Excel\Options. Is that it?
Dim MyXLL As AddIn
Set MyXLL = Application.AddIns.Add(addinFile)
If (Not MyXLL Is Nothing) Then
MyXLL.Installed = True
Else
MsgBox "Failed to add XLL"
End If

You should try using excel interop from c#, instead of modifying the registry directly, which could lead to a nightmare (seriously). Also you would have to deal with different versions of office, etc.
Adding a addin via interop:
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.addins.add(v=office.11).aspx
Installing the addin after added:
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.addin.installed(v=office.11).aspx

Using the Addins method from VBA or automation/interop is probably the easiest method but makes it difficult to handle the situation of more than one version of Excel installed on a PC. A more comprehensive solution involves an install script writing OPENn keys (where n is 1 greater that highest current OPENn key) for each Excel version you want to install for, and reversing these actions in the uninstall script (you would also need to rewrite other OPENn keys that are higher than the OPENn key of your XLL).You can find an example script using LUA for Setup Factory here http://www.jkp-ads.com/articles/AddinsAndSetupFactory.asp

Related

How do I get a reference to MS Access in .Net Core 3.0?

I'm looking for some help. I am in need of figuring out how to get an object reference to Microsoft Access 2013 so that I can (through Automation) call some of the already defined functions in the accdb. For instance; I want to automate the process of "RelinkODBCTables" function which repoints the linked tables to another data source from my .net core 3.0 c# application.
I've not been able to successfully get a reference to interop but I may not be doing it correctly.
Any help would be greatly appreciated.
D-
If you want to
Create a instnce of Access.
Call a VBA sub (say your relink code).
Close the the database.
quit access.
You could use this code:
{
object AccessApp;
AccessApp = Interaction.CreateObject("Access.Application");
AccessApp.OpenCurrentDatabase(#"c:\test\test44.accdb");
AccessApp.Run("MyLinker");
AccessApp.CloseCurrentDatabase();
AccessApp.Quit();
}
So, you don't need any referance at all. Just create a instance of the given applicatin (word, Excel or as per above Access).
At that point, you have full use of the object model, and can use run to call some VBA routine. In above, we call a VBA Sub called MyRelinker.
About the only caution here is that when you create the instance of that object, then all startup code of the application will run. So, if on startup the forms and UI that the developer of the Access program launches any prompt, then you can't "answer" that prompt. So, how well this works will VERY much depend on how nice the application plays on startup, and that calling any of those VBA routines does not trigger some kind of prompt(s) in that Access application. If it does, then you in trouble, since you can't "answer" any of the forms or code prompts that access may very well throw up at the end user.
And, if you do want some "inteli-sense" during coding, then you can add a office "interop" reference to your project. Its not required, but if you not really fluent in the Access VBA + object model, then in place of CreateObject("Access.Application"), if you do referance the office assemby, say this one:
Microsoft.Office.Interop.Access
C:\Program Files (x86)\Microsoft Visual Studio 12.0\
Visual Studio Tools for Office\PIA\Office14\
Microsoft.Office.Interop.Access.dll
Then you code becomes this:
{
Microsoft.Office.Interop.Access.Application AccessApp =
new Microsoft.Office.Interop.Access.Application();
AccessApp.OpenCurrentDatabase(#"c:\test\test44.accdb");
AccessApp.Run("MyLinker");
AccessApp.CloseCurrentDatabase();
AccessApp.Quit();
}
However, while you get stronger typing with the reference, you often will "tie" you code to a given version of Access, and a simple use of CreateObject() quite much means that you can create a instance of Any Access installed on the target computer, and it should work going back all the way to office 2000 - a good 20 years of "coverage".
Keep in mind that you CAN NOT create a instance of the Access runtime, the target computer will requite a full version to "create" a instance of the Access.Application object.
You "can" automate the runtime version. This involves launching Access runtime (via Shell()), and then grabbing an instance with "GetObject()" in place of CreateObject().
Edit
I should point out that in the 2nd above code example, and using the office interop-assembly reference, I choose office 14, which is office 2010. In your case, you have to use office 15 (2013).

Exclude office.interop if MS office not installed

My problem is my program crashes at run when it is opened by a computer that does not have office installed.
I am writing a program where that will be run by multiple users on different computers. Some users computers will have MS office installed, others will not. It is a multi-form program and for ease of reference can be thought of like an ERP type software.
I have included Microsoft.Office.Interop.Excel and Microsoft.Office.Interop.Outlook in the program references. Certain sub forms within my application use both excel and outlook functionality, however many do not.
I would like both users who have and do not have office installed to be able to run the program. Perhaps if they do not have office installed they receive an error stating that they do not if they were to click a button that would normally export an excel spreadsheet of data.
Is there any way to achieve this?
I would like to avoid third party libraries, having to install office on all computers as it will not be needed on those workstations, I would also like to manage one program and not have two separate programs to manage which would share forms and functionality.
With the restrictions mentioned - no third party libraries, no office on some user machines, and no 2 versions of the program // Read the Excel files as datasource into the program and deal with the data that way. For where you mentioned "export an Excel Spreadsheet" you can use ODF/ODS.
I setup a new form and tested out what specifically in my application was causing my program to crash. I found out that including the office references does not cause a problem. Also adding using Microrosoft.Office.Interop.Excel; does not cause a problem.
However I was calling a Class in my main program that that created Excel application's, workbooks and worksheets, despite not actually using those items on program load. An example of a local variable in the class that likely caused the problem was private Excel.Application XLApp = new Excel.Application();.
I will probably use a solution like #Jcl suggested before allowing a user to run anything that may crash the program on them.

Scripting Word doc from external app

I'm trying to automate a tedious process that currently involves launching Word, Creating a new document from a .dot, saving it, running one or two plug-ins that were written in C# using VSTO, saving it again, exiting the document, and exiting Word.
I want to write a C# commandline app that the user can launch with one or two args (conveying all the information that would normally require interaction with dialogs in Word), then walk away from as it runs without further interaction... suppressing any and all focus-stealing by Word while it's running if necessary and possible.
Is there some straightforward way to accomplish this? Here's a Java-like pseudocode example of what I have in mind:
// magic to non-interactively launch Word and expose it as an object
WordHost word = xx;
// create new Word document based on a specific template that isn't the default one.
WordDocument doc = MSWord.create("z:\path\to\arbitraryTemplate.dot");
// If we can avoid physically saving it at this point and just assign a concrete
// file path, it would be even better because the network is glacially slow.
doc.saveAs("z:\path\to\newDoc.docx");
// someZeroArgPlugin and aTwoArgPlugin are VSTO plugins written with C#
doc.someZeroArgPlugin();
doc.aTwoArgPlugin("first", "second");
// done!
doc.save();
doc=null;
word=null; // something like word.unload() first?
// now do more things that don't involve Word directly...
Assuming I'm on the right track...
I'm pretty sure I can find most of what I need to know by searching... once I figure out what I need to be searching for. What should I be searching for?
What kind of project do I want to be creating in Visual Studio? A .net 4.5 C# console application? A Word 2010 Add-In? Some other kind of project?
Details that might or might not make a difference:
my program will only be run on computers that have Word 2010 installed. Compatibility with older versions isn't necessary.
It would be nice if it can run under Vista, but it only has to work under Win7.
I have Visual Studio Ultimate 2012
Here's what you'll need to do:
Have Visual Studio and Office installed.
Create a C# console project using the .NET framework of your choice (recommend 4.0 or above).
Add a reference to the Word COM library (Project menu => Add Reference, COM tab, Microsoft Word XX.0 Object library -- Word 2010 is 14.0).
Set the Embed Interop Types setting to false for the references added above
Expand References in Solution Explorer
Select Microsoft.Office.Core, Microsoft.Office.Interop.Word and VBIDE
Right-click and select Properties to bring up the Properties panel for the references.
In the Properties panel, set Embed Interop Types to False
Code away.
Here's some sample code.
using System;
using Microsoft.Office.Interop.Word;
namespace CSharpConsole
{
static class Program
{
[STAThread]
static void Main()
{
var application = new ApplicationClass();
var document = application.Documents.Add();
document.SaveAs("D:\test.docx");
application.Quit();
}
}
}
For more information, see http://msdn.microsoft.com/en-us/library/office/ff601860(v=office.14).aspx

Writing and Executing VBA Macros on Excel without using Excel.Interop [duplicate]

This question already has answers here:
How to inject VBA code into Excel .xlsm without using Interop?
(2 answers)
Closed 7 years ago.
Scope:
I am generating automated reports using excel, but since we have restrictions on our server, we can't install Excel.Interop or use any COM object to perform such action.
We have been using EPPLUS as our main helper on this task but it has some serious restrictions when it comes to more intricated things such as PivotCharts and Macros.
We have just finished the project, missing only the PivotCharts since EPPLUS has no support for them.
Question:
How can we :
A) Write Macros to a .xlsm file? (We could write one named "Auto_Open" so that excel would run it uppon opening, creating the charts and stuff)
OR
B) Run a macro within our code to generate those charts after putting all the needed data there?
Not using Excel.Interop is a must at this moment. We are open for some suggestions such as
SpreadsheetGear and EasyXLS, but we can't find any sample or piece of code that actually shows how to Write or Run macros.
Thanks in advance
I realise this question is a bit old, but in the interest of helping future visitors I'll add that the current version of EPPlus (4.0.4 at time of writing) supports the inclusion of VBA.
Where excelDoc is your ExcelPackage, you can drop it in using something along the lines of:
excelDoc.Workbook.CreateVBAProject();
StringBuilder vbaCode = new StringBuilder();
vbaCode.AppendLine("Private Sub Workbook_Open()");
vbaCode.AppendLine(" Application.DisplayFormulaBar = False");
vbaCode.AppendLine("End Sub");
excelDoc.Workbook.CodeModule.Code = vbaCode.ToString();
Hope this helps.
Open Excel
Press Alt+F11
You will now be in the VBA IDE.
To run something on Auto Open:
Select ThisWorkbook From the VBAProject in Project Explorer on the Left of your screen
There are Two drop downs near the top of the window one will say (General) and The other (Declarations) click on (General) and select workbook
Excel should automatically bring you to the Open declaration.
Anything written in this sub will execute on open.
Rather than attempting to programatically write macros to an xlsm file, why don't you create a template that already contains the macros you want. Then generate your reports from this template.
When a user opens the report (and allows macros to run), then your macro will run and do the manipultations you want (your option A). Your Auto_Open macro could check some suitable condition (e.g. presence of a value in a specific location, perhaps on a VeryHidden sheet so the user can't easily interfere with it) before doing any work, so that it doesn't run when you open an "empty" template.
As for your option B (run the macro before providing the report to the user): this isn't feasible without Excel Automation.

Using Clipboard Copy Paste in Excel (VSTO code) freezes other Microsoft Office application

Operating System : Microsoft Windows SP1 (64 bit)
Office Suite : Microsoft Office 2010
.Net Framework : 4.0
Subject : Microsoft suites of applications (Word, Outlook) does not respond for the time slice when a excel plugin code is running
Details : We have written VSTO (in C#) based add-in for excel application. This add-in is used for refreshing data in current sheet.
Following steps of events occurs on click of a "Refresh" button
•A call is made to internal web service by passing some metadata to download a file
•File is downloaded and stored on windows Temp folder.
•A VSTO code is executed to copy data from downloaded sheet to current sheet using Clipboard Copy / Paste. Data is copied row by row.
At any point in time, we'll have one row of data in Clipboard. Also the number of rows and columns varies between request.
Issue: While refresh functionality is working as expected, we are experiencing issue with other Office suites applications (Word, Outlook).
For the time slice refresh is running, all Office suites of application stops responding.
Can some one help with this issue?
I think you can not control other office suites application. But what you can do is, try to decrease the time slice for refresh button By using different concept like
•A call is made to internal web service by passing some metadata to
download a file
•File is downloaded and stored on windows Temp folder.
I don't know for above two point whether you have used separate thread for that or not? If not use separate thread for that.
You can also use some Optimization trick while copy pasting data from one sheet to another.
Here are some tricks to optimize vba / vsto code
http://tchhabhaiya.blogspot.in/2012/06/17-ways-to-optimize-vba-code-for-faster.html
I think below code will help a lot to you if you haven't used this.
Application.ScreenUpdating = False //To Turn Off at the start of code.
Application.ScreenUpdating = True //To Turn on at the end of the code.

Categories