Dark Sean
October 9th, 2001, 08:27 AM
Hello all,
I'm having a devil of a time getting my callback procedure to function correctly. I have a C++ dll which performs file splitting, it's multi threaded, so I pass it the AddressOf MyCallBackFunction as one of the parameters so I can perform further processing when it is done. I keep getting an error stating that different calling conventions are being used, the value of ESP is not being saved properly, something like that. I'll post the code for the Split DLL first:
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>
enum SplitTypes
{
binary,
FIXEDWIDTH_ASCII,
FIXEDWIDTH_UNIX,
CSV_ASCII,
CSV_UNIX,
DBASEIII,
}; // end enum
//bool CleanThreadList(void);
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
break;
}; // end case
case DLL_THREAD_ATTACH:
{
break;
}; // end case
case DLL_THREAD_DETACH:
{
break;
}; // end case
case DLL_PROCESS_DETACH:
{
break;
}; // end case
}; // end switch;
return true;
};
//typedef long __stdcall SplitFinishedProc(void *prParameter1,
typedef long __stdcall SplitFinishedProc(void *prParameter1,
//typedef long PASCAL SplitFinishedProc(void *prParameter1,
void *prParameter2,
long &result);
struct JobData
{
long SplitSize;
char *BaseFile;
char *DestinationPath;
long Type;
}; // end JobData struct
struct InternalJobData
{
JobData *Data;
void *Parameter1;
void *Parameter2;
SplitFinishedProc *SplitFinishedProc;
HANDLE Thread;
bool AbortFlag;
}; // end InternalJobData struct
struct ThreadDataNode
{
ThreadDataNode *Previous;
InternalJobData *InternalData;
ThreadDataNode *next;
}; //BaseNode; // end ThreadDataNode struct
class GlobalMemoryClassType
{
public:
ThreadDataNode *AddThreadDataNode(InternalJobData *prInternalJobData);
bool DeleteThreadDataNode(ThreadDataNode *prThreadDataNode);
bool CleanThreadList(void);
GlobalMemoryClassType();
~GlobalMemoryClassType();
private:
ThreadDataNode *BaseNode;
} GlobalMemoryClass;
GlobalMemoryClassType::GlobalMemoryClassType()
{
//MessageBox(null, "Initializing class!", "Check", MB_OK);
// nothing!!
};
GlobalMemoryClassType::~GlobalMemoryClassType()
{
//bool result;
//MessageBox(null, "Disposing!", "Check", MB_OK);
//result = this->CleanThreadList();
};
ThreadDataNode *GlobalMemoryClassType::AddThreadDataNode(InternalJobData *prInternalJobData)
{
CRITICAL_SECTION *LocalCriticalSection = new CRITICAL_SECTION;
InitializeCriticalSection(LocalCriticalSection);
EnterCriticalSection(LocalCriticalSection);
ThreadDataNode *ActualNode;
ThreadDataNode *ReturnNode;
ReturnNode = new ThreadDataNode;
ReturnNode->next = null;
ReturnNode->Previous = null;
if (this->BaseNode == null)
{
this->BaseNode = ReturnNode;
}
else
{
ActualNode = this->BaseNode;
while (ActualNode->next != null)
{
ActualNode = ActualNode->next;
}; // end while
ActualNode->next = ReturnNode;
ReturnNode ->Previous = ActualNode;
}; // end if
ReturnNode->InternalData = new InternalJobData;
ReturnNode->InternalData->Data = new JobData;
ReturnNode->InternalData->Data->BaseFile = new char[256];
strcpy(ReturnNode->InternalData->Data->BaseFile, prInternalJobData->Data->BaseFile);
ReturnNode->InternalData->Data->DestinationPath = new char[256];
strcpy(ReturnNode->InternalData->Data->DestinationPath, prInternalJobData->Data->DestinationPath);
ReturnNode->InternalData->Data->SplitSize = prInternalJobData->Data->SplitSize;
ReturnNode->InternalData->Data->Type = prInternalJobData->Data->Type;
ReturnNode->InternalData->Parameter1 = prInternalJobData->Parameter1;
ReturnNode->InternalData->Parameter2 = prInternalJobData->Parameter2;
ReturnNode->InternalData->SplitFinishedProc = prInternalJobData->SplitFinishedProc;
ReturnNode->InternalData->AbortFlag = false;
LeaveCriticalSection(LocalCriticalSection);
DeleteCriticalSection(LocalCriticalSection);
delete LocalCriticalSection;
return (ReturnNode);
}; // end AddThreadDataNode procedure
bool GlobalMemoryClassType::DeleteThreadDataNode(ThreadDataNode *prThreadDataNode)
{
CRITICAL_SECTION *LocalCriticalSection = new CRITICAL_SECTION;
InitializeCriticalSection(LocalCriticalSection);
EnterCriticalSection(LocalCriticalSection);
bool LocalReturnValue = true;
ThreadDataNode *PreviousNode;
ThreadDataNode *NextNode;
NextNode = prThreadDataNode->next;
PreviousNode = prThreadDataNode->Previous;
if (PreviousNode != null)
{
PreviousNode->next = NextNode;
}; // end if
if (NextNode != null)
{
NextNode->Previous = PreviousNode;
}; // end if
if (prThreadDataNode == this->BaseNode)
{
this->BaseNode = NextNode;
}; // end if
if (!CloseHandle(prThreadDataNode->InternalData->Thread))
{
LocalReturnValue = false;
}; // end if
delete [] (prThreadDataNode->InternalData->Data->BaseFile);
delete [] (prThreadDataNode->InternalData->Data->DestinationPath);
delete(prThreadDataNode->InternalData->Data);
delete(prThreadDataNode->InternalData);
delete(prThreadDataNode);
LeaveCriticalSection(LocalCriticalSection);
DeleteCriticalSection(LocalCriticalSection);
delete LocalCriticalSection;
return LocalReturnValue;
}; // end DeleteThreadDataNode procedure
bool GlobalMemoryClassType::CleanThreadList(void)
{
bool LocalReturnValue = true;
ThreadDataNode *ActualNode;
ThreadDataNode *SaveNode;
CRITICAL_SECTION *LocalCriticalSection = new CRITICAL_SECTION;
InitializeCriticalSection(LocalCriticalSection);
while (this->BaseNode != null)
{
EnterCriticalSection(LocalCriticalSection);
ActualNode = this->BaseNode;
while (ActualNode != null)
{
SaveNode = ActualNode;
ActualNode->InternalData->AbortFlag = true;
ActualNode = ActualNode->next;
};
LeaveCriticalSection(LocalCriticalSection);
};
DeleteCriticalSection(LocalCriticalSection);
// MessageBox(null, "Cleaned up!", "Check", MB_OK);
return (LocalReturnValue);
}; // end CleanThreadList
DWORD WINAPI SplitInternal (void *prThreadDataNode)
{
ThreadDataNode *LocalThreadDataNode = new ThreadDataNode;
long LocalReturnValue = true;
HANDLE LocalBaseFileHandle;
BY_HANDLE_FILE_INFORMATION *LocalByHandleFileInformation = new BY_HANDLE_FILE_INFORMATION;
_int64 LocalBaseFileSize;
long int LocalChunks;
char *LocalDrive = new char[4];
char *LocalPath = new char[256];
char *LocalName = new char[256];
char *LocalExtension = new char[256];
char *LocalAppendName = new char[14];
char *LocalSplitFile = new char[256];
strcpy(LocalSplitFile, "");
HANDLE LocalSplitFileHandle;
unsigned long LocalSplitFilePosition;
long LocalBufferSize;
char *LocalReadBuffer = null;
DWORD LocalBytesToRead = 0;
DWORD LocalBytesRead = 0;
char *LocalWriteBuffer = null;
DWORD LocalBytesToWrite = 0;
DWORD LocalBytesWritten = 0;
char *LocalSaveBuffer = null;
long LocalBaseBufferSize = (1024 * 100);
char LocalDbaseBaseHeader[32]; // Standard DBase base header without field descriptions
char *LocalDbaseHeader = null; // Full Header with field descriptions
int LocalDbaseHeaderSize = 0;
int LocalDbaseRecordSize = 0;
long LocalDbaseRecordsThisChunk = 0;
unsigned long LocalChunkSize = 0;
unsigned long LocalEndOfRecordPosition = 0;
bool LocalFinishedReading = false;
memcpy(LocalThreadDataNode, prThreadDataNode, sizeof(ThreadDataNode));
if (LocalThreadDataNode->InternalData->AbortFlag == true)
{
delete [] (LocalDrive);
delete [] (LocalPath);
delete [] (LocalName);
delete [] (LocalExtension);
delete [] (LocalAppendName);
delete [] (LocalSplitFile);
delete (LocalByHandleFileInformation);
GlobalMemoryClass.DeleteThreadDataNode(LocalThreadDataNode);
ExitThread(0);
};
if (LocalThreadDataNode->InternalData->Data == null)
{
LocalReturnValue = false;
}
else
{
LocalBufferSize = ((LocalBaseBufferSize) < (LocalThreadDataNode->InternalData->Data->SplitSize) ? (LocalBaseBufferSize) : (LocalThreadDataNode->InternalData->Data->SplitSize));
LocalChunkSize = LocalThreadDataNode->InternalData->Data->SplitSize;
LocalReadBuffer = new char[LocalBufferSize];
LocalWriteBuffer = new char[LocalBufferSize];
LocalSaveBuffer = new char[LocalBufferSize];
if ((null == LocalReadBuffer) || (null == LocalWriteBuffer) || (null == LocalSaveBuffer))
{
if (null != LocalReadBuffer)
delete [] (LocalReadBuffer);
if (null != LocalWriteBuffer)
delete [] (LocalWriteBuffer);
if (null != LocalSaveBuffer)
delete [] (LocalSaveBuffer);
LocalReturnValue = false;
}
else
{
LocalBytesToRead = LocalBufferSize;
LocalBaseFileHandle = CreateFile(LocalThreadDataNode->InternalData->Data->BaseFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
if (LocalBaseFileHandle == null)
{
LocalReturnValue = false;
}
else
{
if (!GetFileInformationByHandle(LocalBaseFileHandle, LocalByHandleFileInformation))
{
LocalReturnValue = false;
}
else
{
LocalBaseFileSize = ((LocalByHandleFileInformation->nFileSizeHigh) * 4294967296) + LocalByHandleFileInformation->nFileSizeLow;
LocalChunks = int(LocalBaseFileSize / LocalThreadDataNode->InternalData->Data->SplitSize) + ((LocalBaseFileSize % LocalThreadDataNode->InternalData->Data->SplitSize) == 0 ? 0 : 1);
_splitpath(LocalThreadDataNode->InternalData->Data->BaseFile, LocalDrive, LocalPath, LocalName, LocalExtension);
if (LocalThreadDataNode->InternalData->Data->Type == static_cast <long> (DBASEIII))
{
if (!ReadFile(LocalBaseFileHandle, LocalDbaseBaseHeader, sizeof(LocalDbaseBaseHeader), &LocalBytesRead, null))
{
MessageBox(null , "error reading Small Header", "Check", MB_OK);
}
else
{
if (LocalBytesRead != sizeof(LocalDbaseBaseHeader))
{
MessageBox(null, "The amount of readed bytes does not match the HeaderSize", "Check", MB_OK);
}
else
{
LocalDbaseHeaderSize = 0;
LocalDbaseRecordSize = 0;
memcpy(&LocalDbaseRecordSize, &LocalDbaseBaseHeader[10], 2);
memcpy(&LocalDbaseHeaderSize, &LocalDbaseBaseHeader[8], 2);
LocalChunkSize = (LocalChunkSize - 1) - ((LocalChunkSize - LocalDbaseHeaderSize) % LocalDbaseRecordSize) + 1; // - 1 to have for the EOF char
if (LocalChunkSize <= 0)
{
MessageBox(null, "LocalChunkSize got smaller than 0", "Check", MB_OK);
}
else
{
LocalDbaseHeader = new char[LocalDbaseHeaderSize];
SetFilePointer(LocalBaseFileHandle, 0, 0, FILE_BEGIN);
if (GetLastError() != NO_ERROR)
{
MessageBox(null, "error repositioning the file", "Check", MB_OK);
}
else
{
if (!ReadFile(LocalBaseFileHandle, LocalDbaseHeader, LocalDbaseHeaderSize, &LocalBytesRead, null))
{
MessageBox(null , "error reading Header", "Check", MB_OK);
}
else
{
}; // end if
}; // end if
}; // end if
}; // end if
}; // end if
}; // end if
int i = 0;
for(;;)
{
i++;
if ((LocalThreadDataNode->InternalData->AbortFlag == true) ||
(LocalReturnValue = false))
{
break;
};
strcpy(LocalSplitFile,"");
if (null != LocalThreadDataNode->InternalData->Data->DestinationPath)
{
strcat(LocalSplitFile, LocalThreadDataNode->InternalData->Data->DestinationPath);
}
else
{
strcat(LocalSplitFile, LocalPath);
}; // end if
strcat(LocalSplitFile, "\\");
strcat(LocalSplitFile, LocalName);
strcat(LocalSplitFile, "-");
strcat(LocalSplitFile, ltoa(i,LocalAppendName,10));
strcat(LocalSplitFile, LocalExtension);
if (strlen(LocalSplitFile) > 255)
{
MessageBox(null, itoa(strlen(LocalSplitFile), LocalAppendName, 10), "Check", MB_OK);
MessageBox(null, "The split filename is longer than what the system can handle", "error", MB_OK);
LocalReturnValue = false;
break;
};
//LocalSplitFileHandle = CreateFile(LocalSplitFile, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_WRITE_THROUGH,0);
LocalSplitFileHandle = CreateFile(LocalSplitFile, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,0);
if (LocalSplitFileHandle == null)
{
LocalReturnValue = false;
break;
}
else
{
LocalSplitFilePosition = 0;
if (LocalDbaseHeaderSize != 0)
{
if (i < LocalChunks)
{
LocalDbaseRecordsThisChunk = ((LocalChunkSize - LocalDbaseHeaderSize) / LocalDbaseRecordSize);
}
else
{
LocalDbaseRecordsThisChunk = static_cast <long> ((LocalBaseFileSize - LocalDbaseHeaderSize - 1) % (LocalChunkSize - LocalDbaseHeaderSize)) / LocalDbaseRecordSize;
}; // end if
memcpy(&LocalDbaseHeader[4], &LocalDbaseRecordsThisChunk, sizeof(LocalDbaseRecordsThisChunk));
if (!WriteFile(LocalSplitFileHandle, LocalDbaseHeader, LocalDbaseHeaderSize, &LocalBytesWritten, null))
{
LocalReturnValue = false;
break;
}
else
{
LocalSplitFilePosition += LocalBytesWritten;
}; // end if
}; // end if
for(;;)
{
memcpy(LocalReadBuffer, LocalSaveBuffer, LocalBytesToWrite);
if (!ReadFile(LocalBaseFileHandle, LocalReadBuffer + LocalBytesToWrite, LocalBytesToRead - LocalBytesToWrite, &LocalBytesRead, null))
{
LocalReturnValue = false;
break;
}
else
{
if ((LocalBytesRead + LocalBytesToWrite) == 0)
{
LocalFinishedReading = true;
break;
}
else
{
if ((LocalSplitFilePosition + LocalBytesRead + LocalBytesToWrite) <= LocalChunkSize)
{
LocalEndOfRecordPosition = LocalBytesRead + LocalBytesToWrite;
if ((LocalThreadDataNode->InternalData->Data->Type != static_cast <long> (binary)) &&
(LocalThreadDataNode->InternalData->Data->Type != static_cast <long> (DBASEIII)))
{
for( ; LocalEndOfRecordPosition > 0 ; LocalEndOfRecordPosition--)
{
if (LocalReadBuffer[LocalEndOfRecordPosition - 1] == 10)
{
break;
}; // end if
}; // end for
/*if (LocalEndOfRecordPosition <= 0) // This means the record is bigger than the split size
{
LocalReturnValue = false;
break;
};*/
}
else
{
LocalEndOfRecordPosition = LocalBytesRead + LocalBytesToWrite;
}; // end if
memcpy(LocalWriteBuffer, LocalReadBuffer, LocalEndOfRecordPosition);
memcpy(LocalSaveBuffer, LocalReadBuffer + LocalEndOfRecordPosition, LocalBytesRead + LocalBytesToWrite - LocalEndOfRecordPosition);
if (!WriteFile(LocalSplitFileHandle, LocalWriteBuffer, LocalEndOfRecordPosition, &LocalBytesWritten, null))
{
LocalReturnValue = false;
break;
}
else
{
LocalSplitFilePosition += LocalBytesWritten;
LocalBytesToWrite = LocalBytesRead + LocalBytesToWrite - LocalBytesWritten;
}; // end if
}
else
{
LocalEndOfRecordPosition = (LocalChunkSize - LocalSplitFilePosition);
if ((LocalThreadDataNode->InternalData->Data->Type != static_cast <long> (binary)) &&
(LocalThreadDataNode->InternalData->Data->Type != static_cast <long> (DBASEIII)))
{
for( ; LocalEndOfRecordPosition > 0 ; LocalEndOfRecordPosition--)
{
if (LocalReadBuffer[LocalEndOfRecordPosition - 1] == 10)
{
break;
}; // end if
}; // end for
/*if (LocalEndOfRecordPosition <= 0) // This means the record is bigger than the split size
{
LocalReturnValue = false;
break;
};*/
}
else
{
LocalEndOfRecordPosition = (LocalChunkSize - LocalSplitFilePosition);
}; // end if
memcpy(LocalWriteBuffer, LocalReadBuffer, LocalEndOfRecordPosition);
memcpy(LocalSaveBuffer, LocalReadBuffer + LocalEndOfRecordPosition, LocalBytesRead + LocalBytesToWrite - LocalEndOfRecordPosition);
if (!WriteFile(LocalSplitFileHandle, LocalWriteBuffer, LocalEndOfRecordPosition, &LocalBytesWritten, null))
{
LocalReturnValue = false;
break;
}
else
{
LocalSplitFilePosition += LocalBytesWritten;
LocalBytesToWrite = LocalBytesRead + LocalBytesToWrite - LocalBytesWritten;
}; // end if
break;
}; // end if
}; // end if
}; // end if
}; // end for
}; // end if
if (LocalThreadDataNode->InternalData->Data->Type == static_cast <long> (DBASEIII))
{
LocalWriteBuffer[0] = 0x1A; // Dbase file terminator
if (!WriteFile(LocalSplitFileHandle, LocalWriteBuffer, 1, &LocalBytesWritten, null))
{
LocalReturnValue = false;
break;
}
else
{
LocalSplitFilePosition += 1;
}; // end if
}; // end if
if (!CloseHandle(LocalSplitFileHandle))
{
LocalReturnValue = false;
break;
}; // end if
if (LocalFinishedReading == true)
{
break;
};
}; // end for
}; // end if
if (!CloseHandle(LocalBaseFileHandle))
{
LocalReturnValue = false;
}; // end if
}; // end if
}; // end if
delete[] LocalReadBuffer;
delete[] LocalWriteBuffer;
delete[] LocalSaveBuffer;
}; // end if
// MessageBox(null, "Check on finishing split", "Check", MB_OK);
delete[] LocalDrive;
delete[] LocalPath;
delete[] LocalName;
delete[] LocalExtension;
delete[] LocalAppendName;
// MessageBox(null, "Before deleting localsplitfile", "Check", MB_OK);
delete[] LocalSplitFile;
delete LocalByHandleFileInformation;
// MessageBox(null, "After on finishing split", "Check", MB_OK);
//if ((null != LocalThreadDataNode->InternalData->SplitFinishedProc) && (LocalThreadDataNode == false))
if (null != LocalThreadDataNode->InternalData->SplitFinishedProc)
{
LocalThreadDataNode->InternalData->SplitFinishedProc(LocalThreadDataNode->InternalData->Parameter1, LocalThreadDataNode->InternalData->Parameter2, LocalReturnValue);
}; // end if
GlobalMemoryClass.DeleteThreadDataNode(LocalThreadDataNode);
ExitThread(LocalReturnValue);
return (LocalReturnValue);
}; // end SplitFileInternal procedure
//extern "C" bool __declspec (dllexport) PASCAL Split (JobData *prJobData,
extern "C" bool __declspec (dllexport) __stdcall Split (JobData *prJobData,
SplitFinishedProc *prSplitFinishedProc,
void *prParameter1,
void *prParameter2)
{
bool LocalReturnValue = true;
ThreadDataNode *LocalThreadDataNode;
HANDLE LocalThread;
DWORD LocalThreadId;
InternalJobData *LocalInternalJobData = new InternalJobData;
LocalInternalJobData->Data = prJobData;
LocalInternalJobData->Parameter1 = prParameter1;
LocalInternalJobData->Parameter2 = prParameter2;
LocalInternalJobData->SplitFinishedProc = prSplitFinishedProc;
LocalThreadDataNode = GlobalMemoryClass.AddThreadDataNode(LocalInternalJobData);
if (null == LocalThreadDataNode)
{
LocalReturnValue = false;
}
else
{
LocalThread = CreateThread(null, 0, SplitInternal, LocalThreadDataNode, 0, &LocalThreadId);
if (null == LocalThread)
{
GlobalMemoryClass.DeleteThreadDataNode(LocalThreadDataNode);
LocalReturnValue = false;
}
else
{
LocalThreadDataNode->InternalData->Thread = LocalThread;
}; // end if
}; // end if
delete (LocalInternalJobData);
return (LocalReturnValue);
}; // end Split procedure
Here is how I call the dll:
public Type JobData
SplitSize as Long
BaseFile as string
DestinationPath as string
Type as Long
End Type
Data.SplitSize = lngCDSplitSize '630 mbs
Data.DestinationPath = CDFILEDIRECTORY 'local dir
Data.BaseFile = "C:\test\0001275183.txt"
Data.Type = FIXEDWIDTH_ASCII
Split Data, AddressOf MyCallbackFunction, 0, 0
Then I have a module included in the project with my callback procedure:
public Sub MyCallBackFunction(byval lng1 as Long, byval lng2 as Long, byval lng3 as Long)
on error resume next
DoThis
ThenDoThis
NextDoThis
End Sub
As you can see in the C code, I have tried both __stdcall and PASCAL calling conventions, I really don't know what I am doing wrong. If I eliminate accepting parameters in my callback function, the file splitting works but not everything is done in my callback function. If I leave the parameters as they are now I get the file split, and then the program crashes when it trys to call back.
Can anyone shed some light on this?
Thanks,
Sean
I'm having a devil of a time getting my callback procedure to function correctly. I have a C++ dll which performs file splitting, it's multi threaded, so I pass it the AddressOf MyCallBackFunction as one of the parameters so I can perform further processing when it is done. I keep getting an error stating that different calling conventions are being used, the value of ESP is not being saved properly, something like that. I'll post the code for the Split DLL first:
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>
enum SplitTypes
{
binary,
FIXEDWIDTH_ASCII,
FIXEDWIDTH_UNIX,
CSV_ASCII,
CSV_UNIX,
DBASEIII,
}; // end enum
//bool CleanThreadList(void);
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
break;
}; // end case
case DLL_THREAD_ATTACH:
{
break;
}; // end case
case DLL_THREAD_DETACH:
{
break;
}; // end case
case DLL_PROCESS_DETACH:
{
break;
}; // end case
}; // end switch;
return true;
};
//typedef long __stdcall SplitFinishedProc(void *prParameter1,
typedef long __stdcall SplitFinishedProc(void *prParameter1,
//typedef long PASCAL SplitFinishedProc(void *prParameter1,
void *prParameter2,
long &result);
struct JobData
{
long SplitSize;
char *BaseFile;
char *DestinationPath;
long Type;
}; // end JobData struct
struct InternalJobData
{
JobData *Data;
void *Parameter1;
void *Parameter2;
SplitFinishedProc *SplitFinishedProc;
HANDLE Thread;
bool AbortFlag;
}; // end InternalJobData struct
struct ThreadDataNode
{
ThreadDataNode *Previous;
InternalJobData *InternalData;
ThreadDataNode *next;
}; //BaseNode; // end ThreadDataNode struct
class GlobalMemoryClassType
{
public:
ThreadDataNode *AddThreadDataNode(InternalJobData *prInternalJobData);
bool DeleteThreadDataNode(ThreadDataNode *prThreadDataNode);
bool CleanThreadList(void);
GlobalMemoryClassType();
~GlobalMemoryClassType();
private:
ThreadDataNode *BaseNode;
} GlobalMemoryClass;
GlobalMemoryClassType::GlobalMemoryClassType()
{
//MessageBox(null, "Initializing class!", "Check", MB_OK);
// nothing!!
};
GlobalMemoryClassType::~GlobalMemoryClassType()
{
//bool result;
//MessageBox(null, "Disposing!", "Check", MB_OK);
//result = this->CleanThreadList();
};
ThreadDataNode *GlobalMemoryClassType::AddThreadDataNode(InternalJobData *prInternalJobData)
{
CRITICAL_SECTION *LocalCriticalSection = new CRITICAL_SECTION;
InitializeCriticalSection(LocalCriticalSection);
EnterCriticalSection(LocalCriticalSection);
ThreadDataNode *ActualNode;
ThreadDataNode *ReturnNode;
ReturnNode = new ThreadDataNode;
ReturnNode->next = null;
ReturnNode->Previous = null;
if (this->BaseNode == null)
{
this->BaseNode = ReturnNode;
}
else
{
ActualNode = this->BaseNode;
while (ActualNode->next != null)
{
ActualNode = ActualNode->next;
}; // end while
ActualNode->next = ReturnNode;
ReturnNode ->Previous = ActualNode;
}; // end if
ReturnNode->InternalData = new InternalJobData;
ReturnNode->InternalData->Data = new JobData;
ReturnNode->InternalData->Data->BaseFile = new char[256];
strcpy(ReturnNode->InternalData->Data->BaseFile, prInternalJobData->Data->BaseFile);
ReturnNode->InternalData->Data->DestinationPath = new char[256];
strcpy(ReturnNode->InternalData->Data->DestinationPath, prInternalJobData->Data->DestinationPath);
ReturnNode->InternalData->Data->SplitSize = prInternalJobData->Data->SplitSize;
ReturnNode->InternalData->Data->Type = prInternalJobData->Data->Type;
ReturnNode->InternalData->Parameter1 = prInternalJobData->Parameter1;
ReturnNode->InternalData->Parameter2 = prInternalJobData->Parameter2;
ReturnNode->InternalData->SplitFinishedProc = prInternalJobData->SplitFinishedProc;
ReturnNode->InternalData->AbortFlag = false;
LeaveCriticalSection(LocalCriticalSection);
DeleteCriticalSection(LocalCriticalSection);
delete LocalCriticalSection;
return (ReturnNode);
}; // end AddThreadDataNode procedure
bool GlobalMemoryClassType::DeleteThreadDataNode(ThreadDataNode *prThreadDataNode)
{
CRITICAL_SECTION *LocalCriticalSection = new CRITICAL_SECTION;
InitializeCriticalSection(LocalCriticalSection);
EnterCriticalSection(LocalCriticalSection);
bool LocalReturnValue = true;
ThreadDataNode *PreviousNode;
ThreadDataNode *NextNode;
NextNode = prThreadDataNode->next;
PreviousNode = prThreadDataNode->Previous;
if (PreviousNode != null)
{
PreviousNode->next = NextNode;
}; // end if
if (NextNode != null)
{
NextNode->Previous = PreviousNode;
}; // end if
if (prThreadDataNode == this->BaseNode)
{
this->BaseNode = NextNode;
}; // end if
if (!CloseHandle(prThreadDataNode->InternalData->Thread))
{
LocalReturnValue = false;
}; // end if
delete [] (prThreadDataNode->InternalData->Data->BaseFile);
delete [] (prThreadDataNode->InternalData->Data->DestinationPath);
delete(prThreadDataNode->InternalData->Data);
delete(prThreadDataNode->InternalData);
delete(prThreadDataNode);
LeaveCriticalSection(LocalCriticalSection);
DeleteCriticalSection(LocalCriticalSection);
delete LocalCriticalSection;
return LocalReturnValue;
}; // end DeleteThreadDataNode procedure
bool GlobalMemoryClassType::CleanThreadList(void)
{
bool LocalReturnValue = true;
ThreadDataNode *ActualNode;
ThreadDataNode *SaveNode;
CRITICAL_SECTION *LocalCriticalSection = new CRITICAL_SECTION;
InitializeCriticalSection(LocalCriticalSection);
while (this->BaseNode != null)
{
EnterCriticalSection(LocalCriticalSection);
ActualNode = this->BaseNode;
while (ActualNode != null)
{
SaveNode = ActualNode;
ActualNode->InternalData->AbortFlag = true;
ActualNode = ActualNode->next;
};
LeaveCriticalSection(LocalCriticalSection);
};
DeleteCriticalSection(LocalCriticalSection);
// MessageBox(null, "Cleaned up!", "Check", MB_OK);
return (LocalReturnValue);
}; // end CleanThreadList
DWORD WINAPI SplitInternal (void *prThreadDataNode)
{
ThreadDataNode *LocalThreadDataNode = new ThreadDataNode;
long LocalReturnValue = true;
HANDLE LocalBaseFileHandle;
BY_HANDLE_FILE_INFORMATION *LocalByHandleFileInformation = new BY_HANDLE_FILE_INFORMATION;
_int64 LocalBaseFileSize;
long int LocalChunks;
char *LocalDrive = new char[4];
char *LocalPath = new char[256];
char *LocalName = new char[256];
char *LocalExtension = new char[256];
char *LocalAppendName = new char[14];
char *LocalSplitFile = new char[256];
strcpy(LocalSplitFile, "");
HANDLE LocalSplitFileHandle;
unsigned long LocalSplitFilePosition;
long LocalBufferSize;
char *LocalReadBuffer = null;
DWORD LocalBytesToRead = 0;
DWORD LocalBytesRead = 0;
char *LocalWriteBuffer = null;
DWORD LocalBytesToWrite = 0;
DWORD LocalBytesWritten = 0;
char *LocalSaveBuffer = null;
long LocalBaseBufferSize = (1024 * 100);
char LocalDbaseBaseHeader[32]; // Standard DBase base header without field descriptions
char *LocalDbaseHeader = null; // Full Header with field descriptions
int LocalDbaseHeaderSize = 0;
int LocalDbaseRecordSize = 0;
long LocalDbaseRecordsThisChunk = 0;
unsigned long LocalChunkSize = 0;
unsigned long LocalEndOfRecordPosition = 0;
bool LocalFinishedReading = false;
memcpy(LocalThreadDataNode, prThreadDataNode, sizeof(ThreadDataNode));
if (LocalThreadDataNode->InternalData->AbortFlag == true)
{
delete [] (LocalDrive);
delete [] (LocalPath);
delete [] (LocalName);
delete [] (LocalExtension);
delete [] (LocalAppendName);
delete [] (LocalSplitFile);
delete (LocalByHandleFileInformation);
GlobalMemoryClass.DeleteThreadDataNode(LocalThreadDataNode);
ExitThread(0);
};
if (LocalThreadDataNode->InternalData->Data == null)
{
LocalReturnValue = false;
}
else
{
LocalBufferSize = ((LocalBaseBufferSize) < (LocalThreadDataNode->InternalData->Data->SplitSize) ? (LocalBaseBufferSize) : (LocalThreadDataNode->InternalData->Data->SplitSize));
LocalChunkSize = LocalThreadDataNode->InternalData->Data->SplitSize;
LocalReadBuffer = new char[LocalBufferSize];
LocalWriteBuffer = new char[LocalBufferSize];
LocalSaveBuffer = new char[LocalBufferSize];
if ((null == LocalReadBuffer) || (null == LocalWriteBuffer) || (null == LocalSaveBuffer))
{
if (null != LocalReadBuffer)
delete [] (LocalReadBuffer);
if (null != LocalWriteBuffer)
delete [] (LocalWriteBuffer);
if (null != LocalSaveBuffer)
delete [] (LocalSaveBuffer);
LocalReturnValue = false;
}
else
{
LocalBytesToRead = LocalBufferSize;
LocalBaseFileHandle = CreateFile(LocalThreadDataNode->InternalData->Data->BaseFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
if (LocalBaseFileHandle == null)
{
LocalReturnValue = false;
}
else
{
if (!GetFileInformationByHandle(LocalBaseFileHandle, LocalByHandleFileInformation))
{
LocalReturnValue = false;
}
else
{
LocalBaseFileSize = ((LocalByHandleFileInformation->nFileSizeHigh) * 4294967296) + LocalByHandleFileInformation->nFileSizeLow;
LocalChunks = int(LocalBaseFileSize / LocalThreadDataNode->InternalData->Data->SplitSize) + ((LocalBaseFileSize % LocalThreadDataNode->InternalData->Data->SplitSize) == 0 ? 0 : 1);
_splitpath(LocalThreadDataNode->InternalData->Data->BaseFile, LocalDrive, LocalPath, LocalName, LocalExtension);
if (LocalThreadDataNode->InternalData->Data->Type == static_cast <long> (DBASEIII))
{
if (!ReadFile(LocalBaseFileHandle, LocalDbaseBaseHeader, sizeof(LocalDbaseBaseHeader), &LocalBytesRead, null))
{
MessageBox(null , "error reading Small Header", "Check", MB_OK);
}
else
{
if (LocalBytesRead != sizeof(LocalDbaseBaseHeader))
{
MessageBox(null, "The amount of readed bytes does not match the HeaderSize", "Check", MB_OK);
}
else
{
LocalDbaseHeaderSize = 0;
LocalDbaseRecordSize = 0;
memcpy(&LocalDbaseRecordSize, &LocalDbaseBaseHeader[10], 2);
memcpy(&LocalDbaseHeaderSize, &LocalDbaseBaseHeader[8], 2);
LocalChunkSize = (LocalChunkSize - 1) - ((LocalChunkSize - LocalDbaseHeaderSize) % LocalDbaseRecordSize) + 1; // - 1 to have for the EOF char
if (LocalChunkSize <= 0)
{
MessageBox(null, "LocalChunkSize got smaller than 0", "Check", MB_OK);
}
else
{
LocalDbaseHeader = new char[LocalDbaseHeaderSize];
SetFilePointer(LocalBaseFileHandle, 0, 0, FILE_BEGIN);
if (GetLastError() != NO_ERROR)
{
MessageBox(null, "error repositioning the file", "Check", MB_OK);
}
else
{
if (!ReadFile(LocalBaseFileHandle, LocalDbaseHeader, LocalDbaseHeaderSize, &LocalBytesRead, null))
{
MessageBox(null , "error reading Header", "Check", MB_OK);
}
else
{
}; // end if
}; // end if
}; // end if
}; // end if
}; // end if
}; // end if
int i = 0;
for(;;)
{
i++;
if ((LocalThreadDataNode->InternalData->AbortFlag == true) ||
(LocalReturnValue = false))
{
break;
};
strcpy(LocalSplitFile,"");
if (null != LocalThreadDataNode->InternalData->Data->DestinationPath)
{
strcat(LocalSplitFile, LocalThreadDataNode->InternalData->Data->DestinationPath);
}
else
{
strcat(LocalSplitFile, LocalPath);
}; // end if
strcat(LocalSplitFile, "\\");
strcat(LocalSplitFile, LocalName);
strcat(LocalSplitFile, "-");
strcat(LocalSplitFile, ltoa(i,LocalAppendName,10));
strcat(LocalSplitFile, LocalExtension);
if (strlen(LocalSplitFile) > 255)
{
MessageBox(null, itoa(strlen(LocalSplitFile), LocalAppendName, 10), "Check", MB_OK);
MessageBox(null, "The split filename is longer than what the system can handle", "error", MB_OK);
LocalReturnValue = false;
break;
};
//LocalSplitFileHandle = CreateFile(LocalSplitFile, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_WRITE_THROUGH,0);
LocalSplitFileHandle = CreateFile(LocalSplitFile, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,0);
if (LocalSplitFileHandle == null)
{
LocalReturnValue = false;
break;
}
else
{
LocalSplitFilePosition = 0;
if (LocalDbaseHeaderSize != 0)
{
if (i < LocalChunks)
{
LocalDbaseRecordsThisChunk = ((LocalChunkSize - LocalDbaseHeaderSize) / LocalDbaseRecordSize);
}
else
{
LocalDbaseRecordsThisChunk = static_cast <long> ((LocalBaseFileSize - LocalDbaseHeaderSize - 1) % (LocalChunkSize - LocalDbaseHeaderSize)) / LocalDbaseRecordSize;
}; // end if
memcpy(&LocalDbaseHeader[4], &LocalDbaseRecordsThisChunk, sizeof(LocalDbaseRecordsThisChunk));
if (!WriteFile(LocalSplitFileHandle, LocalDbaseHeader, LocalDbaseHeaderSize, &LocalBytesWritten, null))
{
LocalReturnValue = false;
break;
}
else
{
LocalSplitFilePosition += LocalBytesWritten;
}; // end if
}; // end if
for(;;)
{
memcpy(LocalReadBuffer, LocalSaveBuffer, LocalBytesToWrite);
if (!ReadFile(LocalBaseFileHandle, LocalReadBuffer + LocalBytesToWrite, LocalBytesToRead - LocalBytesToWrite, &LocalBytesRead, null))
{
LocalReturnValue = false;
break;
}
else
{
if ((LocalBytesRead + LocalBytesToWrite) == 0)
{
LocalFinishedReading = true;
break;
}
else
{
if ((LocalSplitFilePosition + LocalBytesRead + LocalBytesToWrite) <= LocalChunkSize)
{
LocalEndOfRecordPosition = LocalBytesRead + LocalBytesToWrite;
if ((LocalThreadDataNode->InternalData->Data->Type != static_cast <long> (binary)) &&
(LocalThreadDataNode->InternalData->Data->Type != static_cast <long> (DBASEIII)))
{
for( ; LocalEndOfRecordPosition > 0 ; LocalEndOfRecordPosition--)
{
if (LocalReadBuffer[LocalEndOfRecordPosition - 1] == 10)
{
break;
}; // end if
}; // end for
/*if (LocalEndOfRecordPosition <= 0) // This means the record is bigger than the split size
{
LocalReturnValue = false;
break;
};*/
}
else
{
LocalEndOfRecordPosition = LocalBytesRead + LocalBytesToWrite;
}; // end if
memcpy(LocalWriteBuffer, LocalReadBuffer, LocalEndOfRecordPosition);
memcpy(LocalSaveBuffer, LocalReadBuffer + LocalEndOfRecordPosition, LocalBytesRead + LocalBytesToWrite - LocalEndOfRecordPosition);
if (!WriteFile(LocalSplitFileHandle, LocalWriteBuffer, LocalEndOfRecordPosition, &LocalBytesWritten, null))
{
LocalReturnValue = false;
break;
}
else
{
LocalSplitFilePosition += LocalBytesWritten;
LocalBytesToWrite = LocalBytesRead + LocalBytesToWrite - LocalBytesWritten;
}; // end if
}
else
{
LocalEndOfRecordPosition = (LocalChunkSize - LocalSplitFilePosition);
if ((LocalThreadDataNode->InternalData->Data->Type != static_cast <long> (binary)) &&
(LocalThreadDataNode->InternalData->Data->Type != static_cast <long> (DBASEIII)))
{
for( ; LocalEndOfRecordPosition > 0 ; LocalEndOfRecordPosition--)
{
if (LocalReadBuffer[LocalEndOfRecordPosition - 1] == 10)
{
break;
}; // end if
}; // end for
/*if (LocalEndOfRecordPosition <= 0) // This means the record is bigger than the split size
{
LocalReturnValue = false;
break;
};*/
}
else
{
LocalEndOfRecordPosition = (LocalChunkSize - LocalSplitFilePosition);
}; // end if
memcpy(LocalWriteBuffer, LocalReadBuffer, LocalEndOfRecordPosition);
memcpy(LocalSaveBuffer, LocalReadBuffer + LocalEndOfRecordPosition, LocalBytesRead + LocalBytesToWrite - LocalEndOfRecordPosition);
if (!WriteFile(LocalSplitFileHandle, LocalWriteBuffer, LocalEndOfRecordPosition, &LocalBytesWritten, null))
{
LocalReturnValue = false;
break;
}
else
{
LocalSplitFilePosition += LocalBytesWritten;
LocalBytesToWrite = LocalBytesRead + LocalBytesToWrite - LocalBytesWritten;
}; // end if
break;
}; // end if
}; // end if
}; // end if
}; // end for
}; // end if
if (LocalThreadDataNode->InternalData->Data->Type == static_cast <long> (DBASEIII))
{
LocalWriteBuffer[0] = 0x1A; // Dbase file terminator
if (!WriteFile(LocalSplitFileHandle, LocalWriteBuffer, 1, &LocalBytesWritten, null))
{
LocalReturnValue = false;
break;
}
else
{
LocalSplitFilePosition += 1;
}; // end if
}; // end if
if (!CloseHandle(LocalSplitFileHandle))
{
LocalReturnValue = false;
break;
}; // end if
if (LocalFinishedReading == true)
{
break;
};
}; // end for
}; // end if
if (!CloseHandle(LocalBaseFileHandle))
{
LocalReturnValue = false;
}; // end if
}; // end if
}; // end if
delete[] LocalReadBuffer;
delete[] LocalWriteBuffer;
delete[] LocalSaveBuffer;
}; // end if
// MessageBox(null, "Check on finishing split", "Check", MB_OK);
delete[] LocalDrive;
delete[] LocalPath;
delete[] LocalName;
delete[] LocalExtension;
delete[] LocalAppendName;
// MessageBox(null, "Before deleting localsplitfile", "Check", MB_OK);
delete[] LocalSplitFile;
delete LocalByHandleFileInformation;
// MessageBox(null, "After on finishing split", "Check", MB_OK);
//if ((null != LocalThreadDataNode->InternalData->SplitFinishedProc) && (LocalThreadDataNode == false))
if (null != LocalThreadDataNode->InternalData->SplitFinishedProc)
{
LocalThreadDataNode->InternalData->SplitFinishedProc(LocalThreadDataNode->InternalData->Parameter1, LocalThreadDataNode->InternalData->Parameter2, LocalReturnValue);
}; // end if
GlobalMemoryClass.DeleteThreadDataNode(LocalThreadDataNode);
ExitThread(LocalReturnValue);
return (LocalReturnValue);
}; // end SplitFileInternal procedure
//extern "C" bool __declspec (dllexport) PASCAL Split (JobData *prJobData,
extern "C" bool __declspec (dllexport) __stdcall Split (JobData *prJobData,
SplitFinishedProc *prSplitFinishedProc,
void *prParameter1,
void *prParameter2)
{
bool LocalReturnValue = true;
ThreadDataNode *LocalThreadDataNode;
HANDLE LocalThread;
DWORD LocalThreadId;
InternalJobData *LocalInternalJobData = new InternalJobData;
LocalInternalJobData->Data = prJobData;
LocalInternalJobData->Parameter1 = prParameter1;
LocalInternalJobData->Parameter2 = prParameter2;
LocalInternalJobData->SplitFinishedProc = prSplitFinishedProc;
LocalThreadDataNode = GlobalMemoryClass.AddThreadDataNode(LocalInternalJobData);
if (null == LocalThreadDataNode)
{
LocalReturnValue = false;
}
else
{
LocalThread = CreateThread(null, 0, SplitInternal, LocalThreadDataNode, 0, &LocalThreadId);
if (null == LocalThread)
{
GlobalMemoryClass.DeleteThreadDataNode(LocalThreadDataNode);
LocalReturnValue = false;
}
else
{
LocalThreadDataNode->InternalData->Thread = LocalThread;
}; // end if
}; // end if
delete (LocalInternalJobData);
return (LocalReturnValue);
}; // end Split procedure
Here is how I call the dll:
public Type JobData
SplitSize as Long
BaseFile as string
DestinationPath as string
Type as Long
End Type
Data.SplitSize = lngCDSplitSize '630 mbs
Data.DestinationPath = CDFILEDIRECTORY 'local dir
Data.BaseFile = "C:\test\0001275183.txt"
Data.Type = FIXEDWIDTH_ASCII
Split Data, AddressOf MyCallbackFunction, 0, 0
Then I have a module included in the project with my callback procedure:
public Sub MyCallBackFunction(byval lng1 as Long, byval lng2 as Long, byval lng3 as Long)
on error resume next
DoThis
ThenDoThis
NextDoThis
End Sub
As you can see in the C code, I have tried both __stdcall and PASCAL calling conventions, I really don't know what I am doing wrong. If I eliminate accepting parameters in my callback function, the file splitting works but not everything is done in my callback function. If I leave the parameters as they are now I get the file split, and then the program crashes when it trys to call back.
Can anyone shed some light on this?
Thanks,
Sean