TN003: Asignar identificadores de Windows a objetos
En esta nota se describen las rutinas de MFC que admiten la asignación de identificadores del objeto de Windows a objetos C++.
El problema
Normalmente, los objetos de Windows suelen estar representados en varios objetos IDENTIFICADOR. Las clases MFC encapsulan los identificadores de objeto de Windows con objetos C++. Con las funciones de encapsulado de identificador de la biblioteca de clases MFC, se pueden buscar el objeto C++ que está encapsulando el objeto de Windows que tiene un identificador determinado. Sin embargo, a veces un objeto no tiene un objeto contenedor C++ y en esos casos el sistema crea un objeto temporal para que actúe como contenedor C++.
A continuación se enumeran los objetos de Windows que usan asignaciones de identificadores:
HWND (CWnd y clases derivadas de
CWnd
)HDC (CDC y clases derivadas de
CDC
)HMENU (CMenu)
HPEN (CGdiObject)
HBRUSH (
CGdiObject
)HFONT (
CGdiObject
)HBITMAP (
CGdiObject
)HPALETTE (
CGdiObject
)HRGN (
CGdiObject
)HIMAGELIST (CImageList)
SOCKET (CSocket)
Dado un identificador a cualquiera de estos objetos, puede encontrar el objeto MFC que encapsula el identificador al llamar al método estático FromHandle
. Por ejemplo, dado un HWND denominadohWnd, la siguiente línea devolverá un punto al CWnd
que encapsula hWnd:
CWnd::FromHandle(hWnd)
Si hWnd no tiene un objeto contenedor específico, se crea un objeto temporal CWnd
para encapsular hWnd. Permite obtener un objeto C++ de cualquier identificador.
Después de tener un objeto contenedor, puede recuperar su identificador de una variable miembro pública de la clase contenedora. En el caso de un CWnd
, m_hWnd contiene el HWND de ese objeto.
Adjuntar identificadores a objetos MFC
Dado un objeto contenedor de controladores recién creado y un identificador a un objeto de Windows, puede asociar los dos al llamar a la función Attach
como se explica en este ejemplo:
CWnd myWnd;
myWnd.Attach(hWnd);
Convierte una entrada en la asignación permanente que se asocia a myWnd y hWnd. La llamada a CWnd::FromHandle(hWnd)
ahora devolverá un puntero a myWnd. Cuando se elimina myWnd, el destructor destruirá automáticamente hWnd al llamar a la función DestroyWindow de Windows. Si no es lo que se busca, hWnd debe desasociarse de myWnd antes de que myWnd se destruya, (normalmente al salir del ámbito en el que se definió myWnd). El método Detach
lo hace.
myWnd.Detach();
Más información sobre objetos temporales
Los objetos temporales se crean siempre que se proporciona a FromHandle
un identificador que aún no tiene un objeto contenedor. Estos objetos temporales se desasocian de su identificador y se eliminan mediante las funciones DeleteTempMap
. De forma predeterminada CWinThread::OnIdle llama automáticamente a DeleteTempMap
para cada clase que admite asignaciones de identificadores temporales. Lo anterior conlleva que no se puede suponer que un puntero a un objeto temporal sea válido después del punto de salida de la función donde se obtuvo el puntero.
Objetos contenedor y varios subprocesos
Los objetos temporales y permanentes se mantienen por subproceso. Es decir, un subproceso no puede acceder a objetos contenedor de C++ de otro subproceso, independientemente de si es temporal o permanente.
Para pasar estos objetos de un subproceso a otro, envíelos siempre como su tipo nativo HANDLE
. Pasar un objeto contenedor de C++ de un subproceso a otro a menudo provocará resultados inesperados.