首页 > 解决方案 > 通过 Windows Powershell pinvoke go c-shared dll 后,可执行文件中没有标准输出

问题描述

这是一个奇怪的问题 - 通过 Powershell 从 golang c-shared dll 调用函数后,可执行文件(例如 hostname.exe、ipconfig 等)的后续执行显示没有输出到 stdout。仅当 powershell 是调用 dll 函数的那个​​时才会发生这种情况(Windows 上的 python 不会重现此问题)。

我做了什么?

我用一个导出函数(HelloWorld)交叉编译了我可以为 Windows 使用的最简单的 c-shared dll。然后我从 Powershell 调用了 dll。

去代码是:

package main

import "C"
import (
        "fmt"
)

//export HelloWorld
func HelloWorld() {
        fmt.Println("Hello World")
}

func main() {}

使用的构建命令(来自 linux)是:

GOARCH=amd64 GOOS=windows CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build -v -buildmode=c-shared -o helloworld.dll .

然后我将生成的 .dll 复制到 Windows 并使用以下 Powershell 脚本调用 HelloWorld() 函数:

$signature = @"
[DllImport("c:\\cshared\\helloworld.dll")]
public static extern void HelloWorld();
"@

Add-Type -MemberDefinition $signature -Name World -Namespace Hello

[Hello.World]::HelloWorld()

我期待看到什么?

我希望 dll 的 HelloWorld() 函数能够成功调用(导致文本“Hello World”被写入控制台),然后我希望能够使用我的 powershell 提示符执行进一步的控制台命令,例如“主机名”或“ipconfig”等

我看到了什么?

这真的很奇怪。HelloWorld() 函数确实执行成功了,我在控制台上看到了文本“Hello World”。但是,在调用该函数后,我不再能够在我的 powershell 窗口中看到 cmd.exe 命令的任何控制台输出。例如,调用“hostname”只会返回没有输出,“ipconfig”也会发生同样的情况。

例如,最初 hostname.exe 工作并提供输出,但在执行 cshared dll 后,我无法在控制台上看到 hostname..exe 的任何进一步输出:

PS C:\cshared> hostname
nick-host
PS C:\cshared> hostname
nick-host
PS C:\cshared> .\helloworld.ps1
Hello World
PS C:\cshared> hostname
PS C:\cshared> ipconfig
PS C:\cshared> hostname

如果我将 hostname.exe 的输出通过管道传输到文件(例如“hostname > out.txt”),那么我可以确认输出存在并且命令成功(如果将可执行命令通过管道传输到“Out-Host”,也会发生同样的情况" cmdlet)....所以执行 c-shared dll 似乎会以某种方式导致 stdout 被重定向或无法正确显示?或者关于 PS 会话的编码要打破的东西?

我尝试从 go 代码中删除 fmt.Println 以查看是否有帮助,但问题仍然相同。我也只在 Powershell 上看到了这一点(如果我做了同样的实验,但在 Windows 上从 python 调用 helloworld.dll,之后我在 shell 中看不到任何问题)。

有任何想法吗?

标签: powershellgostdoutpinvoke

解决方案


这已被 Windows 的控制台所有者识别为 golang 本身的错误。去问题线程在这里:https ://github.com/golang/go/issues/44876


推荐阅读