htm=articulo/gifdll0.htm ok articulo/gifdll0.htm Crear una DLL con Visual C++.

Ficheros que se añaden a la DLL.


GLOBAL.CPP

    Exporta varias funciones cortas que serán necesarias para reservar y liberar memoria, manejar punteros desde Visual Basic, etc... Estas funciones se incluyen para facilitar el uso de la DLL desde Visual Basic.

#include <windows.h>
#include "Gifdll.h"

PUBLIC(LPVOID) GetDirec(LPVOID dir)
{
        return dir;
}
PUBLIC(VOID) CopyMemo(PVOID Dest,PVOID Source, DWORD Length)
{
        CopyMemory(Dest,Source,Length);
}
PUBLIC(void*) AllocBuffer(long size)
{
        HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE, size);
        if(!h) return NULL;
        return  GlobalLock(h);
}
PUBLIC(void) FreeBuffer(void* dir)
{
        HGLOBAL h = GlobalHandle(dir);
        if(h){
                GlobalUnlock(h);
                GlobalFree(h);
        }
}
PUBLIC(void*) ReallocBuffer(void* dir,long size)
{
        HGLOBAL h = GlobalHandle(dir);
        if(!h) return NULL;
        GlobalUnlock(h);
        h = GlobalReAlloc(h, size, GMEM_MOVEABLE);
        if(!h) return NULL;
        return  GlobalLock(h);
}



COMPRESS.CPP

    Exporta la funcion GCompress que sirve para comprimir datos en formato compatible gif. Este fichero incluye todo el código del compresor, además de la funcion exportada.

///////////////////////////////////////////////////////
// compresion  ==> funcion GCompress
///////////////////////////////////////////////////////

#include <windows.h>
//#include <stdio.h>
#include "Gifdll.h"


struct SCode{   //elemento en la tabla de codigos (arbol)
        SCode    *pSiguiente;   //hermano
        unsigned short nHijo;   //primer hijo
        unsigned short nByte;   //byte que añade
};

