Custom Manifest Files in Visual FoxPro EXEs
August 25, 2012 •
Here's a something I didn't know about Visual FoxPro: If you place a Windows Manifest file in the same folder as the FoxPro project you are compiling, you can embed that manifest into the compiled EXE. By default FoxPro will generate it's own manifest file - one problem with this is that if an EXE has an embedded manifest file external manifest files are ignored. So effectively that means that external manifest files are not executed by FoxPro - only the internal compiled in one is.
All you have to do is to create a valid manifest file with the same name as the output EXE and then put that manifest file into the same folder as the PJX file.
So if I have an EXE called:
DotNetWsdlGeneratorConsole.exe
I have to create a matching manifest file in the Project's folder:
DotNetWsdlGeneratorConsole.exe.manifest
When you compile and now use any sort of resource editor you can take a look at the generated manifest in the FoxPro EXE. Cool, eh?
What can I use a Manifest For?
Manifest files are useful for a number of things. They can tell the OS under which security context to load, add self-registering COM components and a host of other things. It often also contains information on how to render themes under Windows XP (I'll get back to that in a minute).
Let's talk about two things that are quite common requests in the FoxPro Community:
Force your application to run in administrative mode
If you're running in Windows Vista, 7 or 8, User Account Control forces all users to run as Standard users even if you are effectively marked as an Administrator. When UAC is on, applications that require Administrative rights should always prompt for this on startup explicitly. If you need admin rights you will be automatically prompted. The only way that this can be done is via a manifest file.
If you don't do this, and you don't have the appropriate rights your app will start but fail on required administrative operations, which is problematic - it's better to notify the user on startup to elevate the rights of the Application.
I need to do this for the West Wind Web Service Proxy Generator tool, the Wizard of which lives in an EXE called:
DotNetWsdlGeneratorConsole.exe
So - in the project directory - I create a manifest file:
DotNetWsdlGeneratorConsole.manifest.exe
that looks like this:
<?xml version="1.0" encoding="utf-8"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity name="DotNetWsdlGeneratorX.exe" version="1.0.0.0" processorArchitecture="x86" type="win32" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> <security> <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> </requestedPrivileges> </security> </trustInfo>
</assembly>
These settings force ask for Administrator rights when launching and should force the app to pop up a UAC dialog that asks for permission to run this application.
- Now build the EXE - in my case I build it into a separate folder (the manifest file is not required).
- And run the EXE from Explorer when UAC is on
When I do I see:
Unfortunately, notice the Publisher Unknown - this because my EXE isn't properly signed, which is OK in my case, but if you need it here is some background information on how to sign an EXE:
Registrationless COM Activation
Another common task for manifest files is registrationless COM, which allows you to define each COM object you need access to and 'register' it inside of the manifest file. It's very easy to do this with code like the following:
<?xml version="1.0" encoding="utf-8"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity name="DotNetWsdlGeneratorConsole.exe" version="1.0.0.0" processorArchitecture="x86" type="win32" /> <file name="multithreadserver.dll"> <comClass clsid="{af2c2811-0657-4264-a1f5-06d033a969ff}" threadingModel="Apartment" progid="multithread.multithreadserver" description="multithread.multithreadserver" /> </file> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> <security> <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> </requestedPrivileges> </security> </trustInfo> </assembly>
Notice the file and comClass elements in the configuration. The file describes the file name (in the same folder) and comClass describes the clsid and progid and threading model for the DLL to be loaded. You can have multiple comClass elements for multiple COM objects contained with in the one physical file on disk.
FoxPro's Default Manifest
It's interesting to take a look and see what a FoxPro EXE's manifest actually looks like. If you have Visual Studio installed (or any other tool that can extract and view Embedded Resources) you can take a look at the EXE file.
To do this:
- Open Visual Studio
- File | Open | File and pick your compiled EXE file
If you do this Visual Studio opens the Resource editor for the EXE since manifests are embedded as resources. Here's what it looks like in VS2012:
If you drill into the '1' file - the manifest you get a split binary/text view of the data. You can cut and paste the text into a new File | New | Xml File window to view the manifest a little bit easier.
The resulting XML looks like this:
<?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" type="win32" name="Microsoft.VisualFoxPro" processorArchitecture="x86" /> <description>Visual FoxPro</description> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" /> </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>
Note that FoxPro automatically adds the requestedPrivileges attribute, but it's defaulted to 'asInvoker' which means it runs in the default system context of the user (which is the default for Windows). In effect this is not necessary, but for whatever reason the FoxPro developers thought this should be there.
The default manifest also has a dependency on the Windows Common controls assembly which forces FoxPro to uses the latest version of the common controls. This is important on XP, because it allows FoxPro to use themes on XP, which without this entry would not work.
So, for this reason, it's important that you add that last dependency into your custom manifest files as well.
So, my complete custom manifest file now looks like this:
<?xml version="1.0" encoding="utf-8"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity name="DotNetWsdlGenerator.exe" version="1.0.0.0" processorArchitecture="x86" type="win32" /> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> <security> <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> </requestedPrivileges> </security> </trustInfo> <file name="multithreadserver.dll"> <comClass clsid="{af2c2811-0657-4264-a1f5-06d033a969ff}" threadingModel="Apartment" progid="multithread.multithreadserver" description="multithread.multithreadserver" /> </file> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" language="*" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" /> </dependentAssembly> </dependency> </assembly>
and if I build my EXE and put the manifest file into the same folder as the project file, I get this exact manifest embedded into my FoxPro project.
Hope some of you find this useful - I know I have as I have a couple of administrative apps that simply work better with admin rights enabled, instead of having to write instructions somewhere that "you have to run this application with administrative rights." Sweet.
GoverL
August 26, 2012