Using a VC++ DLL in a VB6 project
Hey guys,
I am trying to use a certain function from a VC++ DLL in my VB6 project. The original VC++ function looks like this:
Code:
DLLEXPORT UNI_STATUS sysTabRead (const void *pTopicString,
const int topicIndex,
const void *pItemString,
const int itemIndex,
void *tableAddrs,
int tableSize,
SYS_TAB_ACCESS_TYPE accessType)
typedef enum
{
/* bit field */
DYNAMIC=1,
SAVED=2,
DEFAULT=4,
MINIMUM=8,
MAXIMUM=16,
} SYS_TAB_ACCESS_TYPE;
typedef enum {UNI_ERROR=-1, UNI_OK=0} UNI_STATUS;
When integrating the code in VB6, I wrote the following:
vb Code:
Public Enum SYS_TAB_ACCESS_TYPE
DYNAMIC = &H1&
SAVED = &H2&
'DEFAULT = &H4&
MINIMUM = &H8&
MAXIMUM = &H10&
End Enum
Public Enum UNI_STATUS
UNI_ERROR = -1&
UNI_OK = 0&
End Enum
Public Declare Function sysTabRead Lib "systab.dll" ( _
ByVal pTopicString As String, _
ByVal topicIndex As Long, _
ByVal pItemString As String, _
ByVal itemIndex As Long, _
ByRef tableAddrs As Any, _
ByVal tableSize As Long, _
ByVal accessType As SYS_TAB_ACCESS_TYPE) As UNI_STATUS
Now, here comes the tricky part, I have absolutely no idea where the "ByVal" declaration is necessary. I do know, however, that "ByRef" for tabelAddrs is required because tableAddrs is a pointer. The funny thing is that when I call the function, for example, in the following test subroutine:
vb Code:
Public Sub Test()
Dim errRet As UNI_STATUS, tableAddrs As Long
errRet = sysTabRead("testTopic", 0, "testKey", 0, tableAddrs, 4, DYNAMIC)
Debug.Print errRet
Debug.Print tableAddrs
End Sub
I receive a run-time error (49): "Bad DLL calling convention". However, if I choose to disregard the error (On Error Resume Next...), the function actually works, errRet returning as 0 (UNI_OK), and tableAddrs returning as the long value I was expecting. The thing is that a couple of seconds after the sub ends, VB6 crashes due to an incorrect memory "read" request...
I'm pretty sure that my problem is with the ByVals or with the argument types... Any ideas?
Re: Using a VC++ DLL in a VB6 project
If the error occur in the call the function will not return anything simply because it has not been called. The fact that errRet contains 0 after you've tried to make the call is simply because that is what it is initilized to before you make the call in the first place. Have a Debug.Print errRet before the call and lo and behold, it equals UNI_OK even before you've made the call.
You can get the "Bad DLL calling convention" for several reasons, but I suspect that the function isn't exported as a stdcall function but rather exported as the generic C/C++ type cdecl. VB can only call DLL functions that are exported using stdcall.
Re: Using a VC++ DLL in a VB6 project
Hey Joacim,
Thanks for your reply.
Please allow me to clarify: errRet is meaningless to me - it's tableAddrs that I care about. When tableAddrs is passed to the function, it equals 0. After I call the function (with On Error Resume Next), tableAddrs receives the expected value! So the call does work, but not exactly "in the right way"...
Any thoughts?
Re: Using a VC++ DLL in a VB6 project
What does the function do? Is tableAddrs supposed to be a return value (or out parameter) or is it expecting an address to table that you must already have allocated memory for? Why else would it need the size of the table in the next parameter?
Re: Using a VC++ DLL in a VB6 project
The function is similar to advapi32.dll's RegQueryValueExA function. The last parameter of the aforementioned function is the size of the buffer, and the one before it is the buffer itself (ByRef). So, sysTabRead, working in a similar matter, receives a buffer (tableAddrs), and the buffer size. In the case of my example sub, the buffer size is 4 bytes, for a long integer which I am expecting to receive. Once I call the function, the tableAddrs buffer receives the 4-byte long integer. In fact, when I debug the sub, after receiving the Bad DLL convention error message, if I query for the value of tableAddrs, the result is the long integer I was expecting.
Problem is, after several seconds, VB6 crashes with the memory read exception...
Please help?