3

I've got two .net-6 console-apps:

one in C#

using Excel = Microsoft.Office.Interop.Excel;

Console.WriteLine("Hello, World!");

var xl = new Excel.Application();
var wb = xl.Workbooks.Open(@"c:\temp\test-2.xlsx");

wb.Close(0);
xl.Quit();

System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xl);

wb = null;
xl = null;

the other one in VB.NET.

Imports System
Imports Excel = Microsoft.Office.Interop.Excel

Module Program
    Sub Main(args As String())
        Console.WriteLine("Hello World!")

        Dim xl = New Excel.Application()
        Dim wb = xl.Workbooks.Open("c:\\temp\\test-2.xlsx")

        wb.Close(0)
        xl.Quit()

        'System.Runtime.InteropServices.Marshal.ReleaseComObject(wb)
        'System.Runtime.InteropServices.Marshal.ReleaseComObject(xl)

        'wb = Nothing
        'xl = Nothing


    End Sub
End Module

The project configuration is in both consoles is the same:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <RootNamespace>OfficeInteropTest</RootNamespace>        
    </PropertyGroup>

    <ItemGroup>
        <COMReference Include="Microsoft.Office.Interop.Excel">
            <WrapperTool>tlbimp</WrapperTool>
            <VersionMinor>9</VersionMinor>
            <VersionMajor>1</VersionMajor>
            <Guid>00020813-0000-0000-c000-000000000046</Guid>
            <Lcid>0</Lcid>
            <Isolated>false</Isolated>
            <EmbedInteropTypes>true</EmbedInteropTypes>
        </COMReference>
    </ItemGroup>

</Project>

When I run each of them the C# app does not close Excel after the console exits while the VB.NET app does even though I commented out the last four lines.

So, I was wondering what do they do differently and why does it look like VB.NET is better with Office interop?

Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
t3chb0t
  • 16,340
  • 13
  • 78
  • 118
  • 1
    Does `xl.Quit()` return anything? Are any exceptions thrown? What if you use `STAThread`? – Dai Oct 21 '22 at 17:11
  • 1
    [This seems useful](https://social.msdn.microsoft.com/Forums/en-US/246181b3-44ca-4adb-bbbf-396a3c5f93f4/interact-with-microsoftofficeinteropexcelapplication?forum=exceldev) – Robert Harvey Oct 21 '22 at 17:23
  • 1
    @Dai `.Quit`'s return type is `void` and there are no visible exceptions, but I've rewritten the C# app and added the `[STAThread]` and also commented out the last four lines and now Excel exits here too :o Does it mean that VB.NET sets this attribute implicitly? – t3chb0t Oct 21 '22 at 17:26
  • 1
    Is there a reason you are using the interop services instead of [mirosoft's provided sdk for reading and manipulating office documents](https://learn.microsoft.com/en-us/office/open-xml/open-xml-sdk)? – Scott Chamberlain Oct 21 '22 at 17:26
  • @ScottChamberlain the only reason is that I didn't know that such a package existed! Thanks for point it out!!! It'll definitely be useful in data-oriented projects. – t3chb0t Oct 21 '22 at 17:29
  • For what it's worth, the Open SDK is a completely different animal. It certainly has its advantages (i.e. it performs better by 1 to 2 orders of magnitude), but it also has a much steeper learning curve, so there are tradeoffs to consider. – Robert Harvey Oct 21 '22 at 17:31
  • 2
    Try [ClosedXML](https://github.com/ClosedXML/ClosedXML) (does the heavy lifting, implementing the SDK in a *friendly* way) or [ExcelDataReader](https://github.com/ExcelDataReader/ExcelDataReader), depending on the use case - Interop (which implies that Office components must be installed in the machine) not required in both cases – Jimi Oct 21 '22 at 17:34
  • @RobertHarvey I looked at some examples and it's pretty low level and requires the knowledge of the xml-structure :-| – t3chb0t Oct 21 '22 at 17:39
  • 2
    Get hold of Microsoft's _OpenXML Productivty Tool_ (Microsoft has done a good job of making it hard to find). It allows you to create a prototype document and then reflect over it, proving the code you need to create the document. In general, if using the OpenXML SDK, you don't really need to know about the XML structure (though you'll pick up some of it) – Flydog57 Oct 21 '22 at 18:18
  • 1
    @t3chb0t Yes, I believe VB.NET always adds an implicit `STAThread` attribute to the `Main` method but C# requires an explicit annotation. – Dai Oct 21 '22 at 18:41
  • The C# 'top-level statements' feature was not added because it's a smart or recommended thing to do, but that someone thought it was a cool feature. – Dave Doknjas Oct 21 '22 at 20:14
  • @DaveDoknjas it is a cool feature :P Having to put everything in classes is such a pain. I like kotlin and python for allowing this out-of-the-box. – t3chb0t Oct 21 '22 at 20:19

1 Answers1

5

It turns out that Dai's susspicion was correct. VB.NET adds STAThread implicitly. I've looked into the ILCode and there it is:

.method public static void
    Main(
      string[] args
    ) cil managed
  {
    .entrypoint
    .custom instance void [System.Runtime]System.STAThreadAttribute::.ctor()
      = (01 00 00 00 )
    .maxstack 16
    .locals init (
      [0] class Microsoft.Office.Interop.Excel.Application xl,
      [1] class Microsoft.Office.Interop.Excel.Workbook wb
    )

    // [5 5 - 5 31]
    IL_0000: nop

    // [6 9 - 6 42]
    IL_0001: ldstr        "Hello World!"
    IL_0006: call         void [System.Console]System.Console::WriteLine(string)
    IL_000b: nop

Adding the [STATHread] attribute to a C# app fixes the issue with leaving Excel open after the app quits and makes the last four lines unecessary.

t3chb0t
  • 16,340
  • 13
  • 78
  • 118