What does the keyword 'New' do in VBA? - vba

In VBA procedures we are constantly meeting the keyword New usually on instantiation of an object reference to an existing object instance. But in some instantiations we use the keyword New while in others we don't for example:
Dim T As Excel.Workbook
Set T = Application.Workbooks(Bk)
In the upper example No.1 the "New" keyword has not been used
Dim fso As FileSystemObject
Set fso = New FileSystemObject
In the upper example No.2 the New keyword is being used
Why that? Keep in mind i'm fresh of the boat in VBA but i will do my best to understand!
In addition to that i also get confused when is used/not-used in declaring an object reference for example:
Dim WS As Worksheet
In the upper example No.1 the "New" keyword has not been used
Dim myClassModule As New cl_ChartEvents
In the upper example No.2 the New keyword is being used
The Microsoft Help just tells me nothing...
Keyword that enables implicit creation of an object. If you use New when declaring the object variable, a new instance of the object is created on first reference to it, so you don't have to use the Set statement to assign the object reference.
Gratz2u
Dear people just a last dust-off for deep understanding
Dim WS as Worksheet
Set WS = Worksheets("Sheet1")
Right here we are creating an object that already existed in order to open MS Excel (lets say for examples sake in "default mode") of course which is Sheet1. Since it exists and the New keyword is out of the question how could we instantiate this object in one line right away?
4 #exantas
Sorry says not enough rep to post pic :-(

When you Dim a variable you are specifying what data type it will hold. At the time of creation, its value is always Nothing until you initialize it. Set T = Application.Workbook(Bk) initializes the T variable to the specific instance of Application.Workbook, in this case 'Bk'.
When you Dim fso as FileSystemObject, you are basically saying that fso will hold, at some point, a FileSystemObject; however its initial value is Nothing until you initialize it using Set fso = New FileSystemObject. The New keyword implies you're creating a new object instead of initializing the variable with an existing object as you do with Set T = Application.Workbook(Bk)
Also note that Set fso = FileSystemObject would be invalid because it doesn't know what instance of FileSystemObject you wish to assign to it. This is why you use the New keyword to create a new instance of FileSystemObject.
As stated before, Dim WS As Worksheet merely tells the compiler that you want variable WS to hold a Worksheet object. Since nothing else is specified, at the point of Dim, WS is set to Nothing
Dim myClassModule As New cl_ChartEvents is equivalent to doing:
Dim myClassModule as cl_ChartEvents
Set myClassModule = New cl_ChartEvents
... except on one line of code instead of two. This differs from Dim WS As Worksheet in that the variable is initialized straight away, i.e. myClassModule is set to a new instance of cl_ChartEvents instead of Nothing.
Hope this helps!

You said: "[We are] meeting the keyword New usually on instantiation of an object reference to an existing object instance". Exactly the opposite is true: New is used when something does not exist yet and you want to create it, well "new".
You can omit the New keyword if something already exists, e.g. the Application object, ActiveWorkbook object and others in VBA, that is everything which was already opened by you when starting Excel.
Dim ... As New ... is a shortcut for
Dim ... As ...
Set ... = New ...
For your last question to create a new worksheet, it's done by
Dim WS As Worksheet
Set WS = Sheets.Add
WS.Name = "My new worksheet"
You cannot use Dim WS as New Worksheet, because Microsoft prevents you from doing so. Even if you specify New in that instruction, the object is still Nothing.

Related

Vba: Can not establish an object as a range using ActiveWorkbook command, throws error 91

I'm trying to define a variable called dtecell as a range to do handle it in a more easy way. Simplifying, I have the following code:
Sub foo()
Dim dtecell As Range
Dim dte As Date
Dim twbook As Workbook
Dim dtwsheet As Worksheet
Set twbook = ActiveWorkbook
Set dtwsheet = twbook.Worksheets("BT_dd_mm_aaaa")
dtecell = dtwsheet.Range("H9")
dte = dtcell.Value
When it arrives to the line in which code defines dtcell it throws the error:
VBA ACCESS error 91 object variable or with block variable not set
I dont't know why it throws that error. With is when you want to keep constant an object in order to not repeat it when applying methods over it, but here it has not sense.
Could anyone help me?

Defining a variable as a range - VB.NET

I think I'm losing my mind - how do you declare a variable as a string and then set it equal to a range in an Excel workbook in VB.NET? In VBA this was easy:
Dim SQL as string
SQL = ActiveWorkbook.Sheets("MySheet").Range("SQL")
If I try do something like this in VB.NET (in Visual Studio 2015), first I can't find Activeworkbook. Second, if I try Excel.Range("SQL"), I get an error saying that 'Range' is an interface type and cannot be used as an expression. Also, it doesn't look like the Range data type exists either. Surely this functionality exists in VB.NET, right?
Thanks for the help!
To work on Excel since VB.NET, first you must add the reference to your Project :
Microsoft.Office.Interop
To Add a Reference :
In Solution Explorer, right-click on the References node and choose Add Reference.
Import the Reference in your code :
Imports Microsoft.Office.Interop
Try to use this code :
Dim AppExcel As New Excel.Application 'Create a new Excel Application
Dim workbook As Excel.Workbook = AppExcel.Workbooks.Add() 'Create a new workbook
Dim sheet As Excel.Worksheet = workbook.Sheets("Sheet1") ' Create variable a Sheet, Sheet1 must be in WorkBook
'Work with range
Dim cellRange1 As Excel.Range = sheet.Range("A1") 'Range with text address
cellRange1.Value = "Text in Cell A1"
Dim cellRange2 As Excel.Range = sheet.Cells(2, 2) 'Range("B2:B2") with index; Cells(N°Row,N°Col)
cellRange2.Value = "Text in Cell B2"
Dim tableRange3 As Excel.Range = sheet.Range("A1:F4") 'Range with text address
Dim tableRange4 As Excel.Range = sheet.Range(sheet.Cells(1, 1), sheet.Cells(4, 6)) 'Range("A1:F4") with index; Cells(N°Row,N°Col)
AppExcel.Visible = True 'To display the workbook
Code without variable sheet
Dim AppExcel as New Excel.Application
Dim workbook As Excel.Workbook = AppExcel.Workbooks.Add()
'Range
Dim cellrange1 as Excel.Range = AppExcel.ActiveWorkbook.Sheets("Feuil1").Range("A1")
You would need to start from your application object. Suppose that's AppExcel:
Dim AppExcel As New Excel.Application
From there, you could do:
Dim cellrange1 as Excel.Range = AppExcel.ActiveWorkbook.Sheets("MySheet").Range("SQL")
Because you've declared cellrange1 as a Range it can't be set to Range("SQL").Value.
Value returns an object which is the value contained in that Range.
That's so wordy. To put it (maybe) more clearly, Range("SQL") returns a Range. Range("SQL").Value returns an object.
If you want to get the value, that would be cellrange1.Value, or perhaps cellrange1.Text. Assuming that the range contains some sort of SQL, I'd go with Text.
An unfortunate aspect of Excel interop programming is that many properties return objects rather than strongly-typed values. For example, the object returned by Range.Text is always going to be a string, but the property still returns an object. That means that Visual Studio intellisense will often not tell you what type a property returns. You'll need to look up properties and functions in the documentation to really know what they return.

Understanding VBA Object Variables

I'm learning Visual Basic for Applications, and I'm a little unsure of when to use procedures. For example, is a procedure needed every time an object variable is created? Or can an object variable be created without being executed as a procedure?
Could I have just
Dim wkbInventory As Workbook
Set wkbInventory = Application.Workbooks("name.xlsm")
Thank you!
A object variable can be declared outside a procedure. So the
Dim wkbInventory As Workbook
can be in the Declarations (see https://msdn.microsoft.com/en-us/library/dd897495%28v=office.12%29.aspx#odc_ac2007_bk_BeginningAccess2007VBA_Chapt2_CreatingModules) .
The scope of the variable is dependent on where the declaration happens. See http://www.cpearson.com/Excel/Scope.aspx.
But a variable can't be instantiated outside a procedure or function. So the
Set wkbInventory = Application.Workbooks("name.xlsm")
must be inside the Procedures within a sub procedure or a function.
Almost all of the work in VBA happens inside of macros. You can declare variables outside of macros (although this changes the variable's scope compared to declaring it inside a macro) and specify some compiler options but that's about it.
This is OK:
Option Explicit
' Declaration
Dim c As Collection
Sub foo()
Set c = New Collection
c.Add "hello", "world"
MsgBox c.Count
End Sub
whereas this will generate a compile error - "Invalid outside procedure":
Option Explicit
' Declaration
Dim c As Collection
' This causes an error
Set c = New Collection
Sub foo()
c.Add "hello", "world"
MsgBox c.Count
End Sub
If you use implicit creation with your variable declaration (Dim x As New y) then that works outside of a macro. Not all objects can be created that way though. This code works:
Option Explicit
' Declaration with implicit creation
Dim c As New Collection
Sub foo()
c.Add "hello", "world"
MsgBox c.Count
End Sub
whereas this code doesn't work (you'll get error 429 - ActiveX component can't create object):
Option Explicit
' Declaration with implicit creation
Dim w As New Workbook
Sub foo()
MsgBox w.FullName
End Sub
First recommendation I would make is to put Option Explicit at the top of your code(above all subs and functions). That will help you know when things are not correct.
Dim wkbInventory As Workbook Set wkbInventory = Application.Workbooks("name.xlsm")
Will not work. You will have to do
Dim wkbInventory As Workbook
Set wkbInventory = Application.Workbooks("name.xlsm")
FYI, there is late binding versus early binding that might help you (see also this thread for a an overview) . This is something to learn unrelated to procedures so I'm just providing as an if you already din't know...
You can early bind
' Set reference to 'Microsoft Excel 8.0 Object Library' in
' the Project|References dialog (or Tools|References for VB4 or VBA).
' Declare the object as an early-bound object
Dim oExcel As Excel.Application
Set oExcel = CreateObject("Excel.Application")
' The Visible property is called via the v-table
oExcel.Visible = True
' Good practice to explicitly set object variables to "Nothing" when
' done but not mandatory (especially not for local references).
Set oExcel = Nothing
Or late bind
' No reference to a type library is needed to use late binding.
' As long as the object supports IDispatch, the method can
' be dynamically located and invoked at run-time.
' Declare the object as a late-bound object
Dim oExcel As Object
Set oExcel = CreateObject("Excel.Application")
' The Visible property is called via IDispatch
oExcel.Visible = True
' Good practice to explicitly set object variables to "Nothing" when
' done but not mandatory (especially not for local references).
Set oExcel = Nothing

Excel VBA Can't get selected value from combobox

I've been reading numerous posts here in the forum regarding my problem but I'm afraid I'm still doing something awfully wrong.
Overtaken today by the button rage, I admit to some confusion.
I have been trying to put a simple userform combobox (frmWorkers) which includes a combobox (cbWorkers) and linked to a defined rowSource (Workers), the click of which will simply get me the value of that worker's name. (Thank you Ann!)
The combobox opens just fine but refuses to click and there I'm stopped.
I'm now receiving a 'compile error, for each control variable must be variant or object' at **for each WorkerName...
Private Sub UserForm_Initialize()
Dim wsControl As Worksheet
Dim Workers As Range
Dim WorkerName As String
Set Workers = Range("Workers")
**For Each WorkerName In Range("Workers")
If WorkerName = Not Nothing Then
Me.cbWorkers.AddItem WorkerName
End If
End sub
I've also been trying to get it alternatively from ThisWorkbook, but I'm getting a 'run-time error 91, object variable or with block variable not set', right after **WorkerName.
Sub UsingTheScriptingRunTimeLibrary()
Dim fso As Scripting.FileSystemObject
Dim fileMakoret As Scripting.File, filePayroll As Scripting.File
Dim WorkerName As String, folderPath As String, NewFolderPath As String
Dim wsControl As Worksheet
Dim newWbMaskoret As Workbook, wbPayroll As Workbook, wbControl As Workbook
Dim cbWorkers As ComboBox
Set wbControl = ActiveWorkbook
Set wsControl = wbControl.Sheets("Control")
**WorkerName = cbWorkers.Value
WorkerName = Worksheets("wsControl").OLEObjects("cbWorkers").Object.Value
Your help is much appreciated.
Does the object frmWorkerName have a Value property? What type of object is it?
I think the problem with your second code snippet is that you define cbWorkers, but you never assign a value to it. It therefore has a value of Nothing ("null" in other languages.)
When you then try to access the value of cbWorkers, you get an error, since there is no object there to access a property for.
ETA: About your second problem: here's the code:
Dim Workers As Range
Dim WorkerName As String
Set Workers = Range("Workers")
For Each WorkerName In Range("Workers")
You're getting the error because, to do a For Each loop, the type of the variable WorkerName needs to be compatible with the type of the collection Range("Workers") that you're iterating through.
The error message tells you: you need to make WorkerName an Object or a Variant if you're going to use it in a For Each loop with that collection.
I doubt, by the way, that the elements in an Excel Range object are simple strings. They are probably Cell objects, or objects of a type with a similar name. You will need to cast WorkerName to type Cell (or whatever) within the loop, and then access its Text or Value property.

Set xWorkb = New workbook not working, ActiveX error

I have some code below, It works like a charm but I'm curious about some things.
Why can't I make a Set xWorkb = new Workbook statement? Instead I use the Dim xWorkb as new Workbook, which works. But I've learned (hopefully correct) that using the new statement within a Dim is bad practice, and that you should create the object seperately. So why doesn't it work? I get a ActiveX component can't create object error, but the xWorkb is still being created later as an object right due to the new statement in the Dim section? Makes me confusing.
Why can't I use the excel.application.workbooks when defining variable xApp? Is it because I have to specify a workbook and can't just leave the workbooks empty like that? I get a type mismatch error when I'm trying to change excel.application to excel.application.workbooks.
Sub tester()
Dim xWorkb As New Workbook
Dim xApp As Excel.Application: Set xApp = New Excel.Application
Dim xFiles_target() As Variant
Dim file_path As String
xFiles_target = Array("Bella.xls", "Fizz.xls", "Milo.xls", "Jake.xls")
file_path = Dir("C:\Users\hans\Desktop\")
Do While Len(file_path) > 0
Debug.Print file_path
If UBound(Filter(xFiles_target, file_path)) >= 0 Then
Debug.Print "found " & file_path
Set xWorkb = xApp.Workbooks.Open("C:\Users\hans\Desktop\" & file_path)
xApp.ActiveSheet.Cells(2, 2) = "tester"
xWorkb.Save
xWorkb.Close
End If
file_path = Dir
Loop
End Sub
You cannot create new workbooks with New because workbooks are coupled with Application and must be created with Workbooks.Add or Workbooks.Open.
Dim xWorkb as new Workbook does not work - it appears to work because you don't access xWorkb between declaring it and assigning it with Workbooks.Open. If you did, you would get the same ActiveX component can't create object error.
The error is because Excel.Workbook does not have any public constructors.
You cannot define a variable as excel.application.workbooks because that is not a type. It is a property named Workbooks, of type Excel.Workbooks, that belongs to an object named Application of type Excel.Application.
You can declare the variable as Excel.Workbooks, but you probably don't want to, because you will need to create an Excel.Application to use it anyway.