golang实现Windows OLE自动化操作的插件库go-ole的使用

golang实现Windows OLE自动化操作的插件库go-ole的使用

Go OLE

Go OLE是用于Windows COM的Go语言绑定库,使用共享库而不是cgo实现。由Yasuhiro Matsumoto开发。

安装

要实验go-ole,可以编译并运行示例程序:

go get github.com/go-ole/go-ole
cd /path/to/go-ole/
go test

cd /path/to/go-ole/example/excel
go run excel.go

示例代码

下面是一个使用go-ole操作Excel的完整示例:

package main

import (
	"github.com/go-ole/go-ole"
	"github.com/go-ole/go-ole/oleutil"
	"log"
)

func main() {
	// 初始化COM库
	ole.CoInitialize(0)
	defer ole.CoUninitialize()

	// 创建Excel应用程序对象
	unknown, err := oleutil.CreateObject("Excel.Application")
	if err != nil {
		log.Fatal(err)
	}
	excel, err := unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		log.Fatal(err)
	}
	defer excel.Release()

	// 设置Excel可见
	oleutil.PutProperty(excel, "Visible", true)

	// 添加工作簿
	workbooks := oleutil.MustGetProperty(excel, "Workbooks").ToIDispatch()
	workbook := oleutil.MustCallMethod(workbooks, "Add").ToIDispatch()
	defer workbook.Release()

	// 获取活动工作表
	sheet := oleutil.MustGetProperty(excel, "ActiveSheet").ToIDispatch()
	defer sheet.Release()

	// 在单元格A1中写入数据
	oleutil.MustPutProperty(sheet, "Cells", 1, 1, "Hello, World!")

	// 保存工作簿
	oleutil.MustCallMethod(workbook, "SaveAs", "C:\\test.xlsx")

	// 关闭Excel
	oleutil.PutProperty(excel, "DisplayAlerts", false)
	oleutil.MustCallMethod(workbook, "Close")
	oleutil.MustCallMethod(excel, "Quit")
}

多线程处理

处理多线程时有两种解决方案:

  1. 可以将函数或goroutine锁定到单个线程:
runtime.LockOSThread()
defer runtime.UnlockOSThread()
  1. 使用scjalliance/comshim

任何解决方案的关键是必须为每个CoInitialize()调用CoUninitialize()

测试

  1. go-ole/test-com-server下载一个发布版本
  2. 注册COM服务器
    • Windows 32位:
      c:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe /codebase /nologo c:\path\to\TestCOMServer.dll
      
    • Windows 64位:
      c:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe /codebase /nologo c:\path\to\TestCOMServer.dll
      
  3. 运行go test

持续集成

已添加Travis-CI和AppVeyor的持续集成配置。

Travis-CI 用于检查Linux上的构建,确保交叉编译时go get能正常工作。

AppVeyor 用于在Windows上构建,使用(开发中的)测试COM服务器。目前仅用于测试构建并确保代码在Windows上工作。

版本控制

Go OLE使用语义化版本控制进行版本编号,类似于Go语言的版本约定。这意味着主版本将始终与次版本保持向后兼容性。次版本只添加新的功能和更改。修复总是出现在补丁中。

这个约定应该允许你升级到新的次版本和补丁版本,而不会破坏或修改现有代码。

许可证

MIT许可证


更多关于golang实现Windows OLE自动化操作的插件库go-ole的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现Windows OLE自动化操作的插件库go-ole的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Go语言实现Windows OLE自动化操作 - go-ole库使用指南

go-ole是一个用于Go语言与Windows OLE/COM对象交互的库,允许Go程序调用Windows COM组件和自动化对象(如Excel、Word等)。下面详细介绍其使用方法。

安装go-ole

go get github.com/go-ole/go-ole
go get github.com/go-ole/go-ole/oleutil

基础使用示例

1. 初始化OLE

package main

import (
	"github.com/go-ole/go-ole"
	"github.com/go-ole/go-ole/oleutil"
	"log"
)

func main() {
	// 初始化COM库
	err := ole.CoInitialize(0)
	if err != nil {
		log.Fatal(err)
	}
	defer ole.CoUninitialize()
	
	// 其他操作...
}

2. 创建COM对象实例

// 创建Internet Explorer实例
func createIE() {
	unknown, err := oleutil.CreateObject("InternetExplorer.Application")
	if err != nil {
		log.Fatal(err)
	}
	defer unknown.Release()

	ie, err := unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		log.Fatal(err)
	}
	defer ie.Release()

	// 设置IE可见
	oleutil.PutProperty(ie, "Visible", true)
	
	// 导航到网页
	oleutil.CallMethod(ie, "Navigate", "https://www.example.com")
}

常用操作示例

1. 操作Excel