class CCompress{
  SCode  T[4097];   //tabla de codigos (usa 12 bits como maximo)
  int    nelem;     //numero de elementos actuales en la tabla
  UCHAR  *pOut;     //flujo de salida de codigos
  int     nOut;     //bytes que quedan en la salida
  int     bOut;     //remanente de bits
  UCHAR  *pInp;     //flujo de entrada de pixels
  int     nInp;     //bytes que quedan en la entrada
  int     bInp;     //remanente de bits
  int     bitspixel;  //numero de bits por pixel
  int     numbits0;  //numero minimo de bits por codigo
  int     clr;       //codigo de reset-tabla
  int     eot;       //marca de final del flujo de codigos
  int     numbits;       //n_bits por codigo actual !
public:
  CCompress(GData *pData);
  void  __fastcall Run();
  void  GetData(GData *pData);
protected:
  inline void  __fastcall ResetTabla();
  inline int  __fastcall InpPixel();
  inline void __fastcall OutCode(int);
  inline int  __fastcall EnTabla(int old, int c);
};
CCompress::CCompress(GData *pData)
{
        //buffer de salida de codigos
        pOut      = pData->pDest;
        nOut      = pData->nDest;
        bOut      = 0;
        numbits0  = pData->nBitsDest + 1;
        //buffer de entrada de pixels
        pInp      = pData->pSourc;
        nInp      = pData->nSourc;
        bInp      = 0;
        bitspixel  = pData->nBitsSourc;
        *(unsigned*)pOut = 0;
        ResetTabla();    //reset punteros de tabla
}
void  __fastcall CCompress::ResetTabla()  
{
        numbits = numbits0;
        int n = 1 << (numbits0 - 1);
        memset(T, 0, n * sizeof(SCode));
        clr   = n++;
        eot   = n++;
        nelem = n;
}
//////////////////////////////////////
//actualizar descripcion de buffers
void CCompress::GetData(GData *pData)
{
        //buffer de salida de codigos
        if(bOut) {nOut;pOut++;}
        pData->pDest  = pOut;
        pData->nDest  = nOut;
        //buffer de entrada de pixels
        if(bInp) {nInp--;pInp++;}
        pData->pSourc = pInp;
        pData->nSourc = nInp;
}
//////////////////////////////////////
// leer siguiente pixel
int   __fastcall CCompress::InpPixel()
{
        if(bitspixel == 8){  //más rápido
                if(nInp-- < 0) throw(GER_INPDATA);
                return *pInp++;
        }
        unsigned c = * pInp;
        c >>=  8 - bInp - bitspixel;
        c  &=   (1 << bitspixel) - 1;
        bInp += bitspixel;
        if(bInp >= 8){
                bInp -= 8;
                if(nInp-- < 0) throw(GER_INPDATA);
                pInp++;
        }
        return c;
}
//////////////////////////////////////////
// escribir siguiente codigo
void  __fastcall CCompress::OutCode(int b)
{
//      printf("%X ", b);
        *(unsigned*)pOut = *pOut | (b << bOut);
        bOut  += numbits;
        while(bOut >= 8){
                bOut -= 8;
                if(nOut-- < 0) throw(GER_OUTDATA);
                pOut++;
        }
}
///////////////////////////////////////////////////
//comprueba si un elemento esta en la tabla (y lo añade)
int  __fastcall CCompress::EnTabla(int old, int c)
{
        SCode *p = T + old;
        if(p->nHijo){
                p = T + p->nHijo;
                while(1){
                        if(p->nByte ==  c)      return p - T;
                        if(!p->pSiguiente)  break;
                        p = p->pSiguiente;
                }
                p->pSiguiente = T + nelem;
        }
        else{
                p->nHijo = nelem;
        }
        p = T + nelem;
        p->pSiguiente = NULL;
        p->nByte      = c;
        p->nHijo      = 0;
        return -1;
}
///////////////////////////////////////////
//       comprimiendo
void  __fastcall CCompress::Run()
{
        unsigned c;
        int old, act;
        OutCode(clr);
        old = InpPixel();
        while(nInp){
                c = InpPixel();
                act = EnTabla(old, c);
                if(act >= 0){
                        old = act;
                        continue;
                }
                OutCode(old);
                old = c;
                if((nelem & (nelem-1)) == 0){
                        if(numbits == 12){  
                                OutCode(clr);
                                ResetTabla();
                                continue; //evitar  ++nelem;
                        }
                        numbits++;
                }
                nelem++;
        }
        OutCode(old);
        OutCode(eot);
}
///////////////////////////////////////////////////////
//funcion pública para comprimir
PUBLIC(BOOL) GCompress(GData* pData)
{
        pData->nTime = GetTickCount();
        CCompress C(pData);
        try{
                C.Run();
                pData->nError == GER_OK;
        }
        catch(int n){
                pData->nError = n;
        }
        C.GetData(pData);
        pData->nTime = GetTickCount() - pData->nTime;
        return pData->nError == GER_OK;
}
 
 

EXPAND.CPP

    Exporta la funcion GExpand que sirve para descomprimir datos en formato compatible gif. Este fichero incluye todo el código del descompresor, además de la funcion exportada.

///////////////////////////////////////////////////////
//   descomprimir   ==>  funcion GExpand
///////////////////////////////////////////////////////
#include <windows.h>
//#include <stdio.h>
#include "gifdll.h"

