How to use LPCWSTR with Go and Swig?

brunoqc

I'm trying to use a C library with Go using Swig. This is simplified code, I know I can use cgo but I need to use a function with a LPCWSTR argument with Swig.

I saw on https://github.com/AllenDang/w32/blob/c92a5d7c8fed59d96a94905c1a4070fdb79478c9/typedef.go that LPCWSTR is the equivalent of *uint16 so syscall.UTF16PtrFromString() seems to be what I need but I get an exception when I run the code.

I'm wondering if I'm supposed to use SwigcptrLPCWSTR or not.

libtest.c

#include <windows.h>
#include <stdio.h>

#include "libtest.h"

__stdcall void hello(const LPCWSTR s)
{
    printf("hello: %ls\n", s);
}

libtest.h

#ifndef EXAMPLE_DLL_H
#define EXAMPLE_DLL_H

#include <windows.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifdef BUILDING_EXAMPLE_DLL
#define EXAMPLE_DLL __declspec(dllexport)
#else
#define EXAMPLE_DLL __declspec(dllimport)
#endif

void __stdcall EXAMPLE_DLL hello(const LPCWSTR s);

#ifdef __cplusplus
}
#endif

#endif

I build the lib and the DLL with :

gcc -c -DBUILDING_EXAMPLE_DLL libtest.c
gcc -shared -o libtest.dll libtest.o -Wl,--out-implib,libtest.a

main.swig

%module main

%{
#include "libtest.h"
%}

%include "windows.i"
%include "libtest.h"

main.go

package main

import (
    "syscall"
    "unsafe"
)

func main() {
    p, err := syscall.UTF16PtrFromString("test")
    if err != nil {
        panic(err)
    }
    Hello(SwigcptrLPCWSTR(unsafe.Pointer(p)))
}

trace

Exception 0xc0000005 0x0 0xffffffffffffffff 0x7ffcc761f2e1
PC=0x7ffcc761f2e1
signal arrived during external code execution

main._Cfunc__wrap_hello_main_90cec49f7d68ac58(0xc082002110)
        _/D_/lpcwstr/go/_obj/_cgo_gotypes.go:53 +0x38
main.Hello(0x500028, 0xc082002120)
        _/D_/lpcwstr/go/_obj/main.go:63 +0x3c
main.main()
        D:/lpcwstr/go/main.go:9 +0x96

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        c:/go/src/runtime/asm_amd64.s:1696 +0x1
rax     0x6c007400690074
rbx     0x6c007400690074
rcx     0x7ffffffe
rdi     0x24fd73
rsi     0x7
rbp     0x24fb00
rsp     0x24fa00
r8      0xffffffffffffffff
r9      0x7ffcc75d0000
r10     0x0
r11     0x200
r12     0xffffffff
r13     0x24fd60
r14     0x10
r15     0x6264403a
rip     0x7ffcc761f2e1
rflags  0x10202
cs      0x33
fs      0x53
gs      0x2b
Flexo

I suspect the issue you're seeing is because what you're passing into SWIG is a double pointer instead of just a pointer, i.e. wchar_t** instead of just wchar_t*.

I think this comes about because you call UTF16PtrFromString which takes the address of the UTF16 string and then subsequently call unsafe.Pointer(p) which I think again takes the address of its input.

From the go source code:

func UTF16PtrFromString(s string) (*uint16) {
    a := UTF16FromString(s)
    return &a[0]
}

So I think if you instead use:

func main() {
    p, err := syscall.UTF16FromString("test") // Note the subtle change here
    if err != nil {
        panic(err)
    }
    Hello(SwigcptrLPCWSTR(unsafe.Pointer(p)))
}

It should work as intended.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related