IShellLinkインターフェイスを用いることで、ショートカットの作成・読み込みができる。 ここではIShellLinkのラッパークラスとして ShellLinkクラスを作成し、それを使用している。 ShellLinkクラスのメソッドの詳細およびその他の関連クラス・インターフェイス等は以下のコードにある通り。 なお、このコードはCreating and Modifying Shortcuts (vbAccelerator)を参考にして作成した。 また、ANSI環境下では動作確認していない。
なお、Windows Scripting HostのCreateShortcutメソッドを使うことでより簡単にショートカットを作成することもできる。
using System; using System.IO; namespace SantaMarta.Tips.ShellLink { class Shortcut { static void Main( string[] args ) { // 作成先 string shortcutPath = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.Desktop ), "電卓.lnk" ); // ショートカットを作成 ShellLink shortcut = new ShellLink(); shortcut.Description = "電卓のショートカットです。"; shortcut.TargetPath = @"%SystemRoot%\System32\calc.exe"; shortcut.DisplayMode = ShellLink.ShellLinkDisplayMode.Normal; shortcut.Save( shortcutPath ); Console.WriteLine( "{0}を作成しました。", shortcut.CurrentFile ); shortcut.Dispose(); shortcut = null; // ショートカットを読み込み shortcut = new ShellLink( shortcutPath ); Console.WriteLine( "{0}を読み込みます。", shortcut.CurrentFile ); Console.WriteLine( "ターゲット: {0}", shortcut.TargetPath ); Console.WriteLine( "説明: {0}", shortcut.Description ); shortcut.Dispose(); shortcut = null; } } }
C:\Documents and Settings\--------\デスクトップ\電卓.lnkを作成しました。 C:\Documents and Settings\--------\デスクトップ\電卓.lnkを読み込みます。 ターゲット: C:\WINDOWS\system32\calc.exe 説明: 電卓のショートカットです。 Press any key to continue
using System; using System.IO; using System.Text; using System.ComponentModel; using System.Runtime.InteropServices; using System.Windows.Forms; namespace SantaMarta.Tips.ShellLink { #region "COM Interop" /// <summary> /// ShellLink コクラス /// </summary> [ComImport] [Guid("00021401-0000-0000-C000-000000000046")] [ClassInterface(ClassInterfaceType.None)] internal class ShellLinkObject {} #region "Unicode環境用" /// <summary> /// IShellLinkWインターフェイス /// </summary> [ComImport] [Guid("000214F9-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IShellLinkW { void GetPath ( [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cch, [MarshalAs(UnmanagedType.Struct)] ref WIN32_FIND_DATAW pfd, uint fFlags ); void GetIDList( out IntPtr ppidl ); void SetIDList( IntPtr pidl ); void GetDescription( [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cch ); void SetDescription( [MarshalAs(UnmanagedType.LPWStr)] string pszName ); void GetWorkingDirectory( [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cch ); void SetWorkingDirectory( [MarshalAs(UnmanagedType.LPWStr)] string pszDir ); void GetArguments( [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cch ); void SetArguments( [MarshalAs(UnmanagedType.LPWStr)] string pszArgs ); void GetHotkey( out ushort pwHotkey ); void SetHotkey( ushort wHotkey ); void GetShowCmd( out int piShowCmd ); void SetShowCmd( int iShowCmd ); void GetIconLocation ( [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cch, out int piIcon ); void SetIconLocation ( [MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon ); void SetRelativePath ( [MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved ); void Resolve ( IntPtr hwnd, uint fFlags ); void SetPath( [MarshalAs(UnmanagedType.LPWStr)] string pszFile ); } /// <summary> /// WIN32_FIND_DATAW 構造体 /// </summary> [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)] internal struct WIN32_FIND_DATAW { public const int MAX_PATH = 260; public uint dwFileAttributes; public System.Runtime.InteropServices.FILETIME ftCreationTime; public System.Runtime.InteropServices.FILETIME ftLastAccessTime; public System.Runtime.InteropServices.FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; public uint dwReserved0; public uint dwReserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; } #endregion #region "ANSI環境用" /// <summary> /// IShellLinkAインターフェイス /// </summary> [ComImport] [Guid("000214EE-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IShellLinkA { void GetPath ( [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszFile, int cch, [MarshalAs(UnmanagedType.Struct)] ref WIN32_FIND_DATAA pfd, uint fFlags ); void GetIDList( out IntPtr ppidl ); void SetIDList( IntPtr pidl ); void GetDescription( [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszName, int cch ); void SetDescription( [MarshalAs(UnmanagedType.LPStr)] string pszName ); void GetWorkingDirectory( [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszDir, int cch ); void SetWorkingDirectory( [MarshalAs(UnmanagedType.LPStr)] string pszDir ); void GetArguments( [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszArgs, int cch ); void SetArguments( [MarshalAs(UnmanagedType.LPStr)] string pszArgs ); void GetHotkey( out ushort pwHotkey ); void SetHotkey( ushort wHotkey ); void GetShowCmd( out int piShowCmd ); void SetShowCmd( int iShowCmd ); void GetIconLocation ( [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszIconPath, int cch, out int piIcon ); void SetIconLocation ( [MarshalAs(UnmanagedType.LPStr)] string pszIconPath, int iIcon ); void SetRelativePath ( [MarshalAs(UnmanagedType.LPStr)] string pszPathRel, uint dwReserved ); void Resolve ( IntPtr hwnd, uint fFlags ); void SetPath( [MarshalAs(UnmanagedType.LPStr)] string pszFile ); } /// <summary> /// WIN32_FIND_DATAA 構造体 /// </summary> [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)] internal struct WIN32_FIND_DATAA { public const int MAX_PATH = 260; public uint dwFileAttributes; public System.Runtime.InteropServices.FILETIME ftCreationTime; public System.Runtime.InteropServices.FILETIME ftLastAccessTime; public System.Runtime.InteropServices.FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; public uint dwReserved0; public uint dwReserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; } #endregion #endregion /// <summary> /// ショートカットに関する処理を行うためのクラスです。 /// </summary> public sealed class ShellLink : IDisposable { // IShellLinkインターフェイス private IShellLinkW shellLinkW; private IShellLinkA shellLinkA; // カレントファイル private string currentFile; // 実行環境 private bool isUnicodeEnvironment; // 各種定数 internal const int MAX_PATH = 260; internal const uint SLGP_SHORTPATH = 0x0001; // 短い形式(8.3形式)のファイル名を取得する internal const uint SLGP_UNCPRIORITY = 0x0002; // UNCパス名を取得する internal const uint SLGP_RAWPATH = 0x0004; // 環境変数などが変換されていないパス名を取得する #region "[型] ShellLinkDisplayMode列挙型" /// <summary> /// 実行時のウィンドウの表示方法を表す列挙型です。 /// </summary> public enum ShellLinkDisplayMode : int { /// <summary>通常の大きさのウィンドウで起動します。</summary> Normal = 1, /// <summary>最大化された状態で起動します。</summary> Maximized = 3, /// <summary>最小化された状態で起動します。</summary> Minimized = 7, } #endregion #region "[型] ShellLinkResolveFlags列挙型" /// <summary></summary> [Flags] public enum ShellLinkResolveFlags : int { /// <summary></summary> SLR_ANY_MATCH = 0x2, /// <summary></summary> SLR_INVOKE_MSI = 0x80, /// <summary></summary> SLR_NOLINKINFO = 0x40, /// <summary></summary> SLR_NO_UI = 0x1, /// <summary></summary> SLR_NO_UI_WITH_MSG_PUMP = 0x101, /// <summary></summary> SLR_NOUPDATE = 0x8, /// <summary></summary> SLR_NOSEARCH = 0x10, /// <summary></summary> SLR_NOTRACK = 0x20, /// <summary></summary> SLR_UPDATE = 0x4 } #endregion #region "コンストラクション・デストラクション" /// <summary> /// コンストラクタ /// </summary> /// <exception cref="COMException">IShellLinkインターフェイスを取得できませんでした。</exception> public ShellLink() { currentFile = ""; shellLinkW = null; shellLinkA = null; try { if ( Environment.OSVersion.Platform == PlatformID.Win32NT ) { // Unicode環境 shellLinkW = (IShellLinkW)( new ShellLinkObject() ); isUnicodeEnvironment = true; } else { // Ansi環境 shellLinkA = (IShellLinkA)( new ShellLinkObject() ); isUnicodeEnvironment = false; } } catch { throw new COMException( "IShellLinkインターフェイスを取得できませんでした。" ); } } /// <summary> /// コンストラクタ /// </summary> /// <param name="linkFile">ショートカットファイル</param> public ShellLink( string linkFile ) : this() { Load( linkFile ); } /// <summary> /// デストラクタ /// </summary> ~ShellLink() { Dispose(); } /// <summary> /// このインスタンスが使用しているリソースを解放します。 /// </summary> public void Dispose() { if ( shellLinkW != null ) { Marshal.ReleaseComObject( shellLinkW ); shellLinkW = null; } if ( shellLinkA != null ) { Marshal.ReleaseComObject( shellLinkA ); shellLinkA = null; } } #endregion #region "プロパティ" /// <summary> /// カレントファイル。 /// </summary> public string CurrentFile { get { return currentFile; } } /// <summary> /// ショートカットのリンク先。 /// </summary> public string TargetPath { get { StringBuilder targetPath = new StringBuilder( MAX_PATH, MAX_PATH ); if ( isUnicodeEnvironment ) { WIN32_FIND_DATAW data = new WIN32_FIND_DATAW(); shellLinkW.GetPath( targetPath, targetPath.Capacity, ref data, SLGP_UNCPRIORITY ); } else { WIN32_FIND_DATAA data = new WIN32_FIND_DATAA(); shellLinkA.GetPath( targetPath, targetPath.Capacity, ref data, SLGP_UNCPRIORITY ); } return targetPath.ToString(); } set { if ( isUnicodeEnvironment ) { shellLinkW.SetPath( value ); } else { shellLinkA.SetPath( value ); } } } /// <summary> /// 作業ディレクトリ。 /// </summary> public string WorkingDirectory { get { StringBuilder workingDirectory = new StringBuilder( MAX_PATH, MAX_PATH ); if ( isUnicodeEnvironment ) { shellLinkW.GetWorkingDirectory( workingDirectory, workingDirectory.Capacity ); } else { shellLinkA.GetWorkingDirectory( workingDirectory, workingDirectory.Capacity ); } return workingDirectory.ToString(); } set { if ( isUnicodeEnvironment ) { shellLinkW.SetWorkingDirectory( value ); } else { shellLinkA.SetWorkingDirectory( value ); } } } /// <summary> /// コマンドライン引数。 /// </summary> public string Arguments { get { StringBuilder arguments = new StringBuilder( MAX_PATH, MAX_PATH ); if ( isUnicodeEnvironment ) { shellLinkW.GetArguments( arguments, arguments.Capacity ); } else { shellLinkA.GetArguments( arguments, arguments.Capacity ); } return arguments.ToString(); } set { if ( isUnicodeEnvironment ) { shellLinkW.SetArguments( value ); } else { shellLinkA.SetArguments( value ); } } } /// <summary> /// ショートカットの説明。 /// </summary> public string Description { get { StringBuilder description = new StringBuilder( MAX_PATH, MAX_PATH ); if ( isUnicodeEnvironment ) { shellLinkW.GetDescription( description, description.Capacity ); } else { shellLinkA.GetDescription( description, description.Capacity ); } return description.ToString(); } set { if ( isUnicodeEnvironment ) { shellLinkW.SetDescription( value ); } else { shellLinkA.SetDescription( value ); } } } /// <summary> /// アイコンのファイル。 /// </summary> public string IconFile { get { int iconIndex = 0; string iconFile = ""; GetIconLocation( out iconFile, out iconIndex ); return iconFile; } set { int iconIndex = 0; string iconFile = ""; GetIconLocation( out iconFile, out iconIndex ); SetIconLocation( value, iconIndex ); } } /// <summary> /// アイコンのインデックス。 /// </summary> public int IconIndex { get { int iconIndex = 0; string iconPath = ""; GetIconLocation( out iconPath, out iconIndex ); return iconIndex; } set { int iconIndex = 0; string iconPath = ""; GetIconLocation( out iconPath, out iconIndex ); SetIconLocation( iconPath, value ); } } /// <summary> /// アイコンのファイルとインデックスを取得する /// </summary> /// <param name="iconFile">アイコンのファイル</param> /// <param name="iconIndex">アイコンのインデックス</param> private void GetIconLocation( out string iconFile, out int iconIndex ) { StringBuilder iconFileBuffer = new StringBuilder( MAX_PATH, MAX_PATH ); if ( isUnicodeEnvironment ) { shellLinkW.GetIconLocation( iconFileBuffer, iconFileBuffer.Capacity, out iconIndex ); } else { shellLinkA.GetIconLocation( iconFileBuffer, iconFileBuffer.Capacity, out iconIndex ); } iconFile = iconFileBuffer.ToString(); } /// <summary> /// アイコンのファイルとインデックスを設定する /// </summary> /// <param name="iconFile">アイコンのファイル</param> /// <param name="iconIndex">アイコンのインデックス</param> private void SetIconLocation( string iconFile, int iconIndex ) { if ( isUnicodeEnvironment ) { shellLinkW.SetIconLocation( iconFile, iconIndex ); } else { shellLinkA.SetIconLocation( iconFile, iconIndex ); } } /// <summary> /// 実行時のウィンドウの大きさ。 /// </summary> public ShellLinkDisplayMode DisplayMode { get { int showCmd = 0; if ( isUnicodeEnvironment ) { shellLinkW.GetShowCmd( out showCmd ); } else { shellLinkA.GetShowCmd( out showCmd ); } return (ShellLinkDisplayMode)showCmd; } set { if ( isUnicodeEnvironment ) { shellLinkW.SetShowCmd( (int)value ); } else { shellLinkA.SetShowCmd( (int)value ); } } } /// <summary> /// ホットキー。 /// </summary> public Keys HotKey { get { ushort hotKey = 0; if ( isUnicodeEnvironment ) { shellLinkW.GetHotkey( out hotKey ); } else { shellLinkA.GetHotkey( out hotKey ); } return (Keys)hotKey; } set { if ( isUnicodeEnvironment ) { shellLinkW.SetHotkey( (ushort)value ); } else { shellLinkA.SetHotkey( (ushort)value ); } } } #endregion #region "保存と読み込み" /// <summary> /// IShellLinkインターフェイスからキャストされたIPersistFileインターフェイスを取得します。 /// </summary> /// <returns>IPersistFileインターフェイス。 取得できなかった場合はnull。</returns> private UCOMIPersistFile GetIPersistFile() { if ( isUnicodeEnvironment ) { return shellLinkW as UCOMIPersistFile; } else { return shellLinkA as UCOMIPersistFile; } } /// <summary> /// カレントファイルにショートカットを保存します。 /// </summary> /// <exception cref="COMException">IPersistFileインターフェイスを取得できませんでした。</exception> public void Save() { Save( currentFile ); } /// <summary> /// 指定したファイルにショートカットを保存します。 /// </summary> /// <param name="linkFile">ショートカットを保存するファイル</param> /// <exception cref="COMException">IPersistFileインターフェイスを取得できませんでした。</exception> public void Save( string linkFile ) { // IPersistFileインターフェイスを取得して保存 UCOMIPersistFile persistFile = GetIPersistFile(); if ( persistFile == null ) throw new COMException( "IPersistFileインターフェイスを取得できませんでした。" ); persistFile.Save( linkFile, true ); // カレントファイルを保存 currentFile = linkFile; } /// <summary> /// 指定したファイルからショートカットを読み込みます。 /// </summary> /// <param name="linkFile">ショートカットを読み込むファイル</param> /// <exception cref="FileNotFoundException">ファイルが見つかりません。</exception> /// <exception cref="COMException">IPersistFileインターフェイスを取得できませんでした。</exception> public void Load( string linkFile ) { Load( linkFile, IntPtr.Zero, ShellLinkResolveFlags.SLR_ANY_MATCH | ShellLinkResolveFlags.SLR_NO_UI, 1 ); } /// <summary> /// 指定したファイルからショートカットを読み込みます。 /// </summary> /// <param name="linkFile">ショートカットを読み込むファイル</param> /// <param name="hWnd">このコードを呼び出したオーナーのウィンドウハンドル</param> /// <param name="resolveFlags">ショートカット情報の解決に関する動作を表すフラグ</param> /// <exception cref="FileNotFoundException">ファイルが見つかりません。</exception> /// <exception cref="COMException">IPersistFileインターフェイスを取得できませんでした。</exception> public void Load( string linkFile, IntPtr hWnd, ShellLinkResolveFlags resolveFlags ) { Load( linkFile, hWnd, resolveFlags, 1 ); } /// <summary> /// 指定したファイルからショートカットを読み込みます。 /// </summary> /// <param name="linkFile">ショートカットを読み込むファイル</param> /// <param name="hWnd">このコードを呼び出したオーナーのウィンドウハンドル</param> /// <param name="resolveFlags">ショートカット情報の解決に関する動作を表すフラグ</param> /// <param name="timeOut">SLR_NO_UIを指定したときのタイムアウト値(ミリ秒)</param> /// <exception cref="FileNotFoundException">ファイルが見つかりません。</exception> /// <exception cref="COMException">IPersistFileインターフェイスを取得できませんでした。</exception> public void Load( string linkFile, IntPtr hWnd, ShellLinkResolveFlags resolveFlags, TimeSpan timeOut ) { Load( linkFile, hWnd, resolveFlags, (int)timeOut.TotalMilliseconds ); } /// <summary> /// 指定したファイルからショートカットを読み込みます。 /// </summary> /// <param name="linkFile">ショートカットを読み込むファイル</param> /// <param name="hWnd">このコードを呼び出したオーナーのウィンドウハンドル</param> /// <param name="resolveFlags">ショートカット情報の解決に関する動作を表すフラグ</param> /// <param name="timeOutMilliseconds">SLR_NO_UIを指定したときのタイムアウト値(ミリ秒)</param> /// <exception cref="FileNotFoundException">ファイルが見つかりません。</exception> /// <exception cref="COMException">IPersistFileインターフェイスを取得できませんでした。</exception> public void Load( string linkFile, IntPtr hWnd, ShellLinkResolveFlags resolveFlags, int timeOutMilliseconds ) { if ( !File.Exists( linkFile ) ) throw new FileNotFoundException( "ファイルが見つかりません。", linkFile ); // IPersistFileインターフェイスを取得 UCOMIPersistFile persistFile = GetIPersistFile(); if ( persistFile == null ) throw new COMException( "IPersistFileインターフェイスを取得できませんでした。" ); // 読み込み persistFile.Load( linkFile, 0x00000000 ); // フラグを処理 uint flags = (uint)resolveFlags; if ( ( resolveFlags & ShellLinkResolveFlags.SLR_NO_UI ) == ShellLinkResolveFlags.SLR_NO_UI ) { flags |= (uint)( timeOutMilliseconds << 16 ); } // ショートカットに関する情報を読み込む if ( isUnicodeEnvironment ) { shellLinkW.Resolve( hWnd, flags ); } else { shellLinkA.Resolve( hWnd, flags ); } // カレントファイルを指定 currentFile = linkFile; } #endregion } }/// ShellLink コクラス /// [ComImport] [Guid("00021401-0000-0000-C000-000000000046")] [ClassInterface(ClassInterfaceType.None)] internal class ShellLinkObject {} #region "Unicode環境用" ////// IShellLinkWインターフェイス /// [ComImport] [Guid("000214F9-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IShellLinkW { void GetPath ( [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cch, [MarshalAs(UnmanagedType.Struct)] ref WIN32_FIND_DATAW pfd, uint fFlags ); void GetIDList( out IntPtr ppidl ); void SetIDList( IntPtr pidl ); void GetDescription( [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cch ); void SetDescription( [MarshalAs(UnmanagedType.LPWStr)] string pszName ); void GetWorkingDirectory( [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cch ); void SetWorkingDirectory( [MarshalAs(UnmanagedType.LPWStr)] string pszDir ); void GetArguments( [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cch ); void SetArguments( [MarshalAs(UnmanagedType.LPWStr)] string pszArgs ); void GetHotkey( out ushort pwHotkey ); void SetHotkey( ushort wHotkey ); void GetShowCmd( out int piShowCmd ); void SetShowCmd( int iShowCmd ); void GetIconLocation ( [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cch, out int piIcon ); void SetIconLocation ( [MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon ); void SetRelativePath ( [MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved ); void Resolve ( IntPtr hwnd, uint fFlags ); void SetPath( [MarshalAs(UnmanagedType.LPWStr)] string pszFile ); } ////// WIN32_FIND_DATAW 構造体 /// [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)] internal struct WIN32_FIND_DATAW { public const int MAX_PATH = 260; public uint dwFileAttributes; public System.Runtime.InteropServices.FILETIME ftCreationTime; public System.Runtime.InteropServices.FILETIME ftLastAccessTime; public System.Runtime.InteropServices.FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; public uint dwReserved0; public uint dwReserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; } #endregion #region "ANSI環境用" ////// IShellLinkAインターフェイス /// [ComImport] [Guid("000214EE-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] internal interface IShellLinkA { void GetPath ( [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszFile, int cch, [MarshalAs(UnmanagedType.Struct)] ref WIN32_FIND_DATAA pfd, uint fFlags ); void GetIDList( out IntPtr ppidl ); void SetIDList( IntPtr pidl ); void GetDescription( [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszName, int cch ); void SetDescription( [MarshalAs(UnmanagedType.LPStr)] string pszName ); void GetWorkingDirectory( [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszDir, int cch ); void SetWorkingDirectory( [MarshalAs(UnmanagedType.LPStr)] string pszDir ); void GetArguments( [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszArgs, int cch ); void SetArguments( [MarshalAs(UnmanagedType.LPStr)] string pszArgs ); void GetHotkey( out ushort pwHotkey ); void SetHotkey( ushort wHotkey ); void GetShowCmd( out int piShowCmd ); void SetShowCmd( int iShowCmd ); void GetIconLocation ( [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszIconPath, int cch, out int piIcon ); void SetIconLocation ( [MarshalAs(UnmanagedType.LPStr)] string pszIconPath, int iIcon ); void SetRelativePath ( [MarshalAs(UnmanagedType.LPStr)] string pszPathRel, uint dwReserved ); void Resolve ( IntPtr hwnd, uint fFlags ); void SetPath( [MarshalAs(UnmanagedType.LPStr)] string pszFile ); } ////// WIN32_FIND_DATAA 構造体 /// [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)] internal struct WIN32_FIND_DATAA { public const int MAX_PATH = 260; public uint dwFileAttributes; public System.Runtime.InteropServices.FILETIME ftCreationTime; public System.Runtime.InteropServices.FILETIME ftLastAccessTime; public System.Runtime.InteropServices.FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; public uint dwReserved0; public uint dwReserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; } #endregion #endregion ////// ショートカットに関する処理を行うためのクラスです。 /// public sealed class ShellLink : IDisposable { // IShellLinkインターフェイス private IShellLinkW shellLinkW; private IShellLinkA shellLinkA; // カレントファイル private string currentFile; // 実行環境 private bool isUnicodeEnvironment; // 各種定数 internal const int MAX_PATH = 260; internal const uint SLGP_SHORTPATH = 0x0001; // 短い形式(8.3形式)のファイル名を取得する internal const uint SLGP_UNCPRIORITY = 0x0002; // UNCパス名を取得する internal const uint SLGP_RAWPATH = 0x0004; // 環境変数などが変換されていないパス名を取得する #region "[型] ShellLinkDisplayMode列挙型" ////// 実行時のウィンドウの表示方法を表す列挙型です。 /// public enum ShellLinkDisplayMode : int { ///通常の大きさのウィンドウで起動します。 Normal = 1, ///最大化された状態で起動します。 Maximized = 3, ///最小化された状態で起動します。 Minimized = 7, } #endregion #region "[型] ShellLinkResolveFlags列挙型" ///[Flags] public enum ShellLinkResolveFlags : int { /// SLR_ANY_MATCH = 0x2, /// SLR_INVOKE_MSI = 0x80, /// SLR_NOLINKINFO = 0x40, /// SLR_NO_UI = 0x1, /// SLR_NO_UI_WITH_MSG_PUMP = 0x101, /// SLR_NOUPDATE = 0x8, /// SLR_NOSEARCH = 0x10, /// SLR_NOTRACK = 0x20, /// SLR_UPDATE = 0x4 } #endregion #region "コンストラクション・デストラクション" /// /// コンストラクタ /// ///IShellLinkインターフェイスを取得できませんでした。 public ShellLink() { currentFile = ""; shellLinkW = null; shellLinkA = null; try { if ( Environment.OSVersion.Platform == PlatformID.Win32NT ) { // Unicode環境 shellLinkW = (IShellLinkW)( new ShellLinkObject() ); isUnicodeEnvironment = true; } else { // Ansi環境 shellLinkA = (IShellLinkA)( new ShellLinkObject() ); isUnicodeEnvironment = false; } } catch { throw new COMException( "IShellLinkインターフェイスを取得できませんでした。" ); } } ////// コンストラクタ /// /// ショートカットファイル public ShellLink( string linkFile ) : this() { Load( linkFile ); } ////// デストラクタ /// ~ShellLink() { Dispose(); } ////// このインスタンスが使用しているリソースを解放します。 /// public void Dispose() { if ( shellLinkW != null ) { Marshal.ReleaseComObject( shellLinkW ); shellLinkW = null; } if ( shellLinkA != null ) { Marshal.ReleaseComObject( shellLinkA ); shellLinkA = null; } } #endregion #region "プロパティ" ////// カレントファイル。 /// public string CurrentFile { get { return currentFile; } } ////// ショートカットのリンク先。 /// public string TargetPath { get { StringBuilder targetPath = new StringBuilder( MAX_PATH, MAX_PATH ); if ( isUnicodeEnvironment ) { WIN32_FIND_DATAW data = new WIN32_FIND_DATAW(); shellLinkW.GetPath( targetPath, targetPath.Capacity, ref data, SLGP_UNCPRIORITY ); } else { WIN32_FIND_DATAA data = new WIN32_FIND_DATAA(); shellLinkA.GetPath( targetPath, targetPath.Capacity, ref data, SLGP_UNCPRIORITY ); } return targetPath.ToString(); } set { if ( isUnicodeEnvironment ) { shellLinkW.SetPath( value ); } else { shellLinkA.SetPath( value ); } } } ////// 作業ディレクトリ。 /// public string WorkingDirectory { get { StringBuilder workingDirectory = new StringBuilder( MAX_PATH, MAX_PATH ); if ( isUnicodeEnvironment ) { shellLinkW.GetWorkingDirectory( workingDirectory, workingDirectory.Capacity ); } else { shellLinkA.GetWorkingDirectory( workingDirectory, workingDirectory.Capacity ); } return workingDirectory.ToString(); } set { if ( isUnicodeEnvironment ) { shellLinkW.SetWorkingDirectory( value ); } else { shellLinkA.SetWorkingDirectory( value ); } } } ////// コマンドライン引数。 /// public string Arguments { get { StringBuilder arguments = new StringBuilder( MAX_PATH, MAX_PATH ); if ( isUnicodeEnvironment ) { shellLinkW.GetArguments( arguments, arguments.Capacity ); } else { shellLinkA.GetArguments( arguments, arguments.Capacity ); } return arguments.ToString(); } set { if ( isUnicodeEnvironment ) { shellLinkW.SetArguments( value ); } else { shellLinkA.SetArguments( value ); } } } ////// ショートカットの説明。 /// public string Description { get { StringBuilder description = new StringBuilder( MAX_PATH, MAX_PATH ); if ( isUnicodeEnvironment ) { shellLinkW.GetDescription( description, description.Capacity ); } else { shellLinkA.GetDescription( description, description.Capacity ); } return description.ToString(); } set { if ( isUnicodeEnvironment ) { shellLinkW.SetDescription( value ); } else { shellLinkA.SetDescription( value ); } } } ////// アイコンのファイル。 /// public string IconFile { get { int iconIndex = 0; string iconFile = ""; GetIconLocation( out iconFile, out iconIndex ); return iconFile; } set { int iconIndex = 0; string iconFile = ""; GetIconLocation( out iconFile, out iconIndex ); SetIconLocation( value, iconIndex ); } } ////// アイコンのインデックス。 /// public int IconIndex { get { int iconIndex = 0; string iconPath = ""; GetIconLocation( out iconPath, out iconIndex ); return iconIndex; } set { int iconIndex = 0; string iconPath = ""; GetIconLocation( out iconPath, out iconIndex ); SetIconLocation( iconPath, value ); } } ////// アイコンのファイルとインデックスを取得する /// /// アイコンのファイル /// アイコンのインデックス private void GetIconLocation( out string iconFile, out int iconIndex ) { StringBuilder iconFileBuffer = new StringBuilder( MAX_PATH, MAX_PATH ); if ( isUnicodeEnvironment ) { shellLinkW.GetIconLocation( iconFileBuffer, iconFileBuffer.Capacity, out iconIndex ); } else { shellLinkA.GetIconLocation( iconFileBuffer, iconFileBuffer.Capacity, out iconIndex ); } iconFile = iconFileBuffer.ToString(); } ////// アイコンのファイルとインデックスを設定する /// /// アイコンのファイル /// アイコンのインデックス private void SetIconLocation( string iconFile, int iconIndex ) { if ( isUnicodeEnvironment ) { shellLinkW.SetIconLocation( iconFile, iconIndex ); } else { shellLinkA.SetIconLocation( iconFile, iconIndex ); } } ////// 実行時のウィンドウの大きさ。 /// public ShellLinkDisplayMode DisplayMode { get { int showCmd = 0; if ( isUnicodeEnvironment ) { shellLinkW.GetShowCmd( out showCmd ); } else { shellLinkA.GetShowCmd( out showCmd ); } return (ShellLinkDisplayMode)showCmd; } set { if ( isUnicodeEnvironment ) { shellLinkW.SetShowCmd( (int)value ); } else { shellLinkA.SetShowCmd( (int)value ); } } } ////// ホットキー。 /// public Keys HotKey { get { ushort hotKey = 0; if ( isUnicodeEnvironment ) { shellLinkW.GetHotkey( out hotKey ); } else { shellLinkA.GetHotkey( out hotKey ); } return (Keys)hotKey; } set { if ( isUnicodeEnvironment ) { shellLinkW.SetHotkey( (ushort)value ); } else { shellLinkA.SetHotkey( (ushort)value ); } } } #endregion #region "保存と読み込み" ////// IShellLinkインターフェイスからキャストされたIPersistFileインターフェイスを取得します。 /// ///IPersistFileインターフェイス。 取得できなかった場合はnull。 private UCOMIPersistFile GetIPersistFile() { if ( isUnicodeEnvironment ) { return shellLinkW as UCOMIPersistFile; } else { return shellLinkA as UCOMIPersistFile; } } ////// カレントファイルにショートカットを保存します。 /// ///IPersistFileインターフェイスを取得できませんでした。 public void Save() { Save( currentFile ); } ////// 指定したファイルにショートカットを保存します。 /// /// ショートカットを保存するファイル ///IPersistFileインターフェイスを取得できませんでした。 public void Save( string linkFile ) { // IPersistFileインターフェイスを取得して保存 UCOMIPersistFile persistFile = GetIPersistFile(); if ( persistFile == null ) throw new COMException( "IPersistFileインターフェイスを取得できませんでした。" ); persistFile.Save( linkFile, true ); // カレントファイルを保存 currentFile = linkFile; } ////// 指定したファイルからショートカットを読み込みます。 /// /// ショートカットを読み込むファイル ///ファイルが見つかりません。 ///IPersistFileインターフェイスを取得できませんでした。 public void Load( string linkFile ) { Load( linkFile, IntPtr.Zero, ShellLinkResolveFlags.SLR_ANY_MATCH | ShellLinkResolveFlags.SLR_NO_UI, 1 ); } ////// 指定したファイルからショートカットを読み込みます。 /// /// ショートカットを読み込むファイル /// このコードを呼び出したオーナーのウィンドウハンドル /// ショートカット情報の解決に関する動作を表すフラグ ///ファイルが見つかりません。 ///IPersistFileインターフェイスを取得できませんでした。 public void Load( string linkFile, IntPtr hWnd, ShellLinkResolveFlags resolveFlags ) { Load( linkFile, hWnd, resolveFlags, 1 ); } ////// 指定したファイルからショートカットを読み込みます。 /// /// ショートカットを読み込むファイル /// このコードを呼び出したオーナーのウィンドウハンドル /// ショートカット情報の解決に関する動作を表すフラグ /// SLR_NO_UIを指定したときのタイムアウト値(ミリ秒) ///ファイルが見つかりません。 ///IPersistFileインターフェイスを取得できませんでした。 public void Load( string linkFile, IntPtr hWnd, ShellLinkResolveFlags resolveFlags, TimeSpan timeOut ) { Load( linkFile, hWnd, resolveFlags, (int)timeOut.TotalMilliseconds ); } ////// 指定したファイルからショートカットを読み込みます。 /// /// ショートカットを読み込むファイル /// このコードを呼び出したオーナーのウィンドウハンドル /// ショートカット情報の解決に関する動作を表すフラグ /// SLR_NO_UIを指定したときのタイムアウト値(ミリ秒) ///ファイルが見つかりません。 ///IPersistFileインターフェイスを取得できませんでした。 public void Load( string linkFile, IntPtr hWnd, ShellLinkResolveFlags resolveFlags, int timeOutMilliseconds ) { if ( !File.Exists( linkFile ) ) throw new FileNotFoundException( "ファイルが見つかりません。", linkFile ); // IPersistFileインターフェイスを取得 UCOMIPersistFile persistFile = GetIPersistFile(); if ( persistFile == null ) throw new COMException( "IPersistFileインターフェイスを取得できませんでした。" ); // 読み込み persistFile.Load( linkFile, 0x00000000 ); // フラグを処理 uint flags = (uint)resolveFlags; if ( ( resolveFlags & ShellLinkResolveFlags.SLR_NO_UI ) == ShellLinkResolveFlags.SLR_NO_UI ) { flags |= (uint)( timeOutMilliseconds << 16 ); } // ショートカットに関する情報を読み込む if ( isUnicodeEnvironment ) { shellLinkW.Resolve( hWnd, flags ); } else { shellLinkA.Resolve( hWnd, flags ); } // カレントファイルを指定 currentFile = linkFile; } #endregion } }]]>
以下は調査中に書いたメモ。
Windowsのショートカットファイル、.lnkファイルをC#で作成・編集するためのプログラムを書く。
やろうとしていたことが、全てここ記述されている…
要は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#の場合はそっちのキーワードに置き換えた方がコーディングしやすいかも。
.NET FrameworkにはSystem.Runtime.InteropServices.UCOMIPersistFileインターフェイスなるものが存在している(http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/cpref/html/frlrfsystemruntimeinteropservicesucomipersistfileclasstopic.asp)。
UCOMIPersistFile インターフェイス
IPersist 機能を備えた IPersistFile インターフェイスのマネージ定義。
実は頑張って自分で定義する必要がなかったらしい…