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

ShellLink missing ComImport attribute #453

Closed
craigktreasure opened this issue Nov 23, 2021 · 4 comments · Fixed by #454
Closed

ShellLink missing ComImport attribute #453

craigktreasure opened this issue Nov 23, 2021 · 4 comments · Fixed by #454
Assignees
Labels
bug Something isn't working

Comments

@craigktreasure
Copy link
Member

Description

In full disclosure, I'm a COM newb. Feel free to slap me and tell me i'm doing it completely wrong.

I'm using CsWin32 to read the target of an .lnk file. Some searching lead me to this solution, which does work for me. I thought I'd supplement the hand-written bits with types generated from CsWin32. Everything works except the definition of ShellLink, which appears to be a struct instead of a class and lacking the necessary ComImport attributes to allow you to cast it to an IPersistFile and an IShellLInkW.

Actual behavior

The generated code for Windows.Win32.ShellLink.g.cs:

// ------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------

#pragma warning disable CS1591,CS1573,CS0465,CS0649,CS8019,CS1570,CS1584,CS1658,CS0436
namespace Windows.Win32
{
	using global::System;
	using global::System.Diagnostics;
	using global::System.Runtime.CompilerServices;
	using global::System.Runtime.InteropServices;
	using global::System.Runtime.Versioning;
	using winmdroot = global::Windows.Win32;

	namespace UI.Shell
	{
		[Guid("00021401-0000-0000-C000-000000000046")]
		internal partial struct ShellLink
		{
		}
	}
}

Expected behavior

Again, I'm bashing rocks together from StackOverflow, but the signature there includes a ComImport attribute that I believe is necessary and the type is also a class instead of a struct. If I omit ShellLink from NativeMethods.txt and use this definition instead, things do work.

    [
        ComImport(),
        Guid("00021401-0000-0000-C000-000000000046")
    ]
    internal class ShellLink
    {
    }

Repro steps

  1. NativeMethods.txt content:
IPersistFile
IShellLinkW
MAX_PATH
ShellLink
STGM_READ
  1. NativeMethods.json content (if present):
    Not present.

  2. Attempt to resolve the target of a .lnk:

    public static unsafe string ResolveShortcut(string shortcutFilePath)
    {
        ShellLink shellLink = new ShellLink();

        IPersistFile persistFile = (IPersistFile)shellLink;
        fixed (char* shortcutFilePathPcwstr = shortcutFilePath)
        {
            persistFile.Load(shortcutFilePathPcwstr, PInvoke.STGM_READ);
        }

        Span<char> szShortcutTargetPath = stackalloc char[(int)PInvoke.MAX_PATH];
        fixed (char* cShortcutTargetPath = szShortcutTargetPath)
        {
            IShellLinkW shellLinkW = (IShellLinkW)shellLink;
            WIN32_FIND_DATAW data;
            shellLinkW.GetPath(cShortcutTargetPath, (int)PInvoke.MAX_PATH, &data, 0);

            return new string(cShortcutTargetPath);
        }
    }

Context

  • CsWin32 version: 0.1.619-beta
  • Win32Metadata version (if explicitly set by project): Not explicitly set
  • Target Framework: net6.0
  • LangVersion (if explicitly set by project): 10.0
@craigktreasure craigktreasure added the bug Something isn't working label Nov 23, 2021
@jnm2
Copy link
Contributor

jnm2 commented Nov 23, 2021

Discussed here as well: #323

@craigktreasure
Copy link
Member Author

Thanks! Glad to hear i'm not alone. I always forget to check Discussions as well.

@AArnott
Copy link
Member

AArnott commented Nov 23, 2021

I was able to get your code running with just one change:

-ShellLink shellLink = new ShellLink();
+object shellLink = Activator.CreateInstance(Type.GetTypeFromCLSID(typeof(ShellLink).GUID));

@AArnott AArnott self-assigned this Nov 23, 2021
@AArnott
Copy link
Member

AArnott commented Nov 23, 2021

I'll fix this by generating ShellLink as a class with [ComImport] on it, enabling your original syntax.

craigktreasure added a commit to craigktreasure/StartMenuCleaner that referenced this issue Mar 11, 2022
  - In CsWin32 0.1.635-beta, the ShellLink class became cocreatable, which allows me to restore my original method of creating a `ShellLink`. See microsoft/CsWin32#453.
craigktreasure added a commit to craigktreasure/StartMenuCleaner that referenced this issue Mar 11, 2022
  - In CsWin32 0.1.635-beta, the ShellLink class became cocreatable, which allows me to restore my original method of creating a `ShellLink`. See microsoft/CsWin32#453.
craigktreasure added a commit to craigktreasure/StartMenuCleaner that referenced this issue Mar 11, 2022
* Update System.IO.Abstractions to 16.1.20

* Update CsWin32 to 0.1.635-beta

* Use newly cocreatable `ShellLink` from updated CsWin32

  - In CsWin32 0.1.635-beta, the `ShellLink` class became cocreatable, which allows me to restore my original method of creating a `ShellLink`. See microsoft/CsWin32#453.
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

Successfully merging a pull request may close this issue.

3 participants