管理者として起動するショートカットを作る
EXEファイルを実行する際に自動的に「管理者として実行」するには、そのEXEのプロパティ>互換性>特権レベルを設定すればよく、
それをプログラムで設定するには、上記設定に対応するレジストリである
または
に"RUNASADMIN"の値を持つエントリを作ればよいのですが、そうして設定済のEXEファイルをショートカット(.LNK)から実行すると何故か「管理者として実行」されません。
何で?と思って調べたら実は、
「ショートカットファイルは独自に『管理者として実行』のフラグを内部に持っている」
というオチでした。
このショートカットファイルの「管理者として実行」フラグをプログラムで設定する方法を探してみたところ、
- Create a shortcut link which has "Run as administrator" option enabled on Vista
- How do I mark a shortcut file as requiring elevation?
にそのものズバリの答えがありましたが、両者の良いところをマージして、かつATLが無いVisual Studio Expressの環境でもビルドできるようにスマートポインタを_com_ptr_tで書き直してみました。
しかし「管理者として実行」(RUNASADMIN)なのに"SLDF_RUNAS_USER"フラグを立てるというのが何とも…
[stdafx.h]#pragma once #include "targetver.h" #include <stdio.h> #include <windows.h> #include <shlobj.h> #include <comdef.h> #include <locale.h> //typedef _com_ptr_t<_com_IIID<IPersistFile, &IID_IPersistFile>> IPersistFilePtr; typedef _com_ptr_t<_com_IIID<IShellLinkDataList, &IID_IShellLinkDataList>> IShellLinkDataListPtr;
[MarkShortcutRunAs.cpp]
#include "stdafx.h" bool SetLinkAttributes(LPCWSTR pszShortcut, DWORD flags) { IPersistFilePtr sppf; if (FAILED(sppf.CreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER))) return false; if (FAILED(sppf->Load(pszShortcut, STGM_READWRITE))) return false; IShellLinkDataListPtr spdl = sppf; if (!spdl) return false; DWORD dwFlags; if (FAILED(spdl->GetFlags(&dwFlags))) return false; if ((dwFlags & flags) == flags) return true; if (FAILED(spdl->SetFlags(dwFlags | flags))) return false; if (FAILED(sppf->Save(NULL, TRUE))) return false; return true; } int wmain(int argc, wchar_t *argv[]) { int rc = 1; // Only Vista or later if (LOBYTE(LOWORD(GetVersion())) < 6) return rc; _wsetlocale(LC_CTYPE, L""); if (argc > 1 && SUCCEEDED(CoInitialize(NULL))) { rc = 0; for (int i = 1; i < argc; ++i) { if (!SetLinkAttributes(argv[i], SLDF_RUNAS_USER)) { fwprintf(stderr, L"%ls: An error occurred.\n", argv[i]); rc = 1; } } if (0 == rc) wprintf(L"Succeeded.\n"); CoUninitialize(); } return rc; }