How do strings work in VB - vbscript

I am currently reworking an Intranet Website using Active Directory, and the ancient developer did everything in VB, I am now developing it in C# and a bunch of recent technologies. So I am going through his code for a few functionalities I'm having a hard time with (I did a quick overview of VB to see how it works globally) and I don't understand how strings work here.
For example, there is the following declaration:
Dim sGroups, oGroup
sGroups=activeDirectoryUserObject.memberOf //Returns groups that user belongs to
set oGroup = GetObject("LDAP://" & sGroups)
For j = 0 To UBound(sGroups)
Set oGroup = GetObject("LDAP://" & sGroups(j)) //Here!!
What is sGroups(j)? To me sGroups is a string not an array, so what's going on here?
Thanks for your help!

Leonard:
It appears that sGroups(j) is a string and that the (j) part is a counter. Possible that this is being used if the user belongs to more than one group.
Sincerely,
Joe

Strings are not indexed in VBS/VBA/VB6. And the method of indexing is different in VB.NET. So if the object is indexed, "sGroups(j)" it's not a string.
The obvious way to work out what sGroups is, would be to look at activeDirectoryUserObject and it's memberOf attribute. Which you should have done, and you should have included that code here, so that we could see it.
If it's an externally defined object, for which you have no documentation, you can use the Typename() function or VarType function to extract the information. Since this is a website using ASP scripting, either it's going to be a variant array, or the script is completely broken.
Either is possible, since the script fragment you have provided makes no sense by itself (see also the redefinition of oGroup with no code that uses it).

Related

Wrap "Open" VB6 function with custom function as drop in replacement

Question
Is there any way to write a custom function that uses the same pattern as the Open function? Including the fluff keywords like For and As?
Background
I am working on migrating an old VB6 project to use online data via an API, as a first step I'd like to replace all instances of
Open SomeFilename For Binary Access Read As #39
With a custom OpenOnline function
OpenOnline SomeFilename For Binary Access Read As #39
But I do not know how to indicate those keywords are necessary when creating a function, or even if it's possible to do so.
Function openOnline(FileName As String) [For] (Optional Access As AccessType = Binary Access) [As] (Optional FileNumber As Integer) As Boolean
' Do the work of connecting to the online data equivalent of FileName with that access type
End Function
Qualifiers
I understand that these keywords are nonsensical in the context of an OpenOnline function. I also understand that I can use regular expressions to find and replace the syntax to remove keywords like "For" and "Read".
There are hundreds of thousands of instances of this Open function, the Put and Get functions and a few other file related functions, I realize that long term the correct solution is changing the mechanisms fundamentally to use online paradigms, and that work is in progress- on schedule to be completed with about 4 months of effort at the rate things are going.
Bonus Question
Secondarily, is there any way for me to pass a "User Defined Type" variable to the new Put/Get replacements in a way that I can access their fields directly without knowing the type beforehand? (I understand that variants are only available for .cls classes or public user defined types in dlls, neither of which apply in this situation)
As for 1), you can get close but you can't exactly replicate the VB Open statement. Which means you won't get around of some search & replace passes for the current Open statement lines with your newly created one.
For 2), can you illustrate that with an example? I'm trying to think of a situation where you know the UDT member's name in advance, but not its type.
That said, perhaps looking at VB's VarType function gives you an idea for solving that.

What does a double-asterisk mean in a Visual FoxPro function call?

I'm trying to work with some Visual FoxPro 9.0 code written years ago by programmers now long gone. There are several uses of ALLTRIM() that include a double-asterisk in front of the field name being passed, such as:
fred = ALLTRIM( **barney )
where Barney is a character field in a table. When I try running that line in a VFP session, it errors out with "Function is missing )". But I'm uncomfortable supporting code that I don't understand - what does the "**" do?
I've tried storing the field to a memvar, in case there's a SCATTER in the code that calls this, with no change in the resulting error. I've tried storing other data types (numeric and boolean) to the memvar, still no change. I've been programming in dBase, then FoxBase, then FoxPro, then VFP, for almost 35 years - and I don't remember ever coming across this before. And yet, the program runs without errors, I just don't understand what it is doing.
In case any of this matters, the code in question is stored in a memo field in a table, then invoked with an EXECSCRIPT() call. And some of the tables that the code is working with (but not the one containing the code) are SQL Server tables, accessed through cursor adapters - so "barney" in my example is very likely a field in a cursor adapter, not a .DBF.
I found my answer. Searching for asterisks in source code was useless, of course, because of comments. But I finally thought, after posting this question, of searching for the string with surrounding quotes, and found that, before the code I was looking at was called with EXECSCRIPT(), it was also run through STRTRAN(), which substituted "m." or "." or some other appropriate prefix for the "**" in the code.
So, the double asterisk was internal to the application, and meant nothing to VFP itself.

