//go:build windows package main import ( "fmt" "os" "path/filepath" "strings" "github.com/go-ole/go-ole" "github.com/go-ole/go-ole/oleutil" ) func FillCells(cells map[string]interface{}, fileContent []byte, printArea string) ([]byte, error) { ole.CoInitialize(0) defer ole.CoUninitialize() tmpInput, err := os.CreateTemp("", "*.xlsx") if err != nil { return nil, err } tmpInput.Write(fileContent) tmpInput.Close() inputPath, _ := filepath.Abs(tmpInput.Name()) defer os.Remove(inputPath) outputPath, _ := filepath.Abs(filepath.Join(os.TempDir(), "out_"+filepath.Base(inputPath))) defer os.Remove(outputPath) unknown, err := oleutil.CreateObject("Excel.Application") if err != nil { return nil, fmt.Errorf("Excel COM not available: %w", err) } excel, _ := unknown.QueryInterface(ole.IID_IDispatch) defer excel.Release() oleutil.PutProperty(excel, "Visible", false) oleutil.PutProperty(excel, "DisplayAlerts", false) workbooks := oleutil.MustGetProperty(excel, "Workbooks").ToIDispatch() workbook := oleutil.MustCallMethod(workbooks, "Open", inputPath).ToIDispatch() sheet := oleutil.MustGetProperty(workbook, "ActiveSheet").ToIDispatch() for addr, value := range cells { cell := oleutil.MustGetProperty(sheet, "Range", addr).ToIDispatch() oleutil.PutProperty(cell, "Value", value) cell.Release() } if printArea != "" { pageSetup := oleutil.MustGetProperty(sheet, "PageSetup").ToIDispatch() oleutil.PutProperty(pageSetup, "PrintArea", printArea) pageSetup.Release() } oleutil.MustCallMethod(workbook, "SaveAs", outputPath) oleutil.MustCallMethod(workbook, "Close") oleutil.MustCallMethod(excel, "Quit") return os.ReadFile(outputPath) } func ReadCells(fileContent []byte) (map[string]interface{}, error) { ole.CoInitialize(0) defer ole.CoUninitialize() tmpInput, err := os.CreateTemp("", "*.xlsx") if err != nil { return nil, err } tmpInput.Write(fileContent) tmpInput.Close() inputPath, _ := filepath.Abs(tmpInput.Name()) defer os.Remove(inputPath) unknown, err := oleutil.CreateObject("Excel.Application") if err != nil { return nil, fmt.Errorf("Excel COM not available: %w", err) } excel, _ := unknown.QueryInterface(ole.IID_IDispatch) defer excel.Release() oleutil.PutProperty(excel, "Visible", false) oleutil.PutProperty(excel, "DisplayAlerts", false) workbooks := oleutil.MustGetProperty(excel, "Workbooks").ToIDispatch() workbook := oleutil.MustCallMethod(workbooks, "Open", inputPath).ToIDispatch() sheet := oleutil.MustGetProperty(workbook, "ActiveSheet").ToIDispatch() usedRange := oleutil.MustGetProperty(sheet, "UsedRange").ToIDispatch() rowCount := int(oleutil.MustGetProperty(oleutil.MustGetProperty(usedRange, "Rows").ToIDispatch(), "Count").Val) colCount := int(oleutil.MustGetProperty(oleutil.MustGetProperty(usedRange, "Columns").ToIDispatch(), "Count").Val) cells := map[string]interface{}{} for r := 1; r <= rowCount; r++ { for c := 1; c <= colCount; c++ { cell := oleutil.MustGetProperty(sheet, "Cells", r, c).ToIDispatch() val, _ := oleutil.GetProperty(cell, "Value") if val.Val != 0 { addr := oleutil.MustGetProperty(cell, "Address", false, false).ToString() addr = strings.ReplaceAll(addr, "$", "") cells[addr] = val.Value() } cell.Release() } } var merged []map[string]string mergedAreas := oleutil.MustGetProperty(sheet, "MergedCells").ToIDispatch() if mergedAreas != nil { mergeCount, err := oleutil.GetProperty(mergedAreas, "Count") if err == nil && mergeCount.Val > 0 { for i := 1; i <= int(mergeCount.Val); i++ { area := oleutil.MustGetProperty(mergedAreas, "Item", i).ToIDispatch() addrStr := oleutil.MustGetProperty(area, "Address", false, false).ToString() addrStr = strings.ReplaceAll(addrStr, "$", "") parts := strings.Split(addrStr, ":") if len(parts) == 2 { merged = append(merged, map[string]string{"from": parts[0], "to": parts[1]}) } area.Release() } } } oleutil.MustCallMethod(workbook, "Close", false) oleutil.MustCallMethod(excel, "Quit") return map[string]interface{}{"cells": cells, "merged": merged}, nil }