在桌面 C# 上创建固定快捷方式 - .website 扩展

Create pinnable shortcut on desktop C# - .website extension

尝试通过单击按钮 (C#) 在桌面上创建 .website 快捷方式(可固定快捷方式)。

我有现有的代码(有效 - 但浏览器打开后立即关闭)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace ShortcutUpdater
{
    public partial class UserControl1 : UserControl
    {

    private void urlShortcutToDesktop(string linkName, string linkUrl)
    {
        string deskDir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);

        using (StreamWriter writer = new StreamWriter(deskDir + "\" + linkName + ".website"))
        {
            writer.WriteLine("[InternetShortcut]");
            writer.WriteLine("URL=" + linkUrl);
            writer.Flush();
        }
    }


        public UserControl1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string linkName = "My Site";
            string linkUrl = "https://Asite.org";
            urlShortcutToDesktop(linkName, linkUrl);
        }

创建的文件在记事本中打开时如下所示:

[InternetShortcut]
URL=https://Asite.org

如果我通过将图标从浏览器拖动到我的桌面来创建一个可固定的快捷方式,然后用记事本打开它,它看起来像这样(这是我想要实现的,所以它不会只是打开然后关闭浏览器):

[{000214A0-0000-0000-C000-000000000046}]
Prop4=31,asite.org
Prop3=19,11
[{A7AF692E-098D-4C08-A225-D433CA835ED0}]
Prop5=3,0
Prop9=19,0
[InternetShortcut]
URL=https://asite.org/
IDList=
IconFile=https://asite.org/favicon.ico
IconIndex=1
[{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}]
Prop5=8,Microsoft.Website.50DFA192.38C0BBDC

完成此任务的最佳方法是什么?

实际上有一个官方编程接口可以创建internet shortcuts. Unfortunately, the interfaces aren't readily available to .NET programs, and there is no type library either for use with Tlbimp.exe (Type Library Importer)。这只剩下两个选择:尝试在 C# 中复制接口定义,或使用本机实现。

我建议使用本机实现,特别是 C++/CLI Class 库,可以立即使用1 通过 .NET 代码。该实现由 2 种类型组成:本机实现 class (InternetShortcutImpl) 和将功能公开给托管代码的代理,实现为 ref class (InternetShortcut)。两个 class 可以放在同一个文件中。

这是本机访问的实现class:

#pragma once

#include <comip.h>
#include <comdef.h>
#include <IntShCut.h>
#include <ShObjIdl.h>
#include <string>

using namespace System::Runtime::InteropServices;

_COM_SMARTPTR_TYPEDEF( IUniformResourceLocatorW, __uuidof( IUniformResourceLocatorW ) );
_COM_SMARTPTR_TYPEDEF( IPersistFile, __uuidof( IPersistFile ) );
_COM_SMARTPTR_TYPEDEF( IShellLinkW, __uuidof( IShellLinkW ) );
class InternetShortcutImpl
{
public:
    InternetShortcutImpl()
    {
        HRESULT hr = ::CoCreateInstance( CLSID_InternetShortcut, nullptr,
                                         CLSCTX_INPROC_SERVER,
                                         IID_IUniformResourceLocatorW,
                                         (void**)&m_spURL );
        if ( FAILED( hr ) ) {
            throw gcnew ExternalException( nullptr, hr );
        }
    }

    void SetURL( const std::wstring& url ) {
        HRESULT hr = m_spURL->SetURL( url.c_str(), 0x0 );
        if ( FAILED( hr ) ) {
            throw gcnew ExternalException( nullptr, hr );
        }
    }

    void SetIconLocation( const std::wstring& iconpath, int index ) {
        IShellLinkWPtr spLink;
        HRESULT hr = m_spURL->QueryInterface( IID_PPV_ARGS( &spLink ) );
        if ( SUCCEEDED( hr ) ) {
            hr = spLink->SetIconLocation( iconpath.c_str(), index );
        }
        if ( FAILED( hr ) ) {
            throw gcnew ExternalException( nullptr, hr );
        }
    }

    void Save( const std::wstring& pathname, bool remember ) {
        IPersistFilePtr spFile;
        HRESULT hr = m_spURL->QueryInterface( IID_PPV_ARGS( &spFile ) );
        if SUCCEEDED( hr ) {
            hr = spFile->Save( pathname.c_str(), remember ? TRUE : FALSE );
        }
        if ( FAILED( hr ) ) {
            throw gcnew ExternalException( nullptr, hr );
        }
    }
private:
    IUniformResourceLocatorWPtr m_spURL;
};

这是代理 class,它基本上只将调用从 .NET 转发到本机 class,它作为成员包含:

#include <msclr\marshal_cppstd.h>

using namespace System;

namespace ShortcutInteropLib {
#pragma warning(push)
#pragma warning(disable : 4461)  // "this class has a finalizer but no destructor"
    public ref class InternetShortcut
    {
    public:
        InternetShortcut() {
            m_pImpl = new InternetShortcutImpl();
        }

        void SetURL( String^ url ) {
            m_pImpl->SetURL( msclr::interop::marshal_as<std::wstring>( url ) );
        }

        void SetIconLocation( String^ iconpath, int index ) {
            m_pImpl->SetIconLocation( msclr::interop::marshal_as<std::wstring>( iconpath ),
                                      index );
        }

        void Save( String^ pathname, bool remember ) {
            m_pImpl->Save( msclr::interop::marshal_as<std::wstring>( pathname ),
                           remember );
        }

        !InternetShortcut() {
            delete m_pImpl;
        }

    private:
        InternetShortcutImpl* m_pImpl;
    };
#pragma warning(pop)
}

这构成了整个库,可以从 .NET 程序集中引用。调用代码非常简单:

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        var shortcut = new InternetShortcut();
        shortcut.SetURL(@"http://www.example.com");
        //shortcut.SetIconLocation(@"http://www.example.com/favicon", 1);
        shortcut.Save(Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
                      + @"\MyShortCut.url", false);
    }
}

这会在桌面上创建 http://www.example.com 的快捷方式。请注意,虽然我实现了 SetIconLocation,但我不知道如何将它与 URL 一起使用。虽然图标索引正确存储在生成的 MyShortCut.url 文件中,但该路径被解释为进入本地文件系统2 的路径。

该代码在我的系统上生成以下 Internet 快捷方式:

[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
IDList=
URL=http://www.example.com/


1 由于 C++/CLI class 库包含本机代码,因此您必须 select 目标体系结构。客户端代码必须引用适当的程序集。

2 我不知道是否有特殊的语法允许传递 URL,而不让系统解释作为本地文件系统路径的参数。如果有人知道,我会很高兴听到。