ショートカットとインターネットショートカットを作成 :【VC++】

Microsoft のドキュメントに、インターネットショートカットの作成方法が
記述されていますし、ショートカットのアイコンの変更方法もあります。

しかし、非常に簡単にしか書かれておらず、ショートカット作成に関しては「これと同じようにしなさい」と言わんばかりではあります。

確かに、インターネットショートカットの作成方法が理解できるのであれば、
ショートカット作成は難しくありませんが、Shell Interfaces や COM Interfaces の
英文記述のマニュアルの場所を知っている必要があります。

で、サンプルをまとめてみました。

ブラウザでダウンロード

呼び出し部分
ソースを3つに分けました

1) 呼び出し部分( _tWinMain )
2) インターネットショートカットの作成
3) ショートカットの作成

※ ファイルのパスの処理が少し面倒なので、lightbox.lib を使用しました

create_shortcut.exe を実行すると、デスクトップに winofsql.jp のリンクと
dir を実行して pause するコマンドプロンプトのショートカットが作成されます。
#define _WIN32_WINNT 0x0500
#include <tchar.h>
#include "lightbox\lightbox.h"

#pragma comment( lib, "lightbox\\lightbox.lib" )
#pragma comment( lib, "shlwapi.lib" )


HRESULT CreateShortcutToURL(LPCSTR pszURL, LPCSTR pszLinkFile);
HRESULT CreateShortcut(
	LPCSTR pszLink,
	LPCSTR pszLinkFile,
	LPCSTR pszArguments=NULL,
	LPCSTR pszDescription=NULL,
	LPCSTR pszWorkingDirectory=NULL,
	int nSetShowCmd=SW_SHOWNORMAL,
	WORD wHotkey=0,
	LPCSTR pszIcon=NULL,
	int iIcon=0
);


// *********************************************************
// Windows アプリケーションとしてのエントリポイント
// Link.exe で /SUBSYSTEM:WINDOWS がデフォルトで
// 指定される事になります
// *********************************************************
int APIENTRY _tWinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR lpCmdLine,
	int nCmdShow
)
{

	HRESULT hRet;

	char buff[MAX_PATH];
	char file[MAX_PATH];

	hRet = SHGetSpecialFolderPath(
		NULL,
		buff,
		CSIDL_DESKTOPDIRECTORY,
		false
	);

	lstrcpy( file, buff );
	lstrcat( file, "\\winofsql.url" );

	// COM 利用時に必要
	CoInitialize(NULL);

	// URL ショートカットをデスクトップに作成
	hRet = CreateShortcutToURL( "http://winofsql.jp", file );
	if ( SUCCEEDED(hRet) ) {
		// 成功処理
	}

	LboxString exeFile, exePath;
	exeFile = "cmd.exe";
	LboxInfo Info;
	Info.SearchFromPath( exeFile, exePath );

	lstrcpy( file, buff );
	lstrcat( file, "\\コマンドプロンプト.lnk" );
	WORD wHotkey = MAKEWORD(VK_F9,HOTKEYF_CONTROL);

	hRet = CreateShortcut(
		exePath.szLboxString,
		file,
		"/c dir & pause",
		"dir 実行後一時停止",
		NULL,
		SW_SHOWNORMAL,
		wHotkey
	);
	if ( SUCCEEDED(hRet) ) {
		// 成功処理
	}

	// COM 利用終了時に必要
	CoUninitialize();

	return 0;
}
icon の設定はしていませんが、その他の設定可能な内容は全てプログラムで
処理されています。icon も、引数で渡せば処理されます。


HRESULT CreateShortcut(
	LPCSTR pszLink,
	LPCSTR pszLinkFile,
	LPCSTR pszArguments=NULL,
	LPCSTR pszDescription=NULL,
	LPCSTR pszWorkingDirectory=NULL,
	int nSetShowCmd=SW_SHOWNORMAL,
	WORD wHotkey=0,
	LPCSTR pszIcon=NULL,
	int iIcon=0
);

pszLink		実行プログラムのパス。
		フルパスでなくても、OS が補完してくれるが、
		作業ディレクトリをの自動取得させる為に
		SearchFromPath を使用して設定しています。

pszLinkFile	ショートカットが作成されるパス

pszArguments		引数
pszDescription		コメント
pszWorkingDirectory		作業ディレクトリ
nSetShowCmd		実行時の大きさ
wHotkey			LOWORD が仮想キーコード
			HIWORD が以下
			HOTKEYF_ALT
				ALT key 
			HOTKEYF_CONTROL
				CTRL key 
			HOTKEYF_EXT
				Extended key 
			HOTKEYF_SHIFT
				SHIFT key 
pszIcon			アイコンを持つファイルへのパス
iIcon			含まれるアイコンの番号


この処理では、icon を指定せずに省略して呼び出しています
( デフォルト指定による引数の省略 : 途中省略は不可 )

