[assembly: ComVisible(true)]
2. Set the project for "Register for COM Interop": Project's Properties -> Build tab -> Output group -> check box: Register for COM Interop.3. Create public classes and use the ComVisible attribute to hide some members and functions.
[ComVisible(true)] public class Person : IPerson { [ComVisible(true)] public string Name { get; set; } [ComVisible(true)] public string LastName { get; set; } [ComVisible(true)] public DateTime BirthDay { get; set; } [ComVisible(false)] public int Age { get; set; } public Person() { } [ComVisible(true)] public string GetFullName() { return getFullNameInt(); } private string getFullNameInt() { return Name + " " + LastName; } [ComVisible(false)] public int GetAge() { Age = DateTime.Now.Year - BirthDay.Year - 1; return Age; } }You can use this class for Late Bounding.
And, what about Early Bounding?
If we want to expose our classes for Early Bounding, the best practice is:
1. Declare interfaces that represents our objects.
2. Implement interfaces in public classes.
3. Set some attributes for better COM objects exposing:
3.a Use an specific Guid for every interface and every class
3.b Declare the interface as InterfaceIsDual
3.c Qualify every member and function with its DispId
3.d Implement the class with the ClassInterfaceType=None
3.e Set the ProgId for the class
Example:
[Guid("568680FF-FBF8-4b84-A8D6-F430197870F9")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IPerson { [DispId(1)] string Name{get;set;} [DispId(2)] string LastName{get;set;} [DispId(3)] DateTime BirthDay { get; set; } [DispId(4)] string GetFullName(); [DispId(5)] int GetAge(); } [Guid("D798A2FC-01A6-4c97-AC0F-703C3B2DBC81"), ProgId("ComTestLibrary.Person"), ClassInterface(ClassInterfaceType.None)] public class Person : IPerson { public string Name { get; set; } public string LastName { get; set; } public DateTime BirthDay { get; set; } public int Age { get; set; } public Person() { } public string GetFullName() { return getFullNameInt(); } private string getFullNameInt() { return Name + " " + LastName; } public int GetAge() { Age = DateTime.Now.Year - BirthDay.Year - 1; return Age; } }This is old-versions compatible and we are able to add more properties and methods with its own DispId, so we don't need to recompile old consumers for this COM component.
NOTE: Avoid use the ClassInterfaceType.AutoDual attribute because it is not old-versions compatible. Every time you change your .NET class, you must recompile COM clients.
Exposing .NET Events to COM:
For exposing events from .NET to COM, we need to add a new interface that define the events we want to dispatch. Then, we need to change the class according to the events we are exposing (the name must be equals), take a look:
// The new interface declaration [Guid("866226CC-679E-4ce7-B527-5A80D6950278")] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IPersonEvents { [DispId(1)] void BeforeGetFullName(string name, string lastname); // Event declaration [DispId(2)] void OtherEventWithoutParameters(); // Event declaration }
[Guid("D798A2FC-01A6-4c97-AC0F-703C3B2DBC81"), ProgId("ComTestLibrary.Person"), ComSourceInterfaces(typeof(IPersonEvents)), // Events interface implementation ClassInterface(ClassInterfaceType.None)] public class Person : IPerson { // Delegates declaration [ComVisible(false)] public delegate void BeforeGetFullNameHandler(string name, string lastname); [ComVisible(false)] public delegate void OtherEventWithoutParametersHandler(); ... // Our events. The name must match to the definition in // the interface we are implementing public event BeforeGetFullNameHandler BeforeGetFullName; public event OtherEventWithoutParametersHandler OtherEventWithoutParameters; ... public string GetFullName() { // Launching events if (BeforeGetFullName != null) BeforeGetFullName(Name, LastName); if (OtherEventWithoutParameters != null) OtherEventWithoutParameters(); return getFullNameInt(); } ... }We can consume events in some languaje like VB 6.0:
Dim WithEvents c As ComTestLibrary.Person
Private Sub c_BeforeGetFullName(ByVal Name As String, ByVal LastName As String)
MsgBox "Name = " & Name & " LastName = " & LastName
End Sub
Private Sub c_OtherEventWithoutParameters()
MsgBox "Event without parameters"
End Sub
Private Sub Command1_Click()
If (c Is Nothing) Then
Set c = New ComTestLibrary.Person
End If
c.Name = "oscar"
c.LastName = "londono"
MsgBox c.GetFullName
End Sub
8 comments:
hi very good u article the COM. I have the error "cant add a reference to the specifid file" in vb 6.0 when i want add my com the c#. can help me.
Diego, debes verificar que el .COM en C# este bien registrado, es decir, que tenga el codebase actualizado en la ruta donde esta el .COM.
gracias por la pronta respuesta por q la verdad esto me tiene descolocado no logro que la dll que genero en el proyecto de c# sea valido para el vb 6.0. Hay algun paso luedo de la compilacion en release del proyecto c# que debo hacer sobre las dll ? saludos
Diego,
Debes usar la utilidad RegAsm.exe para registrar el assembly y también debes registrar el TypeLib, así:
RegAsm.exe dllname.dll
RegAsm.exe dllname.dll /tlb
Diego,
Recuerda incluirle el parámetro /codebase así: RegAsm.exe dllname.dll /codebase
si el assembly no esta localizado en el global assembly cache (GAC). Esto te produce un warning si la libreria no esta firmada, pero te actualiza la ruta donde esta localizado el assembly.
La verdad es que te agradezco totalmente por la ayuda que me diste. El tema lo solucione
generando el tlb con
tlbexp midll.dll
y luego
RegAsm midll.dll /tlb:midll.dll
tal como me indicaste lo que si es que podia agregar la referencia pero no estaba visible las funcionalidades por lo que agregue en el encabezado de guid
[ComVisible(true), Guid("8176550E-BBB7-4295-B1FF-B9559131105B"),
con eso tuve visibilidad.
MIL GRACIAS oscar.
Una consulta mas te comento el com con vb 6 funciona bien pero cuando lo quiero referenciar en un win32 de vstnet 2003 o 2005 me tira el siguiente error al convertir la biblioteca de tipo en ensamblador net me dice que se exporto desde un ensamblador CLR y no se puede volver a importar como ensamblador CLR. mi consulta el com que hice no deberia ser referenciable desde cualquier lenguaje vb 6 o versiones de NET ? tenes idea como puedo hacer esto sin hacer el com en ATL de VC++ 6.
Diego, no tengo idea de porque te pasa ese error, pero si puedes publicar el error completo, podriamos realizar una búsqueda de las posibles soluciones.
Post a Comment