デスクトップ上にショートカットを作成する方法

戻る

1-1 ある日の会話

K子 「ちょっと教えてくれませんか?」
著者 「はい,何でしょう?」
K子 「Install Sheildの評価版でインストーラを作ろうとしているんですが, デスクトップにアプリケーションのショートカットを作るにはどうすればいいんで しょうか?いろいろ調べてみましたが,どうもスクリプトではできないようです.」
著者 「Install Sheildですか.... そういえばそんなことを考えてもみなかった. スクリプトでの「スタート」メニューにショートカットを追加するAPIは, Windows3.1やWindowsNT3.51でも利用しますし,ファイル名を「短いファイル名」 に変換して利用しなければならないところを見ると,DDEで行っている可能性が 高そうですね.となるとデスクトップにショートカットを作成する専用のAPIを サポートしている可能性は低いかも!?けど,Win32APIを使えばできると 思いますよ.」(もしサポートしているのでしたらすみません.)
K子「DLLを作って呼び出すわけですね.けど,デスクトップの ディレクトリは,Windows95でも複数のユーザが設定されているときとそうでないとき, WindowsNTの場合は,\winnt\profiles の下にユーザごとのディレクトリが作成 されます.それらを切り分けて処理を行うのは大変です.簡単な方法はないの かしら.」
著者 「確かにそうですね.けど,それらのディレクトリが作成された状態から規則を 推測して処理を作るのは危険ですよ.OSのバージョンアップで変更される可能性が ありますし.」
K子「じゃあどうすればいいんでしょう?」
著者「レジストリのどこかに設定されているか, シェルネームスペースで取得できるのではないかと思いますが....」

ということで,デスクトップ上にショートカットを作成する方法について考えてみましょう.

1-2 デスクトップの場所

エクスプローラでディレクトリ構造を表示すると,デスクトップはすべての ディレクトリのルートディレクトリとして表示されます.恐らく,「机」の上に 作業をするためのデバイスやファイルが置かれている状態をイメージしているの でしょう.しかし,実際のディレクトリは,Windowsディレクトリの中にあり, Windows95でシングルユーザで利用しているときには,

「C:\Windows\デスクトップ」