///////////////////////////////////////////////////////
//tabla en arbol, cada elemento cuelga de uno anterior
// y añade un nuevo byte
struct SCode{         //elemento en la tabla de codigos
        SCode*   pAnterior;  //puntero al elemento del que cuelga
        unsigned nByte;      //byte que se añade al anterior
};
///////////////////////////////////////////////////////
// Datos que usan las funciones del descompresor
// no se usa ninguna variable global (permite threads)
class CExpand{
  SCode  T[4097];  //tabla de codigos (usa 12 bits como maximo)
  int    nelem;     //numero de elementos actuales en la tabla
  UCHAR  *pOut;     //flujo de salida de pixels
  int     bOut;     //remanente de bits
  int     nOut;     //bytes disponibles
  int     bitspixel;   //numero de bits por pixel (1-2-4-8)
  UCHAR  *pInp;     //flujo de entrada de bits
  int     bInp;     //remanente de bits
  int     nInp;     //bytes que quedan
  int     numbits0;  //numero minimo de bits por codigo
  int   numbits;       //n_bits por codigo actual !
  int clr, eot;   //codigos especiales
public:
  CExpand(GData *pData);
  void  __fastcall Run();
  void GetData(GData *pData);
protected:
  inline void __fastcall ResetTabla();
  inline int  __fastcall InpCode();
  inline void __fastcall OutPixel(int);
  inline void __fastcall OutString(SCode* pCoce);
};
///////////////////////////////////////////////////////
//constructor, inicializa variables y tabla
CExpand::CExpand(GData *pData)
{
        //buffer de salida de pixels
        pOut      = pData->pDest;
        nOut      = pData->nDest;
        bOut      = 0;
        bitspixel = pData->nBitsDest;
        //buffer de entrada de codigos
        pInp      = pData->pSourc;
        nInp      = pData->nSourc;
        bInp      = 0;
        numbits0  = pData->nBitsSourc + 1;
        //inicializar tabla de codigos 
        int n = 1 << pData->nBitsSourc;
        for(nelem=0;nelem<n;nelem++){
                T[nelem].pAnterior = NULL;
                T[nelem].nByte     = nelem;
        }
        clr = nelem;        //codigo de borrado
        eot = nelem + 1;    //fin de datos
        ResetTabla();           //reset punteros de tabla
}
///////////////////////////////////////////////
//refrescar descipcion de buffers
void CExpand::GetData(GData *pData)
{
        //buffer de salida de pixels
        if(bOut) {nOut;pOut++;}
        pData->pDest = pOut;
        pData->nDest = nOut;
        //buffer de entrada de codigos
        if(bInp) {nInp--;pInp++;}
        pData->pSourc = pInp;
        pData->nSourc = nInp;
}
///////////////////////////////////////////////////////
// resetear la tabla a su tamaño minimo
void __fastcall CExpand::ResetTabla()
{
        nelem   = clr + 2;
        numbits = numbits0;
}
///////////////////////////////////////////////////////
//expandir un string de la tabla (rutina recursiva)
void __fastcall CExpand::OutString(SCode* pCode)
{
        if(pCode->pAnterior) OutString(pCode->pAnterior);
        else{ //colabora para añadir un elemento a la tabla
                T[nelem - 1].nByte  = 
                T[nelem].nByte      = pCode->nByte;
        }
        OutPixel(pCode->nByte); //envia pixel a buffer de salida
}
///////////////////////////////////////////////////////
//entrada de un código (tamaño variable)
int  __fastcall CExpand::InpCode()
{
        unsigned c = *(unsigned*) pInp; //lee siguientes bytes
        c >>=  bInp;                            //quita los bits ya usados
        c  &=   (1 << numbits) - 1; //conserva los bits necesarios
        bInp += numbits;                //lleva la cuenta de bits usados        
        while(bInp >= 8){               //y si pasan de 8
                bInp -= 8;                      //actualiza el contador 
                if(nInp-- < 0) throw(GER_INPDATA);
                pInp++;                         //y el puntero
        }
//      printf("%X ", c);
        return c;               //Devuelve el código 
}
///////////////////////////////////////////////////////
// salida de un pixel al buffer de salida
void __fastcall CExpand::OutPixel(int b)
{
        if(bitspixel == 8){ //si pixel==byte ==> es mas rápido
                if(nOut-- < 0) throw(GER_OUTDATA);
                *pOut++ = (UCHAR) b;
                return;
        }
        *pOut = (UCHAR)((*pOut << bitspixel) | b); //salida de bits
        bOut  += bitspixel;
        if(bOut >= 8){                  //actualizacion del puntero y el contador
                bOut -= 8;
                if(nOut-- < 0) throw(GER_OUTDATA);
                pOut++;
        }
}
///////////////////////////////////////////////////////
//Descompresor
void __fastcall CExpand::Run()
{
        unsigned c;
        unsigned EOT=eot, CLR=clr; //en local, es más rápido
        while(1){                               //bucle de trabajo
                c = InpCode();          //lee un código
                if(c == EOT) break;     //hasta detectar el fin 
                if(c == CLR){           //si es código de reset-tabla
                        ResetTabla();   //borrar la tabla
                        continue;               //y volver a comenzar
                }
                if(c >= (unsigned) nelem) throw(GER_CORRUPT);
                OutString(T[nelem].pAnterior = &T[c]);  //espande tabla y codigo
                if(nelem < 4096){       //hacer efectiva la extension de la tabla
                        if((nelem & (nelem-1)) == 0
                                && numbits < 12)        numbits++;
                        nelem++;
                }
        }
}
///////////////////////////////////////////////////////
//funcion pública para descomprimir
PUBLIC(BOOL) GExpand(GData* pData)
{
        pData->nTime = GetTickCount();
        CExpand E(pData);
        try{
                E.Run();
                pData->nError == GER_OK;
        }
        catch(int n){
                pData->nError = n;
        }
        E.GetData(pData);
        pData->nTime = GetTickCount() - pData->nTime;
        return pData->nError == GER_OK;
}
 

