EternalWindows
独自インストール / ショートカットの作成

インストールしたアプリケーションへ素早くアクセスするために、 デスクトップやスターメニューにショートカットを作成できたら便利です。 次に示すCreateShortcutは、第1引数をリンク先としたショートカットを第2引数のフォルダに作成します。

void CreateShortcut(LPWSTR lpszSrcPath, LPWSTR lpszDestDir, LPWSTR lpszShortcutName)
{
	IShellLinkW  *pShellLink;
	IPersistFile *pPersistFile;
	WCHAR        szLinkPath[MAX_PATH];
	
	CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShellLink));
	pShellLink->SetPath(lpszSrcPath);
	pShellLink->QueryInterface(IID_PPV_ARGS(&pPersistFile));

	wsprintfW(szLinkPath, L"%s\\%s.lnk", lpszDestDir, lpszShortcutName);
	pPersistFile->Save(szLinkPath, TRUE);

	pPersistFile->Release();
	pShellLink->Release();
}

ショートカットの作成するには、まずIShellLinkを取得しなければなりません。 IShellLink::SetPathによってリンク先を決定したら、ファイルとして保存しても問題ありませんが、 この保存のためのメソッドはIShellLinkに含まれていません。 よって、保存用のインターフェースであるIPersistFileを照会し、 IPersistFile::Saveによってショートカットを保存します。 保存先となるフォルダはlpszDestDirであり、保存時のファイル名はlpszShortcutNameであるため、 これらを連結したものを保存先のパスとします。

デスクトップにショートカットを作成するにはどうするかというと、これは簡単です。 先のCreateShortcutの第2引数は保存先フォルダですから、ここにデスクトップのパスを指定すればよいことになります。

BOOL CreateDesktopShortcut(LPWSTR lpszMainFilePath)
{
	LPWSTR lpszPath;

	SHGetKnownFolderPath(FOLDERID_Desktop, 0, NULL, &lpszPath);

	CreateShortcut(lpszMainFilePath, lpszPath, g_szDisplayName);

	CoTaskMemFree(lpszPath);

	return TRUE;
}

SHGetKnownFolderPathにFOLDERID_Desktopを指定すれば、 現在のユーザーのデスクトップのパスを取得できます。 もし、他のユーザーのデスクトップにもショートカットが作成されてほしいならば、 FOLDERID_PublicDesktopを指定します。

スタートメニューにショートカットを作成する場合は、次の2つのフォルダのいずれかを対象にします。 次にフォルダを識別する値と関連するパスを示します。

FOLDERID_Programs
C:\Users\<username>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs

FOLDERID_CommonPrograms
C:\ProgramData\Microsoft\Windows\Start Menu\Programs

前者は特定のユーザーのみショートカットにアクセスできますが、 後者の場合は全てのユーザーがショートカットにアクセスできます。 後者を対象にするものとしてCreateStartMenuShortcutの内部を確認します。

BOOL CreateStartMenuShortcut(LPWSTR lpszMainFilePath, LPWSTR lpszUninstFilePath)
{
	LPWSTR lpszPath;
	WCHAR  szDestDir[MAX_PATH];

	SHGetKnownFolderPath(FOLDERID_CommonPrograms, 0, NULL, &lpszPath);
	wsprintfW(szDestDir, L"%s\\%s", lpszPath, g_szProductName);
	CreateDirectoryW(szDestDir, NULL);

	CreateShortcut(lpszMainFilePath, szDestDir, L"アプリケーションの起動");
	CreateShortcut(lpszUninstFilePath, szDestDir, L"アプリケーションのアンインストール");

	CoTaskMemFree(lpszPath);

	return TRUE;
}

スタートメニューにショートカットを作成する場合は、 インストールしたアプリケーション用のフォルダを作成し、 その中にショートカットを作成するのが一般的です。 よって、CreateDirectoryで明示的にフォルダを作成しています。 フォルダの中に作成するショートカットは、アプリケーション用とアンインストーラー用の2つがあれば便利ですから、 CreateShortcutを2回呼び出すようにしています。

ShellDDEについて

FOLDERID_Programsで識別されるフォルダにショートカットを作成したい場合は、 ShellDDEと呼ばれる機能を使用することもできます。 システムには、PROGMANという名前をサポートするDDEサーバーが存在しますが、 このサーバーに対してショートカットを作成するコマンドを送れば、 DDEサーバーがショートカットを作成するようになります。 次に、例を示します。

BOOL CreateStartMenuShortcut(LPWSTR lpszMainFilePath, LPWSTR lpszUninstFilePath)
{
	LPWSTR lpszGroupName = g_szProductName;
	WCHAR  szCommand[512];

	wsprintfW(szCommand, L"[CreateGroup(%s)]", lpszGroupName);
	DdeCommand(szCommand);

	wsprintfW(szCommand, L"[AddItem(%s,%s)]", lpszMainFilePath, L"アプリケーションの起動");
	DdeCommand(szCommand);

	wsprintfW(szCommand, L"[AddItem(%s,%s)]", lpszUninstFilePath, L"アプリケーションのアンインストール");
	DdeCommand(szCommand);

	return TRUE;
}

BOOL DdeCommand(LPWSTR lpszCommand)
{
	DWORD    dwInst = 0;
	UINT     uResult;
	HSZ      hszService, hszTopic;
	HDDEDATA hData;
	HCONV    hConv;
	BOOL     bResult;

	uResult = DdeInitializeW(&dwInst, NULL, APPCMD_CLIENTONLY, 0);
	if (uResult != DMLERR_NO_ERROR)
		return FALSE;

	hszService = DdeCreateStringHandleW(dwInst, L"PROGMAN", CP_WINUNICODE);
	hszTopic = DdeCreateStringHandleW(dwInst, L"PROGMAN", CP_WINUNICODE);
	hConv = DdeConnect(dwInst, hszService, hszTopic, NULL);
	DdeFreeStringHandle(dwInst, hszService);
	DdeFreeStringHandle(dwInst, hszTopic);
	if (hConv == NULL) {
		DdeUninitialize(dwInst);
		return FALSE;
	}

	hData = DdeClientTransaction((LPBYTE)lpszCommand, (lstrlenW(lpszCommand) + 1) * sizeof(WCHAR), hConv, NULL, CF_UNICODETEXT, XTYP_EXECUTE, 10000, NULL);
	if (hData == NULL)
		bResult = FALSE;
	else
		bResult = TRUE;

	DdeFreeDataHandle(hData);

	DdeDisconnect(hConv);
	DdeUninitialize(dwInst);

	return bResult;
}

PROGMANという名前をサポートするDDEサーバーには、[CreateGroup(%s)]というコマンドを送ることができます。 %sの部分には作成したいグループ名を指定しますが、これはフォルダ名のことであると考えて構いません。 実際にショートカットを作成するためには[AddItem(%s,%s)]というコマンドが必要であり、 最初の引数にはリンク先のパス、2番目の引数にはショートカットの名前を指定します。 コマンドをDDEサーバーに送るにはサーバーへDdeConnectで接続し、 DdeClientTransactionにXTYP_EXECUTEを指定します。 ちなみに、グループの削除は次のコードで可能です。

LPWSTR lpszGroupName = g_szProductName;
WCHAR  szCommand[512];

wsprintfW(szCommand, L"[DeleteGroup(%s)]", lpszGroupName);
DdeCommand(szCommand);

[DeleteGroup(%s)]というコマンドをサーバーに送ります。 これにより、スタートメニューからグループ名と同じ名前のフォルダが削除されます。



戻る