FileVersionInfo.GetVersionInfo() неверно в консольном приложении

Я получаю серьезную странность, используя FileVersionInfo.GetVersionInfo(), и надеялся, что кто-нибудь сможет помочь.

Суть проблемы в том, что я перебираю все файлы в папке, вызывая GetVersionInfo() для каждого. Там около 300 файлов. Это работает нормально для всех файлов, кроме двух. Для этих DLL я получаю полностью неправильную информацию от GetVersionInfo().

Чтобы исключить все другие переменные, я извлек этот вызов в простое тестовое приложение, и у него осталась та же проблема. Однако, если я создал тестовое приложение как приложение Windows (изначально это было консольное приложение), то данные вернулись правильно.

Просто чтобы уточнить, неправильные данные, возвращаемые при работе в качестве консольного приложения, — это не просто нулевая информация, которую вы получили бы, если бы файл не содержал данных о версии. Он содержал разумные данные, но просто неверные данные. Как будто из другого файла читает. Я искал файл, содержащий совпадающие данные о версии, но не смог его найти.

Почему этот простой вызов работает иначе, если он построен как консольное приложение, а не как приложение Windows?

Если кто-то может помочь с этим, я был бы очень благодарен.

С уважением, Энди

-- Добавлен код

using System;
using System.Diagnostics;

namespace test
{
    class Program
    {
        static void Main(string[] args)
        {
            string file = "C:\\ProblemFile.dll";
            FileVersionInfo version = FileVersionInfo.GetVersionInfo(file);
            string fileName = version.FileName;
            string fileVersion = version.FileVersion;

            Console.WriteLine(string.Format("{0} : {1}", fileName, fileVersion));
        }
    }
}

person Andy    schedule 08.02.2010    source источник
comment
как насчет публикации урезанного кода, который демонстрирует проблему...   -  person Mitch Wheat    schedule 08.02.2010
comment
Спасибо, Митч, добавлено. Как видите, ничего особенного он не делает. Я получаю разные результаты, когда он построен как консольное приложение или приложение Windows. (Очевидно, что Console.WriteLine не работает как приложение для Windows, но я вижу результаты с помощью точки останова.) У меня проблема возникает только с парой DLL, все остальное работает нормально. Я не знаю ничего особенного о DLL, они являются продуктом другой команды в компании. Использование VS2005/.NET 2.0, если это поможет.   -  person Andy    schedule 08.02.2010
comment
Примечание. Я использую VS2005/.NET 2.0. Проблемные DLL - это VS6.0 C++   -  person Andy    schedule 08.02.2010


Ответы (4)


Такое поведение действительно кажется странным. Может ли быть так, что консольное приложение загружает DLL не из того же места, что и приложение WinForms? Это будет означать, что GetVersionInfo использует какой-то другой API, а не только Win32 CreateFile (возможно, через какой-то механизм распознавателя DLL, параллельно или что-то еще); помните, что под прикрытием ваш запрос будет выполнять version.dll, а не сама CLR.

Глядя на FileVersionInfo сквозь Reflector, мы видим еще одно направление:

public static unsafe FileVersionInfo GetVersionInfo(string fileName)
{
    // ...
    int fileVersionInfoSize = UnsafeNativeMethods.GetFileVersionInfoSize(fileName, out num);
    FileVersionInfo info = new FileVersionInfo(fileName);
    if (fileVersionInfoSize != 0)
    {
        byte[] buffer = new byte[fileVersionInfoSize];
        fixed (byte* numRef = buffer)
        {
            IntPtr handle = new IntPtr((void*) numRef);
            if (!UnsafeNativeMethods.GetFileVersionInfo(fileName, 0, fileVersionInfoSize, new HandleRef(null, handle)))
            {
                return info;
            }
            int varEntry = GetVarEntry(handle);
            if (!info.GetVersionInfoForCodePage(handle, ConvertTo8DigitHex(varEntry)))
            {
                int[] numArray = new int[] { 0x40904b0, 0x40904e4, 0x4090000 };
                foreach (int num4 in numArray)
                {
                    if ((num4 != varEntry) && info.GetVersionInfoForCodePage(handle, ConvertTo8DigitHex(num4)))
                    {
                        return info;
                    }
                }
            }
        }
    }
    return info;
}

