28 марта 2011 в 19:55

Автоматизация OpenOffice: Начало

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

Open Office api на Linux

Документация оказалась весьма скудная, а примеров работы не через 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.
Алексей Скахин @pihel
карма
30,3
рейтинг 0,0
Похожие публикации
Самое читаемое Разработка

Комментарии (21)

  • +4
    Я просто оставлю это здесь jXLS
    • 0
      А я просто это: www.python-excel.org/
      (думаю, для подобных задач использовать python намного удобнее, чем Java, не говоря уж о C++)
      • 0
        в данном случае условия дикотовали внешние условия
        основная программа на с++
        • +1
          Ну, python можно интегрировать с C++ различными способами и, возможно, это оказалось бы даже проще, чем ваше решение. Впрочем, я не знаю точно, что у вас за задача и с какими ограничениями.
      • 0
        Я думаю что python такое не умеет :)
        jxls.sourceforge.net/samples/tagsample.html

        Опять же с точки зрения переносимости между платформами java лучше.
      • 0
        фух, я боялся, что этого никто не скажет :-)
  • –1
    вы всерьез думаете что кто-то будет читать весь этот код?
    • +2
      тем кому это надо
      хотя наверно можно было оставить одни заголовочные файлы…
      • –1
        Те, кому надо могут и скачать исходники. В самой статье можно просто оставить интересные/тонкие места.
        • +2
          спасибо, буду делать в следующих статьях
          эту уж править не буду.
  • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    Спасибо за статью, мне буквально в тему, т.к. саму предстоит задача экспорта и импорта данных.
  • 0
    мда… а на сколько все легче с другим офисным пакетом, другой операционкой и моим любимым скриптовым языком Tcl/Tk.
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Это детектирование WINE, и эта функция рудимент не используется
    • 0
      а вы про getOOPath(), то там действительно не очень кроссплатформено :) Другие способы у меня не заработали. Представленный будет работать в Linux только под Wine
      • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    По-моему как раз для такого OOo умеет макросы.
  • 0
    Сколько весит получившаяся библиотека? И возможно ли сделать статическую либу?
    • 0
      Библиотека весит всего 39кб.
      Много места занимают другие вещи:
      — OOAPI.rdb: 7,3мб (ну это впринципе можно сгенерировать прямо на машине)
      — куча либ самого офиса. Хотя все эти библиотеки уже должны быть, после установки опен офиса и их достаточно будет скопировать в корень программы.
      Все необходимые либы и пример программы для OO 3.2 есть в продолжении статьи: narod.ru/disk/8667452001/oo.zip.html

      Скомпилировать статическую либу никто не мешает, решается все изменениями свойств проекта.
  • +1
    Эх… :(
    механизм загрузки и выгрузки данных из Excel используя свободные механизмы работающие под разными ОС
    Apache POI

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.