Jump to content

This is a ready-only archive of the InstallSite Forum. You cannot post any new content here. / Dies ist ein Archiv des InstallSite Forums. Hier können keine neuen Beiträge veröffentlicht werden.

Vista UAT Elevation

1 reply to this topic


  • Full Members
  • 1 posts

Posted 05 May 2007 - 20:33

In Vista, a custom action, by default, does not run under the elevated privilege token that the user launches a setup under. I don't see the point in this, and apparently neither does everybody at Microsoft, since most of their custom actions they add to a project have a bit set in the Type field of their custom actions that elevate the privilege. Visual Studio does not provide a way for the rest of us to set this (or if they did, I couldn't find it in the docs or Googling for it).

I wrote this application. It basically takes two parameters, the name of an MSI file and the name of the file containing a custom action (not the name of the entry point) included in the MSI file. The application will identify any custom action associated with the file and mark it with elevated privileges. I run it as a Post Build event in my VS installer projects to make sure what I want to run actually runs.

If you see any problems with the code, please be kind enough to let me know and/or post it up here. This is my first MSI project and I'm sure I've screwed the pooch somewhere...


This application sets the bit on the Type field for a custom action to run
under elevated privileges

Parameters:  [-w] MSIDatabaseFileName CustomActionFileName

If you put in the -w, the app will wait for a key before closing

Copyright 2007, Jason Terando
You can use this for any commercial or non-commercial purposes.  No warranty is
implied - use at your own risk.

#include "stdafx.h"
#include <windows.h>
#include <msi.h>
#include <msiquery.h>
#include <iostream>
#include <conio.h>

using namespace std;

MSIHANDLE hInstall = NULL, hView = NULL, hRecord = NULL;
bool Wait = false;
LPCWSTR DatabaseFileName = L"";
LPCWSTR CustomActionFileName = L"";

// Clean up when we are done
void Shutdown(int ExitCode) {
if(hRecord != NULL) {

if(hView != NULL) {

if(hInstall != NULL) {

if(Wait) {
 wprintf(L"Press any key to exit...");
 while(_kbhit() == 0) {


// Main routine
int _tmain(int argc, _TCHAR* argv[])
UINT result;
WCHAR FileID[128] = {0};

if(argc < 2) {
 wprintf(L"Usage [-w] MSIDatabaseFileName CustomActionFileName\n    -w = Wait for keypress at completion\n   Press any key...\n");
 while(_kbhit() == 0);

int i = 1;
if(wcsicmp(argv[1], L"-w") == 0) {
 Wait = true;
 i = 2;

DatabaseFileName = argv[i++];
CustomActionFileName = argv[i];

wprintf(L"Opening \"%s\"\n", DatabaseFileName);

result = MsiOpenDatabase(DatabaseFileName, MSIDBOPEN_DIRECT, & hInstall);
if(result != ERROR_SUCCESS) {
 fwprintf(stderr, L"Unable to open database: 0x%08X\n",
  DatabaseFileName, result);

// Find our custom action in the file table
wprintf(L"Searching file table for \"%s\"\n", CustomActionFileName);
result = MsiDatabaseOpenView(hInstall,
 L"SELECT `File`, `FileName` FROM `File`",
 & hView);
if(result != ERROR_SUCCESS) {
 fwprintf(stderr, L"Unable to open file table: 0x08X\n", result);

result = MsiViewExecute(hView, 0);
if(result != ERROR_SUCCESS) {
 fwprintf(stderr, L"Unable to view file table: 0x08X", result);

// Locate the file record matching our custom action
while((result = MsiViewFetch(hView, & hRecord)) == ERROR_SUCCESS) {
 MsiRecordGetString(hRecord, 2, FileName, & dw);
 if(dw > 0) {
  WCHAR * ptr = wcsstr(FileName, CustomActionFileName);
  if(ptr != NULL) {
   dw = _MAX_PATH;
   MsiRecordGetString(hRecord, 1, FileID, & dw);

// If we could not find the file, exit
if(FileID[0] == 0) {
 fwprintf(stderr, L"Unable to locate custom action in file table\n",

// Get the custom action table entries for our file
wprintf(L"Searching custom action table for matches\n");
WCHAR query[256];
swprintf_s(query, 256,
 L"SELECT Action, Type, Target FROM CustomAction WHERE Source='%s'",
result = MsiDatabaseOpenView(hInstall, query, & hView);
if(result != ERROR_SUCCESS) {
 fwprintf(stderr, L"Unable to open custom action table: 0x08X\n", result);

result = MsiViewExecute(hView, 0);
if(result != ERROR_SUCCESS) {
 fwprintf(stderr, L"Unable to view custom action table: 0x08X", result);

bool needCommit = false;
while((result = MsiViewFetch(hView, & hRecord)) == ERROR_SUCCESS) {
 WCHAR id[100];
 int type;
 WCHAR target[1024];

 DWORD dw = 100;
 MsiRecordGetString(hRecord, 1, id, & dw);
 type = MsiRecordGetInteger(hRecord, 2);
 dw = 1024;
 MsiRecordGetString(hRecord, 3, target, & dw);

 if((type & 0x800) == 0x800) {
  wprintf(L"%s is already privileged\n", target);
 } else {
  int newType = type | 0x800;
  wprintf(L"Updating type from %04X to %04X for %s\n",
   type, newType, target);
  needCommit = true;
  result = MsiRecordSetInteger(hRecord, 2, newType);
  MsiViewModify(hView, MSIMODIFY_UPDATE, hRecord);
  if(result != ERROR_SUCCESS) {
   fwprintf(stderr, L"Unable to update record: 0x08X", result);

// Commit changes if we made any
if(needCommit) {
 wprintf(L"Committing changes\n");
 result = MsiDatabaseCommit(hInstall);
 if(result != ERROR_SUCCESS) {
  fwprintf(stderr, L"Unable to commit database changes: 0x08X", result);


Attached Files

Edited by Carcass, 07 May 2007 - 16:34.


  • Full Members
  • 104 posts

Posted 16 May 2007 - 16:51

I didn't understand your implementation. It's right that VS 2005 configures the custom actions to run under in the impersonated custom action server in Windows Vista. The simplest method to run in the elevated custom action server is to change the type of the approbriate custom actions in the created package. To automate this, it is possible to use the PostBuildEvent. Copy the attached script into the project directory and insert the following statement in the PostBuildEvent property:

$(ProjectDir)\NoImpersonate.js "$(BuiltOuputPath)"

Hope this helps.


Attached Files

Edited by akerl, 16 May 2007 - 16:57.

Andreas Kerl

Inside Windows Installer 4.5
ISBN 3-86645-431-7