The original version of Project Scanner cannot handle Chinese characters, and now the new version can. I'd like to know what steps you've taken to deal with Chinese characters? Thanks!
You can use WinMerge to see what changed between two VB projects.
- Zombie declarations and procedures. Items that are created/declared but not referenced within your code
- Strings that are duplicated within your code. These can be consolidated to constants
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:
Code:
sToken = Mid$(sLine, iPos + 1, lFlags - iPos - 1)
because lFlags is 0.
I traced the error and it is misinterpreting a line that is:
Code:
Static sVariableName as Boolean
It is interpreting it as it was a Static procedure.
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:
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
Because even when a procedure is Static, it also must have Sub, Function, Etc.
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".
Last edited by Eduardo-; Oct 2nd, 2019 at 12:28 AM.
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.
Insomnia is just a byproduct of, "It can't be done"
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.
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.
Originally Posted by LaVolpe
Underscores on comments: Yep, didn't expect those. Will need to tweak the line parser for that scenario.
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.
@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..
Code:
Static sVariableName as Boolean ' some comments _
If not, could you provide a simple example so I can look at the code in more detail down the road?
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.
Insomnia is just a byproduct of, "It can't be done"
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:
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
'_
Or simpler, causing only the first problem:
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
Insomnia is just a byproduct of, "It can't be done"
' 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
'_
After I changed the comments to:
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
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.
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!
...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
Insomnia is just a byproduct of, "It can't be done"
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.
Last edited by LaVolpe; Apr 18th, 2020 at 11:04 AM.
Insomnia is just a byproduct of, "It can't be done"
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.
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.
I'll take a look. It's something that I may have forgotten to address during the rewrite. I know I addressed it in the previous version. Bug reports always welcomed.
Edited: patched & updated
Last edited by LaVolpe; Apr 18th, 2020 at 04:13 PM.
Insomnia is just a byproduct of, "It can't be done"
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.
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.
Last edited by LaVolpe; Apr 20th, 2020 at 03:14 PM.
Insomnia is just a byproduct of, "It can't be done"
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... :-)
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
Insomnia is just a byproduct of, "It can't be done"
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.
Insomnia is just a byproduct of, "It can't be done"
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).
Yes, this is impossible to track. What *is* possible is to ...
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.
Last edited by LaVolpe; May 10th, 2020 at 11:54 AM.
Insomnia is just a byproduct of, "It can't be done"
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!
Last edited by LaVolpe; May 14th, 2020 at 11:08 AM.
Insomnia is just a byproduct of, "It can't be done"
I was looking for something like this, so I did a try, I think I found a bug,
I get the report:
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
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.
Last edited by LaVolpe; Sep 8th, 2020 at 12:06 PM.
Insomnia is just a byproduct of, "It can't be done"
but I have Dim i&, yy& and I cant find neither in the function.
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.
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.
Insomnia is just a byproduct of, "It can't be done"