How do I callback from C to VB?
I am trying to do a callback from my C++ dll to a VB program
I define the callback function pointer like so
Code:
typedef void ( __stdcall *PFNODSCALLBACK)(PSTR pszString);
VB declares a function that exists in the dll and passes it the Addressof MyCallback as long
The callback function is defined as:
VB Code:
Public Sub MyCallBack(ByVal lpDebug As Long)
Form1.logevent "Debug Output: " & Hex(lpDebug)
End Sub
later on in the dll it's called like this
Code:
//defined earlier
PFNODSCALLBACK m_pfnODSCallback;
//defined and initialized somewhere
char szBuffer[ 1024 ];
//call the VB callback function
m_pfnODSCallback( szBuffer );
Now, the callback is being made, but if I try to access the variable passed back I get a GPF.
So, my question is, how do I pass variables to a VB callback routine?
Re: How do I callback from C to VB?
More info,
The code as presented works as long as the VB program is run from the IDE, but crashes when I try to access the variable from a compiled exe.
Also, the callback is being made from a new thread I created in the dll.
As mentioned above, the callback works OK as long as I don't try to access the parameters passed to it.
What Im' trying to do must be do-able since many API functions rely on callbacks and can be run from VB.
Anyone have any examples of making a callback from C++ dll to VB 6?
Re: How do I callback from C to VB?
I had, a long time ago.
Is the callback sub in a global module?
Re: How do I callback from C to VB?
Yes, the VB callback routine is in a global module.
Re: How do I callback from C to VB?
OK, I've traced the problem to the fact that I'm making the callback from a different thread than the VB address was passed in. Since the call is still being made I know the address is still valid in the separate thread. So, the problem must be with the stack.??
Re: How do I callback from C to VB?
More troubleshooting:
I found that what was causing my program to crash was the VB call to Hex.
This is probably because MyCallBack is running in a different thread than my main VB program so has not been properly initialized (all that COM+ stuff)
Is there some way that I can execute a function in a thread that is already running? Many API's which require callbacks must do it somehow.
Re: How do I callback from C to VB?
Quote:
Originally Posted by moeur
More troubleshooting:
I found that what was causing my program to crash was the VB call to Hex.
This is probably because MyCallBack is running in a different thread than my main VB program so has not been properly initialized (all that COM+ stuff)
Is there some way that I can execute a function in a thread that is already running? Many API's which require callbacks must do it somehow.
Try changing you're callback routine to a function instead of a sub.
Re: How do I callback from C to VB?
Quote:
Try changing you're callback routine to a function instead of a sub.
OK, simple enough to try out...
No, didn't work.
I've been reading more about how VB treats threads. When VB creates threads, each thread acts as if it were an application of its own. Each thread gets its own copy of global variables, the Err object and the App object. The information for the location of these objects is stored in each thread's thread local storage (TLS).
So when I create my own thread, VB has no knowledge of the thread, if I encounter an error for example, VB trys to access the Err object, but instead gets an access violation because I haven't properly set up the TLS.
I came across some code where someone had discovered that the required address in TLS was in slot #4. So I tried the following
Before creating the new thread, get the address from TLS
Code:
LPVOID ThreadInfo = TlsGetValue(4);
Pass this value as the parameter to the ThreadProc when the thread is created.
Inside the threadProc I can put this value in my TLS.
Code:
TlsSetValue(4, lParam);
And tell VB I'm in a single thread Apartment
Unfortunately this didn't solve any problems.
Re: How do I callback from C to VB?
So I guess your problems might get solved if you left threading out completely.
Re: How do I callback from C to VB?
Quote:
So I guess your problems might get solved if you left threading out completely
Then I would be admitting that I've been beaten. Actually I'm about ready to do that.
According to Curland's book, I need to
CoInitialize(0);
CoCreateInstance (...);
before making the callback.
By Creating the instance I will be populating my TLS
Problem is, I don't know how to get a valid CLSID to use
I can get it from ProgId, but I don't know how to get that either.
Re: How do I callback from C to VB?
From the book it looks like you just have to create *some* object in the thread to initialises the TLS slots. So you can just create some dummy COM class and create an object of it. Or just create an object of any other already-defined COM class. You can look up CLSIDs in the registry, or use a tool to do it for you.
I might be wrong with some of that, my COM and VB are hazy nowadays.
Re: How do I callback from C to VB?
Quote:
Originally Posted by moeur
OK, simple enough to try out...
No, didn't work.
I've been reading more about how VB treats threads. When VB creates threads, each thread acts as if it were an application of its own. Each thread gets its own copy of global variables, the Err object and the App object. The information for the location of these objects is stored in each thread's thread local storage (TLS).
So when I create my own thread, VB has no knowledge of the thread, if I encounter an error for example, VB trys to access the Err object, but instead gets an access violation because I haven't properly set up the TLS.
I came across some code where someone had discovered that the required address in TLS was in slot #4. So I tried the following
Before creating the new thread, get the address from TLS
Code:
LPVOID ThreadInfo = TlsGetValue(4);
Pass this value as the parameter to the ThreadProc when the thread is created.
Inside the threadProc I can put this value in my TLS.
Code:
TlsSetValue(4, lParam);
And tell VB I'm in a single thread Apartment
Unfortunately this didn't solve any problems.
I had done this when I was in my little mix asm with vb mood. I just cannot remember what it was, see I had a little hicup as well. It had something to do with how I was calling the damn thing and I cannot remember for the life of me what it was. Try looking it up on msdn because that is likely where I found a solution.
Re: How do I callback from C to VB?
Quote:
From the book it looks like you just have to create *some* object in the thread to initialises the TLS slots. So you can just create some dummy COM class and create an object of it. Or just create an object of any other already-defined COM class.
OK, I tried this
Code:
DEFINE_GUID(CLSID_ListBox,0x58DA8D8AL,0x9D6A,0x101B,0xAF,0xC0,0x42,0x10,0x10,0x2A,0x8D,0xA7);
// Call CoInitialize to initialize the COM library
hr = CoInitialize(NULL);
//Then create an instance of some Com object
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_ListBox,
NULL,
CLSCTX_INPROC_SERVER,
IID_IUnknown,
(void **) &pITS);
if (FAILED(hr))
{
CoUninitialize();
return hr;
}
//make the call
if (DataReadNotify != NULL) DataReadNotify((long)hr);
No luck. I tried several different CLSIDs.
I think it's time to throw in the towel.
Re: How do I callback from C to VB?
So is the conclusion here that it is not possible to create a win32 dll in VB6 even with all these attempted work arounds?
I would love to experiment with hooks inside dlls that I could make in VB, but it seems that this is one tricky case.
What is the current problem here... COM Enabling of a thread?