Как вы видите, с кодовыми страницами происходит интересный танец. Что, если к проверенным вами библиотекам DLL подключено несколько ресурсов с информацией о версии? В зависимости от культуры программы, вызывающей GetVersionInfo, я предполагаю, что вызовы, связанные с кодовой страницей, могут возвращать другие результаты?

Потратьте время на проверку ресурсов DLL и убедитесь, что для информации о версии существует только один язык/кодовая страница. Я надеюсь, это может указать вам на решение.

person Pierre Arnaud    schedule 10.02.2010
comment
Спасибо, Пьер, ты определенно что-то понял. В рассматриваемых библиотеках DLL есть два ресурса версий: один en-GB и один en-US. Версия для США содержит правильные данные. Изменение моей культуры на en-US действительно заставляет консольное приложение выбрать версию для en-US. Однако приложение для Windows подбирает версию для США, даже если моя культура — en-GB. Любая идея, почему это может произойти? - person Andy; 11.02.2010
comment
Привет, Энди. Я бы предложил вам нажать кнопку «Проголосовать за ответ», если вы сочтете его полезным. Вот как работает StackOverflow ;-). И нет, увы, я понятия не имею, как происходят культуры. Вы можете попробовать получить доступ к System.Threading.Thread.CurrentThread.CurrentCulture и сравнить результаты между консольными приложениями и приложениями WinForms. - person Pierre Arnaud; 11.02.2010
comment
Сделали так сейчас. Не хватало репутации раньше! Посмотрел CurrentCulture и CurrentUICulture, и они одинаковы (en-GB, en-US соответственно) как в консоли, так и в Windows. Изменение их обоих на en-US изменяет консольное приложение, но, похоже, ничего не меняет приложение Windows. Это все еще оставляет вопросы, но мне этого хватило для работы с этими двумя DLL. Спасибо за вашу помощь. - person Andy; 11.02.2010

Конечно, «файлы», которые вы видите, не являются файлами . а также .. ? Если вы перебираете все файлы, вы всегда будете видеть записи для . (текущий каталог) и .. (вверх каталог). GetVersion Info вполне может вернуть что-нибудь для них. Вам придется отфильтровать эти записи вручную по имени.

person Bob Moore    schedule 08.02.2010
comment
Спасибо, Боб, но да, я уверен, что это не так. В тестовом приложении, о котором я упоминал, я жестко закодировал имя файла и просто вызываю GetVersion() один раз для одного из проблемных файлов. - person Andy; 08.02.2010

Версии файла и сборки - это две разные вещи.

Вы уверены, что не ожидаете другого?

person leppie    schedule 08.02.2010
comment
Не уверен насчет версии сборки. Когда я смотрю в FileVersionInfo, я вижу FileVersion и ProductVersion. Когда я создаю консольное приложение, оба они равны 1, 0, 0, 1. Когда я создаю приложение для Windows, оба имеют значения 4, 2, 004, 6102. Если я вытащу свойства из проводника Windows и посмотрю на вкладке «Версия». , Другая информация о версии, а затем версия файла и версия продукта отображаются как 4, 2, 004, 6102. - person Andy; 08.02.2010
comment
В «AssemblyInfo.cs» вы применяете 2 разных атрибута, возможно, они разные. Это все, что я могу думать. - person leppie; 08.02.2010
comment
А, я вижу это в своем проекте, но он не отображается на панели свойств для проблемных библиотек DLL. Это не библиотеки .NET, я думаю, что это VS6.0 C++. - person Andy; 08.02.2010

Обновление: пробовал это. Не работает.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace test
{
    class Program
    {
        [DllImport("COMCTL32")]
        private static extern int InitCommonControls(int nExitCode);

        static void Main(string[] args)
        {
            InitCommonControls(0);

            string file = "C:\\ProblemFile.dll";
            FileVersionInfo version = FileVersionInfo.GetVersionInfo(file);
            string fileName = version.FileName;
            string fileVersion = version.FileVersion;

            Console.WriteLine(string.Format("{0} : {1}", fileName, fileVersion));
        }
    }
}
person Andy    schedule 08.02.2010