2009-03-15 30 views
7

Obtengo System.IO.FileNotFoundException: The specified module could not be found cuando ejecuto el código C# que llama a un conjunto C++/CLI que a su vez llama a una DLL C pura. Sucede tan pronto como se crea una instancia de un objeto que llama a las funciones C DLL puras.C# a C++/CLI a C DLL System.IO.FileNotFoundException

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

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

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

Estoy usando Visual Studio 2008 SP1 con .Net 3.5 SP1. Estoy trabajando 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 falta, pero sería aún más estúpido por mi parte perder el tiempo tratando de resolverlo en privado, así que estoy aquí avergonzándome.

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

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

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

 
WPFViewModelInCPP 
    BackingStore 
    CPPViewModel 
    CPPViewModelTestInCS 
    bin 
     Debug 
    Debug 

El mayor nivel de depuración parece haber una carpeta común utilizado por los proyectos de C y C++/CLI, para mi sorpresa.

WPFViewModelInCPP \ depuración contiene BackingStore.dll, CPPDemoViewModel.dll, CPPViewModelTest.dll y su .ilk asociado y .pdb

WPFViewModelInCPP \ CPPViewModelTestInCS \ bin \ Debug contiene CPPDemoViewModel y CPPViewModelTestInCS .dll y .pdb pero no BackingStore. Sin embargo, la copia manual de BackingStore en ese directorio no solucionó el error.

CPPDemoViewModel tiene la propiedad copia local conjunto que supongo que es responsable de copiar su archivo DLL cuando si se hace referencia. No puedo agregar una referencia de un proyecto de C# a una DLL pura de C, simplemente dice No se pudo agregar una referencia a la Tienda de respaldo.

No estoy seguro de si tengo solo uno o dos problemas.

Puedo usar un paso de compilación copiado a la antigua para copiar BackingStore.dll en los directorios de cualquier proyecto C# dado, aunque esperaba que el nuevo modelo .NET no lo requiriera.

DependencyWalker me dice que el archivo que falta es GPSVC.dll, que has been suggested indica problemas de configuración de seguridad. Sospecho que esto es una pista falsa.

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

Respuesta

4

La respuesta de la interfaz gráfica de usuario, aparte de cambiar la configuración de salida, fue la adición de una etapa de pre-Build

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

La respuesta para los proyectos de prueba fue la de añadir el archivo DLL que faltan a la ficha Implementación de la testrunconfig. Puede hacerlo editando directamente el archivo predeterminado LocalTestRun.testrunconfig (aparece en Solución en Elementos de solución) o haciendo clic con el botón derecho en la Solución y agregando una nueva configuración de ejecución de prueba, que luego aparecerá en el menú principal de Prueba.

Gracias por las respuestas en this SO question en configuraciones de prueba para que me lleva a la respuesta.

+0

Sí, sé que es descarado marcar su propia respuesta como aceptada, pero nadie más se acercó a la respuesta real para las pruebas, lo que demoró una buena hora de excavación. Todavía estoy aturdido, tengo que usar una técnica tan anticuada para copiar el archivo DLL. –

+0

Andy, todavía deberías verificar el punto que he planteado, tengo la sensación de que tienes suerte con el orden/momento de inicialización, y puede que no tenga suerte en el futuro sin un control firme sobre este. – RandomNickName42

11

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

Es posible que tenga que cambiar sus ajustes de salida del proyecto de manera que el conjunto C# y los otros archivos DLL todos terminan en la misma carpeta.

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

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

+0

+1 para Dependency Walker; gran herramienta – Randolpho

+0

No había pensado en usar el viejo viejo depends.exe en .Net (soy un Win32/MFC de la vieja escuela y otro tipo de C++). Buen punto. Confirmó la DLL faltante. –

+0

@Andy: Bueno, eso es bueno;] Depends.exe ftw! –

1

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

Si la sugerencia de Daniel no funciona, le sugiero que trate de forma estática que une el código nativo de C para el programa C++/CLI, si es posible. Eso ciertamente resolvería el problema, ya que el .DLL sería absorbido por completo en C++/CLI .DLL.

+0

la vinculación estática es una buena idea, pero no es posible; el código debe permanecer en una DLL C pura por razones de seguridad y porque es antiguo K & R C que no se puede convertir a ANSI (funciones matemáticas desagradables) –

+0

Ah, bueno. Menos mal que Daniel estaba en lo cierto, ¿eh? – Randolpho

1

Asegúrese de que el sistema de destino tiene la correcta ejecución C Visual MS, y que no está construyendo accidentalmente el archivo DLL de C con un tiempo de ejecución de depuración.

+0

+1 buen punto, las cosas de depuración CRT me han llegado antes ... –

+0

¿Esto está diciendo que la DLL C++ nativa no se debe construir con el objetivo de depuración? ¿De qué exactamente estoy "asegurándome"? Tengo una situación muy similar (llamar C# C++/CLI DLL llamando DLL nativa de C++ para incorporar el código heredado) y me gustaría evitar cualquier error que se identifique aquí. –

+0

@richp: IIRC, la dependencia está en msvcrtd.dll. Depends.exe debería confirmar. – leppie

4

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

O bien, no tiene un punto de entrada nativo definido, sin embargo, ha vinculado a MSVCRT. El CLR se inicializa automáticamente con/clr, este detalle causa mucha confusión y debe tenerse en cuenta. Un DLL de modo mixto demora en cargar el CLR mediante el uso de hot-patching de todos los vtables de punto de entrada gestionados en sus clases.

una serie de cuestiones de inicialización de clase rodean este tema, bloqueo del cargador y el retraso CLR carga son un poco trickey veces. Intente declarar global estático y no use #pragma managed/unmanaged, aísle su código con/clr por archivo.

Si no puede aislar su código del código administrado, y tiene 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 aseguraría su completo "in-the-loop" de eventos en tiempo de ejecución y bootstrapping.

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

La vinculación estática no tiene nada que hacer con esto tampoco. Puede NO vincular estáticamente una aplicación C++/CLI que es de modo mixto.

  1. Coloque su función DLLMAIN en un archivo por sí mismo.
  2. Asegúrese de que este archivo tiene NO tienen /CLR conjunto de las opciones de generación (archivo opciones de compilación)
  3. Asegúrese de que su vinculación con/MD o/MDd, y todas sus dependencias que relacionan el uso de exactamente el mismo CRT.
  4. Evalúe la configuración de su enlazador para/DEFAULTLIB y/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, también revise que el libro es muy bueno.

+0

gracias por plantear estos problemas: se tomaron en serio y se agregaron a nuestras tareas para revisar el código –

+0

Punto 2 sobre no configurar/CLR me ayudó. Gracias. – Patel

0

Tuvo el mismo problema al cambiar a Vista de 64 bits. Nuestra aplicación llamaba a Win32 DLL 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. Seleccionar pestaña Generar;
  3. Cambia la opción 'Objetivo de plataforma:' a x86;
  4. Reconstruye la aplicación.

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