Попытка не нуждаться в двух отдельных решениях для программы x86 и x64 - PullRequest
7 голосов
/ 05 января 2011

У меня есть программа, которая должна работать как в среде x86, так и в среде x64.Он использует драйверы ODBC от Oracle.У меня есть ссылка на Oracle.DataAccess.DLL.Эта DLL-библиотека отличается в зависимости от того, является ли система x64 или x86.

В настоящее время у меня есть два отдельных решения, и я поддерживаю код на обоих.Это ужасноМне было интересно, что является правильным решением?

Моя платформа установлена ​​на «Любой процессор».и я понимаю, что VS должен скомпилировать DLL на промежуточный язык, так что не имеет значения, использую ли я версию x86 или x64.Тем не менее, если я пытаюсь использовать библиотеку x64, я получаю сообщение об ошибке «Не удалось загрузить файл или сборку» Oracle.DataAccess, версия = 2.102.3.2, Culture = нейтральный, PublicKeyToken = 89b483f429c47342 'или одну из ее зависимостей.чтобы загрузить программу с неверным форматом. "

Я работаю на 32-битной машине, поэтому сообщение об ошибке имеет смысл, но меня удивляет, как я должен эффективно разрабатывать эту программу, когда это необходиморабота на х64.

спасибо.

Ответы [ 5 ]

3 голосов
/ 30 мая 2013

Это рабочее решение вашей проблемы:

Добавьте 2 DLL (x86 и x64) к вашему решению в подпапке.Сделайте их «Копировать, если новее»

Ссылка на правильную DLL, которую вы используете для разработки для отладки из 2 добавленных вами DLL.Make it Copy Local = false.

Это означает, что при запуске приложения DLL не загружается автоматически.Он не будет загружен, пока вы не используете тип из этой сборки.Как только это произойдет, в .Net будет запущено событие, которое спросит, где он может найти вашу сборку.

Поэтому перед первым использованием этой сборки убедитесь, что вы подключились к этому событию.

AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

В содержимом обработчика убедитесь, что вы загружаете DLL (x86 или x64), когда он запрашивает ее.

    static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
        if (args.Name.Equals("MyFullAssemblyName")) {
            var path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            if (IntPtr.Size > 4) {
                var dll = System.IO.Path.Combine(path, @"MySubDir\MyDLL_x64.dll");
                return System.Reflection.Assembly.LoadFile(dll);
            }
            else {
                var dll = System.IO.Path.Combine(path, @"MySubDir\MyDLL.dll");
                return System.Reflection.Assembly.LoadFile(dll);
            }
        }
        return null;
    }

Вуаля.Теперь вы можете запускать ваше приложение как 32-битное, так и 64-битное.

В качестве альтернативы добавлению библиотек DLL во вложенную папку вы можете сделать их встроенными ресурсами, а затем загрузить их следующим образом:

    static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
        if (args.Name.Equals("MyFullAssemblyName")) {
            var ass = Assembly.GetExecutingAssembly();

            if (IntPtr.Size > 4) {
                var strm = ass.GetManifestResourceStream("the.resource.name.for.MyDLL_x64.dll");
                var data = new byte[strm.Length];
                strm.Read(data, 0, data.Length);
                return Assembly.Load(data);
            }
            else {
                var strm = ass.GetManifestResourceStream("the.resource.name.for.MyDLL.dll");
                var data = new byte[strm.Length];
                strm.Read(data, 0, data.Length);
                return Assembly.Load(data);
            }
        }
        return null;
    }

Это работает не для всех сборок.Некоторые «гибридные» сборки могут давать сбой, если они не загружены с диска (это можно решить, записав их на диск непосредственно перед загрузкой).

3 голосов
/ 05 января 2011

Это чисто проблема развертывания, вам никогда не придется обслуживать разные проекты. Хотя это неловко, и я жалею на Oracle за то, что они сами не позаботились об этом. Другое соображение заключается в том, что эта сборка действительно должна создаваться на целевой машине. Некоторые варианты

  • Создайте два установщика, один для x64 и один для x86. Клиент выбирает правильный, основываясь на операционной системе, которую он использует. Достаточно просто, просто скопируйте нужный файл.
  • Разверните обе сборки в GAC. Теперь он автоматический, .NET выбирает правильный на любом типе машины. Крупные компании должны почти всегда использовать GAC, чтобы развертывать обновления безопасности, не зная, почему Oracle этого не делает.
  • Разверните сборки в подкаталоге x86 и x64 каталога установки. Вам нужно написать обработчик события AppDomain.AssemblyResolve, который на основе значения IntPtr.Size выбирает правильный каталог.
  • Измените целевую платформу в вашем проекте EXE на x86. Учитывая, что ваш код должен работать как на 32-битной, так и на 64-битной машине, для AnyCPU нет / не должно быть причин для сборки.
2 голосов
/ 05 января 2011

Если вы работаете на 32-битной машине, вам нужно загрузить 32-битную версию Oracle DLL. 32-битная программа не может ссылаться на 64-битную DLL. И 64-битная программа не может ссылаться на 32-битную DLL.

«Любой ЦП» является правильной целью, если у вас есть несколько версий внешней DLL. Хитрость заключается в том, чтобы убедиться, что правильная Oracle DLL находится и загружается. Лучше всего найти 64-разрядную версию DLL в 32-разрядной системе и переименовать ее, чтобы среда выполнения не могла ее найти.

0 голосов
/ 05 января 2011

Вы сможете настроить одно и то же решение для отдельной сборки версий x86 / x64. Вам также может понадобиться добавить шаги после сборки, чтобы скопировать правильную версию DLL в соответствующие выходные папки ...

По крайней мере, если вам нужно построить 2 решения - используйте один и тот же источник (добавляйте файлы как ссылки на второе решение, а не копируйте во второе решение).

0 голосов
/ 05 января 2011

Использование AnyCPU с нативными ранними привязками просто не сработает, для этого вам нужно два отдельных решения и сборки, как вы видели.Вы должны овладеть 64-битной системой для разработки или хотя бы тестирования скомпилированных библиотек x64.

Однако, с поздним связыванием, вы можете использовать свойства AnyCPU и System, чтобы выяснить, какую архитектуру вы используетеas и ссылка на правильную dll, если вы сохраняете имя как Oracle.DataAccess.x86.dll.Если они установлены в GAC, это еще проще, вы можете выполнить привязку, даже не потрудившись сначала протестировать архитектуру, но я думаю, что вам все равно придется поздно связывать.

Обратите внимание, что VMware может работать на 64-битнойгость на 32-битном хосте, если вы действительно не хотите переустанавливать Windows.

...