¿Qué es MFC?
Si alguna vez habéis programado para Windows, es posible que conozcáis ya la biblioteca de clases MFC (Microsoft Foundation Classes). Esta biblioteca constituye un marco de trabajo sencillo enfocado al modelo "documento-vista" para el desarrollo de aplicaciones Windows.Evita al programador la necesidad de preocuparse de temas como el punto de entrada "WinMain", la implementación del bucle de procesamiento de mensajes, etc. Y además ofrece acceso orientado a objetos a buena parte de las apis de Windows, un conjunto de tipos básicos tales como listas, tablas asociativas, vectores...
Por si alguno no conoce el modelo "documento-vista" y le interesa profundizar en el tema, en Linux disponemos del combo :Bakery: y STL, con detalles estupendos como usar XML para la seriación de objetos.
Por encima, se trata de una simplificación del modelo MVC, orientado a producir aplicaciones típicamente "de gestión" (acceso a los datos a través de formularios).
Hechas ya las presentaciones :-), vamos con el asunto de este mensaje: explicar como emplear las MFC para hacer un pequeño programita bajo Linux.
¿Cómo usar las MFC en Linux?
Antes de nada, que nadie piense que Microsoft ha portado sus MFC a Linux :-). Los tiros no van por ahí. Tampoco me refiero a los costosos frameworks que disponen ciertas empresas para portar aplicaciones directamente de Windows a algún UNIX (típicamente Solaris).
Nuestras herramientas para portar código van a ser mucho más modestas: emplearemos :Wine: (concretamente, el soporte winelib) y las fuentes de las MFC que podemos encontrar en nuestro cd de "MS Devel Studio" (devstudio/vc/mfc/).
Por tanto, es necesario que tengáis tanto una copia de Wine correctamente configurada (cuyas fuentes podéis encontrar en alguno de los mirrors que aparecen en la página de :Wine:++". Yo estoy utilizando la versión 5.0 (Visual Studio 97), que es la misma que tenemos instalada en el los laboratorios de la universidad.
Lo que haremos en primer lugar será recompilar las MFC contra winelib para obtener una biblioteca nativa para Linux.
Esta posibilidad viene reflejada pero pobremente explicada en los manuales de wine (al menos en la versión wine-20011004, que es la que estoy usando), tanto es así que si hacemos solamente lo que allí aparece, no nos funcionará en absoluto :-(.
Buscando en Internet (en :GruposGoogle: ) se encuentran a patadas las referencias de gente que utiliza MFC nativa en Linux pero ninguna explicación detallada de cómo lo han hecho.
Lo más parecido con lo que me he tropezado ha sido un correo de un tal Jimen Ching en la lista de desarrollo de Twin, en Febrero del 98. El problema, claro, es que él la compila para Twin, no para Wine :-(.
Por todo esto, y ya que me he estado rompiendo los cuernos con ello estos días, me parece interesante explicar cómo lo he hecho yo, pasito a pasito :-)
Primero copiad los directorios mfc/src y mfc/include del cdrom a un directorio de vuestro $HOME:
$ mkdir mfc && cp -r /mnt/cdrom/devstudio/vc/mfc/{include,src} mfc/
También necesitareis el archivo de cabecera "atlconv.h" (que es incluido desde afxconv.h) de las ATL. Si no quereis complicaros la vida, podéis copiarlos todos a un subdirectorio.
$ mkdir mfc/atl && cp -r /mnt/cdrom/devstudio/vc/atl/include mfc/atl/
Ahora debereis retocar un poco los fuentes para que sean "UNIX friendly": eliminar "\r" de más al final de línea y eliminar las directivas problemáticas propias del compilador de Microsoft.
Wine viene con una herramienta que permite hacer todo eso de manera automática. Probad:
$ winemaker --nogenerated-files --nomfc --dll mfc/
Winemaker también es capaz de interpretar el formato de los Makefile de Microsoft y crear un "entorno autoconf" a partir de ellos, para compilar directamente desde Linux el código nativo de Windows... Pero por alguna razón no he sido capaz de compilar las MFC con él :-?.
Ahora es el momento de emplear las herramientas y el parche para las MFC que encontrareis en mfc-4-linux.tar.gz:
$ tar -xzf mfc-4-linux.tar.gz && cd mfc $ patch -p1 < mfc-4.2.patch
Si todo ha ido como debiera, ya podéis compilar las MFC:
$ CXXFLAGS="-O2" ./configure \ --with-winedir=/usr/local/ \ # en mi caso --with-mfcdir=$HOME/mfc/ \ --with-atldir=$HOME/mfc/atl/
Si tenéis un GCC moderno (superior a 2.95), podéis probar a añadir a CXXFLAGS la opción "-fms-extensions".
# make install
Y ya tenéis las MFC instaladas en vuestro sistema :-).
Las bibliotecas están practicamente peladas: por defecto se han compilado desactivando OLE, DHTML, RICHEDIT, DAO, SOCKET, etc. Estas características las podáis activar ("./configure --help"), pero lo más probable es que tengais que retocar (aún más) las fuentes de las MFC para que funcionen.
Ahora probad a compilar algo. Por ejemplo, el programa de dibujo "scribble" del tutorial del "MS Devel Studio":
Lo primero, aplicad el correspondiente parche a winemaker. En el directorio dónde lo instalasteis:
# patch < winemaker.patch
Lo que hace el parche en añadir las opciones necesarias de compilación para las mfc que hemos compilado (por defecto):
-D_AFX_PORTABLE -D_FORCENAMELESSUNION -DNO_WINSOCK -D_AFX_NO_DEBUG_CRT -D_AFX_NO_OLE_SUPPORT -D_AFX_NO_OLEDB_SUPPORT -D_AFX_NO_DHTML_SUPPORT -D_AFX_NO_DAO_SUPPORT -D_AFX_NO_OCX_SUPPORT -D_AFX_NO_OCC_SUPPORT -D_AFX_NO_DB_SUPPORT -D_AFX_NO_SYNC_SUPPORT -D_AFX_NO_INET_SUPPORT -D_AFX_NO_SOCKET_SUPPORT -D_AFX_NO_RICHEDIT_SUPPORT -D_AFX_NO_DOCOBJECT_SUPPORT -D_X86_
Y fija los siguientes directorios:
-I/usr/mfc/include -I/usr/local/include/wine/msvcrt"
Si estas opciones no se ajustan a vuestra instalación deberéis editar el parche.
Seguimos:
$ cd step3 $ winemaker --mfc --wrap . $ CXXFLAGS="-O2" ./configure \ --with-atl-includes=/usr/atl/include \ --with-mfc-includes=/usr/ \ # yo tengo "/usr/mfc/include" --with-wine-libraries=/usr/local/lib \ --with-wine-include=/usr/local/include $ make
Vaya, un fallo: alguien activó los controles en 3d de la aplicación (lo que parece que a Wine no lo implementa :-?).
Comentad la llamada a "Enable3dControlsStatic()" y a partir de ahora, no marquéis la casilla de controles en 3d del "AppWizard" :-).
$ make
Y ya está :-).
La opción "wrap" del winemaker indica que en vez de generar un binario "stand alone", construya una biblioteca dinámica que será cargada a través de un pequeño truco. Esto se hace así por el punto de entrada no estándar que estilan las aplicaciones Windows ("WinMain").
Si todo va bien, tendréis un enlace a wine en el directorio, llamado "scribble". Probad a ejecutarlo:
$ ./scribble
Bastante impresionante, ¿no?.
¿Y qué más se le puede pedir a nuestras MFC?: no demasiado, aunque por ejemplo es capaz de compilar las prácticas de "Programación Visual" sin problemas ;-).
¿Como usar las MFC en Linux según el manual de Wine? (a mí no me funcionó)
Por si alguien quiere intentarlo tal y como viene en el manual de Wine, a ver si tiene más suerte que yo, lo que debe hacer es:
Con el winemaker original (no el parcheado).
$ winemaker --nomfc --dll --interactive mfc/
Ojo: "nomfc" indica que no queremos enlazar la biblioteca con las mfc (lógico :-)), no que lo que vamos a compilar sean las MFC.
Entre las opciones que nos muestra el winemaker en modo interactivo, elegimos alguno de los objetivos (mfcdll, por ejemplo) y dejamos bien claro de que no usaremos ni un wrapper, ni las mfc y que queremos que considere cualquier objetivo "dudoso" como una biblioteca.
Después configuramos los fuentes.
$ ./configure --with-atl-includes=/loquesea \ --with-mfc-includes=/loquesea \ --with-wine-libraries=/loqusea \ --with-wine-include=/loquesea
Editamos el Makefile resultante para que se empleen las opciones:
#define _AFX_PORTABLE #define _FORCENAMELESSUNION #define _AFX_NO_DAO_SUPPORT #define _AFX_NO_DHTML_SUPPORT #define _AFX_NO_OLEDB_SUPPORT #define _AFX_NO_RICHEDIT_SUPPORT
Y algunos archivos como afxcom.h y afxtempl.h de la forma en la que se explica en HOWTO-winelib.
Por último, simplemente haz "make". Si consigues una biblioteca sin referencias no resueltas y con la que puede compilar "scribble", ¡enhorabuena! :-). Y si no, siempre puedes recurrir a mi chapucilla ;-)
... Y por supuesto
Si alguien se anima y sigue tocando las fuentes de las MFC para soportar algo más (Siempre que Wine tb lo soporte, claro :-)), sería un detallazo que lo comentase por aquí ;-)