Add a manifest to control your application Vista UAC behavior

Try this on Windows XP or Vista (I don’t remember if manifests are allowed on Win2000: can someone confirm please? Thanks)

 

Start Notepad, then choose File->Open and navigate to c:\windows\system32\notepad.exe and click Open.

Hit Ctrl-F to find the text “assembly”

You’ve now found the embedded XML manifest file.

 

Try the same with VFP9.EXE, then an EXE that you have built with VFP9

 

On XP, this manifest can specify additional dependencies. For VFP9, it indicates which version of Windows Common Controls to use. For an EXE that VFP built the manifest is the same as VFPs.

 

On Vista, this manifest can further specify security requirements for an application.

For example, on Vista, applications are not allowed to write into “Program Files” or Windows directories. Similarly with the registry. Some applications will attempt to write these.

If there is no requestedExecutionLevel, then the registry and file virtualization will be turned on. The program “thinks” it’s writing to “Program Files”, but it’s really writing to C:\Users\<username>\AppData\Local\VirtualStore\Program Files. The registry redirects HKEY_LOCAL_MACHINE\Software to HKEY_CURRENT_USER\Software\Classes\VirtualStore\MACHINE\SOFTWARE\<Application Registry Keys>

 

You can further control Vista UAC settings by running secpol.msc and navigating to Local Security Settings->Local Policies->Security Options

 

Try this on Vista: Start->Run->Cmd. Try to write a file to Program Files or Windows directories-> “Access Denied”

 

The MT.EXE tool that ships with Visual Studio or the Vista SDK can allow you to embed a manifest as a Windows Resource in an EXE file. Historically, only a Linker could build and manipulate a Windows Resource. Starting with Windows NT, the resources could be manipulated from within a program using the BeginUpdateResource  family of functions.

Foxpro EXE files have been built the same way for about 18 years: using a Fox resource architecture. There is a stub loader, and 0 or more sections (such as the .APP) physically appended to the file. Windows tools that manipulate the EXE file format do not pay attention to any data appended to an EXE file, so when these tools write out the result, they do not write out any additional data. With no APP, the loader merely puts up a File->Open dialog requesting an APP to run.

 

These Windows Tools use the BeginUpdateResource  family of functions, but Foxpro could not, because it still had to run on Windows 95 as well as NT

 

Starting with VFP8 (I think) VFP was able to add a generated Type Library as a Windows Resource inside a DLL, using the BeginUpdateResource functions. Now you know why this feature doesn’t work on Win 95.

 

Start Task Manager on Windows Vista, choose the Processes tab, choose View->Select Columns->Virtualization.

You will see that some processes have virtualization Enabled, Disabled, or nothing at all (depending on the privileges of the launcher) in that column.

 

Save this code as TestVista.Prg and run it

IF _vfp.StartMode>0     && If we're running as an EXE

      MESSAGEBOX("Look at Task Pane Virtualization column for TestVista")

      RETURN

ENDIF

BUILD PROJECT TestVista FROM TestVista

BUILD EXE TestVista FROM TestVista

!/n TestVista

RETURN

It builds an EXE that will show a MessageBox and then runs it. With the MessageBox showing, look at the Task Manager. The Virtualization is Enabled.

 

Now run this line from a VS Command prompt (Start->All Programs->Microsoft Visual Studio->Visual Studio Tools->VS Command prompt) in the same directory

 

mt -manifest TestVista.Exe.Manifest -outputresource: TestVista.exe;#1

 

Then run the TestVista.Exe. The Open File dialog shows up requesting an APP to run. Now the Virtualization is blank.

 

The sample below shows how to create a simple project hook that allows you to embed any file as a manifest. Try running it on Vista, with various values of requestedExecutionLevel.

 

For more about Vista User Account Control and manifests, see

· Registry Virtualization

· https://download.microsoft.com/download/5/6/a/56a0ed11-e073-42f9-932b-38acd478f46d/WindowsVistaUACDevReqs.doc

· The Windows Vista Developer Story: Windows Vista Application Development Requirements for User Account Control (UAC)

· Manifest Resources

· Creating a Manifest for Your Application   

· For another example of project hooks and modifying the VFP built EXE/DLL, see Calvin Hsia's WebLog : Strongly typed methods and properties

 

(Another way to see a manifest: Using Visual Studio, you can chose File->Open->File to open an Executable. The default is to open it with the Resource Editor.

There’s a little down arrow that you can choose on the File->Open dialog so that you can choose to open the file using a different tool, such as the Binary Editor.

In the resource view, you can see the Manifest file of an executable.)

 

 

 

The sample code below creates a manifest and creates a project hook that will embed a manifest file

 

CLEAR

