Excel/VBA do not know where to begin - vba

So I made a simple user form that will allow people to sign out equipment easily. I would like to make it so if something in the "Equipment" column is out, it will say out in the "In/Out" column. But otherwise say in. So if Equipment says "Laptop 1" and Last "Date & Time" Column is empty, then it would say out beside Laptop 1 in the "IN/OUT" column. The equipment column is multiselect with a "," between equipment options.
I have no idea where to start with this. What I have done so far minus populating the listbox and dropdown for the user form entry.
Private Sub cmdout_Click()
Set ws = ThisWorkbook.Worksheets("SignOut")
Dim sh As Worksheet
Dim LastRow As Long
Dim i As Integer
For i = 0 To equip.ListCount - 1
If equip.Selected(i) Then
Msg = Msg & equip.List(i) & ", "
End If
Next i
Msg = Left(Msg, Len(Msg) - 2)
Dim rngFound As Range
Dim strFirst As String
Dim strID As String
Dim strDay As String
Dim taken As Integer
strID = gov.Value
strDay = ""
Set rngFound = Columns("C").Find(strID, Cells(Rows.Count, "C"), xlValues, xlWhole)
If Not rngFound Is Nothing Then
strFirst = rngFound.Address
Do
If LCase(Cells(rngFound.Row, "G").Text) = LCase(strDay) Then
MsgBox "GOV is still signed out."
taken = 1
End If
Set rngFound = Columns("C").Find(strID, rngFound, xlValues, xlWhole)
Loop While rngFound.Address <> strFirst
End If
If taken = 0 Then
Application.Worksheets("SignOut").Range("A" & Rows.Count).End(xlUp).Offset(1).Value = Now()
Application.Worksheets("SignOut").Range("B" & Rows.Count).End(xlUp).Offset(1).Value = techname.Value
Application.Worksheets("SignOut").Range("C" & Rows.Count).End(xlUp).Offset(1).Value = gov.Value
Application.Worksheets("SignOut").Range("D" & Rows.Count).End(xlUp).Offset(1).Value = Msg
Application.Worksheets("SignOut").Range("E" & Rows.Count).End(xlUp).Offset(1).Value = otherequip.Value
End If
Set rngFound = Nothing
End Sub
Sign in form:
Private Sub CommandButton1_Click()
Dim rngFound As Range
Dim strFirst As String
Dim strID As String
Dim strDay As String
strID = techname1.Value
strDay = ""
Set rngFound = Columns("B").Find(strID, Cells(Rows.Count, "B"), xlValues, xlWhole)
If Not rngFound Is Nothing Then
strFirst = rngFound.Address
Do
Application.Worksheets("SignOut").Cells(rngFound.Row, "G").Value = Now()
Set rngFound = Columns("B").Find(strID, rngFound, xlValues, xlWhole)
Loop While rngFound.Address <> strFirst
End If
Set rngFound = Nothing
End Sub

