-
Callback functions
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
-
Re: Callback functions
Maybe this is not the point - I am not a C developer, nor a callBack expert, so
forgive my ignorance- but I think in a callBack function you should name the
function matching cases:
in example you wrote:
Split Data, AddressOf MyCallbackFunction, 0, 0
and then:
public Sub MyCallBackFunction
the "B" in name is different. I have seen public in lowercase, so it seems you
rewrote the whole instead of copying it, and the typo may not exist in your
code. However, it may be a good idea to check...
Special thanks to Lothar "the Great" Haensler, Tom Archer, Chris Eastwood, TCartwright, Bruno Paris, Dr_Michael
and all the other wonderful people who made and make Codeguru a great place.
Come back soon, you Gurus.
The Rater
-
Re: Callback functions
In order to be certain, I'd need your function's TypeDef i.e.:
typedef LRESULT (CALLBACK* MyCallbackProc)(lPar1, lPar2, lPar3, lPar4);
However, the most obvious thing at this stage is that you have called it a callback function but passed it a subroutine.
You can only do this if the typedef is:
typedef VOID (CALLBACK* MyCallbackProc)...
Otherwise change the VB code to:
public Function MyCallbackProc(byval lPar1 as long, byval lpar2 as Long, byval lPar3 as Long, byval lPar4 as Long) as Long
'...yadda
End Function
HTH,
Duncan
-------------------------------------------------
Ex. Datis: Duncan Jones
Merrion Computing Ltd
http://www.merrioncomputing.com
Check out the new downloads - ImageMap.ocx is the VB control that emulates an HTML image map, EventVB.OCX for adding new events to your VB form and adding System Tray support simply, MCL Hotkey for implemenmting system-wide hotkeys in your application...all with source code included.
-
Re: Hi!
Nice to see you here. A pity I am already out of votes...
<Excelent!> should be setted here.
Special thanks to Lothar "the Great" Haensler, Tom Archer, Chris Eastwood, TCartwright, Bruno Paris, Dr_Michael
and all the other wonderful people who made and make Codeguru a great place.
Come back soon, you Gurus.
The Rater
-
Re: Hi!
I'm just cultivating some C programmer contacts. I have finally realised that the global subclassing side of the EventVB.dll cannot be done in VB alone so I'm off to write me a C dll.
-------------------------------------------------
Ex. Datis: Duncan Jones
Merrion Computing Ltd
http://www.merrioncomputing.com
Check out the new downloads - ImageMap.ocx is the VB control that emulates an HTML image map, EventVB.OCX for adding new events to your VB form and adding System Tray support simply, MCL Hotkey for implemenmting system-wide hotkeys in your application...all with source code included.
-
Re: EventVb
I was afraid of it. It seemed too much like a dreeam to have low level functions in Vb... Well, let me know when I can download the new version...
;-)
Have a nice day, Duncan
Special thanks to Lothar "the Great" Haensler, Tom Archer, Chris Eastwood, TCartwright, Bruno Paris, Dr_Michael
and all the other wonderful people who made and make Codeguru a great place.
Come back soon, you Gurus.
The Rater
-
Re: EventVb
Well, the current release candidate (1.1.5) does an awful lot. I need to find out how to list the existing Named Pipes on a system before I "announce" it but the code added for getting the hardware profile and for enumerating the print jobs seems to be very robust.
Unfortunately I now have to do some paid work before I can return to it...an overdraft is a cruel master.
-------------------------------------------------
Ex. Datis: Duncan Jones
Merrion Computing Ltd
http://www.merrioncomputing.com
Check out the new downloads - ImageMap.ocx is the VB control that emulates an HTML image map, EventVB.OCX for adding new events to your VB form and adding System Tray support simply, MCL Hotkey for implemenmting system-wide hotkeys in your application...all with source code included.
-
Re: EventVb
Thanks for the replies guys...I was finally able to get it working by changing what I try to do in my callback function. I now simply change the value of a boolean in the callback, while on the form a timer checks the value of that boolean, and acts when it's value is changed. I think perhaps the way I was doing it before, my split thread didn't end before calling the new procedures. Not sure, but it's working so far... 8-)
Thanks again,
Sean