PlanetSquires Forums

Support Forums => Other Software and Code => Topic started by: Michael Stefanik on November 10, 2009, 02:05:22 PM

Title: Manifests
Post by: Michael Stefanik on November 10, 2009, 02:05:22 PM
While I'm thinking of it, one feature that I think would be a very good thing for FF3 is to improve the intrinsic support for manifests. You already create a manifest if they select the option for the 6.0 common controls (the "Windows XP theme" controls), but there's more to them with Vista and Windows 7. Specifically, you should also allow developers to specify a trustInfo section that tells Windows if the program should execute with elevated privileges. If that trustInfo section is missing from the manifest, Vista and Win7 considers the program to be a "legacy" application.

While allowing developers to provide their own manifest to merge in with the stock manifest would be ideal, you could start with the simple addition of a checkbox in addition to the "Windows XP Theme" checkbox that would say something like "Application requires administrator privileges". If that checkbox is checked, then you'd want to add a section to the manifest that looks like:


<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
        <requestedPrivileges>
            <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
        </requestedPrivileges>
    </security>
</trustInfo>


Otherwise, if the program doesn't require elevated privileges, then you would use:


<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
        <requestedPrivileges>
            <requestedExecutionLevel level="asInvoker" uiAccess="false" />
        </requestedPrivileges>
    </security>
</trustInfo>


Note the only difference is the level attribute being either "requireAdministrator" or "asInvoker".

On a related note that's more of a minor bug, the manifest that you create is not entirely correct. You're just adding a stock manifest that looks like:


<?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="PlanetSquires.FireFly.Visual_Designer"
        type="win32" />
    <description>WinXP Manifest For FireFly Visual Designer</description>
    <dependency>
        <dependentAssembly>
            <assemblyIdentity
                type="win32"
                name="Microsoft.Windows.Common-Controls"
                version="6.0.0.0"
                processorArchitecture="X86"
                publicKeyToken="6595b64144ccf1df"
                language="*" />
        </dependentAssembly>
    </dependency>
</assembly>


The problem is that you're identifying every application built with Firefly as being version 1.0, and of being Firefly itself. You really should be using the executable name and version information provided by the developer, and have some way for them to provide an optional description. Not a huge deal, but technically what you're doing there is incorrect.
Title: Re: Manifests
Post by: Paul Squires on November 10, 2009, 02:15:00 PM
Thanks Mike, I have very little knowledge of the intrinisic benefits of manifests so everything you mentioned in your post certainly helped.

The stock manifest that I used worked so it became a case of "if it ain't broke..."  :)

I will implement youf checkbox option suggestion of allowing the elevated privledges to be inserted into the manifest.
Title: Re: Manifests
Post by: Michael Stefanik on November 10, 2009, 02:22:12 PM
For reference, Wikipedia has a decent article on UAC and how elevation is handled with manifests at http://en.wikipedia.org/wiki/User_Account_Control (http://en.wikipedia.org/wiki/User_Account_Control)
Title: Re: Manifests
Post by: Paul Squires on November 11, 2009, 05:36:51 PM
The changes suggested by Mike in this thread have been implemented. You will see it in the 3.03 update. A checkbox has been added to the Project Properties called "Application requires administrator privileges". The manifest is also updated to correctly show the application's version number, product name and description.
Title: Re: Manifests
Post by: Fred Harris on November 12, 2009, 12:10:57 PM
I'm completely in the dark on manifests, although more and more I seem to be coming across that term.  There is this from Mike's Wikipedia reference...

Quote
A program can request elevation in a number of different ways. One way for program developers is to add a requestedPrivileges section to an XML document, known as the manifest, that is then embedded into the application.