1) A "form" is a specific coding construct in VBA. Based on what you posted, I assume that you aren't referring to it, but instead are just calling this sheet a form? If not, then please post the VBA code that you have tried.
2) Assuming that the list of equipment is in the "Tracker" column, you should use that list to populate a dropdown list in the equipment column to ensure that they match. I am also assuming that your extra equipment column won't have anything in the dropdown list and if people check out 2 tracked items, there will be a line entry for each item. (I'd recommend getting rid of that column if you get users that misuse it)
3) Since you asked where to start, I'll give you that. You'll learn much more by figuring out the exact syntax yourself. You can google "Excel VBA X" where X is basically any of these lines.
Pseudocode - (will not run, needs to be replaced with actual code - also ignore the colored words, they don't mean anything in pseudocode)
Phase 1:
trigger event on save (event handler is another search term for trigger events)
Change all equipment values to In
loop through first date/time column
IF there is a value in that column and there is not a value in the second date/time column get the name of the equipment from the equipment column
Find equipment from tracker column change In/Out value on that row to Out
continue the loop until the next row is blank
Alternate:
remove code to check everything in
add on-edit trigger to equipment column
add row that was edited to array
add on-edit trigger to check in date column
store row number to array
change loop so it only goes through rows in array
change if so that if something is checked out but not in, it is set out
(You will want to do this in case someone selects the wrong thing and then changes it - don't change it to out immediately or you will need logic to realize what was changed to out the previous time and change it back to in.)
else if something is checked out and has a value in check in date column then set it to in
Phase 2:
Implement an actual form that people use to fill in the sheet and check things in and out
Reuse relevant code from above but eliminate human error on dates and other things
(I suggest this as phase 2 as you can do this without a form and you will be using less new code. I would definitely use a form myself but it would be better if you wade into the pool instead of diving in. Unless you have coding experience and just need to learn syntax and vocab, then dive away.)
There are a lot of other things I would do if this was a form I was making, but this should get you started in terms of what to search for to build this project. I tried to make it as simple as possible so that it isn't overwhelming. There are better ways to do it but these methods should be ones that you can grasp quickly and then improve upon later after you learn more. Good luck with your equipment tracking!
Edit: after code posted
Ok, with the code you posted, go all the way to the top before the sub line and put in:
Option Explicit
This will cause the VBE editor to give you more meaningful feedback in quite a few instances. For example, you have your set line before your dim line. Without Option Explicit, when the editor comes to a variable that has not been declared with a Dim statement, it just makes it on the fly and sets it as a variant type. That uses up extra memory and means that typos get variables created on the fly. So when you are doing what you have done here, you end up with
Dim sh As Worksheet ' your sh variable is your worksheet variable. It never gets used again.
Set ws = ThisWorkbook.Worksheets("SignOut")' the ws here should likely be sh to match the Dim statement ... or the sh in the Dim should be a ws. Except it doesn't ever get used again either.
Neither of those matter in this case since you aren't reusing them but if you had code that was referring to one or the other, you would want the compiler to tell you that you are trying to use a variable that hasn't been declared instead of creating a new one.
Generally you want to put your Dim statements all at the top of the sub or function. 1) It is easier to find them and debug or check spelling. 2) It ensures that they are all declared before the script tries to reference them.
Your code here isn't populating the variables before it is referencing them. Pretty much any time that you have a variable you need to populate it before you can do anything with it. There are a number of ways to populate variables with data from the sheet. If you get comfortable with arrays sooner rather than latter (or collections instead of arrays) then you will have a much easier time with a task like this.
Some specific lines:
Dim LastRow as Long 'you have this declared but you need to put in code to get the last row, which will be handy for populating variables later in your code. Do this right after declaring variables. Google excel vba find last row.
For i = 0 To equip.ListCount - 1 ' you need to populate equip before doing this. Lookup excel vba how to copy a range into variable. Then lookup how to loop through range. You can start it at your first line of data and go down to the LastRow to grab them all into the same array (which will basically be a table).
msg = Left(msg, Len(msg) - 2) 'lookup excel vba string manipulations if this isn't doing what you want
'these next lines all have <Variable Name>.value which won't work for you. If those variables are supposed to be things that the sheet prompts someone to enter and then they get populated here you can see how to do that here-> http://www.excel-vba-easy.com/vba-userform-excel-vba.html
Application.Worksheets("SignOut").Range("B" & Rows.Count).End(xlUp).Offset(1).Value = techname.Value
Application.Worksheets("SignOut").Range("C" & Rows.Count).End(xlUp).Offset(1).Value = gov.Value
Application.Worksheets("SignOut").Range("D" & Rows.Count).End(xlUp).Offset(1).Value = msg
Application.Worksheets("SignOut").Range("E" & Rows.Count).End(xlUp).Offset(1).Value = otherequip.Value
With your loop untils you will want to ensure that you test with a short loop and step through it over and over. If you do the logic wrong and end up looping infinitely you can easily stop stepping through and fix it (or fix it while stepping through, then stop and retest,) but if you just hit play then excel will freeze up on you.
If you run into an issue with a specific step you can probably find lots of existing things on SO. If not, post a new thread with the specifics of that step. This posting will be down a few pages by then and people likely won't see your question if you put it here. Also, it will deserve its own thread since you will have moved past the "where to start" stage at that point.
Good luck!

Related

Excel VBA Get Count of Non-Empty Rows in Range

