Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

Скомпилируйте как 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, я назначу ему ответ

Ответ 2

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

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

Ответ 3

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

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

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