func excelExample() {
	// 创建Excel应用
	unknown, err := oleutil.CreateObject("Excel.Application")
	if err != nil {
		log.Fatal(err)
	}
	defer unknown.Release()

	excel, err := unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		log.Fatal(err)
	}
	defer excel.Release()

	// 设置Excel可见
	oleutil.PutProperty(excel, "Visible", true)
	
	// 获取工作簿集合
	workbooks := oleutil.MustGetProperty(excel, "Workbooks").ToIDispatch()
	defer workbooks.Release()
	
	// 添加新工作簿
	workbook := oleutil.MustCallMethod(workbooks, "Add").ToIDispatch()
	defer workbook.Release()
	
	// 获取活动工作表
	sheet := oleutil.MustGetProperty(workbook, "ActiveSheet").ToIDispatch()
	defer sheet.Release()
	
	// 在A1单元格写入数据
	oleutil.MustPutProperty(sheet, "Cells", 1, 1, "Hello from Go!")
	
	// 保存工作簿
	oleutil.MustCallMethod(workbook, "SaveAs", "C:\\test.xlsx")
	
	// 关闭Excel
	oleutil.MustCallMethod(workbook, "Close", false)
	oleutil.MustCallMethod(excel, "Quit")
}

2. 操作Word

func wordExample() {
	// 创建Word应用
	unknown, err := oleutil.CreateObject("Word.Application")
	if err != nil {
		log.Fatal(err)
	}
	defer unknown.Release()

	word, err := unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		log.Fatal(err)
	}
	defer word.Release()

	// 设置Word可见
	oleutil.PutProperty(word, "Visible", true)
	
	// 获取文档集合
	documents := oleutil.MustGetProperty(word, "Documents").ToIDispatch()
	defer documents.Release()
	
	// 添加新文档
	document := oleutil.MustCallMethod(documents, "Add").ToIDispatch()
	defer document.Release()
	
	// 获取内容范围
	content := oleutil.MustGetProperty(document, "Content").ToIDispatch()
	defer content.Release()
	
	// 插入文本
	oleutil.MustPutProperty(content, "Text", "This is a test document created from Go!")
	
	// 保存文档
	oleutil.MustCallMethod(document, "SaveAs", "C:\\test.docx")
	
	// 关闭Word
	oleutil.MustCallMethod(document, "Close", false)
	oleutil.MustCallMethod(word, "Quit")
}

高级用法

1. 处理事件

func eventExample() {
	// 创建IE实例
	unknown, err := oleutil.CreateObject("InternetExplorer.Application")
	if err != nil {
		log.Fatal(err)
	}
	defer unknown.Release()

	ie, err := unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		log.Fatal(err)
	}
	defer ie.Release()

	// 设置事件接收器
	eventSink := &ole.IEventSink{
		OnInvoke: func(disp *ole.IDispatch, dispid int, lcid uint32, flags int16, params *ole.DISPPARAMS) (result *ole.VARIANT, err error) {
			if dispid == 0x000000fc { // DocumentComplete事件
				url := oleutil.MustGetProperty(disp, "LocationURL").ToString()
				log.Printf("Document loaded: %s", url)
			}
			return nil, nil
		},
	}
	
	// 连接事件
	oleutil.ConnectObject(ie, eventSink, &ole.GUID{0x34A715A0, 0x6587, 0x11D0, [8]byte{0x92, 0x4A, 0x00, 0x20, 0xAF, 0xC7, 0xAC, 0x4D}})
	
	// 导航网页
	oleutil.PutProperty(ie, "Visible", true)
	oleutil.CallMethod(ie, "Navigate", "https://www.example.com")
	
	// 等待用户关闭IE
	select {}
}

2. 调用带命名参数的方法

func namedParamsExample() {
	// 创建WScript.Shell对象
	unknown, err := oleutil.CreateObject("WScript.Shell")
	if err != nil {
		log.Fatal(err)
	}
	defer unknown.Release()

	shell, err := unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		log.Fatal(err)
	}
	defer shell.Release()

	// 使用命名参数调用Popup方法
	// 等价于VBScript: WScript.Shell.Popup "Hello", 5, "Title", 64
	result := oleutil.MustCallMethod(
		shell,
		"Popup",
		"Hello",  // 消息
		5,        // 等待时间(秒)
		"Title",  // 标题
		64,       // 按钮类型(0=OK,64=Information图标)
	)
	defer result.Clear()
	
	log.Printf("Popup returned: %d", result.Val)
}

注意事项

  1. 线程模型: OLE操作必须在同一线程中完成,不要在goroutine中直接调用OLE方法
  2. 资源释放: 确保所有创建的COM对象都正确释放(使用Release())
  3. 错误处理: 检查所有可能返回错误的操作
  4. 初始化: 必须调用ole.CoInitialize()和ole.CoUninitialize()

通过go-ole库,Go程序可以方便地与Windows平台上的各种COM组件交互,实现强大的自动化功能。

回到顶部