I know this has been asked at least a dozen times, but of all those questions the solutions seemed to be tailored or simply created an error in my code. For some reason I get an error when I try and reference a range from a different worksheet. Below is my code. I have two worksheets (tabs). One has a button to launch my code MENU, the other is the data I am trying to read and write to RAW. All I am trying to do is find out how many rows of data the sheet has so I can loop through the rows and make changes. For some reason I can't wrap my head around it or something.
Private Sub CommandButton21_Click()
Dim wbCurrent As Workbook
Dim wsCurrent As Worksheet
Set wbCurrent = ThisWorkbook
Set wsCurrent = wbCurrent.Worksheets("RAW")
Dim i As Long
Dim siteCol As Long
siteCol = Range("I" & Rows.Count).End(xlUp).Row
For i = 1 To siteCol
wsCurrent.Range("I" & i) = "MARKED"
Next i
Range("I1") = siteCol
End Sub
1- Always use Long for your variables, not Integer unless you have a specific reason. The maximum value of an Integer is 32767, which might be not enough to hold your count of rows.
2- Dont get the number of rows with COUNTA, this has many drawbacks. use this instead:
siteCol = wsCurrent.Range("I" & wsCurrent.Rows.count).End(xlUp).Row
This finds the Row number of the last occupied cell in wsCurrent, assuming that wsCurrent is at the top of the document (it starts on Row 1). Please note that if wsCurrent is completely empty, this will find the row number of the first occupied cell above wsCurrent, or the first row of the document.
3- When you want to assign a whole range to the same value, you can do it at once, which is much faster and simpler, like this (no loop needed):
wsCurrent.Range("I1:I" & siteCol) = "MARKED"
4- No need to Activate a worksheet to work with it. Drop the statement wsCurrent.Activate and try to always work with qualified ranges.

Find specific cells, change value of adjacent cell, value depends on location (Excel for Mac, 15.6)

