Newsgroup: it.comp.lang.c++
Titolo: Re: Come evitare file temporaneo da 34 Gb?

 I/O ma certo, non vorrei introdurre un collo di bottiglia.
Non è che con queste quantità di dati ti conviene prendere una libreria
di database tosta, tipo PostgreSQL, o anche solo SQLite? Se non conosci
SQL ti posso dire che si impara alla svelta (almeno le prime cose che
servono per leggere e scrivere un record alla volta). In questo modo
scarichi il problema della portabilità su questi altri progetti (che con
tutta probabilità l'hanno già affrontato e risolto al posto tuo) e a te
rimane solo da chiamare un'API invece che preoccuparti dell'implementazione.
Se l'I/O porta via poco tempo rispetto alle elaborazioni, il peso
aggiuntivo dell'interfaccia al database probabilmente non sarà un problema.
Ciao,
- -Federico
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (GNU/Linux)
Comment: Using GnuPG with SUSE - 
http://enigmail.mozdev.org
iD8DBQFIY8n8BIpu+y7DlLcRAjInAJ9amUVfhEA4MDMEHfNWNUE6WslLJACglyDH
Ym4k4ZBQwUKLB63hES6sPQo=
=P7FS
-----END PGP SIGNATURE-----

 grandezza! :(
La documentazione di SQLite è in rete:
http://www.sqlite.org/docs.html
Secondo quello che c'è scritto, il limite pratico indicato è di «qualche
dozzina di GB», quindi sei un po' sul limite ma dovrebbe andar bene.
Direi che per ognuno degli 8000 insiemi di dati puoi fare una tabella
apposita, nella quale inserisci le coppie di dati in colonna. Entrambe
le colonne saranno di tipo REAL (anche se tecnicamente SQLite salva
tutto come stringa, internamente).
NOTA: se uno dei due campi è univoco (per esempio si tratta di dati del
tipo (x, y) dove y= f(x), dovresti assolutamente rendere la variabile
indipendente la chiave primaria. Ciò accelererà moltissimo l'accesso ai
dati, e senza chiave primaria alcune interrogazioni complesse vanno in
gurumeditation.
Questi sono dei comandi SQL comuni, probabilmente ci sono funzioni più
dirette nell'API per C/C++:
Creare una tabella:
CREATE TABLE pippo (x REAL PRIMARY KEY, y REAL);
Inserirci i dati:
INSERT INTO pippo VALUES(val_x, val_y);
Leggerli:
SELECT x, y FROM pippo;
In bocca al lupo,
- -Federico
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (GNU/Linux)
Comment: Using GnuPG with SUSE - 
http://enigmail.mozdev.org
iD8DBQFIZKaGBIpu+y7DlLcRAoImAJ9iBNyLIPJJnywT0Ihgl1X83GvTbACgqDzb
6reFTUnR1S0vpA+zqG5lLdg=
=5Soy
-----END PGP SIGNATURE-----

Ciao ... ho riconosciuto la firma in calce.
Ti hanno dato tutti delle dritte sicuramente migliori della 
mia, in quanto generali e già su strada. Ti dico cmq la mia 
in quanto ho incontrato il problema dell'insufficienza dei 
long e dei file troppo grandi, anche se volevo solo copiarli 
e confrontarli, niente di che quindi rispetto alle tue 
computazioni.
La mia "dritta" è relativa solo a windows (ma suppongo che 
di simili debbano essere possibili con ogni OS che supporti 
file più lunghi di 2 GB ... e quale non lo fa oggi ?)
La prima cosa è :
esiste nei compilatori microsoft il tipo  __int64   che ha 
un range stellare. Puoi compattarlo in una  union  con  una 
struct  contenente due normali  "long",  alto e basso, per 
scriverli o leggerli singolarmente alla bisogna.
Esiste anche il tipo LongLong, ma non ricordo se sia un 
alias di __int64  o  della struct di due long.
Cmq internamente il motore di gestione file a livello di 
kernel, usa puntatori a 64 bit, per cui non hai che da 
scrivere quelle due tre funzioni di conversione per 
manipolare interi lunghi e dialogare con l'OS.
Ora ho trovato un frammento di un programma misto, VB+CPP 
con cui confrontavo liste di files. Non ho moltissima voglia 
di spulciare quel che ti poteva eventualmente interessre e 
cosa no : ti incollo tutto il nocciolo della DLL in C++, ci 
saranno di certo alcune classi per convertire i longlong, 
per chiamare le API a 64 analoghe a fseek. Per leggere uso 
FileRead della API di windows.
Abbi pazienza se non ho tempo di estrarre una parte 
consistente di soltanto quel che potrebbe servire a te (ci 
sono un sacco di robacce per le callback, con cui la DLL in 
C++ richiamava il programma VB per notificare a che punto 
era della fatica di confrontare file di vari GB dando una 
sensazione di interattività all'utente.
ciao
Soviet
Per chiunque non interessato
IL POST FINISCE QUI
------------------------------------------------------------------
------------------------------------------------------------------
// FileComparatorLib_00.cpp : Defines the entry point for 
the DLL application.
//#include <stdio.h>
//#include <io.h>
#include "stdafx.h"
#include "FileComparatorLib_00.h"
#ifndef _CRTIMP
#ifdef  _DLL
#define _CRTIMP __declspec(dllimport)
#else   /* ndef _DLL */
#define _CRTIMP
#endif  /* _DLL */
#endif  /* _CRTIMP */
extern "C" _CRTIMP int __cdecl printf (const char *, ...);
extern "C" _CRTIMP int __cdecl sprintf (char *buffer, const 
char *format, ... );
////////////////////////////////////////////////////////////////////////
#define Stringize(Symbol) ((const unsigned char *)(#Symbol))
////////////////////////////////////////////////////////////////////////
ULONG RtlCompareMemory (IN PVOID  Source1, IN PVOID 
Source2, IN ULONG  Length);
////////////////////////////////////////////////////////////////////////
struct StructReturnCodes
{
	const char * const 
Confronta_Coppia_Files___Errore_Numero_Di_Filenames_Parserizzati_Diverso_Da_Quanto_Indicato;
	const char * const 
Confronta_Coppia_Files___Errore_Numero_Di_Filenames_Dispari_Necessarie_Coppie;
	const char * const 
Confronta_Coppia_Files___Errore_Spazio_Riservato_Array_Risposte_Diverso_Da_Richieste_Coppie_Filenames_Confronti;
	const char * const 
Confronta_Coppia_Files___Errore_File_Listing_Di_Input_Errato_Manca_Termine_Di_Paragone;
	const char * const 
Confronta_Coppia_Files___Errore_File_Listing_Di_Input_Troppo_Grande;
	const char * const 
Confronta_Coppia_Files___Errore_Chiusura_File_Input_Listing;
	const char * const 
Confronta_Coppia_Files___Numero_Confronti_Da_Eseguire_Superiore_A_Size_Array_Log_Esito;
	const char * const 
Confronta_Coppia_Files___Errore_Dimensioni_File_Listing_Di_Input;
	const char * const 
Confronta_Coppia_Files___Errore_Apertura_Input_File_Listing;
	const char * const 
Confronta_Coppia_Files___Errore_Apertura_Output_File_Esito_Confronti;
	const char * const 
Confronta_Coppia_Files___Errore_Apertura_File_One;
	const char * const 
Confronta_Coppia_Files___Errore_Apertura_File_Two;
	const char * const 
Confronta_Coppia_Files___Errore_Lettura_Input_File_Listing;
	const char * const 
Confronta_Coppia_Files___Errore_Scrittura_Output_File_Esito_Confronti;
	const char * const 
Confronta_Coppia_Files___Errore_Lettura_File_One;
	const char * const 
Confronta_Coppia_Files___Errore_Lettura_File_Two;
	const char * const Confronta_Coppia_Files___Bad_Size_File_One;
	const char * const Confronta_Coppia_Files___Bad_Size_File_Two;
	const char * const 
Confronta_Coppia_Files___File_One_Piu_Lungo_Di_File_Two_Ma_Uguali_Contenuti;
	const char * const 
Confronta_Coppia_Files___File_One_Piu_Corto_Di_File_Two_Ma_Uguali_Contenuti;
	const char * const 
Confronta_Coppia_Files___File_One_E_File_Two_Sono_Uguali_E_Identici;
	const char * const 
Confronta_Coppia_Files___File_One_E_File_Two_Sono_Diversi;
	const char * const 
Confronta_Coppia_Files___Errore_Chiusura_File_One;
	const char * const 
Confronta_Coppia_Files___Errore_Chiusura_File_Two;
	const char * const 
Confronta_Coppia_Files___Errore_Chiusura_Entrambi_I_Files;
	const char * const 
Confronta_Coppia_Files___Errore_Indefinito_I_O;
	const char * const 
Confronta_Coppia_Files___Errore_Buffer_Lettura_Troppo_Grande;
	const char * const 
Confronta_Coppia_Files___Errore_Buffer_Lettura_Troppo_Piccolo;
	static const __int8 Byte_Esito_Uguali ;
	static const __int8 Byte_Esito_Diversi;
	static const __int8 
Byte_Esito_File_One_Piu_Lungo_Di_File_Two_Ma_Uguali_Contenuti;
	static const __int8 
Byte_Esito_File_One_Piu_Corto_Di_File_Two_Ma_Uguali_Contenuti;
};
////////////////////////////////////////////////////////////////////////
const __int8 StructReturnCodes :: Byte_Esito_Uguali = 0;
const __int8 StructReturnCodes :: Byte_Esito_Diversi = 1;
const __int8 StructReturnCodes :: 
Byte_Esito_File_One_Piu_Lungo_Di_File_Two_Ma_Uguali_Contenuti 
= 2;
const __int8 StructReturnCodes :: 
Byte_Esito_File_One_Piu_Corto_Di_File_Two_Ma_Uguali_Contenuti 
= 4;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
class LongLong
{
public:
	union // anonima
		{
		__int64 Integer64;
		struct  // anonima
			{
			union { __int32 LowInteger32; unsigned long LowUlong; }; 
// anonima : simula algebra signed e unsigned di pari 
ampiezza di bit
			union { __int32 HighInteger32; unsigned long HighUlong; 
}; // anonima : simula algebra signed e unsigned di pari 
ampiezza di bit
			};
		};
	//operator const __int64 () const { return Integer64; }
	// converte da LongLong all'unico tipo che lo supporti 
appieno : __int64
	operator __int64 () const { return Integer64; }
	// costruttori (convertono da altri tipi a LongLong
	LongLong () : LowInteger32 (0), HighInteger32 (0) { return; }
	LongLong (const __int32 Low, const __int32 High) : 
LowInteger32 (Low), HighInteger32 (High) { return; }
	LongLong (const unsigned long Low, const unsigned long 
High) : LowUlong (Low), HighUlong (High) { return; }
	LongLong (const __int32 Low) : LowInteger32 (Low), 
HighInteger32 (0) { return; }
	LongLong (const __int64 HugeNumber) : Integer64 
(HugeNumber) { return; }
 
	// operatori	
	LongLong & operator = (const __int32 Low) { HighInteger32 = 
0; LowInteger32 = Low; return (* this); }
	LongLong & operator += (const __int32 Low) { LongLong Tmp 
(Low); Integer64 += Tmp . Integer64;  return (* this); }
	LongLong & operator -= (const __int32 Low) { LongLong Tmp 
(Low); Integer64 -= Tmp . Integer64;  return (* this); }
 
	__int64 operator + (const __int32 Low) { LongLong Tmp 
(Low); return (Integer64 + Tmp . Integer64); }
	__int64 operator - (const __int32 Low) { LongLong Tmp 
(Low); return (Integer64 - Tmp . Integer64); }
 
	unsigned operator == (const __int32 Low) { LongLong Tmp 
(Low); return (Integer64 == Tmp . Integer64); }
	unsigned operator != (const __int32 Low) { LongLong Tmp 
(Low); return (Integer64 != Tmp . Integer64); }
	unsigned operator > (const __int32 Low) { LongLong Tmp 
(Low); return (Integer64 > Tmp . Integer64); }
	unsigned operator >= (const __int32 Low) { LongLong Tmp 
(Low); return (Integer64 >= Tmp . Integer64); }
	unsigned operator < (const __int32 Low) { LongLong Tmp 
(Low); return (Integer64 < Tmp . Integer64); }
	unsigned operator <= (const __int32 Low) { LongLong Tmp 
(Low); return (Integer64 <= Tmp . Integer64); }
	inline LongLong & operator = (const __int64 Huge) { 
Integer64 = Huge; return (* this); }
	inline LongLong & operator += (const __int64 Huge) { 
Integer64 += Huge;  return (* this); }
	inline LongLong & operator -= (const __int64 Huge) { 
Integer64 -= Huge;  return (* this); }
	inline __int64 operator + (const __int64 Huge) { return 
(Integer64 + Huge); }
	inline __int64 operator - (const __int64 Huge) { return 
(Integer64 - Huge); }
 
	inline unsigned operator == (const __int64 Huge) { return 
(Integer64 == Huge); }
	inline unsigned operator != (const __int64 Huge) { return 
(Integer64 != Huge); }
	inline unsigned operator > (const __int64 Huge) { return 
(Integer64 > Huge); }
	inline unsigned operator >= (const __int64 Huge) { return 
(Integer64 >= Huge); }
	inline unsigned operator < (const __int64 Huge) { return 
(Integer64 < Huge); }
	inline unsigned operator <= (const __int64 Huge) { return 
(Integer64 <= Huge); }
};
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
const __int64 ConMaxReadBufferSize = 67108864L;
const __int64 ConMinReadBufferSize = 1024L;
const __int64 ConHugeZERO = 0x0000000000000000;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
inline __int64 MakeLongLong (const __int32 low, const 
__int32 high)
	{ return ((__int64)(low) | ((__int64)(high)) << 32); }
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
__int64 Min (const __int64 A, const __int64 B) { return ((A 
< B) ? (A) : (B)); }
__int64 Min (const LongLong A, const __int64 B) { return ((A 
. Integer64 < B) ? (A . Integer64) : (B)); }
__int64 Min (const __int64 A, const LongLong B) { return ((A 
< B . Integer64) ? (A) : (B . Integer64)); }
__int64 Min (const LongLong A, const LongLong B) { return 
((A . Integer64 < B . Integer64) ? (A . Integer64) : (B . 
Integer64)); }
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
__int64 Max (const __int64 A, const __int64 B) { return ((A 
 > B) ? (A) : (B)); }
__int64 Max (const LongLong A, const __int64 B) { return ((A 
. Integer64 > B) ? (A . Integer64) : (B)); }
__int64 Max (const __int64 A, const LongLong B) { return ((A 
 > B . Integer64) ? (A) : (B . Integer64)); }
__int64 Max (const LongLong A, const LongLong B) { return 
((A . Integer64 > B . Integer64) ? (A . Integer64) : (B . 
Integer64)); }
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//typedef struct _WIN32_FILE_ATTRIBUTE_DATA
//	{
//		DWORD      dwFileAttributes;
//		FILETIME   ftCreationTime;
//		FILETIME   ftLastAccessTime;
//		FILETIME   ftLastWriteTime;
//		DWORD      nFileSizeHigh;
//		DWORD      nFileSizeLow;
//	}
//WIN32_FILE_ATTRIBUTE_DATA, * LPWIN32_FILE_ATTRIBUTE_DATA;
////////////////////////////////////////////////////////////////////////
//  LPCTSTR lpFileName : pointer to string that specifies a 
file or directory
//  GET_FILEEX_INFO_LEVELS fInfoLevelId : value that 
specifies the type of attribute information to obtain
//  LPWIN32_FILE_ATTRIBUTE_DATA  lpFileInformation : pointer 
to buffer to receive attribute information
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
unsigned GetFileSize_64 (const char * lpFileName, __int64 * 
ptrFileSize)
{
static WIN32_FILE_ATTRIBUTE_DATA  Attribs;
(* ptrFileSize) = (__int64)(0);
if (GetFileAttributesEx (lpFileName, GetFileExInfoStandard, 
(void *)(& Attribs)) == false)
	return 0;
LongLong Tmp (Attribs . nFileSizeLow, Attribs . nFileSizeHigh);
(* ptrFileSize) = Tmp . Integer64;
return 1;
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
__int64 GetHandleSize_64 (HANDLE hf)
{
LongLong Li;
Li . LowUlong = GetFileSize (hf, & Li .HighUlong);
if (Li . LowUlong == 0xFFFFFFFF)
	Li . Integer64 = (__int64)(0);
return (Li . Integer64);
};
////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
////  GESTIONE  MECCANISMO  REFRESH  CALLBACK  INDICATORI 
AVANZAMENTO ///
//////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
struct StructArgsCallBackSingoloIndicatoreCompletamento
	{ double TotalTaskToDo, CurrentlyDone; };
////////////////////////////////////////////////////////////////////////
struct StructArgsCallBackTuttiGliIndicatori
	{
	StructArgsCallBackSingoloIndicatoreCompletamento 
Avanzamento_ByteDiFileBytes;
	StructArgsCallBackSingoloIndicatoreCompletamento 
Avanzamento_FileDiTotFiles;
	StructArgsCallBackSingoloIndicatoreCompletamento 
Avanzamento_BytesDiTotalBytes;
	};
////////////////////////////////////////////////////////////////////////
// istanziazione variabile di salvataggio (garantisce 
dall'errata inizializzazione)
static StructArgsCallBackTuttiGliIndicatori 
zzz_hidden_CallBackIndicatori;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
typedef long (__stdcall * TypeVB_CallBack) 
(StructArgsCallBackSingoloIndicatoreCompletamento *);
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
struct StructGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento
	{
	// dati statici condivisi
	static StructArgsCallBackTuttiGliIndicatori * 
DatiDiTuttiGliIndicatori;
	// handlers esterni (routine grafiche dell'EXE in VB)
	static TypeVB_CallBack  VB_CallBackFunz_ByteDiFileBytes;
	static TypeVB_CallBack  VB_CallBackFunz_File_Di_Files;
	static TypeVB_CallBack  VB_CallBackFunz_ByteDiTotalBytes;
	static unsigned AreCallBaksRegistered; // flag che segnala 
l'avvenuta inizializzazione CALLBACK dall'esterno
	// funzioni membro che semplicemente delegano le CALLBACK 
dell'EXE in VB
	inline void RefreshStatus_ByteDiFileBytes ()
		{
		if (AreCallBaksRegistered != 0)
			(* VB_CallBackFunz_ByteDiFileBytes) (& 
(DatiDiTuttiGliIndicatori -> Avanzamento_ByteDiFileBytes));
		return;
		}
	inline void RefreshStatus_File_Di_Files ()
		{
		if (AreCallBaksRegistered != 0)
			(* VB_CallBackFunz_File_Di_Files) (& 
(DatiDiTuttiGliIndicatori -> Avanzamento_FileDiTotFiles));
		return;
		}
	inline void RefreshStatus_ByteDiTotalBytes ()
		{
		if (AreCallBaksRegistered != 0)
			(* VB_CallBackFunz_ByteDiTotalBytes) (& 
(DatiDiTuttiGliIndicatori -> Avanzamento_BytesDiTotalBytes));
		return;
		}
	};
////////////////////////////////////////////////////////////////////////
// inizializza a zero tutto
unsigned 
StructGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento :: 
AreCallBaksRegistered = 0;
StructArgsCallBackTuttiGliIndicatori * 
StructGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento :: 
DatiDiTuttiGliIndicatori = & zzz_hidden_CallBackIndicatori;
TypeVB_CallBack 
StructGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento :: 
VB_CallBackFunz_ByteDiFileBytes = 0;
TypeVB_CallBack 
StructGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento :: 
VB_CallBackFunz_ByteDiTotalBytes = 0;
TypeVB_CallBack 
StructGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento :: 
VB_CallBackFunz_File_Di_Files = 0;
////////////////////////////////////////////////////////////////////////
// ISTANZIA UN GESTORE
////////////////////////////////////////////////////////////////////////
static StructGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento
	GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
extern "C" FILECOMPARATORLIB_00_API long __stdcall
fzRegisterCallBackNotifyingAddresses
(
StructArgsCallBackTuttiGliIndicatori * CallBackArgs, //dati
TypeVB_CallBack  VB_Proc_Address_ByteDiFileBytes,
TypeVB_CallBack  VB_Proc_Address_File_Di_Files,
TypeVB_CallBack  VB_Proc_Address_ByteDiTotalBytes
)
{
// chiamata a cura dell'EXE in VB, per fornire gli indirizzi 
delle sue procedure
// callback grafiche e dei dati da refreshare a cura di 
questa DLL
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
AreCallBaksRegistered = 0;
if ((CallBackArgs == 0) || (VB_Proc_Address_ByteDiFileBytes 
== 0) || (VB_Proc_Address_File_Di_Files == 0) || 
(VB_Proc_Address_ByteDiTotalBytes == 0))
	return 0;
// prova a comunicare coi processi prima di registrarli
if ((* VB_Proc_Address_ByteDiFileBytes) (& (CallBackArgs -> 
Avanzamento_ByteDiFileBytes)) == 0)
	return 0;
if ((* VB_Proc_Address_File_Di_Files) (& (CallBackArgs -> 
Avanzamento_FileDiTotFiles)) == 0)
	return 0;
if ((* VB_Proc_Address_ByteDiTotalBytes) (& (CallBackArgs -> 
Avanzamento_BytesDiTotalBytes)) == 0)
	return 0;
// registra indirizzo dati SHARED tra VB EXE e DLL C++
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori = CallBackArgs;
// registra gestori evento asyncroni
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
VB_CallBackFunz_ByteDiFileBytes = 
VB_Proc_Address_ByteDiFileBytes;
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
VB_CallBackFunz_ByteDiTotalBytes = 
VB_Proc_Address_ByteDiTotalBytes;
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
VB_CallBackFunz_File_Di_Files = VB_Proc_Address_File_Di_Files;
// tutto pare funzionare
return 
(GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
AreCallBaksRegistered = 1);
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
long StoreMessageInErrBuffer (const unsigned char * 
ConstMssg, unsigned char * TargetMssg, long TargetSize)
{ // copia AL MASSIMO TargetSize bytes dal messaggio di 
errore originale al buffer di destinazione, se limitato
long Size = (long) strlen ((const char *)(ConstMssg)) + 1; 
// conta anche il null finale
if (Size >= TargetSize)
	Size = TargetSize - 1;
memmove (TargetMssg, ConstMssg, Size);
TargetMssg [Size] = 0;
return Size;
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
char * ScanStringArrayIterator (unsigned Initialize = 0, 
const char * NamesBuffer = 0, unsigned long MaxTotBufferSize 
= 0)
{ // doppia sintassi, senza argomenti per iterazioni 
successive, con tutti i parametri se <<initialize>> != 0, 
per predisporre lo stato valido alle iterazioni
// variabili statiche usate nelle iterazioni successive
static char * OriginalStringArrayAddress;
static char * LastFoundAddress;
static char * EndOfArrayLimit;
// variabili automatiche temporanee
static unsigned long MaxTotBufSize;
char * EndCurrToken;
char * RetVal;
char Byte; unsigned FoundToken;
if (Initialize == 0)
	{
	FoundToken = 0;
	while ((LastFoundAddress < EndOfArrayLimit) && (FoundToken 
== 0))
		{
		Byte = (* LastFoundAddress);
		if ((Byte == 0) || (Byte == '\r') || (Byte == '\n'))
			{
			++ LastFoundAddress; // SKIPS initial contiguous separators
			continue;
			}
		RetVal = EndCurrToken = LastFoundAddress; // salva anche 
valore ritorno
		while ((++ EndCurrToken) < EndOfArrayLimit)
			{
			Byte = (* EndCurrToken);
			if ((Byte == 0) || (Byte == '\r') || (Byte == '\n'))
				{ // interrompe scan alla prima delle tre scelte
				if (Byte != 0) // termina stringa in modo standard
					(* EndCurrToken) = 0;
				LastFoundAddress = EndCurrToken; // vecchio inizio = 
nuova fine
				return RetVal;
				}
			}
		if (FoundToken == 0) return 0;
		}
	if (FoundToken == 0) return 0;
	}
else
	{
	if ((LastFoundAddress = OriginalStringArrayAddress = 
const_cast <char *> (NamesBuffer)) == 0) return 0;
	if ((MaxTotBufSize = MaxTotBufferSize) == 0) return 0;
	EndOfArrayLimit = OriginalStringArrayAddress + MaxTotBufSize;
	// after inited, calls itself !
	return 0;
	}
return 0;
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
long GetNumeroStringheInBuffer (const char * NamesBuffer, 
unsigned long MaxTotBufferSize)
{
long NumItemsFound = 0;
ScanStringArrayIterator (1, NamesBuffer, MaxTotBufferSize);
while (ScanStringArrayIterator () != 0)
	++ NumItemsFound;
return NumItemsFound;
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
struct StructArgsComparazioneCoppiaFiles
	{
	const char * FileNameOne;
	const char * FileNameTwo;
	void * BufUno;
	long BufferSize;
	__int64 TotalBytesCompared;
	unsigned char * RetMsg;
	long MaxRetMsgSize;
	long UsedRetMsgSize;
	__int8 StatoDiversita;
	};
////////////////////////////////////////////////////////////////////////
// INTERFACCIA ESTERNA DELLA DLL
// nome ALIAS per DECLARE in Visual Basic
//                                    _fzCompareFileCouple@4
////////////////////////////////////////////////////////////////////////
//long fzCompareFileCouple
extern "C" FILECOMPARATORLIB_00_API unsigned __stdcall
fzCompareFileCouple (StructArgsComparazioneCoppiaFiles * Args)
{
// ritorna 0 on error, 1 on success (lo stato di errore 
prescinde dall'esito del confronto ! !
// VARIABILI LOCALI
HANDLE HanOne, HanTwo;
__int64 FileSizeOne, FileSizeTwo;
__int64 MaxFileSizeToRead, MaxBuffSize;
__int64 BytesStillLeftToRead;
DWORD NumberOfBytesReaded;
LPVOID BufDue;
int Diversi = 0, Fail = 0;
LongLong SizesOne, SizesTwo, Tmp;
// inizializza a diversi
Args -> StatoDiversita = StructReturnCodes :: 
Byte_Esito_Diversi;
Args -> TotalBytesCompared = (__int64) 0;
// dimezza il buffer per usarlo con entrambi i files
MaxBuffSize = LongLong (((Args -> BufferSize / 2) - 4), 
(__int32)0);
if (MaxBuffSize < ConMinReadBufferSize)
	return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Buffer_Lettura_Troppo_Piccolo), 
Args -> RetMsg, Args -> MaxRetMsgSize), 0);
if (MaxBuffSize >= ConMaxReadBufferSize) // 67108864UL = 64 MB
	return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Buffer_Lettura_Troppo_Grande), 
Args -> RetMsg, Args -> MaxRetMsgSize), 0);
// suddivide la risorsa condivisa
BufDue = ((char *)(Args -> BufUno)) + MaxBuffSize + 2;
// apre primo dei due files
if ((HanOne = CreateFile (Args -> FileNameOne, GENERIC_READ, 
FILE_SHARE_READ, NULL, OPEN_EXISTING, 
FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, NULL)) 
== NULL)
	return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Apertura_File_One), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
// apre secondo dei due files
if ((HanTwo = CreateFile (Args -> FileNameTwo, GENERIC_READ, 
FILE_SHARE_READ, NULL, OPEN_EXISTING, 
FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, NULL)) 
== NULL)
	{
	CloseHandle (HanOne);
	return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Apertura_File_Two), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
	}
// Legge dimensioni fisiche primo file e converte a __int64
SizesOne . LowUlong = GetFileSize (HanOne, & SizesOne . 
HighUlong);
if (SizesOne . LowUlong == 0xFFFFFFFFL)
	{
	CloseHandle (HanOne); CloseHandle (HanTwo);
	return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Bad_Size_File_One), Args -> RetMsg, 
Args -> MaxRetMsgSize), 0);
	}
