各ユーザーの「送る」メニュー(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> |
|