我正在编写 sql.DB 连接的加密,但在 C 和 Go 之间转换指针时遇到一些问题。看来sql.DB不是Go中的简单结构体,并且有GoPointer,任何机会都可以将函数返回*sql.DB导出到C,并由另一个Go调用它?
//test.go
package main
/*
#cgo CFLAGS: -I.
#include <stdlib.h>
*/
import "C"
import (
"database/sql"
"fmt"
_ "github.com/denisenkom/go-mssqldb"
"unsafe"
)
//export GetDBPointer
func GetDBPointer(engine *C.char, connStr *C.char) uintptr {
connStrGo := C.GoString(connStr)
engineStrGo := C.GoString(engine)
// Do something to decrypt connStrGo
db, err := sql.Open(engineStrGo, connStrGo)
if err != nil {
fmt.Println("Failed to open database")
return 0
}
return uintptr(unsafe.Pointer(db))
}
func main() {}
// demo.go
package main
/*
#cgo LDFLAGS: -L. -ltest
#include "test.h"
#include <stdlib.h>
*/
import "C"
import (
"fmt"
"database/sql"
"unsafe"
)
func main() {
// an encrypted connStr, but for easy to understand right now
connStr := "server=;user id=;password=;database="
engine := "sqlserver"
// Convert Go string to C string
connStrC := C.CString(connStr)
engineC := C.CString(engine)
defer C.free(unsafe.Pointer(connStrC))
defer C.free(unsafe.Pointer(engineC))
// Call GetDBPointer to connect to the database
dbPtr := C.GetDBPointer(engineC, connStrC)
if dbPtr == 0 {
fmt.Println("Failed to connect to database")
return
}
dbConn := (*sql.DB)(unsafe.Pointer(dbPtr))
err := dbConn.Ping()
if err != nil {
fmt.Println("Failed to ping.")
}
}
go build -buildmode=c-shared -o test.dll test.go
go build -o demo.exe demo.go
我尝试直接使用指针,一个结构体包含unsafe.Pointer,以及我从书上读到的类似内容:
type ObjectId int32
var refs struct {
sync.Mutex
objs map[ObjectId] interface{}
next ObjectId
}
func init(){
refs.Lock()
defer refs.Unlock()
refs.objs = make(map[ObjectId] interface{})
refs.next = 1000
}
func NewObjectId(obj interface{}) ObjectId {
refs.Lock()
defer refs.Unlock()
id := refs.next
refs.next++
refs.objs[id] = obj
return id
}
func (id ObjectId) IsNil() bool {
return id == 0
}
func (id ObjectId) Get() interface{} {
refs.Lock()
defer refs.Unlock()
return refs.objs[id]
}
func (id *ObjectId) Free() interface{} {
refs.Lock()
defer refs.Unlock()
obj := refs.objs[*id]
delete(refs.objs, *id)
*id = 0
return obj
}
func GetObject(id ObjectId) (interface{}, bool) {
refs.Lock()
defer refs.Unlock()
obj, exists := refs.objs[id]
return obj, exists
}
func FreeObject(id ObjectId) {
refs.Lock()
defer refs.Unlock()
delete(refs.objs, id)
}
这看起来像是在 Go 中固定内存的反映
后来,我从github下载了一个ODBC驱动程序,并在连接函数中做了一些更改:我编写了一个cpp dll,extern连接函数来替换原生的,现在对我来说效果很好。