运用IShellLink和IPersistFile创建快捷方式,设置或读取快捷方式信息

先介绍一下这两个类:

IShellLink


The IShellLink interface allows Shell links to be created, modified, and resolved.

Methods

IShellLink supports the following methods:

GetArgumentsRetrieves the command-line arguments associated with a Shell link object.
GetDescription Retrieves the description string for a Shell link object.
GetHotkeyRetrieves the hot key for a Shell link object.
GetIconLocation Retrieves the location (path and index) of the icon for a Shell link object.
GetIDListRetrieves the list of item identifiers for a Shell link object.
GetPathRetrieves the path and file name of a Shell link object.
GetShowCmdRetrieves the show (SW_) command for a Shell link object.
GetWorkingDirectory Retrieves the name of the working directory for a Shell link object.
ResolveResolves a Shell link by searching for the Shell link object and updating the Shell link path and its list of identifiers (if necessary).
SetArguments Sets the command-line arguments associated with a Shell link object.
SetDescription Sets the description string for a Shell link object.
SetHotkeySets the hot key for a Shell link object.
SetIconLocation Sets the location (path and index) of the icon for a Shell link object.
SetIDListSets the list of item identifiers for a Shell link object.
SetPathSets the path and file name of a Shell link object.
SetRelativePath Sets the relative path for a Shell link object.
SetShowCmdSets the show (SW_) command for a Shell link object.
SetWorkingDirectory Sets the name of the working directory for a Shell link object.
Remarks

Note: The IShellLink interface has an ANSI version (IShellLinkA) and a Unicode version (IShellLinkW). The version that will be used depends on whether you compile for ANSI or Unicode. However, Microsoft® Windows 95 and Microsoft® Windows 98 only support IShellLinkA.

IPersistFile

The IPersistFile interface provides methods that permit an object to be loaded from or saved to a disk file, rather than a storage object or stream. Because the information needed to open a file varies greatly from one application to another, the implementation of IPersistFile::Load on the object must also open its disk file.

The IPersistFile interface inherits its definition from IPersist, so all implementations must also include the GetClassID method of IPersist.

When to Implement

Implement IPersistFile when you want to read or write information from a separate file, which could be of any file format.

This interface should be implemented on any objects that support linking through a file moniker, including the following:

  • Any object that supports links to its files or to pseudo-objects within its files.
  • A container application that supports links to objects within its compound file.

Typically, you implement the IPersistFile interface as part of an aggregate object that includes other interfaces that are appropriate for the type of moniker binding that is supported.

For example, in either of the cases mentioned above, the moniker for the linked object can be a composite moniker. In the first case, a composite moniker identifies the pseudo-object contained within the file. In the second case, a composite moniker identifies the embedded object contained within the compound file. In either case of composite monikers, you must implement the IPersistFile interface as part of the same object on which the IOleItemContainer interface is implemented. Then, when the application for the linked object is run, OLE queries for the IOleItemContainer interface to locate the embedded object or the pseudo-object contained in the file.

As another example, if the moniker is a simple file moniker (i.e., the link is to the entire file), OLE queries for the interface that the initiator of the bind operation requested. Typically, this is one of the compound document interfaces, such as IOleObject, IDataObject, or IPersistStorage.

When to Use

Call methods in the IPersistFile interface to load or save a linked object in a specified file.

When IPersistFile is implemented on an object that supports linking through a file moniker and the application for the linked object is run, OLE calls IPersistFile::Load. Once the file is loaded, OLE calls IPersistFile::QueryInterface to get another interface pointer to the loaded object. The IPersistFile interface is typically part of an aggregate object that offers other interfaces.

In this case, the only IPersistFile method that OLE calls is the Load method to load a file linked to a container, running the application associated with the file. It would also be unusual for applications to call other methods in this case, which support saving an object to a file. Generally, it is left to the end user and the application for the linked object to decide when to save the object. This differs from the situation for an embedded object, in which the container application uses the IPersistStorage interface to provide the storage and to tell the object when to save itself.

Methods in Vtable Order

IUnknown MethodsDescription
QueryInterfaceReturns pointers to supported interfaces.
AddRefIncrements the reference count.
ReleaseDecrements the reference count.
IPersist MethodDescription
GetClassIDReturns the class identifier (CLSID) for the component object.
IPersistFile MethodsDescription
IsDirtyChecks an object for changes since it was last saved to its current file.
LoadOpens the specified file and initializes an object from the file contents.
SaveSaves the object into the specified file.
SaveCompletedNotifies the object that it can revert from NoScribble mode to Normal mode.
GetCurFileGets the current name of the file associated with the object.

