Programming Windows Maniacs - プログラミング ウィンドウズ マニアックス ■ ご利用に際して ■ 更新履歴 ■ お問い合わせ ■ このホームページについて  
ホーム >> シェル >> 各ユーザーの「送る」メニュー(sendto)にショートカットを作成するには

各ユーザーの「送る」メニュー(sendto)にショートカットを作成するには

  ファイルを右クリックしたときに表示される「送る」メニューに表示されるようにするためには、各ユーザーのsendtoというフォルダにショートカットを配置する必要があります。
  しかし、このフォルダは各ユーザーごとには持っていますが、共通(Common)のフォルダがありません。
  つまり、SHGetSpecialFolderPath () APIやSHGetSpecialFolderLocation () APIで取得できるのは、自分自身のアカウント用のsendtoフォルダのみになってしまうのです。

  すべてのSendtoを列挙するようなAPIがないので、対処方法は、かなり地味です。
  手順は下記の通りです。
※ Windows 2000/XP/Vista 用です。9xは特に権限の問題もないので、下記手順でパスさえ変えればすぐにできます。

  (1) Windows 2000/XP用では、Documents and Settingsのフォルダパスを取得し、Windows Vista用ではUsersのフォルダパスを取得します。
  (2) Windowsアカウントを列挙します。
  (3) このプログラムを実行した後でも、新規でWindowsアカウントを作成してもsendtoへ反映されるように、新規Windowsアカウント用のアカウント名も(2)のリストに追加します。Windows 2000/XPでは、"Default User"。Vistaでは、"Default"をリストに追加します。
  (4) Sendto へショートカットを作成します。
    Windows 2000 : C:\Documents and Settings\[Windowsアカウント名]\SendTo
    Windows XP : C:\Documents and Settings\[Windowsアカウント名]\SendTo
    Windows Vista : C:\Users\[Windowsアカウント名]\SendTo

  以下、サンプルのソースコードになります。わたしはクラス化していますが、ここではわかりやすく記載します。

※ Install Shieldもsendtoのショートカットは自動作成・削除してくれないので、LaunchAppAndWait ()で、上記のようなプログラムをInstall Shieldから呼ぶことによりsendtoショートカットの作成・削除をすることになります。
※ Sendtoにショートカットを作成する際、Vistaの場合は、管理者権限への権限上昇が必要です。
※ 2000/XPではAdministratorsグループに所属している必要があります。

 

■■■ shortcut プロジェクト
■ main.cpp
//  netapi32.lib が必要です


#pragma warning ( disable : 4786 )

#include <windows.h>
#include <shlobj.h>

#include <lmaccess.h>
#include <lm.h>
#include <lmapibuf.h>
#include <Sddl.h>

#include <list>


// ショートカット作成
BOOL CreateShortcut ( const char *pszTargetPath,
    const char *pszArguments,
    const char *pszWorkPath,
    int nCmdShow,
    const char *pszShortcutPath )
{
    IShellLink *psl;
    IPersistFile *ppf;
    enum
    {
        MY_MAX_PATH = 65536
    };
    WCHAR wcLink[ MY_MAX_PATH ];

    // IShellLinkインターフェースの作成
    if ( FAILED ( CoCreateInstance ( CLSID_ShellLink, NULL,CLSCTX_INPROC_SERVER, IID_IShellLink, ( void ** ) &psl ) ) )
    {
        return FALSE;
    }

    // 設定
    psl->SetPath ( pszTargetPath );
    psl->SetArguments ( pszArguments );
    psl->SetWorkingDirectory ( pszWorkPath );
    psl->SetShowCmd ( nCmdShow );

    // IPersistFileインターフェースの作成
    if ( FAILED ( psl->QueryInterface ( IID_IPersistFile, ( void ** ) &ppf ) ) )
    {
        psl->Release ();
        return FALSE;
    }
    
    // lpszLinkをWCHAR型に変換
    MultiByteToWideChar ( CP_ACP, 0, pszShortcutPath, -1, wcLink, MY_MAX_PATH );
    if ( FAILED ( ppf->Save ( wcLink, TRUE ) ) )
    {
        ppf->Release ();
        return FALSE;
    }

    // 解放
    ppf->Release ();
    psl->Release ();

    return TRUE;
}


