Accessing property IShellFolderViewDual.Application causes InvalidOleVariantTypeException "Specified OLE variant is invalid"
jnm2 opened this issue · comments
Joseph Musser commented
#1050 broke this at the same time as fixing #862. It changed both interfaces from InterfaceIsIDispatch
to InterfaceIsDual
, but IShellFolderViewDual
currently only works as InterfaceIsIDispatch
.
Repro
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.49-beta" PrivateAssets="all" />
</ItemGroup>
</Project>
using System;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.UI.Shell;
using IServiceProvider = Windows.Win32.System.Com.IServiceProvider;
var shellWindows = (IShellWindows)new ShellWindows();
var serviceProvider = (IServiceProvider)shellWindows.FindWindowSW(
PInvoke.CSIDL_DESKTOP,
pvarLocRoot: null,
ShellWindowTypeConstants.SWC_DESKTOP,
phwnd: out _,
ShellWindowFindWindowOptions.SWFO_NEEDDISPATCH);
serviceProvider.QueryService(PInvoke.SID_STopLevelBrowser, typeof(IShellBrowser).GUID, out var shellBrowserAsObject);
var shellBrowser = (IShellBrowser)shellBrowserAsObject;
shellBrowser.QueryActiveShellView(out var shellView);
var iid_IDispatch = new Guid("00020400-0000-0000-C000-000000000046");
shellView.GetItemObject((uint)_SVGIO.SVGIO_BACKGROUND, iid_IDispatch, out var folderViewAsObject);
var folderView = (IShellFolderViewDual)folderViewAsObject;
_ = folderView.Application; // Throws InvalidOleVariantTypeException "Specified OLE variant is invalid"
ShellWindows
IShellWindows
CSIDL_DESKTOP
IServiceProvider
ShellWindowTypeConstants
ShellWindowFindWindowOptions
IShellBrowser
SID_STopLevelBrowser
_SVGIO
IShellFolderViewDual
Workaround
Declare the same interface but with InterfaceIsIDispatch
:
[Guid("E7A1AF80-4D96-11CF-960C-0080C7F4EE85"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch), ComImport]
interface IShellFolderViewDual
{
/// <summary>Gets the application object.</summary>
/// <returns>
/// <para>Type: <b>HRESULT</b> If this method succeeds, it returns <b xmlns:loc="http://microsoft.com/wdcml/l10n">S_OK</b>. Otherwise, it returns an <b xmlns:loc="http://microsoft.com/wdcml/l10n">HRESULT</b> error code.</para>
/// </returns>
/// <remarks>
/// <para><see href="https://docs.microsoft.com/windows/win32/api//shldisp/nf-shldisp-ishellfolderviewdual-get_application">Learn more about this API from docs.microsoft.com</see>.</para>
/// </remarks>
object Application { get; }
// Other members omitted
}
Joseph Musser commented
@reflectronic suggested something that worked, and opens up a new avenue to explore:
[Guid("E7A1AF80-4D96-11CF-960C-0080C7F4EE85"), InterfaceType(ComInterfaceType.InterfaceIsDual), ComImport]
interface IShellFolderViewDual
{
/// <summary>Gets the application object.</summary>
/// <returns>
/// <para>Type: <b>HRESULT</b> If this method succeeds, it returns <b xmlns:loc="http://microsoft.com/wdcml/l10n">S_OK</b>. Otherwise, it returns an <b xmlns:loc="http://microsoft.com/wdcml/l10n">HRESULT</b> error code.</para>
/// </returns>
/// <remarks>
/// <para><see href="https://docs.microsoft.com/windows/win32/api//shldisp/nf-shldisp-ishellfolderviewdual-get_application">Learn more about this API from docs.microsoft.com</see>.</para>
/// </remarks>
object Application
{
[return: MarshalAs(UnmanagedType.IUnknown)]
get;
}
// Other members omitted
}
I think we can tell that this MarshalAs is needed due to the documented signature of get_Application
at https://learn.microsoft.com/en-us/windows/win32/api/shldisp/nf-shldisp-ishellfolderviewdual-get_application:
HRESULT get_Application(
[out] IDispatch **ppid
);