Home All Groups Group Topic Archive Search About
Author
4 Feb 2009 6:23 PM
Andy Smirala
Hi, please i have a question abot sending data to excel from VB60.

All works fine, but when i export second time,
it doesn't work.

I suppose, i need close excel object, or something, but i don't know how.

Here is my code :

Private Sub Command2_Click()
'definition
Dim oExcel As Object
Dim oBook As Object
Dim oSheet As Object

'Start a new workbook in Excel
Set oExcel = CreateObject("Excel.Application")
Set oBook = oExcel.Workbooks.Add
Set oSheet = oBook.Worksheets(1)

oExcel.Visible = True

With oSheet
    .Range("B1").Value = "my program " & App.Major & "." & App.Minor & "." &
App.Revision
    .Range("B1").Font.Name = "Verdana"
    .Range("B1").Font.Size = 8
    .Range("B3").Value = Text5.Text
    .Range("B4").Value = Text3.Text
    .Range("B5").Value = Text4.Text
    .Range("B3:B5").Font.Bold = True

End With

oSheet.Range("B3:E3").Select
With Selection
    .HorizontalAlignment = xlCenter
    .VerticalAlignment = xlBottom
    .WrapText = False
    .Orientation = 0
    .AddIndent = False
    .IndentLevel = 0
    .ShrinkToFit = False
    .ReadingOrder = xlContext
    .MergeCells = False
End With
Selection.Merge
Range("B4:E4").Select
With Selection
    .HorizontalAlignment = xlCenter
    .VerticalAlignment = xlBottom
    .WrapText = False
    .Orientation = 0
    .AddIndent = False
    .IndentLevel = 0
    .ShrinkToFit = False
    .ReadingOrder = xlContext
    .MergeCells = False
End With
Selection.Merge
Range("B5:E5").Select
With Selection
    .HorizontalAlignment = xlCenter
    .VerticalAlignment = xlBottom
    .WrapText = False
    .Orientation = 0
    .AddIndent = False
    .IndentLevel = 0
    .ShrinkToFit = False
    .ReadingOrder = xlContext
    .MergeCells = False
End With
Selection.Merge
Range("B3:E5").Select
With Selection
    .HorizontalAlignment = xlLeft
    .VerticalAlignment = xlBottom
    .WrapText = False
    .Orientation = 0
    .AddIndent = False
    .IndentLevel = 0
    .ShrinkToFit = False
    .ReadingOrder = xlContext
End With
Selection.Borders(xlDiagonalDown).LineStyle = xlNone
Selection.Borders(xlDiagonalUp).LineStyle = xlNone
With Selection.Borders(xlEdgeLeft)
    .LineStyle = xlContinuous
    .ColorIndex = 0
    .TintAndShade = 0
    .Weight = xlThin
End With
With Selection.Borders(xlEdgeTop)
    .LineStyle = xlContinuous
    .ColorIndex = 0
    .TintAndShade = 0
    .Weight = xlThin
End With
With Selection.Borders(xlEdgeBottom)
    .LineStyle = xlContinuous
    .ColorIndex = 0
    .TintAndShade = 0
    .Weight = xlThin
End With
With Selection.Borders(xlEdgeRight)
    .LineStyle = xlContinuous
    .ColorIndex = 0
    .TintAndShade = 0
    .Weight = xlThin
End With
Selection.Borders(xlInsideVertical).LineStyle = xlNone
Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
With Selection.Interior
    .Pattern = xlSolid
    .PatternColorIndex = xlAutomatic
    .ThemeColor = xlThemeColorAccent2
    .TintAndShade = 0.799981688894314
    .PatternTintAndShade = 0
End With

ActiveWindow.DisplayGridlines = False

End Sub

---------------------------------------------------------------------------------------
When i press a command2, it works fine, excel opens, data are there and
format is OK,
but second time - program opens second excel file (this is OK), exporting
data (OK),
but format cells doesn't work. And :
Message : Run-time error 1004
Application-defined or object-defined error

I suppose, maybe i need close "connection" to excel at the end of
command2.click,
but i tried
Set oExcel = Nothing
Set oBook = Nothing
Set oSheet = Nothing

but it doesn't work.

any ideas ?

thanks
andy

Author
4 Feb 2009 8:07 PM
Andy Smirala
thanks to all

i transfered my code from early to late binding,
so i have not reference to excel.object library

and it is working fine now..

The problem was, i didn't want to close excel.
My program makes data export, so i don't want to close sheet.
When customer changes the source data, he can make export again, but
i want to open a new instance of excel.

Now, with late binding it works.

thank you
andy


Show quoteHide quote
"Andy Smirala" <i***@klimashop.sk> wrote in message
news:eUfwqWvhJHA.2516@TK2MSFTNGP05.phx.gbl...
> Hi, please i have a question abot sending data to excel from VB60.
>
> All works fine, but when i export second time,
> it doesn't work.
>
> I suppose, i need close excel object, or something, but i don't know how.
>
> Here is my code :
>
> Private Sub Command2_Click()
> 'definition
> Dim oExcel As Object
> Dim oBook As Object
> Dim oSheet As Object
>
> 'Start a new workbook in Excel
> Set oExcel = CreateObject("Excel.Application")
> Set oBook = oExcel.Workbooks.Add
> Set oSheet = oBook.Worksheets(1)
>
> oExcel.Visible = True
>
> With oSheet
>    .Range("B1").Value = "my program " & App.Major & "." & App.Minor & "."
> & App.Revision
>    .Range("B1").Font.Name = "Verdana"
>    .Range("B1").Font.Size = 8
>    .Range("B3").Value = Text5.Text
>    .Range("B4").Value = Text3.Text
>    .Range("B5").Value = Text4.Text
>    .Range("B3:B5").Font.Bold = True
>
> End With
>
> oSheet.Range("B3:E3").Select
> With Selection
>    .HorizontalAlignment = xlCenter
>    .VerticalAlignment = xlBottom
>    .WrapText = False
>    .Orientation = 0
>    .AddIndent = False
>    .IndentLevel = 0
>    .ShrinkToFit = False
>    .ReadingOrder = xlContext
>    .MergeCells = False
> End With
> Selection.Merge
> Range("B4:E4").Select
> With Selection
>    .HorizontalAlignment = xlCenter
>    .VerticalAlignment = xlBottom
>    .WrapText = False
>    .Orientation = 0
>    .AddIndent = False
>    .IndentLevel = 0
>    .ShrinkToFit = False
>    .ReadingOrder = xlContext
>    .MergeCells = False
> End With
> Selection.Merge
> Range("B5:E5").Select
> With Selection
>    .HorizontalAlignment = xlCenter
>    .VerticalAlignment = xlBottom
>    .WrapText = False
>    .Orientation = 0
>    .AddIndent = False
>    .IndentLevel = 0
>    .ShrinkToFit = False
>    .ReadingOrder = xlContext
>    .MergeCells = False
> End With
> Selection.Merge
> Range("B3:E5").Select
> With Selection
>    .HorizontalAlignment = xlLeft
>    .VerticalAlignment = xlBottom
>    .WrapText = False
>    .Orientation = 0
>    .AddIndent = False
>    .IndentLevel = 0
>    .ShrinkToFit = False
>    .ReadingOrder = xlContext
> End With
> Selection.Borders(xlDiagonalDown).LineStyle = xlNone
> Selection.Borders(xlDiagonalUp).LineStyle = xlNone
> With Selection.Borders(xlEdgeLeft)
>    .LineStyle = xlContinuous
>    .ColorIndex = 0
>    .TintAndShade = 0
>    .Weight = xlThin
> End With
> With Selection.Borders(xlEdgeTop)
>    .LineStyle = xlContinuous
>    .ColorIndex = 0
>    .TintAndShade = 0
>    .Weight = xlThin
> End With
> With Selection.Borders(xlEdgeBottom)
>    .LineStyle = xlContinuous
>    .ColorIndex = 0
>    .TintAndShade = 0
>    .Weight = xlThin
> End With
> With Selection.Borders(xlEdgeRight)
>    .LineStyle = xlContinuous
>    .ColorIndex = 0
>    .TintAndShade = 0
>    .Weight = xlThin
> End With
> Selection.Borders(xlInsideVertical).LineStyle = xlNone
> Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
> With Selection.Interior
>    .Pattern = xlSolid
>    .PatternColorIndex = xlAutomatic
>    .ThemeColor = xlThemeColorAccent2
>    .TintAndShade = 0.799981688894314
>    .PatternTintAndShade = 0
> End With
>
> ActiveWindow.DisplayGridlines = False
>
> End Sub
>
> ---------------------------------------------------------------------------------------
> When i press a command2, it works fine, excel opens, data are there and
> format is OK,
> but second time - program opens second excel file (this is OK), exporting
> data (OK),
> but format cells doesn't work. And :
> Message : Run-time error 1004
> Application-defined or object-defined error
>
> I suppose, maybe i need close "connection" to excel at the end of
> command2.click,
> but i tried
> Set oExcel = Nothing
> Set oBook = Nothing
> Set oSheet = Nothing
>
> but it doesn't work.
>
> any ideas ?
>
> thanks
> andy
>
>
Author
1 Mar 2009 11:04 PM
GS
Hi Andy,

The issue of early/late binding is not a factor in getting your app to work
properly with Excel. The advantage of using early binding in VB6 is to expose
the Excel object model so you can code qualified refs to its objects. This
would have obviated the issues resulting from using the recorded macro code
because it will force qualified refs with your app or it won't compile. Late
binding will not give you this bonus!

I have included some code, which you may find useful, that I use to automate
Excel from a VB6 FrontLoader app. It does what you want to do using its own
instance of Excel, regardless if the user has an instance of Excel already
running. This makes it independant of any running instances and so obviates
the shutdown dilemna.

You will need to modify the code to suit your needs, but here's how it works
"as is".

It uses late binding to check if Excel is installed on the user's machine
using the CreateObject() function. If this generates an error, it gracefully
notifies the user that Excel is required and shuts itself down. In your case,
it appears to need to gracefully abort a procedure so you'll have to modify
it for doing so.

If Excel does exist it starts a new instance of it and does its thing. In my
useage, it makes the instance visible and turns over control of it to the
user because the application using Excel is actually an Excel addin
(MyApp.xla). In this case, the VB6 FrontLoader unloads the refs to the
workbook and the instance of Excel and quits. Then the user proceeds working
in that instance the FrontLoader created. This, however, does not have to be
the case for you as your app won't unload its refs until it's done or the
user closes the instance (assuming you make it visible and give the user
control of it).

*****************************************
The following code is placed in a standard module

Public Sub Main()

  Dim bHasExcel As Boolean, bLicensed As Boolean
  Dim xlApp As Excel.Application
  Dim wkbAPP As Excel.Workbook
  Dim sMsg As String

  'Verify that we can automate Excel on this computer.
  bHasExcel = bExcelAvailable()

  'If not running as demo then check License hasn't expired
  If Not bDemoOnly() Then bLicensed = bValidateLicense Else bLicensed = True

  If bHasExcel Then
    If bLicensed Then
      'If we successfully automated Excel, load our Excel app and turn it
