passing an array of COM pointers from Python to C++
<p>I've been reading a lot of docs, examples and StackOverflow topics, but still it doesn't work! I'm writing a Python interface to my C++ COM objects. This is not the first time I've done this. In the past I've successfully used comtypes to acquire individual interface pointers and passed them my COM classes, but this time I need to pass a pointer to an array of interface pointers.</p>

<p>The COM interface I need to call:</p>

<pre><code>STDMETHOD(ExportGeopackage)([in] IMap* pMap,
                            [in] imageFormatType imageFormat,
                            [in] long imageQuality,
                            [in] long zoomMin,
                            [in] long zoomMax,
                            [in] IFeatureLayer** attributeExportLayers,
                            [in] BSTR title,
                            [in] BSTR description,
                            [in] BSTR saveToPath,
                            [in] ITrackCancel* pTrackCancel);
</code></pre>

<p>The attributeExportLayers argument is expected to be a pointer to a null-terminated C array of IFeatureLayer pointers. ExportGeopackage() has already been tested with C++ clients. I'm writing the first Python client.</p>

<p>In Python:</p>

<pre><code># append a null pointer to the list of comtypes IFeatureLayer pointers
exportLayers.append(comtypes.cast(0, comtypes.POINTER(esriCarto.IFeatureLayer)))
# create ctypes array and populate
PointerArray = ctypes.c_void_p * len(exportLayers)
pointers = PointerArray()
for i in range(len(exportLayers)):
    pointers[i] = exportLayers[i]

# export is comtypes interface pointer acquired earlier
export.ExportGeopackage(map, format, quality, min, max,
                        ctypes.cast(pointers, ctypes.POINTER(esriCarto.IFeatureLayer)),
                        title, desc, geopackage_path, 0)
</code></pre>

<p>Comparing Python dumps of the content of exportLayer and pointers variables shows the pointer values being successfully transferred from the former to the latter. Python tests of these pointers are successful. However when I debug into ExportGeopackage() the memory pointed to by attributeExportLayers has no resemblance to the expected array of IFeatureLayer pointers. It looks like a single pointer (pointing to the wrong place) followed by a long string of null pointers. Thinking that possibly the Python pointers variable had already been garbage collected, I added a reference to pointers after the call to ExportGeopackage(). This made no difference.</p>

<p>Am I somehow inserting an extra level of indirection, or not enough indirection? I'm mystified.</p>

<p>TIA for any help (or guesses).
Alan</p>

<p>Once again, answering my own question. There is an additional level of indirection being introduced beyond what is required. Apparently, unlike a cast in C, ctypes.cast actually takes the address of the first argument.</p>

<p>Change:</p>

<pre><code>PointerArray = ctypes.c_void_p * len(exportLayers)
</code></pre>

<p>To:</p>

<pre><code>PointerArray = comtypes.POINTER(esriCarto.IFeatureLayer) * len(exportLayers)
</code></pre>

<p>And eliminate the use of ctypes.cast in the call to ExportGeopackage():</p>

<pre><code>export.ExportGeopackage(map, format, quality, min, max,
                        pointers,
                        title, desc, geopackage_path, 0)
</code></pre>

python windows types comtypes