Click to See Complete Forum and Search --> : Callback functions


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

Cimperiali
October 10th, 2001, 03:35 AM
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

Clearcode
October 10th, 2001, 04:26 AM
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.

Cimperiali
October 10th, 2001, 06:27 AM
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

Clearcode
October 10th, 2001, 08:00 AM
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.

Cimperiali
October 10th, 2001, 08:03 AM
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

Clearcode
October 10th, 2001, 08:21 AM
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.

Dark Sean
October 10th, 2001, 02:13 PM
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