473,406 Members | 2,956 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

Help understanding object instantiation using automation

beacon
579 512MB
Hi everybody,

[Access/Excel 2010]

I have a database that I'm using to generate an Excel workbook with 13 worksheets for a list of 50 or so contractors. I have a subroutine that loops through a list of providers, creates a new workbook, adds the 13 worksheets, and formats cells. Soon, I will be calling multiple queries and placing the data into specific cells in each worksheet in each of the workbooks for the contractors.

So far, everything is working as I intend it to, but since I'm always trying to learn and become better at programming, I wanted to break up the subroutine into more manageable pieces before I get to the data step since the subroutine I've written is quite long. I was going to create a container subroutine that would loop through the contractor recordset, then call addditonal subroutines to carry out specific steps.

My question is whether or not I can instantiate the Excel objects in the container subroutine so I don't have to recreate the objects in each of the subroutines that are called from the container or pass the objects to the subroutine from the container.

For instance, will the following pseudo-code work?:
Expand|Select|Wrap|Line Numbers
  1. Public Sub ContractorContainer()
  2.  
  3.      Dim db As DAO.Database
  4.      Dim rs As DAO.Recordset
  5.      Dim objExcel As Object
  6.      Dim objExcelWorkbook As Object
  7.      Dim objExcelWorksheet As Object
  8.  
  9.      Set db = DBEngine(0)(0)
  10.      Set rs = db.OpenRecordset(SELECT Contractor FROM tblContractor, dbOpenDynaset)
  11.  
  12.      With rs
  13.           If Not (.EOF And .BOF) Then
  14.                .MoveFirst
  15.                Do Until .EOF = True
  16.                     On Error Resume Next
  17.  
  18.                     Set objExcel = GetObject(,"Excel.Application")
  19.  
  20.                     If Err.Number <> 0 Then
  21.                          Err.Clear
  22.                          On Error GoTo Error_Handler
  23.                          Set objExcel = CreateObject("Excel.Application")
  24.                     End If
  25.  
  26.                     objExcel.ScreenUpdating = False
  27.                     objExcel.Visible = False
  28.  
  29.                     Set objExcelWorkbook = objExcel.Workbooks.Add
  30.  
  31.                     With objExcelWorkbook     
  32.                          CreateContractorWorkbook
  33.                          FormatFirstTab
  34.                          FormatSecondTab
  35.                     End with
  36.                Loop
  37.                .MoveNext
  38.           End If
  39.      End With
  40.  
  41.      Set objExcelWorkbook = Nothing
  42.      Set objExcel = Nothing
  43.      Set rs = Nothing
  44.      Set db = Nothing
  45.  
  46. End Sub
  47.  
Expand|Select|Wrap|Line Numbers
  1. Public Sub CreateProviderWorkbook()
  2.  
  3.      Dim objExcelWorksheet As Object
  4.  
  5.      Set objExcelWorksheet = objExcelWorkbook.Sheets("First Tab")
  6.  
  7. End Sub
  8.  
As you can see in the example, I refer to 'objExcelWorkbook' in the 'CreateProviderWorkbook' subroutine without re-instantiating the object or passing an argument to the subroutine. I don't mind re-instantiating the worksheet object for each subroutine, but I wanted to reduce the amount of code and increase the readability as much as possible (I also didn't want to have to pass a bunch of arguments to the subroutines because I'm not sure how ByVal/ByRef really works with objects, if at all, especially during automation). Currently, everything in my example, plus much, much more, is all in the same subroutine.

Thanks,
beacon
Nov 20 '12 #1
8 2217
NeoPa
32,556 Expert Mod 16PB
That's a good reason for looking into this Beacon.

The answer's relatively straightforward as I understand it (and I think I do pretty well TBF), and is that any object reference is maintained while the object variable is still in scope. If calling one procedure from another then the other has no access to the variables of the one. As such you have two main options (without introducing extra modules into the mix) :
  1. Pass the object as a parameter. ByRef should work perfectly for you in this case.
  2. Define and use module-level Public variables from the start such that all procedures in the module can share the variables fully.