IF _vfp.StartMode>0     && If we're running as an EXE

      MESSAGEBOX("Look at Task Pane Virtualization column for TestVista")

      RETURN

ENDIF

MODIFY COMMAND PROGRAM() nowait

#if .t.

BUILD PROJECT TestVista FROM TestVista

BUILD EXE TestVista FROM TestVista

!/n TestVista

RETURN

#endif

CLEAR ALL

CLEAR

IF LOWER(JUSTFNAME(PROGRAM()))!="testvista"

      ?"This sample file must be called TestVista"

      RETURN

ENDIF

#if .f.

      To use with your project, you only need the projecthook class

#endif

SET SAFETY off

IF FILE("TestVista.Exe")

      DELETE FILE TestVista.Exe

ENDIF

fAddManifest=.t.

IF !FILE("TestVista.pjx")

      BUILD PROJECT TestVista FROM TestVista

ENDIF

MODIFY PROJECT TestVista NOWAIT

IF fAddManifest

      *cExLevel="highestAvailable"

      cExLevel="asInvoker"

* cExLevel="requireAdministrator"

      TEXT TO cXML  TEXTMERGE

            <?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="CalvinsDemo" type="win32"/>

            <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">

                        <security>

                              <requestedPrivileges>

                                    <requestedExecutionLevel level="<<cExLevel>>" />

                              </requestedPrivileges>

                        </security>

                  </trustInfo>

                  <dependency>

                      <dependentAssembly>

                          <assemblyIdentity

                              type="win32"

                              name="Microsoft.Windows.Common-Controls"

                              version="6.0.0.0"

                              language="*"

                              processorArchitecture="x86"

                              publicKeyToken="6595b64144ccf1df"

                          />

                      </dependentAssembly>

                  </dependency>

            </assembly>

      ENDTEXT

      STRTOFILE(cXML,"TestVista.Exe.xml")

      _vfp.ActiveProject.ProjectHook = NEWOBJECT('MFestPHook')    && use projecthook to modify typelibrary if necessary

ENDIF

BUILD EXE TestVista FROM TestVista

_vfp.ActiveProject.Close

*Now test it. Try running it from Windows Explorer or a CMD prompt

!/n TestVista

#define RT_MANIFEST 24  && from winuser.h

#define FOX_SIG 33536

DEFINE CLASS MFestPHook AS ProjectHook

      PROCEDURE AfterBuild(nError)

            IF nError=0

                  ExeName=JUSTSTEM(_vfp.ActiveProject.Name)+".Exe"

                  MFest=ExeName+".xml"

                  IF FILE(MFest)    && if a manifest exists

                        strMFest=FILETOSTR(MFest)     && read in the manifest into a string

                        DIMENSION asec[1] && preserve 2 sections of EXE

                        nSects=0

                        h=FOPEN(ExeName)

                        fpos=FSEEK(h,0,2) && go to EOF

                        FOR i = 1 TO 20

                              FSEEK(h,fpos-14,0)

                              pmt=FREAD(h,14)

                              sig=BITAND(CTOBIN(SUBSTR(pmt,1,2),"2sr") ,0xffff)

                              sz=CTOBIN(SUBSTR(pmt,11,4),"4sr")

* ?i,sz,sig,TRANSFORM(sig,"@0x")

                              IF sig != FOX_SIG

                                    nSects = i-1

                                    EXIT

                              ENDIF

                              FSEEK(h,fpos-sz,0)

                              DIMENSION  asec[i]

                              asec[i]=FREAD(h,sz)

                              fpos = fpos - sz

                        ENDFOR

                        FCLOSE(h)

                        DECLARE integer BeginUpdateResource IN WIN32API string , integer

                        DECLARE integer EndUpdateResource IN WIN32API integer, integer

                        DECLARE integer UpdateResource IN WIN32API integer,integer,integer,integer, string, integer

                        DECLARE Integer GetLastError IN win32api

                        h=BeginUpdateResource(ExeName,0)

                        IF h =0

                              ?"Err=",GetLastError()

                        ELSE

                              UpdateResource(h,RT_MANIFEST,1,0x409,0,0) && del existing one, if any

                              UpdateResource(h,RT_MANIFEST,1,0x409,strMFest+CHR(0),LEN(strMFest))

                              IF EndUpdateResource(h,0)=0

                                    ?"Err=",GetLastError()

                              ENDIF

                              h=FOPEN(ExeName,2)

                              fpos=FSEEK(h,0,2)

                              FOR i = 1 TO nSects

                                    FWRITE(h,asec[i])

                              ENDFOR

                              FCLOSE(h)

                        ENDIF

                        ?"Added manifest"

                  ENDIF

            ENDIF

ENDDEFINE

 235882