如何在Go和Swig中使用LPCWSTR?

huangapple go评论121阅读模式
英文:

How to use LPCWSTR with Go and Swig?

问题

我正在尝试使用Swig在Go中使用C库。这是简化的代码,我知道我可以使用cgo,但我需要在Swig中使用一个带有LPCWSTR参数的函数。

我在https://github.com/AllenDang/w32/blob/c92a5d7c8fed59d96a94905c1a4070fdb79478c9/typedef.go上看到LPCWSTR相当于*uint16,所以syscall.UTF16PtrFromString()似乎是我需要的,但是当我运行代码时,我遇到了异常。

我想知道我是否应该使用SwigcptrLPCWSTR

libtest.c

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include "libtest.h"
  4. __stdcall void hello(const LPCWSTR s)
  5. {
  6. printf("hello: %ls\n", s);
  7. }

libtest.h

  1. #ifndef EXAMPLE_DLL_H
  2. #define EXAMPLE_DLL_H
  3. #include <windows.h>
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7. #ifdef BUILDING_EXAMPLE_DLL
  8. #define EXAMPLE_DLL __declspec(dllexport)
  9. #else
  10. #define EXAMPLE_DLL __declspec(dllimport)
  11. #endif
  12. void __stdcall EXAMPLE_DLL hello(const LPCWSTR s);
  13. #ifdef __cplusplus
  14. }
  15. #endif
  16. #endif

我使用以下命令构建lib和DLL:

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

main.swig

  1. %module main
  2. %{
  3. #include "libtest.h"
  4. %}
  5. %include "windows.i"
  6. %include "libtest.h"

main.go

  1. package main
  2. import (
  3. "syscall"
  4. "unsafe"
  5. )
  6. func main() {
  7. p, err := syscall.UTF16PtrFromString("test")
  8. if err != nil {
  9. panic(err)
  10. }
  11. Hello(SwigcptrLPCWSTR(unsafe.Pointer(p)))
  12. }

跟踪信息

  1. Exception 0xc0000005 0x0 0xffffffffffffffff 0x7ffcc761f2e1
  2. PC=0x7ffcc761f2e1
  3. signal arrived during external code execution
  4. main._Cfunc__wrap_hello_main_90cec49f7d68ac58(0xc082002110)
  5. _/D_/lpcwstr/go/_obj/_cgo_gotypes.go:53 +0x38
  6. main.Hello(0x500028, 0xc082002120)
  7. _/D_/lpcwstr/go/_obj/main.go:63 +0x3c
  8. main.main()
  9. D:/lpcwstr/go/main.go:9 +0x96
  10. goroutine 17 [syscall, locked to thread]:
  11. runtime.goexit()
  12. c:/go/src/runtime/asm_amd64.s:1696 +0x1
  13. rax 0x6c007400690074
  14. rbx 0x6c007400690074
  15. rcx 0x7ffffffe
  16. rdi 0x24fd73
  17. rsi 0x7
  18. rbp 0x24fb00
  19. rsp 0x24fa00
  20. r8 0xffffffffffffffff
  21. r9 0x7ffcc75d0000
  22. r10 0x0
  23. r11 0x200
  24. r12 0xffffffff
  25. r13 0x24fd60
  26. r14 0x10
  27. r15 0x6264403a
  28. rip 0x7ffcc761f2e1
  29. rflags 0x10202
  30. cs 0x33
  31. fs 0x53
  32. gs 0x2b
英文:

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

  1. #include &lt;windows.h&gt;
  2. #include &lt;stdio.h&gt;
  3. #include &quot;libtest.h&quot;
  4. __stdcall void hello(const LPCWSTR s)
  5. {
  6. printf(&quot;hello: %ls\n&quot;, s);
  7. }