GIFDLL.H

    Define extructuras de datos, declara las funciones públicas, etc... Este fichero sirve tambien para que las aplicaciones externas desarrolladas en CPP puedan usar la DLL. Todos los ficheros CPP de este proyecto incluyen una directiva #include "gifdll.h"

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//
//  IMPLEMENTACION DEL METODO DE COMPRESION/DESCOMPRESION
//  USADO POR LOS FICHEROS GIF. 
//  
//  Atencion: La implementacion de este algoritmo, incluso en
//            programas freeware, ES ILEGAL. 
//
//  El autor  describe el algoritmo y su implementacion únicamente
//  con fines educativos. Para implementar este método de compresion
//  en un programa, es necesario ponerse en contacto con la empresa
//  que detenta los derechos sobre el algoritmo y obtener una licencia. 
//  
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//funciones exportadas compilador borland c++
#ifdef __BORLANDC__
  #define PUBLIC(tipo)  extern "C"  tipo WINAPI _export
#endif
//funciones exportadas compilador microsoft vc++
#ifdef _MSC_VER
  #define PUBLIC(tipo)  extern "C" __declspec(dllexport) tipo WINAPI
#endif
//no se ha probado con otros compiladores
#ifndef PUBLIC
  #error Falta definir simbolo PUBLIC
#endif

//funciones de apoyo a VB  => alloc/free memoria, ....
PUBLIC(void*) AllocBuffer(long size);
PUBLIC(void*) ReallocBuffer(void* dir, long size);
PUBLIC(void)  FreeBuffer(void* dir);
PUBLIC(LPVOID) GetDirec(LPVOID dir);
PUBLIC(VOID) CopyMemo(PVOID Dest,PVOID Source, DWORD Length);


/////////////////////////////////////////////////////////////
// define buffers de entrada y salida para varias funciones
struct GData{
        UCHAR* pSourc;      //direccion fuente de datos
        ULONG  nSourc;          //nº bytes fuente de datos
        ULONG  nBitsSourc;      //nº bits por pixel o por código
        UCHAR* pDest;       //direccion destino de datos
        ULONG  nDest;           //nº bytes destino de datos
        ULONG  nBitsDest;       //nº bits por pixel o por código
        ULONG  nTime;   //return T= milisegundos empleados
        ULONG  nError;  //return numero de error
};
// errores devueltos (nError)
#define GER_OK       0   // no error
#define GER_OUTDATA  1   //output overflow 
#define GER_INPDATA  2   //intput overflow
#define GER_CORRUPT  3   //error codigo-ilegal


