News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

GoAsm and "side by side assembly"

Started by donkey, February 09, 2010, 10:09:47 AM

Previous topic - Next topic

donkey

Starting way back with Windows XP side-by-side assembly was introduced. Back in the bad old days of <=Win2K when you were building an application you had to make sure that the destination machine had the right version of most system DLL's. For example a previous version of common controls may not have had one of the messages your application was expecting and so you were cooked. So with WinSxS, Microsoft began to install mulitple versions of a DLL on the same machine and the program could just pick the one it wanted. This leads to two obvious problems : where to put them and how to access them, you can't have 2 files with the same name in the same folder and if you give them different names it would be a nightmare for programmers. Then along came the SxS folder and side-by-side to the rescue.  The WinSxS folder is found in the Windows folder on all machines from WinXP onward, it contains a very large number of folders that contain each DLL version, the names of the folders describe the DLL and version information. Here's an example

C:\Windows\winsxs\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.6002.18005_none_5cb72f96088b0de0

Lets break it down:

x86 = processorArchitecture
microsoft.windows.common-controls = Library name
6595b64144ccf1df = publicKeyToken
6.0.6002.18005 = Version information
I'm not sure what "_none_5cb72f96088b0de0" are for but they are not important for this discussion.

So how do we use this information ? Well, remember we have to access the correct DLL for our application, the way we do this is with a Manifest file. We've all struggled with manifests before and for the most part just copy and pasted them so they would allow us to use CC6. Well, the manifest is essentially used to build the folder name in WinSxS, sort of since it will find the folder with the highest version that meets your manifests requirements.

Lets look at a Manifest:

<?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="MyApp" type="win32"/>
      <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>
      <dependency>
          <dependentAssembly>
              <assemblyIdentity
                  type="win32"
                  name="microsoft.windows.gdiplus"
                  version="1.1.0.0"
                  language="*"
                  processorArchitecture="x86"
                  publicKeyToken="6595b64144ccf1df"
              />
          </dependentAssembly>
      </dependency>
</assembly>


In the manifest above we first use the standard header that Microsoft has specified for SxS manifests. This simply tells Windows that it is an assembly manifest, version and encoding information and the name and platform for the application.

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


Next, if you're using Vista or above you should have a UAC aware application so we'll put in our UAC section, here I use asInvoker but you can also use highestAvailable or asAdministrator if you like.

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


Finally we get to the SxS part of the manifest, in the above manifest I have specified Common Controls version 6 and GDIPlus version 1.1. And that's where the SxS folders come into play. If you're not sure what versions you have available or what to enter in the manifest file you can check the DLL versions in each of the SxS sub-folders and use the information contained in the folder name to build a manifest section. So if you want to use the GdipBitmapConvertFormat function from GDI+ you need at least version 1.1 (which actually reports 6.0 but that's another issue) and you will find a folder something like this:

x86_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.6000.16386_none_8df21b8362744ace

in WinSxS. Using the descriptions above you can build a manifest dependency easily enough, remember that Windows will find the highest version that will meet your needs so you have only to specify (as in this case) that you want at least 1.1.0.0, it will load the appropriate version.

However, there is a problem with this when using GoAsm, it requires that all imports are done directly from the DLL and it hasn't read the manifest ! So to get around this you have to copy the DLL from the folder and paste it into your project folder. GoAsm will always search your project folder first so you can be assured that the correct version will be used for imports, otherwise it will just use the version in Windows\System32 and that won't get you very far. You only need the DLL in the project folder, you do not need to distribute it with your application as it is only used to get import information when you build your application.

Now, what if you want to ensure that your version of the DLL is exactly the one used ? Well, if its redistributable no problem, you have simply to include it with your distribution. But you ask, won't Windows go looking for the highest version above my requirements and use that instead ? Yes, it will, so we need to use a different manifest if we are distributing the DLL in our application folder, in this case we'll assume that we have shipped GDIPLUS.DLL with the application and we need that particular one:

<?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="MyApp" type="win32"/>
<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>
      <file name="gdiplus.dll"/>
</assembly>


As you can see, instead of using the version information, I have simply used <file name="gdiplus.dll"/>, that will force Windows to use the DLL I have shipped instead of one from WinSxS or System32.

Well, that's all anyone should ever have to know about SxS and manifests in order to successfully build a side-by-side assembly application with GoAsm.

Enjoy,

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable