Go: 解决'cannot use &cmdLine[0] (value of type *byte) as type *uint16' 错误

在 Go 中使用 syscall.CreateProcess 函数创建进程时,可能会遇到以下错误:

..go:23:3: cannot use &cmdLine[0] (value of type *byte) as type *uint16 in argument to syscall.CreateProcess

这个错误通常是因为 cmdLine 的类型为 []byte,而 CreateProcess 函数需要的是 LPWSTR 类型,即以 NULL 结尾的 Unicode 字符串。[]byte 类型无法直接转换为 LPWSTR 类型,需要先将其转换为 []uint16 类型,再通过 unsafe.Pointer 进行类型转换。

解决方法

cmdLine 的类型从 []byte 改为 []uint16 即可解决该问题。修改后的代码如下:

package main

import (
	"fmt"
	"syscall"
	"unsafe"
)

func DllMain() {
	// 无用的代码
	for i := 0; i < 100; i++ {
		fmt.Println(i)
	}

	// 创建子进程
	cmd := "cmd"
	cmdArgs := []string{"\C", "echo", "hello world"}
	cmdLine := []uint16(fmt.Sprintf("%s %s", cmd, cmdArgs))
	startupInfo := &syscall.StartupInfo{}
	processInformation := &syscall.ProcessInformation{}
	err := syscall.CreateProcess(
		nil,
		(*uint16)(unsafe.Pointer(&cmdLine[0])),
		nil,
		nil,
		false,
		0,
		nil,
		nil,
		startupInfo,
		processInformation,
	)
	if err != nil {
		fmt.Println(err)
		return
	}

	// 等待子进程结束并获取返回值
	var exitCode uint32
	syscall.WaitForSingleObject(processInformation.Process, syscall.INFINITE)
	syscall.GetExitCodeProcess(processInformation.Process, &exitCode)

	// 无用的代码
	for i := 0; i < 100; i++ {
		fmt.Println(i)
	}
}

func main() {
	DllMain()
}

// 导出 DllMain 函数
var (
	DllMainPtr = syscall.NewCallback(DllMain)
)

func init() {
	// 将 DllMain 函数注册为 DLL 的入口点
	handle, _ := syscall.LoadLibrary("kernel32.dll")
	defer syscall.FreeLibrary(handle)
	proc, _ := syscall.GetProcAddress(handle, "DllMain")
	syscall.Syscall(proc, 0, 0, 1, uintptr(unsafe.Pointer(&DllMainPtr)))
}

总结

在 Go 中使用 syscall.CreateProcess 函数创建进程时,需要确保 cmdLine 的类型为 []uint16,以便正确转换为 LPWSTR 类型。

Go: 解决

原文地址: https://www.cveoy.top/t/topic/lMQT 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录