Error: Recibe un código de error "0xC0000005" cuando se activa o se desenlaza un evento nativo

Síntomas

Cuando se activa el evento __raise o desenganchar los eventos nativos (__unhook), en una aplicación no administrada, puede recibir el siguiente mensaje de error:
Excepción no controlada en
dirección virtual de
ejecutable: 0xC0000005: infracción de acceso de ubicación de dirección virtual de lectura
donde
direcciones virtuales y
ejecutable son valores que son específicos de la aplicación.

Causa

El problema se produce cuando el constructor del origen de evento se define fuera del ámbito de clase. La lista de controlador de eventos no se inicializa en el constructor del origen de evento en el código insertado. Por lo tanto, se produce la infracción de acceso cuando se tiene acceso a la memoria sin inicializar.

Solución alternativa

Para evitar este problema, utilice uno de los métodos siguientes:

Método 1

Defina el constructor del origen de evento en su ámbito de clase. Para ello, reemplace el código existente:
struct A {__event void Event(); 
A();
void bar(){}
};
//Constructor defined outside class scope.
A::A() { }
con el código siguiente:
struct A {__event void Event(); 
A() { }; //Contructor defined in class scope.
void bar(){}
};

Método 2

Incluya el código de inicialización eventHandlerList en el constructor del origen de evento. Esto supone que el archivo .cpp que contiene la definición de clase de origen de evento es event.cpp. El código insertado generado por el compilador puede almacenarse en un archivo intermedio con ayuda de la opción del compilador de línea de comandos/fx .
  1. En el símbolo del sistema, escriba el comando siguiente:
    cl /Fx event.cpp
    El código insertado generado por el compilador se guarda en un archivo con el. extensión de mrg.cpp. Para event.cpp, el archivo con el código insertado es event.mrg.cpp.
  2. En el archivo intermedio en el que está generada (event.mrg.cpp), agregue el código siguiente al constructor del origen de evento:
    • Si se define la clase de origen de eventos denominado A en un espacio de nombres X, agregue el código siguiente:
      __eventHandlerList_X_A_Event = 0;
      al constructor de A.
    • Si no se define la clase de origen de eventos denominado A ningún espacio de nombres, agregue el código siguiente:
      __eventHandlerList_A_Event = 0;
      al constructor de A.
    Donde A es la clase de origen de evento, X es el espacio de nombres Ay eventos es que el evento identificado por la palabra clave __event en el evento clase de origen.
  3. Compile el archivo intermedio en el símbolo del sistema con el comando siguiente:
    cl event.mrg.cpp

Estado

Microsoft ha confirmado que se trata de un error en los productos de Microsoft que se enumeran al principio de este artículo.

Más información

Pasos para reproducir el comportamiento


Puede reproducir el problema con cualquiera de los dos escenarios siguientes:

Escenario 1

Definir un origen de eventos dentro de un espacio de nombres. Además, el origen del evento y el receptor de eventos se implementan mediante la misma clase o struct. Para ello, siga estos pasos:
  1. En Visual Studio. NET, cree un proyecto aplicación de consola de Win32 de Visual C++.
  2. En el .cpp archivo predeterminado que se genera para la aplicación, reemplace el código existente con el código siguiente:
    #include "stdafx.h"namespace X 
    {
    //Both event source and event receiver
    struct A {
    __event void Event();
    A();
    void bar(){}
    };
    }

    X::A::A() { }

    int main()
    {
    X::A a;
    __hook(&X::A::Event, &a, &X::A::bar, &a);
    a.Event();
    __unhook(&X::A::Event, &a, &X::A::bar, &a);
    }
  3. Genere y ejecute la aplicación.
Recibe el mensaje de error que se describe en la sección "Síntomas" de este artículo.

Escenario 2

Definir un origen de eventos y un receptor de sucesos en dos diferentes clases o estructuras. Para ello, siga estos pasos:
  1. En Visual Studio. NET, cree un proyecto aplicación de consola de Win32 de Visual C++.
  2. En el .cpp archivo predeterminado que se genera para la aplicación, reemplace el código existente con el código siguiente:
    #include "stdafx.h"//Event source
    struct A {
    __event void Event();
    A();
    };

    //Event Receiver
    struct B
    {
    void bar();
    };

    void B::bar(){}
    A::A() { }

    int main()
    {
    A a;
    B b;
    __hook(&A::Event, &a, &B::bar, &b);
    a.Event();
    __unhook(&A::Event, &a, &B::bar, &b);
    }
  3. Genere y ejecute la aplicación.
Recibe el mensaje de error que se describe en la sección "Síntomas" de este artículo.

El problema se produce porque el compilador genera código insertado incorrecto para el constructor del origen de evento. Para ver el código insertado generado por el compilador, compile el código anterior en la línea de comandos como sigue:
cl /Fx event.cpp
donde se guarda el código en event.cpp. El código generado por el compilador está disponible en un archivo que se denomina event.mrg.cpp. El constructor de la clase de evento no contiene el código de inicialización eventHandlerList siguiente al constructor de la clase de evento se define fuera del ámbito de la clase:
  • Cuando se define la clase de origen de evento que se denomina A un espacio de nombres X
    __eventHandlerList_X_A_Event = 0;
  • Cuando no se define la clase de origen de eventos denominado A ningún espacio de nombres
    __eventHandlerList_A_Event = 0;
Donde A es la clase de origen de evento, X es el espacio de nombres Ay evento es el que se identifica mediante la palabra clave __event en el evento de origen de clase.

Nota: De forma similar, la palabra clave __raise event muestra el mismo comportamiento que muestra la palabra clave event __unhook .

Referencias

Para obtener información adicional acerca de palabras clave y atributos de control de eventos nativo, consulte el siguiente sitio Web de MSDN:
Propiedades

Id. de artículo: 811193 - Última revisión: 17 ene. 2017 - Revisión: 1

Comentarios