Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessing property IShellFolderViewDual.Application causes InvalidOleVariantTypeException "Specified OLE variant is invalid" #1139

Open
jnm2 opened this issue Feb 8, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@jnm2
Copy link
Contributor

jnm2 commented Feb 8, 2024

#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     
}
@jnm2 jnm2 added the bug Something isn't working label Feb 8, 2024
@jnm2
Copy link
Contributor Author

jnm2 commented Feb 18, 2024

@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
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant