What is Interaction class? - vb.net

I have two following rows of code:
Microsoft.VisualBasic.Interaction.Beep()
or
Microsoft.VisualBasic.Beep()
The result is the same in this two rows.
what is Interaction class?And when shold i use it?
Thank you in advance.

Those two lines result in exactly the same code being generated. Which one you choose is a matter of style. Personally I would choose to simply use the Beep() command in the abscence of a namespace qualifier
Sub Main()
Beep()
End Sub
Between the two choices you presented though I would choose Microsoft.VisualBasic.Interaction.Beep() over Microsoft.VisualBasic.Beep(). The former is the fully qualified name of the method and it's completely unambiguous to the reader. The latter though is using a trick of VB.Net name resolution and one that would likely fool even the experienced VB.Net user.

One of the best things I love about Visual Basic is that it makes the code easier and usually contains shortcuts to functions commonly used, such as MsgBox, Stop and Beep. That's why both lines yield the same result, because they are actually the same.
Also, as #JaredPar mentions, is better to either use fully qualified name Microsoft.VisualBasic.Interaction.Beep() or just Beep() this will make the code more readable.

It is a bit of an odd-duck name and have no good guess beyond the methods being available in the Immediate window. The key is that the class is decorated with the <StandardModule> attribute. Which is a hint to the compiler to move the members of class into the global name space. So you can simply write MsgBox() and not bother with the class name.
Just like you could in VB6.

Related

Where is "require" defined?

I have been looking in Rakudo source for the implementation of require, first out of curiosity and second because I wanted to know if it was returning something.
I looked up sub require and it returned this hit, which actually seems to be the source for require, but it's called sub REQUIRE_IMPORT. It returns Nil and is declared as such, which pretty much answers my original question. But now my question is: Where's the mapping from that sub to require? Is it really the implementation for that function? Are there some other functions that are declared that way?
require is not a sub, but rather a statement control (so, in the same category of things like use, if, for, etc.) It is parsed by the Perl 6 grammar and there are a few different cases that are accepted. It is compiled in the Perl 6 actions, which has quite a bit to handle.
Much of the work is delegated to the various CompUnit objects, which are also involved with use/need. It also has to take care of stubbing symbols that the require will bring in, since the set of symbols in a given lexical scope is fixed at compile time, and the REQUIRE_IMPORT utility sub is involved with the runtime symbol import too.
The answer to your question as to what it will evaluate to comes at the end of the method:
$past.push($<module_name>
?? self.make_indirect_lookup($longname.components())
!! $<file>.ast);
Which means:
If it was a require Some::Module then evaluate to a lookup of Some::Module
If it was a require $file style case, evaluate to the filename

Implements vs Binary Compatibility

