Where is VB.NET's MsgBox function defined? - vb.net

This is really more of an academic question, but where is this function defined? Within .NET, I'm used to working in an object oriented manner. However, if I define a VB.NET class as follows:
Public Class foo
Public Sub showmessagebox()
Dim i As Integer
i = MsgBox("Message")
End Sub
End Class
Is MsgBox defined in a class? I am not required to reference a static class or inherit from another class. I'm not even required to import a namespace. I did find this link from msdn. But my question remains, where is this defined and how does the CLR just load up a function?

If you enter MsgBox into Visual Studio and hit F12, you will see that it is in the Microsoft.VisualBasic namespace, in the Interaction module.
In fact, this information is also available (although a bit hidden) at the bottom of the MSDN page you referenced:
Namespace: Microsoft.VisualBasic
Module: Interaction
Assembly: Visual Basic Runtime Library (in Microsoft.VisualBasic.dll)
If you look into the References section of your project properties, you'll see that the Microsoft.VisualBasic namespace is automatically imported. Since Interaction is a module, you can use its methods without having to qualify the module name (as opposed to static/Shared methods of a class).
As a side note: If you add a reference to Microsoft.VisualBasic.dll to a C# project, you can use Microsoft.VisualBasic.Interaction.MsgBox("Hello World"); there as well (although most C# users will prefer using the MessageBox class).

Related

What is the use of Module in VB.Net programming?

I am creating a .dll for a CAD tool I use.
After creating a new project (class library) , I got a "public class-end class" block.
I wrote my main method inside that block. When I run the dll in my CAD tool, its giving me main entry point missing error.
So i come back and change the "public class-end class" ---> "Public Module-end Module".
Now its able to find the main method.
Why is this so? Ive read on these forums that we should not be using modules as much.
If I were to not use modules so much, how I am supposed to make it work without the module block?
VB.Net doesn't have static classes like C# has. Static classes allow you to create static methods such that
class foo
{
void bar() {}
}
Accessed in VB.Net like this
foo.bar()
If you want to create the same functionality with VB.Net you have two options, which are either using a Module
Module foo1
Sub bar()
End Sub
End Module
Class foo2
Shared Sub bar()
End Sub
End Class
However the difference is how Module and Class are scoped. Modules are globally scoped so you can call the module method outside of the originating namespace without qualifying it with the Module name, but to call the static method you need to qualify it with the class name, and even import the namespace in the case of a class with static method
bar()
foo2.bar()
But what Modules are certainly good for is Extension Methods, and the global scope actually helps here if you want to extend a class across your project
Module Extensions
<Extension>
Sub bar(value As String)
End Sub
End Module
Dim s = "my string"
s.bar()
In your case, it's expecting a C# style static class with method, and since VB.Net doesn't have static classes, a Module or class with static method both satisfy that.
Modules come from legacy versions of Visual Basic and sort of act as the "OG" of Visual Basic code files. When Visual Basic 6 and earlier was around, Visual Basic was sort of quasi object oriented and while classes existed, it made more sense to use modules in lieu of static classes. Then when Visual Basic .NET was introduced, Microsoft made a real effort to make the programming language a true object oriented programming language.
People likely tell you to use classes over modules because modules are holdovers from the days prior to Visual Basic being a pure object oriented language. Starting from 2005 on forward, anything you could do in a module could basically be done as a static (aka shared) only class with the exception of extension methods. So by using classes over modules, you're taking a more .NET oriented approach rather than a Visual Basic first approach.
With regards to your specific problem, the issue is that your CAD tool is looking for an entry method, but cannot find one. The simple solution is to add a shared method:
Public Class MyClass
Public Shared Sub Main()
' ...
End Sub
End Class

VB.NET - Module Interpreted as Class in VBE