FileSizeOne = SizesOne . Integer64;
// Legge dimensioni fisiche secondo file e converte a __int64
SizesTwo . LowUlong = GetFileSize (HanTwo, & SizesTwo . 
HighUlong);
if (SizesOne . LowUlong == 0xFFFFFFFFL)
	{
	CloseHandle (HanOne); CloseHandle (HanTwo);
	return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Bad_Size_File_Two), Args -> RetMsg, 
Args -> MaxRetMsgSize), 0);
	}
FileSizeTwo = SizesTwo . Integer64;
// computo entità utile della parte da confrontare
MaxFileSizeToRead = Min (FileSizeOne, FileSizeTwo);
Args -> StatoDiversita = StructReturnCodes :: 
Byte_Esito_Diversi;
Args -> UsedRetMsgSize = 0;
Tmp = LongLong (0UL, 0UL);
// refresh preliminare indicatori stato di avanzamento e 
callback routine grafica VB
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_ByteDiFileBytes . 
CurrentlyDone = 0.0;
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_ByteDiFileBytes . 
TotalTaskToDo = (double)(MaxFileSizeToRead);
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
RefreshStatus_ByteDiFileBytes ();
if (MaxFileSizeToRead > MaxBuffSize)
	{ // i files sono da leggere A PEZZETTI, non in una sola volta
	BytesStillLeftToRead = MaxFileSizeToRead;
	Diversi = 0;
	do
		{
		// legge file Uno
		if (ReadFile (HanOne, Args -> BufUno, 
(DWORD)(MaxBuffSize), & NumberOfBytesReaded, 0) == 0)
			{
			CloseHandle (HanTwo); CloseHandle (HanOne);
			return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Lettura_File_One), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
			}
		Tmp . LowUlong = NumberOfBytesReaded;
		if (Tmp . Integer64 != MaxBuffSize)
			{
			CloseHandle (HanTwo); CloseHandle (HanOne);
			return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Lettura_File_One), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
			}
		// legge file Due
		if (ReadFile (HanTwo, BufDue, (DWORD)(MaxBuffSize), & 
NumberOfBytesReaded, 0) == 0)
			{
			CloseHandle (HanTwo); CloseHandle (HanOne);
			return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Lettura_File_Two), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
			}
		Tmp . LowUlong = NumberOfBytesReaded;
		if (Tmp . Integer64 != MaxBuffSize)
			{
			CloseHandle (HanTwo); CloseHandle (HanOne);
			return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Lettura_File_Two), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
			}
		// confronta i dati nei buffers
		if (memcmp (Args -> BufUno, BufDue, (size_t)(MaxBuffSize)) 
!= 0)
			{
			Args -> StatoDiversita = StructReturnCodes :: 
Byte_Esito_Diversi;
			break;
			}
		BytesStillLeftToRead -= Tmp . Integer64;
		Args -> TotalBytesCompared += NumberOfBytesReaded;
		// refresh periodico indicatori stato di avanzamento e 