The phrase 'that is then embedded into the application' suggests to me that these XML strings somehow go into an rc file that is then compiled into the exe?  Where would one go to find out how to do this if that is indeed how it works?  I followed the link in Mike's post, which then provided another link on manifests, but the whole context of that was .NET.  Somehow these things relate to non-.NET development like we all do, but I don't know how.
Title: Re: Manifests
Post by: Michael Stefanik on November 12, 2009, 12:31:40 PM
Quote from: Fred Harris on November 12, 2009, 12:10:57 PM
The phrase 'that is then embedded into the application' suggests to me that these XML strings somehow go into an rc file that is then compiled into the exe?  Where would one go to find out how to do this if that is indeed how it works?

You're right that it's a resource that's compiled into the executable. Here's the steps for a traditional PowerBasic program:

1. Create the XML manifest and name it something like MyProgram.manifest. Here's a complete, example manifest that we use for one of our PowerBasic examples in SocketTools:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity
        version="6.0.6010.1194"
        processorArchitecture="X86"
        name="SocketTools.Example.Download"
        type="win32" />
    <description>SocketTools Example</description>
    <dependency>
        <dependentAssembly>
            <assemblyIdentity
                type="win32"
                name="Microsoft.Windows.Common-Controls"
                version="6.0.0.0"
                processorArchitecture="X86"
                publicKeyToken="6595b64144ccf1df"
                language="*" />
        </dependentAssembly>
    </dependency>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="asInvoker" uiAccess="false" />
            </requestedPrivileges>
        </security>
    </trustInfo>
</assembly>


2. Next, add the manifest file to the program's resource file, typically named something like MyProgram.rc; if the resource file doesn't exist, you should create one with version information. Near the top of the file,  right after the #include "resource.h" line, add:


#define RT_MANIFEST 24
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1

CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "MyProgram.manifest"


Of course, if you prefer to be terse, you could just add the single line:


1 24 "MyProgram.manifest"


All that does is tell the resource compiler that you want to add a resource with an ID of 1 and type of 24 (which is used for manifests) to the resources for the executable.

