Onscroll event handling in C# BHO for IE9 - c#

I’m working on C# BHO plug-in for IE. Plug-in supposed to react on scroll event. Code bellow responsible for it:
var document = (HTMLDocument)webBrowser.Document;
((HTMLWindowEvents2_Event)document.parentWindow).onscroll += WebBrowserWindowOnScroll;
This approach works pretty good in IE7 and IE8. But completely useless in IE9.
I have found this workaround:
http://social.msdn.microsoft.com/Forums/et-EE/ieextensiondevelopment/thread/808df95a-c559-44c3-93b7-b9e3b2c3b737
It seems that it should solve problem but unfortunately it on C++ and I failed to move it on C#.
Can someone suggest workaround for IE9 or how to implement approach mentioned above on C#?
Thanks so much!

I managed to find the solution.
IHTMLWindow3 has a method attachEvent which requires name of the event as a first argument (“onscroll” in my case) and object which will be responsible for event handling. The trickiest part is connected with this handler object. It should implement IDispatch interface, but IE9 use this interface in a pretty bizarre way. It calls IDispatch.Invoke without specifying a method name which should be called. .NET automatically implements IDispatch when class marked by [ClassInterface(ClassInterfaceType.AutoDispatch)] attribute, and uses reflection to call its instance methods according to arguments of IDispatch.Invoke. In our case method name is empty so nothing will be called. [DispId(0)] attribute allows to solve this problem, it specifies method what should be called if Invoke receives empty method name.
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class EventListener
{
[DispId(0)]
public void HandleEvent(object target)
{
}
}
It should be mentioned that name of handler method doesn’t matter. But its signature is important. f.e. for ‘onscroll’ event it should be like shown above, ‘onclick’ handler requires no arguments etc.

Related

How to assign the UIPopoverPresentationControllerDelegate

I try to use the UIPopoverPresentationController. For the presenting I need to assign the delegate (UIPopoverPresentationControllerDelegate) to be able to use methods like prepareForPopoverPresentation,
popoverPresentationControllerDidDismissPopover and so on.
If assign a view controller to the delegate property I get
Error CS0266 Cannot implicitly convert type 'UIKit.UIViewController' to 'UIKit.IUIPopoverPresentationControllerDelegate'. An explicit conversion exists (are you missing a cast?)
So what are my options here? In the native world one could add the required protocoll, but you can't do that in Xamarin. I want that the view controller which is presented in the popover gets the notification (prepare, did dismiss, ...). How can I do that?
Of course I could create a new instance of UIPopoverPresentationControllerDelegate and assign it, but then I would have connect the delegate with the view controller somehow (e.g. through events). Is there a simpler solution?
Edit
It looks like Xamarin has not exposed a WeakDelegate property and has also made the delegate class the abstract class for the protocol and not the interface. In this scenario - you will have to create another class that implements the UIPopoverPresentationControllerDelegate and another for the UIPopoverControllerDelegate.
In the future, it's worth noting that there is often a WeakDelegate property (along with Delegate) which allows assigning any class to the delegate and implementing the protocol implicitly through ExportAttribute on the protocol methods. Xamarin also sometimes uses the protocol's matching interface (such as IUIPopoverPresentationControllerDelegate) instead of the matching abstract class (the UIPopoverPresentationControllerDelegate class).
Mostly incorrect original answer
It should be possible for your UIViewController class to implement the IUIPopoverControllerDelegate and implement any methods that you need. Usually iOS protocols get converted into an interface for Xamarin.iOS and you can find it by appending an "I" to the protocol name.
public class TestVC : UIViewController, IUIPopoverControllerDelegate
{
public override UIPopoverPresentationController PopoverPresentationController {
get {
return base.PopoverPresentationController;
}
}
[Export ("popoverControllerDidDismissPopover:")]
public void DidDismiss (UIPopoverController popoverController)
{
throw new NotImplementedException ();
}
}
Here is an example where I've implemented a few of the popover methods. I hope this helps. I haven't explicitly tested this, but I think it should work. Let me know if it doesn't.
My solution was the following:
I subclassed UIPopoverPresentationControllerDelegate and here I defined the events PrepareForPopover and DidDismiss. So I overwrote PrepareForPopoverPresentation and DidDismissPopover and I throw the belonging events.
Then I assigned this delegate to my UIPopoverPresentationController instance. Through subscribing to the events of my custom delegate I was able to get notified, when the popover is displayed and when it is dismissed. Casting is not possible (as I tried in my question).
With this one can set some variables or call some methods from the view controller, which is presented in the popover.

Subclassing a Custom Control when doing it right is not possible?

I have a stand alone custom control that is extensively deployed.
It has one public property (ClientIdentifier) and two methods (OnLoad and RenderContents)
Over the years there have been some if clauses added to handle certain client specific situations, but now I really need to subclass it. The issue is that I can't break the API.
I have full access to the code, but I can't change the call from the website.
My thinking:
Use Onload as a Factory method, creating another POCO extends interface as a private member based on the ClientIdentifier -- call it SubControl.
In RenderContents, simply past through to SubControl.RenderContents(writer)
Is this the appropriate technique?
Or is there a better idea? (other than throwing it out and starting fresh.)

VB6/COM Interop: where do these events come from?

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.

Change user-type name of Active-X plug-in written in C#

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).

Emulate IDispatchEx in C#

C# 3.0 Extension methods add extensions to the base Type making calling that method on all instances of that Type legal.
Now, JavaScript I know implements IDispatchEx through which it's possible to add methods to a specific instance.
So how do I add a set of methods to an 'instance' of a C# class? I know this is a Dynamic vs. Static Languages holy war territory. :) Let me clarify my intention is NOT that.
I just want to be able to add a set of events to an interface depending on the class implementing that interface.
I was able to do that using Generics
inteface ISample<T> { T SupportedEvents; }
class Sample : ISample<UIWidgetEvent> { }
class Sample2 : ISample<NonVisualUIWidget> { }
class UIWidgetEvent { public EventHandler Clicked; }
class NonVisualUIWidget {public EventHandler Expired;}
class TestSample
{
public void Test()
{
new Sample().SupportedEvents.Clicked += ...
new Sample2().SupportedEvents.Expired += ...
}
}
Then I didn't like SupportedEvents I want to be able to say
new Sample().Clicked +=...
Then I thought JavaScript (I know C# is not JS :))... AND IDispatchEx, IL Weaving, Reflection.Emit etc. etc. and thought may be there's a way to do this... [Design time support would be nice but I can live without]
Yes, I probably could do this "instance augmentation" with a Visitor pattern.
[Not sure if I could get the syntatic sugar though]
Comments?
Well, you could create a DynamicMethod instance for your "new" methods, but statically attaching them to an existing instance at runtime wouldn't work due to the fact it plain wouldn't compile.
You might (I haven't tried this) be able to emit the opcodes into an in-memory assembly, but that's about as far away from being "Syntactically sweet" as you can get (would involve a lot of reflection and InvokeMember calls, I would think)
It also might be worth looking into Extension Methods - although I've never tried attaching events or event-like methods via extension methods...and they are 3.5 only, so that may limit you.
The nicest looking, "pure C#" implementation is probably something very similar to what you've already got with the generic/interface setup...
Honestly, if you're looking for something with true "dynamic support" like this, I'd do this kind of stuff in a DLR-capable language (like IronPython) and call into it from your C# stuff.

Categories