callback routine grafica VB
		GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_ByteDiFileBytes . 
CurrentlyDone += (double)(NumberOfBytesReaded);
		GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
RefreshStatus_ByteDiFileBytes ();
		if (BytesStillLeftToRead <= ConHugeZERO)
			break;
		if (MaxBuffSize > BytesStillLeftToRead)
			 MaxBuffSize = BytesStillLeftToRead;
		}
	while ((BytesStillLeftToRead > ConHugeZERO) && (Diversi == 
0) && (Args -> UsedRetMsgSize == 0));
	// valuta lo stato di uscita dal ciclo di iterazioni di lettura
	if ((Diversi == 0) && (Args -> UsedRetMsgSize == 0))
		Args -> StatoDiversita = StructReturnCodes :: 
Byte_Esito_Uguali;
	// refresh finale indicatori stato di avanzamento e 
callback routine grafica VB
	GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_ByteDiFileBytes . 
CurrentlyDone = 
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_ByteDiFileBytes . 
TotalTaskToDo;
	GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
RefreshStatus_ByteDiFileBytes ();
	}
else // MaxFileSizeToRead <= MaxBuffSize
	{ // i files stanno completamente, giusti o larghi, nel 
buffer di memoria
	MaxBuffSize = MaxFileSizeToRead;
	BytesStillLeftToRead = MaxFileSizeToRead;
	// legge file Uno
	if (ReadFile (HanOne, Args -> BufUno, (DWORD)(MaxBuffSize), 
& NumberOfBytesReaded, 0) == 0)
		{
		CloseHandle (HanTwo); CloseHandle (HanOne);
		return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Lettura_File_One), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
		}
	Tmp . LowUlong = NumberOfBytesReaded;
	if (Tmp . Integer64 != MaxBuffSize)
		{
		CloseHandle (HanTwo); CloseHandle (HanOne);
		return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Lettura_File_One), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
		}
	// legge file Due
	if (ReadFile (HanTwo, BufDue, (DWORD)(MaxBuffSize), & 
NumberOfBytesReaded, 0) == 0)
		{
		CloseHandle (HanTwo); CloseHandle (HanOne);
		return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Lettura_File_Two), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
		}
	Tmp . LowUlong = NumberOfBytesReaded;
	if (Tmp . Integer64 != MaxBuffSize)
		{
		CloseHandle (HanTwo); CloseHandle (HanOne);
		return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Lettura_File_Two), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
		}
	// confronta i dati nei buffers
	if ((Diversi = memcmp (Args -> BufUno, BufDue, 
(size_t)(MaxBuffSize))) == 0)
		Args -> StatoDiversita = StructReturnCodes :: 
