You are on page 1of 14

Sign in

C# Frequently Asked Questions


The C# team posts answers to common questions and describes new language features Search Blogs

Advanced search options...

Search In: Date range: Search Search this blog Options Blog Home Email Blog Author Send to friend RSS for Posts Atom RSS for Comments Search all blogs

Tags

.NET Framework .NET Framework 3.5 .NET Framework 4 C# C# 2.0 C# 3.0 C# 4.0 C# compiler C#/VB.NET Equivalents debugger debugging DLR dynamic dynamic language runtime expression trees IDE

parallel-processing parallel-programming reflection Task Parallel Library Tips TPL Visual Studio Visual Studio 2010 WPF

Archive Archives November 2010 (1) October 2010 (1) September 2010 (1) August 2010 (1) July 2010 (2) June 2010 (2) May 2010 (1) April 2010 (2) March 2010 (1) February 2010 (1) January 2010 (2) November 2009 (1) October 2009 (2) September 2009 (1) March 2009 (1) January 2009 (1) October 2006 (2) March 2006 (3) February 2005 (1) December 2004 (4) November 2004 (1) October 2004 (15) August 2004 (3) July 2004 (3) June 2004 (1) May 2004 (8) April 2004 (4) March 2004 (36)

Converting a VBA Macro to C# 4.0

Converting a VBA Macro to C# 4.0


Alexandra Rusina 27 Sep 2010 5:30 PM Comments 17 I've talked a lot about improved COM interop in C# 4.0 and how much easier it is now to work with Office applications. This time I want to share some tips and tricks on how you can convert Visual Basic for Applications (VBA) macros to C# 4.0 by using Office 2010 and Visual Studio 2010. You can either watch a video or read this post: its the same scenario and the same code, only I tried a different medium this time. If you for some reason decide to take a look at both, let me know which one you liked more and why. One common scenario for people working on Office applications is to record a macro in Office and then use the results in their code. It's often much faster and easier than looking up all the methods and properties. To try this out, record a macro in Excel 2010: create a new workbook, fill a column with numbers from 1 to 10 by using the Auto Fill feature, change the color of the column, and then create a simple graph.

Here's the VBA macro you'll get as a result: Sub Macro1() ActiveCell.FormulaR1C1 = "1" Range("A2").Select ActiveCell.FormulaR1C1 = "2" Range("A1:A2").Select Selection.AutoFill Destination:=Range("A1:A10"), Type:=xlFillDefault

Range("A1:A10").Select With Selection.Interior .Pattern = xlSolid .PatternColorIndex = xlAutomatic .ThemeColor = xlThemeColorAccent1 .TintAndShade = 0.399945066682943 .PatternTintAndShade = 0 End With Range("A1:A10").Select ActiveSheet.Shapes.AddChart.Select ActiveChart.ChartType = xlConeColStacked ActiveChart.SetSourceData Source:=Range("Sheet1!$A$1:$A$10") End Sub Now open Visual Studio 2010, create a new project, and add this reference to the project: Microsoft.Office.Interop.Excel. Then copy the VBA script inside the following code:

