Estoy usando una DLL propietaria de un tercero para la cual el código fuente no está disponible para mí. Sin embargo, el código Wrapper que parece haber sido generado automáticamente usando SWIG 1.3.39 está disponible para mí. El código del contenedor consiste en un archivo C++ que compila (utilizando algunos encabezados que describen el archivo DLL) en un archivo DLL y un proyecto C# que hace que PInvoke llame a la DLL contenedora de C++.¿Cómo evito AccessViolationException al devolver una cadena de C++ a C# en Windows de 64 bits?
Según mi interpretación de la documentación del proveedor, he compilado todo en la solución como x86 o x64, dependiendo de la plataforma de destino. El proveedor proporciona versiones de 32 bits y de 64 bits de la DLL propietaria y me he asegurado de usar la correcta para la compilación determinada. Mi máquina es de 32 bits. Probar la versión x86 de mi aplicación en mi máquina, ya sea en versiones de depuración o de liberación, parece funcionar bien. Sin embargo, en 64 bits, la aplicación funciona en modo Debug pero falla con System.AccessViolationException en modo Release.
He leído this nice blog entry que parece describir bien el problema de depuración frente a versión, así como this question and answer que dieron lugar a la publicación del blog. Sin embargo, no estoy seguro de cómo solucionar el problema en este caso.
Parece que AccessViolationException se produce la primera vez que se devuelve (o se intenta devolver) una cadena de cualquier longitud real del contenedor de C++. Aquí está el infractor del código de C:
// In one file of the C# wrapper:
public string GetKey()
{
// swigCPtr is a HandleRef to an object already created
string ret = csWrapperPINVOKE.mdMUHybrid_GetKey(swigCPtr);
return ret;
}
// In the csWrapperPINVOKE class in another file in the C# wrapper:
[DllImport("csWrapper.dll", EntryPoint="CSharp_mdMUHybrid_GetKey")]
public static extern StringBuilder mdMUHybrid_GetKey(HandleRef jarg1);
Y la problemática código C++ de la envoltura C++:
SWIGEXPORT char * SWIGSTDCALL CSharp_mdMUHybrid_GetKey(void * jarg1) {
char * jresult ;
mdMUHybrid *arg1 = (mdMUHybrid *) 0 ;
char *result = 0 ;
arg1 = (mdMUHybrid *)jarg1;
result = (char *)(arg1)->GetKey();
jresult = SWIG_csharp_string_callback((const char *)result);
return jresult;
}
SWIGEXPORT
ya se había definido como __declspec(dllexport)
. En la depuración, descubrí que SWIG_csharp_string_callback
, definido como:
/* Callback for returning strings to C# without leaking memory */
typedef char * (SWIGSTDCALL* SWIG_CSharpStringHelperCallback)(const char *);
static SWIG_CSharpStringHelperCallback SWIG_csharp_string_callback = NULL;
se estaba estableciendo al delegado (en el C# envoltorio):
static string CreateString(string cString) {
return cString;
}
He tratado de jugar con este código para utilizar constructos tales como Marshal.PtrToStringAut
inútilmente. ¿Cómo soluciono y/o soluciono este problema?
Me encontré con exactamente el mismo problema y esta publicación realmente lo solucionó. Sin embargo, quiero saber cómo encontraste el código ofensivo. Porque cuando ejecutaba mi proyecto en el modo de lanzamiento no recibía ninguna excepción. ¡La "Infracción de acceso" solo aparece en la imagen cuando navego para liberar la carpeta y ejecutar el exe directamente desde allí! – Simsons
@Subhen Ha pasado un tiempo, y desde entonces he cambiado de empleador, por lo que ya no tengo acceso a este código. Si recuerdo, estaba ejecutando esto en una instancia de Windows Server, y pude usar el depurador remoto de alguna manera. Podría estar equivocado con eso, pero sé que me tomó uno o dos días encontrar dónde se estaba rompiendo. El registro también puede ayudar, por supuesto, si puede registrar dónde se encuentra exactamente en el código cuando obtiene la excepción. – Andrew