when you pass a string in, you have to have the dll function looking for a Long not a string. Then you convert the string within the dll to a vbString using the vb StrConv() function. Once the string is in natve vb string form, you can do whatever you like with it within the dll as a normal vb string. Then, once you want to pass the string (or any string) back out of the dll you need to convert it using StrConv() again. I wrote 2 private functions in my dll, 1 that converts the inbound string as its passed in, and 1 that converts a string for output.
Here's the 2 converter functions, and a sample function called Greet() that accepts 1 string as an argument, and returns a string - showing how to do the inbound and outbound conversions:
'//Required for receiving and returning Strings///////////////
Private Function ConvInputStr(strX As Long) As String
ConvInputStr = StrConv(SysAllocStringByteLen(strX, lstrlen(strX)), vbUnicode)
End Function
Private Function ConvOutputStr(strX As String) As String
ConvOutputStr = StrConv(strX, vbFromUnicode)
End Function
Public Function Greet(ByVal msg As Long) As String
Dim s As String
s = ConvInputStr(msg)
Greet = ConvOutputStr("Hello " & s)
End Function
'/////////////////////////////////////////////////////////////
Also, there is 1 module and 1 class file that need to be in your dll which can be found in the vbAdvance example of "non-vb-caller". It is necessary to have this in your dll code so the vb6 runtime is initialized properly ass your dll is instanciated. Also your dll code resides in a module in the dll, not a cls file. I will post it below momentarily....
Required cls file CRuntimeInit.cls:
'---------------------------------------------------------------------------------------
' Module : CRuntimeInit.cls
' Purpose : VB runtime initialization.
' Warnings : DO NOT MODIFY THIS CODE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING.
'---------------------------------------------------------------------------------------
Option Explicit
'------------------------------------------------------------------------------
' Procedure : InitVBCall
' Purpose : Required by MRuntimeInit.bas for VB runtime initialization.
'------------------------------------------------------------------------------
Public Sub InitVBCall()
End Sub
The required bas module MRuntimeInit.bas:
'---------------------------------------------------------------------------------------
' Module : MRuntimeInit.bas
' Purpose : VB runtime initialization.
' Warnings : DO NOT MODIFY THIS CODE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING.
'
' This file depends on:
' References:
' vbAdvance.tlb (vbAdvance Type Library) Needed only at compile-time.
' Files:
' CRuntimeInit.cls
'
'---------------------------------------------------------------------------------------
Option Explicit
'==============================================================================
'FunctionDelegator code from Feb.2000 VBPJ article "Call Function Pointers"
'by Matthew Curland
'http://www.powervb.com
'------------------------------------------------------------------------------
Private Const cDelegateASM As Currency = -368956918007638.6215@
Private m_DelegateASM As Currency
Private Type DelegatorVTables
VTable(7) As Long
End Type
Private m_VTables As DelegatorVTables
Private m_pVTableOKQI As Long
Private m_pVTableFailQI As Long
Public Type FunctionDelegator
pVTable As Long
pfn As Long
End Type
'END FUNCTION DELEGATOR CODE
'==============================================================================
'Object reference which keeps runtime alive:
Private moInitObject As CRuntimeInit
'------------------------------------------------------------------------------
' Procedure : RuntimeInitialize
' Purpose : VB runtime initialization. Pass handle to the DLL that this
' code resides in.
'
' DO NOT MODIFY THIS ROUTINE UNLESS YOU KNOW EXACTLY WHAT YOU
' ARE DOING.
'
'------------------------------------------------------------------------------
Public Sub RuntimeInitialize(ByVal hMod As Long)
Dim sFile As String
Dim lLen As Long
Dim lRet As Long
Dim i As Long
Dim lpTypeLib As Long
Dim TLI As ITypeLib
Dim lppTypeInfo As Long
Dim TI As ITypeInfo
Dim sName As String
Dim pAttr As Long
Dim TA As TYPEATTR
Dim IID_ClassFactory As VBGUID
Dim IID_IUnknown As VBGUID
Dim pGetClass As Long
Dim pCall As ICallDLLGetClassObject
Dim FD As FunctionDelegator
Dim pICF As IClassFactory
Dim pUnk As IUnknown
'Make sure parent process is not VB IDE:
If GetModuleHandle("VBA6.DLL") <> 0 Then Exit Sub
If GetModuleHandle("VBA5.DLL") <> 0 Then Exit Sub
sFile = Space$(260)
lLen = Len(sFile)
lRet = GetModuleFileName(hMod, sFile, lLen)
If lRet Then
sFile = Left$(sFile, lLen - 1)
lpTypeLib = LoadTypeLibEx(sFile, REGKIND_NONE)
CopyMemory TLI, lpTypeLib, 4
For i = 0 To TLI.GetTypeInfoCount - 1
If TLI.GetTypeInfoType(i) = TKIND_COCLASS Then
lppTypeInfo = TLI.GetTypeInfo(i)
CopyMemory TI, lppTypeInfo, 4
TI.GetDocumentation DISPID_UNKNOWN, sName, "", 0, ""
If lstrcmp(sName, "CRuntimeInit") = 0 Then
pAttr = TI.GetTypeAttr
CopyMemory TA, ByVal pAttr, Len(TA)
TI.ReleaseTypeAttr pAttr
If TA.wTypeFlags Then
Exit For
End If
End If
End If
Next i
With IID_ClassFactory
.Data1 = 1
.Data4(0) = &HC0
.Data4(7) = &H46
End With
With IID_IUnknown
.Data4(0) = &HC0
.Data4(7) = &H46
End With
pGetClass = GetProcAddress(hMod, "DllGetClassObject")
If pGetClass Then
CopyMemory pCall, InitDelegator(FD, pGetClass), 4
lRet = pCall.Call(TA.iid, IID_ClassFactory, pICF)
If lRet <> CLASS_E_CLASSNOTAVAILABLE Then
lRet = pICF.CreateInstance(0&, IID_IUnknown, pUnk)
If lRet = S_OK Then
Set moInitObject = pUnk
moInitObject.InitVBCall
CopyMemory pCall, 0&, 4
Set pICF = Nothing
Set pUnk = Nothing
End If
End If
End If
End If
End Sub
'==============================================================================
'FunctionDelegator code from Feb.2000 VBPJ article "Call Function Pointers"
'by Matthew Curland
'http://www.powervb.com
'------------------------------------------------------------------------------
Public Function InitDelegator(Delegator As FunctionDelegator, Optional ByVal pfn As Long) As IUnknown
If m_pVTableOKQI = 0 Then InitVTables
With Delegator
.pVTable = m_pVTableOKQI
.pfn = pfn
End With
CopyMemory InitDelegator, VarPtr(Delegator), 4
End Function
Private Sub InitVTables()
Dim pAddRefRelease As Long
With m_VTables
.VTable(0) = FuncAddr(AddressOf QueryInterfaceOK)
.VTable(4) = FuncAddr(AddressOf QueryInterfaceFail)
pAddRefRelease = FuncAddr(AddressOf AddRefRelease)
.VTable(1) = pAddRefRelease
.VTable(5) = pAddRefRelease
.VTable(2) = pAddRefRelease
.VTable(6) = pAddRefRelease
m_DelegateASM = cDelegateASM
.VTable(3) = VarPtr(m_DelegateASM)
.VTable(7) = .VTable(3)
m_pVTableOKQI = VarPtr(.VTable(0))
m_pVTableFailQI = VarPtr(.VTable(4))
End With
End Sub
Private Function QueryInterfaceOK(This As FunctionDelegator, riid As Long, pvObj As Long) As Long
pvObj = VarPtr(This)
This.pVTable = m_pVTableFailQI
End Function
Private Function AddRefRelease(ByVal This As Long) As Long
End Function
Private Function QueryInterfaceFail(ByVal This As Long, riid As Long, pvObj As Long) As Long
pvObj = 0
QueryInterfaceFail = E_NOINTERFACE
End Function
Private Function FuncAddr(ByVal pfn As Long) As Long
FuncAddr = pfn
End Function
'END FUNCTION DELEGATOR CODE
'==============================================================================
The main bas module where you write your dll functions MExportedFunctions.bas:
(Includes the converter functions and the greet function from example above, but also includes
necessary dll_process_attach code
Option Explicit
Public Function DllMain(ByVal hinstDLL As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long
Const DLL_PROCESS_ATTACH As Long = 1
If fdwReason = DLL_PROCESS_ATTACH Then
'Initialize the VB Runtime when this DLL is first
'loaded by a process:
RuntimeInitialize hinstDLL
'Must return TRUE for success:
DllMain = 1
End If
End Function
'//Required for receiving and returning Strings/////////////
Private Function ConvInputStr(strX As Long) As String
ConvInputStr = StrConv(SysAllocStringByteLen(strX, lstrlen(strX)), vbUnicode)
End Function
Private Function ConvOutputStr(strX As String) As String
ConvOutputStr = StrConv(strX, vbFromUnicode)
End Function
'////////////////////////////////////////////////////////////
Public Function Greet(ByVal msg As Long) As String
Dim s As String
s = ConvInputStr(msg)
Greet = ConvOutputStr("Hello " & s)
End Function
Once you have this all working, your main module can instance any internal vb objects like forms, other modules, classes, system dlls, api's etc etc.
Have fun!