using Excel = Microsoft.Office.Interop.Excel; class Program { static void Main(string[] args) { var excelApp = new Excel.Application(); excelApp.Workbooks.Add(); // Insert VBA code here. excelApp.Visible = true; } }

Of course, the VBA code is all highlighted as an error. Here are the steps that you can use to convert that code into C# code: 1. In this macro, all the objects are in fact properties of the Excel application object. Basically, you need to add excelApp to the beginning of each line. Press ALT and select an area at the start of the lines, as shown here:

2.

Now type excelApp. and notice that it appears at the start of all the lines at once. You can use the same trick to add Selection.Interior to all the lines in the With block. Then delete the first and the last elements of the block (With and End With).

3. For all the Range objects, you need to replace the parentheses with square brackets. This
is because in C# you need to use indexed properties, and their syntax requires, well, square brackets. In this piece of code all of the parentheses should become square brackets, so

you can use the Find and Replace feature. (The keyboard shortcut for this is Ctrl + H.)

4. The next step is to replace the syntax for the named parameters. VBA uses the ":=" operator,
while in C# 4.0 it's simply ":". Once again, simple find and replace can help. 5. Now you need to add semicolons to each line, and add parentheses after each method call. You could probably find a converter that would do this for you, but here you have such a small piece of code that you can do it manually. Update: You can use the multi-line editing for adding semicolons as well. You can select a column in a so-called virtual space, where no characters were typed in.

So, you can type several semicolons at once and then reformat the document. Thanks to Jan B and David Nelson for the tip.

6.

Lets take a look at the code once again.

7.

The last thing to fix is the constants. Press Ctrl+Alt+J to open the Object Browser, and then search for each constant. You should find a class that contains this enumeration:

All you need to do is to add the name of the class to the beginning of the constant.

excelApp.Selection.AutoFill( Destination: excelApp.Range["A1:A10"], Type: Excel.XlAutoFillType.xlFillDefault);


Thats it. Now you can compile and run the program and get exactly the same picture that you saw at the beginning of this post. Here's the final version of this little program.

using Excel = Microsoft.Office.Interop.Excel; class Program { static void Main(string[] args) { var excelApp = new Excel.Application(); excelApp.Workbooks.Add(); excelApp.ActiveCell.FormulaR1C1 = "1"; excelApp.Range["A2"].Select(); excelApp.ActiveCell.FormulaR1C1 = "2"; excelApp.Range["A1:A2"].Select(); excelApp.Selection.AutoFill( Destination: excelApp.Range["A1:A10"], Type: Excel.XlAutoFillType.xlFillDefault); excelApp.Range["A1:A10"].Select(); excelApp.Selection.Interior.Pattern = Excel.Constants.xlSolid; excelApp.Selection.Interior.PatternColorIndex = Excel.Constants.xlAutomatic; excelApp.Selection.Interior.ThemeColor = Excel.XlThemeColor.xlThemeColorAccent1; excelApp.Selection.Interior.TintAndShade = 0.399945066682943; excelApp.Selection.Interior.PatternTintAndShade = 0; excelApp.Range["A1:A10"].Select(); excelApp.ActiveSheet.Shapes.AddChart.Select(); excelApp.ActiveChart.ChartType = Excel.XlChartType.xlConeColStacked; excelApp.ActiveChart.SetSourceData(Source: excelApp.Range["Sheet1! $A$1:$A$10"]); } } excelApp.Visible = true;

If you've read all that and still feel like you missed some steps, watch the video: How Do I: Convert Visual Basic for Applications Macro to C# 4.0 P.S. Thanks to Mads Torgersen and Alex Turner for reviewing this and providing helpful comments, to Mick Alberts for editing.

17 Comments

IDE, Tips, Visual Studio 2010, C# 4.0, C#, Visual Studio, VBA, Visual Basic for Applications

Comments

Jan B 27 Sep 2010 6:59 PM Re: Adding semicolons at the end of each line. Alt-select works for this, too.

Alexandra Rusina 29 Sep 2010 12:54 PM @ Jan B I might be missing something, but as far as I know, block selection works in straight lines only. Since line endings do not form a straight line (do not belong to the same column), the block selection feature would be of a little help there.

PP 29 Sep 2010 10:14 PM Does this also work with VS 2008 as well? I'll make some time to try it out later.

Alexandra Rusina 29 Sep 2010 11:52 PM @PP No, it doesn't work in VS 2008. Indexed properties, named and optional parameters, etc. were all introduced in C# 4.0. The multi-line editing is also VS 2010 feature.


1 Oct 2010 4:56 AM

Gustavo Amanai

Muito bom esse tutorial de como converter o VBA macro para C#.

Alexandra Rusina 1 Oct 2010 10:13 AM @ Gustavo It took me a while to understand what language is that. But now I can say "Obrigado" :-)

4 Oct 2010 8:47 AM

David Nelson

Re: Adding semi-colons at the end of each line: Block selection works in virtual space, so you can create a block selection beyond the end of the longest line, add the semi-colon, then format the document to move all of the semi-colons to the end of their respective lines.

Alexandra Rusina 4 Oct 2010 9:53 AM @David Yes, your are right. Thanks. I'll add it to the post. Unfortunately, it is much harder to change the video.

7 Oct 2010 6:10 AM Hi Alexandra,

Michael Sevestre

Properly releasing COM Handles in C# 3.5 and below is a tricky business. As you know, the difficulty derives from the fact that .NET is calling the Excel object model through the COM Interop.

var range =_excelApp.Workbooks[1].Cells[1,5] would leak three COM handles (the workbook collection handle, the Workbook handle and the Cells collection handle). It was necessary in C#3.5 to create a local variable for each handles and release them EXPLICITLY with Marshal.FinalReleaseComObject(). As you can imagine, it is really really frustrating Is it still necessary in .NET 4? As the management of Interop assembly objects been improved? Otherwise, your code, as neat as it is, will leak.

7 Oct 2010 11:15 PM @Michael,

Misha Shneerson

I do not necessarily agree with you that you have to call Marshal.ReleaseComObject on EVERY COM interop handler. It is one possible technique.which is extremely frustrating. The other easier way is just to place a call to. GC.Collect(). GC.WaitForPendingFinalizers() which will collect the unrooted references. The advantage here is that you can strategically place such calls at the end of large operations with COM objects and this will cause all such temporary unrooted handles to be released. Usually, for small programs like above it is done before closing the workbook/applicaiton itself and usually this technique works well. Usually there is always an argument whether calling GC.Collect is a good programming technique and some people are shying away from using it... IMHO though this is a tool that is available which one can use (but know not to use it too often). .NET 4.0 does have some improvements in the general area of reference counting for COM objects but not something that would help in the above sample. The improvements has to do with managing references to COM objects that are passed to event handlers as event arguments (if you are curious this is the relevant post blogs.msdn.com/.../better-eventing-support-in-clr-4-0-using-nopia-support.aspx) and you would only get these improvements if you use "Embed Interop Types" option when referencing Interop assemblies (fwiw, in the referenced post, codename NoPIA == "Embed Interop Types") Generally marrying mark-and-sweep garbage collectors (.NET) with reference counting systems is an extremely hard problem and the status of this problem has been quite well described by Brian Harry about 10 years ago www.socalnetug.org/.../determ_final.htm Hope this helps, Misha

Alexandra Rusina 8 Oct 2010 12:22 PM Thanks, Misha!


27 Oct 2010 2:43 AM

pam

i'm a beginner of C#,so this is helpfull for me

27 Oct 2010 2:43 AM

pam

i'm a beginner of C#,so this is helpfull for me

9 Nov 2010 8:31 PM

vardhman jain

i am facing some problem in converting the following block (VBA CODE) into c#. Please Help! With Selection.find .Text = "^p" .Replacement.Text = "" .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False End With

R`s VARDHMAN JAIN Broadridge

prabhash 22 Nov 2010 4:26 AM Better to use dymamic object in c# instead of refereing the excel library. And use activator to create the Excel.application class

Alexandra Rusina 22 Nov 2010 6:23 PM @prabhash First of all, using the new dynamic feature doesn't mean that you don't need libraries anymore. You still have to reference the Excel library all the same. Second, the dynamic feature is often used implicitly in COM interop in C# 4.0 - the interfaces that returned "object" before now return "dynamic". I am not sure about "activator". Why do you think it's better? MSDN examples usually use the Application() method: msdn.microsoft.com/.../dd264733%28VS.100%29.aspx

Patrick 23 Nov 2010 5:38 AM whats the benefit of using C# to replace VBA? Can you distribute an Excel workbook with 'macros' written this way?

Leave a Comment

Name

Comment Post

MSDN Blogs > C# Frequently Asked Questions > Converting a VBA Macro to C# 4.0

2010 Microsoft Corporation. Terms of Use Trademarks Privacy Statement Report Abuse

You might also like