over to the user.
      Set xlApp = New Excel.Application
      With xlApp
        Set wkbAPP = .Workbooks.Open(FileName:=App.Path & "\" & gszApp_Wkb,
Password:=gszPWRD)
        .Visible = True
        .UserControl = True
     End With
      wkbAPP.RunAutoMacros xlAutoOpen
      Set wkbAPP = Nothing
      Set xlApp = Nothing
    Else
      'Notify the user license has expired and give user opportunity to
enter License Key or Register
      sMsg = "Your License has expired!" & vbCrLf
      sMsg = sMsg & "You must have a valid license to continue using this
product." & vbCrLf
      sMsg = sMsg & vbCrLf
      sMsg = sMsg & "Options:" & vbCrLf
      sMsg = sMsg & "1.  Enter and validate your License Key." & vbCrLf
      sMsg = sMsg & "2.  Register your product now, obtain a License Key,
then try again later." & vbCrLf
      sMsg = sMsg & "3.  Cancel."
      Load fRegisterApp
      With fRegisterApp
        .lblLicenseKey.Caption = sMsg
        .Show
      End With
      Exit Sub
    End If
  Else
    'If we failed to get a reference to Excel, display a message to the user
and exit.
    sMsg = "This application requires Excel to be installed on your computer."
    sMsg = sMsg & vbCrLf
    sMsg = sMsg & "Excel failed to start. This application can not continue!"
    MsgBox sMsg, vbCritical, "Startup Failure!"
  End If

End Sub

Public Function bExcelAvailable() As Boolean
    Dim xlApp As Object
    'Attempt to start an instance of Excel.
    On Error Resume Next
      Set xlApp = CreateObject("Excel.Application")
    On Error GoTo 0
    'Return the result of the test.
    If Not xlApp Is Nothing Then
      'If we started Excel we need to close it.
      xlApp.Quit
      Set xlApp = Nothing
      bExcelAvailable = True
    Else
      bExcelAvailable = False
    End If
End Function  'bExcelAvailable()
*****************************************

HTH
Kind regards,
Garry
--

Show quoteHide quote
"Andy Smirala" wrote:

> thanks to all
>
> i transfered my code from early to late binding,
> so i have not reference to excel.object library
>
> and it is working fine now..
>
> The problem was, i didn't want to close excel.
> My program makes data export, so i don't want to close sheet.
> When customer changes the source data, he can make export again, but
> i want to open a new instance of excel.
>
> Now, with late binding it works.
>
> thank you
> andy
>
>
> "Andy Smirala" <i***@klimashop.sk> wrote in message
> news:eUfwqWvhJHA.2516@TK2MSFTNGP05.phx.gbl...
> > Hi, please i have a question abot sending data to excel from VB60.
> >
> > All works fine, but when i export second time,
> > it doesn't work.
> >
> > I suppose, i need close excel object, or something, but i don't know how.
> >
> > Here is my code :
> >
> > Private Sub Command2_Click()
> > 'definition
> > Dim oExcel As Object
> > Dim oBook As Object
> > Dim oSheet As Object
> >
> > 'Start a new workbook in Excel
> > Set oExcel = CreateObject("Excel.Application")
> > Set oBook = oExcel.Workbooks.Add
> > Set oSheet = oBook.Worksheets(1)
> >
> > oExcel.Visible = True
> >
> > With oSheet
> >    .Range("B1").Value = "my program " & App.Major & "." & App.Minor & "."
> > & App.Revision
> >    .Range("B1").Font.Name = "Verdana"
> >    .Range("B1").Font.Size = 8
> >    .Range("B3").Value = Text5.Text
> >    .Range("B4").Value = Text3.Text
> >    .Range("B5").Value = Text4.Text
> >    .Range("B3:B5").Font.Bold = True
> >
> > End With
> >
> > oSheet.Range("B3:E3").Select
> > With Selection
> >    .HorizontalAlignment = xlCenter
> >    .VerticalAlignment = xlBottom
> >    .WrapText = False
> >    .Orientation = 0
> >    .AddIndent = False
> >    .IndentLevel = 0
> >    .ShrinkToFit = False
> >    .ReadingOrder = xlContext
> >    .MergeCells = False
> > End With
> > Selection.Merge
> > Range("B4:E4").Select
> > With Selection
> >    .HorizontalAlignment = xlCenter
> >    .VerticalAlignment = xlBottom
> >    .WrapText = False
> >    .Orientation = 0
> >    .AddIndent = False
> >    .IndentLevel = 0
> >    .ShrinkToFit = False
> >    .ReadingOrder = xlContext
> >    .MergeCells = False
> > End With
> > Selection.Merge
> > Range("B5:E5").Select
> > With Selection
> >    .HorizontalAlignment = xlCenter
> >    .VerticalAlignment = xlBottom
> >    .WrapText = False
> >    .Orientation = 0
> >    .AddIndent = False
> >    .IndentLevel = 0
> >    .ShrinkToFit = False
> >    .ReadingOrder = xlContext
> >    .MergeCells = False
> > End With
> > Selection.Merge
> > Range("B3:E5").Select
> > With Selection
> >    .HorizontalAlignment = xlLeft
> >    .VerticalAlignment = xlBottom
> >    .WrapText = False
> >    .Orientation = 0
> >    .AddIndent = False
> >    .IndentLevel = 0
> >    .ShrinkToFit = False
> >    .ReadingOrder = xlContext
> > End With
> > Selection.Borders(xlDiagonalDown).LineStyle = xlNone
> > Selection.Borders(xlDiagonalUp).LineStyle = xlNone
> > With Selection.Borders(xlEdgeLeft)
> >    .LineStyle = xlContinuous
> >    .ColorIndex = 0
> >    .TintAndShade = 0
> >    .Weight = xlThin
> > End With
> > With Selection.Borders(xlEdgeTop)
> >    .LineStyle = xlContinuous
> >    .ColorIndex = 0
> >    .TintAndShade = 0
> >    .Weight = xlThin
> > End With
> > With Selection.Borders(xlEdgeBottom)
> >    .LineStyle = xlContinuous
> >    .ColorIndex = 0
> >    .TintAndShade = 0
> >    .Weight = xlThin
> > End With
> > With Selection.Borders(xlEdgeRight)
> >    .LineStyle = xlContinuous
> >    .ColorIndex = 0
> >    .TintAndShade = 0
> >    .Weight = xlThin
> > End With
> > Selection.Borders(xlInsideVertical).LineStyle = xlNone
> > Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
> > With Selection.Interior
> >    .Pattern = xlSolid
> >    .PatternColorIndex = xlAutomatic
> >    .ThemeColor = xlThemeColorAccent2
> >    .TintAndShade = 0.799981688894314
> >    .PatternTintAndShade = 0
> > End With
> >
> > ActiveWindow.DisplayGridlines = False
> >
> > End Sub
> >
> > ---------------------------------------------------------------------------------------
> > When i press a command2, it works fine, excel opens, data are there and
> > format is OK,
> > but second time - program opens second excel file (this is OK), exporting
> > data (OK),
> > but format cells doesn't work. And :
> > Message : Run-time error 1004
> > Application-defined or object-defined error
> >
> > I suppose, maybe i need close "connection" to excel at the end of
> > command2.click,
> > but i tried
> > Set oExcel = Nothing
> > Set oBook = Nothing
> > Set oSheet = Nothing
> >
> > but it doesn't work.
> >
> > any ideas ?
> >
> > thanks
> > andy
> >
> >
>
>
>
Author
2 Mar 2009 12:07 AM
MikeD
Show quote Hide quote
"GS" <G*@discussions.microsoft.com> wrote in message
news:77B6823C-2F3E-4DA3-A8E5-6AEE82C7238E@microsoft.com...
> Hi Andy,
>
> The issue of early/late binding is not a factor in getting your app to
> work
> properly with Excel. The advantage of using early binding in VB6 is to
> expose
> the Excel object model so you can code qualified refs to its objects. This
> would have obviated the issues resulting from using the recorded macro
> code
> because it will force qualified refs with your app or it won't compile.
> Late
> binding will not give you this bonus!


