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

如何通过编程方式保存并关闭运行中的LibreOffice Calc实例?

问题描述

我正在开发一款集成Excel/LibreOffice Calc的跨平台.NET应用,目前需要实现:打开.xls文件供用户编辑后,通过编程方式保存并关闭文件。我用ProcessStartInfo启动LibreOffice Calc的代码如下:

var startInfo = new ProcessStartInfo
{
    FileName = "libreoffice",
    Arguments = $"--calc {filePath} --single-window-app",
};

启动Calc后,我能关闭文档,但不知道怎么编程保存。终端或C#代码实现都可以,而且我掌握该进程的所有信息(PID、窗口标题等)。

我尝试过用uno命令:

soffice --headless --invisible --norestore \
    "vnd.sun.star.ServiceManager" \
    "com.sun.star.frame.Desktop" ".uno:SaveAll"

但报错:/home/mk/vnd.sun.star.ServiceManager does not exist.

解决方案

1. 修正UNO命令调用格式(终端/C#执行通用)

你之前的命令错误在于把UNO服务标识符当成了文件路径传入,正确做法是通过--accept参数连接到已运行的Calc实例,再执行保存命令。

步骤1:启动Calc时开启远程连接

修改启动代码,添加--accept参数,让实例允许远程调用:

var port = 2002; // 自定义端口,确保未被占用
var startInfo = new ProcessStartInfo
{
    FileName = "libreoffice",
    Arguments = $"--calc {filePath} --single-window-app --accept=\"socket,host=localhost,port={port};urp;\"",
};
Process.Start(startInfo);

步骤2:执行保存命令

需要保存时,运行以下终端命令(或用C#的Process.Start执行):

soffice --headless --invisible --norestore \
    --accept="socket,host=localhost,port=2002;urp;" \
    "macro:///Standard.SaveAllMacro.SaveAll()"

注:需先在LibreOffice中创建宏模块:

  1. 打开LibreOffice Calc,按Alt+F11打开宏编辑器
  2. 创建名为SaveAllMacro的模块,写入以下代码:
Sub SaveAll()
    Dim oDesktop As Object
    oDesktop = CreateUnoService("com.sun.star.frame.Desktop")
    oDesktop.executeDispatch(oDesktop.getCurrentFrame(), ".uno:SaveAll", "", 0, Array())
End Sub

2. C#直接调用UNO API(跨平台推荐)

通过Unofficial.LibreOffice.Interop NuGet包,直接连接到已运行的Calc实例,调用保存和关闭方法:

步骤1:安装NuGet包

Install-Package Unofficial.LibreOffice.Interop

步骤2:编写操作代码

using unoidl.com.sun.star.frame;
using unoidl.com.sun.star.uno;
using unoidl.com.sun.star.util;

// 连接到已运行的LibreOffice实例
var resolver = UnoRuntime.getUniversalContentResolver();
var context = (XComponentContext)resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext");
var desktop = (XDesktop)context.getServiceManager().createInstanceWithContext("com.sun.star.frame.Desktop", context);

// 执行保存所有文档
var dispatchHelper = (XDispatchHelper)context.getServiceManager().createInstanceWithContext("com.sun.star.frame.DispatchHelper", context);
var currentFrame = desktop.getCurrentFrame();
dispatchHelper.executeDispatch(currentFrame, ".uno:SaveAll", "", 0, new PropertyValue[0]);

// 优雅关闭所有文档(可选)
var components = desktop.getComponents();
var enumeration = components.createEnumeration();
while (enumeration.hasMoreElements())
{
    var component = (XComponent)enumeration.nextElement();
    component.dispose();
}

3. Windows平台:模拟快捷键保存(简单方案)

如果仅针对Windows平台,可通过Windows API发送Ctrl+S快捷键到Calc窗口实现保存:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

public class WindowHelper
{
    [DllImport("user32.dll")]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll")]
    private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    private const uint WM_KEYDOWN = 0x0100;
    private const uint WM_KEYUP = 0x0101;
    private const int VK_CONTROL = 0x11;
    private const int VK_S = 0x53;

    public static void SendSaveShortcut(string windowTitle)
    {
        var hwnd = FindWindow(null, windowTitle);
        if (hwnd == IntPtr.Zero) return;

        // 模拟Ctrl+S按键序列
        PostMessage(hwnd, WM_KEYDOWN, (IntPtr)VK_CONTROL, IntPtr.Zero);
        PostMessage(hwnd, WM_KEYDOWN, (IntPtr)VK_S, IntPtr.Zero);
        PostMessage(hwnd, WM_KEYUP, (IntPtr)VK_S, IntPtr.Zero);
        PostMessage(hwnd, WM_KEYUP, (IntPtr)VK_CONTROL, IntPtr.Zero);
    }
}

// 调用示例:传入Calc窗口标题
WindowHelper.SendSaveShortcut("你的文档标题 - LibreOffice Calc");
// 之后可关闭进程
Process.GetProcessById(yourPid).CloseMainWindow();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 21:33:14