mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Fix how COM objects are enumerated (#11795)
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user