// ユーザ名を列挙
BOOL GetUserNames ( std::list < std::basic_string < char > > &rlststrUser )
{
    rlststrUser.clear ();

    LPBYTE pBuffer;
    DWORD  EntriesRead = 0;
    DWORD  TotalEntries = 0;
    DWORD  ResumeHandle = 0;
    DWORD  i;

    PSID   pSid;
    DWORD  cbSid;
    PWSTR  pReferencedDomainName;
    DWORD  cbReferencedDomainName;
    SID_NAME_USE eUse;

    NET_API_STATUS netApiStatus;
    netApiStatus = NetUserEnum ( NULL,
        0,
        0,
        &pBuffer,
        MAX_PREFERRED_LENGTH,
        &EntriesRead,
        &TotalEntries,
        &ResumeHandle );
    if ( ERROR_ACCESS_DENIED == netApiStatus || NERR_InvalidComputer == netApiStatus )
    {
        return FALSE;
    }

    if ( ERROR_MORE_DATA == netApiStatus )
    {
        NetApiBufferFree ( pBuffer );
        return FALSE;
    }

    USER_INFO_0 *pUser = ( USER_INFO_0 * ) pBuffer;

    for ( i = 0; i < EntriesRead; i++ )
    {
        enum
        {
            MY_MAX_BUFFER = 1024
        };
 
        pSid = ( PSID ) malloc ( MY_MAX_BUFFER );
        cbSid = MY_MAX_BUFFER;

        pReferencedDomainName = ( PWSTR ) malloc ( MY_MAX_BUFFER * sizeof ( WCHAR ) );
        cbReferencedDomainName = MY_MAX_BUFFER;

        //------------------------------
        // アカウントを取得
        if ( LookupAccountNameW ( NULL,
                           pUser[i].usri0_name,
                           pSid,
                           &cbSid,
                           pReferencedDomainName,
                           &cbReferencedDomainName,
                           &eUse ) )
        {
            // 取得
            char szUser[ MY_MAX_BUFFER ];
            wsprintf ( szUser, "%ls", pUser[i].usri0_name );
            rlststrUser.push_back ( szUser );

        }

        free ( pSid );
        free ( pReferencedDomainName );

    }

    NetApiBufferFree ( pBuffer );

    OSVERSIONINFO ovi;
    DWORD dwOSVersionInfoSize = sizeof ( OSVERSIONINFO );
    memset ( &ovi, 0, dwOSVersionInfoSize );
    ovi.dwOSVersionInfoSize = dwOSVersionInfoSize; 
    GetVersionEx ( &ovi );

    // 2000/XPのとき
    if ( 5 == ovi.dwMajorVersion )
    {
        rlststrUser.push_back ( "Default User" );
    }
    else // それ以外
    {
        rlststrUser.push_back ( "Default" );
    }

    return TRUE;
}

// 現在のユーザの SendTo へのパスを取得
BOOL GetCurrentUserSendToPath ( std::basic_string < char > &rstrCurrentUserSendTo )
{
    enum
    {
        MY_MAX_PATH = 2048
    };
    char szPath[ MY_MAX_PATH ];
    if ( !SHGetSpecialFolderPath ( NULL, szPath, CSIDL_SENDTO, TRUE ) )
    {
        return FALSE;
    }
    
    rstrCurrentUserSendTo = szPath;
    return TRUE;
}

