0

My ODL file looks like this:

import "oaidl.idl";
import "ocidl.idl";

[oleautomation, uuid(/* redacted */)]
interface ISomething : IUnknown
{
    HRESULT DoSomething(
        [in]BSTR User,
        [in]VARIANT Object,
        [in]SAFEARRAY Array         // may be NULL
        );
}

I'm getting errors:

1>.\Something.odl(17): error MIDL2139: type of the parameter cannot derive from void or void * : [ Type 'PVOID' ( Parameter 'Array' ) ] 1>.\Something.odl(17): error MIDL2105: pointee / array does not derive any size : [ Field 'rgsabound' of Struct 'tagSAFEARRAY' ( Parameter 'Array' ) ] 1>.\Something.odl(17): error MIDL2465: Structures containing conformant arrays must be passed by reference. See MSDN for more details : [ Struct 'tagSAFEARRAY' ( Parameter 'Array' ) ]

If I change the type from SAFEARRAY to SAFEARRAY* (which I don't believe to be correct?) I get different errors:

1>.\Something.odl(17): error MIDL2139: type of the parameter cannot derive from void or void * : [ Type 'PVOID' ( Parameter 'Array' ) ] 1>.\Something.odl(17): error MIDL2105: pointee / array does not derive any size : [ Field 'rgsabound' of Struct 'tagSAFEARRAY' ( Parameter 'Array' ) ]

Is this simply a case that I need to include some other headers? I'm compiling using the MIDL compiler in VS2013, aparently the command-line looks like this:

/iid "./source/Something_i.c" /h "Something.h" /W1 /char signed /notlb /app_config /nologo /dlldata "./source/Something_dlldata.c" /proxy "./source/Something_p.c" 
Mr. Boy
  • 60,845
  • 93
  • 320
  • 589
  • You need to tell it what type of elements are in your SafeArray. For example SAFEARRAY(unsigned char) *Data for an array of unsigned chars. If the data type of the array elements is variable at runtime you could pass the elements as a SafeArray of VARIANT. – JJF Oct 19 '15 at 13:27
  • @JJF I just found this out and was about to answer my own question... if you can add this as an answer (ideally fixing my method signatures) I'll gladly accept it. – Mr. Boy Oct 19 '15 at 13:31

1 Answers1

2

You need to tell it what type of elements are in your SafeArray. For example SAFEARRAY(unsigned char) *Data for an array of unsigned chars. If the data type of the array elements is variable at runtime you could pass the elements as a SafeArray of VARIANT. For example:

import "oaidl.idl";
import "ocidl.idl";

[oleautomation, uuid(/* redacted */)]
interface ISomething : IUnknown
{
    HRESULT DoSomething(
        [in]BSTR User,
        [in]VARIANT Object,
        [in]SAFEARRAY(unsigned char) *Array         // may be NULL
        );
}
JJF
  • 2,681
  • 2
  • 18
  • 31
  • Specifying the content-type was my issue, thanks. However when I specify `SAFEARRAY *` my generated header file looks like `/* [in] */ SAFEARRAY * *Array` which doesn't seem great! – Mr. Boy Oct 19 '15 at 14:08
  • Not sure why this is a problem. I'm not sure if you can even pass a SAFEARRAY by value. What did the midl compiler say when you omitted the '*'? All it means is that you have to add an additional dereference to get to the data. – JJF Oct 19 '15 at 14:38
  • If I specify by-value in the IDL, the C++ header automatically references it by pointer. I assume .net marshalling would simply have an array type. – Mr. Boy Oct 19 '15 at 14:44
  • I don't have much experience marshalling between managed and unmanaged code. The COM stuff I did was a loooong time ago... – JJF Oct 19 '15 at 14:46
  • Anyway that seems to be a side-issue, maybe it warrants a new question but your answer solves my original problem! – Mr. Boy Oct 19 '15 at 14:49
  • The SAFEARRAY(type) delcaration already implies one level of indirection. So [in] parameters are `[in] SAFEARRAY(type) v` (which is passed as `SAFEARRAY *`), and [out] parameters are `[out] SAFEARRAY(type) * v` (which is passed as `SAFEARRAY **`) – peterchen Apr 09 '20 at 06:09