Hi i have a vb6 interface called CLSFW_SBSession with an event:
Public Event DataTransfer(ByVal Data As Variant)
Public Property Get ActionID() As Long
End Property
...
I need to extend it with a c# interop class. I tried with:
[ComVisible(true)]
[Guid("ddb976bd-fe29-44d5-a163-e7780a4bb897")]
public class ClsSbSession : FWBO_LibSrv.CLSFW_SBSession
public event __CLSFW_SBSession_DataTransferEventHandler DataTransfer;
...
Now if i declare a object of this type in vb6 and i instance it, without With events, it works:
Private session As FWBO_LibSrv.CLSFW_SBSession
Set session = new ClsSbSession()
But if i use:
Private WithEvents session As FWBO_LibSrv.CLSFW_SBSession
and i try to instance it:
Set session = new ClsSbSession()
I receive an error:
Object or class does not support the set of events
How can i do for manage events from vb6 of my c# class? thanks
i have a vb6 interface
This is pretty murky, VB6 does not permit declaring an interface. It does generate them from a VB6 Class declaration, their name start with an underscore. There should be two, one for the class and probably named _CLSFW_SBSession, another for the event. One way to find these interface names is by running Oleview.exe from the Visual Studio Command Prompt. Use File + View Typelib and select the VB6 executable. Find the coclass declaration and note the interfaces marked by the [default] and [source] attributes.
You need to derive your class from the [default] interface. And you must use the [ComSourceInterfaces] attribute to name the [source] interface. The MSDN howto page is here. It isn't otherwise clear why you are trying to mimic the VB6 class, that is only necessary if you need a drop-in replacement for the existing VB6 class and need to keep legacy client programs running. That has additional requirements, like matching the guids.
Related
I'm using Xamarin to make an Android and iOS app. I have my code split into 3 projects: Android, iOS and common. The code is basically designed such that common code is abstract and handles the the OS agnostic side of things and the Android/iOS code inherits from the common and handles the OS specific things. However, I'm tripping over how to handle custom member variables following this paradigm, as I need to hold onto a OS specific instance so that the class can do OS things, but I also need to reference the OS specific instance in the common code to commonly handle things.
Example: A common class is comprised of a question and a chart (think public survey where you can see how other people responded). The common version of these things are responsible for retrieving their data from the appropriate places (database, server). The OS specific version of these things are responsible for displaying the UI. I would like to pass into this class the Android version of the question and chart. Then I can call the class' "retrieveData" (common) function and the class' "displayUi" (OS specific function). I would really like to reference the same member variables during this process.
If I program it 'normally', the common class would contain the common class of question and chart and the inherited Android class would access this variables. But this doesn't work because when the Android class access them, it gets the variables as common and doesn't have the OS specific functionality. If I put the variables in the Android class, then the base class doesn't know about them and I can't do common things with them.
Up to this point, I've gotten around this by using Generics. But I've recently ran into a problem with that solution (Inheriting generic can't up cast). Another solution I've thought of is using the 'new' operator on a property in the Android class to mask the inherited member variable and use the get function to automatically down cast the variable into the Android version and the set function to store the variable on the base (base.variable = value). I'm not too keen on this idea as I have to double declare the variables and I have a slight problem with collections of variables (I can either use Array.Convert (or some similar method) if I need to pass in the array/list/dictionary/etc, or I can cast as I iterate though it to do whatever it is I have to do. Not great, but doable.
I'm curious if there's other ways to to handle this situation .
Edit
Here's some simplified code:
public interface IAnsweredCommon { ... }
public interface IAnsweredAndroid : IAnsweredCommon { ... }
public abstract class ConstructorCommon<AnsweredType> where AnsweredType : IAnsweredCommon
{
protected AnsweredType Answered;
...
}
public class ConstructorAndroid : ConstructorCommon<IAnsweredAndroid> { ... }
As you can see, this version is using the generic pattern. ConstructorCommon has a variable of type AnsweredType which is treated as IAnsweredCommon within the class allowing it to do non-OS specific things with it. ConstructorAndroid inherits from ConstructorCommon using IAnsweredAndroid. This allows me to instantiate ConstructorAndroid without having to specify a type and allows it to treat the inherited AnsweredType as a IAnsweredAndroid to do OS specific things.
As mentioned in the previous question; this generic way won't work for an unrelated reason. So, to make code work in that question, I need away to replicate what the generic is doing. The only other way I can think of, is to change the Answered variable type from AnsweredType to IAnsweredCommon and to implement a new property in ConstructorAndroid that hides the Answered variable (via the 'new' keyword) and implement the get to return a casted base variable and set to set the base variable:
public abstract class ConstructorCommon
{
protected IAnsweredCommon Answered;
...
}
public class ConstructorAndroid : ConstructorCommon
{
protected new IAnsweredAndroid Answered
{
get => (IAnsweredAndroid)base.Answered;
set => base.Answered = value;
}
...
}
I'm not super crazy about this idea for the reasons I stated above, so I'm curious if there's another way.
Inheritance of a .Net interface: How to access to base properties
I want to create my own category class inherited from Microsoft.Office.Interop.Outlook.Category interface but I am trying to access members of the base interface without success.
I tried base.Name and this.Name both give me:
Error 2 'object' does not contain a definition for 'Name'
Using VS 2013, .Net 4.5
Code:
using System;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace MyCategory
{
public class MyCategory : Outlook.Category
{
private string colorName;
public string ColorName
{
get
{
return this.colorName;
}
set
{
//Name is a member of Outlook.Category
//https://msdn.microsoft.com/en-us/library/office/microsoft.office.interop.outlook.category_members.aspx
this.colorName = base.Name;
//
}
}
}
}
So far I see on your code, you didn't implement interface. You're not inheriting from a class but following contract established by Outlook.Category interface. There is no "base" members here, you have to add members to your class.
If you put mouse cursor above Outlook.Category it should offer to implement it for you.
I recommend you to take a deeper look to how interfaces work on C#
You are mistaking implementing an interface with object inheritance. Even though they both use the same syntax, they are very different.
An interface is a contract to allow many different implementations of the same general methods and properties. It is a guarantee that the class you wrote supports certain actions. You have to write the implementations for interfaces. This allows others at a higher level to not care about the details of how something gets accomplished, yet it allows them to know it will get accomplished.
Object inheritance allows you to use a parent class's (non-private) stuff. It's really taking a parent class and adding more features. In fact, in Java, this is known as "extending" a class. Find a class that already implements the interface Outlook.Category and inherit from that class and then call base.Name(). Then you could override or extend any additional behavior that you need.
I'm not familiar with the Outlook namespace, but the CategoryClass seems to be a class that implements your interface. You could try inheriting from that.
What is it exactly that you are trying to do? Add a new category in Outlook? In that case, you simply need to access Outlook category storage (either the registry or the default store in the profile).
Take a look at the IPM.Configuration.CategoryList hidden message in the Calendar folder - you can see it using OutlookSpy (I am its author): go to the Calendar folder, click IMAPIFolder button on the OutlookSpy ribbon, go to the "Associated Contents" tab, find the message with PR_MESSAGE_CLASS property = "IPM.Configuration.CategoryList", double click on it. The data will be in the PR_ROAMING_XMLSTREAM property. That hidden message can be accessed using MAPIFolder.GetStorage in the Outlook Object Model.
You can also use Redemption (I am also its author) to add a new category - see the RDOCategories object. Something like the following will do the job (VBA):
set vSession = CreateObject("Redemption.RDOSession")
vSession.MAPIOBJECT = Application.Session.MAPIOBJECT
set vStore = vSession.Stores.DefaultStore
set vCategories = vStore.Categories
set vCategory = vCategories.Add("Redemption Category", olCategoryColorPeach)
I have written a COM-visible class library in C# 4.0 which I'm consuming with VB6. The thing works, only if I open up the VB6 object browser and look at the members exposed, I'm seeing an event for each and every single exposed member... but the C# code doesn't define any of them.
Is this normal? Am I doing something wrong?
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IMyClass))]
public class MyClass : IMyClass
{
public void DoSomething(string someParam)
{
...
}
}
public interface IMyClass
{
void DoSomething(string someParam);
}
The assembly is signed with a strong name key and AssemblyInfo.cs has the [assembly: ComVisible(true)] attribute set, but I'm not sure it has anything to do with the issue.
When I look at the object browser in VB6, I would be expecting to see DoSomething(string) as a member of MyClass, and I do, however I'm also seeing an event with a matching signature for every exposed method, like Event DoSomething(someParam As String) as a member of MyClass.
Even more puzzling (to me at least), properties also have a "matching" event (can only tell from the little lightning icon though) - if MyClass defined a property like this:
public string SomeProperty { get; set; }
The VB6 object browser would say the "event" is defined as Property SomeProperty As String, which leaves me flabbergasted - how does a "property" 1) gets duplicated and 2) the duplicate gets displayed with an "event" icon in the object browser? The same applies to get-only properties, which have their read-only "property/event" counterpart.
Where do these events come from and how do I get rid of them?
UPDATE An image is worth a thousand words:
UPDATE The wrong thing was the ComSourceInterfaces attribute which was mistakenly being used in place of a ComDefaultInterface attribute. Swapping the former for the latter gives the expected result:
By passing typeof(IMyClass) as an argument to the ComSourceInterface attribute you're saying that everything in the IMyClass is an event.
If you don't want an event interface for your class remove the ComSourceInterface attribute.
If you do want to expose events from your C# class to VB then do the following:
When you create a COM visible class you'll also want to create an interface that defines just the event handlers for your class. Your class should be decorated with the COMSourceInterface specifying your event handler interface and should define your events and implement the event handler interface. See How To: Raise Events Handled by a COM sink for another example.
[GuidAttribute("1A585C4D-3371-48dc-AF8A-AFFECC1B0967") ]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface MyEvents
{
void ConnectedEvent(string state);
}
[ComSourceInterfaces(typeof(MyEvents))]
public class MyClass
{
public event Action<string> ConnectedEvent;
public MyClass() { }
public void DoSomething(string state)
{
if (ConnectedEvent != null)
ConnectedEvent(state);
}
}
See also: Murat's Corner: Exposing COM Events
You are basically finding out that there isn't anything special about events in COM. Like anything in COM, events are backed by an interface. The only thing special about an interface that specifies event methods is that it is marked with the [source] attribute in the type library. Which is all that the [ComSourceInterfaces] attribute does, recognized by Tlbexp.exe when it generates the type library.
Nor is there anything particularly special about properties in COM. They work just like they do in .NET, they are implemented with methods. A getter and a setter method.
So VB6 looks at your type library and is happy about a class that has events since it has an interface with the [source] attribute. And is happy about that interface having methods, all they can ever have, so it assumes those are the methods that run when the event is raised. It isn't otherwise smart enough to recognize that those methods are also the accessors for a property, it assumes that the type library author knows what he's doing.
Events are called "connection points" in COM. Google IConnectionPoint to learn more about it. If you ever create a WinRT component with custom event accessors then you'll also see that COM events have little in common with .NET events.
Anyhoo, the workaround is simple, only use [ComSourceInterface] when you raise events.
I am trying to learn OOP concept at an advance level. I was reading through the topic interfaces and have a confusion. But first, let me show you what exactly caused this confusion.
I tested this Code Sample. but I am confused with the use of interfaces. After implementing that code, it seems to me that I can call the method DoFirst from class A by simply creating an instance of it. so why use an interface at first place?
Something like this:
A myA = new A();
myA.DoFirst();
and similiarly,
B myB = new B();
myB.DoFirst();
In both the classes, i have to implement a method called 'DoFirst', so what good does interface provided to me?
Can't I just write these methods in different classes myself?
my Second question, say I have an interface that has 5 methods. If a class implements it, and only wants to provide implementation of 3 methods instead of writing code of all 5 methods supplied by the interface. Isn't this useless? why have access methods that i don't want?
can somebody answer these with example (Highly appreciated) please?
The advantage was already pointed out in the link you provided...
Basically you can also write
void DoSomething(IMyInterface obj)
{
obj.DoFirst();
}
And then send any type of object which implements that interface as a parameter.
A myA = new A();
DoSomething(myA);
B myB = new B();
DoSomething(myB);
The method DoSomethig doesn't care about the object's type, as long as it exposes an interface called IMyInterface.
Some Real Life examples - also, another way/reason to use interfaces.
In my own code I have an Engine which processes code to produce reports in Excel. In this engine, i had to write the code two different ways, one using the Microsoft Excel Interop, the other using the Open Office Interop. Rather than duplicate my entire engine to work two different ways, or write a lot of if statements in all the actual interop functions, I implemented an interface. Then I declared two classes, each one implementing the interface, but one uses Excel and the other uses open office. Then, in my code, I simple reference the interface and its functions and use a single if statement at the very beginning of the function to tell the interface which class to implement.
public class ExcelEngineInterop : ISSinterface
{ ... }
public class OOEngineInterop : ISSinterface
{ ... }
//cant use two variables with the same name, so use 1 interface reference instead
ISSinterface ssInt;
if(ExcelFlag)
ssInt = new ExcelEngineInterop();
else
ssInt = new OOEngineInterop();
//two VERY different functions between Excel and OpenOffice.
ssInt.OpenApp();
ssInt.OpenFile(fileName);
//etc etc and so on
This is the other reason to use an interface. When you need one block of code to act two (or more) different ways depending on some external flag.
Another Example.
There is a top level form with lots of custom user controls under it. The user fires a form level event, like a button click, but depending on which user controls are active and what settings are on them at the time the click happens, the controls themselves need to do something different. Rather than writing what could be a rediculously large number of if statements to make sure each one acts correctly from the top level, just implement an interface on each control, then do something like this:
public ButtonClick(object sender, EventArgs e)
{
//note: I dont know which of my classes currentrightcontrol belongs to at the moment.
// it could be any one of 22 different controls. It must be cast to something
// in order to call the ButtonClick method (its actual type is generic "UserControl"
IMyRunControl ctrl = CurrentRightControl as IMyRunControl;
ctrl.FormButtonClicked();
}
C# is a statically typed language (at least unless you explicitly tell it not to be). This means that the compiler uses the type of the variable to know whether the referenced object has the members you are about to use.
The interface, therefore, provides a contract to the compiler (and to other programmers, too) that this class implements that interface. Because interfaces can be shared across classes that don't have a hierarchical relationship, this means that you can define a method that can take an object as an argument by defining that interface in the parameter type.
I'm currently appointed the task of creating an Active-X plug-in for one of our clients. Now I've successfully created Active-X plug-in in C#/.NET (a Windows Form control which inherits from the System.Windows.Forms.UserControl class), however the application that hosts the plug-in shows the class name of the control in the caption of the dialog window that displays the Active-X plug-in.
After a lot of searching and disassembling I've found that the method IOleObject.GetUserType is called by the host and that it is the return value of this method that is used by the host as the caption of the dialog window. Looking at the System.Windows.Forms.UserControl class I found that this class inherits from the System.Windows.Forms.Control class which in turn explicitly implements the System.Windows.Forms.UnsafeNativeMethods.IOleObject interface.
What I would like to know is if there is someway to override the GetUserType method
in the UserControl class or if there is another way to accomplish what I want (maybe the solution is very simple, but I've failed to see it so far). I've already tried various 'possible' solutions so far:
I've tried to re-implement the IOleObject interface, but since the System.Windows.Forms.UnsafeNativeMethods.IOleObject is internal it is not possible to do this (you must use the exact same interface, and redefining an interface does not result in the exact same interface).
I've tried to use CLR injection as described by Ziad Elmalki on CodeProject.
I've tried to use some form of AOP. Since the Control class inherits from System.MarshalByRefObject through System.ComponentModel.Component I thought it might be possible to get my user control to return some kind of proxy that would intercept calls send to the GetUserType method.
Unfortunately I've not been able to get this to work. What does work is changing the name of the class, but since class names are not allowed to have spaces or other special characters this is not an acceptable solution (underscores are just not the same).
To elaborate, here's a code example of what I want to accomplish (note that it's not complete):
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
[ ComVisible(true)
, ClassInterface(ClassInterfaceType.AutoDual)
, Description("My Active-X plug-in")
, Guid("...")
]
public partial class MyControl : UserControl
{
public override int GetUserType(int dwFromOfType, out string userType)
{
userType = "The caption to show in the host";
// Return S_OK
return 0;
}
}
Hopefully someone here could help me.
Thanks in advance!
You could attempt to implement ICustomQueryInterface (.Net 4.0): http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.icustomqueryinterface.aspx
When the system queries for IOleObject, you could return your own custom object that implements IOleObject, forwards the methods you don't care about to the UserControl implementation, and properly delegate QueryInterface calls on the custom object back to the UserControl (aggregation).