Requirements 

  Windows NT/2000/XP: Requires Windows NT 3.1 or later.
  Windows 95/98: Requires Windows 95 or later.
  Header: Declared in objidl.h.

上面是MSDN种两个类的描述,下面看看怎么用吧!
1、创建快捷方式
//创建快捷方式, SourcePath 源文件路径,  lnkPath 快捷方式路径, pParam 快捷方式的参数
BOOL CreateLnk( char * SourcePath,  char * lnkPath, char* pParam )
{
 WORD wsz[ MAX_PATH] ;
 MultiByteToWideChar( CP_ACP, 0, lnkPath, -1, wsz, MAX_PATH) ;
 HRESULT hr = CoInitialize(NULL);
 if (SUCCEEDED(hr))
 {
  IShellLink *pisl;
  hr = CoCreateInstance(CLSID_ShellLink, NULL,
   CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pisl);
  if (SUCCEEDED(hr))
  {
   IPersistFile* pIPF;
   
   //这里是我们要创建快捷方式的原始文件地址
   pisl->SetPath( SourcePath );
   pisl->SetArguments( pParam ) ;
   hr = pisl->QueryInterface(IID_IPersistFile, (void**)&pIPF);
   if (SUCCEEDED(hr))
   {
    //这里是我们要创建快捷方式的目标地址
    pIPF->Save( wsz, FALSE);
    pIPF->Release();
   }
   else
   {
    DbgPrint( "call QueryInterface failt " ) ;
    return FALSE ;
   }
   pisl->Release();
  }
  else
  {
   DbgPrint( " call CoCreateInstance failt " ) ;
   return FALSE ;
  }
  CoUninitialize();
 }
 else
 {
  DbgPrint( "inint ConInitialize Failt " ) ;
  return FALSE ;
 }
 return TRUE ;
}
 
2、读取快捷方式文件的一些信息。
HWND hWnd ;
  HRESULT hres ;
  IShellLink  * PShLink ;
  WIN32_FIND_DATA wfd ;
  CString lpszLinkName;
  char   lpszPath[MAX_PATH] = {0};
  char   lpszDescription[MAX_PATH] = {0} ;
  lpszLinkName = f.GetFilePath() ;
  //DbgPrint( lpszLinkName ) ;
  hres = CoInitialize( NULL ) ;
  if ( SUCCEEDED(hres) )
  {
   hres = CoCreateInstance( CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&PShLink ) ;
   
   if ( SUCCEEDED(hres) )
   {
    IPersistFile * ppf ;
    
    hres = PShLink->QueryInterface(  IID_IPersistFile, (LPVOID*)&ppf  );
    if ( SUCCEEDED(hres) )
    {
     WORD wsz[MAX_PATH] ;
     MultiByteToWideChar( CP_ACP, 0, lpszLinkName, -1, wsz, MAX_PATH ) ;
     hres = ppf->Load( wsz, STGM_READ ) ;
     if ( SUCCEEDED(hres) )
     {
      hres = PShLink->Resolve(  hWnd, SLR_ANY_MATCH|SLR_NO_UI ) ;
      if( SUCCEEDED(hres) )
      {
 
       //这里就可以用类提供的函数得到一些快捷方式的信息了。
       hres = PShLink->GetPath( lpszPath, MAX_PATH, &wfd, SLGP_SHORTPATH ) ;
       CString sFileNameTemp ;
       sFileNameTemp.Format( "%s", lpszPath ) ; //这里我只得到了源路径
      }
      else
       DbgPrint( "Resolve failt " ) ;
     }
     else
      DbgPrint( "load failt " ) ;
     ppf->Release( ) ;
    }
    else
     DbgPrint( "QueryInterface failt " ) ;
    PShLink->Release(  ) ;
   }
   else
    DbgPrint( "coCreateInStance failt " ) ;
  
   CoUninitialize() ;
  }
  else
  {
   DbgPrint( "call CoInitialize failt " ) ;
  }
 
这两个功能的实现都是从网上收集了些代码,自己修改了一下,现在对这两个类有了初步的认识,谁有更深入的理解,欢迎交流。
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
ショートカット

 

 FAQの中でもトップクラスと言って間違いない「ショートカット」。ですが、それなりにちゃんとしたアンサーがないような気がするのは筆者だけでしょうか? そんな感じでいってみましょう。

