С# в С++/CLI в C DLL System.IO.FileNotFoundException

Я получаю System.IO.FileNotFoundException: The specified module could not be found при запуске кода С#, который вызывает сборку С++/CLI, которая в свою очередь вызывает чистую C DLL. Это происходит, как только создается экземпляр объекта, который вызывает функции C DL для чистого C.

BackingStore - чистый C. CPPDemoViewModel - это С++/CLI, вызывающий BackingStore, он имеет ссылку на BackingStore.

Я попробовал самый простой случай - добавьте новый проект С# unit test, который просто пытается создать объект, определенный в CPPDemoViewModel. Я добавил ссылку из проекта С# в CPPDemoViewModel.

Проект тестирования на С++/CLI отлично работает с добавленным ref в CPPDemoViewModel, чтобы он мог перемещаться между языками.

Я использую Visual Studio 2008 SP1 с .Net 3.5 SP1. Я основываюсь на Vista x64, но старался удостовериться, что мой целевой объект платформы установлен на x86.

Это похоже на что-то глупое и очевидное, которого я пропускаю, но мне было бы еще глупее тратить время на то, чтобы решить это наедине, так что я здесь смущаюсь!

Это тест для переноса проекта огромного количества унаследованного кода C, который я храню в DLL с помощью ViewModel, реализованного в С++/CLI.

изменить После проверки каталогов я могу подтвердить, что файл BackingStore.dll не был скопирован.

У меня есть стандартные уникальные папки проектов, созданные с типичным многопроектным решением.

WPFViewModelInCPP
  BackingStore
  CPPViewModel
  CPPViewModelTestInCS
    bin
      Debug
  Debug

Отладчик более высокого уровня, похоже, является общей папкой, используемой проектами C и С++/CLI, к моему удивлению.

WPFViewModelInCPP\Debug содержит BackingStore.dll, CPPDemoViewModel.dll, CPPViewModelTest.dll и связанные с ними файлы .ilk и .pdb

WPFViewModelInCPP\CPPViewModelTestInCS\bin\Debug содержит файлы CPPDemoViewModel и CPPViewModelTestInCS.dll и .pdb, но не BackingStore. Однако ручное копирование BackingStore в этот каталог не исправило ошибку.

CPPDemoViewModel имеет свойство Copy Local set, которое, как я полагаю, отвечает за копирование его DLL, если на него ссылаются. Я не могу добавить ссылку из проекта С# в чистую DLL C - она ​​просто говорит, что ссылка на резервное хранилище не может быть добавлена.

Я не уверен, есть ли у меня только одна проблема.

Я могу использовать старомодный шаг копирования, чтобы скопировать BackingStore.dll в любые каталоги проектов С#, хотя я надеялся, что новая модель .net этого не потребует.

DependencyWalker сообщает мне, что отсутствующий файл - это файл GPSVC.dll, который был указан, указывает проблемы безопасности. Я подозреваю, что это красная селедка.

edit2 Если ручная копия BackingStore.dll находится рядом с исполняемым файлом, графический интерфейс теперь работает нормально. У проекта тестирования С# все еще есть проблемы, которые, как я подозреваю, обусловлены средой выполнения тестового проекта, но я могу жить без этого.

Ответ 1

Ответ на графический интерфейс, помимо изменения параметров вывода, был добавлением Pre-Build Step

copy $(ProjectDir)..\Debug\BackingStore.* $(TargetDir)

Ответ на тестовые проекты заключался в том, чтобы добавить отсутствующую DLL на вкладку Deployment для testrunconfig. Вы можете сделать это, непосредственно отредактировав по умолчанию LocalTestRun.testrunconfig(появится в решении в разделе "Решение" ) или щелкните правой кнопкой мыши Solution и добавьте новую конфигурацию тестового прогона, которая затем появится в главном меню "Тест".

Спасибо за ответы на этот вопрос SO в тестовых конфигурациях, чтобы привести меня к ответу.

Ответ 2

Являются ли библиотеки C и С++ в том же каталоге, что и сборка С#?

