You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Cocoa的NSDictionary取值并通过Go的cgo获取Chrome窗口参数?

如何通过cgo从Objective-C的NSDictionary中提取Chrome窗口Bounds参数

一、Objective-C中从NSDictionary提取窗口Bounds的方法

kCGWindowBounds对应的是被NSValue包装的CGRect类型,需要先转成CGRect再提取坐标、宽高参数:

// 从窗口字典中获取Bounds值
NSValue *boundsValue = window[(NSString *)kCGWindowBounds];
// 转换为CGRect结构体
CGRect bounds = boundsValue.CGRectValue;
// 提取具体参数
CGFloat x = bounds.origin.x;
CGFloat y = bounds.origin.y;
CGFloat width = bounds.size.width;
CGFloat height = bounds.size.height;

二、修改cgo代码,让Go能直接获取可用参数

Go无法直接操作Objective-C的NSDictionary对象,因此我们在Objective-C层提前提取所需参数,通过C风格结构体返回给Go。修改后的完整代码如下:

package getlark

/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Cocoa
#import <Cocoa/Cocoa.h>
#import <CoreGraphics/CGWindow.h>

// 定义C结构体存储窗口参数,方便Go解析
typedef struct {
    double x;
    double y;
    double width;
    double height;
    int found; // 标记是否找到Chrome窗口
} WindowBounds;

static WindowBounds FindChromeBounds(void){
    WindowBounds result = {0, 0, 0, 0, 0};
    NSArray *windows = (NSArray *)CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements|kCGWindowListOptionOnScreenOnly,kCGNullWindowID);
    
    for(NSDictionary *window in windows)
    {
        NSString *currentApp = window[(NSString *)kCGWindowOwnerName];
        if ([currentApp isEqualToString:@"Google Chrome"]){
            NSValue *boundsValue = window[(NSString *)kCGWindowBounds];
            CGRect bounds = boundsValue.CGRectValue;
            
            result.x = bounds.origin.x;
            result.y = bounds.origin.y;
            result.width = bounds.size.width;
            result.height = bounds.size.height;
            result.found = 1;
            break; // 找到第一个Chrome窗口就终止遍历
        }
    }
    
    CFRelease(windows); // 手动释放CGWindowListCopyWindowInfo返回的对象,避免内存泄漏
    return result;
}
*/
import "C"
import "fmt"

// Go侧对应的窗口参数结构体
type WindowBounds struct {
    X      float64
    Y      float64
    Width  float64
    Height float64
    Found  bool
}

func GetLarkPos() WindowBounds {
    cBounds := C.FindChromeBounds()
    
    return WindowBounds{
        X:      float64(cBounds.x),
        Y:      float64(cBounds.y),
        Width:  float64(cBounds.width),
        Height: float64(cBounds.height),
        Found:  cBounds.found != 0,
    }
}

// 示例调用函数
func main() {
    bounds := GetLarkPos()
    if bounds.Found {
        fmt.Printf("Chrome窗口位置:X=%.2f, Y=%.2f,宽:%.2f,高:%.2f\n", bounds.X, bounds.Y, bounds.Width, bounds.Height)
    } else {
        fmt.Println("未找到Google Chrome窗口")
    }
}

三、关键细节说明

  • 内存管理:CGWindowListCopyWindowInfo返回的是CF类型对象,必须用CFRelease手动释放,避免内存泄漏。
  • 类型映射:C语言的double对应Go的float64,C的int对应Go的int,通过自定义结构体可以批量传递多个参数。
  • 循环优化:原代码中return语句后不需要break(return已退出函数),修改为找到目标窗口就终止循环,减少不必要的遍历。

内容的提问来源于stack exchange,提问作者sgx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:07:04