Как позднее связывать 32-битные / 64-битные библиотеки во время выполнения - PullRequest
17 голосов
/ 22 августа 2008

У меня есть проблема, похожая, но немного отличающаяся от описанной здесь (Загрузка сборок и их зависимостей).

У меня есть C ++ DLL для 3D-рендеринга, это то, что мы продаем клиентам. Для пользователей .NET у нас будет оболочка CLR. DLL C ++ может быть встроена как в 32-, так и в 64-битную версии, но я думаю, что это означает, что нам нужно иметь две оболочки CLR, поскольку CLR связывается с определенной DLL?

Скажем, теперь у нашего клиента есть .NET-приложение, которое может быть 32- или 64-разрядным, и, будучи чистым .NET-приложением, оно оставляет CLR для его обработки из единого набора сборок. Вопрос в том, как код приложения может динамически выбирать между нашими 32- и 64-битными комбинациями CLR / DLL во время выполнения?

Более конкретно, применим ли предлагаемый ответ на вышеупомянутый вопрос и здесь (т. Е. Создать обработчик ResolveEvent)?

Ответы [ 3 ]

8 голосов
/ 26 января 2009

У меня наконец есть ответ на этот вопрос, который, кажется, работает.

Скомпилируйте 32- и 64-разрядные версии - как управляемые, так и неуправляемые - в отдельные папки. Затем приложение .NET во время выполнения выбирает, из какого каталога загружать сборки.

Проблема с использованием ResolveEvent заключается в том, что он вызывается только в том случае, если сборки не найдены, поэтому легко получить случайно 32-битные версии. Вместо этого используйте второй объект AppDomain, где мы можем изменить свойство ApplicationBase так, чтобы оно указывало на нужную папку. Таким образом, вы получите код вроде:

static void Main(String[] argv)
  {
     // Create a new AppDomain, but with the base directory set to either the 32-bit or 64-bit
     // sub-directories.

     AppDomainSetup objADS = new AppDomainSetup();

     System.String assemblyDir = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
     switch (System.IntPtr.Size)
     {
        case (4): assemblyDir += "\\win32\\";
           break;
        case (8): assemblyDir += "\\x64\\";
           break;
     }

     objADS.ApplicationBase = assemblyDir;

     // We set the PrivateBinPath to the application directory, so that we can still
     // load the platform neutral assemblies from the app directory.
     objADS.PrivateBinPath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);

     AppDomain objAD = AppDomain.CreateDomain("", null, objADS);
     if (argv.Length > 0)
        objAD.ExecuteAssembly(argv[0]);
     else
        objAD.ExecuteAssembly("MyApplication.exe");

     AppDomain.Unload(objAD);

  }

В итоге вы получаете 2 exes - ваше обычное приложение и второе приложение переключения, которое выбирает, какие биты загружать. Примечание - я не могу взять кредит на детали этого сам. Один из моих коллег подозревал это, учитывая мой первоначальный указатель. Если и когда он зарегистрируется в StackOverflow, я назначу ему ответ

3 голосов
/ 22 августа 2008

Я смог сделать это около года назад, но я уже не помню всех деталей. По сути, вы можете использовать IntPtr.Size, чтобы определить, какую DLL загрузить, а затем выполнить фактическую библиотеку LoadLibrary через p / Invoke. В этот момент у вас есть модуль в памяти, и вы должны иметь возможность просто п / п вызывать функции изнутри него - одно и то же имя модуля не должно перезагружаться снова.

Я думаю, однако, что в моем приложении у меня фактически была C ++ DLL, зарегистрировавшая себя как COM-сервер, и затем доступ к ее функциональности через сгенерированную оболочку .NET - так что я не знаю, тестировал ли я когда-либо p / Invoking непосредственно.

1 голос
/ 22 августа 2008

Я столкнулся с подобным сценарием некоторое время назад. Набор инструментов, который я использовал, не работал хорошо в 64-битной среде, и я не смог найти способ динамически заставить сборки связываться как 32-битные.

Возможно заставить ваши сборки работать в 32-битном режиме, но для этого необходимо исправить заголовок CLR (в Framework есть инструмент, который делает это), и если ваши сборки имеют строгое имя, это не работает вне.

Боюсь, вам нужно создать и опубликовать два набора двоичных файлов для 32- и 64-битных платформ.

...