Byte_Esito_Uguali;
	else
		Args -> StatoDiversita = StructReturnCodes :: 
Byte_Esito_Diversi;
	Args -> TotalBytesCompared += NumberOfBytesReaded;
	// refresh finale indicatori stato di avanzamento e 
callback routine grafica VB
	GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_ByteDiFileBytes . 
CurrentlyDone = 
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_ByteDiFileBytes . 
TotalTaskToDo;
	GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
RefreshStatus_ByteDiFileBytes ();
	}
Fail = 0;
if (CloseHandle (HanTwo) == 0) Fail |= 1;
if (CloseHandle (HanOne) == 0) Fail |= 2;
if (Args -> UsedRetMsgSize != 0) // controllo errori pregressi
	return 0; // mantiene il messaggio di errore precedente
if (Fail == 3) return (Args -> UsedRetMsgSize = 
StoreMessageInErrBuffer (Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Chiusura_Entrambi_I_Files), 
Args -> RetMsg, Args -> MaxRetMsgSize), 0);
if (Fail == 1) return (Args -> UsedRetMsgSize = 
StoreMessageInErrBuffer (Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Chiusura_File_Two), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
if (Fail == 2) return (Args -> UsedRetMsgSize = 
StoreMessageInErrBuffer (Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Chiusura_File_One), Args -> 
RetMsg, Args -> MaxRetMsgSize), 0);
if (Diversi != 0)
	{
	Args -> StatoDiversita = StructReturnCodes :: 
Byte_Esito_Diversi;
	return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___File_One_E_File_Two_Sono_Diversi), 
