tags:

views:

225

answers:

5

I have a COM API foo, the IDL looks like:

foo([in] unsigned long ulSize, [in, size_is(ulSize)] unsigned char* pData)

when I consume this function with foo(0,NULL); I get an error - NULL argument passed. Is there a way to workaround this?

+2  A: 

Have you tried passing an empty string?

unsigned char Data = 0;
foo(0,&Data);
Binary Worrier
A: 

You should probably mark the char* as as string to get some assistance with the marshaling.

foo([in] unsigned long ulSize, [in,string,size_is(ulSize)] unsigned char* pData)

We don't use the size_is option in the IDL, perhaps it is forcing the issue of having a non NULL address?

foo([in] unsigned long ulSize, [in,string] unsigned char* pData)

I'd certainly recommend using BSTR or SAFEARRAY rather than char. The issue would then be how to handle this empty case best, possibly treating the same as an empty string, or having a separate method.

Passing pointers in COM is very bad form, like passing a pointer using shared memory the (potentially/likely) remote process will not have access to the memory. As such COM tries to help by martialling the actual data for you, but if you have hidden it behind a different data type it won't be martialling the data properly. For instance using wchar_t* it will create a system allocated string available between the processes. or you can do the same and have an interface taking a bstring and pass it the result of a sysallocstring()

Perhaps you could tell us more about the structure you want to use, it might be more appropriate to expand the com interface with objects of this type. Or there may be some other trick in martialling to transfer the data, you can write custom martialling methods to serialize and deserialize the content.

Greg Domjan
Its actually of type void* since there is no void* in IDL, using a char* instead.
atVelu
A: 

Don't use char* in COM APIs -- use BSTR instead. Then pass an empty string.

foo([in] unsigned long ulSize, [in] BSTR pData)

...

foo(1, _bstr_t(""));
John Dibling
I actually wanted to pass a struct of type void* since there is no void* in IDL, I'm using a char*.
atVelu
@null: Passing a void* via a COM interface is fraught with peril. For one thing COM doesn't know how to marshall the data the void* points to, and for another the pointer may not be valid on the other side of the call. You really should not do this.
John Dibling
If the call is in-process it's no more perilous than it ever is to pass a (void *). Both sides must have the same definition for the pointed-to data type, but there are no other requirements just because it's COM.
Daniel Earwicker
A: 

If you're passing in a BSTR you should just pass the BSTR value - they're already length counted (use SysStrLength to find the length).

If you want to pass in a null terminated string, use the [string] attribute as Greg said

But the answer to your actual question is that you need to mark the string parameter as "unique" - that lets the MIDL compiler (and the RPC runtime library) know that it's ok for that parameter to be NULL.

So use:

foo([in, string] unsigned char* pData)

You don't need the length field because it's a null terminated string - so you can use strlen on the string.

Larry Osterman
A: 

foo is probably implemented like this:

HRESULT foo(unsigned long ulSize, unsigned char* pData) {
  if (!pData) {
    return E_POINTER;
  }
  ...
}

In this case the only workaround is to pass non-NULL pData.

Constantin