2008-08-22 8 views
16

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

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

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

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

ответ

8

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

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

1

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

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

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

3

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

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