Args -> RetMsg, Args -> MaxRetMsgSize), 1);
	}
if (FileSizeOne > FileSizeTwo)
	{
	Args -> StatoDiversita = StructReturnCodes :: 
Byte_Esito_File_One_Piu_Lungo_Di_File_Two_Ma_Uguali_Contenuti;
	return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___File_One_Piu_Lungo_Di_File_Two_Ma_Uguali_Contenuti), 
Args -> RetMsg, Args -> MaxRetMsgSize), 1);
	}
if (FileSizeOne < FileSizeTwo)
	{
	Args -> StatoDiversita = StructReturnCodes :: 
Byte_Esito_File_One_Piu_Corto_Di_File_Two_Ma_Uguali_Contenuti;
	return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___File_One_Piu_Corto_Di_File_Two_Ma_Uguali_Contenuti), 
Args -> RetMsg, Args -> MaxRetMsgSize), 1);
	}
Args -> StatoDiversita = StructReturnCodes :: Byte_Esito_Uguali;
return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___File_One_E_File_Two_Sono_Uguali_E_Identici), 
Args -> RetMsg, Args -> MaxRetMsgSize), 1);
};
////////////////////////////////////////////////////////////////////////
// INTERFACCIA ESTERNA DELLA DLL
// nome ALIAS per DECLARE in Visual Basic
// 
_fzCompareManyFilesFromFileListing@32
////////////////////////////////////////////////////////////////////////
struct StructArgsListaComparazioniFilesMultipli
	{
	union
		{
		const char * FileNameListing;
		char * ArrayFileNamesCouples;
		};
	void * Buffer;
	long BufferSize;
	unsigned char * RetMsg;
	long MaxRetMsgSize;
	long UsedRetMsgSize;
	__int8 * ArrayByteEsitoConfronti;
	long SizeArrayEsitoConfronti;
	long FileNameListingWasPassedAsArg; // BOOLEANO
	long PassedCouplesNumber;
	long SizesCouplesNamesArray;
	};
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
extern "C" FILECOMPARATORLIB_00_API long __stdcall
fzCompareManyFilesFromFileListing 
(StructArgsListaComparazioniFilesMultipli * Args)
{
// VARIABILI LOCALI
StructArgsComparazioneCoppiaFiles CoupleArgs;
__int64 FileSizeOne, FileSizeTwo;
__int64 MaxReadableFileSize, TotalBytesToRead;
LongLong SizesInput, Tmp;
long NumeroConfrontiEseguiti;
const char * NamesBuffer = 0;
unsigned long NumberOfBytesReaded;
long ConfrontiDaFarsi;
// nessun messaggio di errore postato
Args -> UsedRetMsgSize = 0;
// Testa adeguatezza buffer (compensa il fatto che venga 
usato splittato in due)
if (Args -> BufferSize < (__int64)(2) * ConMinReadBufferSize)
	return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Buffer_Lettura_Troppo_Piccolo), 
