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"
Related
I'm trying to convert WinForms app into a class library - long story short the production environment I'm working in will allow our users to make changes to DLLs but not EXEs, so I'm trying to shove an entire existing app into a DLL and then just create and show an instance of the startup object/form from a second WinForms app with the goal of creating some kind of auto-update system.
I've changed the output type of the project to Class Library, added the launcher app, etc, but attempting to build the old app as a class library throws hundreds of errors, almost all of which are Reference to a non-shared member requires an object reference.
Upon inspection, these errors are appearing everywhere in the code that the startup object/form or any of its properties or methods are referenced. Since a great many things in a WinForms application naturally reference the main form... this is problematic.
Stuff like:
If DbConn = n.DbConn_.Prod Then
miParent = mainform.MiProdReq
throws the aforementioned error upon the attempt to access mainform.MiProdReq
Am I missing some simple/obvious step here?
You are referring to the default instance of the mainform type in that code. Default instances are provided by something automagically generated when building Windows Forms Application projects. Class Library projects have no such thing as default instances, so any code that tries to use them will appear to be trying to access instance members as though they were Shared.
You need to put an instance somewhere and change your code to refer to that instead. If you use a global variable, which is not ideal itself but the simplest option for where you're at, then you can just do a Find & Replace In Files to find the references you need to change.
Note that default instances are something that most experienced developers would suggest avoiding anyway. They don't exist in C# and I've never heard complaints about that, so it's hardly onerous. They were added to VB as a convenience for beginners and migrating VB6 developers who weren't used to proper OOP.
EDIT:
I haven't tested it but you may be able to use Application.OpenForms(0) to get a reference to the startup form anywhere in your library. You could, perhaps, add a module like this:
Module Module1
Private _mainform As Form1
Public ReadOnly Property mainform As mainform
Get
If _mainform Is Nothing Then
_mainform = DirectCast(Application.OpenForms(0), mainform)
End If
Return _mainform
End Get
End Property
End Module
and then your code may even just work as it is.
my task is to write a VB.NET library to interact with a piece of VB6 application. This VB6 application provides some unmanaged COM DLLs.
I created interop types (by using tlbimp) and added them as a reference in my VB.NET project.
Well, there is also an old VB6 project (library) existing, which is also referencing the (native) COM DLLs, let's call them
COM1.dll, COM2.dll and COM3.dll.
This old project is having a "Class Module" called claMod where it is doing the following:
Option Explicit
Public Property Set GlobalProp(oObj As claClass1)
Set COM1.MyPointer = oObj
Set COM2.MyPointer = oObj
End Property
where claClass1 is a class in COM3 and COM1.MyPointer and COM2.MyPointer are of type System.IntPtr.
My question is: How is possible to set these two pointers without declaring the corresponding objects (instances of COM1 and COM2) ?? And secondly, how can I do the same in my new VB.NET library?
To allow referencing of COM1 and COM2 without specifically instantiating them, set each class's Instancing property to GlobalMultiUse. Then the code that you have in your post will work without having to create a reference to it.
There are many such objects already running in the VB6 environment; the Screen object is a familiar example.
This is basically the same as declaring a Shared class in VB.Net or a static class in C#.
In the day job, I work on a VB6 (I know, but don't mock the afflicted...) application that uses a number of libraries we have written (also in the ever illustrious VB6). One of these supporting libraries had a load of private members exposed via public properties, and I was asked to remove the properties, and promote the private member variables into public fields with the same name as the original properties.
Now, I'm no COM expert, but I was under the impression that each and every exposed item on a class gets it's own GUID. Since we would be going from a situation where each value went from 2 Guids (Property Get and Property Let) to one where they only used the one (the public field), I was expecting this to break binary compatibility - but it seems it hasn't done that.
Can anyone explain why?
No, it hasn't broken compatibility because it hasn't removed the property get and property let methods. It's just that the compiler is now writing them for you.
Isn't this one of the few areas where VB6 is arguably better than .Net?
In .Net public fields behave differently to public properties, and this makes some refactorings difficult and causes confusion.
In VB6 public fields behave exactly like public properties, which is why it's possible to switch without affecting binary compatibility. Behind the scenes, the compiler generates property get and set routines for public fields. In a sense VB6 has automatically implemented properties (now advertised as a "new feature" in VB10)...
I think it's a bit more subtle than that. You get a GUID for the COM interface (not each individual field/method). As I understand it the binary compatibility attempts to work out if the interface your currently compiling is backwards compatible with a reference version of your DLL (assuming you have one) and only changes the GUID if they are not compatible.
I'm therefore also surprised that it has decided removing all the get/set methods is compatible :/
Is it better to use friend or public forms in vb.net? What are the advantages of each?
I notice when you import a vb6 project, the forms come in as friend, but when you add a new form in vb.net it is public. I have not seen any difference in the way they work, though, so I must be missing something.
In my opinion, I would use Friend (aka internal in C#) even though the default is public. I would also use private for controls on the form even though I think VB defaults to protected. In general, think of type/member access as if it were your wife's boobs. Keep them hidden from others up unless there's some benefit to exposing them (like getting out of a speeding ticket or making a shared library of common dialogs, etc.)
One drawback with making things internal is that you have to do some extra work to make them public to your unit tests. See the InternalsVisibleToAttribute for details.
VB6 did not support exporting forms from a class library. The natural mapping for converted code therefore is Friend. However, VB.NET has no such problems. Using Public is fine, assuming any exposed types in public method arguments is Public as well. Easy to find, the compiler will tell you.
If the form is Public it can be accessed from outside the current assembly (.exe). If it's Friend then it's only accessible from within the assembly. The same access level rules apply to Forms as other VB.NET classes.
I can't think of a common Winforms situation where you would need public Forms because they're usually in the same assembly making friend good enough. Unless you had forms scattered through different assemblies and they needed to reference one another.
Maybe the Microsoft team that wrote the import tool decided on Friend because all the forms came from the same classic project, whereas the Visual Studio (New Item) team decided on Public because the .NET way deals more with modularized projects. It might just be as simple as that.
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