のように,Win32 API GetWindowsDirectory で取得できるディレクトリの直下に, 作成されます.「デスクトップ」は,日本語版のWindows95の場合で,US版の場合は 「desktop」になります.
しかし,「C:\Windows\デスクトップ」を直接参照すると正しく動作しないことが あります.

  • Windows95上でコントロールパネルの「ユーザ」を利用して複数のユーザーを設定している場合
  • 日本語版以外のWindows95で実行する場合
  • WindowsNTで実行する場合

    これらの環境でも正しく動作させるには,OSに「デスクトップ」ディレクトリの場所 を問い合わせる必要があります.

    1-3 「デスクトップ」の場所を知るには?

    「デスクトップ」ディレクトリを知るには,シェルネームスペース API SHGetSpecialFolderLocation や SHGetDesktopFolder を利用することで取得できますが,レジストリに設定された値を参照することで知ることでもっと簡単に知ることができます.レジストリを参照する場合,InstallShieldでインストーラを作成する必要があるときは,DLLを作成せずに「デスクトップ」ディレクトリを取得することができます.

    例1-1:Shell API で「デスクトップ」ディレクトリを取得する

    : : hResult = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY , &lpidlst); if(FAILED(hResult)){ return hResult; } hResult = SHGetDesktopFolder(&lpsf); if(FAILED(hResult)){ return hResult; } lpsf->GetDisplayNameOf(lpidlst, SHGDN_FORPARSING, &strret); +----------------------------------------------------------------+ | Windows95とWindowsNTでは,取得できる文字列の形式が異なるため, | | strret に設定された文字列のチェックは必ず行う必要があります. | +-----------+---------------------------------------------------+ ↓ switch(strret.uType){ case STRRET_WSTR: ←[ WindowsNTではこちらに設定される ] WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, strret.pOleStr, -1, lpszPath, dwSize, NULL, NULL); break; case STRRET_CSTR: ←[ Windows95ではこちらに設定される ] lstrcpy(lpszPath, strret.cStr); break; case STRRET_OFFSET: lpszIn = ((LPSTR)lpidlst) + strret.uOffset; lstrcpy(lpszPath, lpszIn); break; } lpsf->Release(); : :


    1-4 「デスクトップ」ディレクトリの設定場所

    「デスクトップ」の位置は,デスクトップを開いているユーザーごとに異なります ので,HKEY_CURRENT_USERに設定されます. ここにはデスクトップ以外にも「スタート」ボタンを押したときに表示されるメニュー の格納ディレクトリや,「送る」で指定できるアプリケーションのショートカットを 格納するディレクトリなどを知ることができます.なお,このレジストリキーは, Windows95, WindowsNTの両方で利用できます.

    <デスクトップのディレクトリが格納されているレジストリキー>
    HKEY_CUURENT_USER
    "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
    REG_SZ Desktop ... デスクトップのディレクトリ


    1-5 ショートカットを作成する

    「デスクトップ」ディレクトリの位置を知ることができましたので,ショートカット を作成する方法に移ります.
    ショートカットを作成する機能は,COMインタフェースで実装してあります. ショートカットを作成するためのオブジェクトである IShellLink を利用するには, OLEのインターフェースを利用するときと同様の手順で,インターフェースへの ポインタを取得する必要があります.

    1-6 コンポーネントオブジェクトAPI

    そもそも コンポーネントオブジェクト関連のAPIは,Windows3.1でのOLE2用APIと して公開されましたが,最近は COM(Component Object Model)のアプリケーションを 作成するためのAPIとして紹介されることが多いようです.OLEのインターフェースは 大変豊富で複雑ですが,インターフェースを利用するために必要なAPIは,どれほど 多くありませんし,実際によく利用するAPIは限られているのではないかと思われます. これらのAPIは「カスタム集成関数」と呼ばれ,関数名は "Co"で始まる名前を 持ちます.ここでは,便宜上 CO API と呼ぶことにします.
    最近では,分散コンピューティングが脚光をあびつつあります.COMをネットワーク 上の他のコンピュータに対しても利用可能にしたDCOMがあります.この機能を 利用するときには,CO API CoCreateInstance の代わりに CO API CoCreateInstanceEx を利用してインスタンスを作成する必要があります.

    1-7 IShellLink インターフェース

    IShellLink インタフェースは,ショートカットを作成したり,情報の設定や更新 を行うために利用します.ショートカットに関するディスクアクセスは, IPersidentFile インタフェースを利用して行います.
    このため,ショートカットをディスクに書き込むときは,QueryInterface で IPersidentFileへのポインタを取得する必要があります.

    表1-1:よく利用するCO API
    HRESULT CoInitialize(lpaloc)
    コンポーネントオブジェクトモデルライブラリを利用するための初期化

    引数
    LPMALLOC lpalloc .... ライブラリや他のタスクが利用するメモリアローケータへのポインタ.
    標準のアローケータを利用するときはNULLを指定する.
    戻り値
    正常終了
     S_OK, S_FALSE
    異常終了
     E_OUTOFMEMORY ... メモリ不足
     E_INVALIDARG ... 引数不正
     E_UNEXPECTED ... 予期しないエラー
    HRESULT CoUninitialize()
    コンポーネントオブジェクトモデルライブラリを利用を停止する

    引数
     なし
    戻り値
     なし
    HRESULT CoCreateInstance(clsid, lpunk, dwClsCtx riid, lplpObj)
    指定されたクラスのインスタンスを生成します

    引数
    REFCLSID clsid ... 作成すべきオブジェクトのCLSID
    IUnknown *lpunk ... IUnknownインタフェース
    DWORD dwClsCtx ... CLSCTX列挙型の値
    enum tagCLSCTX{
     CLSCTX_INPROC_SERVER = 0x1,
     CLSCTX_INPROC_HANDLER = 0x2,
     CLSCTX_LOCAL_SERVER = 0x4,
     CLSCTX_INPROC_SERVER16 = 0x8,
     CLSCTX_REMOTE_SERVER = 0x10,
     CLSCTX_INPROC_HANDLER16 = 0x20,
     CLSCTX_INPROC_SERVERX86 = 0x40,
     CLSCTX_INPROC_HANDLERX86 = 0x80
    } CLSCTX;
    REFIID riid ... オブジェクトとの通信に使うインタフェース
    LPVOID *lplpObj ... インタフェースへのポインタを格納する

    戻り値
    正常終了
     S_OK
    異常終了
     REGDB_E_CLASSNOTREG ... レジストリに登録がない
     E_OUTOFMEMORY ... メモリ不足
     E_INVALIDARG ... 引数不正
     E_UNEXPECTED ... 予期しないエラー
     CLASS_E_NOAGGREGATION ... 作成できなかった

    表:1-2 IShellLink インターフェース
    GetPathファイルパスを取得する
    SetPathファイルパスを設定する
    GetIDListITEMIDLISTを取得する
    SetIDListITEMIDLISTを設定する
    (コントロールパネルなどファイル以外の場所にショートカットを作成するために 利用する)
    GetDescription記述を取得する
    SetDescription記述を設定する
    GetWorkingDirectoryワークディレクトリを取得する
    SetWorkingDirectoryワークディレクトリを設定する
    GetArguments引数を取得する
    SetArguments引数を設定する
    GetHotkeyホットキーを取得する
    SetHotkeyホットキーを設定する
    GetShowCmdShowコマンドを取得する
    SetShowCmdShowコマンドを設定する
    (Win32 API ShowWindowで設定する値)
    GetIconLocationアイコンを取得する
    SetIconLocationアイコンを設定する
    Resolveショートカットを解決する

    1-8 処理手順

    CO API CoInitialize, CO API CoUninitializeは,プロセス内で一度だけ実行します. これらのAPIを実行しておけば,IShellLink以外のインタフェースを利用することも 可能になります.
    MFCから利用する場合は,"SHLOBJ.H"を単純にインクルードすればよいのですが, 利用しない場合には,"INITGUID.H" を先にインクルードしなければリンク時に エラーが発生します.また,ライブラリは "OLE32.LIB", "UUID.LIB" をリンクします.
    図1-1:ショートカットを作成する手順
    CoInitializeでコンポーネントオブジェクトを利用するための初期化を行う ↓ CoCreateInstance で,IShellLinkインターフェースへのポインタを得る ↓ IShellLink::QueryInterfaceでIPersistFileインタフェースへのポインタを得る ↓ IShellLink::SetPath ... プログラムのパス IShellLink::SetDescription ... 記述 IShellLink::SetArguments ... 引数 IShellLink::SetWorkingDirectory ... ワークディレクトリ ↓ IPersistFile::Save でショートカットを書き込む ↓ IPersistFile::Release, IShellLink::Release でインタフェースを解放する ↓ CoUninitializeでコンポーネントオブジェクトの利用を終了する


    1-9 プログラムについて

    アプリケーションのショートカットを「デスクトップ」に作成するアプリケーション です.
    SC.C の#if で,「デスクトップ」ディレクトリ取得関数を切り分けています. サンプルソースでは,レジストリから取得するようになっていますので,ShellAPI版 を試したいときには,"#if 1" を "#if 0" に修正してビルドしてください.

    ●ソースファイル SC.C(メイン)
    SHORTCUT.CPP(ショートカット作成処理)
    SHORTCUT.H(ショートカット作成処理ヘッダー)
    MAKEFILE(メイクファイル)

    SHORTCUT.CPPには,
    LRESULT GetDesktopPath(LPSTR, DWORD); ... デスクトップへのパスを取得する(レジストリ版)
    LRESULT GetDesktopPathSH(LPSTR, DWORD); ... デスクトップへのパスを取得する(ShellAPI版)
    HRESULT CreateShortCut(LPCSTR, LPCSTR, LPCSTR, LPCSTR, LPCSTR); ... ショートカットを作成する
    があります.
    これらの関数を利用するには,利用するアプリケーションであらかじめ, CoInitialize を実行しておく必要があります.

    ●実行例
    SC ファイル名(フルパス)

    >SC c:\windows\regedit.exe
    を実行すると,デスクトップ上に「REGEDIT へのショートカット.LNK」が作成され, 以下の情報が設定されます.

    プログラムのパス : "c:\windows\regedit.exe"
    記述 : "REGEDIT へのショートカット"
    引数 : "???"
    ワークディレクトリ : SC.EXEを実行したディレクトリ

    なお,SC.EXEに指定されたファイル名が存在しない場合でも, ショートカットは作成されます.