Whatever you do, make sure you stay on top of which variables are still instantiated and which objects (like Workbooks and Applications) are still open and active.
Nov 20 '12 #2
ADezii
8,834 Expert 8TB
It appears to be a matter of Scope whereas the Object is Declared and Instantiated at a Procedural Level, as opposed to Modular. To the best of my knowledge, the Object should never be Declared/Instantiated for each Call of the Routine.
Nov 20 '12 #3
beacon
579 512MB
Thanks NeoPa. I thought about that, but really needed, and appreciate, the confirmation.

To the best of my knowledge, the Object should never be Declared/Instantiated for each Call of the Routine.
Thanks ADezii...I knew the object shouldn't be declared/instantiated for each call of the routine (where the same object is open and used throughout).

However, it does raise another question (again, I think I know the answer, but appreciate the confirmation to write it to my personal harddrive, i.e. my brain). Is an object considered to be declared/instantiated when it is dimensioned or when it is set?

If I were working with an object that I intended to set to a worksheet in the called subroutine/function (or set repeatedly through a loop), would I be able to send the object after dimensioning it? If I set it before I pass it, then I would just have to re-set it again in the called subroutine/function, which kind of defeats the purpose for carrying out loop routine in a separate subroutine/function.
Nov 20 '12 #4
NeoPa
32,556 Expert Mod 16PB
It doesn't need to be set in the calling procedure. Unset object variables return Nothing. Not zero, but a special value which indicates that they are variables that refer to no object (yet). An object set to Nothing (or even one set to a valid object) can be passed by the calling procedure and set by the called procedure. This will then be visible to the calling procedure once the called procedure has returned, as long as ByRef is used.
Nov 21 '12 #5
TheSmileyCoder
2,322 Expert Mod 2GB
That is a very good question, and a good basis for some advanced discussions.


When something is declared (dim) within a procedure, it is only visible to that procedure. However you can pass either its value or a reference to the variable/object to another procedure. An example is provided below:
(Aircode)
Expand|Select|Wrap|Line Numbers
  1. Public Sub ExportToExcel()
  2.   Dim objExcel as New Excel.Application
  3.   Dim objWB as Excel.WorkBook
  4.   set objWB=objExcel.Workbooks.Add
  5.   Call  CreateProviderWorkSheet(objWb,7) 'Create sheet for provider 7
  6.   Call CreateProviderWorkSheet(objWb,9) 'Create sheet for provider 9
  7.   Call CreateProviderWorkSheet(objWb,68) 'Create sheet for provider 68
  8.   objExcel.Visible=True
  9.   Set objExcel=Nothing 'Note taht I don't close or quit
  10.   set objWB=nothing
  11. End Sub
  12.  
  13. Private Sub CreateProviderWorkSheet(ByRef objWB as Excel.WorkBook,lngProviderID as long)
  14.   Dim objWS as excel.Worksheet
  15.   set objWS =objWB.WorkSheets.Add
  16.   objWS .Name="Provider " & lngProviderID
  17.   'more code blah blah
  18.   set objWS =Nothing
  19. End Sub
The above code should (barring typos) create a new excel workbook with 3 worksheets. Note that I pass the reference to the workbook to the function.
The above variables are declared at the PROCEDURE scope.

Another way of doing it, would be to declare some of the variables at the MODULE level scope, at the top of the module, usually as private and not public as previously stated. Private basically means that only procedures within the module will have access to the object.


Expand|Select|Wrap|Line Numbers
  1. Option Compare Database
  2. Option Explicit
  3. Private objExcel as Excel.Application 'Note the private instead of the dim
  4. Private objWB as Excel.Workbook
  5.  
  6. Public Sub ExportToExcel()
  7.   Set objExcel=New Excel.Application 'Change made here
  8.   set objWB=objExcel.Workbooks.Add
  9.   Call  CreateProviderWorkSheet(7) 'Create sheet for provider 7
  10.   Call CreateProviderWorkSheet(9) 'Create sheet for provider 9
  11.   Call CreateProviderWorkSheet(68) 'Create sheet for provider 68
  12.   objExcel.Visible=True
  13.   Set objExcel=Nothing 'Note taht I don't close or quit
  14.   set objWB=nothing
  15. End Sub
  16.  
  17. Private Sub CreateProviderWorkSheet(lngProviderID as long) 'This line becomes slightly simpler since I no longer need to pass the WB variable, its available at the module level.
  18.   Dim objWS as excel.Worksheet
  19.   set objWS =objWB.WorkSheets.Add
  20.   objWS .Name="Provider " & lngProviderID
  21.   'more code blah blah
  22.   set objWS =Nothing
  23. End Sub