this is my first post here, I know I'm articulating this poorly.
I'm trying to find cells containing a specific phrase in a column of dates. This phrase marks the beginning of a section. I then want to state the number of days elapsed from the first date in each section to other dates in the section. The values returned should show up in the adjacent column. Below is an example of the columns.
Dates and Elapsed number of days in adjacent column
I use this formula in the 2nd column:
=A15-$A$15
And then drag this down to cells in the relevant section. I'm trying to automate this process.
I found this code on this site and changed it a little bit to get this:
For Each cCell In Range("A1,A900")
cCell.Select
If ActiveCell.Value = "Phrase" Then
ActiveCell.Offset(1, 1).Value = "-"
End If
Next cCell
So my struggle is what to say in the 2nd Value field. I somehow need to get each section to subtract the first date of each section (the date right under "Phrase").
Another challenge is to copy that first adjacent cell that was changed, and then paste special into the cells below, but stopping once the next "Phrase" appears.
I'll elaborate any way I can. Thanks.
I think it's fair to say your question doesn't show much effort at solving this problem and the code snippet simply places a dash next to a "Phrase" cell. However, for a wider audience the question is interesting because it highlights the difference between automating an Excel keystroke task and writing code to process data which is then written in an Excel worksheet. Both use VBA but the former is simply a programmatic record of keystrokes and the latter is an algorithmic solution.
The telling phrase in your question is: I use this formula in the 2nd column ... and then drag this down to cells in the relevant section. I'm trying to automate this process. It would be possible to do this by using VBA to reproduce a bunch of worksheet functions but it's fiddly and could become complicated. I'll leave someone else to answer that as they'd need to spend more time on the answer than you have on the question (one of my don't do rules!).
If, on the other hand, you step away from trying to automate keystrokes and towards VBA for data processing, the problem becomes very trivial. It's a really good example of how VBA, in just a few lines, can solve problems that Excel functions might take pages to do, and probably not reliably.
So here's the code as a VBA solution. It'll need some data checking lines added to deal with blank cells, non-dates, etc. but I'll hand that task back to you:
Dim ws As Worksheet
Dim firstCell As Range
Dim lastCell As Range
Dim dataCells As Range
Dim v As Variant
Dim output() As Variant
Dim r As Long
Dim refDate As Long
'Define the range to be worked
Set ws = ThisWorkbook.Worksheets("Sheet1") 'amend as required
Set firstCell = ws.Range("A1") 'amend as required
Set lastCell = ws.Cells(ws.Rows.Count, "A").End(xlUp) 'amend as required
Set dataCells = ws.Range(firstCell, lastCell)
'Read the values and size the output array
v = dataCells.Value2 'use Value2 to avoid date format issues
ReDim output(1 To UBound(v, 1), 1 To 1)
'Loop through the values, resetting the reference date on each "Phrase"
For r = 1 To UBound(v, 1)
If v(r, 1) = "Phrase" Then
output(r, 1) = "-"
refDate = v(r + 1, 1)
Else
output(r, 1) = v(r, 1) - refDate
End If
Next
'Write output into next column
dataCells.Offset(, 1).Value = output

Copying from outlook

I wrote a VBA program that is supposed to download and copy emails from my outlook account and paste them onto my excel spreadsheet. I would like to run this program daily so obviously, I don't want this to go through my entire mailbox every time. So rather, I want it to start searching for emails after the date of the last copied email. But when I try to run this, it doesn't work. It keeps going through the entire mailbox and loops backward. So for instance, it will look for 6/29/2015 email and then move on to 6/28/2015, 6/27/2015 and so on, which is the opposite of what I am trying to to accomplish. I am not sure what I am doing wrong. Any help would be extremely appreciated. Thanks in advance!
Sub Download_Outlook_Mail_To_Excel()
Dim Folder As Outlook.MAPIFolder
Dim iRow As Integer, oRow As Integer, fRow As Integer
Dim MailBoxName As String, Pst_Folder_Name As String
MailBoxName = "officework#gmail.com"
Pst_Folder_Name = "Inbox" 'Sample "Inbox" or "Sent Items"
Set Folder =
Outlook.Session.Folders(MailBoxName).Folders(Pst_Folder_Name)
If Folder = "" Then
MsgBox "Invalid Data in Input"
GoTo end_lbl1:
End If
ThisWorkbook.Sheets(1).Activate
Folder.Items.Sort "Received"
' Insert Column Headers
' ThisWorkbook.Sheets(1).Cells(1, "A") = "Sender"
' ThisWorkbook.Sheets(1).Cells(1, "D") = "Subject"
' ThisWorkbook.Sheets(1).Cells(1, "F") = "Date"
' ThisWorkbook.Sheets(1).Cells(1, "J") = "EmailID"
' ThisWorkbook.Sheets(1).Cells(1, "M") = "Body"
LastRow = Cells.Find(What:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row
vDate = Cells(LastRow, "F").Value
For fRow = 1 To Folder.Items.Count
If Folder.Items.Item(fRow).ReceivedTime >= vDate Then
For iRow = LastRow To Folder.Items.Count
oRow = iRow + 1
ThisWorkbook.Sheets(1).Cells(oRow, 1).Select
ThisWorkbook.Sheets(1).Cells(oRow, "A") = Folder.Items.Item(iRow).SenderName
ThisWorkbook.Sheets(1).Cells(oRow, "D") = Folder.Items.Item(iRow).Subject
ThisWorkbook.Sheets(1).Cells(oRow, "F") = Folder.Items.Item(iRow).ReceivedTime
ThisWorkbook.Sheets(1).Cells(oRow, "J") = Folder.Items.Item(iRow).SenderEmailAddress
ThisWorkbook.Sheets(1).Cells(oRow, "M") = Folder.Items.Item(iRow).Body
Next iRow
End If
Next fRow
MsgBox "Outlook Mails Extracted to Excel"
end_lbl1:
End Sub
I have noticed the following lines of code:
For fRow = 1 To Folder.Items.Count
If Folder.Items.Item(fRow).ReceivedTime >= vDate Then
It looks like you are iterating through each item in the folder and check the RecievedTime property. Iterating through all items in the folder is not a really good idea. So, I'd suggest using the Find/FindNext or Restrict methods of the Items class instead. The latter applies a filter to the Items collection, returning a new collection containing all of the items from the original that match the filter. So, you just need to iterate through a small number of items and do whatever you need without checking properties each time. You can read more about these methods in the following articles:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder
Dates and times are typically stored with a Date format, but the Find and Restrict methods require that the date and time be converted to a string representation. To make sure that the date is formatted as Microsoft Outlook expects, use the Format function (available in VBA):
sFilter = "[RecevedTime] > '" & Format("6/29/2015 9:30pm", "ddddd h:nn AMPM") & "'"
Also you may find the AdvancedSearch method of the Application class helpful. he key benefits of using the AdvancedSearch method in Outlook are:
The search is performed in another thread. You don’t need to run another thread manually since the AdvancedSearch method runs it automatically in the background.
Possibility to search for any item types: mail, appointment, calendar, notes etc. in any location, i.e. beyond the scope of a certain folder. The Restrict and Find/FindNext methods can be applied to a particular Items collection (see the Items property of the Folder class in Outlook).
Full support for DASL queries (custom properties can be used for searching too). You can read more about this in the Filtering article in MSDN. To improve the search performance, Instant Search keywords can be used if Instant Search is enabled for the store (see the IsInstantSearchEnabled property of the Store class).
You can stop the search process at any moment using the Stop method of the Search class.
See Advanced search in Outlook programmatically: C#, VB.NET for more information.
Finally, take a look at the Getting Started with VBA in Outlook 2010 article in MSDN which explains basics of Outlook programming.
I started my answer before Eugene posted his but finished later because I was trying to do other things in parallel. His answer provides good advice and your code will be better for following that advice. My code is much closer to yours so you might find it easier to understand at this stage in your development as a VBA programmer.
I think I know what is wrong with your code but first some general advice.
Placing Option Explicit at the top of a module means that all variables have to be properly declared. Some of your variables are defined but others are not. If you use a variable that has not been declared with a Dim statement, VBA will declare it for you as a Variant. A variable of type Variant can take any type of value which is slow and error prone. Consider:
X = 5
X = “A”
In the above code, I have not declared X so it is a Variant. Setting X to 5 then “A” is valid code with Variants. Placing these two statements together makes my mistake easy to spot. But if I use X throughout my macro, a statement that sets X to the wrong type of value may be difficult to spot and can lead to strange failures.
Dim X as Long
X = 5
X = “A”
Adding the Dim statement means the interpreter will reject X = “A” at runtime.
If you indent code within For-Next loops and If-Else-EndIf blocks, it becomes much easier to follow the code. I suspect this is one of your problems.
Your other problem is the use of meaningless names. You have iRow, oRow, fRow and LastRow. Perhaps there is a system behind these names but it does not appear so. If there is a system, will you remember that system when you need to update this macro in six or twelve months? I have a system of naming variables which means I can look at macros I wrote ten years ago and immediately know what all the variables are.
My variable names are all a sequence of words or abbreviations. The first word is always what I am using the variable for so “Row” means it’s a Row number. The next word defines what it is a row of. You have rows of an Excel sheet and an Outlook folder so perhaps “RowSht” and “RowFld” or “RowEx” and “RowOut”. Sometimes I need a fourth word but usually three is enough. For a row number, the third word will typically be “Crnt” (for current), First, Last or Next.
There are other general points I could make about your code but I think that is enough for now.
I believe the major problem is that you have both an outer and an inner loop through the rows of the folder. Your choice of variable names makes this difficult to identify,
Issue 1
Dim RcvdPrevLatest as Date
Dim RowShtCrnt as Long
RowShtCrnt = Cells.Find(What:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row
RcvdPrevLatest = Cells(LastRow, "F").Value
RowShtCrnt = RowShtCrnt + 1
You only need one variable for the rows of you worksheet so I have named it RowShtCrnt. I have declared it as Long because Integer declares a 16-bit variable which requires special processing on 32 and 64-bit computers and because Integer only allows for 64K rows which is less than the maximum number of rows unless you are using Excel 2003.
I have declared a variable for your date. My system forces me to think about the purpose of my variables. It holds a Received Date/Time so the first word is “Rcvd”. The particular Received Date/Time being held is the latest Received Date/Time from the previous run of the macro.
Issue 2
You have:
For fRow = 1 To Folder.Items.Count
If Folder.Items.Item(fRow).ReceivedTime >= vDate Then
For iRow = LastRow To Folder.Items.Count
The outer For-Loop searches down the folder for a mail item with a received date/time later than the previous latest. The inner For-Loop then outputs every mail item below it in the folder so you are outputting mail items repeatedly. The inner For-Loop starts iRow at the last row of the worksheet and continues to the last row of the folder. You choice of names makes it difficult to spot that the start and end values do not relate to one another. Since fRow is not used within the inner loop, its value has no effect on the mail items selected for output.
I have not tested this code but it will be closer to what you want:
Dim RowFldCrnt as Long
For RowFldCrnt = 1 To Folder.Items.Count
If Folder.Items.Item(RowFldCrnt).ReceivedTime > RcvdPrevLatest Then
ThisWorkbook.Sheets(1).Cells(RowShtCrnt, "A") = _
Folder.Items.Item(RowFldCrnt).SenderName
ThisWorkbook.Sheets(1).Cells(RowShtCrnt, "D") = _
Folder.Items.Item(RowFldCrnt).Subject
: : :
RowShtCrnt = RowShtCrnt + 1
Next

Condense largely(Unpractical) loop based VBA code; nested For...Next loops

Hello everyone alright let start by giving some brief background on my project then I will follow up with my specific issue and code.
Currently I am building a program to automate the process of filling a template. This template exceeds 60,000 rows of data quite often and I've built the large majority of it to work month to month by plugging in new data sheets and running it. Currently all of the work is based off of one data sheet which I import into excel manually. This data sheet does not contain all the data I need to populate the template so now I am beginning to bring in additional data to supplement this. The problem herein lies with data association. When I was originally pulling from one data sheet I didn't have to worry if the data I pulled for each row coincided with the other rows because it all came from the same sheet. Now I have to cross check data across two sheets to confirm it is pulling the correct information.
Now for what you need to know. I am trying to fill a column that will be referred to as Haircut, but before I do that I need to confirm that I am pulling the correct haircut number in correlation to a Trade ID which was already populated into the template in a previous line of code.
Using similar logic that I have been using throughout my entire project this is a snippet of code I have to perform this task.
Dim anvil as Worksheet
Dim ALLCs as worksheet
Dim DS as worksheet
'''''''''''''''''''''''''''''code above this line is irrelevant to answer this question
ElseIf InStr(1, DS.Cells(x, 2), "Haircut") Then
Anvil.Select
For y = 1 To 80
If Anvil.Cells(1, y) = "Haircut" Then
For Z = 1 To 80
If Anvil.Cells(1, Z) = "Trade ID" Then
For t = 2 To 70000
For u = 16 To 70000
If Anvil.Cells(t, Z) = ALLCs.Cells(u, 34) Then
ALLCs.Cells(u, 27) = Anvil.Cells(t, y)
End If
Next
Next
End If
Next
End If
Next
This code coupled with my other code I assume will in theory work, but I can only imagine that it will take an unbelievable amount of time(this program already takes 7 and a half minutes to run). Any suggestions on how to rewrite this code with better functionality, following this general logic?
Any help is appreciated, whether you completely revamp the code, or if you offer suggestions on how to cut down loops. I am also looking for suggestions to speed up the code in general aside from screen updating and calculation suggestions.
If I understand the logic correctly then you can replace all but one of the loops with a .Find() method like so:
'// Dimension range objects for use
Dim hdHaricut As Excel.Range
Dim hdTradeID As Excel.Range
Dim foundRng As Excel.Range
With Anvil
With .Range("A1:A80") '// Range containing headers
'// Find the cell within the above range that contains a certain string, if it exists set the Range variable to be that cell.
Set hdHaircut = .Find(What:="Haircut", LookAt:=xlWhole)
Set hdTradeID = .Find(What:="Trade ID", LookAt:=xlWhole)
End With
'// Only if BOTH of the above range objects were found, will the following block be executed.
If Not hdHaricut Is Nothing And Not hdTradeID Is Nothing Then
For t = 2 To 70000
'// Using the .Column property of the hdTradeID range, we can see if the value of Cells(t, hdTradeColumn) exists
'// in the other sheet by using another .Find() method.
Set foundRng = ALLCs.Range(ALLCs.Cells(16, 34), ALLCs.Cells(70000, 34)).Find(What:=.Cells(t, hdTradeID.Column).Value, LookAt:=xlWhole)
'// If it exists, then pass that value to another cell on the same row
If Not foundRng Is Nothing Then ALLCs.Cells(foundRng.Row, 27).Value = .Cells(t, hdHaircut.Column).Value
'// Clear the foundRng variable from memory to ensure it isn't mistaken for a match in the next iteration.
Set foundRng = Nothing
Next
End If
End With

Type Mismatch error in function using DateValue(), how to troubleshoot?

Warning: I'm a noob.
I've written a Sub to find cells with red text and alter them.
#ThinkerIV gave me a great function to put in a cell and drag the formula out into adjoining cells, but that won't work due to the number of sheets to work on.
So I wrote my Sub, calling his function (see code below). I passed it a Range of one cell, so it seems to me it should work?
But, it keeps throwing out Type Mismatch (run-time error code 13) on the line where the function calls the DateValue()! The passed range shows a value of 1 (which is the number in the cell it refers to) when I hover over it in the editor, but I don'rt know if that's the cell's contents or some other value 1 being shown.
So, I really don't know how to find out exactly why this is happening. Is it that the range I passed is somehow not the right kind? Please inform me of why this code won't work!
I tried to change that line to the comment line below it (and a couple other blind-guess changes), but that has the same error.
Thanks in advance!
Sub redTextToRealDates()
Dim dateTemp As Date
Dim redCell As Range
Dim foundCell As Range
Dim thisSheetsRange As Range
Dim busyCell As Range
Dim redTextCells As Range
Set thisSheetsRange = ActiveSheet.usedRange
'Build a range containing all the cells in a sheet containing red text.
' well... all cells formatted to HAVE red text, anyway.
' Anyone want to tell me how to write this to skip empty cells?
' Because I don't need to grab empty cells into this range...
For Each busyCell In thisSheetsRange
If (busyCell.Font.ColorIndex()) = 3 Then
If redTextCells Is Nothing Then
Set redTextCells = busyCell
Else: Set redTextCells = Union(redTextCells, busyCell)
End If
End If
Next busyCell
'Change unknown format cells to date cells populated with concantenated
'string of original contents and the active sheet's name.
For Each foundCell In redTextCells
foundCell.NumberFormat = "#"
foundCell = GetConcantDate(foundCell)
Next foundCell
redTextCells.NumberFormat = "dd/mm/yy"
On Error Resume Next
End Sub
Function GetConcantDate(rng As Range) As Date
'Original code supplied by ThinkerIV on StackOverflow.com
Dim dtTemp As Date
dtTemp = DateValue(rng.Range("A1").Value & " " & rng.Parent.Name)
'dateTemp = DateValue(foundCell.Value & " " & ActiveSheet.Name)
GetConcantDate = dtTemp
End Function
EDIT
I cant post my own answer yet, so I am adding this solution:
When feeding data to Format(), the contents of the first cell formatted for red were NOT in text form. I had not put in place any way to ensure that I passed the proper data type. So, the line to format the cell as text (foundCell.NumberFormat = "#") before passing it to the function is what fixed it.
The solution was actually already written when I copy/pasted the code into the question - I just wasn't aware that it had fixed it because of another error on a different Sub. (I'm a noob and was confused dealing with multiple errors in multiple subs) I thought I had tried it again with that new line, but HADN'T, so still thought it was not working.
Thanks to all who helped. I feel a bit of a fool now, having found it like that. Hope you forgive me for my rookie flubber - too many Subs and Functions in a huge list in the editor and I got 'dizzy'... At least I can post a solution in case some other noob needs it!
Ok, I think there are two things here. Firstly, the DateValue function takes a string representation of a date, e.g. "01/01/2013", when you pass through an excel date from a range, you are passing through a number, like 41275. This throws the run time error 13.
However, if you already have a date, why bother converting it? You seem to want all red cells to be converted to a date + the sheetname. To do this you'll have to have strings e.g. "01/01/2013 Sheet1", so you couldn't use DateValue here. Instead perhaps try something like this:
Public Function GetConcatDate(rng As Range) As String
Dim dtTemp As String
dtTemp = Format(rng.Range("A1").Value, "dd/mm/yyyy") & " " & rng.Parent.Name
GetConcatDate = dtTemp
End Function