ショートカットに使うインターフェイス
 ショートカットの操作に必要なのは IShellLinkインターフェイスと、 IPersistFileインターフェイスです。ひとつだけじゃダメなのがみそです。ちなみに、これまで通りどっちもポインタとして扱いますが、 LPなんたらという形にどちらもなってないんで注意。
 まぁ、そんな感じで次のようにメンバ変数として持っておいてください。

  
  
	IShellLink	*m_pShellLink;		//IShellLinkへのポインタ。
	IPersistFile	*m_pPersistFile;	//IPersistFileへのポインタ。
	

 

 あと、とーぜん、アイテムIDリストとか使うのであればこれまでのテクニックを総動員するわけなので、その辺もね。

初期化しましょう
 ショートカットを操作するためには、これまで以上に念入りな準備が必要です。次のような処理を、ショートカットの操作を行う前に(できればコンストラクタとかで)行ってください。

  
  
BOOL CT_Filer2View::LinkInit()
{
	HRESULT hRes;	//各結果。

	// メンバ変数を初期化します。
	m_pPersistFile = NULL;
	m_pShellLink = NULL;

	// まず、OLEを使うために初期化しておきます。
	hRes = ::CoInitialize( NULL );

	if( hRes == E_OUTOFMEMORY )
		return FALSE;
	if( hRes == E_INVALIDARG )
		return FALSE;
	if( hRes == E_UNEXPECTED )
		return FALSE;

	// 空のインターフェイスを用意します。
	hRes = ::CoCreateInstance( CLSID_ShellLink, NULL,
				CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&m_pShellLink );

	if( hRes == CLASS_E_NOAGGREGATION )
		return FALSE;
	if( hRes == REGDB_E_CLASSNOTREG )
		return FALSE;

	
	// IPersistFileへのポインタを取得します。
	hRes = m_pShellLink->QueryInterface( IID_IPersistFile, (LPVOID *)&m_pPersistFile );

	if( hRes != S_OK )
		return FALSE;

	return TRUE;
}
	

 

 これまでのインターフェイス関係とはちょっと違う感じでしょう。でも難しいことはありません。いや、まぁ詳しく知ろうとすれば難しいでしょう。わたしゃ知ろうとしてないので 全然難しくありません、はい。

 まずCoInitialize()。これはAPIです。COM関係のAPIは、どうやらCoがプレフィックスとして付くようです。
 この関数は、そのCOM関係APIを使うための前準備として使用しなければならないようです。
 この関数はただ呼べばいいんですが、注意して欲しいのは、返ってきた値がS_FALSEの時には、基本的に問題ないのでそのまま素通りさせてください。っていうか、たいがいはこの値が返ってくると思います。

 次に呼ぶCoCreateInstance()は、空のインターフェイスを作製するものです。
 これまで、IShellFolderにしろIEnumIDListにしろ、なんらかのAPIやインターフェイスから取得してきました。これらにはすでにデータの入った、いわば「中身の詰まった」インターフェイスだったわけです。
 しかし、ショートカットの場合には少し違ってきます。これまでのインターフェイスはメモリ上の抽象オブジェクトを扱ってきましたが、インターフェイスは「ファイル」という永続オブジェクトです。ファイルの中からデータを取りだし、それを格納する領域が必要というわけです。
 そのための関数がCoCreateInstance()というわけです。引数などについては難しく考えると難しくなってしまうので、簡単にそのまま使ってしまいましょう。

 さて、実はIShellLinkインターフェイスには、ファイルを操作する機能はありません。が、実際には内包しています。ファイルの操作にはIPersistFileインターフェイスを使用します。
 その、内包されているらしいインターフェイスへのポインタを取得するのがQueryInterface()メソッドです。このメソッドはすべてのインターフェイスが持っていて、他のインターフェイスへのポインタを取得できるようになっています。ただ、何でもかんでも好きなインターフェイスを取得できるというわけでもないようです。まー要するによく分からないってことです、はい。
 でもとりあえず、IShellLink::QueryInterface()を使うことでIPersistFileインターフェイスへのポインタを取得できるわけです。このポインタを取得することで、IShellLinkにもファイル操作の機能が付くというわけです。

 とまぁ、ここまでが下準備ですが、この辺はそのまま使って構いません。つまり、アプリケーションの仕様とかでこの辺を書き換える必要とかはないということですね。

後処理もしましょう
 インターフェイス関係にはつきものの後処理です。デストラクタとかでね。

  
  
