It's probably something simple but I have been trying to work out how to fix a compile error I am getting with an excel document I have created for a while now and I have not made any progress.
Basically there is a form that has several buttons that call a public function called "writeEntry" which is stored in a module called "describePhotosExcel". The code breaks no matter where writeEntry is called from.
So far I have tried calling the function from different subs, changing the subs from private to public, adding the module name before the function and renaming the function... I'm not quite sure what else I can do. Any help would be much appreciated.
Code from the form:
Private Sub PrevPhotoBTN_Click()
wrow = CInt(PhotoDataEntry.CurrentRow.Caption)
test = writeEntry(wrow, Direction.Text, RoadCombo.Text, Chainage.Text, Location.Text, CommentsCombo.Text, Condition.Text)
wrow = CInt(PhotoDataEntry.CurrentRow.Caption) - 1
PhotoDataEntry.CurrentRow.Caption = wrow
temp = PopulatePhotoForm()
End Sub
Code from the module "describePhotosExcel":
Public Function writeEntry(CurrentRow, Dir, RoadName, Chainage, Optional Title = "", Optional Comments = "", Optional Rating = "", Optional PhotoNumber = "") As Variant
Application.Workbooks(PhotoDataEntry.WBK.Caption).Activate
Worksheets("Data").Activate
Cells(CurrentRow, 6) = Dir
Cells(CurrentRow, 8) = RoadName
Cells(CurrentRow, 9) = Chainage
Cells(CurrentRow, 10) = Title
Cells(CurrentRow, 11) = Comments
Cells(CurrentRow, 14) = Rating
Cells(CurrentRow, 13) = PhotoNumber
writeEntry = 1
End Function
So I worked it out.
I had created a subroutine called "test" which was used to do some testing.
Therefore when it saw the word test it thought I was referring to this subroutine and not a new variable I was throwing away. Deleted that and it works well now.
Related
I am trying to declare and populate an array variable (coll), but wish to access the contents of the array in another Sub (UnassignButton_Click()). I keep getting the error:
Compile error: Sub or Function not defined
Below is my code:
Public Sub SearchButton_Click()
Dim RowNum As Long
Dim SearchRow As Long
Dim coll As Object
Set coll = CreateObject("System.Collections.ArrayList")
RowNum = 2
SearchRow = 2
Do Until Cells(RowNum, 1).Value = ""
If InStr(1, Cells(RowNum, 1).Value, SearchTextBox.Value, vbTextCompare) > 0 Then
Worksheets("Search_Results").Cells(SearchRow, 1).Value = Cells(RowNum, 1).Value
Worksheets("Search_Results").Cells(SearchRow, 2).Value = Cells(RowNum, 2).Value
Worksheets("Search_Results").Cells(SearchRow, 3).Value = Cells(RowNum, 3).Value
Worksheets("Search_Results").Cells(SearchRow, 4).Value = Cells(RowNum, 4).Value
Worksheets("Search_Results").Cells(SearchRow, 5).Value = Cells(RowNum, 5).Value
Worksheets("Search_Results").Cells(SearchRow, 6).Value = Cells(RowNum, 6).Value
Worksheets("Search_Results").Cells(SearchRow, 7).Value = Cells(RowNum, 7).Value
Worksheets("Search_Results").Cells(SearchRow, 8).Value = Cells(RowNum, 8).Value
Worksheets("Search_Results").Cells(SearchRow, 9).Value = Cells(RowNum, 9).Value
SearchRow = SearchRow + 1
coll.Add RowNum
End If
RowNum = RowNum + 1
Loop
If SearchRow = 2 Then
MsgBox "No products were found that match your search criteria"
Exit Sub
End If
SearchResultsListBox.RowSource = "SearchResults"
End Sub
Private Sub SearchResultsListBox_Click()
NumberIndex = SearchResultsListBox.ListIndex
End Sub
Public Sub UnassignButton_Click()
NumberIndex = SearchResultsListBox.ListIndex
MsgBox coll(NumberIndex)
End Sub
Any help to resolve this issue would be much appreciated!
See this answer for why you can't just willy-nilly tweak event handler procedure signatures to suit your needs.
Each procedure defines a scope. Local variables (whether declared with Dim, ...or not declared at all) live inside that procedure scope, and have no way out.
The next higher-up scope level is module scope. Variables declared in that scope are accessible to all procedures in the module. Use the Private keyword to declare them (Dim is also legal, but I prefer to reserve it for locals, since Private isn't legal at procedure level) - consider using a meaningful identifier name, too... "coll" doesn't say much about what it's for:
Option Explicit
Private RowNumbers As Object
And then you can initialize it in the Initialize handler:
Private Sub UserForm_Initialize()
Set RowNumbers = CreateObject("System.Collections.ArrayList")
End Sub
Probably also a good idea to explicitly wipe it out in the Terminate handler too, since that's a .NET object (FWIW this isn't a VBA array at all and has nothing to do with arrays):
Private Sub UserForm_Terminate()
Set RowNumbers = Nothing
End Sub
The next higher-up scope level is global scope, but once you understand how to pass parameters between procedures, and when to use module scope variables, you pretty much never need any globals. For completleness' sake, a global variable would be declared in a standard module, using the Public keyword (Global works too, but makes things confusing since what we call "global" is really just "project-scope", and besides Public is much more clearly antagonizing Private, so it's good for consistency).
If you added Option Explicit to the top of your modules, VBA would refuse to compile code that uses undeclared variables - and that would have highlighted coll and, likely, NumberIndex as well.
See if Rubberduck inspections flag other issues (disclaimer: I manage that open-source project).
I was writing a function with ws declared already. It works well under the private sub of the command button but when i extract it as a function it shows the object required error. The file is too large and I must make it as a function and call it but the error stopped my program running.
Could anyone please help me thanks a lot.
If Month(ws.Cells(j, 11)) = "a" And Year(ws.Cells(j, 11)) = ComboBox1.Text Then 'this sentence error
If ws.Cells(j, 5) <> "-" Then 'this sentence also error if I deleted the above one
n = 2
Else: n = 1
End If
p = 1
I hope someone can help- I'm hitting the dreaded "Out of memory or system resources" error with some code running in Excel and working with Outlook; from which the error originates.
Short description is it runs through a list of emails looking in the body/subject for a reference. If it finds it, it forwards the email item with the reference in the subject. MWE below; I'm not very experienced handling Outlook objects but I've spent nearly two hours trying different things with no luck. I can't use the GetTable() function since it doesn't include Body text data as far as I know (working off this), unless you can somehow add columns to include the body text?
If I run it in a freshly-opened Outlook session with only a dozen items it isn't a problem but I need it to work on hundreds of emails in one pop. Banging my head against a wall here. Thanks so much in advance!
Private Sub processMWE(ByVal oParent As Outlook.MAPIFolder)
Dim thisMail As Outlook.MailItem
Dim myItems As Outlook.Items
Dim emailindex As Integer
Dim folderpath As String
Dim refandType As Variant
Dim fwdItem
Set myItems = oParent.Items
folderpath = oParent.folderpath
'Starting at row 2 on the current sheet
i = 2
With myItems
'Data output to columns in Excel
For emailindex = 1 To .Count
Set thisMail = .Item(emailindex)
'i takes row value
Cells(i, 1).Value = folderpath
Cells(i, 2).Value = thisMail.Subject + " " + thisMail.Body
Cells(i, 3).Value = thisMail.SenderEmailAddress
Cells(i, 4).Value = thisMail.ReceivedTime
Cells(i, 6).Value = thisMail.Categories
'Reference from body/subject and a match type (integer)
refandType = extractInfo(Cells(i, 2))
'This is the reference
Cells(i, 5).Value = refandType(0)
'And this is the match type.
Select Case refandType(1)
Case 1, 2
'do nothing
Case Else
'For these match types, fwd the message
Set fwdItem = thisMail.Forward
fwdItem.Recipients.Add "#########"
fwdItem.Subject = Cells(i, 5) & " - " & thisMail.Subject
fwdItem.Send
'Edit original message category label
thisMail.Categories = "Forwarded"
thisMail.Save
'Note in spreadsheet
Cells(i, 7).Value = "Forwarded"
End If
End Select
i = i + 1
Next
End With
End Sub
Edit: New development: not only is it always hanging on the same line of code (thisMail.Body) it's actually doing it for specific mail items?! If I give it a batch of one of these problem messages it hangs immediately. Could it be something to do with character encoding or message length? Something that means thisMail.Body won't work that triggers a resources error?
Reason of the problem:
You are creating items without releasing them from memory -with these lines-
For emailindex = 1 To .Count
Set thisMail = .Item(emailindex)
Solution
Release the objects once you are done with them
End Select
i = i + 1
Set thisMail = Nothing
Next
End With
Common language explanation
In this scenario, think about VBA as a waiter, you are telling it that you are going to give some dishes to serve to the customers, you are giving all of them to it, but you never tell it to release them to the table, at one point, it will not be able to handle any more dishes ("Out of memory")
I'm trying to Create a document that has a bunch o constant strings.
I've declared then Public in a Module like this:
Public Abc As String
In "ThisWorkbook" I run the following code to initialize de variable
Private Sub Workbook_Open()
Abc = "C5"
End Sub
I have Buttons coded to change some values like:
If Range(Abc) = "" Then
Range(Abc) = 1
Else
Range(Abc) = Range(Abc) + 1
End If
When I run a button with this code:
Sub BotaoNovoDia()
i = 3
While i <= 33
If Cells(i, 11) = "" Then
Cells(i, 11) = Range(Apresentacao)
Cells(i, 12) = Range(Aceitacao)
Cells(i, 13) = Range(Aceitou)
Cells(i, 31) = Range("D41")
Cells(i, 11).Interior.Color = Range(Apresentacao).Interior.Color
Cells(i, 12).Interior.Color = Range(Aceitacao).Interior.Color
If Range("K34") < 0.65 Then
Range("K34").Interior.Color = vbRed
Else
Range("K34").Interior.Color = vbGreen
End If
If Range("L34") < 0.45 Then
Range("L34").Interior.Color = vbRed
Else
Range("L34").Interior.Color = vbGreen
End If
Range(Aceitou) = 0
Range(Rejeitou) = 0
Range(NaoApres) = 0
End
Else
i = i + 1
End If
Wend
End Sub
And i try to run the first button again I get and error saying: "Run-Time error '1004': Method 'Range' of object '_Global' failed"
the debug button takes me to the fisrt line that tries to access to the public variables value. What can i do to mantain the values in the Public variables?
When you call End (By itself, not as part of End If, etc) you clear your Globals.
Don't use End.
Using a named range is a great idea; but there's no reason why your public declaration shouldn't work - except for that pesky End statement. (I missed that first read through...)
However, your scope isn't clear in each of your functions, e.g. which worksheet is the Range referring to, so if one function works on another worksheet, pushing the button that fires "Change" could refer to a different place that doesn't like that reference.
e.g. your ranges should be something like SomeWorkbook.TheWorksheet.Range(<range>) and when you're changing the cell value, you should use .Value to ensure there's no ambiguity - you'll know from searching through here that error 1004 is the least descriptive error code...
I am calling an object's subroutine in Microsoft excel vba. The sub has 2 parameters, both objects themselves. The line of code I typed is giving an error-> Compile Error: Expected =
Here is the section of code that it occurs in:
' Copy the info from the old sheet and paste into the new sheet
Dim employee as CEmployee
For i = 2 To eswbMaxRow
Set employee = New CEmployee
employee.setNames (eswb.Worksheets("Employee Info").Cells(i, wbColumns.infoNameCol).value)
employee.loadFromAnotherWorkbook(eswb,wbcolumns) ' <- This line is giving the compile error
Next I
I don't understand why this is. This code is similar to code I already have that works fine.
This code works perfectly (Note: this is a separate function):
With ThisWorkbook.Worksheets(sheet)
Do While (.Cells(i, 1).value <> Empty)
' Create an object and set the name property
Set employee = New CEmployee
employee.setNames (.Cells(i, 1).value)
employee.loadFromScratch ' <- This sub is nearly identical to the one that is causing the problem. The only difference is it doesn't take object parameters
i = i + 1
Loop
End With
This is how I am declaring the subroutine that I am calling that gives the compile error:
Public Sub loadFromAnotherWorkbook(ByVal wb As Workbook, ByVal wbColumns As CColumns)
The objects I pass into this sub are of the correct type.
This isn't a function, so I don't understand why I would need to use an equal sign. Anyone know what I am doing wrong?
When calling a Sub, you don't enclose the parameters in brackets
Use it like this
employee.loadFromAnotherWorkbook eswb, wbcolumns