Bueno, en un proyecto he tenido que copiar un fichero de un sitio a otro,
si bueno teniamos la funcion MyCopyFile() que teniamos implementada en
Fivewin de la siguiente manera:
DLL32 FUNCTION MYCOPYFILE( lpExistingFileName AS STRING, lpNewFileName AS STRING, bFailIfExists AS LONG) AS LONG;
PASCAL FROM "CopyFileA" LIB "kernel32.dll"Dicha funcion, para copiar ficheros de 1 o 2 megas, funciona muy bien, porque
da tiempo a nuestra aplicaci贸n que no se vuelva con un '( No responde )'.
Si no lo crees, muy simple, intenta copiar un fichero de 100 Megas, y me cuentas
B谩sicamente, es porque nosotros HEMOS PERDIDO TOTALMENTE el control sobre nuestra
aplicacion, y no podemos recibir/enviar mensajes a Windows en que punto estamos.
Esto tiene f谩cil soluci贸n, nos hacemos nuestra propia funci贸n CopyFile().
El mayor inconveniente es que tenemos que hacerla
驴 Como podemos hacerlo entonces ? Muy simple usando la funcion CopyFileEx(), disponible en el API win32.
Dicha funci贸n no funciona bajo los Windows 98 o similares, est谩is advertidos, o eso dicen las malas lenguas.
Bien, sin m谩s dilaciones vamos a realizar la implementaci贸n, y eso si,
aqui vamos a usar C, por cuesti贸n de velocidad.
Nuestro prototipo
CopyFileEx( Fichero_Origen, Fichero_Destino, bCodeblock ) --> nResult
Fichero_Origen y Fichero_Destino no necesitan explicaci贸n.
bCodeblock , es un bloque de c贸digo que nos va a pasar ;
{ |nPorcentaje, nTotal, nTransferido | MyFunction( nPorcentaje, nTotal, nTransferido ) }
Un ejemplo de llamada;
if ( COPYFILEEX ( cFile_Path_MDB , cFile_Path_Repara+"\TPVMAL.MDB", {|x,y,z| pasa(x,y,z) } ) == 0 )
? "MAL"
endifAh!, Ahora puedes ver, que encima vamos a poder montar una progressbar ,
por ejemplo, para ir mostrando el % que va quedando, es el primer par谩metro,
que simplemente resulta de ;
nPorcentaje = nTransferido * 100 / nTotal
Lo he pasado como par谩metro al codeblock, porque de esta manera, ya lo tienes
calculado a nivel de C, no perdiendo m谩s tiempo.
Lo importante es que puedes crear una funcion como;
STATIC s_lCancel := .F.
#define PROGRESS_CONTINUE 0
#define PROGRESS_CANCEL 1
STATIC FUNCTION PASA( nPorcentaje, nTotal, nTransferido )
static nPasa := 0
if nPasa > 10
SysRefresh()
nPasa := 0
endif
nPasa++
oProgress:SetPos( nPorcentaje )
return( if( s_lCancel, PROGRESS_CANCEL, PROGRESS_CONTINUE ) )Uy! 驴 Pero que ven tus ojitos!! ? Si , PUEDES CANCELAR tambi茅n lo que
estas copiando,
por ejemplo, cr茅eme.
En este caso, por ejemplo, puedes poner un bot贸n similar a esto;
REDEFINE BUTTON oBtn ACTION ( s_lCancel := .T. ) ID 110 OF oWnd
El cambiar el estado de la variable static s_lCancel, simplemente har谩
que cuando el codeblock se vuelva a ejecutar, lo cancelar谩.
Ahora bien, todo esto no es posible sin el codigo fuente de C, asi
que dejo paso al codigo fuente;
#pragma BEGINDUMP
#include <windows.h>
#include <stdio.h>
#include "hbapi.h"
#include "item.api"
#include "hbapiitm.h"
#include "hbvm.h"
#include "hbapiitm.h"
/*
Convertimos un valor LARGE_INTEGER a double
*/
double clarge2int( DWORD Lo, DWORD Hi )
{
double dblLo, dblHi;
double ret;
if( Lo < 0 ){
dblLo = 2 ^ 32 + Lo ;
} else {
dblLo = Lo;
}
if( Hi < 0 ) {
dblHi = 2 ^ 32 + Hi;
} else {
dblHi = Hi;
}
ret = ( dblLo + dblHi);
return( ret );
}
DWORD CALLBACK CopyProgressRoutine(
LARGE_INTEGER TotalFileSize,
LARGE_INTEGER TotalBytesTransferred,
LARGE_INTEGER StreamSize,
LARGE_INTEGER StreamBytesTransferred,
DWORD dwStreamNumber,
DWORD dwCallbackReason,
HANDLE hSourceFile,
HANDLE hDestinationFile,
LPVOID pCallback_Progress
)
{
double TotalSize = clarge2int( TotalFileSize.u.LowPart, TotalFileSize.u.HighPart );
double TotalBytesTrans = clarge2int( TotalBytesTransferred.u.LowPart, TotalBytesTransferred.u.HighPart );
double percent = TotalBytesTrans * 100 / TotalSize ;
if( pCallback_Progress ) {
hb_vmPushSymbol( &hb_symEval );
hb_vmPush( pCallback_Progress );
hb_vmPushDouble( percent,1 );
hb_vmPushDouble( TotalSize,1 );
hb_vmPushDouble( TotalBytesTrans,1 );
hb_vmSend( 3 );
return( hb_parni( -1 ) );
}
return PROGRESS_CONTINUE;
}
HB_FUNC( COPYFILEEX )
{
LPCTSTR lpExistingFileName = hb_parc( 1 );
LPCTSTR lpNewFileName = hb_parc( 2 );
LPPROGRESS_ROUTINE lpProgressRoutine = ( void * )CopyProgressRoutine ;
LPBOOL pbCancel = NULL;
DWORD dwCopyFlags;
BOOL ret;
PHB_ITEM pCallback_Progress;
if( ! ISNIL( 3 ) ) {
pCallback_Progress = hb_itemNew( hb_param( 3, HB_IT_ANY ) );
}
ret = CopyFileEx( lpExistingFileName, lpNewFileName, lpProgressRoutine, pCallback_Progress, pbCancel, NULL );
hb_retni( ret );
hb_itemRelease( (PHB_ITEM) pCallback_Progress );
}
#pragma ENDDUMPLo que m谩s me a costado no a sido la implementaci贸n de la funcion en si
misma, si no, convertir un LARGE_INTEGER en un valor double.
No es una funci贸n portable del API de Windows para Harbour, es una adaptaci贸n
a una necesidad en concreto, si lo quereis hacer compatible con el API de
Windows, ahi ten茅is un punto de partida, por mi parte no pienso mejorarla
m谩s.
Antonio, seria interesante portar esta funcion a Fivewin.
Los warnings de C, son porque no se usan ciertos parametros de la callback, no se como decirle al compilador que no los muestre.
Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)