我在 C# 中有以下代码,我尝试将其移植到 PowerShell。
但我不知道如何移植此转换:
((_ISkypeEvents_Event)skype).CallStatus += CallStatusHandler;
如果我只是在 PowerShell 控制台中输入 [Skype4COM.ISkypeEvents_Event],我会得到:
无法找到类型 [Skype4COM.ISkypeEvents_Event]:请确保加载包含此类型的程序集。
但是,我可以获取 $skype 对象的所有成员:
$skype = New-Object -ComObject Skype4COM.Skype
以下行不起作用:
$skypeevent = [Skype4COM._ISkypeEvents_Event]$skype
如果我尝试直接在 $skype 对象上调用该方法,如下所示:
$skype.add_CallStatus({ write-host "yay" })
...它(如预期)告诉我:
方法调用失败,因为 [System.__ComObject#{b1878bfe-53d3-402e-8c86-190b19af70d5}] 不包含名为“add_CallStatus”的方法。
我尝试创建一个 COM 包装器,但它仍然无法获取 COM 接口的类型...
有什么想法吗?非常感谢!
I have the following code in C# which I try to port to PowerShell.
But I don't know how to port this cast:
((_ISkypeEvents_Event)skype).CallStatus += CallStatusHandler;
If I just type [Skype4COM.ISkypeEvents_Event] in my PowerShell console I get:
Unable to find type [Skype4COM.ISkypeEvents_Event]: make sure that the assembly containing this type is loaded.
However, I can get all the members of the $skype object:
$skype = New-Object -ComObject Skype4COM.Skype
The following line doesn't work:
$skypeevent = [Skype4COM._ISkypeEvents_Event]$skype
If I try to call the method directly on the $skype object, like this:
$skype.add_CallStatus({ write-host "yay" })
...it (as expected) tells me that:
Method invocation failed because [System.__ComObject#{b1878bfe-53d3-402e-8c86-190b19af70d5}] doesn't contain a method named 'add_CallStatus'.
I've tried to create a COM wrapper, but it still fails on getting the type for the COM interface...
Any ideas? Big thanks!
发布评论
评论(1)
PowerShell 使用自己的后期绑定“COM 适配器”对 COM 对象进行特殊处理,以便向调用者公开成员(以及 Get-Member cmdlet)。不幸的是,如果找不到关联的类型库,有时会失败,这通常发生在实例实际上是通过透明代理类型呈现的远程 COM 对象。
此 COM 改编的另一个副作用是间接阻止您使用此类强制转换来访问成员。 PowerShell 通常公开互操作程序集(动态创建或 PIA)的 CoClass 类,其中包括所有接口的成员。事实上,接口上的这种限制不仅仅针对 COM 对象:PowerShell 中的“.NET 适配器”也不处理普通的旧 .NET 接口。老实说,这是 99% 情况下的首选行为。 PowerShell 是一种动态语言,始终会在运行时公开引用的真实类型。任何转换到接口的尝试都将被忽略。
当您在 C# 中显式实现接口时,这会导致更多问题。 PowerShell 根本看不到它们! 我做到了有关使用 v2.0 模块代理显式接口成员的技术的博客。您可以在 COM 接口上尝试它,但我不确定它是否有效。
PowerShell special-cases COM objects with its own late-binding "COM Adapter" in order to expose members to callers (and the Get-Member cmdlet). Unfortunately this sometimes fails if it cannot find the associated type library, which usually happens when the instance is actually a remote COM object surfaced through a transparentproxy type.
Another side-effect of this COM adaptation is that you are indirectly prevented from using these kind of casts to gain access to members. PowerShell generally exposes the interop assembly's (dynamically created or PIA) CoClass class, which includes members of all interfaces. In fact, this limitation on interfaces is not just with COM objects: the ".NET Adapter" in PowerShell doesn't deal with plain old .NET interfaces either. To be honest, this is the preferred behaviour for 99% of cases. PowerShell is a dynamic language and will always expose the true type of a reference at runtime. Any attempts to cast to an interface will be ignored.
This leads to more problems when you get to explicitly implemented interfaces in C#. PowerShell can't see them at all! I did blog about a technique to proxy explicit interface members using a v2.0 module. You could try it against a COM interface, but I'm not sure it would work.