Object to binary[] from COM in .NET using C#

A

A. Gharbeia

Greetings:
It turned out that using COM objects from .NET C# isn't straight forward at
all.
Now, I have successfully used reflection to instantiate the object, and
invoked the methods and properties through Type.InvokeMember, but...

One property whose value I retrieve through :

TImagingObject.InvokeMember("JPGData", BindingFlags.GetProperty, null,
certificateImage, null);

returns an Object.

Now how can I obtain a byte[] out of this returned Object to pass it to
Response.Write?!
I can't cast into an array, of course, and I can't find the right methods to
access the binary data and instantiate an array with it.

Sincerely,
A. Gharbeia
 
M

Mattias Sjögren

Now how can I obtain a byte[] out of this returned Object to pass it to
Response.Write?!
I can't cast into an array, of course,

Why not? What's the actual type of the returned object
(obj.GetType().ToString())?



Mattias
 
A

A. Gharbeia

Thank you for your response, Mattias.

Using .GetType().ToString() directly on the reference returned by System.Type.InvokeMember() (i.e. without first assigning it to an object), returns System.Byte[*].

However, passing this reference also directly to "Response.BinaryWrite()" (i.e. by placing the whole InvokeMember call within the parentheses), yields:

Compiler Error Message: CS1502: The best overloaded method match for 'System.Web.HttpResponse.BinaryWrite(byte[])' has some invalid arguments

I also tried assigning the reference to an Object object and using System.Convert.ChangeType(object, invocation.GetType()) to convert object to the type returned by the invocation and do InvokeMember() once more, this time assigning the returned reference to object. And I got the same error!!


Mattias Sjögren said:
Now how can I obtain a byte[] out of this returned Object to pass it to
Response.Write?!
I can't cast into an array, of course,

Why not? What's the actual type of the returned object
(obj.GetType().ToString())?



Mattias
 
A

A. Gharbeia

One more thing:
Doing the whole thing in JScript.NET is much easier and straighforward,
since calling the COM methods doesn't neccessate using Type.InvokeMember.
However, attempting to output the result to the HTTP stream using
Response.BinaryWrite yields a similar error:

System.InvalidCastException: Specified cast is not valid.

A. Gharbeia

Thank you for your response, Mattias.

Using .GetType().ToString() directly on the reference returned by
System.Type.InvokeMember() (i.e. without first assigning it to an object),
returns System.Byte[*].

However, passing this reference also directly to "Response.BinaryWrite()"
(i.e. by placing the whole InvokeMember call within the parentheses),
yields:

Compiler Error Message: CS1502: The best overloaded method match for
'System.Web.HttpResponse.BinaryWrite(byte[])' has some invalid arguments

I also tried assigning the reference to an Object object and using
System.Convert.ChangeType(object, invocation.GetType()) to convert object to
the type returned by the invocation and do InvokeMember() once more, this
time assigning the returned reference to object. And I got the same error!!


Mattias Sjögren said:
Now how can I obtain a byte[] out of this returned Object to pass it to
Response.Write?!
I can't cast into an array, of course,

Why not? What's the actual type of the returned object
(obj.GetType().ToString())?



Mattias
 
M

Mattias Sjögren

Using .GetType().ToString() directly on the reference returned by System.Type.InvokeMember() (i.e. without first assigning it to an object), returns System.Byte[*].

In that case you should be able to cast it to System.Array and access
the array items with Array.GetValue().



Mattias
 
A

A. Gharbeia

Yes.
But this will mean I will have to access the Array elements one by one!
Then what?

System.Type.InvokeMember() (i.e. without first assigning it to an object),
returns System.Byte[*].
 
M

Mattias Sjögren

Yes.
But this will mean I will have to access the Array elements one by one!
Then what?

Not necessarily, you should be able to copy the contents over to a
regular byte[] using Buffer.BlockCopy().



Mattias
 
A

A. Gharbeia

I tried:

Object o = ImagingComponent.InvokeMember("JPGData",
BindingFlags.GetProperty, null, certificateImage, null);
Array b = Array.CreateInstance(typeof(byte), ((Array)o).LongLength);
b.CopyTo(b, 0);
Response.BinaryWrite(b);

and got the same compiler error:

CS1502: The best overloaded method match for
'System.Web.HttpResponse.BinaryWrite(byte[])' has some invalid arguments