// sendto ショートカット作成
BOOL CreateSendToShortcuts ( const char *pszTargetPath,
    const char *pszArguments,
    const char *pszWorkPath,
    int nCmdShow,
    const char *pszShortcutFileName )
{
// 現在のユーザの SendTo へのパスを取得
    std::basic_string < char > strCurrentUserSendToPath;
    if ( !GetCurrentUserSendToPath ( strCurrentUserSendToPath ) )
    {
        return FALSE;
    }

// ユーザ名列挙
    std::list < std::basic_string < char > > lststrUser;
    if ( !GetUserNames ( lststrUser ) )
    {
        return FALSE;
    }

// SendToディレクトリパスのうち、ユーザ名以外の場所の文字列を取得 (C:\\Users\\ ... or C:\\Documents and Settings\\ ... )
    // "表"などのShift JIS 誤変換対処!
    char *pszPtr = ( char * ) strCurrentUserSendToPath.c_str ();
    char *pKept = NULL;
    char *pKept2 = NULL;
    UINT nBackslashCount = 0;
    while ( *pszPtr != '\0' )
    {
        // 2バイト文字の先頭はスキップ
        if ( 0 == IsDBCSLeadByte ( *pszPtr ) )
        {
            //[\],[/],[:]を見つけたら現在地+1のポインタを保存
            if( (*pszPtr == '\\') || (*pszPtr == '/'))
            {
                nBackslashCount++;

                if ( 2 == nBackslashCount )
                {
                    pKept = pszPtr + 1;
                }

                if ( 3 == nBackslashCount )
                {
                    pKept2 = pszPtr + 1;
                    break;
                }
            }

        }
        //次の文字へ
        pszPtr = CharNext ( pszPtr );
    }

    // 3番目がそもそもないときは失敗
    if ( 3 != nBackslashCount )
    {
        return FALSE;
    }

    // 2番目までを取得 ( C:\\Users\\ or C:\\Documents and Settings\\ )
    std::basic_string < char > strHead;
    strHead = strCurrentUserSendToPath.substr ( 0, strCurrentUserSendToPath.size () - lstrlen ( pKept ) );

    // 3番目以降を取得
    std::basic_string < char > strFoot;
    strFoot = strCurrentUserSendToPath.substr ( strCurrentUserSendToPath.size () - lstrlen ( pKept2 ) - 1 );

// パス作成
    std::list < std::basic_string < char > >::iterator pIt;
    pIt = lststrUser.begin ();

    while ( pIt != lststrUser.end () )
    {
        std::basic_string < char > strSendToPath;
        strSendToPath = strHead;
        strSendToPath += ( *pIt );
        strSendToPath += strFoot;

        std::basic_string < char > strShortcutPath;
        strShortcutPath = strSendToPath;
        strShortcutPath += "\\";
        strShortcutPath += pszShortcutFileName;

        // ショートカット作成処理 ( Default User には作成しない。また、失敗しても無視する(ユーザが作成されていない可能性もあるため) )
        BOOL bNotUsed = CreateShortcut ( pszTargetPath,
            pszArguments,
            pszWorkPath,
            nCmdShow,
            strShortcutPath.c_str () );

        pIt++;
    }

    return TRUE;
}