BOOL CT_Filer2View::UnInit()
{
	// IPersistFileへのポインタを破棄します。
	if( m_pPersistFile != NULL )
		m_pPersistFile->Release();

	// IShellLinkへのポインタを破棄します。
	if( m_pShellLink != NULL )
		m_pShellLink->Release();

	::CoUninitialize();

	return TRUE;
}
	

 

  Release()メソッドはこれまでにも何度か出てきているので説明の必要はないでしょう。 CoUninitialize()CoInitialize()と対になるAPIです。これも気にせず使ってしまえばいいでしょう。

ショートカットのロード
 では、待望のショートカットの読み込みを行ってみましょう。

  
  
BOOL CT_Filer2View::Load(LPCTSTR p_pchFile)
{
	HRESULT	hRes;	//各結果。
	OLECHAR	ochLinkFile[MAX_PATH];

	// ユニコードに変換します。
	::MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, p_pchFile, -1,
                        ochLinkFile, MAX_PATH );

	// ショートカットを読み込みます。
	hRes = m_pPersistFile->Load( ochLinkFile, STGM_READ );
	if( hRes != S_OK )
		return FALSE;

	// リンクを決定します。
	hRes = m_pShellLink->Resolve( NULL, SLR_UPDATE );
	if( hRes != NOERROR )
		return FALSE;

	return TRUE;
}
	

 

 引数には、ショートカットのフルパス(例えば C:/Windows/Desktop/ショートカット.lnkのような形)を渡します。例によってUnicodeでないとダメなので変換します。
 変換した後のパスを IPersistFile::Load()メソッドを使用して読み込みます。でもこれだけではダメです。ここまでは単にファイルとして読み込んだだけなので、ちゃんと「ショートカット」として読み込む必要があります。
 そのためのメソッドが IShellLink::Resolve()メソッド。この時点で初めてショートカットを読み込みます。
 このメソッドのフラグを変えると、ショートカットが見つからなかった場合に 探させたり訊ねさせたりすることができます。実際に試してみるといいでしょう。リンク先のファイル名を変更して、スタートメニューから実行してみると「ショートカットの検索」っていうダイアログが出て、自動的に検索してくれます。
 と言っても、この検索は単にサブフォルダ内を検索していくだけなので、それほどすごいもんでもないと思います。ちなみにこの機能を使うときには、第1引数に親ウィンドウのウィンドウハンドルを指定してください(例えばビューウィンドウとか)。

データの取得
 ロードした後、ショートカットからデータを読み込みます。それには IShellLink::Getなんたらというメソッドを使用すればOK。ただ、いくつかクセがあるのでその辺を注意するべきでしょう。

 指し示すファイルの取得はIShellLink::GetPath()を使用します。ただし、これはフルパスの文字列なので、マイコンピュータとかは取得できません。こういったシェル関係のファイルを取得する場合にはIShellLink::GetIDList()を使用します。こちらならアイテムIDリストとしてファイルを取得できます。

 かなり謎なのがIShellLink::GetDescription()で、普通のショートカットからは、このメソッドで文字列を取得することができません。ただ、後述のIShellLink::SetDescription()で文字列をショートカットにセットして作製すると、その文字列を取得することができます。要するに内部データとしての文字列ということでしょう。でもなんに使うんでしょうね。
 しかも奇妙なことに、コントロールパネル系のショートカットは、内部的に文字列を持っています。そのコントロールパネルの情報が入っていて、例えば「システム」であれば、「システムの基本情報を表示し、詳細設定を変更します。」なんてことが書かれています。でもこの文字列はIShellLink::GetDescription()では取得できません。謎です。

 アイコンの取得はIShellLink::GetIconLocation()で行えますが、中にはこれで取得できないアイコンもあるので、単純にアイコンを取得したい場合にはSHGetFileInfo()を使っちゃうのが一番楽でしょう。

「スタートメニュー」フォルダの取得
 ショートカットの置き場所は、基本的に「スタートメニュー」か「デスクトップ」ということになっています。どちらもウィンドウズフォルダ(たいがいは C:/Windows)の中のフォルダだから、普通のパスとして取得できます。これらの特殊フォルダの取得方法は、ふたつあります。

 ひとつは、SHGetSpecialFolderLocation()を使用するもの。実際には次のような感じ。

  
  
	char		chPath[MAX_PATH];
	LPITEMIDLIST	pidl;

	// デスクトップフォルダ。
	::SHGetSpecialFolderLocation( GetSafeHwnd(), CSIDL_DESKTOPDIRECTORY, &pidl );
	::SHGetPathFromIDList( pidl, chPath );
	TRACE( "CSIDL_DESKTOPDIRECTORY %s/n", (LPCTSTR)chPath );

	// スタートメニューフォルダ。
	::SHGetSpecialFolderLocation( GetSafeHwnd(), CSIDL_STARTMENU, &pidl );
	::SHGetPathFromIDList( pidl, chPath );
	TRACE( "CSIDL_STARTMENU %s/n", (LPCTSTR)chPath );
	

 

 もうひとつはレジストリから取得する方法。 HKEY_CURRENT_USER/Software/Microsoft/Windows
