3

I have a mobile application running on .NET Compact Framework 3.5 and an updater application running on the same platform. When user taps on the app shortcut, updater application runs first and checks if a new version of the main app. is available. To do this, I load the main exe assembly using Assembly.LoadFrom method and get the current version. If it finds a new version (via web service) it downloads the new files and replaces. This works fine. The problem is, when it tries the replace main exe file, it fails with this "used by another process" style exception (probably because it's already loaded before). How can I unload this assembly or how can I get its version without loading it?

I've done some research about Assembly class and AppDomain, but .NET CF has some limitations, so I couldn't figure it out.

Any idea?

Thanks.

Deniz Alpaslan
  • 167
  • 2
  • 16

2 Answers2

2

The "traditional" ways of using AssemblyName.GetAssemblyName(string) or FileVersionInfo won't work as they aren't supported on .NET CF. To do this without using Assembly.LoadFrom, you will need to use P/Invoke to natively get the file version information. You can try this code (untested):

[DllImport("coredll", EntryPoint = "GetFileVersionInfo", SetLastError = true)]
private static extern bool GetFileVersionInfo(string filename, int handle, int len, IntPtr buffer);
[DllImport("coredll", EntryPoint = "GetFileVersionInfoSize", SetLastError = true)]
private static extern int GetFileVersionInfoSize(string filename, ref int handle);
[DllImport("coredll", EntryPoint = "VerQueryValue", SetLastError = true)]
private static extern bool VerQueryValue(IntPtr buffer, string subblock, ref IntPtr blockbuffer, ref int len);

public static Version GetFileVersionCe(string fileName)
{
    int handle = 0;
    int length = GetFileVersionInfoSize(fileName, ref handle);
    Version v = null;
    if (length > 0)
    {
        IntPtr buffer = System.Runtime.InteropServices.Marshal.AllocHGlobal(length);
        if (GetFileVersionInfo(fileName, handle, length, buffer))
        {
            IntPtr fixedbuffer = IntPtr.Zero;
            int fixedlen = 0;
            if (VerQueryValue(buffer, "\\", ref fixedbuffer, ref fixedlen))
            {
                byte[] fixedversioninfo = new byte[fixedlen];
                System.Runtime.InteropServices.Marshal.Copy(fixedbuffer, fixedversioninfo, 0, fixedlen);
                v = new Version(
                    BitConverter.ToInt16(fixedversioninfo, 10), 
                    BitConverter.ToInt16(fixedversioninfo,  8), 
                    BitConverter.ToInt16(fixedversioninfo, 14),
                    BitConverter.ToInt16(fixedversioninfo, 12));
            }
        }
        Marshal.FreeHGlobal(buffer);
    }
    return v;
}
Scott Dorman
  • 42,236
  • 12
  • 79
  • 110
  • I tried this one but GetFileVersionInfoSize method returned zero. I think I'll follow a simpler way, like storing current version info in a text file and updating it when newer version exists. Thank you for your help. – Deniz Alpaslan Apr 04 '14 at 14:50
  • @DenizAlpaslan Have you verified that the file does actually have a file version? You can also call `Marshal.GetLastWin32Error()` to get the error code returned and see why it is failing. – Scott Dorman Apr 04 '14 at 18:32
  • There are many files (DLL, exe) on Windows Mobile that do not have a file version info reource. CF apps do not have these res per default and so the best is to let the CF exe write its "version info" a txt or to registry for outside checks. – josef Apr 06 '14 at 06:20
0

Old post, but in case anyone looking for it. My VB (working) version.

Public Declare Function GetFileVersionInfo Lib "Coredll" (ByVal filename As String, ByVal handle As Integer, ByVal len As Integer, ByVal buffer As IntPtr) As Boolean
        Public Declare Function GetFileVersionInfoSize Lib "Coredll" (ByVal filename As String, ByRef handle As Integer) As Integer
        Public Declare Function VerQueryValue Lib "Coredll" (ByVal buffer As IntPtr, ByVal subblock As String, ByRef blockbuffer As IntPtr, ByRef len As Integer) As Boolean

Public Function GetFileVersionCE(ByVal fileName As String) As Version
            Dim handle = 0
            Dim length = GetFileVersionInfoSize(fileName, handle)
            Dim v As Version = Nothing

            If length > 0 Then
                Dim buffer As IntPtr = Marshal.AllocHGlobal(length)
                If (GetFileVersionInfo(fileName, handle, length, buffer)) Then
                    Dim fixedbuffer As IntPtr = IntPtr.Zero
                    Dim fixedlen As Integer = 0

                    If (VerQueryValue(buffer, "\\", fixedbuffer, fixedlen)) Then

                        Dim fixedversioninfo(fixedlen) As Byte
                        Marshal.Copy(fixedbuffer, fixedversioninfo, 0, fixedlen)
                        v = New Version(BitConverter.ToInt16(fixedversioninfo, 10), _
                                        BitConverter.ToInt16(fixedversioninfo, 8), _
                                        BitConverter.ToInt16(fixedversioninfo, 14), _
                                        BitConverter.ToInt16(fixedversioninfo, 12))
                    End If
                End If
                Marshal.FreeHGlobal(buffer)
            End If

            Return v

        End Function
WindyHen
  • 318
  • 2
  • 6