libtest.h

  1. #ifndef EXAMPLE_DLL_H
  2. #define EXAMPLE_DLL_H
  3. #include &lt;windows.h&gt;
  4. #ifdef __cplusplus
  5. extern &quot;C&quot; {
  6. #endif
  7. #ifdef BUILDING_EXAMPLE_DLL
  8. #define EXAMPLE_DLL __declspec(dllexport)
  9. #else
  10. #define EXAMPLE_DLL __declspec(dllimport)
  11. #endif
  12. void __stdcall EXAMPLE_DLL hello(const LPCWSTR s);
  13. #ifdef __cplusplus
  14. }
  15. #endif
  16. #endif

I build the lib and the DLL with :

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

main.swig

  1. %module main
  2. %{
  3. #include &quot;libtest.h&quot;
  4. %}
  5. %include &quot;windows.i&quot;
  6. %include &quot;libtest.h&quot;

main.go

  1. package main
  2. import (
  3. &quot;syscall&quot;
  4. &quot;unsafe&quot;
  5. )
  6. func main() {
  7. p, err := syscall.UTF16PtrFromString(&quot;test&quot;)
  8. if err != nil {
  9. panic(err)
  10. }
  11. Hello(SwigcptrLPCWSTR(unsafe.Pointer(p)))
  12. }

trace

  1. Exception 0xc0000005 0x0 0xffffffffffffffff 0x7ffcc761f2e1
  2. PC=0x7ffcc761f2e1
  3. signal arrived during external code execution
  4. main._Cfunc__wrap_hello_main_90cec49f7d68ac58(0xc082002110)
  5. _/D_/lpcwstr/go/_obj/_cgo_gotypes.go:53 +0x38
  6. main.Hello(0x500028, 0xc082002120)
  7. _/D_/lpcwstr/go/_obj/main.go:63 +0x3c
  8. main.main()
  9. D:/lpcwstr/go/main.go:9 +0x96
  10. goroutine 17 [syscall, locked to thread]:
  11. runtime.goexit()
  12. c:/go/src/runtime/asm_amd64.s:1696 +0x1
  13. rax 0x6c007400690074
  14. rbx 0x6c007400690074
  15. rcx 0x7ffffffe
  16. rdi 0x24fd73
  17. rsi 0x7
  18. rbp 0x24fb00
  19. rsp 0x24fa00
  20. r8 0xffffffffffffffff
  21. r9 0x7ffcc75d0000
  22. r10 0x0
  23. r11 0x200
  24. r12 0xffffffff
  25. r13 0x24fd60
  26. r14 0x10
  27. r15 0x6264403a
  28. rip 0x7ffcc761f2e1
  29. rflags 0x10202
  30. cs 0x33
  31. fs 0x53
  32. gs 0x2b

答案1

得分: 2

我怀疑你遇到的问题是因为你传递给 SWIG 的是一个双指针,而不是一个指针,即 wchar_t** 而不是 wchar_t*

我认为这是因为你调用了 UTF16PtrFromString,它接受了 UTF16 字符串的地址,然后随后调用了 unsafe.Pointer(p),我认为它再次取得了它的输入的地址。

从 Go 源代码中可以看到:

  1. func UTF16PtrFromString(s string) (*uint16) {
  2. a := UTF16FromString(s)
  3. return &a[0]
  4. }

所以我认为如果你改为:

  1. func main() {
  2. p, err := syscall.UTF16FromString("test") // 注意这里的微妙变化
  3. if err != nil {
  4. panic(err)
  5. }
  6. Hello(SwigcptrLPCWSTR(unsafe.Pointer(p)))
  7. }

它应该按预期工作。

英文:

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:

  1. func UTF16PtrFromString(s string) (*uint16) {
  2. a := UTF16FromString(s)
  3. return &amp;a[0]
  4. }

So I think if you instead use:

  1. func main() {
  2. p, err := syscall.UTF16FromString(&quot;test&quot;) // Note the subtle change here
  3. if err != nil {
  4. panic(err)
  5. }
  6. Hello(SwigcptrLPCWSTR(unsafe.Pointer(p)))
  7. }

It should work as intended.

huangapple
  • 本文由 发表于 2015年8月19日 03:36:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/32081171.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定