Pregunta

Recibo System.IO.FileNotFoundException: no se pudo encontrar el módulo especificado al ejecutar un código C # que llama a un ensamblado C ++ / CLI que a su vez llama a un DLL C puro. Sucede tan pronto como se crea una instancia de un objeto que llama a las funciones de C DLL puro.

BackingStore es puro C. CPPDemoViewModel es C ++ / CLI llamando a BackingStore, tiene una referencia a BackingStore.

Intenté el caso más simple posible: agregué un nuevo proyecto de prueba de unidad C # que solo intenta crear un objeto definido en CPPDemoViewModel. Agregué una referencia del proyecto C # a CPPDemoViewModel.

Un proyecto de prueba C ++ / CLI funciona bien con solo la referencia agregada a CPPDemoViewModel, por lo que se trata de ir entre los idiomas.

Estoy usando Visual Studio 2008 SP1 con .Net 3.5 SP1. Estoy construyendo en Vista x64 pero he tenido cuidado de asegurarme de que mi objetivo de Plataforma esté configurado en x86.

Esto se siente como algo estúpido y obvio que me estoy perdiendo, ¡pero sería aún más estúpido de mi parte perder el tiempo tratando de resolverlo en privado, así que estoy aquí avergonzándome!

Esta es una prueba para un proyecto que porta una gran cantidad de código C heredado que guardo en una DLL con un ViewModel implementado en C ++ / CLI.

editar Después de verificar los directorios, puedo confirmar que BackingStore.dll no se ha copiado.

Tengo las carpetas de proyecto únicas estándar creadas con una solución típica de proyectos múltiples.

WPFViewModelInCPP
  BackingStore
  CPPViewModel
  CPPViewModelTestInCS
    bin
      Debug
  Debug

La depuración de nivel superior parece ser una carpeta común utilizada por los proyectos C y C ++ / CLI, para mi sorpresa.

WPFViewModelInCPP \ Debug contiene BackingStore.dll, CPPDemoViewModel.dll, CPPViewModelTest.dll y sus archivos .ilk y .pdb asociados

WPFViewModelInCPP \ CPPViewModelTestInCS \ bin \ Debug contiene los archivos CPPDemoViewModel y CPPViewModelTestInCS .dll y .pdb pero no BackingStore. Sin embargo, copiar manualmente BackingStore en ese directorio no solucionó el error.

CPPDemoViewModel tiene establecida la propiedad Copiar local que supongo es responsable de copiar su DLL cuando se hace referencia a ella. No puedo agregar una referencia de un proyecto de C # a una DLL de C pura, solo dice No se pudo agregar una referencia a Backing Store.

No estoy seguro si solo tengo uno o dos problemas.

Puedo usar un paso de compilación de copia antigua para copiar el BackingStore.dll en los directorios de cualquier proyecto C # dado, aunque esperaba que el nuevo modelo .net no lo requiera.

DependencyWalker me dice que el archivo que falta es GPSVC.dll que ha sido sugerido indica problemas de configuración de seguridad. Sospecho que esto es un arenque rojo.

edit2 Con una copia manual de BackingStore.dll adyacente al ejecutable, la GUI ahora funciona bien. El Proyecto de prueba de C # todavía tiene problemas que sospecho se deben al entorno de tiempo de ejecución de un proyecto de prueba, pero por ahora puedo vivir sin eso.

¿Fue útil?

Solución 2

La respuesta para la GUI, además de cambiar la configuración de salida, fue la adición de un Paso previo a la compilación

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

La respuesta para los proyectos de prueba fue agregar la DLL que faltaba a la pestaña Implementación de testrunconfig. Puede hacerlo editando directamente la LocalTestRun.testrunconfig predeterminada (aparece en Solución en Elementos de la solución) o haga clic con el botón derecho en la Solución y agregue una nueva configuración de ejecución de prueba, que luego aparecerá en la Prueba principal menú.

Gracias por las respuestas en esta pregunta SO en configuraciones de prueba por llevarme a la respuesta.

Otros consejos

¿Están las DLL de C y C ++ en el mismo directorio que el ensamblado de C # que se está ejecutando?

