
VB, Callbacks and Strings
Hi Jeff,
VB strings are something called BSTR in COM. When interfacing with DLL's
requiring C style strings (zero terminated) VB _does_ a conversion for you
in both directions.
Another important point. On this style of interfacing VB/C code you have to
declare all your string paremeters as ByVal on th VB side!
This is very important.
The next important point. You should declare callbacks on std modules on VB
side!!!
Right! The C side function has to be declared as __stdcall.
Let's have a look at the following code. It gets the caption of a form using
the GetWindowsText API function.
Private Declare Function GetWindowText lib "user32" Alias "GetWindowTextA"
_
ByVal hWnd As Long, _
ByVal lpString As String, _
ByVal nMaxCount As Long _
) As Long
Sub Form1_Click()
Const N = 256
Dim strBuf As String
strBuf = String(N, Chr(0)) ' create a buffer
Dim nLen As Long
nLen = GetWindowText(Me.hWnd, strBuf, Len(strBuf))
strBuf = Left(strBuf, nLen)
MsgBox strBuf
End Sub
Before calling GetWindowText VB converts your UNICODE buffer to ANSI and
after returning it converts the result back to UNICODE.
Back to your problem.
C side declaration (test.dll):
typedef void (__stdcall* CALLBACKPROC)(LPCSTR pszText);
CALLBACKPROC* g_pfnCallback = NULL;
void __stdcall setCallback(CALLBACKPROC* pfnCallback)
{
g_pfnCallback = pfnCallback;
Quote:
}
/* just a stub */
void __stdcall fireEvent(LPCSTR pszText)
{
if (NULL != g_pfnCallback)
(*g_pfnCallback)(pszText);
Quote:
}
void __stdcall doTheJob()
{
fireEvent("Starting...");
// do some work here
for (...)
{
fireEvent("Work in progress...");
}
fireEvent("Done!");
Quote:
}
On VB side (test.bas):
Declare Procedure setCallback Lib "test.dll" (ByVal pfnCallback As Long)
Declare Procedure doTheJob Lib "test.dll"
Public Sub test()
Call setCallback(AddressOf myCallback) ' set callback
Call doTheJob
Call setCallback(0) ' remove callback
End Sub
Public Sub myCallback(ByVal s As String)
Debug.Print s
End Sub
Hope this helps.
IMHO this kind of callbacks are deprecated, we have to use them only when
dealing with legacy code.
The way to go is COM! Even with legacy systems it's better to build COM
wrappers...
Regards,
Peter
Quote:
> OK, here's the problem:
> I have a VB application that uses a C/C++ DLL. The DLL provides an
interface
> that is used to pass error messages back to the calling application. This
> mechanism is handled by having the application designate a callback
function
> to the DLL. The error message is a parameter to the callback, and it is a
> C-style string.
> Here is the callback function I am using:
> Sub ErrorMessageHandler(message As String)
> ' some code here. We would like to use the MsgBox function to display the
> message
> End Sub
> So far, I can get the callback registered properly, and it is called
> appropriately by the DLL (now that I have everything worked out as
__stdcall
> functions, etc.). The problem is that the string passed as a parameter
seems
> to be unusable. That is, it's not a Basic string really, and if I try to
> access it, the application hangs.
> Is there any way that I can somehow convert the C-style string into
> something that Basic can use? An array of Byte? This is frustrating
because
> the data is there, but I can't get my mitts on it.
> Thanks in advance...