Object name becoming lowercase

I have some code which has worked in multiple installations for about a year. Today im doing a small change to a control and then another control seems to have developed an issue. When at runtime im getting a 91 error object variable or with block variable not set.
I therefore looked at the problem line which is: -
If Screen.ActiveForm.name = "frmFoutmelding" Then Exit Sub
so I noticed the name was lowercase. if i delete .name and rehit the "dot" then it shows me i can use .Name but as soon as i move from this line it drops back to .name
I've checked for instances of name and it appears everywhere in the code in different modules but i cant find if i have accidentally defined this lowercase name anywhere?
Googling doesn't seem to show much but i feel Im googling the wrong terms
chaps - thanks for your suggestions - this was the first instance of the lowercase name and searching as Jim suggested didn't reveal anything I'm afraid. What I did discover was that this was suddenly being run before any forms had actually been displayed and so the count was 0. I therefore, did an on error to check the form count and exit the sub if it =0 then if not to carry on with the line I thought I was having issues with.
It's likely that you did create a new variable or property called (lower case) name, or that some included reference did the same. It's possible to use reserved words as variable names in some cases, but it requires taking specific steps.
I would first search your code for instances of name As to see if you created a variable (this assumes you use Option Explicit, which is a must IMO). Then search for Property*name with * as a wildcard.
If those fail you could try unchecking references or components to see if any of them define name. If none of that finds anything, please post back here.
Jim Mack covers a lot of the potential issues. I think another is if you typed a lower case '.name' in association with Activeform at some point earlier in the same code module - the VB6 IDE checks in the current module and uses that to define what case to use. Look further up the same code module (sub or function).
Ultimately, check what changes you made by comparing the old source to the new in a file comparison tool like windiff - you do have backups, right?

Why are files returned by a For Each loop sorted, but not always?

I'm not sure if this is the correct place to post this question because I have a hunch that the behavior I witness will also be observed using other methods. But anyway, here it goes.
I have a VBscript that contains code like this:
For Each objFile In colFiles
...
Next
I've been running this code for quite some time on many different systems. I never bothered to order the files alphabetically. But today I found out by accident that the logic of my program depends on it. I ran the code on a new system (under Citrix) and the files were returned in a seemingly random order.
Does anybody know why Windows sometimes returns the files sorted alphabetically while sometimes it doesn't?
Added note: It might be relevant to note that the script as well as the input folder are on a network share (where my script outputs randomly ordered files).
Ordering is not supported for FileSystemObject. See KB 189751 http://support.microsoft.com/kb/189751/en-us
Also check out an answer on how to deal with that on SO Order of Files collection in FileSystemObject
The docs do not specify an ordering. Thus, you cannot depend on it to have an order. The Files property needs to ask the underlying file system for the files, and then gives it to you as it, without any processing. If that file system happens to return the files in order, that's great. If not, you'll have to sort it. Regardless of whether it is in order, you should always order it if you expect it in a certain order because the implementation may change tomorrow (as you've just witnessed).
It depends on what data structure you are looping through.
You will obviously get a different order if you use foreach loop in an array and a hashset, for example.
Personally, I don't know anything about VB. But it does work this way in C#.

capturing what keys were used to launch vbscript

I have an application that has 'macro' capabilities. When I map some keys on the keyboard to perform the 'macro', I can also have it launch vbscript instead.
What i'd like to try and do is within my vbscript figure out what keys were used in order to launch the script. Is it posible to do this? Could there be a way in vbscript to figure out what keys were last touched on the keyboard and then I could apply my logic.
The purpose of doing this is to keep the code in a single .vb file instead of several seperate .vb script files(one for each keyboard mapping, possible 3-4). Obviously we are looking to just maintain 1 file instead of multiple files with essentially the same code in each one.
I am leaning towards the idea that this is not possible, but i figured this would be a worthy question for the masses of StackOverflow. Thanks for the help everyone!
What you are asking for is not possible.
Can you change your VBScript to accept parameters and then call it with a different parameter based on which hotkey was selected?
I agree with aphoria, the only way to make something like this possible is if your keyboard mapping software allows you to assign a script/command with parameters/arguments. For example if you used
c:\Temp\something.vbs
then you would change this to
%WINDIR%\system32\wscript.exe c:\temp\something.vbs "Ctrl-Alt-R"
Then in your vbscript code you could collect the argument using the wscript.Arguments object collection to do actions based on what argument/parameter was passed. See the following two links for more info:
http://msdn.microsoft.com/en-us/library/z2b05k8s(VS.85).aspx
http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept04/hey0915.mspx
The one possible approach you may use is to install keylogger and read its log in your VBScript.
For example save script start time in the very beginning of the script
StartTime = Timer()
and then read one log record of your keylogger before this time.

Resources