#include<Windows.h>
#include <stdio.h>
#include <sal/main.h>
#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/bridge/XUnoUrlResolver.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/XComponentLoader.hpp>
#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <osl/file.hxx>
#include <com/sun/star/util/XCloseable.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/view/XPrintable.hpp>
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/awt/Size.hpp>
#include<string>
#include<iostream>
#include <chrono>
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::frame;
using namespace com::sun::star::beans;
using namespace com::sun::star::view;
using namespace com::sun::star::style;
using namespace com::sun::star::container;
using namespace com::sun::star::awt;
using ::rtl::OUString;
using ::rtl::OUStringToOString;
using namespace com::sun::star::util;
OUString getPdfExportFilterName(Reference<XComponent>& xComponent)
{
Reference<XServiceInfo> xServiceInfo(xComponent, UNO_QUERY);
if (!xServiceInfo.is())
{
std::cerr << "Failed to get XServiceInfo." << std::endl;
return "";
}
if (xServiceInfo->supportsService("com.sun.star.text.TextDocument"))
return OUString::createFromAscii("writer_pdf_Export");
else if (xServiceInfo->supportsService("com.sun.star.sheet.SpreadsheetDocument"))
return OUString::createFromAscii("calc_pdf_Export");
else if (xServiceInfo->supportsService("com.sun.star.presentation.PresentationDocument"))
return OUString::createFromAscii("impress_pdf_Export");
else if (xServiceInfo->supportsService("com.sun.star.drawing.DrawingDocument"))
return OUString::createFromAscii("draw_pdf_Export");
else if (xServiceInfo->supportsService("com.sun.star.formula.FormulaProperties"))
return OUString::createFromAscii("math_pdf_Export");
else
throw std::runtime_error("Unsupported document type");
}
bool setPageLayout(Reference<XComponent> xComponent, Size pageSize, bool isLandscape)
{
if (!xComponent.is()) return false;
// Try Writer-style modification
try {
Reference<XStyleFamiliesSupplier> xSupplier(xComponent, UNO_QUERY);
if (xSupplier.is()) {
Reference<XNameAccess> xFamilies = xSupplier->getStyleFamilies();
if (xFamilies->hasByName("PageStyles")) {
Any aPageStyles = xFamilies->getByName("PageStyles");
Reference<XNameAccess> xPageStyles;
aPageStyles >>= xPageStyles;
if (xPageStyles->hasByName("Standard")) {
Any aStyle = xPageStyles->getByName("Standard");
Reference<XPropertySet> xStyleProps;
aStyle >>= xStyleProps;
xStyleProps->setPropertyValue("IsLandscape", Any(isLandscape));
xStyleProps->setPropertyValue("Size", Any(pageSize));
return true;
}
else {
std::cerr << "\"Standard\" page style not found." << std::endl;
}
}
}
}
catch (...) {
std::cerr << "Writer-style layout adjustment failed. Trying XPrintable..." << std::endl;
}
// Try XPrintable (Calc, generic fallback)
try {
Reference<XPrintable> xPrintable(xComponent, UNO_QUERY);
if (xPrintable.is()) {
PropertyValue printProps[2];
printProps[0].Name = OUString::createFromAscii("IsLandscape");
printProps[0].Value <<= isLandscape;
printProps[1].Name = OUString::createFromAscii("PaperSize");
printProps[1].Value <<= pageSize;
Sequence<PropertyValue> propsSeq(printProps, 2);
xPrintable->setPrinter(propsSeq);
return true;
}
}
catch (...)
{
std::cerr << "XPrintable layout adjustment failed." << std::endl;
}
std::cerr << "Document type not supported or layout change failed." << std::endl;
return false;
}
SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
{
if (argc < 3) {
fprintf(stderr, "Usage: < input_file_path > <output_file_path>\n");
return 1;
}
auto doc_convert_start = std::chrono::high_resolution_clock::now();
//Convert system paths (argv[1] and argv[2]) to OUString
OUString sInputPath = OUString::createFromAscii(argv[1]);
OUString sOutputPath = OUString::createFromAscii(argv[2]);
// Convert to file:// URL format recognized by LibreOffice
OUString sInputFileURL, sOutputFileURL;
if (osl::FileBase::getFileURLFromSystemPath(sInputPath, sInputFileURL) != osl::FileBase::E_None ||
osl::FileBase::getFileURLFromSystemPath(sOutputPath, sOutputFileURL) != osl::FileBase::E_None) {
std::cerr << "Error: Could not convert file paths to file URLs.\n";
return 1;
}
try
{
//std::string uid = std::to_string(GetCurrentProcessId());
//std::string profile = "file:///C:/Temp/lo-profile-" + uid;
//std::string envVar = "UserInstallation=" + profile;
//_putenv(envVar.c_str());
std::cout << "Bootstrap started" << std::endl;
auto startTime = std::chrono::high_resolution_clock::now();
// get the remote office component context
Reference< XComponentContext > xContext(::cppu::bootstrap());
if (!xContext.is())
{
fprintf(stderr, "no component context!\n");
return 1;
}
std::cout << "Bootstrap Completed" << std::endl;
auto endTime = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
std::cout << "Time taken for Bootstraping: " << duration << " milliseconds" << std::endl;
// get the remote office service manager
Reference< XMultiComponentFactory > xServiceManager(
xContext->getServiceManager());
if (!xServiceManager.is())
{
fprintf(stderr, "no service manager!\n");
return 1;
}
// get an instance of the remote office desktop UNO service
// and query the XComponentLoader interface
Reference < XDesktop2 > xComponentLoader = Desktop::create(xContext);
Sequence<PropertyValue> loadProperties(2);
// Property 1: Open in hidden mode
loadProperties[0].Name = OUString::createFromAscii("Hidden");
loadProperties[0].Value <<= true;
// Property 2: Open in read-only mode
loadProperties[1].Name = OUString::createFromAscii("ReadOnly");
loadProperties[1].Value <<= true;
std::cout << "Document Load Started" << std::endl;
// open a spreadsheet document
Reference< XComponent > xComponent(xComponentLoader->loadComponentFromURL(
sInputFileURL,
OUString("_blank"), 0,
loadProperties));
if (!xComponent.is())
{
fprintf(stderr, "opening document failed!\n");
return 1;
}
std::cout << "Document Loaded successfully" << std::endl;
OUString filterName = getPdfExportFilterName(xComponent);
std::wcout << L"filterName " << filterName.getStr() << std::endl;;
Size tabloidSize;
tabloidSize.Width = 43180; // 17 in
tabloidSize.Height = 27940; // 11 in
setPageLayout(xComponent, tabloidSize, true);
// Export as PDF
Sequence<PropertyValue> storeProps(1);
storeProps[0].Name = OUString::createFromAscii("FilterName");
storeProps[0].Value <<= filterName; //OUString::createFromAscii("writer_pdf_Export");
std::cout << "Document storing to pdf Started" << std::endl;
Reference<XStorable> xStorable(xComponent, UNO_QUERY);
xStorable->storeToURL(sOutputFileURL, storeProps);
std::cout << "Document storing to pdf completed successfully" << std::endl;
Reference<XCloseable> xCloseable(xComponent, UNO_QUERY);
if (xCloseable.is()) xCloseable->close(true);
if(xComponentLoader.is())
xComponentLoader->terminate();
// Clear references
xCloseable.clear();
xStorable.clear();
xComponent.clear();
xComponentLoader.clear();
xServiceManager.clear();
xContext.clear();
auto doc_convert_end = std::chrono::high_resolution_clock::now();
auto doc_convert_duration = std::chrono::duration_cast<std::chrono::seconds>(doc_convert_end - doc_convert_start);
int doc_convert_total_seconds = doc_convert_duration.count();
int doc_convert_minutes = doc_convert_total_seconds / 60;
int doc_convert_seconds = doc_convert_total_seconds % 60;
std::cout << "doc_convert_duration: " << doc_convert_minutes << " minute(s) and "
<< doc_convert_seconds << " second(s)" << std::endl;
return 0;
}
catch (::cppu::BootstrapException& e)
{
fprintf(stderr, "caught BootstrapException: %s\n",
OUStringToOString(e.getMessage(), RTL_TEXTENCODING_ASCII_US).getStr());
return 1;
}
catch (Exception& e)
{
fprintf(stderr, "caught UNO exception: %s\n",
OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US).getStr());
return 1;
}
}
I would like to **terminate the soffice.bin and soffice.exe** if **loadComponentFromURL** or **storeToURL** are taking more time than expected. I just moved all the code to a different thread and waiting on thread for a defined timeout then trying to call the
if(xComponentLoader.is())
xComponentLoader->terminate(); but this is not able to terminate the soffice.bin or soffice.exe
Is there a way to do this ? Please let me know.
Use system means to kill processes.
@mikekaganski I am running multiple instances of the above program at the same time, so it triggers multiple soffice’s and working fine without any issue. I don’t know which soffice to kill in this case as I don’t know the process id.
You are welcome to file an enhancement request to provide means to get the process id from the component context.
This may be a workaround:
https://stackoverflow.com/questions/62365978/get-a-list-of-child-processes-from-parent-process-in-c-and-c-cross-platform