Estoy terminando una DLL de extensión MFC (MFCXDLL_2) para hacer que su funcionalidad esté disponible para los programadores de C#.C# .NET User Control dentro de la aplicación nativa. Problemas de la cadena de recursos
El contenedor es un "archivo DLL estándar que utiliza DLL MFC compartido" con "Common Language Runtime Support (/ clr)". (Modo mezclado).
Las clases en MFCXDLL_2 que estarán disponibles están decoradas en MFCXDLL_3.
El escenario que estoy experimentando es el caso donde MFCXDLL_2 se usa desde un control de usuario C# .NET ejecutándose en una aplicación nativa.
Otra DLL de extensión MFC -MFCXDLL_1-dentro de la aplicación nativa también usa el MFCXDLL_2 y esto causa problemas.
Cuando inicio la aplicación nativa cargará implícitamente el MFCXDLL_2.
Cuando cargo el control de usuario .NET, el mismo MFCXDLL_2 se carga de nuevo explícitamente de acuerdo con el consejo en http://msdn.microsoft.com/en-us/library/ksa99t88.aspx, "Utilizando DLL de extensión de bases de datos, OLE y Sockets en DLL regulares".
Tanto el código nativo como el control de usuario .NET instancian el mismo tipo de clase y llaman al mismo método en el MFCXDLL_2.
El método deserializa los datos (recibidos en la memoria compartida) y devuelve los datos deserializados a la persona que llama. Esto funciona muy bien desde código nativo hasta que cargue el control de usuario .NET.
Después de cargar el control de usuario de .NET, la deserialización deja de funcionar desde el código nativo, pero funciona muy bien cuando se llama desde el control de usuario .NET.
Adjunté WinDbg a la versión de depuración de la aplicación nativa y ejecuté mi escenario. WinDbg encontró lo siguiente durante la deserialización:
"Advertencia: No se puede cargar desde el archivo. Clase no definida. Excepción de CArchive: badClass. "
Creo que hay algunos problemas de recursos aquí, así que ejecuto la versión de lanzamiento de la aplicación nativa cargando la versión de lanzamiento de MFCXDLL_2. Luego cargo la versión de depuración del control de usuario .NET, que nuevamente carga la versión de depuración de MFCXDLL_2 en la aplicación nativa.
Entonces todo funciona muy bien. Una versión de lanzamiento de MFCXDLL_2 cargada por el código nativo y una versión de depuración de MFCXDLL_2 cargada por el control de usuario .NET, todo se ejecuta dentro de la aplicación nativa.
¿Qué está pasando? ¿No es posible acceder al mismo MFCXDLL de, p. Ej., una extensión DLL y una DLL regular al mismo tiempo en la misma aplicación?
¿Se ha destruido la cadena de recursos de alguna manera? ¿Cuáles son las posibles soluciones?
Aquí hay un código que muestra cómo se carga el archivo DLL MFCXDLL_2
Cuando la aplicación nativa comienza MFCXDLL_2 DLLMain se llama:
static AFX_EXTENSION_MODULE MFCXDLL_2 = { NULL, NULL };
static CDynLinkLibrary* gpDynLinkLibrary = NULL;
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// Extension DLL one-time initialization
AfxInitExtensionModule(MFCXDLL_2, hInstance);
// Insert this DLL into the resource chain
gpDynLinkLibrary = new CDynLinkLibrary(MFCXDLL_2);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
if (gpDynLinkLibrary)
{
delete gpDynLinkLibrary;
gpDynLinkLibrary = NULL;
}
// Terminate the library before destructors are called
AfxTermExtensionModule(MFCXDLL_2);
}
return 1; // ok
}
Cuando el.control de usuario NET está cargado, el MFCXDLL_2 DLL se carga de nuevo:
//==============================================================
// Exported DLL initialization to run in context of Regular DLL.
// Must be called in InitInstance
// BOOL CYourRegularDLLApp::InitInstance()
//==============================================================
extern "C" _declspec(dllexport) CDynLinkLibrary* WINAPI InitMFCXDLL_2FromRegularDLL()
{
if (gpDynLinkLibrary)
{
delete gpDynLinkLibrary;
gpDynLinkLibrary = NULL;
}
// Create a new CDynLinkLibrary for this Regular DLL
return new CDynLinkLibrary(MFCXDLL_2);
}
El código deserializar dentro MFCXDLL_2
CMyClass* pMyclass = NULL; //CObject derived serializeable class
BYTE *pBuf = pGlobalCom->GetBuffer(); //Buffer with serialized CMyClass
int nBufSize = pGlobalCom->GetSize(); //Size of buffer
CMemFile mf;
mf.Attach(pBuf,nBufSize);
CArchive ar(&mf, CArchive::load); //“Warning: Cannot load CMyClass from archive. Class not defined.CArchive exception: badClass.”
ar >> pMyclass; //CArchive exception thrown
ar.Close();
mf.Detach();
La imagen muestra la relación entre los DLL.
No puedo ver cómo una envoltura C# resolvería el problema. ¿Cómo soluciona el problema? Estoy siguiendo el patrón dado en el artículo http://www.codeguru.com/cpp/cpp/cpp_managed/interop/article.php/c6867. El puente real entre el mundo gestionado y el no gestionado es el DLL de modo mixto. El contenedor solo decora las clases que quiero que sean visibles para el control de usuario de .NET. – kjella
Tienes razón. La imagen fue incorrecta. Es, por supuesto, el "DLL regular que usa DLL MFC compartido", que es el contenedor. He cambiado la imagen ahora. El MFCXDLL_3 decora algunas de las clases en MFCXDLL_2 y hace que la funcionalidad necesaria esté disponible para el control del usuario. – kjella
El patrón CodeGuru que está viendo es desde 2004. Estoy bastante seguro de que ya no se aplica (al menos para NET 3.5 en adelante). Puedo verificar con el código que tengo en otra máquina y lo publicaré más tarde. – ChrisBD