Problem
I have an excel file with a quite complicated VBA code behind and I am having some problems to track back and debug the errors.
Sometimes a function B gets a value that it should not get and crashes, but at this point it is not possible for me to know which other funciton called that function B, and the anylys process to finding it out is very much time consuming.
My solution
The solution could be transform all the functions I have in the following way:
Sub foo1(variable1 as string)
'do whatever
End Sub
into
Sub foo1(variable1 as string, inforvariable as string)
'do whatever
End Sub
Infovariable being the name of the function calling.
This is obviously very time consuming (refactoring everything). Besides I dont know neither how to access the name of the "sub" of funcion of the code calling, something like:
infovariable = self.name
call foo1(variable1, inforvariable)
Does not seems to exists in VBA
Some ideas?
I have a look here, here, and here
Debug your macro, put a breakpoint on the line with the problem (in case the line gets called too often, add a condition only to break upon that condition), and view the call stack (keyboard shortcut Ctrl+L).
Related
I've looked on some similar question of "Object required on calling sub", but None of them seems to help with my problem. I want to call a sub(for example, in sheet2) from a sub in sheet1 like
Private Sub Worksheet_Activate()
ThisWorkbook.ActiveSheet.Cells.Clear
Call sheet2.generate <== where the error comes from
End Sub
where generate is the sub name on sheet2 which don't require any parameter
but it tells me that Object required and sendback an error.
I've tried:
without using call
sheet2.generate
without sheet name
generate
call generate
and adding a useless parameter for calling( also added to generate sub)
call sheet2.generate(1)
but it's not working too, so i detele that parameter as it have no use in the code.
there is no problem on generate sub(which i test for many time)
still, all of the above do not work for me, can someone provide a vaild way to solve this?
I've found that the problem is not at calling function,but instead, stuffs INSIDE function have problem, and debug arrow goes function and says "error 1004", after fixing some variable problem of the function, the problem no longer shows.
BRUH
I currently have a main excel macro which calls a bunch of functions. Basically:
Sub main()
'Long code
Call init
End Sub
Private Function init()
'Long Code
End Function
Some of these pieces of code are quite long and take some time to process, which is not great because I am constantly testing pieces of the code here and there.
I know that pressing esc multiple times ends an excel macro, and clumping all my code into the main Sub main() works fine. So my two questions are:
If I call a function from my main sub, will the main sub continue to run, or will it wait for a return signal from the function?
Is there a way for me to halt all subs and functions with one keypress? Currently, it seems that although the main sub ends when I spam esc, the function which has been called keeps running.
Cheers!
CTRL + Break will stop any running loops.
The main sub will wait for the return value from another function unless you run it asynchronously.
EDIT:
Misleading VBA does not support asynchronous programming.
For VBA functions and most programming in general i understand general program execution to occur something like this...
Inside a sub procedure if you call a function (it should return a value), in this case it would return a value to variable num.
To expand this means that execution reaches the line where I call the function, and should then skip down to where the function is written, and go through executing each line inside that function.
This is how it has worked for me previously when I use the F8 key to highlight and follow the code execution line by line.
The problem
The problem is when execution reaches the line inside the sub procedure where the function is called the function is just skipped over and execution doesn't go inside the function and run each line inside it.
(and I should say when this happened I had 95% of a working program, and i've tried re-writing the function, calling other functions).
But whenever a function is called execution of the code doesn't go into the function itself it just skips over it, and the variable that holds the result of the function therefore is left empty.
I've tried creating breakpoints at the beginning of the function and when the function is called in the sub procedure however this hasn't worked.
At the very least execution should get to the definition of the function (Function FirstRow() etc) and throw and error but it's not doing that.
Sub Main
Dim num as double
Dim sheet_name as string
num = FirstRow(sheet_name)
End Sub
Function FirstRow(sheet as string) as double
select case sheet '<<----- execution never gets inside the function
case "sheet"
FirstRow = 8
case "sheet2"
FirstRow = 12
end select
End Function
Put a value in sheet_name and try again.
What caused some functions to stop working (and execution of code to not reach the function definition or move inside it) was unloading the form.
All the functions and sub procedures were defined in a module which is part of the form.
Therefore you can only access this module by clicking on the controls on the form.
This meant that I only had one folder FORMS - which had one form inside it, and didn't have a Modules Folder which would normally appear in the VBA Project section.
Therefore I can either:
1) wait until all the data processing has been done before unloading the form right at the last minute
or
2) move the functions to a new module (External to the Form in the MODULES folder) so when the fuctions and sub procedures are called they don't rely on the form being open.
I have a spreadsheet, with the following two subroutines in it (there's a lot more to them, but I've stripped out all the code not directly relevant to the question):
Sub HF_Reset()
Feats_Reset
End Sub
Sub Feats_Reset()
Range("TblAllFeatsSelected").Value = CVErr(xlErrNA)
Range("Test").Value = "Success"
Range("Test2").Value = 1
End Sub
Test is a single cell, Test2 is a two-cell range, TblAllFeatsSelected is a large range.
If I call Feats_Reset, it executes absolutely fine, does what it's intended to do. If I call HF_Reset, then Testgets "Success" put into it, and Test2 is filled with 1s, but TblAllFeatsSelected doesn't change. I have absolutely no clue what's going on - any ideas?
For debugging purposes, I've also tried setting Range("TblAllFeatsSelected").Value = 1 and Range("TblAllFeatsSelected").Value = 0, and again it works fine when calling Feats_Reset but not when calling HF_Reset.
EDIT: I've played some more, and traced the problem to another subroutine called in Feats_Reset. I suspect I'm not going to be able to provide enough information here to get a useful answer - it's a complicated sheet, and there's a lot of interactions that could be the problem. Bother.
EDIT2: Found the problem. The subroutine was setting TblAllFeatsSelected to the value of another range, which when calling from HF_Reset needed to have an Application.Calculate or it would justset it back to what it used to be.
Is there any way I can delete this question as not useful? It's such a specific thing, I doubt it could help anyone else.
Problem Exists Between Keyboard and Chair. I was missing an Application.Calculate in a completely different part of the code.
I've searched the web and I've searched the questions here on stackoverflow, but I haven't been able to find a solution.
Here is what I'd like to do:
Suppose I have the following code in a class module named "MyClass"
Option Explicit
Dim var1 as integer
Sub Initialize(v as integer)
var1 = v
End Sub
Function GetVar1()
GetVar1 = var1
End Function
Then I have a UDF in a separate module with the code
Function InitializeMyClass(v as integer) as MyClass
Dim myvar as MyClass
Set myvar = new MyClass
Call myvar.Initialize(v)
Set InitializeMyClass = myvar
End Function
Function GetMyVar(m as MyClass)
GetMyVar = m.GetVar1()
End Function
Now in cell A1 I have "=InitializeMyClass(3)" and in Cell A2 I have "=GetMyVar(A1)". I get #VALUE errors in both cells. This of course is caused by the fact that I am trying to return a user defined data type into cell A1. I feel that this should be possible, but I am not sure how.
Edit: Oh yeah, the question is, "Is there a way for me to return a user-defined data type into a cell and then have it be callable from another UDF in the example I gave above? I don't know if this requires COM or not. If it does, anyone know how I can get started? Ideally, if someone had an example of how this worked, that would be fantastic!"
Another Edit: Here we go, now i know it can be done: read this description, it's not quantitative, but will give you a sense of what they do, http://www.quanttools.com/index.php?option=com_content&task=view&id=19
As the other answers suggest, the literal answer to your question is "no". You can't store anything other than a number, string, boolean, error, etc. in a cell. You can't return anything other than a simple value such as those, or an array, or a range reference, from a UDF.
However, you can do essentially what you want by passing around (and storing in cells) some kind of handle to your objects that is a legal cell value (i.e. "myclass:instance:42"). This is probably what the example you linked to in your edit does. Your code has to be able to interpret the meaning of the handle values and maintain the objects in memory itself, though. This can get tricky if you care about not leaking objects, since there are lots of ways to erase or overwrite handles that you can't detect if you're using VBA to do all this.
I don't have it in front of me right now, but you might want to look at the book Financial Applications using Excel Add-in Development in C/C++ by Steve Dalton:
http://www.amazon.com/Financial-Applications-using-Development-Finance/dp/0470027975/ref=ntt_at_ep_dpt_1
He discusses ways to work with handles like this more robustly with XLL add-ins.
This looks to be a tough cookie. It's a little hokey, but what you could do is have your Initialize function return a name (string), then add the name parameter to the Get function. Basically manipulating the name string instead of the object directly.
The nesting won't work because myvar goes out of scope as soon as the UDF is done executing. There actually may be other problems associated with trying to return an object in a worksheet function (most certainly there are), but even if there weren't the scope problem would still kill it.
You could store a pointer to the object in a cell and get the object via that pointer, but again the scope will kill it. To get the object from the pointer, it would have to remain in scope, so why bother storing the pointer.
Obviously your real life situation is more complex than your example. So the answer is no as to storing objects in cells, but if you explain what you're trying to accomplish there may be alternatives.