I am building a VB.NET class library that will be used for VBA Projects. In my library, I have a module called "Globals" I wish to store some global (Library level) properties and methods in:
Imports System.Runtime.InteropServices
<ComVisible(True)>
Public Module Globals
<ComVisible(True)>
Public Const TestGlobal As Integer = 0
End Module
However, when I reference my library in the Excel VBE, my module shows up as a Class and I can't see my constant variable in the Object Browser:
What am I missing or doing incorrectly that's causing my module to show up as a class?
There's somewhat of an "impedance mismatch" between VB.NET and COM. COM works primarily with interfaces, and .NET builds the .tlb files from VB projects in a way that makes them more accessible to COM. A Module in VB.NET is basically just a static class in the managed world. When the interop assembly is built from your code, it sees a class, wraps it in an interface, and attaches the interface to the class:
Note that you can't provide your own interface implementation for a Module, because static classes in .NET can't implement interfaces.
The other thing that you can't do in .NET is create member procedures that aren't wrapped in a class. That is basically what a Module is in the COM world. For example, take a look at the IDL for the VBA Strings module:
module Strings {
[entry(516), helpcontext(0x000f665f)]
short _stdcall Asc([in] BSTR String);
[entry(537), helpcontext(0x000f6e9f)]
BSTR _stdcall _B_str_Chr([in] long CharCode);
[entry(608), helpcontext(0x000f64e2)]
VARIANT _stdcall _B_var_Chr([in] long CharCode);
[entry(517), helpcontext(0x000f6ea0)]
Note that all of the entries have a .dll entry point specified. That's basically because you're making raw function calls of the variety you'd find in the C world. If an analogue existed in the .NET world, it would be a Sub or Function declared at the namespace level instead of the class (or module) level...
<ComVisible(True)>
Namespace SomeClass.Functions
<ComVisible(True)>
Public Function Foo() As String
Return "Foo"
End Function
End Namespace
...which obviously isn't valid .NET code.
On a related note, keep in mind that you aren't seeing the entire picture in VBA either. VBA is basically built on top of COM, but it tries really hard to abstract away most of it. A VBA Module can for all intents and purposes be treated as a static class. For example, you can give them properties, public members, etc. At the end of the day, it really doesn't matter whether the VBA Object Browser sees something as a class, a module, or whatever - what matters is that you can use managed code from an unmanaged context. Just work around the differences in the 2 infrastructures to get something usable and call it a day:
Imports System.Runtime.InteropServices
<ComVisible(True)>
Public Enum Constants
GlobalOne = 0
GlobalTwo = 1
GlobalEtc = 2
End Enum
<ComVisible(True)>
Public Class FunctionProvider
<ComVisible(True)>
Public Function Foo() As String
'Note that the class doesn't need to keep track of "state" to be usable.
Return "Foo"
End Function
End Class

How to use reflection to unit-test an internal (Friend in VB) class within an assembly, when the InternalsVisibleToAttribute is not an option?

I have a solution with two projects within:
Company.Project.vbproj
Company.Project.Tests.vbproj
Within the Company.Project.vbproj assembly, I have a class FriendClass.vb which scope is Friend (internal in C#).
Now I wish to test this FriendClass.vb from within the Company.Project.Tests.vbproj assembly. I know about the InternalsVisibleToAttribute, but that is not an option in Visual Basic .NET 2.0, as it is only available with C#, in .NET 2.0 (see here).
I would like to create myself a proxy class using this internal FriendClass from within my testing assembly, so that I could instantiate it and do the testings accordingly.
Any idea or known practices to do so?
Thanks in advance! =)
The only workaround that I have found is one used back in .NET Framework 1.1.
As the InternalsVisibleToAttribute is not useable in .NET 2.0 Visual Basic, the only workaround that I have found is to include my tests within the same project as my library itself. Besides, some further work needs to be accomplished.
Create yourself a new compilation CONFIG called "Tests" (that is where you may select "Release"/"Debug");
Create a new folder named "Tests" within your project;
Add a new class, the one to test your Friend (internal in C#) members;
First line of code within this class should be: #if CONFIG = "Tests" then ... #end if;
Place your code between this compiler IF directive.
For example, if I have the following Friend class:
Friend Class MyFactory
Friend Property Property1 As Object
Get
Return _field1
End Get
Set (ByVal value As Object)
_field1 = value
End Set
End Property
Friend Sub SomeSub(ByVal param1 As Object)
' Processing here...
End Sub
End Class
Then, if you want to test this class in .NET 2.0 Visual Basic, you will need to create a test class within the same project where the MyFactory class sits. This class should look like so:
#If CONFIG = "Tests" Then
Imports NUnit.Framework
<TestFixture()> _
Public Class MyFactoryTests
<Test()> _
Public Sub SettingProperty1Test
' Doing test here...
End Sub
End Class
#End If
Since you have a compiler directive telling the compiler to compile and to include this class only when the "Tests" CONFIG is selected, you won't get this class on "Debug" or on "Release" mode. This class won't even be part of the library, this for not polluting your library unnecessarily, and this allows you to test your Friend class anyway.
That is the smartest way I have found to work around this issue in Visual Basic .NET 2.0.

Will VB.NET automatically generate ComClass attribute and guids?

I've run across some VB.NET code that explicitly creates three GUID constants and uses them in a class's ComClass attribute. I've written COM-aware classes in the past just by checking the "Make COM-Visible" and "Register for COM interop" options in the project options. Is this explicit code simply unnecessary, or is it doing something above-and-beyond what those two options do? Here's a snippet:
<ComClass(MenuHandler.ClassId, MenuHandler.InterfaceId, MenuHandler.EventsId)> _
Public Class MenuHandler
Public Const ClassId As String = "A2204623-A902-44d4-B524-FDFFCD176E53"
Public Const InterfaceId As String = "3449CA8B-16DF-4a61-8BAB-DFF27AE70F5E"
Public Const EventsId As String = "06C156DD-0ABA-437e-9EE0-C1CE2CA34033"
End Class
The ComClass attribute is specific to Visual Basic and is intended to simplify the creation of COM objects in .Net code. When the compiler sees this attribute it do some of the tedious work under the hood that must be manually done in C#. In summary, it's a shortcut for Visual Basic Code for creating COM objects.
Here's a great article on what this provides over doing the same in C#:
http://codebetter.com/blogs/peter.van.ooijen/archive/2005/08/02/130157.aspx
By explicitly putting attributes on the classes and enumerations that you want exposed you can prevent things like helper classes, internal tools, or internal classes that should not be exposed from being exposed. This is the recommended way from Microsoft to do it...and when they recommend something, it usually means that if you don't do it, your program may break in the future. :)
Checking "make COM visible" and "register for COM interop" is the simple method for making COM visible objects, but is not recommended. This will add the overhead for every class visible - even ones that you may not want.
Will VB.NET automatically generate ComClass attribute and guids?
Yes, if you use VB.NET COMClass template to create a class, COMClassAttribute and those GUIDs will be automatically generated.
Detail in MSDN
Section "To create a COM object by using the COM class template"

Problem overriding methods in VB.NET (Error BC30284)

I have an overridable sub in my base class
Project1:
Public Class BaseClass
Protected Overridable Sub MySub(ByVal Parameter as MyType)
End Class
Project2:
Public Class DerivedClass
Inherits BaseClass
Protected Overrides Sub MySub(ByVal Parameter as MyType)
End Class
MyType is a type that comes from external COM library. When I'm trying to override it in a derived class, I'm getting
error BC30284: sub 'MySub' cannot be declared 'Overrides' because it does not override a function in a base class
I've added the required COM reference to both projects containing base and derived classes.
Any idea how to get rid of this error? I'm using VS2005 and .NET 2.0
Edit: Every other override is working fine, I'm only getting error if I'm using referenced COM types as parameters. If I change Parameter to Object, overriding works fine.
Have you considered or tried using TlbImp.exe to generate a static DLL from the COM type library, and reference that from both projects (instead of using a COM reference) to make sure they are referring to exactly the same thing? TlbImp is included with Visual Studio, but I can't find it on my system with only Visual Studio Express installed, so if you're using express, you might have to go hunting for it (the linked page may or may not have the version you want). I suspect that if each project has their own COM reference, Visual Studio may be creating a separate COM wrapper for each project and the generated COM wrappers may not entirely agree with each other when it comes to generated GUIDs and whatnot. So by creating a and forcing the use of a single wrapper you may be able to eliminate that as a possible problem.
Rather than using TlbImp, another option is to have a separate project where you encapsulate the MyType in a .NET class and include that project in both your samples.
So you would end up with an intermediate MyDotNetType which would take as a constructor argument Mytype (the COM object) and expose it out as a read-only property.
Then the MySub call, would take the MyDotNetType as an argument.
Kind Regards
Noel
Please check the signature of the Function in both base class and derived class, if you have different agruments or data type o any arguments is not matched. Then you'll get this type of error. Simple please check the function name, argument name and data type. It worked me. I hope this answer will be helpful.
Thanks,
Ramu V