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

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

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

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

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

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

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

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

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

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

WPFViewModelInCPP
  BackingStore
  CPPViewModel
  CPPViewModelTestInCS
    бункер
      отлаживать
  отлаживать

К моему удивлению, отладка более высокого уровня является общей папкой, используемой проектами C и 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 при обращении к нему. Я не могу добавить ссылку из проекта C# в чистую C DLL - он просто говорит, что Ссылка на Резервное хранилище не может быть добавлена.

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

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

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

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

6 ответов

Решение

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

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

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

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

Находятся ли библиотеки DLL C и C++ в том же каталоге, что и выполняемая сборка C#?

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

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

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

Причина, по которой это происходит, заключается в том, что вы либо загружаете DLLMAIN из управляемого кода, прежде чем CRT сможет инициализироваться. Вы не можете иметь какой-либо управляемый код, выполняться ПРЯМО или НЕРАЗРЕШНО из-за влияния уведомлений DllMain. (См.: Эксперт C++/CLI: .Net для программистов Visual C++, глава 11++).

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

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

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

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

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

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

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

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

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

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

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

  1. Перейти к свойствам проекта;
  2. Выберите вкладку Build;
  3. Измените параметр "Цель платформы:" на x86;
  4. Перестройте приложение.

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

Другие вопросы по тегам