Question

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?

Was it helpful?

Solution

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(""));

OTHER TIPS

Have you tried passing an empty string?

unsigned char Data = 0;
foo(0,&Data);

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.

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top