Mundo Maker
¡Bienvenid@ a Mundo Maker!

¿Quieres aprender todo sobre el RPG Maker?



Regístrate y forma parte de Mundo Maker.

WIN32API - Crea tu primera dll

Ver el tema anterior Ver el tema siguiente Ir abajo

WIN32API - Crea tu primera dll

Mensaje por newold el 2014-09-18, 09:22

Ventajas de poner código en una dll: Casi siempre éste se ejecutará mucho más rápido que hacerlo en rgss

Cómo cargar la dll en tu script:

tuFunción = Win32API.new('dirección de la dll', 'Nombre de la función de la dll', 'Parámetros que recibirá la función', 'Parámetros que devolverá la función')
  • tuFunción: Variable que mantendrá la dll cargada
  • dirección de la dll: Ruta a la dll (es conveniente meter la dll en una carpeta dentro de la carpeta de vuestro proyecto. Si la dejais en la misma carpeta que el game.exe puede llegar a ocasionar errores que ocasionarán crasheos del juego)
  • Nombre de la función de la dll: El nombre de la función que habeis escrito en la dll y será referenciada por tu variable tuFunción
  • Parámetros que recibirá la función: La función en la dll recibirá una serie de parámetros (o ninguno) con los que operar para poder lograr algo. Los parámetros pueden tener los siguientes tipos:

    l o L: Número enorme (−2147483647,+2147483647)
    i o I: Número pequeño ([−32767,+32767])
    p o P: Puntero, estructura, texto o arrays

  • Parámetros que devolverá la función: La función de la dll devolverá como máximo un valor. Este valor podrá ser de uno de los sigientes tipos:

    l o L: Número enorme (−2147483647,+2147483647)
    i o I: Número pequeño ([−32767,+32767])
    v o V: Ningún valor devuelto
Ejemplo: suma = Win32API.new('miDLL','suma','ll','l')

Cómo llamar desde rgss a la función de la dll cargada en tuFunción:

v = tuFunción.call(parámetros) # v recibirá el valor de retorno especificado en la dll.

