You can use WinMerge to see what changed between two VB projects.
Printable View
You can use WinMerge to see what changed between two VB projects.
I haven't downloaded your Project Scanner yet, but from memory; I know that VB6 compiler omits procedures that are not called from anywhere(unless they are Public in a Class, I think). This is called function-level linking in the C world. Also, VB consolidates duplicate string literals into one, so it appears once in the EXE space, but in some cases using constants is better.
Hello LaVolpe, I found a bug in the pvScanProcedures procedure of clsPrjFile. It raises an error in the line:
because lFlags is 0.Code:sToken = Mid$(sLine, iPos + 1, lFlags - iPos - 1)
I traced the error and it is misinterpreting a line that is:
It is interpreting it as it was a Static procedure.Code:Static sVariableName as Boolean
It is a bit strange because I have several other Static variables in the project but they didn't rise the error.
I momentarily fixed it by adding these lines:
Because even when a procedure is Static, it also must have Sub, Function, Etc.Code:Do
iPos = 0: sToken = modMain.GetToken(sLine, iPos, chrSpace)
If lScope = 0 Then
If sToken = ITEM_STATIC Then
sToken = modMain.GetToken(sLine, iPos, chrSpace)
End If
Select Case sToken
Case ITEM_PUBLIC, ITEM_PRIVATE, ITEM_FRIEND
If sToken = ITEM_PRIVATE Then
Update. I found the cause. I was experiencing other anomalies and the cause are some commented lines that end with _ (underscores).
It seems that the scanner intrerprets all lines finished with underscores as continuation to the next line. But that rule doesn't actually apply to comment lines, it is only for code lines.
Also another detail: The procedure named 'Main' in a bas module shouln't be listed as zombie because "it is not used".
Good catches. I do want to return to this project and finish it up. I'll keep these in mind when I come back to this project. If not, I'll ensure that is addressed too.
Sub Main(): I'm not looking at my code, but I thought I only mark it zombie if it isn't the startup routine and no other code calls it.
Underscores on comments: Yep, didn't expect those. Will need to tweak the line parser for that scenario.
Yes... I had forgot to select the Sub Main in the project properties (it is a component).
Now that I fixed that, it disappeared from the zombie report.
The scanner is working fine in that regard, then.
Yes, it is then the only thing I'm reporting.
For my case, I already changed those comment lines to avoid underscores at the end.
Thank you.
Line continuations (underscores) *do* work for comment lines like this.
. . . both first and second lines are part of the comment or am I not understanding the problem?thinBasic Code:
Option Explicit Private Sub Form_Load() Rem First line _ Second line '-- First line _ Second line End Sub
cheers,
</wqw>
@wqweto, that is how I believe I coded the scanner now that I am thinking about it more. I know I've used comments like that in the past -- looks more pleasing to my eyes with just one tick/REM statement
@Eduardo, is this the scenario that was triggering false positives..
If not, could you provide a simple example so I can look at the code in more detail down the road?Code:Static sVariableName as Boolean ' some comments _
It may have interpreted it as a method, but shouldn't have. I'm pretty sure the code requires Sub, Function, Property to flag methods. My guess is that the flags were simply wrong due to failed parsing and 'method' is just a byproduct of bitwise comparison of the faulty flag value.
LaVolpe, in the case of the Static variable, the scan process was silently aborted because of a runtime error. The scanner didn't work at all until I traced the issue to that procedure and made that change.
But after that, I found others issues, this time as false positives like variables not used when they were in fact used. I had several cases like that.
About the issue of line continuations in comment lines, I see what wqweto points (thanks). Then, perhaps it is not that comments lines are handled differently by VB regarding to line continuations, but that line continuations require one space before the last underscore?
Here is a sample of what caused the problem:
Or simpler, causing only the first problem:Code:' declarations...
' declarations...
'_SOME_COMMENT_
' declarations...
Private mVariable As Long ' mVariable Reported as not used
' declarations...
'_
' code...
' code...
'_SOME_COMMENT_
Private Sub NameOfSub()
Static sVariable As Boolean ' Static variable that caused the run time error
If Not sVariable Then
sVariable = True
' code...
' code...
End If
End Sub
'_
' code...
' code...
'_SOME_COMMENT_
Private Function F1() As Boolean
Dim i As Long
' code...
i = mVariable ' mVariable is used
' code...
End Function
'_
Code:' code...
' code...
'_SOME_COMMENT_
Private Sub NameOfSub()
Static sVariable As Boolean ' Static variable that caused the run time error
If Not sVariable Then
sVariable = True
' code...
' code...
End If
End Sub
'_
The problem is likely the trailing underscore. I know I coded to ensure a 'space underscore' is a continuation, but may not have done that for comments. I doubt it is the leading underscore. In any case, I'll need to check the code in more detail.
Thanx Eduardo for the bug report
After I changed the comments to:
all the problems went away.Code:' code...
' code...
'_SOME_COMMENT_1
Private Sub NameOfSub()
Static sVariable As Boolean ' Static variable that caused the run time error
If Not sVariable Then
sVariable = True
' code...
' code...
End If
End Sub
'_2
So the problem is that in comments trailing underscore has to be space prefixed to be treated as line continuation by the parser.
Here is another sample where no comment/code continuation should happen
thinBasic Code:
Option Explicit Private Line_ As Long Private Sub Second(A As Long) End Sub Private Sub Form_Load() '-- First Line_ Second Line_ End Sub
Not that final underscore can be part of variable name in normal code lines so space-underscore combo is actually required to be non-ambiguous.
cheers,
</wqw>
I thought of another check that would be useful under the "zombie" category - labels without a corresponding Goto or On Error Goto. It would catch some non-functioning error handlers.
Updated project posted.
Excellent project LaVolpe!
I made a couple very small modifications to this so it can accept a project file through command line arguments and open it directly. That way I can have the compiled .EXE in my MZ-Tools app shortcuts toolbar and launch it for the currently opened project with just one click. It's such a trivial modification it hardly seems worth it to post the code but there's an idea that you might wanna consider implementing yourself that probably takes no more than a few minutes! :)
Not a bad idea. Might even want to add command line switches to run silent & auto-save validation reports? Food for thought if I update again. And I probably will update again since this was a complete rewrite, logic-wise, which means I might have a logic error or two not yet found
I tested your Project Scanner today and i don't understand why this Item is in zombie state:
It's the Validate event of a text box control (VBCCR16's TextBoxW).Code:Items in zombie state
Method: txtCommentEdit_Validate
The CausesValidation property of the text box is set to True.
I want to add that with Krool controls, GotFocus and LostFocus procedures are also reported as zombie.
I'll look into it this weekend. I may have forgotten to ensure the extender events were included with usercontrols or a logic flaw exists. Once that is resolved, extender events won't show up as zombies
edited: yep, logic flaw. Testing for extender events was mistakenly not applied to uncompiled usercontrols - doh. I'll post an update this weekend after a bit more testing and when I have more time.
Done. Project updated and re-uploaded.
Thanks LaVolpe. Now those zombies does not appear any more.
BTW, another issue that I noticed is that public variables of class modules (that are actually properties in practice) appear as zombies if they are not used in the class module.
LaVolpe,
Is there any documentation for what things went into the list of things to be flagged and what didn't? Some are self-evident like zombies but some I am guessing at (such as the use of CreateObject or CreateProcess) and I would like to know if my ideas match yours. Thanks.
@MountainMan. Yes, press F1. Then Ctrl+F and search for "Safety Warnings". Its near the bottom of the page
Thanks. I didn't know you had a Help system in the program.
You're welcome. In the clsValidation, you see a method not-best-named: pvListMaliciousDLLs
That would be the complete list if there's any difference in the help page -- not 100% that page is 100% accurate any longer with recent tweaking and updates.
That listing in code is just DLLs. The VB functions on the hit list are in the resource file. Open the string table and item #2 is what you are after. You can scroll in the res editor window, but easier to select all & copy/paste elsewhere.
Edited: Don't mess with the string table, unless you keep the sorting correct. Throughout that project, I use binary searches on strings and CRC values. Very fast, but requires lists to be sorted. Having an unsorted list will break the binary search to the point is almost unusable. Elsewhere, if a list isn't coming from the string table, the sorting is done real-time, as needed.
You might want to modifyyour menu for dummies like me such that you have a Help menu item with the View Validation Descriptions as part of that. What you wrote is very helpful though.
One area I go tripped up on was the malicious code thing. I was thinking "hwy of course my ShellW module has a CreateProces call in it. I wrote it and I know it is okay and not malicious." I wasn't thinking that this would be a useful tool for folks who bring in code from elsewhere without going through it. I don't do that; anything I use I take it apart partly to make sure I understand what is going on and partly to avoid the potentially malicious things that might be in the code. I haven't seen any of that on this forum so I wasn't thinking of having to do that. But I can see where it might be useful to some. Thanks, you have widened my perspective today... :-)
That was the intent. I actually started that for me and expanded it over time. One of my pet peeves is forgetting to check for SaveSettings and DLLs that tend to write stuff to the registry. If I'm only helping debug it, I don't want registry stuff written. If I'm only downloading out of curiosity, I don't want registry stuff written. Guess you can tell, that get's under my skin :eek:
Minor modifications made.
When conditional compilation directives are used, i.e., #If #Else, it was possible that the scanner could include statements it should not. Fixed.
Added ability to drag/drop a file onto the compiled exe file. The scanner will open and immediately start processing the dropped vbp/vbg file.
Excellent project.
One feature comes to mind, which could be handy. I constantly find it hard for programmers to avoid mishandling dynamically dimensioned arrays especially udt arrays. Typical error, is passing module level array element as an argument to a procedure or function.
https://docs.microsoft.com/en-us/off...ocked-error-10
Well, I am not looking at trying to follow code execution. In your example, one would need to identify fixed arrays (easy enough), but then would need to see if it is passed to a method, then look into that method to see how it is used, i.e., using ReDim on it. That is outside the scope of the scanner.
That is also a reason why the scanner does not attempt to validate that a Public method in a class, usercontrol, etc is in zombie state. It would require the scanner to track usage of objects/variants and more just to see if one of them were declared as the class, form, etc and determine what methods it may be calling. For example, we can assign a class instance to a variable declared as: Object, item in Object(), Variant, item in Variant(), or a Collection item. And from any of those, we can call any public method directly from the object. To make it even more daunting, is that is possible that the reference is passed yet to another routine where, within that other routine, the public method is eventually called from that item.
Yes, this is impossible to track. What *is* possible is to detect method names used late-bound in a global list. Then if a public method is not directly used early-bound (which is easier to detect) its *name* can be searched in the global late-bound calls list and if not found there too it's probably dead code (unless it's a public method of a public class of an ActiveX DLL/OCX and can be used by external projects).
cheers,
</wqw>
This comment is really intended for others. If I cannot determine zombie state in all scenarios with good confidence, then one can argue it is pointless to try. The results could be 99% correct in 'easy' cases and be less than 50% correct in many other cases. The scanner already has the potential of creating zombie false-positives, but those should be few. I don't want to introduce a scenario where the false positives can be commonplace.
An example of a zombie false-positive. For sake of this argument, a method is not an event. If the scanner checks private methods and a private method is never called, then how can the zombie state be a false-positive? Answer: thunks. Many thunks are created to call private methods of a class, form, etc. No other code in that code page will be calling the method. The thunk calls the method by its pointer, not its name and thunks are 'outside' code, not available until run-time. That private method will be flagged as a zombie even though it is not, but the scanner has no way of knowing that.
As to the larger question. Is it possible to create a 'call tree' for the entire scanned project? Yes. I'll leave that as an exercise for others when they get bored and want to spend a few months on a 'big' project.
DO YOU HAVE CODE FOR SPLIT A function?
can split every part:(public ,private),return type,optional default value
Code:private function sum(byval a as long ,optional byval b as long=12 ) as long 'sum(3,4)=5
sum=a+b
end function
Splitting a function? In the scanner project, that is done because it needs to be done to find the properties of the function:
- start/end of method
- scope
- method type
- return vartype
- parameter count, parameters, parameter vartypes
- executable lines within the method
However, there is no single function in the project that does all of that. The scanner processes code files in two passes. Only if user chooses to validate the project, then a second pass is done to parse out parameters and the executable lines within the method.
If you are asking me to write a routine for you, I will not. It is not that difficult to do, but you have other scenarios you may need to handle. For example, if a method is broken into 2 or more lines using continuation characters. And there are other things that can exist in a method: ParamArray for example, arrays in the parameters and return value. ByRef,ByVal and vartypes are optional also. And scope can be Public, Private, Friend (none are required), and can also include keyword: Static.
If you have any further questions on how to parse something, post it in the general VB forums section. I won't be addressing "how-to" hints and workarounds on this thread regarding that topic. Happy parsing!
I was looking for something like this, so I did a try, I think I found a bug,
I get the report:
Quote:
Results for config
Items in zombie state
Variable: fa in method login_setting_render
Variable: kk in method login_setting_render
Variable: ff in method login_setting_render
ka is missing.Code:Sub login_setting_render()
Dim ff&, kk&, fa&, ka&
Mouse = 0
engine.Render 7, 70, 188, 0, 0, 660, 185
engine.Render 7, 70, 373, 0, 480, 660, 25
engine.Render 7, 80, 211, 10, 1241, 640, 176
WriteText 17, BS.MHelper(23), 380, 196
renderOptions 232
End Sub
and the same in another:
Variable: i in method BoxRender
but I have Dim i&, yy& and I cant find neither in the function.
and the same here:
Variable: weak in method ShowMonster
Variable: strong in method ShowMonster
Variable: c in method ShowMonster
Dim a&, b&, c&, strong$, weak$, immune$
and immune should also be reported.
and a couple more places with similar results.
suggestions:
- check if a function is called from "module1" that is resident in "module2" and make sure its not "private"
(I know your program is not checking, since I can put a "Private" function on another module that is needed from another module, and it will not tell) that function need to be changed to Public to work.
sure if I try to compile it will give me an error, but its good to have.
also, do you check like this:
module1: theres a call to "MyFUNC" that is in module1, but theres another MyFUNC in module2. so doublets. one is Private and one if Public.
from module3 I call MyFUNC believing it will take the "Private" one, but it will instead take the "Public" one. so good to report if theres such scenario.
I'll have to double check and make sure when 2+ variables are declared on same line, the splitting routines are not off-by-one in some cases, ignoring the final variable.
For those routines where you see a 'bug', can you zip up the routines? Also include your module/class-level declarations. Don't worry about including other stuff called from those modules -- it does not need to be able to be compiled. I just want to dump those routines to a module or class in a test project and scan those.
I like your idea of looking for duplicate methods in bas-modules only, where one is public & the others are not. As for the other scenario. I thought I was checking for private methods in a bas-module that were not used -- maybe it's something new I was adding? Need to revisit that. However, the project won't check if a method should be public instead of private. One of the key 'rules' for using this tool is that the project must be able to be compiled, otherwise, false results can be reported.
I've been tweaking that project off & on over the past few months and might be time to post an update but I'd like to verify any changes work with what you are reporting.
baka, the yy& may be a bug mentioned in previous reply where last variable in line might be ignored -- will fix that if that is the case.Quote:
Variable: i in method BoxRender
but I have Dim i&, yy& and I cant find neither in the function.
But the i&, do you have i declared in the declarations section of that code page or publicly in a bas module? If so, then I have a bug where the i variable was found out of scope of the method & determined not a zombie when it should've been. This question is just to help me narrow down where to look.
Nb : La Volpe, have you seen my message?
I managed to remove a lot and just show a bit and the functions that resulted in the missing variables.
yes its about the last variable.