如何将事件附加到动态对象或COM对象
本文关键字:对象 动态 COM 事件 | 更新日期: 2023-09-27 18:05:46
我觉得这篇文章对我来说也有同样的问题。但是,对于我的情况,没有可行的解决方案。
我在程序中使用了Windows Media Player ActiveX。
由于某些原因,我不想添加它的引用并由IDE自动转换为AxHost。
我通过Activator
和ProgID
创建实例
protected const string WMP_PROG_ID = "WMPlayer.OCX.7";
private dynamic _wmp;
protected virtual bool init(){
try{
_wmp = Activator.CreateInstance(Type.GetTypeFromProgID(WMP_PROG_ID));
}
catch{ return false; }
return true;
}
我尝试用Reflection
来做这件事,但我发现dynamic
更适合我的情况。
每个属性和方法都可以正常工作,像这样:
protected override bool setSpeed(float speed){
try{
_wmp.settings.rate = speed;
}
catch { return false; }
return true;
}
protected override int getLength(){
double res;
try{
res = _wmp.currentMedia.duration;
}
catch { return 0; }
return (int)(res * 1000);
}
不幸的是,当我想附加事件时,就像我在顶部指示的文章一样,它没有工作。
我的代码是这样的:protected bool connectEvent(){
_wmp.StatusChange += new EventHandler(_wmp_StatusChange);
return true;
}
protected void _wmp_StatusChange(object sender, EventArgs e){
Console.WriteLine(_wmp.Status);
}
我检查了StatusChange
的事件处理程序的类型,它是EventHandler
。
这些代码编译得很好,我可以加载一些音乐,播放它,暂停它,…我喜欢做什么就做什么。
但StatusChange
事件从未触发。
我试图在connectEvent
处设置断点。
在_wmp.StatusChange += new EventHandler(...)
运行时,IntelliTrace会给我一些信息。
这些信息是用trade写的。中文,我想它的意思是:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
:无法对类型System.Dynamic.DynamicObject
和System.EventHandler
应用运算符"+="
即使有一个异常,但就像我说的,编译通过了,一切仍然正常——除了我不能监听事件。
那么,如何在动态对象_wmp
中成功地附加事件呢?
任何可能的解决方案(如Reflection
)对我都是有用的。
同样,在上面的例子中,StatusChange
的处理程序类型是EventHandler
。
但是如果我想处理PlayStateChange
事件,如果我不添加wmp.dll的引用,它是一个"未知句柄"。
我希望这个解决方案也适用于这种情况。
提前感谢大家对我的支持,请原谅我英语不好
将使用COM对象的程序从早绑定调用转换为晚绑定调用的通用策略是先写入早绑定。智能感知将帮助你成功,确保你使用正确命名的方法,传递正确类型的参数,特别有用的是帮助你找出事件处理程序签名应该是什么样子。
生成这段测试代码:
void testEarlyBound() {
var wmp = new WMPLib.WindowsMediaPlayer();
wmp.StatusChange += new WMPLib._WMPOCXEvents_StatusChangeEventHandler(wmp_StatusChange);
}
void wmp_StatusChange() {
throw new NotImplementedException();
}
使用StatusChange事件处理程序赋值和方法主体完全由智能感知自动生成。注意事件处理程序的签名,它是而不是一个eventandler。只是一个返回void且不带参数的方法,它匹配Action委托类型。现在,您可以很好地编写没有不可诊断的运行时异常的后期绑定版本:
void testLateBound() {
dynamic wmp = Activator.CreateInstance(Type.GetTypeFromProgID("WMPlayer.OCX"));
wmp.StatusChange += new Action(wmp_StatusChange);
}