|
code
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
close excel from VB6All 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 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 > > 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 > > > > > > >
Show quote
Hide quote
"GS" <G*@discussions.microsoft.com> wrote in message You do realize it's been nearly a month since there's been any discussion in 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! 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 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 > > 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 >> >> 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 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 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 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
Pset and SetPixel Bug
How to get special Appdata folder Use Proc with Static Variables Multiple Times What am I doing wrong How difficult is to add my menu to Windows Explorer? Unbelieveable code, it produces one result in VB6 run and another if compiled in a exe file ???? Wha Vista behaves differently to WordBasic command even though same version of Word! OT MS Community Visibility Legacy vs Opp Crash during compile |
|||||||||||||||||||||||