Como configurar correctamente el icono a la ventana e instancia de nuestro proyecto de MonoGame en Windows

Trabajando en MonoGame sobre Windows nos encontramos con que el proyecto que se genera con la plantilla de proyecto que ofrecen para Visual Studio es un proyecto de Aplicación de consola en vez de Aplicación para Windows. Esto es por que MonoGame genera la ventana del programa mediante el framework de OpenTK (Open Tool Kit Library) generando así una ventana externa, esto es similar a lo que hace XNA mediante la API de Windows. El problema que esto conlleva es que al ejecutar el juego nos aparecerá la ventana de consola, que MonoGame utiliza como salida de depuración, y la ventana del juego. El problema es que icono del proyecto se aplica a la ventana propia de la aplicación, la consola de texto, y no a la ventana del juego, la que genera OpenTK.

Lo primero que se nos ocurriría seria configurar el proyecto de Visual Studio como proyecto de Aplicación para Windows desde la ficha de propiedades del proyecto. Esto funciona ya que aunque no agreguemos un formulario WinForm al proyecto MonoGame sigue funcionando sin problemas, OpenTK genera la ventana igualmente, pero al ser una ventana ajena al propio proyecto de Visual Studio el icono no se asigna, provocando que tanto la ventana como la instancia en la barra de tareas aparezca sin icono asignado (aparecerá el icono por defecto para los ejecutables del sistema). Sin embargo esto es fácil de solucionar mediante unas pocas llamadas a la API de Windows en la inicialización de nuestro proyecto.

Lo primero que haremos sera configurar el icono como recurso incrustado (embebed resource) en el inspector de Visual Studio:

Vista de propiedades.

Agregamos después la referencia al ensamblado System.Drawing al proyecto:

Referencia a System.Drawing

Lo siguiente es agregar las declaraciones de la API de Windows necesarias para nuestro propósito en el código de la clase principal del proyecto, por defecto Game1:

// Configuramos el codigo de forma que solo se compile para la plataforma Windows:
#if WINDOWS
    [System.Runtime.InteropServices.DllImport("User32.dll", EntryPoint = "FindWindow")]
    public static extern Int32 FindWindow(String lpClassName, String lpWindowName);

    [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SendMessageA")]
    public static extern Int32 SendMessage(Int32 hWnd, Int32 Msg, Int32 wParam, Int32 lParam);

    private const Int32 WM_SETICON = 0x0080;
    private const Int32 ICON_SMALL = 0;
    private const Int32 ICON_BIG = 1;
#endif

Una vez agregado el código anterior solo debemos realizar la inicialización desde el metodo Initialize (recomiendo hacerlo antes de cualquier otra llamada en el código del método Initialize):

// Cambiamos titulo a la ventana de OpenTK:
this.Window.Title = "MonoGame test";

#if WINDOWS
    // Obtenemos los datos del icono embebido en la aplicación:
    System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
    System.IO.Stream stream = assembly.GetManifestResourceStream(assembly.GetName().Name + ".Icon.ico");
    System.Drawing.Icon icon = new System.Drawing.Icon(stream);

    // Asignamos el icono del programa a la ventana de OpenTK:
    // this.Window.Handle en MonoGame no devuelve idenficador de la ventana, así que usaremos FindWindow de
    // la API de Windows para localizarla mediante el titulo que le asignamos antes:
    SendMessage(FindWindow(null, this.Window.Title), WM_SETICON, ICON_SMALL, icon.Handle.ToInt32());
#endif

Ahora si ejecutamos el proyecto veremos que la ventana de MonoGame se muestra con el icono al igual que la instancia del programa en la barra de tareas.

Espero que este truco os pueda resultar de utilidad.

Salu2…

Deja un comentario