// 削除
BOOL DeleteSendToShortcuts ( const char *pszShortcutFileName )
{
// 現在のユーザの SendTo へのパスを取得
    std::basic_string < char > strCurrentUserSendToPath;
    if ( !GetCurrentUserSendToPath ( strCurrentUserSendToPath ) )
    {
        return FALSE;
    }

// ユーザ名列挙
    std::list < std::basic_string < char > > lststrUser;
    if ( !GetUserNames ( lststrUser ) )
    {
        return FALSE;
    }

// SendToディレクトリパスのうち、ユーザ名以外の場所の文字列を取得 (C:\\Users\\ ... or C:\\Documents and Settings\\ ... )
    // "表"などのShift JIS 誤変換対処!
    char *pszPtr = ( char * ) strCurrentUserSendToPath.c_str ();
    char *pKept = NULL;
    char *pKept2 = NULL;
    UINT nBackslashCount = 0;
    while ( *pszPtr != '\0' )
    {
        // 2バイト文字の先頭はスキップ
        if ( 0 == IsDBCSLeadByte ( *pszPtr ) )
        {
            //[\],[/],[:]を見つけたら現在地+1のポインタを保存
            if( (*pszPtr == '\\') || (*pszPtr == '/'))
            {
                nBackslashCount++;

                if ( 2 == nBackslashCount )
                {
                    pKept = pszPtr + 1;
                }

                if ( 3 == nBackslashCount )
                {
                    pKept2 = pszPtr + 1;
                    break;
                }
            }

        }
        //次の文字へ
        pszPtr = CharNext ( pszPtr );
    }

    // 3番目がそもそもないときは失敗
    if ( 3 != nBackslashCount )
    {
        return FALSE;
    }

    // 2番目までを取得 ( C:\\Users\\ or C:\\Documents and Settings\\ )
    std::basic_string < char > strHead;
    strHead = strCurrentUserSendToPath.substr ( 0, strCurrentUserSendToPath.size () - lstrlen ( pKept ) );

    // 3番目以降を取得
    std::basic_string < char > strFoot;
    strFoot = strCurrentUserSendToPath.substr ( strCurrentUserSendToPath.size () - lstrlen ( pKept2 ) - 1 );

// パス作成
    std::list < std::basic_string < char > >::iterator pIt;
    pIt = lststrUser.begin ();

    while ( pIt != lststrUser.end () )
    {
        std::basic_string < char > strSendToPath;
        strSendToPath = strHead;
        strSendToPath += ( *pIt );
        strSendToPath += strFoot;

        std::basic_string < char > strShortcutPath;
        strShortcutPath = strSendToPath;
        strShortcutPath += "\\";
        strShortcutPath += pszShortcutFileName;

        // ショートカット削除処理
        SetFileAttributes ( strShortcutPath.c_str (), FILE_ATTRIBUTE_NORMAL );
        BOOL bNotUsed = DeleteFile ( strShortcutPath.c_str () );

        pIt++;
    }

    return TRUE;
}



// エントリポイント
int WINAPI WinMain ( HINSTANCE,
    HINSTANCE,
    char *,
    int )
{
// COM 初期化
    CoInitialize ( NULL );

    int nResponse;

// Sendto ショートカット 作成
    nResponse = MessageBox ( NULL, "ショートカットを作成しますか?", "確認", MB_YESNO );
    if ( IDYES == nResponse )
    {
        CreateSendToShortcuts ( "C:\\sample.exe", "", "C:\\", SW_SHOW, "サンプル.lnk" );
        MessageBox ( NULL, "C:\\sample.exeへのショートカット「サンプル」を作成しました", "確認", MB_OK );
    }
    else
    {
        // 何もしない
    }


// Sendto ショートカット 削除
    nResponse = MessageBox ( NULL, "ショートカットを削除しますか?", "確認", MB_YESNO );
    if ( IDYES == nResponse )
    {
        DeleteSendToShortcuts ( "サンプル.lnk" );
        MessageBox ( NULL, "C:\\sample.exeへのショートカット「サンプル」を作成しました", "確認", MB_OK );
    }
    else
    {
        // 何もしない
    }

// COM 解放
    CoUninitialize ();

    return 0;
}
■resrc.rc
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "shortcut.exe.manifest"
■mnfst.exe.manifest
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity version="1.0.0.0"
       processorArchitecture="X86"
       name="shortcut.exe"
       type="win32"/>

    <description>Privilege's elevation for sendto shortcuts </description>
    <!-- Identify the application security requirements. -->
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel
                  level="requireAdministrator"
                  uiAccess="false"/>
            </requestedPrivileges>
        </security>
    </trustInfo>

<dependency>
    <dependentAssembly>
        <assemblyIdentity
            type="win32"
            name="Microsoft.Windows.Common-Controls"
            version="6.0.0.0"
            processorArchitecture="X86"
            publicKeyToken="6595b64144ccf1df"
            language="*"
        />
    </dependentAssembly>
</dependency>
</assembly>
  ■ ご利用に際して ■ 更新履歴 ■ お問い合わせ ■ このホームページについて Copyright © 2014 A.Morita