Und statt OnClick: TOnMenuClick
lieber so:
Cool, dass jmd. das gesehen hat.
Als ich das in einer PlugIn
API gesehen habe, hat gleich meine Augenbraue nervös gezuckt.
Aber ich hatte vorhin ein paar Softkeyboards für mein neues Tablet ausprobiert, deshalb war noch mehr Text, besonders Codebleistifte, ein bissel jenseits meiner Leidensfähigkeit.
Allerdings, wie ich bereits schrieb: safecall ist ein bissel besser.
Standardmäßig werden Interface Methoden in .Net per sdtcall mit HResult durch den
COM/Interop Layer geschleust.
Dieser Layer wird auch bei P/Invoke (klassische DLLs in .Net) verwendet.
Das entspricht dem was safecall in Delphi macht.
Und mal ganz ehrlich: Wer hat Lust bei Exceptions aus einer
DLL gleich alles zum Explodieren zu bringen, ohne eine richtige Meldung liefern zu können?
safecall ist eines dieser sehr coolen Features von Delphi, die gerne übersehen werden. Delphi hat nicht wirklich viele Features, die wirklich cool sind. Die Art wie es
Exception-Handling zwischen DLLs vereinfacht ist IMO extrem cool.
Das hier:
Delphi-Quellcode:
INotifyEvent = interface(IUnknown)
['{EE9407DD-2337-4DFC-BC35-A40C4FA0A1A7}']
procedure OnNotify(const Sender: IUnknown); safecall;
end;
entspricht dem hier:
Delphi-Quellcode:
INotifyEvent = interface(IUnknown)
['...']
function OnNotify(const Sender: IUnknown) : HResult; stdcall;
end;
Delphi setzt nicht nur beim Implementieren von diesen Methoden schön das HResult falls eine
Exception geworfen wird, sondern führt auch SetErrorInfo aus, so dass .Net, VB, C++, ... auf der anderen Seite eine passende
Exception erzeugen können.
Klappt auch supi andersrum.
Code, der in C# implementiert ist und eine
Exception wirft, kann dann dort wieder ein HResult zurückgeben, und SetErrorInfo setzen. In Delphi kriegt man dann eine Delphi
Exception, mit der richtigen Message.
Ich würde aber Events in 2 Typen aufteilen: Den eigentlichen Event und einen Subscriber:
Delphi-Quellcode:
INotifyEvent = interface(IUnknown)
['{EE9407DD-2337-4DFC-BC35-A40C4FA0A1A7}']
procedure Add(const hanlder: INotifyEventHandler); safecall;
procedure Remove(const hanlder: INotifyEventHandler); safecall;
end;
INotifyEventHandler = interface(IUnknown)
['...']
procedure Invoke(const sender : IUnknown); safecall;
end;
Das hat den Vorteil, dass sich viele benachrichtigen lassen können, und diese Benachrichtigung auch wieder abbestellen können.
Aber andere wissen nicht, wer sonst noch benachrichtigt wird, und können erst recht keine fremden Benachrichtigungen stören.
Das würde in C# so aussehen:
Code:
[ComVisible(true),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("EE9407DD-2337-4DFC-BC35-A40C4FA0A1A7")]
public interface INotifyEvent
{
void Add([MarshalAs(UnmanagedType.Interface)]INotifyEventHandler handler);
void Remove([MarshalAs(UnmanagedType.Interface)]INotifyEventHandler handler);
}
[ComVisible(true),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("...")]
public interface INotifyEventHandler
{
void Invoke([MarshalAs(UnmanagedType.IUnknown)]object sender);
}
public class NotifyEventHandler : INotifyEventHandler
{
readonly Action<object> _EventHandler;
public NotifyEventHandler(Action<object> eventHandler)
{
if(eventHandler == null)
throw new ArgumentNullException("eventHandler");
_EventHandler = eventHandler;
}
public void Invoke(object sender)
{
_EventHandler(sender);
}
}
Noch mehr Marshaling Bleistifte