IShellLinkインターフェイスを用いることで、ショートカットの作成・読み込みができる。 ここではIShellLinkのラッパークラスとしてShellLinkクラスを作成し、それを使用している。 IShellLinkインターフェイスについては、IShellLink Interface ()を参照のこと。
参考までに、Windows Scripting HostのCreateShortcutメソッドを使うことでより簡単にショートカットを作成することもできる。
コード
使用例
static void Main(string[] args)
{
// 作成先
var shortcutPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "電卓.lnk");
// ショートカットを作成する
using (var shortcut = new ShellLink()) {
shortcut.Description = "電卓のショートカットです。";
shortcut.TargetPath = @"%SystemRoot%\System32\calc.exe";
shortcut.ShowCommand = SW.NORMAL;
shortcut.Save(shortcutPath);
Console.WriteLine("{0}を作成しました。", shortcut.CurrentFile);
}
// 作成したショートカットを読み込む
using (var shortcut = new ShellLink(shortcutPath)) {
Console.WriteLine("ファイル: {0}", shortcut.CurrentFile);
Console.WriteLine("ターゲット: {0}", shortcut.TargetPath);
Console.WriteLine("説明: {0}", shortcut.Description);
}
}
C:\Documents and Settings\--------\デスクトップ\電卓.lnkを作成しました。 ファイル: C:\Documents and Settings\--------\デスクトップ\電卓.lnk ターゲット: C:\WINDOWS\system32\calc.exe 説明: 電卓のショートカットです。 Press any key to continue
実装
このコードはCreating and Modifying Shortcuts (vbAccelerator)を参考にして作成した。 ANSI環境下での動作も考慮した実装になっているが、確認はしていない。
- 2009-10-14
- 現在のファイルパスをIPersistFileから取得するように修正
IDisposeの実装を修正
ushort<->Keysの変換処理の誤りを修正
System.Runtime.InteropServices.FILETIMEの代わりにSystem.Runtime.InteropServices.ComTypes.FILETIMEを使うように修正
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Windows.Forms;
using ComTypes = System.Runtime.InteropServices.ComTypes;
namespace Smdn.Windows.UserInterfaces.Shells {
/*
* http://msdn.microsoft.com/en-us/library/bb774950%28VS.85%29.aspx
*/
public class ShellLink : IDisposable {
public string CurrentFile {
get
{
string file;
PersistFile.GetCurFile(out file);
return file;
}
}
public string TargetPath {
get
{
CheckDisposed();
var targetPath = CreatePathStringBuffer();
if (shellLinkW != null) {
var data = new WIN32_FIND_DATAW();
shellLinkW.GetPath(targetPath, targetPath.Capacity, ref data, SLGP_FLAGS.UNCPRIORITY);
}
else {
var data = new WIN32_FIND_DATAA();
shellLinkA.GetPath(targetPath, targetPath.Capacity, ref data, SLGP_FLAGS.UNCPRIORITY);
}
return targetPath.ToString();
}
set
{
CheckDisposed();
if (shellLinkW != null)
shellLinkW.SetPath(value);
else
shellLinkA.SetPath(value);
}
}
public string WorkingDirectory {
get
{
CheckDisposed();
var workingDirectory = CreatePathStringBuffer();
if (shellLinkW != null)
shellLinkW.GetWorkingDirectory(workingDirectory, workingDirectory.Capacity);
else
shellLinkA.GetWorkingDirectory(workingDirectory, workingDirectory.Capacity);
return workingDirectory.ToString();
}
set
{
CheckDisposed();
if (shellLinkW != null)
shellLinkW.SetWorkingDirectory(value);
else
shellLinkA.SetWorkingDirectory(value);
}
}
public string Arguments {
get
{
CheckDisposed();
var arguments = CreatePathStringBuffer();
if (shellLinkW != null)
shellLinkW.GetArguments(arguments, arguments.Capacity);
else
shellLinkA.GetArguments(arguments, arguments.Capacity);
return arguments.ToString();
}
set
{
CheckDisposed();
if (shellLinkW != null)
shellLinkW.SetArguments(value);
else
shellLinkA.SetArguments(value);
}
}
public string Description {
get
{
CheckDisposed();
var description = CreatePathStringBuffer();
if (shellLinkW != null)
shellLinkW.GetDescription(description, description.Capacity);
else
shellLinkA.GetDescription(description, description.Capacity);
return description.ToString();
}
set
{
CheckDisposed();
if (shellLinkW != null)
shellLinkW.SetDescription(value);
else
shellLinkA.SetDescription(value);
}
}
public IconLocation IconLocation {
get
{
CheckDisposed();
var iconFileBuffer = CreatePathStringBuffer();
int iconIndex;
if (shellLinkW != null)
shellLinkW.GetIconLocation(iconFileBuffer, iconFileBuffer.Capacity, out iconIndex);
else
shellLinkA.GetIconLocation(iconFileBuffer, iconFileBuffer.Capacity, out iconIndex);
return new IconLocation(iconFileBuffer.ToString(), iconIndex);
}
set
{
CheckDisposed();
if (shellLinkW != null)
shellLinkW.SetIconLocation(value.File, value.Index);
else
shellLinkA.SetIconLocation(value.File, value.Index);
}
}
public SW ShowCommand {
get
{
CheckDisposed();
SW showCmd;
if (shellLinkW != null)
shellLinkW.GetShowCmd(out showCmd);
else
shellLinkA.GetShowCmd(out showCmd);
return showCmd;
}
set
{
CheckDisposed();
if (shellLinkW != null)
shellLinkW.SetShowCmd(value);
else
shellLinkA.SetShowCmd(value);
}
}
public Keys HotKey {
get
{
CheckDisposed();
ushort hotKey;
if (shellLinkW != null)
shellLinkW.GetHotkey(out hotKey);
else
shellLinkA.GetHotkey(out hotKey);
return TranslateKeyCode(hotKey);
}
set
{
CheckDisposed();
var newHotKey = TranslateKeyCode(value);
if (shellLinkW != null)
shellLinkW.SetHotkey(newHotKey);
else
shellLinkA.SetHotkey(newHotKey);
}
}
private IPersistFile PersistFile {
get
{
CheckDisposed();
var ret = (shellLinkW != null)
? shellLinkW as IPersistFile
: shellLinkA as IPersistFile;
if (ret == null)
throw new COMException("cannot create IPersistFile");
else
return ret;
}
}
public ShellLink()
: this(null)
{
}
public ShellLink(string linkFile)
{
try {
if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
shellLinkW = (IShellLinkW)new ShellLinkObject();
shellLinkA = null;
}
else {
shellLinkA = (IShellLinkA)new ShellLinkObject();
shellLinkW = null;
}
}
catch {
throw new COMException("cannot create ShellLinkObject");
}
if (linkFile != null)
Load(linkFile);
}
~ShellLink()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (shellLinkW != null) {
Marshal.ReleaseComObject(shellLinkW);
shellLinkW = null;
}
if (shellLinkA != null) {
Marshal.ReleaseComObject(shellLinkA);
shellLinkA = null;
}
}
public void Save()
{
var file = CurrentFile;
if (file == null)
throw new InvalidOperationException("file name must be specified");
Save(file);
}
public void Save(string file)
{
CheckDisposed();
if (file == null)
throw new ArgumentNullException("file");
PersistFile.Save(file, true);
}
public void Load(string file)
{
Load(file, IntPtr.Zero, SLR_FLAGS.ANY_MATCH | SLR_FLAGS.NO_UI, 1);
}
[CLSCompliant(false)]
public void Load(string file, IntPtr hWnd, SLR_FLAGS flags)
{
Load(file, hWnd, flags, 1);
}
[CLSCompliant(false)]
public void Load(string file, IntPtr hWnd, SLR_FLAGS flags, TimeSpan timeOut)
{
Load(file, hWnd, flags, (int)timeOut.TotalMilliseconds);
}
[CLSCompliant(false)]
public void Load(string file, IntPtr hWnd, SLR_FLAGS flags, int timeoutMilliseconds)
{
CheckDisposed();
if (!File.Exists(file))
throw new FileNotFoundException("file not found", file);
PersistFile.Load(file, 0x00000000);
if ((int)(flags & SLR_FLAGS.NO_UI) != 0)
flags |= (SLR_FLAGS)(timeoutMilliseconds << 16);
if (shellLinkW != null)
shellLinkW.Resolve(hWnd, flags);
else
shellLinkA.Resolve(hWnd, flags);
}
private static StringBuilder CreatePathStringBuffer()
{
return new StringBuilder(Consts.MAX_PATH, Consts.MAX_PATH);
}
private static ushort TranslateKeyCode(Keys key)
{
// IShellLink::SetHotkey Method
// wHotkey
// The new keyboard shortcut. The virtual key code is in the low-order byte, and the modifier flags are in the high-order byte.
// The modifier flags can be a combination of the values specified in the description of the IShellLink::GetHotkey method.
var virtKey = ((int)(key & Keys.KeyCode) & 0x00ff);
var modifier = (((int)(key & Keys.Modifiers) >> 8) & 0xff00);
return (ushort)(virtKey | modifier);
}
private static Keys TranslateKeyCode(ushort key)
{
// IShellLink::GetHotkey Method
// pwHotkey
// The address of the keyboard shortcut. The virtual key code is in the low-order byte,
// and the modifier flags are in the high-order byte. The modifier flags can be a combination of the following values.
var virtKey = (Keys)(key & 0x00ff);
var modifier = (Keys)((key & 0xff00) << 8);
return virtKey | modifier;
}
private void CheckDisposed()
{
if (shellLinkW == null && shellLinkA == null)
throw new ObjectDisposedException(GetType().FullName);
}
private IShellLinkW shellLinkW = null;
private IShellLinkA shellLinkA = null;
}
// ShellLink コクラス
[CLSCompliant(false), ComImport, ClassInterface(ClassInterfaceType.None), Guid("00021401-0000-0000-C000-000000000046")]
public class ShellLinkObject {}
// IShellLinkWインターフェイス
[CLSCompliant(false), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")]
public interface IShellLinkW { // cannot list any base interfaces here
//HRESULT GetPath([out, size_is(cch)] LPWSTR pszFile, [in] int cch, [in, out, ptr] WIN32_FIND_DATAW *pfd, [in] DWORD fFlags);
void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cch, ref WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags);
//HRESULT GetIDList([out] LPITEMIDLIST * ppidl);
void GetIDList(out IntPtr ppidl);
//HRESULT SetIDList([in] LPCITEMIDLIST pidl);
void SetIDList(IntPtr pidl);
//HRESULT GetDescription([out, size_is(cch)] LPWSTR pszName, int cch);
void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cch);
//HRESULT SetDescription([in] LPCWSTR pszName);
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
//HRESULT GetWorkingDirectory([out, size_is(cch)] LPWSTR pszDir, int cch);
void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cch);
//HRESULT SetWorkingDirectory([in] LPCWSTR pszDir);
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
//HRESULT GetArguments([out, size_is(cch)] LPWSTR pszArgs, int cch);
void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cch);
//HRESULT SetArguments([in] LPCWSTR pszArgs);
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
//HRESULT GetHotkey([out] WORD *pwHotkey);
void GetHotkey(out ushort pwHotkey);
//HRESULT SetHotkey([in] WORD wHotkey);
void SetHotkey(ushort wHotkey);
//HRESULT GetShowCmd([out] int *piShowCmd);
void GetShowCmd(out SW piShowCmd);
//HRESULT SetShowCmd([in] int iShowCmd);
void SetShowCmd(SW iShowCmd);
//HRESULT GetIconLocation([out, size_is(cch)] LPWSTR pszIconPath, [in] int cch, [out] int *piIcon);
void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cch, out int piIcon);
//HRESULT SetIconLocation([in] LPCWSTR pszIconPath, [in] int iIcon);
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
//HRESULT SetRelativePath([in] LPCWSTR pszPathRel, [in] DWORD dwReserved);
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved);
//HRESULT Resolve([in] HWND hwnd, [in] DWORD fFlags);
void Resolve(IntPtr hwnd, SLR_FLAGS fFlags);
//HRESULT SetPath([in] LPCWSTR pszFile);
void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}
// IShellLinkAインターフェイス
[CLSCompliant(false), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214EE-0000-0000-C000-000000000046")]
public interface IShellLinkA { // cannot list any base interfaces here
//HRESULT GetPath([out, size_is(cch)] LPSTR pszFile, [in] int cch, [in, out, ptr] WIN32_FIND_DATAW *pfd, [in] DWORD fFlags);
void GetPath([Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszFile, int cch, ref WIN32_FIND_DATAA pfd, SLGP_FLAGS fFlags);
//HRESULT GetIDList([out] LPITEMIDLIST * ppidl);
void GetIDList(out IntPtr ppidl);
//HRESULT SetIDList([in] LPCITEMIDLIST pidl);
void SetIDList(IntPtr pidl);
//HRESULT GetDescription([out, size_is(cch)] LPSTR pszName, int cch);
void GetDescription([Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszName, int cch);
//HRESULT SetDescription([in] LPCSTR pszName);
void SetDescription([MarshalAs(UnmanagedType.LPStr)] string pszName);
//HRESULT GetWorkingDirectory([out, size_is(cch)] LPSTR pszDir, int cch);
void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszDir, int cch);
//HRESULT SetWorkingDirectory([in] LPCSTR pszDir);
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPStr)] string pszDir);
//HRESULT GetArguments([out, size_is(cch)] LPSTR pszArgs, int cch);
void GetArguments([Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszArgs, int cch);
//HRESULT SetArguments([in] LPCSTR pszArgs);
void SetArguments([MarshalAs(UnmanagedType.LPStr)] string pszArgs);
//HRESULT GetHotkey([out] WORD *pwHotkey);
void GetHotkey(out ushort pwHotkey);
//HRESULT SetHotkey([in] WORD wHotkey);
void SetHotkey(ushort wHotkey);
//HRESULT GetShowCmd([out] int *piShowCmd);
void GetShowCmd(out SW piShowCmd);
//HRESULT SetShowCmd([in] int iShowCmd);
void SetShowCmd(SW iShowCmd);
//HRESULT GetIconLocation([out, size_is(cch)] LPSTR pszIconPath, [in] int cch, [out] int *piIcon);
void GetIconLocation([Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszIconPath, int cch, out int piIcon);
//HRESULT SetIconLocation([in] LPCSTR pszIconPath, [in] int iIcon);
void SetIconLocation([MarshalAs(UnmanagedType.LPStr)] string pszIconPath, int iIcon);
//HRESULT SetRelativePath([in] LPCSTR pszPathRel, [in] DWORD dwReserved);
void SetRelativePath([MarshalAs(UnmanagedType.LPStr)] string pszPathRel, uint dwReserved);
//HRESULT Resolve([in] HWND hwnd, [in] DWORD fFlags);
void Resolve(IntPtr hwnd, SLR_FLAGS fFlags);
//HRESULT SetPath([in] LPCSTR pszFile);
void SetPath([MarshalAs(UnmanagedType.LPStr)] string pszFile);
}
public partial class Consts {
public const int MAX_PATH = 260;
}
[CLSCompliant(false), StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
public struct WIN32_FIND_DATAW {
public uint dwFileAttributes;
public ComTypes.FILETIME ftCreationTime;
public ComTypes.FILETIME ftLastAccessTime;
public ComTypes.FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Consts.MAX_PATH)] public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName;
}
[CLSCompliant(false), StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct WIN32_FIND_DATAA {
public uint dwFileAttributes;
public ComTypes.FILETIME ftCreationTime;
public ComTypes.FILETIME ftLastAccessTime;
public ComTypes.FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Consts.MAX_PATH)] public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName;
}
// SW_XXX
public enum SW : int {
HIDE = 0,
NORMAL = 1,
SHOWNORMAL = 1,
SHOWMINIMIZED = 2,
MAXIMIZE = 3,
SHOWMAXIMIZED = 3,
SHOWNOACTIVATE = 4,
SHOW = 5,
MINIMIZE = 6,
SHOWMINNOACTIVE = 7,
SHOWNA = 8,
RESTORE = 9,
SHOWDEFAULT = 10,
FORCEMINIMIZE = 11,
}
[CLSCompliant(false), Flags]
public enum SLGP_FLAGS : uint {
SHORTPATH = 1,
UNCPRIORITY = 2,
RAWPATH = 4,
}
/// <summary>Flags determining how the links with missing targets are resolved.</summary>
[CLSCompliant(false), Flags]
public enum SLR_FLAGS : uint {
/// <summary>
/// Do not display a dialog box if the link cannot be resolved.
/// When SLR_NO_UI is set, a time-out value that specifies the
/// maximum amount of time to be spent resolving the link can
/// be specified in milliseconds. The function returns if the
/// link cannot be resolved within the time-out duration.
/// If the timeout is not set, the time-out duration will be
/// set to the default value of 3,000 milliseconds (3 seconds).
/// </summary>
NO_UI = 1,
/// <summary>
/// Allow any match during resolution. Has no effect
/// on ME/2000 or above, use the other flags instead.
/// </summary>
ANY_MATCH = 2,
/// <summary>
/// If the link object has changed, update its path and list
/// of identifiers. If SLR_UPDATE is set, you do not need to
/// call IPersistFile::IsDirty to determine whether or not
/// the link object has changed.
/// </summary>
UPDATE = 4,
/// <summary>Do not update the link information.</summary>
NOUPDATE = 8,
/// <summary>Do not execute the search heuristics.</summary>
NOSEARCH = 16,
/// <summary>Do not use distributed link tracking.</summary>
NOTRACK = 32,
/// <summary>
/// Disable distributed link tracking. By default,
/// distributed link tracking tracks removable media
/// across multiple devices based on the volume name.
/// It also uses the UNC path to track remote file
/// systems whose drive letter has changed. Setting
/// SLR_NOLINKINFO disables both types of tracking.
/// </summary>
NOLINKINFO = 64,
/// <summary>Call the Microsoft Windows Installer.</summary>
INVOKE_MSI = 128,
/// <summary>
/// Not documented in SDK. Assume same as SLR_NO_UI but
/// intended for applications without a hWnd.
/// </summary>
UI_WITH_MSG_PUMP = 0x101,
}
public struct IconLocation {
public static readonly IconLocation Empty = new IconLocation();
public string File {
get { return file; }
set { file = value; }
}
public int Index {
get { return index; }
set { index = CheckIndex(value); }
}
public IconLocation(string file, int index)
: this()
{
this.file = file;
this.index = CheckIndex(index);
}
private int CheckIndex(int val)
{
if (val < 0)
throw new ArgumentOutOfRangeException("val", "must be zero or positive number");
return val;
}
private string file;
private int index;
}
}
メモ
以下は調査中に書いたメモ。
ショートカットファイルを作成する
Windowsのショートカットファイル、.lnkファイルをC#で作成・編集するためのプログラムを書く。
解答
やろうとしていたことが、全てここ記述されている…
調べてて参考になった
- IShellLinkインターフェイス関連の解説
- http://techtips.belution.com/ja/vc/0032/
- http://yokohama.cool.ne.jp/chokuto/urawaza/interface/IShellLink/
- http://yokohama.cool.ne.jp/chokuto/urawaza/interface/IPersistFile/
- http://www.runan.net/program/tips/sdk_03_CreateShortCut.shtml
- http://homepage2.nifty.com/DSS/WinSys/Win/SCCreate.htm
- http://homepage1.nifty.com/MADIA/vc/vc_bbs/200211_02110015.html
- http://techtips.belution.com/ja/vc/0030/
- COM Interop関連の解説
- http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/csref/html/vcwlkcominteroppart1cclienttutorial.asp
- http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cptools/html/cpgrftypelibraryimportertlbimpexe.asp
- http://www.ma2world.net/category_8_blogid_1.html
- http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cpguide/html/cpcontlbimpmemberconversion.asp
- http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cpguide/html/cpconinheritanceaggregationcontainment.asp
まとめ
要はCOMとして用意されているIShellLinkW(A)やIPersistFileインターフェイスと、同等でマネージドなシグネチャを持つインターフェイスをC#で実装することで、COMと同じ機能を有することができる。 ただし、このときGUIDとInterfaceTypeを指定する必要がある。 たとえば、こんな感じ(コメントはもとのMIDLコード)。
[Guid("000214F9-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IShellLinkW // cannot list any base interfaces here
{
//HRESULT GetPath([out, size_is(cch)] LPWSTR pszFile, [in] int cch, [in, out, ptr] WIN32_FIND_DATAW *pfd, [in] DWORD fFlags);
void GetPath
(
[Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
[In] int cch,
[In, Out, MarshalAs(UnmanagedType.Struct)] WIN32_FIND_DATAW pfd,
[In] uint fFlags
);
// 中略
}
また、COMコクラスと呼ばれるものは、GUIDを指定してやれば実装のないC#クラスとして記述できる。
[ComImport]
[Guid("00021401-0000-0000-C000-000000000046")]
[ClassInterfaceAttribute(ClassInterfaceType.None)]
class ShellLinkObject {}
これを実際に使用する場合はこんな感じ。
static void Main(string[] args)
{
try
{
ShellLinkObject shellLink = new ShellLinkObject();
IShellLinkW sl = (IShellLinkW)shellLink;
sl.SetPath( @"D:\test.jpg" );
sl.SetWorkingDirectory( @"D:\Test\" );
sl.SetDescription( "This is a sample link file." );
IPersistFile pf = (IPersistFile)sl;
pf.Save( @"D:\test.lnk", false );
Marshal.ReleaseComObject( pf );
Marshal.ReleaseComObject( sl );
}
catch( Exception ex )
{
System.Diagnostics.Trace.WriteLine( ex.GetType().Name );
System.Diagnostics.Trace.WriteLine( ex.Message );
System.Diagnostics.Trace.WriteLine( ex.StackTrace );
}
}
ひとまずこんな感じ。 インターフェイスのシグネチャを間違えて書かなければ問題なく動く。 あと、[In, Out]属性はref、[Out]属性はoutに変えられるから、C#の場合はそっちのキーワードに置き換えた方がコーディングしやすいかも。
補足、IPersistFileインターフェイスについて
.NET FrameworkにはSystem.Runtime.InteropServices.UCOMIPersistFileインターフェイスなるものが存在している(http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/cpref/html/frlrfsystemruntimeinteropservicesucomipersistfileclasstopic.asp)。
UCOMIPersistFile インターフェイスIPersist 機能を備えた IPersistFile インターフェイスのマネージ定義。
実は頑張って自分で定義する必要がなかったらしい…