Fix how COM objects are enumerated (#11795)

This commit is contained in:
Dongbo Wang
2020-02-10 13:24:50 -08:00
committed by GitHub
parent 4db018762f
commit 35c7b7842e
3 changed files with 25 additions and 41 deletions
@@ -411,41 +411,7 @@ namespace System.Management.Automation
// The passed-in COM object could already be a IEnumVARIANT interface.
// e.g. user call '_NewEnum()' on a COM collection interface.
var enumVariant = comObject as COM.IEnumVARIANT;
if (enumVariant != null)
{
return new ComEnumerator(enumVariant);
}
// The passed-in COM object could be a collection.
var enumerable = comObject as IEnumerable;
var target = comObject as IDispatch;
if (enumerable != null && target != null)
{
try
{
var comTypeInfo = ComTypeInfo.GetDispatchTypeInfo(comObject);
if (comTypeInfo != null && comTypeInfo.NewEnumInvokeKind.HasValue)
{
// The COM object is a collection and also a IDispatch interface, so we try to get a
// IEnumVARIANT interface out of it by invoking its '_NewEnum (DispId: -4)' function.
var result = ComInvoker.Invoke(target, ComTypeInfo.DISPID_NEWENUM,
args: Array.Empty<object>(), byRef: null,
invokeKind: comTypeInfo.NewEnumInvokeKind.Value);
enumVariant = result as COM.IEnumVARIANT;
if (enumVariant != null)
{
return new ComEnumerator(enumVariant);
}
}
}
catch (Exception)
{
// Ignore exceptions. In case of exception, no enumerator can be created
// for the passed-in COM object, and we will return null eventually.
}
}
return null;
return enumVariant != null ? new ComEnumerator(enumVariant) : null;
}
}
}
@@ -3291,17 +3291,28 @@ namespace System.Management.Automation
internal static IEnumerator GetCOMEnumerator(object obj)
{
object targetValue = PSObject.Base(obj);
try
{
var enumerator = (targetValue as IEnumerable)?.GetEnumerator();
if (enumerator != null)
{
return enumerator;
}
}
catch (Exception)
{
}
// We use ComEnumerator to enumerate COM collections because the following code doesn't work in .NET Core
// IEnumerable enumerable = targetValue as IEnumerable;
// if (enumerable != null)
// IEnumerator enumerator = targetValue as IEnumerator;
// if (enumerator != null)
// {
// var enumerator = enumerable.GetEnumerator();
// enumerable.MoveNext();
// ...
// }
// The call to 'GetEnumerator()' throws exception because COM is not supported in .NET Core.
// See https://github.com/dotnet/corefx/issues/19731 for more information.
// When COM support is back to .NET Core, we need to change back to the original implementation.
// The call to 'MoveNext()' throws exception because COM is not fully supported in .NET Core.
// See https://github.com/dotnet/runtime/issues/21690 for more information.
// When COM support is fully back to .NET Core, we need to change back to directly use the type cast.
return ComEnumerator.Create(targetValue) ?? NonEnumerableObjectEnumerator.Create(obj);
}
@@ -49,6 +49,13 @@ try {
$element | Should -Be $drives.Item($element.DriveLetter)
}
It "Should be able to enumerate 'IADsMembers' object" {
$group = [ADSI]"WinNT://./Users,Group"
$members = $group.Invoke('Members')
$names = $members | ForEach-Object { $_.GetType().InvokeMember('Name', 'GetProperty', $null, $_, $null) }
$names | Should -Contain 'INTERACTIVE'
}
It "ToString() should return method paramter names" {
$shell = New-Object -ComObject "Shell.Application"
$fullSignature = $shell.AddToRecent.ToString()