Args -> RetMsg, Args -> MaxRetMsgSize), 0);
if (Args -> BufferSize > ConMaxReadBufferSize) // 67108864UL 
= 64 MB
	return (Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Buffer_Lettura_Troppo_Grande), 
Args -> RetMsg, Args -> MaxRetMsgSize), 0);
// scelta utilizzo di un file listing di input
// oppure passaggio parametri tramite memoria
if (Args -> FileNameListingWasPassedAsArg == 0)
	{
	NamesBuffer = Args -> ArrayFileNamesCouples;
	SizesInput . HighUlong = 0;
	SizesInput . LowInteger32 = Args -> SizesCouplesNamesArray;
	goto lblSkipInputFileListingLoad;
	}
// apertura file listing di input e caricamento dei tasks
__int64 FileSizeInput;
HANDLE HandleInputFileListing;
// apre il file di INPUT (con la lista di coppie di nomi di 
files da confrontare)
if ((HandleInputFileListing = CreateFile (Args -> 
FileNameListing, GENERIC_READ, 0, NULL, OPEN_EXISTING, 
FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, NULL)) 
== NULL)
	{
	Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Apertura_Input_File_Listing), 
Args -> RetMsg, Args -> MaxRetMsgSize);
	return 0;
	}
// Legge dimensioni fisiche file di INPUT e converte a __int64
SizesInput . LowUlong = GetFileSize (HandleInputFileListing, 
& SizesInput . HighUlong);
if (SizesInput  . LowUlong == 0xFFFFFFFFL)
	{
	CloseHandle (HandleInputFileListing);
	Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Dimensioni_File_Listing_Di_Input), 