3. Compile the resource file (in the PowerBasic IDE, you'd do this by opening the resource file in the editor, and selecting Run | Compile from the menu), and that will create the .pbr and .res files. Then in your program source, add the following:

#RESOURCE "MyProgram.pbr"


That's it. Of course with Firefly, you don't need to worry about any of that. With the option that Paul's adding, you just check a couple of checkboxes and it will do all of this for you so that you don't need to worry about the manifest at all.
Title: Re: Manifests
Post by: Fred Harris on November 12, 2009, 01:07:04 PM
Thanks a lot Mike.  I really appreciate your helpfulness.
Title: Re: Manifests
Post by: Jean-pierre Leroy on November 13, 2009, 05:17:19 PM
Mike,

Is-it normal that after the tag <description> there is not quotes for the description ?

I've some issues with version FF 3.03 when the description contains some accented characters like é è ê a... then I cannot run the executable file.

Jean-Pierre
Title: Re: Manifests
Post by: David Kenny on November 13, 2009, 05:41:22 PM
Jean-Pierre,

Does the executable work if you manually insert the quotes and then manually recompile (not using FF)?

Title: Re: Manifests
Post by: Michael Stefanik on November 13, 2009, 06:44:00 PM
Quote from: Jean-Pierre Leroy on November 13, 2009, 05:17:19 PM
Is-it normal that after the tag <description> there is not quotes for the description ?

As far as I know quotes aren't required, however non-ASCII characters may need to be escaped using an entity code (i.e.: an & followed by #233; etc.) rather than be included as-is.

Edit: The description is completely optional by the way, it's not required to be in the manifest. So if it saves Paul some headaches in this regard, he could just remove it.
Title: Re: Manifests
Post by: Jean-pierre Leroy on November 13, 2009, 07:08:24 PM
David and Mike thank for your help.

For my FF3 project, the field "File Description" in the "Project Proporties" contains the string "évaluation".

In the CODEGEN*.Exe.Manifest the original line was
<description>évaluation</description>
in that case, I was not able to run the executable.


With quotes ...
<description>"évaluation"</description>
I get the same results, I was not able to run the executable.


But with
<description>#233valuation</description>
I'm able to run the executable ===> Correction: the description is displayed but the exe doesn't run

Not sure that it will be easy to fix.

Jean-Pierre
Title: Re: Manifests
Post by: Paul Squires on November 13, 2009, 07:25:40 PM
I can change the code generation when writing the description to the manifest file to simply REPLACE xxx WITH xxx IN xxxx

All I need are the characters that need to be replaced and the #numeric equivalent to replace it with.

I also noticed that Jean-Pierre just used the # sign followed by the number rather than also using the & like Mike suggested.
Title: Re: Manifests
Post by: Michael Stefanik on November 13, 2009, 07:41:41 PM
XML entity codes (and HTML) begin with ampersands; basically what you could do is look at any characters that aren't strictly in the ASCII printable range and replace them with &#nnn;
Title: Re: Manifests
Post by: Jean-pierre Leroy on November 13, 2009, 07:50:20 PM
Paul, Mike I'm sorry for the confusion but I made 3 other tests without any success with theses lines:

<description>#233valuation</description>
or
<description>évaluation</description>
or
<description>évaluation</description>

Seems to be more complex that I thought initially.

Jean-Pierre
Title: Re: Manifests
Post by: Michael Stefanik on November 13, 2009, 08:48:40 PM
I did a little experimenting. The manifest XML expects the document to be UTF-8 encoded (as per the encoding), and the character "é" isn't valid. Apparently, Microsoft also won't accept anything other than UTF-8, I tried different encoding types like ISO-8859-1 and it wouldn't work. If you look in the event log viewer, you can see where the loader is complaining about invalid XML syntax.

So, the solution is that the manifest must be UTF-8 encoded. Now, conveniently, all printable ASCII characters are UTF-8 "encoded" because ASCII and Unicode values in that range are the same; however once you start getting into the extended ANSI characters, the representation changes. For example, the letter "é" is encoded as a two-byte sequence "é" using UTF-8.

Fortunately, Windows makes this pretty easy with the MultiByteToWideChar and WideCharToMultiByte functions. Basically just convert the string to UTF-16 (Unicode) using MultiByteToWideChar, and then from there, convert it from UTF-16 to UTF-8 using WideCharToMultiByte and specify CP_UTF8 as the codepage parameter.
Title: Re: Manifests
Post by: Michael Stefanik on November 13, 2009, 10:09:39 PM
For Paul and anyone else interested, I've attached functions that will convert between ANSI and UTF-8 strings. I'm making the presumption that FF3 was written in PowerBasic, and thought this might help.

Edit: Fixed a minor issue where more memory was being allocated for the ANSI string than was really necessary.
Title: Re: Manifests
Post by: José Roca on November 13, 2009, 11:13:28 PM
See also: UTF-8 (8-bit Unicode Transformation Format)
http://www.jose.it-berater.org/smfforum/index.php?topic=74.0
Title: Re: Manifests
Post by: José Roca on November 13, 2009, 11:14:36 PM

' ========================================================================================
' Converts an Ansi string to an UTF-8 encoded string.
' ========================================================================================
FUNCTION AnsiToUtf8 (BYVAL strAnsi AS STRING) AS STRING

   LOCAL i AS LONG                ' // Loop counter
   LOCAL strUtf8 AS STRING        ' // UTF-8 encoded string
   LOCAL idx AS LONG              ' // Position in the string
   LOCAL c AS LONG                ' // ASCII code
   LOCAL b2 AS LONG               ' // Second byte

   IF LEN(strAnsi) = 0 THEN EXIT FUNCTION

   ' // The maximum length of the translated string will be
   ' // twice the length of the original string.
   ' // We are pre-allocating the buffer for faster operation
   ' // than concatenating each character one by one.
   strUtf8 = SPACE$(LEN(strAnsi) * 2)

   ' // Intialize index position in the string buffer
   ' // used to store the UTF-8 encoded string
   idx = 1

   ' // Examine the contents of each character in the Ascii string
   FOR i = 1 TO LEN(strAnsi)
      ' // Get the Ascii code of the character
      c = ASC(MID$(strAnsi, i, 1))
      ' // If it is betwen 0 and 127...
      IF c < 128 THEN
         ' // ...we simply copy it to the string buffer...
         MID$(strUtf8, idx, 1) = MID$(strAnsi, i, 1)
         ' // ...and increase the position by 1.
         idx = idx + 1
      ELSE
         ' // We need to split the character into two characters.
         ' // For the second byte, we only need the lower six bits of the character,
         ' // and to ensure that the two upper bits will be 10 (in binary),
         ' // i.e. (00111111 AND xxxxxxxx) OR 10000000
         b2 = (c AND &H3F) OR &H80
         ' // For the first byte, we need only the upper two bits from the character,
         ' // and to ensure that the three upper bits will be 110 (in binary).
         SHIFT RIGHT c, 6
         c = c OR &HC0
         ' // Copy the bytes to the buffer string and increase the index position by 2.
         MID$(strUtf8, idx, 2) = CHR$(c, b2)
         idx = idx + 2
      END IF
   NEXT

   ' // Return the encoded string
   FUNCTION = LEFT$(strUtf8, idx - 1)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Converts an UTF-8 encoded string to an Ansi string.
' ========================================================================================
FUNCTION Utf8ToAnsi (BYVAL strUtf8 AS STRING) AS STRING

   LOCAL i AS LONG                ' // Loop counter
   LOCAL strAnsi AS STRING       ' // Ascii string
   LOCAL idx AS LONG              ' // Position in the string
   LOCAL c AS LONG                ' // ASCII code
   LOCAL b2 AS LONG               ' // Second byte
   LOCAL fSkipChar AS LONG        ' // Flag

   IF LEN(strUtf8) = 0 THEN EXIT FUNCTION

   ' // The maximum length of the translated string will be
   ' // the same as the length of the original string.
   ' // We are pre-allocating the buffer for faster operation
   ' // than concatenating each character one by one.
   strAnsi = SPACE$(LEN(strUtf8))

   ' // Intialize index position in the string buffer
   ' // used to store the converted Ascii string
   idx = 1

   ' // Examine the contents of each character in the UTF-8 encoded string
   FOR i = 1 TO LEN(strUtf8)
      ' // If fSkipChar is set we have to skip this character
      IF fSkipChar THEN
         fSkipChar = 0
         ITERATE FOR
      END IF
      ' // Get the Ascii code of the character
      c = ASC(MID$(strUtf8, i, 1))
      ' // If it is betwen 0 and 127...
      IF c < 128 THEN
         ' // ...we simply copy it to the string buffer...
         MID$(strAnsi, idx, 1) = MID$(strUtf8, i, 1)
         ' // ...and increase the position by 1.
         idx = idx + 1
      ELSEIF c < 224 THEN
         ' // We need to join this byte and the next byte.
         b2 = ASC(MID$(strUtf8, i + 1, 1))
         IF b2 > 127 THEN
            c = (c - 192) * 64 + (b2 - 128)
            MID$(strAnsi, idx, 1) = CHR$(c)
            ' // Set the flag to skip the next character
            fSkipChar = %TRUE
            ' // Increase the position by 1.
            idx = idx + 1
         END IF
      END IF
   NEXT

   ' // Return the encoded string
   FUNCTION = LEFT$(strAnsi, idx - 1)

END FUNCTION
' ========================================================================================

Title: Re: Manifests
Post by: Paul Squires on November 14, 2009, 05:03:48 PM
I just heard back from Jean-Pierre. The manifest problem is all fixed now. The utf-8 function to convert the ansi strings fixed the problem. Thanks guys.