C # в C ++ / CLI в C DLL System.IO.FileNotFoundException - PullRequest
7 голосов
/ 15 марта 2009

Я получаю 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
    bin
      Debug
  Debug

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

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

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

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

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

Ответы [ 6 ]

11 голосов
/ 15 марта 2009

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

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

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

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

4 голосов
/ 19 мая 2009

Причина, по которой это происходит, заключается в том, что вы либо загружаете DLLMAIN из управляемого кода, прежде чем CRT сможет инициализироваться. Возможно, у вас нет управляемого кода, который может быть выполнен ПРЯМО или НЕПОСРЕДСТВЕННО из-за уведомлений DllMain. (См .: Expert 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 для переопределения разрешения ссылки по умолчанию для библиотеки.

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

4 голосов
/ 17 марта 2009

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

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

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

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

1 голос
/ 15 марта 2009

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

1 голос
/ 15 марта 2009

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

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

0 голосов
/ 14 июля 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...