If you have alot of stuff going on in your export procedure it might be simpler to declare the variables at the module level so you don't have to pass them back and forth all the time. Another thing you may have noticed is that the ExportToExcel is declared as public, since it will likely by called by the click of a button somewhere, while the CreateProviderWorkSheet is private, it will only be available within the module, which is just fine, since only the ExportToExcel has any reason to call the CreateProviderWorkSheet procedure.

The important thing to remember with using module level variables is to cleanup when you are done. Module level variables don't get cleaned up automatically (by intention). Depending on the object and intended use it may need to be closed/exited and the reference set to nothing.

Is an object considered to be declared/instantiated when it is dimensioned or when it is set?
I call it declaring when I use such keywords as Dim, Private or Public, and I would call it instantiating when I use the keyword set. In order not to make it too simple, there are cases where you can actually do both at the same time:
Expand|Select|Wrap|Line Numbers
  1. Dim objExcel as New Excel.Application
Furthermore there is some difference as to the behaviour of simple variables such as long, integers, strings, and the behaviour of objects, but that's for another discussion.
Nov 21 '12 #6
NeoPa
32,556 Expert Mod 16PB
Smiley:
usually as private and not public as previously stated.
Indeed so. I was considering the third option of declaring it in a separate standard module and confused the two when I posted :-( Good catch :-)

Actually, Public scope wouldn't be an actual problem, but Private is all that would be required, and it's generally better to limit scope to what is required to avoid any possibilities of overlap.
Nov 21 '12 #7
TheSmileyCoder
2,322 Expert Mod 2GB
As NeoPa said, there is little direct "bad" influence by creating it as a public function instead of a private function.

However it can make the code a bit easier to understand later on, and thus to maintain for "the next developer" even if that is just you 6 months from now. Just knowing its a private function makes it easier to spot the possible repercussions from making modifications to it. Still a proper understanding of scope and its implications can save alot of headaches down the line :)
Nov 21 '12 #8
NeoPa
32,556 Expert Mod 16PB
I concur absolutely.

Another reason is to allow the reuse of the name in other modules without any clash or confusion, in the same way that procedures can use variables of the same name as variables in other procedures because the scope of the variables are local to the specific procedures they're defined in.
Nov 22 '12 #9

Sign in to post your reply or Sign up for a free account.

Similar topics

8
by: Vanessa | last post by:
Hi In my VB Dot Net program, I'm using Automation to call Excel worksheet to do some insert some data. I have rename my worksheet to a name. eg. "ABC". How do I insert the worksheet name &...
3
by: Laurie | last post by:
I am using Automation in Access 2003 to open a Word Document and fill in some values using bookmarks. It all works perfectly except for one section. I am filling in some values in a previously...
10
by: cody | last post by:
would it be possible to allow an extended syntax for Object instantiation so that instead of Hashtable<string,int> table = new Hashtable<string,int>(10, 10f); I can write: ...
1
by: Agoston Bejo | last post by:
Hi! This is the smallest example I was able to create to demonstratet the problem. It seems that a certain kind of object instantiation gets parsed as a function definition (or whatever) by the...
0
by: Karel | last post by:
Hi, I have developed a vb.net application to create a mail-merged document by using Automation to word from VB.NET. I added the following reference to the application: Microsoft Office 10.0...
7
by: John A Grandy | last post by:
I'm trying to get a decent idea of the relative performance of three types of implementations of data-access classes in ASP.NET 2.0. I believe this boils down to a more basic question regarding...
4
by: Søren M. Olesen | last post by:
Hi Is it (any way) possible using reflection to set an indicator (property, variable, attribute,..). on an object before it actually instantiated, so that this indicator can be used in the...
4
by: Andrew Taylor | last post by:
Hi, I've been using PHP for a long time, I have designed and developed a number of mid-range systems. I've always used a procedural approach. I fully understand the concept of OO, I know all the...
2
by: Greg Corradini | last post by:
Hello All, A few weeks ago, I wrote two scripts using mx.ODBC on an Access DB. Among other things, both scripts create new tables, perform a query and then populate the tables with data in a...
0
by: ahammad | last post by:
I already know how to open an existing Word document using automation. What I want to do is to open a blank Word document that I can then write to. What changes should be made to this code? ...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.