views:

55

answers:

1

We have a VB6 project that compiles to an ActiveX EXE that happens to have the word "patch" in the filename (it is part of a police dispatch system), which is causing Installer Detection on Windows 7 to think that it requires elevation.

Rather than renaming the EXE, I want to embed a manifest resource into the compiled EXE that will request the asInvoker privilege level. From reading, I know I can do this after compiling the EXE using the mt tool in the Windows SDK, but I'd prefer to put the manifest in a .RES file so that it gets compiled into the program whenever I build the project.

Is there a way to add a manifest resource (resource type 24) to a VB6 project using the Resource Editor add-in? I added the manifest file as a custom resource and tried a few different values for the resource type, such as "RT_MANIFEST" and "24", and then tested whether it was working by using mt to re-extract the manifest, but I cannot get it to work.

Note: As mentioned on a few pages I visited, I did remember to make the manifest an even multiple of 4 bytes, so I don't think that's the problem.

+2  A: 

At first, I thought I'd try using rc to create a .RES file that I could just add to my project. I've never used rc before, so I ended up on this MSDN page while trying to figure it out.

What was interesting was this description for typeNameId on that page (emphasis added):

Type name or identifier for the resource. Specify a string name or a number. If using a number, prepend the string with a "#" to indicate that it represents a number. Each resourceType element must have only one typeNameId attribute.

I thought to myself, "Well, that's interesting and probably wouldn't apply to VB6's Resource Editor, but I'll try it anyway."

Lo and behold, if you add a manifest file as a custom resource, and then change its type to #24 (i.e. use a # prefix), it works! It gets correctly embedded as a manifest resource in the compiled EXE.

Here are the steps in detail:

1) Create a manifest file. I used this one (note that the padding at the end made the file exactly 608 bytes in my case):

<?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" name="DispatchMonitor" type="win32"/>
    <description>DispatchMonitor RunAsInvoker fix</description>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
            </requestedPrivileges>
        </security>
    </trustInfo> 
</assembly> 
<!-- Padding to make filesize even multiple of 4 -->

2) Open the Resource Editor in the VB6 IDE by selecting Resource Editor from the Tools menu (you may have to enable it first in Add-Ins > Add-In Manager).

3) Create a new resource file if necessary.

4) Add a new custom resource (click the button to the left of the "?" icon).

5) A file selection dialog appears: select the manifest file created in step 1.

6) The resource will be added under a "CUSTOM" folder with an ID of 101 by default.

7) Double-click on the new resource. Change the "Type" to #24 and the "Id" to 1.

8) Save your changes and close the Resource Editor.

Mike Spross
No, "#24" is not a an `RT_MANIFEST` resource type. Usually I create and attach an empty .res file and close the VB project, then start VC and edit the .res file to insert manifest. This way the final exe automagically gets a manifest embedded. Also, it turns out VB6 resource editor can enumerate items in the .res file of any type (including `RT_MANIFEST`) but can not view their contents.
wqw
@wqw: "#24" does work. `RT_MANIFEST` is a constant equal to `24`. Try it out. I confirmed that it worked by running `mt` to see if it could recognize the resource as a manifest and extract it to a file: `mt.exe -inputresource:MyExe.exe;#1 -out:extracted.manifest`. This command didn't work with any other resource type, but when I did it with a resource type of `#24`, `mt` was able to extract the manifest from the compiled EXE. In addition, I installed the program on a Windows 7 machine and the operating system was able to read the manifest, because it removed the shield from the EXE's icon.
Mike Spross
Also, the program didn't generate "elevation required" errors anymore after I embedded the manifest in the manner I described in my post, so I am 100% sure that the steps I outlined above work.
Mike Spross
wqw
@wqw: I don't think it's a hack. The documentation for `rc.exe` says prefixing a resource type constant with a `#` is the correct way to identify a resource type by number. and it looks like the VB6 Resource Editor simply follows the same rules. If you decompile the VB6 EXE, the actual resource type that gets compiled into the EXE is the number 24, not the string `#24`. The `#` character simply tells VB6 to interpret it as a raw numeric value, as opposed to a string. Since it works exactly the same as `rc` does, it seems perfectly fine to me.
Mike Spross
This # syntax is a nice find. I don't think I've ever seen it documented for VB6 any place before. I must be tired, I posted as an answer by mistake. :(
Bob Riemersma