Args -> RetMsg, Args -> MaxRetMsgSize);
	return 0;
	}
FileSizeInput = SizesInput . Integer64;
if ((FileSizeInput >= ConMaxReadBufferSize) || (SizesInput . 
HighInteger32 != 0))
	{
	CloseHandle (HandleInputFileListing);
	Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_File_Listing_Di_Input_Troppo_Grande), 
Args -> RetMsg, Args -> MaxRetMsgSize);
	return 0;
	}
// tenta di allocare memoria per caricare in una volta 
l'intero File di Listing di Input
NamesBuffer = 0;
if ((NamesBuffer = new char [SizesInput . LowUlong + 1]) == 0)
	{
	CloseHandle (HandleInputFileListing);
	Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_File_Listing_Di_Input_Troppo_Grande), 
Args -> RetMsg, Args -> MaxRetMsgSize);
	return 0;
	}
// carica l'intero contenuto del file di INPUT in memoria, 
per parsing veloce
if (ReadFile (HandleInputFileListing, const_cast <char *> 
(NamesBuffer), SizesInput . LowUlong, & NumberOfBytesReaded, 
0) == false)
	{
	delete [] (const_cast <char *> (NamesBuffer)); // cleanup
	CloseHandle (HandleInputFileListing);
	Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Lettura_Input_File_Listing), 
Args -> RetMsg, Args -> MaxRetMsgSize);
	return 0;
	}
// errore lettura del file di INPUT
if (NumberOfBytesReaded != SizesInput . LowUlong)
	{
	delete [] const_cast <char *> (NamesBuffer); // cleanup
	CloseHandle (HandleInputFileListing);
	Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Lettura_Input_File_Listing), 
Args -> RetMsg, Args -> MaxRetMsgSize);
	return 0;
	}
// chiude file in ingresso
if ((CloseHandle (HandleInputFileListing)) == 0)
	{	
	delete [] const_cast <char *> (NamesBuffer); // cleanup
	Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Chiusura_File_Input_Listing), 
Args -> RetMsg, Args -> MaxRetMsgSize);
	return 0;
	}
// termina buffer in modo sicuro
(const_cast <char *> (NamesBuffer)) [SizesInput . LowUlong] = 0;
// @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ 
@ @ @ @ @ @ @ @
lblSkipInputFileListingLoad: // ETICHETTA @ @ @ @ @ @ @ @ @ 
@ @ @ @ @ @ @ @ @
// @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ 
@ @ @ @ @ @ @ @
// punto di convergenza del caricamento tramite FILE LISTING 
di INPUT E
// passaggio diretto di array in memoria con le coppie 
asciiZ di filenames
// conteggia numero di coppie di nomi di files da trattare
ConfrontiDaFarsi = GetNumeroStringheInBuffer (NamesBuffer, 
SizesInput . LowUlong); // due filenames per ogni confronto
// argomenti NON in coppie, ma dispari (non posso 
confrontare l'ultimo nome di file)
if ((ConfrontiDaFarsi % 2) != 0)
	{
	if (Args -> FileNameListingWasPassedAsArg != 0)
		delete [] const_cast <char *> (NamesBuffer); // cleanup
	Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Numero_Di_Filenames_Dispari_Necessarie_Coppie), 
Args -> RetMsg, Args -> MaxRetMsgSize);
	return 0;
	}
ConfrontiDaFarsi /= 2;
// verifica numero di richieste e spazio riservato per le 
risposte
if (ConfrontiDaFarsi > Args -> SizeArrayEsitoConfronti)
	{
	if (Args -> FileNameListingWasPassedAsArg != 0)
		delete [] const_cast <char *> (NamesBuffer); // cleanup
	Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Spazio_Riservato_Array_Risposte_Diverso_Da_Richieste_Coppie_Filenames_Confronti), 
Args -> RetMsg, Args -> MaxRetMsgSize);
	return 0;
	}
if (ConfrontiDaFarsi != Args -> PassedCouplesNumber)
	{
	if (Args -> FileNameListingWasPassedAsArg != 0)
		delete [] const_cast <char *> (NamesBuffer); // cleanup
	Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_Numero_Di_Filenames_Parserizzati_Diverso_Da_Quanto_Indicato), 
Args -> RetMsg, Args -> MaxRetMsgSize);
	return 0;
	}
