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






4.96/5 (31投票s)
OOo::DocWindow 和 WTL::COOoCtrl 类,可用于处理任何 Microsoft-Office 文档,并支持 Visual Studio/VCExpress 2005/2008 中的 Open Office SDK 集成
- 下载 WtlOOo 1.1 应用程序 - 88.83 KB
- 下载 SDK 准备脚本 - 1.85 KB
- 下载 WtlOOo 1.1 项目 - 34.73 KB
- 下载(已更新)atlOOo.h 类和函数 - 4.9 KB

演示
OpenOffice.org – OOo – 是一款免费的开源办公套件,可与 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.js 和 OOo.vsprops 从 OOo.zip 解压到 <OOoSdkDir>\sdk 目录。
- 运行 **OOoCpp.js**。此脚本将创建一个 <OOoSdkDir>\includecpp 文件夹,使用正确的参数运行 SDK 的 **cppumaker** 工具,以填充此文件夹,包含与 uno 类型库 types.rdb 和 offapi.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.dll 和 cppuhelper3MSC.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=
                 ""$(OOoSdkDir)\include";"$(OOoSdkDir)\includecpp""
                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:DocWindow和ATL::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)从- LPCWSTRWin32 路径名返回一个正确填充的- com::sun::star::util::URL。
 
- com::sun::star::beans::PropertyValue和- com::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元素,其中包含一个名为- sName的- com::sun::star::beans::PropertyValue<T>。
 
- com::sun::star::uno::Any/- HWND**转换器**- Any OOo::HWNDToAny(HWND hWnd)和
- HWND OOo::AnyToHWND(Any& 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::CWindow 和 OOo::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::OpenFileDocument和Ooo::DocWindow::OpenNewDocument。
- WtlOOo 应用程序:在 _tWinMain中添加了新建文档功能和Ooo::TerminationMonitor。
- 相应的更新了本文档
 
- atlOOo.h:修复了 


