How to create a SequenceInputStream from Delphi code?

Hi,

I have integrated LibreOffice into our Delphi application and would like to load documents directly from memory. For that I need to create a SequenceInputStream and then populate it with the raw file data.

I can create the SequenceInputStream without issue, but for the life of me I cannot figure out how to populate it from e.g. an array of bytes. Here is a small test case:

program SequenceInputStream;

{$APPTYPE CONSOLE}

uses
  System.SysUtils, System.Win.ComObj, Winapi.ActiveX;

var
  ServiceManager: Variant;

function CreateSequenceInputStreamFromByteArray(const AByteArray: TBytes): Variant;
var
  LVariantByteArray: Variant;
begin
  LVariantByteArray := AByteArray;

  Result := ServiceManager.createInstance('com.sun.star.io.SequenceInputStream');

  //EOleError with message 'Method 'createStreamFromSequence' not supported by automation object'.
  Result.createStreamFromSequence(LVariantByteArray);

  //EOleException with message 'com.sun.star.lang.IllegalArgumentException: Wrong number of arguments!'.
  Result.initialize(LVariantByteArray);
end;

var
  LByteArray: TBytes;
  LMyStream: Variant;
begin
  CoInitialize(nil);

  ServiceManager := CreateOleObject('com.sun.star.ServiceManager');

  try
    SetLength(LByteArray, 10000);

    LMyStream := CreateSequenceInputStreamFromByteArray(LByteArray);

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

According to the documentation there should be a “createStreamFromSequence” method, but that doesn’t seem accessible. If It try to call it it returns the error ‘Method ‘createStreamFromSequence’ not supported by automation object’.

“intialize” is available, but it doesn’t accept the array of bytes in any format that I have tried. The error message is ‘com.sun.star.lang.IllegalArgumentException: Wrong number of arguments!’.

Does anyone know how to populate a SequenceInputStream via Delphi code?

Thanks!

I don’t know how exactly service constructors are exposed in Delphi, so you have to find out yourself. That would be the easiest, because it directly takes a sequence of bytes.

If you want to use initialize, it is implemented here, and you can see that you need to pass an array of anys (with exactly one any, holding the array).

Or, if you have access to something like Basic’s CreateUnoServiceWithArguments, use that, with the same structure of the argument.

1 Like

The following VBA macro fails with an error:

Sub TestCreateSequenceInputStreamFromByteArray()
  Dim aData(20) As Byte, v
  Dim oSM As Object, oSIS As Object
  Set oSM = CreateObject("com.sun.star.ServiceManager")
  Set oSIS = oSM.createInstanceWithArguments("com.sun.star.io.SequenceInputStream", Array(aData))
  Set oSM = Nothing
End Sub

Screen 2025-08-03 172145

@sokol92 maybe you get not an array of anys from Array(aData)?

I did it in analogy with this topic.

Microsoft Visual Basic? I have no idea how the bridge will work from there. I very much suspect that no, that doesn’t coerce to array(any).

This is an optical illusion - a message from VBA. :slight_smile:
Some time ago the guys from MS forgot to fix it.

Guys, thank you for your help.

Delphi uses OLE Automation to interface with LibreOffice, just like Visual Basic. If there’s a working Visual Basic example somewhere I am confident I can translate that to Delphi.

I have now also tried the following:

function CreateSequenceInputStreamFromByteArray(const AByteArray: TBytes): Variant;
var
  LVariantByteArray: Variant;
begin
  LVariantByteArray := AByteArray;
  Result := ServiceManager.createInstanceWithArguments('com.sun.star.io.SequenceInputStream', LVariantByteArray); //EOleException with message 'com.sun.star.lang.IllegalArgumentException: Wrong number of arguments!'
end;

This yields an error “EOleException with message ‘com.sun.star.lang.IllegalArgumentException: Wrong number of arguments!’.”

This made me think that perhaps I should not pass the array of bytes directly, but instead make the array of bytes an element in an outer array of length 1, like this:

function CreateSequenceInputStreamFromByteArray(const AByteArray: TBytes): Variant;
var
  LVariantByteArray, LVariantByteArrayArray: Variant;
  LVariantArray: TArray<Variant>;
begin
  LVariantByteArray := AByteArray;
  SetLength(LVariantArray, 1);
  LVariantArray[0] := LVariantByteArray;
  LVariantByteArrayArray := LVariantArray;

  Result := ServiceManager.createInstanceWithArguments('com.sun.star.io.SequenceInputStream', LVariantByteArrayArray); //com.sun.star.lang.IllegalArgumentException: Unexpected type of argument!
end;

With this I see a similar error to the one you’re seeing with the VB code: “EOleException with message ‘com.sun.star.lang.IllegalArgumentException: Unexpected type of argument!’”

Calling “initialize” with the array inside an array, which I am guessing is equivalent to the above, also gives the same error:

  Result := ServiceManager.createInstance('com.sun.star.io.SequenceInputStream');
  Result.initialize(LVariantByteArrayArray); //com.sun.star.lang.IllegalArgumentException: Unexpected type of argument!

I notice in the documentation you linked to above that SequenceInputStream is referred to as a “New-style service”. Since OLE Automation is quite old and I guess not very popular nowadays, is it possible that the OLE Automation code on the LibreOffice side hasn’t been updated to support this functionality?

I do it this way in Python, I don’t know how to migrate this to Delphi.

    def input(buffer):
        service = 'com.sun.star.io.SequenceInputStream'
        stream = create_instance(service, True)
        stream.initialize((uno.ByteSequence(buffer.getvalue()),))
        return stream

@elmau
I can guess how create_instance is defined, but dont have an idea about the buffer-object??

Look:

Blame on me!

From my understanding there are several language bridges. There is one for C++, one for Python and there is also an OLE Automation bridge that is used by Visual Basic and Delphi. Sometimes the way you interact with these bridges differ in subtle ways, as is apparently the case here: Try as I might I have not been able to find the equivalent OLE Automation syntax for your Python code.