Powershell: COM objects are not enumerating properly

Created on 12 May 2017  路  4Comments  路  Source: PowerShell/PowerShell

Repro

Open a File Explorer window first if you find $w.Count is 0

PSv6> $s = New-Object -ComObject "Shell.Application"
PSv6> $w = $s.Windows()
PSv6> $w.Count
1
PSv6> $w  ## dump $w, and powershell should enumerate $w to unwrap the collection

Expected Behavior

$w is unwrapped and the contained items are dumpped out (PSv5 behavior)

Application          : System.__ComObject
Parent               : System.__ComObject
Container            :
Document             : System.__ComObject
TopLevelContainer    : True
Type                 :
Left                 : -32000
Top                  : -32000
Width                : 160
Height               : 28
LocationName         : 6.0.0-beta1
LocationURL          : file:///D:/PowerShell/6.0.0-beta1
Busy                 : False
Name                 : File Explorer
HWND                 : 923136
FullName             : C:\WINDOWS\Explorer.EXE
Path                 : C:\WINDOWS\
Visible              : True
StatusBar            : False
StatusText           :
ToolBar              : 1
MenuBar              : False
FullScreen           : False
ReadyState           : 4
Offline              : False
Silent               : False
RegisterAsBrowser    : False
RegisterAsDropTarget : True
TheaterMode          : False
AddressBar           : True
Resizable            : True

Actual Behavior

Count
-----
    2

Environment

PSv6> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.0.0-beta
PSEdition                      Core
BuildVersion                   3.0.0.0
CLRVersion
GitCommitId                    v6.0.0-beta.1
OS                             Microsoft Windows 10.0.15063
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Additional Observation

The problem appears to be this:

PSv6>  $w._NewEnum()
An error occurred while enumerating through a collection: Could not load type 'System.Runtime.InteropServices.ComTypes.IEnumerator' from assembly 'System.Private.CoreLib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=7cec85d7bea7798e'..
At line:1 char:2
+  $w._NewEnum()
+  ~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.__ComObject:__ComObject) [], RuntimeException
    + FullyQualifiedErrorId : BadEnumeration
Blocked Breaking-Change Issue-Bug WG-Engine

All 4 comments

Good catch 馃憤
My investigation shows this is a bug in .NET Core 2.0. A dotnet/corefx issue has been filed: https://github.com/dotnet/corefx/issues/19731

What happens is that powershell successfully casts the ShellWindows object to IEnumerable, and then a TypeLoadException is thrown when calling GetEnumerator() on the IEnumerable object. PowerShell catches the exception and treat the object as non-enumerable.

The issue description was updated to make it easy to understand the problem.

Reply from CoreCLR team on dotnet/corefx#19731

Thanks for reporting this issue. As previously discussed, CoreCLR doesn't support IDispatch (and that's why you are implementing your own IDispatch). IEnumerable.GetEnumerator uses IDispatch.Invoke(DISPID_NEWENUM) under the hood (that's the convention for IDispatch objects to support enumeration). You need to write your own enumeration code to support that pattern in CoreCLR. Based on what you already have (IDispatch and VARIANT support), it should be pretty straight-forward. I'll be happy to help out offline if you need any help.

So we need to write the enumeration code ourselves.

Should we remove Waiting - NetStandard20 label?

Was this page helpful?
0 / 5 - 0 ratings