System.Type.InvokeMember() (i.e. without first assigning it to an object),
returns System.Byte[*].
 
A

A. Gharbeia

Although I don't know how to create a byte[] with a dynamic size (that will
only be known at runtime), I tried:

Object r = ImaginCOM.InvokeMember("JPGData", BindingFlags.GetProperty,
null, certificateImage, null);
byte[] b;
Buffer.BlockCopy( ((Array)r), 0, b, 0, ((Array)r).Length );

and got:

CS0154: The property or indexer 'System.Web.UI.Page.Buffer' cannot be used
in this context because it lacks the get accessor

I'm trying this and other tricks with JScript.NET in addition to C#. I with
I could find a solution in JScript.NET, as the code there is much cleaner. I
tried to play on the JScript Array/.NET System.Array duality but reached no
where either.

Mattias Sjögren said:
Yes.
But this will mean I will have to access the Array elements one by one!
Then what?

Not necessarily, you should be able to copy the contents over to a
regular byte[] using Buffer.BlockCopy().



Mattias
 
A

A. Gharbeia

Although I don't know how to create a byte[] with a dynamic size (that will
only be known at runtime), I tried:

Object r = ImaginCOM.InvokeMember("JPGData", BindingFlags.GetProperty,
null, certificateImage, null);
byte[] b;
Buffer.BlockCopy( ((Array)r), 0, b, 0, ((Array)r).Length );

and got:

CS0154: The property or indexer 'System.Web.UI.Page.Buffer' cannot be used
in this context because it lacks the get accessor

I'm trying this and other tricks with JScript.NET in addition to C#. I with
I could find a solution in JScript.NET, as the code there is much cleaner. I
tried to play on the JScript Array/.NET System.Array duality but reached no
where either.

What do you think?

A. Gharbeia

Mattias Sjögren said:
Yes.
But this will mean I will have to access the Array elements one by one!
Then what?

Not necessarily, you should be able to copy the contents over to a
regular byte[] using Buffer.BlockCopy().



Mattias
 
M

Mattias Sjögren

CS0154: The property or indexer 'System.Web.UI.Page.Buffer' cannot be used
in this context because it lacks the get accessor

The code looks correct, you just got the wrong Buffer class. Make it

System.Buffer.BlockCopy( ...



Mattias
 
A

A. Gharbeia

that same code from the past post with System.Buffer results in:

CS0165: Use of unassigned local variable 'b'

From what I understand, arrays in C# aren't dynamic and have to be
dimensioned and initialised before use.
 
M

Mattias Sjögren

that same code from the past post with System.Buffer results in:

CS0165: Use of unassigned local variable 'b'

Well you have to instantiate the byte array first.

byte[] b = new byte[((Array)r).Length];



Mattias
 
A

A. Gharbeia

Thank you very much Mattias.
That did it.
I thought I tried that before, but it seems I did something wrong.

I hope you don't mind me asking another question: Is the reflection part
required in ASP.NET C#, or is there a way to add a reference to the COM
object so I can do away with the extra code.


Ahmad Gharbeia
 
G

Guest

Question for A. Gharbeia: do you always know what sort of object you are getting back from your InvokeMember call
For instance, why not cast your original example to an Image instance

Image tImage = (Image) TImagingObject.InvokeMember("JPGData", BindingFlags.GetProperty, null, certificateImage, null)

2 of the overloaded Image.Save() methods allow you to perist the image as a Stream

Stream tImageByteStream = new Stream()
tImage.Save(tImageByteStream, ImagingFormat.Jpeg)

and so on and so forth..
 
A

Ahmad Gharbeia

Carter:
No, I catch the return of the JPEGData property in an Object type variable.

but now I tried:

System.Drawing.Image i = (System.Drawing.Image)
TImagingComponent.InvokeMember("JPGData", BindingFlags.GetProperty, null,
certificateImage, null);
Response.ContentType = "image/jpeg";
i.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);

and got:

System.InvalidCastException: Specified cast is not valid.


I would have used the native .NET imaging classes, except that I need to
embed XMP metadata in the output. I will enhirt System.Drawing.Bitmap class
to include this functionality, but untill then, I'm stuck with the COM
component that I have.
The code would have been much prettier I didn't have to use reflection in
C#, though. I have to find out how to add a reference to the COMponent's
type library or something.

Thank you.
Ahmad
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top