You do realize it's been nearly a month since there's been any discussion in
this thread, right?

And also that Andy replied on 02/04 that the problem was resolved?

I won't even go into the problems that I have with the code you posted.  <g>

--
Mike
Author
4 Mar 2009 6:06 AM
GS
Yes, Mike, I do realize it's been awhile since there's been any discussion in
this thread. I wasn't looking to revive discussion. -I posted only to provide
suggestions that relate to the topic, primarily for the benefit of readers
looking through topics for help.

Sorry if you have problems with the posted code. I do mention it will need
to be modified to suit a situation. It does show opening/closing Excel in a
VB app (which is the subject of this thread), as well as turning control of
it over to the user.

Obviously the refs to the various objects in my app need to be changed, as
well as the workbook ref. It works "as is" for an existing workbook and so
would require using the Add method to go with a new workbook.

As I mentioned in my post, the code works reliably and consistently with
dozens of my projects. If you're interested, I'd be happy to help resolve any
problems you're having with the code.

Kind regards,
Garry
--

Show quoteHide quote
"MikeD" wrote:

> You do realize it's been nearly a month since there's been any discussion in
> this thread, right?
>
> And also that Andy replied on 02/04 that the problem was resolved?
>
> I won't even go into the problems that I have with the code you posted.  <g>
>
> --
> Mike
>
>
Author
4 Mar 2009 9:45 AM
Peter T
Hi Garry,

I am reasonably familiar with Excel so hope you don't mind my butting in
with a few comments about your OP.

"The issue of early/late binding is not a factor in getting your app to
work properly with Excel."

The issue for the OP was he forgot to explicitly qualify "Selection" to the
Excel object. This is not related to early/late binding.

"It [your code example] uses late binding to check if Excel is installed on
the user's machine"

From within a routine, with various early bound to Excel object
declarations, you call another routing to attempt to create an instance,
destroy it, then create yet another instance. Whilst no doubt that works it
is quite unnecessary (irrespective of binding). I suspect there might be
issues if your start up routine with the early bound Excel declarations is
used in a machine without Excel (which is what you are doing). I can't test
as I'd need to uninstall Excel.

Assuming Excel is installed, if in doubt attempt to create with CreateObject
(but keep it), in order to hand over to user simply make the instance
visible with at least one loaded workbook. Explicitly destroy all object
references to the instance and anything in it that would not otherwise
naturally fall out of scope.

As for binding, unless you are sure your app is compiled against the lowest
Excel version of any user, convert to late binding before deploying.

Just to be picky about your example, surely need some error handling in case
cannot load the named Workbook from file.

A quick example of how to create and hand over an Excel instance to user -