Puede que tenga que cambiar la configuración de salida de su proyecto para que el ensamblaje de C # y las otras DLL terminen en la misma carpeta.

A menudo he usado el Dependency Walker en casos como este; es un control de cordura que muestra que todas las dependencias se pueden encontrar realmente.

Una vez que su aplicación se esté ejecutando, también puede probar Process Monitor en el código que está ejecutando, para ver a qué DLL se hace referencia y dónde se encuentran.

La razón por la que esto sucede es porque está cargando DLLMAIN desde el código administrado, antes de que el CRT tenga la oportunidad de inicializarse. Es posible que no tenga ningún código administrado, que se ejecute DIRECTAMENTE o INDERECTAMENTE a partir de un efecto de las notificaciones DllMain. (Consulte: Expert C ++ / CLI: .Net para programadores de Visual C ++, capítulo 11 ++).

O no tiene ningún punto de entrada nativo definido, sin embargo, se ha vinculado a MSVCRT. El CLR se inicializa automáticamente con / clr, este detalle causa mucha confusión y debe tenerse en cuenta. Una DLL de modo mixto en realidad demora carga el CLR mediante el uso de parches en caliente de todas las vtables de punto de entrada administradas en sus clases.

Una serie de problemas de inicialización de clase rodean este tema, el bloqueo del cargador y el retraso en la carga de CLR son a veces un poco complicados. Intente declarar la estática global y no use #pragma administrado / no administrado, aísle su código con / clr por archivo.

Si no puede aislar su código del código administrado y está teniendo problemas (después de seguir algunos de estos pasos), también puede buscar hospedar el CLR usted mismo y quizás realizar el esfuerzo de crear un administrador de dominio, eso garantizaría su total "en el bucle" de eventos de tiempo de ejecución y bootstrapping.

Esto es exactamente por qué, no tiene nada que hacer con su ruta de búsqueda o inicialización. Desafortunadamente, el visor de registro de Fusion no ayuda mucho (que es el lugar habitual para buscar problemas de enlace del ensamblado .NET CLR, no el caminante de dependencia).

Vincular estáticamente tampoco tiene nada que hacer con esto. Puede NO enlazar estáticamente una aplicación C ++ / CLI que está en modo mixto.

  1. Coloque su función DLLMAIN en un archivo por sí mismo.
  2. Asegúrese de que este archivo NO tenga / CLR configurado en las opciones de compilación ( archivo opciones de compilación)
  3. Asegúrese de que su vinculación con / MD o / MDd, y todas sus dependencias que ENLACE utilizan exactamente la misma CRT.
  4. Evalúe la configuración de su enlazador para / DEFAULTLIB e / INCLUDE para identificar cualquier problema de referencia posible, puede declarar un prototipo en su código y usar / INCLUDE para anular la resolución predeterminada del enlace de la biblioteca.

Buena suerte, compruebe también que el libro es muy bueno.

Este es un dilema interesante. Nunca he oído hablar de un problema al cargar archivos .DLL nativos desde C ++ / CLI después de una llamada desde C # antes. Solo puedo suponer que el problema es como @Daniel L sugirió, y que su .DLL simplemente no está en una ruta que el cargador de ensamblaje puede encontrar.

Si la sugerencia de Daniel no funciona, le sugiero que intente vincular estáticamente el código C nativo al programa C ++ / CLI, si puede. Eso ciertamente resolvería el problema, ya que el .DLL sería absorbido por completo en el C ++ / CLI .DLL.

Asegúrese de que el sistema de destino tenga el tiempo de ejecución correcto de MS Visual C, y de que no está creando accidentalmente el C dll con un tiempo de ejecución de depuración.

Tuve el mismo problema al cambiar a Vista de 64 bits. Nuestra aplicación estaba llamando a Win32 DLL, lo que confundía la compilación de destino para la aplicación. Para resolverlo hicimos lo siguiente:

  1. Ir a las propiedades del proyecto;
  2. Seleccione la pestaña Construir;
  3. Cambiar la opción 'Objetivo de plataforma:' a x86;
  4. Reconstruir la aplicación.

Cuando volví a ejecutar la aplicación, funcionó.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top