По работе мне необходимо было разработать механизм загрузки и выгрузки данных из Excel используя свободные механизмы работающие под разными ОС.
Т.к. необходимо было, чтобы сервис работал под Linux, то механизм взаимодействия через OLE не подходил.
Для реализации был выбран OpenOffice с прямым доступом к API через C++.

Документация оказалась весьма скудная, а примеров работы не через OLE почти не было. Так что я решил объединить все мои исследования в одной статье на хабре.
Примерный план статьи:
1. Начало работы с API OpenOffice через C++
1.1. Генерация заголовочных файлов
1.2. Генерация файла типов RDB
1.3. Настройка Visual Studiо 2008
1.4. Собираем динамическую DLL
2. Повторное использование DLL в своей программе
2.1. Пример небольшой программы по выгрузке данных
В принципе, если возможностей DLL достаточно, то повторять действия п. 1 не обязательно.
Этот раздел достаточно подробно описан в вики офиса: wiki.services.openoffice.org/wiki/SDKInstallation.
Для начала работы с API необходимо скачать SDK с адреса download.services.openoffice.org/files/stable. Важно чтобы версия SDK совпадала с версией установленного офиса.
Устанавливаем SDK в любую дирректорию.
Устанавливаем вспомогательные утилиты gnu make, zip (если необходимо)
Внутри директории с SDK должен быть батник setsdkenv_windows.bat, генерирующий другой батник.
Выполняем его, отвечая на вопросы.
Будет сгенерирован батник с установками переменных окружения.
Открываем консоль, выполняем сгенерированный батник, и в этойже подготовленной консоли генерируем заголовочные файлы для конкретной версии офиса.
Команда генерации:
, где
c:\Program Files\OpenOffice_SDK\sdk\inludecpp — папка куда будем генерировать
c:\Program Files\OpenOffice.org 3\ — путь до офиса
Также для начала работы нужно сгенерировать RDB файл конкретно для вашей версии офиса.
RDB файл — это что-то типа файла с описаниями типов и интерфейсов конкретной версии OpenOffice.
Делается это командой:
, где C:\Program Files\OpenOffice.org 3\ — путь до офиса
d:\oo\OOAPI\Debug\ — путь, куда будет сгенерирован файл
После этого регистрируем ее командами:
Подключаем заголовочные файлы и либы:
Tools ->Options->Projects->VC++ Directories -> Include Files
Добавляем папку со сгенерированными заголовочными файлами: <oo_sdk_path>\ inludecpp
Tools ->Options->Projects->VC++ Directories -> Library files
добавляем <oo_sdk_path>\lib directory
Tools ->Options->Projects->VC++ Directories -> Executable files
добавляем <office_programm_dir>\program дирректория
Свойства проекта:
Сменяем конфигурацию на «All Configurations»
Добавляем дополнительные либы
Properties->Linker->ComandLine в Additional Options
добавляем либы:
isal.lib icppu.lib icppuhelper.lib isal.lib isalhelper.lib ireg.lib irmcxt.lib stlport_vc71.lib
Всё готово для создания консольных программ по работе с офисом.
Много полезных примеров можно увидеть тут: wiki.services.openoffice.org/wiki/Calc/API/Programming
План работы DLL примерно такой:
— При старте программы проверяем наличие RDB файла, если его нет, то происходит генерация.
Функции connect, genRdb
Если нет прав администратора на компьютере, то RDB лучше сгенерировать взаранее для типовой версии офиса.
— Стартуем сервер OpenOffice, устанавливаем ему порт для прослушки
startServer, адрес сервера офиса узнается из рееста функцией getOOPath
— Программа подключается к серверу офиса
— создается новый фрейм офиса: новый файл или имортируется xls файл.
— После этого можно посылать команды для управления содержанием
— экспортируем xls файл на диск
функция exportToUrl
— возможен и обратный механизм: имопрт xls файл и чтение из него данных
функциями getVal, getText
Прилагаю код DLL, надеюсь комментариев будет достаточно. Полный проект можно скачать по ссылке.
ooapi.h:
ooapi.cpp:
Финальная чать: использование DLL для загрузки и выгрузки в Excel.
Т.к. необходимо было, чтобы сервис работал под Linux, то механизм взаимодействия через OLE не подходил.
Для реализации был выбран OpenOffice с прямым доступом к API через C++.

