Link to home
Start Free TrialLog in
Avatar of mikexxx
mikexxx

asked on

Receiving an array in a COM object

I am using the ATL wizard to create a COM object. I want to pass a BYTE array to the COM object.

In the ATL Wizard I say that the Parameters are:
[in] long cItems, [in, size_is(cItems)] BYTE aItems[]

I have also tried:
[in] BYTE aItems[1000]

In both cases I get a compilation error:
warning MIDL2039 : interface does not conform to [oleautomation] attribute : [ Parameter 'aItems' of Procedure 'MyMethod' ( Interface 'IMyClass' ) ]

Can someone please give me some clues.
PS. I am a bit new to this stuff.
Avatar of jkr
jkr
Flag of Germany image

MIDL2039 : interface does not conform to [oleautomation] attribute
The interface does not meet the requirements for and Automation interface. Check to make sure the interface is derived from IUnknown or IDispatch.

Do you derive from one of these?
Yuo can do 2 things

1. Chabge the BYTE[] to long and cast this long to BYTE pointer in your ATL control.

2. This may be the Direct way to do. Use OLESAFEARRAY to pass ARRAYs to ATL objects

Good Luck
Avatar of mikexxx
mikexxx

ASKER

Thanks for your suggestions.
I am wanting to pass binary data in a BYTE array from a VB application to a control written in C++. If I change the interface to long, the VB will not pass a byte array to it.

Your second option would work but is hard work. I cannot see from the documentation why my other methods would not work.
To repeat my question - are you deriving your IF from IUnkown or IDispatch?
i suppose for MIDL this has to be byte and not "BYTE", your BYTE is typedefed as unsigned char.

If you look closely it is just a warning and not an error, this seems to be quite un-explainable though as byte is a valid MIDL type and yet MIDL gives a warning, also try it with singned char and still it gives a warning.

Moreover the description of the error is mis-leading as it suggests that the interface may not be properly derived from IUnknown or IDispatch. Whereas the problem can only be that the interface takes types which may not be automation compatible.

But byte should be an automation compatible type, maybe you should ignore the warning and see if you really get any problems.
Avatar of mikexxx

ASKER

Sorry jkr, I didn't see your question. I was in rather a hurry earlier. I am deriving from IDispatch.

After a lot of experimentation and reading, I have got the following working:
[in] long cItems, [in, size_is(cItems)] BYTE *aItems

I am still interested why the other does not work though.

I have been looking in the following documents:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnmsj99/html/wicked0599.asp

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/midl/mi-laref_3zxv.asp

http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0898/idl/idl.htm&nav=/msj/0898/newnav.htm

>> why the other does not work though.

Have you actually checked and found that the other methods dont work ?
Avatar of mikexxx

ASKER

What I meant was:

This works
[in] long cItems, [in, size_is(cItems)] BYTE *aItems

But this
[in] long cItems, [in, size_is(cItems)] BYTE aItems[]

and this
[in] BYTE aItems[1000]

do not work. They give a warning message at compilation as described above.

I have just tested all these 3 again.
>> This works
[in] long cItems, [in, size_is(cItems)] BYTE *aItems
But this
[in] long cItems, [in, size_is(cItems)] BYTE aItems[]
and this
[in] BYTE aItems[1000]
do not work. They give a warning message at compilation as described above.

Sorry, maybe i did not make myself clear, i mean to ask that suppose you ignore the warning (the code compiles, right), so you test the compiled code from VB and see if it realy works or throws and error, or doesnot return anything at all ?

something like makking sure if the warning can be ignored or not.
Avatar of mikexxx

ASKER

When I use
[in] BYTE aItems[1000]
VB gives a compile error "Function or interface marked as restricted, or the function uses an Automation type not supported in Visual Basic".

When I use
[in] long cItems, [in, size_is(cItems)] BYTE aItems[]
VB gives a compile error "Type mismatch".


When I use
[in] long cItems, [in, size_is(cItems)] BYTE *aItems
In VB I have to pass an argument of aItems[0]. This seems to work though.
how are you declaring the array in VB.
Avatar of mikexxx

ASKER

 Dim Buf(100) As Byte
  X = MyClass1.MyMethod(Buf(0))
Avatar of mikexxx

ASKER

I have just noticed that
[in] long cItems, [in, size_is(cItems)] BYTE aItems[]
forces me to make an assignment in the VB.
ie X = MyClass1.MyMethod(2, Buf(0))
rather than just
MyClass1.MyMethod(2, Buf(0))

[in] BYTE aItems[1000]
does not mind is I make an assignment or not.

I don't know what significance this has. It would suggest to me that VB is getting confused though.
>> Dim Buf(100) As Byte

This in VB is declaration for a SafeArray of elements having type Byte.

say you have a method in VB like

Sub Method(arr() as Byte)
End Sub

Its equivalent in IDL would require

[id(0x1)] HRESULT Method([in, out] SAFEARRAY(unsigned char)* arr);
and not
[id(0x1)] HRESULT Method([in, out] byte arr[]);


I hope you see the difference, What you are passing from VB is an automation compatible safe-array of bytes (because arrays in VB are safe-arrays). But what your component expects is not a SafeArray. a Byte[] in IDL is not autmation type and is used by custom interfaces. It is because of this that you cannot use IDispatch::Invoke to pass a BYTE[].

It is because of the presence of a non-automation type that VB gives a type-mismatch.

This is also the reason MIDL complains about the interface having non-automation compatible types. Note that MIDL only complains if you are making a dispinterface not if you are making a custom interface.

You need to find a way in VB to pass something that can qualify as a byte[] and not a safearray. I suppose it might be possible using type-casts or something.If it is not possible then there is no other way but to change the interface definition and make it accept a type that is native to VB.

Hope this helps .. correct me if am wrong ..
Avatar of mikexxx

ASKER

I understand that VB thinks only in terms of SafeArrays.

Somehow in the example that works, COM is converting my data into a SafeArray and passing it to VB.

In the MSDN documents I refered to earlier, they suggest using the array type formats as an alternative to the pointers. They obviously thought it should work in some circumstances.

I don't think this is just a VB issue anyway. I get a warning message when compilling the C++.

Is it that the documents were talking about general COM rather than Active X? Is it that IDL supports arrays but Active X does not?

I think this maybe what you are saying?

The documents I was refering to are:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnmsj99/html/wicked0599.asp

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/midl/mi-laref_3zxv.asp

here is an excerpt from the first article

"Returning variable-length data using indirect pointers is all fine and good for clients written in C++, but clients written in scripting languages such as VBScript require special handling. Today's scripting languages don't deal with C-style arrays very well; in fact, they don't deal with them at all. They expect arrays of data to be packaged in Automation-compatible SAFEARRAYs, which are great for script writers but a pain in the neck for programmers using C++."
Avatar of mikexxx

ASKER

I read that as being for just VBScript. In reality it probably means VB as well.

I have seen in other answers to questions on experts exchange that people seem to always say use SafeArrays. The method I found that appeared to work is much simpler.

Is there anything wrong with doing it that way?
ASKER CERTIFIED SOLUTION
Avatar of ambience
ambience
Flag of Pakistan image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mikexxx

ASKER

Thanks for all your help. I have learnt a lot from you.
Although the use of SAFEARRAYS is all well and good, the cause of the original error is much simpler.  BYTE is a C type and is not recognised by COM as valid for OLE Automation.  The COM type that equates to Byte in VB is unsigned char.  So:

[in] unsigned char aItems[1000]

Should show up in VB as:

aItems(0 to 999) As Byte