Private mObjXL As Object
'Private Sub Command1_Click()
Private Sub Form_Click()
Dim objWS As Object
Dim objWB As Object
Dim objXL As Object

    If MakeXL Then
        Set objWB = mObjXL.Workbooks.Add
        Set objWS = objWB.Worksheets(1)
        With objWS.Range("B1:B5")
            .Cells(1, 1) = "This originally automated instance is"
            .Cells(2, 1) = "just like any other except"
            .Cells(3, 1) = "the author forgot to explicitly load"
            .Cells(4, 1) = "any installed addins (from the Addins
collection)"
            .Cells(5, 1) = "and Personal.xls (find in xl's startup folder)"
            .Cells(6, 1) = "(and do ''RunAutoMacros'' on each)"
        End With

        mObjXL.Visible = True
        Set mObjXL = Nothing    ' hand over to user
    End If
    Unload Me
End Sub
Function MakeXL() As Boolean
    On Error Resume Next
    Set mObjXL = CreateObject("excel.application")
    If mObjXL Is Nothing Then
        MsgBox "Cannot start Excel"
    Else: MakeXL = True
    End If
End Function

If using early binding and unsure if Excel exists, test by attempting to
create it as above (and keep it) before calling any routine with early bound
declarations and/or use of Excel named constants.

Regards,
Peter T


Show quoteHide quote
"GS" <G*@discussions.microsoft.com> wrote in message
news:9BC995D0-930D-48B4-8306-26A11A86BF2F@microsoft.com...
> Yes, Mike, I do realize it's been awhile since there's been any discussion
> in
> this thread. I wasn't looking to revive discussion. -I posted only to
> provide
> suggestions that relate to the topic, primarily for the benefit of readers
> looking through topics for help.
>
> Sorry if you have problems with the posted code. I do mention it will need
> to be modified to suit a situation. It does show opening/closing Excel in
> a
> VB app (which is the subject of this thread), as well as turning control
> of
> it over to the user.
>
> Obviously the refs to the various objects in my app need to be changed, as
> well as the workbook ref. It works "as is" for an existing workbook and so
> would require using the Add method to go with a new workbook.
>
> As I mentioned in my post, the code works reliably and consistently with
> dozens of my projects. If you're interested, I'd be happy to help resolve
> any
> problems you're having with the code.
>
> Kind regards,
> Garry
> --
>
> "MikeD" wrote:
>
>> You do realize it's been nearly a month since there's been any discussion
>> in
>> this thread, right?
>>
>> And also that Andy replied on 02/04 that the problem was resolved?
>>
>> I won't even go into the problems that I have with the code you posted.
>> <g>
>>
>> --
>> Mike
>>
>>
Author
4 Mar 2009 5:31 PM
GS
Hello Peter,

Thank you for your input. I don't consider you to be 'butting in' since you
already were involved previously, and your input (and anyone else's) is
welcome because learning is always an ongoing process. After all, isn't that
why we're here in this forum?

I agree with you on your recommendations, and your code sample. There is a
specific reason why I test for (start and quit) Excel before allowing my app
to proceed, then use another instance of it for my app. I guess some
background info would help here so I'll be brief with that and continue with
my explanation afterward.

Firstly, the code I posted (minus the app registration and licensing
content) was given to me by one of the leading MS Office Automation experts
on the planet. I have added only my startup app registration and licensing
checks. Otherwise, the rest is part of the FrontLoader.vbp I received from my
mentor.

My projects are primarily MS Office Automation apps that either control a
MSO app from a VB6.exe or are a MSO addin interfacing with VB6.DLLs. The
primary MSO app I work with is Excel. My primary programming background is
VBA. While I do have a few VB6 stand-alone apps, they are not the thrust of
my work. In implimenting MSO Automation I never want to use an instance of a
MSO app created with CreateObject() or GetObject() because I would be
hijacking the user's default app. Here's why I wouldn't want to do that:

1.  In most cases, my apps will be customizing the Excel interface such
that, with some of those apps, the user may not realize they are actually
working in Excel. That said, it wouldn't be prudent to do this especially if
the user happens to be using Excel at the time my app is started.

2.  Automated instances of Excel are clean, raw versions. This means they
don't have any addins installed, nor do they execute any macro security
features. This allows my addin to run independantly in its own instance of
Excel.

3.  In cases of controlling MSO apps from a VB6.exe I may want them to run
in the background without the user knowing. This ensures me an uncompromised,
fully qualified object ref which precludes the need for using a separate
instance.

4.  If users have more than one of my apps open, using separate instances is
easier and safer to impliment. Could you imagine what a nightmare it would be
toggling the UI settings for each app if they all were running a single
instance?

5.  Early binding is always used for the executable (main app). Late binding
is used (and required) for testing only. Always, the earliest version of
Excel is the ref for early binding. In my case, that's the Excel9 Object
Library. The individual apps handle forward version features with code
internally. All of my apps work with Excel9 through Excel12, and are tested
in each version on Windows5/6 before release. Version-specific features are,
therefore, no problem.

While I agree with you that the issue with the OP was using "Select" and
"Selection", he does attribute early/late binding as the fix. This suggests
some confusion on his part. As you will probably know, rarely is it necessary
to "select" anything when automating Excel and it's good practice not to
because it forces qualified refs to be required. Using fully qualified refs
obviates any errors that might be raised (assumes existence of the object is
checked)

<Just to be picky about your example, surely need some error handling in
case cannot load the named Workbook from file.>
The workbook being opened is the addin (default app). I think a check for
its existence is a good idea. I never thought to use one here because it's
the default app. I have a bFileExists() function that I always use before
trying to access any file and I'll insert a call to it. After all who
knows.., -someone may have moved/deleted the file. Thanks for bring this to
my attention.

Finally, I must confess that I'm a newbie to programming for the most part.
I'm a machinist by profession. I fell victim to ALS (Lou Gehrig's) back in
the early 1990's so I'm forced to spend my waking hours on my butt. I decided
learning programming was a good idea because my years of business experience
and the solutions I came up with could be shared and thus put to good use by
others. I started with Lotus123 and migrated to Excel4, and have stuck with
it ever since. My formal schooling was business through high school and
college. This gave me tools I could use to make a business out of working at
my hobby. My accountant suggested I might want to share some of my business
solutions with a few of his clients. This woke me up to the fact that most
tradespeople who work at their trade don't have the business skills to give
them the ability to administrate that business in a proficent manner. Hence,
I have new purpose in my life...