// il file di INPUT è pronto per PARSING dei tasks (coppie 
di nomi di files da confrontare)
// inizializza iteratore ottenimento nomi di files
ScanStringArrayIterator (1, NamesBuffer, SizesInput . LowUlong);
// refresh indicatori stato di avanzamento e callback 
routine grafica VB
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_FileDiTotFiles . 
TotalTaskToDo = (double)(ConfrontiDaFarsi);
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_FileDiTotFiles . 
CurrentlyDone = 0.0;
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
RefreshStatus_File_Di_Files ();
// COMPUTO NUMERO TOTALE DI BYTES DA LEGGERE
NumeroConfrontiEseguiti = -1;
TotalBytesToRead = (__int64) 0;
while (1)
	{
	if ((CoupleArgs . FileNameOne = ScanStringArrayIterator ()) 
== 0)
		break; // l'iteratore ha reso stringa non valida, nulla
	if ((CoupleArgs . FileNameTwo = ScanStringArrayIterator ()) 
== 0)
		{
		if (Args -> FileNameListingWasPassedAsArg != 0)
			delete [] const_cast <char *> (NamesBuffer); // cleanup
		Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_File_Listing_Di_Input_Errato_Manca_Termine_Di_Paragone), 
Args -> RetMsg, Args -> MaxRetMsgSize);
		return NumeroConfrontiEseguiti + 1;
		}
	if (GetFileSize_64 (CoupleArgs . FileNameOne, & 
FileSizeOne) == 0)
		{
		if (Args -> FileNameListingWasPassedAsArg != 0)
			delete [] const_cast <char *> (NamesBuffer); // cleanup
		Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Bad_Size_File_One), Args -> RetMsg, 
Args -> MaxRetMsgSize);
		return NumeroConfrontiEseguiti + 1;
		}
	if (GetFileSize_64 (CoupleArgs . FileNameTwo, & 
FileSizeTwo) == 0)
		{
		if (Args -> FileNameListingWasPassedAsArg != 0)
			delete [] const_cast <char *> (NamesBuffer); // cleanup
		Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Bad_Size_File_Two), Args -> RetMsg, 
Args -> MaxRetMsgSize);
		return NumeroConfrontiEseguiti + 1;
		}
	MaxReadableFileSize = Min (FileSizeOne, FileSizeTwo);
	TotalBytesToRead += MaxReadableFileSize;
	}
// refresh indicatori stato di avanzamento e callback 
routine grafica VB
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_FileDiTotFiles . 
TotalTaskToDo = ConfrontiDaFarsi;
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_FileDiTotFiles . 
CurrentlyDone = 0;
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
RefreshStatus_File_Di_Files ();
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_BytesDiTotalBytes . 
TotalTaskToDo = (double)(TotalBytesToRead);
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_BytesDiTotalBytes . 
CurrentlyDone = 0.0;
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
RefreshStatus_ByteDiTotalBytes ();
// prepara parametri costanti per le varie chiamate
CoupleArgs . BufUno = Args -> Buffer;
CoupleArgs . BufferSize = Args -> BufferSize;
CoupleArgs . MaxRetMsgSize = Args -> MaxRetMsgSize;
CoupleArgs . UsedRetMsgSize = 0;
CoupleArgs . RetMsg = Args -> RetMsg;
CoupleArgs . StatoDiversita = StructReturnCodes . 
Byte_Esito_Diversi;
NumeroConfrontiEseguiti = -1;
// reinizializza iteratore ottenimento nomi di files
ScanStringArrayIterator (1, NamesBuffer, SizesInput . LowUlong);
while (1)
	{
	if ((CoupleArgs . FileNameOne = ScanStringArrayIterator ()) 
== 0)
		break; // l'iteratore ha reso stringa non valida, nulla
	if ((CoupleArgs . FileNameTwo = ScanStringArrayIterator ()) 
== 0)
		{
		Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Errore_File_Listing_Di_Input_Errato_Manca_Termine_Di_Paragone), 
Args -> RetMsg, Args -> MaxRetMsgSize);
		break;
		}
	if (++ NumeroConfrontiEseguiti >= Args -> 
SizeArrayEsitoConfronti)
		{
		Args -> UsedRetMsgSize = StoreMessageInErrBuffer 
(Stringize(StructReturnCodes :: 
Confronta_Coppia_Files___Numero_Confronti_Da_Eseguire_Superiore_A_Size_Array_Log_Esito), 
Args -> RetMsg, Args -> MaxRetMsgSize);
		break;
		}
	// delega confronto singole coppie di files
	if (fzCompareFileCouple (& CoupleArgs) == 0)
		{ // mantiene errore memorizzato dalla procedura delegata 
al confronto
		Args -> ArrayByteEsitoConfronti [NumeroConfrontiEseguiti] 
= CoupleArgs . StatoDiversita;
		// break; // tolto break : tenta di procedere con altri files
		}
	// registra esito coppia nell'array
	Args -> ArrayByteEsitoConfronti [NumeroConfrontiEseguiti] = 
CoupleArgs . StatoDiversita;
	// refresh periodico indicatori stato di avanzamento e 
callback routine grafica VB
	GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_FileDiTotFiles . 
CurrentlyDone = (NumeroConfrontiEseguiti + 1);
	GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
RefreshStatus_File_Di_Files ();
	GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
DatiDiTuttiGliIndicatori -> Avanzamento_BytesDiTotalBytes . 
CurrentlyDone += (double)(CoupleArgs . TotalBytesCompared);
	GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento . 
RefreshStatus_ByteDiTotalBytes ();
	}
// se giunge sin qui indenne, ritorna il numero valido di 
confronti fatti
if ((NamesBuffer != 0) && (NamesBuffer != Args -> 
ArrayFileNamesCouples) && (Args -> 
FileNameListingWasPassedAsArg != 0))
	delete [] const_cast <char *> (NamesBuffer); // cleanup
return NumeroConfrontiEseguiti + 1;
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
BOOL APIENTRY DllMain
(
HANDLE hModule,
DWORD  ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
return TRUE;
};
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

Ciao ... ho riconosciuto la firma in calce.
1300 righe di codice che potevano essere spedite per e-mail.
Cmq mi è bastato vedere questo identificatore:
GloGestoreCallbackRefreshTuttiGliIndicatoriAvanzamento
Complimenti.

 Complimenti.
Volendo si può fare un trova >> sostituisti tutto, e 
cambiare il nome in "J"
:-)
ciao
Soviet

non volesse essere infastidito.
Infastidisce dover scaricare un intero polpettone.
La prossima volta chiedi un'e-mail e manda lì.
Comunque stop con la polemica.

 regole sulla lunghezza dei post, dovresti rispettarle.
A questo non ho pensato. Ora dato che mi hai messo il 
rovello ho spulciato il manifesto, ma probabilmente ti 
riferisci a regole implicite più generali di quelle del 
manifesto. Siccome non ho tanta voglia di andare a 
sfrcliarle alla cieca, non è che mi diresti direttamente un 
dato di massima che non si deve sforare ? Come KB. Se te lo 
ricordi. Se no boh, mi sferzerò di ricordarmi della cosa e 
andare a lume di naso
ciao
Soviet