I have one VB6 ActiveX DLL that exposes a class INewReport. I added some new methods to this class and I was able to rebuild it and keep binary compatibility.
I have a second DLL that exposes a class clsNewReport, which implements the first class using:
Implements RSInterfaces.INewReport
Since I added new methods to INewReport, I had to also add those new methods to clsNewReport.
However, when I try to compile the second DLL, I get the binary-compatibility error "...class implemented an interface in the version-compatible component, but not in the current project".
I'm not sure what is happening here. Since I'm only adding to the class, why can't I maintain binary compatibility with the second DLL? Is there any way around this?
I think this is a correct explanation of what is happening, and some potential workarounds.
I made up a test case which reproduced the problem in the description and then dumped the IDL using OLEView from the old & new DLL which contained the interface.
Here is a diff of the old (left) and new IDL from INewReport:
Important differences:
The UUID of interface _INewReport has changed
A typedef called INewReport___v0 has been added which refers to the original UUID of the interface
(I assume that this is also what is happening to the code referred to in the question.)
So now in the client project the bincomp DLL refers to the original interface UUID; but that UUID only matches against a different name (INewReport___v0 instead of INewReport) than it did originally. I think this is the reason VB6 thinks there is a bincomp mismatch.
How to fix this problem? I've not been able to do anything in VB6 that would allow you to use the updated interface DLL with the client code without having to break bincomp of the client code.
A (bad) option could be to just change the client DLL to use project compatibility... but that may or may not be acceptable in your circumstances. It could cause whatever uses the client DLL to break unless all the consumers were also recompiled. (And this could potentially cause a cascade of broken bincomp).
A better but more complex option would be to define the interface in IDL itself, use the MIDL compiler to generate a typelib (TLB file), and reference that directly. Then you would have full control over the interface naming, etc. You could use the IDL generated from OLEView as a starting point for doing this.
This second option assumes that the interface class is really truly an interface only and has no functional code in it.
Here's how I setup a case to reproduce this:
Step 1. Original interface definition - class called INewReport set to binary compatible:
Sub ProcA()
End Sub
Sub ProcB()
End Sub
Step 2. Create a test client DLL which implements INewReport, also set to binary compatible:
Implements INewReport
Sub INewReport_ProcA()
End Sub
Sub INewReport_ProcB()
End Sub
Step 3: Add ProcC to INewReport and recompile (which also registers the newly built DLL):
(above code, plus:)
Sub ProcC()
End Sub
Step 4: Try to run or compile the test client DLL - instantly get the OP's error. No need to change any references or anything at all.
I was able to recreate your problem, using something similar to DaveInCaz's code. I tried a number of things to fix it, probably repeating things you've already tried. I came up with a possible hypothesis as to why this is happening. It doesn't fix the problem, but it may throw some additional light on it.
Quoting from This doc page:
To ensure compatibility, Visual Basic places certain restrictions on changes you make to default interfaces. Visual Basic allows you to add new classes, and to enhance the default interface of any existing class by adding properties and methods. Removing classes, properties, or methods, or changing the arguments of existing properties or methods, will cause Visual Basic to issue incompatibility warnings.
Another quote:
The ActiveX rule you must follow to ensure compatibility with multiple interfaces is simple: once an interface is in use, it can never be changed. The interface ID of a standard interface is fixed by the type library that defines the interface.
So, here's a hypothesis. The first quote mentions the default interface, which suggests that it may not be possible to alter custom interfaces in any way. That's suggested by the second quote as well. You're able to alter the interface class, because you are essentially altering its default interface. However, when you attempt to alter the implementing class in kind, to reflect the changes in your interface, your implementation reference is pointing to the older version of the interface, which no longer exists. Of course, the error message doesn't hint at this at all, because it appears to be based on the idea that you didn't attempt to implement the interface.
I haven't been able to prove this, but looking at DaveInCaz's answer, the fact that the UUID has changed seems to bear this idea out.

Where in the VB6/VBA project references do Array(), LBound(), and UBound() come from..?

