CSharp VB Excel COM Differences

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Alan Roberts

    #1

    CSharp VB Excel COM Differences

    Can someone please explain the following for me...

    I am trying to link to a .NET DLL from Excel. Excel needs to pass a
    reference to itself to the DLL and then the DLL needs to perform some work
    on the running instance of Excel via that reference. As an example, a VB
    DLL to return the path to the current active workbook contains the following
    (in addition to the COM GUIDS automatically added to a new COMClass)...

    Public Class Class1
    Public Sub New()
    MyBase.New()
    End Sub
    Private gExcel As Object
    Public Property Excel() As Object
    Set(ByVal value As Object)
    gExcel = value
    End Set
    Get
    Excel = gExcel
    End Get
    End Property
    Public Function Path() As String
    Return Excel.ThisWorkb ook.Path
    End Function
    End Class

    After adding a refernece to the DLL, a macro in Excel could call this as
    follows

    Sub VBTest()
    Dim VBTest As New VBExcelTest.Cla ss1
    Set VBTest.Excel = Application
    Debug.Print VBTest.Path
    End Sub

    This all work fine

    How can I do the same thing using C#? If I try to create a DLL with
    equivalent(?) code eg

    public class Class1
    {
    public Class1(){
    }
    private object gExcel;
    public object Excel{
    get{
    return gExcel;
    }
    set{
    gExcel = value;
    }
    }
    public string Path(){
    return Excel.ThisWorkb ook.Path;
    }
    }

    I get a compile error saying that - 'object' does not contain a definition
    for 'ThisWorkbook'

    How can I get this to work?

    Thanks

    Alan


  • Nicholas Paldino [.NET/C# MVP]

    #2
    Re: CSharp VB Excel COM Differences

    Alan,

    The reason this works in VB is that the VB compiler will translate
    property and method calls on variables of type object to be reflection
    calls, which cause your code to work.

    Unfortunately, C# doesn't support this functionality. You will have to
    use reflection to get the member names and then invoke them like that.

    OR, you could set a reference to the interop assemblies for Excel, and
    cast the object passed into your method into one of those classes in the
    interop assembly. This would prevent you from having to do any late
    binding.

    Also, you should be careful of the operations you are performing. When
    you call methods on any object in Excel, you are creating a runtime callable
    wrapper which should be disposed of if you aren't using it anymore. In the
    case of your Path property, you should assign the result of ThisWorkbook to
    a variable, then pass that to the static ReleaseComObjec t method on the
    Marshal class.

    Hope this helps.


    --
    - Nicholas Paldino [.NET/C# MVP]
    - mvp@spam.guard. caspershouse.co m

    "Alan Roberts" <alan@statistix l.co.uk> wrote in message
    news:%23FJb3JuB GHA.2704@TK2MSF TNGP15.phx.gbl. ..[color=blue]
    > Can someone please explain the following for me...
    >
    > I am trying to link to a .NET DLL from Excel. Excel needs to pass a
    > reference to itself to the DLL and then the DLL needs to perform some work
    > on the running instance of Excel via that reference. As an example, a VB
    > DLL to return the path to the current active workbook contains the
    > following (in addition to the COM GUIDS automatically added to a new
    > COMClass)...
    >
    > Public Class Class1
    > Public Sub New()
    > MyBase.New()
    > End Sub
    > Private gExcel As Object
    > Public Property Excel() As Object
    > Set(ByVal value As Object)
    > gExcel = value
    > End Set
    > Get
    > Excel = gExcel
    > End Get
    > End Property
    > Public Function Path() As String
    > Return Excel.ThisWorkb ook.Path
    > End Function
    > End Class
    >
    > After adding a refernece to the DLL, a macro in Excel could call this as
    > follows
    >
    > Sub VBTest()
    > Dim VBTest As New VBExcelTest.Cla ss1
    > Set VBTest.Excel = Application
    > Debug.Print VBTest.Path
    > End Sub
    >
    > This all work fine
    >
    > How can I do the same thing using C#? If I try to create a DLL with
    > equivalent(?) code eg
    >
    > public class Class1
    > {
    > public Class1(){
    > }
    > private object gExcel;
    > public object Excel{
    > get{
    > return gExcel;
    > }
    > set{
    > gExcel = value;
    > }
    > }
    > public string Path(){
    > return Excel.ThisWorkb ook.Path;
    > }
    > }
    >
    > I get a compile error saying that - 'object' does not contain a definition
    > for 'ThisWorkbook'
    >
    > How can I get this to work?
    >
    > Thanks
    >
    > Alan
    >[/color]


    Comment

    • Alan Roberts

      #3
      Re: CSharp VB Excel COM Differences

      Hi Nicholas, thanks for the thorough reply! Does this mean that the
      following simple VB code to calculate the sum of the values specified in an
      Excel Range object

      Public Function Sum(ByVal range As String) As Double
      Dim i, j As Integer
      Dim total As Double
      For i = 1 To Excel.Range(ran ge).Rows.Count
      For j = 1 To Excel.Range(ran ge).Columns.Cou nt
      total = total + Convert.ToDoubl e(Excel.Range(r ange).cells(i,
      j).value)
      Next j
      Next i
      Return total
      End Function


      must become something like this in C#???


      public double Sum(string range)
      {
      object oRange, oRows, oCols, oRowCount, oColCount, oCell, oValue;
      object[] Parameters;
      double total= 0;
      Parameters = new Object[1];
      Parameters[0] = range;
      oRange = Excel.GetType() .InvokeMember(" Range", BindingFlags.Ge tProperty,
      null, Excel, Parameters);
      oRows = oRange.GetType( ).InvokeMember( "Rows", BindingFlags.Ge tProperty,
      null, oRange, null);
      oRowCount = oRows.GetType() .InvokeMember(" Count",
      BindingFlags.Ge tProperty, null, oRows, null);
      oCols = oRange.GetType( ).InvokeMember( "Columns",
      BindingFlags.Ge tProperty, null, oRange, null);
      oColCount = oCols.GetType() .InvokeMember(" Count",
      BindingFlags.Ge tProperty, null, oCols, null);
      for (int i = 1; i <= (int)oColCount; i++)
      {
      for (int j = 1; j <= (int)oRowCount; j++)
      {
      Parameters = new Object[2];
      Parameters[0] = j;
      Parameters[1] = i;
      oValue = new Object();
      oCell = new Object();
      oCell = oRange.GetType( ).InvokeMember( "Cells",
      BindingFlags.Ge tProperty, null, oRange, Parameters);
      oValue = oCell.GetType() .InvokeMember(" Value",
      BindingFlags.Ge tProperty, null, oCell, null);
      total += (double)oValue;
      }
      }
      return total;
      }


      Or is there a better way?

      Thanks

      Alan



      "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om> wrote in
      message news:OSx564zBGH A.2920@tk2msftn gp13.phx.gbl...[color=blue]
      > Alan,
      >
      > The reason this works in VB is that the VB compiler will translate
      > property and method calls on variables of type object to be reflection
      > calls, which cause your code to work.
      >
      > Unfortunately, C# doesn't support this functionality. You will have to
      > use reflection to get the member names and then invoke them like that.
      >
      > OR, you could set a reference to the interop assemblies for Excel, and
      > cast the object passed into your method into one of those classes in the
      > interop assembly. This would prevent you from having to do any late
      > binding.
      >
      > Also, you should be careful of the operations you are performing. When
      > you call methods on any object in Excel, you are creating a runtime
      > callable wrapper which should be disposed of if you aren't using it
      > anymore. In the case of your Path property, you should assign the result
      > of ThisWorkbook to a variable, then pass that to the static
      > ReleaseComObjec t method on the Marshal class.
      >
      > Hope this helps.
      >
      >
      > --
      > - Nicholas Paldino [.NET/C# MVP]
      > - mvp@spam.guard. caspershouse.co m
      >
      > "Alan Roberts" <alan@statistix l.co.uk> wrote in message
      > news:%23FJb3JuB GHA.2704@TK2MSF TNGP15.phx.gbl. ..[color=green]
      >> Can someone please explain the following for me...
      >>
      >> I am trying to link to a .NET DLL from Excel. Excel needs to pass a
      >> reference to itself to the DLL and then the DLL needs to perform some
      >> work on the running instance of Excel via that reference. As an example,
      >> a VB DLL to return the path to the current active workbook contains the
      >> following (in addition to the COM GUIDS automatically added to a new
      >> COMClass)...
      >>
      >> Public Class Class1
      >> Public Sub New()
      >> MyBase.New()
      >> End Sub
      >> Private gExcel As Object
      >> Public Property Excel() As Object
      >> Set(ByVal value As Object)
      >> gExcel = value
      >> End Set
      >> Get
      >> Excel = gExcel
      >> End Get
      >> End Property
      >> Public Function Path() As String
      >> Return Excel.ThisWorkb ook.Path
      >> End Function
      >> End Class
      >>
      >> After adding a refernece to the DLL, a macro in Excel could call this as
      >> follows
      >>
      >> Sub VBTest()
      >> Dim VBTest As New VBExcelTest.Cla ss1
      >> Set VBTest.Excel = Application
      >> Debug.Print VBTest.Path
      >> End Sub
      >>
      >> This all work fine
      >>
      >> How can I do the same thing using C#? If I try to create a DLL with
      >> equivalent(?) code eg
      >>
      >> public class Class1
      >> {
      >> public Class1(){
      >> }
      >> private object gExcel;
      >> public object Excel{
      >> get{
      >> return gExcel;
      >> }
      >> set{
      >> gExcel = value;
      >> }
      >> }
      >> public string Path(){
      >> return Excel.ThisWorkb ook.Path;
      >> }
      >> }
      >>
      >> I get a compile error saying that - 'object' does not contain a
      >> definition for 'ThisWorkbook'
      >>
      >> How can I get this to work?
      >>
      >> Thanks
      >>
      >> Alan
      >>[/color]
      >
      >[/color]


      Comment

      • Nicholas Paldino [.NET/C# MVP]

        #4
        Re: CSharp VB Excel COM Differences

        Alan,

        Yes, it's something like that. You could cut down on some of the
        reflection calls, but not by much.

        Also, you need to call ReleaseComObjec t for each object you expose. For
        example, in your Sum method, you need to release the result returned from:

        Excel.Range - Returns a collection of ranges
        Excel.Range(ran ge) - Returns the individual range.
        Excel.Range(ran ge).Rows - Returns the collection of ranges.
        Excel.Range(ran ge).Columns - Returns the collection of columns
        Excel.Range(ran ge).Cells - Returns the collection of cells.
        Excel.Range(ran ge).Cells(i, j) - Returns the range representing the
        individual cell.

        All of those need to have their references released properly.

        Hope this helps.


        --
        - Nicholas Paldino [.NET/C# MVP]
        - mvp@spam.guard. caspershouse.co m

        "Alan Roberts" <alan@statistix l.co.uk> wrote in message
        news:u50iW68BGH A.412@TK2MSFTNG P15.phx.gbl...[color=blue]
        > Hi Nicholas, thanks for the thorough reply! Does this mean that the
        > following simple VB code to calculate the sum of the values specified in
        > an Excel Range object
        >
        > Public Function Sum(ByVal range As String) As Double
        > Dim i, j As Integer
        > Dim total As Double
        > For i = 1 To Excel.Range(ran ge).Rows.Count
        > For j = 1 To Excel.Range(ran ge).Columns.Cou nt
        > total = total + Convert.ToDoubl e(Excel.Range(r ange).cells(i,
        > j).value)
        > Next j
        > Next i
        > Return total
        > End Function
        >
        >
        > must become something like this in C#???
        >
        >
        > public double Sum(string range)
        > {
        > object oRange, oRows, oCols, oRowCount, oColCount, oCell, oValue;
        > object[] Parameters;
        > double total= 0;
        > Parameters = new Object[1];
        > Parameters[0] = range;
        > oRange = Excel.GetType() .InvokeMember(" Range",
        > BindingFlags.Ge tProperty, null, Excel, Parameters);
        > oRows = oRange.GetType( ).InvokeMember( "Rows", BindingFlags.Ge tProperty,
        > null, oRange, null);
        > oRowCount = oRows.GetType() .InvokeMember(" Count",
        > BindingFlags.Ge tProperty, null, oRows, null);
        > oCols = oRange.GetType( ).InvokeMember( "Columns",
        > BindingFlags.Ge tProperty, null, oRange, null);
        > oColCount = oCols.GetType() .InvokeMember(" Count",
        > BindingFlags.Ge tProperty, null, oCols, null);
        > for (int i = 1; i <= (int)oColCount; i++)
        > {
        > for (int j = 1; j <= (int)oRowCount; j++)
        > {
        > Parameters = new Object[2];
        > Parameters[0] = j;
        > Parameters[1] = i;
        > oValue = new Object();
        > oCell = new Object();
        > oCell = oRange.GetType( ).InvokeMember( "Cells",
        > BindingFlags.Ge tProperty, null, oRange, Parameters);
        > oValue = oCell.GetType() .InvokeMember(" Value",
        > BindingFlags.Ge tProperty, null, oCell, null);
        > total += (double)oValue;
        > }
        > }
        > return total;
        > }
        >
        >
        > Or is there a better way?
        >
        > Thanks
        >
        > Alan
        >
        >
        >
        > "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om> wrote
        > in message news:OSx564zBGH A.2920@tk2msftn gp13.phx.gbl...[color=green]
        >> Alan,
        >>
        >> The reason this works in VB is that the VB compiler will translate
        >> property and method calls on variables of type object to be reflection
        >> calls, which cause your code to work.
        >>
        >> Unfortunately, C# doesn't support this functionality. You will have
        >> to use reflection to get the member names and then invoke them like that.
        >>
        >> OR, you could set a reference to the interop assemblies for Excel, and
        >> cast the object passed into your method into one of those classes in the
        >> interop assembly. This would prevent you from having to do any late
        >> binding.
        >>
        >> Also, you should be careful of the operations you are performing.
        >> When you call methods on any object in Excel, you are creating a runtime
        >> callable wrapper which should be disposed of if you aren't using it
        >> anymore. In the case of your Path property, you should assign the result
        >> of ThisWorkbook to a variable, then pass that to the static
        >> ReleaseComObjec t method on the Marshal class.
        >>
        >> Hope this helps.
        >>
        >>
        >> --
        >> - Nicholas Paldino [.NET/C# MVP]
        >> - mvp@spam.guard. caspershouse.co m
        >>
        >> "Alan Roberts" <alan@statistix l.co.uk> wrote in message
        >> news:%23FJb3JuB GHA.2704@TK2MSF TNGP15.phx.gbl. ..[color=darkred]
        >>> Can someone please explain the following for me...
        >>>
        >>> I am trying to link to a .NET DLL from Excel. Excel needs to pass a
        >>> reference to itself to the DLL and then the DLL needs to perform some
        >>> work on the running instance of Excel via that reference. As an
        >>> example, a VB DLL to return the path to the current active workbook
        >>> contains the following (in addition to the COM GUIDS automatically added
        >>> to a new COMClass)...
        >>>
        >>> Public Class Class1
        >>> Public Sub New()
        >>> MyBase.New()
        >>> End Sub
        >>> Private gExcel As Object
        >>> Public Property Excel() As Object
        >>> Set(ByVal value As Object)
        >>> gExcel = value
        >>> End Set
        >>> Get
        >>> Excel = gExcel
        >>> End Get
        >>> End Property
        >>> Public Function Path() As String
        >>> Return Excel.ThisWorkb ook.Path
        >>> End Function
        >>> End Class
        >>>
        >>> After adding a refernece to the DLL, a macro in Excel could call this as
        >>> follows
        >>>
        >>> Sub VBTest()
        >>> Dim VBTest As New VBExcelTest.Cla ss1
        >>> Set VBTest.Excel = Application
        >>> Debug.Print VBTest.Path
        >>> End Sub
        >>>
        >>> This all work fine
        >>>
        >>> How can I do the same thing using C#? If I try to create a DLL with
        >>> equivalent(?) code eg
        >>>
        >>> public class Class1
        >>> {
        >>> public Class1(){
        >>> }
        >>> private object gExcel;
        >>> public object Excel{
        >>> get{
        >>> return gExcel;
        >>> }
        >>> set{
        >>> gExcel = value;
        >>> }
        >>> }
        >>> public string Path(){
        >>> return Excel.ThisWorkb ook.Path;
        >>> }
        >>> }
        >>>
        >>> I get a compile error saying that - 'object' does not contain a
        >>> definition for 'ThisWorkbook'
        >>>
        >>> How can I get this to work?
        >>>
        >>> Thanks
        >>>
        >>> Alan
        >>>[/color]
        >>
        >>[/color]
        >
        >[/color]


        Comment

        • Alan Roberts

          #5
          Re: CSharp VB Excel COM Differences

          Blimey! Thanks a lot Nicholas. I guess I will stick with VB for now. On
          the whole I find C# more elegant but VB seems better suited to this
          particular application.

          Thanks

          Alan

          "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om> wrote in
          message news:edpv$VFCGH A.916@TK2MSFTNG P10.phx.gbl...[color=blue]
          > Alan,
          >
          > Yes, it's something like that. You could cut down on some of the
          > reflection calls, but not by much.
          >
          > Also, you need to call ReleaseComObjec t for each object you expose.
          > For example, in your Sum method, you need to release the result returned
          > from:
          >
          > Excel.Range - Returns a collection of ranges
          > Excel.Range(ran ge) - Returns the individual range.
          > Excel.Range(ran ge).Rows - Returns the collection of ranges.
          > Excel.Range(ran ge).Columns - Returns the collection of columns
          > Excel.Range(ran ge).Cells - Returns the collection of cells.
          > Excel.Range(ran ge).Cells(i, j) - Returns the range representing the
          > individual cell.
          >
          > All of those need to have their references released properly.
          >
          > Hope this helps.
          >
          >
          > --
          > - Nicholas Paldino [.NET/C# MVP]
          > - mvp@spam.guard. caspershouse.co m
          >
          > "Alan Roberts" <alan@statistix l.co.uk> wrote in message
          > news:u50iW68BGH A.412@TK2MSFTNG P15.phx.gbl...[color=green]
          >> Hi Nicholas, thanks for the thorough reply! Does this mean that the
          >> following simple VB code to calculate the sum of the values specified in
          >> an Excel Range object
          >>
          >> Public Function Sum(ByVal range As String) As Double
          >> Dim i, j As Integer
          >> Dim total As Double
          >> For i = 1 To Excel.Range(ran ge).Rows.Count
          >> For j = 1 To Excel.Range(ran ge).Columns.Cou nt
          >> total = total + Convert.ToDoubl e(Excel.Range(r ange).cells(i,
          >> j).value)
          >> Next j
          >> Next i
          >> Return total
          >> End Function
          >>
          >>
          >> must become something like this in C#???
          >>
          >>
          >> public double Sum(string range)
          >> {
          >> object oRange, oRows, oCols, oRowCount, oColCount, oCell, oValue;
          >> object[] Parameters;
          >> double total= 0;
          >> Parameters = new Object[1];
          >> Parameters[0] = range;
          >> oRange = Excel.GetType() .InvokeMember(" Range",
          >> BindingFlags.Ge tProperty, null, Excel, Parameters);
          >> oRows = oRange.GetType( ).InvokeMember( "Rows",
          >> BindingFlags.Ge tProperty, null, oRange, null);
          >> oRowCount = oRows.GetType() .InvokeMember(" Count",
          >> BindingFlags.Ge tProperty, null, oRows, null);
          >> oCols = oRange.GetType( ).InvokeMember( "Columns",
          >> BindingFlags.Ge tProperty, null, oRange, null);
          >> oColCount = oCols.GetType() .InvokeMember(" Count",
          >> BindingFlags.Ge tProperty, null, oCols, null);
          >> for (int i = 1; i <= (int)oColCount; i++)
          >> {
          >> for (int j = 1; j <= (int)oRowCount; j++)
          >> {
          >> Parameters = new Object[2];
          >> Parameters[0] = j;
          >> Parameters[1] = i;
          >> oValue = new Object();
          >> oCell = new Object();
          >> oCell = oRange.GetType( ).InvokeMember( "Cells",
          >> BindingFlags.Ge tProperty, null, oRange, Parameters);
          >> oValue = oCell.GetType() .InvokeMember(" Value",
          >> BindingFlags.Ge tProperty, null, oCell, null);
          >> total += (double)oValue;
          >> }
          >> }
          >> return total;
          >> }
          >>
          >>
          >> Or is there a better way?
          >>
          >> Thanks
          >>
          >> Alan
          >>
          >>
          >>
          >> "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om> wrote
          >> in message news:OSx564zBGH A.2920@tk2msftn gp13.phx.gbl...[color=darkred]
          >>> Alan,
          >>>
          >>> The reason this works in VB is that the VB compiler will translate
          >>> property and method calls on variables of type object to be reflection
          >>> calls, which cause your code to work.
          >>>
          >>> Unfortunately, C# doesn't support this functionality. You will have
          >>> to use reflection to get the member names and then invoke them like
          >>> that.
          >>>
          >>> OR, you could set a reference to the interop assemblies for Excel,
          >>> and cast the object passed into your method into one of those classes in
          >>> the interop assembly. This would prevent you from having to do any late
          >>> binding.
          >>>
          >>> Also, you should be careful of the operations you are performing.
          >>> When you call methods on any object in Excel, you are creating a runtime
          >>> callable wrapper which should be disposed of if you aren't using it
          >>> anymore. In the case of your Path property, you should assign the
          >>> result of ThisWorkbook to a variable, then pass that to the static
          >>> ReleaseComObjec t method on the Marshal class.
          >>>
          >>> Hope this helps.
          >>>
          >>>
          >>> --
          >>> - Nicholas Paldino [.NET/C# MVP]
          >>> - mvp@spam.guard. caspershouse.co m
          >>>
          >>> "Alan Roberts" <alan@statistix l.co.uk> wrote in message
          >>> news:%23FJb3JuB GHA.2704@TK2MSF TNGP15.phx.gbl. ..
          >>>> Can someone please explain the following for me...
          >>>>
          >>>> I am trying to link to a .NET DLL from Excel. Excel needs to pass a
          >>>> reference to itself to the DLL and then the DLL needs to perform some
          >>>> work on the running instance of Excel via that reference. As an
          >>>> example, a VB DLL to return the path to the current active workbook
          >>>> contains the following (in addition to the COM GUIDS automatically
          >>>> added to a new COMClass)...
          >>>>
          >>>> Public Class Class1
          >>>> Public Sub New()
          >>>> MyBase.New()
          >>>> End Sub
          >>>> Private gExcel As Object
          >>>> Public Property Excel() As Object
          >>>> Set(ByVal value As Object)
          >>>> gExcel = value
          >>>> End Set
          >>>> Get
          >>>> Excel = gExcel
          >>>> End Get
          >>>> End Property
          >>>> Public Function Path() As String
          >>>> Return Excel.ThisWorkb ook.Path
          >>>> End Function
          >>>> End Class
          >>>>
          >>>> After adding a refernece to the DLL, a macro in Excel could call this
          >>>> as follows
          >>>>
          >>>> Sub VBTest()
          >>>> Dim VBTest As New VBExcelTest.Cla ss1
          >>>> Set VBTest.Excel = Application
          >>>> Debug.Print VBTest.Path
          >>>> End Sub
          >>>>
          >>>> This all work fine
          >>>>
          >>>> How can I do the same thing using C#? If I try to create a DLL with
          >>>> equivalent(?) code eg
          >>>>
          >>>> public class Class1
          >>>> {
          >>>> public Class1(){
          >>>> }
          >>>> private object gExcel;
          >>>> public object Excel{
          >>>> get{
          >>>> return gExcel;
          >>>> }
          >>>> set{
          >>>> gExcel = value;
          >>>> }
          >>>> }
          >>>> public string Path(){
          >>>> return Excel.ThisWorkb ook.Path;
          >>>> }
          >>>> }
          >>>>
          >>>> I get a compile error saying that - 'object' does not contain a
          >>>> definition for 'ThisWorkbook'
          >>>>
          >>>> How can I get this to work?
          >>>>
          >>>> Thanks
          >>>>
          >>>> Alan
          >>>>
          >>>
          >>>[/color]
          >>
          >>[/color]
          >
          >[/color]


          Comment

          • Nicholas Paldino [.NET/C# MVP]

            #6
            Re: CSharp VB Excel COM Differences

            Alan,

            The problem still exists in VB. In VB, the RCW for all of the objects I
            list out still are out there, and you don't release them.

            The only thing that VB makes easier is having to actually make the
            calls, it will make it easy to perfrom the reflection for you, but not the
            actuall calls to ReleaseComObjec t.


            --
            - Nicholas Paldino [.NET/C# MVP]
            - mvp@spam.guard. caspershouse.co m

            "Alan Roberts" <alan@statistix l.co.uk> wrote in message
            news:uQob93ICGH A.216@TK2MSFTNG P15.phx.gbl...[color=blue]
            > Blimey! Thanks a lot Nicholas. I guess I will stick with VB for now. On
            > the whole I find C# more elegant but VB seems better suited to this
            > particular application.
            >
            > Thanks
            >
            > Alan
            >
            > "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om> wrote
            > in message news:edpv$VFCGH A.916@TK2MSFTNG P10.phx.gbl...[color=green]
            >> Alan,
            >>
            >> Yes, it's something like that. You could cut down on some of the
            >> reflection calls, but not by much.
            >>
            >> Also, you need to call ReleaseComObjec t for each object you expose.
            >> For example, in your Sum method, you need to release the result returned
            >> from:
            >>
            >> Excel.Range - Returns a collection of ranges
            >> Excel.Range(ran ge) - Returns the individual range.
            >> Excel.Range(ran ge).Rows - Returns the collection of ranges.
            >> Excel.Range(ran ge).Columns - Returns the collection of columns
            >> Excel.Range(ran ge).Cells - Returns the collection of cells.
            >> Excel.Range(ran ge).Cells(i, j) - Returns the range representing the
            >> individual cell.
            >>
            >> All of those need to have their references released properly.
            >>
            >> Hope this helps.
            >>
            >>
            >> --
            >> - Nicholas Paldino [.NET/C# MVP]
            >> - mvp@spam.guard. caspershouse.co m
            >>
            >> "Alan Roberts" <alan@statistix l.co.uk> wrote in message
            >> news:u50iW68BGH A.412@TK2MSFTNG P15.phx.gbl...[color=darkred]
            >>> Hi Nicholas, thanks for the thorough reply! Does this mean that the
            >>> following simple VB code to calculate the sum of the values specified in
            >>> an Excel Range object
            >>>
            >>> Public Function Sum(ByVal range As String) As Double
            >>> Dim i, j As Integer
            >>> Dim total As Double
            >>> For i = 1 To Excel.Range(ran ge).Rows.Count
            >>> For j = 1 To Excel.Range(ran ge).Columns.Cou nt
            >>> total = total + Convert.ToDoubl e(Excel.Range(r ange).cells(i,
            >>> j).value)
            >>> Next j
            >>> Next i
            >>> Return total
            >>> End Function
            >>>
            >>>
            >>> must become something like this in C#???
            >>>
            >>>
            >>> public double Sum(string range)
            >>> {
            >>> object oRange, oRows, oCols, oRowCount, oColCount, oCell, oValue;
            >>> object[] Parameters;
            >>> double total= 0;
            >>> Parameters = new Object[1];
            >>> Parameters[0] = range;
            >>> oRange = Excel.GetType() .InvokeMember(" Range",
            >>> BindingFlags.Ge tProperty, null, Excel, Parameters);
            >>> oRows = oRange.GetType( ).InvokeMember( "Rows",
            >>> BindingFlags.Ge tProperty, null, oRange, null);
            >>> oRowCount = oRows.GetType() .InvokeMember(" Count",
            >>> BindingFlags.Ge tProperty, null, oRows, null);
            >>> oCols = oRange.GetType( ).InvokeMember( "Columns",
            >>> BindingFlags.Ge tProperty, null, oRange, null);
            >>> oColCount = oCols.GetType() .InvokeMember(" Count",
            >>> BindingFlags.Ge tProperty, null, oCols, null);
            >>> for (int i = 1; i <= (int)oColCount; i++)
            >>> {
            >>> for (int j = 1; j <= (int)oRowCount; j++)
            >>> {
            >>> Parameters = new Object[2];
            >>> Parameters[0] = j;
            >>> Parameters[1] = i;
            >>> oValue = new Object();
            >>> oCell = new Object();
            >>> oCell = oRange.GetType( ).InvokeMember( "Cells",
            >>> BindingFlags.Ge tProperty, null, oRange, Parameters);
            >>> oValue = oCell.GetType() .InvokeMember(" Value",
            >>> BindingFlags.Ge tProperty, null, oCell, null);
            >>> total += (double)oValue;
            >>> }
            >>> }
            >>> return total;
            >>> }
            >>>
            >>>
            >>> Or is there a better way?
            >>>
            >>> Thanks
            >>>
            >>> Alan
            >>>
            >>>
            >>>
            >>> "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om> wrote
            >>> in message news:OSx564zBGH A.2920@tk2msftn gp13.phx.gbl...
            >>>> Alan,
            >>>>
            >>>> The reason this works in VB is that the VB compiler will translate
            >>>> property and method calls on variables of type object to be reflection
            >>>> calls, which cause your code to work.
            >>>>
            >>>> Unfortunately, C# doesn't support this functionality. You will have
            >>>> to use reflection to get the member names and then invoke them like
            >>>> that.
            >>>>
            >>>> OR, you could set a reference to the interop assemblies for Excel,
            >>>> and cast the object passed into your method into one of those classes
            >>>> in the interop assembly. This would prevent you from having to do any
            >>>> late binding.
            >>>>
            >>>> Also, you should be careful of the operations you are performing.
            >>>> When you call methods on any object in Excel, you are creating a
            >>>> runtime callable wrapper which should be disposed of if you aren't
            >>>> using it anymore. In the case of your Path property, you should assign
            >>>> the result of ThisWorkbook to a variable, then pass that to the static
            >>>> ReleaseComObjec t method on the Marshal class.
            >>>>
            >>>> Hope this helps.
            >>>>
            >>>>
            >>>> --
            >>>> - Nicholas Paldino [.NET/C# MVP]
            >>>> - mvp@spam.guard. caspershouse.co m
            >>>>
            >>>> "Alan Roberts" <alan@statistix l.co.uk> wrote in message
            >>>> news:%23FJb3JuB GHA.2704@TK2MSF TNGP15.phx.gbl. ..
            >>>>> Can someone please explain the following for me...
            >>>>>
            >>>>> I am trying to link to a .NET DLL from Excel. Excel needs to pass a
            >>>>> reference to itself to the DLL and then the DLL needs to perform some
            >>>>> work on the running instance of Excel via that reference. As an
            >>>>> example, a VB DLL to return the path to the current active workbook
            >>>>> contains the following (in addition to the COM GUIDS automatically
            >>>>> added to a new COMClass)...
            >>>>>
            >>>>> Public Class Class1
            >>>>> Public Sub New()
            >>>>> MyBase.New()
            >>>>> End Sub
            >>>>> Private gExcel As Object
            >>>>> Public Property Excel() As Object
            >>>>> Set(ByVal value As Object)
            >>>>> gExcel = value
            >>>>> End Set
            >>>>> Get
            >>>>> Excel = gExcel
            >>>>> End Get
            >>>>> End Property
            >>>>> Public Function Path() As String
            >>>>> Return Excel.ThisWorkb ook.Path
            >>>>> End Function
            >>>>> End Class
            >>>>>
            >>>>> After adding a refernece to the DLL, a macro in Excel could call this
            >>>>> as follows
            >>>>>
            >>>>> Sub VBTest()
            >>>>> Dim VBTest As New VBExcelTest.Cla ss1
            >>>>> Set VBTest.Excel = Application
            >>>>> Debug.Print VBTest.Path
            >>>>> End Sub
            >>>>>
            >>>>> This all work fine
            >>>>>
            >>>>> How can I do the same thing using C#? If I try to create a DLL with
            >>>>> equivalent(?) code eg
            >>>>>
            >>>>> public class Class1
            >>>>> {
            >>>>> public Class1(){
            >>>>> }
            >>>>> private object gExcel;
            >>>>> public object Excel{
            >>>>> get{
            >>>>> return gExcel;
            >>>>> }
            >>>>> set{
            >>>>> gExcel = value;
            >>>>> }
            >>>>> }
            >>>>> public string Path(){
            >>>>> return Excel.ThisWorkb ook.Path;
            >>>>> }
            >>>>> }
            >>>>>
            >>>>> I get a compile error saying that - 'object' does not contain a
            >>>>> definition for 'ThisWorkbook'
            >>>>>
            >>>>> How can I get this to work?
            >>>>>
            >>>>> Thanks
            >>>>>
            >>>>> Alan
            >>>>>
            >>>>
            >>>>
            >>>
            >>>[/color]
            >>
            >>[/color]
            >
            >[/color]


            Comment

            • Alan Roberts

              #7
              Re: CSharp VB Excel COM Differences

              Thanks Nicholas. I guess I am still having dificulties with the Release
              idea....
              I have come up with the following routine in C#


              private static object GetProperty(obj ect obj, string sProperty)
              {
              string[] Properties = sProperty.Split (new char[] {'.'});
              object oProp;
              oProp = obj;
              for (int i = 0; i <= Properties.GetU pperBound(0); i++)
              {
              if (Properties[i].Contains("("))
              oProp = oProp.GetType() .InvokeMember(P roperties[i].Substring(0,
              Properties[i].IndexOf('(')),
              BindingFlags.Ge tProperty, null, oProp,
              Properties[i].Substring(Prop erties[i].IndexOf('(')
              + 1, Properties[i].IndexOf(')') - (Properties[i].IndexOf('(') +
              1)).Split(new char[] { ','
              }));
              else
              oProp = oProp.GetType() .InvokeMember(P roperties[i],
              BindingFlags.Ge tProperty, null,
              oProp, null);
              }

              return oProp;
              }


              basically it simplifies my code as I once I have a link to the Excel object
              I can access properties using code along the lines of
              GetProperty(oEx cel, "ActiveSheet.Ce lls(1,1).Value" );
              rather than having all of the step by step code I presented previousle.

              If I use this function in a routine to calculate the total of a range of
              cells eg


              double total = 0;
              for (int i = 1; i <= 5; i++)
              {
              total += (double)GetProp erty(oRange, "Cells(" + i.ToString() +",
              1").Value");
              }


              What objects do I have to release both in the for loop code above and in the
              GetProperty function that it calls?

              Thanks for your help with this

              Alan



              "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om> wrote in
              message news:eaTawxpCGH A.2036@TK2MSFTN GP14.phx.gbl...[color=blue]
              > Alan,
              >
              > The problem still exists in VB. In VB, the RCW for all of the objects
              > I list out still are out there, and you don't release them.
              >
              > The only thing that VB makes easier is having to actually make the
              > calls, it will make it easy to perfrom the reflection for you, but not the
              > actuall calls to ReleaseComObjec t.
              >
              >
              > --
              > - Nicholas Paldino [.NET/C# MVP]
              > - mvp@spam.guard. caspershouse.co m
              >
              > "Alan Roberts" <alan@statistix l.co.uk> wrote in message
              > news:uQob93ICGH A.216@TK2MSFTNG P15.phx.gbl...[color=green]
              >> Blimey! Thanks a lot Nicholas. I guess I will stick with VB for now.
              >> On the whole I find C# more elegant but VB seems better suited to this
              >> particular application.
              >>
              >> Thanks
              >>
              >> Alan
              >>
              >> "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om> wrote
              >> in message news:edpv$VFCGH A.916@TK2MSFTNG P10.phx.gbl...[color=darkred]
              >>> Alan,
              >>>
              >>> Yes, it's something like that. You could cut down on some of the
              >>> reflection calls, but not by much.
              >>>
              >>> Also, you need to call ReleaseComObjec t for each object you expose.
              >>> For example, in your Sum method, you need to release the result returned
              >>> from:
              >>>
              >>> Excel.Range - Returns a collection of ranges
              >>> Excel.Range(ran ge) - Returns the individual range.
              >>> Excel.Range(ran ge).Rows - Returns the collection of ranges.
              >>> Excel.Range(ran ge).Columns - Returns the collection of columns
              >>> Excel.Range(ran ge).Cells - Returns the collection of cells.
              >>> Excel.Range(ran ge).Cells(i, j) - Returns the range representing the
              >>> individual cell.
              >>>
              >>> All of those need to have their references released properly.
              >>>
              >>> Hope this helps.
              >>>
              >>>
              >>> --
              >>> - Nicholas Paldino [.NET/C# MVP]
              >>> - mvp@spam.guard. caspershouse.co m
              >>>
              >>> "Alan Roberts" <alan@statistix l.co.uk> wrote in message
              >>> news:u50iW68BGH A.412@TK2MSFTNG P15.phx.gbl...
              >>>> Hi Nicholas, thanks for the thorough reply! Does this mean that the
              >>>> following simple VB code to calculate the sum of the values specified
              >>>> in an Excel Range object
              >>>>
              >>>> Public Function Sum(ByVal range As String) As Double
              >>>> Dim i, j As Integer
              >>>> Dim total As Double
              >>>> For i = 1 To Excel.Range(ran ge).Rows.Count
              >>>> For j = 1 To Excel.Range(ran ge).Columns.Cou nt
              >>>> total = total + Convert.ToDoubl e(Excel.Range(r ange).cells(i,
              >>>> j).value)
              >>>> Next j
              >>>> Next i
              >>>> Return total
              >>>> End Function
              >>>>
              >>>>
              >>>> must become something like this in C#???
              >>>>
              >>>>
              >>>> public double Sum(string range)
              >>>> {
              >>>> object oRange, oRows, oCols, oRowCount, oColCount, oCell, oValue;
              >>>> object[] Parameters;
              >>>> double total= 0;
              >>>> Parameters = new Object[1];
              >>>> Parameters[0] = range;
              >>>> oRange = Excel.GetType() .InvokeMember(" Range",
              >>>> BindingFlags.Ge tProperty, null, Excel, Parameters);
              >>>> oRows = oRange.GetType( ).InvokeMember( "Rows",
              >>>> BindingFlags.Ge tProperty, null, oRange, null);
              >>>> oRowCount = oRows.GetType() .InvokeMember(" Count",
              >>>> BindingFlags.Ge tProperty, null, oRows, null);
              >>>> oCols = oRange.GetType( ).InvokeMember( "Columns",
              >>>> BindingFlags.Ge tProperty, null, oRange, null);
              >>>> oColCount = oCols.GetType() .InvokeMember(" Count",
              >>>> BindingFlags.Ge tProperty, null, oCols, null);
              >>>> for (int i = 1; i <= (int)oColCount; i++)
              >>>> {
              >>>> for (int j = 1; j <= (int)oRowCount; j++)
              >>>> {
              >>>> Parameters = new Object[2];
              >>>> Parameters[0] = j;
              >>>> Parameters[1] = i;
              >>>> oValue = new Object();
              >>>> oCell = new Object();
              >>>> oCell = oRange.GetType( ).InvokeMember( "Cells",
              >>>> BindingFlags.Ge tProperty, null, oRange, Parameters);
              >>>> oValue = oCell.GetType() .InvokeMember(" Value",
              >>>> BindingFlags.Ge tProperty, null, oCell, null);
              >>>> total += (double)oValue;
              >>>> }
              >>>> }
              >>>> return total;
              >>>> }
              >>>>
              >>>>
              >>>> Or is there a better way?
              >>>>
              >>>> Thanks
              >>>>
              >>>> Alan
              >>>>
              >>>>
              >>>>
              >>>> "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
              >>>> wrote in message news:OSx564zBGH A.2920@tk2msftn gp13.phx.gbl...
              >>>>> Alan,
              >>>>>
              >>>>> The reason this works in VB is that the VB compiler will translate
              >>>>> property and method calls on variables of type object to be reflection
              >>>>> calls, which cause your code to work.
              >>>>>
              >>>>> Unfortunately, C# doesn't support this functionality. You will
              >>>>> have to use reflection to get the member names and then invoke them
              >>>>> like that.
              >>>>>
              >>>>> OR, you could set a reference to the interop assemblies for Excel,
              >>>>> and cast the object passed into your method into one of those classes
              >>>>> in the interop assembly. This would prevent you from having to do any
              >>>>> late binding.
              >>>>>
              >>>>> Also, you should be careful of the operations you are performing.
              >>>>> When you call methods on any object in Excel, you are creating a
              >>>>> runtime callable wrapper which should be disposed of if you aren't
              >>>>> using it anymore. In the case of your Path property, you should
              >>>>> assign the result of ThisWorkbook to a variable, then pass that to the
              >>>>> static ReleaseComObjec t method on the Marshal class.
              >>>>>
              >>>>> Hope this helps.
              >>>>>
              >>>>>
              >>>>> --
              >>>>> - Nicholas Paldino [.NET/C# MVP]
              >>>>> - mvp@spam.guard. caspershouse.co m
              >>>>>
              >>>>> "Alan Roberts" <alan@statistix l.co.uk> wrote in message
              >>>>> news:%23FJb3JuB GHA.2704@TK2MSF TNGP15.phx.gbl. ..
              >>>>>> Can someone please explain the following for me...
              >>>>>>
              >>>>>> I am trying to link to a .NET DLL from Excel. Excel needs to pass a
              >>>>>> reference to itself to the DLL and then the DLL needs to perform some
              >>>>>> work on the running instance of Excel via that reference. As an
              >>>>>> example, a VB DLL to return the path to the current active workbook
              >>>>>> contains the following (in addition to the COM GUIDS automatically
              >>>>>> added to a new COMClass)...
              >>>>>>
              >>>>>> Public Class Class1
              >>>>>> Public Sub New()
              >>>>>> MyBase.New()
              >>>>>> End Sub
              >>>>>> Private gExcel As Object
              >>>>>> Public Property Excel() As Object
              >>>>>> Set(ByVal value As Object)
              >>>>>> gExcel = value
              >>>>>> End Set
              >>>>>> Get
              >>>>>> Excel = gExcel
              >>>>>> End Get
              >>>>>> End Property
              >>>>>> Public Function Path() As String
              >>>>>> Return Excel.ThisWorkb ook.Path
              >>>>>> End Function
              >>>>>> End Class
              >>>>>>
              >>>>>> After adding a refernece to the DLL, a macro in Excel could call this
              >>>>>> as follows
              >>>>>>
              >>>>>> Sub VBTest()
              >>>>>> Dim VBTest As New VBExcelTest.Cla ss1
              >>>>>> Set VBTest.Excel = Application
              >>>>>> Debug.Print VBTest.Path
              >>>>>> End Sub
              >>>>>>
              >>>>>> This all work fine
              >>>>>>
              >>>>>> How can I do the same thing using C#? If I try to create a DLL with
              >>>>>> equivalent(?) code eg
              >>>>>>
              >>>>>> public class Class1
              >>>>>> {
              >>>>>> public Class1(){
              >>>>>> }
              >>>>>> private object gExcel;
              >>>>>> public object Excel{
              >>>>>> get{
              >>>>>> return gExcel;
              >>>>>> }
              >>>>>> set{
              >>>>>> gExcel = value;
              >>>>>> }
              >>>>>> }
              >>>>>> public string Path(){
              >>>>>> return Excel.ThisWorkb ook.Path;
              >>>>>> }
              >>>>>> }
              >>>>>>
              >>>>>> I get a compile error saying that - 'object' does not contain a
              >>>>>> definition for 'ThisWorkbook'
              >>>>>>
              >>>>>> How can I get this to work?
              >>>>>>
              >>>>>> Thanks
              >>>>>>
              >>>>>> Alan
              >>>>>>
              >>>>>
              >>>>>
              >>>>
              >>>>
              >>>
              >>>[/color]
              >>
              >>[/color]
              >
              >[/color]


              Comment

              • Alvin Bruney - ASP.NET MVP

                #8
                Re: CSharp VB Excel COM Differences

                On a side note, you can optimize your loop heavy code to take advantage of
                the excel internally supported methods.
                [color=blue]
                > double total = 0;
                > for (int i = 1; i <= 5; i++)
                > {
                > total += (double)GetProp erty(oRange, "Cells(" + i.ToString() +",
                > 1").Value");
                > }[/color]

                can be replaced with
                Range r = rangeInQuestion .Formula = "=Sum(1,5)"

                FYI

                --
                Regards,
                Alvin Bruney [MVP ASP.NET]

                [Shameless Author plug]
                The Microsoft Office Web Components Black Book with .NET
                Now Available @ www.lulu.com/owc
                Forth-coming VSTO.NET - Wrox/Wiley 2006
                -------------------------------------------------------



                "Alan Roberts" <alan@statistix l.co.uk> wrote in message
                news:OwvHEFsEGH A.140@TK2MSFTNG P12.phx.gbl...[color=blue]
                > Thanks Nicholas. I guess I am still having dificulties with the Release
                > idea....
                > I have come up with the following routine in C#
                >
                >
                > private static object GetProperty(obj ect obj, string sProperty)
                > {
                > string[] Properties = sProperty.Split (new char[] {'.'});
                > object oProp;
                > oProp = obj;
                > for (int i = 0; i <= Properties.GetU pperBound(0); i++)
                > {
                > if (Properties[i].Contains("("))
                > oProp = oProp.GetType() .InvokeMember(P roperties[i].Substring(0,
                > Properties[i].IndexOf('(')),
                > BindingFlags.Ge tProperty, null, oProp,
                > Properties[i].Substring(Prop erties[i].IndexOf('(')
                > + 1, Properties[i].IndexOf(')') - (Properties[i].IndexOf('(') +
                > 1)).Split(new char[] { ','
                > }));
                > else
                > oProp = oProp.GetType() .InvokeMember(P roperties[i],
                > BindingFlags.Ge tProperty, null,
                > oProp, null);
                > }
                >
                > return oProp;
                > }
                >
                >
                > basically it simplifies my code as I once I have a link to the Excel[/color]
                object[color=blue]
                > I can access properties using code along the lines of
                > GetProperty(oEx cel, "ActiveSheet.Ce lls(1,1).Value" );
                > rather than having all of the step by step code I presented previousle.
                >
                > If I use this function in a routine to calculate the total of a range of
                > cells eg
                >
                >
                > double total = 0;
                > for (int i = 1; i <= 5; i++)
                > {
                > total += (double)GetProp erty(oRange, "Cells(" + i.ToString() +",
                > 1").Value");
                > }
                >
                >
                > What objects do I have to release both in the for loop code above and in[/color]
                the[color=blue]
                > GetProperty function that it calls?
                >
                > Thanks for your help with this
                >
                > Alan
                >
                >
                >
                > "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om> wrote[/color]
                in[color=blue]
                > message news:eaTawxpCGH A.2036@TK2MSFTN GP14.phx.gbl...[color=green]
                > > Alan,
                > >
                > > The problem still exists in VB. In VB, the RCW for all of the[/color][/color]
                objects[color=blue][color=green]
                > > I list out still are out there, and you don't release them.
                > >
                > > The only thing that VB makes easier is having to actually make the
                > > calls, it will make it easy to perfrom the reflection for you, but not[/color][/color]
                the[color=blue][color=green]
                > > actuall calls to ReleaseComObjec t.
                > >
                > >
                > > --
                > > - Nicholas Paldino [.NET/C# MVP]
                > > - mvp@spam.guard. caspershouse.co m
                > >
                > > "Alan Roberts" <alan@statistix l.co.uk> wrote in message
                > > news:uQob93ICGH A.216@TK2MSFTNG P15.phx.gbl...[color=darkred]
                > >> Blimey! Thanks a lot Nicholas. I guess I will stick with VB for now.
                > >> On the whole I find C# more elegant but VB seems better suited to this
                > >> particular application.
                > >>
                > >> Thanks
                > >>
                > >> Alan
                > >>
                > >> "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>[/color][/color][/color]
                wrote[color=blue][color=green][color=darkred]
                > >> in message news:edpv$VFCGH A.916@TK2MSFTNG P10.phx.gbl...
                > >>> Alan,
                > >>>
                > >>> Yes, it's something like that. You could cut down on some of the
                > >>> reflection calls, but not by much.
                > >>>
                > >>> Also, you need to call ReleaseComObjec t for each object you expose.
                > >>> For example, in your Sum method, you need to release the result[/color][/color][/color]
                returned[color=blue][color=green][color=darkred]
                > >>> from:
                > >>>
                > >>> Excel.Range - Returns a collection of ranges
                > >>> Excel.Range(ran ge) - Returns the individual range.
                > >>> Excel.Range(ran ge).Rows - Returns the collection of ranges.
                > >>> Excel.Range(ran ge).Columns - Returns the collection of columns
                > >>> Excel.Range(ran ge).Cells - Returns the collection of cells.
                > >>> Excel.Range(ran ge).Cells(i, j) - Returns the range representing the
                > >>> individual cell.
                > >>>
                > >>> All of those need to have their references released properly.
                > >>>
                > >>> Hope this helps.
                > >>>
                > >>>
                > >>> --
                > >>> - Nicholas Paldino [.NET/C# MVP]
                > >>> - mvp@spam.guard. caspershouse.co m
                > >>>
                > >>> "Alan Roberts" <alan@statistix l.co.uk> wrote in message
                > >>> news:u50iW68BGH A.412@TK2MSFTNG P15.phx.gbl...
                > >>>> Hi Nicholas, thanks for the thorough reply! Does this mean that the
                > >>>> following simple VB code to calculate the sum of the values specified
                > >>>> in an Excel Range object
                > >>>>
                > >>>> Public Function Sum(ByVal range As String) As Double
                > >>>> Dim i, j As Integer
                > >>>> Dim total As Double
                > >>>> For i = 1 To Excel.Range(ran ge).Rows.Count
                > >>>> For j = 1 To Excel.Range(ran ge).Columns.Cou nt
                > >>>> total = total +[/color][/color][/color]
                Convert.ToDoubl e(Excel.Range(r ange).cells(i,[color=blue][color=green][color=darkred]
                > >>>> j).value)
                > >>>> Next j
                > >>>> Next i
                > >>>> Return total
                > >>>> End Function
                > >>>>
                > >>>>
                > >>>> must become something like this in C#???
                > >>>>
                > >>>>
                > >>>> public double Sum(string range)
                > >>>> {
                > >>>> object oRange, oRows, oCols, oRowCount, oColCount, oCell, oValue;
                > >>>> object[] Parameters;
                > >>>> double total= 0;
                > >>>> Parameters = new Object[1];
                > >>>> Parameters[0] = range;
                > >>>> oRange = Excel.GetType() .InvokeMember(" Range",
                > >>>> BindingFlags.Ge tProperty, null, Excel, Parameters);
                > >>>> oRows = oRange.GetType( ).InvokeMember( "Rows",
                > >>>> BindingFlags.Ge tProperty, null, oRange, null);
                > >>>> oRowCount = oRows.GetType() .InvokeMember(" Count",
                > >>>> BindingFlags.Ge tProperty, null, oRows, null);
                > >>>> oCols = oRange.GetType( ).InvokeMember( "Columns",
                > >>>> BindingFlags.Ge tProperty, null, oRange, null);
                > >>>> oColCount = oCols.GetType() .InvokeMember(" Count",
                > >>>> BindingFlags.Ge tProperty, null, oCols, null);
                > >>>> for (int i = 1; i <= (int)oColCount; i++)
                > >>>> {
                > >>>> for (int j = 1; j <= (int)oRowCount; j++)
                > >>>> {
                > >>>> Parameters = new Object[2];
                > >>>> Parameters[0] = j;
                > >>>> Parameters[1] = i;
                > >>>> oValue = new Object();
                > >>>> oCell = new Object();
                > >>>> oCell = oRange.GetType( ).InvokeMember( "Cells",
                > >>>> BindingFlags.Ge tProperty, null, oRange, Parameters);
                > >>>> oValue = oCell.GetType() .InvokeMember(" Value",
                > >>>> BindingFlags.Ge tProperty, null, oCell, null);
                > >>>> total += (double)oValue;
                > >>>> }
                > >>>> }
                > >>>> return total;
                > >>>> }
                > >>>>
                > >>>>
                > >>>> Or is there a better way?
                > >>>>
                > >>>> Thanks
                > >>>>
                > >>>> Alan
                > >>>>
                > >>>>
                > >>>>
                > >>>> "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om>
                > >>>> wrote in message news:OSx564zBGH A.2920@tk2msftn gp13.phx.gbl...
                > >>>>> Alan,
                > >>>>>
                > >>>>> The reason this works in VB is that the VB compiler will[/color][/color][/color]
                translate[color=blue][color=green][color=darkred]
                > >>>>> property and method calls on variables of type object to be[/color][/color][/color]
                reflection[color=blue][color=green][color=darkred]
                > >>>>> calls, which cause your code to work.
                > >>>>>
                > >>>>> Unfortunately, C# doesn't support this functionality. You will
                > >>>>> have to use reflection to get the member names and then invoke them
                > >>>>> like that.
                > >>>>>
                > >>>>> OR, you could set a reference to the interop assemblies for[/color][/color][/color]
                Excel,[color=blue][color=green][color=darkred]
                > >>>>> and cast the object passed into your method into one of those[/color][/color][/color]
                classes[color=blue][color=green][color=darkred]
                > >>>>> in the interop assembly. This would prevent you from having to do[/color][/color][/color]
                any[color=blue][color=green][color=darkred]
                > >>>>> late binding.
                > >>>>>
                > >>>>> Also, you should be careful of the operations you are performing.
                > >>>>> When you call methods on any object in Excel, you are creating a
                > >>>>> runtime callable wrapper which should be disposed of if you aren't
                > >>>>> using it anymore. In the case of your Path property, you should
                > >>>>> assign the result of ThisWorkbook to a variable, then pass that to[/color][/color][/color]
                the[color=blue][color=green][color=darkred]
                > >>>>> static ReleaseComObjec t method on the Marshal class.
                > >>>>>
                > >>>>> Hope this helps.
                > >>>>>
                > >>>>>
                > >>>>> --
                > >>>>> - Nicholas Paldino [.NET/C# MVP]
                > >>>>> - mvp@spam.guard. caspershouse.co m
                > >>>>>
                > >>>>> "Alan Roberts" <alan@statistix l.co.uk> wrote in message
                > >>>>> news:%23FJb3JuB GHA.2704@TK2MSF TNGP15.phx.gbl. ..
                > >>>>>> Can someone please explain the following for me...
                > >>>>>>
                > >>>>>> I am trying to link to a .NET DLL from Excel. Excel needs to pass[/color][/color][/color]
                a[color=blue][color=green][color=darkred]
                > >>>>>> reference to itself to the DLL and then the DLL needs to perform[/color][/color][/color]
                some[color=blue][color=green][color=darkred]
                > >>>>>> work on the running instance of Excel via that reference. As an
                > >>>>>> example, a VB DLL to return the path to the current active workbook
                > >>>>>> contains the following (in addition to the COM GUIDS automatically
                > >>>>>> added to a new COMClass)...
                > >>>>>>
                > >>>>>> Public Class Class1
                > >>>>>> Public Sub New()
                > >>>>>> MyBase.New()
                > >>>>>> End Sub
                > >>>>>> Private gExcel As Object
                > >>>>>> Public Property Excel() As Object
                > >>>>>> Set(ByVal value As Object)
                > >>>>>> gExcel = value
                > >>>>>> End Set
                > >>>>>> Get
                > >>>>>> Excel = gExcel
                > >>>>>> End Get
                > >>>>>> End Property
                > >>>>>> Public Function Path() As String
                > >>>>>> Return Excel.ThisWorkb ook.Path
                > >>>>>> End Function
                > >>>>>> End Class
                > >>>>>>
                > >>>>>> After adding a refernece to the DLL, a macro in Excel could call[/color][/color][/color]
                this[color=blue][color=green][color=darkred]
                > >>>>>> as follows
                > >>>>>>
                > >>>>>> Sub VBTest()
                > >>>>>> Dim VBTest As New VBExcelTest.Cla ss1
                > >>>>>> Set VBTest.Excel = Application
                > >>>>>> Debug.Print VBTest.Path
                > >>>>>> End Sub
                > >>>>>>
                > >>>>>> This all work fine
                > >>>>>>
                > >>>>>> How can I do the same thing using C#? If I try to create a DLL[/color][/color][/color]
                with[color=blue][color=green][color=darkred]
                > >>>>>> equivalent(?) code eg
                > >>>>>>
                > >>>>>> public class Class1
                > >>>>>> {
                > >>>>>> public Class1(){
                > >>>>>> }
                > >>>>>> private object gExcel;
                > >>>>>> public object Excel{
                > >>>>>> get{
                > >>>>>> return gExcel;
                > >>>>>> }
                > >>>>>> set{
                > >>>>>> gExcel = value;
                > >>>>>> }
                > >>>>>> }
                > >>>>>> public string Path(){
                > >>>>>> return Excel.ThisWorkb ook.Path;
                > >>>>>> }
                > >>>>>> }
                > >>>>>>
                > >>>>>> I get a compile error saying that - 'object' does not contain a
                > >>>>>> definition for 'ThisWorkbook'
                > >>>>>>
                > >>>>>> How can I get this to work?
                > >>>>>>
                > >>>>>> Thanks
                > >>>>>>
                > >>>>>> Alan
                > >>>>>>
                > >>>>>
                > >>>>>
                > >>>>
                > >>>>
                > >>>
                > >>>
                > >>
                > >>[/color]
                > >
                > >[/color]
                >
                >[/color]


                Comment

                Working...