Kind regards,
Garry
Author
5 Mar 2009 10:13 AM
Peter T
It sounds like you have tried to be very thorough with your approach.
FrontLoader.vbp was written by Rob Bovey and distributed in an Excel book he
co-authored with Bullen & Green. Indeed all well known in Excel land. The
demo does indeed start by attempting to create various Office apps. But
that's only as a prelude to starting "one" instance of Excel, after
confirming the other apps will be available if/as required for other
purposes later on.

I notice in the VBA example (which goes with the VB6 demo) it is clearly
illustrated NOT to combine any early binding stuff in a particular module
until confirmed that it is available for use in other modules. This is in
direct contrast to your original code, where you not only include in the
same module but within the same startup routine (I also commented on that
last time). In VBA to do otherwise would cause the app to blow (if the
referenced app's were not available), though not quite the same in VB6.

I've read your adjacent post and sort of see your intentions. I still think
quite unnecessary to create an instance of Excel, just to test you can,
destroy it, then immediately create another instance. Surely something like
the following will serve just as well with half the effort -

' assumes a reference set to Excel
Sub Main()
Dim objXL As Object
    If GetExcel(objXL) Then
        DoStuff objXL
    Else
        MsgBox "Failed to start Excel"
    End If
    ' objXL falls out of scope here,
    ' but if module level explicitly destroy objXL
End Sub
Function GetExcel(objXL As Object) As Boolean
    On Error Resume Next
    Set objXL = CreateObject("excel.application")
    GetExcel = Not objXL Is Nothing
End Function

Sub DoStuff(xlApp As Excel.Application)
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet

    If 1 + 1 = 3 Then
        MsgBox "Precheck stuff failed"
    Else
        Set wb = xlApp.Workbooks.Add
        Set ws = wb.Worksheets(1)
        ws.Range("b2") = "hand over to user"
        ws.Range("b3") = "installed addins and Personal.xls not loaded"
        xlApp.WindowState = xlMaximized ' -4137
        xlApp.Visible = True
    End If

End Sub

Regards,
Peter T


Show quoteHide quote
"GS" <G*@discussions.microsoft.com> wrote in message
news:1440B96F-3DD5-41D6-B3B3-CFE14A8946CC@microsoft.com...
> Hello Peter,
>
> Thank you for your input. I don't consider you to be 'butting in' since
> you
> already were involved previously, and your input (and anyone else's) is
> welcome because learning is always an ongoing process. After all, isn't
> that
> why we're here in this forum?
>
> I agree with you on your recommendations, and your code sample. There is a
> specific reason why I test for (start and quit) Excel before allowing my
> app
> to proceed, then use another instance of it for my app. I guess some
> background info would help here so I'll be brief with that and continue
> with
> my explanation afterward.
>
> Firstly, the code I posted (minus the app registration and licensing
> content) was given to me by one of the leading MS Office Automation
> experts
> on the planet. I have added only my startup app registration and licensing
> checks. Otherwise, the rest is part of the FrontLoader.vbp I received from
> my
> mentor.
>
> My projects are primarily MS Office Automation apps that either control a
> MSO app from a VB6.exe or are a MSO addin interfacing with VB6.DLLs. The
> primary MSO app I work with is Excel. My primary programming background is
> VBA. While I do have a few VB6 stand-alone apps, they are not the thrust
> of
> my work. In implimenting MSO Automation I never want to use an instance of
> a
> MSO app created with CreateObject() or GetObject() because I would be
> hijacking the user's default app. Here's why I wouldn't want to do that:
>
> 1.  In most cases, my apps will be customizing the Excel interface such
> that, with some of those apps, the user may not realize they are actually
> working in Excel. That said, it wouldn't be prudent to do this especially
> if
> the user happens to be using Excel at the time my app is started.
>
> 2.  Automated instances of Excel are clean, raw versions. This means they
> don't have any addins installed, nor do they execute any macro security
> features. This allows my addin to run independantly in its own instance of
> Excel.
>
> 3.  In cases of controlling MSO apps from a VB6.exe I may want them to run
> in the background without the user knowing. This ensures me an
> uncompromised,
> fully qualified object ref which precludes the need for using a separate
> instance.
>
> 4.  If users have more than one of my apps open, using separate instances
> is
> easier and safer to impliment. Could you imagine what a nightmare it would
> be
> toggling the UI settings for each app if they all were running a single
> instance?
>
> 5.  Early binding is always used for the executable (main app). Late
> binding
> is used (and required) for testing only. Always, the earliest version of
> Excel is the ref for early binding. In my case, that's the Excel9 Object
> Library. The individual apps handle forward version features with code
> internally. All of my apps work with Excel9 through Excel12, and are
> tested
> in each version on Windows5/6 before release. Version-specific features
> are,
> therefore, no problem.
>
> While I agree with you that the issue with the OP was using "Select" and
> "Selection", he does attribute early/late binding as the fix. This
> suggests
> some confusion on his part. As you will probably know, rarely is it
> necessary
> to "select" anything when automating Excel and it's good practice not to
> because it forces qualified refs to be required. Using fully qualified
> refs
> obviates any errors that might be raised (assumes existence of the object
> is
> checked)
>
> <Just to be picky about your example, surely need some error handling in
> case cannot load the named Workbook from file.>
> The workbook being opened is the addin (default app). I think a check for
> its existence is a good idea. I never thought to use one here because it's
> the default app. I have a bFileExists() function that I always use before
> trying to access any file and I'll insert a call to it. After all who
> knows.., -someone may have moved/deleted the file. Thanks for bring this
> to
> my attention.
>
> Finally, I must confess that I'm a newbie to programming for the most
> part.
> I'm a machinist by profession. I fell victim to ALS (Lou Gehrig's) back in
> the early 1990's so I'm forced to spend my waking hours on my butt. I
> decided
> learning programming was a good idea because my years of business
> experience
> and the solutions I came up with could be shared and thus put to good use
> by
> others. I started with Lotus123 and migrated to Excel4, and have stuck
> with
> it ever since. My formal schooling was business through high school and
> college. This gave me tools I could use to make a business out of working
> at
> my hobby. My accountant suggested I might want to share some of my
> business
> solutions with a few of his clients. This woke me up to the fact that most
> tradespeople who work at their trade don't have the business skills to
> give
> them the ability to administrate that business in a proficent manner.
> Hence,
> I have new purpose in my life...
>
> Kind regards,
> Garry
Author
5 Mar 2009 11:32 PM
GS
Hi Peter,

You are quite correct in your assertion to source for the FrontLoader.vbp.
Though I did receive this directly from Rob prior to the release of that
book, it might be a good idea for me to open the CD and compare versions!<g>

The version I posted was only revised from the original in that Rob was
making the instance visible and turning it over to the user before opening
the app.xla. I reversed this order. Of course, a few global
constant/variables had to be respectively redefined as well. Otherwise, it's
pretty much the way I got it and I only had to add the app license and
registration content to use it.
--

As I mentioned, the bExcelAvailable() function resides in a separate module
(mFunctions.bas) where all my other test functions are stored. It was added
to my post only to demonstrate late binding open/close (,the latter being the
subject of this thread). Thus, the late binding test occurs in another
module; the early binding code is used only after confirmation is made. This
is done in the startup procedure because it's all this FrontLoader does.
Unless I misunderstand you about this, it is the understanding I have from
Rob as to how to use this project.

<AFAIK>I do use it in the context Rob intended it be used. In fact, in the
case of my version of the FrontLoader that I posted here, I have no intention
of using the tested instance. I admit the first version wasn't so clear about
that but the revised version makes this very apparent. The test just sets the
startup parameter bHasExcel which, in this case, is the only prerequesite for
continuing. Only after all other tests determine conditions are 'good to go'
do I create the instance I intend to use.

What you suggest is that I leave the test instance running. I agree with
your point in the context you're implying, which is  immediate use. That is
never my intention in a FrontLoader. This means I would have to add more code
to Sub Main() to destroy it if shutdown is neccessary by results of the
subsequent pre-start tests. It's six-of-one or half-dozen-of-another then,
isn't it? But since the function already exists for its intended purpose then
it makes sense to me to use it that way. They're self-contained tests. They
don't impede performance or require any maintenance. That's why they are
designated as 'test functions' and stored in my mFunctions.bas module. In
some cases, I may test for several MSO apps regardless of which one I use as
my app platform.

Please understand I make no contest that you are correct in your assertion
it isn't necessary to destroy the test instance. I also see that the Sub
Main() procedure could be easily revised to accomodate your suggestion. I've
never looked at this project beyond using it (almost) "as is" given its
source, but you can trust I will certainly discuss it with Rob. Often things
require a second set of eyes to make improvements beyond what the first set
of eyes could see. I know Rob and I both are receptive to this and I will
bring this to his attention.

p.s.: I suppose I should rename that module mTestFunctions.bas so it more
properly complies with my naming conventions. -It's a relic from early days
of getting my feet wet with VBA when I didn't know anything about naming
conventions.
--

Having the group of tests available in another module just facilitates the
ease of using them 'on demand' in a consistent fashion, without worry about
cleaning up if subsequent tests indicate a shutdown. Your noting of my
omission to check for the existence of my XLA file just defers the need of
any instance even further. The app license and registration check could be
lengthy depending on what user inputs may be required.

In other apps (VB/VBA), the MSO group is tested according to app useage.
This is also done at startup so I can set my AppState global parameters to
reflect what app features will be made available to the user. This determines
the .Enabled, .Visible, or .Locked state of respective menus/controls.
Usually, I will notify the user as to what/if any/why features are not going
to be available during the current session.

I think the reason for using early binding in the Sub Main() routine is so
intellisense would be available. I haven't looked at this in any other
context, otherwise. Although I don't see a problem with this, I'll ask Rob
why this is done this way! Late binding works equally well<IMO>, and which is
why I stated in my OP that binding wasn't an issue to the OP's code failing.
--

I agree with you about the VBA context. I avoid this by testing in the
FrontLoader.exe or by using a VB6.DLL in VBA apps. Although my preference is
to test in the FrontLoader and pass the parameters to the running instance,
not all my apps use a FrontLoader yet (unfortunately). I admit the DLL route
can be a bit tricky, but it is definitely safer<IMO> than setting refs in the
VBA app. The startup tests, therefore, allow me to restrict user access to
features that automate unavailable MSO apps. I'm aware that the DLL itself
could trigger the same behavior if it were "MISSING" in the refs. In this
case, startup would notify the user to reinstall.

It's unfortunate that VBA doesn't manage DLLs like VB6 does, in that they
must always be properly registered with the OS. I like the idea that VB6 apps
don't require this!<g>

That said, the FrontLoader approach makes more sense to me! The more I learn
about VB6, using MSO as a platform makes even less sense to me!<g>
--

I like the simplicity of your code sample. Very nice! I see what you mean by
moving things out of my startup procedure because I generally follow this
example. Again, I gave it no thought considering the source and so was
content to use it "as is".

I'm guessing that your useage of Excel (or the other MSO apps) is quite
different than mine, where the VB6 app is the main application and is only
using MSO apps as needed, on demand (if installed). In my case, Excel is the
host for the main application, VB6 is used as a fontloader to, or in-process
component of, the XLA (Excel actually). I will always want a clean instance
that contains only workbooks/addins used by my app. (my apps support
'plugins' and so may open other XLA files on startup) That doesn't dismiss
the fact that the user may open other workbooks in the same running instance,
so shutdown needs to take this into account and handle it appropriately.
Since it does not interfere with a default instance the user may be working
in before starting my app, there's no compromise to that instance.

In the case of dictator apps, the Excel instance is entirely locked down to
only permit app-specific functionality. In most cases, the user has no idea
they are actually working in Excel and therefore wouldn't likely even think
to try to open a workbook (assuming they could find a way that would allow
them to). In fact, even if they tried 'dropping' a file into the UI my app
could close it immediately if it was not a valid app document.
--

Please accept my thanks for your contribution to my learning process. This
is ever-ongoing. Please know I sincerely appreciate the time and effort you
put into addressing these issues. I am most grateful for this opportunity to
learn from you!

Kind regards,
Garry
Author
4 Mar 2009 8:10 PM
GS
Peter,

<..if Excel exists, test by attempting to create it as above (and keep it)
before calling...>
I did not address this in my previous post so I'll finishing explaining why
I don't use the test instance.

I have a group of drop-in functions I use for my projects. The
bExcelAvailable() function is one the group that tests for MSO apps. They are
deigned to be reuseable, stand-alone functions so they deliberately clean up
after themselves. They are not individually written into the module that
contains the Sub Main() procedure, but rather they reside in a mFunctions.bas
that is used as a common component.

Fact is, even if a user has Excel on their machine it doesn't necessarily
mean (however probable) that they'll have Word, or PowerPoint, or Publisher,
or Outlook. Calling these functions from any app (VB or VBA) is common and
thus they are set up to work as shown. This lets me focus on developing the
app independantly, with all its automation properly requirements in place.


<FWIW>
After reading your post I revised my Sub Main() as follows:

Public Sub Main()

  Dim bHasExcel As Boolean, bLicensed As Boolean
  Dim xlApp As Excel.Application
  Dim wkbAPP As Excel.Workbook
  Dim sMsg As String

  'Verify that we can automate Excel on this computer.
  bHasExcel = bExcelAvailable()

  If bHasExcel Then
    'Make sure our addin file exists
    If Not bFileExists(App.Path & "\" & gszApp_Wkb) Then
      sMsg = "The application file can't be found. " & vbCrLf & vbCrLf &
"You must reinstall this program to use it."
      MsgBox sMsg, vbCritical, "Startup Failure"
      Exit Sub
    End If

    'If not running as demo then check License hasn't expired
    If Not bDemoOnly() Then bLicensed = bValidateLicense Else bLicensed = True

    If bLicensed Then
      'If we successfully automated Excel, load our Excel app and turn it
over to the user.
      Set xlApp = New Excel.Application
      With xlApp
        Set wkbAPP = .Workbooks.Open(FileName:=App.Path & "\" & gszApp_Wkb,
Password:=gszPWRD)
        .Visible = True
        .UserControl = True
      End With
      wkbAPP.RunAutoMacros xlAutoOpen
      Set wkbAPP = Nothing
      Set xlApp = Nothing
    Else
      'Notify the user license has expired and give user opportunity to
enter License Key or Register
      sMsg = "Your License has expired!" & vbCrLf
      sMsg = sMsg & "You must have a valid license to continue using this
product." & vbCrLf
      sMsg = sMsg & vbCrLf
      sMsg = sMsg & "Options:" & vbCrLf
      sMsg = sMsg & "1.  Enter and validate your License Key." & vbCrLf
      sMsg = sMsg & "2.  Register your product now, obtain a License Key,
then try again later." & vbCrLf
      sMsg = sMsg & "3.  Cancel."
      Load fRegisterApp
      With fRegisterApp
        .lblLicenseKey.Caption = sMsg
        .Show
      End With
      Exit Sub
    End If
  Else
    'If we failed to get a reference to Excel, display a message to the user
and exit.
    sMsg = "This application requires Excel to be installed on your computer."
    sMsg = sMsg & vbCrLf
    sMsg = sMsg & "Excel failed to start. This application can not continue!"
    MsgBox sMsg, vbCritical, "Startup Failure!"
  End If

End Sub

Kind regards,
Garry