Where in the VB6/VBA project references do Array(), LBound(), and UBound() come from..? When I'm typing in code, they don't appear in the Autocomplete list (ctrl+space), they don't get autocompleted, and they must be typed out completely before the text editor recognizes them. And only when a left-parenthesis is typed will ToolTipText pop up with the command syntax. Also, they do not appear anywhere in Object Explorer.
There's probably a basic concept in play here that I'm not aware of. And it makes me wonder, what other commands/statements/keywords are hidden in the same way..? Is there a list somewhere..? I googled for info but didn't find anything, probably because I don't know what I'm looking for and using the wrong search terms.
I ask these questions because I have the habit of prefixing many VB6 built-in functions like this: VBA.Left(), VBA.Len, VBA.Instr(), and so on. But I can't figure out what reference prefeix to use with Array(), LBound(), and UBound(), or perhaps they're so basic to VB6 that they don't have one.
I do this prefixing because years ago I was working on a large project, and there were functions I was trying to use with the same name in different reference libraries. I was a newbie and it took me a while to figure out, and it was causing tremendous problems since the functions were just NOT working the way I thought they were supposed to. It was then that I developed the prefixing habit after I figured it out. It's just easier that way, and always ensures the expected functions are being used.
The reason that they don't appear as IntelliSense options (and also why they don't appear in the Object Browser) is that they aren't declared in the VBE7.dll typelib for some reason that's beyond me. The Array function is implemented in the .dll as rtcArray. The utility of knowing that is dubious, in that its sole argument is a ParamArray, which means that if you called it directly from VBE7.dll you would need to create an array to have it feed you back the same array... This partially explains why it isn't on the typelib - a COM call would need to do the same thing, and the marshaling would basically be doing the same thing as what you'd expect the function to return.
LBound and UBound don't even appear as functions in the export table, so my guess is that they are handled more like "keywords" than first class functions internally. This makes some sense, in that it's fairly trivial to check the bounds of a SAFEARRAY if you have a pointer to the automation struct (you just index into the rgsabound array at the end of it and read the cElements and lLbound from it. Again a guess, but I'd assume that this allows for flexibility in letting LBound and UBound function with both fixed length and variable length arrays. In the fixed case, the array is basically managed as a block of memory with an indexer (more like a VT_CARRAY than a VT_SAFEARRAY). I'd imagine that handling this internally was easier or more convenient than providing first-class functions.
You won't find Debug in the Object Browser either, nor its methods Assert and Print.
You won't find Statements that are used like methods, like Open, Close, Get and Put, which is why you don't get any Intellisense when you use those statements, and the syntax must be memorized.
You will find Load and Unload as members of VBA.Global, but it's not clear what they belong to otherwise, and their arguments are late-bound Objects. The VBA documentation states that Load and Unload are Statements, even though the Object Browser shows them as Methods.
Keep in mind that you can move the order of references and it will make a difference. Try moving VBA to the top or near the top of your list of references. I believe that if something else also defines a BASIC keyword, it steals it, in a sense. I once had Right disappear and because I was not aware of the order of references, had to change all references of Right to VBA.Right. It's possibly the same with the ubound, lbound, or array.

Odd behaviour of casing of a control name in vb6 code

I have a label control on a form named lblTotal
During my last commit to the repository I was surprised to see this form's name on the modified list.
When I looked through the code I saw that all occurrances of this control's name were now lbltotal, (ie Small t).
The control's name itself was lblTotal in the properties window.
Further when I used ctrl-F with case matching to find lbltotal it would only find one as instantly all other occurrances would revert to lblTotal.
So it seems that at some moment after the IDE records some event in the code window it gets around to making the casing conform to the control's name.
What I don't understand is how this happened in the first place without a change to the control's name?
Can someone explain how?
PS After I wrote the above I saw this. Interestingly I also had a string variable that's name had its casing changed during the same commit and I assumed I must have changed it myself but now, having read the above I think it's because the same variable name was present in a different scope.
However there is no other occurrance of lbltotal anywhere else in the project.
PPS lblTotal is actually lblTotal(0) and many more copies are loaded during runtime, so a lot of the code references are lbltotal(x1).Caption etc. I don't know if this makes any difference.
Finally has anyone ever seen vb6 change the casing of string literals by itself? (Please God no!!)
Actually this last point is what causes me the most unease about this experience as in TOO many places in the codebase string literals are used in conditional clauses.
On top of the behaviour mentioned, VB6 will also re-case variable names that happen to occur in any of the COM interfaces your program references, which means that if you reference a new library, or change their order, you're in for even more fun.
At one time I even wrote a small program that "right-cased" VB6 source code from a dictionary of names ; the main drawback to that is you have to run it before each source commit.
But I think the answer from wqw here -> https://stackoverflow.com/a/1078018/108753 is probably the best solution to the problem I've seen, because he has quantified and exploited the behaviour of the IDE to solve the problem.
At least it's not VB3 - VB3 re-cases every variable in any files you have loaded into memory to what you last typed. Which makes you a lot more precise about typing case in variable names....

Internationalization in VB.Net : Choosing the right structure type

I'm about to start translating my vb.net application, and I don't want to use the default methods provided by Visual Studio to do so. I need my application to be very light, and it nearly doubles it size to use the resources option.
Therefore, I'm planning to use some thing like a class, of which I would have one instance per language. Since I don't want to distribute language files as separate files (I'd rather have them hard-coded), I would like to find an easy way to check if every field of the class is initialized. I was thinking of something like an Interface, where I would do something like this:
Public Interface Language
Dim HelloMsg As String
Dim GoodbyeMsg As String
End Interface
Public class English Implements Language
HelloMsg = "Hello!"
GoodbyeMsg = "Goodbye!"
End Class
It's obviously not the right way to do it (although I could use properties instead of vars), but I was wondering whether the was a way to have the compiler check that everything is translated and warn about it if not.
Anyway, maybe is there a much better way to handle this problem ?
Thanks a lot!
CFP.
I'm not convinced that you should dump the resource-based localization approach just because your app has grown in size. Indeed, it could've grown from 100 Kb to 200 Kb, but this is it! It won't grow this much more. And 200 Kb is nothing nowadays.
So my advice is to reconsider and go resource-based route.
I've decided to use a singleton class that loads a translation file, with a method that loops through all items on a form and translate on-the-fly. See Create Synchronicity source code for more details (more specifically TranslateControl in this code file)