Документация оказалась весьма скудная, а примеров работы не через OLE почти не было. Так что я решил объединить все мои исследования в одной статье на хабре.
Примерный план статьи:
1. Начало работы с API OpenOffice через C++
1.1. Генерация заголовочных файлов
1.2. Генерация файла типов RDB
1.3. Настройка Visual Studiо 2008
1.4. Собираем динамическую DLL
2. Повторное использование DLL в своей программе
2.1. Пример небольшой программы по выгрузке данных
В принципе, если возможностей DLL достаточно, то повторять действия п. 1 не обязательно.
1. Начало работы с API OpenOffice через C++
Этот раздел достаточно подробно описан в вики офиса: wiki.services.openoffice.org/wiki/SDKInstallation.
Для начала работы с API необходимо скачать SDK с адреса download.services.openoffice.org/files/stable. Важно чтобы версия SDK совпадала с версией установленного офиса.
Устанавливаем SDK в любую дирректорию.
Устанавливаем вспомогательные утилиты gnu make, zip (если необходимо)
1.1. Генерация заголовочных файлов
Внутри директории с SDK должен быть батник setsdkenv_windows.bat, генерирующий другой батник.
Выполняем его, отвечая на вопросы.
Будет сгенерирован батник с установками переменных окружения.
Открываем консоль, выполняем сгенерированный батник, и в этойже подготовленной консоли генерируем заголовочные файлы для конкретной версии офиса.
Команда генерации:
cppumaker -Gc -BUCR -O "c:\Program Files\OpenOffice_SDK\sdk\inludecpp" "c:\Program Files\OpenOffice.org 3\URE\misc\types.rdb" "c:\Program Files\OpenOffice.org 3\Basis\program\offapi.rdb"
, где
c:\Program Files\OpenOffice_SDK\sdk\inludecpp — папка куда будем генерировать
c:\Program Files\OpenOffice.org 3\ — путь до офиса
1.2. Генерация RDB файла типов.
Также для начала работы нужно сгенерировать RDB файл конкретно для вашей версии офиса.
RDB файл — это что-то типа файла с описаниями типов и интерфейсов конкретной версии OpenOffice.
Делается это командой:
"C:\Program Files\OpenOffice.org 3\URE\bin\regmerge" "d:\oo\OOAPI\Debug\OOAPI.rdb" / "c:\Program Files\OpenOffice.org 3\URE\misc\types.rdb"
, где C:\Program Files\OpenOffice.org 3\ — путь до офиса
d:\oo\OOAPI\Debug\ — путь, куда будет сгенерирован файл
После этого регистрируем ее командами:
"C:\Program Files\OpenOffice.org 3\URE\bin\regcomp" -register -r "d:\oo\OOAPI\Debug\OOAPI.rdb" -c connector.uno.dll
"C:\Program Files\OpenOffice.org 3\URE\bin\regcomp" -register -r "d:\oo\OOAPI\Debug\OOAPI.rdb" -c remotebridge.uno.dll
"C:\Program Files\OpenOffice.org 3\URE\bin\regcomp" -register -r "d:\oo\OOAPI\Debug\OOAPI.rdb" -c bridgefac.uno.dll
"C:\Program Files\OpenOffice.org 3\URE\bin\regcomp" -register -r "d:\oo\OOAPI\Debug\OOAPI.rdb" -c uuresolver.uno.dll
1.3. Настройка Visual Studiо 2008
Подключаем заголовочные файлы и либы:
Tools ->Options->Projects->VC++ Directories -> Include Files
Добавляем папку со сгенерированными заголовочными файлами: <oo_sdk_path>\ inludecpp
Tools ->Options->Projects->VC++ Directories -> Library files
добавляем <oo_sdk_path>\lib directory
Tools ->Options->Projects->VC++ Directories -> Executable files
добавляем <office_programm_dir>\program дирректория
Свойства проекта:
Сменяем конфигурацию на «All Configurations»
Добавляем дополнительные либы
Properties->Linker->ComandLine в Additional Options
добавляем либы:
isal.lib icppu.lib icppuhelper.lib isal.lib isalhelper.lib ireg.lib irmcxt.lib stlport_vc71.lib
Всё готово для создания консольных программ по работе с офисом.
1.4. Собираем динамическую DLL
Много полезных примеров можно увидеть тут: wiki.services.openoffice.org/wiki/Calc/API/Programming
План работы DLL примерно такой:
— При старте программы проверяем наличие RDB файла, если его нет, то происходит генерация.
Функции connect, genRdb
Если нет прав администратора на компьютере, то RDB лучше сгенерировать взаранее для типовой версии офиса.
— Стартуем сервер OpenOffice, устанавливаем ему порт для прослушки
startServer, адрес сервера офиса узнается из рееста функцией getOOPath
— Программа подключается к серверу офиса
— создается новый фрейм офиса: новый файл или имортируется xls файл.
— После этого можно посылать команды для управления содержанием
— экспортируем xls файл на диск
функция exportToUrl
— возможен и обратный механизм: имопрт xls файл и чтение из него данных
функциями getVal, getText
Прилагаю код DLL, надеюсь комментариев будет достаточно. Полный проект можно скачать по ссылке.
ooapi.h:
//так обозначаются экспортируемые элементы
#define OOAPI3 __declspec(dllexport)
#define WNT 1
#include <stdio.h>
#include <wchar.h>
#include <sal/main.h>
#include <cppuhelper/bootstrap.hxx>
#include <osl/file.hxx>
#include <osl/process.h>
//подключаем заголовки, которые будем использовать
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/bridge/XUnoUrlResolver.hpp>
#include <com/sun/star/frame/XComponentLoader.hpp>
#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/registry/XSimpleRegistry.hpp>
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include <com/sun/star/sheet/XSpreadsheet.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/table/XCellRange.hpp>
#include <com/sun/star/table/BorderLine.hpp>
#include <com/sun/star/table/CellHoriJustify.hpp>
#include <com/sun/star/table/XColumnRowRange.hpp>
#include <com/sun/star/table/XMergeableCell.hpp>
#include <com/sun/star/table/XMergeableCellRange.hpp>
#include <com/sun/star/table/TableBorder.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/util/XMergeable.hpp>
#include <string>
#include <locale>
#include <io.h>
#include <iostream>
#include <sstream>
using namespace rtl;
using namespace std;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::beans;
using namespace com::sun::star::bridge;
using namespace com::sun::star::frame;
using namespace com::sun::star::registry;
using namespace com::sun::star::sheet;
using namespace com::sun::star::table;
using namespace com::sun::star::container;
using namespace com::sun::star::util;
//экспортируемые функции
OOAPI3 bool connect(const char *file, bool hidden);
OOAPI3 void disconnect();
OOAPI3 bool selectSheet(short sheet);
OOAPI3 void setVal(int, int, double);
OOAPI3 void setText(int x, int y, const wchar_t *text);
OOAPI3 bool setBold(int x, int y);
OOAPI3 bool setFontColor(int x, int y, int r, int g, int b);
OOAPI3 bool setBgColor(int x, int y, int r, int g, int b);
OOAPI3 bool setFontSize(int x, int y, short size);
OOAPI3 bool setItalic(int x, int y);
OOAPI3 bool setHoriz(int x, int y, short hor);
OOAPI3 bool setBorders(int x, int y, bool lft, bool tp, bool rt, bool dn, short r, short g, short b);
OOAPI3 bool setColWidth(int col, long width);
OOAPI3 bool mergeRange(const char *range);
OOAPI3 bool exportToUrl(const wchar_t *url);
OOAPI3 double getVal(int x, int y);
OOAPI3 wchar_t* getText(int x, int y);
OOAPI3 bool isWin();
OOAPI3 bool isInstall();
ooapi.cpp:
#include "stdafx.h"
//функция детектирует wine, предполагалась, что реализации будут отличаться
bool isWin() {
//детектируем wine
#ifdef ISWIN
return ISWIN;
#endif
HMODULE h = LoadLibrary(L"ntdll.dll");
bool win = (h != NULL);
if(h != NULL) {
win = GetProcAddress(h, "wine_get_version") == NULL;
FreeLibrary(h);
}
#define ISWIN win
printf("module load on win: %u\n", win);
return win;
}
//функция возвращает путь до офиса, выдирая его из реестра
string getOOPath() {
//есть функции самого ОО, но ни одна у меня не заработала
#ifdef OOPATH
return OOPATH;
#endif
string path;
//читаем дирректорию установки из реестра
HKEY hKey = NULL;
wchar_t * buf = NULL;
ULONG dim = 0;
RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Classes\\opendocument.CalcDocument.1\\protocol\\StdFileEditing\\server"), 0, KEY_ALL_ACCESS, &hKey );
RegQueryValueEx(hKey, TEXT(""), NULL, NULL, NULL, &dim);
buf = new wchar_t[dim + 1];
RegQueryValueEx(hKey, TEXT(""), NULL, NULL, (UCHAR*)buf, &dim);
RegCloseKey(hKey);
//преобразуем unicode в string
wstring upath(buf);
ostringstream stm ;
const ctype<char>& ctfacet = use_facet< ctype<char> >( stm.getloc() ) ;
for( size_t i=0 ; i < upath.size() ; ++i ) stm << ctfacet.narrow( upath[i], 0 ) ;
path = stm.str();
delete buf;
if(path == "") return "";
//обрезаем лишнее, оставляем самую верхнюю папку
path = path.substr(0, path.length()-20);
printf("server path: %s\n", path.c_str());
#define OOPATH path
return path;
}
//запустить процесс
void createProcess(string app) {
STARTUPINFO StartupInfo;
ZeroMemory(&StartupInfo,sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow = SW_MAXIMIZE;
PROCESS_INFORMATION ProcessInfo;
//юникод
//это преобразование не верно работает под wine, изза этого сгенерировать RDB файл не получается
int len = lstrlenA(app.c_str());
BSTR utext = SysAllocStringLen(NULL, len);
::MultiByteToWideChar(CP_ACP, 0, app.c_str(), len, utext, len);
::SysFreeString(utext);
//сам запуск
if (CreateProcess(NULL, utext,NULL,NULL,false,CREATE_NO_WINDOW|NORMAL_PRIORITY_CLASS,
NULL,NULL,&StartupInfo,&ProcessInfo)) {
if (ProcessInfo.hProcess != NULL) {
//задержка, до окончательной загрузки процесса
while (WaitForSingleObject(ProcessInfo.hProcess,200) == WAIT_TIMEOUT) {
Sleep(100);
}
}
}
}
//функция генерации RDB файла типов
void genRDB() {
string rdb = "OOAPI.rdb";
if(access("OOAPI.rdb",0) != -1) {
//rdb файл существует
return;
}
printf("generate RDB\n"); //вроде не работает под wine
//генерируем RDB файл
string oopath = getOOPath();
string oogen = "\"" + oopath + "\\URE\\bin\\regmerge\" \"" + rdb + "\" / \"" + oopath + "\\URE\\misc\\types.rdb\" \"" + oopath + "\\Basis\\program\\offapi.rdb\"";
createProcess(oogen);
//зарегистрируем
string regpath;
regpath = "\"" + oopath + "\\URE\\bin\\regcomp\" -register -r \"" + rdb + "\" -c connector.uno.dll";
createProcess(regpath);
regpath = "\"" + oopath + "\\URE\\bin\\regcomp\" -register -r \"" + rdb + "\" -c remotebridge.uno.dll";
createProcess(regpath);
regpath = "\"" + oopath + "\\URE\\bin\\regcomp\" -register -r \"" + rdb + "\" -c bridgefac.uno.dll";
createProcess(regpath);
regpath = "\"" + oopath + "\\URE\\bin\\regcomp\" -register -r \"" + rdb + "\" -c uuresolver.uno.dll";
createProcess(regpath);
}
//установлен ли офис, если путь до офиса не пустой, то значит - да :)
bool isInstall() {
return getOOPath() != "";
}
//стартуем сервер, вешаем его на нужный порт
void startServer() {
string server_path;
server_path = "\"" + getOOPath() + "\\program\\soffice\" \"-accept=socket,host=localhost,port=2083;urp;StarOffice.ServiceManager\"";
//createProcess(server_path);
//не скрывается
WinExec(server_path.c_str(), SW_HIDE);
}
//######### общие переменные
//документ
Reference< XComponent > xComponent;
//лист документа
Any rSheet;
Reference< XMultiComponentFactory > xMultiComponentFactoryClient_copy;
//создание сервера ОО, подключение к нему и создание нового документа
bool connect(const char *file, bool hidden) {
//вызовем вручную функции макроса SAL_IMPLEMENT_MAIN_WITH_ARGS
//выдрано из sal_main()
sal_detail_initialize(NULL, NULL);
//строка подключения таже, что при запуске сервера
OUString sConnectionString(RTL_CONSTASCII_USTRINGPARAM("uno:socket,host=localhost,port=2083;urp;StarOffice.ServiceManager"));
//переделать параметром
OUString sFileString = OUString::createFromAscii(file);
//генерируем рдб файл по необходимости
genRDB();
//запускаем сервер опенофиса
startServer();
printf("init server start OK\n");
//инициализируем RDB файл
Reference< XSimpleRegistry > xSimpleRegistry(::cppu::createSimpleRegistry() );
xSimpleRegistry->open( OUString( RTL_CONSTASCII_USTRINGPARAM( "OOAPI.rdb") ), sal_True, sal_False );
printf("init rdb OK\n");
//какое-то особое шаманство,
//по всей видимости создание моста между пользовательскими запросами и единым интерфейсом UNO от open office
Reference< XComponentContext > xComponentContext(::cppu::bootstrap_InitialComponentContext( xSimpleRegistry ) );
Reference< XMultiComponentFactory > xMultiComponentFactoryClient( xComponentContext->getServiceManager() );
xMultiComponentFactoryClient_copy = xMultiComponentFactoryClient;
Reference< XInterface > xInterface = xMultiComponentFactoryClient->createInstanceWithContext(
OUString::createFromAscii( "com.sun.star.bridge.UnoUrlResolver" ), xComponentContext );
Reference< XUnoUrlResolver > resolver( xInterface, UNO_QUERY );
printf("init OK\n");
//ловим эксепшены, пока сервер опен офиса не стартует - вот такой вот костыль
int i = 200;
while(i > 0) {
try
{
Sleep(300);
xInterface = Reference< XInterface >( resolver->resolve( sConnectionString ), UNO_QUERY );
i = 0;
}
catch ( Exception& e )
{
i--;
if(i == 0) {
//больше нет смысла ждать
printf("can not connect to server FAIL\n");
return false;
}
}
}
printf("connect to server OK\n");
Reference< XPropertySet > xPropSet( xInterface, UNO_QUERY );
xPropSet->getPropertyValue( OUString::createFromAscii("DefaultContext") ) >>= xComponentContext;
Reference< XMultiComponentFactory > xMultiComponentFactoryServer( xComponentContext->getServiceManager() );
Reference < XComponentLoader > xComponentLoader(
xMultiComponentFactoryServer->createInstanceWithContext(
OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop" ) ),
xComponentContext ), UNO_QUERY );
printf("before create OK\n");
string fl = file;
if(fl.find(".xls") != string::npos) {
//имопортируем xls файл
Sequence<PropertyValue> props(2);
props[0].Name = OUString::createFromAscii( "FilterName" );
props[0].Value <<= OUString::createFromAscii( "MS Excel 97" );
//под wine скрывалось, вне зависимости от параметра
if(hidden) {
props[1].Name = OUString::createFromAscii( "Hidden" );
props[1].Value <<= hidden;
}
xComponent = xComponentLoader->loadComponentFromURL(sFileString,
OUString( RTL_CONSTASCII_USTRINGPARAM("_blank") ), 0, props);
} else {
//создаем новый файл или открываем файл самого опен офиса
Sequence<PropertyValue> props(1);
if(hidden) {
props[0].Name = OUString::createFromAscii( "Hidden" );
props[0].Value <<= hidden;
}
//создаем фрейм офиса
xComponent = xComponentLoader->loadComponentFromURL(sFileString,
OUString( RTL_CONSTASCII_USTRINGPARAM("_blank") ), 0, props);
}
printf("create oocalc OK\n");
return true;
}
//выбор листа книги
bool selectSheet(short sheet) {
//список листов
Reference< XSpreadsheetDocument > rSheetDoc (xComponent, UNO_QUERY);
Reference< XSpreadsheets > rSheets = rSheetDoc->getSheets();
//выбираем лист по индексу
Reference< XIndexAccess > rSheetsByIndex (rSheets, UNO_QUERY);
try {
rSheet = rSheetsByIndex->getByIndex( (short)sheet );
}
catch( Exception &e ) {
disconnect();
return false;
}
return true;
}
//установка числового значения
void setVal(int x, int y, double val) {
Reference< XSpreadsheet > rSpSheet (rSheet, UNO_QUERY);
//позиционируемся на ячейке
Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y);
//устанавливаем значение ячейки
rCell->setValue(val);
}
//установка текста или формулы
void setText(int x, int y, const wchar_t *text) {
Reference< XSpreadsheet > rSpSheet (rSheet, UNO_QUERY);
Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y);
rCell->setFormula(OUString::OUString(text));
}
//установка жирного для ячейки
bool setBold(int x, int y) {
Reference< XSpreadsheet > rSpSheet (rSheet, UNO_QUERY);
Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y);
try {
Reference< XPropertySet > rCellProps (rCell, UNO_QUERY);
Any mPropVal;
mPropVal <<= makeAny((short)150);
rCellProps->setPropertyValue(OUString::createFromAscii("CharWeight"), mPropVal);
return true;
}
catch( Exception &e ) {
return false;
}
}
//установка курсива
bool setItalic(int x, int y) {
Reference< XSpreadsheet > rSpSheet (rSheet, UNO_QUERY);
Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y);
try {
Reference< XPropertySet > rCellProps (rCell, UNO_QUERY);
Any mPropVal4;
mPropVal4 <<= makeAny((short)2);
rCellProps->setPropertyValue(OUString::createFromAscii("CharPosture"), mPropVal4);
return true;
}
catch( Exception &e ) {
return false;
}
}
//установка цвета текста
bool setFontColor(int x, int y, int r, int g, int b) {
Reference< XSpreadsheet > rSpSheet (rSheet, UNO_QUERY);
Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y);
try {
Reference< XPropertySet > rCellProps (rCell, UNO_QUERY);
Any mPropVal1;
mPropVal1 <<= makeAny(RGB(b,g,r));
rCellProps->setPropertyValue(OUString::createFromAscii("CharColor"), mPropVal1);
return true;
}
catch( Exception &e ) {
return false;
}
}
//установка цвета фона
bool setBgColor(int x, int y, int r, int g, int b) {
Reference< XSpreadsheet > rSpSheet (rSheet, UNO_QUERY);
Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y);
try {
Reference< XPropertySet > rCellProps (rCell, UNO_QUERY);
Any mPropVal1;
mPropVal1 <<= makeAny(RGB(b,g,r));
rCellProps->setPropertyValue(OUString::createFromAscii("CellBackColor"), mPropVal1);
return true;
}
catch( Exception &e ) {
return false;
}
}
//установка размера шрифта
bool setFontSize(int x, int y, short size) {
Reference< XSpreadsheet > rSpSheet (rSheet, UNO_QUERY);
Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y);
try {
Reference< XPropertySet > rCellProps (rCell, UNO_QUERY);
Any mPropVal3;
mPropVal3 <<= makeAny((short)size);
rCellProps->setPropertyValue(OUString::createFromAscii("CharHeight"), mPropVal3);
return true;
}
catch( Exception &e ) {
return false;
}
}
//установка горизонтального положения шрифта
bool setHoriz(int x, int y, short hor) {
Reference< XSpreadsheet > rSpSheet (rSheet, UNO_QUERY);
Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y);
try {
Reference< XPropertySet > rCellProps (rCell, UNO_QUERY);
Any mPropVal5;
mPropVal5 <<= makeAny((short)hor);
rCellProps->setPropertyValue(OUString::createFromAscii("HoriJustify"), mPropVal5);
return true;
}
catch( Exception &e ) {
return false;
}
}
//установка бордеров для ячейки
bool setBorders(int x, int y, bool lft, bool tp, bool rt, bool dn, short r, short g, short b) {
try {
Reference< XSpreadsheet > rSpSheet (rSheet, UNO_QUERY);
Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y);
Reference< XPropertySet > rCellProps (rCell, UNO_QUERY);
BorderLine bl;
bl.Color = RGB(b,g,r); //rgb перепутан в сдк?
bl.OuterLineWidth = 10;
TableBorder b;
if(lft) b.LeftLine = bl;
if(tp) b.TopLine = bl;
if(rt) b.RightLine = bl;
if(dn) b.BottomLine = bl;
b.VerticalLine = b.HorizontalLine = bl;
b.IsVerticalLineValid = true;
b.IsHorizontalLineValid = true;
b.IsLeftLineValid = lft;
b.IsRightLineValid = rt;
b.IsTopLineValid = tp;
b.IsBottomLineValid = dn;
rCellProps->setPropertyValue(OUString::createFromAscii("TableBorder"),makeAny(b));
return true;
}
catch( Exception &e ) {
return false;
}
}
//установка ширины столбца в мм
bool setColWidth(int col, long width) {
try {
Reference< XColumnRowRange > rSheetColRange (rSheet, UNO_QUERY);
Reference< XTableColumns > rSheetColumns = rSheetColRange->getColumns();
Any rCol = rSheetColumns->getByIndex(col);
Reference< XPropertySet > rColProps (rCol, UNO_QUERY);
rColProps->setPropertyValue(OUString::createFromAscii("Width"),makeAny(width*100));
return true;
}
catch( Exception &e ) {
return false;
}
}
//объединение ячеек
bool mergeRange(const char *range) {
try {
Reference< XCellRange > rSheetCellRange (rSheet, UNO_QUERY);
Reference< XCellRange> rCellRange = rSheetCellRange->getCellRangeByName(OUString::createFromAscii(range));
Reference< XMergeable > rSheetCellMerge (rCellRange, UNO_QUERY);
rSheetCellMerge->merge(true);
return true;
}
catch( Exception &e ) {
return false;
}
}
//экспорт xls файла по адресу
bool exportToUrl(const wchar_t *url) {
try {
Reference<XStorable> xStore (xComponent, UNO_QUERY);
Sequence<PropertyValue> storeProps(1);
storeProps[0].Name = OUString::createFromAscii( "FilterName" );
storeProps[0].Value <<= OUString::createFromAscii( "MS Excel 97" );
xStore->storeToURL( OUString::OUString(url), storeProps );
return true;
}
catch( Exception &e ) {
return false;
}
}
//получить числовое значение ячейки
double getVal(int x, int y) {
Reference< XSpreadsheet > rSpSheet (rSheet, UNO_QUERY);
Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y);
return rCell->getValue();
}
//получить формулу из ячейки (юникод)
wchar_t* getText(int x, int y) {
Reference< XSpreadsheet > rSpSheet (rSheet, UNO_QUERY);
Reference< XCell > rCell = rSpSheet->getCellByPosition(x, y);
OUString buf = rCell->getFormula();
return buf.pData->buffer;
}
//отключение
void disconnect() {
Reference< XComponent >::query( xMultiComponentFactoryClient_copy )->dispose();
sal_detail_deinitialize();
}
Финальная чать: использование DLL для загрузки и выгрузки в Excel.