DLL for VB6 "Bad DLL calling convention"

I’m traying to do a DLL to Work in VB6.

I have this code in the DLL:

package main

// +build windows win32

import (
	"C"
	"fmt"
)

//export GetIntFromDLL
func GetIntFromDLL() int32 {
	return 42
}

//export PrintHello
func PrintHello(Name *C.char, Output **C.char) int32 {
	*Output = C.CString(fmt.Sprintf("From DLL: Hello, %s!", C.GoString(Name)))
	return int32(len(C.GoString(*Output)))
}

//export PrintBye
func PrintBye(Output **C.char) int32 {
	*Output = C.CString(fmt.Sprintf("From DLL: Bye!"))
	return int32(len(C.GoString(*Output)))
}

//export LenString
func LenString(Input *C.char) int32 {
	return int32(len(C.GoString(Input)))
}

//export OutString
func OutString() (Output *C.char) {
	buf := C.CString("I am out string from DLL")
	return buf
}

func main() {
	// main
}

set CC=mingw32-gcc
set GOOS=windows
set GOARCH=386
set CGO_ENABLED=1
go build -buildmode=c-archive main.go
mingw32-gcc -shared -o testDLL.dll testDLL.c main.a -Wl,–add-stdcall-alias -lWinMM -lntdll -lWS2_32

And the file DLL compiles well.
And I made a test app to use the dll in GO:

package main

import (
	"C"
	"fmt"
	"syscall"
	"time"
	"unsafe"
)

var (
	dllTest           = syscall.NewLazyDLL("testDLL.dll")
	procGetIntFromDLL = dllTest.NewProc("GetIntFromDLL")
	procPrintHello    = dllTest.NewProc("PrintHello")
	procPrintBye      = dllTest.NewProc("PrintBye")
	procLenString     = dllTest.NewProc("LenString")
	procOutString     = dllTest.NewProc("OutString")
)

func main() {
	fmt.Println("usageDLL v1.1")

	start := time.Now()

	x1, _, _ := procGetIntFromDLL.Call()
	fmt.Println("GetIntFromDLL():", x1)
	buffer2 := make([]byte, 256)
	x2, _, _ := procPrintHello.Call(uintptr(unsafe.Pointer(syscall.StringBytePtr("Juan"))), uintptr(unsafe.Pointer(&buffer2)))
	fmt.Println("PrintHello('Juan',&buffer):", string(buffer2[0:x2]))
	buffer3 := make([]byte, 256)
	x3, _, _ := procPrintBye.Call(uintptr(unsafe.Pointer(&buffer3)))
	fmt.Println("PrintBye(&buffer):", string(buffer3[0:x3]))
	x4, _, _ := procLenString.Call(uintptr(unsafe.Pointer(syscall.StringBytePtr("12345678"))))
	fmt.Println("LenString('12345678'):", x4)
	x5, _, _ := procOutString.Call()
	fmt.Println("OutString():", C.GoString((*C.char)(unsafe.Pointer(x5))))
	elapsed := time.Since(start)

	fmt.Printf("Generated in %s\n", elapsed)

}

All right in GO!
But I cant to work this in VB6, I have declare it so:

Declare Function GetIntFromDLL Lib "testDLL.dll" () As Long
Declare Function PrintHello Lib "testDLL.dll" (ByVal Nombre As String, ByRef Output As String) As Long
Declare Function PrintBye Lib "testDLL.dll" (ByRef Output As String) As Long
Declare Function LenString Lib "testDLL.dll" (ByVal Nombre As String) As Long
Declare Function OutString Lib "testDLL.dll" () As String

Only GetIntFromDLL() and OutString() works in VB6. The others return "Bad DLL calling convention ".

I have heard about STDCALL but i don’t know how do this.

Thanks!

Dependency Walker return this errors

Error: At least one required implicit or forwarded dependency was not found.
Warning: At least one delay-load dependency module was not found.
Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module.

You might find the following article useful as it describes how to discover and handle DLL calling conventions by using “dumpbin” utility.

https://www.codeproject.com/Articles/6243/Step-by-Step-Calling-C-DLLs-from-VC-and-VB-Part

1 Like

@Jonathan_Hecl, have there been any findings on how to generate a dll usable in VB6?

From my findings:

  • VB6 needs stdcall calling conventions. It has no other options available.
  • go build --buildmode=c-shared uses cdecl calling conventions.

Hi, I still can’t create a DLL for VB6 from Go. :frowning_face: