COM interface wrappers in PowerShell?

2019-04-09 15:24发布

问题:

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