PUBLIC(BOOL) GExpand(GData* pData);
PUBLIC(BOOL) GCompress(GData* pData);


GIFDLL.DEF

    Declara las funciones exportadas para que el linker las haga públicas.

 
EXPORTS
        
        GExpand
        GCompress

        AllocBuffer
        ReallocBuffer
        FreeBuffer
        GetDirec
        CopyMemo


GIFDLL.BAS

    Este fichero contiene las declaraciones necesarias para usar la DLL en Visual Basic, este módulo se agrega a los proyectos VB que usen la DLL, no es necesario incluir este fichero en el proyecto VC.

'///////////////////////////////////////////////////////////////////////
'///////////////////////////////////////////////////////////////////////
'//
'//  IMPLEMENTACION DEL METODO DE COMPRESION/DESCOMPRESION
'//  USADO POR LOS FICHEROS GIF.
'//
'//  Atencion: La implementacion de este algoritmo, incluso en
'//            programas freeware, ES ILEGAL.
'//
'//  El autor  describe el algoritmo y su implementacion únicamente
'//  con fines educativos. Para implementar este método de compresion
'//  en un programa, es necesario ponerse en contacto con la empresa
'//  que detenta los derechos sobre el algoritmo y obtener una licencia.
'//
'//////////////////////////////////////////////////////////////////////
'//////////////////////////////////////////////////////////////////////
'//funciones de apoyo a VB  => alloc/free memoria, ....
Declare Function AllocBuffer Lib "GIFDLL.dll" (ByVal size As Long) As Long
Declare Function ReallocBuffer Lib "GIFDLL.dll" (ByVal dir As Long, ByVal size As Long) As Long
Declare Sub FreeBuffer Lib "GIFDLL.dll" (ByVal dir As Long)
Declare Function GetDirec Lib "GIFDLL.dll" (variable As Any) As Long
Declare Function GetDirString Lib "GIFDLL.dll" Alias "GetDirec" (ByVal variable As String) As Long
Declare Sub CopyMemo Lib "GIFDLL.dll" (ByVal destino As Long, ByVal fuente As Long, ByVal size As Long)
Declare Sub CopyFromString Lib "GIFDLL.dll" Alias "CopyMemo" (ByVal destino As Long, ByVal fuente As String, ByVal size As Long)
Declare Sub CopyToString Lib "GIFDLL.dll" Alias "CopyMemo" (ByVal destino As String, ByVal fuente As Long, ByVal size As Long)

'//
'/////////////////////////////////////////////////////////////
'// define buffers de entrada y salida para varias funciones
Type GData
        pSourc As Long     '//direccion fuente de datos
        nSourc As Long     '//nº bytes fuente de datos
        nBitsSourc As Long '//nº bits por pixel o por código
        pDest As Long      '//direccion destino de datos
        nDest As Long      '//nº bytes destino de datos
        nBitsDest As Long  '//nº bits por pixel o por código
        nTime As Long      '//return T= milisegundos empleados
        nError As Long     '//return numero de error
End Type
'// errores devueltos (nError)
Const GER_OK = 0        '// no error
Const GER_OUTDATA = 1   '//output overflow
Const GER_INPDATA = 2   '//intput overflow
Const GER_CORRUPT = 3   '//error codigo-ilegal
'
'funciones para comprimir/descomprimir
'
Declare Function GExpand Lib "GIFDLL.dll" (estructura As GData) As Long
Declare Function GCompress Lib "GIFDLL.dll" (estructura As GData) As Long



© info3@maicas.net