Cómo pasar datos como parámetros a tu dll:

  • Pasar un número entero: Definir el parámetro de entrada como L o I y añadir el número tal cual (12).
  • Pasar un decimal: Para pasar un número decimal hay que definir el parámetro de entrada como p o P y empaquetar el número con el comando pack de las arrays de ruby (1.15 sería [1.15].pack('f')).
  • Pasar un texto: Definir el parámetro de entrada como P o p y añadir el texto tal cual ('texto').
  • Pasar un array de números enteros: Definir el parámetro de entrada como p o P y empaquetar el array ([1,2,3,4,5,6].pack('i*') para números pequeños o [1,2,3,4,5,6].pack('l*') para números grandes)
  • Pasar un array de números decimales: Definir el parámetro de entrada como p o P y empaquetar el array ([1.0,2.0,3.0,4.0,5.0,6.0].pack('f*').
  • Pasar otro tipo de array (o estructura): Definir el parámetro de entrada como p o P y empaquetar el array como convenga (ejemplo: un array así [1,1.0,'texto'] sería empaquetado así: [1,1.0,'texto'].pack('lfp'))
  • Pasar una imagen*: Se puede pasar directamente el puntero de una imagen hacia la dll para tratarla ahí con tan solo la __id__ de la imagen (Ejemplo: imagen = Bitmap.new(10,10) para pasarla a la dll sería imagen.__id__ y el parámetro de entrada debería estar definido como l o L).
  • Pasar un color*: Se puede pasar directamente el puntero de un color hacia la dll para tratarlo ahí con tan solo la __id__ del color (Ejemplo: color = Color.new(255,255,255) para pasarlo a la dll sería color.__id__ y el parámetro de entrada debería estar definido como l o L).
* Es necesario el código siguiente en la dll para leer la imagen y el color:
Código:
#include <cstdlib>
#include <ctime>
#include <ctype.h>
#include <math.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

typedef struct {
    DWORD flags;
    DWORD klass;
    void (*dmark) (void*);
    void (*dfree) (void*);
    double *data; //red is index 1, green is index 2, blue 3, alpha 0
} RGSSCOLOR;
 
typedef struct{
    DWORD unk1;
    DWORD unk2;
    BITMAPINFOHEADER *infoheader;
    RGSSCOLOR *firstRow;
    RGBQUAD *lastRow;
} RGSSBMINFO;
 
typedef struct{
    DWORD unk1;
    DWORD unk2;
    RGSSBMINFO *bminfo;
} BITMAPSTRUCT;
 
typedef struct{
    DWORD flags;
    DWORD klass;
    void (*dmark) (void*);
    void (*dfree) (void*);
    BITMAPSTRUCT *bm;
} RGSSBITMAP;
 
#define ASSERT(x) if(!x){DebugOut("Failed: %s: %d", #x, __LINE__);}

// Función para leer la imagen y el color
extern "C" _declspec (dllexport) int Imagen_and_Color(long imagen, long color){
    // IMAGEN
    RGSSBMINFO *bitmap = ((RGSSBITMAP*) (object<<1)) -> bm -> bminfo;
    DWORD rowsize;
    DWORD width, height;
    long x, y;
    double red, green, blue, alpha;
    if(!bitmap) return false;
    width = bitmap -> infoheader -> biWidth;
    height = bitmap -> infoheader -> biHeight;
    rowsize = width * 4;
    row = (LPBYTE) (bitmap -> firstRow);
    for ( y = 0; y < (int) height; y++) {
        LPBYTE thisrow=row;
        for ( x = 0; x < (int) width; x++) {
            red=thisrow[0];
            green=thisrow[1];
            blue=thisrow[2];
            alpha=thisrow[3];
           
            thisrow+=4;
        }
        row-=rowsize;
    }

    // COLOR
    RGSSCOLOR *color = ((RGSSCOLOR *) (object << 1));
    red=color[1];
    green=color[2];
    blue=color[3];
    alpha=color[4];
}




Creando tu DLL:

En esta parte pondré diferentes ejemplos que creo que es la mejor forma para entender todo ésto. Cada ejemplo llevará el código rgss y el de la dll con comentarios.

Para crear la dll lo primero será tener un programa que te permita tal acción. yo estoy usando el dev c++.

nuestra DLL va a llevar un código base, así solo nos ceñiremos a poner funciones directamente.

Código:
#include <cstdlib>
#include <ctime>
#include <ctype.h>
#include <math.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

typedef struct {
    DWORD flags;
    DWORD klass;
    void (*dmark) (void*);
    void (*dfree) (void*);
    double *data; //red is index 1, green is index 2, blue 3, alpha 0
} RGSSCOLOR;
 
typedef struct{
    DWORD unk1;
    DWORD unk2;
    BITMAPINFOHEADER *infoheader;
    RGSSCOLOR *firstRow;
    RGBQUAD *lastRow;
} RGSSBMINFO;
 
typedef struct{
    DWORD unk1;
    DWORD unk2;
    RGSSBMINFO *bminfo;
} BITMAPSTRUCT;
 
typedef struct{
    DWORD flags;
    DWORD klass;
    void (*dmark) (void*);
    void (*dfree) (void*);
    BITMAPSTRUCT *bm;
} RGSSBITMAP;
 
#define ASSERT(x) if(!x){DebugOut("Failed: %s: %d", #x, __LINE__);}

// PONER AQUÍ DEBAJO LAS FUNCIONES QUE QUERAIS




COMENCEMOS:

Función que suma dos números enteros:

Ver código:
código RGSS

Código:
=begin
La dll que voy a cargar se llama miDLL y está en la carpeta Files
dentro de la carpeta de mi proyecto.
Voy a cargar la función suma en la variable suma. Esta función recibe
dos números enteros y devuelve uno (que será la suma de estos dos)
=end
suma = Win32API.new('Files/miDLL','suma','ll','l')
sum = suma.call(2,5)





código DLL

Código Base +
Código:
/*
La función suma recibe 2 números y devuelve la suma de los mismos
*/
extern "C" _declspec (dllexport) long suma(long num1,long num2)
{
    return num1+num2
}






Función que suma un array formado por 2 enteros + 2 decimales + 1 entero:

Ver código:
código RGSS

Código:
=begin
La dll que voy a cargar se llama miDLL y está en la carpeta Files
dentro de la carpeta de mi proyecto.
Voy a cargar la función sumaArray en la variable suma. Esta función recibe
un array formado por 2 enteros + 2 decimales + 1 entero y devuelve la suma de todos ellos.
Para enviar un array a la DLL hay que empaquetarlo debidamente primero para que pueda ser
leído sin problema por la DLL.
=end
array = [10,125,11.5,95.7,1000]
# Documentación ruby sobre pack:
# http://www.ruby-doc.org/core-2.1.2/Array.html#method-i-pack
arrayPack = array.pack('llffl')
suma = Win32API.new('Files/miDLL','sumaArray','p',l)
sum = suma.call(arrayPack)





código DLL

Código Base +
Código:
/*
La función sumaArray recibe un array con diferentes tipos de datos, por lo que se debe crear una estructura que interprete esos datos. Llamaré a esta estructura MiPrimerArray
*/
typedef struct {
   long value1;
   long value2;
   float value3;
        float value4;
   long value5;
} MiPrimerArray;

/*
El tipo de valor que recibirá la función será por tanto del tipo MiPrimerArray
*/
extern "C" _declspec (dllexport) long sumaArray (MiPrimerArray *data)
{
    // Para acceder a las diferentes variables de una estructura se usa
    // nombreEstructura -> nombreVariable

    // Así que la suma quedaría así:
    return data->value1 + data->value2 + data->value3 + data->value4 + data->value5;
}






Función que colorea una imagen:

Ver código:
código RGSS

Código:
=begin
La dll que voy a cargar se llama miDLL y está en la carpeta Files
dentro de la carpeta de mi proyecto.
Voy a cargar la función colorea en la variable recolor. Esta función recibe
un puntero a una imagen y a un color y ejecutará un coloreado de esa imagen con el color dado. Devolverá 1 si todo fue correctamente y 0 si hubo algún error
=end
bitmap = Bitmap.new(100,100) # Imagen de 100x100
color = Color.new(255,0,0) # Color rojo
recolor = Win32API.new('Files/miDLL','colorea','ll','i')
recolor.call(bitmap.__id__,color.__id__)





código DLL

Código Base +
Código:
/*
El tipo de valor que recibirá la función es un puntero a una imagen y a un color.
El código para colorear esa imagen con el color dado es el siguiente:
*/
extern "C" _declspec (dllexport) int colorea (long bitmap_id, long color_id)
{
    RGSSBMINFO *bitmap = ((RGSSBITMAP*) (bitmap_id<<1)) -> bm -> bminfo;
    DWORD rowsize;
    DWORD width, height;
    long x, y;
    double red, green, blue, alpha;
    RGSSCOLOR *color = ((RGSSCOLOR *) (color_id<< 1));
    if(!bitmap) return 0;
    width = bitmap -> infoheader -> biWidth;
    height = bitmap -> infoheader -> biHeight;
    rowsize = width * 4;
    row = (LPBYTE) (bitmap -> firstRow);
    for ( y = 0; y < (int) height; y++) {
        LPBYTE thisrow=row;
        for ( x = 0; x < (int) width; x++) {
            // aplicar el recolor
            red=thisrow[2] + color[1];
            green=thisrow[1] + color[2];
            blue=thisrow[0] + color[3];
            alpha=thisrow[3] + color[4];
            // comprobar valores correctos
            if(red > 255) red = 255;
            if(green > 255) green = 255;
            if(blue > 255) blue = 255;
            if(alpha > 255) alpha = 255;
            // cambiar color actual por el recolor
            thisrow[3] = (BYTE) alpha;
            thisrow[2] = (BYTE) red;
            thisrow[1] = (BYTE) green;
            thisrow[0] = (BYTE) blue;
            thisrow+=4; // próximo pixel
        }
        row-=rowsize;
    }
    return 1
}






Función que se le pasa un rect y lo modifica:

Ver código:
código RGSS

Código:
=begin
La dll que voy a cargar se llama miDLL y está en la carpeta Files
dentro de la carpeta de mi proyecto.
Voy a cargar la función changeRect en la variable newRect. Esta función recibirá un rect que debe ser convertido a array y empaquetado para ser tratado por la dll.
Esta función no devuelve ningún valor así que se usará v como valor de retorno
=end
rect = Rect.new(10,10,100,100)
array = [rect.x,rect.y,rect.width,rect.height]
# Documentación ruby sobre pack:
# http://www.ruby-doc.org/core-2.1.2/Array.html#method-i-pack
arrayPack = array.pack('llll')
newRect = Win32API.new('Files/miDLL','changeRect ','p','v')
newRect.call(arrayPack)
# La dll modificará el arrayPack pasado y después nosotros lo desempaquetaremos
# y modificaremos nuestro rect con los datos nuevos creados por la DLL
# Documentación Ruby sobre unpack:
# http://www.ruby-doc.org/core-2.1.2/String.html#method-i-unpack
array = arrayPack.unpack('llll')
# modicamos los datos de nuestro rect
rect.x = array[0]
rect.y = array[1]
rect.width = array[2]
rect.height = array[3]





código DLL

Código Base +
Código:
/*
La función changeRect recibe un array con el mismo tipo de datos, así que voy a crear dos funciones que valdrían para tratar ese dato.
La primera usaría un struct:
*/
typedef struct {
   long x;
   long y;
   long  width;
        long  height;
} Rect;

/*
El tipo de valor que recibirá la función será por tanto del tipo Rect
*/
extern "C" _declspec (dllexport) void changeRect (Rect *data)
{
    // Para acceder a las diferentes variables de una estructura se usa
    // nombreEstructura -> nombreVariable
 
  // Modificamos los datos del rect a nuestro antojo
  data -> x = data -> x + 100;
  data -> y = data -> y + 100;
  data -> width = data -> width * 2.5;
  data -> height = data -> height * 1.8;
}

/*
Esta función también podría crearse sin el uso de una estructura, ya que el tipo de datos es siempre del tipo long (L). El código sería así:

extern "C" _declspec (dllexport) void changeRect (long *data)
{
    // Modificamos los datos del rect a nuestro antojo
    data[0] = 10;
    data[1] = 100;
    data[2] = 320;
    data[3] = 240;
}

*/






Última edición por newold el 2014-09-21, 21:31, editado 2 veces
avatar
newold
Principiante
Principiante

0/3

Créditos 1235

Gracias : 119

Volver arriba Ir abajo

Re: WIN32API - Crea tu primera dll

Mensaje por Eiser el 2014-09-19, 02:32

Wow tremendo laburo hiciste, muy bueno esto man!
Estoy seguro que le ayudará a muchos.
avatar
Eiser
Novato
Novato

0/3

Créditos 59

Gracias : 2

Volver arriba Ir abajo

Re: WIN32API - Crea tu primera dll

Mensaje por orochii el 2014-09-21, 17:58

NewOld, esto es demasiado sexy, te amo (???????????? de una forma académica, respetuosa y masculina). El código para los bitmaps, y los color, ¡diox! "orz.

Yo diría que cualquier pelao en este mundo debería leerse esta wea sí o sí.
avatar
orochii
Reportero

0/3

Créditos 7724

Gracias : 436

Volver arriba Ir abajo

Re: WIN32API - Crea tu primera dll

Mensaje por xX Kyubey el 2014-09-21, 19:44

Oh, carajo, ahora sí que tengo razones para recordar lo que sabía de C. Gracias por el aporte, camarada, es cierto que las DLL son una herramienta poderosa.
avatar
xX Kyubey
Principiante
Principiante

0/3

Créditos 265

Gracias : 54

Volver arriba Ir abajo

Re: WIN32API - Crea tu primera dll

Mensaje por Contenido patrocinado


Contenido patrocinado


Volver arriba Ir abajo

Ver el tema anterior Ver el tema siguiente Volver arriba


Permisos de este foro:
No puedes responder a temas en este foro.