/CurrentVersion/Explorer/Shell Folders
に特殊フォルダが登録されているのでそちらから取得してもいいでしょう。
 どちらにしろ、 特殊フォルダのパス名はユーザーの設定によって違う可能性があるということだけは憶えておきましょう。以上のようなコードを使用せずに「決め打ち」することだけは 絶対に避けましょう

 あと、インストーラを作製する場合にはSHBrowseForFolder()を使用するといいでしょう(これの解説は「フォルダを選択するダイアログ(前編)(後編)」を見てね)。この場合、ルートフォルダ(BROWSEINFO構造体pidlRootメンバの値)に上で取得した「スタートメニュー」のフォルダを設定するといい感じかも。

データのセット
 さて、ここからは「ショートカットの作製」に入ります。コード自体は「後処理」まで書いてあればOK。もちろん「ショートカットの設定を変更する」のであれば、ここまでのコードすべてが必要になるでしょう。

 データのセットにはIShellLink::Setなんたらというメソッドを使用します。このメソッドは「データの取得」で説明したのと対になって存在しているので、どちらかが使えれば大丈夫でしょう。
 ただ、たったひとつIShellLink::SetRelativePath()だけは謎のメソッドとして君臨します。なんに使うのか分からないし、筆者の持ってるリファレンスと引数が違うし(最後の引数はDWORDです)。なんなんでしょ。

 さて、新規にショートカットを作製する場合には、どのようにデータを設定すればいいか分からないかもしれません。ここで、一例を示しておきます。

  
  
	m_pShellLink->SetIDList( pidl );	//リンク先のアイテムID。
	m_pShellLink->SetShowCmd( SW_SHOW );	//標準の表示。
	m_pShellLink->SetWorkingDirectory( "" );	//カレントフォルダはナシ。
	m_pShellLink->SetIconLocation( NULL, 0 );	//これで、フツーのアイコンが表示されます。
	m_pShellLink->SetHotkey( 0 );			//ホットキーナシ。
	m_pShellLink->SetDescription( "" );	//タイトルナシ。
	

 

 軒並み必要そうなのを羅列していますが、実際には必要ないかもしれません。
 注意としてまずリンク先ですが、上の例ではファイルをアイテムIDリストでセットしています。パスを文字列としてセットするには IShellLink::SetPath()を使ってください。
 アイコンの設定は、上のように省略すると、うまくリンク先のアイコンが指定されるので便利です。
 こんなところでしょう。結構適当にセットしても大丈夫みたいです。

ショートカットのセーブ
 データをセットしたら、ショートカットを保存しましょう。といってもほとんどロードと同じです。

  
  
BOOL CT_Filer2View::Save( LPCTSTR p_pchFile )
{
	HRESULT	hRes;	//各結果。
	OLECHAR	ochLinkFile[MAX_PATH];

	// ユニコードに変換します。
	::MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, p_pchFile, -1,
                        ochLinkFile, MAX_PATH );

	// ショートカットを書き込みます。
	hRes = m_pPersistFile->Save( ochLinkFile, TRUE );

	if( hRes != S_OK )
		return FALSE;

	return TRUE;
}
	

 

 違いとしては IShellLink::Resolve()の必要がないくらいでしょうか。あとは、セーブするパスはちゃんと .lnkの拡張子を付けておきましょう。

以上で終わり!
 いかがだったでしょう。筆者の知る限り、今回のようにC++中心で解説されたものは少ないと思います。MFCで利用するにはいいんじゃないでしょうか。
 ショートカットで難しいのは「初期化」の部分です。が、これはもうそのまま使ってしまってください。少なくとも「ショートカット」においては、この部分について理解する必要はありません。こういう「理解する必要のある部分」と「必要のない部分」の見切りのつけ方なんかも、プログラミング技術のひとつなのかなとか思います。

 さて、次回で「COMインターフェイス・ファイラーを作ろう!」講座は最終回を迎えます。まとめ的なちょこちょことした部分を書いて、この講座を締めくくろうと思ってます。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值