Answered by:
API to set "Run as administrator" flag on a shortcut file?

Question
-
I need my installer to create some shortcuts with "Run as administrator" checked in the shortcuts' Advanced Properties.
How is this flag stored in the file system? Some kind of file attribute? What API could I use to access it?
Thanks for any advice / suggestions.
Thursday, April 5, 2007 6:39 PM
Answers
-
David,
Thanks for the tips. In addition to Save, I needed to do SaveCompleted. This code worked:
Code Snippet#include "stdafx.h" // includes <tchar.h>
#include <windows.h>
#include <shobjidl.h> // ShellLink
#include <shlobj.h> // IShellLinkDataList (build on Vista use shobjidl.h)
#include <objbase.h> // CoInitialize, CoInitializeEx, CoUninitialize
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT result;
WCHAR wbuf[MAX_PATH];
IShellLink* link;
IPersistFile* file;
char szFile[MAX_PATH];
char szProgramMenuFolder[MAX_PATH];
// SHOULD use CoInitializeEx, but compiler can't find it.
result = CoInitialize(NULL); // For Ex: 2nd param: COINIT_APARTMENTTHREADED
// Create IShellLink object
result = CoCreateInstance(CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(void**)&link);
if (result != S_OK) {
CoUninitialize();
return -1;
}
// Retreive the IPersistFile
result = link->QueryInterface(IID_IPersistFile, (void**)&file);
if (result != S_OK) {
link->Release();
CoUninitialize();
return -2;
}
// SHOULD get from registry.
strcpy(szProgramMenuFolder, "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\");
// DEBUG
strcpy(szFile, szProgramMenuFolder);
// SHOULD use your folder and shortcut name.
strcat(szFile, "Program Shortcut Folder\\Shortcut.lnk");
// Convert the filename
MultiByteToWideChar(CP_ACP, 0, szFile, -1, wbuf, sizeof(wbuf)-1);
// Load the link data from the file
result = file->Load(wbuf, STGM_READ);
if (result != S_OK) {
file->Release();
link->Release();
CoUninitialize();
return -3;
}
// Look for IShellLinkDataList interface
IShellLinkDataList* pdl;
result = link->QueryInterface(IID_IShellLinkDataList, (void**)&pdl);
if (result != S_OK) {
file->Release();
link->Release();
CoUninitialize();
return -4; // Where did IShellLinkDataList go?
}
DWORD dwFlags = 0;
result = pdl->GetFlags(&dwFlags);
if (result != S_OK) {
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return -5;
}
// Only set SLDF_RUNAS_USER if it's not set, otherwise
// SetFlags returns an error.
if ((SLDF_RUNAS_USER & dwFlags) != SLDF_RUNAS_USER) {
result = pdl->SetFlags(SLDF_RUNAS_USER | dwFlags);
if (result != S_OK) {
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return -6;
}
}
else {
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return 0;
}
result = file->Save(NULL, true);
if (result != S_OK) {
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return -8;
}
result = file->SaveCompleted(NULL);
if (result != S_OK) {
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return -9;
}
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return ERROR_SUCCESS;
}Thursday, April 26, 2007 5:15 PM
All replies
-
You should mark the target executables as requiring Administrator rights by embedding a Vista Manifest rather than changing the setting in the shortcut file.Thursday, April 5, 2007 7:50 PM
-
I already embedded a manifest in my application but it does not serve all my needs.
It is a console application and I need the calling command prompt to be running elevated
before the application.
If I can check the "Run as administrator" box on shortcuts then it must be a supported feature.
All I need is a programmatic way to do it in my installer so that our customers are not required
to check that flag manually when they install our products.
Thursday, April 5, 2007 9:56 PM -
I'm pretty sure the shortcut flags are for application compatibility only and thus not really exposed programmatically. How about creating a stub executable with an elevation manifest that just launches cmd.exe and pointing the shortcut to that?Friday, April 6, 2007 11:40 AM
-
If you play around with the run as administrator setting for both the current user and all users on an exe's properties you will see the following keys being set:
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
Note that not all shortcuts point directly at an exe, depending upon whether an application is installed as an advertised application.
Setting a shortcut to run an app as admin, when possible (i.e. the shortcut actually points at an exe) is the same as going into the apps exe properties box and selecting run as admin, thus if it is cmd.exe then you would be setting cmd.exe to run as admin no matter how it were started, so you would need to possibly be resetting it back after it were started to avoid making it run as admin thereafter.Friday, April 6, 2007 2:54 PM -
> Setting a shortcut to run an app as admin, when possible (i.e. the shortcut actually points at an exe) is the same as going into the apps exe properties box and selecting run as admin, thus if it is cmd.exe then you would be setting cmd.exe to run as admin no matter how it were started, so you would need to possibly be resetting it back after it were started to avoid making it run as admin thereafter.
This is incorrect.See MSDN for:
IShellLinkDataList::SetFlagsFriday, April 6, 2007 6:26 PM -
David,
I tried IShellLinkDataList:: SetFlags(SLDF_RUNAS_USER), and though it returns S_OK, the shortcut is not set to run as admin.
How should that function be used?Wednesday, April 25, 2007 6:51 PM -
first off, you want to getFlags and then OR in SLDF_RUNAS_USER, I'm guessing?
second, did you save the shortcut with the IPersistFile interface?
Wednesday, April 25, 2007 7:54 PM -
David,
I didn't do GetFlags, and OR in SLDF_RUNAS_USER. You're guessing that will work? How do I set the shortcut to Run as administrator? The documentation for SLDF_RUNAS_USER just says, "Run this link as a different user." How do I set the different user to be Administrator?
I didn't save the shortcut with the IPersistFile interface. I'll try that.Wednesday, April 25, 2007 8:28 PM -
David,
Thanks for the tips. In addition to Save, I needed to do SaveCompleted. This code worked:
Code Snippet#include "stdafx.h" // includes <tchar.h>
#include <windows.h>
#include <shobjidl.h> // ShellLink
#include <shlobj.h> // IShellLinkDataList (build on Vista use shobjidl.h)
#include <objbase.h> // CoInitialize, CoInitializeEx, CoUninitialize
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT result;
WCHAR wbuf[MAX_PATH];
IShellLink* link;
IPersistFile* file;
char szFile[MAX_PATH];
char szProgramMenuFolder[MAX_PATH];
// SHOULD use CoInitializeEx, but compiler can't find it.
result = CoInitialize(NULL); // For Ex: 2nd param: COINIT_APARTMENTTHREADED
// Create IShellLink object
result = CoCreateInstance(CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(void**)&link);
if (result != S_OK) {
CoUninitialize();
return -1;
}
// Retreive the IPersistFile
result = link->QueryInterface(IID_IPersistFile, (void**)&file);
if (result != S_OK) {
link->Release();
CoUninitialize();
return -2;
}
// SHOULD get from registry.
strcpy(szProgramMenuFolder, "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\");
// DEBUG
strcpy(szFile, szProgramMenuFolder);
// SHOULD use your folder and shortcut name.
strcat(szFile, "Program Shortcut Folder\\Shortcut.lnk");
// Convert the filename
MultiByteToWideChar(CP_ACP, 0, szFile, -1, wbuf, sizeof(wbuf)-1);
// Load the link data from the file
result = file->Load(wbuf, STGM_READ);
if (result != S_OK) {
file->Release();
link->Release();
CoUninitialize();
return -3;
}
// Look for IShellLinkDataList interface
IShellLinkDataList* pdl;
result = link->QueryInterface(IID_IShellLinkDataList, (void**)&pdl);
if (result != S_OK) {
file->Release();
link->Release();
CoUninitialize();
return -4; // Where did IShellLinkDataList go?
}
DWORD dwFlags = 0;
result = pdl->GetFlags(&dwFlags);
if (result != S_OK) {
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return -5;
}
// Only set SLDF_RUNAS_USER if it's not set, otherwise
// SetFlags returns an error.
if ((SLDF_RUNAS_USER & dwFlags) != SLDF_RUNAS_USER) {
result = pdl->SetFlags(SLDF_RUNAS_USER | dwFlags);
if (result != S_OK) {
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return -6;
}
}
else {
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return 0;
}
result = file->Save(NULL, true);
if (result != S_OK) {
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return -8;
}
result = file->SaveCompleted(NULL);
if (result != S_OK) {
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return -9;
}
pdl->Release();
file->Release();
link->Release();
CoUninitialize();
return ERROR_SUCCESS;
}Thursday, April 26, 2007 5:15 PM -
This code worked great for me as well.
Charles, David, many thanks to you both.
Jean-Philippe
Monday, May 21, 2007 7:36 PM -
how to get szProgramMenuFolder path? from which registry value?
Monday, January 21, 2008 9:24 AM -
Monday, January 21, 2008 7:12 PM
-
Hi Charles / David / jpm,
Can someone tell me how to use this code to integrate the same with my install script?
I am using Installshield 2008 to build the .msi though new to windows and installer world
.
we are able to install app on XP and VISTA (UAC enabled/disabled) both but not able to launch when we double click the shortcut desktop/system tray icon neither as an admin nor as a standard user when UAC is enabled.
We are using executables built by VS 2005 and have never used or embedded any manifest for creating this .msi file.
Even my script is UI based and i dont see any script function when I open the same in Installshield
It would be great if you can help me to resolve this issue.
many thanks.
Tuesday, June 24, 2008 9:31 AM