65.9K
CodeProject 正在变化。 阅读更多。
Home

在 WTL(或其他原生 Win32)应用程序中集成 OpenOffice.org 的强大功能

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (31投票s)

2009 年 1 月 9 日

CPL

7分钟阅读

viewsIcon

87925

downloadIcon

3363

OOo::DocWindow 和 WTL::COOoCtrl 类,可用于处理任何 Microsoft-Office 文档,并支持 Visual Studio/VCExpress 2005/2008 中的 Open Office SDK 集成

OOo

演示

OpenOffice.orgOOo – 是一款免费的开源办公套件,可与 Microsoft-Office 在许多商务任务中竞争。使用它可以处理 Microsoft-Office 文档,是购买 Microsoft-Office 套件的替代方案。OOo 是免费的。OOo 3.0 于 2008 年 10 月发布,是一款成熟且令人印象深刻的软件

本文档将帮助您开始在 WTL(或其他原生 Win32)应用程序中集成 OpenOffice.org 的强大功能。

预览

首先,如果您尚未安装 OpenOffice.org 3.0,请从 OpenOffice.org 下载并安装。

接下来,将 WtlOOo.exe 应用程序从 WtlOOo_exe.zip 解压到任意合适的位置,然后运行它。尝试打开您手边的任何 Microsoft-Office 文件,并检查打印和打印预览功能以及另存为 PDF 的功能。

这些 OOo 内置功能通过一个简单的 WTL 命令处理程序,使用 WTL::COOoCtrl 类进行调用。

