go - 如何从 cgo 获取 ac 变量?
问题描述
package main
/*
#include <malloc.h>
#include <windows.h>
HDC *hdcArr
BOOL CALLBACK EnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
for (int i = 0; i < (_msize(hdcArr) / sizeof(HDC)); i++) {
if (hdcArr[i] == NULL) {
hdcArr[i] = hdcMonitor;
break;
}
}
return TRUE;
}
void Init() {
int count = GetSystemMetrics(SM_CMONITORS);
hdcArr = (HDC*)malloc(sizeof(HDC) * count);
memset(hdcArr, 0, sizeof(HDC) * count);
}
HDC* GetHDC() {
return *hdcArr;
}
*/
import "C"
import (
"fmt"
"reflect"
"unsafe"
".../w32"
)
func main() {
var hdc w32.HDC
hdc = w32.GetDC(0)
C.Init()
w32.EnumDisplayMonitors(hdc, nil, reflect.ValueOf(C.EnumProc).Pointer(), 0)
t := (*[]w32.HDC)(unsafe.Pointer(&C.hdcArr))
cx := w32.GetDeviceCaps((*t)[0], w32.HORZRES)
fmt.Println(cx)
}
我写了上面的源代码。
我想要的是将 cgo 的 HDC 数组导入到 w32.HDC 数组中,以了解每个监视器的宽度和高度值。
但是,如果您导入t: = (* [] w32.HDC) unsafe.Pointer (& C.hdcArr))
并调用,则cx: = w32.GetDeviceCaps ((* t) [0], w32.HORZRES)
仅返回 0。
如何使用 cgo 查找多个显示器的宽度和高度?
解决方案
package main
/*
#cgo LDFLAGS: -lgdi32
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
HDC *hdcArr;
int count;
BOOL CALLBACK EnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
int i;
for (i = 0; i < (_msize(hdcArr) / sizeof(HDC)); i++) {
if (hdcArr[i] == NULL) {
hdcArr[i] = CreateCompatibleDC(hdcMonitor);
break;
}
}
return TRUE;
}
void Init() {
count = GetSystemMetrics(SM_CMONITORS);
hdcArr = (HDC*)malloc(sizeof(HDC) * count);
memset(hdcArr, 0, sizeof(HDC) * count);
}
*/
import "C"
import (
"fmt"
"reflect"
"unsafe"
"github.com/JamesHovious/w32"
)
func main() {
C.Init()
hdc := w32.GetDC(0)
w32.EnumDisplayMonitors(hdc, nil, reflect.ValueOf(C.EnumProc).Pointer(), 0)
w32.ReleaseDC(0, hdc)
t := (*[256]w32.HDC)(unsafe.Pointer(C.hdcArr))[:C.count:C.count]
for _, dc := range t {
cx := w32.GetDeviceCaps(dc, w32.HORZRES)
fmt.Println(cx)
w32.DeleteDC(dc)
}
C.free(unsafe.Pointer(C.hdcArr))
}
对您来说非常重要的是,指向 C 数组的指针只是一个内存地址,没有任何关于大小的信息(因此您的 t 数组为空)。这就是为什么你必须先把它转换成一个大数组(*[256]w32.HDC)
,然后再把它切成合适的大小[:C.count:C.count]
这就是为什么我创建了count
一个全局变量。
您遇到的另一个问题是传递给的 hdc 句柄EnumProc
仅在回调中有效。要使它们在回调范围之外永久可用,您必须调用CreateCompatibleDC(hdcMonitor);
.
要将此功能与 cgo 一起使用,您必须通过以下方式包含 lib gdi32#cgo LDFLAGS: -lgdi32
一旦你用完这些 DC,你必须再次释放它们w32.DeleteDC(dc)
也不要忘记释放你的 malloced 数组C.free(unsafe.Pointer(C.hdcArr))
我的建议:每当您使用 WinApi 时,请仔细阅读 msdn 文档。这需要一些时间,但可以为您省去很多麻烦
您也可以在没有 cgo 的情况下完全在 golang 中执行此操作:
package main
import (
"fmt"
"syscall"
"github.com/JamesHovious/w32"
)
func EnumProc(hMonitor w32.HMONITOR, hdcMonitor w32.HDC, lprcMonitor *w32.RECT, dwData w32.LPARAM) uintptr {
fmt.Println(w32.GetDeviceCaps(hdcMonitor, w32.HORZRES))
return w32.TRUE
}
func main() {
hdc := w32.GetDC(0)
w32.EnumDisplayMonitors(hdc, nil, syscall.NewCallback(EnumProc), 0)
w32.ReleaseDC(0, hdc)
}
甚至更平滑:
func EnumProc(hMonitor w32.HMONITOR, hdcMonitor w32.HDC, lprcMonitor *w32.RECT, dwData w32.LPARAM) uintptr {
horzres := lprcMonitor.Right - lprcMonitor.Left
fmt.Println(horzres)
return w32.TRUE
}
func main() {
w32.EnumDisplayMonitors(nil, nil, syscall.NewCallback(EnumProc), 0)
}
推荐阅读
- python - 在没有精灵的基本乒乓球游戏中,我将如何检测桨和球之间的碰撞
- python - 将 python 列表中的数组转换为 pandas,最终转换为 df.sum()
- powershell - Connect-PnPOnline : 远程服务器返回错误: (403) Forbidden
- android-studio - Android studio imageView(电话)未显示
- angular - Angular 的 Apollo 客户端 Chrome Devtools 缓存为空
- python - 如何使用 sqlalchemy 进行查询
- multithreading - 在 Common Lisp Bordeaux Threads 中重新启动已退出的线程?
- django - 从 dict 按名称访问对象
- php - Laravel:在 FormRequest 规则上获取 ID
- kdb - 订阅者的订阅详情