
在Go中调用Windows COM接口(如MMDevice API)时,LPWSTR*参数实际是**uint16(即指向*uint16的指针),需传入二级指针以接收由CoTaskMemAlloc分配的宽字符字符串内存地址,并在使用后手动调用CoTaskMemFree释放。
在go中调用windows com接口(如mmdevice api)时,`lpwstr*`参数实际是`**uint16`(即指向`*uint16`的指针),需传入二级指针以接收由`cotaskmemalloc`分配的宽字符字符串内存地址,并在使用后手动调用`cotaskmemfree`释放。
Windows API 中的 LPWSTR 是 wchar_t* 的别名,即指向 UTF-16 编码字符(uint16)的指针;而 LPWSTR*(如 IMMDevice::GetId 的 [out] LPWSTR *ppstrId)则是指向该指针的指针——也就是 Go 中的 **uint16。这意味着该方法不会向你预分配的缓冲区写入数据,而是自行分配内存(通过 CoTaskMemAlloc),将字符串内容写入后,把新分配的内存地址写入你传入的指针变量中。
因此,正确的 Go 实现应如下:
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
func getId(mmd *IMMDevice) (string, error) {
var pStr *uint16 // 用于接收分配后的字符串首地址(LPWSTR)
// 传入 &pStr —— 即 LPWSTR*,对应 **uint16
hr, _, _ := syscall.Syscall(
mmd.VTable().GetId,
2,
uintptr(unsafe.Pointer(mmd)),
uintptr(unsafe.Pointer(&pStr)), // 关键:取地址!
0,
)
if hr != 0 {
return "", windows.Errno(hr)
}
// 将 *uint16 转为 Go string(自动处理 null 终止)
s := syscall.UTF16ToString((*[1 <p>⚠️ 注意事项:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill7640" title="windows-git-ops"><img
src="https://img.php.cn/upload/skill/000/000/081/179161031064883.jpg" alt="windows-git-ops" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill7640" title="windows-git-ops" class="overflowclass">windows-git-ops</a>
<p class="overflowclass">在 Windows PowerShell 工作区执行 Git 操作时使用此技能,特别适用于创建分支、暂存、提交、合并、状态检查等。</p>
</div>
<a rel="nofollow" href="/xiazai/skill7640" title="windows-git-ops" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
- *不可传入 `uint16
或nil`**:否则会导致访问非法内存或崩溃; -
必须检查返回值
hr:仅当hr == 0时才可安全使用pStr; -
必须调用
windows.CoTaskMemFree():不能用free()或C.free(),否则引发内存泄漏或堆损坏; -
syscall.UTF16ToString内部会按\0截断,安全可靠;若需更精细控制(如含嵌入空字符),可手动遍历pStr直到遇到0; - 若函数可能返回
nil指针(尽管GetId文档未声明),建议增加if pStr == nil防御性判断。
综上,理解 Windows 类型语义(尤其 * 和 ** 的层级)、匹配 Go 中的指针层级、并严格遵循 COM 内存管理契约(CoTaskMemAlloc / CoTaskMemFree 配对),是跨语言调用 Windows API 的关键。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