Возможно, вам придется изменить настройки вывода проекта, чтобы сборка С# и другие DLL файлы попадали в одну и ту же папку.

Я часто использовал Dependency Walker в таких случаях; это проверка работоспособности, которая показывает, что все зависимости могут быть найдены.

Как только приложение будет запущено, вы также можете попробовать Process Monitor в коде, который вы используете, чтобы посмотреть, какие DLL файлы ссылки и где они расположены.

Ответ 3

Причина, по которой это происходит, заключается в том, что вы либо загружаете DLLMAIN из управляемого кода, прежде чем CRT получит возможность инициализации. У вас может не быть управляемый код, выполняемый DIRECTLY или НЕОБХОДИМЫЙ из-за эффекта уведомлений DllMain. (См.: Expert С++/CLI:.Net для программистов на Visual С++, глава 11 ++).

Или у вас нет родной точки входа, определенной wahtsoever, но вы связаны с MSVCRT. CLR автоматически инициализируется для вас с /clr, эта деталь вызывает много путаницы и должна быть принята во внимание. DLL с смешанным режимом фактически задерживает загрузку CLR за счет использования горячего исправления всех управляемых точек входа vtables в ваших классах.

Несколько вопросов инициализации класса окружают этот вопрос, блокировка загрузчика и задержка загрузки CLR иногда немного сложны. Попробуйте объявить глобальный статический и не использовать #pragma управляемый/неуправляемый, изолируйте свой код с /clr за файл.

Если вы не можете изолировать свой код от управляемого кода и испытываете проблемы (после выполнения некоторых из этих шагов), вы также можете посмотреть на размещение CLR самостоятельно и, возможно, выполнить усилия по созданию менеджера домена, что обеспечило бы ваш полностью "в цикле" событий времени выполнения и самонастройки.

Это точно, почему это не имеет отношения к вашему пути поиска или инициализации. К сожалению, средство просмотра журнала Fusion не очень помогает (это обычное место для поиска проблем привязки .NET CLR, не связанных с ходом зависимостей).

Связывание статически не имеет ничего общего с этим. Вы можете НЕ статически связать приложение С++/CLI, смешанное.

  • Поместите функцию DLLMAIN в файл самостоятельно.
  • Убедитесь, что в этом файле НЕ установлены /CLR в настройках сборки (параметры сборки файлов)
  • Убедитесь, что вы связываетесь с /MD или/MDd и всеми вашими зависимостями, которые вы используете LINK, с тем же самым CRT.
  • Оцените свои настройки компоновщика для /DEFAULTLIB и/INCLUDE, чтобы идентифицировать возможные возможные проблемы с ссылкой, вы можете объявить прототип в своем коде и использовать /INCLUDE для переопределения разрешения библиотеки по умолчанию.

Удачи, также проверьте, что книга очень хорошая.

Ответ 4

Это интересная дилемма. Я никогда не слышал о проблеме загрузки native.DLLs из С++/CLI после вызова из него с С# раньше. Я могу только предположить, что проблема заключается в @Daniel L, и что ваш .DLL просто не находится в пути, который может найти загрузчик сборок.

Если предложение Daniel не работает, я предлагаю вам попробовать статически связать собственный C-код с программой С++/CLI, если сможете. Это, безусловно, решит проблему, так как .DLL будет полностью поглощен С++/CLI.DLL.

Ответ 5

Убедитесь, что целевая система имеет правильную рабочую среду MS Visual C и что вы случайно не создаете C dll с отладочной средой выполнения.

Ответ 6

Если бы такая же проблема перешла на 64-битную Vista. Наше приложение вызывало библиотеки DLL Win32, которые сбивали с толку целевую сборку для приложения. Чтобы решить эту проблему, мы сделали следующее:

  • Перейдите к свойствам проекта;
  • Выберите вкладку "Сборка";
  • Изменить параметр "Платформа цели:" на x86;
  • Восстановить приложение.

Когда я перезапустил приложение, он сработал.