CreateShortcutToURL
Microsoft のサンプルから、WCHAR の処理を簡単にする為に _bstr_t を使用しています。
何故か Microsoft は、MultiByteToWideChar を使用したサンプルばかりのような
気がしますが、どう考えても _bstr_t を使用すべきです。
// *********************************************************
// URL ショートカットをデスクトップに作成
// *********************************************************

#define _WIN32_WINNT 0x0500
#include <tchar.h>
#include "lightbox\lightbox.h"

#include <intshcut.h>

#pragma comment( lib, "lightbox\\lightbox.lib" )
#pragma comment( lib, "shlwapi.lib" )

HRESULT CreateShortcutToURL(LPCSTR pszURL, LPCSTR pszLinkFile)
{

	HRESULT hRes;
	IUniformResourceLocator *pURL = NULL;

	// オブジェクト作成
	hRes = CoCreateInstance (
		CLSID_InternetShortcut,
		NULL,
		CLSCTX_INPROC_SERVER,
		IID_IUniformResourceLocator,
		(LPVOID*) &pURL
	);

	// 成功処理
	if ( SUCCEEDED( hRes ) ) {

		IPersistFile *pPF = NULL;

		hRes = pURL->SetURL(pszURL, 0);
	
		if ( SUCCEEDED(hRes) ) {

			_bstr_t path = pszLinkFile;

			hRes = pURL->QueryInterface( IID_IPersistFile, (void **)&pPF );
			if ( SUCCEEDED(hRes) ) {
				hRes = pPF->Save((wchar_t *)path, TRUE);
				pPF->Release ();
			}
		}

		pURL->Release ();
	}

	return hRes;
}
CreateShortcut
ソースを見やすくする為に、エラー処理をはしょりましたが、
エラーが出無いような引数を渡すバッチ処理用を想定していますので、
特に問題は無いと思います。
// *********************************************************
// ショートカットをデスクトップに作成
// *********************************************************

#define _WIN32_WINNT 0x0500
#include <tchar.h>
#include "lightbox\lightbox.h"

#include <intshcut.h>

#pragma comment( lib, "lightbox\\lightbox.lib" )
#pragma comment( lib, "shlwapi.lib" )

HRESULT CreateShortcut(
	LPCSTR pszLink,
	LPCSTR pszLinkFile,
	LPCSTR pszArguments=NULL,
	LPCSTR pszDescription=NULL,
	LPCSTR pszWorkingDirectory=NULL,
	int nSetShowCmd=SW_SHOWNORMAL,
	WORD wHotkey=0,
	LPCSTR pszIcon=NULL,
	int iIcon=0
)
{

	HRESULT hRes;
	IShellLink *pLink = NULL;
	char szWorkingDirectory[MAX_PATH];

	// オブジェクト作成
	hRes = CoCreateInstance (
		CLSID_ShellLink,
		NULL,
		CLSCTX_INPROC_SERVER,
		IID_IShellLink,
		(LPVOID*) &pLink
	);

	// 成功処理
	if ( SUCCEEDED( hRes ) ) {

		IPersistFile *pPF = NULL;

		hRes = pLink->SetPath(pszLink);
	
		if ( SUCCEEDED(hRes) ) {
			// 本来は、全てのメソッドで結果をチェックすべきですが、
			// 意味を読み取りやすくする為に省略しています
			if ( pszArguments != NULL ) {
				// 引数
				hRes = pLink->SetArguments(pszArguments);
			}
			if ( pszDescription != NULL ) {
				// コメント
				hRes = pLink->SetDescription(pszDescription);
			}
			if ( pszIcon != NULL ) {
				// コメント
				hRes = pLink->SetIconLocation(pszIcon,iIcon);
			}
			if ( wHotkey != 0 ) {
				// コメント
				hRes = pLink->SetHotkey(wHotkey);
			}
			if ( pszWorkingDirectory != NULL ) {
				// 作業フォルダ
				lstrcpy( szWorkingDirectory, pszWorkingDirectory );
			}
			else {
				// 作業フォルダ
				// lightbox.lib 使用
				// http://winofsql.jp/VA003334/cmstd040521004209.htm#ttl19
				LboxString LString = (LPTSTR)pszLink;
				LString.RemoveFileSpec();
				lstrcpy( szWorkingDirectory, LString.szLboxString );
			}
			hRes = pLink->SetWorkingDirectory( szWorkingDirectory );
			// 実行時の大きさ
			hRes = pLink->SetShowCmd(nSetShowCmd);

			_bstr_t path = pszLinkFile;

			hRes = pLink->QueryInterface( IID_IPersistFile, (void **)&pPF );
			if ( SUCCEEDED(hRes) ) {
				hRes = pPF->Save((wchar_t *)path, TRUE);
				pPF->Release();
			}
		}

		pLink->Release();
	}

	return hRes;
}