class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>,
                   public CMessageFilter, public CIdleHandler
{
//...
        COOoCtrl m_view;

//...
        BEGIN_MSG_MAP(CMainFrame)
//...
                COMMAND_ID_HANDLER(ID_FILE_SAVE, OnSaveToPDF)

//...
        LRESULT OnSaveToPDF(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/,
                BOOL& /*bHandled*/)
        {
                m_view.ExecuteId(ID_OOo_PDF);
                return 0;
        }
//...

准备 OOo SDK

要使用 **Uno API** 并访问您应用程序中的 OOo 功能,您应执行以下步骤:

  • OpenOffice.org 下载并安装 OOo 3.0 SDK 到开发工作站上的一个 <OOoSdkDir> 目录。在 Vista 系统上,请避免安装在 C:\Program Files 或任何其他受 UAC 保护的文件夹中。
  • 生成与您的 OOo 安装匹配的 OOo SDK C++ 代码
    • OOoCpp.jsOOo.vspropsOOo.zip 解压到 <OOoSdkDir>\sdk 目录。
    • 运行 **OOoCpp.js**。此脚本将创建一个 <OOoSdkDir>\includecpp 文件夹,使用正确的参数运行 SDK 的 **cppumaker** 工具,以填充此文件夹,包含与 uno 类型库 types.rdboffapi.rdb 匹配的 C++ 头文件;**cppumaker** 位于 <OOoSdkDir>\bin 目录下,并且需要位于 <OOoInstallDir>\URE\bin 中的 OOo DLL。源类型库位于 <OOoInstallDir> 下的不同文件夹中,因此此脚本是避免许多麻烦的方法。

      OOoCpp.js 还将更新 OOo.vsprops 中的 **OOoSdkDir** 变量,使其指向您的 <OOoSdkDir> 安装文件夹。

将此更新的 OOo.vsprops 属性集添加到 Visual Studio/VCExpress 2005/2008 的任何 Win32 项目中,即可在您的 C++ 项目中使用 OOo SDK。

OOo.vsprops 定义了预处理器宏 **WNT**,设置了正确的头文件和库的搜索路径和名称,并设置了 sal3.dll, cppu3.dllcppuhelper3MSC.dll 的延迟加载。因此,应用程序可以在实际调用它们之前,将其运行时路径添加到 OOo DLL 所在的位置(位于 <OOoInstallDir>\URE\bin 并可在注册表中找到)。

<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioPropertySheet
        ProjectType="Visual C++"
        Version="8.00"
        Name="OOo"
        >
        <Tool
                Name="VCCLCompilerTool"
                AdditionalIncludeDirectories=
                 "&quot;$(OOoSdkDir)\include&quot;;&quot;$(OOoSdkDir)\includecpp&quot;"
                PreprocessorDefinitions="WNT"
        />
        <Tool
                Name="VCLinkerTool"
                PerUserRedirection="true"
                AdditionalDependencies=
                 "isal.lib icppu.lib icppuhelper.lib isal.lib
                  isalhelper.lib ireg.lib irmcxt.lib stlport_vc71.lib"
                AdditionalLibraryDirectories="$(OOoSdkDir)\lib"
                DelayLoadDLLs="sal3.dll;cppu3.dll;cppuhelper3MSC.dll"
                DataExecutionPrevention="1"
        />
        <UserMacro
                Name="OOoSdkDir"
                Value="<OOoSdkDir>\sdk"
                PerformEnvironmentSet="true"
        />
</VisualStudioPropertySheet>

编译 WtlOOo.exe

WTLOOo.sln 是一个 VC2005 Express 解决方案,如果用 VS2008 或 VC2008 Express 打开,它将进行升级。您现在应该可以编译它了。

由于本文档位于 WTL 部分,我假设您的 Visual Studio/VCExpress 2005/2008 编译器已正确配置以访问 **WTL 8.0**。

  • 下载 WtlOOo.zip 并将项目文件解压到您选择的 <WtlOOoProj> 文件夹。
  • 将您更新的 OOo.vsprops<OOoSdkDir>\sdk 复制到 <WtlOOoProj> 文件夹。
  • 编译、运行,尽情享用。

在 WindowsTM 中使用 uno API 进行开发

本文档**不是** uno API 的教程。有关此处使用的命名空间和类的文档,请参阅 OpenOffice.org 开发者指南及相关链接。

atlOOo.h 中的代码分为两个命名空间:

  • OOo 命名空间是纯 Win32 代码,不需要 ATL 或 WTL。它由辅助函数和两个类组成:
    • Ooo::DocWindow.
    • Ooo::TerminationMonitor。
  • WTL::COOoCtrlT<> 类需要 OOo 命名空间的代码,并且基于 OOo:DocWindowATL::CWindow

OOo 函数

  • uno 辅助函数
    • OOo::GetBootContext(),引导上下文访问器:通过 ::cppu::bootstrap() 调用获取 com::sun::star::uno::XComponentContext
    • OOo::GetComponentFactory(),主工厂访问器。
    • OOo::Instance(),uno 服务访问器助手。
  • 运行时辅助函数
    • LRESULT OOo::FindInstallAndSetPath() 如果在注册表中找到 OOo DLL 的位置,则将其添加到应用程序的 **PATH** 环境变量中。
    • const bool OOo::IsAvailable() 执行运行时连接测试:它调用 FindInstallAndSetPath(),如果成功,则调用 GetBootContext(),从而在设置其访问路径后链接到 OOo DLL。

      在应用程序代码的开头调用 OOo::IsAvailable() 是触发 OOo DLL 延迟加载的最佳方式。如果 OOo::IsAvailable() 返回 false,则在此运行时环境中无法使用 OOo。

  • com::sun::star::util::URL **解析器**:OOo 使用其 URL 类来处理许多描述符,而不仅仅是文件说明符。
    • URL OOo::GetURL(LPCWSTR sUrl)LPCWSTR(例如,命令字符串如 ".uno:ExportDirectToPDF")返回一个通用的 com::sun::star::util::URL
    • URL OOo::GetPathURL(LPCWSTR sPath)LPCWSTR Win32 路径名返回一个正确填充的 com::sun::star::util::URL
  • com::sun::star::beans::PropertyValuecom::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> **助手**
    • template <typename T> PropertyValue OOo::PropVal(LPCWSTR sName, T t_Val)LPCWSTR 和任意类型的值返回一个 com::sun::star::beans::PropertyValue
    • template <typename T> Sequence<PropertyValue> OOo::SeqPropVal(LPCWSTR sName, T t_Val) 返回一个 com::sun::star::uno::Sequence 元素,其中包含一个名为 sNamecom::sun::star::beans::PropertyValue<T>
  • com::sun::star::uno::Any/HWND **转换器**
    • Any OOo::HWNDToAny(HWND hWnd)
    • HWND OOo::AnyToHWND(Any& any)
  • 文件可加载性测试:

    • bool OOo::CanLoad(LPCWSTR sPath) 检查名为 sPath 的 Win32 文件是否可以作为 uno 文档加载。

OOo::TerminationMonitor

系统中运行着单个 OOo sOffice.exe 实例,用户可以通过 **Quit** 菜单命令结束它。只要 OOo::TerminationMonitor 对象存在,它就可以阻止 sOffice.exe 被用户或程序终止(这将卸载 OOo DLL 并导致我们的应用程序崩溃)。

默认构造函数:OOo::TerminationMonitor(bool bAllow = false, bool bRegister = true) 设计用于在对象生命周期内防止 OOo 终止。TerminationMonitor 的简单默认实例化将(bRegister = true)与其一起注册到 sOffice.exe,并阻止(bAllow = false)用户终止。

if (OOo::IsAvailable())
{
    OOo::TerminationMonitor tm; // prevent user OOo termination ...
     
} // ...until here

在大多数情况下,这已足够。如果您需要更细粒度的操作,可以使用不带注册的构造函数,然后在之后使用 bool Register(bool bRegister)bool AllowTermination(bool bAllow) 成员。

OOo::DocWindow:一个 uno 文档窗口包装类

这个独立的类包装了一个包含 uno 文档的 OOo 窗口。它没有显式构造函数,并且由于其(private)数据成员都是智能指针,因此也没有显式析构函数。与**窗口**相关的成员是:

  • bool OOo::DocWindow::Create(HWND hWndParent, LPCWSTR sFrameName = NULL, bool bVisible = true) 作为 hWndParent 的子窗口创建 uno 窗口,并将其插入 uno 架构。成功时返回 true,否则返回 false
  • HWND OOo::DocWindow::GetHWND() 返回 DocWindow 的 Win32 HWND,如果未创建则为 NULL
  • void OOo::DocWindow::SetWindowRect(RECT& rect) 通过 OOo 程序设置 DocWindow 的位置。
  • bool OOo::DocWindow::UIShow(LPCWSTR sURL, bool bShow) 设置 UI 元素的可见性:sURL 是一个视觉元素标识符,例如 "private:resource/menubar/menubar"

    与**文档**相关的成员是:

  • bool OOo::DocWindow::OpenDocument(URL& url, Sequence<PropertyValue>& sProperties)

    使用 sProperties PropertyValue 从请求的 URL 打开文档:例如,PropVal(L"ReadOnly", true)

  • bool OOo::DocWindow::OpenNewDocument(LPCWSTR sName, bool bReadOnly = true)

    sName 准备一个空的文档 URL(例如 "private:factory/scalc")和一个 Sequence<PropertyValue>(来自 PropVal(L"ReadOnly", bReadOnly)),然后再调用 OpenDocument(URL&, Sequence<PropertyValue>&)

  • bool OOo::DocWindow::OpenFileDocument(LPCWSTR sPath, bool bReadOnly = true)

    使用文件路径名执行相同操作。

  • bool Ooo::DocWindow::CloseDocument()
  • bool OOo::DocWindow::HasDocument()
  • LPCWSTR Ooo::DocWindow::GetDocTitle()
  • bool OOo::DocWindow::ExecuteURL(URL& url, Sequence<PropertyValue>& sProperties, 
    	Reference<XStatusListener> xListener = NULL)

    执行命令 URL,例如 ".uno:ExportDirectToPDF"。有效的命令名称可以在本文档中找到。

WTL::COOoCtrl:OOo::DocWindow 的 WTL 包装器

这个非常简单的类继承自 ATL::CWindowOOo::DocWindow

一些 CWindow 成员被重写以避免误用:您不能 Attach()Detach() 一个 COOoCtrl

操作的 Create() 成员调用 OOo::DocWindow::Create(),成功后将 CWindow::m_hWnd 设置为 OOo::DocWindow::GetHWND() 的结果。

HWND Create(HWND hWndParent, LPCWSTR szWindowName = NULL, bool bVisible = true)
{
    ATLASSERT(m_hWnd == NULL);
    ATLASSERT(::IsWindow(hWndParent));

    if (DocWindow::Create(hWndParent, szWindowName, bVisible))
        m_hWnd = GetHWND();

    ATLASSERT(IsWindow());

    return m_hWnd;
}

其他 Create() 成员调用此方法,并忽略大部分参数。

WTL::COOoCtrl 向其父类添加了两个成员,允许使用资源字符串进行 UI 可见性和命令执行。

bool ExecuteId(UINT uIdOOoCmd)
{
    CTempBuffer<WCHAR> sCmd(64);
    AtlLoadString(uIdOOoCmd, sCmd, 64);
    return ExecuteURL(GetURL(sCmd), Sequence<PropertyValue>());
}

bool UIShowId(UINT uIdOOoUIPart, bool bShow)
{
    CTempBuffer<WCHAR> sUIPart(64);
    AtlLoadString(uIdOOoUIPart, sUIPart, 64);
    return UIShow(sUIPart, bShow);
}

WtlOOo 对 COOoCtrl 的使用

WtlOOo 从一个简单的(WTL AppWizard 生成的)多线程 SDI 应用程序开始,使用 WTL::COOoCtrl 作为视图。

命令和 UI 描述符字符串资源已添加到 WtlOOo.rc

STRINGTABLE
BEGIN
    IDR_MAINFRAME           "WtlOOo"
    ID_OOo_PDF              ".uno:ExportDirectToPDF"
    ID_OOo_PRINT            ".uno:PrintDefault"
    ID_OOo_PRINT_PREVIEW    ".uno:PrintPreview"
    ID_OOo_UI_MENUBAR       "private:resource/menubar/menubar"
    ID_OOo_UI_STANDARDBAR   "private:resource/toolbar/standardbar"
END

在运行消息循环之前,我们检查 OOo::IsAvailable();如果为 false,我们则使用消息框中止;否则,我们实例化一个 Ooo::TerminationMonitor 并运行应用程序。

// WtlOOo.cpp : main source file for WtlOOo.exe
//...
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/,
      LPTSTR lpstrCmdLine, int nCmdShow)
{
//...
    // BLOCK: Run application
    if (OOo::IsAvailable())
    {
        OOo::TerminationMonitor tm;
        CWtlOOoThreadManager mgr;
        nRet = mgr.Run(lpstrCmdLine, nCmdShow);
    }
    else
        AtlMessageBox(NULL, L"OpenOffice.org 3 not found!", IDR_MAINFRAME,
                MB_OK | MB_ICONERROR);
//...

CMainFrame 中,我们声明一个 COOoCtrl m_view 成员。

// MainFrm.h : interface of the CMainFrame class
//
/////////////////////////////////////////////////////////////////////////////

#pragma once

class CMainFrame : public CFrameWindowImpl<CMainFrame>, public CUpdateUI<CMainFrame>,
        public CMessageFilter, public CIdleHandler
{
public:
    DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)

    COOoCtrl m_view;

我们完成消息映射。

BEGIN_MSG_MAP(CMainFrame)
    MESSAGE_HANDLER(WM_CREATE, OnCreate)
    MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
    COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
    COMMAND_ID_HANDLER(ID_FILE_OPEN, OnFileOpen)
    COMMAND_ID_HANDLER(ID_FILE_NEW, OnNewWindow)
    COMMAND_RANGE_HANDLER(ID_NEW_WRITER, ID_NEW_WEBPAGE, OnNewDoc)
    COMMAND_ID_HANDLER(ID_FILE_SAVE, OnSaveToPDF)
    COMMAND_ID_HANDLER(ID_FILE_PRINT_PREVIEW, OnPrintPreview)
    COMMAND_ID_HANDLER(ID_FILE_PRINT, OnPrint)
    COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
    COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
    NOTIFY_CODE_HANDLER(TBN_DROPDOWN, OnMenuNew)
END_MSG_MAP()

文件打开和新建文档处理

OnFileOpen() 执行文件打开对话框,并检查所选文件是否可以通过 OOo::CanLoad() 加载;OnNewDoc() 构建所选新文档的名称。

两者都在 m_view 中打开它,现有文档以只读方式打开,隐藏菜单和主工具栏(它们附加到文档而不是窗口),并更新窗口标题。

加载新文档将关闭当前文档,因此两者都恢复先前存在的文档菜单和工具栏的可见性。

void ShowDocBars(bool bShow)
{
   if (m_view.HasDocument())
   {
      m_view.UIShowId(ID_OOo_UI_MENUBAR, bShow);
      m_view.UIShowId(ID_OOo_UI_STANDARDBAR, bShow);
   }
}

void UpdateTitle()
{
   static CString sApp(MAKEINTRESOURCE(IDR_MAINFRAME));
   CString sTitle;
   if (m_view.HasDocument())
      sTitle.Format(L"%s - %s", m_view.GetDocTitle(), sApp);
   else
      sTitle = sApp;
   SetWindowText(sTitle);
}

LRESULT OnNewDoc(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, 
    BOOL& /*bHandled*/)
{
   static CString sTitle = L"private:factory/";
   LPCWSTR names[] =
   {
      L"swriter", L"scalc", L"sdraw", L"simpress", L"swriter/web"
   };

   ShowDocBars(true);
   m_view.OpenNewDocument(sTitle + names[wID - ID_NEW_WRITER], false);
   ShowDocBars(false);
   UpdateTitle();
   return 0;
}

LRESULT OnFileOpen(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, 
    BOOL& /*bHandled*/)
{
   CFileDialog dlg(TRUE);
   if (dlg.DoModal() == IDOK && OOo::CanLoad(dlg.m_szFileName))
   {
      CWaitCursor wc;
      ShowDocBars(true);
      m_view.OpenFileDocument(dlg.m_szFileName);
      ShowDocBars(false);
      UpdateTitle();
   }
   return 0;
}

**打印**、**打印预览**和**保存**命令由 CMainFrame 处理,它使用相应的命令字符串 ID 调用 COOoCtrl::ExecuteId()

LRESULT OnSaveToPDF(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/,
     BOOL& /*bHandled*/)
{
    m_view.ExecuteId(ID_OOo_PDF);
    return 0;
}

LRESULT OnPrintPreview(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/,
     BOOL& /*bHandled*/)
{
    m_view.ExecuteId(ID_OOo_PRINT_PREVIEW);
    return 0;
}

LRESULT OnPrint(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
    m_view.ExecuteId(ID_OOo_PRINT);
    return 0;
}

结论

使用 OpenOffice.org 3.0,可以通过一些努力在原生 Win32 应用程序中集成 OOo 文档窗口。OOo 与 WTL 结合可以成为处理商务文档时脚本或宏编程的替代方案。

历史

  • 2009 年 10 月 11 日 - 初始发布
  • 2009 年 6 月 16 日 - 更新
    • atlOOo.h:修复了 Ooo::IsAvailable() 中的错误,添加了 OOO::TerminationMonitor,进行了少量代码改进,将函数名称更改为 Ooo::DocWindow::OpenFileDocumentOoo::DocWindow::OpenNewDocument
    • WtlOOo 应用程序:在 _tWinMain 中添加了新建文档功能和 Ooo::TerminationMonitor
    • 相应的更新了本文档
© . All rights reserved.