My Technical Notes

Tuesday, 5 January 2016

AutoHotkey: Dealing with a SAFEARRAY(BSTR) array from COM

In my COM (Component Object Model) interface, I have a `Suggestions` property that is of the .NET type `string[]`; here is the COM type information (found using OLEView):


[id(0x60020007), propget]
HRESULT Suggestions([out, retval] SAFEARRAY(BSTR)* pRetVal);
[id(0x60020007), propput]
HRESULT Suggestions([in] SAFEARRAY(BSTR) pRetVal);

After invoking the getter:


arr := obj.Suggestions;

we can first check if the array is empty by checking if the `_MaxIndex()` is `-1`:


arr._MaxIndex() == -1 

If there are elements, then `_MaxIndex()` will return a value greater than or equal to `0`.

To get the last element, we pass the `_MaxIndex()` value to the indexer:


lastItem := arr[arr._MaxIndex()]

This is very simple, but one bit of code in which it does NOT work is using the indexer on the COM object's property:


obj.Suggestions[maxIndex]

For whatever reason, we must first evaluate `obj.Suggestions`, and then call the indexer. Therefore this works:


(obj.Suggestions)[maxIndex]

In general, when getting the array, because we are dealing with a copy of the data, if you are using this data multiple times in the code, it is best to assign it to variable before to avoid producing it multiple times.

No comments: